func TestResourceRestrictionsWithWeirdWork(t *testing.T) { test1 := &authorizeTest{ context: kapi.WithUser(kapi.WithNamespace(kapi.NewContext(), "adze"), &user.DefaultInfo{Name: "Rachel"}), attributes: &DefaultAuthorizationAttributes{ Verb: "get", Resource: "BUILDCONFIGS", }, expectedAllowed: true, expectedReason: "allowed by rule in adze", } test1.clusterPolicies = newDefaultClusterPolicies() test1.policies = newAdzePolicies() test1.clusterBindings = newDefaultClusterPolicyBindings() test1.bindings = newAdzeBindings() test1.test(t) test2 := &authorizeTest{ context: kapi.WithUser(kapi.WithNamespace(kapi.NewContext(), "adze"), &user.DefaultInfo{Name: "Rachel"}), attributes: &DefaultAuthorizationAttributes{ Verb: "get", Resource: "buildconfigs", }, expectedAllowed: true, expectedReason: "allowed by rule in adze", } test2.clusterPolicies = newDefaultClusterPolicies() test2.policies = newAdzePolicies() test2.clusterBindings = newDefaultClusterPolicyBindings() test2.bindings = newAdzeBindings() test2.test(t) }
func TestVerbRestrictionsWork(t *testing.T) { test1 := &authorizeTest{ context: kapi.WithUser(kapi.WithNamespace(kapi.NewContext(), "adze"), &user.DefaultInfo{Name: "Valerie"}), attributes: &DefaultAuthorizationAttributes{ Verb: "get", Resource: "buildConfigs", }, expectedAllowed: true, expectedReason: "allowed by rule in adze", } test1.clusterPolicies = newDefaultClusterPolicies() test1.policies = newAdzePolicies() test1.clusterBindings = newDefaultClusterPolicyBindings() test1.bindings = newAdzeBindings() test1.test(t) test2 := &authorizeTest{ context: kapi.WithUser(kapi.WithNamespace(kapi.NewContext(), "adze"), &user.DefaultInfo{Name: "Valerie"}), attributes: &DefaultAuthorizationAttributes{ Verb: "create", Resource: "buildConfigs", }, expectedAllowed: false, expectedReason: `User "Valerie" cannot create buildConfigs in project "adze"`, } test2.clusterPolicies = newDefaultClusterPolicies() test2.policies = newAdzePolicies() test2.clusterBindings = newDefaultClusterPolicyBindings() test2.bindings = newAdzeBindings() test2.test(t) }
// GetRoleReferenceRules attempts resolve the RoleBinding or ClusterRoleBinding. func (r *DefaultRuleResolver) GetRoleReferenceRules(ctx api.Context, roleRef api.ObjectReference, bindingNamespace string) ([]rbac.PolicyRule, error) { switch roleRef.Kind { case "Role": // Roles can only be referenced by RoleBindings within the same namespace. if len(bindingNamespace) == 0 { return nil, fmt.Errorf("cluster role binding references role %q in namespace %q", roleRef.Name, roleRef.Namespace) } else { if bindingNamespace != roleRef.Namespace { return nil, fmt.Errorf("role binding in namespace %q references role %q in namespace %q", bindingNamespace, roleRef.Name, roleRef.Namespace) } } role, err := r.roleGetter.GetRole(api.WithNamespace(ctx, roleRef.Namespace), roleRef.Name) if err != nil { return nil, err } return role.Rules, nil case "ClusterRole": clusterRole, err := r.clusterRoleGetter.GetClusterRole(api.WithNamespace(ctx, ""), roleRef.Name) if err != nil { return nil, err } return clusterRole.Rules, nil default: return nil, fmt.Errorf("unsupported role reference kind: %q", roleRef.Kind) } }
func TestEtcdListRoutesInDifferentNamespaces(t *testing.T) { fakeClient := tools.NewFakeEtcdClient(t) namespaceAlfa := kapi.WithNamespace(kapi.NewContext(), "alfa") namespaceBravo := kapi.WithNamespace(kapi.NewContext(), "bravo") fakeClient.Data["/routes/alfa"] = tools.EtcdResponseWithError{ R: &etcd.Response{ Node: &etcd.Node{ Nodes: []*etcd.Node{ { Value: runtime.EncodeOrDie(latest.Codec, &api.Route{ObjectMeta: kapi.ObjectMeta{Name: "foo1"}}), }, }, }, }, E: nil, } fakeClient.Data["/routes/bravo"] = tools.EtcdResponseWithError{ R: &etcd.Response{ Node: &etcd.Node{ Nodes: []*etcd.Node{ { Value: runtime.EncodeOrDie(latest.Codec, &api.Route{ObjectMeta: kapi.ObjectMeta{Name: "foo2"}}), }, { Value: runtime.EncodeOrDie(latest.Codec, &api.Route{ObjectMeta: kapi.ObjectMeta{Name: "bar2"}}), }, }, }, }, E: nil, } registry := NewTestEtcd(fakeClient) routesAlfa, err := registry.ListRoutes(namespaceAlfa, labels.Everything()) if err != nil { t.Errorf("unexpected error: %v", err) } if len(routesAlfa.Items) != 1 || routesAlfa.Items[0].Name != "foo1" { t.Errorf("Unexpected builds list: %#v", routesAlfa) } routesBravo, err := registry.ListRoutes(namespaceBravo, labels.Everything()) if err != nil { t.Errorf("unexpected error: %v", err) } if len(routesBravo.Items) != 2 || routesBravo.Items[0].Name != "foo2" || routesBravo.Items[1].Name != "bar2" { t.Errorf("Unexpected builds list: %#v", routesBravo) } }
func (t *Tester) TestDeleteGracefulImmediate(existing runtime.Object, expectedGrace int64, wasGracefulFn func() bool) { objectMeta, err := api.ObjectMetaFor(existing) if err != nil { t.Fatalf("object does not have ObjectMeta: %v\n%#v", err, existing) } ctx := api.WithNamespace(t.TestContext(), objectMeta.Namespace) _, err = t.storage.(rest.GracefulDeleter).Delete(ctx, objectMeta.Name, api.NewDeleteOptions(expectedGrace)) if err != nil { t.Errorf("unexpected error: %v", err) } if !wasGracefulFn() { t.Errorf("did not gracefully delete resource") } // second delete is immediate, resource is deleted out, err := t.storage.(rest.GracefulDeleter).Delete(ctx, objectMeta.Name, api.NewDeleteOptions(0)) if err != nil { t.Errorf("unexpected error: %v", err) } _, err = t.storage.(rest.Getter).Get(ctx, objectMeta.Name) if !errors.IsNotFound(err) { t.Errorf("unexpected error, object should be deleted immediately: %v", err) } objectMeta, err = api.ObjectMetaFor(out) if err != nil { t.Errorf("unexpected error: %v", err) return } if objectMeta.DeletionTimestamp == nil || objectMeta.DeletionGracePeriodSeconds == nil || *objectMeta.DeletionGracePeriodSeconds != 0 { t.Errorf("unexpected deleted meta: %#v", objectMeta) } }
func TestUpdate(t *testing.T) { storage := makeLocalTestStorage() ctx := kapi.WithNamespace(kapi.NewContext(), "unittest") realizedRoleObj, _ := storage.Create(ctx, &authorizationapi.Role{ ObjectMeta: kapi.ObjectMeta{Name: "my-role"}, }) realizedRole := realizedRoleObj.(*authorizationapi.Role) role := &authorizationapi.Role{ ObjectMeta: kapi.ObjectMeta{Name: "my-role", ResourceVersion: realizedRole.ResourceVersion}, } obj, created, err := storage.Update(ctx, role) if err != nil || created { t.Errorf("Unexpected error %v", err) } switch obj.(type) { case *unversioned.Status: t.Errorf("Unexpected operation error: %v", obj) case *authorizationapi.Role: if !reflect.DeepEqual(role, obj) { t.Errorf("Updated role does not match input role."+ " Expected: %v, Got: %v", role, obj) } default: t.Errorf("Unexpected result type: %v", obj) } }
// namespacingFilter adds a filter that adds the namespace of the request to the context. Not all requests will have namespaces, // but any that do will have the appropriate value added. func namespacingFilter(handler http.Handler, contextMapper kapi.RequestContextMapper) http.Handler { infoResolver := &apiserver.RequestInfoResolver{APIPrefixes: sets.NewString("api", "osapi", "oapi", "apis"), GrouplessAPIPrefixes: sets.NewString("api", "osapi", "oapi")} return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { ctx, ok := contextMapper.Get(req) if !ok { http.Error(w, "Unable to find request context", http.StatusInternalServerError) return } if _, exists := kapi.NamespaceFrom(ctx); !exists { if requestInfo, err := infoResolver.GetRequestInfo(req); err == nil { // only set the namespace if the apiRequestInfo was resolved // keep in mind that GetAPIRequestInfo will fail on non-api requests, so don't fail the entire http request on that // kind of failure. // TODO reconsider special casing this. Having the special case hereallow us to fully share the kube // APIRequestInfoResolver without any modification or customization. namespace := requestInfo.Namespace if (requestInfo.Resource == "projects") && (len(requestInfo.Name) > 0) { namespace = requestInfo.Name } ctx = kapi.WithNamespace(ctx, namespace) contextMapper.Update(req, ctx) } } handler.ServeHTTP(w, req) }) }
func TestUpdateCannotChangeRoleRefError(t *testing.T) { ctx := kapi.WithUser(kapi.WithNamespace(kapi.NewContext(), "unittest"), &user.DefaultInfo{Name: "system:admin"}) storage := makeTestStorage() obj, err := storage.Create(ctx, &authorizationapi.RoleBinding{ ObjectMeta: kapi.ObjectMeta{Name: "my-different"}, RoleRef: kapi.ObjectReference{Name: "admin"}, }) if err != nil { t.Errorf("unexpected error: %v", err) return } original := obj.(*authorizationapi.RoleBinding) roleBinding := &authorizationapi.RoleBinding{ ObjectMeta: kapi.ObjectMeta{Name: "my-different", ResourceVersion: original.ResourceVersion}, RoleRef: kapi.ObjectReference{Name: "cluster-admin"}, } _, _, err = storage.Update(ctx, roleBinding) if err == nil { t.Errorf("Missing expected error") return } expectedErr := "cannot change roleRef" if !strings.Contains(err.Error(), expectedErr) { t.Errorf("Expected %v, got %v", expectedErr, err.Error()) } }
func TestStatusUpdate(t *testing.T) { storage, server := newStorage(t) defer server.Terminate(t) ctx := api.WithNamespace(api.NewContext(), namespace) key := etcdtest.AddPrefix("/deployments/" + namespace + "/" + name) if err := storage.Deployment.Storage.Set(ctx, key, &validDeployment, nil, 0); err != nil { t.Fatalf("unexpected error: %v", err) } update := extensions.Deployment{ ObjectMeta: validDeployment.ObjectMeta, Spec: extensions.DeploymentSpec{ Replicas: 100, }, Status: extensions.DeploymentStatus{ Replicas: 100, }, } if _, _, err := storage.Status.Update(ctx, &update); err != nil { t.Fatalf("unexpected error: %v", err) } obj, err := storage.Deployment.Get(ctx, name) if err != nil { t.Fatalf("unexpected error: %v", err) } deployment := obj.(*extensions.Deployment) if deployment.Spec.Replicas != 7 { t.Errorf("we expected .spec.replicas to not be updated but it was updated to %v", deployment.Spec.Replicas) } if deployment.Status.Replicas != 100 { t.Errorf("we expected .status.replicas to be updated to 100 but it was %v", deployment.Status.Replicas) } }
func TestConflictingUpdate(t *testing.T) { storage := makeLocalTestStorage() ctx := kapi.WithUser(kapi.WithNamespace(kapi.NewContext(), "unittest"), &user.DefaultInfo{Name: "system:admin"}) realizedRoleObj, err := storage.Create(ctx, &authorizationapi.Role{ ObjectMeta: kapi.ObjectMeta{Name: "my-role"}, Rules: []authorizationapi.PolicyRule{ {Verbs: sets.NewString(authorizationapi.VerbAll)}, }, }) if err != nil { t.Fatalf("unexpected error: %v", err) } realizedRole := realizedRoleObj.(*authorizationapi.Role) role := &authorizationapi.Role{ ObjectMeta: realizedRole.ObjectMeta, Rules: []authorizationapi.PolicyRule{ {Verbs: sets.NewString("list", "update")}, }, } role.ResourceVersion += "1" _, _, err = storage.Update(ctx, role.Name, rest.DefaultUpdatedObjectInfo(role, kapi.Scheme)) if err == nil || !kapierrors.IsConflict(err) { t.Errorf("Expected conflict error, got: %#v", err) } }
func TestStoreDeleteCollection(t *testing.T) { podA := &api.Pod{ObjectMeta: api.ObjectMeta{Name: "foo"}} podB := &api.Pod{ObjectMeta: api.ObjectMeta{Name: "bar"}} testContext := api.WithNamespace(api.NewContext(), "test") server, registry := NewTestGenericStoreRegistry(t) defer server.Terminate(t) if _, err := registry.Create(testContext, podA); err != nil { t.Errorf("Unexpected error: %v", err) } if _, err := registry.Create(testContext, podB); err != nil { t.Errorf("Unexpected error: %v", err) } // Delete all pods. deleted, err := registry.DeleteCollection(testContext, nil, &api.ListOptions{}) if err != nil { t.Fatalf("Unexpected error: %v", err) } deletedPods := deleted.(*api.PodList) if len(deletedPods.Items) != 2 { t.Errorf("Unexpected number of pods deleted: %d, expected: 2", len(deletedPods.Items)) } if _, err := registry.Get(testContext, podA.Name); !errors.IsNotFound(err) { t.Errorf("Unexpected error: %v", err) } if _, err := registry.Get(testContext, podB.Name); !errors.IsNotFound(err) { t.Errorf("Unexpected error: %v", err) } }
// ConfirmNoEscalation determines if the roles for a given user in a given namespace encompass the provided role. func ConfirmNoEscalation(ctx api.Context, ruleResolver AuthorizationRuleResolver, rules []rbac.PolicyRule) error { ruleResolutionErrors := []error{} ownerLocalRules, err := ruleResolver.GetEffectivePolicyRules(ctx) if err != nil { // As per AuthorizationRuleResolver contract, this may return a non fatal error with an incomplete list of policies. Log the error and continue. user, _ := api.UserFrom(ctx) glog.V(1).Infof("non-fatal error getting local rules for %v: %v", user, err) ruleResolutionErrors = append(ruleResolutionErrors, err) } masterContext := api.WithNamespace(ctx, "") ownerGlobalRules, err := ruleResolver.GetEffectivePolicyRules(masterContext) if err != nil { // Same case as above. Log error, don't fail. user, _ := api.UserFrom(ctx) glog.V(1).Infof("non-fatal error getting global rules for %v: %v", user, err) ruleResolutionErrors = append(ruleResolutionErrors, err) } ownerRules := make([]rbac.PolicyRule, 0, len(ownerGlobalRules)+len(ownerLocalRules)) ownerRules = append(ownerRules, ownerLocalRules...) ownerRules = append(ownerRules, ownerGlobalRules...) ownerRightsCover, missingRights := Covers(ownerRules, rules) if !ownerRightsCover { user, _ := api.UserFrom(ctx) return errors.NewUnauthorized(fmt.Sprintf("attempt to grant extra privileges: %v user=%v ownerrules=%v ruleResolutionErrors=%v", missingRights, user, ownerRules, ruleResolutionErrors)) } return nil }
// Bind just does a POST binding RPC. func (b *binder) Bind(binding *api.Binding) error { glog.V(2).Infof("Attempting to bind %v to %v", binding.Name, binding.Target.Name) ctx := api.WithNamespace(api.NewContext(), binding.Namespace) return b.Post().Namespace(api.NamespaceValue(ctx)).Resource("bindings").Body(binding).Do().Error() // TODO: use Pods interface for binding once clusters are upgraded // return b.Pods(binding.Namespace).Bind(binding) }
func (t *Tester) TestDeleteGracefulWithValue(existing runtime.Object, expectedGrace int64, wasGracefulFn func() bool) { objectMeta, err := api.ObjectMetaFor(existing) if err != nil { t.Fatalf("object does not have ObjectMeta: %v\n%#v", err, existing) } ctx := api.WithNamespace(t.TestContext(), objectMeta.Namespace) _, err = t.storage.(rest.GracefulDeleter).Delete(ctx, objectMeta.Name, api.NewDeleteOptions(expectedGrace+2)) if err != nil { t.Errorf("unexpected error: %v", err) } if !wasGracefulFn() { t.Errorf("did not gracefully delete resource") } object, err := t.storage.(rest.Getter).Get(ctx, objectMeta.Name) if err != nil { t.Errorf("unexpected error, object should exist: %v", err) } objectMeta, err = api.ObjectMetaFor(object) if err != nil { t.Fatalf("object does not have ObjectMeta: %v\n%#v", err, object) } if objectMeta.DeletionTimestamp == nil { t.Errorf("did not set deletion timestamp") } if objectMeta.DeletionGracePeriodSeconds == nil { t.Fatalf("did not set deletion grace period seconds") } if *objectMeta.DeletionGracePeriodSeconds != expectedGrace+2 { t.Errorf("actual grace period does not match expected: %d", *objectMeta.DeletionGracePeriodSeconds) } }
func TestUpdateImageStreamConflictingNamespace(t *testing.T) { fakeEtcdClient, helper := newHelper(t) fakeEtcdClient.Data["/imagestreams/legal-name/bar"] = tools.EtcdResponseWithError{ R: &etcd.Response{ Node: &etcd.Node{ Value: runtime.EncodeOrDie(latest.Codec, &api.ImageStream{ ObjectMeta: kapi.ObjectMeta{Name: "bar", Namespace: "default"}, }), ModifiedIndex: 2, }, }, } storage, _ := NewREST(helper, noDefaultRegistry, &fakeSubjectAccessReviewRegistry{}) ctx := kapi.WithUser(kapi.WithNamespace(kapi.NewContext(), "legal-name"), &fakeUser{}) obj, created, err := storage.Update(ctx, &api.ImageStream{ ObjectMeta: kapi.ObjectMeta{Name: "bar", Namespace: "some-value", ResourceVersion: "2"}, }) if obj != nil || created { t.Error("Expected a nil obj, but we got a value") } checkExpectedNamespaceError(t, err) }
func TestUpdate(t *testing.T) { storage, fakeClient := newStorage(t) ctx := api.WithNamespace(api.NewContext(), "test") key := etcdtest.AddPrefix("/controllers/test/foo") if _, err := fakeClient.Set(key, runtime.EncodeOrDie(testapi.Default.Codec(), &validController), 0); err != nil { t.Fatalf("unexpected error: %v", err) } replicas := 12 update := extensions.Scale{ ObjectMeta: api.ObjectMeta{Name: "foo", Namespace: "test"}, Spec: extensions.ScaleSpec{ Replicas: replicas, }, } if _, _, err := storage.Update(ctx, &update); err != nil { t.Fatalf("unexpected error: %v", err) } response, err := fakeClient.Get(key, false, false) if err != nil { t.Fatalf("unexpected error: %v", err) } var controller api.ReplicationController testapi.Extensions.Codec().DecodeInto([]byte(response.Node.Value), &controller) if controller.Spec.Replicas != replicas { t.Errorf("wrong replicas count expected: %d got: %d", replicas, controller.Spec.Replicas) } }
func TestGet(t *testing.T) { expect := validNewPod() expect.Status.Phase = api.PodRunning expect.Spec.NodeName = "machine" fakeEtcdClient, etcdStorage := newEtcdStorage(t) key := etcdtest.AddPrefix("/pods/test/foo") fakeEtcdClient.Data[key] = tools.EtcdResponseWithError{ R: &etcd.Response{ Node: &etcd.Node{ Value: runtime.EncodeOrDie(latest.Codec, expect), }, }, } storage := NewStorage(etcdStorage, nil).Pod obj, err := storage.Get(api.WithNamespace(api.NewContext(), "test"), "foo") pod := obj.(*api.Pod) if err != nil { t.Fatalf("unexpected error: %v", err) } if e, a := expect, pod; !api.Semantic.DeepEqual(e, a) { t.Errorf("Unexpected pod: %s", util.ObjectDiff(e, a)) } }
// OriginAuthorizerAttributes adapts Kubernetes authorization attributes to Origin authorization attributes // Note that some info (like resourceName, apiVersion, apiGroup) is not available from the Kubernetes attributes func OriginAuthorizerAttributes(kattrs kauthorizer.Attributes) (kapi.Context, oauthorizer.AuthorizationAttributes) { // Build a context to hold the namespace and user info ctx := kapi.NewContext() ctx = kapi.WithNamespace(ctx, kattrs.GetNamespace()) ctx = kapi.WithUser(ctx, &user.DefaultInfo{ Name: kattrs.GetUserName(), Groups: kattrs.GetGroups(), }) // If the passed attributes already satisfy our interface, use it directly if oattrs, ok := kattrs.(oauthorizer.AuthorizationAttributes); ok { return ctx, oattrs } // Otherwise build what we can oattrs := &oauthorizer.DefaultAuthorizationAttributes{ Verb: kattrs.GetVerb(), Resource: kattrs.GetResource(), // TODO: add to kube authorizer attributes // APIVersion string // APIGroup string // ResourceName string // RequestAttributes interface{} // NonResourceURL bool // URL string } return ctx, oattrs }
func (r *RBACAuthorizer) Authorize(attr authorizer.Attributes) error { if r.superUser != "" && attr.GetUserName() == r.superUser { return nil } userInfo := &user.DefaultInfo{ Name: attr.GetUserName(), Groups: attr.GetGroups(), } ctx := api.WithNamespace(api.WithUser(api.NewContext(), userInfo), attr.GetNamespace()) // Frame the authorization request as a privilege escalation check. var requestedRule rbac.PolicyRule if attr.IsResourceRequest() { requestedRule = rbac.PolicyRule{ Verbs: []string{attr.GetVerb()}, APIGroups: []string{attr.GetAPIGroup()}, // TODO(ericchiang): add api version here too? Resources: []string{attr.GetResource()}, ResourceNames: []string{attr.GetName()}, } } else { requestedRule = rbac.PolicyRule{ NonResourceURLs: []string{attr.GetPath()}, } } return validation.ConfirmNoEscalation(ctx, r.authorizationRuleResolver, []rbac.PolicyRule{requestedRule}) }
// TestGracefulStoreCanDeleteIfExistingGracePeriodZero tests recovery from // race condition where the graceful delete is unable to complete // in prior operation, but the pod remains with deletion timestamp // and grace period set to 0. func TestGracefulStoreCanDeleteIfExistingGracePeriodZero(t *testing.T) { deletionTimestamp := metav1.NewTime(time.Now()) deletionGracePeriodSeconds := int64(0) initialGeneration := int64(1) pod := &api.Pod{ ObjectMeta: api.ObjectMeta{ Name: "foo", Generation: initialGeneration, DeletionGracePeriodSeconds: &deletionGracePeriodSeconds, DeletionTimestamp: &deletionTimestamp, }, Spec: api.PodSpec{NodeName: "machine"}, } testContext := api.WithNamespace(api.NewContext(), "test") destroyFunc, registry := NewTestGenericStoreRegistry(t) registry.EnableGarbageCollection = false defaultDeleteStrategy := testRESTStrategy{api.Scheme, api.SimpleNameGenerator, true, false, true} registry.DeleteStrategy = testGracefulStrategy{defaultDeleteStrategy} defer destroyFunc() graceful, gracefulPending, err := rest.BeforeDelete(registry.DeleteStrategy, testContext, pod, api.NewDeleteOptions(0)) if err != nil { t.Fatalf("Unexpected error: %v", err) } if graceful { t.Fatalf("graceful should be false if object has DeletionTimestamp and DeletionGracePeriodSeconds is 0") } if gracefulPending { t.Fatalf("gracefulPending should be false if object has DeletionTimestamp and DeletionGracePeriodSeconds is 0") } }
// TestGetClusterPolicy tests that a ReadOnlyPolicyClient GetPolicy() call correctly retrieves a cluster policy // when the namespace given is equal to the empty string func TestGetClusterPolicy(t *testing.T) { testClient, policyStopChannel, bindingStopChannel, testChannel := beforeTestingSetup_readonlycache() defer close(policyStopChannel) defer close(bindingStopChannel) var clusterPolicy *authorizationapi.Policy var err error namespace := "" context := kapi.WithNamespace(kapi.NewContext(), namespace) name := "uniqueClusterPolicyName" util.Until(func() { clusterPolicy, err = testClient.GetPolicy(context, name) if (err == nil) && (clusterPolicy != nil) && (clusterPolicy.Name == name) && (clusterPolicy.Namespace == namespace) { close(testChannel) } }, 1*time.Millisecond, testChannel) switch { case err != nil: t.Errorf("Error getting cluster policy using GetPolicy(): %v", err) case clusterPolicy == nil: t.Error("Policy is nil") case clusterPolicy.Name != name: t.Errorf("Expected policy.Name to be '%s', but got '%s'", name, clusterPolicy.Name) case clusterPolicy.Namespace != "": t.Errorf("Expected policy.Namespace to be '%s', but got '%s'", namespace, clusterPolicy.Namespace) } }
func TestStatusUpdate(t *testing.T) { storage, server := newStorage(t) defer server.Terminate(t) ctx := api.WithNamespace(api.NewContext(), api.NamespaceDefault) key := etcdtest.AddPrefix("/replicasets/" + api.NamespaceDefault + "/foo") if err := storage.ReplicaSet.Storage.Create(ctx, key, &validReplicaSet, nil, 0); err != nil { t.Fatalf("unexpected error: %v", err) } update := extensions.ReplicaSet{ ObjectMeta: validReplicaSet.ObjectMeta, Spec: extensions.ReplicaSetSpec{ Replicas: defaultReplicas, }, Status: extensions.ReplicaSetStatus{ Replicas: defaultReplicas, }, } if _, _, err := storage.Status.Update(ctx, &update); err != nil { t.Fatalf("unexpected error: %v", err) } obj, err := storage.ReplicaSet.Get(ctx, "foo") if err != nil { t.Fatalf("unexpected error: %v", err) } rs := obj.(*extensions.ReplicaSet) if rs.Spec.Replicas != 7 { t.Errorf("we expected .spec.replicas to not be updated but it was updated to %v", rs.Spec.Replicas) } if rs.Status.Replicas != defaultReplicas { t.Errorf("we expected .status.replicas to be updated to %d but it was %v", defaultReplicas, rs.Status.Replicas) } }
func TestStoreBasicExport(t *testing.T) { podA := api.Pod{ ObjectMeta: api.ObjectMeta{ Namespace: "test", Name: "foo", Labels: map[string]string{}, }, Spec: api.PodSpec{NodeName: "machine"}, Status: api.PodStatus{HostIP: "1.2.3.4"}, } server, registry := NewTestGenericStoreRegistry(t) defer server.Terminate(t) testContext := api.WithNamespace(api.NewContext(), "test") registry.UpdateStrategy.(*testRESTStrategy).allowCreateOnUpdate = true if !updateAndVerify(t, testContext, registry, &podA) { t.Errorf("Unexpected error updating podA") } obj, err := registry.Export(testContext, podA.Name, unversioned.ExportOptions{}) if err != nil { t.Errorf("unexpected error: %v", err) } exportedPod := obj.(*api.Pod) if exportedPod.Labels["prepare_create"] != "true" { t.Errorf("expected: prepare_create->true, found: %s", exportedPod.Labels["prepare_create"]) } delete(exportedPod.Labels, "prepare_create") exportObjectMeta(&podA.ObjectMeta, false) podA.Spec = exportedPod.Spec if !reflect.DeepEqual(&podA, exportedPod) { t.Errorf("expected:\n%v\nsaw:\n%v\n", &podA, exportedPod) } }
// ensureComponentAuthorizationRules initializes the cluster policies func (c *MasterConfig) ensureComponentAuthorizationRules() { clusterPolicyRegistry := clusterpolicyregistry.NewRegistry(clusterpolicystorage.NewStorage(c.EtcdHelper)) ctx := kapi.WithNamespace(kapi.NewContext(), "") if _, err := clusterPolicyRegistry.GetClusterPolicy(ctx, authorizationapi.PolicyName); kapierror.IsNotFound(err) { glog.Infof("No cluster policy found. Creating bootstrap policy based on: %v", c.Options.PolicyConfig.BootstrapPolicyFile) if err := admin.OverwriteBootstrapPolicy(c.EtcdHelper, c.Options.PolicyConfig.BootstrapPolicyFile, admin.CreateBootstrapPolicyFileFullCommand, true, ioutil.Discard); err != nil { glog.Errorf("Error creating bootstrap policy: %v", err) } } else { glog.V(2).Infof("Ignoring bootstrap policy file because cluster policy found") } // Wait until the policy cache has caught up before continuing review := &authorizationapi.SubjectAccessReview{Action: authorizationapi.AuthorizationAttributes{Verb: "get", Resource: "clusterpolicies"}} err := wait.PollImmediate(100*time.Millisecond, 30*time.Second, func() (done bool, err error) { result, err := c.PolicyClient().SubjectAccessReviews().Create(review) if err == nil && result.Allowed { return true, nil } if kapierror.IsForbidden(err) || (err == nil && !result.Allowed) { glog.V(2).Infof("waiting for policy cache to initialize") return false, nil } return false, err }) if err != nil { glog.Errorf("error waiting for policy cache to initialize: %v", err) } }
func TestUpdateError(t *testing.T) { ctx := kapi.WithUser(kapi.WithNamespace(kapi.NewContext(), "unittest"), &user.DefaultInfo{Name: "system:admin"}) storage := makeTestStorage() obj, err := storage.Create(ctx, &authorizationapi.RoleBinding{ ObjectMeta: kapi.ObjectMeta{Name: "my-different"}, RoleRef: kapi.ObjectReference{Name: "admin"}, }) if err != nil { t.Errorf("unexpected error: %v", err) return } original := obj.(*authorizationapi.RoleBinding) roleBinding := &authorizationapi.RoleBinding{ ObjectMeta: kapi.ObjectMeta{Name: "my-roleBinding", ResourceVersion: original.ResourceVersion}, RoleRef: kapi.ObjectReference{Name: "admin"}, } _, _, err = storage.Update(ctx, roleBinding) if err == nil { t.Errorf("Missing expected error") return } if !kapierrors.IsNotFound(err) { t.Errorf("Unexpected error %v", err) } }
func TestConflictingUpdate(t *testing.T) { ctx := kapi.WithUser(kapi.WithNamespace(kapi.NewContext(), "unittest"), &user.DefaultInfo{Name: "system:admin"}) storage := makeTestStorage() obj, err := storage.Create(ctx, &authorizationapi.RoleBinding{ ObjectMeta: kapi.ObjectMeta{Name: "my-roleBinding"}, RoleRef: kapi.ObjectReference{Name: "admin"}, }) if err != nil { t.Errorf("unexpected error: %v", err) return } original := obj.(*authorizationapi.RoleBinding) roleBinding := &authorizationapi.RoleBinding{ ObjectMeta: original.ObjectMeta, RoleRef: kapi.ObjectReference{Name: "admin"}, Subjects: []kapi.ObjectReference{{Name: "bob", Kind: "User"}}, } roleBinding.ResourceVersion = roleBinding.ResourceVersion + "1" _, _, err = storage.Update(ctx, roleBinding.Name, rest.DefaultUpdatedObjectInfo(roleBinding, kapi.Scheme)) if err == nil || !kapierrors.IsConflict(err) { t.Errorf("Expected conflict error, got: %#v", err) } }
func TestEtcdDelete(t *testing.T) { podA := &api.Pod{ ObjectMeta: api.ObjectMeta{Name: "foo"}, Spec: api.PodSpec{NodeName: "machine"}, } testContext := api.WithNamespace(api.NewContext(), "test") server, registry := NewTestGenericEtcdRegistry(t) defer server.Terminate(t) // test failure condition _, err := registry.Delete(testContext, podA.Name, nil) if !errors.IsNotFound(err) { t.Errorf("Unexpected error: %v", err) } // create pod _, err = registry.Create(testContext, podA) if err != nil { t.Errorf("Unexpected error: %v", err) } // delete object _, err = registry.Delete(testContext, podA.Name, nil) if err != nil { t.Errorf("Unexpected error: %v", err) } // try to get a item which should be deleted _, err = registry.Get(testContext, podA.Name) if !errors.IsNotFound(err) { t.Errorf("Unexpected error: %v", err) } }
func TestUpdate(t *testing.T) { storage, server, si := newStorage(t) defer server.Terminate(t) ctx := api.WithNamespace(api.NewContext(), "test") key := etcdtest.AddPrefix("/controllers/test/foo") if err := si.Set(ctx, key, &validController, nil, 0); err != nil { t.Fatalf("unexpected error: %v", err) } replicas := 12 update := extensions.Scale{ ObjectMeta: api.ObjectMeta{Name: "foo", Namespace: "test"}, Spec: extensions.ScaleSpec{ Replicas: replicas, }, } if _, _, err := storage.Update(ctx, &update); err != nil { t.Fatalf("unexpected error: %v", err) } obj, err := storage.Get(ctx, "foo") if err != nil { t.Fatalf("unexpected error: %v", err) } updated := obj.(*extensions.Scale) if updated.Spec.Replicas != replicas { t.Errorf("wrong replicas count expected: %d got: %d", replicas, updated.Spec.Replicas) } }
// Ensure that when a deploymentRollback is created for a deployment that has already been deleted // by the API server, API server returns not-found error. func TestEtcdCreateDeploymentRollbackNoDeployment(t *testing.T) { storage, server := newStorage(t) defer server.Terminate(t) rollbackStorage := storage.Rollback ctx := api.WithNamespace(api.NewContext(), namespace) key, _ := storage.Deployment.KeyFunc(ctx, name) key = etcdtest.AddPrefix(key) _, err := rollbackStorage.Create(ctx, &extensions.DeploymentRollback{ Name: name, UpdatedAnnotations: map[string]string{}, RollbackTo: extensions.RollbackConfig{Revision: 1}, }) if err == nil { t.Fatalf("Expected not-found-error but got nothing") } if !errors.IsNotFound(etcderrors.InterpretGetError(err, extensions.Resource("deployments"), name)) { t.Fatalf("Unexpected error returned: %#v", err) } _, err = storage.Deployment.Get(ctx, name) if err == nil { t.Fatalf("Expected not-found-error but got nothing") } if !errors.IsNotFound(etcderrors.InterpretGetError(err, extensions.Resource("deployments"), name)) { t.Fatalf("Unexpected error: %v", err) } }
func NewReadOnlyClusterPolicyBindingCache(registry clusterbindingregistry.WatchingRegistry) *readOnlyClusterPolicyBindingCache { ctx := kapi.WithNamespace(kapi.NewContext(), kapi.NamespaceAll) indexer := cache.NewIndexer(cache.MetaNamespaceKeyFunc, cache.Indexers{"namespace": cache.MetaNamespaceIndexFunc}) reflector := cache.NewReflector( &cache.ListWatch{ ListFunc: func() (runtime.Object, error) { return registry.ListClusterPolicyBindings(ctx, labels.Everything(), fields.Everything()) }, WatchFunc: func(resourceVersion string) (watch.Interface, error) { return registry.WatchClusterPolicyBindings(ctx, labels.Everything(), fields.Everything(), resourceVersion) }, }, &authorizationapi.ClusterPolicyBinding{}, indexer, 2*time.Minute, ) return &readOnlyClusterPolicyBindingCache{ registry: registry, indexer: indexer, reflector: reflector, keyFunc: cache.MetaNamespaceKeyFunc, } }