diff --git a/controllers/util/test_util.go b/controllers/util/test_util.go index 962a5ddbed2..995497de05a 100644 --- a/controllers/util/test_util.go +++ b/controllers/util/test_util.go @@ -54,3 +54,16 @@ func SetOAuthAPIFound(found bool) { func SetOLMAPIFound(found bool) { olmAPIFound = found } + +// *** THIS SHOULD ONLY BE USED FOR UNIT TESTING *** +// SetVerifyAPI overrides the API verification function used by InspectCluster. +// Call with nil to restore the default (argoutil.VerifyAPI). +func SetVerifyAPI(fn func(string, string) (bool, error)) { + if fn == nil { + fn = defaultVerifyAPI + } + verifyAPI = fn +} + +// defaultVerifyAPI stores the original verifyAPI value for restoring in tests. +var defaultVerifyAPI = verifyAPI diff --git a/controllers/util/util.go b/controllers/util/util.go index b7cc6e89032..5714553868c 100644 --- a/controllers/util/util.go +++ b/controllers/util/util.go @@ -56,6 +56,10 @@ var ( appsAPIFound = false oauthAPIFound = false olmAPIFound = false + + // verifyAPI is the function used to check API group availability. + // It defaults to argoutil.VerifyAPI and can be overridden in tests. + verifyAPI = argoutil.VerifyAPI ) // GetClusterVersion returns the OpenShift Cluster version in which the operator is installed @@ -88,6 +92,11 @@ func NewClusterVersion(version string) *configv1.ClusterVersion { } } +// InspectCluster probes the API server to determine which optional API groups +// (OLM, Monitoring, Route, Config, Console, Template, Apps, OAuth) are available +// in the cluster and sets the corresponding package-level flags. On non-OpenShift +// clusters where config.openshift.io is absent, only OLM, Monitoring, and Route +// APIs are checked; remaining OpenShift-specific groups are skipped. func InspectCluster() error { var errs []error if err := verifyOLMAPI(); err != nil { @@ -96,17 +105,19 @@ func InspectCluster() error { if err := verifyMonitoringAPI(); err != nil { errs = append(errs, err) } + if err := verifyRouteAPI(); err != nil { + errs = append(errs, err) + } if err := verifyConfigAPI(); err != nil { errs = append(errs, err) return stderrors.Join(errs...) } if !configAPIFound { - return nil + return stderrors.Join(errs...) } for _, check := range []func() error{ - verifyRouteAPI, verifyConsoleAPI, verifyTemplateAPI, verifyAppsAPI, @@ -131,7 +142,7 @@ func IsOpenShiftCluster() bool { // verify if the Config.Openshift.io API is found func verifyConfigAPI() error { - found, err := argoutil.VerifyAPI(configv1.GroupName, configv1.GroupVersion.Version) + found, err := verifyAPI(configv1.GroupName, configv1.GroupVersion.Version) if err != nil { return err } @@ -145,7 +156,7 @@ func IsConsoleAPIFound() bool { } func verifyConsoleAPI() error { - found, err := argoutil.VerifyAPI(console.GroupName, console.GroupVersion.Version) + found, err := verifyAPI(console.GroupName, console.GroupVersion.Version) if err != nil { return err } @@ -159,7 +170,7 @@ func IsRouteAPIFound() bool { } func verifyRouteAPI() error { - found, err := argoutil.VerifyAPI(routev1.GroupName, routev1.GroupVersion.Version) + found, err := verifyAPI(routev1.GroupName, routev1.GroupVersion.Version) if err != nil { return err } @@ -168,7 +179,7 @@ func verifyRouteAPI() error { } func verifyMonitoringAPI() error { - found, err := argoutil.VerifyAPI( + found, err := verifyAPI( monitoringv1.SchemeGroupVersion.Group, monitoringv1.SchemeGroupVersion.Version, ) @@ -190,7 +201,7 @@ func IsTemplateAPIFound() bool { } func verifyTemplateAPI() error { - found, err := argoutil.VerifyAPI(templatev1.GroupName, templatev1.GroupVersion.Version) + found, err := verifyAPI(templatev1.GroupName, templatev1.GroupVersion.Version) if err != nil { return err } @@ -204,7 +215,7 @@ func IsAppsAPIFound() bool { } func verifyAppsAPI() error { - found, err := argoutil.VerifyAPI(oappsv1.GroupName, oappsv1.GroupVersion.Version) + found, err := verifyAPI(oappsv1.GroupName, oappsv1.GroupVersion.Version) if err != nil { return err } @@ -218,7 +229,7 @@ func IsOAuthAPIFound() bool { } func verifyOAuthAPI() error { - found, err := argoutil.VerifyAPI(oauthv1.GroupName, oauthv1.GroupVersion.Version) + found, err := verifyAPI(oauthv1.GroupName, oauthv1.GroupVersion.Version) if err != nil { return err } @@ -232,7 +243,7 @@ func IsOLMAPIFound() bool { } func verifyOLMAPI() error { - found, err := argoutil.VerifyAPI(operatorsv1.GroupVersion.Group, operatorsv1.GroupVersion.Version) + found, err := verifyAPI(operatorsv1.GroupVersion.Group, operatorsv1.GroupVersion.Version) if err != nil { return err } diff --git a/controllers/util/util_test.go b/controllers/util/util_test.go index 2a254894519..485d2a68ed2 100644 --- a/controllers/util/util_test.go +++ b/controllers/util/util_test.go @@ -20,6 +20,7 @@ import ( "testing" configv1 "github.com/openshift/api/config/v1" + routev1 "github.com/openshift/api/route/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/client-go/kubernetes/scheme" "sigs.k8s.io/controller-runtime/pkg/client/fake" @@ -48,6 +49,51 @@ func TestGetClusterVersion(t *testing.T) { }) } +func TestInspectCluster_RouteDetectedWithoutConfigAPI(t *testing.T) { + // Save and restore package-level state so this test is hermetic. + origRoute := routeAPIFound + origConfig := configAPIFound + origOLM := olmAPIFound + origMonitoring := monitoringAPIFound + t.Cleanup(func() { + routeAPIFound = origRoute + configAPIFound = origConfig + olmAPIFound = origOLM + monitoringAPIFound = origMonitoring + SetVerifyAPI(nil) // restore default + }) + + // Reset all flags before the test. + routeAPIFound = false + configAPIFound = false + olmAPIFound = false + monitoringAPIFound = false + + // Mock API verification: route.openshift.io is present, config.openshift.io is not. + SetVerifyAPI(func(group, version string) (bool, error) { + if group == routev1.GroupName { + return true, nil + } + if group == configv1.GroupName { + return false, nil + } + // All other API groups are absent. + return false, nil + }) + + err := InspectCluster() + assertNoError(t, err) + + // The bug: before the fix, verifyRouteAPI was gated behind configAPIFound, + // so on xKS clusters with Route but without Config, Route was never detected. + if !IsRouteAPIFound() { + t.Fatal("IsRouteAPIFound() = false; want true when route.openshift.io is available without config.openshift.io") + } + if IsConfigAPIFound() { + t.Fatal("IsConfigAPIFound() = true; want false because config.openshift.io is absent") + } +} + func addKnownTypesToScheme(scheme *runtime.Scheme) { scheme.AddKnownTypes(configv1.GroupVersion, &configv1.ClusterVersion{}) }