diff --git a/backend/go-app/go.mod b/backend/go-app/go.mod index 8e686705..ea02517b 100644 --- a/backend/go-app/go.mod +++ b/backend/go-app/go.mod @@ -22,7 +22,7 @@ require ( github.com/gorilla/mux v1.8.1 github.com/h2non/filetype v1.1.3 github.com/satori/go.uuid v1.2.0 - github.com/shuffle/shuffle-shared v0.8.39 + github.com/shuffle/shuffle-shared v0.8.50 golang.org/x/crypto v0.36.0 google.golang.org/api v0.228.0 google.golang.org/grpc v1.71.1 diff --git a/backend/go-app/go.sum b/backend/go-app/go.sum index a3382d6a..ca216f74 100644 --- a/backend/go-app/go.sum +++ b/backend/go-app/go.sum @@ -341,8 +341,8 @@ github.com/sendgrid/sendgrid-go v3.14.0+incompatible h1:KDSasSTktAqMJCYClHVE94Fc github.com/sendgrid/sendgrid-go v3.14.0+incompatible/go.mod h1:QRQt+LX/NmgVEvmdRw0VT/QgUn499+iza2FnDca9fg8= github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 h1:n661drycOFuPLCN3Uc8sB6B/s6Z4t2xvBgU1htSHuq8= github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4= -github.com/shuffle/shuffle-shared v0.8.39 h1:ylRj+2xGIOPQfpawf45udnQzKLtTP9JFEFyREc2GJXM= -github.com/shuffle/shuffle-shared v0.8.39/go.mod h1:z+ISGBgNINmZvWNrtGTc51yVG+pMkpBFu9ZLVlTyuag= +github.com/shuffle/shuffle-shared v0.8.50 h1:Sy6o7Nrcd3QG+m28775STKS3uOfaXDzDcctTuaYfdYQ= +github.com/shuffle/shuffle-shared v0.8.50/go.mod h1:z+ISGBgNINmZvWNrtGTc51yVG+pMkpBFu9ZLVlTyuag= github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= diff --git a/backend/go-app/main.go b/backend/go-app/main.go index 68fc4e88..fbd2a251 100755 --- a/backend/go-app/main.go +++ b/backend/go-app/main.go @@ -5138,7 +5138,7 @@ func initHandlers() { r.HandleFunc("/api/v1/apps/{key}/execute", executeSingleAction).Methods("POST", "OPTIONS") r.HandleFunc("/api/v1/apps/{key}/run", executeSingleAction).Methods("POST", "OPTIONS") r.HandleFunc("/api/v1/apps/categories", shuffle.GetActiveCategories).Methods("GET", "OPTIONS") - r.HandleFunc("/api/v1/apps/categories/run", shuffle.RunCategoryAction).Methods("POST", "OPTIONS") + //r.HandleFunc("/api/v1/apps/categories/run", shuffle.RunCategoryAction).Methods("POST", "OPTIONS") r.HandleFunc("/api/v1/apps/upload", handleAppZipUpload).Methods("POST", "OPTIONS") r.HandleFunc("/api/v1/apps/{appId}/activate", activateWorkflowAppDocker).Methods("GET", "OPTIONS") r.HandleFunc("/api/v1/apps/{appId}/deactivate", activateWorkflowAppDocker).Methods("GET", "OPTIONS") diff --git a/backend/go-app/walkoff.go b/backend/go-app/walkoff.go index 14c5ac28..8357de3e 100755 --- a/backend/go-app/walkoff.go +++ b/backend/go-app/walkoff.go @@ -3039,7 +3039,13 @@ func executeSingleAction(resp http.ResponseWriter, request *http.Request) { shouldRerun = true } - workflowExecution, err := shuffle.PrepareSingleAction(ctx, user, fileId, body, runValidationAction) + decisionId := "" + decision, decisionOk := query["decision_id"] + if decisionOk && len(decision) > 0 { + decisionId = decision[0] + } + + workflowExecution, err := shuffle.PrepareSingleAction(ctx, user, fileId, body, runValidationAction, decisionId) debugUrl := fmt.Sprintf("/workflows/%s?execution_id=%s", workflowExecution.Workflow.ID, workflowExecution.ExecutionId) resp.Header().Add("X-Debug-Url", debugUrl) @@ -3101,7 +3107,12 @@ func executeSingleAction(resp http.ResponseWriter, request *http.Request) { return } - returnBody := shuffle.HandleRetValidation(ctx, workflowExecution, 1) + actionId := "" + if len(workflowExecution.Workflow.Actions) == 1 { + actionId = workflowExecution.Workflow.Actions[0].ID + } + + returnBody := shuffle.HandleRetValidation(ctx, workflowExecution, 1, actionId) returnBytes, err := json.Marshal(returnBody) if err != nil { log.Printf("[ERROR] Failed to marshal retStruct in single execution: %s", err) diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx index 7fa7c847..2192be04 100755 --- a/frontend/src/App.jsx +++ b/frontend/src/App.jsx @@ -791,6 +791,40 @@ const App = (message, props) => { /> } /> + + } + /> + + } + /> { /> } /> + + + } + /> + 0 { + env = append(env, fmt.Sprintf("SHUFFLE_APP_POD_SECURITY_CONTEXT=%s", appPodSecurityContext)) + } + + if len(appContainerSecurityContext) > 0 { + env = append(env, fmt.Sprintf("SHUFFLE_APP_CONTAINER_SECURITY_CONTEXT=%s", appContainerSecurityContext)) + } + clientset, _, err := shuffle.GetKubernetesClient() if err != nil { log.Printf("[ERROR] Error getting kubernetes client:", err) @@ -1085,10 +1097,33 @@ func deployK8sWorker(image string, identifier string, env []string) error { "app.kubernetes.io/instance": identifier, } + // Parse security contexts from env + var podSecurityContext *corev1.PodSecurityContext + var containerSecurityContext *corev1.SecurityContext + + if len(workerPodSecurityContext) > 0 { + podSecurityContext = &corev1.PodSecurityContext{} + err = json.Unmarshal([]byte(workerPodSecurityContext), podSecurityContext) + if err != nil { + log.Printf("[ERROR] Failed to unmarshal worker pod security context: %v", err) + return fmt.Errorf("failed to unmarshal worker pod security context: %v", err) + } + } + + if len(workerContainerSecurityContext) > 0 { + containerSecurityContext = &corev1.SecurityContext{} + err = json.Unmarshal([]byte(workerContainerSecurityContext), containerSecurityContext) + if err != nil { + log.Printf("[ERROR] Failed to unmarshal worker container security context: %v", err) + return fmt.Errorf("failed to unmarshal worker container security context: %v", err) + } + } + containerAttachment := corev1.Container{ - Name: identifier, - Image: kubernetesImage, - Env: buildEnvVars(envMap), + Name: identifier, + Image: kubernetesImage, + Env: buildEnvVars(envMap), + SecurityContext: containerSecurityContext, //ImagePullPolicy: "Never", ImagePullPolicy: corev1.PullIfNotPresent, @@ -1205,6 +1240,7 @@ func deployK8sWorker(image string, identifier string, env []string) error { }, DNSPolicy: corev1.DNSClusterFirst, ServiceAccountName: workerServiceAccountName, + SecurityContext: podSecurityContext, }, }, }, diff --git a/functions/onprem/worker/worker.go b/functions/onprem/worker/worker.go index c411ae52..0fddb006 100644 --- a/functions/onprem/worker/worker.go +++ b/functions/onprem/worker/worker.go @@ -57,9 +57,13 @@ var logsDisabled = os.Getenv("SHUFFLE_LOGS_DISABLED") var cleanupEnv = strings.ToLower(os.Getenv("CLEANUP")) var swarmNetworkName = os.Getenv("SHUFFLE_SWARM_NETWORK_NAME") var dockerApiVersion = strings.ToLower(os.Getenv("DOCKER_API_VERSION")) -var appServiceAccountName = os.Getenv("SHUFFLE_APP_SERVICE_ACCOUNT_NAME") +// Kubernetes settings +var appServiceAccountName = os.Getenv("SHUFFLE_APP_SERVICE_ACCOUNT_NAME") +var appPodSecurityContext = os.Getenv("SHUFFLE_APP_POD_SECURITY_CONTEXT") +var appContainerSecurityContext = os.Getenv("SHUFFLE_APP_CONTAINER_SECURITY_CONTEXT") var kubernetesNamespace = os.Getenv("KUBERNETES_NAMESPACE") + var executionCount int64 var baseimagename = os.Getenv("SHUFFLE_BASE_IMAGE_NAME") @@ -74,6 +78,7 @@ var appsInitialized = false var hostname string var maxReplicas = uint64(12) +var debug bool /* var environments []string @@ -506,6 +511,28 @@ func deployk8sApp(image string, identifier string, env []string) error { "app.kubernetes.io/instance": name, } + // Parse security contexts from env + var podSecurityContext *corev1.PodSecurityContext + var containerSecurityContext *corev1.SecurityContext + + if len(appPodSecurityContext) > 0 { + podSecurityContext = &corev1.PodSecurityContext{} + err = json.Unmarshal([]byte(appPodSecurityContext), podSecurityContext) + if err != nil { + log.Printf("[ERROR] Failed to unmarshal app pod security context: %v", err) + return fmt.Errorf("failed to unmarshal app pod security context: %v", err) + } + } + + if len(appContainerSecurityContext) > 0 { + containerSecurityContext = &corev1.SecurityContext{} + err = json.Unmarshal([]byte(appContainerSecurityContext), containerSecurityContext) + if err != nil { + log.Printf("[ERROR] Failed to unmarshal app container security context: %v", err) + return fmt.Errorf("failed to unmarshal app container security context: %v", err) + } + } + // pod := &corev1.Pod{ // ObjectMeta: metav1.ObjectMeta{ // Name: podName, @@ -608,10 +635,12 @@ func deployk8sApp(image string, identifier string, env []string) error { ContainerPort: int32(deployport), }, }, + SecurityContext: containerSecurityContext, }, }, DNSPolicy: corev1.DNSClusterFirst, ServiceAccountName: appServiceAccountName, + SecurityContext: podSecurityContext, }, }, }, @@ -2555,11 +2584,16 @@ func runWorkflowExecutionTransaction(ctx context.Context, attempts int64, workfl } if setExecution || workflowExecution.Status == "FINISHED" || workflowExecution.Status == "ABORTED" || workflowExecution.Status == "FAILURE" { - log.Printf("[DEBUG][%s] Running setexec with status %s and %d/%d results", workflowExecution.ExecutionId, workflowExecution.Status, len(workflowExecution.Results), len(workflowExecution.Workflow.Actions)) + if debug { + log.Printf("[DEBUG][%s] Running setexec with status %s and %d/%d results", workflowExecution.ExecutionId, workflowExecution.Status, len(workflowExecution.Results), len(workflowExecution.Workflow.Actions)) + } + //result(s)", workflowExecution.ExecutionId, workflowExecution.Status, len(workflowExecution.Results)) err = setWorkflowExecution(ctx, *workflowExecution, dbSave) if err != nil { - resp.WriteHeader(401) + log.Printf("[ERROR][%s] Failed setting execution: %s", workflowExecution.ExecutionId, err) + + resp.WriteHeader(400) resp.Write([]byte(fmt.Sprintf(`{"success": false, "reason": "Failed setting workflowexecution actionresult: %s"}`, err))) return } @@ -2568,7 +2602,10 @@ func runWorkflowExecutionTransaction(ctx context.Context, attempts int64, workfl if os.Getenv("SHUFFLE_SWARM_CONFIG") == "run" || os.Getenv("SHUFFLE_SWARM_CONFIG") == "swarm" { finished := shuffle.ValidateFinished(ctx, -1, *workflowExecution) if !finished { - log.Printf("[DEBUG][%s] Handling next node since it's not finished!", workflowExecution.ExecutionId) + if debug { + log.Printf("[DEBUG][%s] Handling next node since it's not finished!", workflowExecution.ExecutionId) + } + handleExecutionResult(*workflowExecution) } else { shutdownData, err := json.Marshal(workflowExecution) @@ -3526,7 +3563,9 @@ func sendAppRequest(ctx context.Context, incomingUrl, appName string, port int, log.Printf("[ERROR] Failed reading app request body body: %s", err) return err } else { - log.Printf("[DEBUG][%s] NEWRESP (from app): %s", workflowExecution.ExecutionId, string(body)) + if debug { + log.Printf("[DEBUG][%s] NEWRESP (from app): %s", workflowExecution.ExecutionId, string(body)) + } } return nil @@ -3918,6 +3957,10 @@ func checkStandaloneRun() { func main() { checkStandaloneRun() + if os.Getenv("DEBUG") == "true" { + debug = true + } + /*** STARTREMOVE ***/ if os.Getenv("SHUFFLE_SWARM_CONFIG") == "run" || os.Getenv("SHUFFLE_SWARM_CONFIG") == "swarm" { logsDisabled = "true"