Skip to content

Commit fb30a6f

Browse files
authored
Merge pull request kubernetes-sigs#10407 from neolit123/1.7-improve-clusterctl-cert-manager-install
🌱 clusterctl/client/cert_manager: improve shouldUpgrade
2 parents 7485511 + 47dcdda commit fb30a6f

File tree

2 files changed

+113
-70
lines changed

2 files changed

+113
-70
lines changed

cmd/clusterctl/client/cluster/cert_manager.go

Lines changed: 53 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -159,27 +159,26 @@ func (cm *certManagerClient) EnsureInstalled(ctx context.Context) error {
159159
return nil
160160
}
161161

162-
// Otherwise install cert manager.
163-
// NOTE: this instance of cert-manager will have clusterctl specific annotations that will be used to
164-
// manage the lifecycle of all the components.
165-
return cm.install(ctx)
166-
}
167-
168-
func (cm *certManagerClient) install(ctx context.Context) error {
169-
log := logf.Log
170-
171162
config, err := cm.configClient.CertManager().Get()
172163
if err != nil {
173164
return err
174165
}
175-
log.Info("Installing cert-manager", "Version", config.Version())
176-
177-
// Gets the cert-manager components from the repository.
178166
objs, err := cm.getManifestObjs(ctx, config)
179167
if err != nil {
180168
return err
181169
}
182170

171+
// Otherwise install cert manager.
172+
// NOTE: this instance of cert-manager will have clusterctl specific annotations that will be used to
173+
// manage the lifecycle of all the components.
174+
return cm.install(ctx, config.Version(), objs)
175+
}
176+
177+
func (cm *certManagerClient) install(ctx context.Context, version string, objs []unstructured.Unstructured) error {
178+
log := logf.Log
179+
180+
log.Info("Installing cert-manager", "Version", version)
181+
183182
// Install all cert-manager manifests
184183
createCertManagerBackoff := newWriteBackoff()
185184
objs = utilresource.SortForCreate(objs)
@@ -214,15 +213,25 @@ func (cm *certManagerClient) PlanUpgrade(ctx context.Context) (CertManagerUpgrad
214213
return CertManagerUpgradePlan{ExternallyManaged: true}, nil
215214
}
216215

217-
log.Info("Checking cert-manager version...")
218-
currentVersion, targetVersion, shouldUpgrade, err := cm.shouldUpgrade(objs)
216+
// Get the list of objects to install.
217+
config, err := cm.configClient.CertManager().Get()
218+
if err != nil {
219+
return CertManagerUpgradePlan{}, err
220+
}
221+
installObjs, err := cm.getManifestObjs(ctx, config)
222+
if err != nil {
223+
return CertManagerUpgradePlan{}, err
224+
}
225+
226+
log.Info("Checking if cert-manager needs upgrade...")
227+
currentVersion, shouldUpgrade, err := cm.shouldUpgrade(config.Version(), objs, installObjs)
219228
if err != nil {
220229
return CertManagerUpgradePlan{}, err
221230
}
222231

223232
return CertManagerUpgradePlan{
224233
From: currentVersion,
225-
To: targetVersion,
234+
To: config.Version(),
226235
ShouldUpgrade: shouldUpgrade,
227236
}, nil
228237
}
@@ -243,8 +252,18 @@ func (cm *certManagerClient) EnsureLatestVersion(ctx context.Context) error {
243252
return nil
244253
}
245254

