Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added backend changes for stop experiment #4227

Merged
merged 7 commits into from
Oct 26, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ package graph
import (
"context"
"errors"

"github.com/litmuschaos/litmus/chaoscenter/graphql/server/graph/model"
"github.com/litmuschaos/litmus/chaoscenter/graphql/server/pkg/authorization"
data_store "github.com/litmuschaos/litmus/chaoscenter/graphql/server/pkg/data-store"
Expand Down Expand Up @@ -53,6 +52,24 @@ 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
}

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the call to the actual StopExperimentRuns is missing here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes it was in WIP, have added the implementation.

}

func (r *queryResolver) GetExperimentRun(ctx context.Context, projectID string, experimentRunID *string, notifyID *string) (*model.ExperimentRun, error) {
logFields := logrus.Fields{
"projectId": projectID,
Expand Down
123 changes: 123 additions & 0 deletions chaoscenter/graphql/server/graph/generated/generated.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

59 changes: 30 additions & 29 deletions chaoscenter/graphql/server/pkg/authorization/roles.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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,
Expand Down
61 changes: 61 additions & 0 deletions chaoscenter/graphql/server/pkg/chaos_experiment/handler/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"context"
"encoding/json"
"errors"
"fmt"
"strconv"
"time"

Expand Down Expand Up @@ -1316,3 +1317,63 @@ 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
}
}
Comment on lines +1342 to +1348
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can see the use case where users might want to temporarily suspend all ongoing runs but any future runs should still happen. We should give the user the option to explicitly disable the future runs imo instead of disabling by default.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@gdsoumya This case is handled in the backend, so if a user sends a both experimentID and experimentRunID, only the current run will be stopped. but if experimentRunID is nil, it will stop all the running experiment and disable the cron if present. However, in future we are planning to add one more API to just enable/disable the cron.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think then in the future when the cron specific endpoint is introduced the behavior of this endpoint should be changed so that it doesn't stop the cron imo

Copy link
Contributor Author

@Saranya-jena Saranya-jena Oct 25, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, will remove this one with the addition of cron API


// 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")
namkyu1999 marked this conversation as resolved.
Show resolved Hide resolved
}
} else if experimentRunID != nil && *experimentRunID != "" {
experimentRunsID = []string{*experimentRunID}
}

err = c.chaosExperimentRunService.ProcessExperimentRunStop(ctx, query, experimentRunID, experiment, username, projectID, r)
if err != nil {
return false, err
}

return true, nil
}
25 changes: 25 additions & 0 deletions chaoscenter/graphql/server/pkg/chaos_experiment_run/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
Loading