This is an automated email from the ASF dual-hosted git repository.

pcongiusti pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel-k.git


The following commit(s) were added to refs/heads/main by this push:
     new f5e245ab2 feat(#5864): Added configuration for sizeLimit on empty-dirs 
in mount trait (#5865)
f5e245ab2 is described below

commit f5e245ab2855746ed0692b9bfc7810d88b1fbcdb
Author: Hernan Guardado <[email protected]>
AuthorDate: Thu Oct 24 12:19:45 2024 -0400

    feat(#5864): Added configuration for sizeLimit on empty-dirs in mount trait 
(#5865)
    
    * Added configuration for sizeLimit on empty-dirs in mount trait
    
    * refactored emptydir logic to within mount trait
    
    * Adding documetation
    
    * changing method signature
    
    * chore(ci): lint
    
    ---------
    
    Co-authored-by: hernan-abi <[email protected]>
    Co-authored-by: Pasquale Congiusti <[email protected]>
---
 pkg/apis/camel/v1/trait/mount.go |  3 +-
 pkg/trait/mount.go               | 44 ++++++++++++++++++++++++++----
 pkg/trait/mount_test.go          | 59 ++++++++++++++++++++++++++++++++++++++--
 pkg/trait/trait_types.go         |  9 ------
 pkg/util/resource/config.go      | 15 ----------
 5 files changed, 96 insertions(+), 34 deletions(-)

diff --git a/pkg/apis/camel/v1/trait/mount.go b/pkg/apis/camel/v1/trait/mount.go
index 6fa83b745..9521a05b9 100644
--- a/pkg/apis/camel/v1/trait/mount.go
+++ b/pkg/apis/camel/v1/trait/mount.go
@@ -36,7 +36,8 @@ type MountTrait struct {
        // You can use the syntax 
[pvcname:/container/path:size:accessMode<:storageClass>] to create a dynamic 
PVC based on the Storage Class provided
        // or the default cluster Storage Class. However, if the PVC exists, 
the operator would mount it.
        Volumes []string `property:"volumes" json:"volumes,omitempty"`
-       // A list of EmptyDir volumes to be mounted. Syntax: 
[name:/container/path]
+       // A list of EmptyDir volumes to be mounted. An optional size limit may 
be configured (default 500Mi).
+       // Syntax: name:/container/path[:sizeLimit]
        EmptyDirs []string `property:"empty-dirs" json:"emptyDirs,omitempty"`
        // Enable "hot reload" when a secret/configmap mounted is edited 
(default `false`). The configmap/secret must be
        // marked with `camel.apache.org/integration` label to be taken in 
account. The resource will be watched for any kind change, also for
diff --git a/pkg/trait/mount.go b/pkg/trait/mount.go
index b15c9765d..38a770382 100644
--- a/pkg/trait/mount.go
+++ b/pkg/trait/mount.go
@@ -27,7 +27,6 @@ import (
        batchv1 "k8s.io/api/batch/v1"
        corev1 "k8s.io/api/core/v1"
        storagev1 "k8s.io/api/storage/v1"
-       "k8s.io/apimachinery/pkg/api/resource"
        metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 
        serving "knative.dev/serving/pkg/apis/serving/v1"
@@ -40,6 +39,7 @@ import (
        "github.com/apache/camel-k/v2/pkg/util/log"
        "github.com/apache/camel-k/v2/pkg/util/property"
        utilResource "github.com/apache/camel-k/v2/pkg/util/resource"
+       "k8s.io/apimachinery/pkg/api/resource"
 )
 
 const (
@@ -166,11 +166,12 @@ func (t *mountTrait) configureVolumesAndMounts(e 
*Environment, vols *[]corev1.Vo
                *mnts = append(*mnts, *volumeMount)
        }
        for _, v := range t.EmptyDirs {
-               if vol, parseErr := utilResource.ParseEmptyDirVolume(v); 
parseErr == nil {
-                       t.mountResource(vols, mnts, vol)
-               } else {
+               volume, volumeMount, parseErr := ParseEmptyDirVolume(v)
+               if parseErr != nil {
                        return parseErr
                }
+               *vols = append(*vols, *volume)
+               *mnts = append(*mnts, *volumeMount)
        }
 
        return nil
@@ -261,8 +262,7 @@ func (t *mountTrait) mountResource(vols *[]corev1.Volume, 
mnts *[]corev1.VolumeM
        vol := getVolume(refName, string(conf.StorageType()), conf.Name(), 
conf.Key(), dstFile)
        mntPath := getMountPoint(conf.Name(), dstDir, 
string(conf.StorageType()), string(conf.ContentType()))
        readOnly := true
-       if conf.StorageType() == utilResource.StorageTypePVC ||
-               conf.StorageType() == utilResource.StorageTypeEmptyDir {
+       if conf.StorageType() == utilResource.StorageTypePVC {
                readOnly = false
        }
        mnt := getMount(refName, mntPath, dstFile, readOnly)
@@ -281,6 +281,38 @@ func (t *mountTrait) addServiceBindingSecret(e 
*Environment) {
        })
 }
 
+// ParseEmptyDirVolume will parse and return an empty-dir volume.
+func ParseEmptyDirVolume(item string) (*corev1.Volume, *corev1.VolumeMount, 
error) {
+       volumeParts := strings.Split(item, ":")
+
+       if len(volumeParts) != 2 && len(volumeParts) != 3 {
+               return nil, nil, fmt.Errorf("could not match emptyDir volume as 
%s", item)
+       }
+
+       refName := kubernetes.SanitizeLabel(volumeParts[0])
+       sizeLimit := "500Mi"
+       if len(volumeParts) == 3 {
+               sizeLimit = volumeParts[2]
+       }
+
+       parsed, err := resource.ParseQuantity(sizeLimit)
+       if err != nil {
+               return nil, nil, fmt.Errorf("could not parse sizeLimit from 
emptyDir volume: %s", volumeParts[2])
+       }
+
+       volume := &corev1.Volume{
+               Name: refName,
+               VolumeSource: corev1.VolumeSource{
+                       EmptyDir: &corev1.EmptyDirVolumeSource{
+                               SizeLimit: &parsed,
+                       },
+               },
+       }
+
+       volumeMount := getMount(refName, volumeParts[1], "", false)
+       return volume, volumeMount, nil
+}
+
 // ParseAndCreateVolume will parse a volume configuration. If the volume does 
not exist it tries to create one based on the storage
 // class configuration provided or default.
 // item is expected to be as: 
name:path/to/mount<:size:accessMode<:storageClassName>>.
diff --git a/pkg/trait/mount_test.go b/pkg/trait/mount_test.go
index 701380193..2adaff9a4 100644
--- a/pkg/trait/mount_test.go
+++ b/pkg/trait/mount_test.go
@@ -136,14 +136,67 @@ func TestEmptyDirVolumeIntegrationPhaseDeploying(t 
*testing.T) {
        assert.Len(t, spec.Containers[0].VolumeMounts, 3)
        assert.Len(t, spec.Volumes, 3)
 
+       var emptyDirVolume *corev1.Volume
+       for _, v := range spec.Volumes {
+               if v.Name == "my-empty-dir" {
+                       emptyDirVolume = &v
+                       break
+               }
+       }
+
+       assert.NotNil(t, emptyDirVolume)
+       // Default applied by operator
+       assert.Equal(t, "500Mi", emptyDirVolume.EmptyDir.SizeLimit.String())
+
        assert.Condition(t, func() bool {
-               for _, v := range spec.Volumes {
-                       if v.Name == "my-empty-dir" {
-                               return true
+               for _, container := range spec.Containers {
+                       if container.Name == "integration" {
+                               for _, volumeMount := range 
container.VolumeMounts {
+                                       if volumeMount.Name == "my-empty-dir" {
+                                               return true
+                                       }
+                               }
                        }
                }
                return false
        })
+}
+
+func TestEmptyDirVolumeWithSizeLimitIntegrationPhaseDeploying(t *testing.T) {
+       traitCatalog := NewCatalog(nil)
+
+       environment := getNominalEnv(t, traitCatalog)
+       environment.Integration.Spec.Traits.Mount = &traitv1.MountTrait{
+               EmptyDirs: []string{"my-empty-dir:/some/path:450Mi"},
+       }
+       environment.Platform.ResyncStatusFullConfig()
+       conditions, traits, err := traitCatalog.apply(environment)
+
+       require.NoError(t, err)
+       assert.NotEmpty(t, traits)
+       assert.NotEmpty(t, conditions)
+       assert.NotEmpty(t, environment.ExecutedTraits)
+       assert.NotNil(t, environment.GetTrait("mount"))
+
+       deployment := environment.Resources.GetDeployment(func(service 
*appsv1.Deployment) bool {
+               return service.Name == "hello"
+       })
+       assert.NotNil(t, deployment)
+       spec := deployment.Spec.Template.Spec
+
+       assert.Len(t, spec.Containers[0].VolumeMounts, 3)
+       assert.Len(t, spec.Volumes, 3)
+
+       var emptyDirVolume *corev1.Volume
+       for _, v := range spec.Volumes {
+               if v.Name == "my-empty-dir" {
+                       emptyDirVolume = &v
+                       break
+               }
+       }
+       assert.NotNil(t, emptyDirVolume)
+       assert.Equal(t, "450Mi", emptyDirVolume.EmptyDir.SizeLimit.String())
+
        assert.Condition(t, func() bool {
                for _, container := range spec.Containers {
                        if container.Name == "integration" {
diff --git a/pkg/trait/trait_types.go b/pkg/trait/trait_types.go
index edb3bb271..ed681f716 100644
--- a/pkg/trait/trait_types.go
+++ b/pkg/trait/trait_types.go
@@ -28,7 +28,6 @@ import (
        appsv1 "k8s.io/api/apps/v1"
        batchv1 "k8s.io/api/batch/v1"
        corev1 "k8s.io/api/core/v1"
-       "k8s.io/apimachinery/pkg/api/resource"
 
        serving "knative.dev/serving/pkg/apis/serving/v1"
 
@@ -440,14 +439,6 @@ func getVolume(volName, storageType, storageName, 
filterKey, filterValue string)
                volume.VolumeSource.PersistentVolumeClaim = 
&corev1.PersistentVolumeClaimVolumeSource{
                        ClaimName: storageName,
                }
-       case emptyDirStorageType:
-               size, err := resource.ParseQuantity("1Gi")
-               if err != nil {
-                       log.WithValues("Function", 
"trait.getVolume").Errorf(err, "could not parse empty dir quantity, skipping")
-               }
-               volume.VolumeSource.EmptyDir = &corev1.EmptyDirVolumeSource{
-                       SizeLimit: &size,
-               }
        }
 
        return &volume
diff --git a/pkg/util/resource/config.go b/pkg/util/resource/config.go
index 1bb34af7d..61c61217f 100644
--- a/pkg/util/resource/config.go
+++ b/pkg/util/resource/config.go
@@ -136,21 +136,6 @@ func ParseResource(item string) (*Config, error) {
        return parse(item, ContentTypeData)
 }
 
-// ParseEmptyDirVolume will parse an empty dir volume and return a Config.
-func ParseEmptyDirVolume(item string) (*Config, error) {
-       configParts := strings.Split(item, ":")
-
-       if len(configParts) != 2 {
-               return nil, fmt.Errorf("could not match emptyDir volume as %s", 
item)
-       }
-
-       return &Config{
-               storageType:     StorageTypeEmptyDir,
-               resourceName:    configParts[0],
-               destinationPath: configParts[1],
-       }, nil
-}
-
 // ParseVolume will parse a volume and return a Config.
 func ParseVolume(item string) (*Config, error) {
        configParts := strings.Split(item, ":")

Reply via email to