argoproj / argo-workflows

Workflow Engine for Kubernetes
https://argo-workflows.readthedocs.io/
Apache License 2.0
14.57k stars 3.12k forks source link

UI: prompt for string input during suspend #13256

Open sahil-sharma opened 1 week ago

sahil-sharma commented 1 week ago

Pre-requisites

What happened/what did you expect to happen?

We have a Job (defined as a Workflow) that expects user input when a user triggers or re-submit the Workflow (via UI). In an ideal situation upon submission Workflow it should suspend for a user input and pass this input to a further step after receiving it. And if not provided then exit the Workflow.

Upon looking for similar issues I found this #7563 but this is picking up the null value ("") and simply succeeds without prompting for user input in the UI. During suspend-step when click on resume button (hoping it to prompt for user input) I get:

Are you sure you want to resume node user-input-param-example-65qsm-1460707896 ?

There are no errors in Workflow-Server Pod logs.

Also tried the official example defined in Intermediate steps (see here) but it has a boolean value. I expect a string as an input.

Tried a bunch of other methods but none worked.

Version

v3.5.7

Paste a small workflow that reproduces the issue. We must be able to run the workflow; don't enter a workflows that uses private images.

apiVersion: argoproj.io/v1alpha1
kind: Workflow
metadata:
  generateName: user-input-param-example-
  namespace: custom-namespace
spec:
  serviceAccountName: argo-workflows
  entrypoint: main
  arguments:
    parameters:
    - name: user-input
      value: ""
  templates:
  - name: main
    steps:
    - - name: suspend-step
        template: suspend-template
    - - name: user-input-step
        template: user-input-template
        arguments:
          parameters:
          - name: user-input
            value: "{{workflow.parameters.user-input}}"

  - name: suspend-template
    suspend: {}

  - name: user-input-template
    inputs:
      parameters:
      - name: user-input
    container:
      image: alpine:latest
      command: ["/bin/sh", "-c"]
      args: ["echo 'User input received: {{inputs.parameters.user-input}}'"]

Logs from the workflow controller

{"level":"info","msg":"using the default service account for user","subject":"ChU1NXXXXXXXXXXXXXXXXXSBmdvb2dsZQ","time":"2024-06-27T09:41:53.960Z"}
{"grpc.code":"OK","grpc.method":"GetWorkflow","grpc.service":"workflow.WorkflowService","grpc.start_time":"2024-06-27T09:41:53Z","grpc.time_ms":12.671,"level":"info","msg":"finished unary call with code OK","span.kind":"server","system":"grpc","time":"2024-06-27T09:41:53.971Z"}
{"duration":13554002,"level":"info","method":"GET","msg":"","path":"/api/v1/workflows/custom-namespace/user-input-param-example-65qsm","size":3494,"status":0,"time":"2024-06-27T09:41:53.971Z"}
{"level":"info","msg":"using the default service account for user","subject":"ChU1NXXXXXXXXXXXXXXXXXSBmdvb2dsZQ","time":"2024-06-27T09:41:54.146Z"}
{"grpc.code":"OK","grpc.method":"GetWorkflow","grpc.service":"workflow.WorkflowService","grpc.start_time":"2024-06-27T09:41:54Z","grpc.time_ms":7.793,"level":"info","msg":"finished unary call with code OK","span.kind":"server","system":"grpc","time":"2024-06-27T09:41:54.152Z"}
{"duration":8835941,"level":"info","method":"GET","msg":"","path":"/api/v1/workflows/custom-namespace/user-input-param-example-65qsm","size":3494,"status":0,"time":"2024-06-27T09:41:54.153Z"}
{"duration":108225,"level":"info","method":"GET","msg":"","path":"index.html","size":487,"status":0,"time":"2024-06-27T09:42:12.194Z"}
{"duration":110731,"level":"info","method":"GET","msg":"","path":"index.html","size":487,"status":0,"time":"2024-06-27T09:42:32.193Z"}
{"duration":107941,"level":"info","method":"GET","msg":"","path":"index.html","size":487,"status":0,"time":"2024-06-27T09:42:52.193Z"}
{"duration":129058,"level":"info","method":"GET","msg":"","path":"index.html","size":487,"status":0,"time":"2024-06-27T09:43:12.193Z"}
{"duration":110751,"level":"info","method":"GET","msg":"","path":"index.html","size":487,"status":0,"time":"2024-06-27T09:43:32.193Z"}
{"level":"info","msg":"using the default service account for user","subject":"ChU1NXXXXXXXXXXXXXXXXXSBmdvb2dsZQ","time":"2024-06-27T09:43:43.109Z"}
{"duration":188891,"level":"info","method":"GET","msg":"","path":"index.html","size":487,"status":0,"time":"2024-06-27T09:43:52.194Z"}
{"duration":96627,"level":"info","method":"GET","msg":"","path":"index.html","size":487,"status":0,"time":"2024-06-27T09:44:12.193Z"}
{"duration":106622,"level":"info","method":"GET","msg":"","path":"index.html","size":487,"status":0,"time":"2024-06-27T09:44:32.194Z"}
{"duration":86864,"level":"info","method":"GET","msg":"","path":"index.html","size":487,"status":0,"time":"2024-06-27T09:44:52.193Z"}
{"duration":111959,"level":"info","method":"GET","msg":"","path":"index.html","size":487,"status":0,"time":"2024-06-27T09:45:12.193Z"}
{"duration":100345,"level":"info","method":"GET","msg":"","path":"index.html","size":487,"status":0,"time":"2024-06-27T09:45:32.193Z"}
{"duration":134020,"level":"info","method":"GET","msg":"","path":"index.html","size":487,"status":0,"time":"2024-06-27T09:45:52.193Z"}
{"level":"info","msg":"Alloc=10589 TotalAlloc=904429 Sys=32613 NumGC=1300 Goroutines=79","time":"2024-06-27T09:46:09.874Z"}
{"duration":119754,"level":"info","method":"GET","msg":"","path":"index.html","size":487,"status":0,"time":"2024-06-27T09:46:12.193Z"}
{"duration":217945,"level":"info","method":"GET","msg":"","path":"index.html","size":487,"status":0,"time":"2024-06-27T09:46:32.193Z"}
{"duration":97281,"level":"info","method":"GET","msg":"","path":"index.html","size":487,"status":0,"time":"2024-06-27T09:46:52.193Z"}
{"duration":106706,"level":"info","method":"GET","msg":"","path":"index.html","size":487,"status":0,"time":"2024-06-27T09:47:12.193Z"}
{"duration":84185,"level":"info","method":"GET","msg":"","path":"index.html","size":487,"status":0,"time":"2024-06-27T09:47:32.193Z"}
{"duration":863028,"level":"info","method":"GET","msg":"","path":"index.html","size":487,"status":0,"time":"2024-06-27T09:47:52.197Z"}
{"duration":150732,"level":"info","method":"GET","msg":"","path":"index.html","size":487,"status":0,"time":"2024-06-27T09:48:12.193Z"}
{"duration":130787,"level":"info","method":"GET","msg":"","path":"index.html","size":487,"status":0,"time":"2024-06-27T09:48:32.194Z"}

