From 5e47798f44b66ba0a1a3dd4893198d401c32f988 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Du=C5=A1an?= Date: Wed, 18 Dec 2024 15:49:28 +0100 Subject: [PATCH 1/6] feat(GcpRedisInstance): make redis upgradable --- .../v1beta1/redisinstance_types.go | 1 - .../v1beta1/gcpredisinstance_types.go | 1 - ...ontrol.kyma-project.io_redisinstances.yaml | 3 - ...ces.kyma-project.io_gcpredisinstances.yaml | 5 +- ...ontrol.kyma-project.io_redisinstances.yaml | 3 - ...ces.kyma-project.io_gcpredisinstances.yaml | 8 ++- config/patchAfterMakeManifests.sh | 2 +- .../gcp/mock/memoryStoreClientFake.go | 19 ++++++ .../redisinstance/client/memorystoreClient.go | 25 ++++++++ pkg/kcp/provider/gcp/redisinstance/new.go | 1 + pkg/kcp/provider/gcp/redisinstance/state.go | 4 ++ .../gcp/redisinstance/upgradeRedis.go | 64 +++++++++++++++++++ 12 files changed, 120 insertions(+), 16 deletions(-) create mode 100644 pkg/kcp/provider/gcp/redisinstance/upgradeRedis.go diff --git a/api/cloud-control/v1beta1/redisinstance_types.go b/api/cloud-control/v1beta1/redisinstance_types.go index a2d3c568d..d52c99a7a 100644 --- a/api/cloud-control/v1beta1/redisinstance_types.go +++ b/api/cloud-control/v1beta1/redisinstance_types.go @@ -157,7 +157,6 @@ type RedisInstanceGcp struct { // The version of Redis software. // +optional // +kubebuilder:default=REDIS_7_0 - // +kubebuilder:validation:XValidation:rule=(self == oldSelf), message="RedisVersion is immutable." // +kubebuilder:validation:Enum=REDIS_7_2;REDIS_7_0;REDIS_6_X RedisVersion string `json:"redisVersion"` diff --git a/api/cloud-resources/v1beta1/gcpredisinstance_types.go b/api/cloud-resources/v1beta1/gcpredisinstance_types.go index 659d7308a..954c71889 100644 --- a/api/cloud-resources/v1beta1/gcpredisinstance_types.go +++ b/api/cloud-resources/v1beta1/gcpredisinstance_types.go @@ -87,7 +87,6 @@ type GcpRedisInstanceSpec struct { // The version of Redis software. // +optional // +kubebuilder:default=REDIS_7_0 - // +kubebuilder:validation:XValidation:rule=(self == oldSelf), message="RedisVersion is immutable." // +kubebuilder:validation:Enum=REDIS_7_2;REDIS_7_0;REDIS_6_X RedisVersion string `json:"redisVersion"` diff --git a/config/crd/bases/cloud-control.kyma-project.io_redisinstances.yaml b/config/crd/bases/cloud-control.kyma-project.io_redisinstances.yaml index 3d2607a59..b15cd310f 100644 --- a/config/crd/bases/cloud-control.kyma-project.io_redisinstances.yaml +++ b/config/crd/bases/cloud-control.kyma-project.io_redisinstances.yaml @@ -199,9 +199,6 @@ spec: - REDIS_7_0 - REDIS_6_X type: string - x-kubernetes-validations: - - message: RedisVersion is immutable. - rule: (self == oldSelf) replicaCount: default: 0 format: int32 diff --git a/config/crd/bases/cloud-resources.kyma-project.io_gcpredisinstances.yaml b/config/crd/bases/cloud-resources.kyma-project.io_gcpredisinstances.yaml index dc5f5a8c9..00d82b7f0 100644 --- a/config/crd/bases/cloud-resources.kyma-project.io_gcpredisinstances.yaml +++ b/config/crd/bases/cloud-resources.kyma-project.io_gcpredisinstances.yaml @@ -4,7 +4,7 @@ kind: CustomResourceDefinition metadata: annotations: controller-gen.kubebuilder.io/version: v0.16.5 - cloud-resources.kyma-project.io/version: v0.0.18 + cloud-resources.kyma-project.io/version: v0.0.19 name: gcpredisinstances.cloud-resources.kyma-project.io spec: group: cloud-resources.kyma-project.io @@ -153,9 +153,6 @@ spec: - REDIS_7_0 - REDIS_6_X type: string - x-kubernetes-validations: - - message: RedisVersion is immutable. - rule: (self == oldSelf) required: - redisTier type: object diff --git a/config/dist/kcp/crd/bases/cloud-control.kyma-project.io_redisinstances.yaml b/config/dist/kcp/crd/bases/cloud-control.kyma-project.io_redisinstances.yaml index 3d2607a59..b15cd310f 100644 --- a/config/dist/kcp/crd/bases/cloud-control.kyma-project.io_redisinstances.yaml +++ b/config/dist/kcp/crd/bases/cloud-control.kyma-project.io_redisinstances.yaml @@ -199,9 +199,6 @@ spec: - REDIS_7_0 - REDIS_6_X type: string - x-kubernetes-validations: - - message: RedisVersion is immutable. - rule: (self == oldSelf) replicaCount: default: 0 format: int32 diff --git a/config/dist/skr/crd/bases/providers/gcp/cloud-resources.kyma-project.io_gcpredisinstances.yaml b/config/dist/skr/crd/bases/providers/gcp/cloud-resources.kyma-project.io_gcpredisinstances.yaml index dc5f5a8c9..4e8362cab 100644 --- a/config/dist/skr/crd/bases/providers/gcp/cloud-resources.kyma-project.io_gcpredisinstances.yaml +++ b/config/dist/skr/crd/bases/providers/gcp/cloud-resources.kyma-project.io_gcpredisinstances.yaml @@ -3,8 +3,13 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: +<<<<<<< HEAD controller-gen.kubebuilder.io/version: v0.16.5 cloud-resources.kyma-project.io/version: v0.0.18 +======= + controller-gen.kubebuilder.io/version: v0.15.0 + cloud-resources.kyma-project.io/version: v0.0.19 +>>>>>>> 7c8cbb35 (feat(GcpRedisInstance): make redis upgradable) name: gcpredisinstances.cloud-resources.kyma-project.io spec: group: cloud-resources.kyma-project.io @@ -153,9 +158,6 @@ spec: - REDIS_7_0 - REDIS_6_X type: string - x-kubernetes-validations: - - message: RedisVersion is immutable. - rule: (self == oldSelf) required: - redisTier type: object diff --git a/config/patchAfterMakeManifests.sh b/config/patchAfterMakeManifests.sh index b0f75dbc7..d60cef126 100755 --- a/config/patchAfterMakeManifests.sh +++ b/config/patchAfterMakeManifests.sh @@ -10,7 +10,7 @@ yq -i '.metadata.annotations."cloud-resources.kyma-project.io/version" = "v0.0.3 yq -i '.metadata.annotations."cloud-resources.kyma-project.io/version" = "v0.0.3"' $SCRIPT_DIR/crd/bases/cloud-resources.kyma-project.io_awsnfsvolumebackups.yaml yq -i '.metadata.annotations."cloud-resources.kyma-project.io/version" = "v0.0.16"' $SCRIPT_DIR/crd/bases/cloud-resources.kyma-project.io_awsredisinstances.yaml yq -i '.metadata.annotations."cloud-resources.kyma-project.io/version" = "v0.0.8"' $SCRIPT_DIR/crd/bases/cloud-resources.kyma-project.io_gcpnfsvolumes.yaml -yq -i '.metadata.annotations."cloud-resources.kyma-project.io/version" = "v0.0.18"' $SCRIPT_DIR/crd/bases/cloud-resources.kyma-project.io_gcpredisinstances.yaml +yq -i '.metadata.annotations."cloud-resources.kyma-project.io/version" = "v0.0.19"' $SCRIPT_DIR/crd/bases/cloud-resources.kyma-project.io_gcpredisinstances.yaml yq -i '.metadata.annotations."cloud-resources.kyma-project.io/version" = "v0.0.2"' $SCRIPT_DIR/crd/bases/cloud-resources.kyma-project.io_azurevpcpeerings.yaml yq -i '.metadata.annotations."cloud-resources.kyma-project.io/version" = "v0.0.54"' $SCRIPT_DIR/crd/bases/cloud-resources.kyma-project.io_azureredisinstances.yaml yq -i '.metadata.annotations."cloud-resources.kyma-project.io/version" = "v0.0.4"' $SCRIPT_DIR/crd/bases/cloud-resources.kyma-project.io_gcpnfsvolumebackups.yaml diff --git a/pkg/kcp/provider/gcp/mock/memoryStoreClientFake.go b/pkg/kcp/provider/gcp/mock/memoryStoreClientFake.go index 117ed491d..f27f7029f 100644 --- a/pkg/kcp/provider/gcp/mock/memoryStoreClientFake.go +++ b/pkg/kcp/provider/gcp/mock/memoryStoreClientFake.go @@ -54,6 +54,7 @@ func (memoryStoreClientFake *memoryStoreClientFake) CreateRedisInstance(ctx cont RedisConfigs: options.RedisConfigs, MaintenancePolicy: memoryStoreClient.ToMaintenancePolicy(options.MaintenancePolicy), AuthEnabled: options.AuthEnabled, + RedisVersion: options.RedisVersion, } memoryStoreClientFake.redisInstances[name] = redisInstance @@ -80,6 +81,24 @@ func (memoryStoreClientFake *memoryStoreClientFake) UpdateRedisInstance(ctx cont return nil } +func (memoryStoreClientFake *memoryStoreClientFake) UpgradeRedisInstance(ctx context.Context, projectId, locationId, instanceId, redisVersion string) error { + if isContextCanceled(ctx) { + return context.Canceled + } + + memoryStoreClientFake.mutex.Lock() + defer memoryStoreClientFake.mutex.Unlock() + + name := memoryStoreClient.GetGcpMemoryStoreRedisName(projectId, locationId, instanceId) + if instance, ok := memoryStoreClientFake.redisInstances[name]; ok { + instance.State = redispb.Instance_UPDATING + + instance.RedisVersion = redisVersion + } + + return nil +} + func (memoryStoreClientFake *memoryStoreClientFake) DeleteRedisInstance(ctx context.Context, projectId string, locationId string, instanceId string) error { if isContextCanceled(ctx) { return context.Canceled diff --git a/pkg/kcp/provider/gcp/redisinstance/client/memorystoreClient.go b/pkg/kcp/provider/gcp/redisinstance/client/memorystoreClient.go index 6471fa052..0aee73791 100644 --- a/pkg/kcp/provider/gcp/redisinstance/client/memorystoreClient.go +++ b/pkg/kcp/provider/gcp/redisinstance/client/memorystoreClient.go @@ -32,6 +32,7 @@ type MemorystoreClient interface { CreateRedisInstance(ctx context.Context, projectId, locationId, instanceId string, options CreateRedisInstanceOptions) error GetRedisInstance(ctx context.Context, projectId, locationId, instanceId string) (*redispb.Instance, *redispb.InstanceAuthString, error) UpdateRedisInstance(ctx context.Context, redisInstance *redispb.Instance, updateMask []string) error + UpgradeRedisInstance(ctx context.Context, projectId, locationId, instanceId, redisVersion string) error DeleteRedisInstance(ctx context.Context, projectId, locationId, instanceId string) error } @@ -155,6 +156,30 @@ func (memorystoreClient *memorystoreClient) GetRedisInstance(ctx context.Context return instanceResponse, authResponse, nil } +func (memorystoreClient *memorystoreClient) UpgradeRedisInstance(ctx context.Context, projectId, locationId, instanceId, redisVersion string) error { + redisClient, redisClientErr := redis.NewCloudRedisClient(ctx, option.WithCredentialsFile(memorystoreClient.saJsonKeyPath)) + if redisClientErr != nil { + return redisClientErr + } + defer redisClient.Close() + + name := GetGcpMemoryStoreRedisName(projectId, locationId, instanceId) + req := &redispb.UpgradeInstanceRequest{ + Name: name, + RedisVersion: redisVersion, + } + + _, err := redisClient.UpgradeInstance(ctx, req) + + if err != nil { + logger := composed.LoggerFromCtx(ctx) + logger.Error(err, "UpgradeRedisInstance", "projectId", projectId, "locationId", locationId, "instanceId", instanceId) + return err + } + + return nil +} + func (memorystoreClient *memorystoreClient) DeleteRedisInstance(ctx context.Context, projectId string, locationId string, instanceId string) error { redisClient, redisClientErr := redis.NewCloudRedisClient(ctx, option.WithCredentialsFile(memorystoreClient.saJsonKeyPath)) if redisClientErr != nil { diff --git a/pkg/kcp/provider/gcp/redisinstance/new.go b/pkg/kcp/provider/gcp/redisinstance/new.go index d101e44c6..8a39b1ab6 100644 --- a/pkg/kcp/provider/gcp/redisinstance/new.go +++ b/pkg/kcp/provider/gcp/redisinstance/new.go @@ -50,6 +50,7 @@ func New(stateFactory StateFactory) composed.Action { modifyMaintenancePolicy, modifyAuthEnabled, updateRedis, + upgradeRedis, updateStatus, ), composed.ComposeActions( diff --git a/pkg/kcp/provider/gcp/redisinstance/state.go b/pkg/kcp/provider/gcp/redisinstance/state.go index 5f731415a..a4c13be44 100644 --- a/pkg/kcp/provider/gcp/redisinstance/state.go +++ b/pkg/kcp/provider/gcp/redisinstance/state.go @@ -66,6 +66,10 @@ func (s *State) ShouldUpdateRedisInstance() bool { return len(s.updateMask) > 0 } +func (s *State) ShouldUpgradeRedisInstance() bool { + return s.gcpRedisInstance.RedisVersion != s.ObjAsRedisInstance().Spec.Instance.Gcp.RedisVersion +} + func (s *State) UpdateRedisConfigs(redisConfigs map[string]string) { s.updateMask = append(s.updateMask, "redis_configs") // it is 'redis_configs', GCP API says 'redisConfig', but it is wrongly documented s.gcpRedisInstance.RedisConfigs = redisConfigs diff --git a/pkg/kcp/provider/gcp/redisinstance/upgradeRedis.go b/pkg/kcp/provider/gcp/redisinstance/upgradeRedis.go new file mode 100644 index 000000000..c96c33217 --- /dev/null +++ b/pkg/kcp/provider/gcp/redisinstance/upgradeRedis.go @@ -0,0 +1,64 @@ +package redisinstance + +import ( + "context" + + cloudcontrolv1beta1 "github.com/kyma-project/cloud-manager/api/cloud-control/v1beta1" + "github.com/kyma-project/cloud-manager/pkg/composed" + "github.com/kyma-project/cloud-manager/pkg/util" + "k8s.io/apimachinery/pkg/api/meta" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +func upgradeRedis(ctx context.Context, st composed.State) (error, context.Context) { + state := st.(*State) + + logger := composed.LoggerFromCtx(ctx) + redisInstance := state.ObjAsRedisInstance() + + if state.gcpRedisInstance == nil { + return composed.StopWithRequeue, nil + } + + if !state.ShouldUpgradeRedisInstance() { + return nil, nil + } + + logger.Info("Removing ready state to begin upgrade") + meta.RemoveStatusCondition(redisInstance.Conditions(), cloudcontrolv1beta1.ConditionTypeReady) + err := state.UpdateObjStatus(ctx) + if err != nil { + return composed.LogErrorAndReturn(err, + "Error upgrading RedisInstance status", + composed.StopWithRequeueDelay(util.Timing.T10000ms()), + ctx, + ) + } + + logger.Info("Updating redis") + gcpScope := state.Scope().Spec.Scope.Gcp + region := state.Scope().Spec.Region + err = state.memorystoreClient.UpgradeRedisInstance(ctx, gcpScope.Project, region, state.GetRemoteRedisName(), redisInstance.Spec.Instance.Gcp.RedisVersion) + + if err != nil { + logger.Error(err, "Error updating GCP Redis") + meta.SetStatusCondition(redisInstance.Conditions(), metav1.Condition{ + Type: cloudcontrolv1beta1.ConditionTypeError, + Status: "True", + Reason: cloudcontrolv1beta1.ReasonCloudProviderError, + Message: "Failed to upgrade RedisInstance", + }) + err = state.UpdateObjStatus(ctx) + if err != nil { + return composed.LogErrorAndReturn(err, + "Error upgrading RedisInstance status due failed gcp redis creation", + composed.StopWithRequeueDelay((util.Timing.T10000ms())), + ctx, + ) + } + + return composed.StopWithRequeueDelay(util.Timing.T60000ms()), nil + } + + return composed.StopWithRequeueDelay(30 * util.Timing.T1000ms()), nil +} From d3146d443960fc9bb4c67dd21280761573a2100d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Du=C5=A1an?= Date: Fri, 20 Dec 2024 13:36:13 +0100 Subject: [PATCH 2/6] test(GcpRedisInstance): add API tests for redisVersion downgrade --- .../v1beta1/gcpredisinstance_types.go | 5 ++- ...ces.kyma-project.io_gcpredisinstances.yaml | 7 ++++ ...ces.kyma-project.io_gcpredisinstances.yaml | 7 ++++ .../api-tests/skr_gcpredisinstance_test.go | 40 +++++++++++++++++++ 4 files changed, 58 insertions(+), 1 deletion(-) diff --git a/api/cloud-resources/v1beta1/gcpredisinstance_types.go b/api/cloud-resources/v1beta1/gcpredisinstance_types.go index 954c71889..6c02df506 100644 --- a/api/cloud-resources/v1beta1/gcpredisinstance_types.go +++ b/api/cloud-resources/v1beta1/gcpredisinstance_types.go @@ -86,8 +86,11 @@ type GcpRedisInstanceSpec struct { // The version of Redis software. // +optional - // +kubebuilder:default=REDIS_7_0 + // +kubebuilder:default="REDIS_7_0" // +kubebuilder:validation:Enum=REDIS_7_2;REDIS_7_0;REDIS_6_X + // +kubebuilder:validation:XValidation:rule=(self != "REDIS_7_0" || oldSelf == "REDIS_7_0" || oldSelf == "REDIS_6_X"), message="redisVersion cannot be downgraded." + // +kubebuilder:validation:XValidation:rule=(self != "REDIS_7_2" || oldSelf == "REDIS_7_2" || oldSelf == "REDIS_7_0" || oldSelf == "REDIS_6_X"), message="redisVersion cannot be downgraded." + // +kubebuilder:validation:XValidation:rule=(self != "REDIS_6_X" || oldSelf == "REDIS_6_X"), message="redisVersion cannot be downgraded." RedisVersion string `json:"redisVersion"` // Indicates whether OSS Redis AUTH is enabled for the instance. diff --git a/config/crd/bases/cloud-resources.kyma-project.io_gcpredisinstances.yaml b/config/crd/bases/cloud-resources.kyma-project.io_gcpredisinstances.yaml index 00d82b7f0..f3706e4d5 100644 --- a/config/crd/bases/cloud-resources.kyma-project.io_gcpredisinstances.yaml +++ b/config/crd/bases/cloud-resources.kyma-project.io_gcpredisinstances.yaml @@ -153,6 +153,13 @@ spec: - REDIS_7_0 - REDIS_6_X type: string + x-kubernetes-validations: + - message: redisVersion cannot be downgraded. + rule: (self != "REDIS_7_0" || oldSelf == "REDIS_7_0" || oldSelf == "REDIS_6_X") + - message: redisVersion cannot be downgraded. + rule: (self != "REDIS_7_2" || oldSelf == "REDIS_7_2" || oldSelf == "REDIS_7_0" || oldSelf == "REDIS_6_X") + - message: redisVersion cannot be downgraded. + rule: (self != "REDIS_6_X" || oldSelf == "REDIS_6_X") required: - redisTier type: object diff --git a/config/dist/skr/crd/bases/providers/gcp/cloud-resources.kyma-project.io_gcpredisinstances.yaml b/config/dist/skr/crd/bases/providers/gcp/cloud-resources.kyma-project.io_gcpredisinstances.yaml index 4e8362cab..5b4c43764 100644 --- a/config/dist/skr/crd/bases/providers/gcp/cloud-resources.kyma-project.io_gcpredisinstances.yaml +++ b/config/dist/skr/crd/bases/providers/gcp/cloud-resources.kyma-project.io_gcpredisinstances.yaml @@ -158,6 +158,13 @@ spec: - REDIS_7_0 - REDIS_6_X type: string + x-kubernetes-validations: + - message: redisVersion cannot be downgraded. + rule: (self != "REDIS_7_0" || oldSelf == "REDIS_7_0" || oldSelf == "REDIS_6_X") + - message: redisVersion cannot be downgraded. + rule: (self != "REDIS_7_2" || oldSelf == "REDIS_7_2" || oldSelf == "REDIS_7_0" || oldSelf == "REDIS_6_X") + - message: redisVersion cannot be downgraded. + rule: (self != "REDIS_6_X" || oldSelf == "REDIS_6_X") required: - redisTier type: object diff --git a/internal/api-tests/skr_gcpredisinstance_test.go b/internal/api-tests/skr_gcpredisinstance_test.go index 8251199bb..9d6458b48 100644 --- a/internal/api-tests/skr_gcpredisinstance_test.go +++ b/internal/api-tests/skr_gcpredisinstance_test.go @@ -51,6 +51,11 @@ func (b *testGcpRedisInstanceBuilder) WithRedisTier(redisTier cloudresourcesv1be return b } +func (b *testGcpRedisInstanceBuilder) WithRedisVersion(redisVersion string) *testGcpRedisInstanceBuilder { + b.instance.Spec.RedisVersion = redisVersion + return b +} + var _ = Describe("Feature: SKR GcpRedisInstance", Ordered, func() { It("Given SKR default namespace exists", func() { @@ -120,4 +125,39 @@ var _ = Describe("Feature: SKR GcpRedisInstance", Ordered, func() { newTestGcpRedisInstanceBuilder().WithRedisTier("unknown"), "", ) + + allowedVersionUpgrades := [][]string{ + {"REDIS_6_X", "REDIS_7_0"}, + {"REDIS_6_X", "REDIS_7_2"}, + {"REDIS_7_0", "REDIS_7_2"}, + } + for _, upgradePair := range allowedVersionUpgrades { + fromVersion := upgradePair[0] + toVersion := upgradePair[1] + canChangeSkr( + fmt.Sprintf("GcpRedisInstance redisVersion can be upgraded (%s to %s)", fromVersion, toVersion), + newTestGcpRedisInstanceBuilder().WithRedisVersion(fromVersion), + func(b Builder[*cloudresourcesv1beta1.GcpRedisInstance]) { + b.(*testGcpRedisInstanceBuilder).WithRedisVersion(toVersion) + }, + ) + } + + disallowedVersionUpgrades := [][]string{ + {"REDIS_7_2", "REDIS_7_0"}, + {"REDIS_7_2", "REDIS_6_X"}, + {"REDIS_7_0", "REDIS_6_X"}, + } + for _, upgradePair := range disallowedVersionUpgrades { + fromVersion := upgradePair[0] + toVersion := upgradePair[1] + canNotChangeSkr( + fmt.Sprintf("GcpRedisInstance redisVersion can not be downgraded (%s to %s)", fromVersion, toVersion), + newTestGcpRedisInstanceBuilder().WithRedisVersion(fromVersion), + func(b Builder[*cloudresourcesv1beta1.GcpRedisInstance]) { + b.(*testGcpRedisInstanceBuilder).WithRedisVersion(toVersion) + }, + "redisVersion cannot be downgraded", + ) + } }) From 75b80a8e9c585890e57be3af135ad82f0d0fb565 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Du=C5=A1an?= Date: Fri, 20 Dec 2024 15:00:40 +0100 Subject: [PATCH 3/6] feat(GcpRedisInstance): propagade redisVersion from SKR to KCP --- pkg/skr/gcpredisinstance/modifyKcpRedisInstance.go | 1 + pkg/skr/gcpredisinstance/state.go | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/pkg/skr/gcpredisinstance/modifyKcpRedisInstance.go b/pkg/skr/gcpredisinstance/modifyKcpRedisInstance.go index 824603fbb..f7305d753 100644 --- a/pkg/skr/gcpredisinstance/modifyKcpRedisInstance.go +++ b/pkg/skr/gcpredisinstance/modifyKcpRedisInstance.go @@ -51,6 +51,7 @@ func modifyKcpRedisInstance(ctx context.Context, st composed.State) (error, cont state.KcpRedisInstance.Spec.Instance.Gcp.RedisConfigs = gcpRedisInstance.Spec.RedisConfigs state.KcpRedisInstance.Spec.Instance.Gcp.MaintenancePolicy = toGcpMaintenancePolicy(gcpRedisInstance.Spec.MaintenancePolicy) state.KcpRedisInstance.Spec.Instance.Gcp.AuthEnabled = gcpRedisInstance.Spec.AuthEnabled + state.KcpRedisInstance.Spec.Instance.Gcp.RedisVersion = gcpRedisInstance.Spec.RedisVersion err = state.KcpCluster.K8sClient().Update(ctx, state.KcpRedisInstance) if err != nil { diff --git a/pkg/skr/gcpredisinstance/state.go b/pkg/skr/gcpredisinstance/state.go index 180388336..8e1ffb51d 100644 --- a/pkg/skr/gcpredisinstance/state.go +++ b/pkg/skr/gcpredisinstance/state.go @@ -74,11 +74,13 @@ func (s *State) ShouldModifyKcp() bool { areMemorySizesGbDifferent := s.KcpRedisInstance.Spec.Instance.Gcp.MemorySizeGb != memorySizeGb areAuthEnablesDifferent := s.KcpRedisInstance.Spec.Instance.Gcp.AuthEnabled != gcpRedisInstance.Spec.AuthEnabled + areRedisVersionsDifferent := s.KcpRedisInstance.Spec.Instance.Gcp.RedisVersion != gcpRedisInstance.Spec.RedisVersion return areMapsDifferent(s.KcpRedisInstance.Spec.Instance.Gcp.RedisConfigs, gcpRedisInstance.Spec.RedisConfigs) || areMemorySizesGbDifferent || areMaintenancePoliciesDifferent(gcpRedisInstance.Spec.MaintenancePolicy, s.KcpRedisInstance.Spec.Instance.Gcp.MaintenancePolicy) || - areAuthEnablesDifferent + areAuthEnablesDifferent || + areRedisVersionsDifferent } func areMaintenancePoliciesDifferent(skrPolicy *cloudresourcesv1beta1.MaintenancePolicy, kcpPolicy *cloudcontrolv1beta1.MaintenancePolicyGcp) bool { From bb9ff1b3a4c2447bc5c6afe402a608601e99c3cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Du=C5=A1an?= Date: Fri, 20 Dec 2024 16:45:02 +0100 Subject: [PATCH 4/6] feat(GcpRedisInstance): add API validator for KCP as well --- api/cloud-control/v1beta1/redisinstance_types.go | 3 +++ .../cloud-control.kyma-project.io_redisinstances.yaml | 9 +++++++++ .../cloud-control.kyma-project.io_redisinstances.yaml | 9 +++++++++ 3 files changed, 21 insertions(+) diff --git a/api/cloud-control/v1beta1/redisinstance_types.go b/api/cloud-control/v1beta1/redisinstance_types.go index d52c99a7a..b4c00f0fa 100644 --- a/api/cloud-control/v1beta1/redisinstance_types.go +++ b/api/cloud-control/v1beta1/redisinstance_types.go @@ -158,6 +158,9 @@ type RedisInstanceGcp struct { // +optional // +kubebuilder:default=REDIS_7_0 // +kubebuilder:validation:Enum=REDIS_7_2;REDIS_7_0;REDIS_6_X + // +kubebuilder:validation:XValidation:rule=(self != "REDIS_7_0" || oldSelf == "REDIS_7_0" || oldSelf == "REDIS_6_X"), message="redisVersion cannot be downgraded." + // +kubebuilder:validation:XValidation:rule=(self != "REDIS_7_2" || oldSelf == "REDIS_7_2" || oldSelf == "REDIS_7_0" || oldSelf == "REDIS_6_X"), message="redisVersion cannot be downgraded." + // +kubebuilder:validation:XValidation:rule=(self != "REDIS_6_X" || oldSelf == "REDIS_6_X"), message="redisVersion cannot be downgraded." RedisVersion string `json:"redisVersion"` // Indicates whether OSS Redis AUTH is enabled for the instance. diff --git a/config/crd/bases/cloud-control.kyma-project.io_redisinstances.yaml b/config/crd/bases/cloud-control.kyma-project.io_redisinstances.yaml index b15cd310f..9cd0d3d5a 100644 --- a/config/crd/bases/cloud-control.kyma-project.io_redisinstances.yaml +++ b/config/crd/bases/cloud-control.kyma-project.io_redisinstances.yaml @@ -199,6 +199,15 @@ spec: - REDIS_7_0 - REDIS_6_X type: string + x-kubernetes-validations: + - message: redisVersion cannot be downgraded. + rule: (self != "REDIS_7_0" || oldSelf == "REDIS_7_0" || + oldSelf == "REDIS_6_X") + - message: redisVersion cannot be downgraded. + rule: (self != "REDIS_7_2" || oldSelf == "REDIS_7_2" || + oldSelf == "REDIS_7_0" || oldSelf == "REDIS_6_X") + - message: redisVersion cannot be downgraded. + rule: (self != "REDIS_6_X" || oldSelf == "REDIS_6_X") replicaCount: default: 0 format: int32 diff --git a/config/dist/kcp/crd/bases/cloud-control.kyma-project.io_redisinstances.yaml b/config/dist/kcp/crd/bases/cloud-control.kyma-project.io_redisinstances.yaml index b15cd310f..9cd0d3d5a 100644 --- a/config/dist/kcp/crd/bases/cloud-control.kyma-project.io_redisinstances.yaml +++ b/config/dist/kcp/crd/bases/cloud-control.kyma-project.io_redisinstances.yaml @@ -199,6 +199,15 @@ spec: - REDIS_7_0 - REDIS_6_X type: string + x-kubernetes-validations: + - message: redisVersion cannot be downgraded. + rule: (self != "REDIS_7_0" || oldSelf == "REDIS_7_0" || + oldSelf == "REDIS_6_X") + - message: redisVersion cannot be downgraded. + rule: (self != "REDIS_7_2" || oldSelf == "REDIS_7_2" || + oldSelf == "REDIS_7_0" || oldSelf == "REDIS_6_X") + - message: redisVersion cannot be downgraded. + rule: (self != "REDIS_6_X" || oldSelf == "REDIS_6_X") replicaCount: default: 0 format: int32 From 1077c2b022c61a793ad33ac5f6ea8809c7a45644 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Du=C5=A1an?= Date: Mon, 23 Dec 2024 10:31:56 +0100 Subject: [PATCH 5/6] docs(GcpRedisInstance): update redisVersion upgradability info --- docs/user/resources/04-40-20-gcp-redis-instance.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/user/resources/04-40-20-gcp-redis-instance.md b/docs/user/resources/04-40-20-gcp-redis-instance.md index 326c9b491..7e68a507b 100644 --- a/docs/user/resources/04-40-20-gcp-redis-instance.md +++ b/docs/user/resources/04-40-20-gcp-redis-instance.md @@ -61,7 +61,7 @@ This table lists the parameters of GcpRedisInstance, together with their descrip | **ipRange** | object | Optional. IpRange reference. If omitted, the default IpRange is used. If the default IpRange does not exist, it will be created. | | **ipRange.name** | string | Required. Name of the existing IpRange to use. | | **redisTier** | string | Required. The Redis tier of the instance. Supported values are `S1`, `S2`, `S3`, `S4`, `S5`, `S6`, `S7`, `S8` for the **Standard** offering, and `P1`, `P2`, `P3`, `P4`, `P5`, `P6` for the **Premium** offering. | -| **redisVersion** | int | Optional. The version of Redis software. Supported values are `REDIS_7_2`, `REDIS_7_0`, and `REDIS_6_X`. Defaults to `REDIS_7_0`. | +| **redisVersion** | int | Optional. The version of Redis software. Supported values are `REDIS_7_2`, `REDIS_7_0`, and `REDIS_6_X`. Defaults to `REDIS_7_0`. Can be upgraded.| | **authEnabled** | bool | Optional. Indicates whether OSS Redis AUTH is enabled for the instance. If set to `true,` AUTH is enabled on the instance. Defaults to `false` | | **redisConfigs** | object | Optional. Provided values are passed to the Redis configuration. Supported values can be read on [Google's Supported Redis configurations page](https://cloud.google.com/memorystore/docs/redis/supported-redis-configurations). If left empty, defaults to an empty object. | | **maintenancePolicy** | object | Optional. Defines a desired maintenance policy. Only one policy can be active at a time. If not provided, maintenance events can be performed at any time. To learn more about maintenance policy limitations and requirements, see [About maintenance on Memorystore for Redis](https://cloud.google.com/memorystore/docs/redis/about-maintenance). | From fec039f1aa59172ee87bd5665d5fd956d3936011 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Du=C5=A1an?= Date: Mon, 23 Dec 2024 11:07:28 +0100 Subject: [PATCH 6/6] fix: conflict --- .../cloud-resources.kyma-project.io_gcpredisinstances.yaml | 5 ----- 1 file changed, 5 deletions(-) diff --git a/config/dist/skr/crd/bases/providers/gcp/cloud-resources.kyma-project.io_gcpredisinstances.yaml b/config/dist/skr/crd/bases/providers/gcp/cloud-resources.kyma-project.io_gcpredisinstances.yaml index 5b4c43764..f3706e4d5 100644 --- a/config/dist/skr/crd/bases/providers/gcp/cloud-resources.kyma-project.io_gcpredisinstances.yaml +++ b/config/dist/skr/crd/bases/providers/gcp/cloud-resources.kyma-project.io_gcpredisinstances.yaml @@ -3,13 +3,8 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: -<<<<<<< HEAD controller-gen.kubebuilder.io/version: v0.16.5 - cloud-resources.kyma-project.io/version: v0.0.18 -======= - controller-gen.kubebuilder.io/version: v0.15.0 cloud-resources.kyma-project.io/version: v0.0.19 ->>>>>>> 7c8cbb35 (feat(GcpRedisInstance): make redis upgradable) name: gcpredisinstances.cloud-resources.kyma-project.io spec: group: cloud-resources.kyma-project.io