diff --git a/pkg/registry/rbac/reconciliation/BUILD b/pkg/registry/rbac/reconciliation/BUILD index 563d9fec991..33b5a585115 100644 --- a/pkg/registry/rbac/reconciliation/BUILD +++ b/pkg/registry/rbac/reconciliation/BUILD @@ -26,6 +26,7 @@ go_library( srcs = [ "clusterrole_interfaces.go", "clusterrolebinding_interfaces.go", + "namespace.go", "reconcile_role.go", "reconcile_rolebindings.go", "role_interfaces.go", @@ -42,6 +43,7 @@ go_library( "//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/types:go_default_library", + "//staging/src/k8s.io/apimachinery/pkg/util/errors:go_default_library", "//staging/src/k8s.io/client-go/kubernetes/typed/core/v1:go_default_library", "//staging/src/k8s.io/client-go/kubernetes/typed/rbac/v1:go_default_library", ], diff --git a/pkg/registry/rbac/reconciliation/namespace.go b/pkg/registry/rbac/reconciliation/namespace.go new file mode 100644 index 00000000000..2ee7fe9a2b0 --- /dev/null +++ b/pkg/registry/rbac/reconciliation/namespace.go @@ -0,0 +1,44 @@ +/* +Copyright 2018 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 reconciliation + +import ( + corev1 "k8s.io/api/core/v1" + apierrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + utilerrors "k8s.io/apimachinery/pkg/util/errors" + corev1client "k8s.io/client-go/kubernetes/typed/core/v1" +) + +// tryEnsureNamespace gets or creates the given namespace while ignoring forbidden errors. +// It is a best effort attempt as the user may not be able to get or create namespaces. +// This allows us to handle flows where the user can only mutate roles and role bindings. +func tryEnsureNamespace(client corev1client.NamespaceInterface, namespace string) error { + _, getErr := client.Get(namespace, metav1.GetOptions{}) + if getErr == nil { + return nil + } + + if fatalGetErr := utilerrors.FilterOut(getErr, apierrors.IsNotFound, apierrors.IsForbidden); fatalGetErr != nil { + return fatalGetErr + } + + ns := &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: namespace}} + _, createErr := client.Create(ns) + + return utilerrors.FilterOut(createErr, apierrors.IsAlreadyExists, apierrors.IsForbidden) +} diff --git a/pkg/registry/rbac/reconciliation/role_interfaces.go b/pkg/registry/rbac/reconciliation/role_interfaces.go index 24cb7899d37..1c349d36e7d 100644 --- a/pkg/registry/rbac/reconciliation/role_interfaces.go +++ b/pkg/registry/rbac/reconciliation/role_interfaces.go @@ -17,9 +17,7 @@ limitations under the License. package reconciliation import ( - corev1 "k8s.io/api/core/v1" rbacv1 "k8s.io/api/rbac/v1" - apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" corev1client "k8s.io/client-go/kubernetes/typed/core/v1" @@ -90,8 +88,7 @@ func (c RoleModifier) Get(namespace, name string) (RuleOwner, error) { } func (c RoleModifier) Create(in RuleOwner) (RuleOwner, error) { - ns := &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: in.GetNamespace()}} - if _, err := c.NamespaceClient.Create(ns); err != nil && !apierrors.IsAlreadyExists(err) { + if err := tryEnsureNamespace(c.NamespaceClient, in.GetNamespace()); err != nil { return nil, err } diff --git a/pkg/registry/rbac/reconciliation/rolebinding_interfaces.go b/pkg/registry/rbac/reconciliation/rolebinding_interfaces.go index 23bf6b653a8..3d60537815e 100644 --- a/pkg/registry/rbac/reconciliation/rolebinding_interfaces.go +++ b/pkg/registry/rbac/reconciliation/rolebinding_interfaces.go @@ -17,9 +17,7 @@ limitations under the License. package reconciliation import ( - corev1 "k8s.io/api/core/v1" rbacv1 "k8s.io/api/rbac/v1" - apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/types" @@ -92,8 +90,7 @@ func (c RoleBindingClientAdapter) Get(namespace, name string) (RoleBinding, erro } func (c RoleBindingClientAdapter) Create(in RoleBinding) (RoleBinding, error) { - ns := &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: in.GetNamespace()}} - if _, err := c.NamespaceClient.Create(ns); err != nil && !apierrors.IsAlreadyExists(err) { + if err := tryEnsureNamespace(c.NamespaceClient, in.GetNamespace()); err != nil { return nil, err }