diff --git a/cmd/main.go b/cmd/main.go index 95f2d1860a..0197d41911 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -26,6 +26,7 @@ import ( "time" "github.com/cloudflare/cfssl/log" + "github.com/go-logr/logr" "github.com/tigera/operator/pkg/render/common/cloudconfig" v3 "github.com/tigera/api/pkg/apis/projectcalico/v3" @@ -63,6 +64,7 @@ import ( "k8s.io/client-go/kubernetes" clientgoscheme "k8s.io/client-go/kubernetes/scheme" _ "k8s.io/client-go/plugin/pkg/client/auth/gcp" + clientgocache "k8s.io/client-go/tools/cache" "k8s.io/client-go/tools/clientcmd" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/cache" @@ -70,6 +72,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client/apiutil" "sigs.k8s.io/controller-runtime/pkg/client/config" "sigs.k8s.io/controller-runtime/pkg/log/zap" + "sigs.k8s.io/controller-runtime/pkg/manager" ctrlmetrics "sigs.k8s.io/controller-runtime/pkg/metrics" "sigs.k8s.io/controller-runtime/pkg/metrics/server" "sigs.k8s.io/controller-runtime/pkg/webhook" @@ -127,7 +130,7 @@ func main() { var sgSetup bool var manageCRDs bool var preDelete bool - var variant string + var bootstrapVariant string // bootstrapCRDs is a flag that can be used to install the CRDs and exit. This is useful for // workflows that use an init container to install CustomResources prior to the operator starting. @@ -166,7 +169,11 @@ If a value other than 'all' is specified, the first CRD with a prefix of the spe flag.BoolVar(&manageCRDs, "manage-crds", false, "Operator should manage the projectcalico.org and operator.tigera.io CRDs.") flag.BoolVar(&preDelete, "pre-delete", false, "Run helm pre-deletion hook logic, then exit.") flag.BoolVar(&bootstrapCRDs, "bootstrap-crds", false, "Install CRDs and exit") - flag.StringVar(&variant, "variant", string(operatortigeraiov1.Calico), "Default product variant to assume during boostrapping.") + flag.StringVar( + &bootstrapVariant, "variant", string(operatortigeraiov1.Calico), + `Product variant to install CRDs for before an Installation exists. Only affects CRD and +admission policy installation; once an Installation exists it is the authority on the variant.`, + ) opts := zap.Options{} opts.BindFlags(flag.CommandLine) @@ -174,6 +181,15 @@ If a value other than 'all' is specified, the first CRD with a prefix of the spe ctrl.SetLogger(zap.New(zap.WriteTo(os.Stdout), zap.UseFlagOptions(&opts))) + // An unrecognised variant is silently treated as Calico, which installs the wrong CRDs for + // the bootstrap-crds path where nothing runs afterwards to correct them. + switch v := operatortigeraiov1.ProductVariant(bootstrapVariant); { + case v == operatortigeraiov1.Calico, v.IsEnterprise(): + default: + fmt.Printf("Invalid -variant %q\n", bootstrapVariant) + os.Exit(1) + } + if showVersion { // If the following line is updated then it might be necessary to update the assertOperatorImageVersion in hack/release/build.go fmt.Println("Operator:", version.VERSION) @@ -392,17 +408,17 @@ If a value other than 'all' is specified, the first CRD with a prefix of the spe if bootstrapCRDs || manageCRDs { setupLog.WithValues("v3", v3CRDs).Info("Ensuring CRDs are installed") - if err := crds.Ensure(mgr.GetClient(), variant, v3CRDs, setupLog); err != nil { + if err := crds.Ensure(mgr.GetClient(), bootstrapVariant, v3CRDs, setupLog); err != nil { setupLog.Error(err, "Failed to ensure CRDs are created") os.Exit(1) } - if err := admission.Ensure(mgr.GetClient(), variant, v3CRDs, apiDiscovery.ServedVersion(admission.APIGroup, admission.KindPolicy), setupLog); err != nil { + if err := admission.Ensure(mgr.GetClient(), bootstrapVariant, v3CRDs, apiDiscovery.ServedVersion(admission.APIGroup, admission.KindPolicy), setupLog); err != nil { setupLog.Error(err, "Failed to ensure MutatingAdmissionPolicies are created") os.Exit(1) } - if err := admission.EnsureValidating(mgr.GetClient(), variant, v3CRDs, apiDiscovery.ServedVersion(admission.APIGroup, admission.KindValidatingPolicy), setupLog); err != nil { + if err := admission.EnsureValidating(mgr.GetClient(), bootstrapVariant, v3CRDs, apiDiscovery.ServedVersion(admission.APIGroup, admission.KindValidatingPolicy), setupLog); err != nil { setupLog.Error(err, "Failed to ensure ValidatingAdmissionPolicies are created") os.Exit(1) } @@ -413,6 +429,34 @@ If a value other than 'all' is specified, the first CRD with a prefix of the spe } } + // Resolve the variant now that the operator CRDs exist. + variant := waitForVariant(ctx, c, setupLog) + setupLog.WithValues("variant", variant).Info("Resolved product variant") + + // The bootstrap pass above used the flag default, which doesn't cover the enterprise APIs. + if manageCRDs && variant != operatortigeraiov1.ProductVariant(bootstrapVariant) { + setupLog.WithValues("variant", variant).Info("Ensuring CRDs are installed for the resolved variant") + + if err := crds.Ensure(mgr.GetClient(), string(variant), v3CRDs, setupLog); err != nil { + setupLog.Error(err, "Failed to ensure CRDs are created") + os.Exit(1) + } + } + + // The enterprise controllers can't register without their APIs. Exiting lets the kubelet + // retry us once the CRDs are installed. + if variant.IsEnterprise() { + enterpriseAPIs, err := discovery.EnterpriseAPIsExist(cs) + if err != nil { + setupLog.Error(err, "Failed to determine whether the Enterprise APIs are available") + os.Exit(1) + } + if !enterpriseAPIs { + setupLog.Error(fmt.Errorf("the Calico Enterprise CRDs are not installed"), "Cannot run as Calico Enterprise") + os.Exit(1) + } + } + // Start a goroutine to handle termination. go func() { // Cancel the main context when we are done. @@ -497,14 +541,6 @@ If a value other than 'all' is specified, the first CRD with a prefix of the spe } setupLog.WithValues("tenancy", multiTenant).Info("Checking tenancy mode") - // Determine if we need to start the Enterprise specific controllers. - enterpriseCRDExists, err := discovery.RequiresTigeraSecure(clientset) - if err != nil { - setupLog.Error(err, "Failed to determine if Enterprise controllers are required") - os.Exit(1) - } - setupLog.WithValues("required", enterpriseCRDExists).Info("Checking if Enterprise controllers are required") - clusterDomain, err := dns.GetClusterDomain(dns.DefaultResolveConfPath) if err != nil { clusterDomain = dns.DefaultClusterDomain @@ -563,25 +599,31 @@ If a value other than 'all' is specified, the first CRD with a prefix of the spe } // Start a watch on our bootstrap configmap so we can restart if it changes. - if err = utils.MonitorConfigMap(clientset, bootstrapConfigMapName, bootConfig.Data); err != nil { + if err = utils.MonitorConfigMap(ctx, mgr.GetCache(), bootstrapConfigMapName, bootConfig.Data); err != nil { log.Error(err, "Failed to monitor bootstrap configmap") os.Exit(1) } + // Same for the variant, which the process can only change by restarting. + if err = monitorVariant(ctx, mgr, variant); err != nil { + log.Error(err, "Failed to monitor the product variant") + os.Exit(1) + } + options := options.ControllerOptions{ - DetectedProvider: provider, - EnterpriseCRDExists: enterpriseCRDExists, - ClusterDomain: clusterDomain, - KubernetesVersion: kubernetesVersion, - ManageCRDs: manageCRDs, - ShutdownContext: ctx, - K8sClientset: clientset, - MultiTenant: multiTenant, - ElasticExternal: useExternalElastic, - Cloud: isCloudBuild(), - ESMigration: elasticIsMigrating, - UseV3CRDs: v3CRDs, - APIDiscovery: apiDiscovery, + DetectedProvider: provider, + Variant: variant, + ClusterDomain: clusterDomain, + KubernetesVersion: kubernetesVersion, + ManageCRDs: manageCRDs, + ShutdownContext: ctx, + K8sClientset: clientset, + MultiTenant: multiTenant, + ElasticExternal: useExternalElastic, + Cloud: isCloudBuild(), + ESMigration: elasticIsMigrating, + UseV3CRDs: v3CRDs, + APIDiscovery: apiDiscovery, } // Before we start any controllers, make sure our options are valid. @@ -598,7 +640,7 @@ If a value other than 'all' is specified, the first CRD with a prefix of the spe // Register custom Prometheus metrics collector. if common.MetricsEnabled() { - collector := metrics.NewOperatorCollector(mgr.GetClient(), enterpriseCRDExists) + collector := metrics.NewOperatorCollector(mgr.GetClient(), variant.IsEnterprise()) ctrlmetrics.Registry.MustRegister(collector) } @@ -664,6 +706,98 @@ func setKubernetesServiceEnv(kubeconfigFile string) error { return nil } +// waitForVariant blocks until an Installation exists and returns the variant it asks for. The +// operator has nothing to do before then, and the bootstrap flag is only ever for the CRDs above. +func waitForVariant(ctx context.Context, c client.Client, log logr.Logger) operatortigeraiov1.ProductVariant { + for first := true; ; first = false { + variant, err := effectiveVariant(ctx, c) + switch { + case err != nil: + log.Error(err, "Failed to read the Installation, will retry") + case variant != "": + return variant + case first: + log.Info("Waiting for an Installation") + } + + select { + case <-time.After(2 * time.Second): + case <-ctx.Done(): + log.Info("Requested to stop while waiting for an Installation") + os.Exit(0) + } + } +} + +// effectiveVariant returns the variant the Installation asks for, merging in the overlay. It +// returns an empty variant when no Installation exists. +func effectiveVariant(ctx context.Context, c client.Client) (operatortigeraiov1.ProductVariant, error) { + instance := &operatortigeraiov1.Installation{} + if err := c.Get(ctx, utils.DefaultInstanceKey, instance); err != nil { + if errors.IsNotFound(err) { + return "", nil + } + return "", err + } + spec := instance.Spec + + // The overlay can set the variant like any other field, so it has to be merged in. + overlay := &operatortigeraiov1.Installation{} + if err := c.Get(ctx, utils.OverlayInstanceKey, overlay); err != nil { + if !errors.IsNotFound(err) { + return "", err + } + } else { + spec = utils.OverrideInstallationSpec(spec, overlay.Spec) + } + + if spec.Variant == "" { + // An Installation that doesn't ask for a variant gets Calico. + return operatortigeraiov1.Calico, nil + } + return spec.Variant, nil +} + +// monitorVariant restarts the operator when the effective variant moves off the one this +// process booted with. +func monitorVariant(ctx context.Context, mgr manager.Manager, booted operatortigeraiov1.ProductVariant) error { + // The cache isn't running yet, so don't wait on a sync that can't happen. + informer, err := mgr.GetCache().GetInformer(ctx, &operatortigeraiov1.Installation{}, cache.BlockUntilSynced(false)) + if err != nil { + return err + } + + // Re-resolve rather than reading the event's object, since the effective variant is the + // merge of the default Installation and the overlay. + c := mgr.GetClient() + check := func() { + // Exiting mid-uninstall would skip the graceful termination wait in main, which + // holds the process open so controllers can run their finalizers. + instance := &operatortigeraiov1.Installation{} + if err := c.Get(ctx, utils.DefaultInstanceKey, instance); err == nil && instance.DeletionTimestamp != nil { + return + } + + requested, err := effectiveVariant(ctx, c) + if err != nil { + log.Error(err, "Failed to resolve the requested variant") + return + } + + if requested != "" && requested != booted { + log.Info("Requested variant changed, rebooting", "booted", booted, "requested", requested) + os.Exit(0) + } + } + + _, err = informer.AddEventHandler(clientgocache.ResourceEventHandlerFuncs{ + AddFunc: func(any) { check() }, + UpdateFunc: func(_, _ any) { check() }, + DeleteFunc: func(any) { check() }, + }) + return err +} + func showCRDs(variant operatortigeraiov1.ProductVariant, outputType string) error { first := true for _, v := range crds.GetCRDs(variant, os.Getenv("CALICO_API_GROUP") == "projectcalico.org/v3") { diff --git a/pkg/common/discovery/discovery.go b/pkg/common/discovery/discovery.go index 74846f228e..cc0ee2b2b5 100644 --- a/pkg/common/discovery/discovery.go +++ b/pkg/common/discovery/discovery.go @@ -31,10 +31,8 @@ import ( const gkeNodeLabelPrefix = "cloud.google.com/gke-" -// RequiresTigeraSecure determines if the configuration requires we start the tigera secure -// controllers. -func RequiresTigeraSecure(clientset *kubernetes.Clientset) (bool, error) { - // Use the discovery client to determine if the tigera secure specific APIs exist. +// EnterpriseAPIsExist reports whether the cluster serves the Calico Enterprise APIs. +func EnterpriseAPIsExist(clientset *kubernetes.Clientset) (bool, error) { resources, err := clientset.Discovery().ServerResourcesForGroupVersion("operator.tigera.io/v1") if err != nil { return false, err diff --git a/pkg/controller/apiserver/apiserver_controller.go b/pkg/controller/apiserver/apiserver_controller.go index 700a958891..020161d3de 100644 --- a/pkg/controller/apiserver/apiserver_controller.go +++ b/pkg/controller/apiserver/apiserver_controller.go @@ -103,7 +103,7 @@ func Add(mgr manager.Manager, opts options.ControllerOptions) error { return fmt.Errorf("apiserver-controller failed to watch ConfigMap %s: %w", render.K8sSvcEndpointConfigMapName, err) } - if opts.EnterpriseCRDExists { + if opts.Variant.IsEnterprise() { // Watch for changes to ApplicationLayer err = c.WatchObject(&operatorv1.ApplicationLayer{ObjectMeta: metav1.ObjectMeta{Name: utils.DefaultEnterpriseInstanceKey.Name}}, &handler.EnqueueRequestForObject{}) if err != nil { @@ -310,7 +310,7 @@ func (r *ReconcileAPIServer) Reconcile(ctx context.Context, request reconcile.Re } // Query for the installation object. - _, installationSpec, err := utils.GetInstallationSpec(context.Background(), r.client) + installationSpec, err := utils.GetInstallationSpec(context.Background(), r.client) if err != nil { if errors.IsNotFound(err) { r.status.SetDegraded(operatorv1.ResourceNotFound, "Installation not found", err, reqLogger) diff --git a/pkg/controller/apiserver/apiserver_controller_test.go b/pkg/controller/apiserver/apiserver_controller_test.go index d192103173..8d253db514 100644 --- a/pkg/controller/apiserver/apiserver_controller_test.go +++ b/pkg/controller/apiserver/apiserver_controller_test.go @@ -170,8 +170,8 @@ var _ = Describe("apiserver controller tests", func() { tierWatchReady: ready, migrationWatchReady: &utils.ReadyFlag{}, opts: options.ControllerOptions{ - EnterpriseCRDExists: true, - DetectedProvider: operatorv1.ProviderNone, + Variant: operatorv1.CalicoEnterprise, + DetectedProvider: operatorv1.ProviderNone, }, } _, err := r.Reconcile(ctx, reconcile.Request{}) @@ -229,8 +229,8 @@ var _ = Describe("apiserver controller tests", func() { tierWatchReady: ready, migrationWatchReady: &utils.ReadyFlag{}, opts: options.ControllerOptions{ - EnterpriseCRDExists: true, - DetectedProvider: operatorv1.ProviderNone, + Variant: operatorv1.CalicoEnterprise, + DetectedProvider: operatorv1.ProviderNone, }, } _, err := r.Reconcile(ctx, reconcile.Request{}) @@ -282,9 +282,9 @@ var _ = Describe("apiserver controller tests", func() { tierWatchReady: ready, migrationWatchReady: &utils.ReadyFlag{}, opts: options.ControllerOptions{ - EnterpriseCRDExists: true, - DetectedProvider: operatorv1.ProviderNone, - ClusterDomain: dns.DefaultClusterDomain, + Variant: operatorv1.CalicoEnterprise, + DetectedProvider: operatorv1.ProviderNone, + ClusterDomain: dns.DefaultClusterDomain, }, } _, err := r.Reconcile(ctx, reconcile.Request{}) @@ -307,8 +307,8 @@ var _ = Describe("apiserver controller tests", func() { tierWatchReady: ready, migrationWatchReady: &utils.ReadyFlag{}, opts: options.ControllerOptions{ - EnterpriseCRDExists: true, - DetectedProvider: operatorv1.ProviderNone, + Variant: operatorv1.CalicoEnterprise, + DetectedProvider: operatorv1.ProviderNone, }, } _, err := r.Reconcile(ctx, reconcile.Request{}) @@ -329,8 +329,8 @@ var _ = Describe("apiserver controller tests", func() { tierWatchReady: ready, migrationWatchReady: &utils.ReadyFlag{}, opts: options.ControllerOptions{ - EnterpriseCRDExists: true, - DetectedProvider: operatorv1.ProviderNone, + Variant: operatorv1.CalicoEnterprise, + DetectedProvider: operatorv1.ProviderNone, }, } _, err := r.Reconcile(ctx, reconcile.Request{}) @@ -353,8 +353,8 @@ var _ = Describe("apiserver controller tests", func() { tierWatchReady: ready, migrationWatchReady: &utils.ReadyFlag{}, opts: options.ControllerOptions{ - EnterpriseCRDExists: true, - DetectedProvider: operatorv1.ProviderNone, + Variant: operatorv1.CalicoEnterprise, + DetectedProvider: operatorv1.ProviderNone, }, } _, err := r.Reconcile(ctx, reconcile.Request{}) @@ -375,8 +375,8 @@ var _ = Describe("apiserver controller tests", func() { tierWatchReady: notReady, migrationWatchReady: &utils.ReadyFlag{}, opts: options.ControllerOptions{ - EnterpriseCRDExists: true, - DetectedProvider: operatorv1.ProviderNone, + Variant: operatorv1.CalicoEnterprise, + DetectedProvider: operatorv1.ProviderNone, }, } _, err := r.Reconcile(ctx, reconcile.Request{}) @@ -400,8 +400,8 @@ var _ = Describe("apiserver controller tests", func() { tierWatchReady: ready, migrationWatchReady: &utils.ReadyFlag{}, opts: options.ControllerOptions{ - EnterpriseCRDExists: true, - DetectedProvider: operatorv1.ProviderNone, + Variant: operatorv1.CalicoEnterprise, + DetectedProvider: operatorv1.ProviderNone, }, } _, err := r.Reconcile(ctx, reconcile.Request{}) @@ -427,8 +427,8 @@ var _ = Describe("apiserver controller tests", func() { tierWatchReady: ready, migrationWatchReady: &utils.ReadyFlag{}, opts: options.ControllerOptions{ - EnterpriseCRDExists: true, - DetectedProvider: operatorv1.ProviderNone, + Variant: operatorv1.CalicoEnterprise, + DetectedProvider: operatorv1.ProviderNone, }, } _, err := r.Reconcile(ctx, reconcile.Request{}) @@ -452,8 +452,8 @@ var _ = Describe("apiserver controller tests", func() { tierWatchReady: notReady, migrationWatchReady: &utils.ReadyFlag{}, opts: options.ControllerOptions{ - EnterpriseCRDExists: true, - DetectedProvider: operatorv1.ProviderNone, + Variant: operatorv1.CalicoEnterprise, + DetectedProvider: operatorv1.ProviderNone, }, } _, err := r.Reconcile(ctx, reconcile.Request{}) @@ -478,8 +478,8 @@ var _ = Describe("apiserver controller tests", func() { tierWatchReady: ready, migrationWatchReady: &utils.ReadyFlag{}, opts: options.ControllerOptions{ - EnterpriseCRDExists: false, - DetectedProvider: operatorv1.ProviderNone, + Variant: operatorv1.Calico, + DetectedProvider: operatorv1.ProviderNone, }, } _, err := r.Reconcile(ctx, reconcile.Request{}) @@ -520,8 +520,8 @@ var _ = Describe("apiserver controller tests", func() { tierWatchReady: ready, migrationWatchReady: &utils.ReadyFlag{}, opts: options.ControllerOptions{ - EnterpriseCRDExists: true, - DetectedProvider: operatorv1.ProviderNone, + Variant: operatorv1.CalicoEnterprise, + DetectedProvider: operatorv1.ProviderNone, }, } _, err := r.Reconcile(ctx, reconcile.Request{NamespacedName: types.NamespacedName{ @@ -552,8 +552,8 @@ var _ = Describe("apiserver controller tests", func() { tierWatchReady: ready, migrationWatchReady: &utils.ReadyFlag{}, opts: options.ControllerOptions{ - EnterpriseCRDExists: true, - DetectedProvider: operatorv1.ProviderNone, + Variant: operatorv1.CalicoEnterprise, + DetectedProvider: operatorv1.ProviderNone, }, } Expect(cli.Create(ctx, ts)).NotTo(HaveOccurred()) @@ -604,8 +604,8 @@ var _ = Describe("apiserver controller tests", func() { tierWatchReady: ready, migrationWatchReady: &utils.ReadyFlag{}, opts: options.ControllerOptions{ - EnterpriseCRDExists: true, - DetectedProvider: operatorv1.ProviderNone, + Variant: operatorv1.CalicoEnterprise, + DetectedProvider: operatorv1.ProviderNone, }, } _, err := r.Reconcile(ctx, reconcile.Request{NamespacedName: types.NamespacedName{ @@ -673,8 +673,8 @@ var _ = Describe("apiserver controller tests", func() { tierWatchReady: ready, migrationWatchReady: &utils.ReadyFlag{}, opts: options.ControllerOptions{ - EnterpriseCRDExists: true, - DetectedProvider: operatorv1.ProviderNone, + Variant: operatorv1.CalicoEnterprise, + DetectedProvider: operatorv1.ProviderNone, }, } installation.Status.Conditions = []metav1.Condition{ @@ -777,8 +777,8 @@ var _ = Describe("apiserver controller tests", func() { tierWatchReady: ready, migrationWatchReady: &utils.ReadyFlag{}, opts: options.ControllerOptions{ - EnterpriseCRDExists: true, - DetectedProvider: operatorv1.ProviderNone, + Variant: operatorv1.CalicoEnterprise, + DetectedProvider: operatorv1.ProviderNone, }, } @@ -806,8 +806,8 @@ var _ = Describe("apiserver controller tests", func() { tierWatchReady: ready, migrationWatchReady: &utils.ReadyFlag{}, opts: options.ControllerOptions{ - EnterpriseCRDExists: true, - DetectedProvider: operatorv1.ProviderNone, + Variant: operatorv1.CalicoEnterprise, + DetectedProvider: operatorv1.ProviderNone, }, } @@ -836,9 +836,9 @@ var _ = Describe("apiserver controller tests", func() { tierWatchReady: ready, migrationWatchReady: &utils.ReadyFlag{}, opts: options.ControllerOptions{ - EnterpriseCRDExists: true, - DetectedProvider: operatorv1.ProviderNone, - MultiTenant: true, + Variant: operatorv1.CalicoEnterprise, + DetectedProvider: operatorv1.ProviderNone, + MultiTenant: true, }, } @@ -887,9 +887,9 @@ var _ = Describe("apiserver controller tests", func() { tierWatchReady: ready, migrationWatchReady: &utils.ReadyFlag{}, opts: options.ControllerOptions{ - EnterpriseCRDExists: true, - DetectedProvider: operatorv1.ProviderNone, - MultiTenant: true, + Variant: operatorv1.CalicoEnterprise, + DetectedProvider: operatorv1.ProviderNone, + MultiTenant: true, }, } @@ -922,10 +922,10 @@ var _ = Describe("apiserver controller tests", func() { tierWatchReady: ready, migrationWatchReady: &utils.ReadyFlag{}, opts: options.ControllerOptions{ - EnterpriseCRDExists: true, - DetectedProvider: operatorv1.ProviderNone, - UseV3CRDs: true, - ClusterDomain: dns.DefaultClusterDomain, + Variant: operatorv1.CalicoEnterprise, + DetectedProvider: operatorv1.ProviderNone, + UseV3CRDs: true, + ClusterDomain: dns.DefaultClusterDomain, }, } _, err := r.Reconcile(ctx, reconcile.Request{}) @@ -966,10 +966,10 @@ var _ = Describe("apiserver controller tests", func() { tierWatchReady: ready, migrationWatchReady: &utils.ReadyFlag{}, opts: options.ControllerOptions{ - EnterpriseCRDExists: false, - DetectedProvider: operatorv1.ProviderNone, - UseV3CRDs: true, - ClusterDomain: dns.DefaultClusterDomain, + Variant: operatorv1.Calico, + DetectedProvider: operatorv1.ProviderNone, + UseV3CRDs: true, + ClusterDomain: dns.DefaultClusterDomain, }, } _, err := r.Reconcile(ctx, reconcile.Request{}) @@ -994,9 +994,9 @@ var _ = Describe("apiserver controller tests", func() { tierWatchReady: ready, migrationWatchReady: &utils.ReadyFlag{}, opts: options.ControllerOptions{ - EnterpriseCRDExists: true, - DetectedProvider: operatorv1.ProviderNone, - UseV3CRDs: false, + Variant: operatorv1.CalicoEnterprise, + DetectedProvider: operatorv1.ProviderNone, + UseV3CRDs: false, }, } _, err := r.Reconcile(ctx, reconcile.Request{}) diff --git a/pkg/controller/applicationlayer/applicationlayer_controller.go b/pkg/controller/applicationlayer/applicationlayer_controller.go index bdf7195943..d8f0aa103d 100644 --- a/pkg/controller/applicationlayer/applicationlayer_controller.go +++ b/pkg/controller/applicationlayer/applicationlayer_controller.go @@ -54,7 +54,7 @@ var log = logf.Log.WithName("controller_applicationlayer") // Add creates a new ApplicationLayer Controller and adds it to the Manager. // The Manager will set fields on the Controller and Start it when the Manager is Started. func Add(mgr manager.Manager, opts options.ControllerOptions) error { - if !opts.EnterpriseCRDExists { + if !opts.Variant.IsEnterprise() { // No need to start this controller. return nil } @@ -80,6 +80,7 @@ func newReconciler(mgr manager.Manager, opts options.ControllerOptions, licenseA provider: opts.DetectedProvider, status: status.New(mgr.GetClient(), "applicationlayer", opts.KubernetesVersion), clusterDomain: opts.ClusterDomain, + variant: opts.Variant, licenseAPIReady: licenseAPIReady, } r.status.Run(opts.ShutdownContext) @@ -165,6 +166,7 @@ type ReconcileApplicationLayer struct { provider operatorv1.Provider status status.StatusManager clusterDomain string + variant operatorv1.ProductVariant licenseAPIReady *utils.ReadyFlag } @@ -193,6 +195,7 @@ func (r *ReconcileApplicationLayer) Reconcile(ctx context.Context, request recon r.status.SetDegraded(operatorv1.ResourceReadError, "Error querying for Application Layer", err, reqLogger) return reconcile.Result{}, err } + r.status.OnCRFound() // SetMetaData in the TigeraStatus such as observedGenerations. defer r.status.SetMetaData(&instance.ObjectMeta) @@ -226,7 +229,7 @@ func (r *ReconcileApplicationLayer) Reconcile(ctx context.Context, request recon return reconcile.Result{}, err } - variant, installationSpec, err := utils.GetInstallationSpec(ctx, r.client) + installationSpec, err := utils.GetInstallationSpec(ctx, r.client) if err != nil { if apierrors.IsNotFound(err) { r.status.SetDegraded(operatorv1.ResourceNotFound, "Installation not found", err, reqLogger) @@ -236,11 +239,6 @@ func (r *ReconcileApplicationLayer) Reconcile(ctx context.Context, request recon return reconcile.Result{}, err } - if !variant.IsEnterprise() { - r.status.SetDegraded(operatorv1.ResourceNotReady, "Waiting for network to be an enterprise variant", nil, reqLogger) - return reconcile.Result{}, nil - } - pullSecrets, err := utils.GetInstallationPullSecrets(installationSpec, r.client) if err != nil { r.status.SetDegraded(operatorv1.ResourceReadError, "Error retrieving pull secrets", err, reqLogger) @@ -253,6 +251,7 @@ func (r *ReconcileApplicationLayer) Reconcile(ctx context.Context, request recon r.status.SetDegraded(operatorv1.ResourceReadError, "Error checking GatewayAPI WAF state", err, reqLogger) return reconcile.Result{}, err } + if err = r.patchFelixConfiguration(ctx, instance, gatewayWAFEnabled); err != nil { r.status.SetDegraded(operatorv1.ResourcePatchError, "Error patching felix configuration", err, reqLogger) return reconcile.Result{}, err @@ -297,7 +296,7 @@ func (r *ReconcileApplicationLayer) Reconcile(ctx context.Context, request recon ch := utils.NewComponentHandler(log, r.client, r.scheme, instance) - if err = imageset.ApplyImageSet(ctx, r.client, variant, component); err != nil { + if err = imageset.ApplyImageSet(ctx, r.client, r.variant, component); err != nil { r.status.SetDegraded(operatorv1.ResourceUpdateError, "Error with images from ImageSet", err, reqLogger) return reconcile.Result{}, err } @@ -520,17 +519,7 @@ func (r *ReconcileApplicationLayer) patchFelixConfiguration(ctx context.Context, if err != nil { return err } - // Use Spec.Variant (via the second return of GetInstallationSpec) so the - // gate matches the renderer's decision to ship the L7 waypoint sidecar. - var variant operatorv1.ProductVariant - if _, spec, ierr := utils.GetInstallationSpec(ctx, r.client); ierr != nil { - if !apierrors.IsNotFound(ierr) { - return ierr - } - } else if spec != nil { - variant = spec.Variant - } - istioNeeds := utils.IstioRequiresPolicySync(istioCR, variant) + istioNeeds := utils.IstioRequiresPolicySync(istioCR, r.variant) _, err = utils.PatchFelixConfiguration(ctx, r.client, func(fc *v3.FelixConfiguration) (bool, error) { wafEventLogsFileEnabled := wafEventLogsFileRequired(al, gatewayWAFEnabled) diff --git a/pkg/controller/authentication/authentication_controller.go b/pkg/controller/authentication/authentication_controller.go index 7f77f10197..885c0df534 100644 --- a/pkg/controller/authentication/authentication_controller.go +++ b/pkg/controller/authentication/authentication_controller.go @@ -67,7 +67,7 @@ const ( // Add creates a new authentication Controller and adds it to the Manager. The Manager will set fields on the Controller // and Start it when the Manager is Started. func Add(mgr manager.Manager, opts options.ControllerOptions) error { - if !opts.EnterpriseCRDExists { + if !opts.Variant.IsEnterprise() { // No need to start this controller. return nil } @@ -113,6 +113,7 @@ func newReconciler(mgr manager.Manager, opts options.ControllerOptions, tierWatc provider: opts.DetectedProvider, status: status.New(mgr.GetClient(), "authentication", opts.KubernetesVersion), clusterDomain: opts.ClusterDomain, + variant: opts.Variant, tierWatchReady: tierWatchReady, multiTenant: opts.MultiTenant, } @@ -169,6 +170,7 @@ type ReconcileAuthentication struct { provider oprv1.Provider status status.StatusManager clusterDomain string + variant oprv1.ProductVariant tierWatchReady *utils.ReadyFlag multiTenant bool resolvedPodProxies []*httpproxy.Config @@ -192,6 +194,7 @@ func (r *ReconcileAuthentication) Reconcile(ctx context.Context, request reconci } return reconcile.Result{}, err } + r.status.OnCRFound() // SetMetaData in the TigeraStatus such as observedGenerations. @@ -230,7 +233,7 @@ func (r *ReconcileAuthentication) Reconcile(ctx context.Context, request reconci } // Query for the installation object. - variant, installationSpec, err := utils.GetInstallationSpec(context.Background(), r.client) + installationSpec, err := utils.GetInstallationSpec(context.Background(), r.client) if err != nil { if errors.IsNotFound(err) { r.status.SetDegraded(oprv1.ResourceNotFound, "Installation not found", err, reqLogger) @@ -239,10 +242,6 @@ func (r *ReconcileAuthentication) Reconcile(ctx context.Context, request reconci r.status.SetDegraded(oprv1.ResourceReadError, "Error querying installation", err, reqLogger) return reconcile.Result{}, err } - if !variant.IsEnterprise() { - r.status.SetDegraded(oprv1.ResourceNotReady, "Waiting for network to be an enterprise variant", nil, reqLogger) - return reconcile.Result{}, nil - } // Validate that the tier watch is ready before querying the tier to ensure we utilize the cache. if !r.tierWatchReady.IsReady() { @@ -278,6 +277,7 @@ func (r *ReconcileAuthentication) Reconcile(ctx context.Context, request reconci r.status.SetDegraded(oprv1.ResourceCreateError, "Unable to create the Tigera CA", err, reqLogger) return reconcile.Result{}, err } + dnsNames := dns.GetServiceDNSNames(render.DexObjectName, render.DexNamespace, r.clusterDomain) tlsKeyPair, err := certificateManager.GetOrCreateKeyPair(r.client, render.DexTLSSecretName, common.OperatorNamespace(), dnsNames) if err != nil { @@ -403,7 +403,7 @@ func (r *ReconcileAuthentication) Reconcile(ctx context.Context, request reconci reqLogger.V(3).Info("rendering components") component := render.Dex(dexComponentCfg) - if err = imageset.ApplyImageSet(ctx, r.client, variant, component); err != nil { + if err = imageset.ApplyImageSet(ctx, r.client, r.variant, component); err != nil { r.status.SetDegraded(oprv1.ResourceUpdateError, "Error with images from ImageSet", err, reqLogger) return reconcile.Result{}, err } @@ -448,6 +448,7 @@ func (r *ReconcileAuthentication) Reconcile(ctx context.Context, request reconci if err = r.client.Status().Update(ctx, authentication); err != nil { return reconcile.Result{}, err } + return reconcile.Result{}, nil } diff --git a/pkg/controller/authentication/authentication_controller_test.go b/pkg/controller/authentication/authentication_controller_test.go index 542e6bad6b..836c72e35a 100644 --- a/pkg/controller/authentication/authentication_controller_test.go +++ b/pkg/controller/authentication/authentication_controller_test.go @@ -181,7 +181,7 @@ var _ = Describe("authentication controller tests", func() { }, } Expect(cli.Create(ctx, ts)).NotTo(HaveOccurred()) - r := &ReconcileAuthentication{cli, scheme, operatorv1.ProviderNone, mockStatus, "", readyFlag, false, []*httpproxy.Config{}, metav1.Now()} + r := &ReconcileAuthentication{cli, scheme, operatorv1.ProviderNone, mockStatus, "", operatorv1.CalicoEnterprise, readyFlag, false, []*httpproxy.Config{}, metav1.Now()} _, err := r.Reconcile(ctx, reconcile.Request{NamespacedName: types.NamespacedName{ Name: "authentication", Namespace: "", @@ -206,7 +206,7 @@ var _ = Describe("authentication controller tests", func() { Expect(cli.Create(ctx, ts)).NotTo(HaveOccurred()) - r := &ReconcileAuthentication{cli, scheme, operatorv1.ProviderNone, mockStatus, "", readyFlag, false, []*httpproxy.Config{}, metav1.Now()} + r := &ReconcileAuthentication{cli, scheme, operatorv1.ProviderNone, mockStatus, "", operatorv1.CalicoEnterprise, readyFlag, false, []*httpproxy.Config{}, metav1.Now()} _, err := r.Reconcile(ctx, reconcile.Request{NamespacedName: types.NamespacedName{ Name: "authentication", Namespace: "", @@ -247,7 +247,7 @@ var _ = Describe("authentication controller tests", func() { }, } Expect(cli.Create(ctx, ts)).NotTo(HaveOccurred()) - r := &ReconcileAuthentication{cli, scheme, operatorv1.ProviderNone, mockStatus, "", readyFlag, false, []*httpproxy.Config{}, metav1.Now()} + r := &ReconcileAuthentication{cli, scheme, operatorv1.ProviderNone, mockStatus, "", operatorv1.CalicoEnterprise, readyFlag, false, []*httpproxy.Config{}, metav1.Now()} _, err := r.Reconcile(ctx, reconcile.Request{NamespacedName: types.NamespacedName{ Name: "authentication", Namespace: "", @@ -307,7 +307,7 @@ var _ = Describe("authentication controller tests", func() { }, } Expect(cli.Create(ctx, ts)).NotTo(HaveOccurred()) - r := &ReconcileAuthentication{cli, scheme, operatorv1.ProviderNone, mockStatus, "", readyFlag, false, []*httpproxy.Config{}, metav1.Now()} + r := &ReconcileAuthentication{cli, scheme, operatorv1.ProviderNone, mockStatus, "", operatorv1.CalicoEnterprise, readyFlag, false, []*httpproxy.Config{}, metav1.Now()} _, err := r.Reconcile(ctx, reconcile.Request{NamespacedName: types.NamespacedName{ Name: "authentication", Namespace: "", @@ -352,7 +352,7 @@ var _ = Describe("authentication controller tests", func() { Expect(cli.Create(ctx, auth)).ToNot(HaveOccurred()) // Reconcile - r := &ReconcileAuthentication{cli, scheme, operatorv1.ProviderNone, mockStatus, "", readyFlag, false, []*httpproxy.Config{}, metav1.Now()} + r := &ReconcileAuthentication{cli, scheme, operatorv1.ProviderNone, mockStatus, "", operatorv1.CalicoEnterprise, readyFlag, false, []*httpproxy.Config{}, metav1.Now()} _, err := r.Reconcile(ctx, reconcile.Request{}) Expect(err).ShouldNot(HaveOccurred()) authentication, err := utils.GetAuthentication(ctx, cli) @@ -379,7 +379,7 @@ var _ = Describe("authentication controller tests", func() { Expect(cli.Create(ctx, auth)).ToNot(HaveOccurred()) // Reconcile - r := &ReconcileAuthentication{client: cli, scheme: scheme, provider: operatorv1.ProviderNone, status: mockStatus, tierWatchReady: readyFlag, multiTenant: true} + r := &ReconcileAuthentication{client: cli, scheme: scheme, provider: operatorv1.ProviderNone, status: mockStatus, variant: operatorv1.CalicoEnterprise, tierWatchReady: readyFlag, multiTenant: true} _, err := r.Reconcile(ctx, reconcile.Request{}) Expect(err).Should(HaveOccurred()) }) @@ -409,6 +409,7 @@ var _ = Describe("authentication controller tests", func() { scheme: scheme, provider: operatorv1.ProviderNone, status: mockStatus, + variant: operatorv1.CalicoEnterprise, tierWatchReady: readyFlag, } _, err := r.Reconcile(ctx, reconcile.Request{}) @@ -447,6 +448,7 @@ var _ = Describe("authentication controller tests", func() { scheme: scheme, provider: operatorv1.ProviderNone, status: mockStatus, + variant: operatorv1.CalicoEnterprise, tierWatchReady: readyFlag, } _, err := r.Reconcile(ctx, reconcile.Request{}) @@ -498,6 +500,7 @@ var _ = Describe("authentication controller tests", func() { scheme: scheme, provider: operatorv1.ProviderNone, status: mockStatus, + variant: operatorv1.CalicoEnterprise, tierWatchReady: readyFlag, } }) @@ -685,6 +688,7 @@ var _ = Describe("authentication controller tests", func() { scheme: scheme, provider: operatorv1.ProviderNone, status: mockStatus, + variant: operatorv1.CalicoEnterprise, tierWatchReady: readyFlag, } _, err = r.Reconcile(ctx, reconcile.Request{}) @@ -769,7 +773,7 @@ var _ = Describe("authentication controller tests", func() { } Expect(cli.Create(ctx, idpSecret)).ToNot(HaveOccurred()) Expect(cli.Create(ctx, auth)).ToNot(HaveOccurred()) - r := &ReconcileAuthentication{cli, scheme, operatorv1.ProviderNone, mockStatus, "", readyFlag, false, []*httpproxy.Config{}, metav1.Now()} + r := &ReconcileAuthentication{cli, scheme, operatorv1.ProviderNone, mockStatus, "", operatorv1.CalicoEnterprise, readyFlag, false, []*httpproxy.Config{}, metav1.Now()} _, err := r.Reconcile(ctx, reconcile.Request{}) if expectReconcilePass { Expect(err).ToNot(HaveOccurred()) diff --git a/pkg/controller/clusterconnection/clusterconnection_controller.go b/pkg/controller/clusterconnection/clusterconnection_controller.go index 4b1b7dc8f6..4c55406bd9 100644 --- a/pkg/controller/clusterconnection/clusterconnection_controller.go +++ b/pkg/controller/clusterconnection/clusterconnection_controller.go @@ -80,7 +80,7 @@ func Add(mgr manager.Manager, opts options.ControllerOptions) error { return fmt.Errorf("failed to create %s: %w", controllerName, err) } - if opts.EnterpriseCRDExists { + if opts.Variant.IsEnterprise() { // Watch for changes to License and Tier, as their status is used as input to determine whether network policy should be reconciled by this controller. go utils.WaitToAddLicenseKeyWatch(c, opts.K8sClientset, log, nil) } @@ -131,7 +131,7 @@ func Add(mgr manager.Manager, opts options.ControllerOptions) error { return fmt.Errorf("clusterconnection-controller failed to watch management-cluster-connection Tigerastatus: %w", err) } - if opts.EnterpriseCRDExists { + if opts.Variant.IsEnterprise() { err = c.WatchObject(&operatorv1.ManagementCluster{}, &handler.EnqueueRequestForObject{}) if err != nil { return fmt.Errorf("%s failed to watch primary resource: %w", controllerName, err) @@ -174,6 +174,7 @@ func newReconciler( provider: p, status: statusMgr, clusterDomain: opts.ClusterDomain, + variant: opts.Variant, tierWatchReady: tierWatchReady, clusterInfoWatchReady: clusterInfoWatchReady, } @@ -191,6 +192,7 @@ type ReconcileConnection struct { provider operatorv1.Provider status status.StatusManager clusterDomain string + variant operatorv1.ProductVariant tierWatchReady *utils.ReadyFlag clusterInfoWatchReady *utils.ReadyFlag resolvedPodProxies []*httpproxy.Config @@ -206,7 +208,7 @@ func (r *ReconcileConnection) Reconcile(ctx context.Context, request reconcile.R reqLogger.V(2).Info("Reconciling the management cluster connection") result := reconcile.Result{} - variant, installationSpec, err := utils.GetInstallationSpec(ctx, r.cli) + installationSpec, err := utils.GetInstallationSpec(ctx, r.cli) if err != nil { return result, err } @@ -245,7 +247,7 @@ func (r *ReconcileConnection) Reconcile(ctx context.Context, request reconcile.R } // Verify the cluster doesn't also have the ManagementCluster CRD installed. - if variant.IsEnterprise() { + if r.variant.IsEnterprise() { managementCluster, err := utils.GetManagementCluster(ctx, r.cli) if err != nil { r.status.SetDegraded(operatorv1.ResourceReadError, "Error reading ManagementCluster", err, reqLogger) @@ -291,7 +293,7 @@ func (r *ReconcileConnection) Reconcile(ctx context.Context, request reconcile.R includeSystem := false if managementClusterConnection.Spec.TLS.CA == operatorv1.CATypePublic { - if variant == operatorv1.Calico { + if r.variant == operatorv1.Calico { r.status.SetDegraded(operatorv1.InvalidConfigurationError, "Guardian CA cannot be public in Calico.", nil, reqLogger) return reconcile.Result{}, nil } @@ -306,7 +308,7 @@ func (r *ReconcileConnection) Reconcile(ctx context.Context, request reconcile.R } var guardianKeyPair certificatemanagement.KeyPairInterface - if !variant.IsEnterprise() { + if !r.variant.IsEnterprise() { guardianCertificateNames := dns.GetServiceDNSNames("guardian", render.GuardianNamespace, r.clusterDomain) guardianCertificateNames = append(guardianCertificateNames, "localhost", "127.0.0.1") guardianKeyPair, err = certificateManager.GetOrCreateKeyPair(r.cli, render.GuardianKeyPairSecret, whisker.WhiskerNamespace, guardianCertificateNames) @@ -409,7 +411,7 @@ func (r *ReconcileConnection) Reconcile(ctx context.Context, request reconcile.R r.status.SetDegraded(operatorv1.ResourceReadError, "Error querying clusterInformation", err, reqLogger) return reconcile.Result{}, err } - if variant.IsEnterprise() { + if r.variant.IsEnterprise() { managedClusterVersion = clusterInformation.Spec.CNXVersion } else { managedClusterVersion = clusterInformation.Spec.CalicoVersion @@ -422,7 +424,7 @@ func (r *ReconcileConnection) Reconcile(ctx context.Context, request reconcile.R } var includeEgressNetworkPolicy bool - if variant.IsEnterprise() { + if r.variant.IsEnterprise() { // Ensure the license can support enterprise policy, before rendering any network policies within it. if license, err := utils.FetchLicenseKey(ctx, r.cli); err == nil { if utils.IsFeatureActive(license, common.EgressAccessControlFeature) { @@ -483,7 +485,7 @@ func (r *ReconcileConnection) Reconcile(ctx context.Context, request reconcile.R } } - if err = imageset.ApplyImageSet(ctx, r.cli, variant, components...); err != nil { + if err = imageset.ApplyImageSet(ctx, r.cli, r.variant, components...); err != nil { r.status.SetDegraded(operatorv1.ResourceUpdateError, "Error with images from ImageSet", err, reqLogger) return reconcile.Result{}, err } diff --git a/pkg/controller/clusterconnection/shim_test.go b/pkg/controller/clusterconnection/shim_test.go index 7446d229ac..a792f930cf 100644 --- a/pkg/controller/clusterconnection/shim_test.go +++ b/pkg/controller/clusterconnection/shim_test.go @@ -40,6 +40,7 @@ func NewReconcilerWithShims( ) reconcile.Reconciler { opts := options.ControllerOptions{ ShutdownContext: context.Background(), + Variant: operatorv1.CalicoEnterprise, } return newReconciler(cli, schema, status, provider, tierWatchReady, clusterInfoWatchReady, opts) diff --git a/pkg/controller/compliance/compliance_controller.go b/pkg/controller/compliance/compliance_controller.go index d42ff76d62..7bbd6ef306 100644 --- a/pkg/controller/compliance/compliance_controller.go +++ b/pkg/controller/compliance/compliance_controller.go @@ -55,7 +55,7 @@ var log = logf.Log.WithName("controller_compliance") // Add creates a new Compliance Controller and adds it to the Manager. The Manager will set fields on the Controller // and Start it when the Manager is Started. func Add(mgr manager.Manager, opts options.ControllerOptions) error { - if !opts.EnterpriseCRDExists { + if !opts.Variant.IsEnterprise() { // No need to start this controller. return nil } @@ -292,7 +292,7 @@ func (r *ReconcileCompliance) Reconcile(ctx context.Context, request reconcile.R } // Query for the installation object. - variant, installationSpec, err := utils.GetInstallationSpec(ctx, r.client) + installationSpec, err := utils.GetInstallationSpec(ctx, r.client) if err != nil { if errors.IsNotFound(err) { r.status.SetDegraded(operatorv1.ResourceNotFound, "Installation not found", err, reqLogger) @@ -509,7 +509,7 @@ func (r *ReconcileCompliance) Reconcile(ctx context.Context, request reconcile.R return reconcile.Result{}, err } - if err = imageset.ApplyImageSet(ctx, r.client, variant, comp); err != nil { + if err = imageset.ApplyImageSet(ctx, r.client, r.opts.Variant, comp); err != nil { r.status.SetDegraded(operatorv1.ResourceUpdateError, "Error with images from ImageSet", err, reqLogger) return reconcile.Result{}, err } diff --git a/pkg/controller/compliance/compliance_controller_cloud_test.go b/pkg/controller/compliance/compliance_controller_cloud_test.go index f0913860d2..d27839748b 100644 --- a/pkg/controller/compliance/compliance_controller_cloud_test.go +++ b/pkg/controller/compliance/compliance_controller_cloud_test.go @@ -186,6 +186,7 @@ var _ = Describe("Cloud Compliance controller tests", func() { ClusterDomain: dns.DefaultClusterDomain, ShutdownContext: context.TODO(), Cloud: true, + Variant: operatorv1.CalicoEnterprise, }, } r.status.Run(r.opts.ShutdownContext) diff --git a/pkg/controller/compliance/compliance_controller_test.go b/pkg/controller/compliance/compliance_controller_test.go index 7ec3dec59b..9bece1257c 100644 --- a/pkg/controller/compliance/compliance_controller_test.go +++ b/pkg/controller/compliance/compliance_controller_test.go @@ -103,6 +103,7 @@ var _ = Describe("Compliance controller tests", func() { opts: options.ControllerOptions{ DetectedProvider: operatorv1.ProviderNone, ClusterDomain: dns.DefaultClusterDomain, + Variant: operatorv1.CalicoEnterprise, }, } // We start off with a 'standard' installation, with nothing special @@ -642,6 +643,7 @@ var _ = Describe("Compliance controller tests", func() { opts: options.ControllerOptions{ DetectedProvider: operatorv1.ProviderNone, ClusterDomain: dns.DefaultClusterDomain, + Variant: operatorv1.CalicoEnterprise, }, } }) diff --git a/pkg/controller/csr/csr_controller.go b/pkg/controller/csr/csr_controller.go index 32618b5139..20676a956f 100644 --- a/pkg/controller/csr/csr_controller.go +++ b/pkg/controller/csr/csr_controller.go @@ -102,7 +102,7 @@ func Add(mgr manager.Manager, opts options.ControllerOptions) error { return err } - if opts.EnterpriseCRDExists { + if opts.Variant.IsEnterprise() { if err = c.WatchObject(&operatorv1.Monitor{}, &handler.EnqueueRequestForObject{}); err != nil { return fmt.Errorf("monitor-controller failed to watch primary resource: %w", err) } @@ -128,14 +128,14 @@ func newReconciler(mgr manager.Manager, opts options.ControllerOptions) (reconci } return &reconcileCSR{ - client: mgr.GetClient(), - clientset: opts.K8sClientset, - calicoClient: calicoClient, - scheme: mgr.GetScheme(), - provider: opts.DetectedProvider, - clusterDomain: opts.ClusterDomain, - allowedTLSAssets: allowedAssets(opts.ClusterDomain), - enterpriseCRDExists: opts.EnterpriseCRDExists, + client: mgr.GetClient(), + clientset: opts.K8sClientset, + calicoClient: calicoClient, + scheme: mgr.GetScheme(), + provider: opts.DetectedProvider, + clusterDomain: opts.ClusterDomain, + allowedTLSAssets: allowedAssets(opts.ClusterDomain), + variant: opts.Variant, }, nil } @@ -170,14 +170,14 @@ var _ reconcile.Reconciler = &reconcileCSR{} // conditions for signer name "tigera.io/operator-signer". This is the controller that monitors, approves and signs // these CSRs. It will only sign requests that are pre-defined and reject others in order to avoid malicious requests. type reconcileCSR struct { - client client.Client - clientset kubernetes.Interface - calicoClient calicoclient.Interface - scheme *runtime.Scheme - provider operatorv1.Provider - clusterDomain string - allowedTLSAssets map[string]tlsAsset - enterpriseCRDExists bool + client client.Client + clientset kubernetes.Interface + calicoClient calicoclient.Interface + scheme *runtime.Scheme + provider operatorv1.Provider + clusterDomain string + allowedTLSAssets map[string]tlsAsset + variant operatorv1.ProductVariant } func (r *reconcileCSR) Reconcile(ctx context.Context, request reconcile.Request) (reconcile.Result, error) { @@ -194,7 +194,7 @@ func (r *reconcileCSR) Reconcile(ctx context.Context, request reconcile.Request) } needsCSRRole := instance.Spec.CertificateManagement != nil - if !needsCSRRole && r.enterpriseCRDExists { + if !needsCSRRole && r.variant.IsEnterprise() { monitorCR := &operatorv1.Monitor{} if err := r.client.Get(ctx, utils.DefaultEnterpriseInstanceKey, monitorCR); err != nil { if apierrors.IsNotFound(err) { diff --git a/pkg/controller/csr/csr_controller_test.go b/pkg/controller/csr/csr_controller_test.go index ea764bd0e9..3e5f9b2196 100644 --- a/pkg/controller/csr/csr_controller_test.go +++ b/pkg/controller/csr/csr_controller_test.go @@ -98,14 +98,14 @@ var _ = Describe("CSR controller tests", func() { mockStatus = &status.MockStatus{} mockStatus.On("OnCRFound").Return() r = reconcileCSR{ - client: cli, - clientset: clientset, - calicoClient: calicoClientset, - scheme: scheme, - provider: operatorv1.ProviderNone, - clusterDomain: dns.DefaultClusterDomain, - allowedTLSAssets: allowedAssets(dns.DefaultClusterDomain), - enterpriseCRDExists: true, + client: cli, + clientset: clientset, + calicoClient: calicoClientset, + scheme: scheme, + provider: operatorv1.ProviderNone, + clusterDomain: dns.DefaultClusterDomain, + allowedTLSAssets: allowedAssets(dns.DefaultClusterDomain), + variant: operatorv1.TigeraSecureEnterprise, } }) diff --git a/pkg/controller/egressgateway/egressgateway_controller.go b/pkg/controller/egressgateway/egressgateway_controller.go index 1531baf3bf..745083fe14 100644 --- a/pkg/controller/egressgateway/egressgateway_controller.go +++ b/pkg/controller/egressgateway/egressgateway_controller.go @@ -58,7 +58,7 @@ var log = logf.Log.WithName("controller_egressgateway") // Add creates a new EgressGateway Controller and adds it to the Manager. // The Manager will set fields on the Controller and Start it when the Manager is Started. func Add(mgr manager.Manager, opts options.ControllerOptions) error { - if !opts.EnterpriseCRDExists { + if !opts.Variant.IsEnterprise() { // No need to start this controller. return nil } @@ -84,6 +84,7 @@ func newReconciler(mgr manager.Manager, opts options.ControllerOptions, licenseA provider: opts.DetectedProvider, status: status.New(mgr.GetClient(), "egressgateway", opts.KubernetesVersion), clusterDomain: opts.ClusterDomain, + variant: opts.Variant, licenseAPIReady: licenseAPIReady, } r.status.Run(opts.ShutdownContext) @@ -132,6 +133,7 @@ type ReconcileEgressGateway struct { provider operatorv1.Provider status status.StatusManager clusterDomain string + variant operatorv1.ProductVariant licenseAPIReady *utils.ReadyFlag } @@ -241,7 +243,7 @@ func (r *ReconcileEgressGateway) Reconcile(ctx context.Context, request reconcil return reconcile.Result{RequeueAfter: utils.StandardRetry}, nil } - variant, installationSpec, err := utils.GetInstallationSpec(ctx, r.client) + installationSpec, err := utils.GetInstallationSpec(ctx, r.client) if err != nil { if errors.IsNotFound(err) { reqLogger.Error(err, "Installation not found") @@ -260,16 +262,6 @@ func (r *ReconcileEgressGateway) Reconcile(ctx context.Context, request reconcil return reconcile.Result{}, err } - if !variant.IsEnterprise() { - degradedMsg := "Waiting for network to be an enterprise variant" - reqLogger.Error(err, degradedMsg) - r.status.SetDegraded(operatorv1.ResourceNotReady, degradedMsg, nil, reqLogger) - for _, egw := range egwsToReconcile { - setDegraded(r.client, ctx, &egw, reconcileErr, degradedMsg) - } - return reconcile.Result{}, nil - } - installStatus, err := utils.GetInstallationStatus(ctx, r.client) if err != nil { reqLogger.Error(err, "Error querying installation status") @@ -315,7 +307,7 @@ func (r *ReconcileEgressGateway) Reconcile(ctx context.Context, request reconcil // Reconcile all the EGWs var errMsgs []string for _, egw := range egwsToReconcile { - err = r.reconcileEgressGateway(ctx, &egw, reqLogger, variant, fc, pullSecrets, installationSpec, namespaceAndNames) + err = r.reconcileEgressGateway(ctx, &egw, reqLogger, r.variant, fc, pullSecrets, installationSpec, namespaceAndNames) if err != nil { reqLogger.Error(err, "Error reconciling egress gateway") errMsgs = append(errMsgs, err.Error()) diff --git a/pkg/controller/gatewayapi/gatewayapi_controller.go b/pkg/controller/gatewayapi/gatewayapi_controller.go index 62e7c67bf3..9ace267b28 100644 --- a/pkg/controller/gatewayapi/gatewayapi_controller.go +++ b/pkg/controller/gatewayapi/gatewayapi_controller.go @@ -73,10 +73,10 @@ func Add(mgr manager.Manager, opts options.ControllerOptions) error { r := &ReconcileGatewayAPI{ client: mgr.GetClient(), scheme: mgr.GetScheme(), - enterpriseCRDsExist: opts.EnterpriseCRDExists, tierWatchReady: &utils.ReadyFlag{}, status: status.New(mgr.GetClient(), "gatewayapi", opts.KubernetesVersion), clusterDomain: opts.ClusterDomain, + variant: opts.Variant, multiTenant: opts.MultiTenant, newComponentHandler: utils.NewComponentHandler, } @@ -177,10 +177,10 @@ var _ reconcile.Reconciler = &ReconcileGatewayAPI{} type ReconcileGatewayAPI struct { client client.Client scheme *runtime.Scheme - enterpriseCRDsExist bool tierWatchReady *utils.ReadyFlag status status.StatusManager clusterDomain string + variant operatorv1.ProductVariant multiTenant bool newComponentHandler func(log logr.Logger, client client.Client, scheme *runtime.Scheme, cr metav1.Object) utils.ComponentHandler watchEnvoyProxy func(namespacedName operatorv1.NamespacedName) error @@ -220,7 +220,7 @@ func (r *ReconcileGatewayAPI) Reconcile(ctx context.Context, request reconcile.R defer r.status.SetMetaData(&gatewayAPI.ObjectMeta) // Get the Installation, for private registry and pull secret config. - variant, installationSpec, err := utils.GetInstallationSpec(ctx, r.client) + installationSpec, err := utils.GetInstallationSpec(ctx, r.client) if err != nil { if errors.IsNotFound(err) { r.status.SetDegraded(operatorv1.ResourceNotFound, "Installation not found", err, reqLogger) @@ -230,11 +230,6 @@ func (r *ReconcileGatewayAPI) Reconcile(ctx context.Context, request reconcile.R return reconcile.Result{}, err } - if variant == "" { - r.status.SetDegraded(operatorv1.ResourceNotReady, "Waiting for Installation Variant to be set", nil, reqLogger) - return reconcile.Result{}, nil - } - // Render CRDs. Note, we do this as early as possible so as to enable the following // controller code that reads GatewayClasses and EnvoyProxies (which depends on the CRDs // already existing). For the CRDs we specify nil for the owning CR - i.e. no ownership - @@ -566,7 +561,7 @@ func (r *ReconcileGatewayAPI) Reconcile(ctx context.Context, request reconcile.R r.status.SetDegraded(operatorv1.ResourceCreateError, "Error rendering Gateway API resources", err, log) return reconcile.Result{}, err } - err = imageset.ApplyImageSet(ctx, r.client, variant, nonCRDComponent) + err = imageset.ApplyImageSet(ctx, r.client, r.variant, nonCRDComponent) if err != nil { r.status.SetDegraded(operatorv1.ResourceCreateError, "Error with images from ImageSet", err, log) return reconcile.Result{}, err @@ -584,7 +579,7 @@ func (r *ReconcileGatewayAPI) Reconcile(ctx context.Context, request reconcile.R } // Per-namespace resources, owned by the namespace's Gateways so the GC cleans them up. - if err = r.reconcileGatewayNamespaceResources(ctx, trustedBundle, pullSecrets, variant.IsEnterprise(), gwList.Items, ownedClass); err != nil { + if err = r.reconcileGatewayNamespaceResources(ctx, trustedBundle, pullSecrets, r.variant.IsEnterprise(), gwList.Items, ownedClass); err != nil { r.status.SetDegraded(operatorv1.ResourceUpdateError, "Error writing per-namespace Gateway resources", err, log) return reconcile.Result{}, err } diff --git a/pkg/controller/gatewayapi/gatewayapi_controller_test.go b/pkg/controller/gatewayapi/gatewayapi_controller_test.go index 6c04ae5118..c3e2f403af 100644 --- a/pkg/controller/gatewayapi/gatewayapi_controller_test.go +++ b/pkg/controller/gatewayapi/gatewayapi_controller_test.go @@ -116,6 +116,7 @@ var _ = Describe("Gateway API controller tests", func() { client: c, scheme: scheme, status: mockStatus, + variant: operatorv1.CalicoEnterprise, tierWatchReady: &utils.ReadyFlag{}, newComponentHandler: FakeComponentHandler, watchEnvoyProxy: func(namespacedName operatorv1.NamespacedName) error { return nil }, diff --git a/pkg/controller/goldmane/controller.go b/pkg/controller/goldmane/controller.go index 50b705b043..219a5fae0a 100644 --- a/pkg/controller/goldmane/controller.go +++ b/pkg/controller/goldmane/controller.go @@ -126,6 +126,7 @@ func newReconciler( provider: p, status: statusMgr, clusterDomain: opts.ClusterDomain, + variant: opts.Variant, } c.status.Run(opts.ShutdownContext) return c @@ -141,6 +142,7 @@ type Reconciler struct { provider operatorv1.Provider status status.StatusManager clusterDomain string + variant operatorv1.ProductVariant } // Reconcile reads that state of the cluster for a Goldmane object and makes changes based on the @@ -169,7 +171,7 @@ func (r *Reconciler) Reconcile(ctx context.Context, request reconcile.Request) ( // SetMetaData in the TigeraStatus such as observedGenerations. defer r.status.SetMetaData(&goldmaneCR.ObjectMeta) - variant, installationSpec, err := utils.GetInstallationSpec(ctx, r.cli) + installationSpec, err := utils.GetInstallationSpec(ctx, r.cli) if err != nil { return reconcile.Result{}, err } else if installationSpec == nil { @@ -267,7 +269,7 @@ func (r *Reconciler) Reconcile(ctx context.Context, request reconcile.Request) ( } components := []render.Component{certComponent, goldmane.Goldmane(cfg)} - if err = imageset.ApplyImageSet(ctx, r.cli, variant, components...); err != nil { + if err = imageset.ApplyImageSet(ctx, r.cli, r.variant, components...); err != nil { r.status.SetDegraded(operatorv1.ResourceUpdateError, "Error with images from ImageSet", err, reqLogger) return reconcile.Result{}, err } diff --git a/pkg/controller/installation/core_controller.go b/pkg/controller/installation/core_controller.go index 6c3d08279f..6db56d30df 100644 --- a/pkg/controller/installation/core_controller.go +++ b/pkg/controller/installation/core_controller.go @@ -239,7 +239,7 @@ func Add(mgr manager.Manager, opts options.ControllerOptions) error { return fmt.Errorf("tigera-installation-controller failed to watch BGPConfiguration resource: %w", err) } - if opts.EnterpriseCRDExists { + if opts.Variant.IsEnterprise() { // Watch for changes to primary resource ManagementCluster err = c.WatchObject(&operatorv1.ManagementCluster{}, &handler.EnqueueRequestForObject{}) if err != nil { @@ -354,7 +354,7 @@ func newReconciler(mgr manager.Manager, opts options.ControllerOptions) (*Reconc status: statusManager, typhaAutoscaler: typhaScaler, namespaceMigration: nm, - enterpriseCRDsExist: opts.EnterpriseCRDExists, + variant: opts.Variant, clusterDomain: opts.ClusterDomain, manageCRDs: opts.ManageCRDs, tierWatchReady: &utils.ReadyFlag{}, @@ -414,7 +414,7 @@ type ReconcileInstallation struct { typhaAutoscaler *typhaAutoscaler typhaAutoscalerNonClusterHost *typhaAutoscaler namespaceMigration migration.NamespaceMigration - enterpriseCRDsExist bool + variant operatorv1.ProductVariant migrationChecked bool clusterDomain string manageCRDs bool @@ -449,7 +449,7 @@ func GetActivePools(ctx context.Context, client client.Client) (*v3.IPPoolList, } // updateInstallationWithDefaults returns the default installation instance with defaults populated. -func updateInstallationWithDefaults(ctx context.Context, client client.Client, instance *operatorv1.Installation, provider operatorv1.Provider) error { +func updateInstallationWithDefaults(ctx context.Context, client client.Client, instance *operatorv1.Installation, provider operatorv1.Provider, variant operatorv1.ProductVariant) error { // Determine the provider in use by combining any auto-detected value with any value // specified in the Installation CR. mergeProvider updates the CR with the correct value. err := mergeProvider(instance, provider) @@ -472,7 +472,7 @@ func updateInstallationWithDefaults(ctx context.Context, client client.Client, i return fmt.Errorf("unable to list IPPools: %s", err.Error()) } - err = MergeAndFillDefaults(instance, awsNode, currentPools) + err = MergeAndFillDefaults(instance, awsNode, currentPools, variant) if err != nil { return err } @@ -481,21 +481,21 @@ func updateInstallationWithDefaults(ctx context.Context, client client.Client, i // MergeAndFillDefaults merges in configuration from the Kubernetes provider, if applicable, and then // populates defaults in the Installation instance. -func MergeAndFillDefaults(i *operatorv1.Installation, awsNode *appsv1.DaemonSet, currentPools *v3.IPPoolList) error { +func MergeAndFillDefaults(i *operatorv1.Installation, awsNode *appsv1.DaemonSet, currentPools *v3.IPPoolList, variant operatorv1.ProductVariant) error { if awsNode != nil { if err := updateInstallationForAWSNode(i, awsNode); err != nil { return fmt.Errorf("could not resolve AWS node configuration: %s", err.Error()) } } - return fillDefaults(i, currentPools) + return fillDefaults(i, currentPools, variant) } -// fillDefaults populates the default values onto an Installation object. -func fillDefaults(instance *operatorv1.Installation, currentPools *v3.IPPoolList) error { +// fillDefaults populates the default values onto an Installation object. The variant defaults to +// the one the process booted as, so that main and this controller can't disagree about it. +func fillDefaults(instance *operatorv1.Installation, currentPools *v3.IPPoolList, variant operatorv1.ProductVariant) error { if len(instance.Spec.Variant) == 0 { - // Default to installing Calico. - instance.Spec.Variant = operatorv1.Calico + instance.Spec.Variant = variant } if instance.Spec.TyphaAffinity == nil { @@ -876,7 +876,7 @@ func (r *ReconcileInstallation) Reconcile(ctx context.Context, request reconcile } // update Installation with defaults - if err := updateInstallationWithDefaults(ctx, r.client, instance, r.autoDetectedProvider); err != nil { + if err := updateInstallationWithDefaults(ctx, r.client, instance, r.autoDetectedProvider, r.variant); err != nil { r.status.SetDegraded(operatorv1.ResourceReadError, "Error querying installation", err, reqLogger) return reconcile.Result{}, err } @@ -940,7 +940,7 @@ func (r *ReconcileInstallation) Reconcile(ctx context.Context, request reconcile // Update CRDs before persisting defaults. Defaulting can set a value only this operator version's // CRD accepts (e.g. an autodetected kubernetesProvider=Kind); on upgrade the old served CRD would // otherwise reject the write and the reconcile would loop before ever reaching the CRD update. - if err = r.updateCRDs(ctx, instance.Spec.Variant, reqLogger); err != nil { + if err = r.updateCRDs(ctx, r.variant, reqLogger); err != nil { return reconcile.Result{}, err } @@ -1038,27 +1038,6 @@ func (r *ReconcileInstallation) Reconcile(ctx context.Context, request reconcile } } - // The operator supports running in a "Calico only" mode so that it doesn't need to run enterprise-specific controllers. - // If we are switching from this mode to one that enables enterprise, we need to restart the operator to enable the other controllers. - if !r.enterpriseCRDsExist && instance.Spec.Variant.IsEnterprise() { - // Perform an API discovery to determine if the necessary APIs exist. If they do, we can reboot into enterprise mode. - // if they do not, we need to notify the user that the requested configuration is invalid. - b, err := discovery.RequiresTigeraSecure(r.clientset) - if b { - log.Info("Rebooting to enable TigeraSecure controllers") - os.Exit(0) - } else if err != nil { - r.status.SetDegraded(operatorv1.InternalServerError, "Error discovering Tigera Secure availability", err, reqLogger) - } else { - r.status.SetDegraded(operatorv1.InternalServerError, "Cannot deploy Tigera Secure", fmt.Errorf("missing Tigera Secure custom resource definitions"), reqLogger) - } - - // Queue a retry. We don't want to watch the APIServer API since it might not exist and would cause - // this controller to fail. - reqLogger.Info("Scheduling a retry", "when", utils.StandardRetry) - return reconcile.Result{RequeueAfter: utils.StandardRetry}, nil - } - // Query for pull secrets in operator namespace pullSecrets, err := utils.GetInstallationPullSecrets(&instance.Spec, r.client) if err != nil { @@ -1070,7 +1049,7 @@ func (r *ReconcileInstallation) Reconcile(ctx context.Context, request reconcile var managementClusterConnection *operatorv1.ManagementClusterConnection var managerCR *operatorv1.Manager var logCollector *operatorv1.LogCollector - if r.enterpriseCRDsExist { + if r.variant.IsEnterprise() { logCollector, err = utils.GetLogCollector(ctx, r.client) if logCollector != nil { if err != nil { diff --git a/pkg/controller/installation/core_controller_test.go b/pkg/controller/installation/core_controller_test.go index bda4f6065b..22bc779724 100644 --- a/pkg/controller/installation/core_controller_test.go +++ b/pkg/controller/installation/core_controller_test.go @@ -197,7 +197,7 @@ var _ = Describe("Testing core-controller installation", func() { status: mockStatus, typhaAutoscaler: newTyphaAutoscaler(cs, nodeIndexInformer, test.NewTyphaListWatch(cs), mockStatus), namespaceMigration: &fakeNamespaceMigration{}, - enterpriseCRDsExist: true, + variant: operator.CalicoEnterprise, migrationChecked: true, tierWatchReady: ready, migrationWatchReady: &utils.ReadyFlag{}, @@ -708,7 +708,7 @@ var _ = Describe("Testing core-controller installation", func() { VXLANMode: v3.VXLANModeAlways, }, }) - Expect(MergeAndFillDefaults(installation, nil, ¤tPools)).To(BeNil()) + Expect(MergeAndFillDefaults(installation, nil, ¤tPools, operator.Calico)).To(BeNil()) Expect(installation.Spec.CalicoNetwork.NodeAddressAutodetectionV4.SkipInterface).Should(Equal("^br-.*")) Expect(installation.Spec.CalicoNetwork.NodeAddressAutodetectionV6).Should(BeNil()) }) @@ -721,7 +721,7 @@ var _ = Describe("Testing core-controller installation", func() { KubernetesProvider: provider, }, } - Expect(MergeAndFillDefaults(installation, nil, nil)).To(BeNil()) + Expect(MergeAndFillDefaults(installation, nil, nil, operator.Calico)).To(BeNil()) if expected { Expect(installation.Spec.TyphaAffinity).ToNot(BeNil()) Expect(installation.Spec.TyphaAffinity.NodeAffinity.RequiredDuringSchedulingIgnoredDuringExecution.NodeSelectorTerms).Should(Equal(result)) @@ -826,7 +826,7 @@ var _ = Describe("Testing core-controller installation", func() { status: mockStatus, typhaAutoscaler: newTyphaAutoscaler(cs, nodeIndexInformer, test.NewTyphaListWatch(cs), mockStatus), namespaceMigration: &fakeNamespaceMigration{}, - enterpriseCRDsExist: true, + variant: operator.CalicoEnterprise, migrationChecked: true, clusterDomain: dns.DefaultClusterDomain, tierWatchReady: ready, @@ -1048,7 +1048,7 @@ var _ = Describe("Testing core-controller installation", func() { status: mockStatus, typhaAutoscaler: newTyphaAutoscaler(cs, nodeIndexInformer, test.NewTyphaListWatch(cs), mockStatus), namespaceMigration: &fakeNamespaceMigration{}, - enterpriseCRDsExist: true, + variant: operator.CalicoEnterprise, migrationChecked: true, tierWatchReady: ready, migrationWatchReady: &utils.ReadyFlag{}, @@ -2217,7 +2217,7 @@ var _ = Describe("Testing core-controller installation", func() { cr.Spec.Variant = operator.Calico cr.Status.Variant = operator.Calico Expect(c.Create(ctx, cr)).NotTo(HaveOccurred()) - r.enterpriseCRDsExist = false + r.variant = operator.Calico Expect(c.Delete(ctx, &v3.Tier{ObjectMeta: metav1.ObjectMeta{Name: "calico-system"}})).NotTo(HaveOccurred()) _, err := r.Reconcile(ctx, reconcile.Request{}) @@ -2336,7 +2336,7 @@ var _ = Describe("Testing core-controller installation", func() { status: mockStatus, typhaAutoscaler: newTyphaAutoscaler(cs, nodeIndexInformer, test.NewTyphaListWatch(cs), mockStatus), namespaceMigration: &fakeNamespaceMigration{}, - enterpriseCRDsExist: true, + variant: operator.CalicoEnterprise, migrationChecked: true, clusterDomain: dns.DefaultClusterDomain, tierWatchReady: ready, @@ -2473,7 +2473,7 @@ var _ = Describe("Testing core-controller installation", func() { status: mockStatus, typhaAutoscaler: newTyphaAutoscaler(cs, nodeIndexInformer, test.NewTyphaListWatch(cs), mockStatus), namespaceMigration: &fakeNamespaceMigration{}, - enterpriseCRDsExist: true, + variant: operator.CalicoEnterprise, migrationChecked: true, tierWatchReady: ready, migrationWatchReady: &utils.ReadyFlag{}, diff --git a/pkg/controller/installation/defaults_test.go b/pkg/controller/installation/defaults_test.go index f7ebd276d7..6d774b30e2 100644 --- a/pkg/controller/installation/defaults_test.go +++ b/pkg/controller/installation/defaults_test.go @@ -44,7 +44,7 @@ var _ = Describe("Defaulting logic tests", func() { } instance := &operator.Installation{} - err := fillDefaults(instance, ¤tPools) + err := fillDefaults(instance, ¤tPools, operator.Calico) Expect(err).NotTo(HaveOccurred()) // The resulting resource should pass validation. @@ -83,7 +83,7 @@ var _ = Describe("Defaulting logic tests", func() { instance := &operator.Installation{} instance.Spec.Variant = operator.CalicoEnterprise - err := fillDefaults(instance, ¤tPools) + err := fillDefaults(instance, ¤tPools, operator.Calico) Expect(err).NotTo(HaveOccurred()) Expect(validateCustomResource(instance)).NotTo(HaveOccurred()) @@ -195,7 +195,7 @@ var _ = Describe("Defaulting logic tests", func() { }, } instanceCopy := instance.DeepCopyObject().(*operator.Installation) - err := fillDefaults(instanceCopy, nil) + err := fillDefaults(instanceCopy, nil, operator.Calico) Expect(err).NotTo(HaveOccurred()) Expect(instanceCopy.Spec).To(Equal(instance.Spec)) Expect(validateCustomResource(instance)).NotTo(HaveOccurred()) @@ -283,7 +283,7 @@ var _ = Describe("Defaulting logic tests", func() { }, } instanceCopy := instance.DeepCopyObject().(*operator.Installation) - err := fillDefaults(instanceCopy, nil) + err := fillDefaults(instanceCopy, nil, operator.Calico) Expect(err).NotTo(HaveOccurred()) Expect(instanceCopy.Spec).To(Equal(instance.Spec)) Expect(validateCustomResource(instance)).NotTo(HaveOccurred()) @@ -300,7 +300,7 @@ var _ = Describe("Defaulting logic tests", func() { }, }, } - err := fillDefaults(instance, nil) + err := fillDefaults(instance, nil, operator.Calico) Expect(err).NotTo(HaveOccurred()) Expect(len(instance.Spec.CalicoNetwork.IPPools)).To(Equal(0)) Expect(validateCustomResource(instance)).NotTo(HaveOccurred()) @@ -314,7 +314,7 @@ var _ = Describe("Defaulting logic tests", func() { }, }, } - err := fillDefaults(instance, nil) + err := fillDefaults(instance, nil, operator.Calico) Expect(err).NotTo(HaveOccurred()) Expect(*instance.Spec.CalicoNetwork.BGP).To(Equal(operator.BGPEnabled)) Expect(validateCustomResource(instance)).NotTo(HaveOccurred()) @@ -328,7 +328,7 @@ var _ = Describe("Defaulting logic tests", func() { }, }, } - err := fillDefaults(instance, nil) + err := fillDefaults(instance, nil, operator.Calico) Expect(err).NotTo(HaveOccurred()) Expect(instance.Spec.CNI.SpecVersion).NotTo(BeNil()) Expect(*instance.Spec.CNI.SpecVersion).To(Equal(operator.CNISpecVersionAuto)) @@ -344,7 +344,7 @@ var _ = Describe("Defaulting logic tests", func() { CalicoNetwork: &operator.CalicoNetworkSpec{}, }, } - err := fillDefaults(instance, nil) + err := fillDefaults(instance, nil, operator.Calico) Expect(err).NotTo(HaveOccurred()) Expect(instance.Spec.CNI.SpecVersion).To(BeNil()) Expect(validateCustomResource(instance)).NotTo(HaveOccurred()) @@ -359,7 +359,7 @@ var _ = Describe("Defaulting logic tests", func() { CalicoNetwork: &operator.CalicoNetworkSpec{}, }, } - err := fillDefaults(instance, nil) + err := fillDefaults(instance, nil, operator.Calico) Expect(err).NotTo(HaveOccurred()) Expect(*instance.Spec.CalicoNetwork.BGP).To(Equal(operator.BGPDisabled)) @@ -374,14 +374,14 @@ var _ = Describe("Defaulting logic tests", func() { Registry: "test-reg", }, } - err := fillDefaults(instance, nil) + err := fillDefaults(instance, nil, operator.Calico) Expect(err).NotTo(HaveOccurred()) Expect(instance.Spec.Registry).To(Equal("test-reg")) Expect(validateCustomResource(instance)).NotTo(HaveOccurred()) // "UseDefault" should not be modified. instance.Spec.Registry = components.UseDefault - err = fillDefaults(instance, nil) + err = fillDefaults(instance, nil, operator.Calico) Expect(err).NotTo(HaveOccurred()) Expect(instance.Spec.Registry).To(Equal(components.UseDefault)) Expect(validateCustomResource(instance)).NotTo(HaveOccurred()) @@ -398,7 +398,7 @@ var _ = Describe("Defaulting logic tests", func() { }, }, } - err := fillDefaults(instance, nil) + err := fillDefaults(instance, nil, operator.Calico) Expect(err).NotTo(HaveOccurred()) Expect(validateCustomResource(instance)).NotTo(HaveOccurred()) }) @@ -416,14 +416,14 @@ var _ = Describe("Defaulting logic tests", func() { }, }, } - err := fillDefaults(instance, ¤tPools) + err := fillDefaults(instance, ¤tPools, operator.Calico) Expect(err).NotTo(HaveOccurred()) Expect(validateCustomResource(instance)).NotTo(HaveOccurred()) }) DescribeTable("Test different values for FlexVolumePath", func(i *operator.Installation, expectedFlexVolumePath string) { - Expect(fillDefaults(i, nil)).To(BeNil()) + Expect(fillDefaults(i, nil, operator.Calico)).To(BeNil()) Expect(i.Spec.FlexVolumePath).To(Equal(expectedFlexVolumePath)) }, @@ -452,7 +452,7 @@ var _ = Describe("Defaulting logic tests", func() { DescribeTable("Test different values for KubeletVolumePluginPath", func(i *operator.Installation, expectedKubeletVolumePluginPath string) { - Expect(fillDefaults(i, nil)).To(BeNil()) + Expect(fillDefaults(i, nil, operator.Calico)).To(BeNil()) Expect(i.Spec.KubeletVolumePluginPath).To(Equal(expectedKubeletVolumePluginPath)) }, @@ -485,7 +485,7 @@ var _ = Describe("Defaulting logic tests", func() { CNI: &operator.CNISpec{}, }, } - Expect(fillDefaults(instance, nil)).NotTo(HaveOccurred()) + Expect(fillDefaults(instance, nil, operator.Calico)).NotTo(HaveOccurred()) Expect(instance.Spec.CNI.Type).To(Equal(operator.PluginCalico)) Expect(validateCustomResource(instance)).NotTo(HaveOccurred()) }) @@ -496,7 +496,7 @@ var _ = Describe("Defaulting logic tests", func() { CNI: &operator.CNISpec{}, }, } - Expect(fillDefaults(instance, nil)).NotTo(HaveOccurred()) + Expect(fillDefaults(instance, nil, operator.Calico)).NotTo(HaveOccurred()) Expect(*instance.Spec.Logging.CNI.LogSeverity).To(Equal(operator.LogLevelInfo)) Expect(*instance.Spec.Logging.CNI.LogFileMaxCount).To(Equal(uint32(10))) Expect(*instance.Spec.Logging.CNI.LogFileMaxAgeDays).To(Equal(uint32(30))) @@ -509,7 +509,7 @@ var _ = Describe("Defaulting logic tests", func() { instance := &operator.Installation{ Spec: operator.InstallationSpec{KubernetesProvider: provider}, } - Expect(fillDefaults(instance, nil)).NotTo(HaveOccurred()) + Expect(fillDefaults(instance, nil, operator.Calico)).NotTo(HaveOccurred()) Expect(instance.Spec.CNI.Type).To(Equal(plugin)) iptables := operator.LinuxDataplaneIptables winDataplane := operator.WindowsDataplaneDisabled @@ -534,7 +534,7 @@ var _ = Describe("Defaulting logic tests", func() { CNI: &operator.CNISpec{Type: plugin}, }, } - Expect(fillDefaults(instance, nil)).NotTo(HaveOccurred()) + Expect(fillDefaults(instance, nil, operator.Calico)).NotTo(HaveOccurred()) Expect(instance.Spec.CNI.Type).To(Equal(plugin)) iptables := operator.LinuxDataplaneIptables winDataplane := operator.WindowsDataplaneDisabled @@ -563,7 +563,7 @@ var _ = Describe("Defaulting logic tests", func() { }, }, } - err := fillDefaults(instance, nil) + err := fillDefaults(instance, nil, operator.Calico) Expect(err).NotTo(HaveOccurred()) Expect(*instance.Spec.CalicoNetwork.BGP).To(Equal(operator.BGPDisabled)) Expect(validateCustomResource(instance)).NotTo(HaveOccurred()) @@ -593,7 +593,7 @@ var _ = Describe("Defaulting logic tests", func() { }, }, } - err := fillDefaults(instance, nil) + err := fillDefaults(instance, nil, operator.Calico) Expect(err).NotTo(HaveOccurred()) iptables := operator.LinuxDataplaneIptables winDataplane := operator.WindowsDataplaneDisabled @@ -621,7 +621,7 @@ var _ = Describe("Defaulting logic tests", func() { }, }, } - err := fillDefaults(instance, nil) + err := fillDefaults(instance, nil, operator.Calico) Expect(err).NotTo(HaveOccurred()) Expect(*instance.Spec.CalicoNetwork.BGP).To(Equal(operator.BGPDisabled)) Expect(instance.Spec.CalicoNetwork.IPPools).To(BeEmpty()) @@ -644,7 +644,7 @@ var _ = Describe("Defaulting logic tests", func() { }, }, } - err := fillDefaults(instance, nil) + err := fillDefaults(instance, nil, operator.Calico) Expect(err).NotTo(HaveOccurred()) Expect(*instance.Spec.CalicoNetwork.BGP).To(Equal(operator.BGPDisabled)) Expect(instance.Spec.CalicoNetwork.IPPools).To(BeEmpty()) @@ -662,7 +662,7 @@ var _ = Describe("Defaulting logic tests", func() { CNI: &operator.CNISpec{Type: cni}, }, } - Expect(fillDefaults(instance, nil)).NotTo(HaveOccurred()) + Expect(fillDefaults(instance, nil, operator.Calico)).NotTo(HaveOccurred()) Expect(instance.Spec.CNI.IPAM.Type).To(Equal(ipam)) }, @@ -678,7 +678,7 @@ var _ = Describe("Defaulting logic tests", func() { DescribeTable("should handle various pool configurations", func(currentPools []v3.IPPool) { instance := &operator.Installation{} - Expect(fillDefaults(instance, &v3.IPPoolList{Items: currentPools})).NotTo(HaveOccurred()) + Expect(fillDefaults(instance, &v3.IPPoolList{Items: currentPools}, operator.Calico)).NotTo(HaveOccurred()) // The resulting instance should be valid. Expect(validateCustomResource(instance)).NotTo(HaveOccurred()) diff --git a/pkg/controller/installation/validation_test.go b/pkg/controller/installation/validation_test.go index c90200e2b8..f6fac816d7 100644 --- a/pkg/controller/installation/validation_test.go +++ b/pkg/controller/installation/validation_test.go @@ -369,7 +369,7 @@ var _ = Describe("Installation validation tests", func() { instance.Spec.KubernetesProvider = operator.ProviderEKS // Fill in defaults and validate the result. - Expect(fillDefaults(instance, nil)).NotTo(HaveOccurred()) + Expect(fillDefaults(instance, nil, operator.Calico)).NotTo(HaveOccurred()) Expect(validateCustomResource(instance)).NotTo(HaveOccurred()) }) @@ -539,7 +539,7 @@ var _ = Describe("Installation validation tests", func() { }) It("with empty CalicoNetwork validates", func() { - Expect(fillDefaults(instance, nil)).NotTo(HaveOccurred()) + Expect(fillDefaults(instance, nil, operator.Calico)).NotTo(HaveOccurred()) err := validateCustomResource(instance) Expect(err).NotTo(HaveOccurred()) }) @@ -553,7 +553,7 @@ var _ = Describe("Installation validation tests", func() { NodeSelector: "all()", }, } - Expect(fillDefaults(instance, nil)).NotTo(HaveOccurred()) + Expect(fillDefaults(instance, nil, operator.Calico)).NotTo(HaveOccurred()) err := validateCustomResource(instance) Expect(err).NotTo(HaveOccurred()) }) @@ -561,7 +561,7 @@ var _ = Describe("Installation validation tests", func() { It("with BGP enabled validates", func() { enable := operator.BGPEnabled instance.Spec.CalicoNetwork.BGP = &enable - Expect(fillDefaults(instance, nil)).NotTo(HaveOccurred()) + Expect(fillDefaults(instance, nil, operator.Calico)).NotTo(HaveOccurred()) err := validateCustomResource(instance) Expect(err).NotTo(HaveOccurred()) }) @@ -581,7 +581,7 @@ var _ = Describe("Installation validation tests", func() { NodeSelector: "all()", }, } - Expect(fillDefaults(instance, nil)).NotTo(HaveOccurred()) + Expect(fillDefaults(instance, nil, operator.Calico)).NotTo(HaveOccurred()) err := validateCustomResource(instance) Expect(err).NotTo(HaveOccurred()) }) @@ -595,14 +595,14 @@ var _ = Describe("Installation validation tests", func() { }) It("with nil LogSeverity", func() { - Expect(fillDefaults(instance, nil)).NotTo(HaveOccurred()) + Expect(fillDefaults(instance, nil, operator.Calico)).NotTo(HaveOccurred()) err := validateCustomResource(instance) Expect(err).NotTo(HaveOccurred()) Expect(*instance.Spec.Logging.CNI.LogSeverity).To(Equal(operator.LogLevelInfo)) }) It("with nil LogFileMaxAgeDays", func() { - Expect(fillDefaults(instance, nil)).NotTo(HaveOccurred()) + Expect(fillDefaults(instance, nil, operator.Calico)).NotTo(HaveOccurred()) err := validateCustomResource(instance) Expect(err).NotTo(HaveOccurred()) Expect(*instance.Spec.Logging.CNI.LogFileMaxAgeDays).To(Equal(uint32(30))) @@ -611,14 +611,14 @@ var _ = Describe("Installation validation tests", func() { It("with invalid LogFileMaxAgeDays", func() { instance.Spec.Logging.CNI.LogFileMaxAgeDays = new(uint32) *instance.Spec.Logging.CNI.LogFileMaxAgeDays = 0 - Expect(fillDefaults(instance, nil)).NotTo(HaveOccurred()) + Expect(fillDefaults(instance, nil, operator.Calico)).NotTo(HaveOccurred()) err := validateCustomResource(instance) Expect(err).To(HaveOccurred()) Expect(err).To(MatchError("spec.Logging.cni.logFileMaxAgeDays should be a positive non-zero integer")) }) It("with nil LogFileMaxCount", func() { - Expect(fillDefaults(instance, nil)).NotTo(HaveOccurred()) + Expect(fillDefaults(instance, nil, operator.Calico)).NotTo(HaveOccurred()) err := validateCustomResource(instance) Expect(err).NotTo(HaveOccurred()) Expect(*instance.Spec.Logging.CNI.LogFileMaxCount).To(Equal(uint32(10))) @@ -627,14 +627,14 @@ var _ = Describe("Installation validation tests", func() { It("with invalid LogFileMaxCount", func() { instance.Spec.Logging.CNI.LogFileMaxCount = new(uint32) *instance.Spec.Logging.CNI.LogFileMaxCount = 0 - Expect(fillDefaults(instance, nil)).NotTo(HaveOccurred()) + Expect(fillDefaults(instance, nil, operator.Calico)).NotTo(HaveOccurred()) err := validateCustomResource(instance) Expect(err).To(HaveOccurred()) Expect(err).To(MatchError("spec.loggingConfig.cni.logFileMaxCount value should be greater than zero")) }) It("with nil LogFileMaxSize", func() { - Expect(fillDefaults(instance, nil)).NotTo(HaveOccurred()) + Expect(fillDefaults(instance, nil, operator.Calico)).NotTo(HaveOccurred()) err := validateCustomResource(instance) Expect(err).NotTo(HaveOccurred()) Expect(*instance.Spec.Logging.CNI.LogFileMaxSize).To(Equal(resource.MustParse("100Mi"))) @@ -643,25 +643,25 @@ var _ = Describe("Installation validation tests", func() { It("with invalid LogFileMaxSize", func() { instance.Spec.Logging.CNI.LogFileMaxSize = new(resource.Quantity) *instance.Spec.Logging.CNI.LogFileMaxSize = resource.MustParse("1") - Expect(fillDefaults(instance, nil)).NotTo(HaveOccurred()) + Expect(fillDefaults(instance, nil, operator.Calico)).NotTo(HaveOccurred()) err := validateCustomResource(instance) Expect(err).To(HaveOccurred()) Expect(err).To(MatchError("spec.Logging.cni.logFileMaxSize format is not corrent. Suffix should be Ki | Mi | Gi | Ti | Pi | Ei")) *instance.Spec.Logging.CNI.LogFileMaxSize = resource.MustParse("0") - Expect(fillDefaults(instance, nil)).NotTo(HaveOccurred()) + Expect(fillDefaults(instance, nil, operator.Calico)).NotTo(HaveOccurred()) err = validateCustomResource(instance) Expect(err).To(HaveOccurred()) Expect(err).To(MatchError("spec.Logging.cni.logFileMaxSize format is not corrent. Suffix should be Ki | Mi | Gi | Ti | Pi | Ei")) *instance.Spec.Logging.CNI.LogFileMaxSize = resource.MustParse("-1") - Expect(fillDefaults(instance, nil)).NotTo(HaveOccurred()) + Expect(fillDefaults(instance, nil, operator.Calico)).NotTo(HaveOccurred()) err = validateCustomResource(instance) Expect(err).To(HaveOccurred()) Expect(err).To(MatchError("spec.Logging.cni.logFileMaxSize format is not corrent. Suffix should be Ki | Mi | Gi | Ti | Pi | Ei")) *instance.Spec.Logging.CNI.LogFileMaxSize = resource.MustParse("1M") - Expect(fillDefaults(instance, nil)).NotTo(HaveOccurred()) + Expect(fillDefaults(instance, nil, operator.Calico)).NotTo(HaveOccurred()) err = validateCustomResource(instance) Expect(err).To(HaveOccurred()) Expect(err).To(MatchError("spec.Logging.cni.logFileMaxSize format is not corrent. Suffix should be Ki | Mi | Gi | Ti | Pi | Ei")) @@ -691,7 +691,7 @@ var _ = Describe("Installation validation tests", func() { DescribeTable("test allowed plugins", func(plugin operator.CNIPluginType, ipam operator.IPAMPluginType) { instance.Spec.CNI.Type = plugin instance.Spec.CNI.IPAM = &operator.IPAMSpec{Type: ipam} - Expect(fillDefaults(instance, nil)).NotTo(HaveOccurred()) + Expect(fillDefaults(instance, nil, operator.Calico)).NotTo(HaveOccurred()) err := validateCustomResource(instance) Expect(err).NotTo(HaveOccurred()) }, nonCalicoCNIEntries) @@ -916,7 +916,7 @@ var _ = Describe("Installation validation tests", func() { Host: "1.2.3.4", Port: "6443", } - Expect(fillDefaults(instance, nil)).NotTo(HaveOccurred()) + Expect(fillDefaults(instance, nil, operator.Calico)).NotTo(HaveOccurred()) err := validateCustomResource(instance) Expect(err).NotTo(HaveOccurred()) }) diff --git a/pkg/controller/installation/windows_controller.go b/pkg/controller/installation/windows_controller.go index e23bf55db7..fafc671193 100644 --- a/pkg/controller/installation/windows_controller.go +++ b/pkg/controller/installation/windows_controller.go @@ -150,7 +150,7 @@ func AddWindowsController(mgr manager.Manager, opts options.ControllerOptions) e // Watch for changes to IPAMConfiguration. go utils.WaitToAddResourceWatch(c, opts.K8sClientset, logw, ri.ipamConfigWatchReady, []client.Object{&v3.IPAMConfiguration{TypeMeta: metav1.TypeMeta{Kind: v3.KindIPAMConfiguration}}}) - if ri.enterpriseCRDsExist { + if ri.variant.IsEnterprise() { for _, ns := range []string{common.CalicoNamespace, common.OperatorNamespace()} { if err = utils.AddSecretsWatch(c, render.NodePrometheusTLSServerSecret, ns); err != nil { return fmt.Errorf("tigera-windows-controller failed to watch secret '%s' in '%s' namespace: %w", render.NodePrometheusTLSServerSecret, ns, err) @@ -178,7 +178,7 @@ type ReconcileWindows struct { watches map[runtime.Object]struct{} autoDetectedProvider operatorv1.Provider status status.StatusManager - enterpriseCRDsExist bool + variant operatorv1.ProductVariant clusterDomain string ipamConfigWatchReady *utils.ReadyFlag } @@ -194,7 +194,7 @@ func newWindowsReconciler(mgr manager.Manager, opts options.ControllerOptions) ( watches: make(map[runtime.Object]struct{}), autoDetectedProvider: opts.DetectedProvider, status: statusManager, - enterpriseCRDsExist: opts.EnterpriseCRDExists, + variant: opts.Variant, clusterDomain: opts.ClusterDomain, ipamConfigWatchReady: &utils.ReadyFlag{}, } diff --git a/pkg/controller/installation/windows_controller_test.go b/pkg/controller/installation/windows_controller_test.go index ae5866bfa5..2f6661d8b5 100644 --- a/pkg/controller/installation/windows_controller_test.go +++ b/pkg/controller/installation/windows_controller_test.go @@ -124,7 +124,7 @@ var _ = Describe("windows-controller installation tests", func() { scheme: scheme, autoDetectedProvider: operator.ProviderNone, status: mockStatus, - enterpriseCRDsExist: true, + variant: operator.CalicoEnterprise, ipamConfigWatchReady: &utils.ReadyFlag{}, } r.ipamConfigWatchReady.MarkAsReady() @@ -155,7 +155,7 @@ var _ = Describe("windows-controller installation tests", func() { }, }, } - Expect(updateInstallationWithDefaults(ctx, r.client, cr, r.autoDetectedProvider)).NotTo(HaveOccurred()) + Expect(updateInstallationWithDefaults(ctx, r.client, cr, r.autoDetectedProvider, r.variant)).NotTo(HaveOccurred()) certificateManager, err := certificatemanager.Create(c, nil, "", common.OperatorNamespace(), certificatemanager.AllowCACreation()) Expect(err).NotTo(HaveOccurred()) prometheusTLS, err := certificateManager.GetOrCreateKeyPair(c, monitor.PrometheusClientTLSSecretName, common.OperatorNamespace(), []string{monitor.PrometheusClientTLSSecretName}) @@ -194,7 +194,7 @@ var _ = Describe("windows-controller installation tests", func() { cr.Status = operator.InstallationStatus{ Variant: operator.Calico, } - Expect(updateInstallationWithDefaults(ctx, r.client, cr, r.autoDetectedProvider)).NotTo(HaveOccurred()) + Expect(updateInstallationWithDefaults(ctx, r.client, cr, r.autoDetectedProvider, r.variant)).NotTo(HaveOccurred()) // Set serviceCIDRs in the installation (required for Calico for Windows) cr.Spec.ServiceCIDRs = []string{"10.96.0.0/12"} @@ -614,7 +614,7 @@ var _ = Describe("windows-controller installation tests", func() { scheme: scheme, autoDetectedProvider: operator.ProviderNone, status: mockStatus, - enterpriseCRDsExist: true, + variant: operator.CalicoEnterprise, ipamConfigWatchReady: &utils.ReadyFlag{}, } r.ipamConfigWatchReady.MarkAsReady() @@ -663,7 +663,7 @@ var _ = Describe("windows-controller installation tests", func() { }, }, } - Expect(updateInstallationWithDefaults(ctx, r.client, instance, r.autoDetectedProvider)).NotTo(HaveOccurred()) + Expect(updateInstallationWithDefaults(ctx, r.client, instance, r.autoDetectedProvider, r.variant)).NotTo(HaveOccurred()) Expect(c.Create(ctx, instance)).NotTo(HaveOccurred()) }) AfterEach(func() { diff --git a/pkg/controller/intrusiondetection/intrusiondetection_controller.go b/pkg/controller/intrusiondetection/intrusiondetection_controller.go index d1334da2b1..f46915a891 100644 --- a/pkg/controller/intrusiondetection/intrusiondetection_controller.go +++ b/pkg/controller/intrusiondetection/intrusiondetection_controller.go @@ -63,7 +63,7 @@ var log = logf.Log.WithName("controller_intrusiondetection") // Add creates a new IntrusionDetection Controller and adds it to the Manager. The Manager will set fields on the Controller // and Start it when the Manager is Started. func Add(mgr manager.Manager, opts options.ControllerOptions) error { - if !opts.EnterpriseCRDExists { + if !opts.Variant.IsEnterprise() { // No need to start this controller. return nil } @@ -330,7 +330,7 @@ func (r *ReconcileIntrusionDetection) Reconcile(ctx context.Context, request rec } // Query for the installation object. - variant, installationSpec, err := utils.GetInstallationSpec(context.Background(), r.client) + installationSpec, err := utils.GetInstallationSpec(context.Background(), r.client) if err != nil { if errors.IsNotFound(err) { r.status.SetDegraded(operatorv1.ResourceNotFound, "Installation not found", err, reqLogger) @@ -481,7 +481,7 @@ func (r *ReconcileIntrusionDetection) Reconcile(ctx context.Context, request rec }) intrusionDetectionComponent := render.IntrusionDetection(intrusionDetectionCfg) - if err = imageset.ApplyImageSet(ctx, r.client, variant, intrusionDetectionComponent); err != nil { + if err = imageset.ApplyImageSet(ctx, r.client, r.opts.Variant, intrusionDetectionComponent); err != nil { r.status.SetDegraded(operatorv1.ResourceUpdateError, "Error with images from ImageSet", err, reqLogger) return reconcile.Result{}, err } @@ -542,7 +542,7 @@ func (r *ReconcileIntrusionDetection) Reconcile(ctx context.Context, request rec ClusterDomain: r.opts.ClusterDomain, DPICertSecret: dpiKeyPair, }) - if err = imageset.ApplyImageSet(ctx, r.client, variant, dpiComponent); err != nil { + if err = imageset.ApplyImageSet(ctx, r.client, r.opts.Variant, dpiComponent); err != nil { r.status.SetDegraded(operatorv1.ResourceUpdateError, "Error with images from ImageSet", err, reqLogger) return reconcile.Result{}, err } diff --git a/pkg/controller/intrusiondetection/intrusiondetection_controller_test.go b/pkg/controller/intrusiondetection/intrusiondetection_controller_test.go index 38abc7364b..8ed7dee00b 100644 --- a/pkg/controller/intrusiondetection/intrusiondetection_controller_test.go +++ b/pkg/controller/intrusiondetection/intrusiondetection_controller_test.go @@ -111,6 +111,7 @@ var _ = Describe("IntrusionDetection controller tests", func() { tierWatchReady: &utils.ReadyFlag{}, opts: options.ControllerOptions{ DetectedProvider: operatorv1.ProviderNone, + Variant: operatorv1.CalicoEnterprise, }, } @@ -330,6 +331,7 @@ var _ = Describe("IntrusionDetection controller tests", func() { tierWatchReady: readyFlag, opts: options.ControllerOptions{ DetectedProvider: operatorv1.ProviderNone, + Variant: operatorv1.CalicoEnterprise, }, } }) diff --git a/pkg/controller/istio/istio_controller.go b/pkg/controller/istio/istio_controller.go index 1c2d84c28e..d2a0935eed 100644 --- a/pkg/controller/istio/istio_controller.go +++ b/pkg/controller/istio/istio_controller.go @@ -186,7 +186,7 @@ func (r *ReconcileIstio) Reconcile(ctx context.Context, request reconcile.Reques } // Get the Installation, for k8s provider info. - variant, installationSpec, err := utils.GetInstallationSpec(ctx, r) + installationSpec, err := utils.GetInstallationSpec(ctx, r) if err != nil { if errors.IsNotFound(err) { r.status.SetDegraded(operatorv1.ResourceNotFound, "Installation not found", err, reqLogger) @@ -196,11 +196,6 @@ func (r *ReconcileIstio) Reconcile(ctx context.Context, request reconcile.Reques return reconcile.Result{}, err } - if variant == "" { - r.status.SetDegraded(operatorv1.ResourceNotReady, "Waiting for Installation Variant to be set", nil, reqLogger) - return reconcile.Result{}, nil - } - pullSecrets, err := utils.GetInstallationPullSecrets(installationSpec, r) if err != nil { r.status.SetDegraded(operatorv1.ResourceReadError, "Error retrieving pull secrets", err, reqLogger) @@ -391,7 +386,7 @@ func (r *ReconcileIstio) configurePolicySyncPathPrefix(ctx context.Context, inst // installationSpec.Variant (i.e. Installation.Spec.Variant), so the // policy-sync field tracks the renderer's decision to ship the L7 // waypoint sidecar even before Status.Variant catches up. - _, installationSpec, err := utils.GetInstallationSpec(ctx, r.Client) + installationSpec, err := utils.GetInstallationSpec(ctx, r.Client) if err != nil && !errors.IsNotFound(err) { return false, err } diff --git a/pkg/controller/istio/istio_controller_test.go b/pkg/controller/istio/istio_controller_test.go index 95cc14e334..33dcba186e 100644 --- a/pkg/controller/istio/istio_controller_test.go +++ b/pkg/controller/istio/istio_controller_test.go @@ -706,31 +706,6 @@ var _ = Describe("Istio controller tests", func() { }) Context("Error handling tests", func() { - It("should handle missing variant gracefully", func() { - // Create installation without variant - installationNoVariant := &operatorv1.Installation{ - ObjectMeta: metav1.ObjectMeta{ - Name: "default", - }, - Spec: operatorv1.InstallationSpec{ - Variant: "", - }, - } - Expect(cli.Create(ctx, installationNoVariant)).NotTo(HaveOccurred()) - Expect(cli.Create(ctx, istioCR)).NotTo(HaveOccurred()) - - r := &ReconcileIstio{ - Client: cli, - scheme: scheme, - provider: operatorv1.ProviderNone, - status: mockStatus, - } - - _, err := r.Reconcile(ctx, reconcile.Request{NamespacedName: types.NamespacedName{Name: "default"}}) - Expect(err).ShouldNot(HaveOccurred()) - mockStatus.AssertCalled(GinkgoT(), "SetDegraded", operatorv1.ResourceNotReady, "Waiting for Installation Variant to be set", mock.Anything, mock.Anything) - }) - It("should handle TigeraStatus update in reconciliation", func() { createResources() diff --git a/pkg/controller/istio/waypoint/waypoint_controller.go b/pkg/controller/istio/waypoint/waypoint_controller.go index ece0cf89f4..659d5be5d0 100644 --- a/pkg/controller/istio/waypoint/waypoint_controller.go +++ b/pkg/controller/istio/waypoint/waypoint_controller.go @@ -82,7 +82,7 @@ var log = logf.Log.WithName("controller_istio_waypoint") // deletes the resource sets istiod strands when a Gateway's // spec.gatewayClassName changes. func Add(mgr manager.Manager, opts options.ControllerOptions) error { - if !opts.EnterpriseCRDExists { + if !opts.Variant.IsEnterprise() { return nil } @@ -228,7 +228,7 @@ func (r *ReconcileWaypoint) Reconcile(ctx context.Context, request reconcile.Req // garbage collected by owner reference. Objects stranded while the CR still exists and // is the only owner (a removed Gateway, a renamed pull secret) are not yet cleaned up. func (r *ReconcileWaypoint) pullSecretResources(ctx context.Context, reqLogger logr.Logger) ([]client.Object, error) { - _, installationSpec, err := utils.GetInstallationSpec(ctx, r) + installationSpec, err := utils.GetInstallationSpec(ctx, r) if err != nil { if errors.IsNotFound(err) { reqLogger.V(1).Info("Installation not found") diff --git a/pkg/controller/kubeproxy/controller.go b/pkg/controller/kubeproxy/controller.go index 03d8dd7062..94b8a046e8 100644 --- a/pkg/controller/kubeproxy/controller.go +++ b/pkg/controller/kubeproxy/controller.go @@ -117,7 +117,7 @@ func (r *Reconciler) Reconcile(ctx context.Context, request reconcile.Request) ( reqLogger := log.WithValues("Request.Namespace", request.Namespace, "Request.Name", request.Name) reqLogger.V(2).Info("Reconciling KubeProxy") - _, installationSpec, err := utils.GetInstallationSpec(ctx, r.cli) + installationSpec, err := utils.GetInstallationSpec(ctx, r.cli) if err != nil { return reconcile.Result{}, err } else if installationSpec == nil { diff --git a/pkg/controller/logcollector/logcollector_controller.go b/pkg/controller/logcollector/logcollector_controller.go index e56bfb19a3..916c72e6c7 100644 --- a/pkg/controller/logcollector/logcollector_controller.go +++ b/pkg/controller/logcollector/logcollector_controller.go @@ -59,7 +59,7 @@ var log = logf.Log.WithName("controller_logcollector") // Add creates a new LogCollector Controller and adds it to the Manager. The Manager will set fields on the Controller // and Start it when the Manager is Started. func Add(mgr manager.Manager, opts options.ControllerOptions) error { - if !opts.EnterpriseCRDExists { + if !opts.Variant.IsEnterprise() { // No need to start this controller. return nil } @@ -370,7 +370,7 @@ func (r *ReconcileLogCollector) Reconcile(ctx context.Context, request reconcile // Fetch the Installation instance. We need this for a few reasons. // - We need to make sure it has successfully completed installation. // - We need to get the registry information from its spec. - variant, installationSpec, err := utils.GetInstallationSpec(ctx, r.client) + installationSpec, err := utils.GetInstallationSpec(ctx, r.client) if err != nil { if errors.IsNotFound(err) { r.status.SetDegraded(operatorv1.ResourceNotFound, "Installation not found", err, reqLogger) @@ -713,7 +713,7 @@ func (r *ReconcileLogCollector) Reconcile(ctx context.Context, request reconcile rcertificatemanagement.CertificateManagement(&certificateComponent), } - if err = imageset.ApplyImageSet(ctx, r.client, variant, comp); err != nil { + if err = imageset.ApplyImageSet(ctx, r.client, r.opts.Variant, comp); err != nil { r.status.SetDegraded(operatorv1.ResourceUpdateError, "Error with images from ImageSet", err, reqLogger) return reconcile.Result{}, err } @@ -736,7 +736,7 @@ func (r *ReconcileLogCollector) Reconcile(ctx context.Context, request reconcile // OS is what differs, and the component handles the OS-specific logic. comp = rlogcollector.FluentBitOSSpecific(fluentBitCfg, rmeta.OSTypeWindows) - if err = imageset.ApplyImageSet(ctx, r.client, variant, comp); err != nil { + if err = imageset.ApplyImageSet(ctx, r.client, r.opts.Variant, comp); err != nil { r.status.SetDegraded(operatorv1.ResourceUpdateError, "Error with images from ImageSet", err, reqLogger) return reconcile.Result{}, err } diff --git a/pkg/controller/logcollector/logcollector_controller_test.go b/pkg/controller/logcollector/logcollector_controller_test.go index e35ae4180e..5e8fde7861 100644 --- a/pkg/controller/logcollector/logcollector_controller_test.go +++ b/pkg/controller/logcollector/logcollector_controller_test.go @@ -105,6 +105,7 @@ var _ = Describe("LogCollector controller tests", func() { tierWatchReady: &utils.ReadyFlag{}, opts: options.ControllerOptions{ DetectedProvider: operatorv1.ProviderNone, + Variant: operatorv1.CalicoEnterprise, }, } @@ -888,6 +889,7 @@ var _ = Describe("LogCollector controller tests", func() { tierWatchReady: readyFlag, opts: options.ControllerOptions{ DetectedProvider: operatorv1.ProviderNone, + Variant: operatorv1.CalicoEnterprise, }, } }) diff --git a/pkg/controller/logstorage/dashboards/dashboards_controller.go b/pkg/controller/logstorage/dashboards/dashboards_controller.go index 703f00c851..9bf035c1d7 100644 --- a/pkg/controller/logstorage/dashboards/dashboards_controller.go +++ b/pkg/controller/logstorage/dashboards/dashboards_controller.go @@ -63,6 +63,7 @@ type DashboardsSubController struct { status status.StatusManager provider operatorv1.Provider clusterDomain string + variant operatorv1.ProductVariant multiTenant bool elasticExternal bool cloud bool @@ -70,7 +71,7 @@ type DashboardsSubController struct { } func Add(mgr manager.Manager, opts options.ControllerOptions) error { - if !opts.EnterpriseCRDExists || opts.MultiTenant { + if !opts.Variant.IsEnterprise() || opts.MultiTenant { return nil } @@ -79,6 +80,7 @@ func Add(mgr manager.Manager, opts options.ControllerOptions) error { scheme: mgr.GetScheme(), status: status.New(mgr.GetClient(), initializer.TigeraStatusLogStorageDashboards, opts.KubernetesVersion), clusterDomain: opts.ClusterDomain, + variant: opts.Variant, provider: opts.DetectedProvider, tierWatchReady: &utils.ReadyFlag{}, multiTenant: opts.MultiTenant, @@ -196,7 +198,7 @@ func (d DashboardsSubController) Reconcile(ctx context.Context, request reconcil } // Get Installation resource. - variant, installationSpec, err := utils.GetInstallationSpec(context.Background(), d.client) + installationSpec, err := utils.GetInstallationSpec(context.Background(), d.client) if err != nil { if errors.IsNotFound(err) { d.status.SetDegraded(operatorv1.ResourceNotFound, "Installation not found", err, reqLogger) @@ -366,7 +368,7 @@ func (d DashboardsSubController) Reconcile(ctx context.Context, request reconcil } dashboardsComponent := dashboards.Dashboards(cfg) - if err := imageset.ApplyImageSet(ctx, d.client, variant, dashboardsComponent); err != nil { + if err := imageset.ApplyImageSet(ctx, d.client, d.variant, dashboardsComponent); err != nil { d.status.SetDegraded(operatorv1.ResourceUpdateError, "Error with images from ImageSet", err, reqLogger) return reconcile.Result{}, err } diff --git a/pkg/controller/logstorage/dashboards/dashboards_controller_test.go b/pkg/controller/logstorage/dashboards/dashboards_controller_test.go index 4b5d2db5c8..a025ee32f4 100644 --- a/pkg/controller/logstorage/dashboards/dashboards_controller_test.go +++ b/pkg/controller/logstorage/dashboards/dashboards_controller_test.go @@ -72,6 +72,7 @@ func NewDashboardsControllerWithShims( ShutdownContext: context.TODO(), MultiTenant: multiTenant, ElasticExternal: externalElastic, + Variant: operatorv1.CalicoEnterprise, } r := &DashboardsSubController{ @@ -79,6 +80,7 @@ func NewDashboardsControllerWithShims( scheme: scheme, status: status, clusterDomain: opts.ClusterDomain, + variant: opts.Variant, multiTenant: opts.MultiTenant, elasticExternal: opts.ElasticExternal, tierWatchReady: &utils.ReadyFlag{}, diff --git a/pkg/controller/logstorage/elastic/elastic_controller.go b/pkg/controller/logstorage/elastic/elastic_controller.go index 63bda0f9ab..664d026cfb 100644 --- a/pkg/controller/logstorage/elastic/elastic_controller.go +++ b/pkg/controller/logstorage/elastic/elastic_controller.go @@ -79,13 +79,14 @@ type ElasticSubController struct { provider operatorv1.Provider esCliCreator utils.ElasticsearchClientCreator clusterDomain string + variant operatorv1.ProductVariant tierWatchReady *utils.ReadyFlag multiTenant bool cloud bool } func Add(mgr manager.Manager, opts options.ControllerOptions) error { - if !opts.EnterpriseCRDExists { + if !opts.Variant.IsEnterprise() { return nil } if opts.ElasticExternal { @@ -102,6 +103,7 @@ func Add(mgr manager.Manager, opts options.ControllerOptions) error { tierWatchReady: &utils.ReadyFlag{}, status: status.New(mgr.GetClient(), initializer.TigeraStatusLogStorageElastic, opts.KubernetesVersion), clusterDomain: opts.ClusterDomain, + variant: opts.Variant, provider: opts.DetectedProvider, multiTenant: opts.MultiTenant, cloud: opts.Cloud, @@ -284,7 +286,7 @@ func (r *ElasticSubController) Reconcile(ctx context.Context, request reconcile. } // Get Installation resource. - variant, installationSpec, err := utils.GetInstallationSpec(context.Background(), r.client) + installationSpec, err := utils.GetInstallationSpec(context.Background(), r.client) if err != nil { if errors.IsNotFound(err) { r.status.SetDegraded(operatorv1.ResourceNotFound, "Installation not found", err, reqLogger) @@ -293,10 +295,6 @@ func (r *ElasticSubController) Reconcile(ctx context.Context, request reconcile. r.status.SetDegraded(operatorv1.ResourceReadError, "An error occurred while querying Installation", err, reqLogger) return reconcile.Result{}, err } - if !variant.IsEnterprise() { - r.status.SetDegraded(operatorv1.ResourceNotReady, "Waiting for network to be an enterprise variant", nil, reqLogger) - return reconcile.Result{}, nil - } // Validate that the tier watch is ready before querying the tier to ensure we utilize the cache. if !r.tierWatchReady.IsReady() { @@ -326,6 +324,7 @@ func (r *ElasticSubController) Reconcile(ctx context.Context, request reconcile. r.status.SetDegraded(operatorv1.ResourceReadError, "Error reading ManagementClusterConnection", err, reqLogger) return reconcile.Result{}, err } + if managementClusterConnection != nil { // LogStorage is not support on a managed cluster. r.status.SetDegraded(operatorv1.ResourceNotReady, "LogStorage is not supported on a managed cluster", nil, reqLogger) @@ -350,6 +349,7 @@ func (r *ElasticSubController) Reconcile(ctx context.Context, request reconcile. r.status.SetDegraded(operatorv1.ResourceCreateError, "Unable to create the Tigera CA", err, reqLogger) return reconcile.Result{}, err } + cm.AddToStatusManager(r.status, render.ElasticsearchNamespace) esDNSNames := dns.GetServiceDNSNames(render.ElasticsearchServiceName, render.ElasticsearchNamespace, r.clusterDomain) @@ -358,6 +358,7 @@ func (r *ElasticSubController) Reconcile(ctx context.Context, request reconcile. r.status.SetDegraded(operatorv1.ResourceCreateError, "Failed to create Elasticsearch secrets", err, log) return reconcile.Result{}, err } + kbDNSNames := dns.GetServiceDNSNames(kibana.ServiceName, kibana.Namespace, r.clusterDomain) kibanaKeyPair, err := cm.GetKeyPair(r.client, kibana.TigeraKibanaCertSecret, common.OperatorNamespace(), kbDNSNames) if err != nil { @@ -404,6 +405,7 @@ func (r *ElasticSubController) Reconcile(ctx context.Context, request reconcile. r.status.SetDegraded(operatorv1.ResourceReadError, "Failed to get Elasticsearch admin user secret", err, reqLogger) return reconcile.Result{}, err } + if esAdminUserSecret != nil { esAdminUserSecret = rsecret.CopyToNamespace(common.OperatorNamespace(), esAdminUserSecret)[0] } @@ -553,7 +555,7 @@ func (r *ElasticSubController) Reconcile(ctx context.Context, request reconcile. } for _, component := range components { - if err = imageset.ApplyImageSet(ctx, r.client, variant, component); err != nil { + if err = imageset.ApplyImageSet(ctx, r.client, r.variant, component); err != nil { r.status.SetDegraded(operatorv1.ResourceUpdateError, "Error with images from ImageSet", err, reqLogger) return reconcile.Result{}, err } diff --git a/pkg/controller/logstorage/elastic/elastic_controller_test.go b/pkg/controller/logstorage/elastic/elastic_controller_test.go index 1d652d8531..2a343a1207 100644 --- a/pkg/controller/logstorage/elastic/elastic_controller_test.go +++ b/pkg/controller/logstorage/elastic/elastic_controller_test.go @@ -94,6 +94,7 @@ func NewReconcilerWithShims( DetectedProvider: provider, ClusterDomain: clusterDomain, ShutdownContext: context.TODO(), + Variant: operatorv1.CalicoEnterprise, } r := &ElasticSubController{ @@ -103,6 +104,7 @@ func NewReconcilerWithShims( tierWatchReady: tierWatchReady, status: status, clusterDomain: opts.ClusterDomain, + variant: opts.Variant, provider: opts.DetectedProvider, multiTenant: opts.MultiTenant, } diff --git a/pkg/controller/logstorage/elastic/external_elastic_controller.go b/pkg/controller/logstorage/elastic/external_elastic_controller.go index 2b18d64e15..0160730094 100644 --- a/pkg/controller/logstorage/elastic/external_elastic_controller.go +++ b/pkg/controller/logstorage/elastic/external_elastic_controller.go @@ -52,7 +52,7 @@ type ExternalESController struct { } func AddExternalES(mgr manager.Manager, opts options.ControllerOptions) error { - if !opts.EnterpriseCRDExists { + if !opts.Variant.IsEnterprise() { return nil } if !opts.ElasticExternal { @@ -127,7 +127,7 @@ func (r *ExternalESController) Reconcile(ctx context.Context, request reconcile. } r.status.OnCRFound() - _, installationSpec, err := utils.GetInstallationSpec(context.Background(), r.client) + installationSpec, err := utils.GetInstallationSpec(context.Background(), r.client) if err != nil { if errors.IsNotFound(err) { r.status.SetDegraded(operatorv1.ResourceNotFound, "Installation not found", err, reqLogger) diff --git a/pkg/controller/logstorage/elastic/external_elastic_controller_test.go b/pkg/controller/logstorage/elastic/external_elastic_controller_test.go index 551a456b66..1ffc30f6c7 100644 --- a/pkg/controller/logstorage/elastic/external_elastic_controller_test.go +++ b/pkg/controller/logstorage/elastic/external_elastic_controller_test.go @@ -220,6 +220,7 @@ func NewExternalESReconcilerWithShims( ClusterDomain: clusterDomain, ShutdownContext: context.TODO(), ElasticExternal: true, + Variant: operatorv1.CalicoEnterprise, } r := &ExternalESController{ diff --git a/pkg/controller/logstorage/esmetrics/esmetrics_controller.go b/pkg/controller/logstorage/esmetrics/esmetrics_controller.go index 82eaa1db4d..53688e76ab 100644 --- a/pkg/controller/logstorage/esmetrics/esmetrics_controller.go +++ b/pkg/controller/logstorage/esmetrics/esmetrics_controller.go @@ -57,12 +57,13 @@ type ESMetricsSubController struct { status status.StatusManager provider operatorv1.Provider clusterDomain string + variant operatorv1.ProductVariant multiTenant bool tierWatchReady *utils.ReadyFlag } func Add(mgr manager.Manager, opts options.ControllerOptions) error { - if !opts.EnterpriseCRDExists { + if !opts.Variant.IsEnterprise() { return nil } @@ -77,6 +78,7 @@ func Add(mgr manager.Manager, opts options.ControllerOptions) error { scheme: mgr.GetScheme(), status: status.New(mgr.GetClient(), initializer.TigeraStatusLogStorageESMetrics, opts.KubernetesVersion), clusterDomain: opts.ClusterDomain, + variant: opts.Variant, provider: opts.DetectedProvider, tierWatchReady: &utils.ReadyFlag{}, } @@ -180,7 +182,7 @@ func (r *ESMetricsSubController) Reconcile(ctx context.Context, request reconcil return reconcile.Result{}, nil } - variant, installationSpec, err := utils.GetInstallationSpec(context.Background(), r.client) + installationSpec, err := utils.GetInstallationSpec(context.Background(), r.client) if err != nil { if errors.IsNotFound(err) { r.status.SetDegraded(operatorv1.ResourceNotFound, "Installation not found", err, reqLogger) @@ -239,7 +241,7 @@ func (r *ESMetricsSubController) Reconcile(ctx context.Context, request reconcil LogStorage: logStorage, } esMetricsComponent := esmetrics.ElasticsearchMetrics(esMetricsCfg) - if err = imageset.ApplyImageSet(ctx, r.client, variant, esMetricsComponent); err != nil { + if err = imageset.ApplyImageSet(ctx, r.client, r.variant, esMetricsComponent); err != nil { r.status.SetDegraded(operatorv1.ResourceUpdateError, "Error with images from ImageSet", err, reqLogger) return reconcile.Result{}, err } diff --git a/pkg/controller/logstorage/esmetrics/esmetrics_controller_test.go b/pkg/controller/logstorage/esmetrics/esmetrics_controller_test.go index d9e3be78a3..6ae6da29f1 100644 --- a/pkg/controller/logstorage/esmetrics/esmetrics_controller_test.go +++ b/pkg/controller/logstorage/esmetrics/esmetrics_controller_test.go @@ -61,6 +61,7 @@ func NewESMetricsControllerWithShims( ClusterDomain: clusterDomain, ShutdownContext: context.TODO(), MultiTenant: multiTenant, + Variant: operatorv1.CalicoEnterprise, } r := &ESMetricsSubController{ @@ -68,6 +69,7 @@ func NewESMetricsControllerWithShims( scheme: scheme, status: status, clusterDomain: opts.ClusterDomain, + variant: opts.Variant, multiTenant: opts.MultiTenant, tierWatchReady: readyFlag, } diff --git a/pkg/controller/logstorage/initializer/conditions_controller.go b/pkg/controller/logstorage/initializer/conditions_controller.go index a546f22eec..847a589b68 100644 --- a/pkg/controller/logstorage/initializer/conditions_controller.go +++ b/pkg/controller/logstorage/initializer/conditions_controller.go @@ -35,7 +35,7 @@ import ( ) func AddConditionsController(mgr manager.Manager, opts options.ControllerOptions) error { - if !opts.EnterpriseCRDExists { + if !opts.Variant.IsEnterprise() { return nil } diff --git a/pkg/controller/logstorage/initializer/conditions_controller_test.go b/pkg/controller/logstorage/initializer/conditions_controller_test.go index 1a33bff2e5..04e35e83ba 100644 --- a/pkg/controller/logstorage/initializer/conditions_controller_test.go +++ b/pkg/controller/logstorage/initializer/conditions_controller_test.go @@ -48,6 +48,7 @@ func NewTestConditionController( opts := options.ControllerOptions{ ClusterDomain: clusterDomain, ShutdownContext: context.TODO(), + Variant: operatorv1.CalicoEnterprise, } r := &LogStorageConditions{ diff --git a/pkg/controller/logstorage/initializer/initializing_controller.go b/pkg/controller/logstorage/initializer/initializing_controller.go index edcc44f467..33c193f950 100644 --- a/pkg/controller/logstorage/initializer/initializing_controller.go +++ b/pkg/controller/logstorage/initializer/initializing_controller.go @@ -58,7 +58,7 @@ const ( // Add creates a new LogStorage Controller and adds it to the Manager. The Manager will set fields on the Controller // and Start it when the Manager is Started. func Add(mgr manager.Manager, opts options.ControllerOptions) error { - if !opts.EnterpriseCRDExists { + if !opts.Variant.IsEnterprise() { return nil } @@ -237,7 +237,7 @@ func (r *LogStorageInitializer) Reconcile(ctx context.Context, request reconcile r.status.OnCRFound() // Get Installation resource. - _, installationSpec, err := utils.GetInstallationSpec(context.Background(), r.client) + installationSpec, err := utils.GetInstallationSpec(context.Background(), r.client) if err != nil { if errors.IsNotFound(err) { r.status.SetDegraded(operatorv1.ResourceNotFound, "Installation not found", err, reqLogger) diff --git a/pkg/controller/logstorage/initializer/initializing_controller_test.go b/pkg/controller/logstorage/initializer/initializing_controller_test.go index 54fa20f582..aa2ec6194b 100644 --- a/pkg/controller/logstorage/initializer/initializing_controller_test.go +++ b/pkg/controller/logstorage/initializer/initializing_controller_test.go @@ -58,6 +58,7 @@ func NewTestInitializer( DetectedProvider: provider, ClusterDomain: clusterDomain, ShutdownContext: context.TODO(), + Variant: operatorv1.CalicoEnterprise, } r := &LogStorageInitializer{ diff --git a/pkg/controller/logstorage/kubecontrollers/es_kube_controllers.go b/pkg/controller/logstorage/kubecontrollers/es_kube_controllers.go index 2c2ae2c0a1..735685963c 100644 --- a/pkg/controller/logstorage/kubecontrollers/es_kube_controllers.go +++ b/pkg/controller/logstorage/kubecontrollers/es_kube_controllers.go @@ -60,6 +60,7 @@ type ESKubeControllersController struct { scheme *runtime.Scheme status status.StatusManager clusterDomain string + variant operatorv1.ProductVariant elasticExternal bool multiTenant bool cloud bool @@ -67,7 +68,7 @@ type ESKubeControllersController struct { } func Add(mgr manager.Manager, opts options.ControllerOptions) error { - if !opts.EnterpriseCRDExists { + if !opts.Variant.IsEnterprise() { return nil } @@ -84,6 +85,7 @@ func Add(mgr manager.Manager, opts options.ControllerOptions) error { client: mgr.GetClient(), scheme: mgr.GetScheme(), clusterDomain: opts.ClusterDomain, + variant: opts.Variant, status: status.New(mgr.GetClient(), initializer.TigeraStatusLogStorageKubeController, opts.KubernetesVersion), elasticExternal: opts.ElasticExternal, multiTenant: opts.MultiTenant, @@ -211,7 +213,7 @@ func (r *ESKubeControllersController) Reconcile(ctx context.Context, request rec } // Get Installation resource. - variant, installationSpec, err := utils.GetInstallationSpec(context.Background(), r.client) + installationSpec, err := utils.GetInstallationSpec(context.Background(), r.client) if err != nil { if errors.IsNotFound(err) { r.status.SetDegraded(operatorv1.ResourceNotFound, "Installation not found", err, reqLogger) @@ -316,7 +318,7 @@ func (r *ESKubeControllersController) Reconcile(ctx context.Context, request rec ctx, gwNSHelper, installationSpec, - variant, + r.variant, pullSecrets, hdler, reqLogger, @@ -361,7 +363,7 @@ func (r *ESKubeControllersController) Reconcile(ctx context.Context, request rec } esKubeControllerComponents := kubecontrollers.NewElasticsearchKubeControllers(&kubeControllersCfg) - imageSet, err := imageset.GetImageSet(ctx, r.client, variant) + imageSet, err := imageset.GetImageSet(ctx, r.client, r.variant) if err != nil { r.status.SetDegraded(operatorv1.ResourceReadError, "Error getting ImageSet", err, reqLogger) return reconcile.Result{}, err diff --git a/pkg/controller/logstorage/kubecontrollers/es_kube_controllers_test.go b/pkg/controller/logstorage/kubecontrollers/es_kube_controllers_test.go index 298b27e8cf..1052bd148f 100644 --- a/pkg/controller/logstorage/kubecontrollers/es_kube_controllers_test.go +++ b/pkg/controller/logstorage/kubecontrollers/es_kube_controllers_test.go @@ -73,6 +73,7 @@ func NewControllerWithShims( ClusterDomain: clusterDomain, ShutdownContext: context.TODO(), MultiTenant: multiTenant, + Variant: operatorv1.CalicoEnterprise, } r := &ESKubeControllersController{ @@ -80,6 +81,7 @@ func NewControllerWithShims( scheme: scheme, status: status, clusterDomain: opts.ClusterDomain, + variant: opts.Variant, tierWatchReady: tierWatchReady, multiTenant: multiTenant, } diff --git a/pkg/controller/logstorage/linseed/linseed_controller.go b/pkg/controller/logstorage/linseed/linseed_controller.go index 6135175110..1c34680068 100644 --- a/pkg/controller/logstorage/linseed/linseed_controller.go +++ b/pkg/controller/logstorage/linseed/linseed_controller.go @@ -64,6 +64,7 @@ type LinseedSubController struct { scheme *runtime.Scheme status status.StatusManager clusterDomain string + variant operatorv1.ProductVariant tierWatchReady *utils.ReadyFlag dpiAPIReady *utils.ReadyFlag multiTenant bool @@ -72,7 +73,7 @@ type LinseedSubController struct { } func Add(mgr manager.Manager, opts options.ControllerOptions) error { - if !opts.EnterpriseCRDExists { + if !opts.Variant.IsEnterprise() { return nil } @@ -81,6 +82,7 @@ func Add(mgr manager.Manager, opts options.ControllerOptions) error { client: mgr.GetClient(), scheme: mgr.GetScheme(), clusterDomain: opts.ClusterDomain, + variant: opts.Variant, tierWatchReady: &utils.ReadyFlag{}, dpiAPIReady: &utils.ReadyFlag{}, multiTenant: opts.MultiTenant, @@ -247,7 +249,7 @@ func (r *LinseedSubController) Reconcile(ctx context.Context, request reconcile. } // Get Installation resource. - variant, installationSpec, err := utils.GetInstallationSpec(context.Background(), r.client) + installationSpec, err := utils.GetInstallationSpec(context.Background(), r.client) if err != nil { if errors.IsNotFound(err) { r.status.SetDegraded(operatorv1.ResourceNotFound, "Installation not found", err, reqLogger) @@ -471,7 +473,7 @@ func (r *LinseedSubController) Reconcile(ctx context.Context, request reconcile. } linseedComponent := linseed.Linseed(cfg) - if err := imageset.ApplyImageSet(ctx, r.client, variant, linseedComponent); err != nil { + if err := imageset.ApplyImageSet(ctx, r.client, r.variant, linseedComponent); err != nil { r.status.SetDegraded(operatorv1.ResourceUpdateError, "Error with images from ImageSet", err, reqLogger) return reconcile.Result{}, err } diff --git a/pkg/controller/logstorage/linseed/linseed_controller_test.go b/pkg/controller/logstorage/linseed/linseed_controller_test.go index 89ecefe269..9324eac26d 100644 --- a/pkg/controller/logstorage/linseed/linseed_controller_test.go +++ b/pkg/controller/logstorage/linseed/linseed_controller_test.go @@ -72,6 +72,7 @@ func NewLinseedControllerWithShims( ClusterDomain: clusterDomain, ShutdownContext: context.TODO(), MultiTenant: multiTenant, + Variant: operatorv1.CalicoEnterprise, } r := &LinseedSubController{ @@ -79,6 +80,7 @@ func NewLinseedControllerWithShims( scheme: scheme, status: status, clusterDomain: opts.ClusterDomain, + variant: opts.Variant, multiTenant: opts.MultiTenant, tierWatchReady: &utils.ReadyFlag{}, dpiAPIReady: &utils.ReadyFlag{}, diff --git a/pkg/controller/logstorage/managedcluster/managed_cluster_controller.go b/pkg/controller/logstorage/managedcluster/managed_cluster_controller.go index b61f823d3d..ba91718b41 100644 --- a/pkg/controller/logstorage/managedcluster/managed_cluster_controller.go +++ b/pkg/controller/logstorage/managedcluster/managed_cluster_controller.go @@ -47,7 +47,7 @@ type LogStorageManagedClusterController struct { } func Add(mgr manager.Manager, opts options.ControllerOptions) error { - if !opts.EnterpriseCRDExists { + if !opts.Variant.IsEnterprise() { return nil } @@ -103,22 +103,19 @@ func (r *LogStorageManagedClusterController) Reconcile(ctx context.Context, requ reqLogger.Info("Reconciling ManagedCluster resources for log storage") - // Make sure this is an Enterprise cluster. - variant, installationSpec, err := utils.GetInstallationSpec(context.Background(), r.client) + installationSpec, err := utils.GetInstallationSpec(context.Background(), r.client) if err != nil { if errors.IsNotFound(err) { return reconcile.Result{}, err } return reconcile.Result{}, err } - if !variant.IsEnterprise() { - return reconcile.Result{}, nil - } managementCluster, err := utils.GetManagementCluster(ctx, r.client) if err != nil { return reconcile.Result{}, err } + if managementCluster != nil { // ManagementCluster is not supported on a managed cluster. Return an error. return reconcile.Result{}, fmt.Errorf("ManagementCluster is not supported on a managed cluster") @@ -128,6 +125,7 @@ func (r *LogStorageManagedClusterController) Reconcile(ctx context.Context, requ if err != nil { return reconcile.Result{}, err } + if exists { // LogStorage is not supported on a managed cluster. Return an error. return reconcile.Result{}, fmt.Errorf("LogStorage is not supported on a managed cluster") diff --git a/pkg/controller/logstorage/managedcluster/managed_cluster_controller_test.go b/pkg/controller/logstorage/managedcluster/managed_cluster_controller_test.go index 34a44d8de8..195b1da192 100644 --- a/pkg/controller/logstorage/managedcluster/managed_cluster_controller_test.go +++ b/pkg/controller/logstorage/managedcluster/managed_cluster_controller_test.go @@ -47,6 +47,7 @@ func NewReconcilerWithShims( DetectedProvider: provider, ClusterDomain: clusterDomain, ShutdownContext: context.TODO(), + Variant: operatorv1.CalicoEnterprise, } r := &LogStorageManagedClusterController{ diff --git a/pkg/controller/logstorage/secrets/secret_controller.go b/pkg/controller/logstorage/secrets/secret_controller.go index 7c8f76ff0d..4134b49be0 100644 --- a/pkg/controller/logstorage/secrets/secret_controller.go +++ b/pkg/controller/logstorage/secrets/secret_controller.go @@ -67,7 +67,7 @@ type SecretSubController struct { } func Add(mgr manager.Manager, opts options.ControllerOptions) error { - if !opts.EnterpriseCRDExists { + if !opts.Variant.IsEnterprise() { return nil } @@ -217,7 +217,7 @@ func (r *SecretSubController) Reconcile(ctx context.Context, request reconcile.R } // Get Installation resource. - _, installationSpec, err := utils.GetInstallationSpec(context.Background(), r.client) + installationSpec, err := utils.GetInstallationSpec(context.Background(), r.client) if err != nil { if errors.IsNotFound(err) { r.status.SetDegraded(operatorv1.ResourceNotFound, "Installation not found", err, reqLogger) diff --git a/pkg/controller/logstorage/secrets/secret_controller_test.go b/pkg/controller/logstorage/secrets/secret_controller_test.go index cba8f43de9..24ed4e3838 100644 --- a/pkg/controller/logstorage/secrets/secret_controller_test.go +++ b/pkg/controller/logstorage/secrets/secret_controller_test.go @@ -87,6 +87,7 @@ func NewSecretControllerWithShims( DetectedProvider: provider, ClusterDomain: clusterDomain, ShutdownContext: context.TODO(), + Variant: operatorv1.CalicoEnterprise, } r := &SecretSubController{ @@ -113,6 +114,7 @@ func NewMultiTenantSecretControllerWithShims( ShutdownContext: context.TODO(), MultiTenant: true, ElasticExternal: true, + Variant: operatorv1.CalicoEnterprise, } r := &SecretSubController{ diff --git a/pkg/controller/logstorage/users/users_controller.go b/pkg/controller/logstorage/users/users_controller.go index f7a173837d..c1deaf9e1f 100644 --- a/pkg/controller/logstorage/users/users_controller.go +++ b/pkg/controller/logstorage/users/users_controller.go @@ -69,7 +69,7 @@ type UsersCleanupController struct { } func Add(mgr manager.Manager, opts options.ControllerOptions) error { - if !opts.EnterpriseCRDExists { + if !opts.Variant.IsEnterprise() { return nil } if !opts.MultiTenant { diff --git a/pkg/controller/manager/manager_controller.go b/pkg/controller/manager/manager_controller.go index 993e229821..b7a8e06ccc 100644 --- a/pkg/controller/manager/manager_controller.go +++ b/pkg/controller/manager/manager_controller.go @@ -64,7 +64,7 @@ var log = logf.Log.WithName("controller_manager") // Add creates a new Manager Controller and adds it to the Manager. The Manager will set fields on the Controller // and Start it when the Manager is Started. func Add(mgr manager.Manager, opts options.ControllerOptions) error { - if !opts.EnterpriseCRDExists { + if !opts.Variant.IsEnterprise() { // No need to start this controller. return nil } @@ -336,7 +336,7 @@ func (r *ReconcileManager) Reconcile(ctx context.Context, request reconcile.Requ // Fetch the Installation instance. We need this for a few reasons. // - We need to make sure it has successfully completed installation. // - We need to get the registry information from its spec. - variant, installationSpec, err := utils.GetInstallationSpec(ctx, r.client) + installationSpec, err := utils.GetInstallationSpec(ctx, r.client) if err != nil { if errors.IsNotFound(err) { r.status.SetDegraded(operatorv1.ResourceNotFound, "Installation not found", err, logc) @@ -747,7 +747,7 @@ func (r *ReconcileManager) Reconcile(ctx context.Context, request reconcile.Requ return reconcile.Result{}, err } - if err = imageset.ApplyImageSet(ctx, r.client, variant, component); err != nil { + if err = imageset.ApplyImageSet(ctx, r.client, r.opts.Variant, component); err != nil { r.status.SetDegraded(operatorv1.ResourceUpdateError, "Error with images from ImageSet", err, logc) return reconcile.Result{}, err } diff --git a/pkg/controller/manager/manager_controller_test.go b/pkg/controller/manager/manager_controller_test.go index b3960fa4c7..98417f1d98 100644 --- a/pkg/controller/manager/manager_controller_test.go +++ b/pkg/controller/manager/manager_controller_test.go @@ -165,6 +165,7 @@ var _ = Describe("Manager controller tests", func() { opts: options.ControllerOptions{ ClusterDomain: clusterDomain, DetectedProvider: operatorv1.ProviderNone, + Variant: operatorv1.CalicoEnterprise, }, } @@ -454,6 +455,7 @@ var _ = Describe("Manager controller tests", func() { tierWatchReady: &utils.ReadyFlag{}, opts: options.ControllerOptions{ DetectedProvider: operatorv1.ProviderNone, + Variant: operatorv1.CalicoEnterprise, }, } @@ -714,6 +716,7 @@ var _ = Describe("Manager controller tests", func() { tierWatchReady: readyFlag, opts: options.ControllerOptions{ DetectedProvider: operatorv1.ProviderNone, + Variant: operatorv1.CalicoEnterprise, }, } }) diff --git a/pkg/controller/monitor/monitor_controller.go b/pkg/controller/monitor/monitor_controller.go index 5ed2e549fa..eae02c3794 100644 --- a/pkg/controller/monitor/monitor_controller.go +++ b/pkg/controller/monitor/monitor_controller.go @@ -60,7 +60,7 @@ const ResourceName = "monitor" var log = logf.Log.WithName("controller_monitor") func Add(mgr manager.Manager, opts options.ControllerOptions) error { - if !opts.EnterpriseCRDExists { + if !opts.Variant.IsEnterprise() { return nil } @@ -108,6 +108,7 @@ func newReconciler(mgr manager.Manager, opts options.ControllerOptions, promethe tierWatchReady: tierWatchReady, licenseAPIReady: licenseAPIReady, clusterDomain: opts.ClusterDomain, + variant: opts.Variant, multiTenant: opts.MultiTenant, cloud: opts.Cloud, } @@ -189,6 +190,7 @@ type ReconcileMonitor struct { tierWatchReady *utils.ReadyFlag licenseAPIReady *utils.ReadyFlag clusterDomain string + variant operatorv1.ProductVariant multiTenant bool cloud bool } @@ -285,7 +287,7 @@ func (r *ReconcileMonitor) Reconcile(ctx context.Context, request reconcile.Requ graceRequeueAfter = time.Until(license.Status.Expiry.Add(gracePeriod)) } - variant, installationSpec, err := utils.GetInstallationSpec(context.Background(), r.client) + installationSpec, err := utils.GetInstallationSpec(context.Background(), r.client) if err != nil { if errors.IsNotFound(err) { r.status.SetDegraded(operatorv1.ResourceNotFound, "Installation not found", err, reqLogger) @@ -480,7 +482,7 @@ func (r *ReconcileMonitor) Reconcile(ctx context.Context, request reconcile.Requ components = append(components, monitor.MonitorPolicy(monitorCfg)) } - if err = imageset.ApplyImageSet(ctx, r.client, variant, components...); err != nil { + if err = imageset.ApplyImageSet(ctx, r.client, r.variant, components...); err != nil { r.status.SetDegraded(operatorv1.ResourceUpdateError, "Error with images from ImageSet", err, reqLogger) return reconcile.Result{}, err } diff --git a/pkg/controller/nonclusterhost/nonclusterhost_controller.go b/pkg/controller/nonclusterhost/nonclusterhost_controller.go index dd0868ab25..bf3a4bc7a6 100644 --- a/pkg/controller/nonclusterhost/nonclusterhost_controller.go +++ b/pkg/controller/nonclusterhost/nonclusterhost_controller.go @@ -41,7 +41,7 @@ const controllerName = "nonclusterhost-controller" var log = logf.Log.WithName("controller_nonclusterhost") func Add(mgr manager.Manager, opts options.ControllerOptions) error { - if !opts.EnterpriseCRDExists { + if !opts.Variant.IsEnterprise() { return nil } diff --git a/pkg/controller/options/options.go b/pkg/controller/options/options.go index b1f1c50b57..7a7f0d8622 100644 --- a/pkg/controller/options/options.go +++ b/pkg/controller/options/options.go @@ -28,12 +28,16 @@ import ( // use to determine if they should run at all, or store them and influence their // reconciliation loops. type ControllerOptions struct { - DetectedProvider v1.Provider - EnterpriseCRDExists bool - ClusterDomain string - KubernetesVersion *common.VersionInfo - ManageCRDs bool - ShutdownContext context.Context + DetectedProvider v1.Provider + + // Variant is the product variant resolved from the Installation before any controller + // started. The process runs as this variant for its lifetime; a change restarts it. + Variant v1.ProductVariant + + ClusterDomain string + KubernetesVersion *common.VersionInfo + ManageCRDs bool + ShutdownContext context.Context // Kubernetes clientset used by controllers to create watchers and informers. K8sClientset *kubernetes.Clientset diff --git a/pkg/controller/packetcapture/packetcapture_controller.go b/pkg/controller/packetcapture/packetcapture_controller.go index c075178d50..a7228f4cc9 100644 --- a/pkg/controller/packetcapture/packetcapture_controller.go +++ b/pkg/controller/packetcapture/packetcapture_controller.go @@ -55,7 +55,7 @@ var log = logf.Log.WithName("controller_packet_capture") // Add creates a new PacketCapture Controller and adds it to the Manager. The Manager will set fields on the Controller // and Start it when the Manager is Started. func Add(mgr manager.Manager, opts options.ControllerOptions) error { - if !opts.EnterpriseCRDExists { + if !opts.Variant.IsEnterprise() { // No need to start this controller return nil } @@ -159,7 +159,7 @@ func (r *ReconcilePacketCapture) Reconcile(ctx context.Context, request reconcil } } - variant, installationSpec, err := utils.GetInstallationSpec(context.Background(), r.client) + installationSpec, err := utils.GetInstallationSpec(context.Background(), r.client) if err != nil { if errors.IsNotFound(err) { r.status.SetDegraded(operatorv1.ResourceNotFound, "Installation not found", err, reqLogger) @@ -169,11 +169,6 @@ func (r *ReconcilePacketCapture) Reconcile(ctx context.Context, request reconcil return reconcile.Result{}, err } - if !variant.IsEnterprise() { - r.status.SetDegraded(operatorv1.ResourceNotReady, "Waiting for Installation variant to be an enterprise variant", nil, reqLogger) - return reconcile.Result{}, err - } - managementCluster, err := utils.GetManagementCluster(ctx, r.client) if err != nil { r.status.SetDegraded(operatorv1.ResourceReadError, "Error reading ManagementCluster", err, reqLogger) @@ -215,6 +210,7 @@ func (r *ReconcilePacketCapture) Reconcile(ctx context.Context, request reconcil r.status.SetDegraded(operatorv1.ResourceCreateError, "Unable to create the Tigera CA", err, reqLogger) return reconcile.Result{}, err } + packetCaptureCertSecret, err := certificateManager.GetOrCreateKeyPair( r.client, render.PacketCaptureServerCert, @@ -291,7 +287,7 @@ func (r *ReconcilePacketCapture) Reconcile(ctx context.Context, request reconcil components = append(components, pcPolicy) } - if err = imageset.ApplyImageSet(ctx, r.client, variant, components...); err != nil { + if err = imageset.ApplyImageSet(ctx, r.client, r.opts.Variant, components...); err != nil { r.status.SetDegraded(operatorv1.ResourceUpdateError, "Error with images from ImageSet", err, reqLogger) return reconcile.Result{}, err } @@ -321,5 +317,6 @@ func (r *ReconcilePacketCapture) Reconcile(ctx context.Context, request reconcil if err = r.client.Status().Update(ctx, packetcaptureapi); err != nil { return reconcile.Result{}, err } + return reconcile.Result{}, nil } diff --git a/pkg/controller/packetcapture/packetcapture_controller_test.go b/pkg/controller/packetcapture/packetcapture_controller_test.go index c5497e61d8..111940b931 100644 --- a/pkg/controller/packetcapture/packetcapture_controller_test.go +++ b/pkg/controller/packetcapture/packetcapture_controller_test.go @@ -156,8 +156,8 @@ var _ = Describe("packet capture controller tests", func() { status: mockStatus, tierWatchReady: ready, opts: options.ControllerOptions{ - DetectedProvider: operatorv1.ProviderNone, - EnterpriseCRDExists: true, + DetectedProvider: operatorv1.ProviderNone, + Variant: operatorv1.CalicoEnterprise, }, } @@ -320,8 +320,8 @@ var _ = Describe("packet capture controller tests", func() { status: mockStatus, tierWatchReady: readyFlag, opts: options.ControllerOptions{ - DetectedProvider: operatorv1.ProviderNone, - EnterpriseCRDExists: true, + DetectedProvider: operatorv1.ProviderNone, + Variant: operatorv1.CalicoEnterprise, }, } Expect(cli.Create(ctx, installation)).To(BeNil()) @@ -557,9 +557,9 @@ var _ = Describe("packet capture controller tests", func() { status: mockStatus, tierWatchReady: ready, opts: options.ControllerOptions{ - DetectedProvider: operatorv1.ProviderNone, - EnterpriseCRDExists: true, - MultiTenant: true, + DetectedProvider: operatorv1.ProviderNone, + Variant: operatorv1.CalicoEnterprise, + MultiTenant: true, }, } @@ -586,9 +586,9 @@ var _ = Describe("packet capture controller tests", func() { status: mockStatus, tierWatchReady: ready, opts: options.ControllerOptions{ - DetectedProvider: operatorv1.ProviderNone, - EnterpriseCRDExists: true, - MultiTenant: false, + DetectedProvider: operatorv1.ProviderNone, + Variant: operatorv1.CalicoEnterprise, + MultiTenant: false, }, } diff --git a/pkg/controller/podiprecovery/podiprecovery_controller.go b/pkg/controller/podiprecovery/podiprecovery_controller.go index 6858122b7d..8570c87796 100644 --- a/pkg/controller/podiprecovery/podiprecovery_controller.go +++ b/pkg/controller/podiprecovery/podiprecovery_controller.go @@ -330,7 +330,7 @@ func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Resu // Gate on Installation: if Calico hasn't been installed yet, the // operator-managed pods we'd act on don't exist. Bail out silently. - if _, _, err := utils.GetInstallationSpec(ctx, r.client); err != nil { + if _, err := utils.GetInstallationSpec(ctx, r.client); err != nil { if apierrors.IsNotFound(err) { return ctrl.Result{}, nil } diff --git a/pkg/controller/policyrecommendation/policyrecommendation_controller.go b/pkg/controller/policyrecommendation/policyrecommendation_controller.go index 1fca4018cc..3fdd36a259 100644 --- a/pkg/controller/policyrecommendation/policyrecommendation_controller.go +++ b/pkg/controller/policyrecommendation/policyrecommendation_controller.go @@ -59,7 +59,7 @@ var log = logf.Log.WithName("controller_policy_recommendation") // Add creates a new PolicyRecommendation Controller and adds it to the Manager. The Manager will // set fields on the Controller and Start it when the Manager is Started. func Add(mgr manager.Manager, opts options.ControllerOptions) error { - if !opts.EnterpriseCRDExists { + if !opts.Variant.IsEnterprise() { // No need to start this controller return nil } @@ -305,7 +305,7 @@ func (r *ReconcilePolicyRecommendation) Reconcile(ctx context.Context, request r } // Query for the installation object. - variant, installationSpec, err := utils.GetInstallationSpec(ctx, r.client) + installationSpec, err := utils.GetInstallationSpec(ctx, r.client) if err != nil { if errors.IsNotFound(err) { r.status.SetDegraded(operatorv1.ResourceNotFound, "Installation not found", err, logc) @@ -479,7 +479,7 @@ func (r *ReconcilePolicyRecommendation) Reconcile(ctx context.Context, request r // Render the desired objects from the CRD and create or update them. component := render.PolicyRecommendation(policyRecommendationCfg) - if err = imageset.ApplyImageSet(ctx, r.client, variant, component); err != nil { + if err = imageset.ApplyImageSet(ctx, r.client, r.opts.Variant, component); err != nil { r.status.SetDegraded(operatorv1.ResourceUpdateError, "Error with images from ImageSet", err, logc) return reconcile.Result{}, err } diff --git a/pkg/controller/policyrecommendation/policyrecommendation_controller_test.go b/pkg/controller/policyrecommendation/policyrecommendation_controller_test.go index 9b3b9d7c15..a35ed687f0 100644 --- a/pkg/controller/policyrecommendation/policyrecommendation_controller_test.go +++ b/pkg/controller/policyrecommendation/policyrecommendation_controller_test.go @@ -106,6 +106,7 @@ var _ = Describe("PolicyRecommendation controller tests", func() { policyRecScopeWatchReady: &utils.ReadyFlag{}, opts: options.ControllerOptions{ DetectedProvider: operatorv1.ProviderNone, + Variant: operatorv1.CalicoEnterprise, }, } @@ -250,6 +251,7 @@ var _ = Describe("PolicyRecommendation controller tests", func() { policyRecScopeWatchReady: readyFlag, opts: options.ControllerOptions{ DetectedProvider: operatorv1.ProviderNone, + Variant: operatorv1.CalicoEnterprise, }, } }) @@ -520,6 +522,7 @@ var _ = Describe("PolicyRecommendation controller tests", func() { policyRecScopeWatchReady: &utils.ReadyFlag{}, opts: options.ControllerOptions{ DetectedProvider: operatorv1.ProviderNone, + Variant: operatorv1.CalicoEnterprise, }, } @@ -558,6 +561,7 @@ var _ = Describe("PolicyRecommendation controller tests", func() { // Set the provider to OpenShift. opts: options.ControllerOptions{ DetectedProvider: operatorv1.ProviderOpenShift, + Variant: operatorv1.CalicoEnterprise, }, } diff --git a/pkg/controller/secrets/cluster_ca_controller.go b/pkg/controller/secrets/cluster_ca_controller.go index 70fcd74ac7..ba54ac8f01 100644 --- a/pkg/controller/secrets/cluster_ca_controller.go +++ b/pkg/controller/secrets/cluster_ca_controller.go @@ -82,7 +82,7 @@ func (r *ClusterCAController) Reconcile(ctx context.Context, request reconcile.R logc := r.log.WithValues("Request.Namespace", request.Namespace, "Request.Name", request.Name) // Get Installation resource. - _, installationSpec, err := utils.GetInstallationSpec(ctx, r.client) + installationSpec, err := utils.GetInstallationSpec(ctx, r.client) if err != nil { if errors.IsNotFound(err) { logc.Info("Installation not found") diff --git a/pkg/controller/secrets/tenant_controller.go b/pkg/controller/secrets/tenant_controller.go index 65800d68f5..4a15fb46be 100644 --- a/pkg/controller/secrets/tenant_controller.go +++ b/pkg/controller/secrets/tenant_controller.go @@ -137,7 +137,7 @@ func (r *TenantController) Reconcile(ctx context.Context, request reconcile.Requ } } // Get Installation resource. - _, installationSpec, err := utils.GetInstallationSpec(context.Background(), r.client) + installationSpec, err := utils.GetInstallationSpec(context.Background(), r.client) if err != nil { if errors.IsNotFound(err) { r.status.SetDegraded(operatorv1.ResourceNotFound, "Installation not found", err, logc) diff --git a/pkg/controller/tiers/tiers_controller.go b/pkg/controller/tiers/tiers_controller.go index c670af4d90..cd4b4d67c8 100644 --- a/pkg/controller/tiers/tiers_controller.go +++ b/pkg/controller/tiers/tiers_controller.go @@ -168,7 +168,7 @@ func (r *ReconcileTiers) prepareTiersConfig(ctx context.Context, reqLogger logr. namespaces := []string{ common.CalicoNamespace, } - if r.opts.EnterpriseCRDExists { + if r.opts.Variant.IsEnterprise() { namespaces = append(namespaces, render.ComplianceNamespace, render.DexNamespace, diff --git a/pkg/controller/utils/component.go b/pkg/controller/utils/component.go index 8e11568af6..f705df4152 100644 --- a/pkg/controller/utils/component.go +++ b/pkg/controller/utils/component.go @@ -462,7 +462,7 @@ func (c *componentHandler) CreateOrUpdateOrDelete(ctx context.Context, component // Load the InstallationSpec once and reuse it for every object: createOrUpdateObject needs it // for image pull policy and TLS ciphers, and we use it here to decide whether the user has // disabled policy management. - _, installationSpec, err := GetInstallationSpec(ctx, c.client) + installationSpec, err := GetInstallationSpec(ctx, c.client) if err != nil && !errors.IsNotFound(err) { return err } diff --git a/pkg/controller/utils/utils.go b/pkg/controller/utils/utils.go index 5c805ace9e..2e71b5b16e 100644 --- a/pkg/controller/utils/utils.go +++ b/pkg/controller/utils/utils.go @@ -35,7 +35,6 @@ import ( "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" - "k8s.io/apimachinery/pkg/fields" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/types" @@ -43,6 +42,7 @@ import ( "k8s.io/client-go/kubernetes" "k8s.io/client-go/rest" "k8s.io/client-go/tools/cache" + ctrlcache "sigs.k8s.io/controller-runtime/pkg/cache" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/event" @@ -640,14 +640,13 @@ func GetInstallationStatus(ctx context.Context, client client.Client) (*operator return &instance.Status, nil } -// GetInstallationSpec returns the current installation, for use by other controllers. It accounts for overlays and -// returns the variant according to status.Variant, which is leveraged by other controllers to know when it is safe to -// launch enterprise-dependent components. -func GetInstallationSpec(ctx context.Context, client client.Client) (operatorv1.ProductVariant, *operatorv1.InstallationSpec, error) { +// GetInstallationSpec returns the current installation, accounting for overlays. Controllers take +// the variant from their ControllerOptions instead, so that the whole process agrees on one value. +func GetInstallationSpec(ctx context.Context, client client.Client) (*operatorv1.InstallationSpec, error) { // Fetch the Installation instance. We only support a single instance named "default". instance := &operatorv1.Installation{} if err := client.Get(ctx, DefaultInstanceKey, instance); err != nil { - return instance.Status.Variant, nil, err + return nil, err } spec := instance.Spec @@ -656,13 +655,13 @@ func GetInstallationSpec(ctx context.Context, client client.Client) (operatorv1. overlay := operatorv1.Installation{} if err := client.Get(ctx, OverlayInstanceKey, &overlay); err != nil { if !errors.IsNotFound(err) { - return instance.Status.Variant, nil, err + return nil, err } } else { spec = OverrideInstallationSpec(spec, overlay.Spec) } - return instance.Status.Variant, &spec, nil + return &spec, nil } // GetAPIServer finds the correct API server instance and returns a message and error in the case of an error. @@ -986,43 +985,36 @@ func GetDNSServiceName(provider operatorv1.Provider) types.NamespacedName { return kubeDNSServiceName } -// MonitorConfigMap starts a goroutine which exits if the given configmap's data is changed. -func MonitorConfigMap(cs kubernetes.Interface, name string, data map[string]string) error { - informer := cache.NewSharedInformer( - cache.NewListWatchFromClient( - cs.CoreV1().RESTClient(), - "configmaps", - common.OperatorNamespace(), - fields.OneTermEqualSelector("metadata.name", name), - ), - &corev1.ConfigMap{}, - 0, // no resync period - ) - _, err := informer.AddEventHandler(cache.ResourceEventHandlerFuncs{ - UpdateFunc: func(_, newObj interface{}) { - if !compareMap(data, newObj.(*corev1.ConfigMap).Data) { - log.Info("detected config change. rebooting") - os.Exit(0) - } - log.Info("ignoring configmap update as data was not modified") - }, - AddFunc: func(obj interface{}) { - if !compareMap(data, obj.(*corev1.ConfigMap).Data) { - log.Info("detected config creation change. rebooting") - os.Exit(0) - } - log.Info("ignoring configmap creation as data was not modified") - }, - }) +// MonitorConfigMap exits the operator if the given ConfigMap's data is changed. +func MonitorConfigMap(ctx context.Context, ca ctrlcache.Cache, name string, data map[string]string) error { + // The cache isn't running yet, so don't wait on a sync that can't happen. + informer, err := ca.GetInformer(ctx, &corev1.ConfigMap{}, ctrlcache.BlockUntilSynced(false)) if err != nil { return err } - go informer.Run(make(chan struct{})) - for !informer.HasSynced() { - time.Sleep(1 * time.Second) + // The shared cache isn't filtered to this ConfigMap, so match on it here. + namespace := common.OperatorNamespace() + check := func(obj interface{}) { + cm, ok := obj.(*corev1.ConfigMap) + if !ok || cm.Name != name || cm.Namespace != namespace { + return + } + + if compareMap(data, cm.Data) { + log.Info("ignoring configmap event as data was not modified") + return + } + + log.Info("detected config change. rebooting") + os.Exit(0) } - return nil + + _, err = informer.AddEventHandler(cache.ResourceEventHandlerFuncs{ + AddFunc: check, + UpdateFunc: func(_, newObj interface{}) { check(newObj) }, + }) + return err } func compareMap(m1, m2 map[string]string) bool { diff --git a/pkg/controller/whisker/controller.go b/pkg/controller/whisker/controller.go index 18f34ab263..ea86b4b15b 100644 --- a/pkg/controller/whisker/controller.go +++ b/pkg/controller/whisker/controller.go @@ -129,6 +129,7 @@ func newReconciler( provider: p, status: statusMgr, clusterDomain: opts.ClusterDomain, + variant: opts.Variant, } c.status.Run(opts.ShutdownContext) return c @@ -143,6 +144,7 @@ type Reconciler struct { provider operatorv1.Provider status status.StatusManager clusterDomain string + variant operatorv1.ProductVariant } // Reconcile reads that state of the cluster for a Whisker object and makes changes based on the @@ -171,7 +173,7 @@ func (r *Reconciler) Reconcile(ctx context.Context, request reconcile.Request) ( // SetMetaData in the TigeraStatus such as observedGenerations. defer r.status.SetMetaData(&whiskerCR.ObjectMeta) - variant, installationSpec, err := utils.GetInstallationSpec(ctx, r.cli) + installationSpec, err := utils.GetInstallationSpec(ctx, r.cli) if err != nil { return reconcile.Result{}, err } else if installationSpec == nil { @@ -266,7 +268,7 @@ func (r *Reconciler) Reconcile(ctx context.Context, request reconcile.Request) ( }) components := []render.Component{certComponent, whisker.Whisker(cfg)} - if err = imageset.ApplyImageSet(ctx, r.cli, variant, components...); err != nil { + if err = imageset.ApplyImageSet(ctx, r.cli, r.variant, components...); err != nil { r.status.SetDegraded(operatorv1.ResourceUpdateError, "Error with images from ImageSet", err, reqLogger) return reconcile.Result{}, err } diff --git a/test/crd_management_test.go b/test/crd_management_test.go index 063e458c8c..8446de812e 100644 --- a/test/crd_management_test.go +++ b/test/crd_management_test.go @@ -151,7 +151,7 @@ var _ = Describe("CRD management tests", func() { }) It("Should create CRD if it doesn't exist", func() { - c, shutdownContext, cancel, mgr = setupManager(ManageCRDsEnable, SingleTenant, EnterpriseCRDsExist) + c, shutdownContext, cancel, mgr = setupManager(ManageCRDsEnable, SingleTenant, operator.Calico) operatorDone = createInstallation(c, mgr, shutdownContext, nil) np := npCRD.DeepCopy() @@ -185,7 +185,7 @@ var _ = Describe("CRD management tests", func() { }, 60*time.Second, 1*time.Second).Should(BeNil()) }) It("Should add tier to networkpolicy CRD", func() { - c, shutdownContext, cancel, mgr = setupManager(ManageCRDsEnable, SingleTenant, EnterpriseCRDsExist) + c, shutdownContext, cancel, mgr = setupManager(ManageCRDsEnable, SingleTenant, operator.CalicoEnterprise) operatorDone = createInstallation(c, mgr, shutdownContext, &operator.InstallationSpec{Variant: operator.CalicoEnterprise}) By("Checking that the networkpolicies CRD is updated with tier") diff --git a/test/gatewayapi_test.go b/test/gatewayapi_test.go index 1a747f5849..e92dca1fde 100644 --- a/test/gatewayapi_test.go +++ b/test/gatewayapi_test.go @@ -62,12 +62,12 @@ var _ = Describe("GatewayAPI tests", func() { Client: c, Scheme: mgr.GetScheme(), }).SetupWithManager(mgr, options.ControllerOptions{ - DetectedProvider: operator.ProviderNone, - EnterpriseCRDExists: EnterpriseCRDsExist, - ManageCRDs: ManageCRDsDisable, - ShutdownContext: shutdownContext, - K8sClientset: clientset, - MultiTenant: SingleTenant, + DetectedProvider: operator.ProviderNone, + Variant: operator.CalicoEnterprise, + ManageCRDs: ManageCRDsDisable, + ShutdownContext: shutdownContext, + K8sClientset: clientset, + MultiTenant: SingleTenant, }) Expect(err).NotTo(HaveOccurred()) diff --git a/test/mainline_test.go b/test/mainline_test.go index f8a230cb7f..15960e46b5 100644 --- a/test/mainline_test.go +++ b/test/mainline_test.go @@ -55,9 +55,6 @@ const ( ManageCRDsEnable = true ManageCRDsDisable = false - EnterpriseCRDsExist = true - EnterpriseCRDsNotExist = false - WhiskerCRDExists = true WhiskerCRDNotExists = false @@ -73,7 +70,7 @@ var _ = Describe("Mainline component function tests", func() { var operatorDone chan struct{} BeforeEach(func() { - c, shutdownContext, cancel, mgr = setupManager(ManageCRDsDisable, SingleTenant, EnterpriseCRDsExist) + c, shutdownContext, cancel, mgr = setupManager(ManageCRDsDisable, SingleTenant, operator.Calico) By("Cleaning up resources before the test") cleanupResources(c) @@ -236,7 +233,7 @@ var _ = Describe("Mainline component function tests", func() { var _ = Describe("Mainline component function tests - multi-tenant", func() { It("should set up all controllers correctly in multi-tenant mode", func() { - _, _, cancel, _ := setupManager(ManageCRDsDisable, MultiTenant, EnterpriseCRDsExist) + _, _, cancel, _ := setupManager(ManageCRDsDisable, MultiTenant, operator.CalicoEnterprise) cancel() }) }) @@ -332,18 +329,18 @@ func setupManagerNoControllers() (client.Client, *kubernetes.Clientset, manager. return mgr.GetClient(), clientset, mgr } -func setupManager(manageCRDs bool, multiTenant bool, enterpriseCRDsExist bool) (client.Client, context.Context, context.CancelFunc, manager.Manager) { +func setupManager(manageCRDs bool, multiTenant bool, variant operator.ProductVariant) (client.Client, context.Context, context.CancelFunc, manager.Manager) { client, clientset, mgr := setupManagerNoControllers() // Setup all Controllers ctx, cancel := context.WithCancel(context.TODO()) err := controller.AddToManager(mgr, options.ControllerOptions{ - DetectedProvider: operator.ProviderNone, - EnterpriseCRDExists: enterpriseCRDsExist, - ManageCRDs: manageCRDs, - ShutdownContext: ctx, - K8sClientset: clientset, - MultiTenant: multiTenant, + DetectedProvider: operator.ProviderNone, + Variant: variant, + ManageCRDs: manageCRDs, + ShutdownContext: ctx, + K8sClientset: clientset, + MultiTenant: multiTenant, }) Expect(err).NotTo(HaveOccurred()) diff --git a/test/pool_test.go b/test/pool_test.go index c7cc2b00fd..4c44f3100f 100644 --- a/test/pool_test.go +++ b/test/pool_test.go @@ -50,7 +50,7 @@ var _ = Describe("IPPool FV tests", func() { var operatorDone chan struct{} BeforeEach(func() { - c, shutdownContext, cancel, mgr = setupManager(ManageCRDsDisable, SingleTenant, EnterpriseCRDsExist) + c, shutdownContext, cancel, mgr = setupManager(ManageCRDsDisable, SingleTenant, operator.Calico) // We need a v3 client as well. var err error diff --git a/test/whisker_test.go b/test/whisker_test.go index 85380c845a..e8cb70a17d 100644 --- a/test/whisker_test.go +++ b/test/whisker_test.go @@ -47,7 +47,7 @@ var _ = Describe("Tests for Whisker installation", func() { var operatorDone chan struct{} BeforeEach(func() { - c, shutdownContext, cancel, mgr = setupManager(ManageCRDsEnable, SingleTenant, EnterpriseCRDsNotExist) + c, shutdownContext, cancel, mgr = setupManager(ManageCRDsEnable, SingleTenant, operator.Calico) By("Cleaning up resources before the test") cleanupResources(c)