Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Per phase pod override API #3320

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
feat: add phasePodOverrides to ActionSet definition to replace podOve…
…rride

Currently if ActionSet has multiple phases, all of them will use the same podOverride.

This change allows setting override per phase.

phasePodOverrides is a map with keys being phase names and values being overrides.
podOverride now should be deprecated, but until it's removed it will be used as default
unless phasePodOverride is defined for a specific phase

Signed-off-by: Daniil Fedotov <daniil.fedotov@kasten.io>
  • Loading branch information
hairyhum committed Jan 10, 2025
commit 06967bf49335087f7ce6d656945787ca8b007639
6 changes: 6 additions & 0 deletions pkg/apis/cr/v1alpha1/types.go
Original file line number Diff line number Diff line change
@@ -106,7 +106,13 @@ type ActionSpec struct {
RepositoryServer *ObjectReference `json:"repositoryServer,omitempty"`
// PodOverride is used to specify pod specs that will override the
// default pod specs
// DEPRECATED! please use PhasePodOverrides instead to specify overrides per phase
// If PhasePodOverrides is defined for a phase, it will replace this value
PodOverride JSONMap `json:"podOverride,omitempty"`
// PhasePodOverrides is used to specify pod specs that will override default
// specs for phases in the action.
// Keys should be phase names and values should be pod specs
PhasePodOverrides map[string]JSONMap `json:"phasePodOverrides,omitempty"`
// Options will be used to specify additional values
// to be used in the Blueprint.
Options map[string]string `json:"options,omitempty"`
31 changes: 18 additions & 13 deletions pkg/param/param.go
Original file line number Diff line number Diff line change
@@ -59,9 +59,13 @@ type TemplateParams struct {
Object map[string]interface{}
Phases map[string]*Phase
DeferPhase *Phase
PodOverride crv1alpha1.JSONMap
PodAnnotations map[string]string
PodLabels map[string]string
// PhasePodOverrides should be used to access pod override in a phase function
// using CurrentPhase value
PhasePodOverrides map[string]crv1alpha1.JSONMap
// PodOverride field should not be used and will be deprecated
PodOverride crv1alpha1.JSONMap
PodAnnotations map[string]string
PodLabels map[string]string
}

// DeploymentConfigParams are params for deploymentconfig, will be used if working on open shift cluster
@@ -194,16 +198,17 @@ func New(ctx context.Context, cli kubernetes.Interface, dynCli dynamic.Interface
}
now := time.Now().UTC()
tp := TemplateParams{
ArtifactsIn: as.Artifacts,
ConfigMaps: cms,
Secrets: secrets,
Profile: prof,
RepositoryServer: repoServer,
Time: now.Format(timeFormat),
Options: as.Options,
PodOverride: as.PodOverride,
PodAnnotations: as.PodAnnotations,
PodLabels: as.PodLabels,
ArtifactsIn: as.Artifacts,
ConfigMaps: cms,
Secrets: secrets,
Profile: prof,
RepositoryServer: repoServer,
Time: now.Format(timeFormat),
Options: as.Options,
PhasePodOverrides: as.PhasePodOverrides,
PodOverride: as.PodOverride,
PodAnnotations: as.PodAnnotations,
PodLabels: as.PodLabels,
}
var gvr schema.GroupVersionResource
namespace := as.Object.Namespace
17 changes: 17 additions & 0 deletions pkg/phase.go
Original file line number Diff line number Diff line change
@@ -59,6 +59,11 @@ func (p *Phase) Objects() map[string]crv1alpha1.ObjectReference {
// Exec renders the argument templates in this Phase's Func and executes with
// those arguments.
func (p *Phase) Exec(ctx context.Context, bp crv1alpha1.Blueprint, action string, tp param.TemplateParams) (map[string]interface{}, error) {
// Prepare phase-specific template params
// TODO: in the future we might create a separate type for phase execution
// template params instead of using blueprint level params
tp = p.preparePhaseTemplateParams(tp)

if p.args == nil {
// Get the action from Blueprint
a, ok := bp.Actions[action]
@@ -81,6 +86,18 @@ func (p *Phase) Exec(ctx context.Context, bp crv1alpha1.Blueprint, action string
return p.f.Exec(ctx, tp, p.args)
}

func (p *Phase) preparePhaseTemplateParams(tp param.TemplateParams) param.TemplateParams {
phasePodOverride, ok := tp.PhasePodOverrides[p.name]

if ok { // There is a phase specific podOverride
tp.PodOverride = phasePodOverride
}

// TODO: add phase specific labels and annotations support

return tp
}

func (p *Phase) setPhaseArgs(phases []crv1alpha1.BlueprintPhase, tp param.TemplateParams) error {
for _, ap := range phases {
if ap.Name != p.name {
31 changes: 27 additions & 4 deletions pkg/phase_test.go
Original file line number Diff line number Diff line change
@@ -62,7 +62,7 @@ func (tf *testFunc) RequiredArgs() []string {
}

func (tf *testFunc) Arguments() []string {
return nil
return []string{"testKey"}
}

func (tf *testFunc) Validate(args map[string]any) error {
@@ -93,21 +93,44 @@ func (s *PhaseSuite) TestExec(c *check.C) {
argument: "{{ .Options.test | lower}} world",
expected: "hello world",
},
{
artifact: "hello",
argument: "{{ .Options.test }} {{ index .PodOverride \"foo\" }}",
expected: "hello bar",
},
} {
var output string
tf := &testFunc{output: &output}
tp := param.TemplateParams{
Options: map[string]string{
"test": tc.artifact,
},
PhasePodOverrides: map[string]crv1alpha1.JSONMap{
"test_phase": {
"foo": "bar",
},
},
}
rawArgs := map[string]interface{}{
"testKey": tc.argument,
}
args, err := param.RenderArgs(rawArgs, tp)
_, err := param.RenderArgs(rawArgs, tp)
c.Assert(err, check.IsNil)
p := Phase{args: args, f: tf}
_, err = p.Exec(context.Background(), crv1alpha1.Blueprint{}, "", tp)
p := Phase{name: "test_phase", f: tf}
bp := crv1alpha1.Blueprint{
Actions: map[string]*crv1alpha1.BlueprintAction{
"": {
Phases: []crv1alpha1.BlueprintPhase{
{
Name: "test_phase",
Func: tf.Name(),
Args: rawArgs,
},
},
},
},
}
_, err = p.Exec(context.Background(), bp, "", tp)
c.Assert(err, check.IsNil)
c.Assert(output, check.Equals, tc.expected)
}