func TestSAR(t *testing.T) { store := projectcache.NewCacheStore(cache.IndexFuncToKeyFuncAdapter(cache.MetaNamespaceIndexFunc)) mockClient := &testclient.Fake{} mockClient.AddReactor("get", "namespaces", func(action testclient.Action) (handled bool, ret runtime.Object, err error) { return true, nil, fmt.Errorf("shouldn't get here") }) cache := projectcache.NewFake(mockClient.Namespaces(), store, "") mockClientset := clientsetfake.NewSimpleClientset() handler := &lifecycle{client: mockClientset, creatableResources: recommendedCreatableResources} handler.SetProjectCache(cache) tests := map[string]struct { kind string resource string }{ "subject access review": { kind: "SubjectAccessReview", resource: "subjectaccessreviews", }, "local subject access review": { kind: "LocalSubjectAccessReview", resource: "localsubjectaccessreviews", }, } for k, v := range tests { err := handler.Admit(admission.NewAttributesRecord(nil, nil, kapi.Kind(v.kind).WithVersion("v1"), "foo", "name", kapi.Resource(v.resource).WithVersion("v1"), "", "CREATE", nil)) if err != nil { t.Errorf("Unexpected error for %s returned from admission handler: %v", k, err) } } }
func TestSAR(t *testing.T) { store := cache.NewStore(cache.IndexFuncToKeyFuncAdapter(cache.MetaNamespaceIndexFunc)) mockClient := &testclient.Fake{} mockClient.AddReactor("get", "namespaces", func(action testclient.Action) (handled bool, ret runtime.Object, err error) { return true, nil, fmt.Errorf("shouldn't get here") }) projectcache.FakeProjectCache(mockClient, store, "") handler := &lifecycle{client: mockClient} tests := map[string]struct { kind string resource string }{ "subject access review": { kind: "SubjectAccessReview", resource: "subjectaccessreviews", }, "local subject access review": { kind: "LocalSubjectAccessReview", resource: "localsubjectaccessreviews", }, } for k, v := range tests { err := handler.Admit(admission.NewAttributesRecord(nil, v.kind, "foo", "name", v.resource, "", "CREATE", nil)) if err != nil { t.Errorf("Unexpected error for %s returned from admission handler: %v", k, err) } } }
// TestAdmissionLifecycle verifies you cannot create Origin content if namespace is terminating func TestAdmissionLifecycle(t *testing.T) { namespaceObj := &kapi.Namespace{ ObjectMeta: kapi.ObjectMeta{ Name: "test", Namespace: "", }, Status: kapi.NamespaceStatus{ Phase: kapi.NamespaceActive, }, } store := projectcache.NewCacheStore(cache.IndexFuncToKeyFuncAdapter(cache.MetaNamespaceIndexFunc)) store.Add(namespaceObj) mockClient := &testclient.Fake{} cache := projectcache.NewFake(mockClient.Namespaces(), store, "") mockClientset := clientsetfake.NewSimpleClientset(namespaceObj) handler := &lifecycle{client: mockClientset} handler.SetProjectCache(cache) build := &buildapi.Build{ ObjectMeta: kapi.ObjectMeta{Name: "buildid", Namespace: "other"}, Spec: buildapi.BuildSpec{ CommonSpec: buildapi.CommonSpec{ Source: buildapi.BuildSource{ Git: &buildapi.GitBuildSource{ URI: "http://github.com/my/repository", }, ContextDir: "context", }, Strategy: buildapi.BuildStrategy{ DockerStrategy: &buildapi.DockerBuildStrategy{}, }, Output: buildapi.BuildOutput{ To: &kapi.ObjectReference{ Kind: "DockerImage", Name: "repository/data", }, }, }, }, Status: buildapi.BuildStatus{ Phase: buildapi.BuildPhaseNew, }, } err := handler.Admit(admission.NewAttributesRecord(build, nil, kapi.Kind("Build").WithVersion("version"), build.Namespace, "name", kapi.Resource("builds").WithVersion("version"), "", "CREATE", nil)) if err != nil { t.Errorf("Unexpected error returned from admission handler: %v", err) } // change namespace state to terminating namespaceObj.Status.Phase = kapi.NamespaceTerminating store.Add(namespaceObj) // verify create operations in the namespace cause an error err = handler.Admit(admission.NewAttributesRecord(build, nil, kapi.Kind("Build").WithVersion("version"), build.Namespace, "name", kapi.Resource("builds").WithVersion("version"), "", "CREATE", nil)) if err == nil { t.Errorf("Expected error rejecting creates in a namespace when it is terminating") } // verify update operations in the namespace can proceed err = handler.Admit(admission.NewAttributesRecord(build, build, kapi.Kind("Build").WithVersion("version"), build.Namespace, "name", kapi.Resource("builds").WithVersion("version"), "", "UPDATE", nil)) if err != nil { t.Errorf("Unexpected error returned from admission handler: %v", err) } // verify delete operations in the namespace can proceed err = handler.Admit(admission.NewAttributesRecord(nil, nil, kapi.Kind("Build").WithVersion("version"), build.Namespace, "name", kapi.Resource("builds").WithVersion("version"), "", "DELETE", nil)) if err != nil { t.Errorf("Unexpected error returned from admission handler: %v", err) } }
// TestPodAdmission verifies various scenarios involving pod/project/global node label selectors func TestPodAdmission(t *testing.T) { project := &kapi.Namespace{ ObjectMeta: kapi.ObjectMeta{ Name: "testProject", Namespace: "", }, } projectStore := projectcache.NewCacheStore(cache.IndexFuncToKeyFuncAdapter(cache.MetaNamespaceIndexFunc)) projectStore.Add(project) mockClientset := fake.NewSimpleClientset() handler := &podNodeEnvironment{client: mockClientset} pod := &kapi.Pod{ ObjectMeta: kapi.ObjectMeta{Name: "testPod"}, } tests := []struct { defaultNodeSelector string projectNodeSelector string podNodeSelector map[string]string mergedNodeSelector map[string]string ignoreProjectNodeSelector bool admit bool testName string }{ { defaultNodeSelector: "", podNodeSelector: map[string]string{}, mergedNodeSelector: map[string]string{}, ignoreProjectNodeSelector: true, admit: true, testName: "No node selectors", }, { defaultNodeSelector: "infra = false", podNodeSelector: map[string]string{}, mergedNodeSelector: map[string]string{"infra": "false"}, ignoreProjectNodeSelector: true, admit: true, testName: "Default node selector and no conflicts", }, { defaultNodeSelector: "", projectNodeSelector: "infra = false", podNodeSelector: map[string]string{}, mergedNodeSelector: map[string]string{"infra": "false"}, admit: true, testName: "Project node selector and no conflicts", }, { defaultNodeSelector: "infra = false", projectNodeSelector: "", podNodeSelector: map[string]string{}, mergedNodeSelector: map[string]string{}, admit: true, testName: "Empty project node selector and no conflicts", }, { defaultNodeSelector: "infra = false", projectNodeSelector: "infra=true", podNodeSelector: map[string]string{}, mergedNodeSelector: map[string]string{"infra": "true"}, admit: true, testName: "Default and project node selector, no conflicts", }, { defaultNodeSelector: "infra = false", projectNodeSelector: "infra=true", podNodeSelector: map[string]string{"env": "test"}, mergedNodeSelector: map[string]string{"infra": "true", "env": "test"}, admit: true, testName: "Project and pod node selector, no conflicts", }, { defaultNodeSelector: "env = test", projectNodeSelector: "infra=true", podNodeSelector: map[string]string{"infra": "false"}, mergedNodeSelector: map[string]string{"infra": "false"}, admit: false, testName: "Conflicting pod and project node selector, one label", }, { defaultNodeSelector: "env=dev", projectNodeSelector: "infra=false, env = test", podNodeSelector: map[string]string{"env": "dev", "color": "blue"}, mergedNodeSelector: map[string]string{"env": "dev", "color": "blue"}, admit: false, testName: "Conflicting pod and project node selector, multiple labels", }, } for _, test := range tests { cache := projectcache.NewFake(mockClientset.Core().Namespaces(), projectStore, test.defaultNodeSelector) handler.SetProjectCache(cache) if !test.ignoreProjectNodeSelector { project.ObjectMeta.Annotations = map[string]string{"openshift.io/node-selector": test.projectNodeSelector} } pod.Spec = kapi.PodSpec{NodeSelector: test.podNodeSelector} err := handler.Admit(admission.NewAttributesRecord(pod, nil, kapi.Kind("Pod").WithVersion("version"), "namespace", project.ObjectMeta.Name, kapi.Resource("pods").WithVersion("version"), "", admission.Create, nil)) if test.admit && err != nil { t.Errorf("Test: %s, expected no error but got: %s", test.testName, err) } else if !test.admit && err == nil { t.Errorf("Test: %s, expected an error", test.testName) } if !labelselector.Equals(test.mergedNodeSelector, pod.Spec.NodeSelector) { t.Errorf("Test: %s, expected: %s but got: %s", test.testName, test.mergedNodeSelector, pod.Spec.NodeSelector) } } }
// TestAdmission func TestAdmission(t *testing.T) { namespaceObj := &api.Namespace{ ObjectMeta: api.ObjectMeta{ Name: "test", Namespace: "", }, Status: api.NamespaceStatus{ Phase: api.NamespaceActive, }, } store := cache.NewStore(cache.IndexFuncToKeyFuncAdapter(cache.MetaNamespaceIndexFunc)) store.Add(namespaceObj) mockClient := &testclient.Fake{} lfhandler := NewLifecycle(mockClient).(*lifecycle) lfhandler.store = store handler := admission.NewChainHandler(lfhandler) pod := api.Pod{ ObjectMeta: api.ObjectMeta{Name: "123", Namespace: namespaceObj.Namespace}, Spec: api.PodSpec{ Volumes: []api.Volume{{Name: "vol"}}, Containers: []api.Container{{Name: "ctr", Image: "image"}}, }, } err := handler.Admit(admission.NewAttributesRecord(&pod, "Pod", pod.Namespace, pod.Name, "pods", "", admission.Create, nil)) if err != nil { t.Errorf("Unexpected error returned from admission handler: %v", err) } // change namespace state to terminating namespaceObj.Status.Phase = api.NamespaceTerminating store.Add(namespaceObj) // verify create operations in the namespace cause an error err = handler.Admit(admission.NewAttributesRecord(&pod, "Pod", pod.Namespace, pod.Name, "pods", "", admission.Create, nil)) if err == nil { t.Errorf("Expected error rejecting creates in a namespace when it is terminating") } // verify update operations in the namespace can proceed err = handler.Admit(admission.NewAttributesRecord(&pod, "Pod", pod.Namespace, pod.Name, "pods", "", admission.Update, nil)) if err != nil { t.Errorf("Unexpected error returned from admission handler: %v", err) } // verify delete operations in the namespace can proceed err = handler.Admit(admission.NewAttributesRecord(nil, "Pod", pod.Namespace, pod.Name, "pods", "", admission.Delete, nil)) if err != nil { t.Errorf("Unexpected error returned from admission handler: %v", err) } // verify delete of namespace default can never proceed err = handler.Admit(admission.NewAttributesRecord(nil, "Namespace", "", api.NamespaceDefault, "namespaces", "", admission.Delete, nil)) if err == nil { t.Errorf("Expected an error that this namespace can never be deleted") } // verify delete of namespace other than default can proceed err = handler.Admit(admission.NewAttributesRecord(nil, "Namespace", "", "other", "namespaces", "", admission.Delete, nil)) if err != nil { t.Errorf("Did not expect an error %v", err) } }