diff --git a/control-plane-operator/hostedclusterconfigoperator/cmd.go b/control-plane-operator/hostedclusterconfigoperator/cmd.go index d5a34ea14fb..614ea707fd5 100644 --- a/control-plane-operator/hostedclusterconfigoperator/cmd.go +++ b/control-plane-operator/hostedclusterconfigoperator/cmd.go @@ -33,12 +33,14 @@ import ( "github.com/openshift/hypershift/control-plane-operator/hostedclusterconfigoperator/controllers/spotremediation" "github.com/openshift/hypershift/control-plane-operator/hostedclusterconfigoperator/operator" hyperapi "github.com/openshift/hypershift/support/api" + "github.com/openshift/hypershift/support/capabilities" "github.com/openshift/hypershift/support/labelenforcingclient" "github.com/openshift/hypershift/support/releaseinfo" "github.com/openshift/hypershift/support/supportedversion" "github.com/openshift/hypershift/support/upsert" "github.com/openshift/hypershift/support/util" + "k8s.io/client-go/discovery" "k8s.io/client-go/rest" ctrl "sigs.k8s.io/controller-runtime" @@ -222,6 +224,19 @@ func (o *HostedClusterConfigOperator) Run(ctx context.Context) error { } cfg := operator.CfgFromFile(o.TargetKubeconfig) cpConfig := ctrl.GetConfigOrDie() + + // Detect the management cluster capabilities once at startup so controllers can + // gate optional behavior (e.g. watching route.openshift.io Routes) without each + // having to build its own discovery client. + cpDiscoveryClient, err := discovery.NewDiscoveryClientForConfig(cpConfig) + if err != nil { + return fmt.Errorf("failed to create management cluster discovery client: %w", err) + } + mgmtClusterCaps, err := capabilities.DetectManagementClusterCapabilities(cpDiscoveryClient) + if err != nil { + return fmt.Errorf("failed to detect management cluster capabilities: %w", err) + } + mgr := operator.Mgr(ctx, cfg, cpConfig, o.Namespace, o.HostedControlPlaneName) mgr.GetLogger().Info("Starting hosted-cluster-config-operator", "version", supportedversion.String()) cpCluster, err := cluster.New(cpConfig, func(opt *cluster.Options) { @@ -302,27 +317,28 @@ func (o *HostedClusterConfigOperator) Run(ctx context.Context) error { APIClient: apiReadingClient, }, - Config: cpConfig, - TargetConfig: cfg, - KubevirtInfraConfig: kubevirtInfraConfig, - Manager: mgr, - Namespace: o.Namespace, - HCPName: o.HostedControlPlaneName, - InitialCA: string(o.initialCA), - ClusterSignerCA: string(o.clusterSignerCA), - ControllerFuncs: controllersToRun, - Versions: versions, - PlatformType: hyperv1.PlatformType(o.platformType), - CPCluster: cpCluster, - Logger: ctrl.Log.WithName("hypershift-operator"), - ReleaseProvider: releaseProvider, - KonnectivityAddress: o.KonnectivityAddress, - KonnectivityPort: o.KonnectivityPort, - OAuthAddress: o.OAuthAddress, - OAuthPort: o.OAuthPort, - OperateOnReleaseImage: os.Getenv("OPERATE_ON_RELEASE_IMAGE"), - EnableCIDebugOutput: o.enableCIDebugOutput, - ImageMetaDataProvider: imageMetaDataProvider, + Config: cpConfig, + TargetConfig: cfg, + KubevirtInfraConfig: kubevirtInfraConfig, + Manager: mgr, + Namespace: o.Namespace, + HCPName: o.HostedControlPlaneName, + InitialCA: string(o.initialCA), + ClusterSignerCA: string(o.clusterSignerCA), + ControllerFuncs: controllersToRun, + Versions: versions, + PlatformType: hyperv1.PlatformType(o.platformType), + CPCluster: cpCluster, + Logger: ctrl.Log.WithName("hypershift-operator"), + ReleaseProvider: releaseProvider, + KonnectivityAddress: o.KonnectivityAddress, + KonnectivityPort: o.KonnectivityPort, + OAuthAddress: o.OAuthAddress, + OAuthPort: o.OAuthPort, + OperateOnReleaseImage: os.Getenv("OPERATE_ON_RELEASE_IMAGE"), + EnableCIDebugOutput: o.enableCIDebugOutput, + ImageMetaDataProvider: imageMetaDataProvider, + ManagementClusterCapabilities: mgmtClusterCaps, } configmetrics.Register(mgr.GetCache()) return operatorConfig.Start(ctx) diff --git a/control-plane-operator/hostedclusterconfigoperator/controllers/resources/resources.go b/control-plane-operator/hostedclusterconfigoperator/controllers/resources/resources.go index 1ee6a3a7180..3be099af380 100644 --- a/control-plane-operator/hostedclusterconfigoperator/controllers/resources/resources.go +++ b/control-plane-operator/hostedclusterconfigoperator/controllers/resources/resources.go @@ -310,8 +310,12 @@ func Setup(ctx context.Context, opts *operator.HostedClusterConfigOperatorConfig } // Watch metrics-proxy Route on the control plane cluster for hostname changes. - if err := c.Watch(source.Kind[client.Object](opts.CPCluster.GetCache(), &routev1.Route{}, eventHandler())); err != nil { - return fmt.Errorf("failed to watch Route: %w", err) + // Skip when the management cluster does not expose the route.openshift.io API + // (non-OpenShift management cluster); otherwise the watch fails and HCCO does not start. + if opts.ManagementClusterCapabilities.Has(capabilities.CapabilityRoute) { + if err := c.Watch(source.Kind[client.Object](opts.CPCluster.GetCache(), &routev1.Route{}, eventHandler())); err != nil { + return fmt.Errorf("failed to watch Route: %w", err) + } } // Watch HostedControlPlane namespace pull-secret on the control plane cluster so guest pull secrets diff --git a/control-plane-operator/hostedclusterconfigoperator/operator/config.go b/control-plane-operator/hostedclusterconfigoperator/operator/config.go index e59c3b97463..076633d2d89 100644 --- a/control-plane-operator/hostedclusterconfigoperator/operator/config.go +++ b/control-plane-operator/hostedclusterconfigoperator/operator/config.go @@ -56,29 +56,30 @@ func cacheLabelSelector() labels.Selector { type ControllerSetupFunc func(context.Context, *HostedClusterConfigOperatorConfig) error type HostedClusterConfigOperatorConfig struct { - Manager ctrl.Manager - Config *rest.Config - TargetConfig *rest.Config - KubevirtInfraConfig *rest.Config - TargetCreateOrUpdateProvider upsert.CreateOrUpdateProvider - CPCluster cluster.Cluster - Logger logr.Logger - Versions map[string]string - HCPName string - Namespace string - InitialCA string - ClusterSignerCA string - Controllers []string - PlatformType hyperv1.PlatformType - ControllerFuncs map[string]ControllerSetupFunc - ReleaseProvider releaseinfo.Provider - KonnectivityAddress string - KonnectivityPort int32 - OAuthAddress string - OAuthPort int32 - OperateOnReleaseImage string - EnableCIDebugOutput bool - ImageMetaDataProvider util.ImageMetadataProvider + Manager ctrl.Manager + Config *rest.Config + TargetConfig *rest.Config + KubevirtInfraConfig *rest.Config + TargetCreateOrUpdateProvider upsert.CreateOrUpdateProvider + CPCluster cluster.Cluster + Logger logr.Logger + Versions map[string]string + HCPName string + Namespace string + InitialCA string + ClusterSignerCA string + Controllers []string + PlatformType hyperv1.PlatformType + ControllerFuncs map[string]ControllerSetupFunc + ReleaseProvider releaseinfo.Provider + KonnectivityAddress string + KonnectivityPort int32 + OAuthAddress string + OAuthPort int32 + OperateOnReleaseImage string + EnableCIDebugOutput bool + ImageMetaDataProvider util.ImageMetadataProvider + ManagementClusterCapabilities capabilities.CapabiltyChecker kubeClient kubeclient.Interface }