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

commit d7282d5c16c30c48b94cd96de302e946ece8fb0d
Author: Pasquale Congiusti <[email protected]>
AuthorDate: Thu Dec 2 10:13:43 2021 +0100

    feat(cmd/run): convert --resource/--config to related trait
---
 pkg/cmd/run.go                   | 48 ++++++++++++++++++++--------------
 pkg/cmd/run_help.go              | 56 ++++++++++++++--------------------------
 pkg/trait/container.go           |  4 ++-
 pkg/trait/trait_types.go         | 29 +++++++--------------
 pkg/util/resource/config.go      | 43 ++++++++++++------------------
 pkg/util/resource/config_test.go | 15 -----------
 6 files changed, 77 insertions(+), 118 deletions(-)

diff --git a/pkg/cmd/run.go b/pkg/cmd/run.go
index 5ff377e..fcebe0b 100644
--- a/pkg/cmd/run.go
+++ b/pkg/cmd/run.go
@@ -570,29 +570,35 @@ func (o *runCmdOptions) createOrUpdateIntegration(cmd 
*cobra.Command, c client.C
        }
 
        generatedConfigmaps := make([]*corev1.ConfigMap, 0)
-
        for _, res := range o.Resources {
-               if config, parseErr := resource.ParseResource(res); parseErr == 
nil {
-                       if genCm, applyResourceOptionErr := 
ApplyResourceOption(o.Context, config, integration, c, namespace, 
o.Compression); applyResourceOptionErr != nil {
-                               return nil, applyResourceOptionErr
-                       } else if genCm != nil {
-                               generatedConfigmaps = 
append(generatedConfigmaps, genCm)
-                       }
-               } else {
-                       return nil, parseErr
+               config, err := resource.ParseResource(res)
+               if err != nil {
+                       return nil, err
                }
+               // We try to autogenerate a configmap
+               maybeGenCm, err := parseConfigAndGenCm(o.Context, c, config, 
integration, o.Compression)
+               if err != nil {
+                       return nil, err
+               }
+               if maybeGenCm != nil {
+                       generatedConfigmaps = append(generatedConfigmaps, 
maybeGenCm)
+               }
+               o.Traits = append(o.Traits, convertToTrait(config.String(), 
"container.resources"))
        }
-
-       for _, item := range o.Configs {
-               if config, parseErr := resource.ParseConfig(item); parseErr == 
nil {
-                       if genCm, applyConfigOptionErr := 
ApplyConfigOption(o.Context, config, integration, c, namespace, o.Compression); 
applyConfigOptionErr != nil {
-                               return nil, applyConfigOptionErr
-                       } else if genCm != nil {
-                               generatedConfigmaps = 
append(generatedConfigmaps, genCm)
-                       }
-               } else {
-                       return nil, parseErr
+       for _, conf := range o.Configs {
+               config, err := resource.ParseResource(conf)
+               if err != nil {
+                       return nil, err
+               }
+               // We try to autogenerate a configmap
+               maybeGenCm, err := parseConfigAndGenCm(o.Context, c, config, 
integration, o.Compression)
+               if err != nil {
+                       return nil, err
+               }
+               if maybeGenCm != nil {
+                       generatedConfigmaps = append(generatedConfigmaps, 
maybeGenCm)
                }
+               o.Traits = append(o.Traits, convertToTrait(config.String(), 
"container.configs"))
        }
 
        for _, resource := range o.OpenAPIs {
@@ -714,6 +720,10 @@ func addResource(ctx context.Context, resourceLocation 
string, integrationSpec *
        return nil
 }
 
+func convertToTrait(value, traitParameter string) string {
+       return fmt.Sprintf("%s=%s", traitParameter, value)
+}
+
 func convertToTraitParameter(value, traitParameter string) ([]string, error) {
        traits := make([]string, 0)
        props, err := extractProperties(value)
diff --git a/pkg/cmd/run_help.go b/pkg/cmd/run_help.go
index dcbacf5..e9f9758 100644
--- a/pkg/cmd/run_help.go
+++ b/pkg/cmd/run_help.go
@@ -44,65 +44,47 @@ func hashFrom(contents ...[]byte) string {
        return fmt.Sprintf("%x", hash.Sum(nil))
 }
 
-// ApplyConfigOption will set the proper --config option behavior to the 
IntegrationSpec.
-func ApplyConfigOption(ctx context.Context, config *resource.Config, 
integration *v1.Integration, c client.Client,
-       namespace string, enableCompression bool) (*corev1.ConfigMap, error) {
-       // A config option cannot specify destination path
-       if config.DestinationPath() != "" {
-               return nil, fmt.Errorf("cannot specify a destination path for 
this option type")
-       }
-       return applyOption(ctx, config, integration, c, namespace, 
enableCompression, v1.ResourceTypeConfig)
-}
-
-// ApplyResourceOption will set the proper --resource option behavior to the 
IntegrationSpec.
-func ApplyResourceOption(ctx context.Context, config *resource.Config, 
integration *v1.Integration, c client.Client,
-       namespace string, enableCompression bool) (*corev1.ConfigMap, error) {
-       return applyOption(ctx, config, integration, c, namespace, 
enableCompression, v1.ResourceTypeData)
-}
-
-func applyOption(ctx context.Context, config *resource.Config, integration 
*v1.Integration,
-       c client.Client, namespace string, enableCompression bool, resourceType 
v1.ResourceType) (*corev1.ConfigMap, error) {
-       var maybeGenCm *corev1.ConfigMap
+func parseConfigAndGenCm(ctx context.Context, c client.Client, config 
*resource.Config, integration *v1.Integration, enableCompression bool) 
(*corev1.ConfigMap, error) {
        switch config.StorageType() {
        case resource.StorageTypeConfigmap:
-               cm := kubernetes.LookupConfigmap(ctx, c, namespace, 
config.Name())
+               cm := kubernetes.LookupConfigmap(ctx, c, integration.Namespace, 
config.Name())
                if cm == nil {
                        fmt.Printf("Warn: %s Configmap not found in %s 
namespace, make sure to provide it before the Integration can run\n",
-                               config.Name(), namespace)
-               } else if resourceType != v1.ResourceTypeData && cm.BinaryData 
!= nil {
-                       return maybeGenCm, fmt.Errorf("you cannot provide a 
binary config, use a text file instead")
+                               config.Name(), integration.Namespace)
+               } else if config.ContentType() != resource.ContentTypeData && 
cm.BinaryData != nil {
+                       return nil, fmt.Errorf("you cannot provide a binary 
config, use a text file instead")
                }
        case resource.StorageTypeSecret:
-               secret := kubernetes.LookupSecret(ctx, c, namespace, 
config.Name())
+               secret := kubernetes.LookupSecret(ctx, c, 
integration.Namespace, config.Name())
                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.Name(), namespace)
+                               config.Name(), integration.Namespace)
                }
        case resource.StorageTypeFile:
                // Don't allow a binary non compressed resource
                rawData, contentType, err := loadRawContent(ctx, config.Name())
                if err != nil {
-                       return maybeGenCm, err
+                       return nil, err
                }
-               if resourceType != v1.ResourceTypeData && !enableCompression && 
isBinary(contentType) {
-                       return maybeGenCm, fmt.Errorf("you cannot provide a 
binary config, use a text file or check --resource flag instead")
+               if config.ContentType() != resource.ContentTypeData && 
!enableCompression && isBinary(contentType) {
+                       return nil, fmt.Errorf("you cannot provide a binary 
config, use a text file or check --resource flag instead")
                }
-               resourceSpec, err := 
binaryOrTextResource(path.Base(config.Name()), rawData, contentType, 
enableCompression, resourceType, config.DestinationPath())
-               if err != nil {
-                       return maybeGenCm, err
+               resourceType := v1.ResourceTypeData
+               if config.ContentType() == resource.ContentTypeText {
+                       resourceType = v1.ResourceTypeConfig
                }
-               maybeGenCm, err = resource.ConvertFileToConfigmap(ctx, c, 
resourceSpec, config, integration.Namespace, integration.Name, resourceType)
+               resourceSpec, err := 
binaryOrTextResource(path.Base(config.Name()), rawData, contentType, 
enableCompression, resourceType, config.DestinationPath())
                if err != nil {
-                       return maybeGenCm, err
+                       return nil, err
                }
+
+               return resource.ConvertFileToConfigmap(ctx, c, config, 
integration.Namespace, integration.Name, resourceSpec.Content, 
resourceSpec.RawContent)
        default:
                // Should never reach this
-               return maybeGenCm, fmt.Errorf("invalid option type %s", 
config.StorageType())
+               return nil, fmt.Errorf("invalid option type %s", 
config.StorageType())
        }
 
-       
integration.Spec.AddConfigurationAsResource(string(config.StorageType()), 
config.Name(), string(resourceType), config.DestinationPath(), config.Key())
-
-       return maybeGenCm, nil
+       return nil, nil
 }
 
 func binaryOrTextResource(fileName string, data []byte, contentType string, 
base64Compression bool, resourceType v1.ResourceType, destinationPath string) 
(v1.ResourceSpec, error) {
diff --git a/pkg/trait/container.go b/pkg/trait/container.go
index cc0ca1b..ddbea8e 100644
--- a/pkg/trait/container.go
+++ b/pkg/trait/container.go
@@ -360,7 +360,9 @@ func (t *containerTrait) configureVolumesAndMounts(vols 
*[]corev1.Volume, mnts *
 func (t *containerTrait) mountResource(vols *[]corev1.Volume, mnts 
*[]corev1.VolumeMount, conf *utilResource.Config) {
        refName := kubernetes.SanitizeLabel(conf.Name())
        vol := getVolume(refName, string(conf.StorageType()), conf.Name(), 
conf.Key(), conf.Key())
-       mnt := getMount(refName, conf.DestinationPath(), "")
+       mntPath := getMountPoint(conf.Name(), conf.DestinationPath(), 
string(conf.StorageType()), string(conf.ContentType()))
+       // No need to specify a subpath, as we mount the entire configmap/secret
+       mnt := getMount(refName, mntPath, "")
 
        *vols = append(*vols, *vol)
        *mnts = append(*mnts, *mnt)
diff --git a/pkg/trait/trait_types.go b/pkg/trait/trait_types.go
index b83f986..9de2616 100644
--- a/pkg/trait/trait_types.go
+++ b/pkg/trait/trait_types.go
@@ -510,7 +510,7 @@ func (e *Environment) configureVolumesAndMounts(vols 
*[]corev1.Volume, mnts *[]c
        //
        for _, configmaps := range e.collectConfigurations("configmap") {
                refName := kubernetes.SanitizeLabel(configmaps["value"])
-               mountPath := getConfigmapMountPoint(configmaps["value"], 
configmaps["resourceMountPoint"], configmaps["resourceType"])
+               mountPath := getMountPoint(configmaps["value"], 
configmaps["resourceMountPoint"], "configmap", configmaps["resourceType"])
                vol := getVolume(refName, "configmap", configmaps["value"], 
configmaps["resourceKey"], configmaps["resourceKey"])
                mnt := getMount(refName, mountPath, "")
 
@@ -523,7 +523,7 @@ func (e *Environment) configureVolumesAndMounts(vols 
*[]corev1.Volume, mnts *[]c
        //
        for _, secret := range e.collectConfigurations("secret") {
                refName := kubernetes.SanitizeLabel(secret["value"])
-               mountPath := getSecretMountPoint(secret["value"], 
secret["resourceMountPoint"], secret["resourceType"])
+               mountPath := getMountPoint(secret["value"], 
secret["resourceMountPoint"], "secret", secret["resourceType"])
                vol := getVolume(refName, "secret", secret["value"], 
secret["resourceKey"], secret["resourceKey"])
                mnt := getMount(refName, mountPath, "")
 
@@ -633,30 +633,19 @@ func getResourcePath(resourceName string, maybePath 
string, resourceType v1.Reso
        return path.Join(camel.ConfigResourcesMountPath, resourceName)
 }
 
-func getConfigmapMountPoint(resourceName string, maybeMountPoint string, 
resourceType string) string {
-       // If the mount point is specified, we'll return it
-       if maybeMountPoint != "" {
-               return maybeMountPoint
+func getMountPoint(resourceName string, mountPoint string, storagetype, 
resourceType string) string {
+       if mountPoint != "" {
+               return mountPoint
        }
        if resourceType == "data" {
                return path.Join(camel.ResourcesDefaultMountPath, resourceName)
        }
-
-       // Default, config type
-       return path.Join(camel.ConfigConfigmapsMountPath, resourceName)
-}
-
-func getSecretMountPoint(resourceName string, maybeMountPoint string, 
resourceType string) string {
-       // If the mount point is specified, we'll return it
-       if maybeMountPoint != "" {
-               return maybeMountPoint
-       }
-       if resourceType == "data" {
-               return path.Join(camel.ResourcesDefaultMountPath, resourceName)
+       defaultMountPoint := camel.ConfigConfigmapsMountPath
+       if storagetype == "secret" {
+               defaultMountPoint = camel.ConfigSecretsMountPath
        }
 
-       // Default, config type
-       return path.Join(camel.ConfigSecretsMountPath, resourceName)
+       return path.Join(defaultMountPoint, resourceName)
 }
 
 func (e *Environment) collectConfigurationValues(configurationType string) 
[]string {
diff --git a/pkg/util/resource/config.go b/pkg/util/resource/config.go
index d900622..6a53b01 100644
--- a/pkg/util/resource/config.go
+++ b/pkg/util/resource/config.go
@@ -25,7 +25,6 @@ import (
        "regexp"
        "strings"
 
-       v1 "github.com/apache/camel-k/pkg/apis/camel/v1"
        "github.com/apache/camel-k/pkg/client"
        "github.com/apache/camel-k/pkg/util/camel"
        "github.com/apache/camel-k/pkg/util/kubernetes"
@@ -33,8 +32,6 @@ import (
        k8serrors "k8s.io/apimachinery/pkg/api/errors"
 )
 
-var invalidPaths = []string{"/etc/camel", "/deployments/dependencies"}
-
 // Config represents a config option.
 type Config struct {
        storageType     StorageType
@@ -69,19 +66,17 @@ func (config *Config) Key() string {
        return config.resourceKey
 }
 
-// Validate checks if the DestinationPath is correctly configured.
-func (config *Config) Validate() error {
-       if config.destinationPath == "" {
-               return nil
+// String represents the unparsed value of the resource.
+func (config *Config) String() string {
+       s := fmt.Sprintf("%s:%s", config.storageType, config.resourceName)
+       if config.resourceKey != "" {
+               s = fmt.Sprintf("%s/%s", s, config.resourceKey)
        }
-
-       // Check for invalid path
-       for _, invalidPath := range invalidPaths {
-               if config.destinationPath == invalidPath || 
strings.HasPrefix(config.destinationPath, invalidPath+"/") {
-                       return fmt.Errorf("you cannot mount a file under %s 
path", invalidPath)
-               }
+       if config.destinationPath != "" {
+               s = fmt.Sprintf("%s@%s", s, config.destinationPath)
        }
-       return nil
+
+       return s
 }
 
 // StorageType represent a resource/config type such as configmap, secret or 
local file.
@@ -153,7 +148,7 @@ func parseCMOrSecretValue(value string) (resource string, 
maybeKey string, maybe
        return groups[1], groups[3], groups[5]
 }
 
-// ParseResource will parse and return a Config.
+// ParseResource will parse a resource and return a Config.
 func ParseResource(item string) (*Config, error) {
        // Deprecated: ensure backward compatibility with `--resource filename` 
format until version 1.5.x
        // then replace with parse() func directly
@@ -169,7 +164,7 @@ func ParseResource(item string) (*Config, error) {
        return resource, nil
 }
 
-// ParseConfig will parse and return a Config.
+// ParseConfig will parse a config and return a Config.
 func ParseConfig(item string) (*Config, error) {
        return parse(item, ContentTypeText)
 }
@@ -197,24 +192,20 @@ func parse(item string, contentType ContentType) 
(*Config, error) {
                return nil, fmt.Errorf("could not match config, secret or file 
configuration as %s", item)
        }
 
-       configurationOption := newConfig(cot, contentType, value)
-       if err := configurationOption.Validate(); err != nil {
-               return nil, err
-       }
-       return configurationOption, nil
+       return newConfig(cot, contentType, value), nil
 }
 
 // ConvertFileToConfigmap convert a local file resource type in a configmap 
type
 // taking care to create the Configmap on the cluster. The method will change 
the value of config parameter
 // to reflect the conversion applied transparently.
-func ConvertFileToConfigmap(ctx context.Context, c client.Client, resourceSpec 
v1.ResourceSpec, config *Config,
-       namespace string, integrationName string, resourceType v1.ResourceType) 
(*corev1.ConfigMap, error) {
+func ConvertFileToConfigmap(ctx context.Context, c client.Client, config 
*Config, namespace string, integrationName string,
+       content string, rawContent []byte) (*corev1.ConfigMap, error) {
        if config.DestinationPath() == "" {
                config.resourceKey = filepath.Base(config.Name())
                // As we are changing the resource to a configmap type
                // we need to declare the mount path not to use the
                // default behavior of a configmap (which include a 
subdirectory with the configmap name)
-               if resourceType == v1.ResourceTypeData {
+               if config.ContentType() == ContentTypeData {
                        config.destinationPath = camel.ResourcesDefaultMountPath
                } else {
                        config.destinationPath = camel.ConfigResourcesMountPath
@@ -223,8 +214,8 @@ func ConvertFileToConfigmap(ctx context.Context, c 
client.Client, resourceSpec v
                config.resourceKey = filepath.Base(config.DestinationPath())
                config.destinationPath = filepath.Dir(config.DestinationPath())
        }
-       genCmName := fmt.Sprintf("cm-%s", hashFrom([]byte(integrationName), 
[]byte(resourceSpec.Content), resourceSpec.RawContent))
-       cm := kubernetes.NewConfigmap(namespace, genCmName, 
filepath.Base(config.Name()), config.Key(), resourceSpec.Content, 
resourceSpec.RawContent)
+       genCmName := fmt.Sprintf("cm-%s", hashFrom([]byte(integrationName), 
[]byte(content), rawContent))
+       cm := kubernetes.NewConfigmap(namespace, genCmName, 
filepath.Base(config.Name()), config.Key(), content, rawContent)
        err := c.Create(ctx, cm)
        if err != nil {
                if k8serrors.IsAlreadyExists(err) {
diff --git a/pkg/util/resource/config_test.go b/pkg/util/resource/config_test.go
index 5d7fb24..bb28d85 100644
--- a/pkg/util/resource/config_test.go
+++ b/pkg/util/resource/config_test.go
@@ -141,18 +141,3 @@ func TestParseConfigOptionAllParams(t *testing.T) {
        assert.Equal(t, "", parsedFile3.Key())
        assert.Equal(t, "", parsedFile3.DestinationPath())
 }
-
-func TestValidateFileLocation(t *testing.T) {
-       validLocation := "file:my-file.txt@/tmp/another-name.xml"
-       etcCamelLocation := "configmap:my-cm@/etc/camel/configmaps"
-       deploymentsDepsLocation := "secret:my-sec@/deployments/dependencies"
-
-       _, err := ParseConfig(validLocation)
-       assert.Nil(t, err)
-       _, err = ParseConfig(etcCamelLocation)
-       assert.NotNil(t, err)
-       assert.Equal(t, "you cannot mount a file under /etc/camel path", 
err.Error())
-       _, err = ParseConfig(deploymentsDepsLocation)
-       assert.NotNil(t, err)
-       assert.Equal(t, "you cannot mount a file under 
/deployments/dependencies path", err.Error())
-}

Reply via email to