// 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.APIRequestInfoResolver{util.NewStringSet("api", "osapi", "oapi"), latest.RESTMapper} 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.GetAPIRequestInfo(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) }) }
// TestValidNamespace validates that namespace rules are enforced on a resource prior to create or update func TestValidNamespace(t *testing.T) { ctx := api.NewDefaultContext() namespace, _ := api.NamespaceFrom(ctx) resource := api.ReplicationController{} if !api.ValidNamespace(ctx, &resource.ObjectMeta) { t.Errorf("expected success") } if namespace != resource.Namespace { t.Errorf("expected resource to have the default namespace assigned during validation") } resource = api.ReplicationController{ObjectMeta: api.ObjectMeta{Namespace: "other"}} if api.ValidNamespace(ctx, &resource.ObjectMeta) { t.Errorf("Expected error that resource and context errors do not match because resource has different namespace") } ctx = api.NewContext() if api.ValidNamespace(ctx, &resource.ObjectMeta) { t.Errorf("Expected error that resource and context errors do not match since context has no namespace") } ctx = api.NewContext() ns := api.NamespaceValue(ctx) if ns != "" { t.Errorf("Expected the empty string") } }
func (g *podGetter) Get(ctx kapi.Context, name string) (runtime.Object, error) { ns, ok := kapi.NamespaceFrom(ctx) if !ok { return nil, errors.NewBadRequest("namespace parameter required.") } return g.podsNamespacer.Pods(ns).Get(name) }
// TestNamespaceContext validates that a namespace can be get/set on a context object func TestNamespaceContext(t *testing.T) { ctx := api.NewDefaultContext() result, ok := api.NamespaceFrom(ctx) if !ok { t.Errorf("Error getting namespace") } if api.NamespaceDefault != result { t.Errorf("Expected: %v, Actual: %v", api.NamespaceDefault, result) } ctx = api.NewContext() result, ok = api.NamespaceFrom(ctx) if ok { t.Errorf("Should not be ok because there is no namespace on the context") } }
// MakeEtcdListKey constructs etcd paths to resource directories enforcing namespace rules func MakeEtcdListKey(ctx api.Context, prefix string) string { key := prefix ns, ok := api.NamespaceFrom(ctx) if ok && len(ns) > 0 { key = key + "/" + ns } return key }
// NamespaceKeyRootFunc is the default function for constructing etcd paths to resource directories enforcing namespace rules. func NamespaceKeyRootFunc(ctx api.Context, prefix string) string { key := prefix ns, ok := api.NamespaceFrom(ctx) if ok && len(ns) > 0 { key = key + "/" + ns } return key }
// NoNamespaceKeyFunc is the default function for constructing etcd paths to a resource relative to prefix enforcing namespace rules. // If a namespace is on context, it errors. func NoNamespaceKeyFunc(ctx api.Context, prefix string, name string) (string, error) { ns, ok := api.NamespaceFrom(ctx) if ok && len(ns) > 0 { return "", kubeerr.NewBadRequest("Namespace parameter is not allowed.") } if len(name) == 0 { return "", kubeerr.NewBadRequest("Name parameter required.") } return path.Join(prefix, name), nil }
// MakeEtcdItemKey constructs etcd paths to a resource relative to prefix enforcing namespace rules. If no namespace is on context, it errors. func MakeEtcdItemKey(ctx api.Context, prefix string, id string) (string, error) { key := MakeEtcdListKey(ctx, prefix) ns, ok := api.NamespaceFrom(ctx) if !ok || len(ns) == 0 { return "", fmt.Errorf("invalid request. Namespace parameter required.") } if len(id) == 0 { return "", fmt.Errorf("invalid request. Id parameter required.") } key = key + "/" + id return key, nil }
// NamespaceKeyFunc is the default function for constructing etcd paths to a resource relative to prefix enforcing namespace rules. // If no namespace is on context, it errors. func NamespaceKeyFunc(ctx api.Context, prefix string, name string) (string, error) { key := NamespaceKeyRootFunc(ctx, prefix) ns, ok := api.NamespaceFrom(ctx) if !ok || len(ns) == 0 { return "", kubeerr.NewBadRequest("Namespace parameter required.") } if len(name) == 0 { return "", kubeerr.NewBadRequest("Name parameter required.") } key = key + "/" + name return key, nil }
// ListPolicyBindings obtains list of policyBindings that match a selector. It conforms to rulevalidation.BindingLister func (c readOnlyAuthorizationCache) ListPolicyBindings(ctx kapi.Context, label labels.Selector, field fields.Selector) (*authorizationapi.PolicyBindingList, error) { namespace, _ := kapi.NamespaceFrom(ctx) if namespaceRefersToCluster(namespace) { clusterPolicyBindingList, err := c.ReadOnlyClusterPolicyBindings().List(label, field) if err != nil { return &authorizationapi.PolicyBindingList{}, err } return authorizationapi.ToPolicyBindingList(clusterPolicyBindingList), nil } else { policyBindingList, err := c.ReadOnlyPolicyBindings(namespace).List(label, field) if err != nil { return &authorizationapi.PolicyBindingList{}, err } return policyBindingList, nil } }
// GetPolicy retrieves a specific policy. It conforms to rulevalidation.PolicyGetter. func (c readOnlyAuthorizationCache) GetPolicy(ctx kapi.Context, name string) (*authorizationapi.Policy, error) { namespace, _ := kapi.NamespaceFrom(ctx) if namespaceRefersToCluster(namespace) { clusterPolicy, err := c.ReadOnlyClusterPolicies().Get(name) if err != nil { return &authorizationapi.Policy{}, err } return authorizationapi.ToPolicy(clusterPolicy), nil } else { policy, err := c.ReadOnlyPolicies(namespace).Get(name) if err != nil { return &authorizationapi.Policy{}, err } return policy, nil } }
func (a *openshiftAuthorizer) Authorize(ctx kapi.Context, passedAttributes AuthorizationAttributes) (bool, string, error) { attributes := coerceToDefaultAuthorizationAttributes(passedAttributes) // keep track of errors in case we are unable to authorize the action. // It is entirely possible to get an error and be able to continue determine authorization status in spite of it. // This is most common when a bound role is missing, but enough roles are still present and bound to authorize the request. errs := []error{} masterContext := kapi.WithNamespace(ctx, kapi.NamespaceNone) globalAllowed, globalReason, err := a.authorizeWithNamespaceRules(masterContext, attributes) if globalAllowed { return true, globalReason, nil } if err != nil { errs = append(errs, err) } namespace, _ := kapi.NamespaceFrom(ctx) if len(namespace) != 0 { namespaceAllowed, namespaceReason, err := a.authorizeWithNamespaceRules(ctx, attributes) if namespaceAllowed { return true, namespaceReason, nil } if err != nil { errs = append(errs, err) } } if len(errs) > 0 { return false, "", kerrors.NewAggregate(errs) } user, _ := kapi.UserFrom(ctx) denyReason, err := a.forbiddenMessageMaker.MakeMessage(MessageContext{user, namespace, attributes}) if err != nil { denyReason = err.Error() } return false, denyReason, nil }
func TestCreateInvalidDeployment(t *testing.T) { rest := REST{ generator: Client{ GRFn: func(from, to *deployapi.DeploymentConfig, spec *deployapi.DeploymentConfigRollbackSpec) (*deployapi.DeploymentConfig, error) { t.Fatal("unexpected call to generator") return nil, errors.New("something terrible happened") }, RCFn: func(ctx kapi.Context, name string) (*kapi.ReplicationController, error) { // invalidate the encoded config deployment, _ := deployutil.MakeDeployment(deploytest.OkDeploymentConfig(1), kapi.Codec) deployment.Annotations[deployapi.DeploymentEncodedConfigAnnotation] = "" return deployment, nil }, DCFn: func(ctx kapi.Context, name string) (*deployapi.DeploymentConfig, error) { namespace, _ := kapi.NamespaceFrom(ctx) t.Fatalf("unexpected call to GetDeploymentConfig(%s/%s)", namespace, name) return nil, kerrors.NewNotFound("deploymentConfig", name) }, }, codec: api.Codec, } obj, err := rest.Create(kapi.NewDefaultContext(), &deployapi.DeploymentConfigRollback{ Spec: deployapi.DeploymentConfigRollbackSpec{ From: kapi.ObjectReference{ Name: "deployment", Namespace: kapi.NamespaceDefault, }, }, }) if err == nil { t.Errorf("Expected an error") } if obj != nil { t.Error("Unexpected result obj") } }
func (r *ServiceRegistry) ListServices(ctx api.Context) (*api.ServiceList, error) { r.mu.Lock() defer r.mu.Unlock() ns, _ := api.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 (storage *SimpleRESTStorage) checkContext(ctx api.Context) { storage.actualNamespace, storage.namespacePresent = api.NamespaceFrom(ctx) }