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

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

commit 1f958527c5b1db1ed27b99e93c857a3d16f8716d
Author: Pasquale Congiusti <[email protected]>
AuthorDate: Wed Jun 2 15:24:59 2021 +0200

    feat(cmd/run): resource @path support
    
    Adding the possibility to specify the destination path for any resource
    
    Ref #2003
---
 pkg/apis/camel/v1/common_types.go              |  8 ++++--
 pkg/apis/camel/v1/integration_types_support.go | 11 ++++----
 pkg/cmd/run.go                                 |  2 +-
 pkg/cmd/run_help.go                            | 35 ++++++++++++++++++------
 pkg/cmd/run_help_test.go                       |  6 ++++
 pkg/cmd/run_test.go                            |  8 +++---
 pkg/trait/trait_types.go                       | 38 +++++++++++++++++---------
 pkg/trait/util.go                              |  1 +
 8 files changed, 74 insertions(+), 35 deletions(-)

diff --git a/pkg/apis/camel/v1/common_types.go 
b/pkg/apis/camel/v1/common_types.go
index 6b2cda8..42a23fa 100644
--- a/pkg/apis/camel/v1/common_types.go
+++ b/pkg/apis/camel/v1/common_types.go
@@ -26,9 +26,10 @@ const TraitAnnotationPrefix = "trait.camel.apache.org/"
 
 // ConfigurationSpec --
 type ConfigurationSpec struct {
-       Type         string `json:"type"`
-       Value        string `json:"value"`
-       ResourceType string `json:"resourceType,omitempty"`
+       Type               string `json:"type"`
+       Value              string `json:"value"`
+       ResourceType       string `json:"resourceType,omitempty"`
+       ResourceMountPoint string `json:"resourceMountPoint,omitempty"`
 }
 
 // Artifact --
@@ -232,6 +233,7 @@ const (
 // DataSpec --
 type DataSpec struct {
        Name        string `json:"name,omitempty"`
+       Path        string `json:"path,omitempty"`
        Content     string `json:"content,omitempty"`
        RawContent  []byte `json:"rawContent,omitempty"`
        ContentRef  string `json:"contentRef,omitempty"`
diff --git a/pkg/apis/camel/v1/integration_types_support.go 
b/pkg/apis/camel/v1/integration_types_support.go
index acf3bd6..8c2d3e5 100644
--- a/pkg/apis/camel/v1/integration_types_support.go
+++ b/pkg/apis/camel/v1/integration_types_support.go
@@ -109,12 +109,13 @@ func (in *IntegrationSpec) AddConfiguration(confType 
string, confValue string) {
        })
 }
 
