diff --git a/cmd/clusterctl/api/v1alpha3/provider_type.go b/cmd/clusterctl/api/v1alpha3/provider_type.go index 874b3eca1fd5..913d385b7983 100644 --- a/cmd/clusterctl/api/v1alpha3/provider_type.go +++ b/cmd/clusterctl/api/v1alpha3/provider_type.go @@ -68,11 +68,6 @@ func (p *Provider) InstanceName() string { return types.NamespacedName{Namespace: p.Namespace, Name: p.ManifestLabel()}.String() } -// HasWatchingOverlapWith returns true if the provider has an overlapping watching namespace with another provider. -func (p *Provider) HasWatchingOverlapWith(other Provider) bool { - return p.WatchedNamespace == "" || p.WatchedNamespace == other.WatchedNamespace || other.WatchedNamespace == "" -} - // SameAs returns true if two providers have the same ProviderName and Type. // Please note that there could be many instances of the same provider. func (p *Provider) SameAs(other Provider) bool { diff --git a/cmd/clusterctl/client/alias.go b/cmd/clusterctl/client/alias.go index 5dbf6d2d9bd9..3835dbbaad7a 100644 --- a/cmd/clusterctl/client/alias.go +++ b/cmd/clusterctl/client/alias.go @@ -38,7 +38,7 @@ type ComponentsOptions repository.ComponentsOptions // Template wraps a YAML file that defines the cluster objects (Cluster, Machines etc.). type Template repository.Template -// UpgradePlan defines a list of possible upgrade targets for a management group. +// UpgradePlan defines a list of possible upgrade targets for a management cluster. type UpgradePlan cluster.UpgradePlan // CertManagerUpgradePlan defines the upgrade plan if cert-manager needs to be diff --git a/cmd/clusterctl/client/client.go b/cmd/clusterctl/client/client.go index 4e8332a5023a..6bf46b7fb3f8 100644 --- a/cmd/clusterctl/client/client.go +++ b/cmd/clusterctl/client/client.go @@ -52,10 +52,8 @@ type Client interface { Move(options MoveOptions) error // PlanUpgrade returns a set of suggested Upgrade plans for the cluster, and more specifically: - // - Each management group gets separated upgrade plans. - // - For each management group, an upgrade plan is generated for each API Version of Cluster API (contract) available, e.g. - // - Upgrade to the latest version in the the v1alpha2 series: .... - // - Upgrade to the latest version in the the v1alpha3 series: .... + // - Upgrade to the latest version in the the v1alpha3 series: .... + // - Upgrade to the latest version in the the v1alpha4 series: .... PlanUpgrade(options PlanUpgradeOptions) ([]UpgradePlan, error) // PlanCertManagerUpgrade returns a CertManagerUpgradePlan. diff --git a/cmd/clusterctl/client/cluster/installer.go b/cmd/clusterctl/client/cluster/installer.go index fba7e678e262..8cde45a12cfd 100644 --- a/cmd/clusterctl/client/cluster/installer.go +++ b/cmd/clusterctl/client/cluster/installer.go @@ -39,11 +39,8 @@ type ProviderInstaller interface { // Validate performs steps to validate a management cluster by looking at the current state and the providers in the queue. // The following checks are performed in order to ensure a fully operational cluster: - // - There must be only one instance of the same provider per namespace - // - Instances of the same provider must not be fighting for objects (no watching overlap) - // - Providers must combine in valid management groups - // - All the providers must belong to one/only one management groups - // - All the providers in a management group must support the same API Version of Cluster API (contract) + // - There must be only one instance of the same provider + // - All the providers in must support the same API Version of Cluster API (contract) Validate() error // Images returns the list of images required for installing the providers ready in the install queue. @@ -167,43 +164,39 @@ func (i *providerInstaller) Validate() error { // Starts simulating what will be the resulting management cluster by adding to the list the providers in the installQueue. // During this operation following checks are performed: - // - There must be only one instance of the same provider per namespace - // - Instances of the same provider must not be fighting for objects (no watching overlap) + // - There must be only one instance of the same provider for _, components := range i.installQueue { if providerList, err = simulateInstall(providerList, components); err != nil { return errors.Wrapf(err, "installing provider %q can lead to a non functioning management cluster", components.ManifestLabel()) } } - // Now that the provider list contains all the providers that are scheduled for install, gets the resulting management groups. - // During this operation following check is performed: - // - Providers must combine in valid management groups - // - All the providers must belong to one/only one management group - managementGroups, err := deriveManagementGroups(providerList) + // Gets the API Version of Cluster API (contract) all the providers in the management cluster must support, + // which is the same of the core provider. + providerInstanceContracts := map[string]string{} + + coreProviders := providerList.FilterCore() + if len(coreProviders) != 1 { + return errors.Errorf("invalid management cluster: there should a core provider, found %d", len(coreProviders)) + } + coreProvider := coreProviders[0] + + managementClusterContract, err := i.getProviderContract(providerInstanceContracts, coreProvider) if err != nil { return err } - // Checks if all the providers supports the same API Version of Cluster API (contract) of the corresponding management group. - providerInstanceContracts := map[string]string{} + // Checks if all the providers supports the same API Version of Cluster API (contract). for _, components := range i.installQueue { provider := components.InventoryObject() - // Gets the management group the providers belongs to, and then retrieve the API Version of Cluster API (contract) - // all the providers in the management group must support. - managementGroup := managementGroups.FindManagementGroupByProviderInstanceName(provider.InstanceName()) - managementGroupContract, err := i.getProviderContract(providerInstanceContracts, managementGroup.CoreProvider) - if err != nil { - return err - } - - // Gets the API Version of Cluster API (contract) the provider support and compare it with the management group contract. + // Gets the API Version of Cluster API (contract) the provider support and compare it with the management cluster contract. providerContract, err := i.getProviderContract(providerInstanceContracts, provider) if err != nil { return err } - if providerContract != managementGroupContract { - return errors.Errorf("installing provider %q can lead to a non functioning management cluster: the target version for the provider supports the %s API Version of Cluster API (contract), while the management group is using %s", components.ManifestLabel(), providerContract, managementGroupContract) + if providerContract != managementClusterContract { + return errors.Errorf("installing provider %q can lead to a non functioning management cluster: the target version for the provider supports the %s API Version of Cluster API (contract), while the management cluster is using %s", components.ManifestLabel(), providerContract, managementClusterContract) } } return nil @@ -258,26 +251,11 @@ func simulateInstall(providerList *clusterctlv1.ProviderList, components reposit provider := components.InventoryObject() existingInstances := providerList.FilterByProviderNameAndType(provider.ProviderName, provider.GetProviderType()) - - // Target Namespace check - // Installing two instances of the same provider in the same namespace won't be supported - for _, i := range existingInstances { - if i.Namespace == provider.Namespace { - return providerList, errors.Errorf("there is already an instance of the %q provider installed in the %q namespace", provider.ManifestLabel(), provider.Namespace) - } - } - - // Watching Namespace check: - // If we are going to install an instance of a provider watching objects in namespaces already controlled by other providers - // then there will be providers fighting for objects... - for _, i := range existingInstances { - if i.HasWatchingOverlapWith(provider) { - return providerList, errors.Errorf("the new instance of the %q provider is going to watch for objects in the namespace %q that is already controlled by other instances of the same provider", provider.ManifestLabel(), provider.WatchedNamespace) - } + if len(existingInstances) > 0 { + return providerList, errors.Errorf("there is already an instance of the %q provider installed in the %q namespace", provider.ManifestLabel(), provider.Namespace) } providerList.Items = append(providerList.Items, provider) - return providerList, nil } diff --git a/cmd/clusterctl/client/cluster/installer_test.go b/cmd/clusterctl/client/cluster/installer_test.go index f3964ffaf974..b52ad95fb077 100644 --- a/cmd/clusterctl/client/cluster/installer_test.go +++ b/cmd/clusterctl/client/cluster/installer_test.go @@ -128,16 +128,16 @@ func Test_providerInstaller_Validate(t *testing.T) { wantErr: false, }, { - name: "install another instance of infra1/current contract on a cluster already initialized with core/current contract + infra1/current contract, no overlaps", + name: "install another instance of infra1/current contract on a cluster already initialized with core/current contract + infra1/current contract", fields: fields{ proxy: test.NewFakeProxy(). WithProviderInventory("cluster-api", clusterctlv1.CoreProviderType, "v1.0.0", "cluster-api-system", ""). - WithProviderInventory("infra1", clusterctlv1.InfrastructureProviderType, "v1.0.0", "ns1", "ns1"), + WithProviderInventory("infra1", clusterctlv1.InfrastructureProviderType, "v1.0.0", "ns1", ""), installQueue: []repository.Components{ - newFakeComponents("infra2", clusterctlv1.InfrastructureProviderType, "v1.0.0", "ns2", "ns2"), + newFakeComponents("infra1", clusterctlv1.InfrastructureProviderType, "v1.0.0", "ns2", ""), }, }, - wantErr: false, + wantErr: true, }, { name: "install another instance of infra1/current contract on a cluster already initialized with core/current contract + infra1/current contract, same namespace of the existing infra1", @@ -152,37 +152,13 @@ func Test_providerInstaller_Validate(t *testing.T) { wantErr: true, }, { - name: "install another instance of infra1/current contract on a cluster already initialized with core/current contract + infra1/current contract, watching overlap with the existing infra1", + name: "install another instance of infra1/current contract on a cluster already initialized with core/current contract + infra1/current contract, different namespace of the existing infra1", fields: fields{ proxy: test.NewFakeProxy(). WithProviderInventory("cluster-api", clusterctlv1.CoreProviderType, "v1.0.0", "cluster-api-system", ""). - WithProviderInventory("infra1", clusterctlv1.InfrastructureProviderType, "v1.0.0", "infra1-system", ""), - installQueue: []repository.Components{ - newFakeComponents("infra1", clusterctlv1.InfrastructureProviderType, "v1.0.0", "infra2-system", ""), - }, - }, - wantErr: true, - }, - { - name: "install another instance of infra1/current contract on a cluster already initialized with core/current contract + infra1/current contract, not part of the existing management group", - fields: fields{ - proxy: test.NewFakeProxy(). - WithProviderInventory("cluster-api", clusterctlv1.CoreProviderType, "v1.0.0", "ns1", "ns1"). - WithProviderInventory("infra1", clusterctlv1.InfrastructureProviderType, "v1.0.0", "ns1", "ns1"), - installQueue: []repository.Components{ - newFakeComponents("infra1", clusterctlv1.InfrastructureProviderType, "v1.0.0", "ns2", "ns2"), - }, - }, - wantErr: true, - }, - { - name: "install an instance of infra1/current contract on a cluster already initialized with two core/current contract, but it is part of two management group", - fields: fields{ - proxy: test.NewFakeProxy(). // cluster with two core (two management groups) - WithProviderInventory("cluster-api", clusterctlv1.CoreProviderType, "v1.0.0", "ns1", "ns1"). - WithProviderInventory("cluster-api", clusterctlv1.CoreProviderType, "v1.0.0", "ns2", "ns2"), + WithProviderInventory("infra1", clusterctlv1.InfrastructureProviderType, "v1.0.0", "n1", ""), installQueue: []repository.Components{ - newFakeComponents("infra1", clusterctlv1.InfrastructureProviderType, "v1.0.0", "infra1-system", ""), + newFakeComponents("infra1", clusterctlv1.InfrastructureProviderType, "v1.0.0", "n2", ""), }, }, wantErr: true, diff --git a/cmd/clusterctl/client/cluster/inventory.go b/cmd/clusterctl/client/cluster/inventory.go index e20abf747118..c0a535c5b477 100644 --- a/cmd/clusterctl/client/cluster/inventory.go +++ b/cmd/clusterctl/client/cluster/inventory.go @@ -103,9 +103,6 @@ type InventoryClient interface { // this as the default namespace; In case there are more instances for the same provider installed in different namespaces, there is no default provider namespace. GetDefaultProviderNamespace(provider string, providerType clusterctlv1.ProviderType) (string, error) - // GetManagementGroups returns the list of management groups defined in the management cluster. - GetManagementGroups() (ManagementGroupList, error) - // CheckCAPIContract checks the Cluster API version installed in the management cluster, and fails if this version // does not match the current one supported by clusterctl. CheckCAPIContract(...CheckCAPIContractOption) error diff --git a/cmd/clusterctl/client/cluster/inventory_managementgroup.go b/cmd/clusterctl/client/cluster/inventory_managementgroup.go deleted file mode 100644 index ec44435c0b47..000000000000 --- a/cmd/clusterctl/client/cluster/inventory_managementgroup.go +++ /dev/null @@ -1,154 +0,0 @@ -/* -Copyright 2020 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 cluster - -import ( - "strings" - - "github.com/pkg/errors" - clusterctlv1 "sigs.k8s.io/cluster-api/cmd/clusterctl/api/v1alpha3" -) - -// ManagementGroup is a group of providers composed by a CoreProvider and a set of Bootstrap/ControlPlane/Infrastructure providers -// watching objects in the same namespace. For example, a management group can be used for upgrades, in order to ensure all the providers -// in a management group support the same API Version of Cluster API (contract). -type ManagementGroup struct { - CoreProvider clusterctlv1.Provider - Providers []clusterctlv1.Provider -} - -// Equals return true if two management groups have the same core provider. -func (mg *ManagementGroup) Equals(other *ManagementGroup) bool { - return mg.CoreProvider.Equals(other.CoreProvider) -} - -// GetProviderByInstanceName returns a specific provider instance. -func (mg *ManagementGroup) GetProviderByInstanceName(instanceName string) *clusterctlv1.Provider { - for _, provider := range mg.Providers { - if provider.InstanceName() == instanceName { - return &provider - } - } - return nil -} - -// ManagementGroupList defines a list of management groups. -type ManagementGroupList []ManagementGroup - -// FindManagementGroupByProviderInstanceName return the management group that hosts a given provider. -func (ml *ManagementGroupList) FindManagementGroupByProviderInstanceName(instanceName string) *ManagementGroup { - for _, managementGroup := range *ml { - if p := managementGroup.GetProviderByInstanceName(instanceName); p != nil { - return &managementGroup - } - } - return nil -} - -// deriveManagementGroups derives the management groups from a list of providers. -func deriveManagementGroups(providerList *clusterctlv1.ProviderList) (ManagementGroupList, error) { - // If any of the core providers watch the same namespace, we cannot define the management group. - if err := checkOverlappingCoreProviders(providerList); err != nil { - return nil, err - } - - // If any of the Bootstrap/ControlPlane/Infrastructure providers can't be combined with a core provider, - // or if any of the Bootstrap/ControlPlane/Infrastructure providers is watching objects controlled by more than one core provider - // we can't define a management group. - if err := checkOverlappingProviders(providerList); err != nil { - return nil, err - } - - // Composes the management group - managementGroups := ManagementGroupList{} - for _, coreProvider := range providerList.FilterCore() { - group := ManagementGroup{CoreProvider: coreProvider} - for _, provider := range providerList.Items { - if coreProvider.HasWatchingOverlapWith(provider) { - group.Providers = append(group.Providers, provider) - } - } - managementGroups = append(managementGroups, group) - } - - return managementGroups, nil -} - -// checkOverlappingCoreProviders checks if there are core providers with overlapping watching namespaces, if yes, return error e.g. -// cluster-api in capi-system watching all namespaces and another cluster-api in capi-system2 watching capi-system2 (both are watching capi-system2) -// NB. This should not happen because init prevent the users to do so, but nevertheless we are double checking this before upgrades. -func checkOverlappingCoreProviders(providerList *clusterctlv1.ProviderList) error { - for _, provider := range providerList.FilterCore() { - for _, other := range providerList.FilterCore() { - // if the provider to compare is the same of the other provider, skip it - if provider.Equals(other) { - continue - } - - // check for overlapping namespaces - if provider.HasWatchingOverlapWith(other) { - return errors.Errorf("Unable to identify management groups: core providers %s and %s have overlapping watching namespaces", - provider.InstanceName(), - other.InstanceName(), - ) - } - } - } - return nil -} - -// checkOverlappingProviders checks if Bootstrap/ControlPlane/Infrastructure providers: -// 1) can't be combined with any core provider -// e.g. cluster-api in capi-system watching capi-system and aws in capa-system watching capa-system (they are watching different namespaces) -// 2) can be combined with more than one core provider -// e.g. cluster-api in capi-system1 watching all capi-system1, cluster-api in capi-system2 watching all capi-system2, aws in capa-system watching all namespaces (aws is working with both CAPI instances, but this is not a configuration supported by clusterctl) -func checkOverlappingProviders(providerList *clusterctlv1.ProviderList) error { - for _, provider := range providerList.FilterNonCore() { - // check for the core providers watching objects in the same namespace of the provider - var overlappingCoreProviders []string - for _, coreProvider := range providerList.FilterCore() { - if provider.HasWatchingOverlapWith(coreProvider) { - overlappingCoreProviders = append(overlappingCoreProviders, coreProvider.InstanceName()) - } - } - - // if the provider does not overlap with any core provider, return error (it will not be part of any management group) - if len(overlappingCoreProviders) == 0 { - return errors.Errorf("Unable to identify management groups: provider %s can't be combined with any core provider", - provider.InstanceName(), - ) - } - - // if the provider overlaps with more than one core provider, return error (it is part of two management groups --> e.g. there could be potential upgrade conflicts) - if len(overlappingCoreProviders) > 1 { - return errors.Errorf("Unable to identify management groups: provider %s is watching for objects in namespaces controlled by more than one core provider (%s)", - provider.InstanceName(), - strings.Join(overlappingCoreProviders, " ,"), - ) - } - } - return nil -} - -func (p *inventoryClient) GetManagementGroups() (ManagementGroupList, error) { - providerList, err := p.List() - if err != nil { - return nil, err - } - - return deriveManagementGroups(providerList) -} diff --git a/cmd/clusterctl/client/cluster/inventory_managementgroup_test.go b/cmd/clusterctl/client/cluster/inventory_managementgroup_test.go deleted file mode 100644 index 5de1f352162e..000000000000 --- a/cmd/clusterctl/client/cluster/inventory_managementgroup_test.go +++ /dev/null @@ -1,188 +0,0 @@ -/* -Copyright 2020 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 cluster - -import ( - "testing" - - . "github.com/onsi/gomega" - - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - clusterv1 "sigs.k8s.io/cluster-api/api/v1alpha4" - clusterctlv1 "sigs.k8s.io/cluster-api/cmd/clusterctl/api/v1alpha3" - "sigs.k8s.io/cluster-api/cmd/clusterctl/internal/test" -) - -func Test_inventoryClient_GetManagementGroups(t *testing.T) { - type fields struct { - proxy Proxy - } - tests := []struct { - name string - fields fields - want ManagementGroupList - wantErr bool - }{ - { - name: "Simple management cluster", - fields: fields{ // 1 instance for each provider, watching all namespace - proxy: test.NewFakeProxy(). - WithProviderInventory("cluster-api", clusterctlv1.CoreProviderType, "v1.0.0", "cluster-api-system", ""). - WithProviderInventory("bootstrap", clusterctlv1.BootstrapProviderType, "v1.0.0", "bootstrap-system", ""). - WithProviderInventory("infrastructure", clusterctlv1.InfrastructureProviderType, "v1.0.0", "infra-system", ""), - }, - want: ManagementGroupList{ // One Group - { - CoreProvider: fakeProvider("cluster-api", clusterctlv1.CoreProviderType, "v1.0.0", "cluster-api-system", ""), - Providers: []clusterctlv1.Provider{ - fakeProvider("cluster-api", clusterctlv1.CoreProviderType, "v1.0.0", "cluster-api-system", ""), - fakeProvider("bootstrap", clusterctlv1.BootstrapProviderType, "v1.0.0", "bootstrap-system", ""), - fakeProvider("infrastructure", clusterctlv1.InfrastructureProviderType, "v1.0.0", "infra-system", ""), - }, - }, - }, - wantErr: false, - }, - { - name: "1 Core, many infra (1 ManagementGroup)", - fields: fields{ // 1 instance of core and bootstrap provider, watching all namespace; more instances of infrastructure providers, each watching dedicated ns - proxy: test.NewFakeProxy(). - WithProviderInventory("cluster-api", clusterctlv1.CoreProviderType, "v1.0.0", "cluster-api-system", ""). - WithProviderInventory("bootstrap", clusterctlv1.BootstrapProviderType, "v1.0.0", "bootstrap-system", ""). - WithProviderInventory("infrastructure", clusterctlv1.InfrastructureProviderType, "v1.0.0", "infra-system1", "ns1"). - WithProviderInventory("infrastructure", clusterctlv1.InfrastructureProviderType, "v1.0.0", "infra-system2", "ns2"), - }, - want: ManagementGroupList{ // One Group - { - CoreProvider: fakeProvider("cluster-api", clusterctlv1.CoreProviderType, "v1.0.0", "cluster-api-system", ""), - Providers: []clusterctlv1.Provider{ - fakeProvider("cluster-api", clusterctlv1.CoreProviderType, "v1.0.0", "cluster-api-system", ""), - fakeProvider("bootstrap", clusterctlv1.BootstrapProviderType, "v1.0.0", "bootstrap-system", ""), - fakeProvider("infrastructure", clusterctlv1.InfrastructureProviderType, "v1.0.0", "infra-system1", "ns1"), - fakeProvider("infrastructure", clusterctlv1.InfrastructureProviderType, "v1.0.0", "infra-system2", "ns2"), - }, - }, - }, - wantErr: false, - }, - { - name: "two ManagementGroups", - fields: fields{ // more instances of core with related bootstrap, infrastructure - proxy: test.NewFakeProxy(). - WithProviderInventory("cluster-api", clusterctlv1.CoreProviderType, "v1.0.0", "cluster-api-system1", "ns1"). - WithProviderInventory("bootstrap", clusterctlv1.BootstrapProviderType, "v1.0.0", "bootstrap-system1", "ns1"). - WithProviderInventory("infrastructure", clusterctlv1.InfrastructureProviderType, "v1.0.0", "infra-system1", "ns1"). - WithProviderInventory("cluster-api", clusterctlv1.CoreProviderType, "v1.0.0", "cluster-api-system2", "ns2"). - WithProviderInventory("bootstrap", clusterctlv1.BootstrapProviderType, "v1.0.0", "bootstrap-system2", "ns2"). - WithProviderInventory("infrastructure", clusterctlv1.InfrastructureProviderType, "v1.0.0", "infra-system2", "ns2"), - }, - want: ManagementGroupList{ // Two Groups - { - CoreProvider: fakeProvider("cluster-api", clusterctlv1.CoreProviderType, "v1.0.0", "cluster-api-system1", "ns1"), - Providers: []clusterctlv1.Provider{ - fakeProvider("cluster-api", clusterctlv1.CoreProviderType, "v1.0.0", "cluster-api-system1", "ns1"), - fakeProvider("bootstrap", clusterctlv1.BootstrapProviderType, "v1.0.0", "bootstrap-system1", "ns1"), - fakeProvider("infrastructure", clusterctlv1.InfrastructureProviderType, "v1.0.0", "infra-system1", "ns1"), - }, - }, - { - CoreProvider: fakeProvider("cluster-api", clusterctlv1.CoreProviderType, "v1.0.0", "cluster-api-system2", "ns2"), - Providers: []clusterctlv1.Provider{ - fakeProvider("cluster-api", clusterctlv1.CoreProviderType, "v1.0.0", "cluster-api-system2", "ns2"), - fakeProvider("bootstrap", clusterctlv1.BootstrapProviderType, "v1.0.0", "bootstrap-system2", "ns2"), - fakeProvider("infrastructure", clusterctlv1.InfrastructureProviderType, "v1.0.0", "infra-system2", "ns2"), - }, - }, - }, - wantErr: false, - }, - { - name: "fails with overlapping core providers", - fields: fields{ // two core providers watching for the same namespaces - proxy: test.NewFakeProxy(). - WithProviderInventory("cluster-api", clusterctlv1.CoreProviderType, "v1.0.0", "cluster-api-system1", ""). - WithProviderInventory("cluster-api", clusterctlv1.CoreProviderType, "v1.0.0", "cluster-api-system2", ""), - }, - want: nil, - wantErr: true, - }, - { - name: "fails with overlapping core providers", - fields: fields{ // a provider watching for objects controlled by more than one core provider - proxy: test.NewFakeProxy(). - WithProviderInventory("infrastructure", clusterctlv1.InfrastructureProviderType, "v1.0.0", "infra-system", ""). - WithProviderInventory("cluster-api", clusterctlv1.CoreProviderType, "v1.0.0", "cluster-api-system1", "ns1"). - WithProviderInventory("cluster-api", clusterctlv1.CoreProviderType, "v1.0.0", "cluster-api-system2", "ns2"), - }, - want: nil, - wantErr: true, - }, - { - name: "fails with orphan providers", - fields: fields{ // a provider watching for objects not controlled any core provider - proxy: test.NewFakeProxy(). - WithProviderInventory("infrastructure", clusterctlv1.InfrastructureProviderType, "v1.0.0", "infra-system", "ns1"). - WithProviderInventory("cluster-api", clusterctlv1.CoreProviderType, "v1.0.0", "cluster-api-system1", "ns2"), - }, - want: nil, - wantErr: true, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - g := NewWithT(t) - - p := &inventoryClient{ - proxy: tt.fields.proxy, - } - got, err := p.GetManagementGroups() - if tt.wantErr { - g.Expect(err).To(HaveOccurred()) - return - } - g.Expect(err).NotTo(HaveOccurred()) - g.Expect(got).To(HaveLen(len(tt.want))) - for i := range tt.want { - g.Expect(got[i].CoreProvider).To(Equal(tt.want[i].CoreProvider)) - g.Expect(got[i].Providers).To(ConsistOf(tt.want[i].Providers)) - } - }) - } -} - -func fakeProvider(name string, providerType clusterctlv1.ProviderType, version, targetNamespace, watchingNamespace string) clusterctlv1.Provider { - return clusterctlv1.Provider{ - TypeMeta: metav1.TypeMeta{ - APIVersion: clusterctlv1.GroupVersion.String(), - Kind: "Provider", - }, - ObjectMeta: metav1.ObjectMeta{ - ResourceVersion: "1", - Namespace: targetNamespace, - Name: clusterctlv1.ManifestLabel(name, providerType), - Labels: map[string]string{ - clusterctlv1.ClusterctlLabelName: "", - clusterv1.ProviderLabelName: clusterctlv1.ManifestLabel(name, providerType), - clusterctlv1.ClusterctlCoreLabelName: "inventory", - }, - }, - ProviderName: name, - Type: string(providerType), - Version: version, - WatchedNamespace: watchingNamespace, - } -} diff --git a/cmd/clusterctl/client/cluster/upgrader.go b/cmd/clusterctl/client/cluster/upgrader.go index 7c5bdcc06124..fa87c247ce78 100644 --- a/cmd/clusterctl/client/cluster/upgrader.go +++ b/cmd/clusterctl/client/cluster/upgrader.go @@ -29,31 +29,22 @@ import ( // ProviderUpgrader defines methods for supporting provider upgrade. type ProviderUpgrader interface { - // Plan returns a set of suggested Upgrade plans for the cluster, and more specifically: - // - Each management group gets separated upgrade plans. - // - For each management group, an upgrade plan will be generated for each API Version of Cluster API (contract) available, e.g. - // - Upgrade to the latest version in the the v1alpha2 series: .... + // Plan returns a set of suggested Upgrade plans for the management cluster, and more specifically: // - Upgrade to the latest version in the the v1alpha3 series: .... + // - Upgrade to the latest version in the the v1alpha4 series: .... Plan() ([]UpgradePlan, error) // ApplyPlan executes an upgrade following an UpgradePlan generated by clusterctl. - ApplyPlan(coreProvider clusterctlv1.Provider, clusterAPIVersion string) error + ApplyPlan(clusterAPIVersion string) error // ApplyCustomPlan plan executes an upgrade using the UpgradeItems provided by the user. - ApplyCustomPlan(coreProvider clusterctlv1.Provider, providersToUpgrade ...UpgradeItem) error + ApplyCustomPlan(providersToUpgrade ...UpgradeItem) error } -// UpgradePlan defines a list of possible upgrade targets for a management group. +// UpgradePlan defines a list of possible upgrade targets for a management cluster. type UpgradePlan struct { - Contract string - CoreProvider clusterctlv1.Provider - Providers []UpgradeItem -} - -// UpgradeRef returns a string identifying the upgrade plan; this string is derived by the core provider which is -// unique for each management group. -func (u *UpgradePlan) UpgradeRef() string { - return u.CoreProvider.InstanceName() + Contract string + Providers []UpgradeItem } // isPartialUpgrade returns true if at least one upgradeItem in the plan does not have a target version. @@ -66,7 +57,7 @@ func (u *UpgradePlan) isPartialUpgrade() bool { return false } -// UpgradeItem defines a possible upgrade target for a provider in the management group. +// UpgradeItem defines a possible upgrade target for a provider in the management cluster. type UpgradeItem struct { clusterctlv1.Provider NextVersion string @@ -90,61 +81,65 @@ func (u *providerUpgrader) Plan() ([]UpgradePlan, error) { log := logf.Log log.Info("Checking new release availability...") - managementGroups, err := u.providerInventory.GetManagementGroups() + providerList, err := u.providerInventory.List() if err != nil { return nil, err } - var ret []UpgradePlan - for _, managementGroup := range managementGroups { - // The core provider is driving all the plan logic for each management group, because all the providers - // in a management group are expected to support the same API Version of Cluster API (contract). - // e.g if the core provider supports v1alpha4, all the providers in the same management group should support v1alpha4 as well; - // all the providers in the management group can upgrade to the latest release supporting v1alpha4, or if available, - // or if available, all the providers in the management group can upgrade to the latest release supporting v1alpha5 - // (not supported in current clusterctl release, but upgrade plan should report these options) - // Please note that upgrade plan also works on management cluster still in v1alpha3. In this case upgrade plan is shown, but - // upgrade to latest version in the v1alpha3 series are not supported using clusterctl v1alpha4 (use older releases). - - // Gets the upgrade info for the core provider. - coreUpgradeInfo, err := u.getUpgradeInfo(managementGroup.CoreProvider) + // The core provider is driving all the plan logic for entire management cluster, because all the providers + // are expected to support the same API Version of Cluster API (contract). + // e.g if the core provider supports v1alpha4, all the providers in the same management cluster should support v1alpha4 as well; + // all the providers in the management cluster can upgrade to the latest release supporting v1alpha4, or if available, + // all the providers can upgrade to the latest release supporting v1alpha5 (not supported in current clusterctl release, + // but upgrade plan should report these options) + // Please note that upgrade plan also works on management cluster still in v1alpha3. In this case upgrade plan is shown, but + // upgrade to latest version in the v1alpha3 series are not supported using clusterctl v1alpha4 (use older releases). + + // Gets the upgrade info for the core provider. + coreProviders := providerList.FilterCore() + if len(coreProviders) != 1 { + return nil, errors.Errorf("invalid management cluster: there should a core provider, found %d", len(coreProviders)) + } + coreProvider := coreProviders[0] + + coreUpgradeInfo, err := u.getUpgradeInfo(coreProvider) + if err != nil { + return nil, err + } + + // Identifies the API Version of Cluster API (contract) that we should consider for the management cluster update (Nb. the core provider is driving the entire management cluster). + // This includes the current contract and the new ones available, if any. + contractsForUpgrade := coreUpgradeInfo.getContractsForUpgrade() + if len(contractsForUpgrade) == 0 { + return nil, errors.Wrapf(err, "invalid metadata: unable to find th API Version of Cluster API (contract) supported by the %s provider", coreProvider.InstanceName()) + } + + // Creates an UpgradePlan for each contract considered for upgrades; each upgrade plans contains + // an UpgradeItem for each provider defining the next available version with the target contract, if available. + // e.g. v1alpha3, cluster-api --> v0.3.2, kubeadm bootstrap --> v0.3.2, aws --> v0.5.4 (not supported in current clusterctl release, but upgrade plan should report these options). + // e.g. v1alpha4, cluster-api --> v0.4.1, kubeadm bootstrap --> v0.4.1, aws --> v0.X.2 + // e.g. v1alpha4, cluster-api --> v0.5.1, kubeadm bootstrap --> v0.5.1, aws --> v0.Y.4 (not supported in current clusterctl release, but upgrade plan should report these options). + ret := make([]UpgradePlan, 0) + for _, contract := range contractsForUpgrade { + upgradePlan, err := u.getUpgradePlan(providerList.Items, contract) if err != nil { return nil, err } - // Identifies the API Version of Cluster API (contract) that we should consider for the management group update (Nb. the core provider is driving the entire management group). - // This includes the current contract (e.g. v1alpha3) and the new one available, if any. - contractsForUpgrade := coreUpgradeInfo.getContractsForUpgrade() - if len(contractsForUpgrade) == 0 { - return nil, errors.Wrapf(err, "Invalid metadata: unable to find th API Version of Cluster API (contract) supported by the %s provider", managementGroup.CoreProvider.InstanceName()) + // If the upgrade plan is partial (at least one upgradeItem in the plan does not have a target version) and + // the upgrade plan requires a change of the contract for this management cluster, then drop it + // (all the provider in a management cluster are required to change contract at the same time). + if upgradePlan.isPartialUpgrade() && coreUpgradeInfo.currentContract != contract { + continue } - // Creates an UpgradePlan for each contract considered for upgrades; each upgrade plans contains - // an UpgradeItem for each provider defining the next available version with the target contract, if available. - // e.g. v1alpha3, cluster-api --> v0.3.2, kubeadm bootstrap --> v0.3.2, aws --> v0.5.4 (not supported in current clusterctl release, but upgrade plan should report these options). - // e.g. v1alpha4, cluster-api --> v0.4.1, kubeadm bootstrap --> v0.4.1, aws --> v0.X.2 - // e.g. v1alpha4, cluster-api --> v0.5.1, kubeadm bootstrap --> v0.5.1, aws --> v0.Y.4 (not supported in current clusterctl release, but upgrade plan should report these options). - for _, contract := range contractsForUpgrade { - upgradePlan, err := u.getUpgradePlan(managementGroup, contract) - if err != nil { - return nil, err - } - - // If the upgrade plan is partial (at least one upgradeItem in the plan does not have a target version) and - // the upgrade plan requires a change of the contract for this management group, then drop it - // (all the provider in a management group are required to change contract at the same time). - if upgradePlan.isPartialUpgrade() && coreUpgradeInfo.currentContract != contract { - continue - } - - ret = append(ret, *upgradePlan) - } + ret = append(ret, *upgradePlan) } return ret, nil } -func (u *providerUpgrader) ApplyPlan(coreProvider clusterctlv1.Provider, contract string) error { +func (u *providerUpgrader) ApplyPlan(contract string) error { if contract != clusterv1.GroupVersion.Version { return errors.Errorf("current version of clusterctl could only upgrade to %s contract, requested %s", clusterv1.GroupVersion.Version, contract) } @@ -152,14 +147,13 @@ func (u *providerUpgrader) ApplyPlan(coreProvider clusterctlv1.Provider, contrac log := logf.Log log.Info("Performing upgrade...") - // Retrieves the management group. - managementGroup, err := u.getManagementGroup(coreProvider) + // Gets the upgrade plan for the selected API Version of Cluster API (contract). + providerList, err := u.providerInventory.List() if err != nil { return err } - // Gets the upgrade plan for the selected management group/API Version of Cluster API (contract). - upgradePlan, err := u.getUpgradePlan(*managementGroup, contract) + upgradePlan, err := u.getUpgradePlan(providerList.Items, contract) if err != nil { return err } @@ -168,13 +162,13 @@ func (u *providerUpgrader) ApplyPlan(coreProvider clusterctlv1.Provider, contrac return u.doUpgrade(upgradePlan) } -func (u *providerUpgrader) ApplyCustomPlan(coreProvider clusterctlv1.Provider, upgradeItems ...UpgradeItem) error { +func (u *providerUpgrader) ApplyCustomPlan(upgradeItems ...UpgradeItem) error { log := logf.Log log.Info("Performing upgrade...") // Create a custom upgrade plan from the upgrade items, taking care of ensuring all the providers in a management - // group are consistent with the API Version of Cluster API (contract). - upgradePlan, err := u.createCustomPlan(coreProvider, upgradeItems) + // cluster are consistent with the API Version of Cluster API (contract). + upgradePlan, err := u.createCustomPlan(upgradeItems) if err != nil { return err } @@ -183,11 +177,11 @@ func (u *providerUpgrader) ApplyCustomPlan(coreProvider clusterctlv1.Provider, u return u.doUpgrade(upgradePlan) } -// getUpgradePlan returns the upgrade plan for a specific managementGroup/contract +// getUpgradePlan returns the upgrade plan for a specific set of providers/contract // NB. this function is used both for upgrade plan and upgrade apply. -func (u *providerUpgrader) getUpgradePlan(managementGroup ManagementGroup, contract string) (*UpgradePlan, error) { +func (u *providerUpgrader) getUpgradePlan(providers []clusterctlv1.Provider, contract string) (*UpgradePlan, error) { upgradeItems := []UpgradeItem{} - for _, provider := range managementGroup.Providers { + for _, provider := range providers { // Gets the upgrade info for the provider. providerUpgradeInfo, err := u.getUpgradeInfo(provider) if err != nil { @@ -205,51 +199,39 @@ func (u *providerUpgrader) getUpgradePlan(managementGroup ManagementGroup, contr } return &UpgradePlan{ - Contract: contract, - CoreProvider: managementGroup.CoreProvider, - Providers: upgradeItems, + Contract: contract, + Providers: upgradeItems, }, nil } -// getManagementGroup returns the management group for a core provider. -func (u *providerUpgrader) getManagementGroup(coreProvider clusterctlv1.Provider) (*ManagementGroup, error) { - managementGroups, err := u.providerInventory.GetManagementGroups() - if err != nil { - return nil, err - } - - managementGroup := managementGroups.FindManagementGroupByProviderInstanceName(coreProvider.InstanceName()) - if managementGroup == nil { - return nil, errors.Errorf("unable to identify %s/%s the management group", coreProvider.Namespace, coreProvider.ProviderName) - } - - return managementGroup, nil -} - // createCustomPlan creates a custom upgrade plan from a set of upgrade items, taking care of ensuring all the providers -// in a management group are consistent with the API Version of Cluster API (contract). -func (u *providerUpgrader) createCustomPlan(coreProvider clusterctlv1.Provider, upgradeItems []UpgradeItem) (*UpgradePlan, error) { - // Retrieves the management group. - managementGroup, err := u.getManagementGroup(coreProvider) - if err != nil { - return nil, err - } - +// in a management cluster are consistent with the API Version of Cluster API (contract). +func (u *providerUpgrader) createCustomPlan(upgradeItems []UpgradeItem) (*UpgradePlan, error) { // Gets the API Version of Cluster API (contract). - // The this is required to ensure all the providers in a management group are consistent with the contract supported by the core provider. - // e.g if the core provider is v1alpha3, all the provider in the same management group should be v1alpha3 as well. + // The this is required to ensure all the providers in a management cluster are consistent with the contract supported by the core provider. + // e.g if the core provider is v1alpha3, all the provider should be v1alpha3 as well. // The target contract is derived from the current version of the core provider, or, if the core provider is included in the upgrade list, // from its target version. - targetCoreProviderVersion := managementGroup.CoreProvider.Version + providerList, err := u.providerInventory.List() + if err != nil { + return nil, err + } + coreProviders := providerList.FilterCore() + if len(coreProviders) != 1 { + return nil, errors.Errorf("invalid management cluster: there should a core provider, found %d", len(coreProviders)) + } + coreProvider := coreProviders[0] + + targetCoreProviderVersion := coreProvider.Version for _, providerToUpgrade := range upgradeItems { - if providerToUpgrade.InstanceName() == managementGroup.CoreProvider.InstanceName() { + if providerToUpgrade.InstanceName() == coreProvider.InstanceName() { targetCoreProviderVersion = providerToUpgrade.NextVersion break } } - targetContract, err := u.getProviderContractByVersion(managementGroup.CoreProvider, targetCoreProviderVersion) + targetContract, err := u.getProviderContractByVersion(coreProvider, targetCoreProviderVersion) if err != nil { return nil, err } @@ -261,15 +243,20 @@ func (u *providerUpgrader) createCustomPlan(coreProvider clusterctlv1.Provider, // Builds the custom upgrade plan, by adding all the upgrade items after checking consistency with the targetContract. upgradeInstanceNames := sets.NewString() upgradePlan := &UpgradePlan{ - CoreProvider: managementGroup.CoreProvider, - Contract: targetContract, + Contract: targetContract, } for _, upgradeItem := range upgradeItems { - // Match the upgrade item with the corresponding provider in the management group - provider := managementGroup.GetProviderByInstanceName(upgradeItem.InstanceName()) + // Match the upgrade item with the corresponding provider in the management cluster + var provider *clusterctlv1.Provider + for i := range providerList.Items { + if providerList.Items[i].InstanceName() == upgradeItem.InstanceName() { + provider = &providerList.Items[i] + break + } + } if provider == nil { - return nil, errors.Errorf("unable to complete that upgrade: the provider %s in not part of the %s management group", upgradeItem.InstanceName(), coreProvider.InstanceName()) + return nil, errors.Errorf("unable to complete that upgrade: the provider %s in not part of the management cluster", upgradeItem.InstanceName()) } // Retrieves the contract that is supported by the target version of the provider. @@ -279,7 +266,7 @@ func (u *providerUpgrader) createCustomPlan(coreProvider clusterctlv1.Provider, } if contract != targetContract { - return nil, errors.Errorf("unable to complete that upgrade: the target version for the provider %s supports the %s API Version of Cluster API (contract), while the management group is using %s", upgradeItem.InstanceName(), contract, targetContract) + return nil, errors.Errorf("unable to complete that upgrade: the target version for the provider %s supports the %s API Version of Cluster API (contract), while the management cluster is using %s", upgradeItem.InstanceName(), contract, targetContract) } // Migrate the additional provider attributes to the upgrade item @@ -290,8 +277,8 @@ func (u *providerUpgrader) createCustomPlan(coreProvider clusterctlv1.Provider, upgradeInstanceNames.Insert(upgradeItem.InstanceName()) } - // Before doing upgrades, checks if other providers in the management group are lagging behind the target contract. - for _, provider := range managementGroup.Providers { + // Before doing upgrades, checks if other providers in the management cluster are lagging behind the target contract. + for _, provider := range providerList.Items { // skip providers already included in the upgrade plan if upgradeInstanceNames.Has(provider.InstanceName()) { continue @@ -304,7 +291,7 @@ func (u *providerUpgrader) createCustomPlan(coreProvider clusterctlv1.Provider, } if contract != targetContract { - return nil, errors.Errorf("unable to complete that upgrade: the provider %s supports the %s API Version of Cluster API (contract), while the management group is being updated to %s. Please include the %[1]s provider in the upgrade", provider.InstanceName(), contract, targetContract) + return nil, errors.Errorf("unable to complete that upgrade: the provider %s supports the %s API Version of Cluster API (contract), while the management cluster is being updated to %s. Please include the %[1]s provider in the upgrade", provider.InstanceName(), contract, targetContract) } } return upgradePlan, nil diff --git a/cmd/clusterctl/client/cluster/upgrader_info_test.go b/cmd/clusterctl/client/cluster/upgrader_info_test.go index eba9a007be64..dfc977a11193 100644 --- a/cmd/clusterctl/client/cluster/upgrader_info_test.go +++ b/cmd/clusterctl/client/cluster/upgrader_info_test.go @@ -22,6 +22,7 @@ import ( . "github.com/onsi/gomega" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/util/version" + clusterv1 "sigs.k8s.io/cluster-api/api/v1alpha4" clusterctlv1 "sigs.k8s.io/cluster-api/cmd/clusterctl/api/v1alpha3" "sigs.k8s.io/cluster-api/cmd/clusterctl/client/config" "sigs.k8s.io/cluster-api/cmd/clusterctl/client/repository" @@ -432,3 +433,26 @@ func toSemanticVersions(versions []string) []version.Version { } return semanticVersions } + +func fakeProvider(name string, providerType clusterctlv1.ProviderType, version, targetNamespace, watchingNamespace string) clusterctlv1.Provider { + return clusterctlv1.Provider{ + TypeMeta: metav1.TypeMeta{ + APIVersion: clusterctlv1.GroupVersion.String(), + Kind: "Provider", + }, + ObjectMeta: metav1.ObjectMeta{ + ResourceVersion: "1", + Namespace: targetNamespace, + Name: clusterctlv1.ManifestLabel(name, providerType), + Labels: map[string]string{ + clusterctlv1.ClusterctlLabelName: "", + clusterv1.ProviderLabelName: clusterctlv1.ManifestLabel(name, providerType), + clusterctlv1.ClusterctlCoreLabelName: "inventory", + }, + }, + ProviderName: name, + Type: string(providerType), + Version: version, + WatchedNamespace: watchingNamespace, + } +} diff --git a/cmd/clusterctl/client/cluster/upgrader_test.go b/cmd/clusterctl/client/cluster/upgrader_test.go index cf3014744709..b2750d08ac94 100644 --- a/cmd/clusterctl/client/cluster/upgrader_test.go +++ b/cmd/clusterctl/client/cluster/upgrader_test.go @@ -40,7 +40,7 @@ func Test_providerUpgrader_Plan(t *testing.T) { wantErr bool }{ { - name: "Single Management group, no multi-tenancy, upgrade within the current contract", + name: "Upgrade within the current contract", fields: fields{ // config for two providers reader: test.NewFakeReader(). @@ -69,8 +69,7 @@ func Test_providerUpgrader_Plan(t *testing.T) { }, want: []UpgradePlan{ { // one upgrade plan with the latest releases the current contract - Contract: test.CurrentCAPIContract, - CoreProvider: fakeProvider("cluster-api", clusterctlv1.CoreProviderType, "v1.0.0", "cluster-api-system", ""), + Contract: test.CurrentCAPIContract, Providers: []UpgradeItem{ { Provider: fakeProvider("cluster-api", clusterctlv1.CoreProviderType, "v1.0.0", "cluster-api-system", ""), @@ -121,8 +120,7 @@ func Test_providerUpgrader_Plan(t *testing.T) { }, want: []UpgradePlan{ { // one upgrade plan with the latest releases the current contract - Contract: test.CurrentCAPIContract, - CoreProvider: fakeProvider("cluster-api", clusterctlv1.CoreProviderType, "v1.0.0", "cluster-api-system", ""), + Contract: test.CurrentCAPIContract, Providers: []UpgradeItem{ { Provider: fakeProvider("cluster-api", clusterctlv1.CoreProviderType, "v1.0.0", "cluster-api-system", ""), @@ -138,7 +136,7 @@ func Test_providerUpgrader_Plan(t *testing.T) { wantErr: false, }, { - name: "Single Management group, no multi-tenancy, upgrade for previous contract (not supported), current contract", // upgrade plan should report unsupported options + name: "Upgrade for previous contract (not supported), current contract", // upgrade plan should report unsupported options fields: fields{ // config for two providers reader: test.NewFakeReader(). @@ -169,8 +167,7 @@ func Test_providerUpgrader_Plan(t *testing.T) { }, want: []UpgradePlan{ { // one upgrade plan with the latest releases in the previous contract (not supported, but upgrade plan should report these options) - Contract: test.PreviousCAPIContractNotSupported, - CoreProvider: fakeProvider("cluster-api", clusterctlv1.CoreProviderType, "v1.0.0", "cluster-api-system", ""), + Contract: test.PreviousCAPIContractNotSupported, Providers: []UpgradeItem{ { Provider: fakeProvider("cluster-api", clusterctlv1.CoreProviderType, "v1.0.0", "cluster-api-system", ""), @@ -183,8 +180,7 @@ func Test_providerUpgrader_Plan(t *testing.T) { }, }, { // one upgrade plan with the latest releases in the current contract - Contract: test.CurrentCAPIContract, - CoreProvider: fakeProvider("cluster-api", clusterctlv1.CoreProviderType, "v1.0.0", "cluster-api-system", ""), + Contract: test.CurrentCAPIContract, Providers: []UpgradeItem{ { Provider: fakeProvider("cluster-api", clusterctlv1.CoreProviderType, "v1.0.0", "cluster-api-system", ""), @@ -200,7 +196,7 @@ func Test_providerUpgrader_Plan(t *testing.T) { wantErr: false, }, { - name: "Single Management group, no multi-tenancy, upgrade for two current contract, next contract (not supported)", // upgrade plan should report unsupported options + name: "Upgrade for both current contract and next contract (not supported)", // upgrade plan should report unsupported options fields: fields{ // config for two providers reader: test.NewFakeReader(). @@ -231,8 +227,7 @@ func Test_providerUpgrader_Plan(t *testing.T) { }, want: []UpgradePlan{ { // one upgrade plan with the latest releases in the current - Contract: test.CurrentCAPIContract, - CoreProvider: fakeProvider("cluster-api", clusterctlv1.CoreProviderType, "v1.0.0", "cluster-api-system", ""), + Contract: test.CurrentCAPIContract, Providers: []UpgradeItem{ { Provider: fakeProvider("cluster-api", clusterctlv1.CoreProviderType, "v1.0.0", "cluster-api-system", ""), @@ -245,8 +240,7 @@ func Test_providerUpgrader_Plan(t *testing.T) { }, }, { // one upgrade plan with the latest releases in the next contract (not supported, but upgrade plan should report these options) - Contract: test.NextCAPIContractNotSupported, - CoreProvider: fakeProvider("cluster-api", clusterctlv1.CoreProviderType, "v1.0.0", "cluster-api-system", ""), + Contract: test.NextCAPIContractNotSupported, Providers: []UpgradeItem{ { Provider: fakeProvider("cluster-api", clusterctlv1.CoreProviderType, "v1.0.0", "cluster-api-system", ""), @@ -262,446 +256,7 @@ func Test_providerUpgrader_Plan(t *testing.T) { wantErr: false, }, { - name: "Single Management group, n-Infra multi-tenancy, upgrade within the same current contract", - fields: fields{ - // config for two providers - reader: test.NewFakeReader(). - WithProvider("cluster-api", clusterctlv1.CoreProviderType, "https://somewhere.com"). - WithProvider("infra", clusterctlv1.InfrastructureProviderType, "https://somewhere.com"), - repository: map[string]repository.Repository{ - "cluster-api": test.NewFakeRepository(). - WithVersions("v1.0.0", "v1.0.1"). - WithMetadata("v1.0.1", &clusterctlv1.Metadata{ - ReleaseSeries: []clusterctlv1.ReleaseSeries{ - {Major: 1, Minor: 0, Contract: test.CurrentCAPIContract}, - }, - }), - "infrastructure-infra": test.NewFakeRepository(). - WithVersions("v2.0.0", "v2.0.1"). - WithMetadata("v2.0.1", &clusterctlv1.Metadata{ - ReleaseSeries: []clusterctlv1.ReleaseSeries{ - {Major: 2, Minor: 0, Contract: test.CurrentCAPIContract}, - }, - }), - }, - // one core and two infra providers existing in the cluster - proxy: test.NewFakeProxy(). - WithProviderInventory("cluster-api", clusterctlv1.CoreProviderType, "v1.0.0", "cluster-api-system", ""). - WithProviderInventory("infra", clusterctlv1.InfrastructureProviderType, "v2.0.0", "infra-system1", "ns1"). - WithProviderInventory("infra", clusterctlv1.InfrastructureProviderType, "v2.0.0", "infra-system2", "ns2"), - }, - want: []UpgradePlan{ - { // one upgrade plan with the latest releases in the current contract - Contract: test.CurrentCAPIContract, - CoreProvider: fakeProvider("cluster-api", clusterctlv1.CoreProviderType, "v1.0.0", "cluster-api-system", ""), - Providers: []UpgradeItem{ - { - Provider: fakeProvider("cluster-api", clusterctlv1.CoreProviderType, "v1.0.0", "cluster-api-system", ""), - NextVersion: "v1.0.1", - }, - { - Provider: fakeProvider("infra", clusterctlv1.InfrastructureProviderType, "v2.0.0", "infra-system1", "ns1"), - NextVersion: "v2.0.1", - }, - { - Provider: fakeProvider("infra", clusterctlv1.InfrastructureProviderType, "v2.0.0", "infra-system2", "ns2"), - NextVersion: "v2.0.1", - }, - }, - }, - }, - wantErr: false, - }, - { - name: "Single Management group, n-Infra multi-tenancy, upgrade for previous contract (not supported), current contract", // upgrade plan should report unsupported options - fields: fields{ - // config for two providers - reader: test.NewFakeReader(). - WithProvider("cluster-api", clusterctlv1.CoreProviderType, "https://somewhere.com"). - WithProvider("infra", clusterctlv1.InfrastructureProviderType, "https://somewhere.com"), - repository: map[string]repository.Repository{ - "cluster-api": test.NewFakeRepository(). - WithVersions("v1.0.0", "v1.0.1", "v2.0.0"). - WithMetadata("v2.0.0", &clusterctlv1.Metadata{ - ReleaseSeries: []clusterctlv1.ReleaseSeries{ - {Major: 1, Minor: 0, Contract: test.PreviousCAPIContractNotSupported}, - {Major: 2, Minor: 0, Contract: test.CurrentCAPIContract}, - }, - }), - "infrastructure-infra": test.NewFakeRepository(). - WithVersions("v2.0.0", "v2.0.1", "v3.0.0"). - WithMetadata("v3.0.0", &clusterctlv1.Metadata{ - ReleaseSeries: []clusterctlv1.ReleaseSeries{ - {Major: 2, Minor: 0, Contract: test.PreviousCAPIContractNotSupported}, - {Major: 3, Minor: 0, Contract: test.CurrentCAPIContract}, - }, - }), - }, - // one core and two infra providers existing in the cluster - proxy: test.NewFakeProxy(). - WithProviderInventory("cluster-api", clusterctlv1.CoreProviderType, "v1.0.0", "cluster-api-system", ""). - WithProviderInventory("infra", clusterctlv1.InfrastructureProviderType, "v2.0.0", "infra-system1", "ns1"). - WithProviderInventory("infra", clusterctlv1.InfrastructureProviderType, "v2.0.0", "infra-system2", "ns2"), - }, - want: []UpgradePlan{ - { // one upgrade plan with the latest releases in the previous contract (not supported, but upgrade plan should report these options) - Contract: test.PreviousCAPIContractNotSupported, - CoreProvider: fakeProvider("cluster-api", clusterctlv1.CoreProviderType, "v1.0.0", "cluster-api-system", ""), - Providers: []UpgradeItem{ - { - Provider: fakeProvider("cluster-api", clusterctlv1.CoreProviderType, "v1.0.0", "cluster-api-system", ""), - NextVersion: "v1.0.1", - }, - { - Provider: fakeProvider("infra", clusterctlv1.InfrastructureProviderType, "v2.0.0", "infra-system1", "ns1"), - NextVersion: "v2.0.1", - }, - { - Provider: fakeProvider("infra", clusterctlv1.InfrastructureProviderType, "v2.0.0", "infra-system2", "ns2"), - NextVersion: "v2.0.1", - }, - }, - }, - { // one upgrade plan with the latest releases in the current contract - Contract: test.CurrentCAPIContract, - CoreProvider: fakeProvider("cluster-api", clusterctlv1.CoreProviderType, "v1.0.0", "cluster-api-system", ""), - Providers: []UpgradeItem{ - { - Provider: fakeProvider("cluster-api", clusterctlv1.CoreProviderType, "v1.0.0", "cluster-api-system", ""), - NextVersion: "v2.0.0", - }, - { - Provider: fakeProvider("infra", clusterctlv1.InfrastructureProviderType, "v2.0.0", "infra-system1", "ns1"), - NextVersion: "v3.0.0", - }, - { - Provider: fakeProvider("infra", clusterctlv1.InfrastructureProviderType, "v2.0.0", "infra-system2", "ns2"), - NextVersion: "v3.0.0", - }, - }, - }, - }, - wantErr: false, - }, - { - name: "Single Management group, n-Infra multi-tenancy, upgrade for current contract, next contract (not supported)", // upgrade plan should report unsupported options - fields: fields{ - // config for two providers - reader: test.NewFakeReader(). - WithProvider("cluster-api", clusterctlv1.CoreProviderType, "https://somewhere.com"). - WithProvider("infra", clusterctlv1.InfrastructureProviderType, "https://somewhere.com"), - repository: map[string]repository.Repository{ - "cluster-api": test.NewFakeRepository(). - WithVersions("v1.0.0", "v1.0.1", "v2.0.0"). - WithMetadata("v2.0.0", &clusterctlv1.Metadata{ - ReleaseSeries: []clusterctlv1.ReleaseSeries{ - {Major: 1, Minor: 0, Contract: test.CurrentCAPIContract}, - {Major: 2, Minor: 0, Contract: test.NextCAPIContractNotSupported}, - }, - }), - "infrastructure-infra": test.NewFakeRepository(). - WithVersions("v2.0.0", "v2.0.1", "v3.0.0"). - WithMetadata("v3.0.0", &clusterctlv1.Metadata{ - ReleaseSeries: []clusterctlv1.ReleaseSeries{ - {Major: 2, Minor: 0, Contract: test.CurrentCAPIContract}, - {Major: 3, Minor: 0, Contract: test.NextCAPIContractNotSupported}, - }, - }), - }, - // one core and two infra providers existing in the cluster - proxy: test.NewFakeProxy(). - WithProviderInventory("cluster-api", clusterctlv1.CoreProviderType, "v1.0.0", "cluster-api-system", ""). - WithProviderInventory("infra", clusterctlv1.InfrastructureProviderType, "v2.0.0", "infra-system1", "ns1"). - WithProviderInventory("infra", clusterctlv1.InfrastructureProviderType, "v2.0.0", "infra-system2", "ns2"), - }, - want: []UpgradePlan{ - { // one upgrade plan with the latest releases in the current contract - Contract: test.CurrentCAPIContract, - CoreProvider: fakeProvider("cluster-api", clusterctlv1.CoreProviderType, "v1.0.0", "cluster-api-system", ""), - Providers: []UpgradeItem{ - { - Provider: fakeProvider("cluster-api", clusterctlv1.CoreProviderType, "v1.0.0", "cluster-api-system", ""), - NextVersion: "v1.0.1", - }, - { - Provider: fakeProvider("infra", clusterctlv1.InfrastructureProviderType, "v2.0.0", "infra-system1", "ns1"), - NextVersion: "v2.0.1", - }, - { - Provider: fakeProvider("infra", clusterctlv1.InfrastructureProviderType, "v2.0.0", "infra-system2", "ns2"), - NextVersion: "v2.0.1", - }, - }, - }, - { // one upgrade plan with the latest releases in the next contract (not supported, but upgrade plan should report these options) - Contract: test.NextCAPIContractNotSupported, - CoreProvider: fakeProvider("cluster-api", clusterctlv1.CoreProviderType, "v1.0.0", "cluster-api-system", ""), - Providers: []UpgradeItem{ - { - Provider: fakeProvider("cluster-api", clusterctlv1.CoreProviderType, "v1.0.0", "cluster-api-system", ""), - NextVersion: "v2.0.0", - }, - { - Provider: fakeProvider("infra", clusterctlv1.InfrastructureProviderType, "v2.0.0", "infra-system1", "ns1"), - NextVersion: "v3.0.0", - }, - { - Provider: fakeProvider("infra", clusterctlv1.InfrastructureProviderType, "v2.0.0", "infra-system2", "ns2"), - NextVersion: "v3.0.0", - }, - }, - }, - }, - wantErr: false, - }, - { - name: "Single Management group, n-Core multi-tenancy, upgrade within the current contract", - fields: fields{ - // config for two providers - reader: test.NewFakeReader(). - WithProvider("cluster-api", clusterctlv1.CoreProviderType, "https://somewhere.com"). - WithProvider("infra", clusterctlv1.InfrastructureProviderType, "https://somewhere.com"), - repository: map[string]repository.Repository{ - "cluster-api": test.NewFakeRepository(). - WithVersions("v1.0.0", "v1.0.1"). - WithMetadata("v1.0.1", &clusterctlv1.Metadata{ - ReleaseSeries: []clusterctlv1.ReleaseSeries{ - {Major: 1, Minor: 0, Contract: test.CurrentCAPIContract}, - }, - }), - "infrastructure-infra": test.NewFakeRepository(). - WithVersions("v2.0.0", "v2.0.1"). - WithMetadata("v2.0.1", &clusterctlv1.Metadata{ - ReleaseSeries: []clusterctlv1.ReleaseSeries{ - {Major: 2, Minor: 0, Contract: test.CurrentCAPIContract}, - }, - }), - }, - // two management groups existing in the cluster - proxy: test.NewFakeProxy(). - WithProviderInventory("cluster-api", clusterctlv1.CoreProviderType, "v1.0.0", "cluster-api-system1", "ns1"). - WithProviderInventory("infra", clusterctlv1.InfrastructureProviderType, "v2.0.0", "infra-system1", "ns1"). - WithProviderInventory("cluster-api", clusterctlv1.CoreProviderType, "v1.0.0", "cluster-api-system2", "ns2"). - WithProviderInventory("infra", clusterctlv1.InfrastructureProviderType, "v2.0.0", "infra-system2", "ns2"), - }, - want: []UpgradePlan{ - { // one upgrade plan with the latest releases in the current contract for the first management group - Contract: test.CurrentCAPIContract, - CoreProvider: fakeProvider("cluster-api", clusterctlv1.CoreProviderType, "v1.0.0", "cluster-api-system1", "ns1"), - Providers: []UpgradeItem{ - { - Provider: fakeProvider("cluster-api", clusterctlv1.CoreProviderType, "v1.0.0", "cluster-api-system1", "ns1"), - NextVersion: "v1.0.1", - }, - { - Provider: fakeProvider("infra", clusterctlv1.InfrastructureProviderType, "v2.0.0", "infra-system1", "ns1"), - NextVersion: "v2.0.1", - }, - }, - }, - { // one upgrade plan with the latest releases in the current contract for the second management group - Contract: test.CurrentCAPIContract, - CoreProvider: fakeProvider("cluster-api", clusterctlv1.CoreProviderType, "v1.0.0", "cluster-api-system2", "ns2"), - Providers: []UpgradeItem{ - { - Provider: fakeProvider("cluster-api", clusterctlv1.CoreProviderType, "v1.0.0", "cluster-api-system2", "ns2"), - NextVersion: "v1.0.1", - }, - { - Provider: fakeProvider("infra", clusterctlv1.InfrastructureProviderType, "v2.0.0", "infra-system2", "ns2"), - NextVersion: "v2.0.1", - }, - }, - }, - }, - wantErr: false, - }, - { - name: "Single Management group, n-Core multi-tenancy, upgrade for previous contract (not supported), current contract", // upgrade plan should report unsupported options - fields: fields{ - // config for two providers - reader: test.NewFakeReader(). - WithProvider("cluster-api", clusterctlv1.CoreProviderType, "https://somewhere.com"). - WithProvider("infra", clusterctlv1.InfrastructureProviderType, "https://somewhere.com"), - repository: map[string]repository.Repository{ - "cluster-api": test.NewFakeRepository(). - WithVersions("v1.0.0", "v1.0.1", "v2.0.0"). - WithMetadata("v2.0.0", &clusterctlv1.Metadata{ - ReleaseSeries: []clusterctlv1.ReleaseSeries{ - {Major: 1, Minor: 0, Contract: test.PreviousCAPIContractNotSupported}, - {Major: 2, Minor: 0, Contract: test.CurrentCAPIContract}, - }, - }), - "infrastructure-infra": test.NewFakeRepository(). - WithVersions("v2.0.0", "v2.0.1", "v3.0.0"). - WithMetadata("v3.0.0", &clusterctlv1.Metadata{ - ReleaseSeries: []clusterctlv1.ReleaseSeries{ - {Major: 2, Minor: 0, Contract: test.PreviousCAPIContractNotSupported}, - {Major: 3, Minor: 0, Contract: test.CurrentCAPIContract}, - }, - }), - }, - // two management groups existing in the cluster - proxy: test.NewFakeProxy(). - WithProviderInventory("cluster-api", clusterctlv1.CoreProviderType, "v1.0.0", "cluster-api-system1", "ns1"). - WithProviderInventory("infra", clusterctlv1.InfrastructureProviderType, "v2.0.0", "infra-system1", "ns1"). - WithProviderInventory("cluster-api", clusterctlv1.CoreProviderType, "v1.0.0", "cluster-api-system2", "ns2"). - WithProviderInventory("infra", clusterctlv1.InfrastructureProviderType, "v2.0.0", "infra-system2", "ns2"), - }, - want: []UpgradePlan{ - { // one upgrade plan with the latest releases in the previous contract for the first management group (not supported, but upgrade plan should report these options) - Contract: test.PreviousCAPIContractNotSupported, - CoreProvider: fakeProvider("cluster-api", clusterctlv1.CoreProviderType, "v1.0.0", "cluster-api-system1", "ns1"), - Providers: []UpgradeItem{ - { - Provider: fakeProvider("cluster-api", clusterctlv1.CoreProviderType, "v1.0.0", "cluster-api-system1", "ns1"), - NextVersion: "v1.0.1", - }, - { - Provider: fakeProvider("infra", clusterctlv1.InfrastructureProviderType, "v2.0.0", "infra-system1", "ns1"), - NextVersion: "v2.0.1", - }, - }, - }, - { // one upgrade plan with the latest releases in the current contract for the first management group - Contract: test.CurrentCAPIContract, - CoreProvider: fakeProvider("cluster-api", clusterctlv1.CoreProviderType, "v1.0.0", "cluster-api-system1", "ns1"), - Providers: []UpgradeItem{ - { - Provider: fakeProvider("cluster-api", clusterctlv1.CoreProviderType, "v1.0.0", "cluster-api-system1", "ns1"), - NextVersion: "v2.0.0", - }, - { - Provider: fakeProvider("infra", clusterctlv1.InfrastructureProviderType, "v2.0.0", "infra-system1", "ns1"), - NextVersion: "v3.0.0", - }, - }, - }, - { // one upgrade plan with the latest releases in the previous contract for the second management group (not supported, but upgrade plan should report these options) - Contract: test.PreviousCAPIContractNotSupported, - CoreProvider: fakeProvider("cluster-api", clusterctlv1.CoreProviderType, "v1.0.0", "cluster-api-system2", "ns2"), - Providers: []UpgradeItem{ - { - Provider: fakeProvider("cluster-api", clusterctlv1.CoreProviderType, "v1.0.0", "cluster-api-system2", "ns2"), - NextVersion: "v1.0.1", - }, - { - Provider: fakeProvider("infra", clusterctlv1.InfrastructureProviderType, "v2.0.0", "infra-system2", "ns2"), - NextVersion: "v2.0.1", - }, - }, - }, - { // one upgrade plan with the latest releases in the current contract for the second management group - Contract: test.CurrentCAPIContract, - CoreProvider: fakeProvider("cluster-api", clusterctlv1.CoreProviderType, "v1.0.0", "cluster-api-system2", "ns2"), - Providers: []UpgradeItem{ - { - Provider: fakeProvider("cluster-api", clusterctlv1.CoreProviderType, "v1.0.0", "cluster-api-system2", "ns2"), - NextVersion: "v2.0.0", - }, - { - Provider: fakeProvider("infra", clusterctlv1.InfrastructureProviderType, "v2.0.0", "infra-system2", "ns2"), - NextVersion: "v3.0.0", - }, - }, - }, - }, - wantErr: false, - }, - { - name: "Single Management group, n-Core multi-tenancy, upgrade for current contract, next contract (not supported)", // upgrade plan should report unsupported options - fields: fields{ - // config for two providers - reader: test.NewFakeReader(). - WithProvider("cluster-api", clusterctlv1.CoreProviderType, "https://somewhere.com"). - WithProvider("infra", clusterctlv1.InfrastructureProviderType, "https://somewhere.com"), - repository: map[string]repository.Repository{ - "cluster-api": test.NewFakeRepository(). - WithVersions("v1.0.0", "v1.0.1", "v2.0.0"). - WithMetadata("v2.0.0", &clusterctlv1.Metadata{ - ReleaseSeries: []clusterctlv1.ReleaseSeries{ - {Major: 1, Minor: 0, Contract: test.CurrentCAPIContract}, - {Major: 2, Minor: 0, Contract: test.NextCAPIContractNotSupported}, - }, - }), - "infrastructure-infra": test.NewFakeRepository(). - WithVersions("v2.0.0", "v2.0.1", "v3.0.0"). - WithMetadata("v3.0.0", &clusterctlv1.Metadata{ - ReleaseSeries: []clusterctlv1.ReleaseSeries{ - {Major: 2, Minor: 0, Contract: test.CurrentCAPIContract}, - {Major: 3, Minor: 0, Contract: test.NextCAPIContractNotSupported}, - }, - }), - }, - // two management groups existing in the cluster - proxy: test.NewFakeProxy(). - WithProviderInventory("cluster-api", clusterctlv1.CoreProviderType, "v1.0.0", "cluster-api-system1", "ns1"). - WithProviderInventory("infra", clusterctlv1.InfrastructureProviderType, "v2.0.0", "infra-system1", "ns1"). - WithProviderInventory("cluster-api", clusterctlv1.CoreProviderType, "v1.0.0", "cluster-api-system2", "ns2"). - WithProviderInventory("infra", clusterctlv1.InfrastructureProviderType, "v2.0.0", "infra-system2", "ns2"), - }, - want: []UpgradePlan{ - { // one upgrade plan with the latest releases in the current contract for the first management group - Contract: test.CurrentCAPIContract, - CoreProvider: fakeProvider("cluster-api", clusterctlv1.CoreProviderType, "v1.0.0", "cluster-api-system1", "ns1"), - Providers: []UpgradeItem{ - { - Provider: fakeProvider("cluster-api", clusterctlv1.CoreProviderType, "v1.0.0", "cluster-api-system1", "ns1"), - NextVersion: "v1.0.1", - }, - { - Provider: fakeProvider("infra", clusterctlv1.InfrastructureProviderType, "v2.0.0", "infra-system1", "ns1"), - NextVersion: "v2.0.1", - }, - }, - }, - { // one upgrade plan with the latest releases in the next contract for the first management group (not supported, but upgrade plan should report these options) - Contract: test.NextCAPIContractNotSupported, - CoreProvider: fakeProvider("cluster-api", clusterctlv1.CoreProviderType, "v1.0.0", "cluster-api-system1", "ns1"), - Providers: []UpgradeItem{ - { - Provider: fakeProvider("cluster-api", clusterctlv1.CoreProviderType, "v1.0.0", "cluster-api-system1", "ns1"), - NextVersion: "v2.0.0", - }, - { - Provider: fakeProvider("infra", clusterctlv1.InfrastructureProviderType, "v2.0.0", "infra-system1", "ns1"), - NextVersion: "v3.0.0", - }, - }, - }, - { // one upgrade plan with the latest releases in the current contract for the second management group - Contract: test.CurrentCAPIContract, - CoreProvider: fakeProvider("cluster-api", clusterctlv1.CoreProviderType, "v1.0.0", "cluster-api-system2", "ns2"), - Providers: []UpgradeItem{ - { - Provider: fakeProvider("cluster-api", clusterctlv1.CoreProviderType, "v1.0.0", "cluster-api-system2", "ns2"), - NextVersion: "v1.0.1", - }, - { - Provider: fakeProvider("infra", clusterctlv1.InfrastructureProviderType, "v2.0.0", "infra-system2", "ns2"), - NextVersion: "v2.0.1", - }, - }, - }, - { // one upgrade plan with the latest releases in the next contract for the second management group (not supported, but upgrade plan should report these options) - Contract: test.NextCAPIContractNotSupported, - CoreProvider: fakeProvider("cluster-api", clusterctlv1.CoreProviderType, "v1.0.0", "cluster-api-system2", "ns2"), - Providers: []UpgradeItem{ - { - Provider: fakeProvider("cluster-api", clusterctlv1.CoreProviderType, "v1.0.0", "cluster-api-system2", "ns2"), - NextVersion: "v2.0.0", - }, - { - Provider: fakeProvider("infra", clusterctlv1.InfrastructureProviderType, "v2.0.0", "infra-system2", "ns2"), - NextVersion: "v3.0.0", - }, - }, - }, - }, - wantErr: false, - }, - { - name: "Single Management group, no multi-tenancy, partial upgrades for next contract", // upgrade plan should report unsupported options + name: "Partial upgrades for next contract", // upgrade plan should report unsupported options fields: fields{ // config for two providers reader: test.NewFakeReader(). @@ -731,8 +286,7 @@ func Test_providerUpgrader_Plan(t *testing.T) { }, want: []UpgradePlan{ { // one upgrade plan with the latest releases in the current contract - Contract: test.CurrentCAPIContract, - CoreProvider: fakeProvider("cluster-api", clusterctlv1.CoreProviderType, "v1.0.0", "cluster-api-system", ""), + Contract: test.CurrentCAPIContract, Providers: []UpgradeItem{ { Provider: fakeProvider("cluster-api", clusterctlv1.CoreProviderType, "v1.0.0", "cluster-api-system", ""), @@ -829,8 +383,7 @@ func Test_providerUpgrader_createCustomPlan(t *testing.T) { }, }, want: &UpgradePlan{ - Contract: test.CurrentCAPIContract, - CoreProvider: fakeProvider("cluster-api", clusterctlv1.CoreProviderType, "v1.0.0", "cluster-api-system", ""), + Contract: test.CurrentCAPIContract, Providers: []UpgradeItem{ { Provider: fakeProvider("infra", clusterctlv1.InfrastructureProviderType, "v2.0.0", "infra-system", ""), @@ -878,8 +431,7 @@ func Test_providerUpgrader_createCustomPlan(t *testing.T) { }, }, want: &UpgradePlan{ - Contract: test.CurrentCAPIContract, - CoreProvider: fakeProvider("cluster-api", clusterctlv1.CoreProviderType, "v1.0.0", "cluster-api-system", ""), + Contract: test.CurrentCAPIContract, Providers: []UpgradeItem{ { Provider: fakeProvider("cluster-api", clusterctlv1.CoreProviderType, "v1.0.0", "cluster-api-system", ""), @@ -933,8 +485,7 @@ func Test_providerUpgrader_createCustomPlan(t *testing.T) { }, }, want: &UpgradePlan{ - Contract: test.CurrentCAPIContract, - CoreProvider: fakeProvider("cluster-api", clusterctlv1.CoreProviderType, "v1.0.0", "cluster-api-system", ""), + Contract: test.CurrentCAPIContract, Providers: []UpgradeItem{ { Provider: fakeProvider("cluster-api", clusterctlv1.CoreProviderType, "v1.0.0", "cluster-api-system", ""), @@ -1206,8 +757,7 @@ func Test_providerUpgrader_createCustomPlan(t *testing.T) { }, }, want: &UpgradePlan{ - Contract: test.CurrentCAPIContract, - CoreProvider: fakeProvider("cluster-api", clusterctlv1.CoreProviderType, "v1.0.0", "cluster-api-system", ""), + Contract: test.CurrentCAPIContract, Providers: []UpgradeItem{ { Provider: fakeProvider("cluster-api", clusterctlv1.CoreProviderType, "v1.0.0", "cluster-api-system", ""), @@ -1235,7 +785,7 @@ func Test_providerUpgrader_createCustomPlan(t *testing.T) { }, providerInventory: newInventoryClient(tt.fields.proxy, nil), } - got, err := u.createCustomPlan(tt.args.coreProvider, tt.args.providersToUpgrade) + got, err := u.createCustomPlan(tt.args.providersToUpgrade) if tt.wantErr { g.Expect(err).To(HaveOccurred()) return @@ -1256,15 +806,14 @@ func Test_providerUpgrader_ApplyPlan(t *testing.T) { } tests := []struct { - name string - fields fields - coreProvider clusterctlv1.Provider - contract string - wantErr bool - errorMsg string + name string + fields fields + contract string + wantErr bool + errorMsg string }{ { - name: "fails to upgrade to v1alpha4 when there are multiple instances of the same provider", + name: "fails to upgrade to v1alpha4 when there are multiple instances of the core provider", fields: fields{ // config for two providers reader: test.NewFakeReader(). @@ -1276,16 +825,16 @@ func Test_providerUpgrader_ApplyPlan(t *testing.T) { WithVersions("v1.0.0", "v1.0.1", "v2.0.0"). WithMetadata("v2.0.0", &clusterctlv1.Metadata{ ReleaseSeries: []clusterctlv1.ReleaseSeries{ - {Major: 1, Minor: 0, Contract: "v1alpha3"}, - {Major: 2, Minor: 0, Contract: "v1alpha4"}, + {Major: 1, Minor: 0, Contract: test.PreviousCAPIContractNotSupported}, + {Major: 2, Minor: 0, Contract: test.CurrentCAPIContract}, }, }), "infrastructure-infra": test.NewFakeRepository(). WithVersions("v2.0.0", "v2.0.1", "v3.0.0"). WithMetadata("v3.0.0", &clusterctlv1.Metadata{ ReleaseSeries: []clusterctlv1.ReleaseSeries{ - {Major: 2, Minor: 0, Contract: "v1alpha3"}, - {Major: 3, Minor: 0, Contract: "v1alpha4"}, + {Major: 2, Minor: 0, Contract: test.PreviousCAPIContractNotSupported}, + {Major: 3, Minor: 0, Contract: test.CurrentCAPIContract}, }, }), }, @@ -1293,13 +842,47 @@ func Test_providerUpgrader_ApplyPlan(t *testing.T) { proxy: test.NewFakeProxy(). WithProviderInventory("cluster-api", clusterctlv1.CoreProviderType, "v1.0.0", "cluster-api-system", "default"). WithProviderInventory("cluster-api", clusterctlv1.CoreProviderType, "v1.0.0", "cluster-api-system-1", "default-1"). + WithProviderInventory("infra", clusterctlv1.InfrastructureProviderType, "v2.0.0", "infra-system", "default"), + }, + contract: test.CurrentCAPIContract, + wantErr: true, + errorMsg: "detected multiple instances of the same provider", + }, + { + name: "fails to upgrade to v1alpha4 when there are multiple instances of the infra provider", + fields: fields{ + // config for two providers + reader: test.NewFakeReader(). + WithProvider("cluster-api", clusterctlv1.CoreProviderType, "https://somewhere.com"). + WithProvider("infra", clusterctlv1.InfrastructureProviderType, "https://somewhere.com"), + // two provider repositories, with current v1alpha3 contract and new versions for v1alpha4 contract + repository: map[string]repository.Repository{ + "cluster-api": test.NewFakeRepository(). + WithVersions("v1.0.0", "v1.0.1", "v2.0.0"). + WithMetadata("v2.0.0", &clusterctlv1.Metadata{ + ReleaseSeries: []clusterctlv1.ReleaseSeries{ + {Major: 1, Minor: 0, Contract: test.PreviousCAPIContractNotSupported}, + {Major: 2, Minor: 0, Contract: test.CurrentCAPIContract}, + }, + }), + "infrastructure-infra": test.NewFakeRepository(). + WithVersions("v2.0.0", "v2.0.1", "v3.0.0"). + WithMetadata("v3.0.0", &clusterctlv1.Metadata{ + ReleaseSeries: []clusterctlv1.ReleaseSeries{ + {Major: 2, Minor: 0, Contract: test.PreviousCAPIContractNotSupported}, + {Major: 3, Minor: 0, Contract: test.CurrentCAPIContract}, + }, + }), + }, + // two providers with multiple instances existing in the cluster + proxy: test.NewFakeProxy(). + WithProviderInventory("cluster-api", clusterctlv1.CoreProviderType, "v1.0.0", "cluster-api-system", "default"). WithProviderInventory("infra", clusterctlv1.InfrastructureProviderType, "v2.0.0", "infra-system", "default"). WithProviderInventory("infra", clusterctlv1.InfrastructureProviderType, "v2.0.0", "infra-system-1", "default-1"), }, - coreProvider: fakeProvider("cluster-api", clusterctlv1.CoreProviderType, "v1.0.0", "cluster-api-system", ""), - contract: "v1alpha4", - wantErr: true, - errorMsg: "detected multiple instances of the same provider", + contract: test.CurrentCAPIContract, + wantErr: true, + errorMsg: "detected multiple instances of the same provider", }, } @@ -1316,7 +899,7 @@ func Test_providerUpgrader_ApplyPlan(t *testing.T) { }, providerInventory: newInventoryClient(tt.fields.proxy, nil), } - err := u.ApplyPlan(tt.coreProvider, tt.contract) + err := u.ApplyPlan(tt.contract) if tt.wantErr { g.Expect(err).To(HaveOccurred()) g.Expect(err.Error()).Should(ContainSubstring(tt.errorMsg)) @@ -1339,13 +922,12 @@ func Test_providerUpgrader_ApplyCustomPlan(t *testing.T) { tests := []struct { name string fields fields - coreProvider clusterctlv1.Provider providersToUpgrade []UpgradeItem wantErr bool errorMsg string }{ { - name: "fails to upgrade to v1alpha4 when there are multiple instances of the same provider", + name: "fails to upgrade to v1alpha4 when there are multiple instances of the core provider", fields: fields{ // config for two providers reader: test.NewFakeReader(). @@ -1358,15 +940,15 @@ func Test_providerUpgrader_ApplyCustomPlan(t *testing.T) { WithMetadata("v2.0.0", &clusterctlv1.Metadata{ ReleaseSeries: []clusterctlv1.ReleaseSeries{ {Major: 1, Minor: 0, Contract: "v1alpha3"}, - {Major: 2, Minor: 0, Contract: "v1alpha4"}, + {Major: 2, Minor: 0, Contract: test.CurrentCAPIContract}, }, }), "infrastructure-infra": test.NewFakeRepository(). WithVersions("v2.0.0", "v2.0.1", "v3.0.0"). WithMetadata("v3.0.0", &clusterctlv1.Metadata{ ReleaseSeries: []clusterctlv1.ReleaseSeries{ - {Major: 2, Minor: 0, Contract: "v1alpha3"}, - {Major: 3, Minor: 0, Contract: "v1alpha4"}, + {Major: 2, Minor: 0, Contract: test.PreviousCAPIContractNotSupported}, + {Major: 3, Minor: 0, Contract: test.CurrentCAPIContract}, }, }), }, @@ -1374,10 +956,53 @@ func Test_providerUpgrader_ApplyCustomPlan(t *testing.T) { proxy: test.NewFakeProxy(). WithProviderInventory("cluster-api", clusterctlv1.CoreProviderType, "v1.0.0", "cluster-api-system", "default"). WithProviderInventory("cluster-api", clusterctlv1.CoreProviderType, "v1.0.0", "cluster-api-system-1", "default-1"). + WithProviderInventory("infra", clusterctlv1.InfrastructureProviderType, "v2.0.0", "infra-system", "default"), + }, + providersToUpgrade: []UpgradeItem{ + { + Provider: fakeProvider("cluster-api", clusterctlv1.CoreProviderType, "v1.0.0", "cluster-api-system", ""), + NextVersion: "v2.0.0", + }, + { + Provider: fakeProvider("infra", clusterctlv1.InfrastructureProviderType, "v2.0.0", "infra-system", ""), + NextVersion: "v3.0.0", + }, + }, + wantErr: true, + errorMsg: "invalid management cluster: there should a core provider, found 2", + }, + { + name: "fails to upgrade to v1alpha4 when there are multiple instances of the infra provider", + fields: fields{ + // config for two providers + reader: test.NewFakeReader(). + WithProvider("cluster-api", clusterctlv1.CoreProviderType, "https://somewhere.com"). + WithProvider("infra", clusterctlv1.InfrastructureProviderType, "https://somewhere.com"), + // two provider repositories, with current v1alpha3 contract and new versions for v1alpha4 contract + repository: map[string]repository.Repository{ + "cluster-api": test.NewFakeRepository(). + WithVersions("v1.0.0", "v1.0.1", "v2.0.0"). + WithMetadata("v2.0.0", &clusterctlv1.Metadata{ + ReleaseSeries: []clusterctlv1.ReleaseSeries{ + {Major: 1, Minor: 0, Contract: test.PreviousCAPIContractNotSupported}, + {Major: 2, Minor: 0, Contract: test.CurrentCAPIContract}, + }, + }), + "infrastructure-infra": test.NewFakeRepository(). + WithVersions("v2.0.0", "v2.0.1", "v3.0.0"). + WithMetadata("v3.0.0", &clusterctlv1.Metadata{ + ReleaseSeries: []clusterctlv1.ReleaseSeries{ + {Major: 2, Minor: 0, Contract: test.PreviousCAPIContractNotSupported}, + {Major: 3, Minor: 0, Contract: test.CurrentCAPIContract}, + }, + }), + }, + // two providers with multiple instances existing in the cluster + proxy: test.NewFakeProxy(). + WithProviderInventory("cluster-api", clusterctlv1.CoreProviderType, "v1.0.0", "cluster-api-system", "default"). WithProviderInventory("infra", clusterctlv1.InfrastructureProviderType, "v2.0.0", "infra-system", "default"). WithProviderInventory("infra", clusterctlv1.InfrastructureProviderType, "v2.0.0", "infra-system-1", "default-1"), }, - coreProvider: fakeProvider("cluster-api", clusterctlv1.CoreProviderType, "v1.0.0", "cluster-api-system", ""), providersToUpgrade: []UpgradeItem{ { Provider: fakeProvider("cluster-api", clusterctlv1.CoreProviderType, "v1.0.0", "cluster-api-system", ""), @@ -1387,6 +1012,10 @@ func Test_providerUpgrader_ApplyCustomPlan(t *testing.T) { Provider: fakeProvider("infra", clusterctlv1.InfrastructureProviderType, "v2.0.0", "infra-system", ""), NextVersion: "v3.0.0", }, + { + Provider: fakeProvider("infra", clusterctlv1.InfrastructureProviderType, "v2.0.0", "infra-system-1", ""), + NextVersion: "v3.0.0", + }, }, wantErr: true, errorMsg: "detected multiple instances of the same provider", @@ -1406,7 +1035,7 @@ func Test_providerUpgrader_ApplyCustomPlan(t *testing.T) { }, providerInventory: newInventoryClient(tt.fields.proxy, nil), } - err := u.ApplyCustomPlan(tt.coreProvider, tt.providersToUpgrade...) + err := u.ApplyCustomPlan(tt.providersToUpgrade...) if tt.wantErr { g.Expect(err).To(HaveOccurred()) g.Expect(err.Error()).Should(ContainSubstring(tt.errorMsg)) diff --git a/cmd/clusterctl/client/init.go b/cmd/clusterctl/client/init.go index 515d3c00cc4a..e7d8618400f7 100644 --- a/cmd/clusterctl/client/init.go +++ b/cmd/clusterctl/client/init.go @@ -97,11 +97,8 @@ func (c *clusterctlClient) Init(options InitOptions) ([]Components, error) { } // Before installing the providers, validates the management cluster resulting by the planned installation. The following checks are performed: - // - There should be only one instance of the same provider per namespace. - // - Instances of the same provider should not be fighting for objects (no watching overlap). - // - Providers combines in valid management groups - // - All the providers should belong to one/only one management groups - // - All the providers in a management group must support the same API Version of Cluster API (contract) + // - There should be only one instance of the same provider. + // - All the providers must support the same API Version of Cluster API (contract) if err := installer.Validate(); err != nil { return nil, err } diff --git a/cmd/clusterctl/client/upgrade.go b/cmd/clusterctl/client/upgrade.go index e380d6669eac..82c432c885d8 100644 --- a/cmd/clusterctl/client/upgrade.go +++ b/cmd/clusterctl/client/upgrade.go @@ -74,9 +74,8 @@ func (c *clusterctlClient) PlanUpgrade(options PlanUpgradeOptions) ([]UpgradePla aliasUpgradePlan := make([]UpgradePlan, len(upgradePlans)) for i, plan := range upgradePlans { aliasUpgradePlan[i] = UpgradePlan{ - Contract: plan.Contract, - CoreProvider: plan.CoreProvider, - Providers: plan.Providers, + Contract: plan.Contract, + Providers: plan.Providers, } } @@ -88,10 +87,7 @@ type ApplyUpgradeOptions struct { // Kubeconfig to use for accessing the management cluster. If empty, default discovery rules apply. Kubeconfig Kubeconfig - // ManagementGroup that should be upgraded (e.g. capi-system/cluster-api). - ManagementGroup string - - // Contract defines the API Version of Cluster API (contract e.g. v1alpha4) the management group should upgrade to. + // Contract defines the API Version of Cluster API (contract e.g. v1alpha4) the management cluster should upgrade to. // When upgrading by contract, the latest versions available will be used for all the providers; if you want // a more granular control on upgrade, use CoreProvider, BootstrapProviders, ControlPlaneProviders, InfrastructureProviders. Contract string @@ -130,14 +126,6 @@ func (c *clusterctlClient) ApplyUpgrade(options ApplyUpgradeOptions) error { return err } - // The management group name is derived from the core provider name, so now - // convert the reference back into a coreProvider. - coreUpgradeItem, err := parseUpgradeItem(options.ManagementGroup, clusterctlv1.CoreProviderType) - if err != nil { - return err - } - coreProvider := coreUpgradeItem.Provider - // Ensures the latest version of cert-manager. // NOTE: it is safe to upgrade to latest version of cert-manager given that it provides // conversion web-hooks around Issuer/Certificate kinds, so installing an older versions of providers @@ -182,15 +170,15 @@ func (c *clusterctlClient) ApplyUpgrade(options ApplyUpgradeOptions) error { } // Execute the upgrade using the custom upgrade items - if err := clusterClient.ProviderUpgrader().ApplyCustomPlan(coreProvider, upgradeItems...); err != nil { + if err := clusterClient.ProviderUpgrader().ApplyCustomPlan(upgradeItems...); err != nil { return err } return nil } - // Otherwise we are upgrading a whole management group according to a clusterctl generated upgrade plan. - if err := clusterClient.ProviderUpgrader().ApplyPlan(coreProvider, options.Contract); err != nil { + // Otherwise we are upgrading a whole management cluster according to a clusterctl generated upgrade plan. + if err := clusterClient.ProviderUpgrader().ApplyPlan(options.Contract); err != nil { return err } diff --git a/cmd/clusterctl/client/upgrade_test.go b/cmd/clusterctl/client/upgrade_test.go index ac1c67ccb869..f9b33c3fdc40 100644 --- a/cmd/clusterctl/client/upgrade_test.go +++ b/cmd/clusterctl/client/upgrade_test.go @@ -165,7 +165,6 @@ func Test_clusterctlClient_ApplyUpgrade(t *testing.T) { args: args{ options: ApplyUpgradeOptions{ Kubeconfig: Kubeconfig{Path: "kubeconfig", Context: "mgmt-context"}, - ManagementGroup: "cluster-api-system/cluster-api", Contract: test.CurrentCAPIContract, CoreProvider: "", BootstrapProviders: nil, @@ -194,7 +193,6 @@ func Test_clusterctlClient_ApplyUpgrade(t *testing.T) { args: args{ options: ApplyUpgradeOptions{ Kubeconfig: Kubeconfig{Path: "kubeconfig", Context: "mgmt-context"}, - ManagementGroup: "cluster-api-system/cluster-api", Contract: "", CoreProvider: "cluster-api-system/cluster-api:v1.0.1", BootstrapProviders: nil, @@ -223,7 +221,6 @@ func Test_clusterctlClient_ApplyUpgrade(t *testing.T) { args: args{ options: ApplyUpgradeOptions{ Kubeconfig: Kubeconfig{Path: "kubeconfig", Context: "mgmt-context"}, - ManagementGroup: "cluster-api-system/cluster-api", Contract: "", CoreProvider: "", BootstrapProviders: nil, @@ -252,7 +249,6 @@ func Test_clusterctlClient_ApplyUpgrade(t *testing.T) { args: args{ options: ApplyUpgradeOptions{ Kubeconfig: Kubeconfig{Path: "kubeconfig", Context: "mgmt-context"}, - ManagementGroup: "cluster-api-system/cluster-api", Contract: "", CoreProvider: "cluster-api-system/cluster-api:v1.0.1", BootstrapProviders: nil, diff --git a/cmd/clusterctl/cmd/upgrade.go b/cmd/clusterctl/cmd/upgrade.go index 7ac2901580cb..3f07279b8307 100644 --- a/cmd/clusterctl/cmd/upgrade.go +++ b/cmd/clusterctl/cmd/upgrade.go @@ -48,8 +48,7 @@ func sortUpgradeItems(plan client.UpgradePlan) { func sortUpgradePlans(upgradePlans []client.UpgradePlan) { sort.Slice(upgradePlans, func(i, j int) bool { - return upgradePlans[i].CoreProvider.Namespace < upgradePlans[j].CoreProvider.Namespace || - (upgradePlans[i].CoreProvider.Namespace == upgradePlans[j].CoreProvider.Namespace && upgradePlans[i].Contract < upgradePlans[j].Contract) + return upgradePlans[i].Contract < upgradePlans[j].Contract }) } diff --git a/cmd/clusterctl/cmd/upgrade_apply.go b/cmd/clusterctl/cmd/upgrade_apply.go index d285f4c583ed..849071a53e32 100644 --- a/cmd/clusterctl/cmd/upgrade_apply.go +++ b/cmd/clusterctl/cmd/upgrade_apply.go @@ -26,7 +26,6 @@ import ( type upgradeApplyOptions struct { kubeconfig string kubeconfigContext string - managementGroup string contract string coreProvider string bootstrapProviders []string @@ -42,16 +41,16 @@ var upgradeApplyCmd = &cobra.Command{ Long: LongDesc(` The upgrade apply command applies new versions of Cluster API providers as defined by clusterctl upgrade plan. - New version should be applied for each management groups, ensuring all the providers on the same cluster API version + New version should be applied ensuring all the providers uses the same cluster API version in order to guarantee the proper functioning of the management cluster.`), Example: Examples(` - # Upgrades all the providers in the capi-system/cluster-api management group to the latest version available which is compliant + # Upgrades all the providers in the management cluster to the latest version available which is compliant # to the v1alpha4 API Version of Cluster API (contract). - clusterctl upgrade apply --management-group capi-system/cluster-api --contract v1alpha4 + clusterctl upgrade apply --contract v1alpha4 - # Upgrades only the capa-system/aws provider instance in the capi-system/cluster-api management group to the v0.5.0 version. - clusterctl upgrade apply --management-group capi-system/cluster-api --infrastructure capa-system/aws:v0.5.0`), + # Upgrades only the capa-system/aws provider to the v0.5.0 version. + clusterctl upgrade apply --infrastructure capa-system/aws:v0.5.0`), Args: cobra.NoArgs, RunE: func(cmd *cobra.Command, args []string) error { return runUpgradeApply() @@ -63,10 +62,8 @@ func init() { "Path to the kubeconfig file to use for accessing the management cluster. If unspecified, default discovery rules apply.") upgradeApplyCmd.Flags().StringVar(&ua.kubeconfigContext, "kubeconfig-context", "", "Context to be used within the kubeconfig file. If empty, current context will be used.") - upgradeApplyCmd.Flags().StringVar(&ua.managementGroup, "management-group", "", - "The management group that should be upgraded (e.g. capi-system/cluster-api)") upgradeApplyCmd.Flags().StringVar(&ua.contract, "contract", "", - "The API Version of Cluster API (contract, e.g. v1alpha4) the management group should upgrade to") + "The API Version of Cluster API (contract, e.g. v1alpha4) the management cluster should upgrade to") upgradeApplyCmd.Flags().StringVar(&ua.coreProvider, "core", "", "Core provider instance version (e.g. capi-system/cluster-api:v0.3.0) to upgrade to. This flag can be used as alternative to --contract.") @@ -95,7 +92,6 @@ func runUpgradeApply() error { if err := c.ApplyUpgrade(client.ApplyUpgradeOptions{ Kubeconfig: client.Kubeconfig{Path: ua.kubeconfig, Context: ua.kubeconfigContext}, - ManagementGroup: ua.managementGroup, Contract: ua.contract, CoreProvider: ua.coreProvider, BootstrapProviders: ua.bootstrapProviders, diff --git a/cmd/clusterctl/cmd/upgrade_plan.go b/cmd/clusterctl/cmd/upgrade_plan.go index f03f4cbd247a..c231b8a99ad3 100644 --- a/cmd/clusterctl/cmd/upgrade_plan.go +++ b/cmd/clusterctl/cmd/upgrade_plan.go @@ -37,12 +37,13 @@ var upgradePlanCmd = &cobra.Command{ Use: "plan", Short: "Provide a list of recommended target versions for upgrading Cluster API providers in a management cluster", Long: LongDesc(` - The upgrade plan command provides a list of recommended target versions for upgrading Cluster API providers in a management cluster. + The upgrade plan command provides a list of recommended target versions for upgrading the + Cluster API providers in a management cluster. - The providers are grouped into management groups, each one defining a set of providers that should be supporting - the same API Version of Cluster API (contract) in order to guarantee the proper functioning of the management cluster. + All the providers should be supporting the same API Version of Cluster API (contract) in order + to guarantee the proper functioning of the management cluster. - Then, for each provider in a management group, the following upgrade options are provided: + Then, for each provider, the following upgrade options are provided: - The latest patch release for the current API Version of Cluster API (contract). - The latest patch release for the next API Version of Cluster API (contract), if available.`), @@ -89,7 +90,7 @@ func runUpgradePlan() error { } if len(upgradePlans) == 0 { - fmt.Println("There are no management groups in the cluster. Please use clusterctl init to initialize a Cluster API management cluster.") + fmt.Println("There are no providers in the cluster. Please use clusterctl init to initialize a Cluster API management cluster.") return nil } @@ -103,7 +104,7 @@ func runUpgradePlan() error { upgradeAvailable := false fmt.Println("") - fmt.Printf("Management group: %s, latest release available for the %s API Version of Cluster API (contract):\n", plan.CoreProvider.InstanceName(), plan.Contract) + fmt.Printf("Latest release available for the %s API Version of Cluster API (contract):\n", plan.Contract) fmt.Println("") w := tabwriter.NewWriter(os.Stdout, 10, 4, 3, ' ', 0) fmt.Fprintln(w, "NAME\tNAMESPACE\tTYPE\tCURRENT VERSION\tNEXT VERSION") @@ -120,7 +121,7 @@ func runUpgradePlan() error { if plan.Contract == clusterv1.GroupVersion.Version { fmt.Println("You can now apply the upgrade by executing the following command:") fmt.Println("") - fmt.Printf("clusterctl upgrade apply --management-group %s --contract %s\n", plan.CoreProvider.InstanceName(), plan.Contract) + fmt.Printf("clusterctl upgrade apply --contract %s\n", plan.Contract) } else { fmt.Printf("The current version of clusterctl could not upgrade to %s contract (only %s supported).\n", plan.Contract, clusterv1.GroupVersion.Version) } diff --git a/docs/book/src/clusterctl/commands/upgrade.md b/docs/book/src/clusterctl/commands/upgrade.md index 8bf08847a3f3..be4f2a0c1863 100644 --- a/docs/book/src/clusterctl/commands/upgrade.md +++ b/docs/book/src/clusterctl/commands/upgrade.md @@ -17,7 +17,7 @@ Produces an output similar to this: ```shell Checking new release availability... -Management group: capi-system/cluster-api, latest release available for the v1alpha3 API Version of Cluster API (contract): +Latest release available for the v1alpha3 API Version of Cluster API (contract): NAME NAMESPACE TYPE CURRENT VERSION TARGET VERSION cluster-api capi-system CoreProvider v0.3.0 v0.3.1 @@ -28,10 +28,10 @@ docker capd-system InfrastructureProvider You can now apply the upgrade by executing the following command: - clusterctl upgrade apply --management-group capi-system/cluster-api --contract v1alpha3 + clusterctl upgrade apply --contract v1alpha3 ``` -The output contains the latest release available for each management group in the cluster/for each API Version of Cluster API (contract) +The output contains the latest release available for each API Version of Cluster API (contract) available at the moment.