1
16
17 package autoprovision
18
19 import (
20 "context"
21 "fmt"
22 "testing"
23 "time"
24
25 corev1 "k8s.io/api/core/v1"
26 "k8s.io/apimachinery/pkg/api/errors"
27 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
28 "k8s.io/apimachinery/pkg/runtime"
29 "k8s.io/apimachinery/pkg/util/wait"
30 "k8s.io/apiserver/pkg/admission"
31 genericadmissioninitializer "k8s.io/apiserver/pkg/admission/initializer"
32 admissiontesting "k8s.io/apiserver/pkg/admission/testing"
33 "k8s.io/client-go/informers"
34 clientset "k8s.io/client-go/kubernetes"
35 "k8s.io/client-go/kubernetes/fake"
36 core "k8s.io/client-go/testing"
37 api "k8s.io/kubernetes/pkg/apis/core"
38 )
39
40
41 func newHandlerForTest(c clientset.Interface) (admission.MutationInterface, informers.SharedInformerFactory, error) {
42 f := informers.NewSharedInformerFactory(c, 5*time.Minute)
43 handler := NewProvision()
44 pluginInitializer := genericadmissioninitializer.New(c, nil, f, nil, nil, nil, nil)
45 pluginInitializer.Initialize(handler)
46 err := admission.ValidateInitialization(handler)
47 return handler, f, err
48 }
49
50
51 func newMockClientForTest(namespaces []string) *fake.Clientset {
52 mockClient := &fake.Clientset{}
53 mockClient.AddReactor("list", "namespaces", func(action core.Action) (bool, runtime.Object, error) {
54 namespaceList := &corev1.NamespaceList{
55 ListMeta: metav1.ListMeta{
56 ResourceVersion: fmt.Sprintf("%d", len(namespaces)),
57 },
58 }
59 for i, ns := range namespaces {
60 namespaceList.Items = append(namespaceList.Items, corev1.Namespace{
61 ObjectMeta: metav1.ObjectMeta{
62 Name: ns,
63 ResourceVersion: fmt.Sprintf("%d", i),
64 },
65 })
66 }
67 return true, namespaceList, nil
68 })
69 return mockClient
70 }
71
72
73 func newPod(namespace string) api.Pod {
74 return api.Pod{
75 ObjectMeta: metav1.ObjectMeta{Name: "123", Namespace: namespace},
76 Spec: api.PodSpec{
77 Volumes: []api.Volume{{Name: "vol"}},
78 Containers: []api.Container{{Name: "ctr", Image: "image"}},
79 },
80 }
81 }
82
83
84 func hasCreateNamespaceAction(mockClient *fake.Clientset) bool {
85 for _, action := range mockClient.Actions() {
86 if action.GetVerb() == "create" && action.GetResource().Resource == "namespaces" {
87 return true
88 }
89 }
90 return false
91 }
92
93
94 func TestAdmission(t *testing.T) {
95 namespace := "test"
96 mockClient := newMockClientForTest([]string{})
97 handler, informerFactory, err := newHandlerForTest(mockClient)
98 if err != nil {
99 t.Errorf("unexpected error initializing handler: %v", err)
100 }
101 informerFactory.Start(wait.NeverStop)
102
103 pod := newPod(namespace)
104 err = admissiontesting.WithReinvocationTesting(t, handler).Admit(context.TODO(), admission.NewAttributesRecord(&pod, nil, api.Kind("Pod").WithVersion("version"), pod.Namespace, pod.Name, api.Resource("pods").WithVersion("version"), "", admission.Create, &metav1.CreateOptions{}, false, nil), nil)
105 if err != nil {
106 t.Errorf("unexpected error returned from admission handler")
107 }
108 if !hasCreateNamespaceAction(mockClient) {
109 t.Errorf("expected create namespace action")
110 }
111 }
112
113
114 func TestAdmissionNamespaceExists(t *testing.T) {
115 namespace := "test"
116 mockClient := newMockClientForTest([]string{namespace})
117 handler, informerFactory, err := newHandlerForTest(mockClient)
118 if err != nil {
119 t.Errorf("unexpected error initializing handler: %v", err)
120 }
121 informerFactory.Start(wait.NeverStop)
122
123 pod := newPod(namespace)
124 err = admissiontesting.WithReinvocationTesting(t, handler).Admit(context.TODO(), admission.NewAttributesRecord(&pod, nil, api.Kind("Pod").WithVersion("version"), pod.Namespace, pod.Name, api.Resource("pods").WithVersion("version"), "", admission.Create, &metav1.CreateOptions{}, false, nil), nil)
125 if err != nil {
126 t.Errorf("unexpected error returned from admission handler")
127 }
128 if hasCreateNamespaceAction(mockClient) {
129 t.Errorf("unexpected create namespace action")
130 }
131 }
132
133
134 func TestAdmissionDryRun(t *testing.T) {
135 namespace := "test"
136 mockClient := newMockClientForTest([]string{})
137 handler, informerFactory, err := newHandlerForTest(mockClient)
138 if err != nil {
139 t.Errorf("unexpected error initializing handler: %v", err)
140 }
141 informerFactory.Start(wait.NeverStop)
142
143 pod := newPod(namespace)
144 err = admissiontesting.WithReinvocationTesting(t, handler).Admit(context.TODO(), admission.NewAttributesRecord(&pod, nil, api.Kind("Pod").WithVersion("version"), pod.Namespace, pod.Name, api.Resource("pods").WithVersion("version"), "", admission.Create, &metav1.CreateOptions{}, true, nil), nil)
145 if err != nil {
146 t.Errorf("unexpected error returned from admission handler")
147 }
148 if hasCreateNamespaceAction(mockClient) {
149 t.Errorf("unexpected create namespace action")
150 }
151 }
152
153
154 func TestIgnoreAdmission(t *testing.T) {
155 namespace := "test"
156 mockClient := newMockClientForTest([]string{})
157 handler, informerFactory, err := newHandlerForTest(mockClient)
158 if err != nil {
159 t.Errorf("unexpected error initializing handler: %v", err)
160 }
161 informerFactory.Start(wait.NeverStop)
162 chainHandler := admissiontesting.WithReinvocationTesting(t, admission.NewChainHandler(handler))
163
164 pod := newPod(namespace)
165 err = admissiontesting.WithReinvocationTesting(t, chainHandler).Admit(context.TODO(), admission.NewAttributesRecord(&pod, nil, api.Kind("Pod").WithVersion("version"), pod.Namespace, pod.Name, api.Resource("pods").WithVersion("version"), "", admission.Update, &metav1.UpdateOptions{}, false, nil), nil)
166 if err != nil {
167 t.Errorf("unexpected error returned from admission handler")
168 }
169 if hasCreateNamespaceAction(mockClient) {
170 t.Errorf("unexpected create namespace action")
171 }
172 }
173
174 func TestAdmissionWithLatentCache(t *testing.T) {
175 namespace := "test"
176 mockClient := newMockClientForTest([]string{})
177 mockClient.AddReactor("create", "namespaces", func(action core.Action) (bool, runtime.Object, error) {
178 return true, nil, errors.NewAlreadyExists(api.Resource("namespaces"), namespace)
179 })
180 handler, informerFactory, err := newHandlerForTest(mockClient)
181 if err != nil {
182 t.Errorf("unexpected error initializing handler: %v", err)
183 }
184 informerFactory.Start(wait.NeverStop)
185
186 pod := newPod(namespace)
187 err = admissiontesting.WithReinvocationTesting(t, handler).Admit(context.TODO(), admission.NewAttributesRecord(&pod, nil, api.Kind("Pod").WithVersion("version"), pod.Namespace, pod.Name, api.Resource("pods").WithVersion("version"), "", admission.Create, &metav1.CreateOptions{}, false, nil), nil)
188 if err != nil {
189 t.Errorf("unexpected error returned from admission handler")
190 }
191
192 if !hasCreateNamespaceAction(mockClient) {
193 t.Errorf("expected create namespace action")
194 }
195 }
196
View as plain text