Skip to content

Commit 48a0c2b

Browse files
Wieneogardener-ci-robotshafeeqesgardener-robot-ci-2
authored
Update fork to patch v1.120.1 (#153)
* [release-v1.120] Fix credentials rotation without workers rollout for in-place update (gardener#12249) * Use correct lastInitationTime during credentials rotation without workers rollout * Use correct function in e2e test This was wrongly replaced in gardener#11990 * Add e2e tests for in-place and without-workers-rollout combination * Reconcile shoot when rotation status is WaitingForWorkersRollout and manual in-place pending workers are updated --------- Co-authored-by: Shafeeque E S <[email protected]> * Release v1.120.1 --------- Co-authored-by: Gardener Prow Robot <[email protected]> Co-authored-by: Shafeeque E S <[email protected]> Co-authored-by: gardener-robot-ci-2 <[email protected]>
1 parent 38e0351 commit 48a0c2b

10 files changed

Lines changed: 235 additions & 21 deletions

File tree

VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
v1.120.0
1+
v1.120.1

docs/deployment/getting_started_locally.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,8 @@ cat <<EOF | sudo tee -a /etc/hosts
266266
172.18.255.1 api.e2e-rot-noroll.local.internal.local.gardener.cloud
267267
172.18.255.1 api.e2e-rot-ip.local.external.local.gardener.cloud
268268
172.18.255.1 api.e2e-rot-ip.local.internal.local.gardener.cloud
269+
172.18.255.1 api.e2e-rot-nr-ip.local.external.local.gardener.cloud
270+
172.18.255.1 api.e2e-rot-nr-ip.local.internal.local.gardener.cloud
269271
172.18.255.1 api.e2e-default.local.external.local.gardener.cloud
270272
172.18.255.1 api.e2e-default.local.internal.local.gardener.cloud
271273
172.18.255.1 api.e2e-default-wl.local.external.local.gardener.cloud
@@ -296,6 +298,7 @@ cat <<EOF | sudo tee -a /etc/hosts
296298
172.18.255.1 gu-local--e2e-rotate-wl.ingress.local.seed.local.gardener.cloud
297299
172.18.255.1 gu-local--e2e-rot-noroll.ingress.local.seed.local.gardener.cloud
298300
172.18.255.1 gu-local--e2e-rot-ip.ingress.local.seed.local.gardener.cloud
301+
172.18.255.1 gu-local--e2e-rot-nr-ip.ingress.local.seed.local.gardener.cloud
299302
# End of Gardener local setup section
300303
EOF
301304
```

hack/test-e2e-local.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ case $TYPE in
9494
e2e-rotate-wl.local
9595
e2e-rot-noroll.local
9696
e2e-rot-ip.local
97+
e2e-rot-nr-ip.local
9798
e2e-default.local
9899
e2e-default-wl.local
99100
e2e-default-ip.local

pkg/component/extensions/operatingsystemconfig/operatingsystemconfig.go

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -731,12 +731,13 @@ func (o *operatingSystemConfig) newDeployer(version int, osc *extensionsv1alpha1
731731

732732
var caRotationLastInitiationTime, serviceAccountKeyRotationLastInitiationTime *metav1.Time
733733

734-
if o.values.CredentialsRotationStatus != nil {
735-
if o.values.CredentialsRotationStatus.CertificateAuthorities != nil {
736-
caRotationLastInitiationTime = o.values.CredentialsRotationStatus.CertificateAuthorities.LastInitiationTime
734+
if credentialsRotation := o.values.CredentialsRotationStatus; credentialsRotation != nil {
735+
if caRotation := credentialsRotation.CertificateAuthorities; caRotation != nil {
736+
caRotationLastInitiationTime = v1beta1helper.LastInitiationTimeForWorkerPool(worker.Name, caRotation.PendingWorkersRollouts, caRotation.LastInitiationTime)
737737
}
738-
if o.values.CredentialsRotationStatus.ServiceAccountKey != nil {
739-
serviceAccountKeyRotationLastInitiationTime = o.values.CredentialsRotationStatus.ServiceAccountKey.LastInitiationTime
738+
739+
if serviceAccountKeyRotation := credentialsRotation.ServiceAccountKey; serviceAccountKeyRotation != nil {
740+
serviceAccountKeyRotationLastInitiationTime = v1beta1helper.LastInitiationTimeForWorkerPool(worker.Name, serviceAccountKeyRotation.PendingWorkersRollouts, serviceAccountKeyRotation.LastInitiationTime)
740741
}
741742
}
742743

pkg/component/extensions/operatingsystemconfig/operatingsystemconfig_test.go

Lines changed: 33 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,9 @@ var _ = Describe("OperatingSystemConfig", func() {
6060

6161
worker1Name = "worker1"
6262
worker2Name = "worker2"
63+
64+
inPlaceWorkerName1 = worker1Name + "-in-place"
65+
inPlaceWorkerName2 = worker2Name + "-in-place"
6366
)
6467

6568
var (
@@ -143,6 +146,8 @@ var _ = Describe("OperatingSystemConfig", func() {
143146

144147
empty *extensionsv1alpha1.OperatingSystemConfig
145148
expected []*extensionsv1alpha1.OperatingSystemConfig
149+
150+
globalLastInitiationTime = &metav1.Time{Time: time.Date(2020, 12, 2, 10, 0, 0, 0, time.UTC)}
146151
)
147152

148153
computeExpectedOperatingSystemConfigs := func(sshAccessEnabled bool, workers []gardencorev1beta1.Worker, inPlaceUpdate bool) []*extensionsv1alpha1.OperatingSystemConfig {
@@ -315,15 +320,25 @@ var _ = Describe("OperatingSystemConfig", func() {
315320
oscOriginal.Spec.Units = originalUnits
316321
oscOriginal.Spec.Files = originalFiles
317322

323+
caRotationLastInitiationTime := globalLastInitiationTime
324+
if worker.Name == inPlaceWorkerName1 {
325+
caRotationLastInitiationTime = &metav1.Time{Time: time.Date(2020, 12, 2, 1, 0, 0, 0, time.UTC)}
326+
}
327+
328+
serviceAccountKeyRotationLastInitiationTime := globalLastInitiationTime
329+
if worker.Name == inPlaceWorkerName2 {
330+
serviceAccountKeyRotationLastInitiationTime = &metav1.Time{Time: time.Date(2020, 12, 2, 2, 0, 0, 0, time.UTC)}
331+
}
332+
318333
oscOriginal.Spec.InPlaceUpdates = &extensionsv1alpha1.InPlaceUpdates{
319334
OperatingSystemVersion: *worker.Machine.Image.Version,
320335
KubeletVersion: k8sVersion.String(),
321336
CredentialsRotation: &extensionsv1alpha1.CredentialsRotation{
322337
CertificateAuthorities: &extensionsv1alpha1.CARotation{
323-
LastInitiationTime: &metav1.Time{Time: time.Date(2020, 12, 2, 10, 0, 0, 0, time.UTC)},
338+
LastInitiationTime: caRotationLastInitiationTime,
324339
},
325340
ServiceAccountKey: &extensionsv1alpha1.ServiceAccountKeyRotation{
326-
LastInitiationTime: &metav1.Time{Time: time.Date(2020, 12, 2, 10, 0, 0, 0, time.UTC)},
341+
LastInitiationTime: serviceAccountKeyRotationLastInitiationTime,
327342
},
328343
},
329344
}
@@ -388,7 +403,7 @@ var _ = Describe("OperatingSystemConfig", func() {
388403
}
389404
inPlaceUpdateWorkers = []gardencorev1beta1.Worker{
390405
{
391-
Name: worker1Name + "-in-place",
406+
Name: inPlaceWorkerName1,
392407
Machine: gardencorev1beta1.Machine{
393408
Architecture: ptr.To(v1beta1constants.ArchitectureAMD64),
394409
Image: &gardencorev1beta1.ShootMachineImage{
@@ -410,7 +425,7 @@ var _ = Describe("OperatingSystemConfig", func() {
410425
UpdateStrategy: ptr.To(gardencorev1beta1.AutoInPlaceUpdate),
411426
},
412427
{
413-
Name: worker2Name + "-in-place",
428+
Name: inPlaceWorkerName2,
414429
Machine: gardencorev1beta1.Machine{
415430
Architecture: ptr.To(v1beta1constants.ArchitectureAMD64),
416431
Image: &gardencorev1beta1.ShootMachineImage{
@@ -728,10 +743,22 @@ var _ = Describe("OperatingSystemConfig", func() {
728743
},
729744
CredentialsRotationStatus: &gardencorev1beta1.ShootCredentialsRotation{
730745
CertificateAuthorities: &gardencorev1beta1.CARotation{
731-
LastInitiationTime: &metav1.Time{Time: time.Date(2020, 12, 2, 10, 0, 0, 0, time.UTC)},
746+
LastInitiationTime: globalLastInitiationTime,
747+
PendingWorkersRollouts: []gardencorev1beta1.PendingWorkersRollout{
748+
{
749+
Name: inPlaceWorkerName1,
750+
LastInitiationTime: &metav1.Time{Time: time.Date(2020, 12, 2, 1, 0, 0, 0, time.UTC)},
751+
},
752+
},
732753
},
733754
ServiceAccountKey: &gardencorev1beta1.ServiceAccountKeyRotation{
734-
LastInitiationTime: &metav1.Time{Time: time.Date(2020, 12, 2, 10, 0, 0, 0, time.UTC)},
755+
LastInitiationTime: globalLastInitiationTime,
756+
PendingWorkersRollouts: []gardencorev1beta1.PendingWorkersRollout{
757+
{
758+
Name: inPlaceWorkerName2,
759+
LastInitiationTime: &metav1.Time{Time: time.Date(2020, 12, 2, 2, 0, 0, 0, time.UTC)},
760+
},
761+
},
735762
},
736763
},
737764
}

pkg/gardenlet/controller/shoot/status/reconciler.go

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -150,19 +150,20 @@ func (r *Reconciler) Reconcile(ctx context.Context, request reconcile.Request) (
150150
}
151151
}
152152

153-
log.Info("Updating Shoot status with manual in-place pending workers", "shoot", shoot.Name, "manualInPlacePendingWorkers", sets.List(manualInPlacePendingWorkers))
153+
log.Info("Updating Shoot status with manual in-place pending workers", "manualInPlacePendingWorkers", sets.List(manualInPlacePendingWorkers))
154154
if err := r.GardenClient.Status().Patch(ctx, shoot, patch); err != nil {
155155
return reconcile.Result{}, fmt.Errorf("failed to patch Shoot status: %w", err)
156156
}
157157

158158
// The credentials rotation phases are not set to Prepared in the Shoot reconciliation flow if there are manual in-place pending workers. So we need to trigger a reconciliation after they are all updated.
159159
if noManualInPlacePendingWorkers {
160-
shootNeedsReconcile = (v1beta1helper.GetShootCARotationPhase(shoot.Status.Credentials) == gardencorev1beta1.RotationPreparing || v1beta1helper.GetShootServiceAccountKeyRotationPhase(shoot.Status.Credentials) == gardencorev1beta1.RotationPreparing)
160+
shootNeedsReconcile = needsReconcile(shoot)
161161
}
162162

163163
if shootNeedsReconcile || (noInPlacePendingWorkers && kubernetesutils.HasMetaDataAnnotation(shoot, v1beta1constants.GardenerOperation, v1beta1constants.ShootOperationForceInPlaceUpdate)) {
164164
patch := client.MergeFromWithOptions(shoot.DeepCopy(), client.MergeFromWithOptimisticLock{})
165165
if shootNeedsReconcile {
166+
log.Info("Triggering a Shoot reconciliation after credential rotations for manual in-place workers are prepared")
166167
metav1.SetMetaDataAnnotation(&shoot.ObjectMeta, v1beta1constants.GardenerOperation, v1beta1constants.GardenerOperationReconcile)
167168
} else {
168169
delete(shoot.Annotations, v1beta1constants.GardenerOperation)
@@ -175,3 +176,19 @@ func (r *Reconciler) Reconcile(ctx context.Context, request reconcile.Request) (
175176

176177
return reconcile.Result{}, nil
177178
}
179+
180+
func needsReconcile(shoot *gardencorev1beta1.Shoot) bool {
181+
caRotationPhase := v1beta1helper.GetShootCARotationPhase(shoot.Status.Credentials)
182+
serviceAccountKeyRotationPhase := v1beta1helper.GetShootServiceAccountKeyRotationPhase(shoot.Status.Credentials)
183+
184+
if caRotationPhase == gardencorev1beta1.RotationPreparing || serviceAccountKeyRotationPhase == gardencorev1beta1.RotationPreparing {
185+
return true
186+
}
187+
188+
// If there are no pending workers rollouts for either CA or ServiceAccountKey rotation, then we need to reconcile the Shoot.
189+
if caRotationPhase == gardencorev1beta1.RotationWaitingForWorkersRollout && len(shoot.Status.Credentials.Rotation.CertificateAuthorities.PendingWorkersRollouts) == 0 {
190+
return true
191+
}
192+
193+
return serviceAccountKeyRotationPhase == gardencorev1beta1.RotationWaitingForWorkersRollout && len(shoot.Status.Credentials.Rotation.ServiceAccountKey.PendingWorkersRollouts) == 0
194+
}

test/e2e/gardener/shoot/create_rotate_delete.go

Lines changed: 50 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,11 @@ func testCredentialRotation(s *ShootContext, shootVerifiers, utilsverifiers rota
7575
}
7676

7777
ItShouldWaitForShootToBeReconciledAndHealthy(s)
78+
79+
if inPlaceUpdate {
80+
inplace.ItShouldVerifyInPlaceUpdateCompletion(s.GardenClient, s.Shoot)
81+
}
82+
7883
shootVerifiers.AfterPrepared(context.TODO())
7984
for _, k := range utilsverifiers {
8085
It(fmt.Sprintf("Verify after prepared for %T", k), func(ctx SpecContext) {
@@ -122,15 +127,15 @@ func testCredentialRotationComplete(s *ShootContext, shootVerifiers, utilsverifi
122127
}
123128
}
124129

125-
func testCredentialRotationWithoutWorkersRollout(s *ShootContext, shootVerifiers rotationutils.Verifiers, utilsverifiers rotationutils.Verifiers) {
130+
func testCredentialRotationWithoutWorkersRollout(s *ShootContext, shootVerifiers rotationutils.Verifiers, utilsverifiers rotationutils.Verifiers, inPlaceUpdate bool) {
126131
shootVerifiers.Before(context.TODO())
127132
for _, k := range utilsverifiers {
128133
It(fmt.Sprintf("Verify before for %T", k), func(ctx SpecContext) {
129134
k.Before(ctx)
130135
}, SpecTimeout(5*time.Minute))
131136
}
132137

133-
nodesOfInPlaceWorkersBeforeTest := inplace.ItShouldFindNodesOfInPlaceWorkers(s)
138+
machinePodNamesBeforeTest := ItShouldFindAllMachinePodsBefore(s)
134139

135140
ItShouldAnnotateShoot(s, map[string]string{
136141
v1beta1constants.GardenerOperation: v1beta1constants.OperationRotateCredentialsStartWithoutWorkersRollout,
@@ -154,8 +159,7 @@ func testCredentialRotationWithoutWorkersRollout(s *ShootContext, shootVerifiers
154159
}).Should(Succeed())
155160
}, SpecTimeout(time.Minute))
156161

157-
nodesOfInPlaceWorkersAfterTest := inplace.ItShouldFindNodesOfInPlaceWorkers(s)
158-
Expect(nodesOfInPlaceWorkersBeforeTest.UnsortedList()).To(ConsistOf(nodesOfInPlaceWorkersAfterTest.UnsortedList()))
162+
ItShouldCompareMachinePodNamesAfter(s, machinePodNamesBeforeTest)
159163

160164
It("Ensure all worker pools are marked as 'pending for roll out'", func() {
161165
for _, worker := range s.Shoot.Spec.Provider.Workers {
@@ -207,8 +211,17 @@ func testCredentialRotationWithoutWorkersRollout(s *ShootContext, shootVerifiers
207211
})).Should(Succeed())
208212
}, SpecTimeout(time.Minute))
209213

214+
// In case of rotation without workers rollout, the in-place update status in only populated when the rollout for that worker pool is triggered
215+
if inPlaceUpdate {
216+
inplace.ItShouldVerifyInPlaceUpdateStart(s.GardenClient, s.Shoot, true, true)
217+
}
218+
210219
ItShouldWaitForShootToBeReconciledAndHealthy(s)
211220

221+
if inPlaceUpdate {
222+
inplace.ItShouldVerifyInPlaceUpdateCompletion(s.GardenClient, s.Shoot)
223+
}
224+
212225
It("Credential rotation in status prepared", func() {
213226
Expect(s.Shoot.Status.Credentials.Rotation.CertificateAuthorities.Phase).To(Equal(gardencorev1beta1.RotationPrepared))
214227
Expect(s.Shoot.Status.Credentials.Rotation.ServiceAccountKey.Phase).To(Equal(gardencorev1beta1.RotationPrepared))
@@ -323,7 +336,7 @@ var _ = Describe("Shoot Tests", Label("Shoot", "default"), func() {
323336
// test rotation for every rotation type
324337
testCredentialRotation(s, shootVerifiers, utilsVerifiers, v1beta1constants.OperationRotateCredentialsStart, v1beta1constants.OperationRotateCredentialsComplete, inPlaceUpdate)
325338
} else {
326-
testCredentialRotationWithoutWorkersRollout(s, shootVerifiers, utilsVerifiers)
339+
testCredentialRotationWithoutWorkersRollout(s, shootVerifiers, utilsVerifiers, inPlaceUpdate)
327340
}
328341

329342
if !v1beta1helper.IsWorkerless(s.Shoot) {
@@ -334,7 +347,6 @@ var _ = Describe("Shoot Tests", Label("Shoot", "default"), func() {
334347
if inPlaceUpdate {
335348
nodesOfInPlaceWorkersAfterTest := inplace.ItShouldFindNodesOfInPlaceWorkers(s)
336349
Expect(nodesOfInPlaceWorkersBeforeTest.UnsortedList()).To(ConsistOf(nodesOfInPlaceWorkersAfterTest.UnsortedList()))
337-
inplace.ItShouldVerifyInPlaceUpdateCompletion(s.GardenClient, s.Shoot)
338350
}
339351
}
340352

@@ -391,6 +403,38 @@ var _ = Describe("Shoot Tests", Label("Shoot", "default"), func() {
391403
test(s, true, false)
392404
})
393405

406+
Context("without workers rollout, in-place update strategy", Label("without-workers-rollout", "in-place"), Ordered, func() {
407+
var s *ShootContext
408+
BeforeTestSetup(func() {
409+
shoot := DefaultShoot("e2e-rot-nr-ip")
410+
411+
worker1 := DefaultWorker("auto", ptr.To(gardencorev1beta1.AutoInPlaceUpdate))
412+
worker1.Minimum = 2
413+
worker1.Maximum = 2
414+
worker1.MaxUnavailable = ptr.To(intstr.FromInt(1))
415+
worker1.MaxSurge = ptr.To(intstr.FromInt(0))
416+
417+
worker2 := DefaultWorker("manual", ptr.To(gardencorev1beta1.ManualInPlaceUpdate))
418+
419+
// Add a third worker pool when worker rollout should not be performed such that we can make proper
420+
// assertions of the shoot status
421+
worker3 := DefaultWorker("rolling", nil)
422+
423+
shoot.Spec.Provider.Workers = []gardencorev1beta1.Worker{worker1, worker2, worker3}
424+
425+
s = NewTestContext().ForShoot(shoot)
426+
})
427+
428+
// Skip the test for IPv6 single-stack Shoot as it is extremely flaky (success rate < 30%).
429+
//
430+
// TODO(shafeeqes, acumino, ary1992): Debug and fix the flaky test for ipv6.
431+
if os.Getenv("IPFAMILY") == "ipv6" {
432+
s.Log.Info("Skip the flaky credentials rotation with in-place update strategy e2e test for ipv6")
433+
return
434+
}
435+
436+
test(s, true, true)
437+
})
394438
})
395439

396440
Context("Workerless Shoot", Label("workerless"), Ordered, func() {

test/e2e/gardener/shoot/shoot.go

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import (
1313
corev1 "k8s.io/api/core/v1"
1414
apierrors "k8s.io/apimachinery/pkg/api/errors"
1515
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
16+
"k8s.io/apimachinery/pkg/util/sets"
1617
"k8s.io/utils/ptr"
1718
"sigs.k8s.io/controller-runtime/pkg/client"
1819

@@ -261,3 +262,44 @@ func ItShouldAnnotateShoot(s *ShootContext, annotations map[string]string) {
261262
}).Should(Succeed())
262263
}, SpecTimeout(time.Minute))
263264
}
265+
266+
// ItShouldFindAllMachinePodsBefore finds all machine pods before running the required tests and returns their names.
267+
func ItShouldFindAllMachinePodsBefore(s *ShootContext) sets.Set[string] {
268+
GinkgoHelper()
269+
270+
machinePodNamesBeforeTest := sets.New[string]()
271+
272+
It("Find all machine pods to ensure later that they weren't rolled out", func(ctx SpecContext) {
273+
beforeStartMachinePodList := &corev1.PodList{}
274+
Eventually(ctx, s.SeedKomega.List(beforeStartMachinePodList, client.InNamespace(s.Shoot.Status.TechnicalID), client.MatchingLabels{
275+
"app": "machine",
276+
"machine-provider": "local",
277+
})).Should(Succeed())
278+
279+
for _, item := range beforeStartMachinePodList.Items {
280+
machinePodNamesBeforeTest.Insert(item.Name)
281+
}
282+
}, SpecTimeout(time.Minute))
283+
284+
return machinePodNamesBeforeTest
285+
}
286+
287+
// ItShouldCompareMachinePodNamesAfter compares the machine pod names before and after running the required tests.
288+
func ItShouldCompareMachinePodNamesAfter(s *ShootContext, machinePodNamesBeforeTest sets.Set[string]) {
289+
GinkgoHelper()
290+
291+
It("Compare machine pod names", func(ctx SpecContext) {
292+
machinePodListAfterTest := &corev1.PodList{}
293+
Eventually(ctx, s.SeedKomega.List(machinePodListAfterTest, client.InNamespace(s.Shoot.Status.TechnicalID), client.MatchingLabels{
294+
"app": "machine",
295+
"machine-provider": "local",
296+
})).Should(Succeed())
297+
298+
machinePodNamesAfterTest := sets.New[string]()
299+
for _, item := range machinePodListAfterTest.Items {
300+
machinePodNamesAfterTest.Insert(item.Name)
301+
}
302+
303+
Expect(machinePodNamesBeforeTest.UnsortedList()).To(ConsistOf(machinePodNamesAfterTest.UnsortedList()))
304+
}, SpecTimeout(time.Minute))
305+
}

0 commit comments

Comments
 (0)