Skip to content

Commit c976d8e

Browse files
authored
Merge pull request #2277 from fabriziopandini/clusterctl-cleanup-inventory
🏃clusterctl: cleanup inventory
2 parents a552b9d + 8aa5b6a commit c976d8e

19 files changed

+283
-254
lines changed

cmd/clusterctl/api/v1alpha3/metadata_type.go

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -32,29 +32,29 @@ type Metadata struct {
3232
ReleaseSeries []ReleaseSeries `json:"releaseSeries"`
3333
}
3434

35-
// ReleaseSeries maps a provider release series (major/minor) with a ClusterAPIVersion
35+
// ReleaseSeries maps a provider release series (major/minor) with a API Version of Cluster API (contract).
3636
type ReleaseSeries struct {
3737
// Major version of the release series
3838
Major uint `json:"major,omitempty"`
3939

4040
// Minor version of the release series
4141
Minor uint `json:"minor,omitempty"`
4242

43-
// ClusterAPIVersion indicates the cluster API supported version.
44-
ClusterAPIVersion string `json:"clusterAPIVersion,omitempty"`
43+
// Contract defines the API Version of Cluster API (contract) supported by the ReleaseSeries.
44+
Contract string `json:"contract,omitempty"`
4545
}
4646

4747
func init() {
4848
SchemeBuilder.Register(&Metadata{})
4949
}
5050

51-
// HasReleaseSeriesForVersion return true if the given version is in one of the ReleaseSeries.
52-
func (m *Metadata) HasReleaseSeriesForVersion(version *version.Version) bool {
51+
// GetReleaseSeriesForVersion return the release series for a given version.
52+
func (m *Metadata) GetReleaseSeriesForVersion(version *version.Version) *ReleaseSeries {
5353
for _, releaseSeries := range m.ReleaseSeries {
5454
if version.Major() == releaseSeries.Major && version.Minor() == releaseSeries.Minor {
55-
return true
55+
return &releaseSeries
5656
}
5757
}
5858

59-
return false
59+
return nil
6060
}

cmd/clusterctl/api/v1alpha3/provider_type.go

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ package v1alpha3
1818

1919
import (
2020
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
21+
"k8s.io/apimachinery/pkg/types"
2122
)
2223

2324
// +kubebuilder:resource:path=providers,scope=Namespaced,categories=cluster-api
@@ -47,19 +48,6 @@ type Provider struct {
4748
WatchedNamespace string `json:"watchedNamespace,omitempty"`
4849
}
4950

50-
// +kubebuilder:object:root=true
51-
52-
// ProviderList contains a list of Provider
53-
type ProviderList struct {
54-
metav1.TypeMeta `json:",inline"`
55-
metav1.ListMeta `json:"metadata,omitempty"`
56-
Items []Provider `json:"items"`
57-
}
58-
59-
func init() {
60-
SchemeBuilder.Register(&Provider{}, &ProviderList{})
61-
}
62-
6351
// ProviderType is a string representation of a TaskGroup create policy.
6452
type ProviderType string
6553

@@ -95,11 +83,19 @@ func (p *Provider) GetProviderType() ProviderType {
9583
}
9684
}
9785

86+
// InstanceName return the instance name for the provider, that is composed by the provider name and the namespace
87+
// where the provider is installed (nb. clusterctl does not support multiple instances of the same provider to be
88+
// installed in the same namespace)
89+
func (p *Provider) InstanceName() string {
90+
return types.NamespacedName{Namespace: p.Namespace, Name: p.Name}.String()
91+
}
92+
9893
// HasWatchingOverlapWith returns true if the provider has an overlapping watching namespace with another provider.
9994
func (p *Provider) HasWatchingOverlapWith(other Provider) bool {
10095
return p.WatchedNamespace == "" || p.WatchedNamespace == other.WatchedNamespace || other.WatchedNamespace == ""
10196
}
10297

