Skip to content

Commit 9b1be42

Browse files
committed
Update if AlreadyExists
Adds code to the client calls for Create to run an Update if the object already exists. This allows us to bypass issues where the object was not found in cache but already exists in the cluster. Signed-off-by: Daniel Franz <[email protected]>
1 parent be20100 commit 9b1be42

14 files changed

+90
-41
lines changed

Diff for: pkg/api/wrappers/deployment_install_client.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -58,11 +58,11 @@ func (c *InstallStrategyDeploymentClientForNamespace) GetOpLister() operatorlist
5858
}
5959

6060
func (c *InstallStrategyDeploymentClientForNamespace) CreateRole(role *rbacv1.Role) (*rbacv1.Role, error) {
61-
return c.opClient.KubernetesInterface().RbacV1().Roles(c.Namespace).Create(context.TODO(), role, metav1.CreateOptions{})
61+
return c.opClient.CreateRole(role)
6262
}
6363

6464
func (c *InstallStrategyDeploymentClientForNamespace) CreateRoleBinding(roleBinding *rbacv1.RoleBinding) (*rbacv1.RoleBinding, error) {
65-
return c.opClient.KubernetesInterface().RbacV1().RoleBindings(c.Namespace).Create(context.TODO(), roleBinding, metav1.CreateOptions{})
65+
return c.opClient.CreateRoleBinding(roleBinding)
6666
}
6767

