From 001e1df08eadb2d2eea169d82cd1b97c6471f362 Mon Sep 17 00:00:00 2001 From: frikky Date: Sat, 11 Dec 2021 02:43:31 +0100 Subject: [PATCH] #444: Fixed basic pieces for user input trigger to run open source standalone --- backend/app_sdk/app_base.py | 21 ++-- backend/go-app/walkoff.go | 59 ++++++--- frontend/src/views/AngularWorkflow.jsx | 63 +++++++++- frontend/src/views/Workflows.jsx | 6 +- functions/onprem/worker/build.sh | 2 +- functions/onprem/worker/go.mod | 2 +- functions/onprem/worker/go.sum | 4 + functions/onprem/worker/worker.go | 164 ++++++++++++++++++++++--- 8 files changed, 271 insertions(+), 50 deletions(-) diff --git a/backend/app_sdk/app_base.py b/backend/app_sdk/app_base.py index 6889ab75..c205c722 100644 --- a/backend/app_sdk/app_base.py +++ b/backend/app_sdk/app_base.py @@ -65,17 +65,19 @@ class AppBase: # Checks output for whether it should be automatically parsed or not def run_magic_parser(self, input_data): if not isinstance(input_data, str): + self.logger.info("[DEBUG] Not string. Returning from magic") return input_data # Don't touch existing JSON/lists if (input_data.startswith("[") and input_data.endswith("]")) or (input_data.startswith("{") and input_data.endswith("}")): + self.logger.info("[DEBUG] Already JSON-like. Returning from magic") return input_data # Don't touch large data. if len(input_data) > 100000: + self.logger.info("[DEBUG] Value too large. Returning from magic") return input_data - new_input = input_data try: #new_input.strip() @@ -91,6 +93,7 @@ class AppBase: splititem = "," else: new_return.append(item) + index += 1 continue @@ -102,6 +105,7 @@ class AppBase: # Prevent large data or infinite loops if index > 10000: + self.logger.info(f"[DEBUG] Infinite loop. Returning default data.") return input_data fixed_return = [] @@ -120,13 +124,13 @@ class AppBase: new_input = fixed_return except Exception as e: - self.logger.info(f"[DEBUG] Failed to run magic parser (2): {e}") + self.logger.info(f"[ERROR] Failed to run magic parser (2): {e}") return input_data try: new_input = input_data.split() except Exception as e: - self.logger.info(f"[DEBUG] Failed to run magic parser (1): {e}") + self.logger.info(f"[ERROR] Failed to run magic parser (1): {e}") return input_data # Won't ever touch this one? @@ -134,7 +138,7 @@ class AppBase: try: return json.dumps(new_input) except Exception as e: - self.logger.info(f"[DEBUG] Failed to run magic parser: {e}") + self.logger.info(f"[ERROR] Failed to run magic parser: {e}") return new_input @@ -145,13 +149,14 @@ class AppBase: action_result["status"] = "FAILURE" try: - if self.original_action["run_magic_output"] == True: - self.logger.warning("[INFO] Action result ran with Magic parser output.") + #self.logger.info(f"[DEBUG] ACTION: {self.action}") + if self.action["run_magic_output"] == True: + self.logger.warning(f"[INFO] Action result ran with Magic parser output.") action_result["result"] = self.run_magic_parser(action_result["result"]) else: - self.logger.warning("[ERROR] Magic output not defined.") + self.logger.warning(f"[ERROR] Magic output not defined.") except Exception as e: - self.logger.warning("[ERROR] Failed to run magic autoparser: {e}") + self.logger.warning(f"[ERROR] Failed to run magic autoparser: {e}") pass # Try it with some magic diff --git a/backend/go-app/walkoff.go b/backend/go-app/walkoff.go index 420dbd78..7be313e8 100644 --- a/backend/go-app/walkoff.go +++ b/backend/go-app/walkoff.go @@ -366,7 +366,7 @@ func handleGetStreamResults(resp http.ResponseWriter, request *http.Request) { ctx := context.Background() workflowExecution, err := shuffle.GetWorkflowExecution(ctx, actionResult.ExecutionId) if err != nil { - log.Printf("Failed getting execution (streamresult) %s: %s", actionResult.ExecutionId, err) + log.Printf("[WARNING] Failed getting execution (streamresult) %s: %s", actionResult.ExecutionId, err) resp.WriteHeader(401) resp.Write([]byte(fmt.Sprintf(`{"success": false, "reason": "Bad authorization key or execution_id might not exist."}`))) return @@ -494,7 +494,9 @@ func handleWorkflowQueue(resp http.ResponseWriter, request *http.Request) { err := handleUserInput(trigger, orgId, workflowExecution.Workflow.ID, workflowExecution.ExecutionId) if err != nil { log.Printf("[WARNING] Failed userinput handler: %s", err) - actionResult.Result = fmt.Sprintf("Cloud error: %s", err) + + actionResult.Result = fmt.Sprintf(`{"success": False, "reason": "%s"}`, err) + workflowExecution.Results = append(workflowExecution.Results, actionResult) workflowExecution.Status = "ABORTED" err = shuffle.SetWorkflowExecution(ctx, *workflowExecution, true) @@ -506,12 +508,13 @@ func handleWorkflowQueue(resp http.ResponseWriter, request *http.Request) { resp.WriteHeader(401) resp.Write([]byte(fmt.Sprintf(`{"success": false, "reason": "Error: %s"}`, err))) + return } else { log.Printf("[INFO] Successful userinput handler") resp.WriteHeader(200) resp.Write([]byte(fmt.Sprintf(`{"success": true, "reason": "CLOUD IS DONE"}`))) - actionResult.Result = "Waiting for user feedback based on configuration" + actionResult.Result = `{"success": True, "reason": "Waiting for user feedback based on configuration"}` workflowExecution.Results = append(workflowExecution.Results, actionResult) workflowExecution.Status = actionResult.Status @@ -519,7 +522,7 @@ func handleWorkflowQueue(resp http.ResponseWriter, request *http.Request) { if err != nil { log.Printf("[WARNING] Failed setting userinput: %s", err) } else { - log.Printf("Successfully set the execution to waiting.") + log.Printf("[DEBUG] Successfully set the execution to waiting.") } } @@ -1035,13 +1038,7 @@ func executeWorkflow(resp http.ResponseWriter, request *http.Request) { return } - user, err := shuffle.HandleApiAuthentication(resp, request) - if err != nil { - log.Printf("[INFO] Api authentication failed in execute workflow: %s", err) - resp.WriteHeader(401) - resp.Write([]byte(`{"success": false}`)) - return - } + user, userErr := shuffle.HandleApiAuthentication(resp, request) if user.Role == "org-reader" { log.Printf("[WARNING] Org-reader doesn't have access to run workflow: %s (%s)", user.Username, user.Id) @@ -1079,14 +1076,38 @@ func executeWorkflow(resp http.ResponseWriter, request *http.Request) { return } - if user.Id != workflow.Owner && user.Role != "scheduler" && user.Role != fmt.Sprintf("workflow_%s", fileId) { - if workflow.OrgId == user.ActiveOrg.Id && user.Role == "admin" { - log.Printf("[AUDIT] Letting user %s execute %s because they're admin of the same org", user.Username, workflow.ID) - } else { - log.Printf("[AUDIT] Wrong user (%s) for workflow %s (execute)", user.Username, workflow.ID) + executionAuthValid := false + newOrgId := "" + if userErr != nil { + // Check if the execution data has correct info in it! Happens based on subflows. + // 1. Parent workflow contains this workflow ID in the source trigger? + // 2. Parent workflow's owner is same org? + // 3. Parent execution auth is correct + + executionAuthValid, newOrgId = shuffle.RunExecuteAccessValidation(request, workflow) + if !executionAuthValid { + log.Printf("[INFO] Api authentication failed in execute workflow: %s", userErr) resp.WriteHeader(401) resp.Write([]byte(`{"success": false}`)) return + } else { + log.Printf("[DEBUG] Execution of %s successfully validated and started based on subflow or user input execution", workflow.ID) + user.ActiveOrg = shuffle.OrgMini{ + Id: newOrgId, + } + } + } + + if !executionAuthValid { + if user.Id != workflow.Owner && user.Role != "scheduler" && user.Role != fmt.Sprintf("workflow_%s", fileId) { + if workflow.OrgId == user.ActiveOrg.Id && user.Role == "admin" { + log.Printf("[AUDIT] Letting user %s execute %s because they're admin of the same org", user.Username, workflow.ID) + } else { + log.Printf("[AUDIT] Wrong user (%s) for workflow %s (execute)", user.Username, workflow.ID) + resp.WriteHeader(401) + resp.Write([]byte(`{"success": false}`)) + return + } } } @@ -2419,6 +2440,7 @@ func handleUserInput(trigger shuffle.Trigger, organizationId string, workflowId // E.g. check email sms := "" email := "" + subflow := "" triggerType := "" triggerInformation := "" for _, item := range trigger.Parameters { @@ -2430,11 +2452,14 @@ func handleUserInput(trigger shuffle.Trigger, organizationId string, workflowId email = item.Value } else if item.Name == "sms" { sms = item.Value + } else if item.Name == "subflow" { + subflow = item.Value } } + _ = subflow if len(triggerType) == 0 { - log.Printf("No type specified for user input node") + log.Printf("[WARNING] No type specified for user input node") return errors.New("No type specified for user input node") } diff --git a/frontend/src/views/AngularWorkflow.jsx b/frontend/src/views/AngularWorkflow.jsx index a229cbe6..979e438b 100644 --- a/frontend/src/views/AngularWorkflow.jsx +++ b/frontend/src/views/AngularWorkflow.jsx @@ -8705,6 +8705,11 @@ const AngularWorkflow = (props) => { name: "sms", value: "0000000", }; + workflow.triggers[selectedTriggerIndex].parameters[5] = { + name: "subflow", + value: "", + }; + setWorkflow(workflow); } @@ -8807,7 +8812,7 @@ const AngularWorkflow = (props) => { }} />
- Information: + Information
{ }} />
- Contact options: + Contact options
+ { + setTriggerOptionsWrapper("subflow"); + }} + color="primary" + value="subflow" + disabled + /> + } + label={
Subflow
} + /> { }} fullWidth color="primary" + required placeholder={"mail1@company.com,mail2@company.com"} defaultValue={ workflow.triggers[selectedTriggerIndex].parameters[3].value @@ -8960,6 +8986,39 @@ const AngularWorkflow = (props) => { setUpdate(Math.random()); }} /> + ) : null} + {workflow.triggers[selectedTriggerIndex].parameters[2] !== + undefined && + workflow.triggers[ + selectedTriggerIndex + ].parameters[2].value.includes("subflow") ? ( + { + workflow.triggers[selectedTriggerIndex].parameters[5].value = + event.target.value; + setWorkflow(workflow); + setUpdate(Math.random()); + }} + /> ) : null} diff --git a/frontend/src/views/Workflows.jsx b/frontend/src/views/Workflows.jsx index de3740bb..9dc3c71f 100644 --- a/frontend/src/views/Workflows.jsx +++ b/frontend/src/views/Workflows.jsx @@ -400,7 +400,7 @@ export const validateJson = (showResult) => { try { result = jsonvalid ? JSON.parse(showResult) : showResult; } catch (e) { - //console.log("Failed parsing JSON even though its valid: ", e) + ////console.log("Failed parsing JSON even though its valid: ", e) jsonvalid = false; } @@ -413,12 +413,12 @@ export const validateJson = (showResult) => { try { var newstr = showResult.replaceAll("'", '"') - console.log("Try replacements and trimming with new value: ", newstr) + //console.log("Try replacements and trimming with new value: ", newstr) result = JSON.parse(newstr) jsonvalid = true } catch (e) { - console.log("Failed parsing JSON even though its valid (2): ", e) + //console.log("Failed parsing JSON even though its valid (2): ", e) jsonvalid = false } } diff --git a/functions/onprem/worker/build.sh b/functions/onprem/worker/build.sh index cf854af6..1b9c42b3 100644 --- a/functions/onprem/worker/build.sh +++ b/functions/onprem/worker/build.sh @@ -1,5 +1,5 @@ NAME=shuffle-worker -VERSION=0.9.36 +VERSION=0.9.40 echo "Running docker build with $NAME:$VERSION" #CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o worker.bin . diff --git a/functions/onprem/worker/go.mod b/functions/onprem/worker/go.mod index 036d78da..9895637c 100644 --- a/functions/onprem/worker/go.mod +++ b/functions/onprem/worker/go.mod @@ -10,6 +10,6 @@ require ( github.com/docker/go-connections v0.4.0 // indirect github.com/gorilla/mux v1.8.0 github.com/patrickmn/go-cache v2.1.0+incompatible - github.com/shuffle/shuffle-shared v0.1.35 + github.com/shuffle/shuffle-shared v0.1.55 go4.org v0.0.0-20201209231011-d4a079459e60 // indirect ) diff --git a/functions/onprem/worker/go.sum b/functions/onprem/worker/go.sum index 9957793e..98ac5602 100644 --- a/functions/onprem/worker/go.sum +++ b/functions/onprem/worker/go.sum @@ -574,6 +574,10 @@ github.com/shuffle/shuffle-shared v0.1.33 h1:1U0yKWNfW7K7EKOj2aqSmd20UIA+nJeIurG github.com/shuffle/shuffle-shared v0.1.33/go.mod h1:0QrK51T12CpCj/be8hXduj/RtDnoeaZ3rfogELZE2IU= github.com/shuffle/shuffle-shared v0.1.35 h1:CoCur/G+TaM2xiLgDCVdVxPhFffNK/4YRWTtzRBprvg= github.com/shuffle/shuffle-shared v0.1.35/go.mod h1:2ndjLm4ZOvY6arGFwOgGnkQ457Ke7gka9HDF/EkdIxQ= +github.com/shuffle/shuffle-shared v0.1.54 h1:dHpwot+5RPX8k9EC/8Yd+QYsFqCsqsv+J1wC+EtGxzI= +github.com/shuffle/shuffle-shared v0.1.54/go.mod h1:2ndjLm4ZOvY6arGFwOgGnkQ457Ke7gka9HDF/EkdIxQ= +github.com/shuffle/shuffle-shared v0.1.55 h1:feHtTN7Uhr1aMxkMIo3xZbr97599VB2eLekogTj/9Z4= +github.com/shuffle/shuffle-shared v0.1.55/go.mod h1:2ndjLm4ZOvY6arGFwOgGnkQ457Ke7gka9HDF/EkdIxQ= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.0.4-0.20170822132746-89742aefa4b2/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc= github.com/sirupsen/logrus v1.0.6/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc= diff --git a/functions/onprem/worker/worker.go b/functions/onprem/worker/worker.go index 9ed76cfa..36f9c478 100644 --- a/functions/onprem/worker/worker.go +++ b/functions/onprem/worker/worker.go @@ -82,6 +82,12 @@ var executedIds = []string{} var portMappings map[string]int var baseport = 33333 +type UserInputSubflow struct { + Argument string `json:"execution_argument"` + ContinueUrl string `json:"continue_url"` + CancelUrl string `json:"cancel_url"` +} + // removes every container except itself (worker) func shutdown(workflowExecution shuffle.WorkflowExecution, nodeId string, reason string, handleResultSend bool) { log.Printf("[INFO] Shutdown (%s) started with reason %#v. Result amount: %d. ResultsSent: %d, Send result: %#v", workflowExecution.Status, reason, len(workflowExecution.Results), requestsSent, handleResultSend) @@ -642,6 +648,11 @@ func handleExecutionResult(workflowExecution shuffle.WorkflowExecution) { ctx := context.Background() startAction, extra, children, parents, visited, executed, nextActions, environments := shuffle.GetExecutionVariables(ctx, workflowExecution.ExecutionId) log.Printf("[DEBUG] Getting info for %s. Extra: %d", workflowExecution.ExecutionId, extra) + dockercli, err := dockerclient.NewEnvClient() + if err != nil { + log.Printf("[ERROR] Unable to create docker client (3): %s", err) + return + } log.Printf("[INFO] Inside execution results with %d / %d results", len(workflowExecution.Results), len(workflowExecution.Workflow.Actions)+extra) @@ -865,6 +876,7 @@ func handleExecutionResult(workflowExecution shuffle.WorkflowExecution) { } // FIXME: Add startnode from frontend + action.Label = trigger.Label action.Parameters = []shuffle.WorkflowAppActionParameter{} for _, parameter := range trigger.Parameters { parameter.Variant = "STATIC_VALUE" @@ -900,15 +912,15 @@ func handleExecutionResult(workflowExecution shuffle.WorkflowExecution) { //} //continue } else if action.AppName == "User Input" { - log.Printf("USER INPUT!") + log.Printf("[DEBUG] RUNNING USER INPUT!") if action.ID == workflowExecution.Start { - log.Printf("Skipping because it's the startnode") + log.Printf("[DEBUG] Skipping user input because it's the startnode") visited = append(visited, action.ID) executed = append(executed, action.ID) continue } else { - log.Printf("Should stop after this iteration because it's user-input based. %#v", action) + log.Printf("[DEBUG] Should stop after this iteration because it's user-input based. %#v", action) trigger := shuffle.Trigger{} for _, innertrigger := range workflowExecution.Workflow.Triggers { if innertrigger.ID == action.ID { @@ -917,14 +929,23 @@ func handleExecutionResult(workflowExecution shuffle.WorkflowExecution) { } } + action.Label = action.Label + action.Parameters = []shuffle.WorkflowAppActionParameter{} + for _, parameter := range trigger.Parameters { + action.Parameters = append(action.Parameters, shuffle.WorkflowAppActionParameter{ + Name: parameter.Name, + Value: parameter.Value, + }) + } + trigger.LargeImage = "" triggerData, err := json.Marshal(trigger) if err != nil { - log.Printf("Failed unmarshalling action: %s", err) + log.Printf("[WARNING] Failed unmarshalling action: %s", err) triggerData = []byte("Failed unmarshalling. Cancel execution!") } - err = runUserInput(topClient, action, workflowExecution.Workflow.ID, workflowExecution.ExecutionId, workflowExecution.Authorization, string(triggerData)) + err = runUserInput(topClient, action, workflowExecution.Workflow.ID, workflowExecution, workflowExecution.Authorization, string(triggerData), dockercli) if err != nil { log.Printf("[ERROR] Failed launching backend magic: %s", err) os.Exit(3) @@ -1025,12 +1046,6 @@ func handleExecutionResult(workflowExecution shuffle.WorkflowExecution) { //executed = append(executed, action.ID) // FIXME - check whether it's running locally yet too - dockercli, err := dockerclient.NewEnvClient() - if err != nil { - log.Printf("[ERROR] Unable to create docker client (2): %s", err) - //return err - continue - } stats, err := dockercli.ContainerInspect(context.Background(), identifier) if err != nil || stats.ContainerJSONBase.State.Status != "running" { @@ -1328,7 +1343,7 @@ func handleExecutionResult(workflowExecution shuffle.WorkflowExecution) { // FIXME - new request here // FIXME - clean up stopped (remove) containers with this execution id - err := shuffle.UpdateExecutionVariables(ctx, workflowExecution.ExecutionId, startAction, children, parents, visited, executed, nextActions, environments, extra) + err = shuffle.UpdateExecutionVariables(ctx, workflowExecution.ExecutionId, startAction, children, parents, visited, executed, nextActions, environments, extra) if err != nil { log.Printf("\n\n[ERROR] Failed to update exec variables for execution %s: %s (2)\n\n", workflowExecution.ExecutionId, err) } @@ -1661,31 +1676,32 @@ func runSkipAction(client *http.Client, action shuffle.Action, workflowId, workf ) if err != nil { - log.Printf("[WARNING] Error building test request (0): %s", err) + log.Printf("[WARNING] Error building skip request (0): %s", err) return err } newresp, err := client.Do(req) if err != nil { - log.Printf("[WARNING] Error running test request (0): %s", err) + log.Printf("[WARNING] Error running skip request (0): %s", err) return err } body, err := ioutil.ReadAll(newresp.Body) if err != nil { - log.Printf("[WARNING] Failed reading body when waiting (0): %s", err) + log.Printf("[WARNING] Failed reading body when skipping (0): %s", err) return err } - log.Printf("[INFO] User Input Body: %s", string(body)) + log.Printf("[INFO] Skip Action Body: %s", string(body)) return nil } -func runUserInput(client *http.Client, action shuffle.Action, workflowId, workflowExecutionId, authorization string, configuration string) error { +// Sends request back to backend to handle the node +func runUserInput(client *http.Client, action shuffle.Action, workflowId string, workflowExecution shuffle.WorkflowExecution, authorization string, configuration string, dockercli *dockerclient.Client) error { timeNow := time.Now().Unix() result := shuffle.ActionResult{ Action: action, - ExecutionId: workflowExecutionId, + ExecutionId: workflowExecution.ExecutionId, Authorization: authorization, Result: configuration, StartedAt: timeNow, @@ -1693,6 +1709,118 @@ func runUserInput(client *http.Client, action shuffle.Action, workflowId, workfl Status: "WAITING", } + // Checking for userinput to deploy subflow for it + subflow := false + subflowId := "" + argument := "" + continueUrl := "testing continue" + cancelUrl := "testing cancel" + for _, item := range action.Parameters { + if item.Name == "subflow" { + subflow = true + subflowId = item.Value + } else if item.Name == "alertinfo" { + argument = item.Value + } + } + + if subflow { + log.Printf("[DEBUG] Should run action with subflow app with argument %#v", argument) + newAction := shuffle.Action{ + AppName: "shuffle-subflow", + Name: "run_subflow", + AppVersion: "1.0.0", + Label: "User Input Subflow Execution", + } + + identifier := fmt.Sprintf("%s_%s_%s_%s", newAction.AppName, newAction.AppVersion, action.ID, workflowExecution.ExecutionId) + if strings.Contains(identifier, " ") { + identifier = strings.ReplaceAll(identifier, " ", "-") + } + + inputValue := UserInputSubflow{ + Argument: argument, + ContinueUrl: continueUrl, + CancelUrl: cancelUrl, + } + + parsedArgument, err := json.Marshal(inputValue) + if err != nil { + log.Printf("[ERROR] Failed to parse arguments: %s", err) + parsedArgument = []byte(argument) + } + + newAction.Parameters = []shuffle.WorkflowAppActionParameter{ + shuffle.WorkflowAppActionParameter{ + Name: "user_apikey", + Value: workflowExecution.Authorization, + }, + shuffle.WorkflowAppActionParameter{ + Name: "workflow", + Value: subflowId, + }, + shuffle.WorkflowAppActionParameter{ + Name: "argument", + Value: string(parsedArgument), + }, + } + + newAction.Parameters = append(newAction.Parameters, shuffle.WorkflowAppActionParameter{ + Name: "source_workflow", + Value: workflowExecution.Workflow.ID, + }) + + newAction.Parameters = append(newAction.Parameters, shuffle.WorkflowAppActionParameter{ + Name: "source_execution", + Value: workflowExecution.ExecutionId, + }) + + newAction.Parameters = append(newAction.Parameters, shuffle.WorkflowAppActionParameter{ + Name: "source_node", + Value: action.ID, + }) + + newAction.Parameters = append(newAction.Parameters, shuffle.WorkflowAppActionParameter{ + Name: "source_auth", + Value: workflowExecution.Authorization, + }) + + newAction.Parameters = append(newAction.Parameters, shuffle.WorkflowAppActionParameter{ + Name: "startnode", + Value: "", + }) + + // If cleanup is set, it should run for efficiency + //appName := strings.Replace(identifier, fmt.Sprintf("_%s", action.ID), "", -1) + //appName = strings.Replace(appName, fmt.Sprintf("_%s", workflowExecution.ExecutionId), "", -1) + actionData, err := json.Marshal(newAction) + if err != nil { + return err + } + + env := []string{ + fmt.Sprintf("ACTION=%s", string(actionData)), + fmt.Sprintf("EXECUTIONID=%s", workflowExecution.ExecutionId), + fmt.Sprintf("AUTHORIZATION=%s", workflowExecution.Authorization), + fmt.Sprintf("CALLBACK_URL=%s", baseUrl), + fmt.Sprintf("BASE_URL=%s", appCallbackUrl), + fmt.Sprintf("TZ=%s", timezone), + } + + if strings.ToLower(os.Getenv("SHUFFLE_PASS_APP_PROXY")) == "true" { + //log.Printf("APPENDING PROXY TO THE APP!") + env = append(env, fmt.Sprintf("HTTP_PROXY=%s", os.Getenv("HTTP_PROXY"))) + env = append(env, fmt.Sprintf("HTTPS_PROXY=%s", os.Getenv("HTTPS_PROXY"))) + } + + err = deployApp(dockercli, "frikky/shuffle:shuffle-subflow_1.0.0", identifier, env, workflowExecution, newAction) + if err != nil { + log.Printf("[ERROR] Failed to deploy subflow for user input trigger %s: %s", action.ID, err) + } + } else { + log.Printf("[DEBUG] Running user input WITHOUT subflow") + } + resultData, err := json.Marshal(result) if err != nil { return err