246-
log.Info("Checking cert-manager version...")
247-
currentVersion, _, shouldUpgrade, err := cm.shouldUpgrade(objs)
255+
// Get the list of objects to install.
256+
config, err := cm.configClient.CertManager().Get()
257+
if err != nil {
258+
return err
259+
}
260+
installObjs, err := cm.getManifestObjs(ctx, config)
261+
if err != nil {
262+
return err
263+
}
264+
265+
log.Info("Checking if cert-manager needs upgrade...")
266+
currentVersion, shouldUpgrade, err := cm.shouldUpgrade(config.Version(), objs, installObjs)
248267
if err != nil {
249268
return err
250269
}
@@ -256,7 +275,7 @@ func (cm *certManagerClient) EnsureLatestVersion(ctx context.Context) error {
256275

257276
// Migrate CRs to latest CRD storage version, if necessary.
258277
// Note: We have to do this before cert-manager is deleted so conversion webhooks still work.
259-
if err := cm.migrateCRDs(ctx); err != nil {
278+
if err := cm.migrateCRDs(ctx, installObjs); err != nil {
260279
return err
261280
}
262281

@@ -269,27 +288,16 @@ func (cm *certManagerClient) EnsureLatestVersion(ctx context.Context) error {
269288
}
270289

271290
// Install cert-manager.
272-
return cm.install(ctx)
291+
return cm.install(ctx, config.Version(), installObjs)
273292
}
274293

275-
func (cm *certManagerClient) migrateCRDs(ctx context.Context) error {
276-
config, err := cm.configClient.CertManager().Get()
277-
if err != nil {
278-
return err
279-
}
280-
281-
// Gets the new cert-manager components from the repository.
282-
objs, err := cm.getManifestObjs(ctx, config)
283-
if err != nil {
284-
return err
285-
}
286-
294+
func (cm *certManagerClient) migrateCRDs(ctx context.Context, installObj []unstructured.Unstructured) error {
287295
c, err := cm.proxy.NewClient(ctx)
288296
if err != nil {
289297
return err
290298
}
291299

292-
return NewCRDMigrator(c).Run(ctx, objs)
300+
return NewCRDMigrator(c).Run(ctx, installObj)
293301
}
294302

295303
func (cm *certManagerClient) deleteObjs(ctx context.Context, objs []unstructured.Unstructured) error {
@@ -322,16 +330,10 @@ func (cm *certManagerClient) deleteObjs(ctx context.Context, objs []unstructured
322330
return nil
323331
}
324332

325-
func (cm *certManagerClient) shouldUpgrade(objs []unstructured.Unstructured) (string, string, bool, error) {
326-
config, err := cm.configClient.CertManager().Get()
327-
if err != nil {
328-
return "", "", false, err
329-
}
330-
331-
desiredVersion := config.Version()
333+
func (cm *certManagerClient) shouldUpgrade(desiredVersion string, objs, installObjs []unstructured.Unstructured) (string, bool, error) {
332334
desiredSemVersion, err := semver.ParseTolerant(desiredVersion)
333335
if err != nil {
334-
return "", "", false, errors.Wrapf(err, "failed to parse config version [%s] for cert-manager component", desiredVersion)
336+
return "", false, errors.Wrapf(err, "failed to parse config version [%s] for cert-manager component", desiredVersion)
335337
}
336338

337339
needUpgrade := false
@@ -358,25 +360,31 @@ func (cm *certManagerClient) shouldUpgrade(objs []unstructured.Unstructured) (st
358360

359361
objSemVersion, err := semver.ParseTolerant(objVersion)
360362
if err != nil {
361-
return "", "", false, errors.Wrapf(err, "failed to parse version for cert-manager component %s/%s", obj.GetKind(), obj.GetName())
363+
return "", false, errors.Wrapf(err, "failed to parse version for cert-manager component %s/%s", obj.GetKind(), obj.GetName())
362364
}
363365

364366
c := version.Compare(objSemVersion, desiredSemVersion, version.WithBuildTags())
365367
switch {
366368
case c < 0 || c == 2:
367-
// if version < current or same version and different non-numeric build metadata, then upgrade
369+
// The installed version is lower than the desired version or they are equal, but their metadata
370+
// is different non-numerically (see version.WithBuildTags()). Upgrade is required.
368371
currentVersion = objVersion
369372
needUpgrade = true
370-
case c >= 0:
371-
// the installed version is greater than or equal to one required by clusterctl, so we are ok
373+
case c == 0:
374+
// The installed version is equal to the desired version. Upgrade is required only if the number
375+
// of available objects and objects to install differ. This would act as a re-install.
376+
currentVersion = objVersion
377+
needUpgrade = len(objs) != len(installObjs)
378+
case c > 0:
379+
// The installed version is greater than the desired version. Upgrade is not required.
372380
currentVersion = objVersion
373381
}
374382

375383
if needUpgrade {
376384
break
377385
}
378386
}
379-
return currentVersion, desiredVersion, needUpgrade, nil
387+
return currentVersion, needUpgrade, nil
380388
}
381389

382390
func (cm *certManagerClient) getWaitTimeout() time.Duration {

cmd/clusterctl/client/cluster/cert_manager_test.go

Lines changed: 60 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -211,16 +211,17 @@ func Test_shouldUpgrade(t *testing.T) {
211211
objs []unstructured.Unstructured
212212
}
213213
tests := []struct {
214-
name string
215-
configVersion string
216-
args args
217-
wantFromVersion string
218-
wantToVersion string
219-
want bool
220-
wantErr bool
214+
name string
215+
configVersion string
216+
args args
217+
wantFromVersion string
218+
hasDiffInstallObjs bool
219+
want bool
220+
wantErr bool
221221
}{
222222
{
223-
name: "Version is not defined (e.g. cluster created with clusterctl < v0.3.9), should upgrade",
223+
name: "Version is not defined (e.g. cluster created with clusterctl < v0.3.9), should upgrade",
224+
configVersion: config.CertManagerDefaultVersion,
224225
args: args{
225226
objs: []unstructured.Unstructured{
226227
{
@@ -229,12 +230,12 @@ func Test_shouldUpgrade(t *testing.T) {
229230
},
230231
},
231232
wantFromVersion: "v0.11.0",
232-
wantToVersion: config.CertManagerDefaultVersion,
233233
want: true,
234234
wantErr: false,
235235
},
236236
{
237-
name: "Version is equal, should not upgrade",
237+
name: "Version is equal, should not upgrade",
238+
configVersion: config.CertManagerDefaultVersion,
238239
args: args{
239240
objs: []unstructured.Unstructured{
240241
{
@@ -249,7 +250,6 @@ func Test_shouldUpgrade(t *testing.T) {
249250
},
250251
},
251252
wantFromVersion: config.CertManagerDefaultVersion,
252-
wantToVersion: config.CertManagerDefaultVersion,
253253
want: false,
254254
wantErr: false,
255255
},
@@ -270,7 +270,6 @@ func Test_shouldUpgrade(t *testing.T) {
270270
},
271271
},
272272
wantFromVersion: "v1.5.3",
273-
wantToVersion: "v1.5.3+h4fd4",
274273
want: true,
275274
wantErr: false,
276275
},
@@ -291,7 +290,6 @@ func Test_shouldUpgrade(t *testing.T) {
291290
},
292291
},
293292
wantFromVersion: "v1.5.3+h4fd5",
294-
wantToVersion: "v1.5.3+h4fd4",
295293
want: true,
296294
wantErr: false,
297295
},
@@ -312,7 +310,6 @@ func Test_shouldUpgrade(t *testing.T) {
312310
},
313311
},
314312
wantFromVersion: "v1.5.3+h4fd5",
315-
wantToVersion: "v1.5.3+h4fd5",
316313
want: false,
317314
wantErr: false,
318315
},
@@ -333,7 +330,6 @@ func Test_shouldUpgrade(t *testing.T) {
333330
},
334331
},
335332
wantFromVersion: "v1.5.3+build.2",
336-
wantToVersion: "v1.5.3+build.1",
337333
want: false,
338334
wantErr: false,
339335
},
@@ -354,12 +350,33 @@ func Test_shouldUpgrade(t *testing.T) {
354350
},
355351
},
356352
wantFromVersion: "v1.5.3+build.2",
357-
wantToVersion: "v1.5.3+build.3",
358353
want: true,
359354
wantErr: false,
360355
},
361356
{
362-
name: "Version is older, should upgrade",
357+
name: "Version is equal, but should upgrade because objects to install are a different size",
358+
configVersion: config.CertManagerDefaultVersion,
359+
args: args{
360+
objs: []unstructured.Unstructured{
361+
{
362+
Object: map[string]interface{}{
363+
"metadata": map[string]interface{}{
364+
"annotations": map[string]interface{}{
365+
clusterctlv1.CertManagerVersionAnnotation: config.CertManagerDefaultVersion,
366+
},
367+
},
368+
},
369+
},
370+
},
371+
},
372+
wantFromVersion: config.CertManagerDefaultVersion,
373+
hasDiffInstallObjs: true,
374+
want: true,
375+
wantErr: false,
376+
},
377+
{
378+
name: "Version is older, should upgrade",
379+
configVersion: config.CertManagerDefaultVersion,
363380
args: args{
364381
objs: []unstructured.Unstructured{
365382
{
@@ -374,12 +391,12 @@ func Test_shouldUpgrade(t *testing.T) {
374391
},
375392
},
376393
wantFromVersion: "v0.11.0",
377-
wantToVersion: config.CertManagerDefaultVersion,
378394
want: true,
379395
wantErr: false,
380396
},
381397
{
382-
name: "Version is newer, should not upgrade",
398+
name: "Version is newer, should not upgrade",
399+
configVersion: config.CertManagerDefaultVersion,
383400
args: args{
384401
objs: []unstructured.Unstructured{
385402
{
@@ -394,12 +411,13 @@ func Test_shouldUpgrade(t *testing.T) {
394411
},
395412
},
396413
wantFromVersion: "v100.0.0",
397-
wantToVersion: config.CertManagerDefaultVersion,
398414
want: false,
399415
wantErr: false,
400416
},
417+
401418
{
402-
name: "Endpoint are ignored",
419+
name: "Endpoint are ignored",
420+
configVersion: config.CertManagerDefaultVersion,
403421
args: args{
404422
objs: []unstructured.Unstructured{
405423
{
@@ -415,7 +433,6 @@ func Test_shouldUpgrade(t *testing.T) {
415433
},
416434
},
417435
wantFromVersion: "",
418-
wantToVersion: config.CertManagerDefaultVersion,
419436
want: false,
420437
wantErr: false,
421438
},
@@ -431,7 +448,16 @@ func Test_shouldUpgrade(t *testing.T) {
431448
}
432449
cm := newCertManagerClient(fakeConfigClient, nil, proxy, pollImmediateWaiter)
433450

434-
fromVersion, toVersion, got, err := cm.shouldUpgrade(tt.args.objs)
451+
// By default, make the installed and to-be-installed objects the same, but if hasDiffInstallObjs is set,
452+
// just append an empty unstructured object at the end to make them different.
453+
installObjs := tt.args.objs
454+
if tt.hasDiffInstallObjs {
455+
installObjs = make([]unstructured.Unstructured, len(tt.args.objs))
456+
copy(installObjs, tt.args.objs)
457+
installObjs = append(installObjs, unstructured.Unstructured{})
458+
}
459+
460+
fromVersion, got, err := cm.shouldUpgrade(tt.configVersion, tt.args.objs, installObjs)
435461
if tt.wantErr {
436462
g.Expect(err).To(HaveOccurred())
437463
return
@@ -440,7 +466,6 @@ func Test_shouldUpgrade(t *testing.T) {
440466

441467
g.Expect(got).To(Equal(tt.want))
442468
g.Expect(fromVersion).To(Equal(tt.wantFromVersion))
443-
g.Expect(toVersion).To(Equal(tt.wantToVersion))
444469
})
445470
}
446471
}
@@ -718,7 +743,17 @@ func Test_certManagerClient_PlanUpgrade(t *testing.T) {
718743
pollImmediateWaiter := func(context.Context, time.Duration, time.Duration, wait.ConditionWithContextFunc) error {
719744
return nil
720745
}
721-
cm := newCertManagerClient(fakeConfigClient, nil, proxy, pollImmediateWaiter)
746+
747+
// Prepare a fake memory repo from which getManifestObjs(), called from PlanUpgrade() will fetch to-be-installed objects.
748+
fakeRepositoryClientFactory := func(ctx context.Context, provider config.Provider, configClient config.Client, _ ...repository.Option) (repository.Client, error) {
749+
repo := repository.NewMemoryRepository().
750+
WithPaths("root", "components.yaml").
751+
WithDefaultVersion(config.CertManagerDefaultVersion).
752+
WithFile(config.CertManagerDefaultVersion, "components.yaml", certManagerDeploymentYaml)
753+
return repository.New(ctx, provider, configClient, repository.InjectRepository(repo))
754+
}
755+
756+
cm := newCertManagerClient(fakeConfigClient, fakeRepositoryClientFactory, proxy, pollImmediateWaiter)
722757

723758
actualPlan, err := cm.PlanUpgrade(ctx)
724759
if tt.expectErr {

0 commit comments

Comments
 (0)