Logs from in your workflow's wait container

{"level":"info","msg":"Starting Workflow Executor","time":"2024-06-27T10:03:20.400Z","version":"v3.5.7"}
{"Duration":1000000000,"Factor":1.6,"Jitter":0.5,"Steps":5,"level":"info","msg":"Using executor retry strategy","time":"2024-06-27T10:03:20.417Z"}
{"deadline":"0001-01-01T00:00:00Z","includeScriptOutput":false,"level":"info","msg":"Executor initialized","namespace":"custom-namespace","podName":"user-input-param-example-h9zbh-user-input-template-3923484286","templateName":"user-input-template","time":"2024-06-27T10:03:20.417Z","version":"\u0026Version{Version:v3.5.7,BuildDate:2024-05-27T06:18:59Z,GitCommit:503eef1357ebc9facc3f463708031441072ef7c2,GitTag:v3.5.7,GitTreeState:clean,GoVersion:go1.21.10,Compiler:gc,Platform:linux/amd64,}"}
{"level":"info","msg":"Starting deadline monitor","time":"2024-06-27T10:03:20.436Z"}
{"error":null,"level":"info","msg":"Main container completed","time":"2024-06-27T10:03:22.438Z"}
{"level":"info","msg":"No Script output reference in workflow. Capturing script output ignored","time":"2024-06-27T10:03:22.438Z"}
{"level":"info","msg":"No output parameters","time":"2024-06-27T10:03:22.438Z"}
{"level":"info","msg":"No output artifacts","time":"2024-06-27T10:03:22.438Z"}
{"level":"info","msg":"Alloc=7596 TotalAlloc=13519 Sys=23653 NumGC=4 Goroutines=8","time":"2024-06-27T10:03:22.453Z"}
agilgur5 commented 1 week ago

Also tried the official example defined in Intermediate steps (see here) but it has a boolean value. I expect a string as an input.

It's actually an enum of options. The first example on the page shows "YES" or "NO" and the second one shows a list of "db1", "db2", or "db3" that you have to choose from.

I believe you can do something similar to accept an arbitrary string, particularly as the enum option is actually UI only and can be bypassed in the API.

Try:

apiVersion: argoproj.io/v1alpha1
kind: Workflow
metadata:
  generateName: user-input-param-example-
  namespace: custom-namespace
spec:
  serviceAccountName: argo-workflows
  entrypoint: main
  templates:
  - name: main
    steps:
    - - name: suspend-step
        template: suspend-template
    - - name: echo-user-input-step
        template: echo-user-input-template
        arguments:
          parameters:
          - name: user-input
            value: "{{steps.suspend-step.outputs.parameters.user-input}}"

  - name: suspend-template
    inputs:
      parameters:
      - name: user-input
        description: Type something in
    outputs:
      parameters:
      - name: user-input
        valueFrom:
          supplied: {}

  - name: echo-user-input-template
    inputs:
      parameters:
      - name: user-input
    container:
      image: alpine:latest
      command: ["/bin/sh", "-c"]
      args: ["echo 'User input received: {{inputs.parameters.user-input}}'"]

Upon looking for similar issues I found this #7563 but this is picking up the null value ("") and simply succeeds without prompting for user input in the UI.

Since that was an old bug that was fixed, I believe using the correct valueFrom.supplied: {} syntax should work now:

        valueFrom:
          supplied: {}