Skip to content

Commit 0ff1e8d

Browse files
authored
Merge pull request #7376 from oscr/clusterctl-upgrade-syntax
✨ Improve clusterctl upgrade syntax. Don't require namespace
2 parents e437ecf + 8eb5a2f commit 0ff1e8d

File tree

6 files changed

+124
-35
lines changed

6 files changed

+124
-35
lines changed

cmd/clusterctl/client/client.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ type RepositoryClientFactoryInput struct {
127127
// RepositoryClientFactory is a factory of repository.Client from a given input.
128128
type RepositoryClientFactory func(RepositoryClientFactoryInput) (repository.Client, error)
129129

130-
// ClusterClientFactoryInput reporesents the inputs required by the factory.
130+
// ClusterClientFactoryInput represents the inputs required by the factory.
131131
type ClusterClientFactoryInput struct {
132132
Kubeconfig Kubeconfig
133133
Processor Processor

cmd/clusterctl/client/upgrade.go

Lines changed: 65 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ import (
3030
"sigs.k8s.io/cluster-api/cmd/clusterctl/client/cluster"
3131
)
3232

33+
const upgradeItemProviderNameError = "invalid provider name %q. Provider name should be in the form namespace/provider:version or provider:version"
34+
3335
// PlanUpgradeOptions carries the options supported by upgrade plan.
3436
type PlanUpgradeOptions struct {
3537
// Kubeconfig defines the kubeconfig to use for accessing the management cluster. If empty, default discovery rules apply.
@@ -97,16 +99,20 @@ type ApplyUpgradeOptions struct {
9799
// a more granular control on upgrade, use CoreProvider, BootstrapProviders, ControlPlaneProviders, InfrastructureProviders.
98100
Contract string
99101

100-
// CoreProvider instance and version (e.g. capi-system/cluster-api:v1.1.5) to upgrade to. This field can be used as alternative to Contract.
102+
// CoreProvider instance and version (e.g. [capi-system/]cluster-api:v1.1.5) to upgrade to. This field can be used as alternative to Contract.
103+
// Specifying a namespace is now optional and in the future it will be deprecated.
101104
CoreProvider string
102105

103-
// BootstrapProviders instance and versions (e.g. capi-kubeadm-bootstrap-system/kubeadm:v1.1.5) to upgrade to. This field can be used as alternative to Contract.
106+
// BootstrapProviders instance and versions (e.g. [capi-kubeadm-bootstrap-system/]kubeadm:v1.1.5) to upgrade to. This field can be used as alternative to Contract.
107+
// Specifying a namespace is now optional and in the future it will be deprecated.
104108
BootstrapProviders []string
105109

106-
// ControlPlaneProviders instance and versions (e.g. capi-kubeadm-control-plane-system/kubeadm:v1.1.5) to upgrade to. This field can be used as alternative to Contract.
110+
// ControlPlaneProviders instance and versions (e.g. [capi-kubeadm-control-plane-system/]kubeadm:v1.1.5) to upgrade to. This field can be used as alternative to Contract.
111+
// Specifying a namespace is now optional and in the future it will be deprecated.
107112
ControlPlaneProviders []string
108113

109-
// InfrastructureProviders instance and versions (e.g. capa-system/aws:v0.5.0) to upgrade to. This field can be used as alternative to Contract.
114+
// InfrastructureProviders instance and versions (e.g. [capa-system/]aws:v0.5.0) to upgrade to. This field can be used as alternative to Contract.
115+
// Specifying a namespace is now optional and in the future it will be deprecated.
110116
InfrastructureProviders []string
111117

112118
// IPAMProviders instance and versions (e.g. ipam-system/infoblox:v0.0.1) to upgrade to. This field can be used as alternative to Contract.
@@ -176,28 +182,28 @@ func (c *clusterctlClient) ApplyUpgrade(options ApplyUpgradeOptions) error {
176182
upgradeItems := []cluster.UpgradeItem{}
177183

178184
if options.CoreProvider != "" {
179-
upgradeItems, err = addUpgradeItems(upgradeItems, clusterctlv1.CoreProviderType, options.CoreProvider)
185+
upgradeItems, err = addUpgradeItems(clusterClient, upgradeItems, clusterctlv1.CoreProviderType, options.CoreProvider)
180186
if err != nil {
181187
return err
182188
}
183189
}
184-
upgradeItems, err = addUpgradeItems(upgradeItems, clusterctlv1.BootstrapProviderType, options.BootstrapProviders...)
190+
upgradeItems, err = addUpgradeItems(clusterClient, upgradeItems, clusterctlv1.BootstrapProviderType, options.BootstrapProviders...)
185191
if err != nil {
186192
return err
187193
}
188-
upgradeItems, err = addUpgradeItems(upgradeItems, clusterctlv1.ControlPlaneProviderType, options.ControlPlaneProviders...)
194+
upgradeItems, err = addUpgradeItems(clusterClient, upgradeItems, clusterctlv1.ControlPlaneProviderType, options.ControlPlaneProviders...)
189195
if err != nil {
190196
return err
191197
}
192-
upgradeItems, err = addUpgradeItems(upgradeItems, clusterctlv1.InfrastructureProviderType, options.InfrastructureProviders...)
198+
upgradeItems, err = addUpgradeItems(clusterClient, upgradeItems, clusterctlv1.InfrastructureProviderType, options.InfrastructureProviders...)
193199
if err != nil {
194200
return err
195201
}
196-
upgradeItems, err = addUpgradeItems(upgradeItems, clusterctlv1.IPAMProviderType, options.IPAMProviders...)
202+
upgradeItems, err = addUpgradeItems(clusterClient, upgradeItems, clusterctlv1.IPAMProviderType, options.IPAMProviders...)
197203
if err != nil {
198204
return err
199205
}
200-
upgradeItems, err = addUpgradeItems(upgradeItems, clusterctlv1.RuntimeExtensionProviderType, options.RuntimeExtensionProviders...)
206+
upgradeItems, err = addUpgradeItems(clusterClient, upgradeItems, clusterctlv1.RuntimeExtensionProviderType, options.RuntimeExtensionProviders...)
201207
if err != nil {
202208
return err
203209
}
@@ -210,9 +216,9 @@ func (c *clusterctlClient) ApplyUpgrade(options ApplyUpgradeOptions) error {
210216
return clusterClient.ProviderUpgrader().ApplyPlan(opts, options.Contract)
211217
}
212218

213-
func addUpgradeItems(upgradeItems []cluster.UpgradeItem, providerType clusterctlv1.ProviderType, providers ...string) ([]cluster.UpgradeItem, error) {
219+
func addUpgradeItems(clusterClient cluster.Client, upgradeItems []cluster.UpgradeItem, providerType clusterctlv1.ProviderType, providers ...string) ([]cluster.UpgradeItem, error) {
214220
for _, upgradeReference := range providers {
215-
providerUpgradeItem, err := parseUpgradeItem(upgradeReference, providerType)
221+
providerUpgradeItem, err := parseUpgradeItem(clusterClient, upgradeReference, providerType)
216222
if err != nil {
217223
return nil, err
218224
}
@@ -224,20 +230,63 @@ func addUpgradeItems(upgradeItems []cluster.UpgradeItem, providerType clusterctl
224230
return upgradeItems, nil
225231
}
226232

227-
func parseUpgradeItem(ref string, providerType clusterctlv1.ProviderType) (*cluster.UpgradeItem, error) {
233+
func parseUpgradeItem(clusterClient cluster.Client, ref string, providerType clusterctlv1.ProviderType) (*cluster.UpgradeItem, error) {
234+
// TODO(oscr) Remove when explicit namespaces for providers is removed
235+
// ref format is old format: namespace/provider:version
236+
if strings.Contains(ref, "/") {
237+
return parseUpgradeItemWithNamespace(ref, providerType)
238+
}
239+
240+
// ref format is: provider:version
241+
return parseUpgradeItemWithoutNamespace(clusterClient, ref, providerType)
242+
}
243+
244+
func parseUpgradeItemWithNamespace(ref string, providerType clusterctlv1.ProviderType) (*cluster.UpgradeItem, error) {
228245
refSplit := strings.Split(strings.ToLower(ref), "/")
246+
229247
if len(refSplit) != 2 {
230-
return nil, errors.Errorf("invalid provider name %q. Provider name should be in the form namespace/provider[:version]", ref)
248+
return nil, errors.Errorf(upgradeItemProviderNameError, ref)
231249
}
232250

233251
if refSplit[0] == "" {
234-
return nil, errors.Errorf("invalid provider name %q. Provider name should be in the form namespace/name[:version] and namespace cannot be empty", ref)
252+
return nil, errors.Errorf(upgradeItemProviderNameError, ref)
235253
}
236254
namespace := refSplit[0]
237255

238256
name, version, err := parseProviderName(refSplit[1])
239257
if err != nil {
240-
return nil, errors.Wrapf(err, "invalid provider name %q. Provider name should be in the form namespace/name[:version] and the namespace should be valid", ref)
258+
return nil, errors.Wrapf(err, upgradeItemProviderNameError, ref)
259+
}
260+
261+
return &cluster.UpgradeItem{
262+
Provider: clusterctlv1.Provider{
263+
ObjectMeta: metav1.ObjectMeta{
264+
Namespace: namespace,
265+
Name: clusterctlv1.ManifestLabel(name, providerType),
266+
},
267+
ProviderName: name,
268+
Type: string(providerType),
269+
// The value for the following fields will be retrieved while
270+
// creating the custom upgrade plan.
271+
WatchedNamespace: "",
272+
},
273+
NextVersion: version,
274+
}, nil
275+
}
276+
277+
func parseUpgradeItemWithoutNamespace(clusterClient cluster.Client, ref string, providerType clusterctlv1.ProviderType) (*cluster.UpgradeItem, error) {
278+
if !strings.Contains(ref, ":") {
279+
return nil, errors.Errorf(upgradeItemProviderNameError, ref)
280+
}
281+
282+
name, version, err := parseProviderName(ref)
283+
if err != nil {
284+
return nil, errors.Wrapf(err, upgradeItemProviderNameError, ref)
285+
}
286+
287+
namespace, err := clusterClient.ProviderInventory().GetProviderNamespace(name, providerType)
288+
if err != nil {
289+
return nil, errors.Errorf("unable to find default namespace for provider %q", ref)
241290
}
242291

243292
return &cluster.UpgradeItem{

cmd/clusterctl/client/upgrade_test.go

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -375,6 +375,11 @@ func Test_parseUpgradeItem(t *testing.T) {
375375
type args struct {
376376
provider string
377377
}
378+
379+
configClient := newFakeConfig()
380+
clusterClient := newFakeCluster(cluster.Kubeconfig{Path: "cluster1"}, configClient)
381+
clusterClient.WithProviderInventory("best-provider", clusterctlv1.CoreProviderType, "v1.0.0", "best-provider-system")
382+
378383
tests := []struct {
379384
name string
380385
args args
@@ -418,9 +423,35 @@ func Test_parseUpgradeItem(t *testing.T) {
418423
wantErr: false,
419424
},
420425
{
421-
name: "namespace missing",
426+
name: "provider:version",
427+
args: args{
428+
provider: "best-provider:v1.0.0",
429+
},
430+
want: &cluster.UpgradeItem{
431+
Provider: clusterctlv1.Provider{
432+
ObjectMeta: metav1.ObjectMeta{
433+
Namespace: "best-provider-system",
434+
Name: clusterctlv1.ManifestLabel("best-provider", clusterctlv1.CoreProviderType),
435+
},
436+
ProviderName: "best-provider",
437+
Type: string(clusterctlv1.CoreProviderType),
438+
},
439+
NextVersion: "v1.0.0",
440+
},
441+
wantErr: false,
442+
},
443+
{
444+
name: "provider: with no version",
445+
args: args{
446+
provider: "provider:",
447+
},
448+
want: nil,
449+
wantErr: true,
450+
},
451+
{
452+
name: "provider with no version",
422453
args: args{
423-
provider: "provider:version",
454+
provider: "provider",
424455
},
425456
want: nil,
426457
wantErr: true,
@@ -438,7 +469,7 @@ func Test_parseUpgradeItem(t *testing.T) {
438469
t.Run(tt.name, func(t *testing.T) {
439470
g := NewWithT(t)
440471

441-
got, err := parseUpgradeItem(tt.args.provider, clusterctlv1.CoreProviderType)
472+
got, err := parseUpgradeItem(clusterClient, tt.args.provider, clusterctlv1.CoreProviderType)
442473
if tt.wantErr {
443474
g.Expect(err).To(HaveOccurred())
444475
return

cmd/clusterctl/cmd/upgrade_apply.go

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -48,15 +48,17 @@ var upgradeApplyCmd = &cobra.Command{
4848
The upgrade apply command applies new versions of Cluster API providers as defined by clusterctl upgrade plan.
4949
5050
New version should be applied ensuring all the providers uses the same cluster API version
51-
in order to guarantee the proper functioning of the management cluster.`),
51+
in order to guarantee the proper functioning of the management cluster.
52+
53+
Specifying the provider using namespace/name:version is deprecated and will be dropped in a future release.`),
5254

5355
Example: Examples(`
5456
# Upgrades all the providers in the management cluster to the latest version available which is compliant
5557
# to the v1alpha4 API Version of Cluster API (contract).
5658
clusterctl upgrade apply --contract v1alpha4
5759
58-
# Upgrades only the capa-system/aws provider to the v0.5.0 version.
59-
clusterctl upgrade apply --infrastructure capa-system/aws:v0.5.0`),
60+
# Upgrades only the aws provider to the v2.0.1 version.
61+
clusterctl upgrade apply --infrastructure aws:v2.0.1`),
6062
Args: cobra.NoArgs,
6163
RunE: func(cmd *cobra.Command, args []string) error {
6264
return runUpgradeApply()
@@ -72,13 +74,13 @@ func init() {
7274
"The API Version of Cluster API (contract, e.g. v1alpha4) the management cluster should upgrade to")
7375

7476
upgradeApplyCmd.Flags().StringVar(&ua.coreProvider, "core", "",
75-
"Core provider instance version (e.g. capi-system/cluster-api:v1.1.5) to upgrade to. This flag can be used as alternative to --contract.")
77+
"Core provider instance version (e.g. cluster-api:v1.1.5) to upgrade to. This flag can be used as alternative to --contract.")
7678
upgradeApplyCmd.Flags().StringSliceVarP(&ua.infrastructureProviders, "infrastructure", "i", nil,
77-
"Infrastructure providers instance and versions (e.g. capa-system/aws:v0.5.0) to upgrade to. This flag can be used as alternative to --contract.")
79+
"Infrastructure providers instance and versions (e.g. aws:v2.0.1) to upgrade to. This flag can be used as alternative to --contract.")
7880
upgradeApplyCmd.Flags().StringSliceVarP(&ua.bootstrapProviders, "bootstrap", "b", nil,
79-
"Bootstrap providers instance and versions (e.g. capi-kubeadm-bootstrap-system/kubeadm:v1.1.5) to upgrade to. This flag can be used as alternative to --contract.")
81+
"Bootstrap providers instance and versions (e.g. kubeadm:v1.1.5) to upgrade to. This flag can be used as alternative to --contract.")
8082
upgradeApplyCmd.Flags().StringSliceVarP(&ua.controlPlaneProviders, "control-plane", "c", nil,
81-
"ControlPlane providers instance and versions (e.g. capi-kubeadm-control-plane-system/kubeadm:v1.1.5) to upgrade to. This flag can be used as alternative to --contract.")
83+
"ControlPlane providers instance and versions (e.g. kubeadm:v1.1.5) to upgrade to. This flag can be used as alternative to --contract.")
8284
upgradeApplyCmd.Flags().StringSliceVar(&ua.ipamProviders, "ipam", nil,
8385
"IPAM providers and versions (e.g. infoblox:v0.0.1) to upgrade to. This flag can be used as alternative to --contract.")
8486
upgradeApplyCmd.Flags().StringSliceVar(&ua.runtimeExtensionProviders, "runtime-extension", nil,

docs/book/src/clusterctl/commands/upgrade.md

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,13 @@ The upgrade process is composed by three steps:
6666
Please note that clusterctl does not upgrade Cluster API objects (Clusters, MachineDeployments, Machine etc.); upgrading
6767
such objects are the responsibility of the provider's controllers.
6868

69+
It is also possible to explicitly upgrade one or more components to specific versions.
70+
```bash
71+
clusterctl upgrade apply \
72+
--core cluster-api:v1.2.4 \
73+
--infrastructure docker:v1.2.4
74+
```
75+
6976
<aside class="note warning">
7077

7178
<h1>Warning!</h1>
@@ -86,10 +93,10 @@ the following:
8693

8794
```bash
8895
clusterctl upgrade apply \
89-
--core capi-system/cluster-api:v1.0.0 \
90-
--bootstrap capi-kubeadm-bootstrap-system/kubeadm:v1.0.0 \
91-
--control-plane capi-kubeadm-control-plane-system/kubeadm:v1.0.0 \
92-
--infrastructure capd-system/docker:v1.0.0-rc.0
96+
--core cluster-api:v1.0.0 \
97+
--bootstrap kubeadm:v1.0.0 \
98+
--control-plane kubeadm:v1.0.0 \
99+
--infrastructure docker:v1.0.0-rc.0
93100
```
94101

95102
In this case, all the provider's versions must be explicitly stated.

docs/book/src/developer/providers/v1.3-to-v1.4.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,8 @@ maintainers of providers and consumers of our Go API.
99

1010
## Dependencies
1111

12-
**Note**: Only the most relevant dependencies are listed, `k8s.io/` and `ginkgo`/`gomega` dependencies
13-
in Cluster API are kept in sync with the versions used by `sigs.k8s.io/controller-runtime`.
12+
**Note**: Only the most relevant dependencies are listed, `k8s.io/` and `ginkgo`/`gomega` dependencies in Cluster API are kept in sync with the versions used by `sigs.k8s.io/controller-runtime`.
1413

15-
-
1614

1715
## Changes by Kind
1816

@@ -30,4 +28,6 @@ in Cluster API are kept in sync with the versions used by `sigs.k8s.io/controlle
3028

3129
### Other
3230

33-
-
31+
- `clusterctl upgrade apply` no longer requires a namespace when updating providers. It is now optional and in a future release it will be deprecated. The new syntax is `[namespace/]provider:version`.
32+
33+
### Suggested changes for providers

0 commit comments

Comments
 (0)