diff --git a/.chloggen/3305-persistentVolumeClaimRetentionPolicy.yaml b/.chloggen/3305-persistentVolumeClaimRetentionPolicy.yaml new file mode 100755 index 0000000000..93ca955f4c --- /dev/null +++ b/.chloggen/3305-persistentVolumeClaimRetentionPolicy.yaml @@ -0,0 +1,16 @@ +# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix' +change_type: enhancement + +# The name of the component, or a single word describing the area of concern, (e.g. collector, target allocator, auto-instrumentation, opamp, github action) +component: collector + +# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`). +note: "Add support for persistentVolumeClaimRetentionPolicy field" + +# One or more tracking issues related to the change +issues: [3305] + +# (Optional) One or more lines of additional information to render under the primary note. +# These lines will be padded with 2 spaces and then inserted directly into the document. +# Use pipe (|) for multiline entries. +subtext: diff --git a/apis/v1beta1/collector_webhook.go b/apis/v1beta1/collector_webhook.go index 5a6b80a3b9..68b572b8c1 100644 --- a/apis/v1beta1/collector_webhook.go +++ b/apis/v1beta1/collector_webhook.go @@ -188,6 +188,11 @@ func (c CollectorWebhook) Validate(ctx context.Context, r *OpenTelemetryCollecto return warnings, fmt.Errorf("the OpenTelemetry Collector mode is set to %s, which does not support the attribute 'volumeClaimTemplates'", r.Spec.Mode) } + // validate persistentVolumeClaimRetentionPolicy + if r.Spec.Mode != ModeStatefulSet && r.Spec.PersistentVolumeClaimRetentionPolicy != nil { + return warnings, fmt.Errorf("the OpenTelemetry Collector mode is set to %s, which does not support the attribute 'persistentVolumeClaimRetentionPolicy'", r.Spec.Mode) + } + // validate tolerations if r.Spec.Mode == ModeSidecar && len(r.Spec.Tolerations) > 0 { return warnings, fmt.Errorf("the OpenTelemetry Collector mode is set to %s, which does not support the attribute 'tolerations'", r.Spec.Mode) diff --git a/apis/v1beta1/collector_webhook_test.go b/apis/v1beta1/collector_webhook_test.go index a30d74a66c..72ab56aab0 100644 --- a/apis/v1beta1/collector_webhook_test.go +++ b/apis/v1beta1/collector_webhook_test.go @@ -763,6 +763,21 @@ func TestOTELColValidatingWebhook(t *testing.T) { }, expectedErr: "does not support the attribute 'volumeClaimTemplates'", }, + { + name: "invalid mode with persistentVolumeClaimRetentionPolicy", + otelcol: v1beta1.OpenTelemetryCollector{ + Spec: v1beta1.OpenTelemetryCollectorSpec{ + Mode: v1beta1.ModeSidecar, + StatefulSetCommonFields: v1beta1.StatefulSetCommonFields{ + PersistentVolumeClaimRetentionPolicy: &appsv1.StatefulSetPersistentVolumeClaimRetentionPolicy{ + WhenDeleted: appsv1.RetainPersistentVolumeClaimRetentionPolicyType, + WhenScaled: appsv1.DeletePersistentVolumeClaimRetentionPolicyType, + }, + }, + }, + }, + expectedErr: "does not support the attribute 'persistentVolumeClaimRetentionPolicy'", + }, { name: "invalid mode with tolerations", otelcol: v1beta1.OpenTelemetryCollector{ diff --git a/apis/v1beta1/common.go b/apis/v1beta1/common.go index cf31de5118..77044771a5 100644 --- a/apis/v1beta1/common.go +++ b/apis/v1beta1/common.go @@ -15,6 +15,7 @@ package v1beta1 import ( + appsv1 "k8s.io/api/apps/v1" autoscalingv2 "k8s.io/api/autoscaling/v2" v1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/util/intstr" @@ -243,4 +244,9 @@ type StatefulSetCommonFields struct { // +optional // +listType=atomic VolumeClaimTemplates []v1.PersistentVolumeClaim `json:"volumeClaimTemplates,omitempty"` + // PersistentVolumeClaimRetentionPolicy describes the lifecycle of persistent volume claims + // created from volumeClaimTemplates. + // This only works with the following OpenTelemetryCollector modes: statefulset. + // +optional + PersistentVolumeClaimRetentionPolicy *appsv1.StatefulSetPersistentVolumeClaimRetentionPolicy `json:"persistentVolumeClaimRetentionPolicy,omitempty"` } diff --git a/apis/v1beta1/zz_generated.deepcopy.go b/apis/v1beta1/zz_generated.deepcopy.go index eaf24ed0ba..b508f0be76 100644 --- a/apis/v1beta1/zz_generated.deepcopy.go +++ b/apis/v1beta1/zz_generated.deepcopy.go @@ -19,6 +19,7 @@ package v1beta1 import ( + appsv1 "k8s.io/api/apps/v1" "k8s.io/api/autoscaling/v2" "k8s.io/api/core/v1" networkingv1 "k8s.io/api/networking/v1" @@ -680,6 +681,11 @@ func (in *StatefulSetCommonFields) DeepCopyInto(out *StatefulSetCommonFields) { (*in)[i].DeepCopyInto(&(*out)[i]) } } + if in.PersistentVolumeClaimRetentionPolicy != nil { + in, out := &in.PersistentVolumeClaimRetentionPolicy, &out.PersistentVolumeClaimRetentionPolicy + *out = new(appsv1.StatefulSetPersistentVolumeClaimRetentionPolicy) + **out = **in + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StatefulSetCommonFields. diff --git a/bundle/community/manifests/opentelemetry.io_opentelemetrycollectors.yaml b/bundle/community/manifests/opentelemetry.io_opentelemetrycollectors.yaml index 594e0f4aea..6ccb1c9e5f 100644 --- a/bundle/community/manifests/opentelemetry.io_opentelemetrycollectors.yaml +++ b/bundle/community/manifests/opentelemetry.io_opentelemetrycollectors.yaml @@ -6963,6 +6963,13 @@ spec: type: boolean type: object type: object + persistentVolumeClaimRetentionPolicy: + properties: + whenDeleted: + type: string + whenScaled: + type: string + type: object podAnnotations: additionalProperties: type: string diff --git a/bundle/openshift/manifests/opentelemetry.io_opentelemetrycollectors.yaml b/bundle/openshift/manifests/opentelemetry.io_opentelemetrycollectors.yaml index 594e0f4aea..6ccb1c9e5f 100644 --- a/bundle/openshift/manifests/opentelemetry.io_opentelemetrycollectors.yaml +++ b/bundle/openshift/manifests/opentelemetry.io_opentelemetrycollectors.yaml @@ -6963,6 +6963,13 @@ spec: type: boolean type: object type: object + persistentVolumeClaimRetentionPolicy: + properties: + whenDeleted: + type: string + whenScaled: + type: string + type: object podAnnotations: additionalProperties: type: string diff --git a/config/crd/bases/opentelemetry.io_opentelemetrycollectors.yaml b/config/crd/bases/opentelemetry.io_opentelemetrycollectors.yaml index 05baaaa5df..fc36f4deb5 100644 --- a/config/crd/bases/opentelemetry.io_opentelemetrycollectors.yaml +++ b/config/crd/bases/opentelemetry.io_opentelemetrycollectors.yaml @@ -6949,6 +6949,13 @@ spec: type: boolean type: object type: object + persistentVolumeClaimRetentionPolicy: + properties: + whenDeleted: + type: string + whenScaled: + type: string + type: object podAnnotations: additionalProperties: type: string diff --git a/docs/api.md b/docs/api.md index dc327344f8..d921a01256 100644 --- a/docs/api.md +++ b/docs/api.md @@ -31176,6 +31176,15 @@ This only works with the following OpenTelemetryCollector mode's: daemonset, sta ObservabilitySpec defines how telemetry data gets handled.
false + + persistentVolumeClaimRetentionPolicy + object + + PersistentVolumeClaimRetentionPolicy describes the lifecycle of persistent volume claims +created from volumeClaimTemplates. +This only works with the following OpenTelemetryCollector modes: statefulset.
+ + false podAnnotations map[string]string @@ -40936,6 +40945,49 @@ The operator.observability.prometheus feature gate must be enabled to use this f +### OpenTelemetryCollector.spec.persistentVolumeClaimRetentionPolicy +[↩ Parent](#opentelemetrycollectorspec-1) + + + +PersistentVolumeClaimRetentionPolicy describes the lifecycle of persistent volume claims +created from volumeClaimTemplates. +This only works with the following OpenTelemetryCollector modes: statefulset. + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescriptionRequired
whenDeletedstring + WhenDeleted specifies what happens to PVCs created from StatefulSet +VolumeClaimTemplates when the StatefulSet is deleted. The default policy +of `Retain` causes PVCs to not be affected by StatefulSet deletion. The +`Delete` policy causes those PVCs to be deleted.
+
false
whenScaledstring + WhenScaled specifies what happens to PVCs created from StatefulSet +VolumeClaimTemplates when the StatefulSet is scaled down. The default +policy of `Retain` causes PVCs to not be affected by a scaledown. The +`Delete` policy causes the associated PVCs for any excess pods above +the replica count to be deleted.
+
false
+ + ### OpenTelemetryCollector.spec.podDisruptionBudget [↩ Parent](#opentelemetrycollectorspec-1) diff --git a/internal/manifests/collector/statefulset.go b/internal/manifests/collector/statefulset.go index 6b7e92ec05..3a98611c4e 100644 --- a/internal/manifests/collector/statefulset.go +++ b/internal/manifests/collector/statefulset.go @@ -73,9 +73,10 @@ func StatefulSet(params manifests.Params) (*appsv1.StatefulSet, error) { TopologySpreadConstraints: params.OtelCol.Spec.TopologySpreadConstraints, }, }, - Replicas: params.OtelCol.Spec.Replicas, - PodManagementPolicy: "Parallel", - VolumeClaimTemplates: VolumeClaimTemplates(params.OtelCol), + Replicas: params.OtelCol.Spec.Replicas, + PodManagementPolicy: "Parallel", + VolumeClaimTemplates: VolumeClaimTemplates(params.OtelCol), + PersistentVolumeClaimRetentionPolicy: params.OtelCol.Spec.PersistentVolumeClaimRetentionPolicy, }, }, nil } diff --git a/internal/manifests/collector/statefulset_test.go b/internal/manifests/collector/statefulset_test.go index 916e25e4bb..1963afe131 100644 --- a/internal/manifests/collector/statefulset_test.go +++ b/internal/manifests/collector/statefulset_test.go @@ -178,6 +178,45 @@ func TestStatefulSetVolumeClaimTemplates(t *testing.T) { assert.Equal(t, resource.MustParse("1Gi"), ss.Spec.VolumeClaimTemplates[0].Spec.Resources.Requests["storage"]) } +func TestStatefulSetPeristentVolumeRetentionPolicy(t *testing.T) { + // prepare + otelcol := v1beta1.OpenTelemetryCollector{ + ObjectMeta: metav1.ObjectMeta{ + Name: "my-instance", + }, + Spec: v1beta1.OpenTelemetryCollectorSpec{ + Mode: "statefulset", + StatefulSetCommonFields: v1beta1.StatefulSetCommonFields{ + PersistentVolumeClaimRetentionPolicy: &appsv1.StatefulSetPersistentVolumeClaimRetentionPolicy{ + WhenDeleted: appsv1.RetainPersistentVolumeClaimRetentionPolicyType, + WhenScaled: appsv1.DeletePersistentVolumeClaimRetentionPolicyType, + }, + }, + }, + } + cfg := config.New() + + params := manifests.Params{ + OtelCol: otelcol, + Config: cfg, + Log: logger, + } + + // test + ss, err := StatefulSet(params) + require.NoError(t, err) + + // assert PersistentVolumeClaimRetentionPolicy added + assert.NotNil(t, ss.Spec.PersistentVolumeClaimRetentionPolicy) + + // assert correct WhenDeleted value + assert.Equal(t, ss.Spec.PersistentVolumeClaimRetentionPolicy.WhenDeleted, appsv1.RetainPersistentVolumeClaimRetentionPolicyType) + + // assert correct WhenScaled value + assert.Equal(t, ss.Spec.PersistentVolumeClaimRetentionPolicy.WhenScaled, appsv1.DeletePersistentVolumeClaimRetentionPolicyType) + +} + func TestStatefulSetPodAnnotations(t *testing.T) { // prepare testPodAnnotationValues := map[string]string{"annotation-key": "annotation-value"}