Skip to content

Commit

Permalink
Merge pull request #417 from akgalwas/fix-update-problem
Browse files Browse the repository at this point in the history
Fixed problem with skipping update operations
  • Loading branch information
kyma-bot authored Oct 16, 2024
2 parents d1bcfb5 + b1d0280 commit 1f97066
Show file tree
Hide file tree
Showing 6 changed files with 84 additions and 26 deletions.
8 changes: 6 additions & 2 deletions internal/controller/runtime/fsm/runtime_fsm_patch_shoot.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
imv1 "github.com/kyma-project/infrastructure-manager/api/v1"
"github.com/kyma-project/infrastructure-manager/internal/config"
gardener_shoot "github.com/kyma-project/infrastructure-manager/internal/gardener/shoot"
k8serrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/utils/ptr"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
Expand All @@ -29,6 +30,11 @@ func sFnPatchExistingShoot(ctx context.Context, m *fsm, s *systemState) (stateFn
})

if err != nil {
if k8serrors.IsConflict(err) {
m.log.Info("Gardener shoot for runtime is outdated, retrying", "Name", s.shoot.Name, "Namespace", s.shoot.Namespace)
return updateStatusAndRequeueAfter(gardenerRequeueDuration)
}

m.log.Error(err, "Failed to patch shoot object, exiting with no retry")
return updateStatePendingWithErrorAndStop(&s.instance, imv1.ConditionTypeRuntimeProvisioned, imv1.ConditionReasonProcessingErr, "Shoot patch error")
}
Expand All @@ -40,8 +46,6 @@ func sFnPatchExistingShoot(ctx context.Context, m *fsm, s *systemState) (stateFn

m.log.Info("Gardener shoot for runtime patched successfully", "Name", s.shoot.Name, "Namespace", s.shoot.Namespace)

s.shoot = updatedShoot.DeepCopy()

s.instance.UpdateStatePending(
imv1.ConditionTypeRuntimeProvisioned,
imv1.ConditionReasonProcessing,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@ package fsm
import (
"context"
"fmt"
"strconv"

gardener "github.com/gardener/gardener/pkg/apis/core/v1beta1"
imv1 "github.com/kyma-project/infrastructure-manager/api/v1"
"github.com/kyma-project/infrastructure-manager/internal/gardener/shoot/extender"
ctrl "sigs.k8s.io/controller-runtime"
)

Expand All @@ -27,8 +29,14 @@ func sFnSelectShootProcessing(_ context.Context, m *fsm, s *systemState) (stateF
return updateStatusAndRequeueAfter(gardenerRequeueDuration)
}

if s.instance.Status.State == imv1.RuntimeStateReady && lastOperation.State == gardener.LastOperationStateSucceeded {
// only allow to patch if full previous cycle was completed
patchShoot, err := shouldPatchShoot(&s.instance, s.shoot)
if err != nil {
msg := fmt.Sprintf("Failed to get applied generation for shoot: %s, scheduling for retry", s.shoot.Name)
m.log.Error(err, msg)
return updateStatusAndStop()
}

if patchShoot {
m.log.Info("Gardener shoot already exists, updating")
return switchState(sFnPatchExistingShoot)
}
Expand All @@ -44,3 +52,19 @@ func sFnSelectShootProcessing(_ context.Context, m *fsm, s *systemState) (stateF
m.log.Info("Unknown shoot operation type, exiting with no retry")
return stop()
}

func shouldPatchShoot(runtime *imv1.Runtime, shoot *gardener.Shoot) (bool, error) {
runtimeGeneration := runtime.GetGeneration()
appliedGenerationString, found := shoot.GetAnnotations()[extender.ShootRuntimeGenerationAnnotation]

if !found {
return true, nil
}

appliedGeneration, err := strconv.ParseInt(appliedGenerationString, 10, 64)
if err != nil {
return false, err
}

return appliedGeneration < runtimeGeneration, nil
}
4 changes: 2 additions & 2 deletions internal/controller/runtime/runtime_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,13 @@ package runtime

import (
"context"
k8serrors "k8s.io/apimachinery/pkg/api/errors"
"time"

gardener "github.com/gardener/gardener/pkg/apis/core/v1beta1"
imv1 "github.com/kyma-project/infrastructure-manager/api/v1"
. "github.com/onsi/ginkgo/v2" //nolint:revive
. "github.com/onsi/gomega" //nolint:revive
k8serrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
"k8s.io/utils/ptr"
Expand Down Expand Up @@ -178,7 +178,6 @@ var _ = Describe("Runtime Controller", func() {
Expect(customTracker.IsSequenceFullyUsed()).To(BeTrue())

// next test will be for runtime deletion

By("Process deleting of Runtime CR and delete GardenerCluster CR and Shoot")
setupGardenerTestClientForDelete()

Expand Down Expand Up @@ -253,6 +252,7 @@ func CreateRuntimeStub(resourceName string) *imv1.Runtime {
imv1.LabelKymaSubaccountID: "c5ad84ae-3d1b-4592-bee1-f022661f7b30",
imv1.LabelControlledByProvisioner: "false",
},
Generation: 1,
},
Spec: imv1.RuntimeSpec{
Shoot: imv1.RuntimeShoot{
Expand Down
45 changes: 33 additions & 12 deletions internal/controller/runtime/suite_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,10 @@ package runtime
import (
"context"
"encoding/json"
"github.com/pkg/errors"
"k8s.io/apimachinery/pkg/types"
"path/filepath"
"sigs.k8s.io/controller-runtime/pkg/client/interceptor"
"testing"
"time"

Expand Down Expand Up @@ -170,7 +173,20 @@ func setupGardenerClientWithSequence(shoots []*gardener_api.Shoot, seeds []*gard

tracker := clienttesting.NewObjectTracker(clientScheme, serializer.NewCodecFactory(clientScheme).UniversalDecoder())
customTracker = NewCustomTracker(tracker, shoots, seeds)
gardenerTestClient = fake.NewClientBuilder().WithScheme(clientScheme).WithObjectTracker(customTracker).Build()
gardenerTestClient = fake.NewClientBuilder().WithScheme(clientScheme).WithObjectTracker(customTracker).
WithInterceptorFuncs(interceptor.Funcs{Patch: func(ctx context.Context, clnt client.WithWatch, obj client.Object, patch client.Patch, opts ...client.PatchOption) error {
// Apply patches are supposed to upsert, but fake client fails if the object doesn't exist,
// Update the generation to simulate the object being updated using interceptor function.
if patch.Type() != types.ApplyPatchType {
return clnt.Patch(ctx, obj, patch, opts...)
}
shoot, ok := obj.(*gardener_api.Shoot)
if !ok {
return errors.New("failed to cast object to shoot")
}
shoot.Generation++
return nil
}}).Build()
runtimeReconciler.UpdateShootClient(gardenerTestClient)
}

Expand Down Expand Up @@ -226,22 +242,27 @@ func fixShootsSequenceForProvisioning(shoot *gardener_api.Shoot) []*gardener_api
}

func fixShootsSequenceForUpdate(shoot *gardener_api.Shoot) []*gardener_api.Shoot {
pendingShoot := shoot.DeepCopy()

addAuditLogConfigToShoot(pendingShoot)
existingShoot := shoot.DeepCopy()
existingShoot.Spec.SeedName = ptr.To("test-seed")

pendingShoot.Spec.DNS = &gardener_api.DNS{
Domain: ptr.To("test.domain"),
}

pendingShoot.Status = gardener_api.ShootStatus{
existingShoot.Status = gardener_api.ShootStatus{
LastOperation: &gardener_api.LastOperation{
Type: gardener_api.LastOperationTypeReconcile,
State: gardener_api.LastOperationStatePending,
State: gardener_api.LastOperationStateSucceeded,
},
}

pendingShoot.Spec.SeedName = ptr.To("test-seed")
existingShoot.Spec.DNS = &gardener_api.DNS{
Domain: ptr.To("test.domain"),
}

addAuditLogConfigToShoot(existingShoot)

pendingShoot := existingShoot.DeepCopy()

pendingShoot.ObjectMeta.Annotations["infrastructuremanager.kyma-project.io/runtime-generation"] = "2"

pendingShoot.Status.LastOperation.State = gardener_api.LastOperationStatePending

processingShoot := pendingShoot.DeepCopy()

Expand All @@ -253,7 +274,7 @@ func fixShootsSequenceForUpdate(shoot *gardener_api.Shoot) []*gardener_api.Shoot

// processedShoot := processingShoot.DeepCopy() // will add specific data later

return []*gardener_api.Shoot{pendingShoot, processingShoot, readyShoot, readyShoot}
return []*gardener_api.Shoot{existingShoot, pendingShoot, processingShoot, readyShoot, readyShoot}
}

func fixShootsSequenceForDelete(shoot *gardener_api.Shoot) []*gardener_api.Shoot {
Expand Down
6 changes: 5 additions & 1 deletion internal/gardener/shoot/extender/annotations.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package extender

import (
"fmt"

gardener "github.com/gardener/gardener/pkg/apis/core/v1beta1"
imv1 "github.com/kyma-project/infrastructure-manager/api/v1"
)
Expand All @@ -11,6 +13,7 @@ import (
//- support.gardener.cloud/eu-access-for-cluster-nodes

const (
ShootRuntimeGenerationAnnotation = "infrastructuremanager.kyma-project.io/runtime-generation"
ShootRuntimeIDAnnotation = "infrastructuremanager.kyma-project.io/runtime-id"
ShootLicenceTypeAnnotation = "infrastructuremanager.kyma-project.io/licence-type"
RuntimeIDLabel = "kyma-project.io/runtime-id"
Expand All @@ -25,7 +28,8 @@ func ExtendWithAnnotations(runtime imv1.Runtime, shoot *gardener.Shoot) error {

func getAnnotations(runtime imv1.Runtime) map[string]string {
annotations := map[string]string{
ShootRuntimeIDAnnotation: runtime.Labels[RuntimeIDLabel],
ShootRuntimeIDAnnotation: runtime.Labels[RuntimeIDLabel],
ShootRuntimeGenerationAnnotation: fmt.Sprintf("%v", runtime.Generation),
}

if runtime.Spec.Shoot.LicenceType != nil && *runtime.Spec.Shoot.LicenceType != "" {
Expand Down
19 changes: 12 additions & 7 deletions internal/gardener/shoot/extender/annotations_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,12 @@ func TestAnnotationsExtender(t *testing.T) {
Labels: map[string]string{
"kyma-project.io/runtime-id": "runtime-id",
},
Generation: 100,
},
},
expectedAnnotations: map[string]string{
"infrastructuremanager.kyma-project.io/runtime-id": "runtime-id"},
"infrastructuremanager.kyma-project.io/runtime-id": "runtime-id",
"infrastructuremanager.kyma-project.io/runtime-generation": "100"},
},
{
name: "Create licence type annotation",
Expand All @@ -48,8 +50,9 @@ func TestAnnotationsExtender(t *testing.T) {
},
},
expectedAnnotations: map[string]string{
"infrastructuremanager.kyma-project.io/runtime-id": "runtime-id",
"infrastructuremanager.kyma-project.io/licence-type": "licence"},
"infrastructuremanager.kyma-project.io/runtime-id": "runtime-id",
"infrastructuremanager.kyma-project.io/licence-type": "licence",
"infrastructuremanager.kyma-project.io/runtime-generation": "0"},
},
{
name: "Create restricted EU access annotation for cf-eu11 region",
Expand All @@ -68,8 +71,9 @@ func TestAnnotationsExtender(t *testing.T) {
},
},
expectedAnnotations: map[string]string{
"infrastructuremanager.kyma-project.io/runtime-id": "runtime-id",
"support.gardener.cloud/eu-access-for-cluster-nodes": "true"},
"infrastructuremanager.kyma-project.io/runtime-id": "runtime-id",
"support.gardener.cloud/eu-access-for-cluster-nodes": "true",
"infrastructuremanager.kyma-project.io/runtime-generation": "0"},
},
{
name: "Create restricted EU access annotation for cf-ch20 region",
Expand All @@ -88,8 +92,9 @@ func TestAnnotationsExtender(t *testing.T) {
},
},
expectedAnnotations: map[string]string{
"infrastructuremanager.kyma-project.io/runtime-id": "runtime-id",
"support.gardener.cloud/eu-access-for-cluster-nodes": "true"},
"infrastructuremanager.kyma-project.io/runtime-id": "runtime-id",
"support.gardener.cloud/eu-access-for-cluster-nodes": "true",
"infrastructuremanager.kyma-project.io/runtime-generation": "0"},
},
} {
// given
Expand Down

0 comments on commit 1f97066

Please sign in to comment.