// TestNamespaceContext validates that a namespace can be get/set on a context object func TestNamespaceContext(t *testing.T) { ctx := genericapirequest.NewDefaultContext() result, ok := genericapirequest.NamespaceFrom(ctx) if !ok { t.Fatalf("Error getting namespace") } if api.NamespaceDefault != result { t.Fatalf("Expected: %s, Actual: %s", api.NamespaceDefault, result) } ctx = genericapirequest.NewContext() result, ok = genericapirequest.NamespaceFrom(ctx) if ok { t.Fatalf("Should not be ok because there is no namespace on the context") } }
// ValidNamespace returns false if the namespace on the context differs from the resource. If the resource has no namespace, it is set to the value in the context. // TODO(sttts): move into pkg/genericapiserver/endpoints func ValidNamespace(ctx genericapirequest.Context, resource *metav1.ObjectMeta) bool { ns, ok := genericapirequest.NamespaceFrom(ctx) if len(resource.Namespace) == 0 { resource.Namespace = ns } return ns == resource.Namespace && ok }
// TestValidNamespace validates that namespace rules are enforced on a resource prior to create or update func TestValidNamespace(t *testing.T) { ctx := genericapirequest.NewDefaultContext() namespace, _ := genericapirequest.NamespaceFrom(ctx) resource := api.ReplicationController{} if !ValidNamespace(ctx, &resource.ObjectMeta) { t.Fatalf("expected success") } if namespace != resource.Namespace { t.Fatalf("expected resource to have the default namespace assigned during validation") } resource = api.ReplicationController{ObjectMeta: metav1.ObjectMeta{Namespace: "other"}} if ValidNamespace(ctx, &resource.ObjectMeta) { t.Fatalf("Expected error that resource and context errors do not match because resource has different namespace") } ctx = genericapirequest.NewContext() if ValidNamespace(ctx, &resource.ObjectMeta) { t.Fatalf("Expected error that resource and context errors do not match since context has no namespace") } ctx = genericapirequest.NewContext() ns := genericapirequest.NamespaceValue(ctx) if ns != "" { t.Fatalf("Expected the empty string") } }
// NamespaceKeyRootFunc is the default function for constructing storage paths to resource directories enforcing namespace rules. func NamespaceKeyRootFunc(ctx genericapirequest.Context, prefix string) string { key := prefix ns, ok := genericapirequest.NamespaceFrom(ctx) if ok && len(ns) > 0 { key = key + "/" + ns } return key }
// NamespaceKeyFunc is the default function for constructing storage paths to a resource relative to prefix enforcing namespace rules. // If no namespace is on context, it errors. func NamespaceKeyFunc(ctx genericapirequest.Context, prefix string, name string) (string, error) { key := NamespaceKeyRootFunc(ctx, prefix) ns, ok := genericapirequest.NamespaceFrom(ctx) if !ok || len(ns) == 0 { return "", kubeerr.NewBadRequest("Namespace parameter required.") } if len(name) == 0 { return "", kubeerr.NewBadRequest("Name parameter required.") } if msgs := path.IsValidPathSegmentName(name); len(msgs) != 0 { return "", kubeerr.NewBadRequest(fmt.Sprintf("Name parameter invalid: %q: %s", name, strings.Join(msgs, ";"))) } key = key + "/" + name return key, nil }
// ConfirmNoEscalation determines if the roles for a given user in a given namespace encompass the provided role. func ConfirmNoEscalation(ctx genericapirequest.Context, ruleResolver AuthorizationRuleResolver, rules []rbac.PolicyRule) error { ruleResolutionErrors := []error{} user, ok := genericapirequest.UserFrom(ctx) if !ok { return fmt.Errorf("no user on context") } namespace, _ := genericapirequest.NamespaceFrom(ctx) ownerRules, err := ruleResolver.RulesFor(user, namespace) 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. glog.V(1).Infof("non-fatal error getting local rules for %v: %v", user, err) ruleResolutionErrors = append(ruleResolutionErrors, err) } ownerRightsCover, missingRights := Covers(ownerRules, rules) if !ownerRightsCover { user, _ := genericapirequest.UserFrom(ctx) return apierrors.NewUnauthorized(fmt.Sprintf("attempt to grant extra privileges: %v user=%v ownerrules=%v ruleResolutionErrors=%v", missingRights, user, ownerRules, ruleResolutionErrors)) } return nil }
func (r *ServiceRegistry) ListServices(ctx genericapirequest.Context, options *api.ListOptions) (*api.ServiceList, error) { r.mu.Lock() defer r.mu.Unlock() ns, _ := genericapirequest.NamespaceFrom(ctx) // Copy metadata from internal list into result res := new(api.ServiceList) res.TypeMeta = r.List.TypeMeta res.ListMeta = r.List.ListMeta if ns != api.NamespaceAll { for _, service := range r.List.Items { if ns == service.Namespace { res.Items = append(res.Items, service) } } } else { res.Items = append([]api.Service{}, r.List.Items...) } return res, r.Err }
func newTestGenericStoreRegistry(t *testing.T, hasCacheEnabled bool) (factory.DestroyFunc, *Store) { podPrefix := "/pods" server, sc := etcdtesting.NewUnsecuredEtcd3TestClientServer(t) strategy := &testRESTStrategy{api.Scheme, names.SimpleNameGenerator, true, false, true} sc.Codec = testapi.Default.StorageCodec() s, dFunc, err := factory.Create(*sc) if err != nil { t.Fatalf("Error creating storage: %v", err) } destroyFunc := func() { dFunc() server.Terminate(t) } if hasCacheEnabled { config := storage.CacherConfig{ CacheCapacity: 10, Storage: s, Versioner: etcdstorage.APIObjectVersioner{}, Type: &api.Pod{}, ResourcePrefix: podPrefix, KeyFunc: func(obj runtime.Object) (string, error) { return storage.NoNamespaceKeyFunc(podPrefix, obj) }, GetAttrsFunc: getPodAttrs, NewListFunc: func() runtime.Object { return &api.PodList{} }, Codec: sc.Codec, } cacher := storage.NewCacherFromConfig(config) d := destroyFunc s = cacher destroyFunc = func() { cacher.Stop() d() } } return destroyFunc, &Store{ NewFunc: func() runtime.Object { return &api.Pod{} }, NewListFunc: func() runtime.Object { return &api.PodList{} }, QualifiedResource: api.Resource("pods"), CreateStrategy: strategy, UpdateStrategy: strategy, DeleteStrategy: strategy, KeyRootFunc: func(ctx genericapirequest.Context) string { return podPrefix }, KeyFunc: func(ctx genericapirequest.Context, id string) (string, error) { if _, ok := genericapirequest.NamespaceFrom(ctx); !ok { return "", fmt.Errorf("namespace is required") } return path.Join(podPrefix, id), nil }, ObjectNameFunc: func(obj runtime.Object) (string, error) { return obj.(*api.Pod).Name, nil }, PredicateFunc: func(label labels.Selector, field fields.Selector) storage.SelectionPredicate { return storage.SelectionPredicate{ Label: label, Field: field, GetAttrs: func(obj runtime.Object) (labels.Set, fields.Set, error) { pod, ok := obj.(*api.Pod) if !ok { return nil, nil, fmt.Errorf("not a pod") } return labels.Set(pod.ObjectMeta.Labels), generic.ObjectMetaFieldsSet(&pod.ObjectMeta, true), nil }, } }, Storage: s, } }