diff --git a/cmd/main.go b/cmd/main.go index 84fe5b2e2..16d38f701 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -48,6 +48,8 @@ import ( operatorv1 "sigs.k8s.io/cluster-api-operator/api/v1alpha2" providercontroller "sigs.k8s.io/cluster-api-operator/internal/controller" healtchcheckcontroller "sigs.k8s.io/cluster-api-operator/internal/controller/healthcheck" + "sigs.k8s.io/cluster-api-operator/internal/controller/phases" + "sigs.k8s.io/cluster-api-operator/internal/controller/providers" ) var ( @@ -134,7 +136,9 @@ func main() { pflag.CommandLine.AddGoFlagSet(flag.CommandLine) pflag.Parse() - ctrl.SetLogger(textlogger.NewLogger(textlogger.NewConfig())) + loggerConfig := textlogger.NewConfig([]textlogger.ConfigOption{}...) + ctrl.SetLogger(textlogger.NewLogger(loggerConfig)) + restConfig := ctrl.GetConfigOrDie() tlsOptions, metricsOptions, err := flags.GetManagerOptions(managerOptions) @@ -220,79 +224,65 @@ func setupChecks(mgr ctrl.Manager) { } func setupReconcilers(ctx context.Context, mgr ctrl.Manager, watchConfigSecretChanges bool) { - if err := (&providercontroller.GenericProviderReconciler{ - Provider: &operatorv1.CoreProvider{}, - ProviderList: &operatorv1.CoreProviderList{}, - Client: mgr.GetClient(), - Config: mgr.GetConfig(), - WatchConfigSecretChanges: watchConfigSecretChanges, - }).SetupWithManager(ctx, mgr, concurrency(concurrencyNumber)); err != nil { + if err := providercontroller.NewProviderControllerWrapper( + providers.NewCoreProviderReconciler(mgr), + phases.NewPhase, + watchConfigSecretChanges, + ).SetupWithManager(ctx, mgr, concurrency(concurrencyNumber)); err != nil { setupLog.Error(err, "unable to create controller", "controller", "CoreProvider") os.Exit(1) } - if err := (&providercontroller.GenericProviderReconciler{ - Provider: &operatorv1.InfrastructureProvider{}, - ProviderList: &operatorv1.InfrastructureProviderList{}, - Client: mgr.GetClient(), - Config: mgr.GetConfig(), - WatchConfigSecretChanges: watchConfigSecretChanges, - }).SetupWithManager(ctx, mgr, concurrency(concurrencyNumber)); err != nil { + if err := providercontroller.NewProviderControllerWrapper( + providers.NewInfrastructureProviderReconciler(mgr), + phases.NewPhase, + watchConfigSecretChanges, + ).SetupWithManager(ctx, mgr, concurrency(concurrencyNumber)); err != nil { setupLog.Error(err, "unable to create controller", "controller", "InfrastructureProvider") os.Exit(1) } - if err := (&providercontroller.GenericProviderReconciler{ - Provider: &operatorv1.BootstrapProvider{}, - ProviderList: &operatorv1.BootstrapProviderList{}, - Client: mgr.GetClient(), - Config: mgr.GetConfig(), - WatchConfigSecretChanges: watchConfigSecretChanges, - }).SetupWithManager(ctx, mgr, concurrency(concurrencyNumber)); err != nil { + if err := providercontroller.NewProviderControllerWrapper( + providers.NewBootstrapProviderReconciler(mgr), + phases.NewPhase, + watchConfigSecretChanges, + ).SetupWithManager(ctx, mgr, concurrency(concurrencyNumber)); err != nil { setupLog.Error(err, "unable to create controller", "controller", "BootstrapProvider") os.Exit(1) } - if err := (&providercontroller.GenericProviderReconciler{ - Provider: &operatorv1.ControlPlaneProvider{}, - ProviderList: &operatorv1.ControlPlaneProviderList{}, - Client: mgr.GetClient(), - Config: mgr.GetConfig(), - WatchConfigSecretChanges: watchConfigSecretChanges, - }).SetupWithManager(ctx, mgr, concurrency(concurrencyNumber)); err != nil { + if err := providercontroller.NewProviderControllerWrapper( + providers.NewControlPlaneProviderReconciler(mgr), + phases.NewPhase, + watchConfigSecretChanges, + ).SetupWithManager(ctx, mgr, concurrency(concurrencyNumber)); err != nil { setupLog.Error(err, "unable to create controller", "controller", "ControlPlaneProvider") os.Exit(1) } - if err := (&providercontroller.GenericProviderReconciler{ - Provider: &operatorv1.AddonProvider{}, - ProviderList: &operatorv1.AddonProviderList{}, - Client: mgr.GetClient(), - Config: mgr.GetConfig(), - WatchConfigSecretChanges: watchConfigSecretChanges, - }).SetupWithManager(ctx, mgr, concurrency(concurrencyNumber)); err != nil { + if err := providercontroller.NewProviderControllerWrapper( + providers.NewAddonProviderReconciler(mgr), + phases.NewPhase, + watchConfigSecretChanges, + ).SetupWithManager(ctx, mgr, concurrency(concurrencyNumber)); err != nil { setupLog.Error(err, "unable to create controller", "controller", "AddonProvider") os.Exit(1) } - if err := (&providercontroller.GenericProviderReconciler{ - Provider: &operatorv1.IPAMProvider{}, - ProviderList: &operatorv1.IPAMProviderList{}, - Client: mgr.GetClient(), - Config: mgr.GetConfig(), - WatchConfigSecretChanges: watchConfigSecretChanges, - }).SetupWithManager(ctx, mgr, concurrency(concurrencyNumber)); err != nil { + if err := providercontroller.NewProviderControllerWrapper( + providers.NewIPAMProviderReconciler(mgr), + phases.NewPhase, + watchConfigSecretChanges, + ).SetupWithManager(ctx, mgr, concurrency(concurrencyNumber)); err != nil { setupLog.Error(err, "unable to create controller", "controller", "IPAMProvider") os.Exit(1) } - if err := (&providercontroller.GenericProviderReconciler{ - Provider: &operatorv1.RuntimeExtensionProvider{}, - ProviderList: &operatorv1.RuntimeExtensionProviderList{}, - Client: mgr.GetClient(), - Config: mgr.GetConfig(), - WatchConfigSecretChanges: watchConfigSecretChanges, - }).SetupWithManager(ctx, mgr, concurrency(concurrencyNumber)); err != nil { + if err := providercontroller.NewProviderControllerWrapper( + providers.NewRuntimeExtensionProviderReconciler(mgr), + phases.NewPhase, + watchConfigSecretChanges, + ).SetupWithManager(ctx, mgr, concurrency(concurrencyNumber)); err != nil { setupLog.Error(err, "unable to create controller", "controller", "RuntimeExtensionProvider") os.Exit(1) } diff --git a/cmd/plugin/cmd/delete.go b/cmd/plugin/cmd/delete.go index a9c207432..638817a05 100644 --- a/cmd/plugin/cmd/delete.go +++ b/cmd/plugin/cmd/delete.go @@ -28,9 +28,10 @@ import ( "k8s.io/apimachinery/pkg/api/meta" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/fields" - kerrors "k8s.io/apimachinery/pkg/util/errors" "k8s.io/apimachinery/pkg/util/wait" "k8s.io/klog/v2/textlogger" + + kerrors "k8s.io/apimachinery/pkg/util/errors" ctrl "sigs.k8s.io/controller-runtime" apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" @@ -38,6 +39,7 @@ import ( ctrlclient "sigs.k8s.io/controller-runtime/pkg/client" operatorv1 "sigs.k8s.io/cluster-api-operator/api/v1alpha2" + "sigs.k8s.io/cluster-api-operator/internal/controller/generic" ) type deleteOptions struct { @@ -139,7 +141,8 @@ func init() { func runDelete() error { ctx := context.Background() - ctrl.SetLogger(textlogger.NewLogger(textlogger.NewConfig())) + loggerConfig := textlogger.NewConfig([]textlogger.ConfigOption{}...) + ctrl.SetLogger(textlogger.NewLogger(loggerConfig)) hasProviderNames := deleteOpts.coreProvider || (len(deleteOpts.bootstrapProviders) > 0) || @@ -168,7 +171,7 @@ func runDelete() error { group := &DeleteGroup{ selectors: []fields.Set{}, - providers: []genericProviderList{}, + providers: []generic.ProviderList{}, } errors := append([]error{}, group.delete(&operatorv1.BootstrapProviderList{}, deleteOpts.bootstrapProviders...), @@ -195,10 +198,10 @@ func runDelete() error { type DeleteGroup struct { selectors []fields.Set - providers []genericProviderList + providers []generic.ProviderList } -func (d *DeleteGroup) delete(providerType genericProviderList, names ...string) error { +func (d *DeleteGroup) delete(providerType generic.ProviderList, names ...string) error { for _, provider := range names { selector, err := selectorFromProvider(provider) if err != nil { @@ -214,7 +217,7 @@ func (d *DeleteGroup) delete(providerType genericProviderList, names ...string) func (d *DeleteGroup) deleteAll() { for _, list := range operatorv1.ProviderLists { - providerList, ok := list.(genericProviderList) + providerList, ok := list.(generic.ProviderList) if !ok { log.V(5).Info("Expected to get GenericProviderList") continue @@ -282,9 +285,9 @@ func selectorFromProvider(provider string) (fields.Set, error) { return selector, nil } -func deleteProviders(ctx context.Context, client ctrlclient.Client, providerList genericProviderList, selector ctrlclient.MatchingFieldsSelector) (bool, error) { +func deleteProviders(ctx context.Context, client ctrlclient.Client, providerList generic.ProviderList, selector ctrlclient.MatchingFieldsSelector) (bool, error) { //nolint:forcetypeassert - providerList = providerList.DeepCopyObject().(genericProviderList) + providerList = providerList.DeepCopyObject().(generic.ProviderList) ready := true gvks, _, err := scheme.ObjectKinds(providerList) @@ -305,12 +308,6 @@ func deleteProviders(ctx context.Context, client ctrlclient.Client, providerList for _, provider := range providerList.GetItems() { log.Info(fmt.Sprintf("Deleting %s %s/%s", provider.GetType(), provider.GetName(), provider.GetNamespace())) - provider, ok := provider.(genericProvider) - if !ok { - log.Info(fmt.Sprintf("Expected to get GenericProvider for %s", gvk)) - continue - } - if err := client.DeleteAllOf(ctx, provider, ctrlclient.InNamespace(provider.GetNamespace())); err != nil { return false, fmt.Errorf("unable to issue delete for %s: %w", gvk, err) } diff --git a/cmd/plugin/cmd/delete_test.go b/cmd/plugin/cmd/delete_test.go index 6c2778b7c..bfb211bb7 100644 --- a/cmd/plugin/cmd/delete_test.go +++ b/cmd/plugin/cmd/delete_test.go @@ -24,6 +24,7 @@ import ( "k8s.io/apimachinery/pkg/fields" operatorv1 "sigs.k8s.io/cluster-api-operator/api/v1alpha2" + "sigs.k8s.io/cluster-api-operator/internal/controller/generic" ctrlclient "sigs.k8s.io/controller-runtime/pkg/client" ) @@ -79,13 +80,13 @@ func TestSelectorFromProvider(t *testing.T) { func TestDeleteProviders(t *testing.T) { tests := []struct { name string - list genericProviderList - providers []genericProvider + list generic.ProviderList + providers []generic.Provider selector fields.Set }{{ name: "Delete providers", list: &operatorv1.AddonProviderList{}, - providers: []genericProvider{&operatorv1.AddonProvider{ + providers: []generic.Provider{&operatorv1.AddonProvider{ ObjectMeta: metav1.ObjectMeta{ Name: "addon", Namespace: "default", diff --git a/cmd/plugin/cmd/init.go b/cmd/plugin/cmd/init.go index 1e41895f8..5a9f7beee 100644 --- a/cmd/plugin/cmd/init.go +++ b/cmd/plugin/cmd/init.go @@ -28,6 +28,9 @@ import ( corev1 "k8s.io/api/core/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/util/wait" + operatorv1 "sigs.k8s.io/cluster-api-operator/api/v1alpha2" + "sigs.k8s.io/cluster-api-operator/internal/controller/generic" + "sigs.k8s.io/cluster-api-operator/util" clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1" clusterctlv1 "sigs.k8s.io/cluster-api/cmd/clusterctl/api/v1alpha3" "sigs.k8s.io/cluster-api/cmd/clusterctl/client/cluster" @@ -35,9 +38,6 @@ import ( "sigs.k8s.io/cluster-api/cmd/clusterctl/client/repository" "sigs.k8s.io/cluster-api/cmd/clusterctl/client/yamlprocessor" ctrlclient "sigs.k8s.io/controller-runtime/pkg/client" - - operatorv1 "sigs.k8s.io/cluster-api-operator/api/v1alpha2" - "sigs.k8s.io/cluster-api-operator/util" ) type initOptions struct { @@ -482,7 +482,8 @@ func templateGenericProvider(providerType clusterctlv1.ProviderType, providerInp return nil, fmt.Errorf("provider name can't be empty") } - provider := NewGenericProvider(providerType) + rec := generic.ProviderReconcilers[providerType] + provider := rec.GenericProvider() // Set name and namespace provider.SetName(name) diff --git a/cmd/plugin/cmd/init_test.go b/cmd/plugin/cmd/init_test.go index 01c791003..0ca30978d 100644 --- a/cmd/plugin/cmd/init_test.go +++ b/cmd/plugin/cmd/init_test.go @@ -18,8 +18,9 @@ package cmd import ( "context" - "fmt" + "os" "testing" + "time" . "github.com/onsi/gomega" ctrlclient "sigs.k8s.io/controller-runtime/pkg/client" @@ -27,12 +28,12 @@ import ( appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/types" + clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1" clusterctlv1 "sigs.k8s.io/cluster-api/cmd/clusterctl/api/v1alpha3" + "sigs.k8s.io/cluster-api/util/kubeconfig" operatorv1 "sigs.k8s.io/cluster-api-operator/api/v1alpha2" - "sigs.k8s.io/cluster-api-operator/internal/controller/genericprovider" - "sigs.k8s.io/cluster-api-operator/util" + "sigs.k8s.io/cluster-api-operator/internal/controller/generic" ) func TestCheckCAPIOperatorAvailability(t *testing.T) { @@ -108,7 +109,9 @@ func TestCheckCAPIOperatorAvailability(t *testing.T) { deployment := generateCAPIOperatorDeployment("capi-operator-controller-manager", "default") resources = append(resources, deployment) - g.Expect(env.Create(ctx, deployment)).To(Succeed()) + g.Eventually(func() error { + return env.Create(ctx, deployment) + }, 10*time.Second).Should(Succeed()) g.Eventually(func() (bool, error) { deploymentFromServer := &appsv1.Deployment{} @@ -159,18 +162,18 @@ func TestInitProviders(t *testing.T) { tests := []struct { name string opts *initOptions - wantedProviders []genericprovider.GenericProvider + wantedProviders []generic.Provider wantErr bool }{ { name: "no providers", - wantedProviders: []genericprovider.GenericProvider{}, + wantedProviders: []generic.Provider{}, wantErr: false, opts: &initOptions{}, }, { name: "core provider", - wantedProviders: []genericprovider.GenericProvider{ + wantedProviders: []generic.Provider{ generateGenericProvider(clusterctlv1.CoreProviderType, "cluster-api", "capi-system", "v1.8.0", "", ""), }, wantErr: false, @@ -181,7 +184,7 @@ func TestInitProviders(t *testing.T) { }, { name: "core provider in default target namespace", - wantedProviders: []genericprovider.GenericProvider{ + wantedProviders: []generic.Provider{ generateGenericProvider(clusterctlv1.CoreProviderType, "cluster-api", "capi-operator-system", "v1.8.0", "", ""), }, wantErr: false, @@ -192,7 +195,7 @@ func TestInitProviders(t *testing.T) { }, { name: "core provider without version", - wantedProviders: []genericprovider.GenericProvider{ + wantedProviders: []generic.Provider{ generateGenericProvider(clusterctlv1.CoreProviderType, "cluster-api", "capi-system", "", "", ""), }, wantErr: false, @@ -203,7 +206,7 @@ func TestInitProviders(t *testing.T) { }, { name: "core provider without namespace and version", - wantedProviders: []genericprovider.GenericProvider{ + wantedProviders: []generic.Provider{ generateGenericProvider(clusterctlv1.CoreProviderType, "cluster-api", "capi-operator-system", "", "", ""), }, wantErr: false, @@ -214,7 +217,7 @@ func TestInitProviders(t *testing.T) { }, { name: "core provider with config secret", - wantedProviders: []genericprovider.GenericProvider{ + wantedProviders: []generic.Provider{ generateGenericProvider(clusterctlv1.CoreProviderType, "cluster-api", "capi-operator-system", "", "capi-secrets", ""), }, wantErr: false, @@ -226,7 +229,7 @@ func TestInitProviders(t *testing.T) { }, { name: "core provider with config secret in a custom namespace", - wantedProviders: []genericprovider.GenericProvider{ + wantedProviders: []generic.Provider{ generateGenericProvider(clusterctlv1.CoreProviderType, "cluster-api", "capi-operator-system", "", "capi-secrets", "custom-namespace"), }, wantErr: false, @@ -238,7 +241,7 @@ func TestInitProviders(t *testing.T) { }, { name: "multiple providers of one type", - wantedProviders: []genericprovider.GenericProvider{ + wantedProviders: []generic.Provider{ generateGenericProvider(clusterctlv1.InfrastructureProviderType, "aws", "capa-operator-system", "", "", ""), generateGenericProvider(clusterctlv1.InfrastructureProviderType, "docker", "capd-operator-system", "", "", ""), }, @@ -253,7 +256,7 @@ func TestInitProviders(t *testing.T) { }, { name: "all providers", - wantedProviders: []genericprovider.GenericProvider{ + wantedProviders: []generic.Provider{ generateGenericProvider(clusterctlv1.CoreProviderType, "cluster-api", "capi-system", "v1.8.0", "", ""), generateGenericProvider(clusterctlv1.InfrastructureProviderType, "aws", "capa-operator-system", "", "", ""), generateGenericProvider(clusterctlv1.InfrastructureProviderType, "docker", "capd-operator-system", "", "", ""), @@ -282,7 +285,7 @@ func TestInitProviders(t *testing.T) { }, { name: "invalid input", - wantedProviders: []genericprovider.GenericProvider{}, + wantedProviders: []generic.Provider{}, wantErr: true, opts: &initOptions{ infrastructureProviders: []string{ @@ -293,7 +296,7 @@ func TestInitProviders(t *testing.T) { }, { name: "empty provider", - wantedProviders: []genericprovider.GenericProvider{}, + wantedProviders: []generic.Provider{}, wantErr: true, opts: &initOptions{ infrastructureProviders: []string{ @@ -323,18 +326,11 @@ func TestInitProviders(t *testing.T) { } for _, genericProvider := range tt.wantedProviders { - g.Eventually(func() (bool, error) { - provider, err := getGenericProvider(ctx, env, string(util.ClusterctlProviderType(genericProvider)), genericProvider.GetName(), genericProvider.GetNamespace()) - if err != nil { - return false, err - } - - if provider.GetSpec().Version != genericProvider.GetSpec().Version { - return false, nil - } - - return true, nil - }, waitShort).Should(BeTrue()) + g.Eventually(func(g Gomega) { + copy := genericProvider.DeepCopyObject().(generic.Provider) //nolint + g.Expect(env.Get(ctx, ctrlclient.ObjectKeyFromObject(genericProvider), copy)).To(Succeed()) + g.Expect(copy.GetSpec().Version).To(Equal(genericProvider.GetSpec().Version)) + }, waitShort).Should(Succeed()) } g.Expect(env.CleanupAndWait(ctx, resources...)).To(Succeed()) @@ -370,8 +366,103 @@ func generateCAPIOperatorDeployment(name, namespace string) *appsv1.Deployment { } } -func generateGenericProvider(providerType clusterctlv1.ProviderType, name, namespace, version, configSecretName, configSecretNamespace string) genericprovider.GenericProvider { - genericProvider := NewGenericProvider(providerType) +func TestDeployCAPIOperator(t *testing.T) { + g := NewWithT(t) + + envCluster := &clusterv1.Cluster{} + envCluster.Name = "test-cluster" + + kubeconfigRaw := kubeconfig.FromEnvTestConfig(env.GetConfig(), envCluster) + + tempDir := os.TempDir() + + kubeconfigFile, err := os.CreateTemp(tempDir, "kubeconfig") + g.Expect(err).NotTo(HaveOccurred()) + + defer func() { + if err := os.Remove(kubeconfigFile.Name()); err != nil { + t.Error(err) + } + }() + + _, err = kubeconfigFile.Write(kubeconfigRaw) + g.Expect(err).NotTo(HaveOccurred()) + + tests := []struct { + name string + opts *initOptions + wantedVersion string + wantErr bool + }{ + { + name: "with version", + wantedVersion: "v0.7.0", + wantErr: false, + opts: &initOptions{ + kubeconfig: kubeconfigFile.Name(), + kubeconfigContext: "@test-cluster", + operatorVersion: "v0.7.0", + }, + }, + { + name: "incorrect version", + wantErr: true, + opts: &initOptions{ + kubeconfig: kubeconfigFile.Name(), + kubeconfigContext: "@test-cluster", + operatorVersion: "v1000000", + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + g := NewWithT(t) + + ctx, cancel := context.WithTimeout(context.Background(), waitLong) + + defer cancel() + + resources := []ctrlclient.Object{} + + deployment := generateCAPIOperatorDeployment("capi-operator-controller-manager", "capi-operator-system") + + err := deployCAPIOperator(ctx, tt.opts) + + if tt.wantErr { + g.Expect(err).To(HaveOccurred()) + + return + } else { + g.Expect(err).NotTo(HaveOccurred()) + } + + resources = append(resources, deployment) + + g.Eventually(func() (bool, error) { + err := env.Get(ctx, ctrlclient.ObjectKeyFromObject(deployment), deployment) + if err != nil { + return false, err + } + + return deployment != nil, nil + }, waitShort).Should(BeTrue()) + + g.Expect(deployment.Spec.Template.Spec.Containers).NotTo(BeEmpty()) + + if tt.wantedVersion != "" { + g.Expect(deployment.Spec.Template.Spec.Containers[0].Image).To(HaveSuffix(tt.wantedVersion)) + } else { + g.Expect(deployment.Spec.Template.Spec.Containers[0].Image).To(HaveSuffix(tt.opts.operatorVersion)) + } + + g.Expect(env.CleanupAndWait(ctx, resources...)).To(Succeed()) + }) + } +} + +func generateGenericProvider(providerType clusterctlv1.ProviderType, name, namespace, version, configSecretName, configSecretNamespace string) generic.Provider { + rec := generic.ProviderReconcilers[providerType] + genericProvider := rec.GenericProvider() genericProvider.SetName(name) @@ -387,52 +478,3 @@ func generateGenericProvider(providerType clusterctlv1.ProviderType, name, names return genericProvider } - -func getGenericProvider(ctx context.Context, client ctrlclient.Client, providerKind, providerName, providerNamespace string) (genericprovider.GenericProvider, error) { - switch providerKind { - case "CoreProvider": - provider := &operatorv1.CoreProvider{} - if err := client.Get(ctx, types.NamespacedName{Name: providerName, Namespace: providerNamespace}, provider); err != nil { - return nil, err - } - - return provider, nil - case "BootstrapProvider": - provider := &operatorv1.BootstrapProvider{} - if err := client.Get(ctx, types.NamespacedName{Name: providerName, Namespace: providerNamespace}, provider); err != nil { - return nil, err - } - - return provider, nil - case "ControlPlaneProvider": - provider := &operatorv1.ControlPlaneProvider{} - if err := client.Get(ctx, types.NamespacedName{Name: providerName, Namespace: providerNamespace}, provider); err != nil { - return nil, err - } - - return provider, nil - case "InfrastructureProvider": - provider := &operatorv1.InfrastructureProvider{} - if err := client.Get(ctx, types.NamespacedName{Name: providerName, Namespace: providerNamespace}, provider); err != nil { - return nil, err - } - - return provider, nil - case "AddonProvider": - provider := &operatorv1.AddonProvider{} - if err := client.Get(ctx, types.NamespacedName{Name: providerName, Namespace: providerNamespace}, provider); err != nil { - return nil, err - } - - return provider, nil - case "RuntimeExtensionProvider": - provider := &operatorv1.RuntimeExtensionProvider{} - if err := client.Get(ctx, types.NamespacedName{Name: providerName, Namespace: providerNamespace}, provider); err != nil { - return nil, err - } - - return provider, nil - default: - return nil, fmt.Errorf("failed to cast interface for type: %s", providerKind) - } -} diff --git a/cmd/plugin/cmd/preload.go b/cmd/plugin/cmd/preload.go index 384837b3c..5c7a7249e 100644 --- a/cmd/plugin/cmd/preload.go +++ b/cmd/plugin/cmd/preload.go @@ -27,7 +27,8 @@ import ( kerrors "k8s.io/apimachinery/pkg/util/errors" "oras.land/oras-go/v2/registry/remote/auth" operatorv1 "sigs.k8s.io/cluster-api-operator/api/v1alpha2" - providercontroller "sigs.k8s.io/cluster-api-operator/internal/controller" + "sigs.k8s.io/cluster-api-operator/internal/controller/generic" + "sigs.k8s.io/cluster-api-operator/internal/controller/phases" "sigs.k8s.io/cluster-api-operator/util" clusterctlv1 "sigs.k8s.io/cluster-api/cmd/clusterctl/api/v1alpha3" configclient "sigs.k8s.io/cluster-api/cmd/clusterctl/client/config" @@ -237,13 +238,13 @@ func preloadExisting(ctx context.Context, cl client.Client) ([]*corev1.ConfigMap configMaps := []*corev1.ConfigMap{} for _, list := range operatorv1.ProviderLists { - list, ok := list.(genericProviderList) + list, ok := list.(generic.ProviderList) if !ok { log.V(5).Info("Expected to get GenericProviderList") continue } - list, ok = list.DeepCopyObject().(genericProviderList) + list, ok = list.DeepCopyObject().(generic.ProviderList) if !ok { log.V(5).Info("Expected to get GenericProviderList") continue @@ -257,7 +258,7 @@ func preloadExisting(ctx context.Context, cl client.Client) ([]*corev1.ConfigMap return configMaps, kerrors.NewAggregate(errors) } -func fetchProviders(ctx context.Context, cl client.Client, providerList genericProviderList) ([]*corev1.ConfigMap, error) { +func fetchProviders(ctx context.Context, cl client.Client, providerList generic.ProviderList) ([]*corev1.ConfigMap, error) { configMaps := []*corev1.ConfigMap{} if err := retryWithExponentialBackoff(ctx, newReadBackoff(), func(ctx context.Context) error { @@ -270,7 +271,7 @@ func fetchProviders(ctx context.Context, cl client.Client, providerList genericP for _, provider := range providerList.GetItems() { if provider.GetSpec().FetchConfig != nil && provider.GetSpec().FetchConfig.OCI != "" { - cm, err := providercontroller.OCIConfigMap(ctx, provider, ociAuthentication()) + cm, err := phases.OCIConfigMap(ctx, provider, ociAuthentication()) if err != nil { return configMaps, err } @@ -304,7 +305,7 @@ func templateConfigMap(ctx context.Context, providerType clusterctlv1.ProviderTy provider.SetSpec(spec) if spec.Version != "" { - return providercontroller.OCIConfigMap(ctx, provider, ociAuthentication()) + return phases.OCIConfigMap(ctx, provider, ociAuthentication()) } // User didn't set the version, try to get repository default. @@ -313,7 +314,7 @@ func templateConfigMap(ctx context.Context, providerType clusterctlv1.ProviderTy return nil, fmt.Errorf("cannot create config client: %w", err) } - providerConfig, err := configClient.Providers().Get(provider.GetName(), util.ClusterctlProviderType(provider)) + providerConfig, err := configClient.Providers().Get(provider.GetName(), clusterctlv1.ProviderType(provider.GetType())) if err != nil { if !strings.Contains(err.Error(), "failed to get configuration") { return nil, err @@ -329,7 +330,7 @@ func templateConfigMap(ctx context.Context, providerType clusterctlv1.ProviderTy provider.SetSpec(spec) - return providercontroller.OCIConfigMap(ctx, provider, ociAuthentication()) + return phases.OCIConfigMap(ctx, provider, ociAuthentication()) } func providerConfigMap(ctx context.Context, provider operatorv1.GenericProvider) (*corev1.ConfigMap, error) { @@ -340,7 +341,7 @@ func providerConfigMap(ctx context.Context, provider operatorv1.GenericProvider) // If provided store fetch config url in memory reader. if provider.GetSpec().FetchConfig != nil && provider.GetSpec().FetchConfig.URL != "" { - _, err := mr.AddProvider(provider.GetName(), util.ClusterctlProviderType(provider), provider.GetSpec().FetchConfig.URL) + _, err := mr.AddProvider(provider.GetName(), clusterctlv1.ProviderType(provider.GetType()), provider.GetSpec().FetchConfig.URL) if err != nil { return nil, fmt.Errorf("cannot add custom url provider: %w", err) } @@ -351,7 +352,7 @@ func providerConfigMap(ctx context.Context, provider operatorv1.GenericProvider) return nil, fmt.Errorf("cannot create config client: %w", err) } - providerConfig, err := configClient.Providers().Get(provider.GetName(), util.ClusterctlProviderType(provider)) + providerConfig, err := configClient.Providers().Get(provider.GetName(), clusterctlv1.ProviderType(provider.GetType())) if err != nil { if !strings.Contains(err.Error(), "failed to get configuration") { return nil, err @@ -363,15 +364,15 @@ func providerConfigMap(ctx context.Context, provider operatorv1.GenericProvider) return nil, fmt.Errorf("cannot create repository: %w", err) } - return providercontroller.RepositoryConfigMap(ctx, provider, repo) + return phases.RepositoryConfigMap(ctx, provider, repo) } // ociAuthentication returns user supplied credentials from provider variables. func ociAuthentication() *auth.Credential { - username := os.Getenv(providercontroller.OCIUsernameKey) - password := os.Getenv(providercontroller.OCIPasswordKey) - accessToken := os.Getenv(providercontroller.OCIAccessTokenKey) - refreshToken := os.Getenv(providercontroller.OCIRefreshTokenKey) + username := os.Getenv(phases.OCIUsernameKey) + password := os.Getenv(phases.OCIPasswordKey) + accessToken := os.Getenv(phases.OCIAccessTokenKey) + refreshToken := os.Getenv(phases.OCIRefreshTokenKey) if username != "" || password != "" || accessToken != "" || refreshToken != "" { return &auth.Credential{ diff --git a/cmd/plugin/cmd/preload_test.go b/cmd/plugin/cmd/preload_test.go index e2455a677..cf52198e0 100644 --- a/cmd/plugin/cmd/preload_test.go +++ b/cmd/plugin/cmd/preload_test.go @@ -29,12 +29,12 @@ import ( ctrlclient "sigs.k8s.io/controller-runtime/pkg/client" operatorv1 "sigs.k8s.io/cluster-api-operator/api/v1alpha2" - "sigs.k8s.io/cluster-api-operator/internal/controller/genericprovider" + "sigs.k8s.io/cluster-api-operator/internal/controller/generic" ) type publishProvider struct { configMapName string - provider genericprovider.GenericProvider + provider generic.Provider metadataKey string componentsKey string metadataData []byte @@ -51,7 +51,7 @@ func TestPreloadCommand(t *testing.T) { name string customURL string publishOpts *publishOptions - existingProviders []genericprovider.GenericProvider + existingProviders []generic.Provider expectedConfigMaps int wantErr bool }{ @@ -98,8 +98,8 @@ func TestPreloadCommand(t *testing.T) { }, { name: "custom url infra provider", - existingProviders: []genericprovider.GenericProvider{ - func() genericprovider.GenericProvider { + existingProviders: []generic.Provider{ + func() generic.Provider { p := generateGenericProvider(clusterctlv1.InfrastructureProviderType, "docker", "default", "v1.10.0-beta.0", "", "") spec := p.GetSpec() spec.FetchConfig = &operatorv1.FetchConfiguration{ @@ -114,7 +114,7 @@ func TestPreloadCommand(t *testing.T) { }, { name: "regular core and infra provider", - existingProviders: []genericprovider.GenericProvider{ + existingProviders: []generic.Provider{ generateGenericProvider(clusterctlv1.CoreProviderType, "cluster-api", "default", "v1.10.0-beta.0", "", ""), generateGenericProvider(clusterctlv1.InfrastructureProviderType, "docker", "default", "v1.10.0-beta.0", "", ""), }, @@ -152,8 +152,8 @@ func TestPreloadCommand(t *testing.T) { }, { name: "OCI override with missing image", - existingProviders: []genericprovider.GenericProvider{ - func() genericprovider.GenericProvider { + existingProviders: []generic.Provider{ + func() generic.Provider { p := generateGenericProvider(clusterctlv1.InfrastructureProviderType, "docker", "default", "v1.10.0-beta.0", "", "") spec := p.GetSpec() spec.FetchConfig = &operatorv1.FetchConfiguration{ diff --git a/cmd/plugin/cmd/suite_test.go b/cmd/plugin/cmd/suite_test.go index 35f29c8e7..ba2b4a938 100644 --- a/cmd/plugin/cmd/suite_test.go +++ b/cmd/plugin/cmd/suite_test.go @@ -27,6 +27,9 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" operatorv1 "sigs.k8s.io/cluster-api-operator/api/v1alpha2" + + // We need to initialize all registered providers. + _ "sigs.k8s.io/cluster-api-operator/internal/controller/providers" ) const ( diff --git a/cmd/plugin/cmd/upgrade_plan.go b/cmd/plugin/cmd/upgrade_plan.go index 9b71afbf8..3debbe03d 100644 --- a/cmd/plugin/cmd/upgrade_plan.go +++ b/cmd/plugin/cmd/upgrade_plan.go @@ -448,7 +448,7 @@ func getProviderFetchConfig(ctx context.Context, genericProvider operatorv1.Gene return "", "", err } - providerConfig, err := configClient.Providers().Get(genericProvider.GetName(), util.ClusterctlProviderType(genericProvider)) + providerConfig, err := configClient.Providers().Get(genericProvider.GetName(), clusterctlv1.ProviderType(genericProvider.GetType())) if err != nil { // TODO: implement support of fetching data from config maps // This is a temporary fix for providers installed from config maps diff --git a/cmd/plugin/cmd/upgrade_plan_test.go b/cmd/plugin/cmd/upgrade_plan_test.go index 4abb5895e..9b94d6dfb 100644 --- a/cmd/plugin/cmd/upgrade_plan_test.go +++ b/cmd/plugin/cmd/upgrade_plan_test.go @@ -24,8 +24,7 @@ import ( ctrlclient "sigs.k8s.io/controller-runtime/pkg/client" operatorv1 "sigs.k8s.io/cluster-api-operator/api/v1alpha2" - "sigs.k8s.io/cluster-api-operator/internal/controller/genericprovider" - "sigs.k8s.io/cluster-api-operator/util" + "sigs.k8s.io/cluster-api-operator/internal/controller/generic" ) func TestUpgradePlan(t *testing.T) { @@ -34,7 +33,7 @@ func TestUpgradePlan(t *testing.T) { opts *initOptions customURL string wantedUpgradePlan upgradePlan - wantedProviders []genericprovider.GenericProvider + wantedProviders []generic.Provider wantErr bool }{ { @@ -61,7 +60,7 @@ func TestUpgradePlan(t *testing.T) { }, }, }, - wantedProviders: []genericprovider.GenericProvider{ + wantedProviders: []generic.Provider{ generateGenericProvider(clusterctlv1.CoreProviderType, "cluster-api", "capi-system", "v1.8.0", "", ""), }, wantErr: false, @@ -86,7 +85,7 @@ func TestUpgradePlan(t *testing.T) { }, }, }, - wantedProviders: []genericprovider.GenericProvider{ + wantedProviders: []generic.Provider{ generateGenericProvider(clusterctlv1.InfrastructureProviderType, "docker", "capi-system", "v1.8.0", "", ""), }, wantErr: false, @@ -117,7 +116,9 @@ func TestUpgradePlan(t *testing.T) { for _, genericProvider := range tt.wantedProviders { g.Eventually(func() (bool, error) { - provider, err := getGenericProvider(ctx, env, string(util.ClusterctlProviderType(genericProvider)), genericProvider.GetName(), genericProvider.GetNamespace()) + provider := genericProvider.DeepCopyObject().(generic.Provider) + + err := env.Get(ctx, ctrlclient.ObjectKeyFromObject(genericProvider), provider) if err != nil { return false, err } @@ -133,7 +134,9 @@ func TestUpgradePlan(t *testing.T) { // Init doesn't support custom URLs yet, so we have to update providers here if tt.customURL != "" { for _, genericProvider := range tt.wantedProviders { - provider, err := getGenericProvider(ctx, env, string(util.ClusterctlProviderType(genericProvider)), genericProvider.GetName(), genericProvider.GetNamespace()) + provider := genericProvider.DeepCopyObject().(generic.Provider) + + err := env.Get(ctx, ctrlclient.ObjectKeyFromObject(genericProvider), provider) g.Expect(err).NotTo(HaveOccurred()) spec := provider.GetSpec() @@ -146,7 +149,9 @@ func TestUpgradePlan(t *testing.T) { g.Expect(env.Update(ctx, provider)).NotTo(HaveOccurred()) g.Eventually(func() (bool, error) { - provider, err := getGenericProvider(ctx, env, string(util.ClusterctlProviderType(genericProvider)), genericProvider.GetName(), genericProvider.GetNamespace()) + provider := genericProvider.DeepCopyObject().(generic.Provider) + + err := env.Get(ctx, ctrlclient.ObjectKeyFromObject(genericProvider), provider) if err != nil { return false, err } diff --git a/cmd/plugin/cmd/utils.go b/cmd/plugin/cmd/utils.go index f5023d9c0..27aa30a5e 100644 --- a/cmd/plugin/cmd/utils.go +++ b/cmd/plugin/cmd/utils.go @@ -68,18 +68,6 @@ func init() { utilruntime.Must(clusterctlv1.AddToScheme(scheme)) } -type genericProvider interface { - ctrlclient.Object - operatorv1.GenericProvider -} - -type genericProviderList interface { - ctrlclient.ObjectList - operatorv1.GenericProviderList -} - -var errNotFound = errors.New("404 Not Found") - // CreateKubeClient creates a kubernetes client from provided kubeconfig and kubecontext. func CreateKubeClient(kubeconfigPath, kubeconfigContext string) (ctrlclient.Client, error) { // Use specified kubeconfig path and context @@ -181,27 +169,6 @@ func GetKubeconfigLocation() string { return clientcmd.RecommendedHomeFile } -func NewGenericProvider(providerType clusterctlv1.ProviderType) operatorv1.GenericProvider { - switch providerType { - case clusterctlv1.CoreProviderType: - return &operatorv1.CoreProvider{} - case clusterctlv1.BootstrapProviderType: - return &operatorv1.BootstrapProvider{} - case clusterctlv1.ControlPlaneProviderType: - return &operatorv1.ControlPlaneProvider{} - case clusterctlv1.InfrastructureProviderType: - return &operatorv1.InfrastructureProvider{} - case clusterctlv1.AddonProviderType: - return &operatorv1.AddonProvider{} - case clusterctlv1.RuntimeExtensionProviderType: - return &operatorv1.RuntimeExtensionProvider{} - case clusterctlv1.IPAMProviderType, clusterctlv1.ProviderTypeUnknown: - panic(fmt.Sprintf("unsupported provider type %s", providerType)) - default: - panic(fmt.Sprintf("unknown provider type %s", providerType)) - } -} - // GetLatestRelease returns the latest patch release. func GetLatestRelease(ctx context.Context, repo repository.Repository) (string, error) { versions, err := repo.GetVersions(ctx) @@ -260,7 +227,7 @@ func GetLatestRelease(ctx context.Context, repo repository.Repository) (string, _, err := repo.GetFile(ctx, versionString, repo.ComponentsPath()) if err != nil { - if errors.Is(err, errNotFound) { + if errors.Is(err, ErrNotFound) { // Ignore this version continue } diff --git a/cmd/plugin/main.go b/cmd/plugin/main.go index d041a1e4b..ae3fc56e5 100644 --- a/cmd/plugin/main.go +++ b/cmd/plugin/main.go @@ -20,6 +20,9 @@ import ( _ "k8s.io/client-go/plugin/pkg/client/auth" "sigs.k8s.io/cluster-api-operator/cmd/plugin/cmd" + + // We need to initialize all registered providers. + _ "sigs.k8s.io/cluster-api-operator/internal/controller/providers" ) func main() { diff --git a/config/crd/bases/operator.cluster.x-k8s.io_addonproviders.yaml b/config/crd/bases/operator.cluster.x-k8s.io_addonproviders.yaml index 73af2c9e0..dbf7a7c20 100644 --- a/config/crd/bases/operator.cluster.x-k8s.io_addonproviders.yaml +++ b/config/crd/bases/operator.cluster.x-k8s.io_addonproviders.yaml @@ -1804,13 +1804,13 @@ spec: description: |- MatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key in (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both matchLabelKeys and labelSelector. - Also, matchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MatchLabelKeys and LabelSelector. + Also, MatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -1819,13 +1819,13 @@ spec: description: |- MismatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key notin (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. - Also, mismatchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MismatchLabelKeys and LabelSelector. + Also, MismatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -1986,13 +1986,13 @@ spec: description: |- MatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key in (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both matchLabelKeys and labelSelector. - Also, matchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MatchLabelKeys and LabelSelector. + Also, MatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -2001,13 +2001,13 @@ spec: description: |- MismatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key notin (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. - Also, mismatchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MismatchLabelKeys and LabelSelector. + Also, MismatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -2166,13 +2166,13 @@ spec: description: |- MatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key in (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both matchLabelKeys and labelSelector. - Also, matchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MatchLabelKeys and LabelSelector. + Also, MatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -2181,13 +2181,13 @@ spec: description: |- MismatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key notin (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. - Also, mismatchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MismatchLabelKeys and LabelSelector. + Also, MismatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -2348,13 +2348,13 @@ spec: description: |- MatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key in (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both matchLabelKeys and labelSelector. - Also, matchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MatchLabelKeys and LabelSelector. + Also, MatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -2363,13 +2363,13 @@ spec: description: |- MismatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key notin (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. - Also, mismatchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MismatchLabelKeys and LabelSelector. + Also, MismatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array diff --git a/config/crd/bases/operator.cluster.x-k8s.io_bootstrapproviders.yaml b/config/crd/bases/operator.cluster.x-k8s.io_bootstrapproviders.yaml index 269a241ee..da3e8d9c5 100644 --- a/config/crd/bases/operator.cluster.x-k8s.io_bootstrapproviders.yaml +++ b/config/crd/bases/operator.cluster.x-k8s.io_bootstrapproviders.yaml @@ -352,13 +352,13 @@ spec: description: |- MatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key in (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both matchLabelKeys and labelSelector. - Also, matchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MatchLabelKeys and LabelSelector. + Also, MatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -367,13 +367,13 @@ spec: description: |- MismatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key notin (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. - Also, mismatchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MismatchLabelKeys and LabelSelector. + Also, MismatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -534,13 +534,13 @@ spec: description: |- MatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key in (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both matchLabelKeys and labelSelector. - Also, matchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MatchLabelKeys and LabelSelector. + Also, MatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -549,13 +549,13 @@ spec: description: |- MismatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key notin (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. - Also, mismatchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MismatchLabelKeys and LabelSelector. + Also, MismatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -714,13 +714,13 @@ spec: description: |- MatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key in (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both matchLabelKeys and labelSelector. - Also, matchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MatchLabelKeys and LabelSelector. + Also, MatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -729,13 +729,13 @@ spec: description: |- MismatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key notin (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. - Also, mismatchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MismatchLabelKeys and LabelSelector. + Also, MismatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -896,13 +896,13 @@ spec: description: |- MatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key in (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both matchLabelKeys and labelSelector. - Also, matchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MatchLabelKeys and LabelSelector. + Also, MatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -911,13 +911,13 @@ spec: description: |- MismatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key notin (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. - Also, mismatchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MismatchLabelKeys and LabelSelector. + Also, MismatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -3441,13 +3441,13 @@ spec: description: |- MatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key in (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both matchLabelKeys and labelSelector. - Also, matchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MatchLabelKeys and LabelSelector. + Also, MatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -3456,13 +3456,13 @@ spec: description: |- MismatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key notin (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. - Also, mismatchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MismatchLabelKeys and LabelSelector. + Also, MismatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -3623,13 +3623,13 @@ spec: description: |- MatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key in (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both matchLabelKeys and labelSelector. - Also, matchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MatchLabelKeys and LabelSelector. + Also, MatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -3638,13 +3638,13 @@ spec: description: |- MismatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key notin (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. - Also, mismatchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MismatchLabelKeys and LabelSelector. + Also, MismatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -3803,13 +3803,13 @@ spec: description: |- MatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key in (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both matchLabelKeys and labelSelector. - Also, matchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MatchLabelKeys and LabelSelector. + Also, MatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -3818,13 +3818,13 @@ spec: description: |- MismatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key notin (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. - Also, mismatchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MismatchLabelKeys and LabelSelector. + Also, MismatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -3985,13 +3985,13 @@ spec: description: |- MatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key in (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both matchLabelKeys and labelSelector. - Also, matchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MatchLabelKeys and LabelSelector. + Also, MatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -4000,13 +4000,13 @@ spec: description: |- MismatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key notin (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. - Also, mismatchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MismatchLabelKeys and LabelSelector. + Also, MismatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array diff --git a/config/crd/bases/operator.cluster.x-k8s.io_controlplaneproviders.yaml b/config/crd/bases/operator.cluster.x-k8s.io_controlplaneproviders.yaml index 28765b2d2..1caed9e8b 100644 --- a/config/crd/bases/operator.cluster.x-k8s.io_controlplaneproviders.yaml +++ b/config/crd/bases/operator.cluster.x-k8s.io_controlplaneproviders.yaml @@ -352,13 +352,13 @@ spec: description: |- MatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key in (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both matchLabelKeys and labelSelector. - Also, matchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MatchLabelKeys and LabelSelector. + Also, MatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -367,13 +367,13 @@ spec: description: |- MismatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key notin (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. - Also, mismatchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MismatchLabelKeys and LabelSelector. + Also, MismatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -534,13 +534,13 @@ spec: description: |- MatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key in (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both matchLabelKeys and labelSelector. - Also, matchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MatchLabelKeys and LabelSelector. + Also, MatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -549,13 +549,13 @@ spec: description: |- MismatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key notin (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. - Also, mismatchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MismatchLabelKeys and LabelSelector. + Also, MismatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -714,13 +714,13 @@ spec: description: |- MatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key in (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both matchLabelKeys and labelSelector. - Also, matchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MatchLabelKeys and LabelSelector. + Also, MatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -729,13 +729,13 @@ spec: description: |- MismatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key notin (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. - Also, mismatchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MismatchLabelKeys and LabelSelector. + Also, MismatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -896,13 +896,13 @@ spec: description: |- MatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key in (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both matchLabelKeys and labelSelector. - Also, matchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MatchLabelKeys and LabelSelector. + Also, MatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -911,13 +911,13 @@ spec: description: |- MismatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key notin (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. - Also, mismatchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MismatchLabelKeys and LabelSelector. + Also, MismatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -3443,13 +3443,13 @@ spec: description: |- MatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key in (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both matchLabelKeys and labelSelector. - Also, matchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MatchLabelKeys and LabelSelector. + Also, MatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -3458,13 +3458,13 @@ spec: description: |- MismatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key notin (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. - Also, mismatchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MismatchLabelKeys and LabelSelector. + Also, MismatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -3625,13 +3625,13 @@ spec: description: |- MatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key in (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both matchLabelKeys and labelSelector. - Also, matchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MatchLabelKeys and LabelSelector. + Also, MatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -3640,13 +3640,13 @@ spec: description: |- MismatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key notin (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. - Also, mismatchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MismatchLabelKeys and LabelSelector. + Also, MismatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -3805,13 +3805,13 @@ spec: description: |- MatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key in (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both matchLabelKeys and labelSelector. - Also, matchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MatchLabelKeys and LabelSelector. + Also, MatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -3820,13 +3820,13 @@ spec: description: |- MismatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key notin (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. - Also, mismatchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MismatchLabelKeys and LabelSelector. + Also, MismatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -3987,13 +3987,13 @@ spec: description: |- MatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key in (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both matchLabelKeys and labelSelector. - Also, matchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MatchLabelKeys and LabelSelector. + Also, MatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -4002,13 +4002,13 @@ spec: description: |- MismatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key notin (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. - Also, mismatchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MismatchLabelKeys and LabelSelector. + Also, MismatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array diff --git a/config/crd/bases/operator.cluster.x-k8s.io_coreproviders.yaml b/config/crd/bases/operator.cluster.x-k8s.io_coreproviders.yaml index 7bda5c379..62f8c19ca 100644 --- a/config/crd/bases/operator.cluster.x-k8s.io_coreproviders.yaml +++ b/config/crd/bases/operator.cluster.x-k8s.io_coreproviders.yaml @@ -352,13 +352,13 @@ spec: description: |- MatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key in (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both matchLabelKeys and labelSelector. - Also, matchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MatchLabelKeys and LabelSelector. + Also, MatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -367,13 +367,13 @@ spec: description: |- MismatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key notin (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. - Also, mismatchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MismatchLabelKeys and LabelSelector. + Also, MismatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -534,13 +534,13 @@ spec: description: |- MatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key in (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both matchLabelKeys and labelSelector. - Also, matchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MatchLabelKeys and LabelSelector. + Also, MatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -549,13 +549,13 @@ spec: description: |- MismatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key notin (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. - Also, mismatchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MismatchLabelKeys and LabelSelector. + Also, MismatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -714,13 +714,13 @@ spec: description: |- MatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key in (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both matchLabelKeys and labelSelector. - Also, matchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MatchLabelKeys and LabelSelector. + Also, MatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -729,13 +729,13 @@ spec: description: |- MismatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key notin (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. - Also, mismatchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MismatchLabelKeys and LabelSelector. + Also, MismatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -896,13 +896,13 @@ spec: description: |- MatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key in (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both matchLabelKeys and labelSelector. - Also, matchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MatchLabelKeys and LabelSelector. + Also, MatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -911,13 +911,13 @@ spec: description: |- MismatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key notin (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. - Also, mismatchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MismatchLabelKeys and LabelSelector. + Also, MismatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -3441,13 +3441,13 @@ spec: description: |- MatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key in (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both matchLabelKeys and labelSelector. - Also, matchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MatchLabelKeys and LabelSelector. + Also, MatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -3456,13 +3456,13 @@ spec: description: |- MismatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key notin (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. - Also, mismatchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MismatchLabelKeys and LabelSelector. + Also, MismatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -3623,13 +3623,13 @@ spec: description: |- MatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key in (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both matchLabelKeys and labelSelector. - Also, matchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MatchLabelKeys and LabelSelector. + Also, MatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -3638,13 +3638,13 @@ spec: description: |- MismatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key notin (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. - Also, mismatchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MismatchLabelKeys and LabelSelector. + Also, MismatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -3803,13 +3803,13 @@ spec: description: |- MatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key in (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both matchLabelKeys and labelSelector. - Also, matchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MatchLabelKeys and LabelSelector. + Also, MatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -3818,13 +3818,13 @@ spec: description: |- MismatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key notin (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. - Also, mismatchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MismatchLabelKeys and LabelSelector. + Also, MismatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -3985,13 +3985,13 @@ spec: description: |- MatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key in (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both matchLabelKeys and labelSelector. - Also, matchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MatchLabelKeys and LabelSelector. + Also, MatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -4000,13 +4000,13 @@ spec: description: |- MismatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key notin (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. - Also, mismatchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MismatchLabelKeys and LabelSelector. + Also, MismatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array diff --git a/config/crd/bases/operator.cluster.x-k8s.io_infrastructureproviders.yaml b/config/crd/bases/operator.cluster.x-k8s.io_infrastructureproviders.yaml index fe0cfb325..26b8a14c0 100644 --- a/config/crd/bases/operator.cluster.x-k8s.io_infrastructureproviders.yaml +++ b/config/crd/bases/operator.cluster.x-k8s.io_infrastructureproviders.yaml @@ -352,13 +352,13 @@ spec: description: |- MatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key in (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both matchLabelKeys and labelSelector. - Also, matchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MatchLabelKeys and LabelSelector. + Also, MatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -367,13 +367,13 @@ spec: description: |- MismatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key notin (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. - Also, mismatchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MismatchLabelKeys and LabelSelector. + Also, MismatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -534,13 +534,13 @@ spec: description: |- MatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key in (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both matchLabelKeys and labelSelector. - Also, matchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MatchLabelKeys and LabelSelector. + Also, MatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -549,13 +549,13 @@ spec: description: |- MismatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key notin (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. - Also, mismatchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MismatchLabelKeys and LabelSelector. + Also, MismatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -714,13 +714,13 @@ spec: description: |- MatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key in (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both matchLabelKeys and labelSelector. - Also, matchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MatchLabelKeys and LabelSelector. + Also, MatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -729,13 +729,13 @@ spec: description: |- MismatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key notin (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. - Also, mismatchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MismatchLabelKeys and LabelSelector. + Also, MismatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -896,13 +896,13 @@ spec: description: |- MatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key in (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both matchLabelKeys and labelSelector. - Also, matchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MatchLabelKeys and LabelSelector. + Also, MatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -911,13 +911,13 @@ spec: description: |- MismatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key notin (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. - Also, mismatchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MismatchLabelKeys and LabelSelector. + Also, MismatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -3443,13 +3443,13 @@ spec: description: |- MatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key in (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both matchLabelKeys and labelSelector. - Also, matchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MatchLabelKeys and LabelSelector. + Also, MatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -3458,13 +3458,13 @@ spec: description: |- MismatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key notin (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. - Also, mismatchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MismatchLabelKeys and LabelSelector. + Also, MismatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -3625,13 +3625,13 @@ spec: description: |- MatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key in (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both matchLabelKeys and labelSelector. - Also, matchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MatchLabelKeys and LabelSelector. + Also, MatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -3640,13 +3640,13 @@ spec: description: |- MismatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key notin (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. - Also, mismatchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MismatchLabelKeys and LabelSelector. + Also, MismatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -3805,13 +3805,13 @@ spec: description: |- MatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key in (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both matchLabelKeys and labelSelector. - Also, matchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MatchLabelKeys and LabelSelector. + Also, MatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -3820,13 +3820,13 @@ spec: description: |- MismatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key notin (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. - Also, mismatchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MismatchLabelKeys and LabelSelector. + Also, MismatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -3987,13 +3987,13 @@ spec: description: |- MatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key in (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both matchLabelKeys and labelSelector. - Also, matchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MatchLabelKeys and LabelSelector. + Also, MatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -4002,13 +4002,13 @@ spec: description: |- MismatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key notin (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. - Also, mismatchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MismatchLabelKeys and LabelSelector. + Also, MismatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array diff --git a/config/crd/bases/operator.cluster.x-k8s.io_ipamproviders.yaml b/config/crd/bases/operator.cluster.x-k8s.io_ipamproviders.yaml index f76475b7c..78944e220 100644 --- a/config/crd/bases/operator.cluster.x-k8s.io_ipamproviders.yaml +++ b/config/crd/bases/operator.cluster.x-k8s.io_ipamproviders.yaml @@ -1804,13 +1804,13 @@ spec: description: |- MatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key in (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both matchLabelKeys and labelSelector. - Also, matchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MatchLabelKeys and LabelSelector. + Also, MatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -1819,13 +1819,13 @@ spec: description: |- MismatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key notin (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. - Also, mismatchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MismatchLabelKeys and LabelSelector. + Also, MismatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -1986,13 +1986,13 @@ spec: description: |- MatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key in (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both matchLabelKeys and labelSelector. - Also, matchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MatchLabelKeys and LabelSelector. + Also, MatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -2001,13 +2001,13 @@ spec: description: |- MismatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key notin (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. - Also, mismatchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MismatchLabelKeys and LabelSelector. + Also, MismatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -2166,13 +2166,13 @@ spec: description: |- MatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key in (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both matchLabelKeys and labelSelector. - Also, matchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MatchLabelKeys and LabelSelector. + Also, MatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -2181,13 +2181,13 @@ spec: description: |- MismatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key notin (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. - Also, mismatchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MismatchLabelKeys and LabelSelector. + Also, MismatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -2348,13 +2348,13 @@ spec: description: |- MatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key in (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both matchLabelKeys and labelSelector. - Also, matchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MatchLabelKeys and LabelSelector. + Also, MatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -2363,13 +2363,13 @@ spec: description: |- MismatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key notin (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. - Also, mismatchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MismatchLabelKeys and LabelSelector. + Also, MismatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array diff --git a/controller/alias.go b/controller/alias.go index 89a0f0bab..b10701ed0 100644 --- a/controller/alias.go +++ b/controller/alias.go @@ -16,6 +16,9 @@ limitations under the License. package controller -import providercontroller "sigs.k8s.io/cluster-api-operator/internal/controller" +import ( + providercontroller "sigs.k8s.io/cluster-api-operator/internal/controller" + "sigs.k8s.io/cluster-api-operator/internal/controller/generic" +) -type GenericProviderReconciler = providercontroller.GenericProviderReconciler +type GenericProviderReconciler = providercontroller.ProviderControllerWrapper[generic.Provider, generic.ProviderReconciler[generic.Provider]] diff --git a/go.mod b/go.mod index 52d5d906e..4e60447be 100644 --- a/go.mod +++ b/go.mod @@ -13,6 +13,7 @@ require ( github.com/google/go-cmp v0.7.0 github.com/google/go-github/v52 v52.0.0 github.com/google/gofuzz v1.2.0 + github.com/onsi/ginkgo/v2 v2.23.3 github.com/onsi/gomega v1.37.0 github.com/opencontainers/image-spec v1.1.1 github.com/spf13/cobra v1.9.1 @@ -57,6 +58,7 @@ require ( github.com/go-openapi/jsonpointer v0.21.0 // indirect github.com/go-openapi/jsonreference v0.20.2 // indirect github.com/go-openapi/swag v0.23.0 // indirect + github.com/go-task/slim-sprig/v3 v3.0.0 // indirect github.com/go-viper/mapstructure/v2 v2.2.1 // indirect github.com/gobuffalo/flect v1.0.3 // indirect github.com/gogo/protobuf v1.3.2 // indirect @@ -66,6 +68,7 @@ require ( github.com/google/gnostic-models v0.6.9-0.20230804172637-c7be7c783f49 // indirect github.com/google/go-github/v53 v53.2.0 // indirect github.com/google/go-querystring v1.1.0 // indirect + github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad // indirect github.com/google/uuid v1.6.0 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 // indirect github.com/huandu/xstrings v1.5.0 // indirect @@ -112,6 +115,7 @@ require ( golang.org/x/term v0.30.0 // indirect golang.org/x/text v0.23.0 // indirect golang.org/x/time v0.8.0 // indirect + golang.org/x/tools v0.30.0 // indirect gomodules.xyz/jsonpatch/v2 v2.5.0 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20241209162323-e6fa225c2576 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20241223144023-3abc09e42ca8 // indirect diff --git a/internal/controller/consts.go b/internal/controller/consts.go deleted file mode 100644 index ac0c4598d..000000000 --- a/internal/controller/consts.go +++ /dev/null @@ -1,22 +0,0 @@ -/* -Copyright 2021 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package controller - -const ( - // configPath is the path to the clusterctl config file. - configPath = "/config/clusterctl.yaml" -) diff --git a/internal/controller/coreprovider_to_providers.go b/internal/controller/coreprovider_to_providers.go index 1adffda12..920bcc6fb 100644 --- a/internal/controller/coreprovider_to_providers.go +++ b/internal/controller/coreprovider_to_providers.go @@ -21,7 +21,7 @@ import ( "fmt" operatorv1 "sigs.k8s.io/cluster-api-operator/api/v1alpha2" - "sigs.k8s.io/cluster-api-operator/internal/controller/genericprovider" + "sigs.k8s.io/cluster-api-operator/internal/controller/generic" clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1" "sigs.k8s.io/cluster-api/util/conditions" ctrl "sigs.k8s.io/controller-runtime" @@ -33,7 +33,7 @@ import ( // newCoreProviderToProviderFuncMapForProviderList maps a ready CoreProvider object to all other provider objects. // It lists all the providers and if its PreflightCheckCondition is not True, this object will be added to the resulting request. // This means that notifications will only be sent to those objects that have not pass PreflightCheck. -func newCoreProviderToProviderFuncMapForProviderList(k8sClient client.Client, providerList genericprovider.GenericProviderList) handler.MapFunc { +func newCoreProviderToProviderFuncMapForProviderList(k8sClient client.Client, providerList generic.ProviderList) handler.MapFunc { providerListType := fmt.Sprintf("%T", providerList) return func(ctx context.Context, obj client.Object) []reconcile.Request { diff --git a/internal/controller/generic/interfaces.go b/internal/controller/generic/interfaces.go new file mode 100644 index 000000000..8cefb947e --- /dev/null +++ b/internal/controller/generic/interfaces.go @@ -0,0 +1,120 @@ +/* +Copyright 2021 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package generic + +import ( + "context" + + "k8s.io/client-go/rest" + operatorv1 "sigs.k8s.io/cluster-api-operator/api/v1alpha2" + clusterctlv1 "sigs.k8s.io/cluster-api/cmd/clusterctl/api/v1alpha3" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/reconcile" +) + +// Provider is an GenericProvider. +type Provider = operatorv1.GenericProvider + +// ProviderList is a GenericProviderList satisfying ObjectList interface. +type ProviderList interface { + client.ObjectList + operatorv1.GenericProviderList +} + +// Getter is a base interface for provider reconcilers. +type Getter interface { + ClusterctlProviderType() clusterctlv1.ProviderType + GenericProvider() Provider + GetProviderList() ProviderList +} + +// Connector is a base interface for building phase reconcile and accessing cluster via client. +type Connector interface { + GetClient() client.Client + GetConfig() *rest.Config +} + +// GroupBuilder implementation allows to build a generic Group acting on specific provider type, +// preserving the type info. +type GroupBuilder[P Provider] interface { + Connector + Getter + ClusterctlProvider(provider P) *clusterctlv1.Provider +} + +// Group is a generic interface with access to typed Provider object. +// Each reconciler phase expected to work with a Provider Group. +type Group[P Provider] interface { + Connector + Getter + GetProvider() P + GetClusterctlProvider() *clusterctlv1.Provider +} + +// NewGroup is a function that creates a new group. +type NewGroup[P Provider] func(P, ProviderList, GroupBuilder[P]) Group[P] + +// ProviderReconciler is a reconciler methods interface related to specified provider +// The reconcile is split into 4 stages, each executed after another, and accepting any Provider object. +// Each stage will return a list of phases for controller execution, typed for defined Provider: +// +// - PreflightChecks(ctx context.Context, provider P) []ReconcileFn[P, Group[P]] +// - ReconcileNormal(ctx context.Context, provider P) []ReconcileFn[P, Group[P]] +// - ReportStatus(ctx context.Context, provider P) []ReconcileFn[P, Group[P]] +// - ReconcileDelete(ctx context.Context, provider P) []ReconcileFn[P, Group[P]]. +type ProviderReconciler[P Provider] interface { + GroupBuilder[P] + Init() + PreflightChecks(ctx context.Context, provider P) []ReconcileFn[P, Group[P]] + ReconcileNormal(ctx context.Context, provider P) []ReconcileFn[P, Group[P]] + ReportStatus(ctx context.Context, provider P) []ReconcileFn[P, Group[P]] + ReconcileDelete(ctx context.Context, provider P) []ReconcileFn[P, Group[P]] +} + +// ReconcileFn is a function that represent a phase of the reconciliation. +type ReconcileFn[P Provider, G Group[P]] func(context.Context, G) (reconcile.Result, error) + +// NewReconcileFnList created a list of reconcile phases, with a typed group working with a defined provider only +// Example: +// +// generic.NewReconcileFnList(r.corePreflightChecks) // Will only compile when passed to core provider reconciler working on CoreProvider +// +// func (r *CoreProviderReconciler) corePreflightChecks(ctx context.Context, phase generic.Group[*operatorv1.CoreProvider]) (ctrl.Result, error) { +// var p *operatorv1.CoreProvider +// // getting actual core provider instead of interface for resource specific operations or validation +// p = phase.GetProvider() // this works +// } +func NewReconcileFnList[P Provider, G Group[P]](phaseFunc ...ReconcileFn[P, G]) []ReconcileFn[P, G] { + return phaseFunc +} + +// ProviderReconcilers is a storage of registered provider reconcilers on controller startup. +// It is used to access reconciler specific methods, allowing to map Clusterctl provider type +// on an actual Provider object, which represents it. +var ProviderReconcilers = map[clusterctlv1.ProviderType]Getter{} + +// GetBuilder provides an initialized reconciler to fetch component in the domail of provider, like +// provider list type, clusterctl provider, etc. without need to maintain an evergrowing switch statement. +func GetBuilder[P Provider](_ P) GroupBuilder[P] { + for _, reconciler := range ProviderReconcilers { + if r, ok := reconciler.(ProviderReconciler[P]); ok { + return r + } + } + + return nil +} diff --git a/internal/controller/genericprovider/genericprovider_interfaces.go b/internal/controller/genericprovider/genericprovider_interfaces.go deleted file mode 100644 index 83228fb1f..000000000 --- a/internal/controller/genericprovider/genericprovider_interfaces.go +++ /dev/null @@ -1,32 +0,0 @@ -/* -Copyright 2021 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package genericprovider - -import ( - operatorv1 "sigs.k8s.io/cluster-api-operator/api/v1alpha2" - "sigs.k8s.io/controller-runtime/pkg/client" -) - -type GenericProvider interface { - client.Object - operatorv1.GenericProvider -} - -type GenericProviderList interface { - client.ObjectList - operatorv1.GenericProviderList -} diff --git a/internal/controller/healthcheck/healthcheck_controller.go b/internal/controller/healthcheck/healthcheck_controller.go index 8ece61ff4..66dd0b518 100644 --- a/internal/controller/healthcheck/healthcheck_controller.go +++ b/internal/controller/healthcheck/healthcheck_controller.go @@ -63,46 +63,31 @@ type ProviderHealthCheckReconciler struct { Client client.Client } -type GenericProviderHealthCheckReconciler struct { +type GenericProviderHealthCheckReconciler[P operatorv1.GenericProvider] struct { Client client.Client - Provider operatorv1.GenericProvider + Provider P providerGVK schema.GroupVersionKind } +func NewGenericHealthCheckReconciler[P operatorv1.GenericProvider](mgr ctrl.Manager, provider P) *GenericProviderHealthCheckReconciler[P] { + return &GenericProviderHealthCheckReconciler[P]{ + Client: mgr.GetClient(), + Provider: provider, + } +} + func (r *ProviderHealthCheckReconciler) SetupWithManager(mgr ctrl.Manager, options controller.Options) error { return kerrors.NewAggregate([]error{ - (&GenericProviderHealthCheckReconciler{ - Client: mgr.GetClient(), - Provider: &operatorv1.CoreProvider{}, - }).SetupWithManager(mgr, options), - (&GenericProviderHealthCheckReconciler{ - Client: mgr.GetClient(), - Provider: &operatorv1.InfrastructureProvider{}, - }).SetupWithManager(mgr, options), - (&GenericProviderHealthCheckReconciler{ - Client: mgr.GetClient(), - Provider: &operatorv1.BootstrapProvider{}, - }).SetupWithManager(mgr, options), - (&GenericProviderHealthCheckReconciler{ - Client: mgr.GetClient(), - Provider: &operatorv1.ControlPlaneProvider{}, - }).SetupWithManager(mgr, options), - (&GenericProviderHealthCheckReconciler{ - Client: mgr.GetClient(), - Provider: &operatorv1.AddonProvider{}, - }).SetupWithManager(mgr, options), - (&GenericProviderHealthCheckReconciler{ - Client: mgr.GetClient(), - Provider: &operatorv1.RuntimeExtensionProvider{}, - }).SetupWithManager(mgr, options), - (&GenericProviderHealthCheckReconciler{ - Client: mgr.GetClient(), - Provider: &operatorv1.IPAMProvider{}, - }).SetupWithManager(mgr, options), + NewGenericHealthCheckReconciler(mgr, &operatorv1.CoreProvider{}).SetupWithManager(mgr, options), + NewGenericHealthCheckReconciler(mgr, &operatorv1.InfrastructureProvider{}).SetupWithManager(mgr, options), + NewGenericHealthCheckReconciler(mgr, &operatorv1.BootstrapProvider{}).SetupWithManager(mgr, options), + NewGenericHealthCheckReconciler(mgr, &operatorv1.ControlPlaneProvider{}).SetupWithManager(mgr, options), + NewGenericHealthCheckReconciler(mgr, &operatorv1.AddonProvider{}).SetupWithManager(mgr, options), + NewGenericHealthCheckReconciler(mgr, &operatorv1.IPAMProvider{}).SetupWithManager(mgr, options), }) } -func (r *GenericProviderHealthCheckReconciler) SetupWithManager(mgr ctrl.Manager, options controller.Options) error { +func (r *GenericProviderHealthCheckReconciler[P]) SetupWithManager(mgr ctrl.Manager, options controller.Options) error { kinds, _, err := r.Client.Scheme().ObjectKinds(r.Provider) if err != nil { return err @@ -119,23 +104,16 @@ func (r *GenericProviderHealthCheckReconciler) SetupWithManager(mgr ctrl.Manager For(&appsv1.Deployment{}, builder.WithPredicates(r.providerDeploymentPredicates())). WithEventFilter(deploymentPredicate). WithOptions(options). - Complete(r) + Complete(reconcile.AsReconciler(mgr.GetClient(), r)) } -func (r *GenericProviderHealthCheckReconciler) Reconcile(ctx context.Context, req reconcile.Request) (_ reconcile.Result, reterr error) { +func (r *GenericProviderHealthCheckReconciler[P]) Reconcile(ctx context.Context, deployment *appsv1.Deployment) (_ reconcile.Result, reterr error) { log := ctrl.LoggerFrom(ctx) log.Info("Checking provider health") result := ctrl.Result{} - deployment := &appsv1.Deployment{} - - if err := r.Client.Get(ctx, req.NamespacedName, deployment); err != nil { - // Error reading the object - requeue the request. - return result, err - } - // There should be one owner pointing to the Provider resource. if err := r.Client.Get(ctx, r.getProviderKey(deployment), r.Provider); err != nil { // Error reading the object - requeue the request. @@ -187,7 +165,7 @@ func (r *GenericProviderHealthCheckReconciler) Reconcile(ctx context.Context, re return result, patchHelper.Patch(ctx, typedProvider, options) } -func (r *GenericProviderHealthCheckReconciler) getProviderName(deploy client.Object) string { +func (r *GenericProviderHealthCheckReconciler[P]) getProviderName(deploy client.Object) string { for _, owner := range deploy.GetOwnerReferences() { if owner.Kind == r.providerGVK.Kind { return owner.Name @@ -197,7 +175,7 @@ func (r *GenericProviderHealthCheckReconciler) getProviderName(deploy client.Obj return "" } -func (r *GenericProviderHealthCheckReconciler) getProviderKey(deploy client.Object) types.NamespacedName { +func (r *GenericProviderHealthCheckReconciler[P]) getProviderKey(deploy client.Object) types.NamespacedName { return types.NamespacedName{ Namespace: deploy.GetNamespace(), Name: r.getProviderName(deploy), @@ -216,7 +194,7 @@ func getDeploymentCondition(status appsv1.DeploymentStatus, condType appsv1.Depl return nil } -func (r *GenericProviderHealthCheckReconciler) providerDeploymentPredicates() predicate.Funcs { +func (r *GenericProviderHealthCheckReconciler[P]) providerDeploymentPredicates() predicate.Funcs { isProviderDeployment := func(obj runtime.Object) bool { deployment, ok := obj.(*appsv1.Deployment) if !ok { diff --git a/internal/controller/healthcheck/suite_test.go b/internal/controller/healthcheck/suite_test.go index 5a9cad06f..fee2788d1 100644 --- a/internal/controller/healthcheck/suite_test.go +++ b/internal/controller/healthcheck/suite_test.go @@ -25,8 +25,9 @@ import ( ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/controller" - operatorv1 "sigs.k8s.io/cluster-api-operator/api/v1alpha2" providercontroller "sigs.k8s.io/cluster-api-operator/internal/controller" + "sigs.k8s.io/cluster-api-operator/internal/controller/phases" + "sigs.k8s.io/cluster-api-operator/internal/controller/providers" "sigs.k8s.io/cluster-api-operator/internal/envtest" ) @@ -44,11 +45,11 @@ func TestMain(m *testing.M) { env = envtest.New() - if err := (&providercontroller.GenericProviderReconciler{ - Provider: &operatorv1.CoreProvider{}, - ProviderList: &operatorv1.CoreProviderList{}, - Client: env, - }).SetupWithManager(ctx, env.Manager, controller.Options{MaxConcurrentReconciles: 1}); err != nil { + if err := providercontroller.NewProviderControllerWrapper( + providers.NewCoreProviderReconciler(env), + phases.NewPhase, + false, + ).SetupWithManager(ctx, env.Manager, controller.Options{MaxConcurrentReconciles: 1}); err != nil { panic(fmt.Sprintf("Failed to start CoreProviderReconciler: %v", err)) } diff --git a/internal/controller/component_customizer.go b/internal/controller/phases/component_customizer.go similarity index 99% rename from internal/controller/component_customizer.go rename to internal/controller/phases/component_customizer.go index 255b374e0..9f1c2c795 100644 --- a/internal/controller/component_customizer.go +++ b/internal/controller/phases/component_customizer.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package controller +package phases import ( "fmt" diff --git a/internal/controller/component_customizer_test.go b/internal/controller/phases/component_customizer_test.go similarity index 99% rename from internal/controller/component_customizer_test.go rename to internal/controller/phases/component_customizer_test.go index 17583f65f..9714c5f8b 100644 --- a/internal/controller/component_customizer_test.go +++ b/internal/controller/phases/component_customizer_test.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package controller +package phases import ( "reflect" diff --git a/internal/controller/component_patches.go b/internal/controller/phases/component_patches.go similarity index 98% rename from internal/controller/component_patches.go rename to internal/controller/phases/component_patches.go index f1b4648d0..bccec2ebd 100644 --- a/internal/controller/component_patches.go +++ b/internal/controller/phases/component_patches.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package controller +package phases import ( "context" diff --git a/internal/controller/phases/consts.go b/internal/controller/phases/consts.go new file mode 100644 index 000000000..93b21c71a --- /dev/null +++ b/internal/controller/phases/consts.go @@ -0,0 +1,39 @@ +/* +Copyright 2024 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package phases + +const ( + // configPath is the path to the clusterctl config file. + configPath = "/config/clusterctl.yaml" + + configMapVersionLabel = "provider.cluster.x-k8s.io/version" + configMapTypeLabel = "provider.cluster.x-k8s.io/type" + configMapNameLabel = "provider.cluster.x-k8s.io/name" + operatorManagedLabel = "managed-by.operator.cluster.x-k8s.io" + + compressedAnnotation = "provider.cluster.x-k8s.io/compressed" + + ociSource = "oci" + configMapSourceLabel = "provider.cluster.x-k8s.io/source" + configMapSourceAnnotation = "provider.cluster.x-k8s.io/source" + + metadataConfigMapKey = "metadata" + componentsConfigMapKey = "components" + additionalManifestsConfigMapKey = "manifests" + + maxConfigMapSize = 1 * 1024 * 1024 +) diff --git a/internal/controller/image_overrides.go b/internal/controller/phases/image_overrides.go similarity index 99% rename from internal/controller/image_overrides.go rename to internal/controller/phases/image_overrides.go index aebf9b8ff..25a985bdd 100644 --- a/internal/controller/image_overrides.go +++ b/internal/controller/phases/image_overrides.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package controller +package phases import ( "fmt" diff --git a/internal/controller/image_overrides_test.go b/internal/controller/phases/image_overrides_test.go similarity index 99% rename from internal/controller/image_overrides_test.go rename to internal/controller/phases/image_overrides_test.go index 2c92c6aed..016aafdb1 100644 --- a/internal/controller/image_overrides_test.go +++ b/internal/controller/phases/image_overrides_test.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package controller +package phases import ( "fmt" diff --git a/internal/controller/manifests_downloader.go b/internal/controller/phases/manifests_downloader.go similarity index 86% rename from internal/controller/manifests_downloader.go rename to internal/controller/phases/manifests_downloader.go index df612dbb1..0408da9cd 100644 --- a/internal/controller/manifests_downloader.go +++ b/internal/controller/phases/manifests_downloader.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package controller +package phases import ( "bytes" @@ -37,21 +37,12 @@ import ( "sigs.k8s.io/cluster-api-operator/util" ) -const ( - configMapSourceLabel = "provider.cluster.x-k8s.io/source" - configMapSourceAnnotation = "provider.cluster.x-k8s.io/source" - operatorManagedLabel = "managed-by.operator.cluster.x-k8s.io" - - maxConfigMapSize = 1 * 1024 * 1024 - ociSource = "oci" -) - -// downloadManifests downloads CAPI manifests from a url. -func (p *phaseReconciler) downloadManifests(ctx context.Context) (reconcile.Result, error) { +// DownloadManifests downloads CAPI manifests from a url. +func (p *PhaseReconciler[P, G]) DownloadManifests(ctx context.Context, phase G) (reconcile.Result, error) { log := ctrl.LoggerFrom(ctx) // Return immediately if a custom config map is used instead of a url. - if p.provider.GetSpec().FetchConfig != nil && p.provider.GetSpec().FetchConfig.Selector != nil { + if phase.GetProvider().GetSpec().FetchConfig != nil && phase.GetProvider().GetSpec().FetchConfig.Selector != nil { log.V(5).Info("Custom config map is used, skip downloading provider manifests") return reconcile.Result{}, nil @@ -59,10 +50,10 @@ func (p *phaseReconciler) downloadManifests(ctx context.Context) (reconcile.Resu // Check if manifests are already downloaded and stored in a configmap labelSelector := metav1.LabelSelector{ - MatchLabels: p.prepareConfigMapLabels(), + MatchLabels: ProviderLabels(phase.GetProvider()), } - exists, err := p.checkConfigMapExists(ctx, labelSelector, p.provider.GetNamespace()) + exists, err := checkConfigMapExists(ctx, phase.GetClient(), labelSelector, phase.GetProvider().GetNamespace()) if err != nil { return reconcile.Result{}, wrapPhaseError(err, "failed to check that config map with manifests exists", operatorv1.ProviderInstalledCondition) } @@ -75,8 +66,8 @@ func (p *phaseReconciler) downloadManifests(ctx context.Context) (reconcile.Resu log.Info("Downloading provider manifests") - if p.providerConfig.URL() != fakeURL { - p.repo, err = util.RepositoryFactory(ctx, p.providerConfig, p.configClient.Variables()) + if p.ProviderConfig.URL() != fakeURL { + p.Repo, err = util.RepositoryFactory(ctx, p.ProviderConfig, p.ConfigClient.Variables()) if err != nil { err = fmt.Errorf("failed to create repo from provider url for provider %q: %w", p.provider.GetName(), err) @@ -84,26 +75,26 @@ func (p *phaseReconciler) downloadManifests(ctx context.Context) (reconcile.Resu } } - spec := p.provider.GetSpec() + spec := phase.GetProvider().GetSpec() - if spec.Version == "" && p.repo != nil { + if spec.Version == "" && p.Repo != nil { // User didn't set the version, try to get repository default. - spec.Version = p.repo.DefaultVersion() + spec.Version = p.Repo.DefaultVersion() // Add version to the provider spec. - p.provider.SetSpec(spec) + phase.GetProvider().SetSpec(spec) } var configMap *corev1.ConfigMap // Fetch the provider metadata and components yaml files from the provided repository GitHub/GitLab or OCI source if p.provider.GetSpec().FetchConfig != nil && p.provider.GetSpec().FetchConfig.OCI != "" { - configMap, err = OCIConfigMap(ctx, p.provider, OCIAuthentication(p.configClient.Variables())) + configMap, err = OCIConfigMap(ctx, p.provider, OCIAuthentication(p.ConfigClient.Variables())) if err != nil { return reconcile.Result{}, wrapPhaseError(err, operatorv1.ComponentsFetchErrorReason, operatorv1.ProviderInstalledCondition) } } else { - configMap, err = RepositoryConfigMap(ctx, p.provider, p.repo) + configMap, err = RepositoryConfigMap(ctx, p.provider, p.Repo) if err != nil { err = fmt.Errorf("failed to create config map for provider %q: %w", p.provider.GetName(), err) @@ -119,7 +110,7 @@ func (p *phaseReconciler) downloadManifests(ctx context.Context) (reconcile.Resu } // checkConfigMapExists checks if a config map exists in Kubernetes with the given LabelSelector. -func (p *phaseReconciler) checkConfigMapExists(ctx context.Context, labelSelector metav1.LabelSelector, namespace string) (bool, error) { +func checkConfigMapExists(ctx context.Context, cl client.Client, labelSelector metav1.LabelSelector, namespace string) (bool, error) { labelSet := labels.Set(labelSelector.MatchLabels) listOpts := []client.ListOption{ client.MatchingLabelsSelector{Selector: labels.SelectorFromSet(labelSet)}, @@ -128,7 +119,7 @@ func (p *phaseReconciler) checkConfigMapExists(ctx context.Context, labelSelecto var configMapList corev1.ConfigMapList - if err := p.ctrlClient.List(ctx, &configMapList, listOpts...); err != nil { + if err := cl.List(ctx, &configMapList, listOpts...); err != nil { return false, fmt.Errorf("failed to list ConfigMaps: %w", err) } @@ -139,11 +130,6 @@ func (p *phaseReconciler) checkConfigMapExists(ctx context.Context, labelSelecto return len(configMapList.Items) == 1, nil } -// prepareConfigMapLabels returns labels that identify a config map with downloaded manifests. -func (p *phaseReconciler) prepareConfigMapLabels() map[string]string { - return ProviderLabels(p.provider) -} - // TemplateManifestsConfigMap prepares a config map with downloaded manifests. func TemplateManifestsConfigMap(provider operatorv1.GenericProvider, labels map[string]string, metadata, components []byte, compress bool) (*corev1.ConfigMap, error) { configMapName := fmt.Sprintf("%s-%s-%s", provider.GetType(), provider.GetName(), provider.GetSpec().Version) diff --git a/internal/controller/manifests_downloader_test.go b/internal/controller/phases/manifests_downloader_test.go similarity index 56% rename from internal/controller/manifests_downloader_test.go rename to internal/controller/phases/manifests_downloader_test.go index 762475a6c..5c6b3920d 100644 --- a/internal/controller/manifests_downloader_test.go +++ b/internal/controller/phases/manifests_downloader_test.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package controller +package phases import ( "context" @@ -36,33 +36,45 @@ func TestManifestsDownloader(t *testing.T) { fakeclient := fake.NewClientBuilder().WithObjects().Build() - p := &phaseReconciler{ - ctrlClient: fakeclient, - provider: &operatorv1.CoreProvider{ - ObjectMeta: metav1.ObjectMeta{ - Name: "cluster-api", - Namespace: testNamespaceName, - }, - Spec: operatorv1.CoreProviderSpec{ - ProviderSpec: operatorv1.ProviderSpec{ - Version: "v1.4.3", - }, + namespace := "test-namespace" + + core := &operatorv1.CoreProvider{ + ObjectMeta: metav1.ObjectMeta{ + Name: "cluster-api", + Namespace: namespace, + }, + Spec: operatorv1.CoreProviderSpec{ + ProviderSpec: operatorv1.ProviderSpec{ + Version: "v1.4.3", }, }, } - _, err := p.initializePhaseReconciler(ctx) + p := &PhaseReconciler[*operatorv1.CoreProvider, Phase[*operatorv1.CoreProvider]]{ + ctrlClient: fakeclient, + } + + _, err := p.InitializePhaseReconciler(ctx, Phase[*operatorv1.CoreProvider]{ + Provider: core, + ProviderType: clusterctlv1.CoreProviderType, + ProviderList: &operatorv1.CoreProviderList{}, + }) g.Expect(err).ToNot(HaveOccurred()) - _, err = p.downloadManifests(ctx) + _, err = p.DownloadManifests(ctx, Phase[*operatorv1.CoreProvider]{ + Client: fakeclient, + Provider: core, + ProviderType: clusterctlv1.CoreProviderType, + ProviderList: &operatorv1.CoreProviderList{}, + }) g.Expect(err).ToNot(HaveOccurred()) // Ensure that config map was created labelSelector := metav1.LabelSelector{ - MatchLabels: p.prepareConfigMapLabels(), + MatchLabels: ProviderLabels(core), } - exists, err := p.checkConfigMapExists(ctx, labelSelector, p.provider.GetNamespace()) + exists, err := checkConfigMapExists(ctx, fakeclient, labelSelector, core.GetNamespace()) g.Expect(err).ToNot(HaveOccurred()) g.Expect(exists).To(BeTrue()) @@ -82,30 +94,38 @@ func TestProviderDownloadWithOverrides(t *testing.T) { overridesClient, err := configclient.New(ctx, "", configclient.InjectReader(reader)) g.Expect(err).ToNot(HaveOccurred()) - p := &phaseReconciler{ - ctrlClient: fakeclient, - provider: &operatorv1.CoreProvider{ - ObjectMeta: metav1.ObjectMeta{ - Name: "cluster-api", - Namespace: testNamespaceName, - }, - Spec: operatorv1.CoreProviderSpec{}, + core := &operatorv1.CoreProvider{ + ObjectMeta: metav1.ObjectMeta{ + Name: "cluster-api", + Namespace: testNamespaceName, }, + Spec: operatorv1.CoreProviderSpec{}, + } + + p := &PhaseReconciler[*operatorv1.CoreProvider, Phase[*operatorv1.CoreProvider]]{ + ctrlClient: fakeclient, overridesClient: overridesClient, } - _, err = p.initializePhaseReconciler(ctx) + phase := Phase[*operatorv1.CoreProvider]{ + Client: fakeclient, + Provider: core, + ProviderType: clusterctlv1.CoreProviderType, + ProviderList: &operatorv1.CoreProviderList{}, + } + + _, err = p.InitializePhaseReconciler(ctx, phase) g.Expect(err).ToNot(HaveOccurred()) - _, err = p.downloadManifests(ctx) + _, err = p.DownloadManifests(ctx, phase) g.Expect(err).ToNot(HaveOccurred()) - _, err = p.load(ctx) + _, err = p.Load(ctx, phase) g.Expect(err).ToNot(HaveOccurred()) - _, err = p.fetch(ctx) + _, err = p.Fetch(ctx, phase) g.Expect(err).ToNot(HaveOccurred()) - g.Expect(p.components.Images()).To(HaveExactElements([]string{"registry.k8s.io/cluster-api/cluster-api-controller:v1.4.3"})) - g.Expect(p.components.Version()).To(Equal("v1.4.3")) + g.Expect(p.Components.Images()).To(HaveExactElements([]string{"registry.k8s.io/cluster-api/cluster-api-controller:v1.4.3"})) + g.Expect(p.Components.Version()).To(Equal("v1.4.3")) } diff --git a/internal/controller/oci_source.go b/internal/controller/phases/oci_source.go similarity index 99% rename from internal/controller/oci_source.go rename to internal/controller/phases/oci_source.go index 608ce76e7..811e9f9f7 100644 --- a/internal/controller/oci_source.go +++ b/internal/controller/phases/oci_source.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package controller +package phases import ( "context" diff --git a/internal/controller/phases.go b/internal/controller/phases/phases.go similarity index 57% rename from internal/controller/phases.go rename to internal/controller/phases/phases.go index 06e2a6aae..87dcb359b 100644 --- a/internal/controller/phases.go +++ b/internal/controller/phases/phases.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package controller +package phases import ( "bytes" @@ -29,13 +29,14 @@ import ( "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/serializer" "k8s.io/apimachinery/pkg/types" + kerrors "k8s.io/apimachinery/pkg/util/errors" versionutil "k8s.io/apimachinery/pkg/util/version" "k8s.io/apimachinery/pkg/util/wait" "k8s.io/client-go/kubernetes/scheme" "k8s.io/client-go/rest" operatorv1 "sigs.k8s.io/cluster-api-operator/api/v1alpha2" - "sigs.k8s.io/cluster-api-operator/internal/controller/genericprovider" - "sigs.k8s.io/cluster-api-operator/util" + "sigs.k8s.io/cluster-api-operator/internal/controller/generic" + "sigs.k8s.io/cluster-api-operator/internal/controller/proxy" clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1" clusterctlv1 "sigs.k8s.io/cluster-api/cmd/clusterctl/api/v1alpha3" "sigs.k8s.io/cluster-api/cmd/clusterctl/client/cluster" @@ -51,26 +52,80 @@ import ( // fakeURL is the stub url for custom providers, missing from clusterctl repository. const fakeURL = "https://example.com/my-provider" -// phaseReconciler holds all required information for interacting with clusterctl code and +// PhaseReconciler holds all required information for interacting with clusterctl code and // helps to iterate through provider reconciliation phases. -type phaseReconciler struct { - provider genericprovider.GenericProvider - providerList genericprovider.GenericProviderList +type PhaseReconciler[P generic.Provider, G generic.Group[P]] struct { + provider generic.Provider + providerList generic.ProviderList ctrlClient client.Client ctrlConfig *rest.Config - repo repository.Repository - contract string - options repository.ComponentsOptions - providerConfig configclient.Provider - configClient configclient.Client + Repo repository.Repository + Contract string + Options repository.ComponentsOptions + ProviderConfig configclient.Provider + ConfigClient configclient.Client overridesClient configclient.Client - components repository.Components + Components repository.Components clusterctlProvider *clusterctlv1.Provider } -// reconcilePhaseFn is a function that represent a phase of the reconciliation. -type reconcilePhaseFn func(context.Context) (reconcile.Result, error) +type Phase[P generic.Provider] struct { + client.Client + Provider P + Config *rest.Config + ProviderList generic.ProviderList + ProviderType clusterctlv1.ProviderType + ClusterctlProvider *clusterctlv1.Provider +} + +var _ generic.Group[generic.Provider] = Phase[generic.Provider]{} + +func NewPhase[P generic.Provider](provider P, providerList generic.ProviderList, src generic.GroupBuilder[P]) generic.Group[P] { + return Phase[P]{ + Provider: provider, + ProviderList: providerList, + Client: src.GetClient(), + Config: src.GetConfig(), + ProviderType: src.ClusterctlProviderType(), + ClusterctlProvider: src.ClusterctlProvider(provider), + } +} + +// ClusterctlProviderType implements generic.ProviderGroup. +func (p Phase[P]) ClusterctlProviderType() clusterctlv1.ProviderType { + return p.ProviderType +} + +// GenericProvider implements generic.ProviderGroup. +func (p Phase[P]) GenericProvider() generic.Provider { + return p.Provider +} + +// GetClient implements generic.ProviderGroup. +func (p Phase[P]) GetClient() client.Client { + return p.Client +} + +// GetConfig implements generic.ProviderGroup. +func (p Phase[P]) GetConfig() *rest.Config { + return p.Config +} + +// GetProvider implements generic.ProviderGroup. +func (p Phase[P]) GetProvider() P { + return p.Provider +} + +// GetClusterctlProvider implements generic.ProviderGroup. +func (p Phase[P]) GetClusterctlProvider() *clusterctlv1.Provider { + return p.ClusterctlProvider +} + +// GetProviderList implements generic.ProviderGroup. +func (p Phase[P]) GetProviderList() generic.ProviderList { + return p.ProviderList +} // PhaseError custom error type for phases. type PhaseError struct { @@ -97,24 +152,15 @@ func wrapPhaseError(err error, reason string, condition clusterv1.ConditionType) } } -// newPhaseReconciler returns phase reconciler for the given provider. -func newPhaseReconciler(r GenericProviderReconciler, provider genericprovider.GenericProvider, providerList genericprovider.GenericProviderList) *phaseReconciler { - return &phaseReconciler{ - ctrlClient: r.Client, - ctrlConfig: r.Config, - clusterctlProvider: &clusterctlv1.Provider{}, - provider: provider, - providerList: providerList, +// NewPhaseReconciler returns phase reconciler for the given phase.GetProvider(). +func NewPhaseReconciler[P generic.Provider, G generic.Group[P]](cl client.Client) *PhaseReconciler[P, G] { + return &PhaseReconciler[P, G]{ + ctrlClient: cl, } } -// preflightChecks a wrapper around the preflight checks. -func (p *phaseReconciler) preflightChecks(ctx context.Context) (reconcile.Result, error) { - return reconcile.Result{}, preflightChecks(ctx, p.ctrlClient, p.provider, p.providerList) -} - -// initializePhaseReconciler initializes phase reconciler. -func (p *phaseReconciler) initializePhaseReconciler(ctx context.Context) (reconcile.Result, error) { +// InitializePhaseReconciler initializes phase reconciler. +func (p *PhaseReconciler[P, G]) InitializePhaseReconciler(ctx context.Context, phase G) (reconcile.Result, error) { path := configPath if _, err := os.Stat(configPath); os.IsNotExist(err) { path = "" @@ -142,7 +188,7 @@ func (p *phaseReconciler) initializePhaseReconciler(ctx context.Context) (reconc overrideProviders = providers } - reader, err := p.secretReader(ctx, overrideProviders...) + reader, err := secretReader(ctx, phase, overrideProviders...) if err != nil { return reconcile.Result{}, err } @@ -160,14 +206,14 @@ func (p *phaseReconciler) initializePhaseReconciler(ctx context.Context) (reconc } // Load provider's secret and config url. - p.configClient, err = configclient.New(ctx, "", configclient.InjectReader(reader)) + p.ConfigClient, err = configclient.New(ctx, "", configclient.InjectReader(reader)) if err != nil { return reconcile.Result{}, wrapPhaseError(err, "failed to load the secret reader", operatorv1.ProviderInstalledCondition) } // Get returns the configuration for the provider with a given name/type. // This is done using clusterctl internal API types. - p.providerConfig, err = p.configClient.Providers().Get(p.provider.GetName(), util.ClusterctlProviderType(p.provider)) + p.ProviderConfig, err = p.ConfigClient.Providers().Get(phase.GetProvider().GetName(), phase.ClusterctlProviderType()) if err != nil { return reconcile.Result{}, wrapPhaseError(err, operatorv1.UnknownProviderReason, operatorv1.ProviderInstalledCondition) } @@ -175,59 +221,59 @@ func (p *phaseReconciler) initializePhaseReconciler(ctx context.Context) (reconc return reconcile.Result{}, nil } -// load provider specific configuration into phaseReconciler object. -func (p *phaseReconciler) load(ctx context.Context) (reconcile.Result, error) { +// Load provider specific configuration into phaseReconciler object. +func (p *PhaseReconciler[P, G]) Load(ctx context.Context, phase G) (reconcile.Result, error) { log := ctrl.LoggerFrom(ctx) log.Info("Loading provider") var err error - spec := p.provider.GetSpec() + spec := phase.GetProvider().GetSpec() labelSelector := &metav1.LabelSelector{ - MatchLabels: p.prepareConfigMapLabels(), + MatchLabels: ProviderLabels(phase.GetProvider()), } // Replace label selector if user wants to use custom config map - if p.provider.GetSpec().FetchConfig != nil && p.provider.GetSpec().FetchConfig.Selector != nil { - labelSelector = p.provider.GetSpec().FetchConfig.Selector + if phase.GetProvider().GetSpec().FetchConfig != nil && phase.GetProvider().GetSpec().FetchConfig.Selector != nil { + labelSelector = phase.GetProvider().GetSpec().FetchConfig.Selector } - additionalManifests, err := p.fetchAdditionalManifests(ctx) + additionalManifests, err := fetchAddionalManifests(ctx, phase) if err != nil { return reconcile.Result{}, wrapPhaseError(err, "failed to load additional manifests", operatorv1.ProviderInstalledCondition) } - p.repo, err = p.configmapRepository(ctx, labelSelector, p.provider.GetNamespace(), additionalManifests) + p.Repo, err = configmapRepository(ctx, phase.GetClient(), labelSelector, phase.GetProvider().GetNamespace(), additionalManifests) if err != nil { return reconcile.Result{}, wrapPhaseError(err, "failed to load the repository", operatorv1.ProviderInstalledCondition) } if spec.Version == "" { // User didn't set the version, so we need to find the latest one from the matching config maps. - repoVersions, err := p.repo.GetVersions(ctx) + repoVersions, err := p.Repo.GetVersions(ctx) if err != nil { - return reconcile.Result{}, wrapPhaseError(err, fmt.Sprintf("failed to get a list of available versions for provider %q", p.provider.GetName()), operatorv1.ProviderInstalledCondition) + return reconcile.Result{}, wrapPhaseError(err, fmt.Sprintf("failed to get a list of available versions for provider %q", phase.GetProvider().GetName()), operatorv1.ProviderInstalledCondition) } spec.Version, err = getLatestVersion(repoVersions) if err != nil { - return reconcile.Result{}, wrapPhaseError(err, fmt.Sprintf("failed to get the latest version for provider %q", p.provider.GetName()), operatorv1.ProviderInstalledCondition) + return reconcile.Result{}, wrapPhaseError(err, fmt.Sprintf("failed to get the latest version for provider %q", phase.GetProvider().GetName()), operatorv1.ProviderInstalledCondition) } // Add latest version to the provider spec. - p.provider.SetSpec(spec) + phase.GetProvider().SetSpec(spec) } // Store some provider specific inputs for passing it to clusterctl library - p.options = repository.ComponentsOptions{ - TargetNamespace: p.provider.GetNamespace(), + p.Options = repository.ComponentsOptions{ + TargetNamespace: phase.GetProvider().GetNamespace(), SkipTemplateProcess: false, Version: spec.Version, } - if err := p.validateRepoCAPIVersion(ctx); err != nil { + if err := p.validateRepoCAPIVersion(ctx, phase); err != nil { return reconcile.Result{}, wrapPhaseError(err, operatorv1.CAPIVersionIncompatibilityReason, operatorv1.ProviderInstalledCondition) } @@ -236,7 +282,7 @@ func (p *phaseReconciler) load(ctx context.Context) (reconcile.Result, error) { // secretReader use clusterctl MemoryReader structure to store the configuration variables // that are obtained from a secret and try to set fetch url config. -func (p *phaseReconciler) secretReader(ctx context.Context, providers ...configclient.Provider) (configclient.Reader, error) { +func secretReader[P generic.Provider](ctx context.Context, phase generic.Group[P], providers ...configclient.Provider) (configclient.Reader, error) { log := ctrl.LoggerFrom(ctx) mr := configclient.NewMemoryReader() @@ -246,11 +292,11 @@ func (p *phaseReconciler) secretReader(ctx context.Context, providers ...configc } // Fetch configuration variables from the secret. See API field docs for more info. - if p.provider.GetSpec().ConfigSecret != nil { + if phase.GetProvider().GetSpec().ConfigSecret != nil { secret := &corev1.Secret{} - key := types.NamespacedName{Namespace: p.provider.GetSpec().ConfigSecret.Namespace, Name: p.provider.GetSpec().ConfigSecret.Name} + key := types.NamespacedName{Namespace: phase.GetProvider().GetSpec().ConfigSecret.Namespace, Name: phase.GetProvider().GetSpec().ConfigSecret.Name} - if err := p.ctrlClient.Get(ctx, key, secret); err != nil { + if err := phase.GetClient().Get(ctx, key, secret); err != nil { return nil, err } @@ -268,29 +314,29 @@ func (p *phaseReconciler) secretReader(ctx context.Context, providers ...configc return nil, err } - if provider.Type() == clusterctlv1.ProviderType(p.provider.GetType()) && provider.Name() == p.provider.GetName() { + if provider.Type() == clusterctlv1.ProviderType(phase.GetProvider().GetType()) && provider.Name() == phase.GetProvider().GetName() { isCustom = false } } // If provided store fetch config url in memory reader. - if p.provider.GetSpec().FetchConfig != nil { - if p.provider.GetSpec().FetchConfig.URL != "" { + if phase.GetProvider().GetSpec().FetchConfig != nil { + if phase.GetProvider().GetSpec().FetchConfig.URL != "" { log.Info("Custom fetch configuration url was provided") - return mr.AddProvider(p.provider.GetName(), util.ClusterctlProviderType(p.provider), p.provider.GetSpec().FetchConfig.URL) + return mr.AddProvider(phase.GetProvider().GetName(), phase.ClusterctlProviderType(), phase.GetProvider().GetSpec().FetchConfig.URL) } - if p.provider.GetSpec().FetchConfig.Selector != nil { + if phase.GetProvider().GetSpec().FetchConfig.Selector != nil { log.Info("Custom fetch configuration config map was provided") // To register a new provider from the config map, we need to specify a URL with a valid // format. However, since we're using data from a local config map, URLs are not needed. // As a workaround, we add a fake but well-formatted URL. - return mr.AddProvider(p.provider.GetName(), util.ClusterctlProviderType(p.provider), fakeURL) + return mr.AddProvider(phase.GetProvider().GetName(), util.ClusterctlProviderType(phase.GetProvider()), fakeURL) } - if isCustom && p.provider.GetSpec().FetchConfig.OCI != "" { - return mr.AddProvider(p.provider.GetName(), util.ClusterctlProviderType(p.provider), fakeURL) + if isCustom && phase.GetProvider().GetSpec().FetchConfig.OCI != "" { + return mr.AddProvider(phase.GetProvider().GetName(), util.ClusterctlProviderType(phase.GetProvider()), fakeURL) } } @@ -299,7 +345,7 @@ func (p *phaseReconciler) secretReader(ctx context.Context, providers ...configc // configmapRepository use clusterctl NewMemoryRepository structure to store the manifests // and metadata from a given configmap. -func (p *phaseReconciler) configmapRepository(ctx context.Context, labelSelector *metav1.LabelSelector, namespace, additionalManifests string) (repository.Repository, error) { +func configmapRepository(ctx context.Context, cl client.Client, labelSelector *metav1.LabelSelector, namespace, additionalManifests string) (repository.Repository, error) { mr := repository.NewMemoryRepository() mr.WithPaths("", "components.yaml") @@ -310,7 +356,7 @@ func (p *phaseReconciler) configmapRepository(ctx context.Context, labelSelector return nil, err } - if err = p.ctrlClient.List(ctx, cml, &client.ListOptions{LabelSelector: selector, Namespace: namespace}); err != nil { + if err = cl.List(ctx, cml, &client.ListOptions{LabelSelector: selector, Namespace: namespace}); err != nil { return nil, err } @@ -356,13 +402,13 @@ func (p *phaseReconciler) configmapRepository(ctx context.Context, labelSelector return mr, nil } -func (p *phaseReconciler) fetchAdditionalManifests(ctx context.Context) (string, error) { +func fetchAddionalManifests[P generic.Provider, G generic.Group[P]](ctx context.Context, phase G) (string, error) { cm := &corev1.ConfigMap{} - if p.provider.GetSpec().AdditionalManifestsRef != nil { - key := types.NamespacedName{Namespace: p.provider.GetSpec().AdditionalManifestsRef.Namespace, Name: p.provider.GetSpec().AdditionalManifestsRef.Name} + if phase.GetProvider().GetSpec().AdditionalManifestsRef != nil { + key := types.NamespacedName{Namespace: phase.GetProvider().GetSpec().AdditionalManifestsRef.Namespace, Name: phase.GetProvider().GetSpec().AdditionalManifestsRef.Name} - if err := p.ctrlClient.Get(ctx, key, cm); err != nil { + if err := phase.GetClient().Get(ctx, key, cm); err != nil { return "", fmt.Errorf("failed to get ConfigMap %s/%s: %w", key.Namespace, key.Name, err) } } @@ -406,10 +452,10 @@ func getComponentsData(cm corev1.ConfigMap) (string, error) { } // validateRepoCAPIVersion checks that the repo is using the correct version. -func (p *phaseReconciler) validateRepoCAPIVersion(ctx context.Context) error { - name := p.provider.GetName() +func (p *PhaseReconciler[P, G]) validateRepoCAPIVersion(ctx context.Context, phase G) error { + name := phase.GetProvider().GetName() - file, err := p.repo.GetFile(ctx, p.options.Version, metadataFile) + file, err := p.Repo.GetFile(ctx, p.Options.Version, metadataFile) if err != nil { return fmt.Errorf("failed to read %q from the repository for provider %q: %w", metadataFile, name, err) } @@ -423,34 +469,34 @@ func (p *phaseReconciler) validateRepoCAPIVersion(ctx context.Context) error { } // Gets the contract for the target release. - targetVersion, err := versionutil.ParseSemantic(p.options.Version) + targetVersion, err := versionutil.ParseSemantic(p.Options.Version) if err != nil { return fmt.Errorf("failed to parse current version for the %s provider: %w", name, err) } releaseSeries := latestMetadata.GetReleaseSeriesForVersion(targetVersion) if releaseSeries == nil { - return fmt.Errorf("invalid provider metadata: version %s for the provider %s does not match any release series", p.options.Version, name) + return fmt.Errorf("invalid provider metadata: version %s for the provider %s does not match any release series", p.Options.Version, name) } if releaseSeries.Contract != "v1alpha4" && releaseSeries.Contract != "v1beta1" { return fmt.Errorf(capiVersionIncompatibilityMessage, clusterv1.GroupVersion.Version, releaseSeries.Contract, name) } - p.contract = releaseSeries.Contract + p.Contract = releaseSeries.Contract return nil } -// fetch fetches the provider components from the repository and processes all yaml manifests. -func (p *phaseReconciler) fetch(ctx context.Context) (reconcile.Result, error) { +// Fetch fetches the provider components from the repository and processes all yaml manifests. +func (p *PhaseReconciler[P, G]) Fetch(ctx context.Context, phase G) (reconcile.Result, error) { log := ctrl.LoggerFrom(ctx) log.Info("Fetching provider") // Fetch the provider components yaml file from the provided repository GitHub/GitLab/ConfigMap. - componentsFile, err := p.repo.GetFile(ctx, p.options.Version, p.repo.ComponentsPath()) + componentsFile, err := p.Repo.GetFile(ctx, p.Options.Version, p.Repo.ComponentsPath()) if err != nil { - err = fmt.Errorf("failed to read %q from provider's repository %q: %w", p.repo.ComponentsPath(), p.providerConfig.ManifestLabel(), err) + err = fmt.Errorf("failed to read %q from provider's repository %q: %w", p.Repo.ComponentsPath(), p.ProviderConfig.ManifestLabel(), err) return reconcile.Result{}, wrapPhaseError(err, operatorv1.ComponentsFetchErrorReason, operatorv1.ProviderInstalledCondition) } @@ -458,12 +504,12 @@ func (p *phaseReconciler) fetch(ctx context.Context) (reconcile.Result, error) { // Generate a set of new objects using the clusterctl library. NewComponents() will do the yaml processing, // like ensure all the provider components are in proper namespace, replace variables, etc. See the clusterctl // documentation for more details. - p.components, err = repository.NewComponents(repository.ComponentsInput{ - Provider: p.providerConfig, - ConfigClient: p.configClient, + p.Components, err = repository.NewComponents(repository.ComponentsInput{ + Provider: p.ProviderConfig, + ConfigClient: p.ConfigClient, Processor: yamlprocessor.NewSimpleProcessor(), RawYaml: componentsFile, - Options: p.options, + Options: p.Options, }) if err != nil { return reconcile.Result{}, wrapPhaseError(err, operatorv1.ComponentsFetchErrorReason, operatorv1.ProviderInstalledCondition) @@ -471,17 +517,17 @@ func (p *phaseReconciler) fetch(ctx context.Context) (reconcile.Result, error) { // ProviderSpec provides fields for customizing the provider deployment options. // We can use clusterctl library to apply this customizations. - if err := repository.AlterComponents(p.components, customizeObjectsFn(p.provider)); err != nil { + if err := repository.AlterComponents(p.Components, customizeObjectsFn(phase.GetProvider())); err != nil { return reconcile.Result{}, wrapPhaseError(err, operatorv1.ComponentsFetchErrorReason, operatorv1.ProviderInstalledCondition) } // Apply patches to the provider components if specified. - if err := repository.AlterComponents(p.components, applyPatches(ctx, p.provider)); err != nil { + if err := repository.AlterComponents(p.Components, applyPatches(ctx, phase.GetProvider())); err != nil { return reconcile.Result{}, wrapPhaseError(err, operatorv1.ComponentsFetchErrorReason, operatorv1.ProviderInstalledCondition) } // Apply image overrides to the provider manifests. - if err := repository.AlterComponents(p.components, imageOverrides(p.components.ManifestLabel(), p.overridesClient)); err != nil { + if err := repository.AlterComponents(p.Components, imageOverrides(p.Components.ManifestLabel(), p.overridesClient)); err != nil { return reconcile.Result{}, wrapPhaseError(err, operatorv1.ComponentsFetchErrorReason, operatorv1.ProviderInstalledCondition) } @@ -490,50 +536,50 @@ func (p *phaseReconciler) fetch(ctx context.Context) (reconcile.Result, error) { return reconcile.Result{}, nil } -// upgrade ensure all the clusterctl CRDs are available before installing the provider, +// Upgrade ensure all the clusterctl CRDs are available before installing the provider, // and update existing components if required. -func (p *phaseReconciler) upgrade(ctx context.Context) (reconcile.Result, error) { +func (p *PhaseReconciler[P, G]) Upgrade(ctx context.Context, phase G) (reconcile.Result, error) { log := ctrl.LoggerFrom(ctx) // Nothing to do if it's a fresh installation. - if p.provider.GetStatus().InstalledVersion == nil { + if phase.GetProvider().GetStatus().InstalledVersion == nil { return reconcile.Result{}, nil } // Provider needs to be re-installed - if *p.provider.GetStatus().InstalledVersion == p.provider.GetSpec().Version { + if *phase.GetProvider().GetStatus().InstalledVersion == phase.GetProvider().GetSpec().Version { return reconcile.Result{}, nil } log.Info("Version changes detected, updating existing components") - if err := p.newClusterClient().ProviderUpgrader().ApplyCustomPlan(ctx, cluster.UpgradeOptions{}, cluster.UpgradeItem{ - NextVersion: p.provider.GetSpec().Version, - Provider: getProvider(p.provider, p.options.Version), + if err := newClusterClient(p, phase).ProviderUpgrader().ApplyCustomPlan(ctx, cluster.UpgradeOptions{}, cluster.UpgradeItem{ + NextVersion: phase.GetProvider().GetSpec().Version, + Provider: setProviderVersion(phase.GetClusterctlProvider(), phase.GetProvider().GetSpec().Version), }); err != nil { return reconcile.Result{}, wrapPhaseError(err, operatorv1.ComponentsUpgradeErrorReason, operatorv1.ProviderUpgradedCondition) } log.Info("Provider successfully upgraded") - conditions.Set(p.provider, conditions.TrueCondition(operatorv1.ProviderUpgradedCondition)) + conditions.Set(phase.GetProvider(), conditions.TrueCondition(operatorv1.ProviderUpgradedCondition)) return reconcile.Result{}, nil } -// install installs the provider components using clusterctl library. -func (p *phaseReconciler) install(ctx context.Context) (reconcile.Result, error) { +// Install installs the provider components using clusterctl library. +func (p *PhaseReconciler[P, G]) Install(ctx context.Context, phase G) (reconcile.Result, error) { log := ctrl.LoggerFrom(ctx) // Provider was upgraded, nothing to do - if p.provider.GetStatus().InstalledVersion != nil && *p.provider.GetStatus().InstalledVersion != p.provider.GetSpec().Version { + if phase.GetProvider().GetStatus().InstalledVersion != nil && *phase.GetProvider().GetStatus().InstalledVersion != phase.GetProvider().GetSpec().Version { return reconcile.Result{}, nil } - clusterClient := p.newClusterClient() + clusterClient := newClusterClient(p, phase) log.Info("Installing provider") - if err := clusterClient.ProviderComponents().Create(ctx, p.components.Objs()); err != nil { + if err := clusterClient.ProviderComponents().Create(ctx, p.Components.Objs()); err != nil { reason := "Install failed" if wait.Interrupted(err) { reason = "Timed out waiting for deployment to become ready" @@ -543,33 +589,23 @@ func (p *phaseReconciler) install(ctx context.Context) (reconcile.Result, error) } log.Info("Provider successfully installed") - conditions.Set(p.provider, conditions.TrueCondition(operatorv1.ProviderInstalledCondition)) + conditions.Set(phase.GetProvider(), conditions.TrueCondition(operatorv1.ProviderInstalledCondition)) return reconcile.Result{}, nil } -func (p *phaseReconciler) reportStatus(_ context.Context) (reconcile.Result, error) { - status := p.provider.GetStatus() - status.Contract = &p.contract - installedVersion := p.components.Version() +func (p *PhaseReconciler[P, G]) ReportStatus(_ context.Context, phase G) (reconcile.Result, error) { + status := phase.GetProvider().GetStatus() + status.Contract = &p.Contract + installedVersion := p.Components.Version() status.InstalledVersion = &installedVersion - p.provider.SetStatus(status) + phase.GetProvider().SetStatus(status) return reconcile.Result{}, nil } -func getProvider(provider operatorv1.GenericProvider, defaultVersion string) clusterctlv1.Provider { - clusterctlProvider := &clusterctlv1.Provider{} - clusterctlProvider.Name = clusterctlProviderName(provider).Name - clusterctlProvider.Namespace = provider.GetNamespace() - clusterctlProvider.Type = string(util.ClusterctlProviderType(provider)) - clusterctlProvider.ProviderName = provider.GetName() - - if provider.GetStatus().InstalledVersion != nil { - clusterctlProvider.Version = *provider.GetStatus().InstalledVersion - } else { - clusterctlProvider.Version = defaultVersion - } +func setProviderVersion(clusterctlProvider *clusterctlv1.Provider, version string) clusterctlv1.Provider { + clusterctlProvider.Version = version return *clusterctlProvider } @@ -597,14 +633,14 @@ func loadCustomProviders(providers []operatorv1.GenericProvider, reader configcl } // delete deletes the provider components using clusterctl library. -func (p *phaseReconciler) delete(ctx context.Context) (reconcile.Result, error) { +func (p *PhaseReconciler[P, G]) Delete(ctx context.Context, phase G) (reconcile.Result, error) { log := ctrl.LoggerFrom(ctx) log.Info("Deleting provider") - clusterClient := p.newClusterClient() + clusterClient := newClusterClient(p, phase) err := clusterClient.ProviderComponents().Delete(ctx, cluster.DeleteOptions{ - Provider: getProvider(p.provider, p.options.Version), + Provider: *phase.GetClusterctlProvider(), IncludeNamespace: false, IncludeCRDs: false, }) @@ -612,36 +648,16 @@ func (p *phaseReconciler) delete(ctx context.Context) (reconcile.Result, error) return reconcile.Result{}, wrapPhaseError(err, operatorv1.OldComponentsDeletionErrorReason, operatorv1.ProviderInstalledCondition) } -func clusterctlProviderName(provider operatorv1.GenericProvider) client.ObjectKey { - prefix := "" - switch provider.(type) { - case *operatorv1.BootstrapProvider: - prefix = "bootstrap-" - case *operatorv1.ControlPlaneProvider: - prefix = "control-plane-" - case *operatorv1.InfrastructureProvider: - prefix = "infrastructure-" - case *operatorv1.AddonProvider: - prefix = "addon-" - case *operatorv1.IPAMProvider: - prefix = "ipam-" - case *operatorv1.RuntimeExtensionProvider: - prefix = "runtime-extension-" - } - - return client.ObjectKey{Name: prefix + provider.GetName(), Namespace: provider.GetNamespace()} -} - -func (p *phaseReconciler) repositoryProxy(ctx context.Context, provider configclient.Provider, configClient configclient.Client, options ...repository.Option) (repository.Client, error) { - injectRepo := p.repo +func (p *PhaseReconciler[P, G]) repositoryProxy(ctx context.Context, provider configclient.Provider, configClient configclient.Client, options ...repository.Option) (repository.Client, error) { + injectRepo := p.Repo - if !provider.SameAs(p.providerConfig) { - genericProvider, err := util.GetGenericProvider(ctx, p.ctrlClient, provider) + if !provider.SameAs(p.ProviderConfig) { + genericProvider, err := GetGenericProvider(ctx, p.ctrlClient, provider) if err != nil { return nil, wrapPhaseError(err, "unable to find generic provider for configclient "+string(provider.Type())+": "+provider.Name(), operatorv1.ProviderUpgradedCondition) } - if exists, err := p.checkConfigMapExists(ctx, *providerLabelSelector(genericProvider), genericProvider.GetNamespace()); err != nil { + if exists, err := checkConfigMapExists(ctx, p.ctrlClient, *providerLabelSelector(genericProvider), genericProvider.GetNamespace()); err != nil { provider := client.ObjectKeyFromObject(genericProvider) return nil, wrapPhaseError(err, "failed to check the config map repository existence for provider "+provider.String(), operatorv1.ProviderUpgradedCondition) } else if !exists { @@ -649,7 +665,7 @@ func (p *phaseReconciler) repositoryProxy(ctx context.Context, provider configcl return nil, wrapPhaseError(fmt.Errorf("config map not found"), "config map repository required for validation does not exist yet for provider "+provider.String(), operatorv1.ProviderUpgradedCondition) } - repo, err := p.configmapRepository(ctx, providerLabelSelector(genericProvider), genericProvider.GetNamespace(), "") + repo, err := configmapRepository(ctx, p.ctrlClient, providerLabelSelector(genericProvider), genericProvider.GetNamespace(), "") if err != nil { provider := client.ObjectKeyFromObject(genericProvider) return nil, wrapPhaseError(err, "failed to load the repository for provider "+provider.String(), operatorv1.ProviderUpgradedCondition) @@ -663,17 +679,75 @@ func (p *phaseReconciler) repositoryProxy(ctx context.Context, provider configcl return nil, err } - return repositoryProxy{Client: cl, components: p.components}, nil + return proxy.RepositoryProxy{Client: cl, RepositoryComponents: p.Components}, nil +} + +// GetGenericProvider returns the first of generic providers matching the type and the name from the configclient.Provider. +func GetGenericProvider(ctx context.Context, cl client.Client, provider configclient.Provider) (operatorv1.GenericProvider, error) { + p, found := generic.ProviderReconcilers[provider.Type()] + if !found { + return nil, fmt.Errorf("provider %s type %s is not supported", provider.Name(), provider.Type()) + } + + list := p.GetProviderList() + if err := cl.List(ctx, list); err != nil { + return nil, err + } + + for _, p := range list.GetItems() { + if p.GetName() == provider.Name() { + return p, nil + } + } + + return nil, fmt.Errorf("unable to find provider manifest with name %s", provider.Name()) } // newClusterClient returns a clusterctl client for interacting with management cluster. -func (p *phaseReconciler) newClusterClient() cluster.Client { - return cluster.New(cluster.Kubeconfig{}, p.configClient, cluster.InjectProxy(&controllerProxy{ - ctrlClient: clientProxy{p.ctrlClient}, - ctrlConfig: p.ctrlConfig, +func newClusterClient[P generic.Provider, G generic.Group[P]](p *PhaseReconciler[P, G], phase G) cluster.Client { + return cluster.New(cluster.Kubeconfig{}, p.ConfigClient, cluster.InjectProxy(&proxy.ControllerProxy{ + CtrlClient: proxy.ClientProxy{ + Client: phase.GetClient(), + ListProviders: listProviders, + }, + CtrlConfig: phase.GetConfig(), }), cluster.InjectRepositoryFactory(p.repositoryProxy)) } +func listProviders(ctx context.Context, cl client.Client, list *clusterctlv1.ProviderList, opts ...client.ListOption) error { + return kerrors.NewAggregate([]error{ + combineProviders[*operatorv1.CoreProvider](ctx, cl, list, opts...), + combineProviders[*operatorv1.InfrastructureProvider](ctx, cl, list, opts...), + combineProviders[*operatorv1.BootstrapProvider](ctx, cl, list, opts...), + combineProviders[*operatorv1.ControlPlaneProvider](ctx, cl, list, opts...), + combineProviders[*operatorv1.AddonProvider](ctx, cl, list, opts...), + combineProviders[*operatorv1.IPAMProvider](ctx, cl, list, opts...), + }) +} + +func combineProviders[P generic.Provider](ctx context.Context, cl client.Client, list *clusterctlv1.ProviderList, opts ...client.ListOption) error { + reconciler := generic.GetBuilder(*new(P)) + if reconciler == nil { + return fmt.Errorf("unable to find registered reconciler for type: %T", *new(P)) + } + + l := reconciler.GetProviderList() + if err := cl.List(ctx, l, opts...); err != nil { + return err + } + + for _, p := range l.GetItems() { + provider, ok := p.(P) + if !ok { + return fmt.Errorf("unexpected provider type: %T, expected %T", p, new(P)) + } + + list.Items = append(list.Items, *reconciler.ClusterctlProvider(provider)) + } + + return nil +} + func getLatestVersion(repoVersions []string) (string, error) { if len(repoVersions) == 0 { err := fmt.Errorf("no versions available") diff --git a/internal/controller/phases_test.go b/internal/controller/phases/phases_test.go similarity index 92% rename from internal/controller/phases_test.go rename to internal/controller/phases/phases_test.go index e06cfe9b2..e16a801ca 100644 --- a/internal/controller/phases_test.go +++ b/internal/controller/phases/phases_test.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package controller +package phases import ( "context" @@ -31,9 +31,12 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client/fake" operatorv1 "sigs.k8s.io/cluster-api-operator/api/v1alpha2" + "sigs.k8s.io/cluster-api-operator/internal/controller/generic" "sigs.k8s.io/cluster-api-operator/util" ) +const testCurrentVersion = "v0.4.2" + func TestSecretReader(t *testing.T) { g := NewWithT(t) @@ -41,27 +44,24 @@ func TestSecretReader(t *testing.T) { secretName := "test-secret" secretNamespace := "test-secret-namespace" - - p := &phaseReconciler{ - ctrlClient: fakeclient, - provider: &operatorv1.CoreProvider{ - ObjectMeta: metav1.ObjectMeta{ - Name: "cluster-api", - Namespace: testNamespaceName, - }, - TypeMeta: metav1.TypeMeta{ - Kind: "CoreProvider", - APIVersion: "operator.cluster.x-k8s.io/v1alpha1", - }, - Spec: operatorv1.CoreProviderSpec{ - ProviderSpec: operatorv1.ProviderSpec{ - ConfigSecret: &operatorv1.SecretReference{ - Name: secretName, - Namespace: secretNamespace, - }, - FetchConfig: &operatorv1.FetchConfiguration{ - URL: "https://example.com", - }, + namespace := "test-namespace" + core := &operatorv1.CoreProvider{ + ObjectMeta: metav1.ObjectMeta{ + Name: "cluster-api", + Namespace: namespace, + }, + TypeMeta: metav1.TypeMeta{ + Kind: "CoreProvider", + APIVersion: "operator.cluster.x-k8s.io/v1alpha1", + }, + Spec: operatorv1.CoreProviderSpec{ + ProviderSpec: operatorv1.ProviderSpec{ + ConfigSecret: &operatorv1.SecretReference{ + Name: secretName, + Namespace: secretNamespace, + }, + FetchConfig: &operatorv1.FetchConfiguration{ + URL: "https://example.com", }, }, }, @@ -85,7 +85,12 @@ func TestSecretReader(t *testing.T) { }, })).To(Succeed()) - configreader, err := p.secretReader(context.TODO(), configclient.NewProvider(testKey3, testValue3, clusterctlv1.CoreProviderType)) + configreader, err := secretReader(context.TODO(), Phase[*operatorv1.CoreProvider]{ + Client: fakeclient, + Provider: core, + ProviderType: clusterctlv1.CoreProviderType, + ClusterctlProvider: &clusterctlv1.Provider{}, + }, configclient.NewProvider(testKey3, testValue3, clusterctlv1.CoreProviderType)) g.Expect(err).ToNot(HaveOccurred()) expectedValue1, err := configreader.Get(testKey1) @@ -380,17 +385,12 @@ metadata: g := NewWithT(t) fakeclient := fake.NewClientBuilder().WithScheme(setupScheme()).WithObjects(provider).Build() - p := &phaseReconciler{ - ctrlClient: fakeclient, - provider: provider, - } for i := range tt.configMaps { g.Expect(fakeclient.Create(ctx, &tt.configMaps[i])).To(Succeed()) } - got, err := p.configmapRepository(context.TODO(), p.provider.GetSpec().FetchConfig.Selector, "ns1", tt.additionalManifests) - + got, err := configmapRepository(context.TODO(), fakeclient, provider.GetSpec().FetchConfig.Selector, "ns1", tt.additionalManifests) if len(tt.wantErr) > 0 { g.Expect(err).Should(MatchError(tt.wantErr)) return @@ -416,6 +416,12 @@ metadata: } func TestRepositoryProxy(t *testing.T) { + generic.ProviderReconcilers[clusterctlv1.InfrastructureProviderType] = Phase[*operatorv1.InfrastructureProvider]{ + ProviderType: clusterctlv1.InfrastructureProviderType, + Provider: &operatorv1.InfrastructureProvider{}, + ProviderList: &operatorv1.InfrastructureProviderList{}, + } + coreProvider := configclient.NewProvider("cluster-api", "https://github.com/kubernetes-sigs/cluster-api/releases/latest/core-components.yaml", clusterctlv1.CoreProviderType) awsProvider := configclient.NewProvider("aws", "https://github.com/kubernetes-sigs/cluster-api-provider-aws/releases/v1.4.1/infrastructure-components.yaml", clusterctlv1.InfrastructureProviderType) @@ -579,11 +585,10 @@ releaseSeries: g := NewWithT(t) fakeclient := fake.NewClientBuilder().WithScheme(setupScheme()).WithObjects(tt.genericProviders...).Build() - p := &phaseReconciler{ + p := &PhaseReconciler[*operatorv1.CoreProvider, Phase[*operatorv1.CoreProvider]]{ ctrlClient: fakeclient, - providerConfig: coreProvider, - repo: repository.NewMemoryRepository(), - provider: core, + ProviderConfig: coreProvider, + Repo: repository.NewMemoryRepository(), } for i := range tt.configMaps { @@ -592,7 +597,7 @@ releaseSeries: if tt.defaultRepository { var err error - p.repo, err = p.configmapRepository(ctx, &metav1.LabelSelector{ + p.Repo, err = configmapRepository(ctx, fakeclient, &metav1.LabelSelector{ MatchLabels: map[string]string{ operatorManagedLabel: "true", }, diff --git a/internal/controller/preflight_checks.go b/internal/controller/phases/preflight_checks.go similarity index 63% rename from internal/controller/preflight_checks.go rename to internal/controller/phases/preflight_checks.go index fea422fb8..e7383bf69 100644 --- a/internal/controller/preflight_checks.go +++ b/internal/controller/phases/preflight_checks.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package controller +package phases import ( "context" @@ -28,18 +28,12 @@ import ( "k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/util/version" operatorv1 "sigs.k8s.io/cluster-api-operator/api/v1alpha2" - "sigs.k8s.io/cluster-api-operator/internal/controller/genericprovider" - "sigs.k8s.io/cluster-api-operator/util" + "sigs.k8s.io/cluster-api-operator/internal/controller/generic" clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1" clusterctlv1 "sigs.k8s.io/cluster-api/cmd/clusterctl/api/v1alpha3" configclient "sigs.k8s.io/cluster-api/cmd/clusterctl/client/config" "sigs.k8s.io/cluster-api/util/conditions" ctrl "sigs.k8s.io/controller-runtime" - "sigs.k8s.io/controller-runtime/pkg/client" -) - -const ( - coreProvider = "CoreProvider" ) var ( @@ -54,39 +48,25 @@ var ( errCoreProviderWait = errors.New(waitingForCoreProviderReadyMessage) ) -// preflightChecks performs preflight checks before installing provider. -func preflightChecks(ctx context.Context, c client.Client, provider genericprovider.GenericProvider, providerList genericprovider.GenericProviderList) error { +// PreflightChecks performs preflight checks before installing provider. +func PreflightChecks[P generic.Provider](ctx context.Context, phase generic.Group[P]) (ctrl.Result, error) { log := ctrl.LoggerFrom(ctx) log.Info("Performing preflight checks") - spec := provider.GetSpec() + spec := phase.GetProvider().GetSpec() if spec.Version != "" { // Check that the provider version is supported. - if err := checkProviderVersion(ctx, spec.Version, provider); err != nil { - return err - } - } - - // Ensure that the CoreProvider is called "cluster-api". - if util.IsCoreProvider(provider) { - if provider.GetName() != configclient.ClusterAPIProviderName { - conditions.Set(provider, conditions.FalseCondition( - operatorv1.PreflightCheckCondition, - operatorv1.IncorrectCoreProviderNameReason, - clusterv1.ConditionSeverityError, - "%s", fmt.Sprintf(incorrectCoreProviderNameMessage, provider.GetName(), configclient.ClusterAPIProviderName), - )) - - return fmt.Errorf("incorrect CoreProvider name: %s, it should be %s", provider.GetName(), configclient.ClusterAPIProviderName) + if err := checkProviderVersion(ctx, spec.Version, phase.GetProvider()); err != nil { + return ctrl.Result{}, err } } // Check that if a predefined provider is being installed, and if it's not - ensure that FetchConfig is specified. - isPredefinedProvider, err := isPredefinedProvider(ctx, provider.GetName(), util.ClusterctlProviderType(provider)) + isPredefinedProvider, err := isPredefinedProvider(ctx, phase.GetProvider().GetName(), phase.ClusterctlProviderType()) if err != nil { - return fmt.Errorf("failed to generate a list of predefined providers: %w", err) + return ctrl.Result{}, fmt.Errorf("failed to generate a list of predefined providers: %w", err) } if !isPredefinedProvider { @@ -98,29 +78,27 @@ func preflightChecks(ctx context.Context, c client.Client, provider genericprovi "Either Selector, OCI URL or provider URL must be provided for a not predefined provider", )) - return fmt.Errorf("either selector, OCI URL or provider URL must be provided for a not predefined provider %s", provider.GetName()) + return ctrl.Result{}, fmt.Errorf("either selector, OCI URL or provider URL must be provided for a not predefined provider %s", provider.GetName()) } - } - - if spec.FetchConfig != nil && spec.FetchConfig.Selector != nil && spec.FetchConfig.URL != "" { + } else if spec.FetchConfig != nil && spec.FetchConfig.Selector != nil && spec.FetchConfig.URL != "" { // If FetchConfiguration is not nil, exactly one of `URL` or `Selector` must be specified. - conditions.Set(provider, conditions.FalseCondition( + conditions.Set(phase.GetProvider(), conditions.FalseCondition( operatorv1.PreflightCheckCondition, operatorv1.FetchConfigValidationErrorReason, clusterv1.ConditionSeverityError, "Only one of Selector and URL must be provided, not both", )) - return fmt.Errorf("only one of Selector and URL must be provided for provider %s", provider.GetName()) + return ctrl.Result{}, fmt.Errorf("only one of Selector and URL must be provided for provider %s", phase.GetProvider().GetName()) } // Validate that provided GitHub token works and has repository access. if spec.ConfigSecret != nil { secret := &corev1.Secret{} - key := types.NamespacedName{Namespace: provider.GetSpec().ConfigSecret.Namespace, Name: provider.GetSpec().ConfigSecret.Name} + key := types.NamespacedName{Namespace: phase.GetProvider().GetSpec().ConfigSecret.Namespace, Name: phase.GetProvider().GetSpec().ConfigSecret.Name} - if err := c.Get(ctx, key, secret); err != nil { - return fmt.Errorf("failed to get providers secret: %w", err) + if err := phase.GetClient().Get(ctx, key, secret); err != nil { + return ctrl.Result{}, fmt.Errorf("failed to get providers secret: %w", err) } if token, ok := secret.Data[configclient.GitHubTokenVariable]; ok { @@ -128,26 +106,22 @@ func preflightChecks(ctx context.Context, c client.Client, provider genericprovi &oauth2.Token{AccessToken: string(token)}, ))) if _, _, err := githubClient.Organizations.List(ctx, "kubernetes-sigs", nil); err != nil { - conditions.Set(provider, conditions.FalseCondition( + conditions.Set(phase.GetProvider(), conditions.FalseCondition( operatorv1.PreflightCheckCondition, operatorv1.InvalidGithubTokenReason, clusterv1.ConditionSeverityError, "%s", invalidGithubTokenMessage, )) - return fmt.Errorf("failed to validate provided github token: %w", err) + return ctrl.Result{}, fmt.Errorf("failed to validate provided github token: %w", err) } } } - if err := c.List(ctx, providerList); err != nil { - return fmt.Errorf("failed to list providers: %w", err) - } - // Check that no more than one instance of the provider is installed. - for _, p := range providerList.GetItems() { + for _, p := range phase.GetProviderList().GetItems() { // Skip if provider in the list is the same as provider it's compared with. - if p.GetNamespace() == provider.GetNamespace() && p.GetName() == provider.GetName() { + if p.GetNamespace() == phase.GetProvider().GetNamespace() && p.GetName() == phase.GetProvider().GetName() { continue } @@ -158,46 +132,17 @@ func preflightChecks(ctx context.Context, c client.Client, provider genericprovi "", ) - // CoreProvider is a singleton resource, more than one instances should not exist - if util.IsCoreProvider(p) { - log.Info(moreThanOneCoreProviderInstanceExistsMessage) - preflightFalseCondition.Message = moreThanOneCoreProviderInstanceExistsMessage - conditions.Set(provider, preflightFalseCondition) - - return fmt.Errorf("only one instance of CoreProvider is allowed") - } - // For any other provider we should check that instances with similar name exist in any namespace - if p.GetObjectKind().GroupVersionKind().Kind != coreProvider && p.GetName() == provider.GetName() { + if p.GetName() == phase.GetProvider().GetName() { preflightFalseCondition.Message = fmt.Sprintf(moreThanOneProviderInstanceExistsMessage, p.GetName(), p.GetNamespace()) log.Info(preflightFalseCondition.Message) - conditions.Set(provider, preflightFalseCondition) + conditions.Set(phase.GetProvider(), preflightFalseCondition) return fmt.Errorf("only one %s provider is allowed in the cluster", p.GetName()) } } - // Wait for core provider to be ready before we install other providers. - if !util.IsCoreProvider(provider) { - ready, err := coreProviderIsReady(ctx, c) - if err != nil { - return fmt.Errorf("failed to get coreProvider ready condition: %w", err) - } - - if !ready { - log.Info(waitingForCoreProviderReadyMessage) - conditions.Set(provider, conditions.FalseCondition( - operatorv1.PreflightCheckCondition, - operatorv1.WaitingForCoreProviderReadyReason, - clusterv1.ConditionSeverityInfo, - "%s", waitingForCoreProviderReadyMessage, - )) - - return errCoreProviderWait - } - } - - conditions.Set(provider, conditions.TrueCondition(operatorv1.PreflightCheckCondition)) + conditions.Set(phase.GetProvider(), conditions.TrueCondition(operatorv1.PreflightCheckCondition)) log.Info("Preflight checks passed") @@ -205,7 +150,7 @@ func preflightChecks(ctx context.Context, c client.Client, provider genericprovi } // checkProviderVersion verifies that target and installed provider versions are correct. -func checkProviderVersion(ctx context.Context, providerVersion string, provider genericprovider.GenericProvider) error { +func checkProviderVersion[P generic.Provider](ctx context.Context, providerVersion string, provider P) error { log := ctrl.LoggerFrom(ctx) // Check that provider version contains a valid value if it's not empty. @@ -244,23 +189,6 @@ func checkProviderVersion(ctx context.Context, providerVersion string, provider return nil } -// coreProviderIsReady returns true if the core provider is ready. -func coreProviderIsReady(ctx context.Context, c client.Client) (bool, error) { - cpl := &operatorv1.CoreProviderList{} - - if err := c.List(ctx, cpl); err != nil { - return false, err - } - - for _, cp := range cpl.Items { - if conditions.IsTrue(&cp, clusterv1.ReadyCondition) { - return true, nil - } - } - - return false, nil -} - // ignoreCoreProviderWaitError ignores errCoreProviderWait error. func ignoreCoreProviderWaitError(err error) error { if errors.Is(err, errCoreProviderWait) { diff --git a/internal/controller/preflight_checks_test.go b/internal/controller/phases/preflight_checks_test.go similarity index 62% rename from internal/controller/preflight_checks_test.go rename to internal/controller/phases/preflight_checks_test.go index b1e45f5a2..322b7622b 100644 --- a/internal/controller/preflight_checks_test.go +++ b/internal/controller/phases/preflight_checks_test.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package controller +package phases import ( "context" @@ -24,28 +24,480 @@ import ( . "github.com/onsi/gomega" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/rest" + providercontroller "sigs.k8s.io/cluster-api-operator/internal/controller" clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1" + clusterctlv1 "sigs.k8s.io/cluster-api/cmd/clusterctl/api/v1alpha3" + "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/client/fake" operatorv1 "sigs.k8s.io/cluster-api-operator/api/v1alpha2" - "sigs.k8s.io/cluster-api-operator/internal/controller/genericprovider" + "sigs.k8s.io/cluster-api-operator/internal/controller/generic" + "sigs.k8s.io/cluster-api-operator/internal/controller/providers" ) -func TestPreflightChecks(t *testing.T) { +type mockConnector struct { + client.Client +} + +// GetClient implements Connector. +func (m mockConnector) GetClient() client.Client { + return m.Client +} + +// GetConfig implements Connector. +func (m mockConnector) GetConfig() *rest.Config { + return nil +} + +func newConnector(fake client.Client) generic.Connector { + return mockConnector{ + Client: fake, + } +} + +func TestInfrastructurePreflightChecks(t *testing.T) { namespaceName1 := "provider-test-ns-1" namespaceName2 := "provider-test-ns-2" + core := &operatorv1.CoreProvider{ + ObjectMeta: metav1.ObjectMeta{ + Name: "cluster-api", + Namespace: namespaceName2, + }, + TypeMeta: metav1.TypeMeta{ + Kind: "CoreProvider", + APIVersion: "operator.cluster.x-k8s.io/v1alpha4", + }, + Spec: operatorv1.CoreProviderSpec{ + ProviderSpec: operatorv1.ProviderSpec{ + Version: "v1.0.0", + }, + }, + Status: operatorv1.CoreProviderStatus{ + ProviderStatus: operatorv1.ProviderStatus{ + Conditions: []clusterv1.Condition{ + { + Type: clusterv1.ReadyCondition, + Status: corev1.ConditionTrue, + LastTransitionTime: metav1.Now(), + }, + }, + }, + }, + } + + coreNotReady := core.DeepCopy() + coreNotReady.Status = operatorv1.CoreProviderStatus{} + testCases := []struct { name string - providers []operatorv1.GenericProvider - providerList genericprovider.GenericProviderList + providers []*operatorv1.InfrastructureProvider + otherProviders []generic.Provider + expectedCondition clusterv1.Condition + expectedError bool + }{ + { + name: "only one infra provider exists, preflight check passed", + providers: []*operatorv1.InfrastructureProvider{ + { + ObjectMeta: metav1.ObjectMeta{ + Name: "aws", + Namespace: namespaceName1, + }, + TypeMeta: metav1.TypeMeta{ + Kind: "InfrastructureProvider", + APIVersion: "operator.cluster.x-k8s.io/v1alpha1", + }, + Spec: operatorv1.InfrastructureProviderSpec{ + ProviderSpec: operatorv1.ProviderSpec{ + Version: "v1.0.0", + }, + }, + }, + }, + otherProviders: []generic.Provider{ + core, + }, + expectedCondition: clusterv1.Condition{ + Type: operatorv1.PreflightCheckCondition, + Status: corev1.ConditionTrue, + }, + }, + { + name: "missing core provider for one infra, preflight check fails", + providers: []*operatorv1.InfrastructureProvider{ + { + ObjectMeta: metav1.ObjectMeta{ + Name: "aws", + Namespace: namespaceName1, + }, + TypeMeta: metav1.TypeMeta{ + Kind: "InfrastructureProvider", + APIVersion: "operator.cluster.x-k8s.io/v1alpha1", + }, + Spec: operatorv1.InfrastructureProviderSpec{ + ProviderSpec: operatorv1.ProviderSpec{ + Version: "v1.0.0", + }, + }, + }, + }, + expectedCondition: clusterv1.Condition{ + Type: operatorv1.PreflightCheckCondition, + Status: corev1.ConditionFalse, + Message: "Waiting for the core provider to be installed.", + Severity: clusterv1.ConditionSeverityInfo, + }, + }, + { + name: "waiting for ready condtion on core provider for one infra, preflight check fails", + providers: []*operatorv1.InfrastructureProvider{ + { + ObjectMeta: metav1.ObjectMeta{ + Name: "aws", + Namespace: namespaceName1, + }, + TypeMeta: metav1.TypeMeta{ + Kind: "InfrastructureProvider", + APIVersion: "operator.cluster.x-k8s.io/v1alpha1", + }, + Spec: operatorv1.InfrastructureProviderSpec{ + ProviderSpec: operatorv1.ProviderSpec{ + Version: "v1.0.0", + }, + }, + }, + }, + otherProviders: []generic.Provider{ + coreNotReady, + }, + expectedCondition: clusterv1.Condition{ + Type: operatorv1.PreflightCheckCondition, + Status: corev1.ConditionFalse, + Message: "Waiting for the core provider to be installed.", + Severity: clusterv1.ConditionSeverityInfo, + }, + }, + { + name: "two different infra providers exist in same namespaces, preflight check passed", + providers: []*operatorv1.InfrastructureProvider{ + { + ObjectMeta: metav1.ObjectMeta{ + Name: "metal3", + Namespace: namespaceName1, + }, + TypeMeta: metav1.TypeMeta{ + Kind: "InfrastructureProvider", + APIVersion: "operator.cluster.x-k8s.io/v1alpha1", + }, + Spec: operatorv1.InfrastructureProviderSpec{ + ProviderSpec: operatorv1.ProviderSpec{ + Version: "v1.0.0", + }, + }, + }, + { + ObjectMeta: metav1.ObjectMeta{ + Name: "aws", + Namespace: namespaceName1, + }, + TypeMeta: metav1.TypeMeta{ + Kind: "InfrastructureProvider", + APIVersion: "operator.cluster.x-k8s.io/v1alpha1", + }, + Spec: operatorv1.InfrastructureProviderSpec{ + ProviderSpec: operatorv1.ProviderSpec{ + Version: "v1.0.0", + }, + }, + }, + }, + otherProviders: []generic.Provider{ + core, + }, + expectedCondition: clusterv1.Condition{ + Type: operatorv1.PreflightCheckCondition, + Status: corev1.ConditionTrue, + }, + }, + { + name: "two different infra providers exist in different namespaces, preflight check passed", + providers: []*operatorv1.InfrastructureProvider{ + { + ObjectMeta: metav1.ObjectMeta{ + Name: "metal3", + Namespace: namespaceName1, + }, + TypeMeta: metav1.TypeMeta{ + Kind: "InfrastructureProvider", + APIVersion: "operator.cluster.x-k8s.io/v1alpha1", + }, + Spec: operatorv1.InfrastructureProviderSpec{ + ProviderSpec: operatorv1.ProviderSpec{ + Version: "v1.0.0", + }, + }, + }, + { + ObjectMeta: metav1.ObjectMeta{ + Name: "aws", + Namespace: namespaceName2, + }, + TypeMeta: metav1.TypeMeta{ + Kind: "InfrastructureProvider", + APIVersion: "operator.cluster.x-k8s.io/v1alpha1", + }, + Spec: operatorv1.InfrastructureProviderSpec{ + ProviderSpec: operatorv1.ProviderSpec{ + Version: "v1.0.0", + }, + }, + }, + }, + otherProviders: []generic.Provider{ + core, + }, + expectedCondition: clusterv1.Condition{ + Type: operatorv1.PreflightCheckCondition, + Status: corev1.ConditionTrue, + }, + }, + { + name: "two similar infra provider exist in different namespaces, preflight check failed", + expectedError: true, + providers: []*operatorv1.InfrastructureProvider{ + { + ObjectMeta: metav1.ObjectMeta{ + Name: "aws", + Namespace: namespaceName1, + }, + TypeMeta: metav1.TypeMeta{ + Kind: "InfrastructureProvider", + APIVersion: "operator.cluster.x-k8s.io/v1alpha1", + }, + Spec: operatorv1.InfrastructureProviderSpec{ + ProviderSpec: operatorv1.ProviderSpec{ + Version: "v1.0.0", + }, + }, + }, + { + ObjectMeta: metav1.ObjectMeta{ + Name: "aws", + Namespace: namespaceName2, + }, + TypeMeta: metav1.TypeMeta{ + Kind: "InfrastructureProvider", + APIVersion: "operator.cluster.x-k8s.io/v1alpha1", + }, + Spec: operatorv1.InfrastructureProviderSpec{ + ProviderSpec: operatorv1.ProviderSpec{ + Version: "v1.0.0", + }, + }, + }, + }, + otherProviders: []generic.Provider{ + core, + }, + expectedCondition: clusterv1.Condition{ + Type: operatorv1.PreflightCheckCondition, + Reason: operatorv1.MoreThanOneProviderInstanceExistsReason, + Severity: clusterv1.ConditionSeverityError, + Message: fmt.Sprintf("There is already a %s with name %s in the cluster. Only one is allowed.", "aws", namespaceName2), + Status: corev1.ConditionFalse, + }, + }, + { + name: "wrong version, preflight check failed", + expectedError: true, + providers: []*operatorv1.InfrastructureProvider{ + { + ObjectMeta: metav1.ObjectMeta{ + Name: "aws", + Namespace: namespaceName1, + }, + TypeMeta: metav1.TypeMeta{ + Kind: "InfrastructureProvider", + APIVersion: "operator.cluster.x-k8s.io/v1alpha1", + }, + Spec: operatorv1.InfrastructureProviderSpec{ + ProviderSpec: operatorv1.ProviderSpec{ + Version: "one", + }, + }, + }, + }, + otherProviders: []generic.Provider{ + core, + }, + expectedCondition: clusterv1.Condition{ + Type: operatorv1.PreflightCheckCondition, + Reason: operatorv1.IncorrectVersionFormatReason, + Severity: clusterv1.ConditionSeverityError, + Message: "could not parse \"one\" as version", + Status: corev1.ConditionFalse, + }, + }, + { + name: "incorrect fetchConfig, preflight check failed", + expectedError: true, + providers: []*operatorv1.InfrastructureProvider{ + { + ObjectMeta: metav1.ObjectMeta{ + Name: "aws", + Namespace: namespaceName1, + }, + TypeMeta: metav1.TypeMeta{ + Kind: "InfrastructureProvider", + APIVersion: "operator.cluster.x-k8s.io/v1alpha1", + }, + Spec: operatorv1.InfrastructureProviderSpec{ + ProviderSpec: operatorv1.ProviderSpec{ + Version: "v1.0.0", + FetchConfig: &operatorv1.FetchConfiguration{ + URL: "https://example.com", + Selector: &metav1.LabelSelector{ + MatchLabels: map[string]string{"provider-components": "aws"}, + }, + }, + }, + }, + }, + }, + otherProviders: []generic.Provider{ + core, + }, + expectedCondition: clusterv1.Condition{ + Type: operatorv1.PreflightCheckCondition, + Reason: operatorv1.FetchConfigValidationErrorReason, + Severity: clusterv1.ConditionSeverityError, + Message: "Only one of Selector and URL must be provided, not both", + Status: corev1.ConditionFalse, + }, + }, + { + name: "custom Infrastructure Provider without fetch config, preflight check failed", + expectedError: true, + providers: []*operatorv1.InfrastructureProvider{ + { + ObjectMeta: metav1.ObjectMeta{ + Name: "my-custom-aws", + Namespace: namespaceName1, + }, + TypeMeta: metav1.TypeMeta{ + Kind: "InfrastructureProvider", + APIVersion: "operator.cluster.x-k8s.io/v1alpha1", + }, + Spec: operatorv1.InfrastructureProviderSpec{ + ProviderSpec: operatorv1.ProviderSpec{ + Version: "v1.0.0", + }, + }, + }, + }, + otherProviders: []generic.Provider{ + core, + }, + expectedCondition: clusterv1.Condition{ + Type: operatorv1.PreflightCheckCondition, + Reason: operatorv1.FetchConfigValidationErrorReason, + Severity: clusterv1.ConditionSeverityError, + Message: "Either Selector or URL must be provided for a not predefined provider", + Status: corev1.ConditionFalse, + }, + }, + { + name: "custom Infrastructure Provider with fetch config with empty values, preflight check failed", + expectedError: true, + providers: []*operatorv1.InfrastructureProvider{ + { + ObjectMeta: metav1.ObjectMeta{ + Name: "my-custom-aws", + Namespace: namespaceName1, + }, + TypeMeta: metav1.TypeMeta{ + Kind: "InfrastructureProvider", + APIVersion: "operator.cluster.x-k8s.io/v1alpha1", + }, + Spec: operatorv1.InfrastructureProviderSpec{ + ProviderSpec: operatorv1.ProviderSpec{ + Version: "v1.0.0", + FetchConfig: &operatorv1.FetchConfiguration{ + URL: "", + Selector: nil, + }, + }, + }, + }, + }, + otherProviders: []generic.Provider{ + core, + }, + expectedCondition: clusterv1.Condition{ + Type: operatorv1.PreflightCheckCondition, + Reason: operatorv1.FetchConfigValidationErrorReason, + Severity: clusterv1.ConditionSeverityError, + Message: "Either Selector or URL must be provided for a fetchConfig", + Status: corev1.ConditionFalse, + }, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + gs := NewWithT(t) + + fakeclient := fake.NewClientBuilder().WithObjects().Build() + + for _, c := range tc.providers { + gs.Expect(fakeclient.Create(ctx, c)).To(Succeed()) + } + + for _, c := range tc.otherProviders { + gs.Expect(fakeclient.Create(ctx, c.DeepCopyObject().(client.Object))).To(Succeed()) //nolint:forcetypeassert + } + + rec := providercontroller.NewProviderControllerWrapper( + providers.NewInfrastructureProviderReconciler(newConnector(fakeclient)), + NewPhase, + false, + ) + + rec.Reconciler.Init() + + _, err := rec.reconcilePhases(ctx, tc.providers[0], rec.Reconciler.PreflightChecks(context.Background(), tc.providers[0])) + if tc.expectedError { + gs.Expect(err).To(HaveOccurred()) + } else { + gs.Expect(err).ToNot(HaveOccurred()) + } + + // Check if proper condition is returned + gs.Expect(tc.providers[0].GetStatus().Conditions).To(HaveLen(1)) + gs.Expect(tc.providers[0].GetStatus().Conditions[0].Type).To(Equal(tc.expectedCondition.Type)) + gs.Expect(tc.providers[0].GetStatus().Conditions[0].Status).To(Equal(tc.expectedCondition.Status)) + gs.Expect(tc.providers[0].GetStatus().Conditions[0].Message).To(Equal(tc.expectedCondition.Message)) + gs.Expect(tc.providers[0].GetStatus().Conditions[0].Severity).To(Equal(tc.expectedCondition.Severity)) + }) + } +} + +func TestCorePreflightChecks(t *testing.T) { + namespaceName1 := "provider-test-ns-1" + namespaceName2 := "provider-test-ns-2" + + testCases := []struct { + name string + providers []*operatorv1.CoreProvider expectedCondition clusterv1.Condition expectedError bool }{ { name: "only one core provider exists, preflight check passed", - providers: []operatorv1.GenericProvider{ - &operatorv1.CoreProvider{ + providers: []*operatorv1.CoreProvider{ + { ObjectMeta: metav1.ObjectMeta{ Name: "cluster-api", Namespace: namespaceName1, @@ -68,13 +520,12 @@ func TestPreflightChecks(t *testing.T) { Type: operatorv1.PreflightCheckCondition, Status: corev1.ConditionTrue, }, - providerList: &operatorv1.CoreProviderList{}, }, { name: "core provider with incorrect name, preflight check failed", expectedError: true, - providers: []operatorv1.GenericProvider{ - &operatorv1.CoreProvider{ + providers: []*operatorv1.CoreProvider{ + { ObjectMeta: metav1.ObjectMeta{ Name: "my-fancy-cluster-api", Namespace: namespaceName1, @@ -100,13 +551,12 @@ func TestPreflightChecks(t *testing.T) { Message: "Incorrect CoreProvider name: my-fancy-cluster-api. It should be cluster-api", Status: corev1.ConditionFalse, }, - providerList: &operatorv1.CoreProviderList{}, }, { name: "two core providers were created, preflight check failed", expectedError: true, - providers: []operatorv1.GenericProvider{ - &operatorv1.CoreProvider{ + providers: []*operatorv1.CoreProvider{ + { ObjectMeta: metav1.ObjectMeta{ Name: "cluster-api", Namespace: namespaceName1, @@ -121,7 +571,7 @@ func TestPreflightChecks(t *testing.T) { }, }, }, - &operatorv1.CoreProvider{ + { ObjectMeta: metav1.ObjectMeta{ Name: "core-3", Namespace: namespaceName1, @@ -141,16 +591,15 @@ func TestPreflightChecks(t *testing.T) { Type: operatorv1.PreflightCheckCondition, Reason: operatorv1.MoreThanOneProviderInstanceExistsReason, Severity: clusterv1.ConditionSeverityError, - Message: moreThanOneCoreProviderInstanceExistsMessage, + Message: "CoreProvider already exists in the cluster. Only one is allowed.", Status: corev1.ConditionFalse, }, - providerList: &operatorv1.CoreProviderList{}, }, { name: "two core providers in two different namespaces were created, preflight check failed", expectedError: true, - providers: []operatorv1.GenericProvider{ - &operatorv1.CoreProvider{ + providers: []*operatorv1.CoreProvider{ + { ObjectMeta: metav1.ObjectMeta{ Name: "cluster-api", Namespace: namespaceName1, @@ -165,7 +614,7 @@ func TestPreflightChecks(t *testing.T) { }, }, }, - &operatorv1.CoreProvider{ + { ObjectMeta: metav1.ObjectMeta{ Name: "cluster-api", Namespace: namespaceName2, @@ -185,7 +634,7 @@ func TestPreflightChecks(t *testing.T) { Type: operatorv1.PreflightCheckCondition, Reason: operatorv1.MoreThanOneProviderInstanceExistsReason, Severity: clusterv1.ConditionSeverityError, - Message: moreThanOneCoreProviderInstanceExistsMessage, + Message: "CoreProvider already exists in the cluster. Only one is allowed.", Status: corev1.ConditionFalse, }, providerList: &operatorv1.CoreProviderList{}, @@ -503,8 +952,8 @@ func TestPreflightChecks(t *testing.T) { }, { name: "missing version, preflight check passed", - providers: []operatorv1.GenericProvider{ - &operatorv1.CoreProvider{ + providers: []*operatorv1.CoreProvider{ + { ObjectMeta: metav1.ObjectMeta{ Name: "cluster-api", Namespace: namespaceName1, @@ -526,47 +975,11 @@ func TestPreflightChecks(t *testing.T) { Type: operatorv1.PreflightCheckCondition, Status: corev1.ConditionTrue, }, - providerList: &operatorv1.CoreProviderList{}, - }, - { - name: "incorrect fetchConfig, preflight check failed", - expectedError: true, - providers: []operatorv1.GenericProvider{ - &operatorv1.InfrastructureProvider{ - ObjectMeta: metav1.ObjectMeta{ - Name: "aws", - Namespace: namespaceName1, - }, - TypeMeta: metav1.TypeMeta{ - Kind: "InfrastructureProvider", - APIVersion: "operator.cluster.x-k8s.io/v1alpha1", - }, - Spec: operatorv1.InfrastructureProviderSpec{ - ProviderSpec: operatorv1.ProviderSpec{ - Version: "v1.0.0", - FetchConfig: &operatorv1.FetchConfiguration{ - URL: "https://example.com", - Selector: &metav1.LabelSelector{ - MatchLabels: map[string]string{"provider-components": "aws"}, - }, - }, - }, - }, - }, - }, - expectedCondition: clusterv1.Condition{ - Type: operatorv1.PreflightCheckCondition, - Reason: operatorv1.FetchConfigValidationErrorReason, - Severity: clusterv1.ConditionSeverityError, - Message: "Only one of Selector and URL must be provided, not both", - Status: corev1.ConditionFalse, - }, - providerList: &operatorv1.InfrastructureProviderList{}, }, { - name: "predefined core provider without fetch config, preflight check passed", - providers: []operatorv1.GenericProvider{ - &operatorv1.CoreProvider{ + name: "predefined Core Provider without fetch config, preflight check passed", + providers: []*operatorv1.CoreProvider{ + { ObjectMeta: metav1.ObjectMeta{ Name: "cluster-api", Namespace: namespaceName1, @@ -586,19 +999,18 @@ func TestPreflightChecks(t *testing.T) { Type: operatorv1.PreflightCheckCondition, Status: corev1.ConditionTrue, }, - providerList: &operatorv1.CoreProviderList{}, }, { - name: "custom Infrastructure Provider without fetch config, preflight check failed", + name: "custom Core Provider with fetch config with empty values, preflight check failed (similar to secondary providers)", expectedError: true, - providers: []operatorv1.GenericProvider{ - &operatorv1.InfrastructureProvider{ + providers: []*operatorv1.CoreProvider{ + { ObjectMeta: metav1.ObjectMeta{ - Name: "my-custom-aws", + Name: "cluster-api", Namespace: namespaceName1, }, TypeMeta: metav1.TypeMeta{ - Kind: "InfrastructureProvider", + Kind: "CoreProvider", APIVersion: "operator.cluster.x-k8s.io/v1alpha1", }, Spec: operatorv1.InfrastructureProviderSpec{ @@ -648,7 +1060,6 @@ func TestPreflightChecks(t *testing.T) { Message: "Either Selector, OCI URL or provider URL must be provided for a not predefined provider", Status: corev1.ConditionFalse, }, - providerList: &operatorv1.CoreProviderList{}, }, } @@ -662,7 +1073,14 @@ func TestPreflightChecks(t *testing.T) { gs.Expect(fakeClient.Create(ctx, c)).To(Succeed()) } - err := preflightChecks(context.Background(), fakeClient, tc.providers[0], tc.providerList) + rec := NewProviderControllerWrapper( + providers.NewCoreProviderReconciler(newConnector(fakeclient)), + phases.NewPhase, + false, + ) + + rec.Reconciler.Init() + _, err := rec.reconcilePhases(ctx, tc.providers[0], rec.Reconciler.PreflightChecks(context.Background(), tc.providers[0])) if tc.expectedError { gs.Expect(err).To(HaveOccurred()) } else { @@ -759,7 +1177,12 @@ func TestPreflightChecksUpgradesDowngrades(t *testing.T) { gs.Expect(fakeClient.Create(ctx, provider)).To(Succeed()) - err := preflightChecks(context.Background(), fakeClient, provider, &operatorv1.CoreProviderList{}) + _, err := phases.PreflightChecks(context.Background(), phases.Phase[operatorv1.GenericProvider]{ + Client: fakeClient, + Provider: provider, + ProviderList: &operatorv1.CoreProviderList{}, + ClusterctlProvider: &clusterctlv1.Provider{}, + }) if tc.expectedError { gs.Expect(err).To(HaveOccurred()) } else { diff --git a/internal/controller/phases/suite_test.go b/internal/controller/phases/suite_test.go new file mode 100644 index 000000000..e30b2c276 --- /dev/null +++ b/internal/controller/phases/suite_test.go @@ -0,0 +1,71 @@ +/* +Copyright 2021 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package phases + +import ( + "fmt" + "os" + "testing" + + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/runtime" + utilruntime "k8s.io/apimachinery/pkg/util/runtime" + operatorv1 "sigs.k8s.io/cluster-api-operator/api/v1alpha2" + "sigs.k8s.io/cluster-api-operator/internal/envtest" + + clusterctlv1 "sigs.k8s.io/cluster-api/cmd/clusterctl/api/v1alpha3" + ctrl "sigs.k8s.io/controller-runtime" +) + +var ( + env *envtest.Environment + ctx = ctrl.SetupSignalHandler() + + testNamespaceName = "test-namespace" +) + +func setupScheme() *runtime.Scheme { + scheme := runtime.NewScheme() + utilruntime.Must(corev1.AddToScheme(scheme)) + utilruntime.Must(operatorv1.AddToScheme(scheme)) + utilruntime.Must(clusterctlv1.AddToScheme(scheme)) + + return scheme +} + +func TestMain(m *testing.M) { + fmt.Println("Creating new test environment") + + env = envtest.New() + + go func() { + if err := env.Start(ctx); err != nil { + panic(fmt.Sprintf("Failed to start the envtest manager: %v", err)) + } + }() + <-env.Manager.Elected() + + // Run tests + code := m.Run() + // Tearing down the test environment + if err := env.Stop(); err != nil { + panic(fmt.Sprintf("Failed to stop the envtest: %v", err)) + } + + // Report exit code + os.Exit(code) +} diff --git a/internal/controller/genericprovider_controller.go b/internal/controller/provider_controller_wrapper.go similarity index 58% rename from internal/controller/genericprovider_controller.go rename to internal/controller/provider_controller_wrapper.go index d2fc49e0a..d606eaec7 100644 --- a/internal/controller/genericprovider_controller.go +++ b/internal/controller/provider_controller_wrapper.go @@ -26,12 +26,12 @@ import ( "reflect" corev1 "k8s.io/api/core/v1" - apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + kerrors "k8s.io/apimachinery/pkg/util/errors" - "k8s.io/client-go/rest" operatorv1 "sigs.k8s.io/cluster-api-operator/api/v1alpha2" - "sigs.k8s.io/cluster-api-operator/internal/controller/genericprovider" + "sigs.k8s.io/cluster-api-operator/internal/controller/generic" + "sigs.k8s.io/cluster-api-operator/internal/controller/phases" clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1" "sigs.k8s.io/cluster-api/util/conditions" "sigs.k8s.io/cluster-api/util/patch" @@ -43,66 +43,63 @@ import ( "sigs.k8s.io/controller-runtime/pkg/reconcile" ) -type GenericProviderReconciler struct { - Provider genericprovider.GenericProvider - ProviderList genericprovider.GenericProviderList - Client client.Client - Config *rest.Config +type ProviderControllerWrapper[P generic.Provider, R generic.ProviderReconciler[P]] struct { + Reconciler R + NewGroup generic.NewGroup[P] WatchConfigSecretChanges bool } +func NewProviderControllerWrapper[P generic.Provider, R generic.ProviderReconciler[P]](rec R, groupFn generic.NewGroup[P], watchConfigSecretChanges bool) *ProviderControllerWrapper[P, R] { + return &ProviderControllerWrapper[P, R]{ + Reconciler: rec, + NewGroup: groupFn, + WatchConfigSecretChanges: watchConfigSecretChanges, + } +} + const ( appliedSpecHashAnnotation = "operator.cluster.x-k8s.io/applied-spec-hash" ) -func (r *GenericProviderReconciler) SetupWithManager(ctx context.Context, mgr ctrl.Manager, options controller.Options) error { +func (r *ProviderControllerWrapper[P, R]) SetupWithManager(ctx context.Context, mgr ctrl.Manager, options controller.Options) error { + provider := reflect.New(reflect.TypeOf(*new(P)).Elem()).Interface().(P) //nolint:forcetypeassert builder := ctrl.NewControllerManagedBy(mgr). - For(r.Provider) + For(provider). + WithOptions(options) if r.WatchConfigSecretChanges { - if err := mgr.GetFieldIndexer().IndexField(ctx, r.Provider, configSecretNameField, configSecretNameIndexFunc); err != nil { + if err := mgr.GetFieldIndexer().IndexField(ctx, provider, configSecretNameField, configSecretNameIndexFunc); err != nil { return err } - if err := mgr.GetFieldIndexer().IndexField(ctx, r.Provider, configSecretNamespaceField, configSecretNamespaceIndexFunc); err != nil { + if err := mgr.GetFieldIndexer().IndexField(ctx, provider, configSecretNamespaceField, configSecretNamespaceIndexFunc); err != nil { return err } builder.Watches( &corev1.Secret{}, - handler.EnqueueRequestsFromMapFunc(newSecretToProviderFuncMapForProviderList(r.Client, r.ProviderList)), + handler.EnqueueRequestsFromMapFunc(newSecretToProviderFuncMapForProviderList(mgr.GetClient(), r.Reconciler.GetProviderList())), ) } // We don't want to receive secondary events from the CoreProvider for itself. - if reflect.TypeOf(r.Provider) != reflect.TypeOf(genericprovider.GenericProvider(&operatorv1.CoreProvider{})) { + if reflect.TypeOf(provider) != reflect.TypeOf(&operatorv1.CoreProvider{}) { builder.Watches( &operatorv1.CoreProvider{}, - handler.EnqueueRequestsFromMapFunc(newCoreProviderToProviderFuncMapForProviderList(r.Client, r.ProviderList)), + handler.EnqueueRequestsFromMapFunc(newCoreProviderToProviderFuncMapForProviderList(mgr.GetClient(), r.Reconciler.GetProviderList())), ) } - return builder.WithOptions(options). - Complete(r) + return builder.Complete(reconcile.AsReconciler(mgr.GetClient(), r)) } -func (r *GenericProviderReconciler) Reconcile(ctx context.Context, req reconcile.Request) (_ reconcile.Result, reterr error) { +func (r *ProviderControllerWrapper[P, R]) Reconcile(ctx context.Context, provider P) (_ reconcile.Result, reterr error) { log := ctrl.LoggerFrom(ctx) log.Info("Reconciling provider") - if err := r.Client.Get(ctx, req.NamespacedName, r.Provider); err != nil { - if apierrors.IsNotFound(err) { - // Object not found, return. Created objects are automatically garbage collected. - // For additional cleanup logic use finalizers. - return ctrl.Result{}, nil - } - // Error reading the object - requeue the request. - return ctrl.Result{}, err - } - // Initialize the patch helper - patchHelper, err := patch.NewHelper(r.Provider, r.Client) + patchHelper, err := patch.NewHelper(provider, r.Reconciler.GetClient()) if err != nil { return ctrl.Result{}, err } @@ -115,36 +112,36 @@ func (r *GenericProviderReconciler) Reconcile(ctx context.Context, req reconcile patchOpts = append(patchOpts, patch.WithStatusObservedGeneration{}) } - if err := patchProvider(ctx, r.Provider, patchHelper, patchOpts...); err != nil { + if err := patchProvider(ctx, provider, patchHelper, patchOpts...); err != nil { reterr = kerrors.NewAggregate([]error{reterr, err}) } }() // Add finalizer first if not exist to avoid the race condition between init and delete - if !controllerutil.ContainsFinalizer(r.Provider, operatorv1.ProviderFinalizer) { - controllerutil.AddFinalizer(r.Provider, operatorv1.ProviderFinalizer) + if !controllerutil.ContainsFinalizer(provider, operatorv1.ProviderFinalizer) { + controllerutil.AddFinalizer(provider, operatorv1.ProviderFinalizer) return ctrl.Result{}, nil } // Handle deletion reconciliation loop. - if !r.Provider.GetDeletionTimestamp().IsZero() { - return r.reconcileDelete(ctx, r.Provider) + if !provider.GetDeletionTimestamp().IsZero() { + return r.reconcileDelete(ctx, provider) } // Check if spec hash stays the same and don't go further in this case. - specHash, err := calculateHash(ctx, r.Client, r.Provider) + specHash, err := calculateHash(ctx, r.Reconciler.GetClient(), r.Provider) if err != nil { return ctrl.Result{}, err } - if r.Provider.GetAnnotations()[appliedSpecHashAnnotation] == specHash { + if provider.GetAnnotations()[appliedSpecHashAnnotation] == specHash { log.Info("No changes detected, skipping further steps") return ctrl.Result{}, nil } - res, err := r.reconcile(ctx, r.Provider, r.ProviderList) + res, err := r.reconcileNormal(ctx, provider) - annotations := r.Provider.GetAnnotations() + annotations := provider.GetAnnotations() if annotations == nil { annotations = map[string]string{} } @@ -152,7 +149,7 @@ func (r *GenericProviderReconciler) Reconcile(ctx context.Context, req reconcile // Set the spec hash annotation if reconciliation was successful or reset it otherwise. if res.IsZero() && err == nil { // Recalculate spec hash in case it was changed during reconciliation process. - specHash, err := calculateHash(ctx, r.Client, r.Provider) + specHash, err := calculateHash(ctx, r.Reconciler.GetClient(), r.Provider) if err != nil { return ctrl.Result{}, err } @@ -162,7 +159,7 @@ func (r *GenericProviderReconciler) Reconcile(ctx context.Context, req reconcile annotations[appliedSpecHashAnnotation] = "" } - r.Provider.SetAnnotations(annotations) + provider.SetAnnotations(annotations) return res, ignoreCoreProviderWaitError(err) } @@ -178,27 +175,26 @@ func patchProvider(ctx context.Context, provider operatorv1.GenericProvider, pat return patchHelper.Patch(ctx, provider, options...) } -func (r *GenericProviderReconciler) reconcile(ctx context.Context, provider genericprovider.GenericProvider, genericProviderList genericprovider.GenericProviderList) (ctrl.Result, error) { - reconciler := newPhaseReconciler(*r, provider, genericProviderList) - phases := []reconcilePhaseFn{ - reconciler.preflightChecks, - reconciler.initializePhaseReconciler, - reconciler.downloadManifests, - reconciler.load, - reconciler.fetch, - reconciler.upgrade, - reconciler.install, - reconciler.reportStatus, - } +func (r *ProviderControllerWrapper[P, R]) reconcileNormal(ctx context.Context, provider P) (ctrl.Result, error) { + r.Reconciler.Init() - res := reconcile.Result{} + phases := r.Reconciler.PreflightChecks(ctx, provider) + phases = append(phases, r.Reconciler.ReconcileNormal(ctx, provider)...) + phases = append(phases, r.Reconciler.ReportStatus(ctx, provider)...) - var err error + return r.reconcilePhases(ctx, provider, phases) +} - for _, phase := range phases { - res, err = phase(ctx) +func (r *ProviderControllerWrapper[P, R]) reconcilePhases(ctx context.Context, provider P, p []generic.ReconcileFn[P, generic.Group[P]]) (res ctrl.Result, err error) { + providerList := r.Reconciler.GetProviderList() + if err := r.Reconciler.GetClient().List(ctx, providerList); err != nil { + return ctrl.Result{}, fmt.Errorf("failed to list providers: %w", err) + } + + for _, phase := range p { + res, err = phase(ctx, r.NewGroup(provider, providerList, r.Reconciler)) if err != nil { - var pe *PhaseError + var pe *phases.PhaseError if errors.As(err, &pe) { conditions.Set(provider, conditions.FalseCondition(pe.Type, pe.Reason, pe.Severity, "%s", err.Error())) } @@ -213,41 +209,19 @@ func (r *GenericProviderReconciler) reconcile(ctx context.Context, provider gene return res, nil } -func (r *GenericProviderReconciler) reconcileDelete(ctx context.Context, provider operatorv1.GenericProvider) (ctrl.Result, error) { +func (r *ProviderControllerWrapper[P, R]) reconcileDelete(ctx context.Context, provider P) (ctrl.Result, error) { log := ctrl.LoggerFrom(ctx) log.Info("Deleting provider resources") - reconciler := newPhaseReconciler(*r, provider, nil) - phases := []reconcilePhaseFn{ - reconciler.delete, - } - - res := reconcile.Result{} - - var err error - - for _, phase := range phases { - res, err = phase(ctx) - if err != nil { - var pe *PhaseError - if errors.As(err, &pe) { - conditions.Set(provider, conditions.FalseCondition(pe.Type, pe.Reason, pe.Severity, "%s", err.Error())) - } - } - - if !res.IsZero() || err != nil { - // the steps are sequential, so we must be complete before progressing. - return res, err - } - } + r.Reconciler.Init() controllerutil.RemoveFinalizer(provider, operatorv1.ProviderFinalizer) - return res, nil + return r.reconcilePhases(ctx, provider, r.Reconciler.ReconcileDelete(ctx, provider)) } -func addConfigSecretToHash(ctx context.Context, k8sClient client.Client, hash hash.Hash, provider genericprovider.GenericProvider) error { +func addConfigSecretToHash(ctx context.Context, k8sClient client.Client, hash hash.Hash, provider generic.Provider) error { if provider.GetSpec().ConfigSecret != nil { secret := &corev1.Secret{ ObjectMeta: metav1.ObjectMeta{ @@ -288,7 +262,7 @@ func addObjectToHash(hash hash.Hash, object interface{}) error { return nil } -func calculateHash(ctx context.Context, k8sClient client.Client, provider genericprovider.GenericProvider) (string, error) { +func calculateHash(ctx context.Context, k8sClient client.Client, provider generic.Provider) (string, error) { hash := sha256.New() err := addObjectToHash(hash, provider.GetSpec()) diff --git a/internal/controller/genericprovider_controller_test.go b/internal/controller/provider_controller_wrapper_test.go similarity index 92% rename from internal/controller/genericprovider_controller_test.go rename to internal/controller/provider_controller_wrapper_test.go index f6d6f4b17..f1d82c8bc 100644 --- a/internal/controller/genericprovider_controller_test.go +++ b/internal/controller/provider_controller_wrapper_test.go @@ -25,17 +25,14 @@ import ( appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" - utilruntime "k8s.io/apimachinery/pkg/util/runtime" "k8s.io/utils/ptr" clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1" - clusterctlv1 "sigs.k8s.io/cluster-api/cmd/clusterctl/api/v1alpha3" "sigs.k8s.io/cluster-api/util/conditions" "sigs.k8s.io/cluster-api/util/patch" "sigs.k8s.io/controller-runtime/pkg/client" operatorv1 "sigs.k8s.io/cluster-api-operator/api/v1alpha2" - "sigs.k8s.io/cluster-api-operator/internal/controller/genericprovider" + "sigs.k8s.io/cluster-api-operator/internal/controller/generic" ) const ( @@ -82,7 +79,7 @@ spec: testCurrentVersion = "v0.4.2" ) -func insertDummyConfig(provider genericprovider.GenericProvider) { +func insertDummyConfig(provider generic.Provider) { spec := provider.GetSpec() spec.FetchConfig = &operatorv1.FetchConfiguration{ Selector: &metav1.LabelSelector{ @@ -110,7 +107,7 @@ func dummyConfigMap(ns string) *corev1.ConfigMap { } } -func createDummyProviderWithConfigSecret(objs []client.Object, provider genericprovider.GenericProvider, configSecret *corev1.Secret) ([]client.Object, error) { +func createDummyProviderWithConfigSecret(objs []client.Object, provider generic.Provider, configSecret *corev1.Secret) ([]client.Object, error) { cm := dummyConfigMap(provider.GetNamespace()) if err := env.CreateAndWait(ctx, cm); err != nil { @@ -222,12 +219,12 @@ func TestReconcilerPreflightConditions(t *testing.T) { testCases := []struct { name string namespace string - providers []genericprovider.GenericProvider + providers []generic.Provider }{ { name: "preflight conditions for CoreProvider", namespace: "test-core-provider", - providers: []genericprovider.GenericProvider{ + providers: []generic.Provider{ &operatorv1.CoreProvider{ ObjectMeta: metav1.ObjectMeta{ Name: "cluster-api", @@ -243,7 +240,7 @@ func TestReconcilerPreflightConditions(t *testing.T) { { name: "preflight conditions for ControlPlaneProvider", namespace: "test-cp-provider", - providers: []genericprovider.GenericProvider{ + providers: []generic.Provider{ &operatorv1.CoreProvider{ ObjectMeta: metav1.ObjectMeta{ Name: "cluster-api", @@ -365,32 +362,60 @@ releaseSeries: newVersion: "v999.9.1", }, } + g := NewWithT(t) + + core := &operatorv1.CoreProvider{ + ObjectMeta: metav1.ObjectMeta{ + Name: "cluster-api", + }, + Spec: operatorv1.CoreProviderSpec{ + ProviderSpec: operatorv1.ProviderSpec{ + Version: "v999.9.3", + }, + }, + } + + namespace := "test-upgrades-downgrades" + + t.Log("Ensure namespace exists", namespace) + g.Expect(env.EnsureNamespaceExists(ctx, namespace)).To(Succeed()) + + insertDummyConfig(core) + core.SetNamespace(namespace) + t.Log("creating core provider", core.GetName()) + g.Expect(env.CreateAndWait(ctx, dummyFutureConfigMap(namespace, "v999.9.3"))).To(Succeed()) + g.Expect(env.CreateAndWait(ctx, core)).To(Succeed()) + + g.Eventually(func() error { + if err := env.Get(ctx, client.ObjectKeyFromObject(core), core); err != nil { + return err + } + + conditions.MarkTrue(core, clusterv1.ReadyCondition) + + return env.Status().Update(ctx, core) + }).Should(Succeed()) for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - g := NewWithT(t) - - provider := &operatorv1.CoreProvider{ + provider := &operatorv1.InfrastructureProvider{ ObjectMeta: metav1.ObjectMeta{ - Name: "cluster-api", + Name: "docker", }, - Spec: operatorv1.CoreProviderSpec{ + Spec: operatorv1.InfrastructureProviderSpec{ ProviderSpec: operatorv1.ProviderSpec{ Version: currentVersion, }, }, } - namespace := "test-upgrades-downgrades" - - t.Log("Ensure namespace exists", namespace) - g.Expect(env.EnsureNamespaceExists(ctx, namespace)).To(Succeed()) - - g.Expect(env.CreateAndWait(ctx, dummyFutureConfigMap(namespace, currentVersion))).To(Succeed()) + ns, err := env.CreateNamespace(ctx, "infra") + g.Expect(err).ToNot(HaveOccurred()) - insertDummyConfig(provider) - provider.SetNamespace(namespace) t.Log("creating test provider", provider.GetName()) + provider.SetNamespace(ns.Name) + insertDummyConfig(provider) + g.Expect(env.CreateAndWait(ctx, dummyFutureConfigMap(ns.Name, currentVersion))).To(Succeed()) g.Expect(env.CreateAndWait(ctx, provider)).To(Succeed()) defer func() { @@ -404,6 +429,7 @@ releaseSeries: } if provider.GetStatus().InstalledVersion == nil || *provider.GetStatus().InstalledVersion != currentVersion { + t.Log(t.Name(), provider.GetName(), provider.GetStatus().InstalledVersion) return false } @@ -421,7 +447,7 @@ releaseSeries: // creating another configmap with another version if tc.newVersion != currentVersion { - g.Expect(env.CreateAndWait(ctx, dummyFutureConfigMap(namespace, tc.newVersion))).To(Succeed()) + g.Expect(env.CreateAndWait(ctx, dummyFutureConfigMap(ns.Name, tc.newVersion))).To(Succeed()) } // Change provider version @@ -441,7 +467,9 @@ releaseSeries: labels["provider-version"] = tc.newVersion provider.SetLabels(labels) - g.Expect(env.Client.Update(ctx, provider)).To(Succeed()) + g.Eventually(func() error { + return env.Client.Update(ctx, provider.DeepCopy()) + }, timeout).Should(Succeed()) g.Eventually(func() bool { if err := env.Get(ctx, client.ObjectKeyFromObject(provider), provider); err != nil { @@ -601,7 +629,7 @@ func TestReconcilerPreflightConditionsFromCoreProviderEvents(t *testing.T) { g.Expect(env.CreateAndWait(ctx, dummyConfigMap(namespace))).To(Succeed()) - for _, p := range []genericprovider.GenericProvider{coreProvider, infrastructureProvider} { + for _, p := range []generic.Provider{coreProvider, infrastructureProvider} { insertDummyConfig(p) p.SetNamespace(namespace) t.Log("creating test provider", p.GetName()) @@ -960,7 +988,7 @@ func TestProviderSpecChanges(t *testing.T) { } } -func generateExpectedResultChecker(provider genericprovider.GenericProvider, specHash string, condStatus corev1.ConditionStatus) func() bool { +func generateExpectedResultChecker(provider generic.Provider, specHash string, condStatus corev1.ConditionStatus) func() bool { return func() bool { if err := env.Get(ctx, client.ObjectKeyFromObject(provider), provider); err != nil { return false @@ -976,12 +1004,3 @@ func generateExpectedResultChecker(provider genericprovider.GenericProvider, spe return condition != nil && condition.Status == condStatus } } - -func setupScheme() *runtime.Scheme { - scheme := runtime.NewScheme() - utilruntime.Must(corev1.AddToScheme(scheme)) - utilruntime.Must(operatorv1.AddToScheme(scheme)) - utilruntime.Must(clusterctlv1.AddToScheme(scheme)) - - return scheme -} diff --git a/internal/controller/providers/addon.go b/internal/controller/providers/addon.go new file mode 100644 index 000000000..4742c75b1 --- /dev/null +++ b/internal/controller/providers/addon.go @@ -0,0 +1,62 @@ +/* +Copyright 2024 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package providers + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + "k8s.io/utils/ptr" + operatorv1 "sigs.k8s.io/cluster-api-operator/api/v1alpha2" + "sigs.k8s.io/cluster-api-operator/internal/controller/generic" + "sigs.k8s.io/cluster-api-operator/util" + clusterctlv1 "sigs.k8s.io/cluster-api/cmd/clusterctl/api/v1alpha3" +) + +type AddonProviderReconciler struct { + *CommonProviderReconciler[*operatorv1.AddonProvider] +} + +func NewAddonProviderReconciler(conn generic.Connector) generic.ProviderReconciler[*operatorv1.AddonProvider] { + return &AddonProviderReconciler{ + CommonProviderReconciler: NewCommonProviderReconciler[*operatorv1.AddonProvider](conn), + } +} + +// ClusterctlProviderType returns ProviderType for the underlying clusterctl provider. +func (r *AddonProviderReconciler) ClusterctlProviderType() clusterctlv1.ProviderType { + return clusterctlv1.AddonProviderType +} + +// ClusterctlProvider returns Provider structure of the underlying clusterctl provider. +func (r *AddonProviderReconciler) ClusterctlProvider(provider *operatorv1.AddonProvider) *clusterctlv1.Provider { + clusterctlProvider := &clusterctlv1.Provider{ + ObjectMeta: metav1.ObjectMeta{ + Name: "addon-" + provider.GetName(), + Namespace: provider.GetNamespace(), + }, + Type: string(r.ClusterctlProviderType()), + ProviderName: provider.GetName(), + Version: *util.Or(provider.GetStatus().InstalledVersion, ptr.To("")), + } + + return clusterctlProvider +} + +// GetProviderList returns empty typed list for provider. +func (r *AddonProviderReconciler) GetProviderList() generic.ProviderList { + return &operatorv1.AddonProviderList{} +} diff --git a/internal/controller/providers/bootstrap.go b/internal/controller/providers/bootstrap.go new file mode 100644 index 000000000..00dddae0d --- /dev/null +++ b/internal/controller/providers/bootstrap.go @@ -0,0 +1,62 @@ +/* +Copyright 2024 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package providers + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + "k8s.io/utils/ptr" + operatorv1 "sigs.k8s.io/cluster-api-operator/api/v1alpha2" + "sigs.k8s.io/cluster-api-operator/internal/controller/generic" + "sigs.k8s.io/cluster-api-operator/util" + clusterctlv1 "sigs.k8s.io/cluster-api/cmd/clusterctl/api/v1alpha3" +) + +type BootstrapProviderReconciler struct { + *CommonProviderReconciler[*operatorv1.BootstrapProvider] +} + +func NewBootstrapProviderReconciler(conn generic.Connector) generic.ProviderReconciler[*operatorv1.BootstrapProvider] { + return &BootstrapProviderReconciler{ + CommonProviderReconciler: NewCommonProviderReconciler[*operatorv1.BootstrapProvider](conn), + } +} + +// ClusterctlProviderType returns ProviderType for the underlying clusterctl provider. +func (r *BootstrapProviderReconciler) ClusterctlProviderType() clusterctlv1.ProviderType { + return clusterctlv1.BootstrapProviderType +} + +// ClusterctlProvider returns Provider structure of the underlying clusterctl provider. +func (r *BootstrapProviderReconciler) ClusterctlProvider(provider *operatorv1.BootstrapProvider) *clusterctlv1.Provider { + clusterctlProvider := &clusterctlv1.Provider{ + ObjectMeta: metav1.ObjectMeta{ + Name: "bootstrap-" + provider.GetName(), + Namespace: provider.GetNamespace(), + }, + Type: string(r.ClusterctlProviderType()), + ProviderName: provider.GetName(), + Version: *util.Or(provider.GetStatus().InstalledVersion, ptr.To("")), + } + + return clusterctlProvider +} + +// GetProviderList returns empty typed list for provider. +func (r *BootstrapProviderReconciler) GetProviderList() generic.ProviderList { + return &operatorv1.BootstrapProviderList{} +} diff --git a/internal/controller/providers/consts.go b/internal/controller/providers/consts.go new file mode 100644 index 000000000..678a40bf8 --- /dev/null +++ b/internal/controller/providers/consts.go @@ -0,0 +1,56 @@ +/* +Copyright 2024 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package providers + +import ( + "time" + + "k8s.io/client-go/rest" + "sigs.k8s.io/cluster-api-operator/internal/controller/generic" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +const ( + // preflightFailedRequeueAfter is how long to wait before trying to reconcile + // if some preflight check has failed. + preflightFailedRequeueAfter = 30 * time.Second + + incorrectCoreProviderNameMessage = "Incorrect CoreProvider name: %s. It should be %s" + moreThanOneCoreProviderInstanceExistsMessage = "CoreProvider already exists in the cluster. Only one is allowed." + waitingForCoreProviderReadyMessage = "Waiting for the core provider to be installed." +) + +type ConnectorStub struct{} + +// GetClient implements generic.Connector. +func (c ConnectorStub) GetClient() client.Client { + return nil +} + +// GetConfig implements generic.Connector. +func (c ConnectorStub) GetConfig() *rest.Config { + return nil +} + +func init() { + generic.ProviderReconcilers[(&CoreProviderReconciler{}).ClusterctlProviderType()] = NewCoreProviderReconciler(ConnectorStub{}) + generic.ProviderReconcilers[(&InfrastructureProviderReconciler{}).ClusterctlProviderType()] = NewInfrastructureProviderReconciler(ConnectorStub{}) + generic.ProviderReconcilers[(&BootstrapProviderReconciler{}).ClusterctlProviderType()] = NewBootstrapProviderReconciler(ConnectorStub{}) + generic.ProviderReconcilers[(&ControlPlaneProviderReconciler{}).ClusterctlProviderType()] = NewControlPlaneProviderReconciler(ConnectorStub{}) + generic.ProviderReconcilers[(&AddonProviderReconciler{}).ClusterctlProviderType()] = NewAddonProviderReconciler(ConnectorStub{}) + generic.ProviderReconcilers[(&IPAMProviderReconciler{}).ClusterctlProviderType()] = NewIPAMProviderReconciler(ConnectorStub{}) +} diff --git a/internal/controller/providers/control_plane.go b/internal/controller/providers/control_plane.go new file mode 100644 index 000000000..75f3c3c84 --- /dev/null +++ b/internal/controller/providers/control_plane.go @@ -0,0 +1,61 @@ +/* +Copyright 2021 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package providers + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/utils/ptr" + operatorv1 "sigs.k8s.io/cluster-api-operator/api/v1alpha2" + "sigs.k8s.io/cluster-api-operator/internal/controller/generic" + "sigs.k8s.io/cluster-api-operator/util" + clusterctlv1 "sigs.k8s.io/cluster-api/cmd/clusterctl/api/v1alpha3" +) + +type ControlPlaneProviderReconciler struct { + *CommonProviderReconciler[*operatorv1.ControlPlaneProvider] +} + +func NewControlPlaneProviderReconciler(conn generic.Connector) generic.ProviderReconciler[*operatorv1.ControlPlaneProvider] { + return &ControlPlaneProviderReconciler{ + CommonProviderReconciler: NewCommonProviderReconciler[*operatorv1.ControlPlaneProvider](conn), + } +} + +// ClusterctlProviderType returns ProviderType for the underlying clusterctl provider. +func (r *ControlPlaneProviderReconciler) ClusterctlProviderType() clusterctlv1.ProviderType { + return clusterctlv1.ControlPlaneProviderType +} + +// ClusterctlProvider returns Provider structure of the underlying clusterctl provider. +func (r *ControlPlaneProviderReconciler) ClusterctlProvider(provider *operatorv1.ControlPlaneProvider) *clusterctlv1.Provider { + clusterctlProvider := &clusterctlv1.Provider{ + ObjectMeta: metav1.ObjectMeta{ + Name: "control-plane-" + provider.GetName(), + Namespace: provider.GetNamespace(), + }, + Type: string(r.ClusterctlProviderType()), + ProviderName: provider.GetName(), + Version: *util.Or(provider.GetStatus().InstalledVersion, ptr.To("")), + } + + return clusterctlProvider +} + +// GetProviderList returns empty typed list for provider. +func (r *ControlPlaneProviderReconciler) GetProviderList() generic.ProviderList { + return &operatorv1.ControlPlaneProviderList{} +} diff --git a/internal/controller/providers/core.go b/internal/controller/providers/core.go new file mode 100644 index 000000000..8f1adb0fa --- /dev/null +++ b/internal/controller/providers/core.go @@ -0,0 +1,117 @@ +/* +Copyright 2021 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package providers + +import ( + "context" + "fmt" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/utils/ptr" + operatorv1 "sigs.k8s.io/cluster-api-operator/api/v1alpha2" + "sigs.k8s.io/cluster-api-operator/internal/controller/generic" + "sigs.k8s.io/cluster-api-operator/util" + clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1" + clusterctlv1 "sigs.k8s.io/cluster-api/cmd/clusterctl/api/v1alpha3" + configclient "sigs.k8s.io/cluster-api/cmd/clusterctl/client/config" + "sigs.k8s.io/cluster-api/util/conditions" + ctrl "sigs.k8s.io/controller-runtime" +) + +type CoreProviderReconciler struct { + *GenericProviderReconciler[*operatorv1.CoreProvider] +} + +func NewCoreProviderReconciler(conn generic.Connector) generic.ProviderReconciler[*operatorv1.CoreProvider] { + return &CoreProviderReconciler{ + GenericProviderReconciler: NewGenericProviderReconciler[*operatorv1.CoreProvider](conn), + } +} + +// PreflightChecks implements GenericReconciler. +func (r *CoreProviderReconciler) PreflightChecks( + ctx context.Context, + provider *operatorv1.CoreProvider, +) []generic.ReconcileFn[*operatorv1.CoreProvider, generic.Group[*operatorv1.CoreProvider]] { + return append( + generic.NewReconcileFnList(r.corePreflightChecks), + r.GenericProviderReconciler.PreflightChecks(ctx, provider)..., + ) +} + +// ClusterctlProviderType returns ProviderType for the underlying clusterctl provider. +func (r *CoreProviderReconciler) ClusterctlProviderType() clusterctlv1.ProviderType { + return clusterctlv1.CoreProviderType +} + +// ClusterctlProvider returns Provider structure of the underlying clusterctl provider. +func (r *CoreProviderReconciler) ClusterctlProvider(provider *operatorv1.CoreProvider) *clusterctlv1.Provider { + clusterctlProvider := &clusterctlv1.Provider{ + ObjectMeta: metav1.ObjectMeta{ + Name: provider.GetName(), + Namespace: provider.GetNamespace(), + }, + Type: string(r.ClusterctlProviderType()), + ProviderName: provider.GetName(), + Version: *util.Or(provider.GetStatus().InstalledVersion, ptr.To("")), + } + + return clusterctlProvider +} + +// GetProviderList returns empty typed list for provider. +func (r *CoreProviderReconciler) GetProviderList() generic.ProviderList { + return &operatorv1.CoreProviderList{} +} + +// corePreflightChecks performs preflight checks on core provider before installing . +func (r *CoreProviderReconciler) corePreflightChecks(ctx context.Context, phase generic.Group[*operatorv1.CoreProvider]) (ctrl.Result, error) { + log := ctrl.LoggerFrom(ctx) + + log.Info("Performing core provider preflight checks") + + // Ensure that the CoreProvider is called "cluster-api". + if phase.GetProvider().GetName() != configclient.ClusterAPIProviderName { + conditions.Set(phase.GetProvider(), conditions.FalseCondition( + operatorv1.PreflightCheckCondition, + operatorv1.IncorrectCoreProviderNameReason, + clusterv1.ConditionSeverityError, + fmt.Sprintf(incorrectCoreProviderNameMessage, phase.GetProvider().GetName(), configclient.ClusterAPIProviderName), + )) + + return ctrl.Result{}, fmt.Errorf("incorrect CoreProvider name: %s, it should be %s", phase.GetProvider().GetName(), configclient.ClusterAPIProviderName) + } + + // Check that no more than one instance of the provider is installed. + if len(phase.GetProviderList().GetItems()) > 1 { + preflightFalseCondition := conditions.FalseCondition( + operatorv1.PreflightCheckCondition, + operatorv1.MoreThanOneProviderInstanceExistsReason, + clusterv1.ConditionSeverityError, + "", + ) + + // CoreProvider is a singleton resource, more than one instances should not exist + log.Info(moreThanOneCoreProviderInstanceExistsMessage) + preflightFalseCondition.Message = moreThanOneCoreProviderInstanceExistsMessage + conditions.Set(phase.GetProvider(), preflightFalseCondition) + + return ctrl.Result{}, fmt.Errorf("only one instance of CoreProvider is allowed") + } + + return ctrl.Result{}, nil +} diff --git a/internal/controller/providers/generic_provider.go b/internal/controller/providers/generic_provider.go new file mode 100644 index 000000000..0f3242f30 --- /dev/null +++ b/internal/controller/providers/generic_provider.go @@ -0,0 +1,181 @@ +/* +Copyright 2021 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package providers + +import ( + "context" + "fmt" + "reflect" + + corev1 "k8s.io/api/core/v1" + "k8s.io/client-go/rest" + operatorv1 "sigs.k8s.io/cluster-api-operator/api/v1alpha2" + "sigs.k8s.io/cluster-api-operator/internal/controller/generic" + "sigs.k8s.io/cluster-api-operator/internal/controller/phases" + clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1" + clusterctlv1 "sigs.k8s.io/cluster-api/cmd/clusterctl/api/v1alpha3" + "sigs.k8s.io/cluster-api/util/conditions" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +type GenericProviderReconciler[P generic.Provider] struct { + Client client.Client + Config *rest.Config + PhaseReconciler *phases.PhaseReconciler[P, generic.Group[P]] +} + +func NewGenericProviderReconciler[P generic.Provider](conn generic.Connector) *GenericProviderReconciler[P] { + return &GenericProviderReconciler[P]{ + Client: conn.GetClient(), + Config: conn.GetConfig(), + } +} + +func (r *GenericProviderReconciler[P]) Init() { + r.PhaseReconciler = phases.NewPhaseReconciler[P, generic.Group[P]](r.Client) +} + +// GetClient implements GenericReconciler. +func (r *GenericProviderReconciler[P]) GetClient() client.Client { + return r.Client +} + +// GetConfig implements GenericReconciler. +func (r *GenericProviderReconciler[P]) GetConfig() *rest.Config { + return r.Config +} + +// ReconcileDelete implements GenericReconciler. +func (r *GenericProviderReconciler[P]) ReconcileDelete(ctx context.Context, provider P) []generic.ReconcileFn[P, generic.Group[P]] { + log := ctrl.LoggerFrom(ctx) + + log.Info("Deleting provider resources") + + return generic.NewReconcileFnList( + r.PhaseReconciler.Delete, + ) +} + +// PreflightChecks implements preflight checks for GenericReconciler. +func (r *GenericProviderReconciler[P]) PreflightChecks(ctx context.Context, provider P) []generic.ReconcileFn[P, generic.Group[P]] { + return generic.NewReconcileFnList( + phases.PreflightChecks[P], + ) +} + +// ReconcileNormal implements GenericReconciler. +func (r *GenericProviderReconciler[P]) ReconcileNormal(ctx context.Context, provider P) []generic.ReconcileFn[P, generic.Group[P]] { + return generic.NewReconcileFnList( + r.PhaseReconciler.InitializePhaseReconciler, + r.PhaseReconciler.DownloadManifests, + r.PhaseReconciler.Load, + r.PhaseReconciler.Fetch, + r.PhaseReconciler.Upgrade, + r.PhaseReconciler.Install, + ) +} + +// ReportStatus reports changes in status for the reconciled provider. +func (r *GenericProviderReconciler[P]) ReportStatus(ctx context.Context, provider P) []generic.ReconcileFn[P, generic.Group[P]] { + return generic.NewReconcileFnList( + r.PhaseReconciler.ReportStatus, + ) +} + +// ClusterctlProviderType returns ProviderType for the underlying clusterctl provider. +func (r *GenericProviderReconciler[P]) ClusterctlProviderType() clusterctlv1.ProviderType { + panic("Generic Provider Reconciler has no provider type") +} + +// ClusterctlProvider returns initialized underlying clusterctl provider. +func (r *GenericProviderReconciler[P]) ClusterctlProvider(provider P) *clusterctlv1.Provider { + panic("Generic Provider Reconciler has no clusterctl provider") +} + +// GetProviderList returns empty typed list for provider. +func (r *GenericProviderReconciler[P]) GetProviderList() generic.ProviderList { + panic("Generic Provider Reconciler has no provider list") +} + +// GenericProvider returns empty typed provider for generic reconciler. +func (r *GenericProviderReconciler[P]) GenericProvider() generic.Provider { + return reflect.New(reflect.TypeOf(*new(P)).Elem()).Interface().(P) //nolint:forcetypeassert +} + +type CommonProviderReconciler[P generic.Provider] struct { + generic.ProviderReconciler[P] +} + +func NewCommonProviderReconciler[P generic.Provider](conn generic.Connector) *CommonProviderReconciler[P] { + return &CommonProviderReconciler[P]{ + ProviderReconciler: NewGenericProviderReconciler[P](conn), + } +} + +// PreflightChecks implements GenericReconciler. +func (r *CommonProviderReconciler[P]) PreflightChecks( + ctx context.Context, + provider P, +) []generic.ReconcileFn[P, generic.Group[P]] { + return append( + generic.NewReconcileFnList(r.waitForCoreReady), + r.ProviderReconciler.PreflightChecks(ctx, provider)...) +} + +func (r *CommonProviderReconciler[P]) waitForCoreReady(ctx context.Context, phase generic.Group[P]) (ctrl.Result, error) { + log := ctrl.LoggerFrom(ctx) + + // Wait for core provider to be ready before we install other providers. + ready, err := coreProviderIsReady(ctx, phase.GetClient()) + if err != nil { + return ctrl.Result{}, fmt.Errorf("failed to get coreProvider ready condition: %w", err) + } + + if !ready { + log.Info(waitingForCoreProviderReadyMessage) + conditions.Set(phase.GetProvider(), conditions.FalseCondition( + operatorv1.PreflightCheckCondition, + operatorv1.WaitingForCoreProviderReadyReason, + clusterv1.ConditionSeverityInfo, + waitingForCoreProviderReadyMessage, + )) + + return ctrl.Result{RequeueAfter: preflightFailedRequeueAfter}, nil + } + + return ctrl.Result{}, nil +} + +// coreProviderIsReady returns true if the core provider is ready. +func coreProviderIsReady(ctx context.Context, c client.Client) (bool, error) { + cpl := &operatorv1.CoreProviderList{} + + if err := c.List(ctx, cpl); err != nil { + return false, err + } + + for _, cp := range cpl.Items { + for _, cond := range cp.Status.Conditions { + if cond.Type == clusterv1.ReadyCondition && cond.Status == corev1.ConditionTrue { + return true, nil + } + } + } + + return false, nil +} diff --git a/internal/controller/providers/infrastructure.go b/internal/controller/providers/infrastructure.go new file mode 100644 index 000000000..8a8858710 --- /dev/null +++ b/internal/controller/providers/infrastructure.go @@ -0,0 +1,61 @@ +/* +Copyright 2024 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package providers + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/utils/ptr" + operatorv1 "sigs.k8s.io/cluster-api-operator/api/v1alpha2" + "sigs.k8s.io/cluster-api-operator/internal/controller/generic" + "sigs.k8s.io/cluster-api-operator/util" + clusterctlv1 "sigs.k8s.io/cluster-api/cmd/clusterctl/api/v1alpha3" +) + +type InfrastructureProviderReconciler struct { + *CommonProviderReconciler[*operatorv1.InfrastructureProvider] +} + +func NewInfrastructureProviderReconciler(conn generic.Connector) generic.ProviderReconciler[*operatorv1.InfrastructureProvider] { + return &InfrastructureProviderReconciler{ + CommonProviderReconciler: NewCommonProviderReconciler[*operatorv1.InfrastructureProvider](conn), + } +} + +// ClusterctlProviderType returns ProviderType for the underlying clusterctl provider. +func (r *InfrastructureProviderReconciler) ClusterctlProviderType() clusterctlv1.ProviderType { + return clusterctlv1.InfrastructureProviderType +} + +// ClusterctlProvider returns Provider structure of the underlying clusterctl provider. +func (r *InfrastructureProviderReconciler) ClusterctlProvider(provider *operatorv1.InfrastructureProvider) *clusterctlv1.Provider { + clusterctlProvider := &clusterctlv1.Provider{ + ObjectMeta: metav1.ObjectMeta{ + Name: "infrastructure-" + provider.GetName(), + Namespace: provider.GetNamespace(), + }, + Type: string(r.ClusterctlProviderType()), + ProviderName: provider.GetName(), + Version: *util.Or(provider.GetStatus().InstalledVersion, ptr.To("")), + } + + return clusterctlProvider +} + +// GetProviderList returns empty typed list for provider. +func (r *InfrastructureProviderReconciler) GetProviderList() generic.ProviderList { + return &operatorv1.InfrastructureProviderList{} +} diff --git a/internal/controller/providers/ipam.go b/internal/controller/providers/ipam.go new file mode 100644 index 000000000..e4342def0 --- /dev/null +++ b/internal/controller/providers/ipam.go @@ -0,0 +1,62 @@ +/* +Copyright 2024 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package providers + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + "k8s.io/utils/ptr" + operatorv1 "sigs.k8s.io/cluster-api-operator/api/v1alpha2" + "sigs.k8s.io/cluster-api-operator/internal/controller/generic" + "sigs.k8s.io/cluster-api-operator/util" + clusterctlv1 "sigs.k8s.io/cluster-api/cmd/clusterctl/api/v1alpha3" +) + +type IPAMProviderReconciler struct { + *CommonProviderReconciler[*operatorv1.IPAMProvider] +} + +func NewIPAMProviderReconciler(conn generic.Connector) generic.ProviderReconciler[*operatorv1.IPAMProvider] { + return &IPAMProviderReconciler{ + CommonProviderReconciler: NewCommonProviderReconciler[*operatorv1.IPAMProvider](conn), + } +} + +// ClusterctlProviderType returns ProviderType for the underlying clusterctl provider. +func (r *IPAMProviderReconciler) ClusterctlProviderType() clusterctlv1.ProviderType { + return clusterctlv1.IPAMProviderType +} + +// ClusterctlProvider returns Provider structure of the underlying clusterctl provider. +func (r *IPAMProviderReconciler) ClusterctlProvider(provider *operatorv1.IPAMProvider) *clusterctlv1.Provider { + clusterctlProvider := &clusterctlv1.Provider{ + ObjectMeta: metav1.ObjectMeta{ + Name: "ipam-" + provider.GetName(), + Namespace: provider.GetNamespace(), + }, + Type: string(r.ClusterctlProviderType()), + ProviderName: provider.GetName(), + Version: *util.Or(provider.GetStatus().InstalledVersion, ptr.To("")), + } + + return clusterctlProvider +} + +// GetProviderList returns empty typed list for provider. +func (r *IPAMProviderReconciler) GetProviderList() generic.ProviderList { + return &operatorv1.IPAMProviderList{} +} diff --git a/internal/controller/providers/runtime_extension.go b/internal/controller/providers/runtime_extension.go new file mode 100644 index 000000000..3d439748b --- /dev/null +++ b/internal/controller/providers/runtime_extension.go @@ -0,0 +1,61 @@ +/* +Copyright 2024 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package providers + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + "k8s.io/utils/ptr" + operatorv1 "sigs.k8s.io/cluster-api-operator/api/v1alpha2" + "sigs.k8s.io/cluster-api-operator/internal/controller/generic" + "sigs.k8s.io/cluster-api-operator/util" + clusterctlv1 "sigs.k8s.io/cluster-api/cmd/clusterctl/api/v1alpha3" +) + +type RuntimeExtensionProvider struct { + generic.ProviderReconciler[*operatorv1.RuntimeExtensionProvider] +} + +func NewRuntimeExtensionProviderReconciler(conn generic.Connector) generic.ProviderReconciler[*operatorv1.RuntimeExtensionProvider] { + return &RuntimeExtensionProvider{ + ProviderReconciler: NewCommonProviderReconciler[*operatorv1.RuntimeExtensionProvider](conn), + } +} + +// ClusterctlProviderType returns ProviderType for the underlying clusterctl provider +func (r *RuntimeExtensionProvider) ClusterctlProviderType() clusterctlv1.ProviderType { + return clusterctlv1.RuntimeExtensionProviderType +} + +// ClusterctlProvider returns Provider stucture of the underlying clusterctl provider +func (r *RuntimeExtensionProvider) ClusterctlProvider(provider *operatorv1.RuntimeExtensionProvider) *clusterctlv1.Provider { + clusterctlProvider := &clusterctlv1.Provider{ObjectMeta: metav1.ObjectMeta{ + Name: "runtime-extension-" + provider.GetName(), // TODO: verify correctness of the name + Namespace: provider.GetNamespace(), + }, + Type: string(r.ClusterctlProviderType()), + ProviderName: provider.GetName(), + Version: *util.Or(provider.GetStatus().InstalledVersion, ptr.To("")), + } + + return clusterctlProvider +} + +// ProviderList returns empty typed list for provider +func (r *RuntimeExtensionProvider) GetProviderList() generic.ProviderList { + return &operatorv1.RuntimeExtensionProviderList{} +} diff --git a/internal/controller/providers/suite_test.go b/internal/controller/providers/suite_test.go new file mode 100644 index 000000000..43a8f5e66 --- /dev/null +++ b/internal/controller/providers/suite_test.go @@ -0,0 +1,54 @@ +/* +Copyright 2021 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package providers + +import ( + "fmt" + "os" + "testing" + + "sigs.k8s.io/cluster-api-operator/internal/envtest" + ctrl "sigs.k8s.io/controller-runtime" +) + +var ( + env *envtest.Environment + ctx = ctrl.SetupSignalHandler() +) + +func TestMain(m *testing.M) { + fmt.Println("Creating new test environment") + + env = envtest.New() + + go func() { + if err := env.Start(ctx); err != nil { + panic(fmt.Sprintf("Failed to start the envtest manager: %v", err)) + } + }() + <-env.Manager.Elected() + + // Run tests + code := m.Run() + // Tearing down the test environment + if err := env.Stop(); err != nil { + panic(fmt.Sprintf("Failed to stop the envtest: %v", err)) + } + + // Report exit code + os.Exit(code) +} diff --git a/internal/controller/client_proxy.go b/internal/controller/proxy/client_proxy.go similarity index 65% rename from internal/controller/client_proxy.go rename to internal/controller/proxy/client_proxy.go index 4b52bcfbf..620655ecb 100644 --- a/internal/controller/client_proxy.go +++ b/internal/controller/proxy/client_proxy.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package controller +package proxy import ( "context" @@ -25,33 +25,36 @@ import ( "k8s.io/apimachinery/pkg/api/meta" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + // kerrors "k8s.io/apimachinery/pkg/util/errors". + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/client-go/rest" "k8s.io/klog/v2" - operatorv1 "sigs.k8s.io/cluster-api-operator/api/v1alpha2" + // "sigs.k8s.io/cluster-api-operator/internal/controller/generic". clusterctlv1 "sigs.k8s.io/cluster-api/cmd/clusterctl/api/v1alpha3" "sigs.k8s.io/cluster-api/cmd/clusterctl/client/cluster" "sigs.k8s.io/cluster-api/cmd/clusterctl/client/repository" "sigs.k8s.io/controller-runtime/pkg/client" ) -// clientProxy implements the Proxy interface from the clusterctl. It is used to +// ClientProxy implements the Proxy interface from the clusterctl. It is used to // interact with the management cluster. -type clientProxy struct { +type ClientProxy struct { client.Client + ListProviders func(context.Context, client.Client, *clusterctlv1.ProviderList, ...client.ListOption) error } -func (c clientProxy) List(ctx context.Context, list client.ObjectList, opts ...client.ListOption) error { +func (c ClientProxy) List(ctx context.Context, list client.ObjectList, opts ...client.ListOption) error { switch l := list.(type) { case *clusterctlv1.ProviderList: - return listProviders(ctx, c.Client, l) + return c.ListProviders(ctx, c.Client, l, opts...) default: return c.Client.List(ctx, l, opts...) } } -func (c clientProxy) Get(ctx context.Context, key client.ObjectKey, obj client.Object, opts ...client.GetOption) error { +func (c ClientProxy) Get(ctx context.Context, key client.ObjectKey, obj client.Object, opts ...client.GetOption) error { switch o := obj.(type) { case *clusterctlv1.Provider: return nil @@ -60,7 +63,7 @@ func (c clientProxy) Get(ctx context.Context, key client.ObjectKey, obj client.O } } -func (c clientProxy) Patch(ctx context.Context, obj client.Object, patch client.Patch, opts ...client.PatchOption) error { +func (c ClientProxy) Patch(ctx context.Context, obj client.Object, patch client.Patch, opts ...client.PatchOption) error { switch o := obj.(type) { case *clusterctlv1.Provider: return nil @@ -69,53 +72,27 @@ func (c clientProxy) Patch(ctx context.Context, obj client.Object, patch client. } } -func listProviders(ctx context.Context, cl client.Client, list *clusterctlv1.ProviderList) error { - providers := []operatorv1.GenericProviderList{ - &operatorv1.CoreProviderList{}, - &operatorv1.InfrastructureProviderList{}, - &operatorv1.BootstrapProviderList{}, - &operatorv1.ControlPlaneProviderList{}, - &operatorv1.AddonProviderList{}, - &operatorv1.IPAMProviderList{}, - } - - for _, group := range providers { - g, ok := group.(client.ObjectList) - if !ok { - continue - } - - if err := cl.List(ctx, g); err != nil { - return err - } - - for _, p := range group.GetItems() { - list.Items = append(list.Items, getProvider(p, "")) - } - } - - return nil -} - -// controllerProxy implements the Proxy interface from the clusterctl. It is used to +// ControllerProxy implements the Proxy interface from the clusterctl. It is used to // interact with the management cluster. -type controllerProxy struct { - ctrlClient clientProxy - ctrlConfig *rest.Config +type ControllerProxy struct { + CtrlClient ClientProxy + CtrlConfig *rest.Config } -var _ cluster.Proxy = &controllerProxy{} +var _ cluster.Proxy = &ControllerProxy{} -func (k *controllerProxy) CurrentNamespace() (string, error) { return "default", nil } -func (k *controllerProxy) ValidateKubernetesVersion() error { return nil } -func (k *controllerProxy) GetConfig() (*rest.Config, error) { return k.ctrlConfig, nil } -func (k *controllerProxy) NewClient(context.Context) (client.Client, error) { return k.ctrlClient, nil } -func (k *controllerProxy) GetContexts(prefix string) ([]string, error) { return nil, nil } -func (k *controllerProxy) CheckClusterAvailable(context.Context) error { return nil } +func (k *ControllerProxy) CurrentNamespace() (string, error) { return "default", nil } +func (k *ControllerProxy) ValidateKubernetesVersion() error { return nil } +func (k *ControllerProxy) GetConfig() (*rest.Config, error) { return k.CtrlConfig, nil } +func (k *ControllerProxy) NewClient(context.Context) (client.Client, error) { + return k.CtrlClient, nil +} +func (k *ControllerProxy) GetContexts(prefix string) ([]string, error) { return nil, nil } +func (k *ControllerProxy) CheckClusterAvailable(ctx context.Context) error { return nil } // GetResourceNames returns the list of resource names which begin with prefix. -func (k *controllerProxy) GetResourceNames(ctx context.Context, groupVersion, kind string, options []client.ListOption, prefix string) ([]string, error) { - objList, err := listObjByGVK(ctx, k.ctrlClient, groupVersion, kind, options) +func (k *ControllerProxy) GetResourceNames(ctx context.Context, groupVersion, kind string, options []client.ListOption, prefix string) ([]string, error) { + objList, err := listObjByGVK(ctx, k.CtrlClient, groupVersion, kind, options) if err != nil { return nil, err } @@ -134,7 +111,7 @@ func (k *controllerProxy) GetResourceNames(ctx context.Context, groupVersion, ki } // ListResources lists namespaced and cluster-wide resources for a component matching the labels. -func (k *controllerProxy) ListResources(ctx context.Context, labels map[string]string, namespaces ...string) ([]unstructured.Unstructured, error) { +func (k *ControllerProxy) ListResources(ctx context.Context, labels map[string]string, namespaces ...string) ([]unstructured.Unstructured, error) { resourceList := []*metav1.APIResourceList{ { GroupVersion: "v1", @@ -183,7 +160,7 @@ func (k *controllerProxy) ListResources(ctx context.Context, labels map[string]s for _, resourceKind := range resourceGroup.APIResources { if resourceKind.Namespaced { for _, namespace := range namespaces { - objList, err := listObjByGVK(ctx, k.ctrlClient, resourceGroup.GroupVersion, resourceKind.Kind, []client.ListOption{client.MatchingLabels(labels), client.InNamespace(namespace)}) + objList, err := listObjByGVK(ctx, k.CtrlClient, resourceGroup.GroupVersion, resourceKind.Kind, []client.ListOption{client.MatchingLabels(labels), client.InNamespace(namespace)}) if err != nil { return nil, err } @@ -193,7 +170,7 @@ func (k *controllerProxy) ListResources(ctx context.Context, labels map[string]s ret = append(ret, objList.Items...) } } else { - objList, err := listObjByGVK(ctx, k.ctrlClient, resourceGroup.GroupVersion, resourceKind.Kind, []client.ListOption{client.MatchingLabels(labels)}) + objList, err := listObjByGVK(ctx, k.CtrlClient, resourceGroup.GroupVersion, resourceKind.Kind, []client.ListOption{client.MatchingLabels(labels)}) if err != nil { return nil, err } @@ -222,24 +199,24 @@ func listObjByGVK(ctx context.Context, c client.Client, groupVersion, kind strin return objList, nil } -type repositoryProxy struct { +type RepositoryProxy struct { repository.Client - components repository.Components + RepositoryComponents repository.Components } -type repositoryClient struct { - components repository.Components +type RepositoryClient struct { + repository.Components } -func (r repositoryClient) Raw(ctx context.Context, options repository.ComponentsOptions) ([]byte, error) { +func (r RepositoryClient) Raw(ctx context.Context, options repository.ComponentsOptions) ([]byte, error) { return nil, nil } -func (r repositoryClient) Get(ctx context.Context, options repository.ComponentsOptions) (repository.Components, error) { - return r.components, nil +func (r RepositoryClient) Get(ctx context.Context, options repository.ComponentsOptions) (repository.Components, error) { + return r.Components, nil } -func (r repositoryProxy) Components() repository.ComponentsClient { - return repositoryClient{r.components} +func (r RepositoryProxy) Components() repository.ComponentsClient { + return RepositoryClient{r.RepositoryComponents} } diff --git a/internal/controller/secrets_to_providers.go b/internal/controller/secrets_to_providers.go index 8f4aaf9c8..f4f64f92a 100644 --- a/internal/controller/secrets_to_providers.go +++ b/internal/controller/secrets_to_providers.go @@ -22,7 +22,7 @@ import ( "github.com/Masterminds/goutils" operatorv1 "sigs.k8s.io/cluster-api-operator/api/v1alpha2" - "sigs.k8s.io/cluster-api-operator/internal/controller/genericprovider" + "sigs.k8s.io/cluster-api-operator/internal/controller/generic" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/handler" @@ -37,7 +37,7 @@ const ( // newSecretToProviderFuncMapForProviderList maps a Kubernetes secret to all the providers that reference it. // It lists all the providers matching spec.configSecret.name values with the secret name querying by index. // If the provider references a secret without a namespace, it will assume the secret is in the same namespace as the provider. -func newSecretToProviderFuncMapForProviderList(k8sClient client.Client, providerList genericprovider.GenericProviderList) handler.MapFunc { +func newSecretToProviderFuncMapForProviderList(k8sClient client.Client, providerList generic.ProviderList) handler.MapFunc { providerListType := fmt.Sprintf("%T", providerList) return func(ctx context.Context, secret client.Object) []reconcile.Request { diff --git a/internal/controller/suite_test.go b/internal/controller/suite_test.go index 06dd9ca25..63d1d2016 100644 --- a/internal/controller/suite_test.go +++ b/internal/controller/suite_test.go @@ -22,11 +22,17 @@ import ( "testing" "time" + "k8s.io/apimachinery/pkg/runtime" + utilruntime "k8s.io/apimachinery/pkg/util/runtime" + "sigs.k8s.io/cluster-api-operator/internal/controller/phases" + "sigs.k8s.io/cluster-api-operator/internal/controller/providers" + "sigs.k8s.io/cluster-api-operator/internal/envtest" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/controller" + corev1 "k8s.io/api/core/v1" operatorv1 "sigs.k8s.io/cluster-api-operator/api/v1alpha2" - "sigs.k8s.io/cluster-api-operator/internal/envtest" + clusterctlv1 "sigs.k8s.io/cluster-api/cmd/clusterctl/api/v1alpha3" ) const ( @@ -39,44 +45,49 @@ var ( ctx = ctrl.SetupSignalHandler() ) +func setupScheme() *runtime.Scheme { + scheme := runtime.NewScheme() + utilruntime.Must(corev1.AddToScheme(scheme)) + utilruntime.Must(operatorv1.AddToScheme(scheme)) + utilruntime.Must(clusterctlv1.AddToScheme(scheme)) + + return scheme +} + func TestMain(m *testing.M) { fmt.Println("Creating new test environment") env = envtest.New() - if err := (&GenericProviderReconciler{ - Provider: &operatorv1.CoreProvider{}, - ProviderList: &operatorv1.CoreProviderList{}, - Client: env, - WatchConfigSecretChanges: true, - }).SetupWithManager(ctx, env.Manager, controller.Options{MaxConcurrentReconciles: 1}); err != nil { + if err := NewProviderControllerWrapper( + providers.NewCoreProviderReconciler(env), + phases.NewPhase, + true, + ).SetupWithManager(ctx, env.Manager, controller.Options{MaxConcurrentReconciles: 1}); err != nil { panic(fmt.Sprintf("Failed to start CoreProviderReconciler: %v", err)) } - if err := (&GenericProviderReconciler{ - Provider: &operatorv1.InfrastructureProvider{}, - ProviderList: &operatorv1.InfrastructureProviderList{}, - Client: env, - WatchConfigSecretChanges: true, - }).SetupWithManager(ctx, env.Manager, controller.Options{MaxConcurrentReconciles: 1}); err != nil { + if err := NewProviderControllerWrapper( + providers.NewInfrastructureProviderReconciler(env), + phases.NewPhase, + true, + ).SetupWithManager(ctx, env.Manager, controller.Options{MaxConcurrentReconciles: 1}); err != nil { panic(fmt.Sprintf("Failed to start InfrastructureProviderReconciler: %v", err)) } - if err := (&GenericProviderReconciler{ - Provider: &operatorv1.BootstrapProvider{}, - ProviderList: &operatorv1.BootstrapProviderList{}, - Client: env, - WatchConfigSecretChanges: true, - }).SetupWithManager(ctx, env.Manager, controller.Options{MaxConcurrentReconciles: 1}); err != nil { + if err := NewProviderControllerWrapper( + providers.NewBootstrapProviderReconciler(env), + phases.NewPhase, + true, + ).SetupWithManager(ctx, env.Manager, controller.Options{MaxConcurrentReconciles: 1}); err != nil { panic(fmt.Sprintf("Failed to start BootstrapProviderReconciler: %v", err)) } - if err := (&GenericProviderReconciler{ - Provider: &operatorv1.ControlPlaneProvider{}, - ProviderList: &operatorv1.ControlPlaneProviderList{}, - Client: env, - WatchConfigSecretChanges: true, - }).SetupWithManager(ctx, env.Manager, controller.Options{MaxConcurrentReconciles: 1}); err != nil { + if err := NewProviderControllerWrapper( + providers.NewControlPlaneProviderReconciler(env), + phases.NewPhase, + true, + ).SetupWithManager(ctx, env.Manager, controller.Options{MaxConcurrentReconciles: 1}); err != nil { panic(fmt.Sprintf("Failed to start ControlPlaneProviderReconciler: %v", err)) } diff --git a/internal/envtest/environment.go b/internal/envtest/environment.go index 00f47864b..97eaf7ee5 100644 --- a/internal/envtest/environment.go +++ b/internal/envtest/environment.go @@ -29,6 +29,7 @@ import ( "sync" "time" + ginkgo "github.com/onsi/ginkgo/v2" admissionv1 "k8s.io/api/admissionregistration/v1" corev1 "k8s.io/api/core/v1" apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" @@ -56,7 +57,11 @@ import ( func init() { klog.InitFlags(nil) - ctrl.SetLogger(textlogger.NewLogger(textlogger.NewConfig())) + // Additionally force all of the controllers to use the Ginkgo logger. + loggerConfig := textlogger.NewConfig( + textlogger.Output(ginkgo.GinkgoWriter), + ) + ctrl.SetLogger(textlogger.NewLogger(loggerConfig)) // Calculate the scheme. utilruntime.Must(apiextensionsv1.AddToScheme(scheme.Scheme)) diff --git a/test/e2e/resources/full-chart-install.yaml b/test/e2e/resources/full-chart-install.yaml index 0d4541061..56ef712e1 100644 --- a/test/e2e/resources/full-chart-install.yaml +++ b/test/e2e/resources/full-chart-install.yaml @@ -1829,13 +1829,13 @@ spec: description: |- MatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key in (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both matchLabelKeys and labelSelector. - Also, matchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MatchLabelKeys and LabelSelector. + Also, MatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -1844,13 +1844,13 @@ spec: description: |- MismatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key notin (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. - Also, mismatchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MismatchLabelKeys and LabelSelector. + Also, MismatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -2011,13 +2011,13 @@ spec: description: |- MatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key in (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both matchLabelKeys and labelSelector. - Also, matchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MatchLabelKeys and LabelSelector. + Also, MatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -2026,13 +2026,13 @@ spec: description: |- MismatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key notin (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. - Also, mismatchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MismatchLabelKeys and LabelSelector. + Also, MismatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -2191,13 +2191,13 @@ spec: description: |- MatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key in (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both matchLabelKeys and labelSelector. - Also, matchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MatchLabelKeys and LabelSelector. + Also, MatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -2206,13 +2206,13 @@ spec: description: |- MismatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key notin (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. - Also, mismatchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MismatchLabelKeys and LabelSelector. + Also, MismatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -2373,13 +2373,13 @@ spec: description: |- MatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key in (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both matchLabelKeys and labelSelector. - Also, matchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MatchLabelKeys and LabelSelector. + Also, MatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -2388,13 +2388,13 @@ spec: description: |- MismatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key notin (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. - Also, mismatchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MismatchLabelKeys and LabelSelector. + Also, MismatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -3493,13 +3493,13 @@ spec: description: |- MatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key in (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both matchLabelKeys and labelSelector. - Also, matchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MatchLabelKeys and LabelSelector. + Also, MatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -3508,13 +3508,13 @@ spec: description: |- MismatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key notin (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. - Also, mismatchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MismatchLabelKeys and LabelSelector. + Also, MismatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -3675,13 +3675,13 @@ spec: description: |- MatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key in (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both matchLabelKeys and labelSelector. - Also, matchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MatchLabelKeys and LabelSelector. + Also, MatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -3690,13 +3690,13 @@ spec: description: |- MismatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key notin (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. - Also, mismatchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MismatchLabelKeys and LabelSelector. + Also, MismatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -3855,13 +3855,13 @@ spec: description: |- MatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key in (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both matchLabelKeys and labelSelector. - Also, matchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MatchLabelKeys and LabelSelector. + Also, MatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -3870,13 +3870,13 @@ spec: description: |- MismatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key notin (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. - Also, mismatchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MismatchLabelKeys and LabelSelector. + Also, MismatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -4037,13 +4037,13 @@ spec: description: |- MatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key in (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both matchLabelKeys and labelSelector. - Also, matchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MatchLabelKeys and LabelSelector. + Also, MatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -4052,13 +4052,13 @@ spec: description: |- MismatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key notin (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. - Also, mismatchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MismatchLabelKeys and LabelSelector. + Also, MismatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -6582,13 +6582,13 @@ spec: description: |- MatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key in (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both matchLabelKeys and labelSelector. - Also, matchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MatchLabelKeys and LabelSelector. + Also, MatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -6597,13 +6597,13 @@ spec: description: |- MismatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key notin (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. - Also, mismatchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MismatchLabelKeys and LabelSelector. + Also, MismatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -6764,13 +6764,13 @@ spec: description: |- MatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key in (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both matchLabelKeys and labelSelector. - Also, matchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MatchLabelKeys and LabelSelector. + Also, MatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -6779,13 +6779,13 @@ spec: description: |- MismatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key notin (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. - Also, mismatchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MismatchLabelKeys and LabelSelector. + Also, MismatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -6944,13 +6944,13 @@ spec: description: |- MatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key in (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both matchLabelKeys and labelSelector. - Also, matchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MatchLabelKeys and LabelSelector. + Also, MatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -6959,13 +6959,13 @@ spec: description: |- MismatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key notin (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. - Also, mismatchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MismatchLabelKeys and LabelSelector. + Also, MismatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -7126,13 +7126,13 @@ spec: description: |- MatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key in (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both matchLabelKeys and labelSelector. - Also, matchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MatchLabelKeys and LabelSelector. + Also, MatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -7141,13 +7141,13 @@ spec: description: |- MismatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key notin (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. - Also, mismatchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MismatchLabelKeys and LabelSelector. + Also, MismatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -8246,13 +8246,13 @@ spec: description: |- MatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key in (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both matchLabelKeys and labelSelector. - Also, matchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MatchLabelKeys and LabelSelector. + Also, MatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -8261,13 +8261,13 @@ spec: description: |- MismatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key notin (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. - Also, mismatchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MismatchLabelKeys and LabelSelector. + Also, MismatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -8428,13 +8428,13 @@ spec: description: |- MatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key in (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both matchLabelKeys and labelSelector. - Also, matchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MatchLabelKeys and LabelSelector. + Also, MatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -8443,13 +8443,13 @@ spec: description: |- MismatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key notin (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. - Also, mismatchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MismatchLabelKeys and LabelSelector. + Also, MismatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -8608,13 +8608,13 @@ spec: description: |- MatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key in (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both matchLabelKeys and labelSelector. - Also, matchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MatchLabelKeys and LabelSelector. + Also, MatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -8623,13 +8623,13 @@ spec: description: |- MismatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key notin (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. - Also, mismatchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MismatchLabelKeys and LabelSelector. + Also, MismatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -8790,13 +8790,13 @@ spec: description: |- MatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key in (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both matchLabelKeys and labelSelector. - Also, matchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MatchLabelKeys and LabelSelector. + Also, MatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -8805,13 +8805,13 @@ spec: description: |- MismatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key notin (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. - Also, mismatchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MismatchLabelKeys and LabelSelector. + Also, MismatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -11337,13 +11337,13 @@ spec: description: |- MatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key in (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both matchLabelKeys and labelSelector. - Also, matchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MatchLabelKeys and LabelSelector. + Also, MatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -11352,13 +11352,13 @@ spec: description: |- MismatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key notin (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. - Also, mismatchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MismatchLabelKeys and LabelSelector. + Also, MismatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -11519,13 +11519,13 @@ spec: description: |- MatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key in (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both matchLabelKeys and labelSelector. - Also, matchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MatchLabelKeys and LabelSelector. + Also, MatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -11534,13 +11534,13 @@ spec: description: |- MismatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key notin (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. - Also, mismatchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MismatchLabelKeys and LabelSelector. + Also, MismatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -11699,13 +11699,13 @@ spec: description: |- MatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key in (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both matchLabelKeys and labelSelector. - Also, matchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MatchLabelKeys and LabelSelector. + Also, MatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -11714,13 +11714,13 @@ spec: description: |- MismatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key notin (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. - Also, mismatchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MismatchLabelKeys and LabelSelector. + Also, MismatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -11881,13 +11881,13 @@ spec: description: |- MatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key in (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both matchLabelKeys and labelSelector. - Also, matchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MatchLabelKeys and LabelSelector. + Also, MatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -11896,13 +11896,13 @@ spec: description: |- MismatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key notin (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. - Also, mismatchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MismatchLabelKeys and LabelSelector. + Also, MismatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -13002,13 +13002,13 @@ spec: description: |- MatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key in (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both matchLabelKeys and labelSelector. - Also, matchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MatchLabelKeys and LabelSelector. + Also, MatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -13017,13 +13017,13 @@ spec: description: |- MismatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key notin (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. - Also, mismatchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MismatchLabelKeys and LabelSelector. + Also, MismatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -13184,13 +13184,13 @@ spec: description: |- MatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key in (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both matchLabelKeys and labelSelector. - Also, matchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MatchLabelKeys and LabelSelector. + Also, MatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -13199,13 +13199,13 @@ spec: description: |- MismatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key notin (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. - Also, mismatchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MismatchLabelKeys and LabelSelector. + Also, MismatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -13364,13 +13364,13 @@ spec: description: |- MatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key in (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both matchLabelKeys and labelSelector. - Also, matchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MatchLabelKeys and LabelSelector. + Also, MatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -13379,13 +13379,13 @@ spec: description: |- MismatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key notin (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. - Also, mismatchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MismatchLabelKeys and LabelSelector. + Also, MismatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -13546,13 +13546,13 @@ spec: description: |- MatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key in (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both matchLabelKeys and labelSelector. - Also, matchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MatchLabelKeys and LabelSelector. + Also, MatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -13561,13 +13561,13 @@ spec: description: |- MismatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key notin (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. - Also, mismatchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MismatchLabelKeys and LabelSelector. + Also, MismatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -16091,13 +16091,13 @@ spec: description: |- MatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key in (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both matchLabelKeys and labelSelector. - Also, matchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MatchLabelKeys and LabelSelector. + Also, MatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -16106,13 +16106,13 @@ spec: description: |- MismatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key notin (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. - Also, mismatchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MismatchLabelKeys and LabelSelector. + Also, MismatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -16273,13 +16273,13 @@ spec: description: |- MatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key in (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both matchLabelKeys and labelSelector. - Also, matchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MatchLabelKeys and LabelSelector. + Also, MatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -16288,13 +16288,13 @@ spec: description: |- MismatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key notin (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. - Also, mismatchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MismatchLabelKeys and LabelSelector. + Also, MismatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -16453,13 +16453,13 @@ spec: description: |- MatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key in (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both matchLabelKeys and labelSelector. - Also, matchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MatchLabelKeys and LabelSelector. + Also, MatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -16468,13 +16468,13 @@ spec: description: |- MismatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key notin (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. - Also, mismatchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MismatchLabelKeys and LabelSelector. + Also, MismatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -16635,13 +16635,13 @@ spec: description: |- MatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key in (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both matchLabelKeys and labelSelector. - Also, matchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MatchLabelKeys and LabelSelector. + Also, MatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -16650,13 +16650,13 @@ spec: description: |- MismatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key notin (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. - Also, mismatchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MismatchLabelKeys and LabelSelector. + Also, MismatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -17755,13 +17755,13 @@ spec: description: |- MatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key in (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both matchLabelKeys and labelSelector. - Also, matchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MatchLabelKeys and LabelSelector. + Also, MatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -17770,13 +17770,13 @@ spec: description: |- MismatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key notin (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. - Also, mismatchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MismatchLabelKeys and LabelSelector. + Also, MismatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -17937,13 +17937,13 @@ spec: description: |- MatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key in (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both matchLabelKeys and labelSelector. - Also, matchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MatchLabelKeys and LabelSelector. + Also, MatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -17952,13 +17952,13 @@ spec: description: |- MismatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key notin (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. - Also, mismatchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MismatchLabelKeys and LabelSelector. + Also, MismatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -18117,13 +18117,13 @@ spec: description: |- MatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key in (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both matchLabelKeys and labelSelector. - Also, matchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MatchLabelKeys and LabelSelector. + Also, MatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -18132,13 +18132,13 @@ spec: description: |- MismatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key notin (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. - Also, mismatchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MismatchLabelKeys and LabelSelector. + Also, MismatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -18299,13 +18299,13 @@ spec: description: |- MatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key in (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both matchLabelKeys and labelSelector. - Also, matchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MatchLabelKeys and LabelSelector. + Also, MatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -18314,13 +18314,13 @@ spec: description: |- MismatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key notin (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. - Also, mismatchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MismatchLabelKeys and LabelSelector. + Also, MismatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -20846,13 +20846,13 @@ spec: description: |- MatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key in (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both matchLabelKeys and labelSelector. - Also, matchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MatchLabelKeys and LabelSelector. + Also, MatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -20861,13 +20861,13 @@ spec: description: |- MismatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key notin (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. - Also, mismatchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MismatchLabelKeys and LabelSelector. + Also, MismatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -21028,13 +21028,13 @@ spec: description: |- MatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key in (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both matchLabelKeys and labelSelector. - Also, matchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MatchLabelKeys and LabelSelector. + Also, MatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -21043,13 +21043,13 @@ spec: description: |- MismatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key notin (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. - Also, mismatchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MismatchLabelKeys and LabelSelector. + Also, MismatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -21208,13 +21208,13 @@ spec: description: |- MatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key in (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both matchLabelKeys and labelSelector. - Also, matchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MatchLabelKeys and LabelSelector. + Also, MatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -21223,13 +21223,13 @@ spec: description: |- MismatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key notin (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. - Also, mismatchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MismatchLabelKeys and LabelSelector. + Also, MismatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -21390,13 +21390,13 @@ spec: description: |- MatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key in (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both matchLabelKeys and labelSelector. - Also, matchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MatchLabelKeys and LabelSelector. + Also, MatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -21405,13 +21405,13 @@ spec: description: |- MismatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key notin (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. - Also, mismatchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MismatchLabelKeys and LabelSelector. + Also, MismatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -23963,13 +23963,13 @@ spec: description: |- MatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key in (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both matchLabelKeys and labelSelector. - Also, matchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MatchLabelKeys and LabelSelector. + Also, MatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -23978,13 +23978,13 @@ spec: description: |- MismatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key notin (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. - Also, mismatchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MismatchLabelKeys and LabelSelector. + Also, MismatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -24145,13 +24145,13 @@ spec: description: |- MatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key in (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both matchLabelKeys and labelSelector. - Also, matchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MatchLabelKeys and LabelSelector. + Also, MatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -24160,13 +24160,13 @@ spec: description: |- MismatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key notin (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. - Also, mismatchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MismatchLabelKeys and LabelSelector. + Also, MismatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -24325,13 +24325,13 @@ spec: description: |- MatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key in (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both matchLabelKeys and labelSelector. - Also, matchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MatchLabelKeys and LabelSelector. + Also, MatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -24340,13 +24340,13 @@ spec: description: |- MismatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key notin (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. - Also, mismatchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MismatchLabelKeys and LabelSelector. + Also, MismatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -24507,13 +24507,13 @@ spec: description: |- MatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key in (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both matchLabelKeys and labelSelector. - Also, matchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MatchLabelKeys and LabelSelector. + Also, MatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array @@ -24522,13 +24522,13 @@ spec: description: |- MismatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key notin (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. - The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. - Also, mismatchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + The same key is forbidden to exist in both MismatchLabelKeys and LabelSelector. + Also, MismatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. items: type: string type: array diff --git a/util/util.go b/util/util.go index c8d0f208d..ecf06acd9 100644 --- a/util/util.go +++ b/util/util.go @@ -23,12 +23,8 @@ import ( "regexp" "strings" - operatorv1 "sigs.k8s.io/cluster-api-operator/api/v1alpha2" - "sigs.k8s.io/cluster-api-operator/internal/controller/genericprovider" - clusterctlv1 "sigs.k8s.io/cluster-api/cmd/clusterctl/api/v1alpha3" configclient "sigs.k8s.io/cluster-api/cmd/clusterctl/client/config" "sigs.k8s.io/cluster-api/cmd/clusterctl/client/repository" - ctrlclient "sigs.k8s.io/controller-runtime/pkg/client" ) const ( @@ -38,101 +34,17 @@ const ( gitlabPackagesAPIPrefix = "/api/v4/projects/" ) -type genericProviderList interface { - ctrlclient.ObjectList - operatorv1.GenericProviderList -} - -func IsCoreProvider(p genericprovider.GenericProvider) bool { - _, ok := p.(*operatorv1.CoreProvider) - return ok -} - -// ClusterctlProviderType returns the provider type from the genericProvider. -func ClusterctlProviderType(genericProvider operatorv1.GenericProvider) clusterctlv1.ProviderType { - switch genericProvider.(type) { - case *operatorv1.CoreProvider: - return clusterctlv1.CoreProviderType - case *operatorv1.ControlPlaneProvider: - return clusterctlv1.ControlPlaneProviderType - case *operatorv1.InfrastructureProvider: - return clusterctlv1.InfrastructureProviderType - case *operatorv1.BootstrapProvider: - return clusterctlv1.BootstrapProviderType - case *operatorv1.AddonProvider: - return clusterctlv1.AddonProviderType - case *operatorv1.IPAMProvider: - return clusterctlv1.IPAMProviderType - case *operatorv1.RuntimeExtensionProvider: - return clusterctlv1.RuntimeExtensionProviderType - } - - return clusterctlv1.ProviderTypeUnknown -} - -// GetCustomProviders retrieves all custom providers using `FetchConfig` that aren't the current provider name / type. -func GetCustomProviders(ctx context.Context, cl ctrlclient.Client, currProvider genericprovider.GenericProvider) ([]operatorv1.GenericProvider, error) { - customProviders := []operatorv1.GenericProvider{} - currProviderName := currProvider.GetName() - currProviderType := currProvider.GetType() - - for _, providerList := range operatorv1.ProviderLists { - genProviderList, ok := providerList.(genericProviderList) - if !ok { - return nil, fmt.Errorf("cannot cast providers list to genericProviderList") - } - - if err := cl.List(ctx, genProviderList); err != nil { - return nil, fmt.Errorf("cannot get a list of providers from the server: %w", err) - } - - genProviderListItems := genProviderList.GetItems() - for i, provider := range genProviderListItems { - if provider.GetName() == currProviderName && provider.GetType() == currProviderType || provider.GetSpec().FetchConfig == nil { - continue - } - - customProviders = append(customProviders, genProviderListItems[i]) - } - } - - return customProviders, nil -} - -// GetGenericProvider returns the first of generic providers matching the type and the name from the configclient.Provider. -func GetGenericProvider(ctx context.Context, cl ctrlclient.Client, provider configclient.Provider) (operatorv1.GenericProvider, error) { - var list genericProviderList - - switch provider.Type() { - case clusterctlv1.CoreProviderType: - list = &operatorv1.CoreProviderList{} - case clusterctlv1.ControlPlaneProviderType: - list = &operatorv1.ControlPlaneProviderList{} - case clusterctlv1.InfrastructureProviderType: - list = &operatorv1.InfrastructureProviderList{} - case clusterctlv1.BootstrapProviderType: - list = &operatorv1.BootstrapProviderList{} - case clusterctlv1.AddonProviderType: - list = &operatorv1.AddonProviderList{} - case clusterctlv1.IPAMProviderType: - list = &operatorv1.IPAMProviderList{} - case clusterctlv1.RuntimeExtensionProviderType: - list = &operatorv1.RuntimeExtensionProviderList{} - case clusterctlv1.ProviderTypeUnknown: - return nil, fmt.Errorf("provider %s type is not supported %s", provider.Name(), provider.Type()) - } - - if err := cl.List(ctx, list); err != nil { - return nil, err - } +// Or compares the values and returns first non-empty occurrence. +func Or[T comparable](values ...T) T { + var zero T - for _, p := range list.GetItems() { - if p.GetName() == provider.Name() { - return p, nil + for _, v := range values { + if v != zero { + return v } } - return nil, fmt.Errorf("unable to find provider manifest with name %s", provider.Name()) + return zero } // RepositoryFactory returns the repository implementation corresponding to the provider URL.