github.com/docker/app@v0.9.1-beta3.0.20210611140623-a48f773ab002/internal/bundle/parameters.go (about) 1 package bundle 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "io" 7 "os" 8 "strings" 9 10 "github.com/deislabs/cnab-go/bundle" 11 "github.com/docker/app/internal" 12 "github.com/docker/app/internal/packager" 13 "github.com/docker/app/internal/store" 14 "github.com/docker/app/types/parameters" 15 cliopts "github.com/docker/cli/opts" 16 "github.com/pkg/errors" 17 ) 18 19 // MergeBundleConfig is the actual parameters and bundle parameters to be merged 20 type MergeBundleConfig struct { 21 bundle *bundle.Bundle 22 params map[string]string 23 stderr io.Writer 24 } 25 26 // MergeBundleOpt is a functional option of the bundle parameter merge function 27 type MergeBundleOpt func(c *MergeBundleConfig) error 28 29 func WithFileParameters(parametersFiles []string) MergeBundleOpt { 30 return func(c *MergeBundleConfig) error { 31 p, err := parameters.LoadFiles(parametersFiles) 32 if err != nil { 33 return err 34 } 35 for k, v := range p.Flatten() { 36 c.params[k] = v 37 } 38 return nil 39 } 40 } 41 42 func WithCommandLineParameters(overrides []string) MergeBundleOpt { 43 return func(c *MergeBundleConfig) error { 44 d := cliopts.ConvertKVStringsToMap(overrides) 45 for k, v := range d { 46 c.params[k] = v 47 } 48 return nil 49 } 50 } 51 52 func WithLabels(labels []string) MergeBundleOpt { 53 return func(c *MergeBundleConfig) error { 54 for _, l := range labels { 55 if strings.HasPrefix(l, internal.Namespace) { 56 return errors.Errorf("labels cannot start with %q", internal.Namespace) 57 } 58 } 59 l := packager.DockerAppArgs{ 60 Labels: cliopts.ConvertKVStringsToMap(labels), 61 } 62 out, err := json.Marshal(l) 63 if err != nil { 64 return err 65 } 66 if _, ok := c.bundle.Parameters[internal.ParameterArgs]; ok { 67 c.params[internal.ParameterArgs] = string(out) 68 } 69 return nil 70 } 71 } 72 73 func WithSendRegistryAuth(sendRegistryAuth bool) MergeBundleOpt { 74 return func(c *MergeBundleConfig) error { 75 if _, ok := c.bundle.Definitions[internal.ParameterShareRegistryCredsName]; ok { 76 val := "false" 77 if sendRegistryAuth { 78 val = "true" 79 } 80 c.params[internal.ParameterShareRegistryCredsName] = val 81 } 82 return nil 83 } 84 } 85 86 func WithOrchestratorParameters(orchestrator string, kubeNamespace string) MergeBundleOpt { 87 return func(c *MergeBundleConfig) error { 88 if _, ok := c.bundle.Definitions[internal.ParameterOrchestratorName]; ok { 89 c.params[internal.ParameterOrchestratorName] = orchestrator 90 } 91 if _, ok := c.bundle.Definitions[internal.ParameterKubernetesNamespaceName]; ok { 92 c.params[internal.ParameterKubernetesNamespaceName] = kubeNamespace 93 } 94 return nil 95 } 96 } 97 98 func WithErrorWriter(w io.Writer) MergeBundleOpt { 99 return func(c *MergeBundleConfig) error { 100 c.stderr = w 101 return nil 102 } 103 } 104 105 // MergeBundleParameters merges current, provided and bundle default parameters 106 func MergeBundleParameters(installation *store.Installation, ops ...MergeBundleOpt) error { 107 bndl := installation.Bundle 108 if installation.Parameters == nil { 109 installation.Parameters = make(map[string]interface{}) 110 } 111 userParams := map[string]string{} 112 cfg := &MergeBundleConfig{ 113 bundle: bndl, 114 params: userParams, 115 stderr: os.Stderr, 116 } 117 118 for _, op := range ops { 119 if err := op(cfg); err != nil { 120 return err 121 } 122 } 123 mergedValues, err := matchAndMergeParametersDefinition(installation.Parameters, cfg) 124 if err != nil { 125 return err 126 } 127 installation.Parameters, err = bundle.ValuesOrDefaults(mergedValues, bndl) 128 return err 129 } 130 131 func matchAndMergeParametersDefinition(currentValues map[string]interface{}, cfg *MergeBundleConfig) (map[string]interface{}, error) { 132 mergedValues := make(map[string]interface{}) 133 for k, v := range currentValues { 134 mergedValues[k] = v 135 } 136 for k, v := range cfg.params { 137 param, ok := cfg.bundle.Parameters[k] 138 if !ok { 139 fmt.Fprintf(cfg.stderr, "Warning: parameter %q is not defined in the bundle\n", k) 140 continue 141 } 142 definition, ok := cfg.bundle.Definitions[param.Definition] 143 if !ok { 144 return nil, fmt.Errorf("invalid bundle: definition not found for parameter %q", k) 145 } 146 value, err := definition.ConvertValue(v) 147 if err != nil { 148 return nil, errors.Wrapf(err, "invalid value for parameter %q", k) 149 } 150 valErrors, err := definition.Validate(value) 151 if valErrors != nil { 152 errs := make([]string, len(valErrors)) 153 for i, v := range valErrors { 154 errs[i] = v.Error 155 } 156 errMsg := strings.Join(errs, ", ") 157 return nil, errors.Wrapf(fmt.Errorf(errMsg), "invalid value for parameter %q", k) 158 } 159 if err != nil { 160 return nil, errors.Wrapf(err, "invalid value for parameter %q", k) 161 } 162 mergedValues[k] = value 163 } 164 return mergedValues, nil 165 }