From a0393efce537ef47938460dbfb6ad71fb070882d Mon Sep 17 00:00:00 2001 From: Saranya Jena Date: Thu, 26 Oct 2023 11:02:03 +0530 Subject: [PATCH] Added backend changes for stop experiment (#4227) * Added backend changes for stop experiment Signed-off-by: Saranya-jena * fixed issues with subscriber for stop experiemnt Signed-off-by: Saranya-jena * updated logic Signed-off-by: Saranya-jena * fixed imports Signed-off-by: Saranya-jena * fixed imports Signed-off-by: Saranya-jena --------- Signed-off-by: Saranya-jena --- .../shared/chaos_experiment_run.graphqls | 5 + .../graph/chaos_experiment_run.resolvers.go | 24 ++++ .../server/graph/generated/generated.go | 123 ++++++++++++++++++ .../graphql/server/pkg/authorization/roles.go | 59 ++++----- .../pkg/chaos_experiment/handler/handler.go | 63 +++++++++ .../pkg/chaos_experiment_run/service.go | 25 ++++ .../subscriber/pkg/events/chaosengine.go | 21 ++- chaoscenter/subscriber/pkg/events/workflow.go | 3 +- .../subscriber/pkg/requests/webhook.go | 2 +- chaoscenter/subscriber/pkg/utils/workflow.go | 15 +++ 10 files changed, 308 insertions(+), 32 deletions(-) diff --git a/chaoscenter/graphql/definitions/shared/chaos_experiment_run.graphqls b/chaoscenter/graphql/definitions/shared/chaos_experiment_run.graphqls index 44f387555f1..15ea5f9bd3e 100644 --- a/chaoscenter/graphql/definitions/shared/chaos_experiment_run.graphqls +++ b/chaoscenter/graphql/definitions/shared/chaos_experiment_run.graphqls @@ -32,4 +32,9 @@ extend type Mutation { experimentID: String! projectID: ID! ): RunChaosExperimentResponse! + + """ + stopExperiment will halt all the ongoing runs of a particular experiment + """ + stopExperimentRuns(projectID: ID!, experimentID:String!, experimentRunID: String, notifyID: String): Boolean! @authorized } \ No newline at end of file diff --git a/chaoscenter/graphql/server/graph/chaos_experiment_run.resolvers.go b/chaoscenter/graphql/server/graph/chaos_experiment_run.resolvers.go index 61b4140c5a9..8731d90e0c1 100644 --- a/chaoscenter/graphql/server/graph/chaos_experiment_run.resolvers.go +++ b/chaoscenter/graphql/server/graph/chaos_experiment_run.resolvers.go @@ -53,6 +53,30 @@ func (r *mutationResolver) RunChaosExperiment(ctx context.Context, experimentID return &model.RunChaosExperimentResponse{NotifyID: uiResponse.NotifyID}, err } +func (r *mutationResolver) StopExperimentRuns(ctx context.Context, projectID string, experimentID string, experimentRunID *string, notifyID *string) (bool, error) { + logFields := logrus.Fields{ + "projectId": projectID, + "chaosExperimentId": experimentID, + "chaosExperimentRunId": experimentRunID, + "notifyID": notifyID, + } + + logrus.WithFields(logFields).Info("request received to stop chaos experiment") + err := authorization.ValidateRole(ctx, projectID, + authorization.MutationRbacRules[authorization.StopChaosExperiment], + model.InvitationAccepted.String()) + if err != nil { + return false, err + } + + uiResponse, err := r.chaosExperimentHandler.StopExperimentRuns(ctx, projectID, experimentID, experimentRunID, data_store.Store) + if err != nil { + logrus.WithFields(logFields).Error(err) + return false, err + } + return uiResponse, nil +} + func (r *queryResolver) GetExperimentRun(ctx context.Context, projectID string, experimentRunID *string, notifyID *string) (*model.ExperimentRun, error) { logFields := logrus.Fields{ "projectId": projectID, diff --git a/chaoscenter/graphql/server/graph/generated/generated.go b/chaoscenter/graphql/server/graph/generated/generated.go index 2d20f2bdd98..28850be057c 100644 --- a/chaoscenter/graphql/server/graph/generated/generated.go +++ b/chaoscenter/graphql/server/graph/generated/generated.go @@ -501,6 +501,7 @@ type ComplexityRoot struct { RunChaosExperiment func(childComplexity int, experimentID string, projectID string) int SaveChaosExperiment func(childComplexity int, request model.SaveChaosExperimentRequest, projectID string) int SaveChaosHub func(childComplexity int, projectID string, request model.CreateChaosHubRequest) int + StopExperimentRuns func(childComplexity int, projectID string, experimentID string, experimentRunID *string, notifyID *string) int SyncChaosHub func(childComplexity int, id string, projectID string) int UpdateChaosExperiment func(childComplexity int, request *model.ChaosExperimentRequest, projectID string) int UpdateChaosHub func(childComplexity int, projectID string, request model.UpdateChaosHubRequest) int @@ -715,6 +716,7 @@ type MutationResolver interface { DeleteChaosExperiment(ctx context.Context, experimentID string, experimentRunID *string, projectID string) (bool, error) ChaosExperimentRun(ctx context.Context, request model.ExperimentRunRequest) (string, error) RunChaosExperiment(ctx context.Context, experimentID string, projectID string) (*model.RunChaosExperimentResponse, error) + StopExperimentRuns(ctx context.Context, projectID string, experimentID string, experimentRunID *string, notifyID *string) (bool, error) RegisterInfra(ctx context.Context, projectID string, request model.RegisterInfraRequest) (*model.RegisterInfraResponse, error) ConfirmInfraRegistration(ctx context.Context, request model.InfraIdentity) (*model.ConfirmInfraRegistrationResponse, error) DeleteInfra(ctx context.Context, projectID string, infraID string) (string, error) @@ -3143,6 +3145,18 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.Mutation.SaveChaosHub(childComplexity, args["projectID"].(string), args["request"].(model.CreateChaosHubRequest)), true + case "Mutation.stopExperimentRuns": + if e.complexity.Mutation.StopExperimentRuns == nil { + break + } + + args, err := ec.field_Mutation_stopExperimentRuns_args(context.TODO(), rawArgs) + if err != nil { + return 0, false + } + + return e.complexity.Mutation.StopExperimentRuns(childComplexity, args["projectID"].(string), args["experimentID"].(string), args["experimentRunID"].(*string), args["notifyID"].(*string)), true + case "Mutation.syncChaosHub": if e.complexity.Mutation.SyncChaosHub == nil { break @@ -5180,6 +5194,11 @@ extend type Mutation { experimentID: String! projectID: ID! ): RunChaosExperimentResponse! + + """ + stopExperiment will halt all the ongoing runs of a particular experiment + """ + stopExperimentRuns(projectID: ID!, experimentID:String!, experimentRunID: String, notifyID: String): Boolean! @authorized }`, BuiltIn: false}, &ast.Source{Name: "../definitions/shared/chaos_infrastructure.graphqls", Input: `directive @authorized on FIELD_DEFINITION @@ -8547,6 +8566,44 @@ func (ec *executionContext) field_Mutation_saveChaosHub_args(ctx context.Context return args, nil } +func (ec *executionContext) field_Mutation_stopExperimentRuns_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { + var err error + args := map[string]interface{}{} + var arg0 string + if tmp, ok := rawArgs["projectID"]; ok { + arg0, err = ec.unmarshalNID2string(ctx, tmp) + if err != nil { + return nil, err + } + } + args["projectID"] = arg0 + var arg1 string + if tmp, ok := rawArgs["experimentID"]; ok { + arg1, err = ec.unmarshalNString2string(ctx, tmp) + if err != nil { + return nil, err + } + } + args["experimentID"] = arg1 + var arg2 *string + if tmp, ok := rawArgs["experimentRunID"]; ok { + arg2, err = ec.unmarshalOString2ᚖstring(ctx, tmp) + if err != nil { + return nil, err + } + } + args["experimentRunID"] = arg2 + var arg3 *string + if tmp, ok := rawArgs["notifyID"]; ok { + arg3, err = ec.unmarshalOString2ᚖstring(ctx, tmp) + if err != nil { + return nil, err + } + } + args["notifyID"] = arg3 + return args, nil +} + func (ec *executionContext) field_Mutation_syncChaosHub_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { var err error args := map[string]interface{}{} @@ -19349,6 +19406,67 @@ func (ec *executionContext) _Mutation_runChaosExperiment(ctx context.Context, fi return ec.marshalNRunChaosExperimentResponse2ᚖgithubᚗcomᚋlitmuschaosᚋlitmusᚋchaoscenterᚋgraphqlᚋserverᚋgraphᚋmodelᚐRunChaosExperimentResponse(ctx, field.Selections, res) } +func (ec *executionContext) _Mutation_stopExperimentRuns(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "Mutation", + Field: field, + Args: nil, + IsMethod: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + rawArgs := field.ArgumentMap(ec.Variables) + args, err := ec.field_Mutation_stopExperimentRuns_args(ctx, rawArgs) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + fc.Args = args + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + directive0 := func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Mutation().StopExperimentRuns(rctx, args["projectID"].(string), args["experimentID"].(string), args["experimentRunID"].(*string), args["notifyID"].(*string)) + } + directive1 := func(ctx context.Context) (interface{}, error) { + if ec.directives.Authorized == nil { + return nil, errors.New("directive authorized is not implemented") + } + return ec.directives.Authorized(ctx, nil, directive0) + } + + tmp, err := directive1(rctx) + if err != nil { + return nil, err + } + if tmp == nil { + return nil, nil + } + if data, ok := tmp.(bool); ok { + return data, nil + } + return nil, fmt.Errorf(`unexpected type %T from directive, should be bool`, tmp) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(bool) + fc.Result = res + return ec.marshalNBoolean2bool(ctx, field.Selections, res) +} + func (ec *executionContext) _Mutation_registerInfra(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { defer func() { if r := recover(); r != nil { @@ -31761,6 +31879,11 @@ func (ec *executionContext) _Mutation(ctx context.Context, sel ast.SelectionSet) if out.Values[i] == graphql.Null { invalids++ } + case "stopExperimentRuns": + out.Values[i] = ec._Mutation_stopExperimentRuns(ctx, field) + if out.Values[i] == graphql.Null { + invalids++ + } case "registerInfra": out.Values[i] = ec._Mutation_registerInfra(ctx, field) if out.Values[i] == graphql.Null { diff --git a/chaoscenter/graphql/server/pkg/authorization/roles.go b/chaoscenter/graphql/server/pkg/authorization/roles.go index 4e06885e5cc..3cdceeaa78e 100644 --- a/chaoscenter/graphql/server/pkg/authorization/roles.go +++ b/chaoscenter/graphql/server/pkg/authorization/roles.go @@ -12,6 +12,7 @@ const ( CreateChaosWorkFlow RoleQuery = "CreateChaosWorkFlow" ReRunChaosWorkFlow RoleQuery = "ReRunChaosWorkFlow" DeleteChaosWorkflow RoleQuery = "DeleteChaosWorkflow" + StopChaosExperiment RoleQuery = "StopChaosExperiment" TerminateChaosWorkflow RoleQuery = "TerminateChaosWorkflow" SyncWorkflow RoleQuery = "SyncWorkflow" SendInvitation RoleQuery = "SendInvitation" @@ -84,35 +85,35 @@ const ( ) var MutationRbacRules = map[RoleQuery][]string{ - UserInfrastructureReg: {MemberRoleOwnerString, MemberRoleEditorString}, - CreateChaosWorkFlow: {MemberRoleOwnerString, MemberRoleEditorString}, - ReRunChaosWorkFlow: {MemberRoleOwnerString, MemberRoleEditorString}, - DeleteChaosWorkflow: {MemberRoleOwnerString, MemberRoleEditorString}, - TerminateChaosWorkflow: {MemberRoleOwnerString, MemberRoleEditorString}, - SyncWorkflow: {MemberRoleOwnerString, MemberRoleEditorString}, - SendInvitation: {MemberRoleOwnerString}, - AcceptInvitation: {MemberRoleViewerString, MemberRoleEditorString}, - DeclineInvitation: {MemberRoleViewerString, MemberRoleEditorString}, - RemoveInvitation: {MemberRoleOwnerString}, - LeaveProject: {MemberRoleViewerString, MemberRoleEditorString}, - UpdateProjectName: {MemberRoleOwnerString}, - AddChaosHub: {MemberRoleOwnerString, MemberRoleEditorString}, - SyncHub: {MemberRoleOwnerString, MemberRoleEditorString}, - UpdateChaosWorkflow: {MemberRoleOwnerString, MemberRoleEditorString}, - DeleteInfrastructures: {MemberRoleOwnerString, MemberRoleEditorString}, - UpdateChaosHub: {MemberRoleOwnerString, MemberRoleEditorString}, - DeleteChaosHub: {MemberRoleOwnerString, MemberRoleEditorString}, - EnableGitOps: {MemberRoleOwnerString}, - DisableGitOps: {MemberRoleOwnerString}, - UpdateGitOps: {MemberRoleOwnerString}, - CreateDataSource: {MemberRoleOwnerString, MemberRoleEditorString}, - CreateDashBoard: {MemberRoleOwnerString, MemberRoleEditorString}, - UpdateDataSource: {MemberRoleOwnerString, MemberRoleEditorString}, - UpdateDashboard: {MemberRoleOwnerString, MemberRoleEditorString}, - DeleteDashboard: {MemberRoleOwnerString, MemberRoleEditorString}, - DeleteDataSource: {MemberRoleOwnerString, MemberRoleEditorString}, - ListWorkflowRuns: {MemberRoleOwnerString, MemberRoleEditorString, MemberRoleViewerString}, - GetWorkflowRun: {MemberRoleOwnerString, MemberRoleEditorString, MemberRoleViewerString}, + UserInfrastructureReg: {MemberRoleOwnerString, MemberRoleEditorString}, + CreateChaosWorkFlow: {MemberRoleOwnerString, MemberRoleEditorString}, + ReRunChaosWorkFlow: {MemberRoleOwnerString, MemberRoleEditorString}, + DeleteChaosWorkflow: {MemberRoleOwnerString, MemberRoleEditorString}, + StopChaosExperiment: {MemberRoleOwnerString, MemberRoleEditorString}, + SyncWorkflow: {MemberRoleOwnerString, MemberRoleEditorString}, + SendInvitation: {MemberRoleOwnerString}, + AcceptInvitation: {MemberRoleViewerString, MemberRoleEditorString}, + DeclineInvitation: {MemberRoleViewerString, MemberRoleEditorString}, + RemoveInvitation: {MemberRoleOwnerString}, + LeaveProject: {MemberRoleViewerString, MemberRoleEditorString}, + UpdateProjectName: {MemberRoleOwnerString}, + AddChaosHub: {MemberRoleOwnerString, MemberRoleEditorString}, + SyncHub: {MemberRoleOwnerString, MemberRoleEditorString}, + UpdateChaosWorkflow: {MemberRoleOwnerString, MemberRoleEditorString}, + DeleteInfrastructures: {MemberRoleOwnerString, MemberRoleEditorString}, + UpdateChaosHub: {MemberRoleOwnerString, MemberRoleEditorString}, + DeleteChaosHub: {MemberRoleOwnerString, MemberRoleEditorString}, + EnableGitOps: {MemberRoleOwnerString}, + DisableGitOps: {MemberRoleOwnerString}, + UpdateGitOps: {MemberRoleOwnerString}, + CreateDataSource: {MemberRoleOwnerString, MemberRoleEditorString}, + CreateDashBoard: {MemberRoleOwnerString, MemberRoleEditorString}, + UpdateDataSource: {MemberRoleOwnerString, MemberRoleEditorString}, + UpdateDashboard: {MemberRoleOwnerString, MemberRoleEditorString}, + DeleteDashboard: {MemberRoleOwnerString, MemberRoleEditorString}, + DeleteDataSource: {MemberRoleOwnerString, MemberRoleEditorString}, + ListWorkflowRuns: {MemberRoleOwnerString, MemberRoleEditorString, MemberRoleViewerString}, + GetWorkflowRun: {MemberRoleOwnerString, MemberRoleEditorString, MemberRoleViewerString}, ListInfrastructures: {MemberRoleOwnerString, MemberRoleEditorString, MemberRoleViewerString}, GetInfrastructure: {MemberRoleOwnerString, MemberRoleEditorString, diff --git a/chaoscenter/graphql/server/pkg/chaos_experiment/handler/handler.go b/chaoscenter/graphql/server/pkg/chaos_experiment/handler/handler.go index f6e3b2c1f6f..35d9a8a0652 100644 --- a/chaoscenter/graphql/server/pkg/chaos_experiment/handler/handler.go +++ b/chaoscenter/graphql/server/pkg/chaos_experiment/handler/handler.go @@ -4,6 +4,7 @@ import ( "context" "encoding/json" "errors" + "fmt" "strconv" "time" @@ -1316,3 +1317,65 @@ func (c *ChaosExperimentHandler) validateDuplicateExperimentName(ctx context.Con return nil } + +func (c *ChaosExperimentHandler) StopExperimentRuns(ctx context.Context, projectID string, experimentID string, experimentRunID *string, r *store.StateData) (bool, error) { + + var experimentRunsID []string + + tkn := ctx.Value(authorization.AuthKey).(string) + username, err := authorization.GetUsername(tkn) + + query := bson.D{ + {"experiment_id", experimentID}, + {"project_id", projectID}, + {"is_removed", false}, + } + experiment, err := c.chaosExperimentOperator.GetExperiment(context.TODO(), query) + if err != nil { + return false, err + } + + // if experimentID is provided & no expRunID is present (stop all the corresponding experiment runs) + if experimentRunID == nil { + + // if experiment is of cron type, disable it + if experiment.CronSyntax != "" { + + err = c.DisableCronExperiment(username, experiment, projectID, r) + if err != nil { + return false, err + } + } + + // Fetching all the experiment runs in the experiment + expRuns, err := dbChaosExperimentRun.NewChaosExperimentRunOperator(c.mongodbOperator).GetExperimentRuns(bson.D{ + {"experiment_id", experimentID}, + {"is_removed", false}, + }) + if err != nil { + return false, err + } + + for _, runs := range expRuns { + if (runs.Phase == string(model.ExperimentRunStatusRunning) || runs.Phase == string(model.ExperimentRunStatusTimeout)) && !runs.Completed { + experimentRunsID = append(experimentRunsID, runs.ExperimentRunID) + } + } + + // Check if experiment run count is 0 and if it's not a cron experiment + if len(experimentRunsID) == 0 && experiment.CronSyntax == "" { + return false, fmt.Errorf("no running or timeout experiments found") + } + } else if experimentRunID != nil && *experimentRunID != "" { + experimentRunsID = []string{*experimentRunID} + } + + for _, runID := range experimentRunsID { + err = c.chaosExperimentRunService.ProcessExperimentRunStop(ctx, query, &runID, experiment, username, projectID, r) + if err != nil { + return false, err + } + } + + return true, nil +} diff --git a/chaoscenter/graphql/server/pkg/chaos_experiment_run/service.go b/chaoscenter/graphql/server/pkg/chaos_experiment_run/service.go index cd4a72b4ca3..1a7180ebee9 100644 --- a/chaoscenter/graphql/server/pkg/chaos_experiment_run/service.go +++ b/chaoscenter/graphql/server/pkg/chaos_experiment_run/service.go @@ -27,6 +27,7 @@ import ( type Service interface { ProcessExperimentRunDelete(ctx context.Context, query bson.D, workflowRunID *string, experimentRun dbChaosExperimentRun.ChaosExperimentRun, workflow dbChaosExperiment.ChaosExperimentRequest, username string, r *store.StateData) error ProcessCompletedExperimentRun(execData ExecutionData, wfID string, runID string) (ExperimentRunMetrics, error) + ProcessExperimentRunStop(ctx context.Context, query bson.D, experimentRunID *string, experiment dbChaosExperiment.ChaosExperimentRequest, username string, projectID string, r *store.StateData) error } // chaosWorkflowService is the implementation of the chaos workflow service @@ -70,6 +71,30 @@ func (c *chaosExperimentRunService) ProcessExperimentRunDelete(ctx context.Conte return nil } +// ProcessExperimentRunStop deletes a workflow entry and updates the database +func (c *chaosExperimentRunService) ProcessExperimentRunStop(ctx context.Context, query bson.D, experimentRunID *string, experiment dbChaosExperiment.ChaosExperimentRequest, username string, projectID string, r *store.StateData) error { + update := bson.D{ + {"$set", bson.D{ + {"updated_at", time.Now().UnixMilli()}, + {"updated_by", mongodb.UserDetailResponse{ + Username: username, + }}, + }}, + } + + err := c.chaosExperimentRunOperator.UpdateExperimentRunWithQuery(ctx, query, update) + if err != nil { + return err + } + if r != nil { + chaos_infrastructure.SendExperimentToSubscriber(projectID, &model.ChaosExperimentRequest{ + InfraID: experiment.InfraID, + }, &username, experimentRunID, "workflow_run_stop", r) + } + + return nil +} + // ProcessCompletedExperimentRun calculates the Resiliency Score and returns the updated ExecutionData func (c *chaosExperimentRunService) ProcessCompletedExperimentRun(execData ExecutionData, wfID string, runID string) (ExperimentRunMetrics, error) { weightSum, totalTestResult := 0, 0 diff --git a/chaoscenter/subscriber/pkg/events/chaosengine.go b/chaoscenter/subscriber/pkg/events/chaosengine.go index acf9b476769..e7983297aab 100644 --- a/chaoscenter/subscriber/pkg/events/chaosengine.go +++ b/chaoscenter/subscriber/pkg/events/chaosengine.go @@ -8,6 +8,8 @@ import ( "subscriber/pkg/k8s" "subscriber/pkg/types" + wfclientset "github.com/argoproj/argo-workflows/v3/pkg/client/clientset/versioned" + "github.com/argoproj/argo-workflows/v3/pkg/apis/workflow/v1alpha1" chaosTypes "github.com/litmuschaos/chaos-operator/api/litmuschaos/v1alpha1" "github.com/litmuschaos/chaos-operator/pkg/client/clientset/versioned" @@ -197,6 +199,23 @@ func StopChaosEngineState(namespace string, workflowRunID *string) error { return nil } +// StopWorkflow will patch the workflow based on workflow name using the shutdown strategy +func StopWorkflow(wfName string, namespace string) error { + + conf, err := k8s.GetKubeConfig() + wfClient := wfclientset.NewForConfigOrDie(conf).ArgoprojV1alpha1().Workflows(namespace) + patch := []byte(`{"spec":{"shutdown":"Stop"}}`) + wf, err := wfClient.Patch(context.TODO(), wfName, mergeType.MergePatchType, patch, v1.PatchOptions{}) + if err != nil { + return fmt.Errorf("error in patching workflow: %w", err) + } + if wf != nil { + logrus.Info("Successfully patched workflow: ", wf.GetName()) + return nil + } + return nil +} + func mapStatus(status chaosTypes.EngineStatus) string { switch status { case chaosTypes.EngineStatusInitialized: @@ -204,7 +223,7 @@ func mapStatus(status chaosTypes.EngineStatus) string { case chaosTypes.EngineStatusCompleted: return "Succeeded" case chaosTypes.EngineStatusStopped: - return "Skipped" + return "Stopped" default: return "Running" } diff --git a/chaoscenter/subscriber/pkg/events/workflow.go b/chaoscenter/subscriber/pkg/events/workflow.go index ce102d1d249..19efbc3f06e 100644 --- a/chaoscenter/subscriber/pkg/events/workflow.go +++ b/chaoscenter/subscriber/pkg/events/workflow.go @@ -162,7 +162,7 @@ func WorkflowEventHandler(workflowObj *v1alpha1.Workflow, eventType string, star status := updateWorkflowStatus(workflowObj.Status.Phase) finishedTime := StrConvTime(workflowObj.Status.FinishedAt.Unix()) - if eventType == "STOPPED" { + if workflowObj.Spec.Shutdown.Enabled() { status = "Stopped" finishedTime = StrConvTime(time.Now().Unix()) nodes[workflowObj.Name] = types.Node{ @@ -217,6 +217,7 @@ func SendWorkflowUpdates(infraData map[string]string, event types.WorkflowEvent) nodeData := event.Nodes[key] nodeData.Phase = "Stopped" event.Nodes[key] = nodeData + nodeData.FinishedAt = event.FinishedAt } } } diff --git a/chaoscenter/subscriber/pkg/requests/webhook.go b/chaoscenter/subscriber/pkg/requests/webhook.go index c4a8b79a2c2..e400f4e87bf 100644 --- a/chaoscenter/subscriber/pkg/requests/webhook.go +++ b/chaoscenter/subscriber/pkg/requests/webhook.go @@ -131,7 +131,7 @@ func RequestProcessor(infraData map[string]string, r types.RawData) error { if err != nil { return errors.New("error performing infra operation: " + err.Error()) } - } else if strings.Index("workflow_delete workflow_run_delete ", strings.ToLower(r.Payload.Data.InfraConnect.Action.RequestType)) >= 0 { + } else if strings.Index("workflow_delete workflow_run_delete workflow_run_stop ", strings.ToLower(r.Payload.Data.InfraConnect.Action.RequestType)) >= 0 { err := utils.WorkflowRequest(infraData, r.Payload.Data.InfraConnect.Action.RequestType, r.Payload.Data.InfraConnect.Action.ExternalData, r.Payload.Data.InfraConnect.Action.Username) if err != nil { diff --git a/chaoscenter/subscriber/pkg/utils/workflow.go b/chaoscenter/subscriber/pkg/utils/workflow.go index b397724e8ff..ec44e4e9965 100644 --- a/chaoscenter/subscriber/pkg/utils/workflow.go +++ b/chaoscenter/subscriber/pkg/utils/workflow.go @@ -40,6 +40,21 @@ func WorkflowRequest(agentData map[string]string, requestType string, externalDa } logrus.Info("events delete name: ", wfOb.Name, "namespace: ", wfOb.Namespace) + } else if requestType == "workflow_run_stop" { + wfOb, err := events.GetWorkflowObj(externalData) + if err != nil { + return err + } + err = events.StopChaosEngineState(agentData["INFRA_NAMESPACE"], &externalData) + if err != nil { + logrus.Info("failed to stop chaosEngine for : ", wfOb.Name, " namespace: ", wfOb.Namespace, " : ", err) + } + err = events.StopWorkflow(wfOb.Name, wfOb.Namespace) + if err != nil { + logrus.Info("failed to stop experiment: ", wfOb.Name, " namespace: ", wfOb.Namespace, " : ", err) + } + logrus.Info("events stop name: ", wfOb.Name, " namespace: ", wfOb.Namespace) + } return nil