From 35fb9c03cd19ff293b6917d7271e234a564570e0 Mon Sep 17 00:00:00 2001 From: Moritz Clasmeier Date: Mon, 4 May 2026 18:08:43 +0200 Subject: [PATCH 1/3] Use kubectl api-resources for OLM check --- internal/deployer/operator_olm.go | 33 ++++++++++++++++++++----------- 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/internal/deployer/operator_olm.go b/internal/deployer/operator_olm.go index 662fbd0..387e848 100644 --- a/internal/deployer/operator_olm.go +++ b/internal/deployer/operator_olm.go @@ -72,25 +72,34 @@ func (d *Deployer) deployOperatorViaOLM(ctx context.Context) error { return nil } -// checkOLMInstalled checks if OLM is installed in the cluster. +// checkOLMInstalled checks if OLM is installed in the cluster by verifying +// the API server is ready to serve the required OLM resource types. func (d *Deployer) checkOLMInstalled(ctx context.Context) error { - // Check for OLM CRDs - requiredCRDs := []string{ + requiredResources := []string{ "catalogsources.operators.coreos.com", "subscriptions.operators.coreos.com", "installplans.operators.coreos.com", "clusterserviceversions.operators.coreos.com", } - for _, crd := range requiredCRDs { - // TODO(ROX-34499): actually this is not the right way to check whether it's safe to create a resource of a given kind. - // A CRD can be present, but still being loaded or end up not accepted by the API server. - // Instead we should use the `kubectl api-resources` subcommand which exposes the status we're looking for. - _, err := d.runKubectl(ctx, k8s.KubectlOptions{ - Args: []string{"get", "crd", crd}, - }) - if err != nil { - return fmt.Errorf("OLM not installed: CRD %s not found. Please install OLM first", crd) + result, err := d.runKubectl(ctx, k8s.KubectlOptions{ + Args: []string{"api-resources", "--api-group=operators.coreos.com", "-o", "name"}, + }) + if err != nil { + return fmt.Errorf("OLM not installed: api-group operators.coreos.com not available. Please install OLM first") + } + + available := make(map[string]bool) + for line := range strings.SplitSeq(strings.TrimSpace(result.Stdout), "\n") { + name := strings.TrimSpace(line) + available[name] = true + } + + for _, resource := range requiredResources { + if !available[resource] { + d.logger.Errorf("OLM is not properly installed: resource %s not served by the API server.", resource) + d.logger.Errorf("Please make sure that OLM is installed properly.") + return fmt.Errorf("OLM resource %s not served by the API server", resource) } } From 18c6681e226f1db2c90e622fa30cfba6b684e8c8 Mon Sep 17 00:00:00 2001 From: Moritz Clasmeier Date: Thu, 7 May 2026 13:00:40 +0200 Subject: [PATCH 2/3] Log stderr and wrap error in OLM availability check The kubectl api-resources command can fail for reasons other than OLM not being installed. Logging stderr and wrapping the error helps users diagnose the actual issue. Co-Authored-By: Claude Opus 4.6 --- internal/deployer/operator_olm.go | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/internal/deployer/operator_olm.go b/internal/deployer/operator_olm.go index 387e848..6759829 100644 --- a/internal/deployer/operator_olm.go +++ b/internal/deployer/operator_olm.go @@ -86,7 +86,13 @@ func (d *Deployer) checkOLMInstalled(ctx context.Context) error { Args: []string{"api-resources", "--api-group=operators.coreos.com", "-o", "name"}, }) if err != nil { - return fmt.Errorf("OLM not installed: api-group operators.coreos.com not available. Please install OLM first") + if result.Stderr != "" { + d.logger.Error("kubectl stderr:") + for stderrLine := range strings.SplitSeq(result.Stderr, "\n") { + d.logger.Errorf("stderr: %s", stderrLine) + } + } + return fmt.Errorf("failed to query api-group operators.coreos.com: %w", err) } available := make(map[string]bool) From af3dcfffac95ebd6be8688a282077e571fcd2f42 Mon Sep 17 00:00:00 2001 From: Moritz Clasmeier Date: Thu, 7 May 2026 13:04:28 +0200 Subject: [PATCH 3/3] Report all missing OLM resources before returning error Instead of returning on the first missing resource, collect all missing ones and log each individually. The returned error gives a concise summary without duplicating the per-resource details. Co-Authored-By: Claude Opus 4.6 --- internal/deployer/operator_olm.go | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/internal/deployer/operator_olm.go b/internal/deployer/operator_olm.go index 6759829..7e41608 100644 --- a/internal/deployer/operator_olm.go +++ b/internal/deployer/operator_olm.go @@ -101,13 +101,18 @@ func (d *Deployer) checkOLMInstalled(ctx context.Context) error { available[name] = true } + var missingResources []string for _, resource := range requiredResources { if !available[resource] { - d.logger.Errorf("OLM is not properly installed: resource %s not served by the API server.", resource) - d.logger.Errorf("Please make sure that OLM is installed properly.") - return fmt.Errorf("OLM resource %s not served by the API server", resource) + missingResources = append(missingResources, resource) } } + if len(missingResources) > 0 { + for _, resource := range missingResources { + d.logger.Errorf("OLM resource not served by the API server: %s", resource) + } + return fmt.Errorf("OLM is not properly installed, %d required resource(s) missing", len(missingResources)) + } d.logger.Success("✓ OLM detected in cluster") return nil