From 1760a8857ff49794b97bafd0e799f864bc41e208 Mon Sep 17 00:00:00 2001 From: Nahshon Unna-Tsameret Date: Mon, 7 Nov 2022 14:24:29 +0200 Subject: [PATCH] Allow running the SSP Operator on plain kubernetes SSP can't run on a plain kubernetes, because it requires the `Infrastructure` kind to be present on the cluster. When deploying KubeVirt with HCO using OLM on plain kubernetes, the deployment is never completed because SSP operator never becomes ready. More details and full description of the issue can be found here: https://github.com/kubevirt/hyperconverged-cluster-operator/issues/2129 This commit disables the reconcilers and all the watches, in case the `Infrastructure` is not found on the cluster, instead of killing the process. That way, the SSP operator is runing and responding to the health and ready checks, but does nothing else. The result is that SSP is still not working on plain kubernetest, but the OLM deployment is successfully completed. Signed-off-by: Nahshon Unna-Tsameret --- config/rbac/role.yaml | 1 + controllers/setup.go | 94 +++++++++++++++++++--------------- controllers/ssp_controller.go | 2 +- internal/common/environment.go | 20 ++++++++ 4 files changed, 75 insertions(+), 42 deletions(-) diff --git a/config/rbac/role.yaml b/config/rbac/role.yaml index 0fcf395b9..568979d96 100644 --- a/config/rbac/role.yaml +++ b/config/rbac/role.yaml @@ -114,6 +114,7 @@ rules: - apiGroups: - config.openshift.io resources: + - clusterversions - infrastructures verbs: - get diff --git a/controllers/setup.go b/controllers/setup.go index e4d892ac8..43eb187d4 100644 --- a/controllers/setup.go +++ b/controllers/setup.go @@ -3,6 +3,7 @@ package controllers import ( "context" "fmt" + "github.com/go-logr/logr" "path/filepath" "kubevirt.io/ssp-operator/internal/common" @@ -36,64 +37,75 @@ func CreateAndStartReconciler(ctx context.Context, mgr controllerruntime.Manager node_labeller.New(), } - var requiredCrds []string - for i := range sspOperands { - requiredCrds = append(requiredCrds, sspOperands[i].RequiredCrds()...) - } - mgrCtx, cancel := context.WithCancel(ctx) defer cancel() + mgrCtx = logr.NewContext(mgrCtx, mgr.GetLogger()) - crdWatch := crd_watch.New(requiredCrds...) - // Cleanly stops the manager and exit. The pod will be restarted. - crdWatch.AllCrdsAddedHandler = cancel - crdWatch.SomeCrdRemovedHandler = cancel - - err = crdWatch.Init(mgrCtx, mgr.GetAPIReader()) + runningOnOpenShift, err := common.RunningOnOpenshift(ctx, mgr.GetAPIReader()) if err != nil { return err } - if missingCrds := crdWatch.MissingCrds(); len(missingCrds) > 0 { - mgr.GetLogger().Error(nil, "Some required crds are missing. The operator will not create any new resources.", - "missingCrds", missingCrds, - ) - } + if runningOnOpenShift { + var requiredCrds []string + for i := range sspOperands { + requiredCrds = append(requiredCrds, sspOperands[i].RequiredCrds()...) + } - err = mgr.Add(crdWatch) - if err != nil { - return err - } + crdWatch := crd_watch.New(requiredCrds...) + // Cleanly stops the manager and exit. The pod will be restarted. + crdWatch.AllCrdsAddedHandler = cancel + crdWatch.SomeCrdRemovedHandler = cancel - infrastructureTopology, err := common.GetInfrastructureTopology(mgrCtx, mgr.GetAPIReader()) - if err != nil { - return fmt.Errorf("failed to get infrastructure topology: %w", err) - } + err = crdWatch.Init(mgrCtx, mgr.GetAPIReader()) + if err != nil { + return err + } - serviceController, err := CreateServiceController(mgrCtx, mgr) - if err != nil { - return fmt.Errorf("failed to create service controller: %w", err) - } + if missingCrds := crdWatch.MissingCrds(); len(missingCrds) > 0 { + mgr.GetLogger().Error(nil, "Some required crds are missing. The operator will not create any new resources.", + "missingCrds", missingCrds, + ) + } - err = mgr.Add(manager.RunnableFunc(func(ctx context.Context) error { - err := serviceController.Start(ctx, mgr) + infrastructureTopology, err := common.GetInfrastructureTopology(mgrCtx, mgr.GetAPIReader()) if err != nil { - return fmt.Errorf("error starting serviceController: %w", err) + return err } - mgr.GetLogger().Info("Services Controller started") + err = mgr.Add(crdWatch) + if err != nil { + return err + } - return nil - })) - if err != nil { - return fmt.Errorf("error adding service controller: %w", err) - } + serviceController, err := CreateServiceController(mgrCtx, mgr) + if err != nil { + return fmt.Errorf("failed to create service controller: %w", err) + } - reconciler := NewSspReconciler(mgr.GetClient(), mgr.GetAPIReader(), infrastructureTopology, sspOperands, crdWatch) + err = mgr.Add(manager.RunnableFunc(func(ctx context.Context) error { + err := serviceController.Start(ctx, mgr) + if err != nil { + return fmt.Errorf("error starting serviceController: %w", err) + } - err = reconciler.setupController(mgr) - if err != nil { - return err + mgr.GetLogger().Info("Services Controller started") + + return nil + })) + if err != nil { + return fmt.Errorf("error adding service controller: %w", err) + } + + reconciler := NewSspReconciler(mgr.GetClient(), mgr.GetAPIReader(), infrastructureTopology, sspOperands, crdWatch) + + err = reconciler.setupController(mgr) + if err != nil { + return err + } + + } else { // if !runningOnOpenShift + mgr.GetLogger().Info("SSP operator is running in inactive mode. The operator will not react to any event.") } mgr.GetLogger().Info("starting manager") diff --git a/controllers/ssp_controller.go b/controllers/ssp_controller.go index b73142365..1774e88a2 100644 --- a/controllers/ssp_controller.go +++ b/controllers/ssp_controller.go @@ -98,7 +98,7 @@ var _ reconcile.Reconciler = &sspReconciler{} // +kubebuilder:rbac:groups=ssp.kubevirt.io,resources=ssps,verbs=get;list;watch;create;update;patch;delete // +kubebuilder:rbac:groups=ssp.kubevirt.io,resources=ssps/status,verbs=get;update;patch // +kubebuilder:rbac:groups=ssp.kubevirt.io,resources=ssps/finalizers,verbs=update -// +kubebuilder:rbac:groups=config.openshift.io,resources=infrastructures,verbs=get;list;watch +// +kubebuilder:rbac:groups=config.openshift.io,resources=infrastructures;clusterversions,verbs=get;list;watch // +kubebuilder:rbac:groups=apiextensions.k8s.io,resources=customresourcedefinitions,verbs=list // +kubebuilder:rbac:groups=ssp.kubevirt.io,resources=kubevirtcommontemplatesbundles,verbs=get;list;watch;create;update;patch;delete // +kubebuilder:rbac:groups=ssp.kubevirt.io,resources=kubevirtmetricsaggregations,verbs=get;list;watch;create;update;patch;delete diff --git a/internal/common/environment.go b/internal/common/environment.go index 6dbdd3ebf..6252c4f53 100644 --- a/internal/common/environment.go +++ b/internal/common/environment.go @@ -9,6 +9,9 @@ import ( "github.com/go-logr/logr" osconfv1 "github.com/openshift/api/config/v1" + apierrors "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/api/meta" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" "sigs.k8s.io/controller-runtime/pkg/client" ) @@ -33,6 +36,23 @@ func GetOperatorVersion() string { return EnvOrDefault(OperatorVersionKey, defaultOperatorVersion) } +func RunningOnOpenshift(ctx context.Context, cl client.Reader) (bool, error) { + clusterVersion := &osconfv1.ClusterVersion{ + ObjectMeta: metav1.ObjectMeta{ + Name: "version", + }, + } + if err := cl.Get(ctx, client.ObjectKeyFromObject(clusterVersion), clusterVersion); err != nil { + if meta.IsNoMatchError(err) || apierrors.IsNotFound(err) { + // Not on OpenShift + return false, nil + } else { + return false, err + } + } + return true, nil +} + func GetInfrastructureTopology(ctx context.Context, c client.Reader) (osconfv1.TopologyMode, error) { infraConfig := &osconfv1.Infrastructure{} if err := c.Get(ctx, types.NamespacedName{Name: "cluster"}, infraConfig); err != nil {