From f0663bfa87bb164ad288c8a49f73bcad12e16a81 Mon Sep 17 00:00:00 2001 From: Antonin Stefanutti Date: Wed, 1 Mar 2023 12:51:00 +0100 Subject: [PATCH] feat(cli): Support setting maps in traits API --- pkg/cmd/trait_support.go | 24 ++++++++++++++++++++---- pkg/trait/trait_catalog.go | 6 +++++- pkg/util/util.go | 19 +++++++++++++++---- 3 files changed, 40 insertions(+), 9 deletions(-) diff --git a/pkg/cmd/trait_support.go b/pkg/cmd/trait_support.go index 6e8abfa222..a85cc2080a 100644 --- a/pkg/cmd/trait_support.go +++ b/pkg/cmd/trait_support.go @@ -36,7 +36,7 @@ type optionMap map[string]map[string]interface{} // The list of known addons is used for handling backward compatibility. var knownAddons = []string{"keda", "master", "strimzi", "3scale", "tracing"} -var traitConfigRegexp = regexp.MustCompile(`^([a-z0-9-]+)((?:\.[a-z0-9-]+)(?:\[[0-9]+\]|\.[A-Za-z0-9-_]+)*)=(.*)$`) +var traitConfigRegexp = regexp.MustCompile(`^([a-z0-9-]+)((?:\.[a-z0-9-]+)(?:\[[0-9]+\]|\..+)*)=(.*)$`) func validateTraits(catalog *trait.Catalog, traits []string) error { tp := catalog.ComputeTraitsProperties() @@ -46,7 +46,9 @@ func validateTraits(catalog *trait.Catalog, traits []string) error { if strings.Contains(prefix, "[") { prefix = prefix[0:strings.Index(prefix, "[")] } - if !util.StringSliceExists(tp, prefix) { + if valid, err := validateTrait(tp, prefix); err != nil { + return err + } else if !valid { return fmt.Errorf("%s is not a valid trait property", t) } } @@ -54,18 +56,32 @@ func validateTraits(catalog *trait.Catalog, traits []string) error { return nil } +func validateTrait(properties []string, item string) (bool, error) { + for i := 0; i < len(properties); i++ { + if strings.HasSuffix(properties[i], ".*") { + if match, err := regexp.MatchString(properties[i], item); err != nil { + return false, err + } else if match { + return true, nil + } + } else if properties[i] == item { + return true, nil + } + } + + return false, nil +} + func configureTraits(options []string, traits interface{}, catalog trait.Finder) error { config, err := optionsToMap(options) if err != nil { return err } - // // Known addons need to be put aside here, as otherwise the deprecated addon fields on // Traits might be accidentally populated. The deprecated addon fields are preserved // for backward compatibility and should be populated only when the operator reads // existing CRs from the API server. - // addons := make(optionMap) for _, id := range knownAddons { if config[id] != nil { diff --git a/pkg/trait/trait_catalog.go b/pkg/trait/trait_catalog.go index 5acbaf94c4..6992abd268 100644 --- a/pkg/trait/trait_catalog.go +++ b/pkg/trait/trait_catalog.go @@ -182,7 +182,11 @@ func (c *Catalog) processFields(fields []*structs.Field, processor func(string)) if property != "" { items := strings.Split(property, ",") - processor(items[0]) + if f.Kind() == reflect.Map { + processor(items[0] + ".*") + } else { + processor(items[0]) + } } } } diff --git a/pkg/util/util.go b/pkg/util/util.go index 750aada65d..28de402f3b 100644 --- a/pkg/util/util.go +++ b/pkg/util/util.go @@ -93,7 +93,7 @@ var QuarkusDependenciesBaseDirectory = "/quarkus-app" // These are sensitive values or values that may have different values depending on // where the integration is run (locally vs. the cloud). These environment variables // are evaluated at the time of the integration invocation. -var ListOfLazyEvaluatedEnvVars = []string{} +var ListOfLazyEvaluatedEnvVars []string // CLIEnvVars -- List of CLI provided environment variables. They take precedence over // any environment variables with the same name. @@ -645,12 +645,14 @@ func WithTempDir(pattern string, consumer func(string) error) error { return multierr.Append(consumerErr, removeErr) } -// Parses a property spec and returns its parts. +var propertyRegex = regexp.MustCompile("'.+'|\".+\"|[^.]+") + +// ConfigTreePropertySplit Parses a property spec and returns its parts. func ConfigTreePropertySplit(property string) []string { var res = make([]string, 0) - initialParts := strings.Split(property, ".") + initialParts := propertyRegex.FindAllString(property, -1) for _, p := range initialParts { - cur := p + cur := trimQuotes(p) var tmp []string for strings.Contains(cur[1:], "[") && strings.HasSuffix(cur, "]") { pos := strings.LastIndex(cur, "[") @@ -667,6 +669,15 @@ func ConfigTreePropertySplit(property string) []string { return res } +func trimQuotes(s string) string { + if len(s) >= 2 { + if c := s[len(s)-1]; s[0] == c && (c == '"' || c == '\'') { + return s[1 : len(s)-1] + } + } + return s +} + // NavigateConfigTree switch to the element in the tree represented by the "nodes" spec and creates intermediary // nodes if missing. Nodes specs starting with "[" and ending in "]" are treated as slice indexes. func NavigateConfigTree(current interface{}, nodes []string) (interface{}, error) {