Skip to content

Commit 597d792

Browse files
mclasmeierMoritz Clasmeier
andauthored
More robust OLM deployment check (#133)
Co-authored-by: Moritz Clasmeier <mclasmeier@redhat.com>
1 parent 9729433 commit 597d792

4 files changed

Lines changed: 58 additions & 23 deletions

File tree

internal/deployer/deploy_via_operator.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,10 @@ func (d *Deployer) ensureOperatorDeployed(ctx context.Context) error {
5555
}
5656

5757
// Detect current operator deployment mode
58-
operatorExists, currentMode := d.detectOperatorDeploymentMode(ctx)
58+
operatorExists, currentMode, err := d.detectOperatorDeploymentMode(ctx)
59+
if err != nil {
60+
return fmt.Errorf("detecting operator deployment mode: %w", err)
61+
}
5962
needsDeployment := false
6063
needsTeardown := false
6164

internal/deployer/operator.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -642,7 +642,10 @@ func (d *Deployer) teardownOperatorNonOLM(ctx context.Context) error {
642642

643643
// teardownOperator removes the operator if it exists, detecting the deployment mode automatically.
644644
func (d *Deployer) teardownOperator(ctx context.Context) error {
645-
operatorExists, operatorMode := d.detectOperatorDeploymentMode(ctx)
645+
operatorExists, operatorMode, err := d.detectOperatorDeploymentMode(ctx)
646+
if err != nil {
647+
return fmt.Errorf("detecting operator deployment mode: %w", err)
648+
}
646649
if !operatorExists {
647650
d.logger.Dim("No operator deployment found, skipping operator teardown")
648651
return nil

internal/deployer/operator_olm.go

Lines changed: 19 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -335,35 +335,34 @@ func (d *Deployer) waitForCSVSuccess(ctx context.Context) error {
335335

336336
// detectOperatorDeploymentMode detects how the operator is currently deployed.
337337
// Returns (operatorExists bool, isOLM OperatorDeploymentMode)
338-
func (d *Deployer) detectOperatorDeploymentMode(ctx context.Context) (bool, OperatorDeploymentMode) {
338+
func (d *Deployer) detectOperatorDeploymentMode(ctx context.Context) (bool, OperatorDeploymentMode, error) {
339+
const olmOwnerLabel = "olm.owner"
340+
339341
// First, check if a Subscription exists (OLM-specific resource)
340342
_, err := d.runKubectl(ctx, k8s.KubectlOptions{
341343
Args: []string{"get", "subscription", subscriptionName, "-n", operatorNamespace},
342344
})
343345
if err == nil {
344-
return true, OperatorModeOLM
346+
return true, OperatorModeOLM, nil
345347
}
346348

347-
// If no subscription, check if operator deployment exists.
348-
_, err = d.runKubectl(ctx, k8s.KubectlOptions{
349-
Args: []string{"get", "deployment", operatorDeploymentName, "-n", operatorNamespace},
350-
})
351-
if err == nil {
352-
// Deployment exists - check if it has OLM owner labels.
353-
result, err := d.runKubectl(ctx, k8s.KubectlOptions{
354-
Args: []string{"get", "deployment", operatorDeploymentName, "-n", operatorNamespace, "-o", "jsonpath={.metadata.labels}"},
355-
})
356-
// TODO(ROX-34499): This is not very robust. Better retrieve a specific label in the `get`
357-
// command?
358-
if err == nil && strings.Contains(result.Stdout, "olm.owner") {
359-
return true, OperatorModeOLM
360-
}
361-
// Deployment exists without OLM labels = non-OLM deployment.
362-
return true, OperatorModeNonOLM
349+
// If no subscription, check if operator deployment exists/if it has the expected OLM label.
350+
labelValue, err := k8s.RetrieveClusterResourceLabel(ctx, d.logger, operatorNamespace, "deployment", operatorDeploymentName, olmOwnerLabel)
351+
if k8s.IsResourceNotFound(err) {
352+
// No operator deployment found.
353+
return false, OperatorModeNonOLM, nil
354+
}
355+
if err != nil {
356+
return false, OperatorModeNonOLM, err
357+
}
358+
359+
if labelValue == "" {
360+
// Deployment exists without OLM labels -> non-OLM deployment.
361+
return true, OperatorModeNonOLM, nil
363362
}
364363

365-
// No operator found.
366-
return false, OperatorModeNonOLM
364+
// Label set -> OLM deployment.
365+
return true, OperatorModeOLM, nil
367366
}
368367

369368
// teardownOperatorOLM removes the operator when installed via OLM.

internal/k8s/resource.go

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ func RetrieveResourceFromCluster(ctx context.Context, log *logger.Logger, namesp
6464

6565
// IsResourceNotFound checks if an error is a resource not found error.
6666
func IsResourceNotFound(err error) bool {
67-
return err == ErrResourceNotFound
67+
return errors.Is(err, ErrResourceNotFound)
6868
}
6969

7070
// ResourceNotOwnedByName checks if the given unstructured object does not have an owner reference with the specified owner name.
@@ -80,3 +80,33 @@ func ResourceNotOwnedByName(obj *unstructured.Unstructured, ownerName string) bo
8080
}
8181
return true
8282
}
83+
84+
// RetrieveClusterResourceLabel retrieves the specified label from a Kubernetes resource from the cluster.
85+
//
86+
// Parameters: Same as for RetrieveResourceFromCluster, plus
87+
// - label: The label to retrieve.
88+
//
89+
// Returns:
90+
// - string: the label value -- if the label is not found, an empty string is returned without error.
91+
// - error: nil if successful, error otherwise (including ErrResourceNotFound for not found resources)
92+
func RetrieveClusterResourceLabel(ctx context.Context, log *logger.Logger, namespace, resourceType, resourceName, label string) (string, error) {
93+
u, err := RetrieveResourceFromCluster(ctx, log, namespace, resourceType, resourceName)
94+
if err != nil {
95+
return "", fmt.Errorf("retrieving resource %s/%s from namespace %s: %w", resourceType, resourceName, namespace, err)
96+
}
97+
98+
val, found, err := unstructured.NestedFieldCopy(u.Object, "metadata", "labels", label)
99+
if err != nil {
100+
return "", fmt.Errorf("extracting label value: %w", err)
101+
}
102+
if !found {
103+
return "", nil
104+
}
105+
106+
valStr, ok := val.(string)
107+
if !ok {
108+
return "", fmt.Errorf("unexpected type for label %q (%T)", label, val)
109+
}
110+
111+
return valStr, nil
112+
}

0 commit comments

Comments
 (0)