Skip to content

Commit

Permalink
Make {{pod.name}} available as a parameter in pod templates (resolves a…
Browse files Browse the repository at this point in the history
  • Loading branch information
jessesuen committed Mar 3, 2018
1 parent 3cf4bb1 commit 7d7b74f
Show file tree
Hide file tree
Showing 7 changed files with 78 additions and 22 deletions.
9 changes: 9 additions & 0 deletions pkg/apis/workflow/v1alpha1/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -616,6 +616,15 @@ func (tmpl *Template) GetType() TemplateType {
return "Unknown"
}

// IsPodType returns whether or not the template is a pod type
func (tmpl *Template) IsPodType() bool {
switch tmpl.GetType() {
case TemplateTypeContainer, TemplateTypeScript, TemplateTypeResource:
return true
}
return false
}

// DAGTemplate is a template subtype for directed acyclic graph templates
type DAGTemplate struct {
// Target are one or more names of targets to execute in a DAG
Expand Down
30 changes: 17 additions & 13 deletions workflow/common/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ func DefaultConfigMapName(controllerName string) string {
// It also substitutes parameters in the template from the arguments
// It will also substitute any global variables referenced in template
// (e.g. {{workflow.parameters.XX}}, {{workflow.name}}, {{workflow.status}})
func ProcessArgs(tmpl *wfv1.Template, args wfv1.Arguments, globalParams map[string]string, validateOnly bool) (*wfv1.Template, error) {
func ProcessArgs(tmpl *wfv1.Template, args wfv1.Arguments, globalParams, localParams map[string]string, validateOnly bool) (*wfv1.Template, error) {
// For each input parameter:
// 1) check if was supplied as argument. if so use the supplied value from arg
// 2) if not, use default value.
Expand All @@ -146,11 +146,12 @@ func ProcessArgs(tmpl *wfv1.Template, args wfv1.Arguments, globalParams map[stri
}
tmpl.Inputs.Parameters[i] = inParam
}
tmpl, err := substituteParams(tmpl, globalParams)
tmpl, err := substituteParams(tmpl, globalParams, localParams)
if err != nil {
return nil, err
}

// Performs susbstitution of input artifacts
newInputArtifacts := make([]wfv1.Artifact, len(tmpl.Inputs.Artifacts))
for i, inArt := range tmpl.Inputs.Artifacts {
// if artifact has hard-wired location, we prefer that
Expand All @@ -174,16 +175,22 @@ func ProcessArgs(tmpl *wfv1.Template, args wfv1.Arguments, globalParams map[stri
return tmpl, nil
}

// substituteParams returns a new copy of the template with all input parameters substituted
func substituteParams(tmpl *wfv1.Template, globalParams map[string]string) (*wfv1.Template, error) {
// substituteParams returns a new copy of the template with global, pod, and input parameters substituted
func substituteParams(tmpl *wfv1.Template, globalParams, localParams map[string]string) (*wfv1.Template, error) {
tmplBytes, err := json.Marshal(tmpl)
if err != nil {
return nil, errors.InternalWrapError(err)
}
// First replace globals then replace inputs because globals could be referenced in the
// inputs. Note globals cannot be unresolved
// First replace globals & locals, then replace inputs because globals could be referenced in the inputs
replaceMap := make(map[string]string)
for k, v := range globalParams {
replaceMap[k] = v
}
for k, v := range localParams {
replaceMap[k] = v
}
fstTmpl := fasttemplate.New(string(tmplBytes), "{{", "}}")
globalReplacedTmplStr, err := Replace(fstTmpl, globalParams, false, "workflow.")
globalReplacedTmplStr, err := Replace(fstTmpl, replaceMap, true)
if err != nil {
return nil, err
}
Expand All @@ -193,15 +200,15 @@ func substituteParams(tmpl *wfv1.Template, globalParams map[string]string) (*wfv
return nil, errors.InternalWrapError(err)
}
// Now replace the rest of substitutions (the ones that can be made) in the template
replaceMap := make(map[string]string)
replaceMap = make(map[string]string)
for _, inParam := range globalReplacedTmpl.Inputs.Parameters {
if inParam.Value == nil {
return nil, errors.InternalErrorf("inputs.parameters.%s had no value", inParam.Name)
}
replaceMap["inputs.parameters."+inParam.Name] = *inParam.Value
}
fstTmpl = fasttemplate.New(globalReplacedTmplStr, "{{", "}}")
s, err := Replace(fstTmpl, replaceMap, true, "")
s, err := Replace(fstTmpl, replaceMap, true)
if err != nil {
return nil, err
}
Expand All @@ -217,12 +224,9 @@ func substituteParams(tmpl *wfv1.Template, globalParams map[string]string) (*wfv
// allowUnresolved indicates whether or not it is acceptable to have unresolved variables
// remaining in the substituted template. prefixFilter will apply the replacements only
// to variables with the specified prefix
func Replace(fstTmpl *fasttemplate.Template, replaceMap map[string]string, allowUnresolved bool, prefixFilter string) (string, error) {
func Replace(fstTmpl *fasttemplate.Template, replaceMap map[string]string, allowUnresolved bool) (string, error) {
var unresolvedErr error
replacedTmpl := fstTmpl.ExecuteFuncString(func(w io.Writer, tag string) (int, error) {
if !strings.HasPrefix(tag, prefixFilter) {
return w.Write([]byte(fmt.Sprintf("{{%s}}", tag)))
}
replacement, ok := replaceMap[tag]
if !ok {
if allowUnresolved {
Expand Down
13 changes: 9 additions & 4 deletions workflow/common/validate.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,14 +90,19 @@ func (ctx *wfValidationCtx) validateTemplate(tmpl *wfv1.Template, args wfv1.Argu
if err := validateTemplateType(tmpl); err != nil {
return err
}
_, err := ProcessArgs(tmpl, args, ctx.globalParams, true)
if err != nil {
return errors.Errorf(errors.CodeBadRequest, "templates.%s %s", tmpl.Name, err)
}
scope, err := validateInputs(tmpl)
if err != nil {
return err
}
localParams := make(map[string]string)
if tmpl.IsPodType() {
localParams["pod.name"] = placeholderValue
scope["pod.name"] = placeholderValue
}
_, err = ProcessArgs(tmpl, args, ctx.globalParams, localParams, true)
if err != nil {
return errors.Errorf(errors.CodeBadRequest, "templates.%s %s", tmpl.Name, err)
}
for globalVar, val := range ctx.globalParams {
scope[globalVar] = val
}
Expand Down
35 changes: 35 additions & 0 deletions workflow/common/validate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1006,3 +1006,38 @@ func TestValidWithItems(t *testing.T) {
assert.Contains(t, err.Error(), "withItems")
}
}

var podNameVariable = `
apiVersion: argoproj.io/v1alpha1
kind: Workflow
metadata:
name: pod-name-variable
spec:
entrypoint: pod-name-variable
templates:
- name: pod-name-variable
container:
image: debian:9.1
command: [sh, -c]
args: ["kubectl {{pod.name}}"]
outputs:
artifacts:
- name: my-out
path: /tmp/hello_world.txt
s3:
endpoint: s3.amazonaws.com
bucket: my-bucket
key: path/{{pod.name}}/hello_world.tgz
accessKeySecret:
name: my-s3-credentials
key: accessKey
secretKeySecret:
name: my-s3-credentials
key: secretKey
`

func TestPodNameVariable(t *testing.T) {
err := validate(podNameVariable)

assert.Nil(t, err)
}
2 changes: 1 addition & 1 deletion workflow/controller/dag.go
Original file line number Diff line number Diff line change
Expand Up @@ -294,7 +294,7 @@ func (woc *wfOperationCtx) resolveDependencyReferences(dagCtx *dagContext, task
return nil, errors.InternalWrapError(err)
}
fstTmpl := fasttemplate.New(string(taskBytes), "{{", "}}")
newTaskStr, err := common.Replace(fstTmpl, scope.replaceMap(), true, "")
newTaskStr, err := common.Replace(fstTmpl, scope.replaceMap(), true)
if err != nil {
return nil, err
}
Expand Down
7 changes: 5 additions & 2 deletions workflow/controller/operator.go
Original file line number Diff line number Diff line change
Expand Up @@ -832,8 +832,11 @@ func (woc *wfOperationCtx) executeTemplate(templateName string, args wfv1.Argume
if err := woc.checkParallelism(tmpl, node, boundaryID); err != nil {
return err
}

tmpl, err := common.ProcessArgs(tmpl, args, woc.globalParams, false)
localParams := make(map[string]string)
if tmpl.IsPodType() {
localParams["pod.name"] = woc.wf.NodeID(nodeName)
}
tmpl, err := common.ProcessArgs(tmpl, args, woc.globalParams, localParams, false)
if err != nil {
woc.initializeNode(nodeName, wfv1.NodeTypeSkipped, templateName, boundaryID, wfv1.NodeError, err.Error())
return err
Expand Down
4 changes: 2 additions & 2 deletions workflow/controller/steps.go
Original file line number Diff line number Diff line change
Expand Up @@ -251,7 +251,7 @@ func (woc *wfOperationCtx) resolveReferences(stepGroup []wfv1.WorkflowStep, scop
}
}
fstTmpl := fasttemplate.New(string(stepBytes), "{{", "}}")
newStepStr, err := common.Replace(fstTmpl, replaceMap, true, "")
newStepStr, err := common.Replace(fstTmpl, replaceMap, true)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -348,7 +348,7 @@ func (woc *wfOperationCtx) expandStep(step wfv1.WorkflowStep) ([]wfv1.WorkflowSt
default:
return nil, errors.Errorf(errors.CodeBadRequest, "withItems[%d] expected string, number, or map. received: %s", i, val)
}
newStepStr, err := common.Replace(fstTmpl, replaceMap, false, "")
newStepStr, err := common.Replace(fstTmpl, replaceMap, false)
if err != nil {
return nil, err
}
Expand Down

0 comments on commit 7d7b74f

Please sign in to comment.