6868
func (c *InstallStrategyDeploymentClientForNamespace) EnsureServiceAccount(serviceAccount *corev1.ServiceAccount, owner ownerutil.Owner) (*corev1.ServiceAccount, error) {

Diff for: pkg/controller/bundle/bundle_unpacker.go

+6
Original file line numberDiff line numberDiff line change
@@ -734,6 +734,9 @@ func (c *ConfigMapUnpacker) ensureRole(cmRef *corev1.ObjectReference) (role *rba
734734
if err != nil {
735735
if apierrors.IsNotFound(err) {
736736
role, err = c.client.RbacV1().Roles(fresh.GetNamespace()).Create(context.TODO(), fresh, metav1.CreateOptions{})
737+
if apierrors.IsAlreadyExists(err) {
738+
role, err = c.client.RbacV1().Roles(fresh.GetNamespace()).Update(context.TODO(), fresh, metav1.UpdateOptions{})
739+
}
737740
}
738741

739742
return
@@ -778,6 +781,9 @@ func (c *ConfigMapUnpacker) ensureRoleBinding(cmRef *corev1.ObjectReference) (ro
778781
if err != nil {
779782
if apierrors.IsNotFound(err) {
780783
roleBinding, err = c.client.RbacV1().RoleBindings(fresh.GetNamespace()).Create(context.TODO(), fresh, metav1.CreateOptions{})
784+
if apierrors.IsAlreadyExists(err) {
785+
roleBinding, err = c.client.RbacV1().RoleBindings(fresh.GetNamespace()).Update(context.TODO(), fresh, metav1.UpdateOptions{})
786+
}
781787
}
782788

783789
return

Diff for: pkg/controller/operators/olm/operatorgroup.go

+5-18
Original file line numberDiff line numberDiff line change
@@ -408,11 +408,8 @@ func (a *Operator) ensureProvidedAPIClusterRole(namePrefix, suffix string, verbs
408408
return err
409409
}
410410
if apierrors.IsNotFound(err) {
411-
existingCR, err = a.opClient.KubernetesInterface().RbacV1().ClusterRoles().Create(context.TODO(), clusterRole, metav1.CreateOptions{})
412-
if err == nil {
413-
return nil
414-
}
415-
if !apierrors.IsAlreadyExists(err) {
411+
existingCR, err = a.opClient.CreateClusterRole(clusterRole)
412+
if err != nil {
416413
a.logger.WithError(err).Errorf("Create cluster role failed: %v", clusterRole)
417414
return err
418415
}
@@ -546,12 +543,7 @@ func (a *Operator) ensureSingletonRBAC(operatorNamespace string, csv *v1alpha1.C
546543
Resources: []string{"namespaces"},
547544
}),
548545
}
549-
// TODO: this should do something smarter if the cluster role already exists
550-
if cr, err := a.opClient.CreateClusterRole(clusterRole); err != nil {
551-
// If the CR already exists, but the label is correct, the cache is just behind
552-
if apierrors.IsAlreadyExists(err) && cr != nil && ownerutil.IsOwnedByLabel(cr, csv) {
553-
continue
554-
}
546+
if _, err := a.opClient.CreateClusterRole(clusterRole); err != nil {
555547
return err
556548
}
557549
a.logger.Debug("created cluster role")
@@ -585,12 +577,7 @@ func (a *Operator) ensureSingletonRBAC(operatorNamespace string, csv *v1alpha1.C
585577
Name: r.RoleRef.Name,
586578
},
587579
}
588-
// TODO: this should do something smarter if the cluster role binding already exists
589-
if crb, err := a.opClient.CreateClusterRoleBinding(clusterRoleBinding); err != nil {
590-
// If the CRB already exists, but the label is correct, the cache is just behind
591-
if apierrors.IsAlreadyExists(err) && crb != nil && ownerutil.IsOwnedByLabel(crb, csv) {
592-
continue
593-
}
580+
if _, err := a.opClient.CreateClusterRoleBinding(clusterRoleBinding); err != nil {
594581
return err
595582
}
596583
}
@@ -1056,7 +1043,7 @@ func (a *Operator) ensureOpGroupClusterRole(op *operatorsv1.OperatorGroup, suffi
10561043
clusterRole.Labels[install.OLMManagedLabelKey] = install.OLMManagedLabelValue
10571044

10581045
a.logger.Infof("creating cluster role: %s owned by operator group: %s/%s", clusterRole.GetName(), op.GetNamespace(), op.GetName())
1059-
_, err = a.opClient.KubernetesInterface().RbacV1().ClusterRoles().Create(context.TODO(), clusterRole, metav1.CreateOptions{})
1046+
_, err = a.opClient.CreateClusterRole(clusterRole)
10601047
return err
10611048
}
10621049

Diff for: pkg/controller/operators/operatorcondition_controller.go

+8-2
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,10 @@ func (r *OperatorConditionReconciler) ensureOperatorConditionRole(operatorCondit
150150
if !apierrors.IsNotFound(err) {
151151
return err
152152
}
153-
return r.Client.Create(context.TODO(), role)
153+
err = r.Client.Create(context.TODO(), role)
154+
if apierrors.IsAlreadyExists(err) {
155+
return r.Client.Update(context.TODO(), role)
156+
}
154157
}
155158

156159
if ownerutil.IsOwnedBy(existingRole, operatorCondition) &&
@@ -199,7 +202,10 @@ func (r *OperatorConditionReconciler) ensureOperatorConditionRoleBinding(operato
199202
if !apierrors.IsNotFound(err) {
200203
return err
201204
}
202-
return r.Client.Create(context.TODO(), roleBinding)
205+
err = r.Client.Create(context.TODO(), roleBinding)
206+
if apierrors.IsAlreadyExists(err) {
207+
return r.Client.Update(context.TODO(), roleBinding)
208+
}
203209
}
204210

205211
if ownerutil.IsOwnedBy(existingRoleBinding, operatorCondition) &&

Diff for: pkg/lib/operatorclient/apiservice.go

+7-2
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,20 @@ import (
44
"context"
55
"fmt"
66

7+
apierrors "k8s.io/apimachinery/pkg/api/errors"
78
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
89
"k8s.io/apimachinery/pkg/types"
910
"k8s.io/klog"
1011
apiregistrationv1 "k8s.io/kube-aggregator/pkg/apis/apiregistration/v1"
1112
)
1213

13-
// CreateAPIService creates the APIService.
14+
// CreateAPIService creates the APIService or Updates if it already exists.
1415
func (c *Client) CreateAPIService(ig *apiregistrationv1.APIService) (*apiregistrationv1.APIService, error) {
15-
return c.ApiregistrationV1Interface().ApiregistrationV1().APIServices().Create(context.TODO(), ig, metav1.CreateOptions{})
16+
createdAS, err := c.ApiregistrationV1Interface().ApiregistrationV1().APIServices().Create(context.TODO(), ig, metav1.CreateOptions{})
17+
if apierrors.IsAlreadyExists(err) {
18+
return c.UpdateAPIService(ig)
19+
}
20+
return createdAS, err
1621
}
1722

1823
// GetAPIService returns the existing APIService.

Diff for: pkg/lib/operatorclient/clusterrole.go

+7-2
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,19 @@ import (
55
"fmt"
66

77
rbacv1 "k8s.io/api/rbac/v1"
8+
apierrors "k8s.io/apimachinery/pkg/api/errors"
89
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
910
"k8s.io/apimachinery/pkg/types"
1011
"k8s.io/klog"
1112
)
1213

13-
// CreateClusterRole creates the ClusterRole.
14+
// CreateClusterRole creates the ClusterRole or Updates if it already exists.
1415
func (c *Client) CreateClusterRole(r *rbacv1.ClusterRole) (*rbacv1.ClusterRole, error) {
15-
return c.RbacV1().ClusterRoles().Create(context.TODO(), r, metav1.CreateOptions{})
16+
createdClusterRole, err := c.RbacV1().ClusterRoles().Create(context.TODO(), r, metav1.CreateOptions{})
17+
if apierrors.IsAlreadyExists(err) {
18+
return c.UpdateClusterRole(r)
19+
}
20+
return createdClusterRole, err
1621
}
1722

1823
// GetClusterRole returns the existing ClusterRole.

Diff for: pkg/lib/operatorclient/clusterrolebinding.go

+7-2
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"fmt"
66

77
rbacv1 "k8s.io/api/rbac/v1"
8+
apierrors "k8s.io/apimachinery/pkg/api/errors"
89
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
910
"k8s.io/apimachinery/pkg/types"
1011
acv1 "k8s.io/client-go/applyconfigurations/rbac/v1"
@@ -16,9 +17,13 @@ func (c *Client) ApplyClusterRoleBinding(applyConfig *acv1.ClusterRoleBindingApp
1617
return c.RbacV1().ClusterRoleBindings().Apply(context.TODO(), applyConfig, applyOptions)
1718
}
1819

19-
// CreateRoleBinding creates the roleBinding.
20+
// CreateRoleBinding creates the roleBinding or Updates if it already exists.
2021
func (c *Client) CreateClusterRoleBinding(ig *rbacv1.ClusterRoleBinding) (*rbacv1.ClusterRoleBinding, error) {
21-
return c.RbacV1().ClusterRoleBindings().Create(context.TODO(), ig, metav1.CreateOptions{})
22+
createdCRB, err := c.RbacV1().ClusterRoleBindings().Create(context.TODO(), ig, metav1.CreateOptions{})
23+
if apierrors.IsAlreadyExists(err) {
24+
return c.UpdateClusterRoleBinding(ig)
25+
}
26+
return createdCRB, err
2227
}
2328

2429
// GetRoleBinding returns the existing roleBinding.

Diff for: pkg/lib/operatorclient/configmap.go

+6-1
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,19 @@ import (
55
"fmt"
66

77
corev1 "k8s.io/api/core/v1"
8+
apierrors "k8s.io/apimachinery/pkg/api/errors"
89
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
910
"k8s.io/apimachinery/pkg/types"
1011
"k8s.io/klog"
1112
)
1213

1314
// CreateConfigMap creates the ConfigMap.
1415
func (c *Client) CreateConfigMap(ig *corev1.ConfigMap) (*corev1.ConfigMap, error) {
15-
return c.CoreV1().ConfigMaps(ig.GetNamespace()).Create(context.TODO(), ig, metav1.CreateOptions{})
16+
createdCM, err := c.CoreV1().ConfigMaps(ig.GetNamespace()).Create(context.TODO(), ig, metav1.CreateOptions{})
17+
if apierrors.IsAlreadyExists(err) {
18+
return c.UpdateConfigMap(ig)
19+
}
20+
return createdCM, err
1621
}
1722

1823
// GetConfigMap returns the existing ConfigMap.

Diff for: pkg/lib/operatorclient/customresources.go

+7-2
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"time"
1010

1111
"k8s.io/apimachinery/pkg/api/errors"
12+
apierrors "k8s.io/apimachinery/pkg/api/errors"
1213
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
1314
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
1415
"k8s.io/apimachinery/pkg/util/wait"
@@ -92,7 +93,7 @@ func (c *Client) CreateCustomResourceRaw(apiGroup, version, namespace, kind stri
9293
return nil
9394
}
9495

95-
// CreateCustomResourceRawIfNotFound creates the raw bytes of the custom resource if it doesn't exist.
96+
// CreateCustomResourceRawIfNotFound creates the raw bytes of the custom resource if it doesn't exist, or Updates if it does exist.
9697
// It also returns a boolean to indicate whether a new custom resource is created.
9798
func (c *Client) CreateCustomResourceRawIfNotFound(apiGroup, version, namespace, kind, name string, data []byte) (bool, error) {
9899
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,
104105
return false, err
105106
}
106107
err = c.CreateCustomResourceRaw(apiGroup, version, namespace, kind, data)
107-
if err != nil {
108+
if apierrors.IsAlreadyExists(err) {
109+
if err = c.UpdateCustomResourceRaw(apiGroup, version, namespace, kind, name, data); err != nil {
110+
return false, err
111+
}
112+
} else if err != nil {
108113
return false, err
109114
}
110115
return true, nil

Diff for: pkg/lib/operatorclient/deployment.go

+7-2
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,15 @@ func (c *Client) GetDeployment(namespace, name string) (*appsv1.Deployment, erro
2525
return c.AppsV1().Deployments(namespace).Get(context.TODO(), name, metav1.GetOptions{})
2626
}
2727

28-
// CreateDeployment creates the Deployment object.
28+
// CreateDeployment creates the Deployment object or Updates if it already exists.
2929
func (c *Client) CreateDeployment(dep *appsv1.Deployment) (*appsv1.Deployment, error) {
3030
klog.V(4).Infof("[CREATE Deployment]: %s:%s", dep.Namespace, dep.Name)
31-
return c.AppsV1().Deployments(dep.Namespace).Create(context.TODO(), dep, metav1.CreateOptions{})
31+
createdDep, err := c.AppsV1().Deployments(dep.Namespace).Create(context.TODO(), dep, metav1.CreateOptions{})
32+
if apierrors.IsAlreadyExists(err) {
33+
updatedDep, _, err := c.UpdateDeployment(dep)
34+
return updatedDep, err
35+
}
36+
return createdDep, err
3237
}
3338

3439
// DeleteDeployment deletes the Deployment object.

Diff for: pkg/lib/operatorclient/role.go

+7-2
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,19 @@ import (
55
"fmt"
66

77
rbacv1 "k8s.io/api/rbac/v1"
8+
apierrors "k8s.io/apimachinery/pkg/api/errors"
89
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
910
"k8s.io/apimachinery/pkg/types"
1011
"k8s.io/klog"
1112
)
1213

13-
// CreateRole creates the role.
14+
// CreateRole creates the role or Updates if it already exists.
1415
func (c *Client) CreateRole(r *rbacv1.Role) (*rbacv1.Role, error) {
15-
return c.RbacV1().Roles(r.GetNamespace()).Create(context.TODO(), r, metav1.CreateOptions{})
16+
createdRole, err := c.RbacV1().Roles(r.GetNamespace()).Create(context.TODO(), r, metav1.CreateOptions{})
17+
if apierrors.IsAlreadyExists(err) {
18+
return c.UpdateRole(r)
19+
}
20+
return createdRole, err
1621
}
1722

1823
// GetRole returns the existing role.

Diff for: pkg/lib/operatorclient/rolebinding.go

+7-2
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"fmt"
66

77
rbacv1 "k8s.io/api/rbac/v1"
8+
apierrors "k8s.io/apimachinery/pkg/api/errors"
89
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
910
"k8s.io/apimachinery/pkg/types"
1011
acv1 "k8s.io/client-go/applyconfigurations/rbac/v1"
@@ -16,9 +17,13 @@ func (c *Client) ApplyRoleBinding(applyConfig *acv1.RoleBindingApplyConfiguratio
1617
return c.RbacV1().RoleBindings(*applyConfig.Namespace).Apply(context.TODO(), applyConfig, applyOptions)
1718
}
1819

19-
// CreateRoleBinding creates the roleBinding.
20+
// CreateRoleBinding creates the roleBinding or Updates if it already exists.
2021
func (c *Client) CreateRoleBinding(ig *rbacv1.RoleBinding) (*rbacv1.RoleBinding, error) {
21-
return c.RbacV1().RoleBindings(ig.GetNamespace()).Create(context.TODO(), ig, metav1.CreateOptions{})
22+
createdRB, err := c.RbacV1().RoleBindings(ig.GetNamespace()).Create(context.TODO(), ig, metav1.CreateOptions{})
23+
if apierrors.IsAlreadyExists(err) {
24+
return c.UpdateRoleBinding(ig)
25+
}
26+
return createdRB, err
2227
}
2328

2429
// GetRoleBinding returns the existing roleBinding.

Diff for: pkg/lib/operatorclient/secret.go

+7-2
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,19 @@ import (
55
"fmt"
66

77
v1 "k8s.io/api/core/v1"
8+
apierrors "k8s.io/apimachinery/pkg/api/errors"
89
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
910
"k8s.io/apimachinery/pkg/types"
1011
"k8s.io/klog"
1112
)
1213

13-
// CreateSecret creates the Secret.
14+
// CreateSecret creates the Secret or Updates if it already exists.
1415
func (c *Client) CreateSecret(ig *v1.Secret) (*v1.Secret, error) {
15-
return c.CoreV1().Secrets(ig.GetNamespace()).Create(context.TODO(), ig, metav1.CreateOptions{})
16+
createdSecret, err := c.CoreV1().Secrets(ig.GetNamespace()).Create(context.TODO(), ig, metav1.CreateOptions{})
17+
if apierrors.IsAlreadyExists(err) {
18+
return c.UpdateSecret(ig)
19+
}
20+
return createdSecret, err
1621
}
1722

1823
// GetSecret returns the existing Secret.

Diff for: pkg/lib/operatorclient/service.go

+7-2
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"fmt"
66

77
v1 "k8s.io/api/core/v1"
8+
apierrors "k8s.io/apimachinery/pkg/api/errors"
89
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
910
"k8s.io/apimachinery/pkg/types"
1011
acv1 "k8s.io/client-go/applyconfigurations/core/v1"
@@ -16,9 +17,13 @@ func (c *Client) ApplyService(applyConfig *acv1.ServiceApplyConfiguration, apply
1617
return c.CoreV1().Services(*applyConfig.Namespace).Apply(context.TODO(), applyConfig, applyOptions)
1718
}
1819

19-
// CreateService creates the Service.
20+
// CreateService creates the Service or Updates if it already exists.
2021
func (c *Client) CreateService(ig *v1.Service) (*v1.Service, error) {
21-
return c.CoreV1().Services(ig.GetNamespace()).Create(context.TODO(), ig, metav1.CreateOptions{})
22+
createdService, err := c.CoreV1().Services(ig.GetNamespace()).Create(context.TODO(), ig, metav1.CreateOptions{})
23+
if apierrors.IsAlreadyExists(err) {
24+
return c.UpdateService(ig)
25+
}
26+
return createdService, err
2227
}
2328

2429
// GetService returns the existing Service.

0 commit comments

Comments
 (0)