2016-07-27 14:29:31 +00:00
/ *
Copyright 2016 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 .
* /
2016-09-23 19:10:47 +00:00
package rest
2016-07-27 14:29:31 +00:00
import (
2016-08-26 15:06:27 +00:00
"fmt"
2016-12-22 13:19:11 +00:00
"time"
2016-07-27 14:29:31 +00:00
2018-11-09 18:49:10 +00:00
"k8s.io/klog"
2016-08-26 15:06:27 +00:00
2017-07-26 14:36:43 +00:00
rbacapiv1 "k8s.io/api/rbac/v1"
2017-06-22 18:24:23 +00:00
rbacapiv1beta1 "k8s.io/api/rbac/v1beta1"
2017-10-20 15:01:52 +00:00
apierrors "k8s.io/apimachinery/pkg/api/errors"
2017-02-27 20:09:27 +00:00
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2017-01-09 17:24:21 +00:00
"k8s.io/apimachinery/pkg/runtime/schema"
2017-01-11 14:09:48 +00:00
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
"k8s.io/apimachinery/pkg/util/wait"
2017-01-09 14:36:17 +00:00
"k8s.io/apiserver/pkg/authorization/authorizer"
2017-02-02 09:25:56 +00:00
"k8s.io/apiserver/pkg/registry/generic"
"k8s.io/apiserver/pkg/registry/rest"
genericapiserver "k8s.io/apiserver/pkg/server"
2017-02-11 11:26:43 +00:00
serverstorage "k8s.io/apiserver/pkg/server/storage"
2018-04-19 11:57:45 +00:00
corev1client "k8s.io/client-go/kubernetes/typed/core/v1"
rbacv1client "k8s.io/client-go/kubernetes/typed/rbac/v1"
2017-08-10 07:03:41 +00:00
"k8s.io/client-go/util/retry"
2017-10-16 11:41:50 +00:00
"k8s.io/kubernetes/pkg/api/legacyscheme"
2016-07-27 14:29:31 +00:00
"k8s.io/kubernetes/pkg/apis/rbac"
2016-09-15 17:41:48 +00:00
"k8s.io/kubernetes/pkg/registry/rbac/clusterrole"
clusterrolepolicybased "k8s.io/kubernetes/pkg/registry/rbac/clusterrole/policybased"
2016-11-07 19:45:16 +00:00
clusterrolestore "k8s.io/kubernetes/pkg/registry/rbac/clusterrole/storage"
2016-09-15 17:41:48 +00:00
"k8s.io/kubernetes/pkg/registry/rbac/clusterrolebinding"
clusterrolebindingpolicybased "k8s.io/kubernetes/pkg/registry/rbac/clusterrolebinding/policybased"
2016-11-07 19:45:16 +00:00
clusterrolebindingstore "k8s.io/kubernetes/pkg/registry/rbac/clusterrolebinding/storage"
2017-02-07 20:06:27 +00:00
"k8s.io/kubernetes/pkg/registry/rbac/reconciliation"
2016-09-15 17:41:48 +00:00
"k8s.io/kubernetes/pkg/registry/rbac/role"
rolepolicybased "k8s.io/kubernetes/pkg/registry/rbac/role/policybased"
2016-11-07 19:45:16 +00:00
rolestore "k8s.io/kubernetes/pkg/registry/rbac/role/storage"
2016-09-15 17:41:48 +00:00
"k8s.io/kubernetes/pkg/registry/rbac/rolebinding"
rolebindingpolicybased "k8s.io/kubernetes/pkg/registry/rbac/rolebinding/policybased"
2016-11-07 19:45:16 +00:00
rolebindingstore "k8s.io/kubernetes/pkg/registry/rbac/rolebinding/storage"
2017-01-11 10:11:25 +00:00
rbacregistryvalidation "k8s.io/kubernetes/pkg/registry/rbac/validation"
2016-08-26 15:06:27 +00:00
"k8s.io/kubernetes/plugin/pkg/auth/authorizer/rbac/bootstrappolicy"
2016-07-27 14:29:31 +00:00
)
2017-03-31 01:40:51 +00:00
const PostStartHookName = "rbac/bootstrap-roles"
2017-01-09 14:36:17 +00:00
type RESTStorageProvider struct {
Authorizer authorizer . Authorizer
}
2016-07-27 14:29:31 +00:00
2016-10-27 18:24:11 +00:00
var _ genericapiserver . PostStartHookProvider = RESTStorageProvider { }
2016-07-27 14:29:31 +00:00
2017-02-11 11:26:43 +00:00
func ( p RESTStorageProvider ) NewRESTStorage ( apiResourceConfigSource serverstorage . APIResourceConfigSource , restOptionsGetter generic . RESTOptionsGetter ) ( genericapiserver . APIGroupInfo , bool ) {
2018-05-07 12:32:20 +00:00
apiGroupInfo := genericapiserver . NewDefaultAPIGroupInfo ( rbac . GroupName , legacyscheme . Scheme , legacyscheme . ParameterCodec , legacyscheme . Codecs )
2017-06-09 20:34:04 +00:00
// If you add a version here, be sure to add an entry in `k8s.io/kubernetes/cmd/kube-apiserver/app/aggregator.go with specific priorities.
// TODO refactor the plumbing to provide the information in the APIGroupInfo
2016-07-27 14:29:31 +00:00
2018-01-27 07:18:25 +00:00
if apiResourceConfigSource . VersionEnabled ( rbacapiv1beta1 . SchemeGroupVersion ) {
2017-01-09 17:24:21 +00:00
apiGroupInfo . VersionedResourcesStorageMap [ rbacapiv1beta1 . SchemeGroupVersion . Version ] = p . storage ( rbacapiv1beta1 . SchemeGroupVersion , apiResourceConfigSource , restOptionsGetter )
}
2018-01-27 07:18:25 +00:00
if apiResourceConfigSource . VersionEnabled ( rbacapiv1 . SchemeGroupVersion ) {
2017-09-23 19:02:59 +00:00
apiGroupInfo . VersionedResourcesStorageMap [ rbacapiv1 . SchemeGroupVersion . Version ] = p . storage ( rbacapiv1 . SchemeGroupVersion , apiResourceConfigSource , restOptionsGetter )
}
2016-07-27 14:29:31 +00:00
return apiGroupInfo , true
}
2017-02-11 11:26:43 +00:00
func ( p RESTStorageProvider ) storage ( version schema . GroupVersion , apiResourceConfigSource serverstorage . APIResourceConfigSource , restOptionsGetter generic . RESTOptionsGetter ) map [ string ] rest . Storage {
2018-01-27 07:18:25 +00:00
storage := map [ string ] rest . Storage { }
rolesStorage := rolestore . NewREST ( restOptionsGetter )
roleBindingsStorage := rolebindingstore . NewREST ( restOptionsGetter )
clusterRolesStorage := clusterrolestore . NewREST ( restOptionsGetter )
clusterRoleBindingsStorage := clusterrolebindingstore . NewREST ( restOptionsGetter )
authorizationRuleResolver := rbacregistryvalidation . NewDefaultRuleResolver (
role . AuthorizerAdapter { Registry : role . NewRegistry ( rolesStorage ) } ,
rolebinding . AuthorizerAdapter { Registry : rolebinding . NewRegistry ( roleBindingsStorage ) } ,
clusterrole . AuthorizerAdapter { Registry : clusterrole . NewRegistry ( clusterRolesStorage ) } ,
clusterrolebinding . AuthorizerAdapter { Registry : clusterrolebinding . NewRegistry ( clusterRoleBindingsStorage ) } ,
2016-12-01 02:09:56 +00:00
)
2018-01-27 07:18:25 +00:00
// roles
2018-05-02 16:46:42 +00:00
storage [ "roles" ] = rolepolicybased . NewStorage ( rolesStorage , p . Authorizer , authorizationRuleResolver )
2018-01-27 07:18:25 +00:00
// rolebindings
storage [ "rolebindings" ] = rolebindingpolicybased . NewStorage ( roleBindingsStorage , p . Authorizer , authorizationRuleResolver )
// clusterroles
2018-05-02 16:46:42 +00:00
storage [ "clusterroles" ] = clusterrolepolicybased . NewStorage ( clusterRolesStorage , p . Authorizer , authorizationRuleResolver )
2018-01-27 07:18:25 +00:00
// clusterrolebindings
storage [ "clusterrolebindings" ] = clusterrolebindingpolicybased . NewStorage ( clusterRoleBindingsStorage , p . Authorizer , authorizationRuleResolver )
2016-07-27 14:29:31 +00:00
return storage
}
2016-08-26 15:06:27 +00:00
2016-10-27 18:24:11 +00:00
func ( p RESTStorageProvider ) PostStartHook ( ) ( string , genericapiserver . PostStartHookFunc , error ) {
2017-08-15 17:32:38 +00:00
policy := & PolicyData {
2019-02-07 04:25:01 +00:00
ClusterRoles : append ( bootstrappolicy . ClusterRoles ( ) , bootstrappolicy . ControllerRoles ( ) ... ) ,
ClusterRoleBindings : append ( bootstrappolicy . ClusterRoleBindings ( ) , bootstrappolicy . ControllerRoleBindings ( ) ... ) ,
Roles : bootstrappolicy . NamespaceRoles ( ) ,
RoleBindings : bootstrappolicy . NamespaceRoleBindings ( ) ,
ClusterRolesToAggregate : bootstrappolicy . ClusterRolesToAggregate ( ) ,
ClusterRoleBindingsToSplit : bootstrappolicy . ClusterRoleBindingsToSplit ( ) ,
2017-08-15 17:32:38 +00:00
}
return PostStartHookName , policy . EnsureRBACPolicy ( ) , nil
2016-08-26 15:06:27 +00:00
}
2017-08-15 17:32:38 +00:00
type PolicyData struct {
2018-04-19 11:57:45 +00:00
ClusterRoles [ ] rbacapiv1 . ClusterRole
ClusterRoleBindings [ ] rbacapiv1 . ClusterRoleBinding
Roles map [ string ] [ ] rbacapiv1 . Role
RoleBindings map [ string ] [ ] rbacapiv1 . RoleBinding
2017-10-20 15:01:52 +00:00
// ClusterRolesToAggregate maps from previous clusterrole name to the new clusterrole name
ClusterRolesToAggregate map [ string ] string
2019-02-07 04:25:01 +00:00
// ClusterRoleBindingsToSplit maps from previous ClusterRoleBinding Name to a template for the new ClusterRoleBinding
ClusterRoleBindingsToSplit map [ string ] rbacapiv1 . ClusterRoleBinding
2017-08-15 17:32:38 +00:00
}
2017-07-04 23:14:41 +00:00
2017-08-15 17:32:38 +00:00
func ( p * PolicyData ) EnsureRBACPolicy ( ) genericapiserver . PostStartHookFunc {
return func ( hookContext genericapiserver . PostStartHookContext ) error {
// intializing roles is really important. On some e2e runs, we've seen cases where etcd is down when the server
// starts, the roles don't initialize, and nothing works.
err := wait . Poll ( 1 * time . Second , 30 * time . Second , func ( ) ( done bool , err error ) {
2016-09-29 19:10:04 +00:00
2018-04-19 11:57:45 +00:00
coreclientset , err := corev1client . NewForConfig ( hookContext . LoopbackClientConfig )
2017-02-07 20:06:27 +00:00
if err != nil {
2017-08-15 17:32:38 +00:00
utilruntime . HandleError ( fmt . Errorf ( "unable to initialize client: %v" , err ) )
return false , nil
2016-12-22 13:19:11 +00:00
}
2016-10-04 14:34:01 +00:00
2018-04-19 11:57:45 +00:00
clientset , err := rbacv1client . NewForConfig ( hookContext . LoopbackClientConfig )
2017-02-07 20:06:27 +00:00
if err != nil {
2017-08-15 17:32:38 +00:00
utilruntime . HandleError ( fmt . Errorf ( "unable to initialize client: %v" , err ) )
return false , nil
}
// Make sure etcd is responding before we start reconciling
if _ , err := clientset . ClusterRoles ( ) . List ( metav1 . ListOptions { } ) ; err != nil {
utilruntime . HandleError ( fmt . Errorf ( "unable to initialize clusterroles: %v" , err ) )
return false , nil
}
if _ , err := clientset . ClusterRoleBindings ( ) . List ( metav1 . ListOptions { } ) ; err != nil {
utilruntime . HandleError ( fmt . Errorf ( "unable to initialize clusterrolebindings: %v" , err ) )
return false , nil
2016-12-22 13:19:11 +00:00
}
2017-10-20 15:01:52 +00:00
// if the new cluster roles to aggregate do not yet exist, then we need to copy the old roles if they don't exist
// in new locations
if err := primeAggregatedClusterRoles ( p . ClusterRolesToAggregate , clientset ) ; err != nil {
utilruntime . HandleError ( fmt . Errorf ( "unable to prime aggregated clusterroles: %v" , err ) )
return false , nil
}
2019-02-07 04:25:01 +00:00
if err := primeSplitClusterRoleBindings ( p . ClusterRoleBindingsToSplit , clientset ) ; err != nil {
utilruntime . HandleError ( fmt . Errorf ( "unable to prime split ClusterRoleBindings: %v" , err ) )
return false , nil
}
2017-08-15 17:32:38 +00:00
// ensure bootstrap roles are created or reconciled
for _ , clusterRole := range p . ClusterRoles {
2017-02-28 16:05:57 +00:00
opts := reconciliation . ReconcileRoleOptions {
2017-08-15 17:32:38 +00:00
Role : reconciliation . ClusterRoleRuleOwner { ClusterRole : & clusterRole } ,
Client : reconciliation . ClusterRoleModifier { Client : clientset . ClusterRoles ( ) } ,
2017-02-23 16:45:49 +00:00
Confirm : true ,
}
err := retry . RetryOnConflict ( retry . DefaultBackoff , func ( ) error {
result , err := opts . Run ( )
if err != nil {
return err
}
switch {
case result . Protected && result . Operation != reconciliation . ReconcileNone :
2018-11-09 18:49:10 +00:00
klog . Warningf ( "skipped reconcile-protected clusterrole.%s/%s with missing permissions: %v" , rbac . GroupName , clusterRole . Name , result . MissingRules )
2017-02-23 16:45:49 +00:00
case result . Operation == reconciliation . ReconcileUpdate :
2018-11-09 18:49:10 +00:00
klog . Infof ( "updated clusterrole.%s/%s with additional permissions: %v" , rbac . GroupName , clusterRole . Name , result . MissingRules )
2017-02-23 16:45:49 +00:00
case result . Operation == reconciliation . ReconcileCreate :
2018-11-09 18:49:10 +00:00
klog . Infof ( "created clusterrole.%s/%s" , rbac . GroupName , clusterRole . Name )
2017-02-23 16:45:49 +00:00
}
return nil
} )
if err != nil {
// don't fail on failures, try to create as many as you can
2017-08-15 17:32:38 +00:00
utilruntime . HandleError ( fmt . Errorf ( "unable to reconcile clusterrole.%s/%s: %v" , rbac . GroupName , clusterRole . Name , err ) )
2017-02-23 16:45:49 +00:00
}
}
2017-08-15 17:32:38 +00:00
// ensure bootstrap rolebindings are created or reconciled
for _ , clusterRoleBinding := range p . ClusterRoleBindings {
2017-02-28 16:11:32 +00:00
opts := reconciliation . ReconcileRoleBindingOptions {
2017-08-15 17:32:38 +00:00
RoleBinding : reconciliation . ClusterRoleBindingAdapter { ClusterRoleBinding : & clusterRoleBinding } ,
Client : reconciliation . ClusterRoleBindingClientAdapter { Client : clientset . ClusterRoleBindings ( ) } ,
2017-02-28 16:11:32 +00:00
Confirm : true ,
}
err := retry . RetryOnConflict ( retry . DefaultBackoff , func ( ) error {
result , err := opts . Run ( )
if err != nil {
return err
}
switch {
case result . Protected && result . Operation != reconciliation . ReconcileNone :
2018-11-09 18:49:10 +00:00
klog . Warningf ( "skipped reconcile-protected clusterrolebinding.%s/%s with missing subjects: %v" , rbac . GroupName , clusterRoleBinding . Name , result . MissingSubjects )
2017-02-28 16:11:32 +00:00
case result . Operation == reconciliation . ReconcileUpdate :
2018-11-09 18:49:10 +00:00
klog . Infof ( "updated clusterrolebinding.%s/%s with additional subjects: %v" , rbac . GroupName , clusterRoleBinding . Name , result . MissingSubjects )
2017-02-28 16:11:32 +00:00
case result . Operation == reconciliation . ReconcileCreate :
2018-11-09 18:49:10 +00:00
klog . Infof ( "created clusterrolebinding.%s/%s" , rbac . GroupName , clusterRoleBinding . Name )
2017-02-28 16:11:32 +00:00
case result . Operation == reconciliation . ReconcileRecreate :
2018-11-09 18:49:10 +00:00
klog . Infof ( "recreated clusterrolebinding.%s/%s" , rbac . GroupName , clusterRoleBinding . Name )
2017-02-28 16:11:32 +00:00
}
return nil
} )
if err != nil {
// don't fail on failures, try to create as many as you can
2017-08-15 17:32:38 +00:00
utilruntime . HandleError ( fmt . Errorf ( "unable to reconcile clusterrolebinding.%s/%s: %v" , rbac . GroupName , clusterRoleBinding . Name , err ) )
}
}
// ensure bootstrap namespaced roles are created or reconciled
for namespace , roles := range p . Roles {
for _ , role := range roles {
opts := reconciliation . ReconcileRoleOptions {
Role : reconciliation . RoleRuleOwner { Role : & role } ,
Client : reconciliation . RoleModifier { Client : clientset , NamespaceClient : coreclientset . Namespaces ( ) } ,
Confirm : true ,
}
err := retry . RetryOnConflict ( retry . DefaultBackoff , func ( ) error {
result , err := opts . Run ( )
if err != nil {
return err
}
switch {
case result . Protected && result . Operation != reconciliation . ReconcileNone :
2018-11-09 18:49:10 +00:00
klog . Warningf ( "skipped reconcile-protected role.%s/%s in %v with missing permissions: %v" , rbac . GroupName , role . Name , namespace , result . MissingRules )
2017-08-15 17:32:38 +00:00
case result . Operation == reconciliation . ReconcileUpdate :
2018-11-09 18:49:10 +00:00
klog . Infof ( "updated role.%s/%s in %v with additional permissions: %v" , rbac . GroupName , role . Name , namespace , result . MissingRules )
2017-08-15 17:32:38 +00:00
case result . Operation == reconciliation . ReconcileCreate :
2018-11-09 18:49:10 +00:00
klog . Infof ( "created role.%s/%s in %v" , rbac . GroupName , role . Name , namespace )
2017-08-15 17:32:38 +00:00
}
return nil
} )
if err != nil {
// don't fail on failures, try to create as many as you can
utilruntime . HandleError ( fmt . Errorf ( "unable to reconcile role.%s/%s in %v: %v" , rbac . GroupName , role . Name , namespace , err ) )
}
2017-02-28 16:11:32 +00:00
}
}
2017-08-15 17:32:38 +00:00
// ensure bootstrap namespaced rolebindings are created or reconciled
for namespace , roleBindings := range p . RoleBindings {
for _ , roleBinding := range roleBindings {
opts := reconciliation . ReconcileRoleBindingOptions {
RoleBinding : reconciliation . RoleBindingAdapter { RoleBinding : & roleBinding } ,
Client : reconciliation . RoleBindingClientAdapter { Client : clientset , NamespaceClient : coreclientset . Namespaces ( ) } ,
Confirm : true ,
}
err := retry . RetryOnConflict ( retry . DefaultBackoff , func ( ) error {
result , err := opts . Run ( )
if err != nil {
return err
}
switch {
case result . Protected && result . Operation != reconciliation . ReconcileNone :
2018-11-09 18:49:10 +00:00
klog . Warningf ( "skipped reconcile-protected rolebinding.%s/%s in %v with missing subjects: %v" , rbac . GroupName , roleBinding . Name , namespace , result . MissingSubjects )
2017-08-15 17:32:38 +00:00
case result . Operation == reconciliation . ReconcileUpdate :
2018-11-09 18:49:10 +00:00
klog . Infof ( "updated rolebinding.%s/%s in %v with additional subjects: %v" , rbac . GroupName , roleBinding . Name , namespace , result . MissingSubjects )
2017-08-15 17:32:38 +00:00
case result . Operation == reconciliation . ReconcileCreate :
2018-11-09 18:49:10 +00:00
klog . Infof ( "created rolebinding.%s/%s in %v" , rbac . GroupName , roleBinding . Name , namespace )
2017-08-15 17:32:38 +00:00
case result . Operation == reconciliation . ReconcileRecreate :
2018-11-09 18:49:10 +00:00
klog . Infof ( "recreated rolebinding.%s/%s in %v" , rbac . GroupName , roleBinding . Name , namespace )
2017-08-15 17:32:38 +00:00
}
return nil
} )
if err != nil {
// don't fail on failures, try to create as many as you can
utilruntime . HandleError ( fmt . Errorf ( "unable to reconcile rolebinding.%s/%s in %v: %v" , rbac . GroupName , roleBinding . Name , namespace , err ) )
}
}
}
return true , nil
} )
2018-02-09 06:53:53 +00:00
// if we're never able to make it through initialization, kill the API server
2017-08-15 17:32:38 +00:00
if err != nil {
return fmt . Errorf ( "unable to initialize roles: %v" , err )
2017-02-28 16:11:32 +00:00
}
2017-08-15 17:32:38 +00:00
return nil
2016-10-04 14:34:01 +00:00
}
2016-08-26 15:06:27 +00:00
}
2016-10-27 18:24:11 +00:00
func ( p RESTStorageProvider ) GroupName ( ) string {
return rbac . GroupName
}
2017-10-20 15:01:52 +00:00
// primeAggregatedClusterRoles copies roles that have transitioned to aggregated roles and may need to pick up changes
// that were done to the legacy roles.
2018-04-19 11:57:45 +00:00
func primeAggregatedClusterRoles ( clusterRolesToAggregate map [ string ] string , clusterRoleClient rbacv1client . ClusterRolesGetter ) error {
2017-10-20 15:01:52 +00:00
for oldName , newName := range clusterRolesToAggregate {
_ , err := clusterRoleClient . ClusterRoles ( ) . Get ( newName , metav1 . GetOptions { } )
if err == nil {
continue
}
if ! apierrors . IsNotFound ( err ) {
return err
}
existingRole , err := clusterRoleClient . ClusterRoles ( ) . Get ( oldName , metav1 . GetOptions { } )
if apierrors . IsNotFound ( err ) {
continue
}
if err != nil {
return err
}
2018-05-13 19:07:38 +00:00
if existingRole . AggregationRule != nil {
// the old role already moved to an aggregated role, so there are no custom rules to migrate at this point
return nil
}
2018-11-09 18:49:10 +00:00
klog . V ( 1 ) . Infof ( "migrating %v to %v" , existingRole . Name , newName )
2017-10-20 15:01:52 +00:00
existingRole . Name = newName
2017-11-22 21:16:01 +00:00
existingRole . ResourceVersion = "" // clear this so the object can be created.
2017-10-20 15:01:52 +00:00
if _ , err := clusterRoleClient . ClusterRoles ( ) . Create ( existingRole ) ; err != nil && ! apierrors . IsAlreadyExists ( err ) {
return err
}
}
return nil
}
2019-02-07 04:25:01 +00:00
// primeSplitClusterRoleBindings ensures the existence of target ClusterRoleBindings
// by copying Subjects, Annotations, and Labels from the specified source
// ClusterRoleBinding, if present.
func primeSplitClusterRoleBindings ( clusterRoleBindingToSplit map [ string ] rbacapiv1 . ClusterRoleBinding , clusterRoleBindingClient rbacv1client . ClusterRoleBindingsGetter ) error {
for existingBindingName , clusterRoleBindingToCreate := range clusterRoleBindingToSplit {
// If source ClusterRoleBinding does not exist, do nothing.
existingRoleBinding , err := clusterRoleBindingClient . ClusterRoleBindings ( ) . Get ( existingBindingName , metav1 . GetOptions { } )
if apierrors . IsNotFound ( err ) {
continue
}
if err != nil {
return err
}
// If the target ClusterRoleBinding already exists, do nothing.
_ , err = clusterRoleBindingClient . ClusterRoleBindings ( ) . Get ( clusterRoleBindingToCreate . Name , metav1 . GetOptions { } )
if err == nil {
continue
}
if ! apierrors . IsNotFound ( err ) {
return err
}
// If the source exists, but the target does not,
// copy the subjects, labels, and annotations from the former to create the latter.
klog . V ( 1 ) . Infof ( "copying subjects, labels, and annotations from ClusterRoleBinding %q to template %q" , existingBindingName , clusterRoleBindingToCreate . Name )
newCRB := clusterRoleBindingToCreate . DeepCopy ( )
newCRB . Subjects = existingRoleBinding . Subjects
newCRB . Labels = existingRoleBinding . Labels
newCRB . Annotations = existingRoleBinding . Annotations
if _ , err := clusterRoleBindingClient . ClusterRoleBindings ( ) . Create ( newCRB ) ; err != nil && ! apierrors . IsAlreadyExists ( err ) {
return err
}
}
return nil
}