98+
// Equals returns true if two providers are exactly the same.
10399
func (p *Provider) Equals(other Provider) bool {
104100
return p.Name == other.Name &&
105101
p.Namespace == other.Namespace &&
@@ -108,6 +104,15 @@ func (p *Provider) Equals(other Provider) bool {
108104
p.Version == other.Version
109105
}
110106

107+
// +kubebuilder:object:root=true
108+
109+
// ProviderList contains a list of Provider
110+
type ProviderList struct {
111+
metav1.TypeMeta `json:",inline"`
112+
metav1.ListMeta `json:"metadata,omitempty"`
113+
Items []Provider `json:"items"`
114+
}
115+
111116
func (l *ProviderList) FilterByName(name string) []Provider {
112117
return l.filterBy(func(p Provider) bool {
113118
return p.Name == name
@@ -147,3 +152,7 @@ func (l *ProviderList) filterBy(predicate func(p Provider) bool) []Provider {
147152
}
148153
return ret
149154
}
155+
156+
func init() {
157+
SchemeBuilder.Register(&Provider{}, &ProviderList{})
158+
}

cmd/clusterctl/cmd/upgrade.go

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -46,12 +46,12 @@ var upgradePlanCmd = &cobra.Command{
4646
Long: LongDesc(`
4747
The upgrade plan command provides a list of recommended target versions for upgrading Cluster API providers in a management cluster.
4848
49-
The providers are grouped into management groups, each one defining a set of providers that should be supporting the same cluster API version
50-
in order to guarantee the proper functioning of the management cluster.
49+
The providers are grouped into management groups, each one defining a set of providers that should be supporting
50+
the same API Version of Cluster API (contract) in order to guarantee the proper functioning of the management cluster.
5151
5252
Then, for each provider in a management group, the following upgrade options are provided:
53-
- The latest patch release for the current Cluster API version.
54-
- The latest patch release for the next Cluster API version, if available.`),
53+
- The latest patch release for the current API Version of Cluster API (contract).
54+
- The latest patch release for the next API Version of Cluster API (contract), if available.`),
5555

5656
Example: Examples(`
5757
# Gets the recommended target versions for upgrading Cluster API providers.
@@ -83,7 +83,7 @@ func runUpgradePlan() error {
8383
return err
8484
}
8585

86-
// ensure upgrade plans are sorted consistently (by CoreProvider.Namespace, ClusterAPIVersion).
86+
// ensure upgrade plans are sorted consistently (by CoreProvider.Namespace, Contract).
8787
sortUpgradePlans(upgradePlans)
8888

8989
if len(upgradePlans) == 0 {
@@ -98,7 +98,7 @@ func runUpgradePlan() error {
9898
upgradeAvailable := false
9999

100100
fmt.Println("")
101-
fmt.Printf("Management group: %s/%s, latest release available for the %s Cluster API version:\n", plan.CoreProvider.Namespace, plan.CoreProvider.Name, plan.ClusterAPIVersion)
101+
fmt.Printf("Management group: %s, latest release available for the %s API Version of Cluster API (contract):\n", plan.CoreProvider.InstanceName(), plan.Contract)
102102
fmt.Println("")
103103
w := tabwriter.NewWriter(os.Stdout, 10, 4, 3, ' ', 0)
104104
fmt.Fprintln(w, "NAME\tNAMESPACE\tTYPE\tCURRENT VERSION\tNEXT VERSION")
@@ -114,7 +114,7 @@ func runUpgradePlan() error {
114114
if upgradeAvailable {
115115
fmt.Println("You can now apply the upgrade by executing the following command:")
116116
fmt.Println("")
117-
fmt.Println(fmt.Sprintf(" upgrade apply --management-group %s/%s --cluster-api-version %s", plan.CoreProvider.Namespace, plan.CoreProvider.Name, plan.ClusterAPIVersion))
117+
fmt.Println(fmt.Sprintf(" upgrade apply --management-group %s --cluster-api-version %s", plan.CoreProvider.InstanceName(), plan.Contract))
118118
} else {
119119
fmt.Println("You are already up to date!")
120120
}
@@ -136,7 +136,7 @@ func sortUpgradeItems(plan client.UpgradePlan) {
136136
func sortUpgradePlans(upgradePlans []client.UpgradePlan) {
137137
sort.Slice(upgradePlans, func(i, j int) bool {
138138
return upgradePlans[i].CoreProvider.Namespace < upgradePlans[j].CoreProvider.Namespace ||
139-
(upgradePlans[i].CoreProvider.Namespace == upgradePlans[j].CoreProvider.Namespace && upgradePlans[i].ClusterAPIVersion < upgradePlans[j].ClusterAPIVersion)
139+
(upgradePlans[i].CoreProvider.Namespace == upgradePlans[j].CoreProvider.Namespace && upgradePlans[i].Contract < upgradePlans[j].Contract)
140140
})
141141
}
142142

cmd/clusterctl/config/crd/bases/clusterctl.cluster.x-k8s.io_metadata.yaml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,11 +35,11 @@ spec:
3535
releaseSeries:
3636
items:
3737
description: ReleaseSeries maps a provider release series (major/minor)
38-
with a ClusterAPIVersion
38+
with a API Version of Cluster API (contract).
3939
properties:
40-
clusterAPIVersion:
41-
description: ClusterAPIVersion indicates the cluster API supported
42-
version.
40+
contract:
41+
description: Contract defines the API Version of Cluster API (contract)
42+
supported by the ReleaseSeries.
4343
type: string
4444
major:
4545
description: Major version of the release series

cmd/clusterctl/pkg/client/client.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@ type Client interface {
148148

149149
// PlanUpgrade returns a set of suggested Upgrade plans for the cluster, and more specifically:
150150
// - Each management group gets separated upgrade plans.
151-
// - For each management group, an upgrade plan is generated for each ClusterAPIVersion available, e.g.
151+
// - For each management group, an upgrade plan is generated for each API Version of Cluster API (contract) available, e.g.
152152
// - Upgrade to the latest version in the the v1alpha2 series: ....
153153
// - Upgrade to the latest version in the the v1alpha3 series: ....
154154
PlanUpgrade(options PlanUpgradeOptions) ([]UpgradePlan, error)

cmd/clusterctl/pkg/client/cluster/inventory.go

Lines changed: 7 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ type InventoryClient interface {
5353
Create(clusterctlv1.Provider) error
5454

5555
// List returns the inventory items for all the provider instances installed in the cluster.
56-
List() ([]clusterctlv1.Provider, error)
56+
List() (*clusterctlv1.ProviderList, error)
5757

5858
// GetDefaultProviderName returns the default provider for a given ProviderType.
5959
// In case there is only a single provider for a given type, e.g. only the AWS infrastructure Provider, it returns
@@ -71,15 +71,7 @@ type InventoryClient interface {
7171
GetDefaultProviderNamespace(provider string) (string, error)
7272

7373
// GetManagementGroups returns the list of management groups defined in the management cluster.
74-
GetManagementGroups() ([]ManagementGroup, error)
75-
}
76-
77-
// ManagementGroup is a group of providers composed by a CoreProvider and a set of Bootstrap/ControlPlane/Infrastructure providers
78-
// watching objects in the same namespace. For example, a management group can be used for upgrades, in order to ensure all the providers
79-
// in a management group support the same ClusterAPI version.
80-
type ManagementGroup struct {
81-
CoreProvider clusterctlv1.Provider
82-
Providers []clusterctlv1.Provider
74+
GetManagementGroups() (ManagementGroupList, error)
8375
}
8476

8577
// inventoryClient implements InventoryClient.
@@ -178,7 +170,7 @@ func (p *inventoryClient) EnsureCustomResourceDefinitions() error {
178170
}
179171

180172
func (p *inventoryClient) Validate(m clusterctlv1.Provider) error {
181-
providerList, err := p.list()
173+
providerList, err := p.List()
182174
if err != nil {
183175
return err
184176
}
@@ -242,15 +234,7 @@ func (p *inventoryClient) Create(m clusterctlv1.Provider) error {
242234
return nil
243235
}
244236

245-
func (p *inventoryClient) List() ([]clusterctlv1.Provider, error) {
246-
providerList, err := p.list()
247-
if err != nil {
248-
return nil, err
249-
}
250-
return providerList.Items, nil
251-
}
252-
253-
func (p *inventoryClient) list() (*clusterctlv1.ProviderList, error) {
237+
func (p *inventoryClient) List() (*clusterctlv1.ProviderList, error) {
254238
cl, err := p.proxy.NewClient()
255239
if err != nil {
256240
return nil, err
@@ -264,7 +248,7 @@ func (p *inventoryClient) list() (*clusterctlv1.ProviderList, error) {
264248
}
265249

266250
func (p *inventoryClient) GetDefaultProviderName(providerType clusterctlv1.ProviderType) (string, error) {
267-
providerList, err := p.list()
251+
providerList, err := p.List()
268252
if err != nil {
269253
return "", err
270254
}
@@ -285,7 +269,7 @@ func (p *inventoryClient) GetDefaultProviderName(providerType clusterctlv1.Provi
285269
}
286270

287271
func (p *inventoryClient) GetDefaultProviderVersion(provider string) (string, error) {
288-
providerList, err := p.list()
272+
providerList, err := p.List()
289273
if err != nil {
290274
return "", err
291275
}
@@ -305,7 +289,7 @@ func (p *inventoryClient) GetDefaultProviderVersion(provider string) (string, er
305289
}
306290

307291
func (p *inventoryClient) GetDefaultProviderNamespace(provider string) (string, error) {
308-
providerList, err := p.list()
292+
providerList, err := p.List()
309293
if err != nil {
310294
return "", err
311295
}

cmd/clusterctl/pkg/client/cluster/inventory_managementgroup.go

Lines changed: 54 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -17,19 +17,50 @@ limitations under the License.
1717
package cluster
1818

1919
import (
20-
"fmt"
2120
"strings"
2221

2322
"github.com/pkg/errors"
2423
clusterctlv1 "sigs.k8s.io/cluster-api/cmd/clusterctl/api/v1alpha3"
2524
)
2625

27-
func (p *inventoryClient) GetManagementGroups() ([]ManagementGroup, error) {
28-
providerList, err := p.list()
29-
if err != nil {
30-
return nil, err
26+
// ManagementGroup is a group of providers composed by a CoreProvider and a set of Bootstrap/ControlPlane/Infrastructure providers
27+
// watching objects in the same namespace. For example, a management group can be used for upgrades, in order to ensure all the providers
28+
// in a management group support the same API Version of Cluster API (contract).
29+
type ManagementGroup struct {
30+
CoreProvider clusterctlv1.Provider
31+
Providers []clusterctlv1.Provider
32+
}
33+
34+
// Equals return true if two management groups have the same core provider.
35+
func (mg *ManagementGroup) Equals(other *ManagementGroup) bool {
36+
return mg.CoreProvider.Equals(other.CoreProvider)
37+
}
38+
39+
// GetProviderByInstanceName returns a specific provider instance.
40+
func (mg *ManagementGroup) GetProviderByInstanceName(instanceName string) *clusterctlv1.Provider {
41+
for _, provider := range mg.Providers {
42+
if provider.InstanceName() == instanceName {
43+
return &provider
44+
}
3145
}
46+
return nil
47+
}
3248

49+
// ManagementGroupList defines a list of management groups
50+
type ManagementGroupList []ManagementGroup
51+
52+
// FindManagementGroupByProviderInstanceName return the management group that hosts a given provider.
53+
func (ml *ManagementGroupList) FindManagementGroupByProviderInstanceName(instanceName string) *ManagementGroup {
54+
for _, managementGroup := range *ml {
55+
if p := managementGroup.GetProviderByInstanceName(instanceName); p != nil {
56+
return &managementGroup
57+
}
58+
}
59+
return nil
60+
}
61+
62+
// deriveManagementGroups derives the management groups from a list of providers.
63+
func deriveManagementGroups(providerList *clusterctlv1.ProviderList) (ManagementGroupList, error) {
3364
// If any of the core providers watch the same namespace, we cannot define the management group.
3465
if err := checkOverlappingCoreProviders(providerList); err != nil {
3566
return nil, err
@@ -43,7 +74,7 @@ func (p *inventoryClient) GetManagementGroups() ([]ManagementGroup, error) {
4374
}
4475

4576
// Composes the management group
46-
managementGroups := []ManagementGroup{}
77+
managementGroups := ManagementGroupList{}
4778
for _, coreProvider := range providerList.FilterCore() {
4879
group := ManagementGroup{CoreProvider: coreProvider}
4980
for _, provider := range providerList.Items {
@@ -70,9 +101,9 @@ func checkOverlappingCoreProviders(providerList *clusterctlv1.ProviderList) erro
70101

71102
// check for overlapping namespaces
72103
if provider.HasWatchingOverlapWith(other) {
73-
return errors.Errorf("Unable to identify management groups: core providers %s/%s and %s/%s have overlapping watching namespaces",
74-
provider.Namespace, provider.Name,
75-
other.Namespace, other.Name,
104+
return errors.Errorf("Unable to identify management groups: core providers %s and %s have overlapping watching namespaces",
105+
provider.InstanceName(),
106+
other.InstanceName(),
76107
)
77108
}
78109
}
@@ -91,24 +122,33 @@ func checkOverlappingProviders(providerList *clusterctlv1.ProviderList) error {
91122
var overlappingCoreProviders []string
92123
for _, coreProvider := range providerList.FilterCore() {
93124
if provider.HasWatchingOverlapWith(coreProvider) {
94-
overlappingCoreProviders = append(overlappingCoreProviders, fmt.Sprintf("%s/%s", coreProvider.Namespace, coreProvider.Name))
125+
overlappingCoreProviders = append(overlappingCoreProviders, coreProvider.InstanceName())
95126
}
96127
}
97128

98129
// if the provider does not overlap with any core provider, return error (it will not be part of any management group)
99130
if len(overlappingCoreProviders) == 0 {
100-
return errors.Errorf("Unable to identify management groups: provider %s/%s can't be combined with any core provider",
101-
provider.Namespace, provider.Name,
131+
return errors.Errorf("Unable to identify management groups: provider %s can't be combined with any core provider",
132+
provider.InstanceName(),
102133
)
103134
}
104135

105136
// 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)
106137
if len(overlappingCoreProviders) > 1 {
107-
return errors.Errorf("Unable to identify management groupss: provider %s/%s is watching for objects in namespaces controlled by more than one core provider (%s)",
108-
provider.Namespace, provider.Name,
138+
return errors.Errorf("Unable to identify management groupss: provider %s is watching for objects in namespaces controlled by more than one core provider (%s)",
139+
provider.InstanceName(),
109140
strings.Join(overlappingCoreProviders, " ,"),
110141
)
111142
}
112143
}
113144
return nil
114145
}
146+
147+
func (p *inventoryClient) GetManagementGroups() (ManagementGroupList, error) {
148+
providerList, err := p.List()
149+
if err != nil {
150+
return nil, err
151+
}
152+
153+
return deriveManagementGroups(providerList)
154+
}

0 commit comments

Comments
 (0)