diff --git a/CHANGELOG.md b/CHANGELOG.md index 98d308f0..b225eeaf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ Changelog for Cass Operator, new PRs should update the `main / unreleased` secti ## unreleased +* [ENHANCEMENT] [#922](https://github.com/k8ssandra/cass-operator/issues/922) Allow VolumeAttributesClassName changes in storageConfig webhook to support in-place EBS volume performance class updates on AWS * [ENHANCEMENT] [#912](https://github.com/k8ssandra/cass-operator/issues/912) Add new webhook validations for maxUnavailable string format as well as PVC sizes * [ENHANCEMENT] [#902](https://github.com/k8ssandra/cass-operator/issues/902) If scaling down or scaling up process is still ongoing, the webhook will prevent changing the cluster size. diff --git a/internal/webhooks/cassandra/v1beta1/cassandradatacenter_webhook.go b/internal/webhooks/cassandra/v1beta1/cassandradatacenter_webhook.go index 99766b2a..e5e570ca 100644 --- a/internal/webhooks/cassandra/v1beta1/cassandradatacenter_webhook.go +++ b/internal/webhooks/cassandra/v1beta1/cassandradatacenter_webhook.go @@ -204,12 +204,15 @@ func ValidateDatacenterFieldChanges(oldDc *api.CassandraDatacenter, newDc *api.C return attemptedTo( "shrink storageConfig.CassandraDataVolumeClaimSpec from %s to %s", oldStorageRequest.String(), newStorageRequest.String()) } - } - // CassandraDataVolumeClaimSpec changes are disallowed - if metav1.HasAnnotation(newDc.ObjectMeta, api.AllowStorageChangesAnnotation) && newDc.Annotations[api.AllowStorageChangesAnnotation] == "true" { - // If the AllowStorageChangesAnnotation is set, we allow changes to the CassandraDataVolumeClaimSpec sizes, but not other fields - oldClaimSpec.Resources.Requests = newClaimSpec.Resources.Requests + if metav1.HasAnnotation(newDc.ObjectMeta, api.AllowStorageChangesAnnotation) && newDc.Annotations[api.AllowStorageChangesAnnotation] == "true" { + // If the AllowStorageChangesAnnotation is set, we allow changes to the CassandraDataVolumeClaimSpec sizes, but not other fields + oldClaimSpec.Resources.Requests = newClaimSpec.Resources.Requests + } + + // VolumeAttributesClassName changes are always allowed as they represent in-place volume + // performance class changes (e.g. AWS EBS VolumeAttributesClass) and do not replace the PVC. + oldClaimSpec.VolumeAttributesClassName = newClaimSpec.VolumeAttributesClassName } if !apiequality.Semantic.DeepEqual(oldClaimSpec, newClaimSpec) { diff --git a/internal/webhooks/cassandra/v1beta1/cassandradatacenter_webhook_test.go b/internal/webhooks/cassandra/v1beta1/cassandradatacenter_webhook_test.go index b805a835..1df29d8a 100644 --- a/internal/webhooks/cassandra/v1beta1/cassandradatacenter_webhook_test.go +++ b/internal/webhooks/cassandra/v1beta1/cassandradatacenter_webhook_test.go @@ -786,6 +786,82 @@ func Test_ValidateDatacenterFieldChanges(t *testing.T) { }, errString: "", }, + { + name: "VolumeAttributesClassName change is allowed", + oldDc: &api.CassandraDatacenter{ + ObjectMeta: metav1.ObjectMeta{ + Name: "exampleDC", + }, + Spec: api.CassandraDatacenterSpec{ + StorageConfig: api.StorageConfig{ + CassandraDataVolumeClaimSpec: &corev1.PersistentVolumeClaimSpec{ + StorageClassName: storageName, + AccessModes: []corev1.PersistentVolumeAccessMode{"ReadWriteOnce"}, + VolumeAttributesClassName: ptr.To[string]("gp3-cassandra-general"), + Resources: corev1.VolumeResourceRequirements{ + Requests: map[corev1.ResourceName]resource.Quantity{"storage": storageSize}, + }, + }, + }, + }, + }, + newDc: &api.CassandraDatacenter{ + ObjectMeta: metav1.ObjectMeta{ + Name: "exampleDC", + }, + Spec: api.CassandraDatacenterSpec{ + StorageConfig: api.StorageConfig{ + CassandraDataVolumeClaimSpec: &corev1.PersistentVolumeClaimSpec{ + StorageClassName: storageName, + AccessModes: []corev1.PersistentVolumeAccessMode{"ReadWriteOnce"}, + VolumeAttributesClassName: ptr.To[string]("gp3-cassandra"), + Resources: corev1.VolumeResourceRequirements{ + Requests: map[corev1.ResourceName]resource.Quantity{"storage": storageSize}, + }, + }, + }, + }, + }, + errString: "", + }, + { + name: "VolumeAttributesClassName change with other field change is rejected", + oldDc: &api.CassandraDatacenter{ + ObjectMeta: metav1.ObjectMeta{ + Name: "exampleDC", + }, + Spec: api.CassandraDatacenterSpec{ + StorageConfig: api.StorageConfig{ + CassandraDataVolumeClaimSpec: &corev1.PersistentVolumeClaimSpec{ + StorageClassName: storageName, + AccessModes: []corev1.PersistentVolumeAccessMode{"ReadWriteOnce"}, + VolumeAttributesClassName: ptr.To[string]("gp3-cassandra-general"), + Resources: corev1.VolumeResourceRequirements{ + Requests: map[corev1.ResourceName]resource.Quantity{"storage": storageSize}, + }, + }, + }, + }, + }, + newDc: &api.CassandraDatacenter{ + ObjectMeta: metav1.ObjectMeta{ + Name: "exampleDC", + }, + Spec: api.CassandraDatacenterSpec{ + StorageConfig: api.StorageConfig{ + CassandraDataVolumeClaimSpec: &corev1.PersistentVolumeClaimSpec{ + StorageClassName: storageName, + AccessModes: []corev1.PersistentVolumeAccessMode{"ReadWriteMany"}, + VolumeAttributesClassName: ptr.To[string]("gp3-cassandra"), + Resources: corev1.VolumeResourceRequirements{ + Requests: map[corev1.ResourceName]resource.Quantity{"storage": storageSize}, + }, + }, + }, + }, + }, + errString: "change storageConfig.CassandraDataVolumeClaimSpec", + }, { name: "Removing a rack", oldDc: &api.CassandraDatacenter{