diff --git a/api/v1alpha1/provider_conversion.go b/api/v1alpha1/provider_conversion.go index 05e06ee4a..55e2f5337 100644 --- a/api/v1alpha1/provider_conversion.go +++ b/api/v1alpha1/provider_conversion.go @@ -20,7 +20,7 @@ import ( "strings" apimachineryconversion "k8s.io/apimachinery/pkg/conversion" - "k8s.io/utils/pointer" + "k8s.io/utils/ptr" utilconversion "sigs.k8s.io/cluster-api/util/conversion" ctrlconfigv1 "sigs.k8s.io/controller-runtime/pkg/config/v1alpha1" "sigs.k8s.io/controller-runtime/pkg/conversion" @@ -525,5 +525,5 @@ func fromImageMeta(im *ImageMeta) *string { result = result + ":" + im.Tag } - return pointer.String(result) + return ptr.To(result) } diff --git a/cmd/main.go b/cmd/main.go index 397369997..9fb919421 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -30,7 +30,7 @@ import ( utilruntime "k8s.io/apimachinery/pkg/util/runtime" clientgoscheme "k8s.io/client-go/kubernetes/scheme" "k8s.io/klog/v2" - "k8s.io/klog/v2/klogr" + "k8s.io/klog/v2/textlogger" "sigs.k8s.io/cluster-api-operator/internal/webhook" clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1" clusterctlv1 "sigs.k8s.io/cluster-api/cmd/clusterctl/api/v1alpha3" @@ -47,6 +47,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 ( @@ -129,7 +131,9 @@ func main() { pflag.CommandLine.AddGoFlagSet(flag.CommandLine) pflag.Parse() - ctrl.SetLogger(klogr.New()) + loggerConfig := textlogger.NewConfig([]textlogger.ConfigOption{}...) + ctrl.SetLogger(textlogger.NewLogger(loggerConfig)) + restConfig := ctrl.GetConfigOrDie() diagnosticsOpts := flags.GetDiagnosticsOptions(diagnosticsOptions) @@ -210,62 +214,50 @@ func setupChecks(mgr ctrl.Manager) { } func setupReconcilers(mgr ctrl.Manager) { - if err := (&providercontroller.GenericProviderReconciler{ - Provider: &operatorv1.CoreProvider{}, - ProviderList: &operatorv1.CoreProviderList{}, - Client: mgr.GetClient(), - Config: mgr.GetConfig(), - }).SetupWithManager(mgr, concurrency(concurrencyNumber)); err != nil { + if err := providercontroller.NewProviderControllerWrapper( + providers.NewCoreProviderReconciler(mgr), + phases.NewPhase, + ).SetupWithManager(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(), - }).SetupWithManager(mgr, concurrency(concurrencyNumber)); err != nil { + if err := providercontroller.NewProviderControllerWrapper( + providers.NewInfrastructureProviderReconciler(mgr), + phases.NewPhase, + ).SetupWithManager(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(), - }).SetupWithManager(mgr, concurrency(concurrencyNumber)); err != nil { + if err := providercontroller.NewProviderControllerWrapper( + providers.NewBootstrapProviderReconciler(mgr), + phases.NewPhase, + ).SetupWithManager(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(), - }).SetupWithManager(mgr, concurrency(concurrencyNumber)); err != nil { + if err := providercontroller.NewProviderControllerWrapper( + providers.NewControlPlaneProviderReconciler(mgr), + phases.NewPhase, + ).SetupWithManager(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(), - }).SetupWithManager(mgr, concurrency(concurrencyNumber)); err != nil { + if err := providercontroller.NewProviderControllerWrapper( + providers.NewAddonProviderReconciler(mgr), + phases.NewPhase, + ).SetupWithManager(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(), - }).SetupWithManager(mgr, concurrency(concurrencyNumber)); err != nil { + if err := providercontroller.NewProviderControllerWrapper( + providers.NewIPAMProviderReconciler(mgr), + phases.NewPhase, + ).SetupWithManager(mgr, concurrency(concurrencyNumber)); err != nil { setupLog.Error(err, "unable to create controller", "controller", "IPAMProvider") os.Exit(1) } diff --git a/cmd/plugin/cmd/delete.go b/cmd/plugin/cmd/delete.go index 365eefcf9..eacfdb23b 100644 --- a/cmd/plugin/cmd/delete.go +++ b/cmd/plugin/cmd/delete.go @@ -28,7 +28,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/fields" "k8s.io/apimachinery/pkg/util/wait" - "k8s.io/klog/v2/klogr" + "k8s.io/klog/v2/textlogger" kerrors "k8s.io/apimachinery/pkg/util/errors" @@ -40,6 +40,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 { @@ -141,7 +142,8 @@ func init() { func runDelete() error { ctx := context.Background() - ctrl.SetLogger(klogr.New()) + loggerConfig := textlogger.NewConfig([]textlogger.ConfigOption{}...) + ctrl.SetLogger(textlogger.NewLogger(loggerConfig)) hasProviderNames := deleteOpts.coreProvider || (len(deleteOpts.bootstrapProviders) > 0) || @@ -170,7 +172,7 @@ func runDelete() error { group := &DeleteGroup{ selectors: []fields.Set{}, - providers: []genericProviderList{}, + providers: []generic.ProviderList{}, } errors := append([]error{}, group.delete(&operatorv1.BootstrapProviderList{}, deleteOpts.bootstrapProviders...), @@ -196,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 { @@ -215,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 @@ -283,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) @@ -306,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 dfc2ca464..7dd40c9f6 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" ) @@ -78,13 +79,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 42a4c9660..c3d0439e6 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 { @@ -471,7 +471,8 @@ func createGenericProvider(ctx context.Context, client ctrlclient.Client, provid 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 1d2ac7650..06081ffd7 100644 --- a/cmd/plugin/cmd/init_test.go +++ b/cmd/plugin/cmd/init_test.go @@ -18,9 +18,9 @@ package cmd import ( "context" - "fmt" "os" "testing" + "time" . "github.com/onsi/gomega" ctrlclient "sigs.k8s.io/controller-runtime/pkg/client" @@ -28,14 +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 TestCheckCAPIOpearatorAvailability(t *testing.T) { @@ -112,7 +110,9 @@ func TestCheckCAPIOpearatorAvailability(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{} @@ -163,18 +163,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.6.0", "", ""), }, wantErr: false, @@ -185,7 +185,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.6.0", "", ""), }, wantErr: false, @@ -196,7 +196,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, @@ -207,7 +207,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, @@ -218,7 +218,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, @@ -230,7 +230,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, @@ -242,7 +242,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", "", "", ""), }, @@ -257,7 +257,7 @@ func TestInitProviders(t *testing.T) { }, { name: "all providers", - wantedProviders: []genericprovider.GenericProvider{ + wantedProviders: []generic.Provider{ generateGenericProvider(clusterctlv1.CoreProviderType, "cluster-api", "capi-system", "v1.6.0", "", ""), generateGenericProvider(clusterctlv1.InfrastructureProviderType, "aws", "capa-operator-system", "", "", ""), generateGenericProvider(clusterctlv1.InfrastructureProviderType, "docker", "capd-operator-system", "", "", ""), @@ -287,7 +287,7 @@ func TestInitProviders(t *testing.T) { }, { name: "invalid input", - wantedProviders: []genericprovider.GenericProvider{}, + wantedProviders: []generic.Provider{}, wantErr: true, opts: &initOptions{ infrastructureProviders: []string{ @@ -298,7 +298,7 @@ func TestInitProviders(t *testing.T) { }, { name: "empty provider", - wantedProviders: []genericprovider.GenericProvider{}, + wantedProviders: []generic.Provider{}, wantErr: true, opts: &initOptions{ infrastructureProviders: []string{ @@ -328,18 +328,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()) @@ -469,8 +462,9 @@ func TestDeployCAPIOperator(t *testing.T) { } } -func generateGenericProvider(providerType clusterctlv1.ProviderType, name, namespace, version, configSecretName, configSecretNamespace string) genericprovider.GenericProvider { - genericProvider := NewGenericProvider(providerType) +func generateGenericProvider(providerType clusterctlv1.ProviderType, name, namespace, version, configSecretName, configSecretNamespace string) generic.Provider { + rec := generic.ProviderReconcilers[providerType] + genericProvider := rec.GenericProvider() genericProvider.SetName(name) @@ -486,45 +480,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 - default: - return nil, fmt.Errorf("failed to cast interface for type: %s", providerKind) - } -} diff --git a/cmd/plugin/cmd/suite_test.go b/cmd/plugin/cmd/suite_test.go index 87bd0ae9b..57209f57b 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/utils.go b/cmd/plugin/cmd/utils.go index 0a5c2a0e3..ba2964020 100644 --- a/cmd/plugin/cmd/utils.go +++ b/cmd/plugin/cmd/utils.go @@ -60,18 +60,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 @@ -168,25 +156,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.IPAMProviderType, clusterctlv1.RuntimeExtensionProviderType, 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) @@ -244,7 +213,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 dcfcfe0b2..d96fe7a89 100644 --- a/config/crd/bases/operator.cluster.x-k8s.io_addonproviders.yaml +++ b/config/crd/bases/operator.cluster.x-k8s.io_addonproviders.yaml @@ -305,8 +305,9 @@ spec: with the corresponding weight. properties: labelSelector: - description: A label query over a set of resources, - in this case pods. + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. properties: matchExpressions: description: matchExpressions is a list @@ -350,6 +351,36 @@ spec: type: object type: object x-kubernetes-map-type: atomic + matchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic namespaceSelector: description: |- A label query over the set of namespaces that the term applies to. @@ -450,8 +481,9 @@ spec: a pod of the set of pods is running properties: labelSelector: - description: A label query over a set of resources, - in this case pods. + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. properties: matchExpressions: description: matchExpressions is a list of label @@ -495,6 +527,36 @@ spec: type: object type: object x-kubernetes-map-type: atomic + matchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic namespaceSelector: description: |- A label query over the set of namespaces that the term applies to. @@ -593,8 +655,9 @@ spec: with the corresponding weight. properties: labelSelector: - description: A label query over a set of resources, - in this case pods. + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. properties: matchExpressions: description: matchExpressions is a list @@ -638,6 +701,36 @@ spec: type: object type: object x-kubernetes-map-type: atomic + matchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic namespaceSelector: description: |- A label query over the set of namespaces that the term applies to. @@ -738,8 +831,9 @@ spec: a pod of the set of pods is running properties: labelSelector: - description: A label query over a set of resources, - in this case pods. + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. properties: matchExpressions: description: matchExpressions is a list of label @@ -783,6 +877,36 @@ spec: type: object type: object x-kubernetes-map-type: atomic + matchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic namespaceSelector: description: |- A label query over the set of namespaces that the term applies to. 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 8043dd822..84e4a56e0 100644 --- a/config/crd/bases/operator.cluster.x-k8s.io_bootstrapproviders.yaml +++ b/config/crd/bases/operator.cluster.x-k8s.io_bootstrapproviders.yaml @@ -291,8 +291,9 @@ spec: with the corresponding weight. properties: labelSelector: - description: A label query over a set of resources, - in this case pods. + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. properties: matchExpressions: description: matchExpressions is a list @@ -336,6 +337,36 @@ spec: type: object type: object x-kubernetes-map-type: atomic + matchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic namespaceSelector: description: |- A label query over the set of namespaces that the term applies to. @@ -436,8 +467,9 @@ spec: a pod of the set of pods is running properties: labelSelector: - description: A label query over a set of resources, - in this case pods. + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. properties: matchExpressions: description: matchExpressions is a list of label @@ -481,6 +513,36 @@ spec: type: object type: object x-kubernetes-map-type: atomic + matchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic namespaceSelector: description: |- A label query over the set of namespaces that the term applies to. @@ -579,8 +641,9 @@ spec: with the corresponding weight. properties: labelSelector: - description: A label query over a set of resources, - in this case pods. + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. properties: matchExpressions: description: matchExpressions is a list @@ -624,6 +687,36 @@ spec: type: object type: object x-kubernetes-map-type: atomic + matchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic namespaceSelector: description: |- A label query over the set of namespaces that the term applies to. @@ -724,8 +817,9 @@ spec: a pod of the set of pods is running properties: labelSelector: - description: A label query over a set of resources, - in this case pods. + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. properties: matchExpressions: description: matchExpressions is a list of label @@ -769,6 +863,36 @@ spec: type: object type: object x-kubernetes-map-type: atomic + matchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic namespaceSelector: description: |- A label query over the set of namespaces that the term applies to. @@ -1766,8 +1890,9 @@ spec: with the corresponding weight. properties: labelSelector: - description: A label query over a set of resources, - in this case pods. + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. properties: matchExpressions: description: matchExpressions is a list @@ -1811,6 +1936,36 @@ spec: type: object type: object x-kubernetes-map-type: atomic + matchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic namespaceSelector: description: |- A label query over the set of namespaces that the term applies to. @@ -1911,8 +2066,9 @@ spec: a pod of the set of pods is running properties: labelSelector: - description: A label query over a set of resources, - in this case pods. + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. properties: matchExpressions: description: matchExpressions is a list of label @@ -1956,6 +2112,36 @@ spec: type: object type: object x-kubernetes-map-type: atomic + matchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic namespaceSelector: description: |- A label query over the set of namespaces that the term applies to. @@ -2054,8 +2240,9 @@ spec: with the corresponding weight. properties: labelSelector: - description: A label query over a set of resources, - in this case pods. + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. properties: matchExpressions: description: matchExpressions is a list @@ -2099,6 +2286,36 @@ spec: type: object type: object x-kubernetes-map-type: atomic + matchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic namespaceSelector: description: |- A label query over the set of namespaces that the term applies to. @@ -2199,8 +2416,9 @@ spec: a pod of the set of pods is running properties: labelSelector: - description: A label query over a set of resources, - in this case pods. + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. properties: matchExpressions: description: matchExpressions is a list of label @@ -2244,6 +2462,36 @@ spec: type: object type: object x-kubernetes-map-type: atomic + matchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic namespaceSelector: description: |- A label query over the set of namespaces that the term applies to. 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 0bbe7639a..61109668a 100644 --- a/config/crd/bases/operator.cluster.x-k8s.io_controlplaneproviders.yaml +++ b/config/crd/bases/operator.cluster.x-k8s.io_controlplaneproviders.yaml @@ -291,8 +291,9 @@ spec: with the corresponding weight. properties: labelSelector: - description: A label query over a set of resources, - in this case pods. + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. properties: matchExpressions: description: matchExpressions is a list @@ -336,6 +337,36 @@ spec: type: object type: object x-kubernetes-map-type: atomic + matchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic namespaceSelector: description: |- A label query over the set of namespaces that the term applies to. @@ -436,8 +467,9 @@ spec: a pod of the set of pods is running properties: labelSelector: - description: A label query over a set of resources, - in this case pods. + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. properties: matchExpressions: description: matchExpressions is a list of label @@ -481,6 +513,36 @@ spec: type: object type: object x-kubernetes-map-type: atomic + matchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic namespaceSelector: description: |- A label query over the set of namespaces that the term applies to. @@ -579,8 +641,9 @@ spec: with the corresponding weight. properties: labelSelector: - description: A label query over a set of resources, - in this case pods. + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. properties: matchExpressions: description: matchExpressions is a list @@ -624,6 +687,36 @@ spec: type: object type: object x-kubernetes-map-type: atomic + matchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic namespaceSelector: description: |- A label query over the set of namespaces that the term applies to. @@ -724,8 +817,9 @@ spec: a pod of the set of pods is running properties: labelSelector: - description: A label query over a set of resources, - in this case pods. + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. properties: matchExpressions: description: matchExpressions is a list of label @@ -769,6 +863,36 @@ spec: type: object type: object x-kubernetes-map-type: atomic + matchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic namespaceSelector: description: |- A label query over the set of namespaces that the term applies to. @@ -1768,8 +1892,9 @@ spec: with the corresponding weight. properties: labelSelector: - description: A label query over a set of resources, - in this case pods. + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. properties: matchExpressions: description: matchExpressions is a list @@ -1813,6 +1938,36 @@ spec: type: object type: object x-kubernetes-map-type: atomic + matchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic namespaceSelector: description: |- A label query over the set of namespaces that the term applies to. @@ -1913,8 +2068,9 @@ spec: a pod of the set of pods is running properties: labelSelector: - description: A label query over a set of resources, - in this case pods. + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. properties: matchExpressions: description: matchExpressions is a list of label @@ -1958,6 +2114,36 @@ spec: type: object type: object x-kubernetes-map-type: atomic + matchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic namespaceSelector: description: |- A label query over the set of namespaces that the term applies to. @@ -2056,8 +2242,9 @@ spec: with the corresponding weight. properties: labelSelector: - description: A label query over a set of resources, - in this case pods. + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. properties: matchExpressions: description: matchExpressions is a list @@ -2101,6 +2288,36 @@ spec: type: object type: object x-kubernetes-map-type: atomic + matchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic namespaceSelector: description: |- A label query over the set of namespaces that the term applies to. @@ -2201,8 +2418,9 @@ spec: a pod of the set of pods is running properties: labelSelector: - description: A label query over a set of resources, - in this case pods. + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. properties: matchExpressions: description: matchExpressions is a list of label @@ -2246,6 +2464,36 @@ spec: type: object type: object x-kubernetes-map-type: atomic + matchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic namespaceSelector: description: |- A label query over the set of namespaces that the term applies to. 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 1aad749b9..c6e7a0fb5 100644 --- a/config/crd/bases/operator.cluster.x-k8s.io_coreproviders.yaml +++ b/config/crd/bases/operator.cluster.x-k8s.io_coreproviders.yaml @@ -291,8 +291,9 @@ spec: with the corresponding weight. properties: labelSelector: - description: A label query over a set of resources, - in this case pods. + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. properties: matchExpressions: description: matchExpressions is a list @@ -336,6 +337,36 @@ spec: type: object type: object x-kubernetes-map-type: atomic + matchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic namespaceSelector: description: |- A label query over the set of namespaces that the term applies to. @@ -436,8 +467,9 @@ spec: a pod of the set of pods is running properties: labelSelector: - description: A label query over a set of resources, - in this case pods. + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. properties: matchExpressions: description: matchExpressions is a list of label @@ -481,6 +513,36 @@ spec: type: object type: object x-kubernetes-map-type: atomic + matchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic namespaceSelector: description: |- A label query over the set of namespaces that the term applies to. @@ -579,8 +641,9 @@ spec: with the corresponding weight. properties: labelSelector: - description: A label query over a set of resources, - in this case pods. + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. properties: matchExpressions: description: matchExpressions is a list @@ -624,6 +687,36 @@ spec: type: object type: object x-kubernetes-map-type: atomic + matchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic namespaceSelector: description: |- A label query over the set of namespaces that the term applies to. @@ -724,8 +817,9 @@ spec: a pod of the set of pods is running properties: labelSelector: - description: A label query over a set of resources, - in this case pods. + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. properties: matchExpressions: description: matchExpressions is a list of label @@ -769,6 +863,36 @@ spec: type: object type: object x-kubernetes-map-type: atomic + matchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic namespaceSelector: description: |- A label query over the set of namespaces that the term applies to. @@ -1766,8 +1890,9 @@ spec: with the corresponding weight. properties: labelSelector: - description: A label query over a set of resources, - in this case pods. + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. properties: matchExpressions: description: matchExpressions is a list @@ -1811,6 +1936,36 @@ spec: type: object type: object x-kubernetes-map-type: atomic + matchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic namespaceSelector: description: |- A label query over the set of namespaces that the term applies to. @@ -1911,8 +2066,9 @@ spec: a pod of the set of pods is running properties: labelSelector: - description: A label query over a set of resources, - in this case pods. + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. properties: matchExpressions: description: matchExpressions is a list of label @@ -1956,6 +2112,36 @@ spec: type: object type: object x-kubernetes-map-type: atomic + matchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic namespaceSelector: description: |- A label query over the set of namespaces that the term applies to. @@ -2054,8 +2240,9 @@ spec: with the corresponding weight. properties: labelSelector: - description: A label query over a set of resources, - in this case pods. + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. properties: matchExpressions: description: matchExpressions is a list @@ -2099,6 +2286,36 @@ spec: type: object type: object x-kubernetes-map-type: atomic + matchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic namespaceSelector: description: |- A label query over the set of namespaces that the term applies to. @@ -2199,8 +2416,9 @@ spec: a pod of the set of pods is running properties: labelSelector: - description: A label query over a set of resources, - in this case pods. + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. properties: matchExpressions: description: matchExpressions is a list of label @@ -2244,6 +2462,36 @@ spec: type: object type: object x-kubernetes-map-type: atomic + matchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic namespaceSelector: description: |- A label query over the set of namespaces that the term applies to. 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 8abef860a..0e6b57724 100644 --- a/config/crd/bases/operator.cluster.x-k8s.io_infrastructureproviders.yaml +++ b/config/crd/bases/operator.cluster.x-k8s.io_infrastructureproviders.yaml @@ -291,8 +291,9 @@ spec: with the corresponding weight. properties: labelSelector: - description: A label query over a set of resources, - in this case pods. + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. properties: matchExpressions: description: matchExpressions is a list @@ -336,6 +337,36 @@ spec: type: object type: object x-kubernetes-map-type: atomic + matchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic namespaceSelector: description: |- A label query over the set of namespaces that the term applies to. @@ -436,8 +467,9 @@ spec: a pod of the set of pods is running properties: labelSelector: - description: A label query over a set of resources, - in this case pods. + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. properties: matchExpressions: description: matchExpressions is a list of label @@ -481,6 +513,36 @@ spec: type: object type: object x-kubernetes-map-type: atomic + matchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic namespaceSelector: description: |- A label query over the set of namespaces that the term applies to. @@ -579,8 +641,9 @@ spec: with the corresponding weight. properties: labelSelector: - description: A label query over a set of resources, - in this case pods. + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. properties: matchExpressions: description: matchExpressions is a list @@ -624,6 +687,36 @@ spec: type: object type: object x-kubernetes-map-type: atomic + matchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic namespaceSelector: description: |- A label query over the set of namespaces that the term applies to. @@ -724,8 +817,9 @@ spec: a pod of the set of pods is running properties: labelSelector: - description: A label query over a set of resources, - in this case pods. + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. properties: matchExpressions: description: matchExpressions is a list of label @@ -769,6 +863,36 @@ spec: type: object type: object x-kubernetes-map-type: atomic + matchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic namespaceSelector: description: |- A label query over the set of namespaces that the term applies to. @@ -1768,8 +1892,9 @@ spec: with the corresponding weight. properties: labelSelector: - description: A label query over a set of resources, - in this case pods. + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. properties: matchExpressions: description: matchExpressions is a list @@ -1813,6 +1938,36 @@ spec: type: object type: object x-kubernetes-map-type: atomic + matchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic namespaceSelector: description: |- A label query over the set of namespaces that the term applies to. @@ -1913,8 +2068,9 @@ spec: a pod of the set of pods is running properties: labelSelector: - description: A label query over a set of resources, - in this case pods. + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. properties: matchExpressions: description: matchExpressions is a list of label @@ -1958,6 +2114,36 @@ spec: type: object type: object x-kubernetes-map-type: atomic + matchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic namespaceSelector: description: |- A label query over the set of namespaces that the term applies to. @@ -2056,8 +2242,9 @@ spec: with the corresponding weight. properties: labelSelector: - description: A label query over a set of resources, - in this case pods. + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. properties: matchExpressions: description: matchExpressions is a list @@ -2101,6 +2288,36 @@ spec: type: object type: object x-kubernetes-map-type: atomic + matchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic namespaceSelector: description: |- A label query over the set of namespaces that the term applies to. @@ -2201,8 +2418,9 @@ spec: a pod of the set of pods is running properties: labelSelector: - description: A label query over a set of resources, - in this case pods. + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. properties: matchExpressions: description: matchExpressions is a list of label @@ -2246,6 +2464,36 @@ spec: type: object type: object x-kubernetes-map-type: atomic + matchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic namespaceSelector: description: |- A label query over the set of namespaces that the term applies to. 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 5e5f79596..aa5359161 100644 --- a/config/crd/bases/operator.cluster.x-k8s.io_ipamproviders.yaml +++ b/config/crd/bases/operator.cluster.x-k8s.io_ipamproviders.yaml @@ -305,8 +305,9 @@ spec: with the corresponding weight. properties: labelSelector: - description: A label query over a set of resources, - in this case pods. + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. properties: matchExpressions: description: matchExpressions is a list @@ -350,6 +351,36 @@ spec: type: object type: object x-kubernetes-map-type: atomic + matchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic namespaceSelector: description: |- A label query over the set of namespaces that the term applies to. @@ -450,8 +481,9 @@ spec: a pod of the set of pods is running properties: labelSelector: - description: A label query over a set of resources, - in this case pods. + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. properties: matchExpressions: description: matchExpressions is a list of label @@ -495,6 +527,36 @@ spec: type: object type: object x-kubernetes-map-type: atomic + matchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic namespaceSelector: description: |- A label query over the set of namespaces that the term applies to. @@ -593,8 +655,9 @@ spec: with the corresponding weight. properties: labelSelector: - description: A label query over a set of resources, - in this case pods. + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. properties: matchExpressions: description: matchExpressions is a list @@ -638,6 +701,36 @@ spec: type: object type: object x-kubernetes-map-type: atomic + matchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic namespaceSelector: description: |- A label query over the set of namespaces that the term applies to. @@ -738,8 +831,9 @@ spec: a pod of the set of pods is running properties: labelSelector: - description: A label query over a set of resources, - in this case pods. + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. properties: matchExpressions: description: matchExpressions is a list of label @@ -783,6 +877,36 @@ spec: type: object type: object x-kubernetes-map-type: atomic + matchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic namespaceSelector: description: |- A label query over the set of namespaces that the term applies to. diff --git a/go.mod b/go.mod index 422e32aef..543cdd388 100644 --- a/go.mod +++ b/go.mod @@ -6,23 +6,24 @@ require ( github.com/MakeNowJust/heredoc v1.0.0 github.com/evanphx/json-patch/v5 v5.9.0 github.com/go-errors/errors v1.5.1 - github.com/go-logr/logr v1.3.0 + github.com/go-logr/logr v1.4.1 github.com/google/go-cmp v0.6.0 github.com/google/go-github/v52 v52.0.0 github.com/google/gofuzz v1.2.0 + github.com/onsi/ginkgo/v2 v2.15.0 github.com/onsi/gomega v1.32.0 github.com/spf13/cobra v1.8.0 github.com/spf13/pflag v1.0.5 golang.org/x/oauth2 v0.18.0 - k8s.io/api v0.28.8 - k8s.io/apiextensions-apiserver v0.28.8 - k8s.io/apimachinery v0.28.8 - k8s.io/client-go v0.28.8 - k8s.io/component-base v0.28.8 - k8s.io/klog/v2 v2.100.1 - k8s.io/utils v0.0.0-20230406110748-d93618cff8a2 + k8s.io/api v0.29.0 + k8s.io/apiextensions-apiserver v0.29.0 + k8s.io/apimachinery v0.29.0 + k8s.io/client-go v0.29.0 + k8s.io/component-base v0.29.0 + k8s.io/klog/v2 v2.110.1 + k8s.io/utils v0.0.0-20230726121419-3b25d923346b sigs.k8s.io/cluster-api v1.6.3 - sigs.k8s.io/controller-runtime v0.16.5 + sigs.k8s.io/controller-runtime v0.17.2 sigs.k8s.io/yaml v1.4.0 ) @@ -41,29 +42,28 @@ require ( github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/cloudflare/circl v1.3.7 // indirect github.com/coredns/caddy v1.1.1 // indirect - github.com/coreos/go-semver v0.3.1 // indirect - github.com/coreos/go-systemd/v22 v22.5.0 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/distribution/reference v0.5.0 // indirect github.com/drone/envsubst/v2 v2.0.0-20210730161058-179042472c46 // indirect github.com/emicklei/go-restful/v3 v3.11.0 // indirect github.com/evanphx/json-patch v5.6.0+incompatible // indirect github.com/felixge/httpsnoop v1.0.4 // indirect - github.com/fsnotify/fsnotify v1.6.0 // indirect + github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-openapi/jsonpointer v0.19.6 // indirect github.com/go-openapi/jsonreference v0.20.2 // indirect github.com/go-openapi/swag v0.22.3 // indirect + github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect github.com/gobuffalo/flect v1.0.2 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/protobuf v1.5.4 // indirect - github.com/google/cel-go v0.16.1 // indirect + github.com/google/cel-go v0.17.7 // indirect github.com/google/gnostic-models v0.6.8 // 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-20210720184732-4bb14d4b1be1 // indirect github.com/google/uuid v1.4.0 // indirect - github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0 // indirect github.com/hashicorp/hcl v1.0.0 // indirect github.com/huandu/xstrings v1.3.3 // indirect @@ -73,7 +73,7 @@ require ( github.com/json-iterator/go v1.1.12 // indirect github.com/magiconair/properties v1.8.7 // indirect github.com/mailru/easyjson v0.7.7 // indirect - github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect + github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 // indirect github.com/mitchellh/copystructure v1.2.0 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/mitchellh/reflectwalk v1.0.2 // indirect @@ -83,10 +83,10 @@ require ( github.com/opencontainers/go-digest v1.0.0 // indirect github.com/pelletier/go-toml/v2 v2.1.0 // indirect github.com/pkg/errors v0.9.1 // indirect - github.com/prometheus/client_golang v1.17.0 // indirect - github.com/prometheus/client_model v0.4.1-0.20230718164431-9a2bf3000d16 // indirect - github.com/prometheus/common v0.44.0 // indirect - github.com/prometheus/procfs v0.11.1 // indirect + github.com/prometheus/client_golang v1.18.0 // indirect + github.com/prometheus/client_model v0.5.0 // indirect + github.com/prometheus/common v0.45.0 // indirect + github.com/prometheus/procfs v0.12.0 // indirect github.com/sagikazarmark/locafero v0.3.0 // indirect github.com/sagikazarmark/slog-shim v0.1.0 // indirect github.com/shopspring/decimal v1.3.1 // indirect @@ -97,10 +97,6 @@ require ( github.com/stoewer/go-strcase v1.2.0 // indirect github.com/subosito/gotenv v1.6.0 // indirect github.com/valyala/fastjson v1.6.4 // indirect - go.etcd.io/etcd/api/v3 v3.5.10 // indirect - go.etcd.io/etcd/client/pkg/v3 v3.5.10 // indirect - go.etcd.io/etcd/client/v3 v3.5.10 // indirect - go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.0 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.46.0 // indirect go.opentelemetry.io/otel v1.20.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.20.0 // indirect @@ -110,7 +106,6 @@ require ( go.opentelemetry.io/otel/trace v1.20.0 // indirect go.opentelemetry.io/proto/otlp v1.0.0 // indirect go.uber.org/multierr v1.11.0 // indirect - go.uber.org/zap v1.25.0 // indirect golang.org/x/crypto v0.21.0 // indirect golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect golang.org/x/net v0.22.0 // indirect @@ -119,23 +114,21 @@ require ( golang.org/x/term v0.18.0 // indirect golang.org/x/text v0.14.0 // indirect golang.org/x/time v0.3.0 // indirect + golang.org/x/tools v0.16.1 // indirect gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect google.golang.org/appengine v1.6.7 // indirect - google.golang.org/genproto v0.0.0-20231016165738-49dd2c1f3d0b // indirect google.golang.org/genproto/googleapis/api v0.0.0-20231016165738-49dd2c1f3d0b // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20231030173426-d783a09b4405 // indirect google.golang.org/grpc v1.59.0 // indirect google.golang.org/protobuf v1.33.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/ini.v1 v1.67.0 // indirect - gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - k8s.io/apiserver v0.28.8 // indirect + k8s.io/apiserver v0.29.0 // indirect k8s.io/cluster-bootstrap v0.28.4 // indirect - k8s.io/kms v0.28.8 // indirect - k8s.io/kube-openapi v0.0.0-20230717233707-2695361300d9 // indirect - sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.1.2 // indirect + k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00 // indirect + sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.28.0 // indirect sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect - sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect + sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect ) diff --git a/go.sum b/go.sum index 639f39ae4..4b8499252 100644 --- a/go.sum +++ b/go.sum @@ -17,17 +17,12 @@ cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHOb cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY= -cloud.google.com/go v0.110.8 h1:tyNdfIxjzaWctIiLYOTalaLKZ17SI44SKFW26QbOhME= cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= -cloud.google.com/go/compute v1.23.1 h1:V97tBoDaZHb6leicZ1G6DLK2BAaZLJ/7+9BB/En3hR0= -cloud.google.com/go/compute v1.23.1/go.mod h1:CqB3xpmPKKt3OJpW2ndFIXnA9A4xAy/F3Xp1ixncW78= -cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= -cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= @@ -61,8 +56,6 @@ github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230305170008-8188dc5388df h github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230305170008-8188dc5388df/go.mod h1:pSwJ0fSY5KhvocuWSx4fz3BA8OrA1bQn+K1Eli3BRwM= github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d h1:Byv0BzEl3/e6D5CLfI0j/7hiIEtvGVFPCZ7Ei2oq8iQ= github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= -github.com/benbjohnson/clock v1.3.0 h1:ip6w0uFQkncKQ979AypyG0ER7mqUSBdKLOgAle/AT8A= -github.com/benbjohnson/clock v1.3.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM= @@ -83,14 +76,13 @@ github.com/cloudflare/circl v1.3.7/go.mod h1:sRTcRWXGLrKw6yIGJ+l7amYJFfAXbZG0kBS github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= -github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4 h1:/inchEIKaYC1Akx+H+gqO04wryn5h75LSazbRlnya1k= -github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/coredns/caddy v1.1.1 h1:2eYKZT7i6yxIfGP3qLJoJ7HAsDJqYB+X68g4NYjSrE0= github.com/coredns/caddy v1.1.1/go.mod h1:A6ntJQlAWuQfFlsd9hvigKbo2WS0VUs2l1e2F+BawD4= github.com/coredns/corefile-migration v1.0.21 h1:W/DCETrHDiFo0Wj03EyMkaQ9fwsmSgqTCQDHpceaSsE= github.com/coredns/corefile-migration v1.0.21/go.mod h1:XnhgULOEouimnzgn0t4WPuFDN2/PJQcTxdWKC5eXNGE= github.com/coreos/go-semver v0.3.1 h1:yi21YpKnrx1gt5R+la8n5WgS0kCrsPp33dmEyHReZr4= github.com/coreos/go-semver v0.3.1/go.mod h1:irMmmIw/7yzSRPWryHsK7EYSg09caPQL03VsM8rvUec= +github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf h1:iW4rZ826su+pqaw19uhpSCzhj44qo35pNgKFGqzDKkU= github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs= github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= @@ -113,8 +105,6 @@ github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1m github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/envoyproxy/protoc-gen-validate v1.0.2 h1:QkIBuU5k+x7/QXPvPPnWXWlCdaBFApVqftFV6k087DA= -github.com/envoyproxy/protoc-gen-validate v1.0.2/go.mod h1:GpiZQP3dDbg4JouG/NNS7QWXpgx6x8QiMKdmN72jogE= github.com/evanphx/json-patch v5.6.0+incompatible h1:jBYDEEiFBPxA0v50tFdvOzQQTCvpL6mnFh5mB2/l16U= github.com/evanphx/json-patch v5.6.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evanphx/json-patch/v5 v5.9.0 h1:kcBlZQbplgElYIlo/n1hJbls2z/1awpXxpRi0/FOJfg= @@ -124,21 +114,21 @@ github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSw github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY= github.com/frankban/quicktest v1.14.4/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= -github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= -github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= +github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= +github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= github.com/go-errors/errors v1.5.1 h1:ZwEMSLRCapFLflTpT7NKaAc7ukJ8ZPEjzlxt8rPN8bk= github.com/go-errors/errors v1.5.1/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= -github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.3.0 h1:2y3SDp0ZXuc6/cjLSZ+Q3ir+QB9T/iG5yYRXqsagWSY= github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= +github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= -github.com/go-logr/zapr v1.2.4 h1:QHVo+6stLbfJmYGkQ7uGHUCu5hnAFAj6mDe6Ea0SeOo= -github.com/go-logr/zapr v1.2.4/go.mod h1:FyHWQIzQORZ0QVE1BtVHv3cKtNLuXsbNLtpuhNapBOA= +github.com/go-logr/zapr v1.3.0 h1:XGdV8XW8zdwFiwOA2Dryh1gj2KRQyOOoNmBy4EplIcQ= +github.com/go-logr/zapr v1.3.0/go.mod h1:YKepepNBd1u/oyhd/yQmtjVXmm9uML4IXUgMOwR8/Gg= github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE= github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs= github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE= @@ -149,7 +139,6 @@ github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEe github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= github.com/gobuffalo/flect v1.0.2 h1:eqjPGSo2WmjgY2XlpGwo2NXgL3RucAKo4k4qQMNA5sA= github.com/gobuffalo/flect v1.0.2/go.mod h1:A5msMlrHtLqh9umBSnvabjsMrCcCpAyzglnDvkbYKHs= -github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg= @@ -189,8 +178,8 @@ github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Z github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4= github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA= -github.com/google/cel-go v0.16.1 h1:3hZfSNiAU3KOiNtxuFXVp5WFy4hf/Ly3Sa4/7F8SXNo= -github.com/google/cel-go v0.16.1/go.mod h1:HXZKzB0LXqer5lHHgfWAnlYwJaQBDKMjxjulNQzhwhY= +github.com/google/cel-go v0.17.7 h1:6ebJFzu1xO2n7TLtN+UBqShGBhlD85bhvglh5DpcfqQ= +github.com/google/cel-go v0.17.7/go.mod h1:HXZKzB0LXqer5lHHgfWAnlYwJaQBDKMjxjulNQzhwhY= github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I= github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= @@ -237,8 +226,8 @@ github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+ github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= -github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= -github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= +github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 h1:+9834+KizmvFV7pXQGSXQTsaWhq2GjuNUt0aUU0YBYw= github.com/grpc-ecosystem/go-grpc-middleware v1.3.0/go.mod h1:z0ButlSOZa5vEBq9m2m2hlwIgKw+rp3sdCBRoJY+30Y= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92BcuyuQ/YW4NSIpoGtfXNho= @@ -283,8 +272,8 @@ github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0V github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= -github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= -github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= +github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 h1:jWpvCLoY8Z/e3VKvlsiIGKtc+UG6U5vzxaoagmhXfyg= +github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0/go.mod h1:QUyp042oQthUoa9bqDv0ER0wrtXnBruoNd7aNjkbP+k= github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= @@ -314,15 +303,15 @@ github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qR github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/prometheus/client_golang v1.17.0 h1:rl2sfwZMtSthVU752MqfjQozy7blglC+1SOtjMAMh+Q= -github.com/prometheus/client_golang v1.17.0/go.mod h1:VeL+gMmOAxkS2IqfCq0ZmHSL+LjWfWDUmp1mBz9JgUY= +github.com/prometheus/client_golang v1.18.0 h1:HzFfmkOzH5Q8L8G+kSJKUx5dtG87sewO+FoDDqP5Tbk= +github.com/prometheus/client_golang v1.18.0/go.mod h1:T+GXkCk5wSJyOqMIzVgvvjFDlkOQntgjkJWKrN5txjA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.4.1-0.20230718164431-9a2bf3000d16 h1:v7DLqVdK4VrYkVD5diGdl4sxJurKJEMnODWRJlxV9oM= -github.com/prometheus/client_model v0.4.1-0.20230718164431-9a2bf3000d16/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU= -github.com/prometheus/common v0.44.0 h1:+5BrQJwiBB9xsMygAB3TNvpQKOwlkc25LbISbrdOOfY= -github.com/prometheus/common v0.44.0/go.mod h1:ofAIvZbQ1e/nugmZGz4/qCb9Ap1VoSTIO7x0VV9VvuY= -github.com/prometheus/procfs v0.11.1 h1:xRC8Iq1yyca5ypa9n1EZnWZkt7dwcoRPQwX/5gwaUuI= -github.com/prometheus/procfs v0.11.1/go.mod h1:eesXgaPo1q7lBpVMoMy0ZOFTth9hBn4W/y0/p/ScXhY= +github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw= +github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI= +github.com/prometheus/common v0.45.0 h1:2BGz0eBc2hdMDLnO/8n0jeB3oPrt2D08CekT0lneoxM= +github.com/prometheus/common v0.45.0/go.mod h1:YJmSTw9BoKxJplESWWxlbyttQR4uaEcGyv9MZjVOJsY= +github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo= +github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= @@ -360,6 +349,7 @@ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXf github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= @@ -379,22 +369,22 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= -go.etcd.io/bbolt v1.3.7 h1:j+zJOnnEjF/kyHlDDgGnVL/AIqIJPq8UoB2GSNfkUfQ= -go.etcd.io/bbolt v1.3.7/go.mod h1:N9Mkw9X8x5fupy0IKsmuqVtoGDyxsaDlbk4Rd05IAQw= +go.etcd.io/bbolt v1.3.8 h1:xs88BrvEv273UsB79e0hcVrlUWmS0a8upikMFhSyAtA= +go.etcd.io/bbolt v1.3.8/go.mod h1:N9Mkw9X8x5fupy0IKsmuqVtoGDyxsaDlbk4Rd05IAQw= go.etcd.io/etcd/api/v3 v3.5.10 h1:szRajuUUbLyppkhs9K6BRtjY37l66XQQmw7oZRANE4k= go.etcd.io/etcd/api/v3 v3.5.10/go.mod h1:TidfmT4Uycad3NM/o25fG3J07odo4GBB9hoxaodFCtI= go.etcd.io/etcd/client/pkg/v3 v3.5.10 h1:kfYIdQftBnbAq8pUWFXfpuuxFSKzlmM5cSn76JByiT0= go.etcd.io/etcd/client/pkg/v3 v3.5.10/go.mod h1:DYivfIviIuQ8+/lCq4vcxuseg2P2XbHygkKwFo9fc8U= -go.etcd.io/etcd/client/v2 v2.305.9 h1:YZ2OLi0OvR0H75AcgSUajjd5uqKDKocQUqROTG11jIo= -go.etcd.io/etcd/client/v2 v2.305.9/go.mod h1:0NBdNx9wbxtEQLwAQtrDHwx58m02vXpDcgSYI2seohQ= +go.etcd.io/etcd/client/v2 v2.305.10 h1:MrmRktzv/XF8CvtQt+P6wLUlURaNpSDJHFZhe//2QE4= +go.etcd.io/etcd/client/v2 v2.305.10/go.mod h1:m3CKZi69HzilhVqtPDcjhSGp+kA1OmbNn0qamH80xjA= go.etcd.io/etcd/client/v3 v3.5.10 h1:W9TXNZ+oB3MCd/8UjxHTWK5J9Nquw9fQBLJd5ne5/Ao= go.etcd.io/etcd/client/v3 v3.5.10/go.mod h1:RVeBnDz2PUEZqTpgqwAtUd8nAPf5kjyFyND7P1VkOKc= -go.etcd.io/etcd/pkg/v3 v3.5.9 h1:6R2jg/aWd/zB9+9JxmijDKStGJAPFsX3e6BeJkMi6eQ= -go.etcd.io/etcd/pkg/v3 v3.5.9/go.mod h1:BZl0SAShQFk0IpLWR78T/+pyt8AruMHhTNNX73hkNVY= -go.etcd.io/etcd/raft/v3 v3.5.9 h1:ZZ1GIHoUlHsn0QVqiRysAm3/81Xx7+i2d7nSdWxlOiI= -go.etcd.io/etcd/raft/v3 v3.5.9/go.mod h1:WnFkqzFdZua4LVlVXQEGhmooLeyS7mqzS4Pf4BCVqXg= -go.etcd.io/etcd/server/v3 v3.5.9 h1:vomEmmxeztLtS5OEH7d0hBAg4cjVIu9wXuNzUZx2ZA0= -go.etcd.io/etcd/server/v3 v3.5.9/go.mod h1:GgI1fQClQCFIzuVjlvdbMxNbnISt90gdfYyqiAIt65g= +go.etcd.io/etcd/pkg/v3 v3.5.10 h1:WPR8K0e9kWl1gAhB5A7gEa5ZBTNkT9NdNWrR8Qpo1CM= +go.etcd.io/etcd/pkg/v3 v3.5.10/go.mod h1:TKTuCKKcF1zxmfKWDkfz5qqYaE3JncKKZPFf8c1nFUs= +go.etcd.io/etcd/raft/v3 v3.5.10 h1:cgNAYe7xrsrn/5kXMSaH8kM/Ky8mAdMqGOxyYwpP0LA= +go.etcd.io/etcd/raft/v3 v3.5.10/go.mod h1:odD6kr8XQXTy9oQnyMPBOr0TVe+gT0neQhElQ6jbGRc= +go.etcd.io/etcd/server/v3 v3.5.10 h1:4NOGyOwD5sUZ22PiWYKmfxqoeh72z6EhYjNosKGLmZg= +go.etcd.io/etcd/server/v3 v3.5.10/go.mod h1:gBplPHfs6YI0L+RpGkTQO7buDbHv5HJGG/Bst0/zIPo= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= @@ -423,8 +413,8 @@ go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= -go.uber.org/zap v1.25.0 h1:4Hvk6GtkucQ790dqmj7l1eEnRdKm3k3ZUrUMS2d5+5c= -go.uber.org/zap v1.25.0/go.mod h1:JIAUzQIH94IC4fOJQm7gMmBJP5k7wQfdcnYdPoEXJYk= +go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo= +go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= @@ -571,7 +561,6 @@ golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= @@ -780,40 +769,38 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -k8s.io/api v0.28.8 h1:G0/G7yX1puRAcon/+XPLsKXZ9A5L7Ds6oKbDIe027xw= -k8s.io/api v0.28.8/go.mod h1:rU8f1t9CNUAXlk/1j/wMJ7XnaxkR1g1AlZGQAOOL+sw= -k8s.io/apiextensions-apiserver v0.28.8 h1:JucS9tcaMMlfFrJ09cgh1Maeb8X2wlnxcfNpplyGHXs= -k8s.io/apiextensions-apiserver v0.28.8/go.mod h1:IKpLiKmvEYq/ti8sNtB1sM3A3vVV7fILIsvdmZswhoQ= -k8s.io/apimachinery v0.28.8 h1:hi/nrxHwk4QLV+W/SHve1bypTE59HCDorLY1stBIxKQ= -k8s.io/apimachinery v0.28.8/go.mod h1:cBnwIM3fXoRo28SqbV/Ihxf/iviw85KyXOrzxvZQ83U= -k8s.io/apiserver v0.28.8 h1:lvgyawcJFRW12oqXLydxY83nAJ5pvJJM9JX35JnKEvg= -k8s.io/apiserver v0.28.8/go.mod h1:ruOdEqhd7TzAwXMlIXdig3tQJrsv9g1F+kIF8OJRGHM= -k8s.io/client-go v0.28.8 h1:TE59Tjd87WKvS2FPBTfIKLFX0nQJ4SSHsnDo5IHjgOw= -k8s.io/client-go v0.28.8/go.mod h1:uDVQ/rPzWpWIy40c6lZ4mUwaEvRWGnpoqSO4FM65P3o= +k8s.io/api v0.29.0 h1:NiCdQMY1QOp1H8lfRyeEf8eOwV6+0xA6XEE44ohDX2A= +k8s.io/api v0.29.0/go.mod h1:sdVmXoz2Bo/cb77Pxi71IPTSErEW32xa4aXwKH7gfBA= +k8s.io/apiextensions-apiserver v0.29.0 h1:0VuspFG7Hj+SxyF/Z/2T0uFbI5gb5LRgEyUVE3Q4lV0= +k8s.io/apiextensions-apiserver v0.29.0/go.mod h1:TKmpy3bTS0mr9pylH0nOt/QzQRrW7/h7yLdRForMZwc= +k8s.io/apimachinery v0.29.0 h1:+ACVktwyicPz0oc6MTMLwa2Pw3ouLAfAon1wPLtG48o= +k8s.io/apimachinery v0.29.0/go.mod h1:eVBxQ/cwiJxH58eK/jd/vAk4mrxmVlnpBH5J2GbMeis= +k8s.io/apiserver v0.29.0 h1:Y1xEMjJkP+BIi0GSEv1BBrf1jLU9UPfAnnGGbbDdp7o= +k8s.io/apiserver v0.29.0/go.mod h1:31n78PsRKPmfpee7/l9NYEv67u6hOL6AfcE761HapDM= +k8s.io/client-go v0.29.0 h1:KmlDtFcrdUzOYrBhXHgKw5ycWzc3ryPX5mQe0SkG3y8= +k8s.io/client-go v0.29.0/go.mod h1:yLkXH4HKMAywcrD82KMSmfYg2DlE8mepPR4JGSo5n38= k8s.io/cluster-bootstrap v0.28.4 h1:4MKNy1Qd9QY7pl47rSMGIORF+tm3CUaqC1M8U9bjn4Q= k8s.io/cluster-bootstrap v0.28.4/go.mod h1:/c4ro/R4yf4EtJgFgFtvnHkbDOHwubeKJXh5R1c89Bc= -k8s.io/component-base v0.28.8 h1:N/c5L6Ty5rcrFyhsMYsqRFUOVGrqGQsLfjB0yj6npqM= -k8s.io/component-base v0.28.8/go.mod h1:9PjQ4nM1Hth6WGe/O+wgLF32eSwf4oPOoN5elmFznJM= -k8s.io/klog/v2 v2.100.1 h1:7WCHKK6K8fNhTqfBhISHQ97KrnJNFZMcQvKp7gP/tmg= -k8s.io/klog/v2 v2.100.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= -k8s.io/kms v0.28.8 h1:XtRE2ouizgt3RECxUcDLsa11pmURj+2sfA55wbtd8EY= -k8s.io/kms v0.28.8/go.mod h1:tdtu+bD8i4FU+QZ0gq1Xr1FjomhyUsaSD3ljK0YFwUg= -k8s.io/kube-openapi v0.0.0-20230717233707-2695361300d9 h1:LyMgNKD2P8Wn1iAwQU5OhxCKlKJy0sHc+PcDwFB24dQ= -k8s.io/kube-openapi v0.0.0-20230717233707-2695361300d9/go.mod h1:wZK2AVp1uHCp4VamDVgBP2COHZjqD1T68Rf0CM3YjSM= -k8s.io/utils v0.0.0-20230406110748-d93618cff8a2 h1:qY1Ad8PODbnymg2pRbkyMT/ylpTrCM8P2RJ0yroCyIk= -k8s.io/utils v0.0.0-20230406110748-d93618cff8a2/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +k8s.io/component-base v0.29.0 h1:T7rjd5wvLnPBV1vC4zWd/iWRbV8Mdxs+nGaoaFzGw3s= +k8s.io/component-base v0.29.0/go.mod h1:sADonFTQ9Zc9yFLghpDpmNXEdHyQmFIGbiuZbqAXQ1M= +k8s.io/klog/v2 v2.110.1 h1:U/Af64HJf7FcwMcXyKm2RPM22WZzyR7OSpYj5tg3cL0= +k8s.io/klog/v2 v2.110.1/go.mod h1:YGtd1984u+GgbuZ7e08/yBuAfKLSO0+uR1Fhi6ExXjo= +k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00 h1:aVUu9fTY98ivBPKR9Y5w/AuzbMm96cd3YHRTU83I780= +k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00/go.mod h1:AsvuZPBlUDVuCdzJ87iajxtXuR9oktsTctW/R9wwouA= +k8s.io/utils v0.0.0-20230726121419-3b25d923346b h1:sgn3ZU783SCgtaSJjpcVVlRqd6GSnlTLKgpAAttJvpI= +k8s.io/utils v0.0.0-20230726121419-3b25d923346b/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= -sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.1.2 h1:trsWhjU5jZrx6UvFu4WzQDrN7Pga4a7Qg+zcfcj64PA= -sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.1.2/go.mod h1:+qG7ISXqCDVVcyO8hLn12AKVYYUjM7ftlqsqmrhMZE0= +sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.28.0 h1:TgtAeesdhpm2SGwkQasmbeqDo8th5wOBA5h/AjTKA4I= +sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.28.0/go.mod h1:VHVDI/KrK4fjnV61bE2g3sA7tiETLn8sooImelsCx3Y= sigs.k8s.io/cluster-api v1.6.3 h1:VOlPNg92PQLlhBVLc5pg+cbAuPvGOOBujeFLk9zgnoo= sigs.k8s.io/cluster-api v1.6.3/go.mod h1:4FzfgPPiYaFq8X9F9j2SvmggH/4OOLEDgVJuWDqKLig= -sigs.k8s.io/controller-runtime v0.16.5 h1:yr1cEJbX08xsTW6XEIzT13KHHmIyX8Umvme2cULvFZw= -sigs.k8s.io/controller-runtime v0.16.5/go.mod h1:j7bialYoSn142nv9sCOJmQgDXQXxnroFU4VnX/brVJ0= +sigs.k8s.io/controller-runtime v0.17.2 h1:FwHwD1CTUemg0pW2otk7/U5/i5m2ymzvOXdbeGOUvw0= +sigs.k8s.io/controller-runtime v0.17.2/go.mod h1:+MngTvIQQQhfXtwfdGw/UOQ/aIaqsYywfCINOtwMO/s= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= -sigs.k8s.io/structured-merge-diff/v4 v4.2.3 h1:PRbqxJClWWYMNV1dhaG4NsibJbArud9kFxnAMREiWFE= -sigs.k8s.io/structured-merge-diff/v4 v4.2.3/go.mod h1:qjx8mGObPmV2aSZepjQjbmb2ihdVs8cGKBraizNC69E= +sigs.k8s.io/structured-merge-diff/v4 v4.4.1 h1:150L+0vs/8DA78h1u02ooW1/fFq/Lwr+sGiqlzvrtq4= +sigs.k8s.io/structured-merge-diff/v4 v4.4.1/go.mod h1:N8hJocpFajUSSeSJ9bOZ77VzejKZaXsTtZo4/u7Io08= sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E= sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY= 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 c6c8c1813..dd33891e8 100644 --- a/internal/controller/healthcheck/healthcheck_controller.go +++ b/internal/controller/healthcheck/healthcheck_controller.go @@ -62,42 +62,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.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 @@ -109,23 +98,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. @@ -177,7 +159,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 @@ -187,7 +169,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), @@ -206,7 +188,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 04b4b69a4..885566ba5 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,10 @@ func TestMain(m *testing.M) { env = envtest.New() - if err := (&providercontroller.GenericProviderReconciler{ - Provider: &operatorv1.CoreProvider{}, - ProviderList: &operatorv1.CoreProviderList{}, - Client: env, - }).SetupWithManager(env.Manager, controller.Options{MaxConcurrentReconciles: 1}); err != nil { + if err := providercontroller.NewProviderControllerWrapper( + providers.NewCoreProviderReconciler(env), + phases.NewPhase, + ).SetupWithManager(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 7b0531e9c..91bea13f7 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" @@ -28,7 +28,7 @@ import ( "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/client-go/kubernetes/scheme" configv1alpha1 "k8s.io/component-base/config/v1alpha1" - "k8s.io/utils/pointer" + "k8s.io/utils/ptr" operatorv1 "sigs.k8s.io/cluster-api-operator/api/v1alpha2" "sigs.k8s.io/cluster-api/util" ) @@ -131,7 +131,7 @@ func customizeDeploymentSpec(pSpec operatorv1.ProviderSpec, d *appsv1.Deployment dSpec := pSpec.Deployment if dSpec.Replicas != nil { - d.Spec.Replicas = pointer.Int32(int32(*dSpec.Replicas)) + d.Spec.Replicas = ptr.To(int32(*dSpec.Replicas)) } if dSpec.Affinity != nil { diff --git a/internal/controller/component_customizer_test.go b/internal/controller/phases/component_customizer_test.go similarity index 97% rename from internal/controller/component_customizer_test.go rename to internal/controller/phases/component_customizer_test.go index 9b386811b..2ed76b788 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" @@ -30,7 +30,7 @@ import ( "k8s.io/apimachinery/pkg/util/intstr" "k8s.io/client-go/kubernetes/scheme" configv1alpha1 "k8s.io/component-base/config/v1alpha1" - "k8s.io/utils/pointer" + "k8s.io/utils/ptr" operatorv1 "sigs.k8s.io/cluster-api-operator/api/v1alpha2" ) @@ -112,11 +112,11 @@ func TestCustomizeDeployment(t *testing.T) { { name: "only replicas modified", inputDeploymentSpec: &operatorv1.DeploymentSpec{ - Replicas: pointer.Int(3), + Replicas: ptr.To(3), }, expectedDeploymentSpec: func(inputDS *appsv1.DeploymentSpec) (*appsv1.DeploymentSpec, bool) { expectedDS := &appsv1.DeploymentSpec{ - Replicas: pointer.Int32(3), + Replicas: ptr.To(int32(3)), } return expectedDS, reflect.DeepEqual(inputDS.Replicas, expectedDS.Replicas) @@ -251,7 +251,7 @@ func TestCustomizeDeployment(t *testing.T) { Containers: []operatorv1.ContainerSpec{ { Name: "manager", - ImageURL: pointer.String("quay.io/dev/mydns:v3.4.2"), + ImageURL: ptr.To("quay.io/dev/mydns:v3.4.2"), Env: []corev1.EnvVar{ { Name: "test1", @@ -324,7 +324,7 @@ func TestCustomizeDeployment(t *testing.T) { { name: "all deployment options", inputDeploymentSpec: &operatorv1.DeploymentSpec{ - Replicas: pointer.Int(3), + Replicas: ptr.To(3), NodeSelector: map[string]string{"a": "b"}, Tolerations: []corev1.Toleration{ { @@ -351,7 +351,7 @@ func TestCustomizeDeployment(t *testing.T) { Containers: []operatorv1.ContainerSpec{ { Name: "manager", - ImageURL: pointer.String("quay.io/dev/mydns:v3.4.2"), + ImageURL: ptr.To("quay.io/dev/mydns:v3.4.2"), Env: []corev1.EnvVar{ { Name: "test1", @@ -375,7 +375,7 @@ func TestCustomizeDeployment(t *testing.T) { }, expectedDeploymentSpec: func(inputDS *appsv1.DeploymentSpec) (*appsv1.DeploymentSpec, bool) { expectedDS := &appsv1.DeploymentSpec{ - Replicas: pointer.Int32(3), + Replicas: ptr.To(int32(3)), Template: corev1.PodTemplateSpec{ Spec: corev1.PodSpec{ NodeSelector: map[string]string{"a": "b"}, @@ -480,11 +480,11 @@ func TestCustomizeDeployment(t *testing.T) { LivenessEndpointName: "mostly", }, Webhook: operatorv1.ControllerWebhook{ - Port: pointer.Int(3579), + Port: ptr.To(3579), CertDir: "/tmp/certs", }, LeaderElection: &configv1alpha1.LeaderElectionConfiguration{ - LeaderElect: pointer.Bool(true), + LeaderElect: ptr.To(true), ResourceName: "foo", ResourceNamespace: "here", LeaseDuration: metav1.Duration{Duration: sevenHours}, @@ -602,7 +602,7 @@ func TestCustomizeMultipleDeployment(t *testing.T) { Namespace: metav1.NamespaceSystem, }, Spec: appsv1.DeploymentSpec{ - Replicas: pointer.Int32(3), + Replicas: ptr.To(int32(3)), }, } @@ -627,7 +627,7 @@ func TestCustomizeMultipleDeployment(t *testing.T) { Spec: operatorv1.CoreProviderSpec{ ProviderSpec: operatorv1.ProviderSpec{ Deployment: &operatorv1.DeploymentSpec{ - Replicas: pointer.Int(10), + Replicas: ptr.To(10), }, }, }, 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/consts.go b/internal/controller/phases/consts.go similarity index 54% rename from internal/controller/consts.go rename to internal/controller/phases/consts.go index 8606017ad..8e3541ef1 100644 --- a/internal/controller/consts.go +++ b/internal/controller/phases/consts.go @@ -1,5 +1,5 @@ /* -Copyright 2021 The Kubernetes Authors. +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. @@ -14,15 +14,22 @@ See the License for the specific language governing permissions and limitations under the License. */ -package controller - -import "time" +package phases const ( - // preflightFailedRequeueAfter is how long to wait before trying to reconcile - // if some preflight check has failed. - preflightFailedRequeueAfter = 30 * time.Second - // 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" + + metadataConfigMapKey = "metadata" + componentsConfigMapKey = "components" + additionalManifestsConfigMapKey = "manifests" + + maxConfigMapSize = 1 * 1024 * 1024 ) diff --git a/internal/controller/manifests_downloader.go b/internal/controller/phases/manifests_downloader.go similarity index 72% rename from internal/controller/manifests_downloader.go rename to internal/controller/phases/manifests_downloader.go index dc29d190e..7d38a3226 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" @@ -32,30 +32,16 @@ import ( "sigs.k8s.io/controller-runtime/pkg/reconcile" 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 ( - 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" - - metadataConfigMapKey = "metadata" - componentsConfigMapKey = "components" - additionalManifestsConfigMapKey = "manifests" - - maxConfigMapSize = 1 * 1024 * 1024 -) - -// 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 @@ -63,10 +49,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) } @@ -79,42 +65,42 @@ func (p *phaseReconciler) downloadManifests(ctx context.Context) (reconcile.Resu log.Info("Downloading provider manifests") - repo, err := util.RepositoryFactory(ctx, p.providerConfig, p.configClient.Variables()) + 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) + err = fmt.Errorf("failed to create repo from provider url for provider %q: %w", phase.GetProvider().GetName(), err) return reconcile.Result{}, wrapPhaseError(err, operatorv1.ComponentsFetchErrorReason, operatorv1.ProviderInstalledCondition) } - spec := p.provider.GetSpec() + spec := phase.GetProvider().GetSpec() if spec.Version == "" { // User didn't set the version, try to get repository default. spec.Version = repo.DefaultVersion() // Add version to the provider spec. - p.provider.SetSpec(spec) + phase.GetProvider().SetSpec(spec) } // Fetch the provider metadata and components yaml files from the provided repository GitHub/GitLab. metadataFile, err := repo.GetFile(ctx, spec.Version, metadataFile) if err != nil { - err = fmt.Errorf("failed to read %q from the repository for provider %q: %w", metadataFile, p.provider.GetName(), err) + err = fmt.Errorf("failed to read %q from the repository for provider %q: %w", metadataFile, phase.GetProvider().GetName(), err) return reconcile.Result{}, wrapPhaseError(err, operatorv1.ComponentsFetchErrorReason, operatorv1.ProviderInstalledCondition) } componentsFile, err := repo.GetFile(ctx, spec.Version, repo.ComponentsPath()) if err != nil { - err = fmt.Errorf("failed to read %q from the repository for provider %q: %w", componentsFile, p.provider.GetName(), err) + err = fmt.Errorf("failed to read %q from the repository for provider %q: %w", componentsFile, phase.GetProvider().GetName(), err) return reconcile.Result{}, wrapPhaseError(err, operatorv1.ComponentsFetchErrorReason, operatorv1.ProviderInstalledCondition) } withCompression := needToCompress(metadataFile, componentsFile) - if err := p.createManifestsConfigMap(ctx, metadataFile, componentsFile, withCompression); err != nil { - err = fmt.Errorf("failed to create config map for provider %q: %w", p.provider.GetName(), err) + if err := p.createManifestsConfigMap(ctx, phase, metadataFile, componentsFile, withCompression); err != nil { + err = fmt.Errorf("failed to create config map for provider %q: %w", phase.GetProvider().GetName(), err) return reconcile.Result{}, wrapPhaseError(err, operatorv1.ComponentsFetchErrorReason, operatorv1.ProviderInstalledCondition) } @@ -123,7 +109,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)}, @@ -132,7 +118,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) } @@ -143,20 +129,15 @@ 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) -} - // createManifestsConfigMap creates a config map with downloaded manifests. -func (p *phaseReconciler) createManifestsConfigMap(ctx context.Context, metadata, components []byte, compress bool) error { - configMapName := fmt.Sprintf("%s-%s-%s", p.provider.GetType(), p.provider.GetName(), p.provider.GetSpec().Version) +func (p *PhaseReconciler[P, G]) createManifestsConfigMap(ctx context.Context, phase generic.Group[P], metadata, components []byte, compress bool) error { + configMapName := fmt.Sprintf("%s-%s-%s", phase.GetProvider().GetType(), phase.GetProvider().GetName(), phase.GetProvider().GetSpec().Version) configMap := &corev1.ConfigMap{ ObjectMeta: metav1.ObjectMeta{ Name: configMapName, - Namespace: p.provider.GetNamespace(), - Labels: p.prepareConfigMapLabels(), + Namespace: phase.GetProvider().GetNamespace(), + Labels: providerLabels(phase.GetProvider()), }, Data: map[string]string{ metadataConfigMapKey: string(metadata), @@ -172,7 +153,7 @@ func (p *phaseReconciler) createManifestsConfigMap(ctx context.Context, metadata _, err := zw.Write(components) if err != nil { - return fmt.Errorf("cannot compress data for provider %s/%s: %w", p.provider.GetNamespace(), p.provider.GetName(), err) + return fmt.Errorf("cannot compress data for provider %s/%s: %w", phase.GetProvider().GetNamespace(), phase.GetProvider().GetName(), err) } if err := zw.Close(); err != nil { @@ -187,14 +168,14 @@ func (p *phaseReconciler) createManifestsConfigMap(ctx context.Context, metadata configMap.SetAnnotations(map[string]string{compressedAnnotation: "true"}) } - gvk := p.provider.GetObjectKind().GroupVersionKind() + gvk := phase.GetProvider().GetObjectKind().GroupVersionKind() configMap.SetOwnerReferences([]metav1.OwnerReference{ { APIVersion: gvk.GroupVersion().String(), Kind: gvk.Kind, - Name: p.provider.GetName(), - UID: p.provider.GetUID(), + Name: phase.GetProvider().GetName(), + UID: phase.GetProvider().GetUID(), }, }) diff --git a/internal/controller/manifests_downloader_test.go b/internal/controller/phases/manifests_downloader_test.go similarity index 57% rename from internal/controller/manifests_downloader_test.go rename to internal/controller/phases/manifests_downloader_test.go index f564100b9..3177b1f2b 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" @@ -25,6 +25,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client/fake" operatorv1 "sigs.k8s.io/cluster-api-operator/api/v1alpha2" + clusterctlv1 "sigs.k8s.io/cluster-api/cmd/clusterctl/api/v1alpha3" ) func TestManifestsDownloader(t *testing.T) { @@ -36,33 +37,43 @@ func TestManifestsDownloader(t *testing.T) { namespace := "test-namespace" - p := &phaseReconciler{ - ctrlClient: fakeclient, - provider: &operatorv1.CoreProvider{ - ObjectMeta: metav1.ObjectMeta{ - Name: "cluster-api", - Namespace: namespace, - }, - Spec: operatorv1.CoreProviderSpec{ - ProviderSpec: operatorv1.ProviderSpec{ - Version: "v1.4.3", - }, + 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()) diff --git a/internal/controller/phases.go b/internal/controller/phases/phases.go similarity index 55% rename from internal/controller/phases.go rename to internal/controller/phases/phases.go index e2b2147cf..d24532b26 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" @@ -52,25 +53,74 @@ const ( metadataFile = "metadata.yaml" ) -// 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 { + ctrlClient client.Client + Repo repository.Repository + Contract string + Options repository.ComponentsOptions + ProviderConfig configclient.Provider + ConfigClient configclient.Client + Components repository.Components +} + +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 +} - ctrlClient client.Client - ctrlConfig *rest.Config - repo repository.Repository - contract string - options repository.ComponentsOptions - providerConfig configclient.Provider - configClient configclient.Client - components repository.Components - clusterctlProvider *clusterctlv1.Provider +// GetConfig implements generic.ProviderGroup. +func (p Phase[P]) GetConfig() *rest.Config { + return p.Config } -// reconcilePhaseFn is a function that represent a phase of the reconciliation. -type reconcilePhaseFn func(context.Context) (reconcile.Result, error) +// 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 +147,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 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 = "" @@ -133,20 +174,20 @@ func (p *phaseReconciler) initializePhaseReconciler(ctx context.Context) (reconc return reconcile.Result{}, err } - reader, err := p.secretReader(ctx, providers...) + reader, err := secretReader(ctx, phase, providers...) if err != nil { return reconcile.Result{}, err } // 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) } @@ -154,59 +195,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.fetchAddionalManifests(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) } @@ -215,7 +256,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() @@ -225,11 +266,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 } @@ -247,13 +288,13 @@ func (p *phaseReconciler) secretReader(ctx context.Context, providers ...configc } // 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 @@ -262,7 +303,7 @@ func (p *phaseReconciler) secretReader(ctx context.Context, providers ...configc fakeURL := "https://example.com/my-provider" - return mr.AddProvider(p.provider.GetName(), util.ClusterctlProviderType(p.provider), fakeURL) + return mr.AddProvider(phase.GetProvider().GetName(), phase.ClusterctlProviderType(), fakeURL) } } @@ -271,7 +312,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") @@ -282,7 +323,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 } @@ -328,13 +369,13 @@ func (p *phaseReconciler) configmapRepository(ctx context.Context, labelSelector return mr, nil } -func (p *phaseReconciler) fetchAddionalManifests(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) } } @@ -378,10 +419,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) } @@ -395,34 +436,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) } @@ -430,12 +471,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) @@ -443,64 +484,64 @@ 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) } - conditions.Set(p.provider, conditions.TrueCondition(operatorv1.ProviderInstalledCondition)) + conditions.Set(phase.GetProvider(), conditions.TrueCondition(operatorv1.ProviderInstalledCondition)) 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" @@ -510,46 +551,36 @@ 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(ctx 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 } -// delete deletes the provider components using clusterctl library. -func (p *phaseReconciler) delete(ctx context.Context) (reconcile.Result, error) { +// Delete deletes the provider components using clusterctl library. +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, }) @@ -557,34 +588,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-" - } - - 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 { @@ -592,7 +605,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) @@ -606,17 +619,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 d4308d603..a45c4983c 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) @@ -42,27 +45,23 @@ func TestSecretReader(t *testing.T) { secretName := "test-secret" secretNamespace := "test-secret-namespace" namespace := "test-namespace" - - p := &phaseReconciler{ - ctrlClient: fakeclient, - provider: &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", - }, + 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", }, }, }, @@ -86,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) @@ -381,16 +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 @@ -415,6 +415,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) @@ -578,11 +584,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 { @@ -590,7 +595,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 53% rename from internal/controller/preflight_checks.go rename to internal/controller/phases/preflight_checks.go index 260d96c96..311688ca5 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" @@ -27,96 +27,79 @@ 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 ( - moreThanOneCoreProviderInstanceExistsMessage = "CoreProvider already exists in the cluster. Only one is allowed." - moreThanOneProviderInstanceExistsMessage = "There is already a %s with name %s in the cluster. Only one is allowed." - capiVersionIncompatibilityMessage = "CAPI operator is only compatible with %s providers, detected %s for provider %s." - invalidGithubTokenMessage = "Invalid github token, please check your github token value and its permissions" //nolint:gosec - waitingForCoreProviderReadyMessage = "Waiting for the core provider to be installed." - incorrectCoreProviderNameMessage = "Incorrect CoreProvider name: %s. It should be %s" - unsupportedProviderDowngradeMessage = "Downgrade is not supported for provider %s" + moreThanOneProviderInstanceExistsMessage = "There is already a %s with name %s in the cluster. Only one is allowed." + capiVersionIncompatibilityMessage = "CAPI operator is only compatible with %s providers, detected %s for provider %s." + invalidGithubTokenMessage = "Invalid github token, please check your github token value and its permissions" //nolint:gosec + unsupportedProviderDowngradeMessage = "Downgrade is not supported for provider %s" ) -// preflightChecks performs preflight checks before installing provider. -func preflightChecks(ctx context.Context, c client.Client, provider genericprovider.GenericProvider, providerList genericprovider.GenericProviderList) (ctrl.Result, 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 { + if err := checkProviderVersion(ctx, spec.Version, phase.GetProvider()); err != nil { return ctrl.Result{}, 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, - fmt.Sprintf(incorrectCoreProviderNameMessage, provider.GetName(), configclient.ClusterAPIProviderName), - )) - - return ctrl.Result{}, fmt.Errorf("incorrect CoreProvider name: %s, it should be %s", provider.GetName(), configclient.ClusterAPIProviderName) - } - } - // 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 ctrl.Result{}, fmt.Errorf("failed to generate a list of predefined providers: %w", err) } - if !isPredefinedProvider { - if spec.FetchConfig == nil || spec.FetchConfig.Selector == nil && spec.FetchConfig.URL == "" { - conditions.Set(provider, conditions.FalseCondition( - operatorv1.PreflightCheckCondition, - operatorv1.FetchConfigValidationErrorReason, - clusterv1.ConditionSeverityError, - "Either Selector or URL must be provided for a not predefined provider", - )) + switch { + case !isPredefinedProvider && spec.FetchConfig == nil: + conditions.Set(phase.GetProvider(), conditions.FalseCondition( + operatorv1.PreflightCheckCondition, + operatorv1.FetchConfigValidationErrorReason, + clusterv1.ConditionSeverityError, + "Either Selector or URL must be provided for a not predefined provider", + )) - return ctrl.Result{}, fmt.Errorf("either selector or URL must be provided for a not predefined provider %s", provider.GetName()) - } - } + return ctrl.Result{}, fmt.Errorf("either selector or URL must be provided for a not predefined provider %s", phase.GetProvider().GetName()) + case spec.FetchConfig != nil && (spec.FetchConfig.Selector == nil && spec.FetchConfig.URL == ""): + conditions.Set(phase.GetProvider(), conditions.FalseCondition( + operatorv1.PreflightCheckCondition, + operatorv1.FetchConfigValidationErrorReason, + clusterv1.ConditionSeverityError, + "Either Selector or URL must be provided for a fetchConfig", + )) - if spec.FetchConfig != nil && spec.FetchConfig.Selector != nil && spec.FetchConfig.URL != "" { + return ctrl.Result{}, fmt.Errorf("either selector or URL must be provided for provider %s", phase.GetProvider().GetName()) + case 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 ctrl.Result{}, 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 { + if err := phase.GetClient().Get(ctx, key, secret); err != nil { return ctrl.Result{}, fmt.Errorf("failed to get providers secret: %w", err) } @@ -125,7 +108,7 @@ func preflightChecks(ctx context.Context, c client.Client, provider genericprovi &oauth2.Token{AccessToken: string(token)}, ))) if _, _, err := client.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, @@ -137,14 +120,10 @@ func preflightChecks(ctx context.Context, c client.Client, provider genericprovi } } - if err := c.List(ctx, providerList); err != nil { - return ctrl.Result{}, 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 } @@ -155,46 +134,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 ctrl.Result{}, 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 ctrl.Result{}, 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 ctrl.Result{}, 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, - waitingForCoreProviderReadyMessage, - )) - - return ctrl.Result{RequeueAfter: preflightFailedRequeueAfter}, nil - } - } - - conditions.Set(provider, conditions.TrueCondition(operatorv1.PreflightCheckCondition)) + conditions.Set(phase.GetProvider(), conditions.TrueCondition(operatorv1.PreflightCheckCondition)) log.Info("Preflight checks passed") @@ -202,7 +152,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. @@ -241,25 +191,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 { - for _, cond := range cp.Status.Conditions { - if cond.Type == clusterv1.ReadyCondition && cond.Status == corev1.ConditionTrue { - return true, nil - } - } - } - - return false, nil -} - // isPredefinedProvider checks if a given provider is known for Cluster API. // The list of known providers can be found here: // https://github.com/kubernetes-sigs/cluster-api/blob/main/cmd/clusterctl/client/config/providers_client.go diff --git a/internal/controller/phases/suite_test.go b/internal/controller/phases/suite_test.go new file mode 100644 index 000000000..65204d4c0 --- /dev/null +++ b/internal/controller/phases/suite_test.go @@ -0,0 +1,69 @@ +/* +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() +) + +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/preflight_checks_test.go b/internal/controller/preflight_checks_test.go index 072e065ac..7a82b4af5 100644 --- a/internal/controller/preflight_checks_test.go +++ b/internal/controller/preflight_checks_test.go @@ -24,178 +24,209 @@ import ( . "github.com/onsi/gomega" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/rest" 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/phases" + "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 core provider exists, preflight check passed", - providers: []operatorv1.GenericProvider{ - &operatorv1.CoreProvider{ + name: "only one infra provider exists, preflight check passed", + providers: []*operatorv1.InfrastructureProvider{ + { ObjectMeta: metav1.ObjectMeta{ - Name: "cluster-api", + Name: "aws", Namespace: namespaceName1, }, TypeMeta: metav1.TypeMeta{ - Kind: "CoreProvider", + Kind: "InfrastructureProvider", APIVersion: "operator.cluster.x-k8s.io/v1alpha1", }, - Spec: operatorv1.CoreProviderSpec{ + Spec: operatorv1.InfrastructureProviderSpec{ ProviderSpec: operatorv1.ProviderSpec{ Version: "v1.0.0", - FetchConfig: &operatorv1.FetchConfiguration{ - URL: "https://example.com", - }, }, }, }, }, + otherProviders: []generic.Provider{ + core, + }, expectedCondition: clusterv1.Condition{ 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{ + name: "missing core provider for one infra, preflight check fails", + providers: []*operatorv1.InfrastructureProvider{ + { ObjectMeta: metav1.ObjectMeta{ - Name: "my-fancy-cluster-api", + Name: "aws", Namespace: namespaceName1, }, TypeMeta: metav1.TypeMeta{ - Kind: "CoreProvider", + Kind: "InfrastructureProvider", APIVersion: "operator.cluster.x-k8s.io/v1alpha1", }, - Spec: operatorv1.CoreProviderSpec{ + Spec: operatorv1.InfrastructureProviderSpec{ ProviderSpec: operatorv1.ProviderSpec{ Version: "v1.0.0", - FetchConfig: &operatorv1.FetchConfiguration{ - URL: "https://example.com", - }, }, }, }, }, expectedCondition: clusterv1.Condition{ Type: operatorv1.PreflightCheckCondition, - Reason: operatorv1.IncorrectCoreProviderNameReason, - Severity: clusterv1.ConditionSeverityError, - Message: "Incorrect CoreProvider name: my-fancy-cluster-api. It should be cluster-api", Status: corev1.ConditionFalse, + Message: "Waiting for the core provider to be installed.", + Severity: clusterv1.ConditionSeverityInfo, }, - providerList: &operatorv1.CoreProviderList{}, }, { - name: "two core providers were created, preflight check failed", - expectedError: true, - providers: []operatorv1.GenericProvider{ - &operatorv1.CoreProvider{ + name: "waiting for ready condtion on core provider for one infra, preflight check fails", + providers: []*operatorv1.InfrastructureProvider{ + { ObjectMeta: metav1.ObjectMeta{ - Name: "cluster-api", - Namespace: namespaceName1, - }, - TypeMeta: metav1.TypeMeta{ - Kind: "CoreProvider", - APIVersion: "operator.cluster.x-k8s.io/v1alpha1", - }, - Spec: operatorv1.CoreProviderSpec{ - ProviderSpec: operatorv1.ProviderSpec{ - Version: "v1.0.0", - }, - }, - }, - &operatorv1.CoreProvider{ - ObjectMeta: metav1.ObjectMeta{ - Name: "core-3", + Name: "aws", Namespace: namespaceName1, }, TypeMeta: metav1.TypeMeta{ - Kind: "CoreProvider", + Kind: "InfrastructureProvider", APIVersion: "operator.cluster.x-k8s.io/v1alpha1", }, - Spec: operatorv1.CoreProviderSpec{ + Spec: operatorv1.InfrastructureProviderSpec{ ProviderSpec: operatorv1.ProviderSpec{ Version: "v1.0.0", }, }, }, }, + otherProviders: []generic.Provider{ + coreNotReady, + }, expectedCondition: clusterv1.Condition{ Type: operatorv1.PreflightCheckCondition, - Reason: operatorv1.MoreThanOneProviderInstanceExistsReason, - Severity: clusterv1.ConditionSeverityError, - Message: moreThanOneCoreProviderInstanceExistsMessage, Status: corev1.ConditionFalse, + Message: "Waiting for the core provider to be installed.", + Severity: clusterv1.ConditionSeverityInfo, }, - providerList: &operatorv1.CoreProviderList{}, }, { - name: "two core providers in two different namespaces were created, preflight check failed", - expectedError: true, - providers: []operatorv1.GenericProvider{ - &operatorv1.CoreProvider{ + name: "two different infra providers exist in same namespaces, preflight check passed", + providers: []*operatorv1.InfrastructureProvider{ + { ObjectMeta: metav1.ObjectMeta{ - Name: "cluster-api", + Name: "metal3", Namespace: namespaceName1, }, TypeMeta: metav1.TypeMeta{ - Kind: "CoreProvider", + Kind: "InfrastructureProvider", APIVersion: "operator.cluster.x-k8s.io/v1alpha1", }, - Spec: operatorv1.CoreProviderSpec{ + Spec: operatorv1.InfrastructureProviderSpec{ ProviderSpec: operatorv1.ProviderSpec{ Version: "v1.0.0", }, }, }, - &operatorv1.CoreProvider{ + { ObjectMeta: metav1.ObjectMeta{ - Name: "cluster-api", - Namespace: namespaceName2, + Name: "aws", + Namespace: namespaceName1, }, TypeMeta: metav1.TypeMeta{ - Kind: "CoreProvider", + Kind: "InfrastructureProvider", APIVersion: "operator.cluster.x-k8s.io/v1alpha1", }, - Spec: operatorv1.CoreProviderSpec{ + 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: moreThanOneCoreProviderInstanceExistsMessage, - Status: corev1.ConditionFalse, + Type: operatorv1.PreflightCheckCondition, + Status: corev1.ConditionTrue, }, - providerList: &operatorv1.CoreProviderList{}, }, { - name: "only one infra provider exists, preflight check passed", - providers: []operatorv1.GenericProvider{ - &operatorv1.InfrastructureProvider{ + name: "two different infra providers exist in different namespaces, preflight check passed", + providers: []*operatorv1.InfrastructureProvider{ + { ObjectMeta: metav1.ObjectMeta{ - Name: "aws", + Name: "metal3", Namespace: namespaceName1, }, TypeMeta: metav1.TypeMeta{ @@ -208,45 +239,37 @@ func TestPreflightChecks(t *testing.T) { }, }, }, - &operatorv1.CoreProvider{ + { ObjectMeta: metav1.ObjectMeta{ - Name: "cluster-api", + Name: "aws", Namespace: namespaceName2, }, TypeMeta: metav1.TypeMeta{ - Kind: "CoreProvider", - APIVersion: "operator.cluster.x-k8s.io/v1alpha4", + Kind: "InfrastructureProvider", + APIVersion: "operator.cluster.x-k8s.io/v1alpha1", }, - Spec: operatorv1.CoreProviderSpec{ + Spec: operatorv1.InfrastructureProviderSpec{ 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(), - }, - }, - }, - }, }, }, + otherProviders: []generic.Provider{ + core, + }, expectedCondition: clusterv1.Condition{ Type: operatorv1.PreflightCheckCondition, Status: corev1.ConditionTrue, }, - providerList: &operatorv1.InfrastructureProviderList{}, }, { - name: "two different infra providers exist in same namespaces, preflight check passed", - providers: []operatorv1.GenericProvider{ - &operatorv1.InfrastructureProvider{ + name: "two similar infra provider exist in different namespaces, preflight check failed", + expectedError: true, + providers: []*operatorv1.InfrastructureProvider{ + { ObjectMeta: metav1.ObjectMeta{ - Name: "metal3", + Name: "aws", Namespace: namespaceName1, }, TypeMeta: metav1.TypeMeta{ @@ -259,10 +282,10 @@ func TestPreflightChecks(t *testing.T) { }, }, }, - &operatorv1.InfrastructureProvider{ + { ObjectMeta: metav1.ObjectMeta{ Name: "aws", - Namespace: namespaceName1, + Namespace: namespaceName2, }, TypeMeta: metav1.TypeMeta{ Kind: "InfrastructureProvider", @@ -274,45 +297,93 @@ func TestPreflightChecks(t *testing.T) { }, }, }, - &operatorv1.CoreProvider{ + }, + 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: "cluster-api", - Namespace: namespaceName2, + Name: "aws", + Namespace: namespaceName1, }, TypeMeta: metav1.TypeMeta{ - Kind: "CoreProvider", - APIVersion: "operator.cluster.x-k8s.io/v1alpha4", + Kind: "InfrastructureProvider", + APIVersion: "operator.cluster.x-k8s.io/v1alpha1", }, - Spec: operatorv1.CoreProviderSpec{ + Spec: operatorv1.InfrastructureProviderSpec{ ProviderSpec: operatorv1.ProviderSpec{ - Version: "v1.0.0", + Version: "one", }, }, - Status: operatorv1.CoreProviderStatus{ - ProviderStatus: operatorv1.ProviderStatus{ - Conditions: []clusterv1.Condition{ - { - Type: clusterv1.ReadyCondition, - Status: corev1.ConditionTrue, - LastTransitionTime: metav1.Now(), + }, + }, + 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, - Status: corev1.ConditionTrue, + 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: "two different infra providers exist in different namespaces, preflight check passed", - providers: []operatorv1.GenericProvider{ - &operatorv1.InfrastructureProvider{ + name: "custom Infrastructure Provider without fetch config, preflight check failed", + expectedError: true, + providers: []*operatorv1.InfrastructureProvider{ + { ObjectMeta: metav1.ObjectMeta{ - Name: "metal3", + Name: "my-custom-aws", Namespace: namespaceName1, }, TypeMeta: metav1.TypeMeta{ @@ -325,10 +396,26 @@ func TestPreflightChecks(t *testing.T) { }, }, }, - &operatorv1.InfrastructureProvider{ + }, + 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: "aws", - Namespace: namespaceName2, + Name: "my-custom-aws", + Namespace: namespaceName1, }, TypeMeta: metav1.TypeMeta{ Kind: "InfrastructureProvider", @@ -337,31 +424,92 @@ func TestPreflightChecks(t *testing.T) { Spec: operatorv1.InfrastructureProviderSpec{ ProviderSpec: operatorv1.ProviderSpec{ Version: "v1.0.0", + FetchConfig: &operatorv1.FetchConfiguration{ + URL: "", + Selector: nil, + }, }, }, }, - &operatorv1.CoreProvider{ + }, + 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 := NewProviderControllerWrapper( + providers.NewInfrastructureProviderReconciler(newConnector(fakeclient)), + phases.NewPhase, + ) + + 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.CoreProvider{ + { ObjectMeta: metav1.ObjectMeta{ Name: "cluster-api", - Namespace: namespaceName2, + Namespace: namespaceName1, }, TypeMeta: metav1.TypeMeta{ Kind: "CoreProvider", - APIVersion: "operator.cluster.x-k8s.io/v1alpha4", + APIVersion: "operator.cluster.x-k8s.io/v1alpha1", }, 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(), - }, + FetchConfig: &operatorv1.FetchConfiguration{ + URL: "https://example.com", }, }, }, @@ -371,85 +519,86 @@ func TestPreflightChecks(t *testing.T) { Type: operatorv1.PreflightCheckCondition, Status: corev1.ConditionTrue, }, - providerList: &operatorv1.InfrastructureProviderList{}, }, { - name: "two similar infra provider exist in different namespaces, preflight check failed", + name: "core provider with incorrect name, preflight check failed", expectedError: true, - providers: []operatorv1.GenericProvider{ - &operatorv1.InfrastructureProvider{ + providers: []*operatorv1.CoreProvider{ + { ObjectMeta: metav1.ObjectMeta{ - Name: "aws", + Name: "my-fancy-cluster-api", Namespace: namespaceName1, }, TypeMeta: metav1.TypeMeta{ - Kind: "InfrastructureProvider", + Kind: "CoreProvider", APIVersion: "operator.cluster.x-k8s.io/v1alpha1", }, - Spec: operatorv1.InfrastructureProviderSpec{ + Spec: operatorv1.CoreProviderSpec{ ProviderSpec: operatorv1.ProviderSpec{ Version: "v1.0.0", + FetchConfig: &operatorv1.FetchConfiguration{ + URL: "https://example.com", + }, }, }, }, - &operatorv1.InfrastructureProvider{ + }, + expectedCondition: clusterv1.Condition{ + Type: operatorv1.PreflightCheckCondition, + Reason: operatorv1.IncorrectCoreProviderNameReason, + Severity: clusterv1.ConditionSeverityError, + Message: "Incorrect CoreProvider name: my-fancy-cluster-api. It should be cluster-api", + Status: corev1.ConditionFalse, + }, + }, + { + name: "two core providers were created, preflight check failed", + expectedError: true, + providers: []*operatorv1.CoreProvider{ + { ObjectMeta: metav1.ObjectMeta{ - Name: "aws", - Namespace: namespaceName2, + Name: "cluster-api", + Namespace: namespaceName1, }, TypeMeta: metav1.TypeMeta{ - Kind: "InfrastructureProvider", + Kind: "CoreProvider", APIVersion: "operator.cluster.x-k8s.io/v1alpha1", }, - Spec: operatorv1.InfrastructureProviderSpec{ + Spec: operatorv1.CoreProviderSpec{ ProviderSpec: operatorv1.ProviderSpec{ Version: "v1.0.0", }, }, }, - }, - expectedCondition: clusterv1.Condition{ - Type: operatorv1.PreflightCheckCondition, - Reason: operatorv1.MoreThanOneProviderInstanceExistsReason, - Severity: clusterv1.ConditionSeverityError, - Message: fmt.Sprintf(moreThanOneProviderInstanceExistsMessage, "aws", namespaceName2), - Status: corev1.ConditionFalse, - }, - providerList: &operatorv1.InfrastructureProviderList{}, - }, - { - name: "wrong version, preflight check failed", - expectedError: true, - providers: []operatorv1.GenericProvider{ - &operatorv1.InfrastructureProvider{ + { ObjectMeta: metav1.ObjectMeta{ - Name: "aws", + Name: "core-3", Namespace: namespaceName1, }, TypeMeta: metav1.TypeMeta{ - Kind: "InfrastructureProvider", + Kind: "CoreProvider", APIVersion: "operator.cluster.x-k8s.io/v1alpha1", }, - Spec: operatorv1.InfrastructureProviderSpec{ + Spec: operatorv1.CoreProviderSpec{ ProviderSpec: operatorv1.ProviderSpec{ - Version: "one", + Version: "v1.0.0", }, }, }, }, expectedCondition: clusterv1.Condition{ Type: operatorv1.PreflightCheckCondition, - Reason: operatorv1.IncorrectVersionFormatReason, + Reason: operatorv1.MoreThanOneProviderInstanceExistsReason, Severity: clusterv1.ConditionSeverityError, - Message: "could not parse \"one\" as version", + Message: "CoreProvider already exists in the cluster. Only one is allowed.", Status: corev1.ConditionFalse, }, - providerList: &operatorv1.InfrastructureProviderList{}, }, { - name: "missing version, preflight check passed", - providers: []operatorv1.GenericProvider{ - &operatorv1.CoreProvider{ + name: "two core providers in two different namespaces were created, preflight check failed", + expectedError: true, + providers: []*operatorv1.CoreProvider{ + { ObjectMeta: metav1.ObjectMeta{ Name: "cluster-api", Namespace: namespaceName1, @@ -460,58 +609,38 @@ func TestPreflightChecks(t *testing.T) { }, Spec: operatorv1.CoreProviderSpec{ ProviderSpec: operatorv1.ProviderSpec{ - FetchConfig: &operatorv1.FetchConfiguration{ - URL: "https://example.com", - }, + Version: "v1.0.0", }, }, }, - }, - expectedCondition: clusterv1.Condition{ - 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, + Name: "cluster-api", + Namespace: namespaceName2, }, TypeMeta: metav1.TypeMeta{ - Kind: "InfrastructureProvider", + Kind: "CoreProvider", APIVersion: "operator.cluster.x-k8s.io/v1alpha1", }, - Spec: operatorv1.InfrastructureProviderSpec{ + Spec: operatorv1.CoreProviderSpec{ 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, + Reason: operatorv1.MoreThanOneProviderInstanceExistsReason, Severity: clusterv1.ConditionSeverityError, - Message: "Only one of Selector and URL must be provided, not both", + Message: "CoreProvider already exists in the cluster. Only one is allowed.", Status: corev1.ConditionFalse, }, - providerList: &operatorv1.InfrastructureProviderList{}, }, { - name: "predefined Core Provider without fetch config, preflight check passed", - providers: []operatorv1.GenericProvider{ - &operatorv1.CoreProvider{ + name: "missing version, preflight check passed", + providers: []*operatorv1.CoreProvider{ + { ObjectMeta: metav1.ObjectMeta{ Name: "cluster-api", Namespace: namespaceName1, @@ -522,7 +651,9 @@ func TestPreflightChecks(t *testing.T) { }, Spec: operatorv1.CoreProviderSpec{ ProviderSpec: operatorv1.ProviderSpec{ - Version: "v1.0.0", + FetchConfig: &operatorv1.FetchConfiguration{ + URL: "https://example.com", + }, }, }, }, @@ -531,22 +662,20 @@ func TestPreflightChecks(t *testing.T) { Type: operatorv1.PreflightCheckCondition, Status: corev1.ConditionTrue, }, - providerList: &operatorv1.CoreProviderList{}, }, { - name: "custom Infrastructure Provider without fetch config, preflight check failed", - expectedError: true, - providers: []operatorv1.GenericProvider{ - &operatorv1.InfrastructureProvider{ + name: "predefined Core Provider without fetch config, preflight check passed", + 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{ + Spec: operatorv1.CoreProviderSpec{ ProviderSpec: operatorv1.ProviderSpec{ Version: "v1.0.0", }, @@ -554,28 +683,24 @@ func TestPreflightChecks(t *testing.T) { }, }, 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, + Type: operatorv1.PreflightCheckCondition, + Status: corev1.ConditionTrue, }, - providerList: &operatorv1.CoreProviderList{}, }, { - name: "custom Infrastructure Provider with fetch config with empty values, 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{ + Spec: operatorv1.CoreProviderSpec{ ProviderSpec: operatorv1.ProviderSpec{ Version: "v1.0.0", FetchConfig: &operatorv1.FetchConfiguration{ @@ -590,10 +715,9 @@ func TestPreflightChecks(t *testing.T) { Type: operatorv1.PreflightCheckCondition, Reason: operatorv1.FetchConfigValidationErrorReason, Severity: clusterv1.ConditionSeverityError, - Message: "Either Selector or URL must be provided for a not predefined provider", + Message: "Either Selector or URL must be provided for a fetchConfig", Status: corev1.ConditionFalse, }, - providerList: &operatorv1.CoreProviderList{}, }, } @@ -607,7 +731,13 @@ 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, + ) + + 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 { @@ -704,7 +834,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/genericprovider_controller.go b/internal/controller/provider_controller_wrapper.go similarity index 56% rename from internal/controller/genericprovider_controller.go rename to internal/controller/provider_controller_wrapper.go index 4e172dfec..436019b00 100644 --- a/internal/controller/genericprovider_controller.go +++ b/internal/controller/provider_controller_wrapper.go @@ -22,57 +22,51 @@ import ( "encoding/json" "errors" "fmt" + "reflect" - apierrors "k8s.io/apimachinery/pkg/api/errors" 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" ctrl "sigs.k8s.io/controller-runtime" - "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/controller" "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" "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] +} + +func NewProviderControllerWrapper[P generic.Provider, R generic.ProviderReconciler[P]](rec R, groupFn generic.NewGroup[P]) *ProviderControllerWrapper[P, R] { + return &ProviderControllerWrapper[P, R]{ + Reconciler: rec, + NewGroup: groupFn, + } } const ( appliedSpecHashAnnotation = "operator.cluster.x-k8s.io/applied-spec-hash" ) -func (r *GenericProviderReconciler) SetupWithManager(mgr ctrl.Manager, options controller.Options) error { +func (r *ProviderControllerWrapper[P, R]) SetupWithManager(mgr ctrl.Manager, options controller.Options) error { return ctrl.NewControllerManagedBy(mgr). - For(r.Provider). + For(reflect.New(reflect.TypeOf(*new(P)).Elem()).Interface().(P)). //nolint:forcetypeassert WithOptions(options). - Complete(r) + 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 } @@ -85,37 +79,37 @@ 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(r.Provider.GetSpec()) + specHash, err := calculateHash(provider.GetSpec()) 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{} } @@ -123,7 +117,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(r.Provider.GetSpec()) + specHash, err = calculateHash(provider.GetSpec()) if err != nil { return ctrl.Result{}, err } @@ -133,7 +127,7 @@ func (r *GenericProviderReconciler) Reconcile(ctx context.Context, req reconcile annotations[appliedSpecHashAnnotation] = "" } - r.Provider.SetAnnotations(annotations) + provider.SetAnnotations(annotations) return res, err } @@ -149,27 +143,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() + + phases := r.Reconciler.PreflightChecks(ctx, provider) + phases = append(phases, r.Reconciler.ReconcileNormal(ctx, provider)...) + phases = append(phases, r.Reconciler.ReportStatus(ctx, provider)...) - res := reconcile.Result{} + return r.reconcilePhases(ctx, provider, phases) +} - var err error +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 phases { - res, err = phase(ctx) + 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, err.Error())) } @@ -184,38 +177,16 @@ 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, 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 calculateHash(object interface{}) (string, error) { diff --git a/internal/controller/genericprovider_controller_test.go b/internal/controller/provider_controller_wrapper_test.go similarity index 86% rename from internal/controller/genericprovider_controller_test.go rename to internal/controller/provider_controller_wrapper_test.go index fa619d19a..128830dd9 100644 --- a/internal/controller/genericprovider_controller_test.go +++ b/internal/controller/provider_controller_wrapper_test.go @@ -24,15 +24,13 @@ 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/pointer" + "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/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 ( @@ -77,7 +75,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{ @@ -109,12 +107,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", @@ -130,7 +128,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", @@ -260,32 +258,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()) g.Eventually(func() bool { @@ -294,6 +320,7 @@ releaseSeries: } if provider.GetStatus().InstalledVersion == nil || *provider.GetStatus().InstalledVersion != currentVersion { + t.Log(t.Name(), provider.GetName(), provider.GetStatus().InstalledVersion) return false } @@ -311,14 +338,14 @@ 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 providerSpec := provider.GetSpec() providerSpec.Version = tc.newVersion providerSpec.Deployment = &operatorv1.DeploymentSpec{ - Replicas: pointer.Int(2), + Replicas: ptr.To(2), } provider.SetSpec(providerSpec) @@ -330,7 +357,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 { @@ -403,24 +432,12 @@ releaseSeries: }, 2*time.Second).Should(BeTrue()) // Clean up - objs := []client.Object{provider} - objs = append(objs, &corev1.ConfigMap{ - ObjectMeta: metav1.ObjectMeta{ - Name: currentVersion, - Namespace: namespace, - }, - }) - - objs = append(objs, &corev1.ConfigMap{ - ObjectMeta: metav1.ObjectMeta{ - Name: tc.newVersion, - Namespace: namespace, - }, - }) - - g.Expect(env.CleanupAndWait(ctx, objs...)).To(Succeed()) + g.Expect(env.CleanupAndWait(ctx, provider, dummyFutureConfigMap(ns.Name, currentVersion), dummyFutureConfigMap(ns.Name, tc.newVersion))).To(Succeed()) + g.Expect(env.Cleanup(ctx, ns)).To(Succeed()) }) } + + g.Expect(env.CleanupAndWait(ctx, core)).To(Succeed()) } func TestProviderSpecChanges(t *testing.T) { @@ -468,7 +485,7 @@ func TestProviderSpecChanges(t *testing.T) { updatedSpec: operatorv1.ProviderSpec{ Version: testCurrentVersion, Deployment: &operatorv1.DeploymentSpec{ - Replicas: pointer.Int(2), + Replicas: ptr.To(2), }, FetchConfig: &operatorv1.FetchConfiguration{ Selector: &metav1.LabelSelector{ @@ -495,7 +512,7 @@ func TestProviderSpecChanges(t *testing.T) { updatedSpec: operatorv1.ProviderSpec{ Version: "10000.0.0-NONEXISTENT", Deployment: &operatorv1.DeploymentSpec{ - Replicas: pointer.Int(2), + Replicas: ptr.To(2), }, FetchConfig: &operatorv1.FetchConfiguration{ Selector: &metav1.LabelSelector{ @@ -573,7 +590,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 @@ -595,12 +612,3 @@ func generateExpectedResultChecker(provider genericprovider.GenericProvider, spe return false } } - -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/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 67% rename from internal/controller/client_proxy.go rename to internal/controller/proxy/client_proxy.go index e12119a43..579a9ffcc 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,25 @@ 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() (client.Client, error) { return k.ctrlClient, nil } -func (k *controllerProxy) GetContexts(prefix string) ([]string, error) { return nil, nil } -func (k *controllerProxy) CheckClusterAvailable() 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() (client.Client, error) { return k.CtrlClient, nil } +func (k *ControllerProxy) GetContexts(prefix string) ([]string, error) { return nil, nil } +func (k *ControllerProxy) CheckClusterAvailable() 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 +109,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 +158,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 +168,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 } @@ -220,24 +195,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/suite_test.go b/internal/controller/suite_test.go index 0c37d8ef9..b66e5d0dd 100644 --- a/internal/controller/suite_test.go +++ b/internal/controller/suite_test.go @@ -22,11 +22,11 @@ import ( "testing" "time" + "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" - - operatorv1 "sigs.k8s.io/cluster-api-operator/api/v1alpha2" - "sigs.k8s.io/cluster-api-operator/internal/envtest" ) const ( @@ -43,35 +43,31 @@ func TestMain(m *testing.M) { env = envtest.New() - if err := (&GenericProviderReconciler{ - Provider: &operatorv1.CoreProvider{}, - ProviderList: &operatorv1.CoreProviderList{}, - Client: env, - }).SetupWithManager(env.Manager, controller.Options{MaxConcurrentReconciles: 1}); err != nil { + if err := NewProviderControllerWrapper( + providers.NewCoreProviderReconciler(env), + phases.NewPhase, + ).SetupWithManager(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, - }).SetupWithManager(env.Manager, controller.Options{MaxConcurrentReconciles: 1}); err != nil { + if err := NewProviderControllerWrapper( + providers.NewInfrastructureProviderReconciler(env), + phases.NewPhase, + ).SetupWithManager(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, - }).SetupWithManager(env.Manager, controller.Options{MaxConcurrentReconciles: 1}); err != nil { + if err := NewProviderControllerWrapper( + providers.NewBootstrapProviderReconciler(env), + phases.NewPhase, + ).SetupWithManager(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, - }).SetupWithManager(env.Manager, controller.Options{MaxConcurrentReconciles: 1}); err != nil { + if err := NewProviderControllerWrapper( + providers.NewControlPlaneProviderReconciler(env), + phases.NewPhase, + ).SetupWithManager(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 2fc7bc34a..1fe9770be 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" @@ -40,7 +41,7 @@ import ( "k8s.io/client-go/kubernetes/scheme" "k8s.io/client-go/rest" "k8s.io/klog/v2" - "k8s.io/klog/v2/klogr" + "k8s.io/klog/v2/textlogger" operatorv1 "sigs.k8s.io/cluster-api-operator/api/v1alpha2" clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1" clusterctlv1 "sigs.k8s.io/cluster-api/cmd/clusterctl/api/v1alpha3" @@ -56,9 +57,11 @@ import ( func init() { klog.InitFlags(nil) - logger := klogr.New() // Additionally force all of the controllers to use the Ginkgo logger. - ctrl.SetLogger(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 91eca6f56..a5c5216b6 100644 --- a/test/e2e/resources/full-chart-install.yaml +++ b/test/e2e/resources/full-chart-install.yaml @@ -321,8 +321,9 @@ spec: with the corresponding weight. properties: labelSelector: - description: A label query over a set of resources, - in this case pods. + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. properties: matchExpressions: description: matchExpressions is a list @@ -366,6 +367,36 @@ spec: type: object type: object x-kubernetes-map-type: atomic + matchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic namespaceSelector: description: |- A label query over the set of namespaces that the term applies to. @@ -466,8 +497,9 @@ spec: a pod of the set of pods is running properties: labelSelector: - description: A label query over a set of resources, - in this case pods. + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. properties: matchExpressions: description: matchExpressions is a list of label @@ -511,6 +543,36 @@ spec: type: object type: object x-kubernetes-map-type: atomic + matchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic namespaceSelector: description: |- A label query over the set of namespaces that the term applies to. @@ -609,8 +671,9 @@ spec: with the corresponding weight. properties: labelSelector: - description: A label query over a set of resources, - in this case pods. + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. properties: matchExpressions: description: matchExpressions is a list @@ -654,6 +717,36 @@ spec: type: object type: object x-kubernetes-map-type: atomic + matchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic namespaceSelector: description: |- A label query over the set of namespaces that the term applies to. @@ -754,8 +847,9 @@ spec: a pod of the set of pods is running properties: labelSelector: - description: A label query over a set of resources, - in this case pods. + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. properties: matchExpressions: description: matchExpressions is a list of label @@ -799,6 +893,36 @@ spec: type: object type: object x-kubernetes-map-type: atomic + matchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic namespaceSelector: description: |- A label query over the set of namespaces that the term applies to. @@ -1800,8 +1924,9 @@ spec: with the corresponding weight. properties: labelSelector: - description: A label query over a set of resources, - in this case pods. + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. properties: matchExpressions: description: matchExpressions is a list @@ -1845,6 +1970,36 @@ spec: type: object type: object x-kubernetes-map-type: atomic + matchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic namespaceSelector: description: |- A label query over the set of namespaces that the term applies to. @@ -1945,8 +2100,9 @@ spec: a pod of the set of pods is running properties: labelSelector: - description: A label query over a set of resources, - in this case pods. + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. properties: matchExpressions: description: matchExpressions is a list of label @@ -1990,6 +2146,36 @@ spec: type: object type: object x-kubernetes-map-type: atomic + matchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic namespaceSelector: description: |- A label query over the set of namespaces that the term applies to. @@ -2088,8 +2274,9 @@ spec: with the corresponding weight. properties: labelSelector: - description: A label query over a set of resources, - in this case pods. + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. properties: matchExpressions: description: matchExpressions is a list @@ -2133,6 +2320,36 @@ spec: type: object type: object x-kubernetes-map-type: atomic + matchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic namespaceSelector: description: |- A label query over the set of namespaces that the term applies to. @@ -2233,8 +2450,9 @@ spec: a pod of the set of pods is running properties: labelSelector: - description: A label query over a set of resources, - in this case pods. + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. properties: matchExpressions: description: matchExpressions is a list of label @@ -2278,6 +2496,36 @@ spec: type: object type: object x-kubernetes-map-type: atomic + matchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic namespaceSelector: description: |- A label query over the set of namespaces that the term applies to. @@ -3275,8 +3523,9 @@ spec: with the corresponding weight. properties: labelSelector: - description: A label query over a set of resources, - in this case pods. + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. properties: matchExpressions: description: matchExpressions is a list @@ -3320,6 +3569,36 @@ spec: type: object type: object x-kubernetes-map-type: atomic + matchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic namespaceSelector: description: |- A label query over the set of namespaces that the term applies to. @@ -3420,8 +3699,9 @@ spec: a pod of the set of pods is running properties: labelSelector: - description: A label query over a set of resources, - in this case pods. + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. properties: matchExpressions: description: matchExpressions is a list of label @@ -3465,6 +3745,36 @@ spec: type: object type: object x-kubernetes-map-type: atomic + matchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic namespaceSelector: description: |- A label query over the set of namespaces that the term applies to. @@ -3563,8 +3873,9 @@ spec: with the corresponding weight. properties: labelSelector: - description: A label query over a set of resources, - in this case pods. + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. properties: matchExpressions: description: matchExpressions is a list @@ -3608,6 +3919,36 @@ spec: type: object type: object x-kubernetes-map-type: atomic + matchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic namespaceSelector: description: |- A label query over the set of namespaces that the term applies to. @@ -3708,8 +4049,9 @@ spec: a pod of the set of pods is running properties: labelSelector: - description: A label query over a set of resources, - in this case pods. + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. properties: matchExpressions: description: matchExpressions is a list of label @@ -3753,6 +4095,36 @@ spec: type: object type: object x-kubernetes-map-type: atomic + matchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic namespaceSelector: description: |- A label query over the set of namespaces that the term applies to. @@ -4754,8 +5126,9 @@ spec: with the corresponding weight. properties: labelSelector: - description: A label query over a set of resources, - in this case pods. + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. properties: matchExpressions: description: matchExpressions is a list @@ -4799,6 +5172,36 @@ spec: type: object type: object x-kubernetes-map-type: atomic + matchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic namespaceSelector: description: |- A label query over the set of namespaces that the term applies to. @@ -4899,8 +5302,9 @@ spec: a pod of the set of pods is running properties: labelSelector: - description: A label query over a set of resources, - in this case pods. + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. properties: matchExpressions: description: matchExpressions is a list of label @@ -4944,6 +5348,36 @@ spec: type: object type: object x-kubernetes-map-type: atomic + matchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic namespaceSelector: description: |- A label query over the set of namespaces that the term applies to. @@ -5042,8 +5476,9 @@ spec: with the corresponding weight. properties: labelSelector: - description: A label query over a set of resources, - in this case pods. + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. properties: matchExpressions: description: matchExpressions is a list @@ -5087,6 +5522,36 @@ spec: type: object type: object x-kubernetes-map-type: atomic + matchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic namespaceSelector: description: |- A label query over the set of namespaces that the term applies to. @@ -5187,8 +5652,9 @@ spec: a pod of the set of pods is running properties: labelSelector: - description: A label query over a set of resources, - in this case pods. + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. properties: matchExpressions: description: matchExpressions is a list of label @@ -5232,6 +5698,36 @@ spec: type: object type: object x-kubernetes-map-type: atomic + matchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic namespaceSelector: description: |- A label query over the set of namespaces that the term applies to. @@ -6231,8 +6727,9 @@ spec: with the corresponding weight. properties: labelSelector: - description: A label query over a set of resources, - in this case pods. + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. properties: matchExpressions: description: matchExpressions is a list @@ -6276,6 +6773,36 @@ spec: type: object type: object x-kubernetes-map-type: atomic + matchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic namespaceSelector: description: |- A label query over the set of namespaces that the term applies to. @@ -6376,8 +6903,9 @@ spec: a pod of the set of pods is running properties: labelSelector: - description: A label query over a set of resources, - in this case pods. + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. properties: matchExpressions: description: matchExpressions is a list of label @@ -6421,6 +6949,36 @@ spec: type: object type: object x-kubernetes-map-type: atomic + matchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic namespaceSelector: description: |- A label query over the set of namespaces that the term applies to. @@ -6519,8 +7077,9 @@ spec: with the corresponding weight. properties: labelSelector: - description: A label query over a set of resources, - in this case pods. + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. properties: matchExpressions: description: matchExpressions is a list @@ -6564,6 +7123,36 @@ spec: type: object type: object x-kubernetes-map-type: atomic + matchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic namespaceSelector: description: |- A label query over the set of namespaces that the term applies to. @@ -6664,8 +7253,9 @@ spec: a pod of the set of pods is running properties: labelSelector: - description: A label query over a set of resources, - in this case pods. + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. properties: matchExpressions: description: matchExpressions is a list of label @@ -6709,6 +7299,36 @@ spec: type: object type: object x-kubernetes-map-type: atomic + matchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic namespaceSelector: description: |- A label query over the set of namespaces that the term applies to. @@ -7711,8 +8331,9 @@ spec: with the corresponding weight. properties: labelSelector: - description: A label query over a set of resources, - in this case pods. + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. properties: matchExpressions: description: matchExpressions is a list @@ -7756,6 +8377,36 @@ spec: type: object type: object x-kubernetes-map-type: atomic + matchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic namespaceSelector: description: |- A label query over the set of namespaces that the term applies to. @@ -7856,8 +8507,9 @@ spec: a pod of the set of pods is running properties: labelSelector: - description: A label query over a set of resources, - in this case pods. + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. properties: matchExpressions: description: matchExpressions is a list of label @@ -7901,6 +8553,36 @@ spec: type: object type: object x-kubernetes-map-type: atomic + matchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic namespaceSelector: description: |- A label query over the set of namespaces that the term applies to. @@ -7999,8 +8681,9 @@ spec: with the corresponding weight. properties: labelSelector: - description: A label query over a set of resources, - in this case pods. + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. properties: matchExpressions: description: matchExpressions is a list @@ -8044,6 +8727,36 @@ spec: type: object type: object x-kubernetes-map-type: atomic + matchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic namespaceSelector: description: |- A label query over the set of namespaces that the term applies to. @@ -8144,8 +8857,9 @@ spec: a pod of the set of pods is running properties: labelSelector: - description: A label query over a set of resources, - in this case pods. + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. properties: matchExpressions: description: matchExpressions is a list of label @@ -8189,6 +8903,36 @@ spec: type: object type: object x-kubernetes-map-type: atomic + matchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic namespaceSelector: description: |- A label query over the set of namespaces that the term applies to. @@ -9186,8 +9930,9 @@ spec: with the corresponding weight. properties: labelSelector: - description: A label query over a set of resources, - in this case pods. + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. properties: matchExpressions: description: matchExpressions is a list @@ -9231,6 +9976,36 @@ spec: type: object type: object x-kubernetes-map-type: atomic + matchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic namespaceSelector: description: |- A label query over the set of namespaces that the term applies to. @@ -9331,8 +10106,9 @@ spec: a pod of the set of pods is running properties: labelSelector: - description: A label query over a set of resources, - in this case pods. + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. properties: matchExpressions: description: matchExpressions is a list of label @@ -9376,6 +10152,36 @@ spec: type: object type: object x-kubernetes-map-type: atomic + matchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic namespaceSelector: description: |- A label query over the set of namespaces that the term applies to. @@ -9474,8 +10280,9 @@ spec: with the corresponding weight. properties: labelSelector: - description: A label query over a set of resources, - in this case pods. + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. properties: matchExpressions: description: matchExpressions is a list @@ -9519,6 +10326,36 @@ spec: type: object type: object x-kubernetes-map-type: atomic + matchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic namespaceSelector: description: |- A label query over the set of namespaces that the term applies to. @@ -9619,8 +10456,9 @@ spec: a pod of the set of pods is running properties: labelSelector: - description: A label query over a set of resources, - in this case pods. + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. properties: matchExpressions: description: matchExpressions is a list of label @@ -9664,6 +10502,36 @@ spec: type: object type: object x-kubernetes-map-type: atomic + matchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic namespaceSelector: description: |- A label query over the set of namespaces that the term applies to. @@ -10665,8 +11533,9 @@ spec: with the corresponding weight. properties: labelSelector: - description: A label query over a set of resources, - in this case pods. + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. properties: matchExpressions: description: matchExpressions is a list @@ -10710,6 +11579,36 @@ spec: type: object type: object x-kubernetes-map-type: atomic + matchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic namespaceSelector: description: |- A label query over the set of namespaces that the term applies to. @@ -10810,8 +11709,9 @@ spec: a pod of the set of pods is running properties: labelSelector: - description: A label query over a set of resources, - in this case pods. + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. properties: matchExpressions: description: matchExpressions is a list of label @@ -10855,6 +11755,36 @@ spec: type: object type: object x-kubernetes-map-type: atomic + matchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic namespaceSelector: description: |- A label query over the set of namespaces that the term applies to. @@ -10953,8 +11883,9 @@ spec: with the corresponding weight. properties: labelSelector: - description: A label query over a set of resources, - in this case pods. + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. properties: matchExpressions: description: matchExpressions is a list @@ -10998,6 +11929,36 @@ spec: type: object type: object x-kubernetes-map-type: atomic + matchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic namespaceSelector: description: |- A label query over the set of namespaces that the term applies to. @@ -11098,8 +12059,9 @@ spec: a pod of the set of pods is running properties: labelSelector: - description: A label query over a set of resources, - in this case pods. + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. properties: matchExpressions: description: matchExpressions is a list of label @@ -11143,6 +12105,36 @@ spec: type: object type: object x-kubernetes-map-type: atomic + matchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic namespaceSelector: description: |- A label query over the set of namespaces that the term applies to. @@ -12142,8 +13134,9 @@ spec: with the corresponding weight. properties: labelSelector: - description: A label query over a set of resources, - in this case pods. + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. properties: matchExpressions: description: matchExpressions is a list @@ -12187,6 +13180,36 @@ spec: type: object type: object x-kubernetes-map-type: atomic + matchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic namespaceSelector: description: |- A label query over the set of namespaces that the term applies to. @@ -12287,8 +13310,9 @@ spec: a pod of the set of pods is running properties: labelSelector: - description: A label query over a set of resources, - in this case pods. + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. properties: matchExpressions: description: matchExpressions is a list of label @@ -12332,6 +13356,36 @@ spec: type: object type: object x-kubernetes-map-type: atomic + matchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic namespaceSelector: description: |- A label query over the set of namespaces that the term applies to. @@ -12430,8 +13484,9 @@ spec: with the corresponding weight. properties: labelSelector: - description: A label query over a set of resources, - in this case pods. + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. properties: matchExpressions: description: matchExpressions is a list @@ -12475,6 +13530,36 @@ spec: type: object type: object x-kubernetes-map-type: atomic + matchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic namespaceSelector: description: |- A label query over the set of namespaces that the term applies to. @@ -12575,8 +13660,9 @@ spec: a pod of the set of pods is running properties: labelSelector: - description: A label query over a set of resources, - in this case pods. + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. properties: matchExpressions: description: matchExpressions is a list of label @@ -12620,6 +13706,36 @@ spec: type: object type: object x-kubernetes-map-type: atomic + matchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic namespaceSelector: description: |- A label query over the set of namespaces that the term applies to. @@ -13636,8 +14752,9 @@ spec: with the corresponding weight. properties: labelSelector: - description: A label query over a set of resources, - in this case pods. + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. properties: matchExpressions: description: matchExpressions is a list @@ -13681,6 +14798,36 @@ spec: type: object type: object x-kubernetes-map-type: atomic + matchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic namespaceSelector: description: |- A label query over the set of namespaces that the term applies to. @@ -13781,8 +14928,9 @@ spec: a pod of the set of pods is running properties: labelSelector: - description: A label query over a set of resources, - in this case pods. + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. properties: matchExpressions: description: matchExpressions is a list of label @@ -13826,6 +14974,36 @@ spec: type: object type: object x-kubernetes-map-type: atomic + matchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic namespaceSelector: description: |- A label query over the set of namespaces that the term applies to. @@ -13924,8 +15102,9 @@ spec: with the corresponding weight. properties: labelSelector: - description: A label query over a set of resources, - in this case pods. + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. properties: matchExpressions: description: matchExpressions is a list @@ -13969,6 +15148,36 @@ spec: type: object type: object x-kubernetes-map-type: atomic + matchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic namespaceSelector: description: |- A label query over the set of namespaces that the term applies to. @@ -14069,8 +15278,9 @@ spec: a pod of the set of pods is running properties: labelSelector: - description: A label query over a set of resources, - in this case pods. + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. properties: matchExpressions: description: matchExpressions is a list of label @@ -14114,6 +15324,36 @@ spec: type: object type: object x-kubernetes-map-type: atomic + matchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + 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)` + 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 an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic namespaceSelector: description: |- A label query over the set of namespaces that the term applies to. diff --git a/test/go.mod b/test/go.mod index fe0fb0555..9f10a5db7 100644 --- a/test/go.mod +++ b/test/go.mod @@ -8,15 +8,15 @@ require ( github.com/onsi/ginkgo/v2 v2.17.1 github.com/onsi/gomega v1.32.0 golang.org/x/tools v0.19.0 - k8s.io/api v0.28.8 - k8s.io/apiextensions-apiserver v0.28.8 - k8s.io/apimachinery v0.28.8 - k8s.io/klog/v2 v2.100.1 + k8s.io/api v0.29.0 + k8s.io/apiextensions-apiserver v0.29.0 + k8s.io/apimachinery v0.29.0 + k8s.io/klog/v2 v2.110.1 k8s.io/utils v0.0.0-20230726121419-3b25d923346b sigs.k8s.io/cluster-api v1.6.3 sigs.k8s.io/cluster-api-operator v0.0.0-00010101000000-000000000000 sigs.k8s.io/cluster-api/test v1.6.3 - sigs.k8s.io/controller-runtime v0.16.5 + sigs.k8s.io/controller-runtime v0.17.2 sigs.k8s.io/yaml v1.4.0 ) @@ -46,7 +46,7 @@ require ( github.com/emicklei/go-restful/v3 v3.11.0 // indirect github.com/evanphx/json-patch v5.6.0+incompatible // indirect github.com/evanphx/json-patch/v5 v5.9.0 // indirect - github.com/fsnotify/fsnotify v1.6.0 // indirect + github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/go-logr/logr v1.4.1 // indirect github.com/go-openapi/jsonpointer v0.19.6 // indirect github.com/go-openapi/jsonreference v0.20.2 // indirect @@ -56,7 +56,7 @@ require ( github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/protobuf v1.5.4 // indirect - github.com/google/cel-go v0.16.1 // indirect + github.com/google/cel-go v0.17.7 // indirect github.com/google/gnostic-models v0.6.8 // indirect github.com/google/go-cmp v0.6.0 // indirect github.com/google/go-github/v53 v53.2.0 // indirect @@ -74,7 +74,7 @@ require ( github.com/magiconair/properties v1.8.7 // indirect github.com/mailru/easyjson v0.7.7 // indirect github.com/mattn/go-isatty v0.0.20 // indirect - github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect + github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 // indirect github.com/mitchellh/copystructure v1.2.0 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/mitchellh/reflectwalk v1.0.2 // indirect @@ -86,10 +86,10 @@ require ( github.com/pelletier/go-toml v1.9.5 // indirect github.com/pelletier/go-toml/v2 v2.1.0 // indirect github.com/pkg/errors v0.9.1 // indirect - github.com/prometheus/client_golang v1.17.0 // indirect - github.com/prometheus/client_model v0.4.1-0.20230718164431-9a2bf3000d16 // indirect - github.com/prometheus/common v0.44.0 // indirect - github.com/prometheus/procfs v0.11.1 // indirect + github.com/prometheus/client_golang v1.18.0 // indirect + github.com/prometheus/client_model v0.5.0 // indirect + github.com/prometheus/common v0.45.0 // indirect + github.com/prometheus/procfs v0.12.0 // indirect github.com/sagikazarmark/locafero v0.3.0 // indirect github.com/sagikazarmark/slog-shim v0.1.0 // indirect github.com/shopspring/decimal v1.3.1 // indirect @@ -102,7 +102,6 @@ require ( github.com/stoewer/go-strcase v1.2.0 // indirect github.com/subosito/gotenv v1.6.0 // indirect github.com/valyala/fastjson v1.6.4 // indirect - go.uber.org/goleak v1.3.0 // indirect go.uber.org/multierr v1.11.0 // indirect golang.org/x/crypto v0.21.0 // indirect golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect @@ -123,12 +122,12 @@ require ( gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - k8s.io/apiserver v0.28.8 // indirect - k8s.io/client-go v0.28.8 // indirect + k8s.io/apiserver v0.29.0 // indirect + k8s.io/client-go v0.29.0 // indirect k8s.io/cluster-bootstrap v0.28.4 // indirect - k8s.io/component-base v0.28.8 // indirect - k8s.io/kube-openapi v0.0.0-20230717233707-2695361300d9 // indirect + k8s.io/component-base v0.29.0 // indirect + k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00 // indirect sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect sigs.k8s.io/kind v0.20.0 // indirect - sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect + sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect ) diff --git a/test/go.sum b/test/go.sum index 0356249f0..51f979b1f 100644 --- a/test/go.sum +++ b/test/go.sum @@ -67,6 +67,8 @@ github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6r github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM= github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= github.com/bwesterb/go-ristretto v1.2.0/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0= +github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM= +github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= @@ -84,6 +86,11 @@ github.com/coredns/caddy v1.1.1 h1:2eYKZT7i6yxIfGP3qLJoJ7HAsDJqYB+X68g4NYjSrE0= github.com/coredns/caddy v1.1.1/go.mod h1:A6ntJQlAWuQfFlsd9hvigKbo2WS0VUs2l1e2F+BawD4= github.com/coredns/corefile-migration v1.0.21 h1:W/DCETrHDiFo0Wj03EyMkaQ9fwsmSgqTCQDHpceaSsE= github.com/coredns/corefile-migration v1.0.21/go.mod h1:XnhgULOEouimnzgn0t4WPuFDN2/PJQcTxdWKC5eXNGE= +github.com/coreos/go-semver v0.3.1 h1:yi21YpKnrx1gt5R+la8n5WgS0kCrsPp33dmEyHReZr4= +github.com/coreos/go-semver v0.3.1/go.mod h1:irMmmIw/7yzSRPWryHsK7EYSg09caPQL03VsM8rvUec= +github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf h1:iW4rZ826su+pqaw19uhpSCzhj44qo35pNgKFGqzDKkU= +github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs= +github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= @@ -116,18 +123,22 @@ github.com/evanphx/json-patch v5.6.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLi github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= github.com/evanphx/json-patch/v5 v5.9.0 h1:kcBlZQbplgElYIlo/n1hJbls2z/1awpXxpRi0/FOJfg= github.com/evanphx/json-patch/v5 v5.9.0/go.mod h1:VNkHZ/282BpEyt/tObQO8s5CMPmYYq14uClGH4abBuQ= +github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= +github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY= github.com/frankban/quicktest v1.14.4/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= -github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= -github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= +github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= +github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= -github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= -github.com/go-logr/zapr v1.2.4 h1:QHVo+6stLbfJmYGkQ7uGHUCu5hnAFAj6mDe6Ea0SeOo= -github.com/go-logr/zapr v1.2.4/go.mod h1:FyHWQIzQORZ0QVE1BtVHv3cKtNLuXsbNLtpuhNapBOA= +github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/go-logr/zapr v1.3.0 h1:XGdV8XW8zdwFiwOA2Dryh1gj2KRQyOOoNmBy4EplIcQ= +github.com/go-logr/zapr v1.3.0/go.mod h1:YKepepNBd1u/oyhd/yQmtjVXmm9uML4IXUgMOwR8/Gg= github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE= github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs= github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE= @@ -171,8 +182,8 @@ github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/cel-go v0.16.1 h1:3hZfSNiAU3KOiNtxuFXVp5WFy4hf/Ly3Sa4/7F8SXNo= -github.com/google/cel-go v0.16.1/go.mod h1:HXZKzB0LXqer5lHHgfWAnlYwJaQBDKMjxjulNQzhwhY= +github.com/google/cel-go v0.17.7 h1:6ebJFzu1xO2n7TLtN+UBqShGBhlD85bhvglh5DpcfqQ= +github.com/google/cel-go v0.17.7/go.mod h1:HXZKzB0LXqer5lHHgfWAnlYwJaQBDKMjxjulNQzhwhY= github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I= github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= @@ -219,6 +230,11 @@ github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+ github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= +github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92BcuyuQ/YW4NSIpoGtfXNho= +github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= +github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0 h1:YBftPWNWd4WwGqtY2yeZL2ef8rHAxPBD8KFhJpmcqms= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0/go.mod h1:YN5jB8ie0yfIUg6VvR9Kz84aCaG7AsGZnLjhHbUqwPg= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= @@ -258,8 +274,8 @@ github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJ github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= -github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= +github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 h1:jWpvCLoY8Z/e3VKvlsiIGKtc+UG6U5vzxaoagmhXfyg= +github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0/go.mod h1:QUyp042oQthUoa9bqDv0ER0wrtXnBruoNd7aNjkbP+k= github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= @@ -300,15 +316,15 @@ github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qR github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/prometheus/client_golang v1.17.0 h1:rl2sfwZMtSthVU752MqfjQozy7blglC+1SOtjMAMh+Q= -github.com/prometheus/client_golang v1.17.0/go.mod h1:VeL+gMmOAxkS2IqfCq0ZmHSL+LjWfWDUmp1mBz9JgUY= +github.com/prometheus/client_golang v1.18.0 h1:HzFfmkOzH5Q8L8G+kSJKUx5dtG87sewO+FoDDqP5Tbk= +github.com/prometheus/client_golang v1.18.0/go.mod h1:T+GXkCk5wSJyOqMIzVgvvjFDlkOQntgjkJWKrN5txjA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.4.1-0.20230718164431-9a2bf3000d16 h1:v7DLqVdK4VrYkVD5diGdl4sxJurKJEMnODWRJlxV9oM= -github.com/prometheus/client_model v0.4.1-0.20230718164431-9a2bf3000d16/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU= -github.com/prometheus/common v0.44.0 h1:+5BrQJwiBB9xsMygAB3TNvpQKOwlkc25LbISbrdOOfY= -github.com/prometheus/common v0.44.0/go.mod h1:ofAIvZbQ1e/nugmZGz4/qCb9Ap1VoSTIO7x0VV9VvuY= -github.com/prometheus/procfs v0.11.1 h1:xRC8Iq1yyca5ypa9n1EZnWZkt7dwcoRPQwX/5gwaUuI= -github.com/prometheus/procfs v0.11.1/go.mod h1:eesXgaPo1q7lBpVMoMy0ZOFTth9hBn4W/y0/p/ScXhY= +github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw= +github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI= +github.com/prometheus/common v0.45.0 h1:2BGz0eBc2hdMDLnO/8n0jeB3oPrt2D08CekT0lneoxM= +github.com/prometheus/common v0.45.0/go.mod h1:YJmSTw9BoKxJplESWWxlbyttQR4uaEcGyv9MZjVOJsY= +github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo= +github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= @@ -362,18 +378,42 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +go.etcd.io/etcd/api/v3 v3.5.10 h1:szRajuUUbLyppkhs9K6BRtjY37l66XQQmw7oZRANE4k= +go.etcd.io/etcd/api/v3 v3.5.10/go.mod h1:TidfmT4Uycad3NM/o25fG3J07odo4GBB9hoxaodFCtI= +go.etcd.io/etcd/client/pkg/v3 v3.5.10 h1:kfYIdQftBnbAq8pUWFXfpuuxFSKzlmM5cSn76JByiT0= +go.etcd.io/etcd/client/pkg/v3 v3.5.10/go.mod h1:DYivfIviIuQ8+/lCq4vcxuseg2P2XbHygkKwFo9fc8U= +go.etcd.io/etcd/client/v3 v3.5.10 h1:W9TXNZ+oB3MCd/8UjxHTWK5J9Nquw9fQBLJd5ne5/Ao= +go.etcd.io/etcd/client/v3 v3.5.10/go.mod h1:RVeBnDz2PUEZqTpgqwAtUd8nAPf5kjyFyND7P1VkOKc= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.0 h1:PzIubN4/sjByhDRHLviCjJuweBXWFZWhghjg7cS28+M= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.0/go.mod h1:Ct6zzQEuGK3WpJs2n4dn+wfJYzd/+hNnxMRTWjGn30M= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.46.0 h1:1eHu3/pUSWaOgltNK3WJFaywKsTIr/PwvHyDmi0lQA0= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.46.0/go.mod h1:HyABWq60Uy1kjJSa2BVOxUVao8Cdick5AWSKPutqy6U= +go.opentelemetry.io/otel v1.20.0 h1:vsb/ggIY+hUjD/zCAQHpzTmndPqv/ml2ArbsbfBYTAc= +go.opentelemetry.io/otel v1.20.0/go.mod h1:oUIGj3D77RwJdM6PPZImDpSZGDvkD9fhesHny69JFrs= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.20.0 h1:DeFD0VgTZ+Cj6hxravYYZE2W4GlneVH81iAOPjZkzk8= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.20.0/go.mod h1:GijYcYmNpX1KazD5JmWGsi4P7dDTTTnfv1UbGn84MnU= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.20.0 h1:gvmNvqrPYovvyRmCSygkUDyL8lC5Tl845MLEwqpxhEU= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.20.0/go.mod h1:vNUq47TGFioo+ffTSnKNdob241vePmtNZnAODKapKd0= +go.opentelemetry.io/otel/metric v1.20.0 h1:ZlrO8Hu9+GAhnepmRGhSU7/VkpjrNowxRN9GyKR4wzA= +go.opentelemetry.io/otel/metric v1.20.0/go.mod h1:90DRw3nfK4D7Sm/75yQ00gTJxtkBxX+wu6YaNymbpVM= +go.opentelemetry.io/otel/sdk v1.20.0 h1:5Jf6imeFZlZtKv9Qbo6qt2ZkmWtdWx/wzcCbNUlAWGM= +go.opentelemetry.io/otel/sdk v1.20.0/go.mod h1:rmkSx1cZCm/tn16iWDn1GQbLtsW/LvsdEEFzCSRM6V0= +go.opentelemetry.io/otel/trace v1.20.0 h1:+yxVAPZPbQhbC3OfAkeIVTky6iTFpcr4SiY9om7mXSQ= +go.opentelemetry.io/otel/trace v1.20.0/go.mod h1:HJSK7F/hA5RlzpZ0zKDCHCDHm556LCDtKaAo6JmBFUU= +go.opentelemetry.io/proto/otlp v1.0.0 h1:T0TX0tmXU8a3CbNXzEKGeU5mIVOdf0oykP+u2lIVU/I= +go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v80hjKIs5JXpM= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= -go.uber.org/zap v1.25.0 h1:4Hvk6GtkucQ790dqmj7l1eEnRdKm3k3ZUrUMS2d5+5c= -go.uber.org/zap v1.25.0/go.mod h1:JIAUzQIH94IC4fOJQm7gMmBJP5k7wQfdcnYdPoEXJYk= +go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo= +go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= @@ -525,7 +565,6 @@ golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= @@ -672,6 +711,8 @@ google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20231016165738-49dd2c1f3d0b h1:+YaDE2r2OG8t/z5qmsh7Y+XXwCbvadxxZ0YY6mTdrVA= +google.golang.org/genproto v0.0.0-20231016165738-49dd2c1f3d0b/go.mod h1:CgAqfJo+Xmu0GwA0411Ht3OU3OntXwsGmrmjI8ioGXI= google.golang.org/genproto/googleapis/api v0.0.0-20231016165738-49dd2c1f3d0b h1:CIC2YMXmIhYw6evmhPxBKJ4fmLbOFtXQN/GV3XOZR8k= google.golang.org/genproto/googleapis/api v0.0.0-20231016165738-49dd2c1f3d0b/go.mod h1:IBQ646DjkDkvUIsVq/cc03FUFQ9wbZu7yE396YcL870= google.golang.org/genproto/googleapis/rpc v0.0.0-20231030173426-d783a09b4405 h1:AB/lmRny7e2pLhFEYIbl5qkDAUt2h0ZRO4wGPhZf+ik= @@ -692,6 +733,8 @@ google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.59.0 h1:Z5Iec2pjwb+LEOqzpB2MR12/eKFhDPhuqW91O+4bwUk= +google.golang.org/grpc v1.59.0/go.mod h1:aUPDwccQo6OTjy7Hct4AfBPD1GptF4fyUjIkQ9YtF98= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -732,41 +775,43 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -k8s.io/api v0.28.8 h1:G0/G7yX1puRAcon/+XPLsKXZ9A5L7Ds6oKbDIe027xw= -k8s.io/api v0.28.8/go.mod h1:rU8f1t9CNUAXlk/1j/wMJ7XnaxkR1g1AlZGQAOOL+sw= -k8s.io/apiextensions-apiserver v0.28.8 h1:JucS9tcaMMlfFrJ09cgh1Maeb8X2wlnxcfNpplyGHXs= -k8s.io/apiextensions-apiserver v0.28.8/go.mod h1:IKpLiKmvEYq/ti8sNtB1sM3A3vVV7fILIsvdmZswhoQ= -k8s.io/apimachinery v0.28.8 h1:hi/nrxHwk4QLV+W/SHve1bypTE59HCDorLY1stBIxKQ= -k8s.io/apimachinery v0.28.8/go.mod h1:cBnwIM3fXoRo28SqbV/Ihxf/iviw85KyXOrzxvZQ83U= -k8s.io/apiserver v0.28.8 h1:lvgyawcJFRW12oqXLydxY83nAJ5pvJJM9JX35JnKEvg= -k8s.io/apiserver v0.28.8/go.mod h1:ruOdEqhd7TzAwXMlIXdig3tQJrsv9g1F+kIF8OJRGHM= -k8s.io/client-go v0.28.8 h1:TE59Tjd87WKvS2FPBTfIKLFX0nQJ4SSHsnDo5IHjgOw= -k8s.io/client-go v0.28.8/go.mod h1:uDVQ/rPzWpWIy40c6lZ4mUwaEvRWGnpoqSO4FM65P3o= +k8s.io/api v0.29.0 h1:NiCdQMY1QOp1H8lfRyeEf8eOwV6+0xA6XEE44ohDX2A= +k8s.io/api v0.29.0/go.mod h1:sdVmXoz2Bo/cb77Pxi71IPTSErEW32xa4aXwKH7gfBA= +k8s.io/apiextensions-apiserver v0.29.0 h1:0VuspFG7Hj+SxyF/Z/2T0uFbI5gb5LRgEyUVE3Q4lV0= +k8s.io/apiextensions-apiserver v0.29.0/go.mod h1:TKmpy3bTS0mr9pylH0nOt/QzQRrW7/h7yLdRForMZwc= +k8s.io/apimachinery v0.29.0 h1:+ACVktwyicPz0oc6MTMLwa2Pw3ouLAfAon1wPLtG48o= +k8s.io/apimachinery v0.29.0/go.mod h1:eVBxQ/cwiJxH58eK/jd/vAk4mrxmVlnpBH5J2GbMeis= +k8s.io/apiserver v0.29.0 h1:Y1xEMjJkP+BIi0GSEv1BBrf1jLU9UPfAnnGGbbDdp7o= +k8s.io/apiserver v0.29.0/go.mod h1:31n78PsRKPmfpee7/l9NYEv67u6hOL6AfcE761HapDM= +k8s.io/client-go v0.29.0 h1:KmlDtFcrdUzOYrBhXHgKw5ycWzc3ryPX5mQe0SkG3y8= +k8s.io/client-go v0.29.0/go.mod h1:yLkXH4HKMAywcrD82KMSmfYg2DlE8mepPR4JGSo5n38= k8s.io/cluster-bootstrap v0.28.4 h1:4MKNy1Qd9QY7pl47rSMGIORF+tm3CUaqC1M8U9bjn4Q= k8s.io/cluster-bootstrap v0.28.4/go.mod h1:/c4ro/R4yf4EtJgFgFtvnHkbDOHwubeKJXh5R1c89Bc= -k8s.io/component-base v0.28.8 h1:N/c5L6Ty5rcrFyhsMYsqRFUOVGrqGQsLfjB0yj6npqM= -k8s.io/component-base v0.28.8/go.mod h1:9PjQ4nM1Hth6WGe/O+wgLF32eSwf4oPOoN5elmFznJM= -k8s.io/klog/v2 v2.100.1 h1:7WCHKK6K8fNhTqfBhISHQ97KrnJNFZMcQvKp7gP/tmg= -k8s.io/klog/v2 v2.100.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= -k8s.io/kube-openapi v0.0.0-20230717233707-2695361300d9 h1:LyMgNKD2P8Wn1iAwQU5OhxCKlKJy0sHc+PcDwFB24dQ= -k8s.io/kube-openapi v0.0.0-20230717233707-2695361300d9/go.mod h1:wZK2AVp1uHCp4VamDVgBP2COHZjqD1T68Rf0CM3YjSM= +k8s.io/component-base v0.29.0 h1:T7rjd5wvLnPBV1vC4zWd/iWRbV8Mdxs+nGaoaFzGw3s= +k8s.io/component-base v0.29.0/go.mod h1:sADonFTQ9Zc9yFLghpDpmNXEdHyQmFIGbiuZbqAXQ1M= +k8s.io/klog/v2 v2.110.1 h1:U/Af64HJf7FcwMcXyKm2RPM22WZzyR7OSpYj5tg3cL0= +k8s.io/klog/v2 v2.110.1/go.mod h1:YGtd1984u+GgbuZ7e08/yBuAfKLSO0+uR1Fhi6ExXjo= +k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00 h1:aVUu9fTY98ivBPKR9Y5w/AuzbMm96cd3YHRTU83I780= +k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00/go.mod h1:AsvuZPBlUDVuCdzJ87iajxtXuR9oktsTctW/R9wwouA= k8s.io/utils v0.0.0-20230726121419-3b25d923346b h1:sgn3ZU783SCgtaSJjpcVVlRqd6GSnlTLKgpAAttJvpI= k8s.io/utils v0.0.0-20230726121419-3b25d923346b/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= +sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.28.0 h1:TgtAeesdhpm2SGwkQasmbeqDo8th5wOBA5h/AjTKA4I= +sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.28.0/go.mod h1:VHVDI/KrK4fjnV61bE2g3sA7tiETLn8sooImelsCx3Y= sigs.k8s.io/cluster-api v1.6.3 h1:VOlPNg92PQLlhBVLc5pg+cbAuPvGOOBujeFLk9zgnoo= sigs.k8s.io/cluster-api v1.6.3/go.mod h1:4FzfgPPiYaFq8X9F9j2SvmggH/4OOLEDgVJuWDqKLig= sigs.k8s.io/cluster-api/test v1.6.3 h1:ZCboLCTpKWzSbf+f7MpQT7EN8aeH9DNhJC1T9/vAuAM= sigs.k8s.io/cluster-api/test v1.6.3/go.mod h1:AKs25dgW6AnyGaQBoWuXfWnBs+FT7vJmAI/aox64DEI= -sigs.k8s.io/controller-runtime v0.16.5 h1:yr1cEJbX08xsTW6XEIzT13KHHmIyX8Umvme2cULvFZw= -sigs.k8s.io/controller-runtime v0.16.5/go.mod h1:j7bialYoSn142nv9sCOJmQgDXQXxnroFU4VnX/brVJ0= +sigs.k8s.io/controller-runtime v0.17.2 h1:FwHwD1CTUemg0pW2otk7/U5/i5m2ymzvOXdbeGOUvw0= +sigs.k8s.io/controller-runtime v0.17.2/go.mod h1:+MngTvIQQQhfXtwfdGw/UOQ/aIaqsYywfCINOtwMO/s= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= sigs.k8s.io/kind v0.20.0 h1:f0sc3v9mQbGnjBUaqSFST1dwIuiikKVGgoTwpoP33a8= sigs.k8s.io/kind v0.20.0/go.mod h1:aBlbxg08cauDgZ612shr017/rZwqd7AS563FvpWKPVs= -sigs.k8s.io/structured-merge-diff/v4 v4.2.3 h1:PRbqxJClWWYMNV1dhaG4NsibJbArud9kFxnAMREiWFE= -sigs.k8s.io/structured-merge-diff/v4 v4.2.3/go.mod h1:qjx8mGObPmV2aSZepjQjbmb2ihdVs8cGKBraizNC69E= +sigs.k8s.io/structured-merge-diff/v4 v4.4.1 h1:150L+0vs/8DA78h1u02ooW1/fFq/Lwr+sGiqlzvrtq4= +sigs.k8s.io/structured-merge-diff/v4 v4.4.1/go.mod h1:N8hJocpFajUSSeSJ9bOZ77VzejKZaXsTtZo4/u7Io08= sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E= sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY= diff --git a/util/util.go b/util/util.go index 949882eaf..728a71ab6 100644 --- a/util/util.go +++ b/util/util.go @@ -22,12 +22,8 @@ import ( "net/url" "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 ( @@ -37,68 +33,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 - } - - return clusterctlv1.ProviderTypeUnknown -} - -// 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, 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.