Skip to content

Commit

Permalink
Teach package verifier about pipe tasks. (#1402)
Browse files Browse the repository at this point in the history
Signed-off-by: Marcin Owsiany <mowsiany@D2iQ.com>
  • Loading branch information
porridge committed Mar 10, 2020
1 parent 221e1ba commit 53e3510
Show file tree
Hide file tree
Showing 4 changed files with 92 additions and 24 deletions.
12 changes: 6 additions & 6 deletions pkg/controller/instance/instance_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -310,12 +310,12 @@ func preparePlanExecution(instance *kudov1beta1.Instance, ov *kudov1beta1.Operat
return nil, &engine.ExecutionError{Err: fmt.Errorf("%wcould not find required plan: '%v'", engine.ErrFatalExecution, activePlanStatus.Name), EventName: "InvalidPlan"}
}

params, err := paramsMap(instance, ov)
params, err := ParamsMap(instance, ov)
if err != nil {
return nil, &engine.ExecutionError{Err: fmt.Errorf("%wcould not parse parameters: %v", engine.ErrFatalExecution, err), EventName: "InvalidParams"}
}

pipes, err := pipesMap(activePlanStatus.Name, &planSpec, ov.Spec.Tasks, meta)
pipes, err := PipesMap(activePlanStatus.Name, &planSpec, ov.Spec.Tasks, meta)
if err != nil {
return nil, &engine.ExecutionError{Err: fmt.Errorf("%wcould not make task pipes: %v", engine.ErrFatalExecution, err), EventName: "InvalidPlan"}
}
Expand Down Expand Up @@ -393,8 +393,8 @@ func GetOperatorVersion(instance *kudov1beta1.Instance, c client.Reader) (ov *ku
return ov, nil
}

// paramsMap generates {{ Params.* }} map of keys and values which is later used during template rendering.
func paramsMap(instance *kudov1beta1.Instance, operatorVersion *kudov1beta1.OperatorVersion) (map[string]interface{}, error) {
// ParamsMap generates {{ Params.* }} map of keys and values which is later used during template rendering.
func ParamsMap(instance *kudov1beta1.Instance, operatorVersion *kudov1beta1.OperatorVersion) (map[string]interface{}, error) {
params := make(map[string]interface{}, len(operatorVersion.Spec.Parameters))

for _, param := range operatorVersion.Spec.Parameters {
Expand All @@ -417,8 +417,8 @@ func paramsMap(instance *kudov1beta1.Instance, operatorVersion *kudov1beta1.Oper
return params, nil
}

// pipesMap generates {{ Pipes.* }} map of keys and values which is later used during template rendering.
func pipesMap(planName string, plan *v1beta1.Plan, tasks []v1beta1.Task, emeta *engine.Metadata) (map[string]string, error) {
// PipesMap generates {{ Pipes.* }} map of keys and values which is later used during template rendering.
func PipesMap(planName string, plan *v1beta1.Plan, tasks []v1beta1.Task, emeta *engine.Metadata) (map[string]string, error) {
taskByName := func(name string) (*v1beta1.Task, bool) {
for _, t := range tasks {
if t.Name == name {
Expand Down
4 changes: 2 additions & 2 deletions pkg/controller/instance/instance_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -327,10 +327,10 @@ func Test_makePipes(t *testing.T) {

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := pipesMap(tt.planName, tt.plan, tt.tasks, tt.emeta)
got, err := PipesMap(tt.planName, tt.plan, tt.tasks, tt.emeta)
if err != nil {
if !tt.wantErr {
t.Fatalf("pipesMap() error = %v, wantErr %v", err, tt.wantErr)
t.Fatalf("PipesMap() error = %v, wantErr %v", err, tt.wantErr)
}
return
}
Expand Down
48 changes: 33 additions & 15 deletions pkg/kudoctl/packages/verifier/template/verify_render.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@ package template
import (
"fmt"

"github.com/kudobuilder/kudo/pkg/apis/kudo/v1beta1"
"github.com/kudobuilder/kudo/pkg/controller/instance"
"github.com/kudobuilder/kudo/pkg/engine"
"github.com/kudobuilder/kudo/pkg/engine/renderer"
"github.com/kudobuilder/kudo/pkg/kudoctl/packages"
packageconvert "github.com/kudobuilder/kudo/pkg/kudoctl/packages/convert"
"github.com/kudobuilder/kudo/pkg/kudoctl/verifier"
"github.com/kudobuilder/kudo/pkg/util/convert"
)

var _ packages.Verifier = &RenderVerifier{}
Expand All @@ -24,30 +26,23 @@ func (RenderVerifier) Verify(pf *packages.Files) verifier.Result {
func templateCompilable(pf *packages.Files) verifier.Result {
res := verifier.NewResult()

params := make(map[string]interface{}, len(pf.Params.Parameters))

parameters, err := packageconvert.ParametersToCRDType(pf.Params.Parameters)
params, err := collectParams(pf)
if err != nil {
res.AddErrors(err.Error())
return res
}

for _, p := range parameters {
value, err := convert.UnwrapParamValue(p.Default, p.Type)
if err != nil {
res.AddErrors(fmt.Sprintf("failed to unwrap %s default for parameter '%s': %v", p.Type, p.Name, err))
continue
}

params[p.Name] = value
pipes, err := collectPipes(pf)
if err != nil {
res.AddErrors(err.Error())
return res
}

configs := make(map[string]interface{})
configs["OperatorName"] = "OperatorName"
configs["Name"] = "Name"
configs["Namespace"] = "Namespace"
configs["Params"] = params
configs["Pipes"] = make(map[string]string)
configs["Pipes"] = pipes
configs["PlanName"] = "PlanName"
configs["PhaseName"] = "PhaseName"
configs["StepName"] = "StepName"
Expand All @@ -58,7 +53,7 @@ func templateCompilable(pf *packages.Files) verifier.Result {
// Render the template
s, err := engine.Render(k, v, configs)
if err != nil {
res.AddErrors(fmt.Sprintf("rendering template %s failed: %v", k, err))
res.AddErrors(err.Error()) // err already mentions template name
}

// Try to parse rendered template as valid Kubernetes objects
Expand All @@ -70,3 +65,26 @@ func templateCompilable(pf *packages.Files) verifier.Result {

return res
}

func collectPipes(pf *packages.Files) (map[string]string, error) {
pipes := make(map[string]string)
for name, plan := range pf.Operator.Plans {
plan := plan
planPipes, err := instance.PipesMap(name, &plan, pf.Operator.Tasks, &engine.Metadata{})
if err != nil {
return nil, err
}
for key, value := range planPipes {
pipes[key] = value
}
}
return pipes, nil
}

func collectParams(pf *packages.Files) (map[string]interface{}, error) {
parameters, err := packageconvert.ParametersToCRDType(pf.Params.Parameters)
if err != nil {
return nil, err
}
return instance.ParamsMap(&v1beta1.Instance{}, &v1beta1.OperatorVersion{Spec: v1beta1.OperatorVersionSpec{Parameters: parameters}})
}
52 changes: 51 additions & 1 deletion pkg/kudoctl/packages/verifier/template/verify_render_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,57 @@ func TestTemplateRenderVerifier(t *testing.T) {

assert.Equal(t, 0, len(res.Warnings))
assert.Equal(t, 1, len(res.Errors))
assert.Equal(t, `rendering template foo.yaml failed: error rendering template: template: foo.yaml:2:6: executing "foo.yaml" at <eq>: wrong number of args for eq: want at least 1 got 0`, res.Errors[0])
assert.Equal(t, `error rendering template: template: foo.yaml:2:6: executing "foo.yaml" at <eq>: wrong number of args for eq: want at least 1 got 0`, res.Errors[0])
}

func TestTemplateRenderVerifier_Pipes(t *testing.T) {
params := make([]packages.Parameter, 0)
paramFile := packages.ParamsFile{Parameters: params}
templates := make(map[string]string)
templates["foo.yaml"] = `
correct: {{ .Pipes.existing }}
wrong: {{ .Pipes.inexistent }}
`
operator := packages.OperatorFile{
Tasks: []v1beta1.Task{
{
Name: "a-task",
Kind: "Pipe",
Spec: v1beta1.TaskSpec{
PipeTaskSpec: v1beta1.PipeTaskSpec{
Pipe: []v1beta1.PipeSpec{
{
Key: "existing",
},
},
},
},
},
},
Plans: map[string]v1beta1.Plan{
"a-plan": {
Phases: []v1beta1.Phase{
{
Steps: []v1beta1.Step{
{Tasks: []string{"a-task"}},
},
},
},
},
},
}
pf := packages.Files{
Templates: templates,
Operator: &operator,
Params: &paramFile,
}
verifier := RenderVerifier{}
res := verifier.Verify(&pf)

assert.Equal(t, 0, len(res.Warnings))
assert.Equal(t, 1, len(res.Errors))
assert.Equal(t, `error rendering template: template: foo.yaml:3:16: executing "foo.yaml" at <.Pipes.inexistent>: `+
`map has no entry for key "inexistent"`, res.Errors[0])
}

func TestTemplateRenderVerifier_InvalidYAML(t *testing.T) {
Expand Down

0 comments on commit 53e3510

Please sign in to comment.