diff --git a/controllers/setup.go b/controllers/setup.go index e4d892ac8..e423dd8f9 100644 --- a/controllers/setup.go +++ b/controllers/setup.go @@ -36,14 +36,19 @@ func CreateAndStartReconciler(ctx context.Context, mgr controllerruntime.Manager node_labeller.New(), } + mgrCtx, cancel := context.WithCancel(ctx) + defer cancel() + + infrastructureTopology, err := common.GetInfrastructureTopology(mgrCtx, mgr.GetAPIReader()) + if err != nil { + return err + } + var requiredCrds []string for i := range sspOperands { requiredCrds = append(requiredCrds, sspOperands[i].RequiredCrds()...) } - mgrCtx, cancel := context.WithCancel(ctx) - defer cancel() - crdWatch := crd_watch.New(requiredCrds...) // Cleanly stops the manager and exit. The pod will be restarted. crdWatch.AllCrdsAddedHandler = cancel @@ -60,33 +65,30 @@ func CreateAndStartReconciler(ctx context.Context, mgr controllerruntime.Manager ) } - err = mgr.Add(crdWatch) - if err != nil { - return err - } - - infrastructureTopology, err := common.GetInfrastructureTopology(mgrCtx, mgr.GetAPIReader()) - if err != nil { - return fmt.Errorf("failed to get infrastructure topology: %w", err) - } - - serviceController, err := CreateServiceController(mgrCtx, mgr) - if err != nil { - return fmt.Errorf("failed to create service controller: %w", err) - } + if len(infrastructureTopology) > 0 { + err = mgr.Add(crdWatch) + if err != nil { + return err + } - err = mgr.Add(manager.RunnableFunc(func(ctx context.Context) error { - err := serviceController.Start(ctx, mgr) + serviceController, err := CreateServiceController(mgrCtx, mgr) if err != nil { - return fmt.Errorf("error starting serviceController: %w", err) + return fmt.Errorf("failed to create service controller: %w", err) } - mgr.GetLogger().Info("Services Controller started") + 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) + } - return nil - })) - if err != nil { - return fmt.Errorf("error adding service controller: %w", 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) diff --git a/controllers/ssp_controller.go b/controllers/ssp_controller.go index b73142365..2fd160acd 100644 --- a/controllers/ssp_controller.go +++ b/controllers/ssp_controller.go @@ -117,11 +117,13 @@ func (r *sspReconciler) setupController(mgr ctrl.Manager) error { builder := ctrl.NewControllerManagedBy(mgr) watchSspResource(builder) - r.areCrdsMissing = len(r.crdWatch.MissingCrds()) > 0 + if len(r.topologyMode) > 0 { + r.areCrdsMissing = len(r.crdWatch.MissingCrds()) > 0 - // Register watches for created objects only if all required CRDs exist - watchClusterResources(builder, r.crdWatch, r.operands, eventHandlerHook) - watchNamespacedResources(builder, r.crdWatch, r.operands, eventHandlerHook) + // Register watches for created objects only if all required CRDs exist + watchClusterResources(builder, r.crdWatch, r.operands, eventHandlerHook) + watchNamespacedResources(builder, r.crdWatch, r.operands, eventHandlerHook) + } return builder.Complete(r) } diff --git a/internal/common/environment.go b/internal/common/environment.go index 6dbdd3ebf..df1b4766a 100644 --- a/internal/common/environment.go +++ b/internal/common/environment.go @@ -4,6 +4,7 @@ import ( "context" "fmt" "io/ioutil" + "k8s.io/apimachinery/pkg/api/meta" "os" "strings" @@ -36,6 +37,11 @@ func GetOperatorVersion() string { 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 { + if _, ok := err.(*meta.NoKindMatchError); ok { + // if the Infrastructure type is not known in this cluster, then it's a plain kubernetes. + // we'll use the stale reconciler, so the operator will actually do nothing + return "", nil + } return "", err } diff --git a/internal/common/resource.go b/internal/common/resource.go index 5eb0f93c5..c7a5f3a91 100644 --- a/internal/common/resource.go +++ b/internal/common/resource.go @@ -9,6 +9,7 @@ import ( "github.com/prometheus/client_golang/prometheus" "k8s.io/apimachinery/pkg/api/equality" "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/utils/pointer" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" ) @@ -207,6 +208,10 @@ func CreateOrUpdate(request *Request) ReconcileBuilder { panic("Request should not be nil") } + if request.TopologyMode == "" { + return theStaleReconsiler + } + return &reconcileBuilder{ request: request, updateFunc: func(_, _ client.Object) { @@ -431,3 +436,29 @@ func ResourceDeletedResult(resource client.Object, res OperationResult) Reconcil OperationResult: res, } } + +// staleReconsiler is a reconsiler that does nothing, in case the operator is running on a plain kubernetes +type staleReconsiler struct{} + +func (r *staleReconsiler) NamespacedResource(client.Object) ReconcileBuilder { return r } +func (r *staleReconsiler) ClusterResource(client.Object) ReconcileBuilder { return r } +func (r *staleReconsiler) WithAppLabels(name string, component AppComponent) ReconcileBuilder { + return r +} +func (r *staleReconsiler) UpdateFunc(ResourceUpdateFunc) ReconcileBuilder { return r } +func (r *staleReconsiler) StatusFunc(ResourceStatusFunc) ReconcileBuilder { return r } +func (r *staleReconsiler) ImmutableSpec(getter ResourceSpecGetter) ReconcileBuilder { return r } +func (r *staleReconsiler) Options(options ReconcileOptions) ReconcileBuilder { return r } +func (r *staleReconsiler) Reconcile() (ReconcileResult, error) { + return ReconcileResult{ + Status: ResourceStatus{ + Progressing: pointer.StringPtr("false"), + NotAvailable: pointer.StringPtr("true"), + Degraded: pointer.StringPtr("false"), + }, + Resource: nil, + OperationResult: OperationResultNone, + }, nil +} + +var theStaleReconsiler = &staleReconsiler{} diff --git a/internal/common/resource_test.go b/internal/common/resource_test.go index eb1f17cc5..19ba8cde8 100644 --- a/internal/common/resource_test.go +++ b/internal/common/resource_test.go @@ -6,6 +6,7 @@ import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" + osconfv1 "github.com/openshift/api/config/v1" libhandler "github.com/operator-framework/operator-lib/handler" v1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/errors" @@ -59,6 +60,7 @@ var _ = Describe("Resource", func() { }, Logger: log, VersionCache: VersionCache{}, + TopologyMode: osconfv1.HighlyAvailableTopologyMode, } }) diff --git a/internal/operands/common-templates/reconcile_test.go b/internal/operands/common-templates/reconcile_test.go index fd3cd3c91..32ed710cd 100644 --- a/internal/operands/common-templates/reconcile_test.go +++ b/internal/operands/common-templates/reconcile_test.go @@ -7,6 +7,7 @@ import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" + osconfv1 "github.com/openshift/api/config/v1" templatev1 "github.com/openshift/api/template/v1" libhandler "github.com/operator-framework/operator-lib/handler" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -78,6 +79,7 @@ var _ = Describe("Common-Templates operand", func() { }, Logger: log, VersionCache: common.VersionCache{}, + TopologyMode: osconfv1.HighlyAvailableTopologyMode, } }) diff --git a/internal/operands/data-sources/reconcile_test.go b/internal/operands/data-sources/reconcile_test.go index 34416a4b1..c6f081862 100644 --- a/internal/operands/data-sources/reconcile_test.go +++ b/internal/operands/data-sources/reconcile_test.go @@ -7,6 +7,7 @@ import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" + osconfv1 "github.com/openshift/api/config/v1" v1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -72,6 +73,7 @@ var _ = Describe("Data-Sources operand", func() { }, Logger: log, VersionCache: common.VersionCache{}, + TopologyMode: osconfv1.HighlyAvailableTopologyMode, } }) diff --git a/internal/operands/metrics/reconcile_test.go b/internal/operands/metrics/reconcile_test.go index cde9c8595..2baa9354d 100644 --- a/internal/operands/metrics/reconcile_test.go +++ b/internal/operands/metrics/reconcile_test.go @@ -6,6 +6,8 @@ import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" + + osconfv1 "github.com/openshift/api/config/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" . "kubevirt.io/ssp-operator/internal/test-utils" @@ -53,6 +55,7 @@ var _ = Describe("Metrics operand", func() { }, Logger: log, VersionCache: common.VersionCache{}, + TopologyMode: osconfv1.HighlyAvailableTopologyMode, } _, err := operand.Reconcile(&request) diff --git a/internal/operands/template-validator/reconcile_test.go b/internal/operands/template-validator/reconcile_test.go index 2e3b71934..efbd066d5 100644 --- a/internal/operands/template-validator/reconcile_test.go +++ b/internal/operands/template-validator/reconcile_test.go @@ -9,6 +9,7 @@ import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" + osconfv1 "github.com/openshift/api/config/v1" admission "k8s.io/api/admissionregistration/v1" apps "k8s.io/api/apps/v1" core "k8s.io/api/core/v1" @@ -75,6 +76,7 @@ var _ = Describe("Template validator operand", func() { }, Logger: log, VersionCache: common.VersionCache{}, + TopologyMode: osconfv1.HighlyAvailableTopologyMode, } })