Skip to content

Commit f1c5606

Browse files
clusterctl upgrade plan apply
1 parent c976d8e commit f1c5606

12 files changed

+1036
-51
lines changed

cmd/clusterctl/cmd/upgrade.go

Lines changed: 56 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,11 +62,49 @@ var upgradePlanCmd = &cobra.Command{
6262
},
6363
}
6464

65+
type upgradeApplyOptions struct {
66+
kubeconfig string
67+
managementGroup string
68+
contract string
69+
upgradeReferences []string
70+
}
71+
72+
var ua = &upgradeApplyOptions{}
73+
74+
var upgradeApplyCmd = &cobra.Command{
75+
Use: "apply",
76+
Short: "Applies new versions of Cluster API providers in a management cluster",
77+
Long: LongDesc(`
78+
The upgrade apply command applies new versions of Cluster API providers as defined by clusterctl upgrade plan.
79+
80+
New version should be applied for each management groups, ensuring all the providers on the same cluster API version
81+
in order to guarantee the proper functioning of the management cluster.`),
82+
83+
Example: Examples(`
84+
# Upgrades all the providers in the capi-system/cluster-api to the latest version available which is compliant
85+
# to the v1alpha3 API Version of Cluster API (contract).
86+
clusterctl upgrade apply --management-group capi-system/cluster-api --contract v1alpha3
87+
88+
# Upgrades the kubeadm-provider in the capi-system/cluster-api to the v0.3.1 version.
89+
clusterctl upgrade apply --management-group capi-system/cluster-api --cluster-api-version v1alpha3 --provider capi-kubeadm-bootstrap-system/kubeadm-bootstrap:v0.3.1`),
90+
91+
RunE: func(cmd *cobra.Command, args []string) error {
92+
return runUpgradeApply()
93+
},
94+
}
95+
6596
func init() {
6697
upgradePlanCmd.Flags().StringVarP(&up.kubeconfig, "kubeconfig", "", "", "Path to the kubeconfig file to use for accessing the management cluster. If empty, default rules for kubeconfig discovery will be used")
6798

6899
upgradeCmd.AddCommand(upgradePlanCmd)
69100

101+
upgradeApplyCmd.Flags().StringVarP(&ua.kubeconfig, "kubeconfig", "", "", "Path to the kubeconfig file to use for accessing the management cluster. If empty, default rules for kubeconfig discovery will be used")
102+
upgradeApplyCmd.Flags().StringVarP(&ua.managementGroup, "management-group", "", "", "The management group that should be upgraded")
103+
upgradeApplyCmd.Flags().StringVarP(&ua.contract, "contract", "", "", "The API Version of Cluster API (contract) the management group should upgrade to")
104+
upgradeApplyCmd.Flags().StringSliceVarP(&ua.upgradeReferences, "provider", "", nil, "Providers and versions (e.g. caps-system/aws:v0.5.0) to upgrade to. If empty (default) the latest versions available will be used for all the providers")
105+
106+
upgradeCmd.AddCommand(upgradeApplyCmd)
107+
70108
RootCmd.AddCommand(upgradeCmd)
71109
}
72110

@@ -114,7 +152,7 @@ func runUpgradePlan() error {
114152
if upgradeAvailable {
115153
fmt.Println("You can now apply the upgrade by executing the following command:")
116154
fmt.Println("")
117-
fmt.Println(fmt.Sprintf(" upgrade apply --management-group %s --cluster-api-version %s", plan.CoreProvider.InstanceName(), plan.Contract))
155+
fmt.Println(fmt.Sprintf(" upgrade apply --management-group %s --contract %s", plan.CoreProvider.InstanceName(), plan.Contract))
118156
} else {
119157
fmt.Println("You are already up to date!")
120158
}
@@ -146,3 +184,20 @@ func prettifyTargetVersion(version string) string {
146184
}
147185
return version
148186
}
187+
188+
func runUpgradeApply() error {
189+
c, err := client.New(cfgFile)
190+
if err != nil {
191+
return err
192+
}
193+
194+
if err := c.ApplyUpgrade(client.ApplyUpgradeOptions{
195+
Kubeconfig: ua.kubeconfig,
196+
ManagementGroup: ua.managementGroup,
197+
Contract: ua.contract,
198+
UpgradeReferences: ua.upgradeReferences,
199+
}); err != nil {
200+
return err
201+
}
202+
return nil
203+
}

