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, ":")