1
16
17 package namespace
18
19 import (
20 "context"
21 "encoding/json"
22 "fmt"
23 "testing"
24 "time"
25
26 appsv1 "k8s.io/api/apps/v1"
27 corev1 "k8s.io/api/core/v1"
28 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
29 "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
30 "k8s.io/apimachinery/pkg/util/dump"
31 "k8s.io/apimachinery/pkg/util/wait"
32 "k8s.io/client-go/dynamic"
33 "k8s.io/client-go/informers"
34 clientset "k8s.io/client-go/kubernetes"
35 "k8s.io/client-go/metadata"
36 restclient "k8s.io/client-go/rest"
37 "k8s.io/klog/v2/ktesting"
38 kubeapiservertesting "k8s.io/kubernetes/cmd/kube-apiserver/app/testing"
39 "k8s.io/kubernetes/pkg/controller/namespace"
40 "k8s.io/kubernetes/test/integration/etcd"
41 "k8s.io/kubernetes/test/integration/framework"
42 )
43
44 func TestNamespaceCondition(t *testing.T) {
45 closeFn, nsController, informers, kubeClient, dynamicClient := namespaceLifecycleSetup(t)
46 defer closeFn()
47 nsName := "test-namespace-conditions"
48 _, err := kubeClient.CoreV1().Namespaces().Create(context.TODO(), &corev1.Namespace{
49 ObjectMeta: metav1.ObjectMeta{
50 Name: nsName,
51 },
52 }, metav1.CreateOptions{})
53 if err != nil {
54 t.Fatal(err)
55 }
56
57
58 _, ctx := ktesting.NewTestContext(t)
59 ctx, cancel := context.WithCancel(ctx)
60 defer cancel()
61
62 informers.Start(ctx.Done())
63 go nsController.Run(ctx, 5)
64
65 data := etcd.GetEtcdStorageDataForNamespace(nsName)
66 podJSON, err := jsonToUnstructured(data[corev1.SchemeGroupVersion.WithResource("pods")].Stub, "v1", "Pod")
67 if err != nil {
68 t.Fatal(err)
69 }
70 _, err = dynamicClient.Resource(corev1.SchemeGroupVersion.WithResource("pods")).Namespace(nsName).Create(context.TODO(), podJSON, metav1.CreateOptions{})
71 if err != nil {
72 t.Fatal(err)
73 }
74
75 deploymentJSON, err := jsonToUnstructured(data[appsv1.SchemeGroupVersion.WithResource("deployments")].Stub, "apps/v1", "Deployment")
76 if err != nil {
77 t.Fatal(err)
78 }
79 deploymentJSON.SetFinalizers([]string{"custom.io/finalizer"})
80 _, err = dynamicClient.Resource(appsv1.SchemeGroupVersion.WithResource("deployments")).Namespace(nsName).Create(context.TODO(), deploymentJSON, metav1.CreateOptions{})
81 if err != nil {
82 t.Fatal(err)
83 }
84
85 if err = kubeClient.CoreV1().Namespaces().Delete(context.TODO(), nsName, metav1.DeleteOptions{}); err != nil {
86 t.Fatal(err)
87 }
88
89 err = wait.PollImmediate(1*time.Second, 60*time.Second, func() (bool, error) {
90 curr, err := kubeClient.CoreV1().Namespaces().Get(context.TODO(), nsName, metav1.GetOptions{})
91 if err != nil {
92 return false, err
93 }
94
95 conditionsFound := 0
96 for _, condition := range curr.Status.Conditions {
97 if condition.Type == corev1.NamespaceDeletionGVParsingFailure && condition.Message == `All legacy kube types successfully parsed` {
98 conditionsFound++
99 }
100 if condition.Type == corev1.NamespaceDeletionDiscoveryFailure && condition.Message == `All resources successfully discovered` {
101 conditionsFound++
102 }
103 if condition.Type == corev1.NamespaceDeletionContentFailure && condition.Message == `All content successfully deleted, may be waiting on finalization` {
104 conditionsFound++
105 }
106 if condition.Type == corev1.NamespaceContentRemaining && condition.Message == `Some resources are remaining: deployments.apps has 1 resource instances` {
107 conditionsFound++
108 }
109 if condition.Type == corev1.NamespaceFinalizersRemaining && condition.Message == `Some content in the namespace has finalizers remaining: custom.io/finalizer in 1 resource instances` {
110 conditionsFound++
111 }
112 }
113
114 t.Log(dump.Pretty(curr))
115 return conditionsFound == 5, nil
116 })
117 if err != nil {
118 t.Fatal(err)
119 }
120 }
121
122
123 func TestNamespaceLabels(t *testing.T) {
124 closeFn, nsController, _, kubeClient, _ := namespaceLifecycleSetup(t)
125 defer closeFn()
126
127
128
129 _, ctx := ktesting.NewTestContext(t)
130 ctx, cancel := context.WithCancel(ctx)
131 defer cancel()
132 go nsController.Run(ctx, 5)
133
134 nsName := "test-namespace-labels-generated"
135
136 ns, err := kubeClient.CoreV1().Namespaces().Create(context.TODO(), &corev1.Namespace{
137 ObjectMeta: metav1.ObjectMeta{
138 GenerateName: nsName,
139 },
140 }, metav1.CreateOptions{})
141
142 if err != nil {
143 t.Fatal(err)
144 }
145
146 if ns.Name != ns.Labels[corev1.LabelMetadataName] {
147 t.Fatal(fmt.Errorf("expected %q, got %q", ns.Name, ns.Labels[corev1.LabelMetadataName]))
148 }
149
150 nsList, err := kubeClient.CoreV1().Namespaces().List(context.TODO(), metav1.ListOptions{})
151
152 if err != nil {
153 t.Fatal(err)
154 }
155
156 for _, ns := range nsList.Items {
157 if ns.Name != ns.Labels[corev1.LabelMetadataName] {
158 t.Fatal(fmt.Errorf("expected %q, got %q", ns.Name, ns.Labels[corev1.LabelMetadataName]))
159 }
160 }
161 }
162
163
164
165 func jsonToUnstructured(stub, version, kind string) (*unstructured.Unstructured, error) {
166 typeMetaAdder := map[string]interface{}{}
167 if err := json.Unmarshal([]byte(stub), &typeMetaAdder); err != nil {
168 return nil, err
169 }
170
171
172 typeMetaAdder["apiVersion"] = version
173 typeMetaAdder["kind"] = kind
174
175 return &unstructured.Unstructured{Object: typeMetaAdder}, nil
176 }
177
178 func namespaceLifecycleSetup(t *testing.T) (kubeapiservertesting.TearDownFunc, *namespace.NamespaceController, informers.SharedInformerFactory, clientset.Interface, dynamic.Interface) {
179
180 server := kubeapiservertesting.StartTestServerOrDie(t, nil, []string{"--disable-admission-plugins=ServiceAccount"}, framework.SharedEtcd())
181
182 config := restclient.CopyConfig(server.ClientConfig)
183 config.QPS = 10000
184 config.Burst = 10000
185 clientSet, err := clientset.NewForConfig(config)
186 if err != nil {
187 t.Fatalf("error in create clientset: %v", err)
188 }
189 resyncPeriod := 12 * time.Hour
190 informers := informers.NewSharedInformerFactory(clientset.NewForConfigOrDie(restclient.AddUserAgent(config, "deployment-informers")), resyncPeriod)
191
192 metadataClient, err := metadata.NewForConfig(config)
193 if err != nil {
194 panic(err)
195 }
196
197 discoverResourcesFn := clientSet.Discovery().ServerPreferredNamespacedResources
198 _, ctx := ktesting.NewTestContext(t)
199 controller := namespace.NewNamespaceController(
200 ctx,
201 clientSet,
202 metadataClient,
203 discoverResourcesFn,
204 informers.Core().V1().Namespaces(),
205 10*time.Hour,
206 corev1.FinalizerKubernetes)
207
208 return server.TearDownFn, controller, informers, clientSet, dynamic.NewForConfigOrDie(config)
209 }
210
View as plain text