Skip to content

Commit

Permalink
feat: mainEntrypoint variable (#11151)
Browse files Browse the repository at this point in the history
Signed-off-by: Alan Clucas <alan@clucas.org>
  • Loading branch information
Joibel committed Jun 1, 2023
1 parent bccba40 commit b9f9544
Show file tree
Hide file tree
Showing 8 changed files with 141 additions and 2 deletions.
64 changes: 63 additions & 1 deletion docs/variables.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ The tag is substituted with the variable that has a name the same as the tag.
Simple tags **may** have white-space between the brackets and variable as seen below. However, there is a known issue where variables may fail to interpolate with white-space, so it is recommended to avoid using white-space until this issue is resolved. [Please report](https://github.com/argoproj/argo-workflows/issues/8960) unexpected behavior with reproducible examples.

```yaml
args: [ "{{ inputs.parameters.message }}" ]
args: [ "{{ inputs.parameters.message }}" ]
```

### Expression
Expand Down Expand Up @@ -247,6 +247,7 @@ For `Template`-level metrics:
|----------|------------|
| `workflow.name` | Workflow name |
| `workflow.namespace` | Workflow namespace |
| `workflow.mainEntrypoint` | Workflow's initial entrypoint |
| `workflow.serviceAccountName` | Workflow service account name |
| `workflow.uid` | Workflow UID. Useful for setting ownership reference to a resource, or a unique artifact location |
| `workflow.parameters.<NAME>` | Input parameter to the workflow |
Expand All @@ -271,3 +272,64 @@ For `Template`-level metrics:
|----------|------------|
| `workflow.status` | Workflow status. One of: `Succeeded`, `Failed`, `Error` |
| `workflow.failures` | A list of JSON objects containing information about nodes that failed or errored during execution. Available fields: `displayName`, `message`, `templateName`, `phase`, `podName`, and `finishedAt`. |

### Knowing where you are

The idea with creating a `WorkflowTemplate` is that they are reusable bits of code you will use in many actual Workflows. Sometimes it is useful to know which workflow you are part of.

`workflow.mainEntrypoint` is one way you can do this. If each of your actual workflows has a differing entrypoint, you can identify the workflow you're part of. Given this use in a `WorkflowTemplate`:

```yaml
apiVersion: argoproj.io/v1alpha1
kind: WorkflowTemplate
metadata:
name: say-main-entrypoint
spec:
entrypoint: echo
templates:
- name: echo
container:
image: alpine
command: [echo]
args: ["{{workflow.mainEntrypoint}}"]
```

I can distinguish my caller:

```yaml
apiVersion: argoproj.io/v1alpha1
kind: Workflow
metadata:
generateName: foo-
spec:
entrypoint: foo
templates:
- name: foo
steps:
- - name: step
templateRef:
name: say-main-entrypoint
template: echo
```

results in a log of `foo`

```yaml
apiVersion: argoproj.io/v1alpha1
kind: Workflow
metadata:
generateName: bar-
spec:
entrypoint: bar
templates:
- name: bar
steps:
- - name: step
templateRef:
name: say-main-entrypoint
template: echo
```

results in a log of `bar`

This shouldn't be that helpful in logging, you should be able to identify workflows through other labels in your cluster's log tool, but can be helpful when generating metrics for the workflow for example.
16 changes: 16 additions & 0 deletions test/e2e/functional/entrypointName-template.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
apiVersion: argoproj.io/v1alpha1
kind: WorkflowTemplate
metadata:
name: next-template
spec:
entrypoint: next
templates:
- name: next
inputs:
parameters:
- name: test
value: "{{ workflow.mainEntrypoint }}"
container:
image: alpine
command: [echo]
args: ["We got here!"]
13 changes: 13 additions & 0 deletions test/e2e/functional/entrypointName-workflow.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
apiVersion: argoproj.io/v1alpha1
kind: Workflow
metadata:
generateName: bar-
spec:
entrypoint: bar
templates:
- name: bar
steps:
- - name: step
templateRef:
name: next-template
template: next
16 changes: 16 additions & 0 deletions test/e2e/functional_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1184,3 +1184,19 @@ func (s *FunctionalSuite) TestTemplateDefaultImage() {
SubmitWorkflow().
WaitForWorkflow(fixtures.ToBeSucceeded)
}

func (s *FunctionalSuite) TestEntrypointName() {
s.Given().
WorkflowTemplate(`@functional/entrypointName-template.yaml`).
Workflow(`@functional/entrypointName-workflow.yaml`).
When().
CreateWorkflowTemplates().
SubmitWorkflow().
WaitForWorkflow().
Then().
ExpectWorkflowNode(wfv1.NodeWithDisplayName("step"), func(t *testing.T, n *wfv1.NodeStatus, p *apiv1.Pod) {
assert.Equal(t, wfv1.NodeSucceeded, n.Phase)
assert.Equal(t, "bar", n.Inputs.Parameters[0].Value.String())
})

}
2 changes: 2 additions & 0 deletions workflow/common/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,8 @@ const (
GlobalVarWorkflowName = "workflow.name"
// GlobalVarWorkflowNamespace is a global workflow variable referencing the workflow's metadata.namespace field
GlobalVarWorkflowNamespace = "workflow.namespace"
// GlobalVarWorkflowMainEntrypoint is a global workflow variable referencing the workflow's top level entrypoint name
GlobalVarWorkflowMainEntrypoint = "workflow.mainEntrypoint"
// GlobalVarWorkflowServiceAccountName is a global workflow variable referencing the workflow's spec.serviceAccountName field
GlobalVarWorkflowServiceAccountName = "workflow.serviceAccountName"
// GlobalVarWorkflowUID is a global workflow variable referencing the workflow's metadata.uid field
Expand Down
1 change: 1 addition & 0 deletions workflow/controller/operator.go
Original file line number Diff line number Diff line change
Expand Up @@ -581,6 +581,7 @@ func (woc *wfOperationCtx) getWorkflowDeadline() *time.Time {
func (woc *wfOperationCtx) setGlobalParameters(executionParameters wfv1.Arguments) error {
woc.globalParams[common.GlobalVarWorkflowName] = woc.wf.ObjectMeta.Name
woc.globalParams[common.GlobalVarWorkflowNamespace] = woc.wf.ObjectMeta.Namespace
woc.globalParams[common.GlobalVarWorkflowMainEntrypoint] = woc.execWf.Spec.Entrypoint
woc.globalParams[common.GlobalVarWorkflowServiceAccountName] = woc.execWf.Spec.ServiceAccountName
woc.globalParams[common.GlobalVarWorkflowUID] = string(woc.wf.ObjectMeta.UID)
woc.globalParams[common.GlobalVarWorkflowCreationTimestamp] = woc.wf.ObjectMeta.CreationTimestamp.Format(time.RFC3339)
Expand Down
30 changes: 29 additions & 1 deletion workflow/controller/operator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -367,6 +367,7 @@ func TestGlobalParams(t *testing.T) {
assert.Contains(t, woc.globalParams, "workflow.duration")
assert.Contains(t, woc.globalParams, "workflow.name")
assert.Contains(t, woc.globalParams, "workflow.namespace")
assert.Contains(t, woc.globalParams, "workflow.mainEntrypoint")
assert.Contains(t, woc.globalParams, "workflow.parameters")
assert.Contains(t, woc.globalParams, "workflow.annotations")
assert.Contains(t, woc.globalParams, "workflow.labels")
Expand Down Expand Up @@ -6704,7 +6705,7 @@ spec:
container:
image: docker/whalesay:latest
command: [cowsay]
args: ["{{workflows.scheduledTime}}"]
args: ["{{workflow.scheduledTime}}"]
`

func TestWorkflowScheduledTimeVariable(t *testing.T) {
Expand All @@ -6718,6 +6719,33 @@ func TestWorkflowScheduledTimeVariable(t *testing.T) {
assert.Equal(t, "2006-01-02T15:04:05-07:00", woc.globalParams[common.GlobalVarWorkflowCronScheduleTime])
}

var wfMainEntrypointVariable = `
apiVersion: argoproj.io/v1alpha1
kind: Workflow
metadata:
name: hello-world
spec:
entrypoint: whalesay
shutdown: "Stop"
templates:
- name: whalesay
container:
image: docker/whalesay:latest
command: [cowsay]
args: ["{{workflow.mainEntrypoint}}"]
`

func TestWorkflowMainEntrypointVariable(t *testing.T) {
wf := wfv1.MustUnmarshalWorkflow(wfMainEntrypointVariable)
cancel, controller := newController(wf)
defer cancel()

ctx := context.Background()
woc := newWorkflowOperationCtx(wf, controller)
woc.operate(ctx)
assert.Equal(t, "whalesay", woc.globalParams[common.GlobalVarWorkflowMainEntrypoint])
}

var wfNodeNameField = `
apiVersion: argoproj.io/v1alpha1
kind: Workflow
Expand Down
1 change: 1 addition & 0 deletions workflow/validate/validate.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ func newTemplateValidationCtx(wf *wfv1.Workflow, opts ValidateOpts) *templateVal
globalParams := make(map[string]string)
globalParams[common.GlobalVarWorkflowName] = placeholderGenerator.NextPlaceholder()
globalParams[common.GlobalVarWorkflowNamespace] = placeholderGenerator.NextPlaceholder()
globalParams[common.GlobalVarWorkflowMainEntrypoint] = placeholderGenerator.NextPlaceholder()
globalParams[common.GlobalVarWorkflowServiceAccountName] = placeholderGenerator.NextPlaceholder()
globalParams[common.GlobalVarWorkflowUID] = placeholderGenerator.NextPlaceholder()
return &templateValidationCtx{
Expand Down

0 comments on commit b9f9544

Please sign in to comment.