Skip to content

Commit dc71d16

Browse files
committed
Improve applying installation parameters without reparsing as flags
Do not re-parse parameters set on an installation resource as --param flags and instead apply any --param flag overrides on top of parameters defined on the installation. This changes the current behavior which would remove any parameter overrides set on an installation resource when the overrides were not re-specified with --param. Example: ``` porter install mybuns --param logLevel=10 porter installation show mybuns -o yaml > mybuns.yaml porter installation apply mybuns.yaml ``` Signed-off-by: Carolyn Van Slyck <[email protected]>
1 parent 902da0c commit dc71d16

File tree

6 files changed

+89
-42
lines changed

6 files changed

+89
-42
lines changed

pkg/porter/install.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ func (p *Porter) InstallBundle(ctx context.Context, opts InstallOptions) error {
101101
// Users are expected to edit the installation record if they don't want that behavior.
102102
func (p *Porter) applyActionOptionsToInstallation(ctx context.Context, i *storage.Installation, opts *BundleExecutionOptions) error {
103103
// Record the parameters specified by the user, with flags taking precedence over parameter set values
104-
err := opts.LoadParameters(ctx, p, opts.bundleRef.Definition)
104+
err := opts.LoadParameters(ctx, p, opts.bundleRef.Definition, i.Parameters)
105105
if err != nil {
106106
return err
107107
}

pkg/porter/lifecycle.go

+20-14
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ func (o *BundleExecutionOptions) Validate(ctx context.Context, args []string, p
102102

103103
// LoadParameters validates and resolves the parameters and sets. It must be
104104
// called after porter has loaded the bundle definition.
105-
func (o *BundleExecutionOptions) LoadParameters(ctx context.Context, p *Porter, bun cnab.ExtendedBundle) error {
105+
func (o *BundleExecutionOptions) LoadParameters(ctx context.Context, p *Porter, bun cnab.ExtendedBundle, internalPs storage.ParameterSet) error {
106106
// This is called in multiple code paths, so exit early if
107107
// we have already loaded the parameters into combinedParameters
108108
if o.combinedParameters != nil {
@@ -114,7 +114,7 @@ func (o *BundleExecutionOptions) LoadParameters(ctx context.Context, p *Porter,
114114
return err
115115
}
116116

117-
err = o.parseParamSets(ctx, p, bun)
117+
err = o.parseParamSets(ctx, p, bun, internalPs)
118118
if err != nil {
119119
return err
120120
}
@@ -135,33 +135,39 @@ func (o *BundleExecutionOptions) parseParams() error {
135135
return nil
136136
}
137137

138-
func (o *BundleExecutionOptions) populateInternalParameterSet(ctx context.Context, p *Porter, bun cnab.ExtendedBundle, i *storage.Installation) error {
138+
func (o *BundleExecutionOptions) populateInternalParameterSet(ctx context.Context, p *Porter, bun cnab.ExtendedBundle, inst *storage.Installation) error {
139139
strategies := make([]secrets.Strategy, 0, len(o.parsedParams))
140140
for name, value := range o.parsedParams {
141141
strategies = append(strategies, storage.ValueStrategy(name, value))
142142
}
143143

144-
strategies, err := p.Sanitizer.CleanParameters(ctx, strategies, bun, i.ID)
144+
strategies, err := p.Sanitizer.CleanParameters(ctx, strategies, bun, inst.ID)
145145
if err != nil {
146146
return err
147147
}
148148

149-
if len(strategies) == 0 {
150-
// if no override is specified, clear out the old parameters on the
151-
// installation record
152-
i.Parameters.Parameters = nil
153-
return nil
154-
}
149+
for _, paramOverride := range strategies {
150+
replaced := false
151+
for i, existingParam := range inst.Parameters.Parameters {
152+
if paramOverride.Name == existingParam.Name {
153+
inst.Parameters.Parameters[i] = paramOverride
154+
replaced = true
155+
break
156+
}
157+
}
155158

156-
i.Parameters = i.NewInternalParameterSet(strategies...)
159+
if !replaced {
160+
inst.Parameters.Parameters = append(inst.Parameters.Parameters, paramOverride)
161+
}
162+
}
157163

158164
return nil
159165
}
160166

161167
// parseParamSets parses the variable assignments in ParameterSets.
162-
func (o *BundleExecutionOptions) parseParamSets(ctx context.Context, p *Porter, bun cnab.ExtendedBundle) error {
168+
func (o *BundleExecutionOptions) parseParamSets(ctx context.Context, p *Porter, bun cnab.ExtendedBundle, internalPs storage.ParameterSet) error {
163169
if len(o.ParameterSets) > 0 {
164-
parsed, err := p.loadParameterSets(ctx, bun, o.Namespace, o.ParameterSets)
170+
parsed, err := p.loadParameterSets(ctx, bun, o.Namespace, o.ParameterSets, internalPs)
165171
if err != nil {
166172
return fmt.Errorf("unable to process provided parameter sets: %w", err)
167173
}
@@ -358,7 +364,7 @@ func (p *Porter) BuildActionArgs(ctx context.Context, installation storage.Insta
358364

359365
// Resolve the final set of typed parameters, taking into account the user overrides, parameter sources
360366
// and defaults
361-
err = opts.LoadParameters(ctx, p, opts.bundleRef.Definition)
367+
err = opts.LoadParameters(ctx, p, opts.bundleRef.Definition, installation.Parameters)
362368
if err != nil {
363369
return bundleruntime.ActionArguments{}, err
364370
}

pkg/porter/lifecycle_test.go

+52-8
Original file line numberDiff line numberDiff line change
@@ -252,7 +252,7 @@ func TestBundleExecutionOptions_ParseParamSets(t *testing.T) {
252252
err := opts.Validate(ctx, []string{}, p.Porter)
253253
assert.NoError(t, err)
254254

255-
err = opts.parseParamSets(ctx, p.Porter, cnab.ExtendedBundle{})
255+
err = opts.parseParamSets(ctx, p.Porter, cnab.ExtendedBundle{}, storage.ParameterSet{})
256256
assert.NoError(t, err)
257257

258258
wantParams := map[string]string{
@@ -282,7 +282,7 @@ func TestBundleExecutionOptions_ParseParamSets_Failed(t *testing.T) {
282282
err = opts.Validate(ctx, []string{}, p.Porter)
283283
assert.NoError(t, err)
284284

285-
err = opts.parseParamSets(ctx, p.Porter, bun)
285+
err = opts.parseParamSets(ctx, p.Porter, bun, storage.ParameterSet{})
286286
assert.Error(t, err)
287287

288288
}
@@ -302,7 +302,7 @@ func TestBundleExecutionOptions_LoadParameters(t *testing.T) {
302302
opts := NewBundleExecutionOptions()
303303
opts.Params = []string{"my-first-param=1", "my-second-param=2"}
304304

305-
err = opts.LoadParameters(context.Background(), p.Porter, bun)
305+
err = opts.LoadParameters(context.Background(), p.Porter, bun, storage.ParameterSet{})
306306
require.NoError(t, err)
307307

308308
assert.Len(t, opts.Params, 2)
@@ -383,11 +383,11 @@ func TestBundleExecutionOptions_populateInternalParameterSet(t *testing.T) {
383383
opts := NewBundleExecutionOptions()
384384
opts.Params = []string{nonsensitiveParamName + "=" + nonsensitiveParamValue, sensitiveParamName + "=" + sensitiveParamValue}
385385

386-
err = opts.LoadParameters(ctx, p.Porter, bun)
387-
require.NoError(t, err)
388-
389386
i := storage.NewInstallation("", bun.Name)
390387

388+
err = opts.LoadParameters(ctx, p.Porter, bun, i.Parameters)
389+
require.NoError(t, err)
390+
391391
err = opts.populateInternalParameterSet(ctx, p.Porter, bun, &i)
392392
require.NoError(t, err)
393393

@@ -408,10 +408,54 @@ func TestBundleExecutionOptions_populateInternalParameterSet(t *testing.T) {
408408
// as well
409409
opts.combinedParameters = nil
410410
opts.Params = make([]string, 0)
411-
err = opts.LoadParameters(ctx, p.Porter, bun)
411+
err = opts.LoadParameters(ctx, p.Porter, bun, i.Parameters)
412+
require.NoError(t, err)
413+
err = opts.populateInternalParameterSet(ctx, p.Porter, bun, &i)
414+
require.NoError(t, err)
415+
416+
// Check that when no parameter overrides are specified, we use the originally specified parameters from the previous run
417+
require.Len(t, i.Parameters.Parameters, 2)
418+
require.Equal(t, "my-first-param", i.Parameters.Parameters[0].Name)
419+
require.Equal(t, "1", i.Parameters.Parameters[0].Source.Value)
420+
require.Equal(t, "my-second-param", i.Parameters.Parameters[1].Name)
421+
require.Equal(t, "secret", i.Parameters.Parameters[1].Source.Key)
422+
}
423+
424+
func TestBundleExecutionOptions_populateInternalParameterSet_ExistingParams(t *testing.T) {
425+
p := NewTestPorter(t)
426+
defer p.Close()
427+
428+
ctx := context.Background()
429+
430+
p.TestConfig.TestContext.AddTestFile("testdata/porter.yaml", config.Name)
431+
m, err := manifest.LoadManifestFrom(context.Background(), p.Config, config.Name)
432+
require.NoError(t, err)
433+
bun, err := configadapter.ConvertToTestBundle(ctx, p.Config, m)
412434
require.NoError(t, err)
435+
436+
nonsensitiveParamName := "my-first-param"
437+
nonsensitiveParamValue := "3"
438+
opts := NewBundleExecutionOptions()
439+
opts.Params = []string{nonsensitiveParamName + "=" + nonsensitiveParamValue}
440+
441+
i := storage.NewInstallation("", bun.Name)
442+
i.Parameters = storage.NewParameterSet("", "internal-ps",
443+
storage.ValueStrategy("my-first-param", "1"),
444+
storage.ValueStrategy("my-second-param", "2"),
445+
)
446+
err = opts.LoadParameters(ctx, p.Porter, bun, i.Parameters)
447+
require.NoError(t, err)
448+
413449
err = opts.populateInternalParameterSet(ctx, p.Porter, bun, &i)
414450
require.NoError(t, err)
415451

416-
require.Len(t, i.Parameters.Parameters, 0)
452+
require.Len(t, i.Parameters.Parameters, 2)
453+
454+
// Check that overrides are applied on top of existing parameters
455+
require.Len(t, i.Parameters.Parameters, 2)
456+
require.Equal(t, "my-first-param", i.Parameters.Parameters[0].Name)
457+
require.Equal(t, "3", i.Parameters.Parameters[0].Source.Value)
458+
require.Equal(t, "my-second-param", i.Parameters.Parameters[1].Name)
459+
require.Equal(t, "value", i.Parameters.Parameters[1].Source.Key)
460+
require.Equal(t, "2", i.Parameters.Parameters[1].Source.Value)
417461
}

pkg/porter/list.go

+4-7
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,7 @@ func (d DisplayInstallation) ConvertToInstallation() (storage.Installation, erro
168168
}
169169

170170
var err error
171-
i.Parameters, err = d.ConvertParamToSet(i)
171+
i.Parameters, err = d.ConvertParamToSet()
172172
if err != nil {
173173
return storage.Installation{}, err
174174
}
@@ -182,18 +182,15 @@ func (d DisplayInstallation) ConvertToInstallation() (storage.Installation, erro
182182
}
183183

184184
// ConvertParamToSet converts a Parameters into a internal ParameterSet.
185-
func (d DisplayInstallation) ConvertParamToSet(i storage.Installation) (storage.ParameterSet, error) {
185+
func (d DisplayInstallation) ConvertParamToSet() (storage.ParameterSet, error) {
186186
strategies := make([]secrets.Strategy, 0, len(d.Parameters))
187187
for name, value := range d.Parameters {
188188
stringVal, err := cnab.WriteParameterToString(name, value)
189189
if err != nil {
190190
return storage.ParameterSet{}, err
191191
}
192-
strategy := secrets.Strategy{
193-
Name: name,
194-
Value: stringVal,
195-
}
196-
strategies = append(strategies, strategy)
192+
193+
strategies = append(strategies, storage.ValueStrategy(name, stringVal))
197194
}
198195

199196
return storage.NewInternalParameterSet(d.Namespace, d.Name, strategies...), nil

pkg/porter/parameters.go

+12-2
Original file line numberDiff line numberDiff line change
@@ -343,10 +343,11 @@ func validateParameterName(args []string) error {
343343
}
344344

345345
// loadParameterSets loads parameter values per their parameter set strategies
346-
func (p *Porter) loadParameterSets(ctx context.Context, bun cnab.ExtendedBundle, namespace string, params []string) (secrets.Set, error) {
346+
func (p *Porter) loadParameterSets(ctx context.Context, bun cnab.ExtendedBundle, namespace string, params []string, internalPs storage.ParameterSet) (secrets.Set, error) {
347347
resolvedParameters := secrets.Set{}
348-
for _, name := range params {
349348

349+
// First apply all named parameter sets
350+
for _, name := range params {
350351
// Try to get the params in the local namespace first, fallback to the global creds
351352
query := storage.FindOptions{
352353
Sort: []string{"-namespace"},
@@ -398,6 +399,15 @@ func (p *Porter) loadParameterSets(ctx context.Context, bun cnab.ExtendedBundle,
398399
}
399400
}
400401

402+
// Then resolve the installation's internal parameter set and apply it on top
403+
rc, err := p.Parameters.ResolveAll(ctx, internalPs)
404+
if err != nil {
405+
return nil, err
406+
}
407+
for k, v := range rc {
408+
resolvedParameters[k] = v
409+
}
410+
401411
return resolvedParameters, nil
402412
}
403413

pkg/porter/reconcile.go

-10
Original file line numberDiff line numberDiff line change
@@ -73,24 +73,14 @@ func (p *Porter) ReconcileInstallation(ctx context.Context, opts ReconcileOption
7373
lifecycleOpts.Name = opts.Name
7474
lifecycleOpts.Namespace = opts.Namespace
7575
lifecycleOpts.CredentialIdentifiers = opts.Installation.CredentialSets
76-
7776
lifecycleOpts.ParameterSets = opts.Installation.ParameterSets
78-
lifecycleOpts.Params = make([]string, 0, len(opts.Installation.Parameters.Parameters))
7977

8078
// Write out the parameters as string values. Not efficient but reusing ExecuteAction would need more refactoring otherwise
8179
_, err = p.resolveBundleReference(ctx, lifecycleOpts.BundleReferenceOptions)
8280
if err != nil {
8381
return err
8482
}
8583

86-
for _, param := range opts.Installation.Parameters.Parameters {
87-
lifecycleOpts.Params = append(lifecycleOpts.Params, fmt.Sprintf("%s=%s", param.Name, param.Value))
88-
}
89-
90-
if err := p.applyActionOptionsToInstallation(ctx, &opts.Installation, lifecycleOpts); err != nil {
91-
return err
92-
}
93-
9484
if !opts.DryRun {
9585
if err = p.Installations.UpsertInstallation(ctx, opts.Installation); err != nil {
9686
return err

0 commit comments

Comments
 (0)