diff --git a/staging/operator-lifecycle-manager/pkg/api/wrappers/deployment_install_client.go b/staging/operator-lifecycle-manager/pkg/api/wrappers/deployment_install_client.go index dc3fcd32e0..f2bc748c22 100644 --- a/staging/operator-lifecycle-manager/pkg/api/wrappers/deployment_install_client.go +++ b/staging/operator-lifecycle-manager/pkg/api/wrappers/deployment_install_client.go @@ -58,11 +58,11 @@ func (c *InstallStrategyDeploymentClientForNamespace) GetOpLister() operatorlist } func (c *InstallStrategyDeploymentClientForNamespace) CreateRole(role *rbacv1.Role) (*rbacv1.Role, error) { - return c.opClient.KubernetesInterface().RbacV1().Roles(c.Namespace).Create(context.TODO(), role, metav1.CreateOptions{}) + return c.opClient.CreateRole(role) } func (c *InstallStrategyDeploymentClientForNamespace) CreateRoleBinding(roleBinding *rbacv1.RoleBinding) (*rbacv1.RoleBinding, error) { - return c.opClient.KubernetesInterface().RbacV1().RoleBindings(c.Namespace).Create(context.TODO(), roleBinding, metav1.CreateOptions{}) + return c.opClient.CreateRoleBinding(roleBinding) } func (c *InstallStrategyDeploymentClientForNamespace) EnsureServiceAccount(serviceAccount *corev1.ServiceAccount, owner ownerutil.Owner) (*corev1.ServiceAccount, error) { diff --git a/staging/operator-lifecycle-manager/pkg/controller/bundle/bundle_unpacker.go b/staging/operator-lifecycle-manager/pkg/controller/bundle/bundle_unpacker.go index cfe46187bb..59a86cc44b 100644 --- a/staging/operator-lifecycle-manager/pkg/controller/bundle/bundle_unpacker.go +++ b/staging/operator-lifecycle-manager/pkg/controller/bundle/bundle_unpacker.go @@ -734,6 +734,9 @@ func (c *ConfigMapUnpacker) ensureRole(cmRef *corev1.ObjectReference) (role *rba if err != nil { if apierrors.IsNotFound(err) { role, err = c.client.RbacV1().Roles(fresh.GetNamespace()).Create(context.TODO(), fresh, metav1.CreateOptions{}) + if apierrors.IsAlreadyExists(err) { + role, err = c.client.RbacV1().Roles(fresh.GetNamespace()).Update(context.TODO(), fresh, metav1.UpdateOptions{}) + } } return @@ -778,6 +781,9 @@ func (c *ConfigMapUnpacker) ensureRoleBinding(cmRef *corev1.ObjectReference) (ro if err != nil { if apierrors.IsNotFound(err) { roleBinding, err = c.client.RbacV1().RoleBindings(fresh.GetNamespace()).Create(context.TODO(), fresh, metav1.CreateOptions{}) + if apierrors.IsAlreadyExists(err) { + roleBinding, err = c.client.RbacV1().RoleBindings(fresh.GetNamespace()).Update(context.TODO(), fresh, metav1.UpdateOptions{}) + } } return diff --git a/staging/operator-lifecycle-manager/pkg/controller/install/certresources.go b/staging/operator-lifecycle-manager/pkg/controller/install/certresources.go index 25f4fd3f82..d0dc664cc7 100644 --- a/staging/operator-lifecycle-manager/pkg/controller/install/certresources.go +++ b/staging/operator-lifecycle-manager/pkg/controller/install/certresources.go @@ -463,53 +463,24 @@ func (i *StrategyDeploymentInstaller) installCertRequirementsForDeployment(deplo return nil, nil, err } - // Create RoleBinding to extension-apiserver-authentication-reader Role in the kube-system namespace. - authReaderRoleBinding := &rbacv1.RoleBinding{ - Subjects: []rbacv1.Subject{ - { - Kind: "ServiceAccount", - APIGroup: "", - Name: depSpec.Template.Spec.ServiceAccountName, - Namespace: i.owner.GetNamespace(), - }, - }, - RoleRef: rbacv1.RoleRef{ - APIGroup: "rbac.authorization.k8s.io", - Kind: "Role", - Name: "extension-apiserver-authentication-reader", - }, - } - authReaderRoleBinding.SetName(AuthReaderRoleBindingName(serviceName)) - authReaderRoleBinding.SetNamespace(KubeSystem) - authReaderRoleBinding.SetLabels(map[string]string{OLMManagedLabelKey: OLMManagedLabelValue}) + // Apply RoleBinding to extension-apiserver-authentication-reader Role in the kube-system namespace. + authReaderRoleBindingApplyConfig := rbacv1ac.RoleBinding(AuthReaderRoleBindingName(serviceName), KubeSystem). + WithLabels(map[string]string{OLMManagedLabelKey: OLMManagedLabelValue}). + WithSubjects(rbacv1ac.Subject(). + WithKind("ServiceAccount"). + WithAPIGroup(""). + WithName(depSpec.Template.Spec.ServiceAccountName). + WithNamespace(i.owner.GetNamespace())). + WithRoleRef(rbacv1ac.RoleRef(). + WithAPIGroup("rbac.authorization.k8s.io"). + WithKind("Role"). + WithName("extension-apiserver-authentication-reader")) - existingAuthReaderRoleBinding, err := i.strategyClient.GetOpLister().RbacV1().RoleBindingLister().RoleBindings(KubeSystem).Get(authReaderRoleBinding.GetName()) - if err == nil { - // Check if the only owners are this CSV or in this CSV's replacement chain. - if ownerutil.AdoptableLabels(existingAuthReaderRoleBinding.GetLabels(), true, i.owner) { - logger.WithFields(log.Fields{"obj": "existingAuthReaderRB", "labels": existingAuthReaderRoleBinding.GetLabels()}).Debug("adopting") - if err := ownerutil.AddOwnerLabels(authReaderRoleBinding, i.owner); err != nil { - return nil, nil, err - } - } - // Attempt an update. - if _, err := i.strategyClient.GetOpClient().UpdateRoleBinding(authReaderRoleBinding); err != nil { - logger.Warnf("could not update auth reader role binding %s", authReaderRoleBinding.GetName()) - return nil, nil, err - } - } else if apierrors.IsNotFound(err) { - // Create the role. - if err := ownerutil.AddOwnerLabels(authReaderRoleBinding, i.owner); err != nil { - return nil, nil, err - } - _, err = i.strategyClient.GetOpClient().CreateRoleBinding(authReaderRoleBinding) - if err != nil { - log.Warnf("could not create auth reader role binding %s", authReaderRoleBinding.GetName()) - return nil, nil, err - } - } else { + if _, err = i.strategyClient.GetOpClient().ApplyRoleBinding(authReaderRoleBindingApplyConfig, metav1.ApplyOptions{Force: true, FieldManager: "olm.install"}); err != nil { + log.Errorf("could not apply auth reader rolebinding %s: %s", *authReaderRoleBindingApplyConfig.Name, err.Error()) return nil, nil, err } + AddDefaultCertVolumeAndVolumeMounts(&depSpec, secret.GetName()) // Setting the olm hash label forces a rollout and ensures that the new secret diff --git a/staging/operator-lifecycle-manager/pkg/controller/install/certresources_test.go b/staging/operator-lifecycle-manager/pkg/controller/install/certresources_test.go index 2682e98ffa..eb31c550d4 100644 --- a/staging/operator-lifecycle-manager/pkg/controller/install/certresources_test.go +++ b/staging/operator-lifecycle-manager/pkg/controller/install/certresources_test.go @@ -309,7 +309,19 @@ func TestInstallCertRequirementsForDeployment(t *testing.T) { authReaderRoleBinding.SetNamespace(KubeSystem) authReaderRoleBinding.SetLabels(map[string]string{OLMManagedLabelKey: OLMManagedLabelValue}) - mockOpClient.EXPECT().UpdateRoleBinding(authReaderRoleBinding).Return(authReaderRoleBinding, nil) + authReaderRoleBindingApplyConfig := rbacv1ac.RoleBinding(AuthReaderRoleBindingName(service.GetName()), KubeSystem). + WithLabels(map[string]string{OLMManagedLabelKey: OLMManagedLabelValue}). + WithSubjects(rbacv1ac.Subject(). + WithKind("ServiceAccount"). + WithAPIGroup(""). + WithName(args.depSpec.Template.Spec.ServiceAccountName). + WithNamespace(namespace)). + WithRoleRef(rbacv1ac.RoleRef(). + WithAPIGroup("rbac.authorization.k8s.io"). + WithKind("Role"). + WithName("extension-apiserver-authentication-reader")) + + mockOpClient.EXPECT().ApplyRoleBinding(authReaderRoleBindingApplyConfig, metav1.ApplyOptions{Force: true, FieldManager: "olm.install"}).Return(authReaderRoleBinding, nil) }, state: fakeState{ existingService: &corev1.Service{ @@ -569,7 +581,19 @@ func TestInstallCertRequirementsForDeployment(t *testing.T) { authReaderRoleBinding.SetNamespace(KubeSystem) authReaderRoleBinding.SetLabels(map[string]string{OLMManagedLabelKey: OLMManagedLabelValue}) - mockOpClient.EXPECT().UpdateRoleBinding(authReaderRoleBinding).Return(authReaderRoleBinding, nil) + authReaderRoleBindingApplyConfig := rbacv1ac.RoleBinding(AuthReaderRoleBindingName(service.GetName()), KubeSystem). + WithLabels(map[string]string{OLMManagedLabelKey: OLMManagedLabelValue}). + WithSubjects(rbacv1ac.Subject(). + WithKind("ServiceAccount"). + WithAPIGroup(""). + WithName(args.depSpec.Template.Spec.ServiceAccountName). + WithNamespace(namespace)). + WithRoleRef(rbacv1ac.RoleRef(). + WithAPIGroup("rbac.authorization.k8s.io"). + WithKind("Role"). + WithName("extension-apiserver-authentication-reader")) + + mockOpClient.EXPECT().ApplyRoleBinding(authReaderRoleBindingApplyConfig, metav1.ApplyOptions{Force: true, FieldManager: "olm.install"}).Return(authReaderRoleBinding, nil) }, state: fakeState{ existingService: &corev1.Service{ @@ -831,7 +855,19 @@ func TestInstallCertRequirementsForDeployment(t *testing.T) { authReaderRoleBinding.SetNamespace(KubeSystem) authReaderRoleBinding.SetLabels(map[string]string{OLMManagedLabelKey: OLMManagedLabelValue}) - mockOpClient.EXPECT().UpdateRoleBinding(authReaderRoleBinding).Return(authReaderRoleBinding, nil) + authReaderRoleBindingApplyConfig := rbacv1ac.RoleBinding(AuthReaderRoleBindingName(service.GetName()), KubeSystem). + WithLabels(map[string]string{OLMManagedLabelKey: OLMManagedLabelValue}). + WithSubjects(rbacv1ac.Subject(). + WithKind("ServiceAccount"). + WithAPIGroup(""). + WithName(args.depSpec.Template.Spec.ServiceAccountName). + WithNamespace(namespace)). + WithRoleRef(rbacv1ac.RoleRef(). + WithAPIGroup("rbac.authorization.k8s.io"). + WithKind("Role"). + WithName("extension-apiserver-authentication-reader")) + + mockOpClient.EXPECT().ApplyRoleBinding(authReaderRoleBindingApplyConfig, metav1.ApplyOptions{Force: true, FieldManager: "olm.install"}).Return(authReaderRoleBinding, nil) }, state: fakeState{ existingService: nil, diff --git a/staging/operator-lifecycle-manager/pkg/controller/operators/olm/operator_test.go b/staging/operator-lifecycle-manager/pkg/controller/operators/olm/operator_test.go index 79cd22cc79..e5bf822a9e 100644 --- a/staging/operator-lifecycle-manager/pkg/controller/operators/olm/operator_test.go +++ b/staging/operator-lifecycle-manager/pkg/controller/operators/olm/operator_test.go @@ -1511,6 +1511,7 @@ func TestTransitionCSV(t *testing.T) { // Note: Ideally we would not pre-create these objects, but fake client does not support // creation through SSA, see issue here: https://github.com/kubernetes/kubernetes/issues/115598 // Once resolved, these objects and others in this file may be removed. + roleBinding("a1-service-auth-reader", "kube-system", "extension-apiserver-authentication-reader", "sa", namespace), service("a1-service", namespace, "a1", 80), clusterRoleBinding("a1-service-system:auth-delegator", "system:auth-delegator", "sa", namespace), }, @@ -5985,8 +5986,9 @@ func TestCARotation(t *testing.T) { ), defaultTemplateAnnotations), apis("a1.v1.a1Kind"), nil), }, clientObjs: []runtime.Object{addAnnotation(defaultOperatorGroup, operatorsv1.OperatorGroupProvidedAPIsAnnotationKey, "c1.v1.g1,a1Kind.v1.a1")}, - // The service and clusterRoleBinding have been added here as a workaround to fake client not supporting SSA + // The rolebinding, service, and clusterRoleBinding have been added here as a workaround to fake client not supporting SSA objs: []runtime.Object{ + roleBinding("a1-service-auth-reader", "kube-system", "extension-apiserver-authentication-reader", "sa", namespace), service("a1-service", namespace, "a1", 80, ownerReference), clusterRoleBinding("a1-service-system:auth-delegator", "system:auth-delegator", "sa", namespace), }, diff --git a/staging/operator-lifecycle-manager/pkg/controller/operators/olm/operatorgroup.go b/staging/operator-lifecycle-manager/pkg/controller/operators/olm/operatorgroup.go index 3594c544f4..73a52caa9d 100644 --- a/staging/operator-lifecycle-manager/pkg/controller/operators/olm/operatorgroup.go +++ b/staging/operator-lifecycle-manager/pkg/controller/operators/olm/operatorgroup.go @@ -408,11 +408,8 @@ func (a *Operator) ensureProvidedAPIClusterRole(namePrefix, suffix string, verbs return err } if apierrors.IsNotFound(err) { - existingCR, err = a.opClient.KubernetesInterface().RbacV1().ClusterRoles().Create(context.TODO(), clusterRole, metav1.CreateOptions{}) - if err == nil { - return nil - } - if !apierrors.IsAlreadyExists(err) { + existingCR, err = a.opClient.CreateClusterRole(clusterRole) + if err != nil { a.logger.WithError(err).Errorf("Create cluster role failed: %v", clusterRole) return err } @@ -546,12 +543,7 @@ func (a *Operator) ensureSingletonRBAC(operatorNamespace string, csv *v1alpha1.C Resources: []string{"namespaces"}, }), } - // TODO: this should do something smarter if the cluster role already exists - if cr, err := a.opClient.CreateClusterRole(clusterRole); err != nil { - // If the CR already exists, but the label is correct, the cache is just behind - if apierrors.IsAlreadyExists(err) && cr != nil && ownerutil.IsOwnedByLabel(cr, csv) { - continue - } + if _, err := a.opClient.CreateClusterRole(clusterRole); err != nil { return err } a.logger.Debug("created cluster role") @@ -585,12 +577,7 @@ func (a *Operator) ensureSingletonRBAC(operatorNamespace string, csv *v1alpha1.C Name: r.RoleRef.Name, }, } - // TODO: this should do something smarter if the cluster role binding already exists - if crb, err := a.opClient.CreateClusterRoleBinding(clusterRoleBinding); err != nil { - // If the CRB already exists, but the label is correct, the cache is just behind - if apierrors.IsAlreadyExists(err) && crb != nil && ownerutil.IsOwnedByLabel(crb, csv) { - continue - } + if _, err := a.opClient.CreateClusterRoleBinding(clusterRoleBinding); err != nil { return err } } @@ -1056,7 +1043,7 @@ func (a *Operator) ensureOpGroupClusterRole(op *operatorsv1.OperatorGroup, suffi clusterRole.Labels[install.OLMManagedLabelKey] = install.OLMManagedLabelValue a.logger.Infof("creating cluster role: %s owned by operator group: %s/%s", clusterRole.GetName(), op.GetNamespace(), op.GetName()) - _, err = a.opClient.KubernetesInterface().RbacV1().ClusterRoles().Create(context.TODO(), clusterRole, metav1.CreateOptions{}) + _, err = a.opClient.CreateClusterRole(clusterRole) return err } diff --git a/staging/operator-lifecycle-manager/pkg/controller/operators/operatorcondition_controller.go b/staging/operator-lifecycle-manager/pkg/controller/operators/operatorcondition_controller.go index c805977c01..ab462fee37 100644 --- a/staging/operator-lifecycle-manager/pkg/controller/operators/operatorcondition_controller.go +++ b/staging/operator-lifecycle-manager/pkg/controller/operators/operatorcondition_controller.go @@ -150,7 +150,10 @@ func (r *OperatorConditionReconciler) ensureOperatorConditionRole(operatorCondit if !apierrors.IsNotFound(err) { return err } - return r.Client.Create(context.TODO(), role) + err = r.Client.Create(context.TODO(), role) + if apierrors.IsAlreadyExists(err) { + return r.Client.Update(context.TODO(), role) + } } if ownerutil.IsOwnedBy(existingRole, operatorCondition) && @@ -199,7 +202,10 @@ func (r *OperatorConditionReconciler) ensureOperatorConditionRoleBinding(operato if !apierrors.IsNotFound(err) { return err } - return r.Client.Create(context.TODO(), roleBinding) + err = r.Client.Create(context.TODO(), roleBinding) + if apierrors.IsAlreadyExists(err) { + return r.Client.Update(context.TODO(), roleBinding) + } } if ownerutil.IsOwnedBy(existingRoleBinding, operatorCondition) && diff --git a/staging/operator-lifecycle-manager/pkg/lib/operatorclient/apiservice.go b/staging/operator-lifecycle-manager/pkg/lib/operatorclient/apiservice.go index 2267a85ad8..ceea0e18a7 100644 --- a/staging/operator-lifecycle-manager/pkg/lib/operatorclient/apiservice.go +++ b/staging/operator-lifecycle-manager/pkg/lib/operatorclient/apiservice.go @@ -4,15 +4,20 @@ import ( "context" "fmt" + apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" "k8s.io/klog" apiregistrationv1 "k8s.io/kube-aggregator/pkg/apis/apiregistration/v1" ) -// CreateAPIService creates the APIService. +// CreateAPIService creates the APIService or Updates if it already exists. func (c *Client) CreateAPIService(ig *apiregistrationv1.APIService) (*apiregistrationv1.APIService, error) { - return c.ApiregistrationV1Interface().ApiregistrationV1().APIServices().Create(context.TODO(), ig, metav1.CreateOptions{}) + createdAS, err := c.ApiregistrationV1Interface().ApiregistrationV1().APIServices().Create(context.TODO(), ig, metav1.CreateOptions{}) + if apierrors.IsAlreadyExists(err) { + return c.UpdateAPIService(ig) + } + return createdAS, err } // GetAPIService returns the existing APIService. diff --git a/staging/operator-lifecycle-manager/pkg/lib/operatorclient/client.go b/staging/operator-lifecycle-manager/pkg/lib/operatorclient/client.go index a7c27ae07b..cc89369fb7 100644 --- a/staging/operator-lifecycle-manager/pkg/lib/operatorclient/client.go +++ b/staging/operator-lifecycle-manager/pkg/lib/operatorclient/client.go @@ -94,6 +94,7 @@ type RoleClient interface { // RoleBindingClient contains methods for manipulating RoleBindings. type RoleBindingClient interface { + ApplyRoleBinding(applyConfig *rbacv1ac.RoleBindingApplyConfiguration, applyOptions metav1.ApplyOptions) (*rbacv1.RoleBinding, error) CreateRoleBinding(*rbacv1.RoleBinding) (*rbacv1.RoleBinding, error) GetRoleBinding(namespace, name string) (*rbacv1.RoleBinding, error) UpdateRoleBinding(modified *rbacv1.RoleBinding) (*rbacv1.RoleBinding, error) diff --git a/staging/operator-lifecycle-manager/pkg/lib/operatorclient/clusterrole.go b/staging/operator-lifecycle-manager/pkg/lib/operatorclient/clusterrole.go index 58db0fc795..e9060994d5 100644 --- a/staging/operator-lifecycle-manager/pkg/lib/operatorclient/clusterrole.go +++ b/staging/operator-lifecycle-manager/pkg/lib/operatorclient/clusterrole.go @@ -5,14 +5,19 @@ import ( "fmt" 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/types" "k8s.io/klog" ) -// CreateClusterRole creates the ClusterRole. +// CreateClusterRole creates the ClusterRole or Updates if it already exists. func (c *Client) CreateClusterRole(r *rbacv1.ClusterRole) (*rbacv1.ClusterRole, error) { - return c.RbacV1().ClusterRoles().Create(context.TODO(), r, metav1.CreateOptions{}) + createdClusterRole, err := c.RbacV1().ClusterRoles().Create(context.TODO(), r, metav1.CreateOptions{}) + if apierrors.IsAlreadyExists(err) { + return c.UpdateClusterRole(r) + } + return createdClusterRole, err } // GetClusterRole returns the existing ClusterRole. diff --git a/staging/operator-lifecycle-manager/pkg/lib/operatorclient/clusterrolebinding.go b/staging/operator-lifecycle-manager/pkg/lib/operatorclient/clusterrolebinding.go index 0ab429accc..24cc3177c9 100644 --- a/staging/operator-lifecycle-manager/pkg/lib/operatorclient/clusterrolebinding.go +++ b/staging/operator-lifecycle-manager/pkg/lib/operatorclient/clusterrolebinding.go @@ -5,6 +5,7 @@ import ( "fmt" 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/types" acv1 "k8s.io/client-go/applyconfigurations/rbac/v1" @@ -16,9 +17,13 @@ func (c *Client) ApplyClusterRoleBinding(applyConfig *acv1.ClusterRoleBindingApp return c.RbacV1().ClusterRoleBindings().Apply(context.TODO(), applyConfig, applyOptions) } -// CreateRoleBinding creates the roleBinding. +// CreateRoleBinding creates the roleBinding or Updates if it already exists. func (c *Client) CreateClusterRoleBinding(ig *rbacv1.ClusterRoleBinding) (*rbacv1.ClusterRoleBinding, error) { - return c.RbacV1().ClusterRoleBindings().Create(context.TODO(), ig, metav1.CreateOptions{}) + createdCRB, err := c.RbacV1().ClusterRoleBindings().Create(context.TODO(), ig, metav1.CreateOptions{}) + if apierrors.IsAlreadyExists(err) { + return c.UpdateClusterRoleBinding(ig) + } + return createdCRB, err } // GetRoleBinding returns the existing roleBinding. diff --git a/staging/operator-lifecycle-manager/pkg/lib/operatorclient/configmap.go b/staging/operator-lifecycle-manager/pkg/lib/operatorclient/configmap.go index 0ac2e7c013..44565fe6a4 100644 --- a/staging/operator-lifecycle-manager/pkg/lib/operatorclient/configmap.go +++ b/staging/operator-lifecycle-manager/pkg/lib/operatorclient/configmap.go @@ -5,6 +5,7 @@ import ( "fmt" corev1 "k8s.io/api/core/v1" + apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" "k8s.io/klog" @@ -12,7 +13,11 @@ import ( // CreateConfigMap creates the ConfigMap. func (c *Client) CreateConfigMap(ig *corev1.ConfigMap) (*corev1.ConfigMap, error) { - return c.CoreV1().ConfigMaps(ig.GetNamespace()).Create(context.TODO(), ig, metav1.CreateOptions{}) + createdCM, err := c.CoreV1().ConfigMaps(ig.GetNamespace()).Create(context.TODO(), ig, metav1.CreateOptions{}) + if apierrors.IsAlreadyExists(err) { + return c.UpdateConfigMap(ig) + } + return createdCM, err } // GetConfigMap returns the existing ConfigMap. diff --git a/staging/operator-lifecycle-manager/pkg/lib/operatorclient/customresources.go b/staging/operator-lifecycle-manager/pkg/lib/operatorclient/customresources.go index 2d4b7b26a5..0ee0f0eb40 100644 --- a/staging/operator-lifecycle-manager/pkg/lib/operatorclient/customresources.go +++ b/staging/operator-lifecycle-manager/pkg/lib/operatorclient/customresources.go @@ -9,6 +9,7 @@ import ( "time" "k8s.io/apimachinery/pkg/api/errors" + apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/util/wait" @@ -92,7 +93,7 @@ func (c *Client) CreateCustomResourceRaw(apiGroup, version, namespace, kind stri return nil } -// CreateCustomResourceRawIfNotFound creates the raw bytes of the custom resource if it doesn't exist. +// CreateCustomResourceRawIfNotFound creates the raw bytes of the custom resource if it doesn't exist, or Updates if it does exist. // It also returns a boolean to indicate whether a new custom resource is created. func (c *Client) CreateCustomResourceRawIfNotFound(apiGroup, version, namespace, kind, name string, data []byte) (bool, error) { klog.V(4).Infof("[CREATE CUSTOM RESOURCE RAW if not found]: %s:%s", namespace, name) @@ -104,7 +105,11 @@ func (c *Client) CreateCustomResourceRawIfNotFound(apiGroup, version, namespace, return false, err } err = c.CreateCustomResourceRaw(apiGroup, version, namespace, kind, data) - if err != nil { + if apierrors.IsAlreadyExists(err) { + if err = c.UpdateCustomResourceRaw(apiGroup, version, namespace, kind, name, data); err != nil { + return false, err + } + } else if err != nil { return false, err } return true, nil diff --git a/staging/operator-lifecycle-manager/pkg/lib/operatorclient/deployment.go b/staging/operator-lifecycle-manager/pkg/lib/operatorclient/deployment.go index 327826f875..b7e3632d0b 100644 --- a/staging/operator-lifecycle-manager/pkg/lib/operatorclient/deployment.go +++ b/staging/operator-lifecycle-manager/pkg/lib/operatorclient/deployment.go @@ -25,10 +25,15 @@ func (c *Client) GetDeployment(namespace, name string) (*appsv1.Deployment, erro return c.AppsV1().Deployments(namespace).Get(context.TODO(), name, metav1.GetOptions{}) } -// CreateDeployment creates the Deployment object. +// CreateDeployment creates the Deployment object or Updates if it already exists. func (c *Client) CreateDeployment(dep *appsv1.Deployment) (*appsv1.Deployment, error) { klog.V(4).Infof("[CREATE Deployment]: %s:%s", dep.Namespace, dep.Name) - return c.AppsV1().Deployments(dep.Namespace).Create(context.TODO(), dep, metav1.CreateOptions{}) + createdDep, err := c.AppsV1().Deployments(dep.Namespace).Create(context.TODO(), dep, metav1.CreateOptions{}) + if apierrors.IsAlreadyExists(err) { + updatedDep, _, err := c.UpdateDeployment(dep) + return updatedDep, err + } + return createdDep, err } // DeleteDeployment deletes the Deployment object. diff --git a/staging/operator-lifecycle-manager/pkg/lib/operatorclient/operatorclientmocks/mock_client.go b/staging/operator-lifecycle-manager/pkg/lib/operatorclient/operatorclientmocks/mock_client.go index 99ad7bc9df..b82217b8d1 100644 --- a/staging/operator-lifecycle-manager/pkg/lib/operatorclient/operatorclientmocks/mock_client.go +++ b/staging/operator-lifecycle-manager/pkg/lib/operatorclient/operatorclientmocks/mock_client.go @@ -89,6 +89,21 @@ func (mr *MockClientInterfaceMockRecorder) ApplyClusterRoleBinding(applyConfig, return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ApplyClusterRoleBinding", reflect.TypeOf((*MockClientInterface)(nil).ApplyClusterRoleBinding), applyConfig, applyOptions) } +// ApplyRoleBinding mocks base method. +func (m *MockClientInterface) ApplyRoleBinding(applyConfig *v14.RoleBindingApplyConfiguration, applyOptions v12.ApplyOptions) (*v11.RoleBinding, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ApplyRoleBinding", applyConfig, applyOptions) + ret0, _ := ret[0].(*v11.RoleBinding) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ApplyRoleBinding indicates an expected call of ApplyRoleBinding. +func (mr *MockClientInterfaceMockRecorder) ApplyRoleBinding(applyConfig, applyOptions interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ApplyRoleBinding", reflect.TypeOf((*MockClientInterface)(nil).ApplyRoleBinding), applyConfig, applyOptions) +} + // ApplyService mocks base method. func (m *MockClientInterface) ApplyService(arg0 *v13.ServiceApplyConfiguration, arg1 v12.ApplyOptions) (*v10.Service, error) { m.ctrl.T.Helper() @@ -1607,6 +1622,21 @@ func (m *MockRoleBindingClient) EXPECT() *MockRoleBindingClientMockRecorder { return m.recorder } +// ApplyRoleBinding mocks base method. +func (m *MockRoleBindingClient) ApplyRoleBinding(applyConfig *v14.RoleBindingApplyConfiguration, applyOptions v12.ApplyOptions) (*v11.RoleBinding, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ApplyRoleBinding", applyConfig, applyOptions) + ret0, _ := ret[0].(*v11.RoleBinding) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ApplyRoleBinding indicates an expected call of ApplyRoleBinding. +func (mr *MockRoleBindingClientMockRecorder) ApplyRoleBinding(applyConfig, applyOptions interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ApplyRoleBinding", reflect.TypeOf((*MockRoleBindingClient)(nil).ApplyRoleBinding), applyConfig, applyOptions) +} + // CreateRoleBinding mocks base method. func (m *MockRoleBindingClient) CreateRoleBinding(arg0 *v11.RoleBinding) (*v11.RoleBinding, error) { m.ctrl.T.Helper() diff --git a/staging/operator-lifecycle-manager/pkg/lib/operatorclient/role.go b/staging/operator-lifecycle-manager/pkg/lib/operatorclient/role.go index b3cacd95d7..7f6700c4fc 100644 --- a/staging/operator-lifecycle-manager/pkg/lib/operatorclient/role.go +++ b/staging/operator-lifecycle-manager/pkg/lib/operatorclient/role.go @@ -5,14 +5,19 @@ import ( "fmt" 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/types" "k8s.io/klog" ) -// CreateRole creates the role. +// CreateRole creates the role or Updates if it already exists. func (c *Client) CreateRole(r *rbacv1.Role) (*rbacv1.Role, error) { - return c.RbacV1().Roles(r.GetNamespace()).Create(context.TODO(), r, metav1.CreateOptions{}) + createdRole, err := c.RbacV1().Roles(r.GetNamespace()).Create(context.TODO(), r, metav1.CreateOptions{}) + if apierrors.IsAlreadyExists(err) { + return c.UpdateRole(r) + } + return createdRole, err } // GetRole returns the existing role. diff --git a/staging/operator-lifecycle-manager/pkg/lib/operatorclient/rolebinding.go b/staging/operator-lifecycle-manager/pkg/lib/operatorclient/rolebinding.go index 2cfc5434db..8fe41cfe0d 100644 --- a/staging/operator-lifecycle-manager/pkg/lib/operatorclient/rolebinding.go +++ b/staging/operator-lifecycle-manager/pkg/lib/operatorclient/rolebinding.go @@ -5,14 +5,25 @@ import ( "fmt" 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/types" + acv1 "k8s.io/client-go/applyconfigurations/rbac/v1" "k8s.io/klog" ) -// CreateRoleBinding creates the roleBinding. +// ApplyRoleBinding applies the roleBinding. +func (c *Client) ApplyRoleBinding(applyConfig *acv1.RoleBindingApplyConfiguration, applyOptions metav1.ApplyOptions) (*rbacv1.RoleBinding, error) { + return c.RbacV1().RoleBindings(*applyConfig.Namespace).Apply(context.TODO(), applyConfig, applyOptions) +} + +// CreateRoleBinding creates the roleBinding or Updates if it already exists. func (c *Client) CreateRoleBinding(ig *rbacv1.RoleBinding) (*rbacv1.RoleBinding, error) { - return c.RbacV1().RoleBindings(ig.GetNamespace()).Create(context.TODO(), ig, metav1.CreateOptions{}) + createdRB, err := c.RbacV1().RoleBindings(ig.GetNamespace()).Create(context.TODO(), ig, metav1.CreateOptions{}) + if apierrors.IsAlreadyExists(err) { + return c.UpdateRoleBinding(ig) + } + return createdRB, err } // GetRoleBinding returns the existing roleBinding. diff --git a/staging/operator-lifecycle-manager/pkg/lib/operatorclient/secret.go b/staging/operator-lifecycle-manager/pkg/lib/operatorclient/secret.go index 5727a27249..6f74e51035 100644 --- a/staging/operator-lifecycle-manager/pkg/lib/operatorclient/secret.go +++ b/staging/operator-lifecycle-manager/pkg/lib/operatorclient/secret.go @@ -5,14 +5,19 @@ import ( "fmt" v1 "k8s.io/api/core/v1" + apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" "k8s.io/klog" ) -// CreateSecret creates the Secret. +// CreateSecret creates the Secret or Updates if it already exists. func (c *Client) CreateSecret(ig *v1.Secret) (*v1.Secret, error) { - return c.CoreV1().Secrets(ig.GetNamespace()).Create(context.TODO(), ig, metav1.CreateOptions{}) + createdSecret, err := c.CoreV1().Secrets(ig.GetNamespace()).Create(context.TODO(), ig, metav1.CreateOptions{}) + if apierrors.IsAlreadyExists(err) { + return c.UpdateSecret(ig) + } + return createdSecret, err } // GetSecret returns the existing Secret. diff --git a/staging/operator-lifecycle-manager/pkg/lib/operatorclient/service.go b/staging/operator-lifecycle-manager/pkg/lib/operatorclient/service.go index 89c593e67e..63c0800954 100644 --- a/staging/operator-lifecycle-manager/pkg/lib/operatorclient/service.go +++ b/staging/operator-lifecycle-manager/pkg/lib/operatorclient/service.go @@ -5,6 +5,7 @@ import ( "fmt" v1 "k8s.io/api/core/v1" + apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" acv1 "k8s.io/client-go/applyconfigurations/core/v1" @@ -16,9 +17,13 @@ func (c *Client) ApplyService(applyConfig *acv1.ServiceApplyConfiguration, apply return c.CoreV1().Services(*applyConfig.Namespace).Apply(context.TODO(), applyConfig, applyOptions) } -// CreateService creates the Service. +// CreateService creates the Service or Updates if it already exists. func (c *Client) CreateService(ig *v1.Service) (*v1.Service, error) { - return c.CoreV1().Services(ig.GetNamespace()).Create(context.TODO(), ig, metav1.CreateOptions{}) + createdService, err := c.CoreV1().Services(ig.GetNamespace()).Create(context.TODO(), ig, metav1.CreateOptions{}) + if apierrors.IsAlreadyExists(err) { + return c.UpdateService(ig) + } + return createdService, err } // GetService returns the existing Service. diff --git a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/api/wrappers/deployment_install_client.go b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/api/wrappers/deployment_install_client.go index dc3fcd32e0..f2bc748c22 100644 --- a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/api/wrappers/deployment_install_client.go +++ b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/api/wrappers/deployment_install_client.go @@ -58,11 +58,11 @@ func (c *InstallStrategyDeploymentClientForNamespace) GetOpLister() operatorlist } func (c *InstallStrategyDeploymentClientForNamespace) CreateRole(role *rbacv1.Role) (*rbacv1.Role, error) { - return c.opClient.KubernetesInterface().RbacV1().Roles(c.Namespace).Create(context.TODO(), role, metav1.CreateOptions{}) + return c.opClient.CreateRole(role) } func (c *InstallStrategyDeploymentClientForNamespace) CreateRoleBinding(roleBinding *rbacv1.RoleBinding) (*rbacv1.RoleBinding, error) { - return c.opClient.KubernetesInterface().RbacV1().RoleBindings(c.Namespace).Create(context.TODO(), roleBinding, metav1.CreateOptions{}) + return c.opClient.CreateRoleBinding(roleBinding) } func (c *InstallStrategyDeploymentClientForNamespace) EnsureServiceAccount(serviceAccount *corev1.ServiceAccount, owner ownerutil.Owner) (*corev1.ServiceAccount, error) { diff --git a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/bundle/bundle_unpacker.go b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/bundle/bundle_unpacker.go index cfe46187bb..59a86cc44b 100644 --- a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/bundle/bundle_unpacker.go +++ b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/bundle/bundle_unpacker.go @@ -734,6 +734,9 @@ func (c *ConfigMapUnpacker) ensureRole(cmRef *corev1.ObjectReference) (role *rba if err != nil { if apierrors.IsNotFound(err) { role, err = c.client.RbacV1().Roles(fresh.GetNamespace()).Create(context.TODO(), fresh, metav1.CreateOptions{}) + if apierrors.IsAlreadyExists(err) { + role, err = c.client.RbacV1().Roles(fresh.GetNamespace()).Update(context.TODO(), fresh, metav1.UpdateOptions{}) + } } return @@ -778,6 +781,9 @@ func (c *ConfigMapUnpacker) ensureRoleBinding(cmRef *corev1.ObjectReference) (ro if err != nil { if apierrors.IsNotFound(err) { roleBinding, err = c.client.RbacV1().RoleBindings(fresh.GetNamespace()).Create(context.TODO(), fresh, metav1.CreateOptions{}) + if apierrors.IsAlreadyExists(err) { + roleBinding, err = c.client.RbacV1().RoleBindings(fresh.GetNamespace()).Update(context.TODO(), fresh, metav1.UpdateOptions{}) + } } return diff --git a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/install/certresources.go b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/install/certresources.go index 25f4fd3f82..d0dc664cc7 100644 --- a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/install/certresources.go +++ b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/install/certresources.go @@ -463,53 +463,24 @@ func (i *StrategyDeploymentInstaller) installCertRequirementsForDeployment(deplo return nil, nil, err } - // Create RoleBinding to extension-apiserver-authentication-reader Role in the kube-system namespace. - authReaderRoleBinding := &rbacv1.RoleBinding{ - Subjects: []rbacv1.Subject{ - { - Kind: "ServiceAccount", - APIGroup: "", - Name: depSpec.Template.Spec.ServiceAccountName, - Namespace: i.owner.GetNamespace(), - }, - }, - RoleRef: rbacv1.RoleRef{ - APIGroup: "rbac.authorization.k8s.io", - Kind: "Role", - Name: "extension-apiserver-authentication-reader", - }, - } - authReaderRoleBinding.SetName(AuthReaderRoleBindingName(serviceName)) - authReaderRoleBinding.SetNamespace(KubeSystem) - authReaderRoleBinding.SetLabels(map[string]string{OLMManagedLabelKey: OLMManagedLabelValue}) + // Apply RoleBinding to extension-apiserver-authentication-reader Role in the kube-system namespace. + authReaderRoleBindingApplyConfig := rbacv1ac.RoleBinding(AuthReaderRoleBindingName(serviceName), KubeSystem). + WithLabels(map[string]string{OLMManagedLabelKey: OLMManagedLabelValue}). + WithSubjects(rbacv1ac.Subject(). + WithKind("ServiceAccount"). + WithAPIGroup(""). + WithName(depSpec.Template.Spec.ServiceAccountName). + WithNamespace(i.owner.GetNamespace())). + WithRoleRef(rbacv1ac.RoleRef(). + WithAPIGroup("rbac.authorization.k8s.io"). + WithKind("Role"). + WithName("extension-apiserver-authentication-reader")) - existingAuthReaderRoleBinding, err := i.strategyClient.GetOpLister().RbacV1().RoleBindingLister().RoleBindings(KubeSystem).Get(authReaderRoleBinding.GetName()) - if err == nil { - // Check if the only owners are this CSV or in this CSV's replacement chain. - if ownerutil.AdoptableLabels(existingAuthReaderRoleBinding.GetLabels(), true, i.owner) { - logger.WithFields(log.Fields{"obj": "existingAuthReaderRB", "labels": existingAuthReaderRoleBinding.GetLabels()}).Debug("adopting") - if err := ownerutil.AddOwnerLabels(authReaderRoleBinding, i.owner); err != nil { - return nil, nil, err - } - } - // Attempt an update. - if _, err := i.strategyClient.GetOpClient().UpdateRoleBinding(authReaderRoleBinding); err != nil { - logger.Warnf("could not update auth reader role binding %s", authReaderRoleBinding.GetName()) - return nil, nil, err - } - } else if apierrors.IsNotFound(err) { - // Create the role. - if err := ownerutil.AddOwnerLabels(authReaderRoleBinding, i.owner); err != nil { - return nil, nil, err - } - _, err = i.strategyClient.GetOpClient().CreateRoleBinding(authReaderRoleBinding) - if err != nil { - log.Warnf("could not create auth reader role binding %s", authReaderRoleBinding.GetName()) - return nil, nil, err - } - } else { + if _, err = i.strategyClient.GetOpClient().ApplyRoleBinding(authReaderRoleBindingApplyConfig, metav1.ApplyOptions{Force: true, FieldManager: "olm.install"}); err != nil { + log.Errorf("could not apply auth reader rolebinding %s: %s", *authReaderRoleBindingApplyConfig.Name, err.Error()) return nil, nil, err } + AddDefaultCertVolumeAndVolumeMounts(&depSpec, secret.GetName()) // Setting the olm hash label forces a rollout and ensures that the new secret diff --git a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/olm/operatorgroup.go b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/olm/operatorgroup.go index 3594c544f4..73a52caa9d 100644 --- a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/olm/operatorgroup.go +++ b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/olm/operatorgroup.go @@ -408,11 +408,8 @@ func (a *Operator) ensureProvidedAPIClusterRole(namePrefix, suffix string, verbs return err } if apierrors.IsNotFound(err) { - existingCR, err = a.opClient.KubernetesInterface().RbacV1().ClusterRoles().Create(context.TODO(), clusterRole, metav1.CreateOptions{}) - if err == nil { - return nil - } - if !apierrors.IsAlreadyExists(err) { + existingCR, err = a.opClient.CreateClusterRole(clusterRole) + if err != nil { a.logger.WithError(err).Errorf("Create cluster role failed: %v", clusterRole) return err } @@ -546,12 +543,7 @@ func (a *Operator) ensureSingletonRBAC(operatorNamespace string, csv *v1alpha1.C Resources: []string{"namespaces"}, }), } - // TODO: this should do something smarter if the cluster role already exists - if cr, err := a.opClient.CreateClusterRole(clusterRole); err != nil { - // If the CR already exists, but the label is correct, the cache is just behind - if apierrors.IsAlreadyExists(err) && cr != nil && ownerutil.IsOwnedByLabel(cr, csv) { - continue - } + if _, err := a.opClient.CreateClusterRole(clusterRole); err != nil { return err } a.logger.Debug("created cluster role") @@ -585,12 +577,7 @@ func (a *Operator) ensureSingletonRBAC(operatorNamespace string, csv *v1alpha1.C Name: r.RoleRef.Name, }, } - // TODO: this should do something smarter if the cluster role binding already exists - if crb, err := a.opClient.CreateClusterRoleBinding(clusterRoleBinding); err != nil { - // If the CRB already exists, but the label is correct, the cache is just behind - if apierrors.IsAlreadyExists(err) && crb != nil && ownerutil.IsOwnedByLabel(crb, csv) { - continue - } + if _, err := a.opClient.CreateClusterRoleBinding(clusterRoleBinding); err != nil { return err } } @@ -1056,7 +1043,7 @@ func (a *Operator) ensureOpGroupClusterRole(op *operatorsv1.OperatorGroup, suffi clusterRole.Labels[install.OLMManagedLabelKey] = install.OLMManagedLabelValue a.logger.Infof("creating cluster role: %s owned by operator group: %s/%s", clusterRole.GetName(), op.GetNamespace(), op.GetName()) - _, err = a.opClient.KubernetesInterface().RbacV1().ClusterRoles().Create(context.TODO(), clusterRole, metav1.CreateOptions{}) + _, err = a.opClient.CreateClusterRole(clusterRole) return err } diff --git a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/operatorcondition_controller.go b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/operatorcondition_controller.go index c805977c01..ab462fee37 100644 --- a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/operatorcondition_controller.go +++ b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/operatorcondition_controller.go @@ -150,7 +150,10 @@ func (r *OperatorConditionReconciler) ensureOperatorConditionRole(operatorCondit if !apierrors.IsNotFound(err) { return err } - return r.Client.Create(context.TODO(), role) + err = r.Client.Create(context.TODO(), role) + if apierrors.IsAlreadyExists(err) { + return r.Client.Update(context.TODO(), role) + } } if ownerutil.IsOwnedBy(existingRole, operatorCondition) && @@ -199,7 +202,10 @@ func (r *OperatorConditionReconciler) ensureOperatorConditionRoleBinding(operato if !apierrors.IsNotFound(err) { return err } - return r.Client.Create(context.TODO(), roleBinding) + err = r.Client.Create(context.TODO(), roleBinding) + if apierrors.IsAlreadyExists(err) { + return r.Client.Update(context.TODO(), roleBinding) + } } if ownerutil.IsOwnedBy(existingRoleBinding, operatorCondition) && diff --git a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/lib/operatorclient/apiservice.go b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/lib/operatorclient/apiservice.go index 2267a85ad8..ceea0e18a7 100644 --- a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/lib/operatorclient/apiservice.go +++ b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/lib/operatorclient/apiservice.go @@ -4,15 +4,20 @@ import ( "context" "fmt" + apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" "k8s.io/klog" apiregistrationv1 "k8s.io/kube-aggregator/pkg/apis/apiregistration/v1" ) -// CreateAPIService creates the APIService. +// CreateAPIService creates the APIService or Updates if it already exists. func (c *Client) CreateAPIService(ig *apiregistrationv1.APIService) (*apiregistrationv1.APIService, error) { - return c.ApiregistrationV1Interface().ApiregistrationV1().APIServices().Create(context.TODO(), ig, metav1.CreateOptions{}) + createdAS, err := c.ApiregistrationV1Interface().ApiregistrationV1().APIServices().Create(context.TODO(), ig, metav1.CreateOptions{}) + if apierrors.IsAlreadyExists(err) { + return c.UpdateAPIService(ig) + } + return createdAS, err } // GetAPIService returns the existing APIService. diff --git a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/lib/operatorclient/client.go b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/lib/operatorclient/client.go index a7c27ae07b..cc89369fb7 100644 --- a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/lib/operatorclient/client.go +++ b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/lib/operatorclient/client.go @@ -94,6 +94,7 @@ type RoleClient interface { // RoleBindingClient contains methods for manipulating RoleBindings. type RoleBindingClient interface { + ApplyRoleBinding(applyConfig *rbacv1ac.RoleBindingApplyConfiguration, applyOptions metav1.ApplyOptions) (*rbacv1.RoleBinding, error) CreateRoleBinding(*rbacv1.RoleBinding) (*rbacv1.RoleBinding, error) GetRoleBinding(namespace, name string) (*rbacv1.RoleBinding, error) UpdateRoleBinding(modified *rbacv1.RoleBinding) (*rbacv1.RoleBinding, error) diff --git a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/lib/operatorclient/clusterrole.go b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/lib/operatorclient/clusterrole.go index 58db0fc795..e9060994d5 100644 --- a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/lib/operatorclient/clusterrole.go +++ b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/lib/operatorclient/clusterrole.go @@ -5,14 +5,19 @@ import ( "fmt" 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/types" "k8s.io/klog" ) -// CreateClusterRole creates the ClusterRole. +// CreateClusterRole creates the ClusterRole or Updates if it already exists. func (c *Client) CreateClusterRole(r *rbacv1.ClusterRole) (*rbacv1.ClusterRole, error) { - return c.RbacV1().ClusterRoles().Create(context.TODO(), r, metav1.CreateOptions{}) + createdClusterRole, err := c.RbacV1().ClusterRoles().Create(context.TODO(), r, metav1.CreateOptions{}) + if apierrors.IsAlreadyExists(err) { + return c.UpdateClusterRole(r) + } + return createdClusterRole, err } // GetClusterRole returns the existing ClusterRole. diff --git a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/lib/operatorclient/clusterrolebinding.go b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/lib/operatorclient/clusterrolebinding.go index 0ab429accc..24cc3177c9 100644 --- a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/lib/operatorclient/clusterrolebinding.go +++ b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/lib/operatorclient/clusterrolebinding.go @@ -5,6 +5,7 @@ import ( "fmt" 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/types" acv1 "k8s.io/client-go/applyconfigurations/rbac/v1" @@ -16,9 +17,13 @@ func (c *Client) ApplyClusterRoleBinding(applyConfig *acv1.ClusterRoleBindingApp return c.RbacV1().ClusterRoleBindings().Apply(context.TODO(), applyConfig, applyOptions) } -// CreateRoleBinding creates the roleBinding. +// CreateRoleBinding creates the roleBinding or Updates if it already exists. func (c *Client) CreateClusterRoleBinding(ig *rbacv1.ClusterRoleBinding) (*rbacv1.ClusterRoleBinding, error) { - return c.RbacV1().ClusterRoleBindings().Create(context.TODO(), ig, metav1.CreateOptions{}) + createdCRB, err := c.RbacV1().ClusterRoleBindings().Create(context.TODO(), ig, metav1.CreateOptions{}) + if apierrors.IsAlreadyExists(err) { + return c.UpdateClusterRoleBinding(ig) + } + return createdCRB, err } // GetRoleBinding returns the existing roleBinding. diff --git a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/lib/operatorclient/configmap.go b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/lib/operatorclient/configmap.go index 0ac2e7c013..44565fe6a4 100644 --- a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/lib/operatorclient/configmap.go +++ b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/lib/operatorclient/configmap.go @@ -5,6 +5,7 @@ import ( "fmt" corev1 "k8s.io/api/core/v1" + apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" "k8s.io/klog" @@ -12,7 +13,11 @@ import ( // CreateConfigMap creates the ConfigMap. func (c *Client) CreateConfigMap(ig *corev1.ConfigMap) (*corev1.ConfigMap, error) { - return c.CoreV1().ConfigMaps(ig.GetNamespace()).Create(context.TODO(), ig, metav1.CreateOptions{}) + createdCM, err := c.CoreV1().ConfigMaps(ig.GetNamespace()).Create(context.TODO(), ig, metav1.CreateOptions{}) + if apierrors.IsAlreadyExists(err) { + return c.UpdateConfigMap(ig) + } + return createdCM, err } // GetConfigMap returns the existing ConfigMap. diff --git a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/lib/operatorclient/customresources.go b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/lib/operatorclient/customresources.go index 2d4b7b26a5..0ee0f0eb40 100644 --- a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/lib/operatorclient/customresources.go +++ b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/lib/operatorclient/customresources.go @@ -9,6 +9,7 @@ import ( "time" "k8s.io/apimachinery/pkg/api/errors" + apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/util/wait" @@ -92,7 +93,7 @@ func (c *Client) CreateCustomResourceRaw(apiGroup, version, namespace, kind stri return nil } -// CreateCustomResourceRawIfNotFound creates the raw bytes of the custom resource if it doesn't exist. +// CreateCustomResourceRawIfNotFound creates the raw bytes of the custom resource if it doesn't exist, or Updates if it does exist. // It also returns a boolean to indicate whether a new custom resource is created. func (c *Client) CreateCustomResourceRawIfNotFound(apiGroup, version, namespace, kind, name string, data []byte) (bool, error) { klog.V(4).Infof("[CREATE CUSTOM RESOURCE RAW if not found]: %s:%s", namespace, name) @@ -104,7 +105,11 @@ func (c *Client) CreateCustomResourceRawIfNotFound(apiGroup, version, namespace, return false, err } err = c.CreateCustomResourceRaw(apiGroup, version, namespace, kind, data) - if err != nil { + if apierrors.IsAlreadyExists(err) { + if err = c.UpdateCustomResourceRaw(apiGroup, version, namespace, kind, name, data); err != nil { + return false, err + } + } else if err != nil { return false, err } return true, nil diff --git a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/lib/operatorclient/deployment.go b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/lib/operatorclient/deployment.go index 327826f875..b7e3632d0b 100644 --- a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/lib/operatorclient/deployment.go +++ b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/lib/operatorclient/deployment.go @@ -25,10 +25,15 @@ func (c *Client) GetDeployment(namespace, name string) (*appsv1.Deployment, erro return c.AppsV1().Deployments(namespace).Get(context.TODO(), name, metav1.GetOptions{}) } -// CreateDeployment creates the Deployment object. +// CreateDeployment creates the Deployment object or Updates if it already exists. func (c *Client) CreateDeployment(dep *appsv1.Deployment) (*appsv1.Deployment, error) { klog.V(4).Infof("[CREATE Deployment]: %s:%s", dep.Namespace, dep.Name) - return c.AppsV1().Deployments(dep.Namespace).Create(context.TODO(), dep, metav1.CreateOptions{}) + createdDep, err := c.AppsV1().Deployments(dep.Namespace).Create(context.TODO(), dep, metav1.CreateOptions{}) + if apierrors.IsAlreadyExists(err) { + updatedDep, _, err := c.UpdateDeployment(dep) + return updatedDep, err + } + return createdDep, err } // DeleteDeployment deletes the Deployment object. diff --git a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/lib/operatorclient/role.go b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/lib/operatorclient/role.go index b3cacd95d7..7f6700c4fc 100644 --- a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/lib/operatorclient/role.go +++ b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/lib/operatorclient/role.go @@ -5,14 +5,19 @@ import ( "fmt" 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/types" "k8s.io/klog" ) -// CreateRole creates the role. +// CreateRole creates the role or Updates if it already exists. func (c *Client) CreateRole(r *rbacv1.Role) (*rbacv1.Role, error) { - return c.RbacV1().Roles(r.GetNamespace()).Create(context.TODO(), r, metav1.CreateOptions{}) + createdRole, err := c.RbacV1().Roles(r.GetNamespace()).Create(context.TODO(), r, metav1.CreateOptions{}) + if apierrors.IsAlreadyExists(err) { + return c.UpdateRole(r) + } + return createdRole, err } // GetRole returns the existing role. diff --git a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/lib/operatorclient/rolebinding.go b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/lib/operatorclient/rolebinding.go index 2cfc5434db..8fe41cfe0d 100644 --- a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/lib/operatorclient/rolebinding.go +++ b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/lib/operatorclient/rolebinding.go @@ -5,14 +5,25 @@ import ( "fmt" 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/types" + acv1 "k8s.io/client-go/applyconfigurations/rbac/v1" "k8s.io/klog" ) -// CreateRoleBinding creates the roleBinding. +// ApplyRoleBinding applies the roleBinding. +func (c *Client) ApplyRoleBinding(applyConfig *acv1.RoleBindingApplyConfiguration, applyOptions metav1.ApplyOptions) (*rbacv1.RoleBinding, error) { + return c.RbacV1().RoleBindings(*applyConfig.Namespace).Apply(context.TODO(), applyConfig, applyOptions) +} + +// CreateRoleBinding creates the roleBinding or Updates if it already exists. func (c *Client) CreateRoleBinding(ig *rbacv1.RoleBinding) (*rbacv1.RoleBinding, error) { - return c.RbacV1().RoleBindings(ig.GetNamespace()).Create(context.TODO(), ig, metav1.CreateOptions{}) + createdRB, err := c.RbacV1().RoleBindings(ig.GetNamespace()).Create(context.TODO(), ig, metav1.CreateOptions{}) + if apierrors.IsAlreadyExists(err) { + return c.UpdateRoleBinding(ig) + } + return createdRB, err } // GetRoleBinding returns the existing roleBinding. diff --git a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/lib/operatorclient/secret.go b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/lib/operatorclient/secret.go index 5727a27249..6f74e51035 100644 --- a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/lib/operatorclient/secret.go +++ b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/lib/operatorclient/secret.go @@ -5,14 +5,19 @@ import ( "fmt" v1 "k8s.io/api/core/v1" + apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" "k8s.io/klog" ) -// CreateSecret creates the Secret. +// CreateSecret creates the Secret or Updates if it already exists. func (c *Client) CreateSecret(ig *v1.Secret) (*v1.Secret, error) { - return c.CoreV1().Secrets(ig.GetNamespace()).Create(context.TODO(), ig, metav1.CreateOptions{}) + createdSecret, err := c.CoreV1().Secrets(ig.GetNamespace()).Create(context.TODO(), ig, metav1.CreateOptions{}) + if apierrors.IsAlreadyExists(err) { + return c.UpdateSecret(ig) + } + return createdSecret, err } // GetSecret returns the existing Secret. diff --git a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/lib/operatorclient/service.go b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/lib/operatorclient/service.go index 89c593e67e..63c0800954 100644 --- a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/lib/operatorclient/service.go +++ b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/lib/operatorclient/service.go @@ -5,6 +5,7 @@ import ( "fmt" v1 "k8s.io/api/core/v1" + apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" acv1 "k8s.io/client-go/applyconfigurations/core/v1" @@ -16,9 +17,13 @@ func (c *Client) ApplyService(applyConfig *acv1.ServiceApplyConfiguration, apply return c.CoreV1().Services(*applyConfig.Namespace).Apply(context.TODO(), applyConfig, applyOptions) } -// CreateService creates the Service. +// CreateService creates the Service or Updates if it already exists. func (c *Client) CreateService(ig *v1.Service) (*v1.Service, error) { - return c.CoreV1().Services(ig.GetNamespace()).Create(context.TODO(), ig, metav1.CreateOptions{}) + createdService, err := c.CoreV1().Services(ig.GetNamespace()).Create(context.TODO(), ig, metav1.CreateOptions{}) + if apierrors.IsAlreadyExists(err) { + return c.UpdateService(ig) + } + return createdService, err } // GetService returns the existing Service.