-// AddConfigurationAsResourceType will set a configuration specified with a 
resource type
-func (in *IntegrationSpec) AddConfigurationAsResourceType(confType string, 
confValue string, resourceType string) {
+// AddConfigurationAsResource will set a configuration specified with a 
resource type
+func (in *IntegrationSpec) AddConfigurationAsResource(confType string, 
confValue string, resourceType string, resourceMountPoint string) {
        in.Configuration = append(in.Configuration, ConfigurationSpec{
-               Type:         confType,
-               Value:        confValue,
-               ResourceType: resourceType,
+               Type:               confType,
+               Value:              confValue,
+               ResourceType:       resourceType,
+               ResourceMountPoint: resourceMountPoint,
        })
 }
 
diff --git a/pkg/cmd/run.go b/pkg/cmd/run.go
index ad0485d..6e4c373 100644
--- a/pkg/cmd/run.go
+++ b/pkg/cmd/run.go
@@ -82,7 +82,7 @@ func newCmdRun(rootCmdOptions *RootCmdOptions) 
(*cobra.Command, *runCmdOptions)
        cmd.Flags().StringArrayP("property", "p", nil, "Add a runtime property 
or properties file (syntax: 
[my-key=my-value|file:/path/to/my-conf.properties])")
        cmd.Flags().StringArray("build-property", nil, "Add a build time 
property or properties file (syntax: 
[my-key=my-value|file:/path/to/my-conf.properties])")
        cmd.Flags().StringArray("config", nil, "Add a runtime configuration 
from a Configmap, a Secret or a file (syntax: [configmap|secret|file]:name)")
-       cmd.Flags().StringArray("resource", nil, "Add a runtime resource from a 
Configmap, a Secret or a file (syntax: [configmap|secret|file]:name)")
+       cmd.Flags().StringArray("resource", nil, "Add a runtime resource from a 
Configmap, a Secret or a file (syntax: [configmap|secret|file]:name[@path])")
        cmd.Flags().StringArray("configmap", nil, "[Deprecated] Add a 
ConfigMap")
        cmd.Flags().StringArray("secret", nil, "[Deprecated] Add a Secret")
        cmd.Flags().StringArray("maven-repository", nil, "Add a maven 
repository")
diff --git a/pkg/cmd/run_help.go b/pkg/cmd/run_help.go
index ca36a91..12264c2 100644
--- a/pkg/cmd/run_help.go
+++ b/pkg/cmd/run_help.go
@@ -31,8 +31,14 @@ import (
 
 // RunConfigOption represents a config option
 type RunConfigOption struct {
-       ConfigType configOptionType
-       Value      string
+       ConfigType      configOptionType
+       Value           string
+       destinationPath string
+}
+
+// DestinationPath is the location where the resource will be stored on 
destination
+func (runConfigOption *RunConfigOption) DestinationPath() string {
+       return runConfigOption.destinationPath
 }
 
 type configOptionType string
@@ -46,13 +52,23 @@ const (
        ConfigOptionTypeFile configOptionType = "file"
 )
 
-var validConfigRegexp = 
regexp.MustCompile(`^(configmap|secret|file)\:([\w\.\-\_\:\/]+)$`)
+var validConfigRegexp = 
regexp.MustCompile(`^(configmap|secret|file)\:([\w\.\-\_\:\/@]+)$`)
 
 func newRunConfigOption(configType configOptionType, value string) 
*RunConfigOption {
+       optionValue, maybeDestinationPath := parseFileValue(value)
        return &RunConfigOption{
-               ConfigType: configType,
-               Value:      value,
+               ConfigType:      configType,
+               Value:           optionValue,
+               destinationPath: maybeDestinationPath,
+       }
+}
+
+func parseFileValue(value string) (string, string) {
+       split := strings.SplitN(value, "@", 2)
+       if len(split) == 2 {
+               return split[0], split[1]
        }
+       return value, ""
 }
 
 // ParseResourceOption will parse and return a runConfigOption
@@ -107,14 +123,14 @@ func applyOption(config *RunConfigOption, integrationSpec 
*v1.IntegrationSpec,
                } else if resourceType != v1.ResourceTypeData && cm.BinaryData 
!= nil {
                        return fmt.Errorf("you cannot provide a binary config, 
use a text file instead")
                }
-               
integrationSpec.AddConfigurationAsResourceType(string(config.ConfigType), 
config.Value, string(resourceType))
+               
integrationSpec.AddConfigurationAsResource(string(config.ConfigType), 
config.Value, string(resourceType), config.DestinationPath())
        case ConfigOptionTypeSecret:
                secret := kubernetes.LookupSecret(context.Background(), c, 
namespace, config.Value)
                if secret == nil {
                        fmt.Printf("Warn: %s Secret not found in %s namespace, 
make sure to provide it before the Integration can run\n",
                                config.Value, namespace)
                }
-               
integrationSpec.AddConfigurationAsResourceType(string(config.ConfigType), 
config.Value, string(resourceType))
+               
integrationSpec.AddConfigurationAsResource(string(config.ConfigType), 
config.Value, string(resourceType), config.DestinationPath())
        case ConfigOptionTypeFile:
                // Don't allow a binary non compressed resource
                rawData, contentType, err := loadRawContent(config.Value)
@@ -124,7 +140,7 @@ func applyOption(config *RunConfigOption, integrationSpec 
*v1.IntegrationSpec,
                if resourceType != v1.ResourceTypeData && !enableCompression && 
isBinary(contentType) {
                        return fmt.Errorf("you cannot provide a binary config, 
use a text file or check --resource flag instead")
                }
-               resourceSpec, err := 
binaryOrTextResource(path.Base(config.Value), rawData, contentType, 
enableCompression, resourceType)
+               resourceSpec, err := 
binaryOrTextResource(path.Base(config.Value), rawData, contentType, 
enableCompression, resourceType, config.DestinationPath())
                if err != nil {
                        return err
                }
@@ -147,10 +163,11 @@ func ApplyResourceOption(config *RunConfigOption, 
integrationSpec *v1.Integratio
        return applyOption(config, integrationSpec, c, namespace, 
enableCompression, v1.ResourceTypeData)
 }
 
-func binaryOrTextResource(fileName string, data []byte, contentType string, 
base64Compression bool, resourceType v1.ResourceType) (v1.ResourceSpec, error) {
+func binaryOrTextResource(fileName string, data []byte, contentType string, 
base64Compression bool, resourceType v1.ResourceType, destinationPath string) 
(v1.ResourceSpec, error) {
        resourceSpec := v1.ResourceSpec{
                DataSpec: v1.DataSpec{
                        Name:        fileName,
+                       Path:        destinationPath,
                        ContentKey:  fileName,
                        ContentType: contentType,
                        Compression: false,
diff --git a/pkg/cmd/run_help_test.go b/pkg/cmd/run_help_test.go
index 39d67f0..5eab301 100644
--- a/pkg/cmd/run_help_test.go
+++ b/pkg/cmd/run_help_test.go
@@ -28,6 +28,7 @@ func TestParseConfigOption(t *testing.T) {
        validSecret := "secret:my-secret"
        validFile := "file:/tmp/my-file.txt"
        notValid := "someprotocol:wrong"
+       validLocation := "file:my-file.txt@/tmp/another-name.xml"
 
        configmap, err := ParseConfigOption(validConfigMap)
        assert.Nil(t, err)
@@ -43,4 +44,9 @@ func TestParseConfigOption(t *testing.T) {
        assert.Equal(t, "/tmp/my-file.txt", file.Value)
        _, err = ParseConfigOption(notValid)
        assert.NotNil(t, err)
+       location, err := ParseConfigOption(validLocation)
+       assert.Nil(t, err)
+       assert.Equal(t, ConfigOptionTypeFile, location.ConfigType)
+       assert.Equal(t, "my-file.txt", location.Value)
+       assert.Equal(t, "/tmp/another-name.xml", location.DestinationPath())
 }
diff --git a/pkg/cmd/run_test.go b/pkg/cmd/run_test.go
index 7d1f8cd..bae4c9d 100644
--- a/pkg/cmd/run_test.go
+++ b/pkg/cmd/run_test.go
@@ -487,7 +487,7 @@ func TestRunWithSavedValues(t *testing.T) {
 }*/
 
 func TestRunBinaryResource(t *testing.T) {
-       binaryResourceSpec, err := binaryOrTextResource("file.ext", []byte{1, 
2, 3, 4}, "application/octet-stream", false, v1.ResourceTypeData)
+       binaryResourceSpec, err := binaryOrTextResource("file.ext", []byte{1, 
2, 3, 4}, "application/octet-stream", false, v1.ResourceTypeData, "")
        assert.Nil(t, err)
        assert.Equal(t, "", binaryResourceSpec.Content)
        assert.NotNil(t, binaryResourceSpec.RawContent)
@@ -499,7 +499,7 @@ func TestRunBinaryResource(t *testing.T) {
 func TestRunBinaryCompressedResource(t *testing.T) {
        data := []byte{1, 2, 3, 4}
        base64Compressed, _ := compressToString(data)
-       binaryResourceSpec, err := binaryOrTextResource("file.ext", data, 
"application/octet-stream", true, v1.ResourceTypeData)
+       binaryResourceSpec, err := binaryOrTextResource("file.ext", data, 
"application/octet-stream", true, v1.ResourceTypeData, "")
        assert.Nil(t, err)
        assert.Equal(t, base64Compressed, binaryResourceSpec.Content)
        assert.Nil(t, binaryResourceSpec.RawContent)
@@ -509,7 +509,7 @@ func TestRunBinaryCompressedResource(t *testing.T) {
 }
 
 func TestRunTextResource(t *testing.T) {
-       textResourceSpec, err := binaryOrTextResource("file.ext", []byte("hello 
world"), "text/plain", false, v1.ResourceTypeData)
+       textResourceSpec, err := binaryOrTextResource("file.ext", []byte("hello 
world"), "text/plain", false, v1.ResourceTypeData, "")
        assert.Nil(t, err)
        assert.Equal(t, "hello world", textResourceSpec.Content)
        assert.Nil(t, textResourceSpec.RawContent)
@@ -521,7 +521,7 @@ func TestRunTextResource(t *testing.T) {
 func TestRunTextCompressedResource(t *testing.T) {
        data := []byte("hello horld")
        base64Compressed, _ := compressToString(data)
-       textResourceSpec, err := binaryOrTextResource("file.ext", []byte("hello 
horld"), "text/plain", true, v1.ResourceTypeData)
+       textResourceSpec, err := binaryOrTextResource("file.ext", []byte("hello 
horld"), "text/plain", true, v1.ResourceTypeData, "")
        assert.Nil(t, err)
        assert.Equal(t, base64Compressed, textResourceSpec.Content)
        assert.Nil(t, textResourceSpec.RawContent)
diff --git a/pkg/trait/trait_types.go b/pkg/trait/trait_types.go
index 2786f25..9049fe0 100644
--- a/pkg/trait/trait_types.go
+++ b/pkg/trait/trait_types.go
@@ -613,8 +613,7 @@ func (e *Environment) configureVolumesAndMounts(vols 
*[]corev1.Volume, mnts *[]c
                refName := fmt.Sprintf("i-resource-%03d", i)
                resName := strings.TrimPrefix(r.Name, "/")
                cmKey := "content"
-               resourceMountPoint := getResourceMountPoint(r.Type)
-               resPath := path.Join(resourceMountPoint, resName)
+               resPath := getResourcePath(resName, r.Path, r.Type)
 
                if r.ContentRef != "" {
                        cmName = r.ContentRef
@@ -711,7 +710,7 @@ func (e *Environment) configureVolumesAndMounts(vols 
*[]corev1.Volume, mnts *[]c
 
                *mnts = append(*mnts, corev1.VolumeMount{
                        Name:      refName,
-                       MountPath: 
path.Join(getConfigmapMountPoint(configmaps["resourceType"]), 
strings.ToLower(configmaps["value"])),
+                       MountPath: getConfigmapMountPoint(configmaps["value"], 
configmaps["resourceMountPoint"], configmaps["resourceType"]),
                        ReadOnly:  true,
                })
        }
@@ -751,7 +750,7 @@ func (e *Environment) configureVolumesAndMounts(vols 
*[]corev1.Volume, mnts *[]c
 
                *mnts = append(*mnts, corev1.VolumeMount{
                        Name:      refName,
-                       MountPath: 
path.Join(getSecretMountPoint(secret["resourceType"]), 
strings.ToLower(secret["value"])),
+                       MountPath: getSecretMountPoint(secret["value"], 
secret["resourceMountPoint"], secret["resourceType"]),
                        ReadOnly:  true,
                })
        }
@@ -786,31 +785,44 @@ func (e *Environment) configureVolumesAndMounts(vols 
*[]corev1.Volume, mnts *[]c
        }
 }
 
-func getResourceMountPoint(resourceType v1.ResourceType) string {
+func getResourcePath(resourceName string, maybePath string, resourceType 
v1.ResourceType) string {
+       // If the path is specified, we'll return it
+       if maybePath != "" {
+               return maybePath
+       }
+       // otherwise return a default path, according to the resource type
        switch resourceType {
        case v1.ResourceTypeData:
-               return dataResourcesMountPath
+               return path.Join(dataResourcesMountPath, resourceName)
        }
        // Default, config type
-       return configResourcesMountPath
+       return path.Join(configResourcesMountPath, resourceName)
 }
 
-func getConfigmapMountPoint(resourceType string) string {
+func getConfigmapMountPoint(resourceName string, maybeMountPoint string, 
resourceType string) string {
+       // If the mount point is specified, we'll return it
+       if maybeMountPoint != "" {
+               return maybeMountPoint
+       }
        switch resourceType {
        case "data":
-               return dataConfigmapsMountPath
+               return path.Join(dataConfigmapsMountPath, resourceName)
        }
        // Default, config type
-       return configConfigmapsMountPath
+       return path.Join(configConfigmapsMountPath, resourceName)
 }
 
-func getSecretMountPoint(resourceType string) string {
+func getSecretMountPoint(resourceName string, maybeMountPoint string, 
resourceType string) string {
+       // If the mount point is specified, we'll return it
+       if maybeMountPoint != "" {
+               return maybeMountPoint
+       }
        switch resourceType {
        case "data":
-               return dataSecretsMountPath
+               return path.Join(dataSecretsMountPath, resourceName)
        }
        // Default, config type
-       return configSecretsMountPath
+       return path.Join(configSecretsMountPath, resourceName)
 }
 
 func (e *Environment) collectConfigurationValues(configurationType string) 
[]string {
diff --git a/pkg/trait/util.go b/pkg/trait/util.go
index 4a2dc5d..0f5d936 100644
--- a/pkg/trait/util.go
+++ b/pkg/trait/util.go
@@ -97,6 +97,7 @@ func collectConfigurations(configurationType string, 
configurable ...v1.Configur
                                var item = make(map[string]string)
                                item["value"] = entry.Value
                                item["resourceType"] = entry.ResourceType
+                               item["resourceMountPoint"] = 
entry.ResourceMountPoint
                                result = append(result, item)
                        }
                }

Reply via email to