cmd/clusterctl/pkg/client/client.go

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -120,12 +120,6 @@ type MoveOptions struct {
120120
Namespace string
121121
}
122122

123-
// PlanUpgradeOptions carries the options supported by upgrade plan.
124-
type PlanUpgradeOptions struct {
125-
// Kubeconfig file to use for accessing the management cluster. If empty, default rules for kubeconfig discovery will be used.
126-
Kubeconfig string
127-
}
128-
129123
// Client is exposes the clusterctl high-level client library.
130124
type Client interface {
131125
// GetProvidersConfig returns the list of providers configured for this instance of clusterctl.
@@ -152,6 +146,9 @@ type Client interface {
152146
// - Upgrade to the latest version in the the v1alpha2 series: ....
153147
// - Upgrade to the latest version in the the v1alpha3 series: ....
154148
PlanUpgrade(options PlanUpgradeOptions) ([]UpgradePlan, error)
149+
150+
// ApplyUpgrade executes an upgrade plan.
151+
ApplyUpgrade(options ApplyUpgradeOptions) error
155152
}
156153

157154
// clusterctlClient implements Client.

cmd/clusterctl/pkg/client/client_test.go

Lines changed: 39 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ func TestNewFakeClient(t *testing.T) {
4646
WithFile("v1.0", "components.yaml", []byte("content"))
4747

4848
// create a fake cluster, eventually adding some existing runtime objects to it
49-
cluster1 := newFakeCluster("cluster1").
49+
cluster1 := newFakeCluster("cluster1", config1).
5050
WithObjs()
5151

5252
// create a new fakeClient that allows to execute tests on the fake config, the fake repositories and the fake cluster.
@@ -92,6 +92,10 @@ func (f fakeClient) PlanUpgrade(options PlanUpgradeOptions) ([]UpgradePlan, erro
9292
return f.internalClient.PlanUpgrade(options)
9393
}
9494

95+
func (f fakeClient) ApplyUpgrade(options ApplyUpgradeOptions) error {
96+
return f.internalClient.ApplyUpgrade(options)
97+
}
98+
9599
// newFakeClient returns a clusterctl client that allows to execute tests on a set of fake config, fake repositories and fake clusters.
96100
// you can use WithCluster and WithRepository to prepare for the test case.
97101
func newFakeClient(configClient config.Client) *fakeClient {
@@ -143,20 +147,29 @@ func (f *fakeClient) WithRepository(repositoryClient repository.Client) *fakeCli
143147
// newFakeCluster returns a fakeClusterClient that
144148
// internally uses a FakeProxy (based on the controller-runtime FakeClient).
145149
// You can use WithObjs to pre-load a set of runtime objects in the cluster.
146-
func newFakeCluster(kubeconfig string) *fakeClusterClient {
147-
configClient := newFakeConfig()
148-
fakeProxy := test.NewFakeProxy()
150+
func newFakeCluster(kubeconfig string, configClient config.Client) *fakeClusterClient {
151+
fake := &fakeClusterClient{
152+
kubeconfig: kubeconfig,
153+
repositories: map[string]repository.Client{},
154+
}
155+
156+
fake.fakeProxy = test.NewFakeProxy()
149157
pollImmediateWaiter := func(interval, timeout time.Duration, condition wait.ConditionFunc) error {
150158
return nil
151159
}
152160

153-
client := cluster.New("", configClient, cluster.InjectProxy(fakeProxy), cluster.InjectPollImmediateWaiter(pollImmediateWaiter))
161+
fake.internalclient = cluster.New("", configClient,
162+
cluster.InjectProxy(fake.fakeProxy),
163+
cluster.InjectPollImmediateWaiter(pollImmediateWaiter),
164+
cluster.InjectRepositoryFactory(func(provider config.Provider, configVariablesClient config.VariablesClient, options ...repository.Option) (repository.Client, error) {
165+
if _, ok := fake.repositories[provider.Name()]; !ok {
166+
return nil, errors.Errorf("Repository for kubeconfig %q does not exists.", provider.Name())
167+
}
168+
return fake.repositories[provider.Name()], nil
169+
}),
170+
)
154171

155-
return &fakeClusterClient{
156-
kubeconfig: kubeconfig,
157-
fakeProxy: fakeProxy,
158-
internalclient: client,
159-
}
172+
return fake
160173
}
161174

162175
type fakeCertManagerClient struct {
@@ -172,6 +185,7 @@ func (p *fakeCertManagerClient) EnsureWebHook() error {
172185
type fakeClusterClient struct {
173186
kubeconfig string
174187
fakeProxy *test.FakeProxy
188+
repositories map[string]repository.Client
175189
internalclient cluster.Client
176190
}
177191

@@ -219,6 +233,11 @@ func (f *fakeClusterClient) WithProviderInventory(name string, providerType clus
219233
return f
220234
}
221235

236+
func (f *fakeClusterClient) WithRepository(repositoryClient repository.Client) *fakeClusterClient {
237+
f.repositories[repositoryClient.Name()] = repositoryClient
238+
return f
239+
}
240+
222241
// newFakeConfig return a fake implementation of the client for low-level config library.
223242
// The implementation uses a FakeReader that stores configuration settings in a map; you can use
224243
// the WithVar or WithProvider methods to set the map values.
@@ -315,6 +334,16 @@ func (f *fakeRepositoryClient) WithDefaultVersion(version string) *fakeRepositor
315334
return f
316335
}
317336

337+
func (f *fakeRepositoryClient) WithVersions(version ...string) *fakeRepositoryClient {
338+
f.fakeRepository.WithVersions(version...)
339+
return f
340+
}
341+
342+
func (f *fakeRepositoryClient) WithMetadata(version string, metadata *clusterctlv1.Metadata) *fakeRepositoryClient {
343+
f.fakeRepository.WithMetadata(version, metadata)
344+
return f
345+
}
346+
318347
func (f *fakeRepositoryClient) WithFile(version, path string, content []byte) *fakeRepositoryClient {
319348
f.fakeRepository.WithFile(version, path, content)
320349
return f

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ func (c *clusterClient) ObjectMover() ObjectMover {
114114
}
115115

116116
func (c *clusterClient) ProviderUpgrader() ProviderUpgrader {
117-
return newProviderUpgrader(c.configClient, c.repositoryClientFactory, c.ProviderInventory())
117+
return newProviderUpgrader(c.configClient, c.repositoryClientFactory, c.ProviderInventory(), c.ProviderComponents())
118118
}
119119

120120
// Option is a configuration option supplied to New

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

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -53,11 +53,7 @@ func (i *providerInstaller) Add(components repository.Components) error {
5353
func (i *providerInstaller) Install() ([]repository.Components, error) {
5454
ret := make([]repository.Components, 0, len(i.installQueue))
5555
for _, components := range i.installQueue {
56-
if err := i.providerComponents.Create(components); err != nil {
57-
return nil, err
58-
}
59-
60-
if err := i.providerInventory.Create(components.InventoryObject()); err != nil {
56+
if err := installComponentsAndUpdateInventory(components, i.providerComponents, i.providerInventory); err != nil {
6157
return nil, err
6258
}
6359

@@ -66,6 +62,18 @@ func (i *providerInstaller) Install() ([]repository.Components, error) {
6662
return ret, nil
6763
}
6864

65+
func installComponentsAndUpdateInventory(components repository.Components, providerComponents ComponentsClient, providerInventory InventoryClient) error {
66+
if err := providerComponents.Create(components); err != nil {
67+
return err
68+
}
69+
70+
if err := providerInventory.Create(components.InventoryObject()); err != nil {
71+
return err
72+
}
73+
74+
return nil
75+
}
76+
6977
func newProviderInstaller(proxy Proxy, providerMetadata InventoryClient, providerComponents ComponentsClient) *providerInstaller {
7078
return &providerInstaller{
7179
proxy: proxy,

0 commit comments

Comments
 (0)