| /* |
| Copyright 2014 The Kubernetes Authors. |
| |
| Licensed under the Apache License, Version 2.0 (the "License"); |
| you may not use this file except in compliance with the License. |
| You may obtain a copy of the License at |
| |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, software |
| distributed under the License is distributed on an "AS IS" BASIS, |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| See the License for the specific language governing permissions and |
| limitations under the License. |
| */ |
| |
| package exists |
| |
| import ( |
| "fmt" |
| "testing" |
| "time" |
| |
| corev1 "k8s.io/api/core/v1" |
| metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" |
| "k8s.io/apimachinery/pkg/runtime" |
| "k8s.io/apimachinery/pkg/util/wait" |
| "k8s.io/apiserver/pkg/admission" |
| genericadmissioninitializer "k8s.io/apiserver/pkg/admission/initializer" |
| informers "k8s.io/client-go/informers" |
| "k8s.io/client-go/kubernetes" |
| "k8s.io/client-go/kubernetes/fake" |
| core "k8s.io/client-go/testing" |
| api "k8s.io/kubernetes/pkg/apis/core" |
| ) |
| |
| // newHandlerForTest returns the admission controller configured for testing. |
| func newHandlerForTest(c kubernetes.Interface) (admission.ValidationInterface, informers.SharedInformerFactory, error) { |
| f := informers.NewSharedInformerFactory(c, 5*time.Minute) |
| handler := NewExists() |
| pluginInitializer := genericadmissioninitializer.New(c, f, nil, nil) |
| pluginInitializer.Initialize(handler) |
| err := admission.ValidateInitialization(handler) |
| return handler, f, err |
| } |
| |
| // newMockClientForTest creates a mock client that returns a client configured for the specified list of namespaces. |
| func newMockClientForTest(namespaces []string) *fake.Clientset { |
| mockClient := &fake.Clientset{} |
| mockClient.AddReactor("list", "namespaces", func(action core.Action) (bool, runtime.Object, error) { |
| namespaceList := &corev1.NamespaceList{ |
| ListMeta: metav1.ListMeta{ |
| ResourceVersion: fmt.Sprintf("%d", len(namespaces)), |
| }, |
| } |
| for i, ns := range namespaces { |
| namespaceList.Items = append(namespaceList.Items, corev1.Namespace{ |
| ObjectMeta: metav1.ObjectMeta{ |
| Name: ns, |
| ResourceVersion: fmt.Sprintf("%d", i), |
| }, |
| }) |
| } |
| return true, namespaceList, nil |
| }) |
| return mockClient |
| } |
| |
| // newPod returns a new pod for the specified namespace |
| func newPod(namespace string) api.Pod { |
| return api.Pod{ |
| ObjectMeta: metav1.ObjectMeta{Name: "123", Namespace: namespace}, |
| Spec: api.PodSpec{ |
| Volumes: []api.Volume{{Name: "vol"}}, |
| Containers: []api.Container{{Name: "ctr", Image: "image"}}, |
| }, |
| } |
| } |
| |
| // TestAdmissionNamespaceExists verifies pod is admitted only if namespace exists. |
| func TestAdmissionNamespaceExists(t *testing.T) { |
| namespace := "test" |
| mockClient := newMockClientForTest([]string{namespace}) |
| handler, informerFactory, err := newHandlerForTest(mockClient) |
| if err != nil { |
| t.Errorf("unexpected error initializing handler: %v", err) |
| } |
| informerFactory.Start(wait.NeverStop) |
| |
| pod := newPod(namespace) |
| err = handler.Validate(admission.NewAttributesRecord(&pod, nil, api.Kind("Pod").WithVersion("version"), pod.Namespace, pod.Name, api.Resource("pods").WithVersion("version"), "", admission.Create, false, nil)) |
| if err != nil { |
| t.Errorf("unexpected error returned from admission handler") |
| } |
| } |
| |
| // TestAdmissionNamespaceDoesNotExist verifies pod is not admitted if namespace does not exist. |
| func TestAdmissionNamespaceDoesNotExist(t *testing.T) { |
| namespace := "test" |
| mockClient := newMockClientForTest([]string{}) |
| mockClient.AddReactor("get", "namespaces", func(action core.Action) (bool, runtime.Object, error) { |
| return true, nil, fmt.Errorf("nope, out of luck") |
| }) |
| handler, informerFactory, err := newHandlerForTest(mockClient) |
| if err != nil { |
| t.Errorf("unexpected error initializing handler: %v", err) |
| } |
| informerFactory.Start(wait.NeverStop) |
| |
| pod := newPod(namespace) |
| err = handler.Validate(admission.NewAttributesRecord(&pod, nil, api.Kind("Pod").WithVersion("version"), pod.Namespace, pod.Name, api.Resource("pods").WithVersion("version"), "", admission.Create, false, nil)) |
| if err == nil { |
| actions := "" |
| for _, action := range mockClient.Actions() { |
| actions = actions + action.GetVerb() + ":" + action.GetResource().Resource + ":" + action.GetSubresource() + ", " |
| } |
| t.Errorf("expected error returned from admission handler: %v", actions) |
| } |
| } |