Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 20 additions & 3 deletions api/operator/v1beta1/vmextra_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -188,23 +188,39 @@ type StorageSpec struct {

// IntoSTSVolume converts storageSpec into proper volume for statefulsetSpec
// by default, it adds emptyDir volume.
func (ss *StorageSpec) IntoSTSVolume(name string, sts *appsv1.StatefulSetSpec) {
func (ss *StorageSpec) IntoSTSVolume(name string, sts *appsv1.StatefulSetSpec) error {
podSpec := &sts.Template.Spec
foundVolume := false
for _, volume := range podSpec.Volumes {
if volume.Name == name {
foundVolume = true
}
}
switch {
case ss == nil:
sts.Template.Spec.Volumes = append(sts.Template.Spec.Volumes, corev1.Volume{
if foundVolume {
return nil
}
podSpec.Volumes = append(podSpec.Volumes, corev1.Volume{
Name: name,
VolumeSource: corev1.VolumeSource{
EmptyDir: &corev1.EmptyDirVolumeSource{},
},
})
case ss.EmptyDir != nil:
sts.Template.Spec.Volumes = append(sts.Template.Spec.Volumes, corev1.Volume{
if foundVolume {
return fmt.Errorf("either unset storage.emptyDir or remove volume=%q from spec", name)
}
podSpec.Volumes = append(podSpec.Volumes, corev1.Volume{
Name: name,
VolumeSource: corev1.VolumeSource{
EmptyDir: ss.EmptyDir,
},
})
default:
if foundVolume {
return fmt.Errorf("either unset storage.volumeClaimTemplate or remove volume=%q from spec", name)
}
claimTemplate := ss.VolumeClaimTemplate
stsClaim := corev1.PersistentVolumeClaim{
TypeMeta: metav1.TypeMeta{
Expand All @@ -224,6 +240,7 @@ func (ss *StorageSpec) IntoSTSVolume(name string, sts *appsv1.StatefulSetSpec) {
}
sts.VolumeClaimTemplates = append(sts.VolumeClaimTemplates, stsClaim)
}
return nil
}

// EmbeddedPersistentVolumeClaim is an embedded version of k8s.io/api/core/v1.PersistentVolumeClaim.
Expand Down
3 changes: 3 additions & 0 deletions docs/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ aliases:

## tip

* BUGFIX: [vmagent](https://docs.victoriametrics.com/operator/resources/vmagent/): use volume from spec.volumes as persistent queue volume if its name is `persistent-queue-data`, previously emptyDir was mounted. See [#1677](https://github.com/VictoriaMetrics/operator/issues/1677).
Comment thread
vrutkovs marked this conversation as resolved.
* BUGFIX: [vmcluster](https://docs.victoriametrics.com/operator/resources/vmcluster/): use volume from spec.vmstorage.volumes and spec.vmselect.volumes as data and cache volumes if its name is `vmstorage-db` and `vmselect-cachedir` respectively. See [#784](https://github.com/VictoriaMetrics/operator/issues/784).
Comment thread
vrutkovs marked this conversation as resolved.

## [v0.68.4](https://github.com/VictoriaMetrics/operator/releases/tag/v0.68.4)
**Release date:** 09 April 2026

Expand Down
5 changes: 4 additions & 1 deletion internal/controller/operator/factory/build/container.go
Original file line number Diff line number Diff line change
Expand Up @@ -607,7 +607,7 @@ func AddSyslogTLSConfigToVolumes(dstVolumes []corev1.Volume, dstMounts []corev1.
return dstVolumes, dstMounts
}

func StorageVolumeMountsTo(volumes []corev1.Volume, mounts []corev1.VolumeMount, pvcSrc *corev1.PersistentVolumeClaimVolumeSource, storagePath, dataVolumeName string) ([]corev1.Volume, []corev1.VolumeMount, error) {
func StorageVolumeMountsTo(volumes []corev1.Volume, mounts []corev1.VolumeMount, pvcSrc *corev1.PersistentVolumeClaimVolumeSource, storagePath, dataVolumeName string, isStatefulSet bool) ([]corev1.Volume, []corev1.VolumeMount, error) {
foundMount := false
for _, volumeMount := range mounts {
rel, err := filepath.Rel(volumeMount.MountPath, storagePath)
Expand Down Expand Up @@ -643,6 +643,9 @@ func StorageVolumeMountsTo(volumes []corev1.Volume, mounts []corev1.VolumeMount,
return volumes, mounts, nil
}
}
if isStatefulSet {
return volumes, mounts, nil
}
var source corev1.VolumeSource
if pvcSrc != nil {
source.PersistentVolumeClaim = pvcSrc
Expand Down
58 changes: 57 additions & 1 deletion internal/controller/operator/factory/build/container_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -356,10 +356,11 @@ func TestStorageVolumeMountsTo(t *testing.T) {
mounts []corev1.VolumeMount
expectedMounts []corev1.VolumeMount
wantErr bool
isStatefulSet bool
}
f := func(o opts) {
t.Helper()
gotVolumes, gotMounts, err := StorageVolumeMountsTo(o.volumes, o.mounts, o.pvcSrc, o.storagePath, DataVolumeName)
gotVolumes, gotMounts, err := StorageVolumeMountsTo(o.volumes, o.mounts, o.pvcSrc, o.storagePath, DataVolumeName, o.isStatefulSet)
assert.Equal(t, o.expectedMounts, gotMounts)
assert.Equal(t, o.expectedVolumes, gotVolumes)
if o.wantErr {
Expand Down Expand Up @@ -542,6 +543,61 @@ func TestStorageVolumeMountsTo(t *testing.T) {
},
wantErr: true,
})

// isStatefulSet, add data volume
f(opts{
isStatefulSet: true,
storagePath: "/test",
expectedVolumes: nil,
expectedMounts: []corev1.VolumeMount{{
Name: DataVolumeName,
MountPath: "/test",
}},
})

// isStatefulSet, mount PVC
f(opts{
isStatefulSet: true,
volumes: []corev1.Volume{{
Name: DataVolumeName,
VolumeSource: corev1.VolumeSource{
PersistentVolumeClaim: &corev1.PersistentVolumeClaimVolumeSource{
ClaimName: "test-claim",
},
},
}},
storagePath: "/test",
expectedVolumes: []corev1.Volume{{
Name: DataVolumeName,
VolumeSource: corev1.VolumeSource{
PersistentVolumeClaim: &corev1.PersistentVolumeClaimVolumeSource{
ClaimName: "test-claim",
},
},
}},
expectedMounts: []corev1.VolumeMount{{
Name: DataVolumeName,
MountPath: "/test",
}},
})

// isStatefulSet, existing volume + pvcSrc — error
f(opts{
isStatefulSet: true,
volumes: []corev1.Volume{{
Name: DataVolumeName,
VolumeSource: corev1.VolumeSource{
AWSElasticBlockStore: &corev1.AWSElasticBlockStoreVolumeSource{
VolumeID: "aws-volume",
},
},
}},
storagePath: "/test",
pvcSrc: &corev1.PersistentVolumeClaimVolumeSource{
ClaimName: "test-claim",
},
wantErr: true,
})
}

func TestBuildConfigReloaderContainer(t *testing.T) {
Expand Down
24 changes: 13 additions & 11 deletions internal/controller/operator/factory/vlagent/vlagent.go
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,9 @@ func newK8sApp(cr *vmv1.VLAgent) (client.Object, error) {
build.StatefulSetAddCommonParams(stsSpec, &cr.Spec.CommonAppsParams)

if cr.Spec.TmpDataPath == nil {
cr.Spec.Storage.IntoSTSVolume(tmpDataVolumeName, &stsSpec.Spec)
if err := cr.Spec.Storage.IntoSTSVolume(tmpDataVolumeName, &stsSpec.Spec); err != nil {
return nil, err
}
}
stsSpec.Spec.VolumeClaimTemplates = append(stsSpec.Spec.VolumeClaimTemplates, cr.Spec.ClaimTemplates...)
return stsSpec, nil
Expand Down Expand Up @@ -268,7 +270,7 @@ func newPodSpec(cr *vmv1.VLAgent) (*corev1.PodSpec, error) {
args = append(args, "-envflag.enable=true")
}

var agentVolumeMounts []corev1.VolumeMount
var vmMounts []corev1.VolumeMount
var volumes []corev1.Volume
tmpDataPath := defaultTmpDataPath
if cr.Spec.K8sCollector.Enabled {
Expand Down Expand Up @@ -330,7 +332,7 @@ func newPodSpec(cr *vmv1.VLAgent) (*corev1.PodSpec, error) {
},
},
})
agentVolumeMounts = append(agentVolumeMounts, corev1.VolumeMount{
vmMounts = append(vmMounts, corev1.VolumeMount{
Name: logVolumeName,
MountPath: logVolumePath,
ReadOnly: true,
Expand Down Expand Up @@ -359,7 +361,7 @@ func newPodSpec(cr *vmv1.VLAgent) (*corev1.PodSpec, error) {
}

if cr.Spec.TmpDataPath == nil {
agentVolumeMounts = append(agentVolumeMounts,
vmMounts = append(vmMounts,
corev1.VolumeMount{
Name: tmpDataVolumeName,
MountPath: tmpDataPath,
Expand All @@ -377,14 +379,14 @@ func newPodSpec(cr *vmv1.VLAgent) (*corev1.PodSpec, error) {

if cr.Spec.SyslogSpec != nil {
args = build.AddSyslogArgsTo(args, cr.Spec.SyslogSpec, tlsServerConfigMountPath)
volumes, agentVolumeMounts = build.AddSyslogTLSConfigToVolumes(volumes, agentVolumeMounts, cr.Spec.SyslogSpec, tlsServerConfigMountPath)
volumes, vmMounts = build.AddSyslogTLSConfigToVolumes(volumes, vmMounts, cr.Spec.SyslogSpec, tlsServerConfigMountPath)
ports = build.AddSyslogPortsTo(ports, cr.Spec.SyslogSpec)
}

volumes, agentVolumeMounts = build.LicenseVolumeTo(volumes, agentVolumeMounts, cr.Spec.License, vmv1beta1.SecretsDir)
volumes, vmMounts = build.LicenseVolumeTo(volumes, vmMounts, cr.Spec.License, vmv1beta1.SecretsDir)
args = build.LicenseArgsTo(args, cr.Spec.License, vmv1beta1.SecretsDir)

agentVolumeMounts = append(agentVolumeMounts, cr.Spec.VolumeMounts...)
vmMounts = append(vmMounts, cr.Spec.VolumeMounts...)
volumes = append(volumes, cr.Spec.Volumes...)

for _, s := range cr.Spec.Secrets {
Expand All @@ -396,7 +398,7 @@ func newPodSpec(cr *vmv1.VLAgent) (*corev1.PodSpec, error) {
},
},
})
agentVolumeMounts = append(agentVolumeMounts, corev1.VolumeMount{
vmMounts = append(vmMounts, corev1.VolumeMount{
Name: k8stools.SanitizeVolumeName("secret-" + s),
ReadOnly: true,
MountPath: path.Join(vmv1beta1.SecretsDir, s),
Expand All @@ -419,9 +421,9 @@ func newPodSpec(cr *vmv1.VLAgent) (*corev1.PodSpec, error) {
ReadOnly: true,
MountPath: path.Join(vmv1beta1.ConfigMapsDir, c),
}
agentVolumeMounts = append(agentVolumeMounts, cvm)
vmMounts = append(vmMounts, cvm)
}
volumes, agentVolumeMounts = addRemoteWriteAssetsToVolumes(volumes, agentVolumeMounts, cr)
volumes, vmMounts = addRemoteWriteAssetsToVolumes(volumes, vmMounts, cr)
args = build.AddExtraArgsOverrideDefaults(args, cr.Spec.ExtraArgs, "-")
sort.Strings(args)

Expand All @@ -433,7 +435,7 @@ func newPodSpec(cr *vmv1.VLAgent) (*corev1.PodSpec, error) {
Args: args,
Env: envs,
EnvFrom: cr.Spec.ExtraEnvsFrom,
VolumeMounts: agentVolumeMounts,
VolumeMounts: vmMounts,
Resources: cr.Spec.Resources,
TerminationMessagePolicy: corev1.TerminationMessageFallbackToLogsOnError,
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,9 @@ func buildVLStorageSTSSpec(cr *vmv1.VLCluster) (*appsv1.StatefulSet, error) {
}
build.StatefulSetAddCommonParams(stsSpec, &cr.Spec.VLStorage.CommonAppsParams)
storageSpec := cr.Spec.VLStorage.Storage
storageSpec.IntoSTSVolume(cr.Spec.VLStorage.GetStorageVolumeName(), &stsSpec.Spec)
if err := storageSpec.IntoSTSVolume(cr.Spec.VLStorage.GetStorageVolumeName(), &stsSpec.Spec); err != nil {
return nil, err
}
stsSpec.Spec.VolumeClaimTemplates = append(stsSpec.Spec.VolumeClaimTemplates, cr.Spec.VLStorage.ClaimTemplates...)

return stsSpec, nil
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,7 @@ func makePodSpec(r *vmv1.VLSingle) (*corev1.PodTemplateSpec, error) {
ClaimName: r.PrefixedName(),
}
}
volumes, vmMounts, err := build.StorageVolumeMountsTo(r.Spec.Volumes, r.Spec.VolumeMounts, pvcSrc, storagePath, build.DataVolumeName)
volumes, vmMounts, err := build.StorageVolumeMountsTo(r.Spec.Volumes, r.Spec.VolumeMounts, pvcSrc, storagePath, build.DataVolumeName, false)
if err != nil {
return nil, err
}
Expand Down
49 changes: 17 additions & 32 deletions internal/controller/operator/factory/vmagent/vmagent.go
Original file line number Diff line number Diff line change
Expand Up @@ -426,7 +426,9 @@ func newK8sApp(cr *vmv1beta1.VMAgent, ac *build.AssetsCache) (client.Object, err
}
build.StatefulSetAddCommonParams(stsSpec, &cr.Spec.CommonAppsParams)
stsSpec.Spec.Template.Spec.Volumes = build.AddServiceAccountTokenVolume(stsSpec.Spec.Template.Spec.Volumes, &cr.Spec.CommonAppsParams)
cr.Spec.StatefulStorage.IntoSTSVolume(persistentQueueMountName, &stsSpec.Spec)
if err := cr.Spec.StatefulStorage.IntoSTSVolume(persistentQueueMountName, &stsSpec.Spec); err != nil {
return nil, err
}
stsSpec.Spec.VolumeClaimTemplates = append(stsSpec.Spec.VolumeClaimTemplates, cr.Spec.ClaimTemplates...)
return stsSpec, nil
}
Expand Down Expand Up @@ -523,35 +525,19 @@ func newPodSpec(cr *vmv1beta1.VMAgent, ac *build.AssetsCache) (*corev1.PodSpec,
ports = append(ports, corev1.ContainerPort{Name: "http", Protocol: "TCP", ContainerPort: intstr.Parse(cr.Spec.Port).IntVal})
ports = build.AppendInsertPorts(ports, cr.Spec.InsertPorts)

var agentVolumeMounts []corev1.VolumeMount
var crMounts []corev1.VolumeMount
// mount data path any way, even if user changes its value
// we cannot rely on value of remoteWriteSettings.
pqMountPath := persistentQueueDir
if cr.Spec.StatefulMode {
pqMountPath = persistentQueueSTSDir
}
agentVolumeMounts = append(agentVolumeMounts,
corev1.VolumeMount{
Name: persistentQueueMountName,
MountPath: pqMountPath,
},
)
agentVolumeMounts = append(agentVolumeMounts, cr.Spec.VolumeMounts...)

var volumes []corev1.Volume
// in case for sts, we have to use persistentVolumeClaimTemplate instead
if !cr.Spec.StatefulMode {
volumes = append(volumes, corev1.Volume{
Name: persistentQueueMountName,
VolumeSource: corev1.VolumeSource{
EmptyDir: &corev1.EmptyDirVolumeSource{},
},
})
volumes, vmMounts, err := build.StorageVolumeMountsTo(cr.Spec.Volumes, cr.Spec.VolumeMounts, nil, pqMountPath, persistentQueueMountName, cr.Spec.StatefulMode)
if err != nil {
return nil, fmt.Errorf("cannot configure persistent queue volume: %w", err)
}

volumes = append(volumes, cr.Spec.Volumes...)

if !ptr.Deref(cr.Spec.IngestOnlyMode, false) {
args = append(args,
fmt.Sprintf("-promscrape.config=%s", path.Join(confOutDir, configFilename)))
Expand Down Expand Up @@ -588,23 +574,23 @@ func newPodSpec(cr *vmv1beta1.VMAgent, ac *build.AssetsCache) (*corev1.PodSpec,
}
crMounts = append(crMounts, m)
m.ReadOnly = true
agentVolumeMounts = append(agentVolumeMounts, m)
agentVolumeMounts = append(agentVolumeMounts, corev1.VolumeMount{
vmMounts = append(vmMounts, m)
vmMounts = append(vmMounts, corev1.VolumeMount{
Name: string(build.TLSAssetsResourceKind),
MountPath: tlsAssetsDir,
ReadOnly: true,
})
agentVolumeMounts = append(agentVolumeMounts, corev1.VolumeMount{
vmMounts = append(vmMounts, corev1.VolumeMount{
Name: string(build.SecretConfigResourceKind),
MountPath: confDir,
ReadOnly: true,
})

}
mountsLen := len(agentVolumeMounts)
volumes, agentVolumeMounts = build.StreamAggrVolumeTo(volumes, agentVolumeMounts, cr)
volumes, agentVolumeMounts = build.RelabelVolumeTo(volumes, agentVolumeMounts, cr)
crMounts = append(crMounts, agentVolumeMounts[mountsLen:]...)
mountsLen := len(vmMounts)
volumes, vmMounts = build.StreamAggrVolumeTo(volumes, vmMounts, cr)
volumes, vmMounts = build.RelabelVolumeTo(volumes, vmMounts, cr)
crMounts = append(crMounts, vmMounts[mountsLen:]...)
for _, s := range cr.Spec.Secrets {
volumes = append(volumes, corev1.Volume{
Name: k8stools.SanitizeVolumeName("secret-" + s),
Expand All @@ -614,7 +600,7 @@ func newPodSpec(cr *vmv1beta1.VMAgent, ac *build.AssetsCache) (*corev1.PodSpec,
},
},
})
agentVolumeMounts = append(agentVolumeMounts, corev1.VolumeMount{
vmMounts = append(vmMounts, corev1.VolumeMount{
Name: k8stools.SanitizeVolumeName("secret-" + s),
ReadOnly: true,
MountPath: path.Join(vmv1beta1.SecretsDir, s),
Expand All @@ -637,11 +623,11 @@ func newPodSpec(cr *vmv1beta1.VMAgent, ac *build.AssetsCache) (*corev1.PodSpec,
ReadOnly: true,
MountPath: path.Join(vmv1beta1.ConfigMapsDir, c),
}
agentVolumeMounts = append(agentVolumeMounts, cvm)
vmMounts = append(vmMounts, cvm)
crMounts = append(crMounts, cvm)
}

volumes, agentVolumeMounts = build.LicenseVolumeTo(volumes, agentVolumeMounts, cr.Spec.License, vmv1beta1.SecretsDir)
volumes, vmMounts = build.LicenseVolumeTo(volumes, vmMounts, cr.Spec.License, vmv1beta1.SecretsDir)
args = build.LicenseArgsTo(args, cr.Spec.License, vmv1beta1.SecretsDir)

relabelKeys := []string{globalRelabelingName}
Expand All @@ -664,7 +650,7 @@ func newPodSpec(cr *vmv1beta1.VMAgent, ac *build.AssetsCache) (*corev1.PodSpec,
Args: args,
Env: envs,
EnvFrom: cr.Spec.ExtraEnvsFrom,
VolumeMounts: agentVolumeMounts,
VolumeMounts: vmMounts,
Resources: cr.Spec.Resources,
TerminationMessagePolicy: corev1.TerminationMessageFallbackToLogsOnError,
}
Expand All @@ -691,7 +677,6 @@ func newPodSpec(cr *vmv1beta1.VMAgent, ac *build.AssetsCache) (*corev1.PodSpec,
configReloader := build.ConfigReloaderContainer(false, cr, crMounts, ss)
operatorContainers = append(operatorContainers, configReloader)
}
var err error
ic, err = k8stools.MergePatchContainers(ic, cr.Spec.InitContainers)
if err != nil {
return nil, fmt.Errorf("cannot apply patch for initContainers: %w", err)
Expand Down
Loading
Loading