diff --git a/chaoscenter/graphql/server/graph/probe.resolvers.go b/chaoscenter/graphql/server/graph/probe.resolvers.go index f053f9d6ee3..8ce59a758b9 100644 --- a/chaoscenter/graphql/server/graph/probe.resolvers.go +++ b/chaoscenter/graphql/server/graph/probe.resolvers.go @@ -7,8 +7,6 @@ import ( "context" "errors" - "github.com/litmuschaos/litmus/chaoscenter/graphql/server/pkg/probe/handler" - "github.com/litmuschaos/litmus/chaoscenter/graphql/server/graph/model" "github.com/litmuschaos/litmus/chaoscenter/graphql/server/pkg/authorization" "github.com/sirupsen/logrus" @@ -53,8 +51,8 @@ func (r *mutationResolver) AddProbe(ctx context.Context, request model.ProbeRequ logrus.WithFields(logFields).Error(err) return nil, errors.New(err) } - p := handler.NewProbeRepository(projectID) - response, err := p.AddProbe(ctx, request) + + response, err := r.probeService.AddProbe(ctx, request, projectID) if err != nil { logrus.WithFields(logFields).Error(err) return nil, err @@ -78,8 +76,7 @@ func (r *mutationResolver) UpdateProbe(ctx context.Context, request model.ProbeR return "", err } - p := handler.NewProbeRepository(projectID) - response, err := p.UpdateProbe(ctx, request) + response, err := r.probeService.UpdateProbe(ctx, request, projectID) if err != nil { logrus.WithFields(logFields).Error(err) return "", err @@ -103,8 +100,7 @@ func (r *mutationResolver) DeleteProbe(ctx context.Context, probeName string, pr return false, err } - p := handler.NewProbeRepository(projectID) - response, err := p.DeleteProbe(ctx, probeName) + response, err := r.probeService.DeleteProbe(ctx, probeName, projectID) if err != nil { logrus.WithFields(logFields).Error(err) return false, err @@ -127,8 +123,7 @@ func (r *queryResolver) ListProbes(ctx context.Context, projectID string, infras return nil, err } - p := handler.NewProbeRepository(projectID) - response, err := p.ListProbes(ctx, probeNames, infrastructureType, filter) + response, err := r.probeService.ListProbes(ctx, probeNames, infrastructureType, filter, projectID) if err != nil { logrus.WithFields(logFields).Error(err) return nil, err @@ -152,8 +147,7 @@ func (r *queryResolver) GetProbe(ctx context.Context, projectID string, probeNam return nil, err } - p := handler.NewProbeRepository(projectID) - response, err := p.GetProbe(ctx, probeName) + response, err := r.probeService.GetProbe(ctx, probeName, projectID) if err != nil { logrus.WithFields(logFields).Error(err) return nil, err @@ -177,8 +171,7 @@ func (r *queryResolver) GetProbeYaml(ctx context.Context, projectID string, requ return "", err } - p := handler.NewProbeRepository(projectID) - response, err := p.GetProbeYAMLData(ctx, request) + response, err := r.probeService.GetProbeYAMLData(ctx, request, projectID) if err != nil { logrus.WithFields(logFields).Error(err) return "", err @@ -202,8 +195,7 @@ func (r *queryResolver) GetProbeReference(ctx context.Context, projectID string, return nil, err } - p := handler.NewProbeRepository(projectID) - response, err := p.GetProbeReference(ctx, probeName) + response, err := r.probeService.GetProbeReference(ctx, probeName, projectID) if err != nil { logrus.WithFields(logFields).Error(err) return nil, err @@ -251,8 +243,7 @@ func (r *queryResolver) ValidateUniqueProbe(ctx context.Context, projectID strin return false, err } - p := handler.NewProbeRepository(projectID) - response, err := p.ValidateUniqueProbe(ctx, probeName) + response, err := r.probeService.ValidateUniqueProbe(ctx, probeName, projectID) if err != nil { logrus.WithFields(logFields).Error(err) return false, err diff --git a/chaoscenter/graphql/server/graph/resolver.go b/chaoscenter/graphql/server/graph/resolver.go index 4dcaaa98619..79a835b7100 100644 --- a/chaoscenter/graphql/server/graph/resolver.go +++ b/chaoscenter/graphql/server/graph/resolver.go @@ -24,6 +24,7 @@ import ( envHandler "github.com/litmuschaos/litmus/chaoscenter/graphql/server/pkg/environment/handler" gitops3 "github.com/litmuschaos/litmus/chaoscenter/graphql/server/pkg/gitops" "github.com/litmuschaos/litmus/chaoscenter/graphql/server/pkg/image_registry" + probe "github.com/litmuschaos/litmus/chaoscenter/graphql/server/pkg/probe/handler" ) // This file will not be regenerated automatically. @@ -40,6 +41,7 @@ type Resolver struct { chaosExperimentHandler handler.ChaosExperimentHandler chaosExperimentRunHandler runHandler.ChaosExperimentRunHandler environmentService envHandler.EnvironmentHandler + probeService probe.Service } func NewConfig(mongodbOperator mongodb.MongoOperator) generated.Config { @@ -53,9 +55,10 @@ func NewConfig(mongodbOperator mongodb.MongoOperator) generated.Config { EnvironmentOperator := environments.NewEnvironmentOperator(mongodbOperator) //service + probeService := probe.NewProbeService() chaosHubService := chaoshub.NewService(chaosHubOperator) chaosInfrastructureService := chaos_infrastructure.NewChaosInfrastructureService(chaosInfraOperator, EnvironmentOperator) - chaosExperimentService := chaos_experiment2.NewChaosExperimentService(chaosExperimentOperator, chaosInfraOperator, chaosExperimentRunOperator) + chaosExperimentService := chaos_experiment2.NewChaosExperimentService(chaosExperimentOperator, chaosInfraOperator, chaosExperimentRunOperator, probeService) chaosExperimentRunService := chaos_experiment_run2.NewChaosExperimentRunService(chaosExperimentOperator, chaosInfraOperator, chaosExperimentRunOperator) gitOpsService := gitops3.NewGitOpsService(gitopsOperator, chaosExperimentService, *chaosExperimentOperator) imageRegistryService := image_registry.NewImageRegistryService(imageRegistryOperator) @@ -76,6 +79,7 @@ func NewConfig(mongodbOperator mongodb.MongoOperator) generated.Config { gitopsService: gitOpsService, chaosExperimentHandler: *chaosExperimentHandler, chaosExperimentRunHandler: *choasExperimentRunHandler, + probeService: probeService, }} config.Directives.Authorized = func(ctx context.Context, obj interface{}, next graphql.Resolver) (interface{}, error) { diff --git a/chaoscenter/graphql/server/pkg/chaos_experiment/handler/handler.go b/chaoscenter/graphql/server/pkg/chaos_experiment/handler/handler.go index 6db5e1027e6..0a955d7904d 100644 --- a/chaoscenter/graphql/server/pkg/chaos_experiment/handler/handler.go +++ b/chaoscenter/graphql/server/pkg/chaos_experiment/handler/handler.go @@ -102,12 +102,15 @@ func (c *ChaosExperimentHandler) SaveChaosExperiment(ctx context.Context, reques Tags: request.Tags, } - newRequest, wfType, err := c.chaosExperimentService.ProcessExperiment(&chaosWfReq, projectID, revID) + newRequest, wfType, err := c.chaosExperimentService.ProcessExperiment(ctx, &chaosWfReq, projectID, revID) if err != nil { return "", err } tkn := ctx.Value(authorization.AuthKey).(string) username, err := authorization.GetUsername(tkn) + if err != nil { + return "", err + } // Updating the existing experiment if wfDetails.ExperimentID == request.ID { logrus.WithFields(logFields).Info("request received to update k8s chaos experiment") @@ -152,7 +155,7 @@ func (c *ChaosExperimentHandler) CreateChaosExperiment(ctx context.Context, requ return nil, err } - newRequest, wfType, err := c.chaosExperimentService.ProcessExperiment(request, projectID, revID) + newRequest, wfType, err := c.chaosExperimentService.ProcessExperiment(ctx, request, projectID, revID) if err != nil { return nil, err } @@ -240,7 +243,7 @@ func (c *ChaosExperimentHandler) UpdateChaosExperiment(ctx context.Context, requ return nil, err } - newRequest, wfType, err := c.chaosExperimentService.ProcessExperiment(request, projectID, revID) + newRequest, wfType, err := c.chaosExperimentService.ProcessExperiment(ctx, request, projectID, revID) if err != nil { return nil, err } diff --git a/chaoscenter/graphql/server/pkg/chaos_experiment/handler/handler_test.go b/chaoscenter/graphql/server/pkg/chaos_experiment/handler/handler_test.go index 397eef9973b..7fe5c27a2e6 100644 --- a/chaoscenter/graphql/server/pkg/chaos_experiment/handler/handler_test.go +++ b/chaoscenter/graphql/server/pkg/chaos_experiment/handler/handler_test.go @@ -114,7 +114,7 @@ func TestChaosExperimentHandler_SaveChaosExperiment(t *testing.T) { singleResult := mongo.NewSingleResultFromDocument(findResult[0], nil, nil) mockServices.MongodbOperator.On("Get", mock.Anything, mongodb.ChaosExperimentCollection, mock.Anything).Return(singleResult, nil).Once() - mockServices.ChaosExperimentService.On("ProcessExperiment", request2, mock.Anything, mock.Anything).Return(request2, &experimentType, nil).Once() + mockServices.ChaosExperimentService.On("ProcessExperiment", mock.Anything, request2, mock.Anything, mock.Anything).Return(request2, &experimentType, nil).Once() mockServices.ChaosExperimentService.On("ProcessExperimentUpdate", request2, mock.Anything, mock.Anything, mock.Anything, false, mock.Anything, mock.Anything).Return(nil).Once() }, @@ -165,7 +165,7 @@ func TestChaosExperimentHandler_SaveChaosExperiment(t *testing.T) { singleResult := mongo.NewSingleResultFromDocument(findResult[0], nil, nil) mockServices.MongodbOperator.On("Get", mock.Anything, mongodb.ChaosExperimentCollection, mock.Anything).Return(singleResult, nil).Once() - mockServices.ChaosExperimentService.On("ProcessExperiment", request2, mock.Anything, mock.Anything).Return(request2, &experimentType, errors.New("Incorrect request format")).Once() + mockServices.ChaosExperimentService.On("ProcessExperiment", mock.Anything, request2, mock.Anything, mock.Anything).Return(request2, &experimentType, errors.New("Incorrect request format")).Once() }, wantErr: true, }, @@ -192,7 +192,7 @@ func TestChaosExperimentHandler_SaveChaosExperiment(t *testing.T) { singleResult := mongo.NewSingleResultFromDocument(findResult[0], nil, nil) mockServices.MongodbOperator.On("Get", mock.Anything, mongodb.ChaosExperimentCollection, mock.Anything).Return(singleResult, nil).Once() - mockServices.ChaosExperimentService.On("ProcessExperiment", request2, mock.Anything, mock.Anything).Return(request2, &experimentType, nil).Once() + mockServices.ChaosExperimentService.On("ProcessExperiment", mock.Anything, request2, mock.Anything, mock.Anything).Return(request2, &experimentType, nil).Once() mockServices.ChaosExperimentService.On("ProcessExperimentUpdate", request2, mock.Anything, mock.Anything, mock.Anything, false, mock.Anything, mock.Anything).Return(nil).Once() }, @@ -372,7 +372,7 @@ func TestChaosExperimentHandler_UpdateChaosExperiment(t *testing.T) { given: func(request *model.ChaosExperimentRequest, mockServices *MockServices) { ctx = context.WithValue(ctx, authorization.AuthKey, username) mockServices.MongodbOperator.On("CountDocuments", ctx, mongodb.ChaosExperimentCollection, mock.Anything, mock.Anything).Return(int64(0), nil).Once() - mockServices.ChaosExperimentService.On("ProcessExperiment", mock.Anything, mock.Anything, mock.Anything).Return(request, &experimentType, nil).Once() + mockServices.ChaosExperimentService.On("ProcessExperiment", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(request, &experimentType, nil).Once() mockServices.ChaosExperimentService.On("ProcessExperimentUpdate", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil).Once() }, wantErr: false, @@ -390,7 +390,7 @@ func TestChaosExperimentHandler_UpdateChaosExperiment(t *testing.T) { given: func(request *model.ChaosExperimentRequest, mockServices *MockServices) { ctx = context.WithValue(ctx, authorization.AuthKey, username) mockServices.MongodbOperator.On("CountDocuments", ctx, mongodb.ChaosExperimentCollection, mock.Anything, mock.Anything).Return(int64(0), nil).Once() - mockServices.ChaosExperimentService.On("ProcessExperiment", mock.Anything, mock.Anything, mock.Anything).Return(request, &experimentType, errors.New("Incorrect request format")).Once() + mockServices.ChaosExperimentService.On("ProcessExperiment", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(request, &experimentType, errors.New("Incorrect request format")).Once() }, wantErr: true, }, @@ -409,7 +409,7 @@ func TestChaosExperimentHandler_UpdateChaosExperiment(t *testing.T) { mockServices.MongodbOperator.On("CountDocuments", ctx, mongodb.ChaosExperimentCollection, mock.Anything, mock.Anything).Return(int64(0), nil).Once() - mockServices.ChaosExperimentService.On("ProcessExperiment", mock.Anything, mock.Anything, mock.Anything).Return(request, &experimentType, nil).Once() + mockServices.ChaosExperimentService.On("ProcessExperiment", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(request, &experimentType, nil).Once() mockServices.ChaosExperimentService.On("ProcessExperimentUpdate", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(errors.New("experiment update failed")).Once() }, diff --git a/chaoscenter/graphql/server/pkg/chaos_experiment/model/mocks/chaos_engine.yaml b/chaoscenter/graphql/server/pkg/chaos_experiment/model/mocks/chaos_engine.yaml index 78f67a13e3b..078d7c213b2 100644 --- a/chaoscenter/graphql/server/pkg/chaos_experiment/model/mocks/chaos_engine.yaml +++ b/chaoscenter/graphql/server/pkg/chaos_experiment/model/mocks/chaos_engine.yaml @@ -1,6 +1,8 @@ apiVersion: litmuschaos.io/v1alpha1 kind: ChaosEngine metadata: + annotations: + probeRef: '[{"name":"http-probe"}]' generateName: nginx-chaos name: nginx-chaos namespace: default diff --git a/chaoscenter/graphql/server/pkg/chaos_experiment/model/mocks/chaos_schedule.yaml b/chaoscenter/graphql/server/pkg/chaos_experiment/model/mocks/chaos_schedule.yaml index 1d089f30b0b..eb9e1586053 100644 --- a/chaoscenter/graphql/server/pkg/chaos_experiment/model/mocks/chaos_schedule.yaml +++ b/chaoscenter/graphql/server/pkg/chaos_experiment/model/mocks/chaos_schedule.yaml @@ -1,6 +1,8 @@ apiVersion: litmuschaos.io/v1alpha1 kind: ChaosSchedule metadata: + annotations: + probeRef: '[{"name":"http-probe"}]' name: schedule-nginx generateName: schedule-nginx spec: diff --git a/chaoscenter/graphql/server/pkg/chaos_experiment/model/mocks/cron_workflow.yaml b/chaoscenter/graphql/server/pkg/chaos_experiment/model/mocks/cron_workflow.yaml index d5797bb818c..6a67204bfa7 100644 --- a/chaoscenter/graphql/server/pkg/chaos_experiment/model/mocks/cron_workflow.yaml +++ b/chaoscenter/graphql/server/pkg/chaos_experiment/model/mocks/cron_workflow.yaml @@ -72,6 +72,8 @@ spec: kind: ChaosEngine metadata: + annotations: + probeRef: '[{"name":"http-probe"}]' namespace: "{{workflow.parameters.adminModeNamespace}}" labels: workflow_run_id: "{{workflow.uid}}" diff --git a/chaoscenter/graphql/server/pkg/chaos_experiment/model/mocks/service.go b/chaoscenter/graphql/server/pkg/chaos_experiment/model/mocks/service.go index 0f2991811b7..b5b051f39aa 100644 --- a/chaoscenter/graphql/server/pkg/chaos_experiment/model/mocks/service.go +++ b/chaoscenter/graphql/server/pkg/chaos_experiment/model/mocks/service.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.39.1. DO NOT EDIT. +// Code generated by mockery v2.40.1. DO NOT EDIT. package mocks @@ -31,9 +31,9 @@ func (_m *ChaosExperimentService) EXPECT() *ChaosExperimentService_Expecter { return &ChaosExperimentService_Expecter{mock: &_m.Mock} } -// ProcessExperiment provides a mock function with given fields: workflow, projectID, revID -func (_m *ChaosExperimentService) ProcessExperiment(workflow *model.ChaosExperimentRequest, projectID string, revID string) (*model.ChaosExperimentRequest, *chaos_experiment.ChaosExperimentType, error) { - ret := _m.Called(workflow, projectID, revID) +// ProcessExperiment provides a mock function with given fields: ctx, workflow, projectID, revID +func (_m *ChaosExperimentService) ProcessExperiment(ctx context.Context, workflow *model.ChaosExperimentRequest, projectID string, revID string) (*model.ChaosExperimentRequest, *chaos_experiment.ChaosExperimentType, error) { + ret := _m.Called(ctx, workflow, projectID, revID) if len(ret) == 0 { panic("no return value specified for ProcessExperiment") @@ -42,27 +42,27 @@ func (_m *ChaosExperimentService) ProcessExperiment(workflow *model.ChaosExperim var r0 *model.ChaosExperimentRequest var r1 *chaos_experiment.ChaosExperimentType var r2 error - if rf, ok := ret.Get(0).(func(*model.ChaosExperimentRequest, string, string) (*model.ChaosExperimentRequest, *chaos_experiment.ChaosExperimentType, error)); ok { - return rf(workflow, projectID, revID) + if rf, ok := ret.Get(0).(func(context.Context, *model.ChaosExperimentRequest, string, string) (*model.ChaosExperimentRequest, *chaos_experiment.ChaosExperimentType, error)); ok { + return rf(ctx, workflow, projectID, revID) } - if rf, ok := ret.Get(0).(func(*model.ChaosExperimentRequest, string, string) *model.ChaosExperimentRequest); ok { - r0 = rf(workflow, projectID, revID) + if rf, ok := ret.Get(0).(func(context.Context, *model.ChaosExperimentRequest, string, string) *model.ChaosExperimentRequest); ok { + r0 = rf(ctx, workflow, projectID, revID) } else { if ret.Get(0) != nil { r0 = ret.Get(0).(*model.ChaosExperimentRequest) } } - if rf, ok := ret.Get(1).(func(*model.ChaosExperimentRequest, string, string) *chaos_experiment.ChaosExperimentType); ok { - r1 = rf(workflow, projectID, revID) + if rf, ok := ret.Get(1).(func(context.Context, *model.ChaosExperimentRequest, string, string) *chaos_experiment.ChaosExperimentType); ok { + r1 = rf(ctx, workflow, projectID, revID) } else { if ret.Get(1) != nil { r1 = ret.Get(1).(*chaos_experiment.ChaosExperimentType) } } - if rf, ok := ret.Get(2).(func(*model.ChaosExperimentRequest, string, string) error); ok { - r2 = rf(workflow, projectID, revID) + if rf, ok := ret.Get(2).(func(context.Context, *model.ChaosExperimentRequest, string, string) error); ok { + r2 = rf(ctx, workflow, projectID, revID) } else { r2 = ret.Error(2) } @@ -76,16 +76,17 @@ type ChaosExperimentService_ProcessExperiment_Call struct { } // ProcessExperiment is a helper method to define mock.On call +// - ctx context.Context // - workflow *model.ChaosExperimentRequest // - projectID string // - revID string -func (_e *ChaosExperimentService_Expecter) ProcessExperiment(workflow interface{}, projectID interface{}, revID interface{}) *ChaosExperimentService_ProcessExperiment_Call { - return &ChaosExperimentService_ProcessExperiment_Call{Call: _e.mock.On("ProcessExperiment", workflow, projectID, revID)} +func (_e *ChaosExperimentService_Expecter) ProcessExperiment(ctx interface{}, workflow interface{}, projectID interface{}, revID interface{}) *ChaosExperimentService_ProcessExperiment_Call { + return &ChaosExperimentService_ProcessExperiment_Call{Call: _e.mock.On("ProcessExperiment", ctx, workflow, projectID, revID)} } -func (_c *ChaosExperimentService_ProcessExperiment_Call) Run(run func(workflow *model.ChaosExperimentRequest, projectID string, revID string)) *ChaosExperimentService_ProcessExperiment_Call { +func (_c *ChaosExperimentService_ProcessExperiment_Call) Run(run func(ctx context.Context, workflow *model.ChaosExperimentRequest, projectID string, revID string)) *ChaosExperimentService_ProcessExperiment_Call { _c.Call.Run(func(args mock.Arguments) { - run(args[0].(*model.ChaosExperimentRequest), args[1].(string), args[2].(string)) + run(args[0].(context.Context), args[1].(*model.ChaosExperimentRequest), args[2].(string), args[3].(string)) }) return _c } @@ -95,7 +96,7 @@ func (_c *ChaosExperimentService_ProcessExperiment_Call) Return(_a0 *model.Chaos return _c } -func (_c *ChaosExperimentService_ProcessExperiment_Call) RunAndReturn(run func(*model.ChaosExperimentRequest, string, string) (*model.ChaosExperimentRequest, *chaos_experiment.ChaosExperimentType, error)) *ChaosExperimentService_ProcessExperiment_Call { +func (_c *ChaosExperimentService_ProcessExperiment_Call) RunAndReturn(run func(context.Context, *model.ChaosExperimentRequest, string, string) (*model.ChaosExperimentRequest, *chaos_experiment.ChaosExperimentType, error)) *ChaosExperimentService_ProcessExperiment_Call { _c.Call.Return(run) return _c } diff --git a/chaoscenter/graphql/server/pkg/chaos_experiment/model/mocks/workflow.yaml b/chaoscenter/graphql/server/pkg/chaos_experiment/model/mocks/workflow.yaml index 994bc5891ba..684a51e08ac 100644 --- a/chaoscenter/graphql/server/pkg/chaos_experiment/model/mocks/workflow.yaml +++ b/chaoscenter/graphql/server/pkg/chaos_experiment/model/mocks/workflow.yaml @@ -71,6 +71,8 @@ spec: kind: ChaosEngine metadata: + annotations: + probeRef: '[{"name":"http-probe"}]' namespace: "{{workflow.parameters.adminModeNamespace}}" labels: workflow_run_id: "{{workflow.uid}}" diff --git a/chaoscenter/graphql/server/pkg/chaos_experiment/ops/service.go b/chaoscenter/graphql/server/pkg/chaos_experiment/ops/service.go index 0dac05fb2d9..229cbef3d21 100644 --- a/chaoscenter/graphql/server/pkg/chaos_experiment/ops/service.go +++ b/chaoscenter/graphql/server/pkg/chaos_experiment/ops/service.go @@ -8,6 +8,7 @@ import ( "strings" "time" + probeUtils "github.com/litmuschaos/litmus/chaoscenter/graphql/server/pkg/probe/utils" "github.com/litmuschaos/litmus/chaoscenter/graphql/server/utils" "github.com/litmuschaos/litmus/chaoscenter/graphql/server/pkg/chaos_infrastructure" @@ -30,13 +31,14 @@ import ( "github.com/google/uuid" chaosTypes "github.com/litmuschaos/chaos-operator/api/litmuschaos/v1alpha1" scheduleTypes "github.com/litmuschaos/chaos-scheduler/api/litmuschaos/v1alpha1" + probe "github.com/litmuschaos/litmus/chaoscenter/graphql/server/pkg/probe/handler" "go.mongodb.org/mongo-driver/bson" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" ) type Service interface { - ProcessExperiment(workflow *model.ChaosExperimentRequest, projectID string, revID string) (*model.ChaosExperimentRequest, *dbChaosExperiment.ChaosExperimentType, error) + ProcessExperiment(ctx context.Context, workflow *model.ChaosExperimentRequest, projectID string, revID string) (*model.ChaosExperimentRequest, *dbChaosExperiment.ChaosExperimentType, error) ProcessExperimentCreation(ctx context.Context, input *model.ChaosExperimentRequest, username string, projectID string, wfType *dbChaosExperiment.ChaosExperimentType, revisionID string, r *store.StateData) error ProcessExperimentUpdate(workflow *model.ChaosExperimentRequest, username string, wfType *dbChaosExperiment.ChaosExperimentType, revisionID string, updateRevision bool, projectID string, r *store.StateData) error ProcessExperimentDelete(query bson.D, workflow dbChaosExperiment.ChaosExperimentRequest, username string, r *store.StateData) error @@ -48,19 +50,21 @@ type chaosExperimentService struct { chaosExperimentOperator *dbChaosExperiment.Operator chaosInfrastructureOperator *dbChaosInfra.Operator chaosExperimentRunOperator *dbChaosExperimentRun.Operator + probeService probe.Service } // NewChaosExperimentService returns a new instance of the chaos workflow service -func NewChaosExperimentService(chaosWorkflowOperator *dbChaosExperiment.Operator, clusterOperator *dbChaosInfra.Operator, chaosExperimentRunOperator *dbChaosExperimentRun.Operator) Service { +func NewChaosExperimentService(chaosWorkflowOperator *dbChaosExperiment.Operator, clusterOperator *dbChaosInfra.Operator, chaosExperimentRunOperator *dbChaosExperimentRun.Operator, probeService probe.Service) Service { return &chaosExperimentService{ chaosExperimentOperator: chaosWorkflowOperator, chaosInfrastructureOperator: clusterOperator, chaosExperimentRunOperator: chaosExperimentRunOperator, + probeService: probeService, } } // ProcessExperiment takes the workflow and processes it as required -func (c *chaosExperimentService) ProcessExperiment(workflow *model.ChaosExperimentRequest, projectID string, revID string) (*model.ChaosExperimentRequest, *dbChaosExperiment.ChaosExperimentType, error) { +func (c *chaosExperimentService) ProcessExperiment(ctx context.Context, workflow *model.ChaosExperimentRequest, projectID string, revID string) (*model.ChaosExperimentRequest, *dbChaosExperiment.ChaosExperimentType, error) { // security check for chaos_infra access infra, err := c.chaosInfrastructureOperator.GetInfra(workflow.InfraID) if err != nil { @@ -105,7 +109,7 @@ func (c *chaosExperimentService) ProcessExperiment(workflow *model.ChaosExperime switch strings.ToLower(objMeta.GetKind()) { case "workflow": { - err = processExperimentManifest(workflow, weights, revID) + err = c.processExperimentManifest(ctx, workflow, weights, revID, projectID) if err != nil { return nil, nil, err } @@ -113,7 +117,7 @@ func (c *chaosExperimentService) ProcessExperiment(workflow *model.ChaosExperime case "cronworkflow": { wfType = dbChaosExperiment.CronExperiment - err = processCronExperimentManifest(workflow, weights, revID) + err = c.processCronExperimentManifest(ctx, workflow, weights, revID, projectID) if err != nil { return nil, nil, err } @@ -121,7 +125,7 @@ func (c *chaosExperimentService) ProcessExperiment(workflow *model.ChaosExperime case "chaosengine": { wfType = dbChaosExperiment.ChaosEngine - err = processChaosEngineManifest(workflow, weights, revID) + err = c.processChaosEngineManifest(ctx, workflow, weights, revID, projectID) if err != nil { return nil, nil, err } @@ -130,7 +134,7 @@ func (c *chaosExperimentService) ProcessExperiment(workflow *model.ChaosExperime case "chaosschedule": { wfType = dbChaosExperiment.ChaosEngine - err = processChaosScheduleManifest(workflow, weights, revID) + err = c.processChaosScheduleManifest(ctx, workflow, weights, revID, projectID) if err != nil { return nil, nil, err } @@ -259,7 +263,8 @@ func (c *chaosExperimentService) ProcessExperimentUpdate(workflow *model.ChaosEx query = bson.D{ {"experiment_id", workflow.ExperimentID}, {"project_id", projectID}, - {"revision.revision_id", revisionID}} + {"revision.revision_id", revisionID}, + } update = bson.D{ {"$set", bson.D{ {"updated_at", time.Now().UnixMilli()}, @@ -349,7 +354,8 @@ func (c *chaosExperimentService) ProcessExperimentDelete(query bson.D, workflow return nil } -func processExperimentManifest(workflow *model.ChaosExperimentRequest, weights map[string]int, revID string) error { + +func (c *chaosExperimentService) processExperimentManifest(ctx context.Context, workflow *model.ChaosExperimentRequest, weights map[string]int, revID, projectID string) error { var ( newWeights []*model.WeightagesInput workflowManifest v1alpha1.Workflow @@ -404,6 +410,42 @@ func processExperimentManifest(workflow *model.ChaosExperimentRequest, weights m return errors.New("no experiments specified in chaosengine - " + meta.Name) } + // Check if probeRef annotation is present in chaosengine, if not then create new probes + if _, ok := meta.GetObjectMeta().GetAnnotations()["probeRef"]; !ok { + // Check if probes are specified in chaosengine + if meta.Spec.Experiments[0].Spec.Probe != nil { + type probeRef struct { + Name string `json:"name"` + Mode string `json:"mode"` + } + probeRefs := []probeRef{} + for _, p := range meta.Spec.Experiments[0].Spec.Probe { + // Generate new probes for the experiment + probe, err := probeUtils.ProbeInputsToProbeRequestConverter(p) + if err != nil { + return err + } + result, err := c.probeService.AddProbe(ctx, probe, projectID) + if err != nil { + return err + } + // If probes are created then update the probeRef annotation in chaosengine + probeRefs = append(probeRefs, probeRef{ + Name: result.Name, + Mode: p.Mode, + }) + } + probeRefBytes, _ := json.Marshal(probeRefs) + rawYaml, err := probeUtils.InsertProbeRefAnnotation(artifact[0].Raw.Data, string(probeRefBytes)) + if err != nil { + return err + } + artifact[0].Raw.Data = rawYaml + } else { + return errors.New("no probes specified in chaosengine - " + meta.Name) + } + } + if val, ok := weights[exprname]; ok { workflowManifest.Spec.Templates[i].Metadata.Labels = map[string]string{ "weight": strconv.Itoa(val), @@ -442,7 +484,7 @@ func processExperimentManifest(workflow *model.ChaosExperimentRequest, weights m return nil } -func processCronExperimentManifest(workflow *model.ChaosExperimentRequest, weights map[string]int, revID string) error { +func (c *chaosExperimentService) processCronExperimentManifest(ctx context.Context, workflow *model.ChaosExperimentRequest, weights map[string]int, revID, projectID string) error { var ( newWeights []*model.WeightagesInput cronExperimentManifest v1alpha1.CronWorkflow @@ -526,6 +568,41 @@ func processCronExperimentManifest(workflow *model.ChaosExperimentRequest, weigh } else { return errors.New("no experiments specified in chaosengine - " + meta.Name) } + // Check if probeRef annotation is present in chaosengine, if not then create new probes + if _, ok := meta.GetObjectMeta().GetAnnotations()["probeRef"]; !ok { + // Check if probes are specified in chaosengine + if meta.Spec.Experiments[0].Spec.Probe != nil { + type probeRef struct { + Name string `json:"name"` + Mode string `json:"mode"` + } + probeRefs := []probeRef{} + for _, p := range meta.Spec.Experiments[0].Spec.Probe { + // Generate new probes for the experiment + probe, err := probeUtils.ProbeInputsToProbeRequestConverter(p) + if err != nil { + return err + } + result, err := c.probeService.AddProbe(ctx, probe, projectID) + if err != nil { + return err + } + // If probes are created then update the probeRef annotation in chaosengine + probeRefs = append(probeRefs, probeRef{ + Name: result.Name, + Mode: p.Mode, + }) + } + probeRefBytes, _ := json.Marshal(probeRefs) + rawYaml, err := probeUtils.InsertProbeRefAnnotation(artifact[0].Raw.Data, string(probeRefBytes)) + if err != nil { + return err + } + artifact[0].Raw.Data = rawYaml + } else { + return errors.New("no probes specified in chaosengine - " + meta.Name) + } + } if val, ok := weights[exprname]; ok { cronExperimentManifest.Spec.WorkflowSpec.Templates[i].Metadata.Labels = map[string]string{ "weight": strconv.Itoa(val), @@ -564,7 +641,7 @@ func processCronExperimentManifest(workflow *model.ChaosExperimentRequest, weigh return nil } -func processChaosEngineManifest(workflow *model.ChaosExperimentRequest, weights map[string]int, revID string) error { +func (c *chaosExperimentService) processChaosEngineManifest(ctx context.Context, workflow *model.ChaosExperimentRequest, weights map[string]int, revID, projectID string) error { var ( newWeights []*model.WeightagesInput workflowManifest chaosTypes.ChaosEngine @@ -596,6 +673,41 @@ func processChaosEngineManifest(workflow *model.ChaosExperimentRequest, weights if len(exprName) == 0 { return errors.New("empty chaos experiment name") } + // Check if probeRef annotation is present in chaosengine, if not then create new probes + if _, ok := workflowManifest.GetObjectMeta().GetAnnotations()["probeRef"]; !ok { + // Check if probes are specified in chaosengine + if workflowManifest.Spec.Experiments[0].Spec.Probe != nil { + type probeRef struct { + Name string `json:"name"` + Mode string `json:"mode"` + } + probeRefs := []probeRef{} + for _, p := range workflowManifest.Spec.Experiments[0].Spec.Probe { + // Generate new probes for the experiment + probe, err := probeUtils.ProbeInputsToProbeRequestConverter(p) + if err != nil { + return err + } + result, err := c.probeService.AddProbe(ctx, probe, projectID) + if err != nil { + return err + } + // If probes are created then update the probeRef annotation in chaosengine + probeRefs = append(probeRefs, probeRef{ + Name: result.Name, + Mode: p.Mode, + }) + } + probeRefBytes, _ := json.Marshal(probeRefs) + if workflowManifest.GetObjectMeta().GetAnnotations() == nil { + workflowManifest.GetObjectMeta().SetAnnotations(map[string]string{}) + } + workflowManifest.GetObjectMeta().GetAnnotations()["probeRef"] = string(probeRefBytes) + } else { + return errors.New("no probes specified in chaosengine - " + workflowManifest.Name) + } + } + if val, ok := weights[exprName]; ok { workflowManifest.Labels["weight"] = strconv.Itoa(val) } else if val, ok := workflowManifest.Labels["weight"]; ok { @@ -624,7 +736,7 @@ func processChaosEngineManifest(workflow *model.ChaosExperimentRequest, weights return nil } -func processChaosScheduleManifest(workflow *model.ChaosExperimentRequest, weights map[string]int, revID string) error { +func (c *chaosExperimentService) processChaosScheduleManifest(ctx context.Context, workflow *model.ChaosExperimentRequest, weights map[string]int, revID, projectID string) error { var ( newWeights []*model.WeightagesInput workflowManifest scheduleTypes.ChaosSchedule @@ -655,6 +767,40 @@ func processChaosScheduleManifest(workflow *model.ChaosExperimentRequest, weight if len(exprName) == 0 { return errors.New("empty chaos experiment name") } + // Check if probeRef annotation is present in chaosengine, if not then create new probes + if _, ok := workflowManifest.GetObjectMeta().GetAnnotations()["probeRef"]; !ok { + // Check if probes are specified in chaosengine + if workflowManifest.Spec.EngineTemplateSpec.Experiments[0].Spec.Probe != nil { + type probeRef struct { + Name string `json:"name"` + Mode string `json:"mode"` + } + probeRefs := []probeRef{} + for _, p := range workflowManifest.Spec.EngineTemplateSpec.Experiments[0].Spec.Probe { + // Generate new probes for the experiment + probe, err := probeUtils.ProbeInputsToProbeRequestConverter(p) + if err != nil { + return err + } + result, err := c.probeService.AddProbe(ctx, probe, projectID) + if err != nil { + return err + } + // If probes are created then update the probeRef annotation in chaosengine + probeRefs = append(probeRefs, probeRef{ + Name: result.Name, + Mode: p.Mode, + }) + } + probeRefBytes, _ := json.Marshal(probeRefs) + if workflowManifest.GetObjectMeta().GetAnnotations() == nil { + workflowManifest.GetObjectMeta().SetAnnotations(map[string]string{}) + } + workflowManifest.GetObjectMeta().GetAnnotations()["probeRef"] = string(probeRefBytes) + } else { + return errors.New("no probes specified in chaosengine - " + workflowManifest.Name) + } + } if val, ok := weights[exprName]; ok { workflowManifest.Labels["weight"] = strconv.Itoa(val) @@ -722,8 +868,8 @@ func (c *chaosExperimentService) UpdateRuntimeCronWorkflowConfiguration(cronWork } } probes = append(probes, dbChaosExperimentRun.Probes{ - artifact[0].Name, - annotationArray, + FaultName: artifact[0].Name, + ProbeNames: annotationArray, }) meta.Annotations = annotation diff --git a/chaoscenter/graphql/server/pkg/chaos_experiment/ops/service_test.go b/chaoscenter/graphql/server/pkg/chaos_experiment/ops/service_test.go index 4e515011426..65f2a6bfce0 100644 --- a/chaoscenter/graphql/server/pkg/chaos_experiment/ops/service_test.go +++ b/chaoscenter/graphql/server/pkg/chaos_experiment/ops/service_test.go @@ -19,6 +19,7 @@ import ( dbChaosExperimentRun "github.com/litmuschaos/litmus/chaoscenter/graphql/server/pkg/database/mongodb/chaos_experiment_run" dbChaosInfra "github.com/litmuschaos/litmus/chaoscenter/graphql/server/pkg/database/mongodb/chaos_infrastructure" dbMocks "github.com/litmuschaos/litmus/chaoscenter/graphql/server/pkg/database/mongodb/mocks" + probe "github.com/litmuschaos/litmus/chaoscenter/graphql/server/pkg/probe/handler" "github.com/stretchr/testify/mock" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/mongo" @@ -30,9 +31,10 @@ var ( infraOperator = dbChaosInfra.NewInfrastructureOperator(mongodbMockOperator) chaosExperimentOperator = dbChaosExperiment.NewChaosExperimentOperator(mongodbMockOperator) chaosExperimentRunOperator = dbChaosExperimentRun.NewChaosExperimentRunOperator(mongodbMockOperator) + probeService = probe.NewProbeService() ) -var chaosExperimentRunTestService = NewChaosExperimentService(chaosExperimentOperator, infraOperator, chaosExperimentRunOperator) +var chaosExperimentRunTestService = NewChaosExperimentService(chaosExperimentOperator, infraOperator, chaosExperimentRunOperator, probeService) func TestMain(m *testing.M) { gin.SetMode(gin.TestMode) @@ -57,6 +59,7 @@ func TestNewChaosExperimentService(t *testing.T) { chaosWorkflowOperator *dbChaosExperiment.Operator clusterOperator *dbChaosInfra.Operator chaosExperimentRunOperator *dbChaosExperimentRun.Operator + probeService probe.Service } tests := []struct { name string @@ -69,17 +72,19 @@ func TestNewChaosExperimentService(t *testing.T) { chaosWorkflowOperator: chaosExperimentOperator, clusterOperator: infraOperator, chaosExperimentRunOperator: chaosExperimentRunOperator, + probeService: probeService, }, want: &chaosExperimentService{ chaosExperimentOperator: chaosExperimentOperator, chaosInfrastructureOperator: infraOperator, chaosExperimentRunOperator: chaosExperimentRunOperator, + probeService: probeService, }, }, } for _, tc := range tests { t.Run(tc.name, func(t *testing.T) { - if got := NewChaosExperimentService(tc.args.chaosWorkflowOperator, tc.args.clusterOperator, tc.args.chaosExperimentRunOperator); !reflect.DeepEqual(got, tc.want) { + if got := NewChaosExperimentService(tc.args.chaosWorkflowOperator, tc.args.clusterOperator, tc.args.chaosExperimentRunOperator, tc.args.probeService); !reflect.DeepEqual(got, tc.want) { t.Errorf("NewChaosExperimentService() = %v, want %v", got, tc.want) } }) @@ -334,7 +339,7 @@ func Test_chaosExperimentService_ProcessExperiment(t *testing.T) { for _, tc := range tests { t.Run(tc.name, func(t *testing.T) { tc.given(tc.experiment) - _, _, err := chaosExperimentRunTestService.ProcessExperiment(tc.experiment, projectID, revID) + _, _, err := chaosExperimentRunTestService.ProcessExperiment(context.Background(), tc.experiment, projectID, revID) if (err != nil) != tc.wantErr { t.Errorf("chaosExperimentService.ProcessExperiment() error = %v, wantErr %v", err, tc.wantErr) return diff --git a/chaoscenter/graphql/server/pkg/chaos_experiment_run/model/mocks/service.go b/chaoscenter/graphql/server/pkg/chaos_experiment_run/model/mocks/service.go index 339e9bfa49f..b0293d32c0c 100644 --- a/chaoscenter/graphql/server/pkg/chaos_experiment_run/model/mocks/service.go +++ b/chaoscenter/graphql/server/pkg/chaos_experiment_run/model/mocks/service.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.39.1. DO NOT EDIT. +// Code generated by mockery v2.40.1. DO NOT EDIT. package mocks diff --git a/chaoscenter/graphql/server/pkg/gitops/service.go b/chaoscenter/graphql/server/pkg/gitops/service.go index ccad77d084e..9fbb662fecd 100644 --- a/chaoscenter/graphql/server/pkg/gitops/service.go +++ b/chaoscenter/graphql/server/pkg/gitops/service.go @@ -487,7 +487,7 @@ func (g *gitOpsService) SyncDBToGit(ctx context.Context, config GitConfig) error logrus.Info("WFID in changed File :", wfID) if wfID == "" { logrus.Info("New Experiment pushed to git : " + file) - flag, err := g.createExperiment(string(data), file, config) + flag, err := g.createExperiment(ctx, string(data), file, config) if err != nil { logrus.Error("Error while creating new experiment db entry : " + file + " | " + err.Error()) continue @@ -496,7 +496,7 @@ func (g *gitOpsService) SyncDBToGit(ctx context.Context, config GitConfig) error newExperiments = true } } else { - err = g.updateExperiment(string(data), wfID, file, config) + err = g.updateExperiment(ctx, string(data), wfID, file, config) if err != nil { logrus.Error("Error while updating experiment db entry : " + file + " | " + err.Error()) continue @@ -534,7 +534,7 @@ func (g *gitOpsService) SyncDBToGit(ctx context.Context, config GitConfig) error } // createExperiment helps in creating a new experiment during the SyncDBToGit operation -func (g *gitOpsService) createExperiment(data, file string, config GitConfig) (bool, error) { +func (g *gitOpsService) createExperiment(ctx context.Context, data, file string, config GitConfig) (bool, error) { _, fileName := filepath.Split(file) fileName = strings.Replace(fileName, ".yaml", "", -1) wfName := gjson.Get(data, "metadata.name").String() @@ -557,7 +557,7 @@ func (g *gitOpsService) createExperiment(data, file string, config GitConfig) (b InfraID: infraID, } revID := "" - input, wfType, err := g.chaosExperimentService.ProcessExperiment(&experiment, config.ProjectID, revID) + input, wfType, err := g.chaosExperimentService.ProcessExperiment(ctx, &experiment, config.ProjectID, revID) if err != nil { return false, err } @@ -582,7 +582,7 @@ func (g *gitOpsService) createExperiment(data, file string, config GitConfig) (b } // updateExperiment helps in updating an existing experiment during the SyncDBToGit operation -func (g *gitOpsService) updateExperiment(data, wfID, file string, config GitConfig) error { +func (g *gitOpsService) updateExperiment(ctx context.Context, data, wfID, file string, config GitConfig) error { _, fileName := filepath.Split(file) fileName = strings.Replace(fileName, ".yaml", "", -1) wfName := gjson.Get(data, "metadata.name").String() @@ -620,7 +620,7 @@ func (g *gitOpsService) updateExperiment(data, wfID, file string, config GitConf revID := "" updateRevision := false - input, wfType, err := g.chaosExperimentService.ProcessExperiment(&experimentData, config.ProjectID, revID) + input, wfType, err := g.chaosExperimentService.ProcessExperiment(ctx, &experimentData, config.ProjectID, revID) if err != nil { return err } diff --git a/chaoscenter/graphql/server/pkg/probe/handler/handler.go b/chaoscenter/graphql/server/pkg/probe/handler/handler.go index 4413ae90a65..680a1053e40 100644 --- a/chaoscenter/graphql/server/pkg/probe/handler/handler.go +++ b/chaoscenter/graphql/server/pkg/probe/handler/handler.go @@ -25,26 +25,21 @@ import ( "go.mongodb.org/mongo-driver/mongo" ) -type ProbeInterface interface { - AddProbe(ctx context.Context, probe model.ProbeRequest) (*model.Probe, error) - UpdateProbe(ctx context.Context, probe model.ProbeRequest) (string, error) - ListProbes(ctx context.Context, probeNames []string, infrastructureType *model.InfrastructureType, filter *model.ProbeFilterInput) ([]*model.Probe, error) - DeleteProbe(ctx context.Context, probeName string) (bool, error) - GetProbe(ctx context.Context, probeName string) (*model.Probe, error) - GetProbeReference(ctx context.Context, probeName string) (*model.GetProbeReferenceResponse, error) - GetProbeYAMLData(ctx context.Context, probe model.GetProbeYAMLRequest) (string, error) - ValidateUniqueProbe(ctx context.Context, probeName string) (bool, error) +type Service interface { + AddProbe(ctx context.Context, probe model.ProbeRequest, projectID string) (*model.Probe, error) + UpdateProbe(ctx context.Context, probe model.ProbeRequest, projectID string) (string, error) + ListProbes(ctx context.Context, probeNames []string, infrastructureType *model.InfrastructureType, filter *model.ProbeFilterInput, projectID string) ([]*model.Probe, error) + DeleteProbe(ctx context.Context, probeName, projectID string) (bool, error) + GetProbe(ctx context.Context, probeName, projectID string) (*model.Probe, error) + GetProbeReference(ctx context.Context, probeName, projectID string) (*model.GetProbeReferenceResponse, error) + GetProbeYAMLData(ctx context.Context, probe model.GetProbeYAMLRequest, projectID string) (string, error) + ValidateUniqueProbe(ctx context.Context, probeName, projectID string) (bool, error) } -type probe struct { - ProjectID string -} - -func NewProbeRepository(projectID string) ProbeInterface { - return &probe{ +type probe struct{} - ProjectID: projectID, - } +func NewProbeService() Service { + return &probe{} } func Error(logFields logrus.Fields, message string) error { @@ -53,18 +48,24 @@ func Error(logFields logrus.Fields, message string) error { } // AddProbe - Create a new Probe -func (p *probe) AddProbe(ctx context.Context, probe model.ProbeRequest) (*model.Probe, error) { +func (p *probe) AddProbe(ctx context.Context, probe model.ProbeRequest, projectID string) (*model.Probe, error) { // TODO: Add check if probe exists var ( currTime = time.Now().UnixMilli() ) - tkn := ctx.Value(authorization.AuthKey).(string) + tkn, ok := ctx.Value(authorization.AuthKey).(string) + if !ok { + return nil, errors.New("JWT token not found") + } + username, err := authorization.GetUsername(tkn) + if err != nil { + return nil, err + } logFields := logrus.Fields{ - - "projectId": p.ProjectID, + "projectId": projectID, "probeName": probe.Name, } @@ -77,7 +78,7 @@ func (p *probe) AddProbe(ctx context.Context, probe model.ProbeRequest) (*model. Name: probe.Name, Tags: probe.Tags, }, - ProjectID: p.ProjectID, + ProjectID: projectID, Audit: mongodb.Audit{ CreatedAt: currTime, UpdatedAt: currTime, @@ -126,11 +127,14 @@ func (p *probe) AddProbe(ctx context.Context, probe model.ProbeRequest) (*model. } // UpdateProbe - Update a new Probe -func (p *probe) UpdateProbe(ctx context.Context, request model.ProbeRequest) (string, error) { +func (p *probe) UpdateProbe(ctx context.Context, request model.ProbeRequest, projectID string) (string, error) { tkn := ctx.Value(authorization.AuthKey).(string) username, err := authorization.GetUsername(tkn) + if err != nil { + return "", err + } - pr, err := dbSchemaProbe.GetProbeByName(ctx, request.Name, p.ProjectID) + pr, err := dbSchemaProbe.GetProbeByName(ctx, request.Name, projectID) if err != nil { return "", err } @@ -141,7 +145,7 @@ func (p *probe) UpdateProbe(ctx context.Context, request model.ProbeRequest) (st Name: request.Name, Tags: request.Tags, }, - ProjectID: p.ProjectID, + ProjectID: projectID, Audit: mongodb.Audit{ CreatedAt: pr.CreatedAt, UpdatedAt: time.Now().UnixMilli(), @@ -189,7 +193,7 @@ func (p *probe) UpdateProbe(ctx context.Context, request model.ProbeRequest) (st filterQuery := bson.D{ {"name", request.Name}, - {"project_id", p.ProjectID}, + {"project_id", projectID}, {"is_removed", false}, } @@ -202,9 +206,9 @@ func (p *probe) UpdateProbe(ctx context.Context, request model.ProbeRequest) (st } // GetProbe - List a single Probe -func (p *probe) GetProbe(ctx context.Context, probeName string) (*model.Probe, error) { +func (p *probe) GetProbe(ctx context.Context, probeName, projectID string) (*model.Probe, error) { - probe, err := dbSchemaProbe.GetProbeByName(ctx, probeName, p.ProjectID) + probe, err := dbSchemaProbe.GetProbeByName(ctx, probeName, projectID) if err != nil { return nil, err } @@ -213,9 +217,9 @@ func (p *probe) GetProbe(ctx context.Context, probeName string) (*model.Probe, e } // GetProbeYAMLData - Get the probe yaml data compatible with the chaos engine manifest -func (p *probe) GetProbeYAMLData(ctx context.Context, probeRequest model.GetProbeYAMLRequest) (string, error) { +func (p *probe) GetProbeYAMLData(ctx context.Context, probeRequest model.GetProbeYAMLRequest, projectID string) (string, error) { - probe, err := dbSchemaProbe.GetProbeByName(ctx, probeRequest.ProbeName, p.ProjectID) + probe, err := dbSchemaProbe.GetProbeByName(ctx, probeRequest.ProbeName, projectID) if err != nil { return "", err } @@ -229,7 +233,7 @@ func (p *probe) GetProbeYAMLData(ctx context.Context, probeRequest model.GetProb } // ListProbes - List a single/all Probes -func (p *probe) ListProbes(ctx context.Context, probeNames []string, infrastructureType *model.InfrastructureType, filter *model.ProbeFilterInput) ([]*model.Probe, error) { +func (p *probe) ListProbes(ctx context.Context, probeNames []string, infrastructureType *model.InfrastructureType, filter *model.ProbeFilterInput, projectID string) ([]*model.Probe, error) { var pipeline mongo.Pipeline // Match the Probe Names from the input array @@ -298,10 +302,21 @@ func (p *probe) ListProbes(ctx context.Context, probeNames []string, infrastruct filterProbeDateStage := bson.D{ { "$match", - bson.D{{"updated_at", bson.D{ - {"$lte", endDate}, - {"$gte", startDate}, - }}}, + bson.D{ + { + "updated_at", + bson.D{ + { + "$lte", + endDate, + }, + { + "$gte", + startDate, + }, + }, + }, + }, }, } pipeline = append(pipeline, filterProbeDateStage) @@ -312,7 +327,7 @@ func (p *probe) ListProbes(ctx context.Context, probeNames []string, infrastruct matchIdentifierStage := bson.D{ { Key: "$match", Value: bson.D{ - {"project_id", p.ProjectID}, + {"project_id", projectID}, {"is_removed", false}, }, }, @@ -335,7 +350,7 @@ func (p *probe) ListProbes(ctx context.Context, probeNames []string, infrastruct for _, probe := range allProbes { var lastTenExecutions []*model.ProbeRecentExecutions - recentExecutions, err := GetProbeExecutionHistoryInExperimentRuns(p.ProjectID, probe.Name) + recentExecutions, err := GetProbeExecutionHistoryInExperimentRuns(projectID, probe.Name) if err != nil { return nil, err } @@ -369,10 +384,12 @@ func GetProbeExecutionHistoryInExperimentRuns(projectID string, probeName string // Match with identifiers matchIdentifierStage := bson.D{ - {"$match", bson.D{ - {"project_id", projectID}, - {"probes.probe_names", probeName}, - }}, + { + "$match", bson.D{ + {"project_id", projectID}, + {"probes.probe_names", probeName}, + }, + }, } pipeline = append(pipeline, matchIdentifierStage) @@ -457,9 +474,9 @@ func GetProbeExecutionHistoryInExperimentRuns(projectID string, probeName string } // DeleteProbe - Deletes a single Probe -func (p *probe) DeleteProbe(ctx context.Context, probeName string) (bool, error) { +func (p *probe) DeleteProbe(ctx context.Context, probeName, projectID string) (bool, error) { - _, err := dbSchemaProbe.GetProbeByName(ctx, probeName, p.ProjectID) + _, err := dbSchemaProbe.GetProbeByName(ctx, probeName, projectID) if err != nil { return false, err } @@ -470,7 +487,7 @@ func (p *probe) DeleteProbe(ctx context.Context, probeName string) (bool, error) query := bson.D{ {"name", probeName}, - {"project_id", p.ProjectID}, + {"project_id", projectID}, {"is_removed", false}, } update := bson.D{ @@ -492,22 +509,24 @@ func (p *probe) DeleteProbe(ctx context.Context, probeName string) (bool, error) } // GetProbeReference - Get the experiment details the probe is referencing to -func (p *probe) GetProbeReference(ctx context.Context, probeName string) (*model.GetProbeReferenceResponse, error) { +func (p *probe) GetProbeReference(ctx context.Context, probeName, projectID string) (*model.GetProbeReferenceResponse, error) { var pipeline mongo.Pipeline // Matching with identifiers matchIdentifiersStage := bson.D{ { - "$match", bson.D{{ - "$and", bson.A{ - bson.D{ - {"project_id", p.ProjectID}, - {"name", probeName}, - {"is_removed", false}, + "$match", bson.D{ + { + "$and", bson.A{ + bson.D{ + {"project_id", projectID}, + {"name", probeName}, + {"is_removed", false}, + }, }, }, - }}, + }, }, } pipeline = append(pipeline, matchIdentifiersStage) @@ -675,11 +694,11 @@ func (p *probe) GetProbeReference(ctx context.Context, probeName string) (*model } // ValidateUniqueProbe - Validates the uniqueness of the probe, returns true if unique -func (p *probe) ValidateUniqueProbe(ctx context.Context, probeName string) (bool, error) { +func (p *probe) ValidateUniqueProbe(ctx context.Context, probeName, projectID string) (bool, error) { query := bson.D{ {"name", probeName}, - {"project_id", p.ProjectID}, + {"project_id", projectID}, } isUnique, err := dbSchemaProbe.IsProbeUnique(ctx, query) diff --git a/chaoscenter/graphql/server/pkg/probe/utils/utils.go b/chaoscenter/graphql/server/pkg/probe/utils/utils.go index 1be18a199ad..af24c44c773 100644 --- a/chaoscenter/graphql/server/pkg/probe/utils/utils.go +++ b/chaoscenter/graphql/server/pkg/probe/utils/utils.go @@ -1003,3 +1003,164 @@ func GenerateCronExperimentManifestWithProbes(manifest string, projectID string) return cronManifest, nil } + +func InsertProbeRefAnnotation(rawYaml, value string) (string, error) { + var data interface{} + + err := yaml.Unmarshal([]byte(rawYaml), &data) + if err != nil { + return "", err + } + + dataMap := data.(map[string]interface{}) + + metadata := dataMap["metadata"] + if metadata == nil { + return "", errors.New("metadata not found") + } + + annotations := metadata.(map[string]interface{})["annotations"] + if annotations == nil { + // create new annotations + annotations = make(map[string]interface{}) + metadata.(map[string]interface{})["annotations"] = annotations + } + + annotations.(map[string]interface{})["probeRef"] = value + + result, err := yaml.Marshal(dataMap) + if err != nil { + return "", err + } + + return string(result), nil +} + +// Convert the probe inputs to probe request +func ProbeInputsToProbeRequestConverter(probeInputs v1alpha1.ProbeAttributes) (model.ProbeRequest, error) { + var kubernetesHTTPProperties *model.KubernetesHTTPProbeRequest + var kubernetesCMDProperties *model.KubernetesCMDProbeRequest + var k8sProperties *model.K8SProbeRequest + var promProperties *model.PROMProbeRequest + + if probeInputs.RunProperties.ProbeTimeout == "" || probeInputs.RunProperties.Interval == "" { + return model.ProbeRequest{}, errors.New("values for ProbeTimeout and Interval are required") + } + + switch model.ProbeType(probeInputs.Type) { + case model.ProbeTypeHTTPProbe: + method := &model.MethodRequest{} + if probeInputs.HTTPProbeInputs.Method.Get != nil { + method.Get = &model.GETRequest{ + Criteria: probeInputs.HTTPProbeInputs.Method.Get.Criteria, + ResponseCode: probeInputs.HTTPProbeInputs.Method.Get.ResponseCode, + } + } else if probeInputs.HTTPProbeInputs.Method.Post != nil { + method.Post = &model.POSTRequest{ + Criteria: probeInputs.HTTPProbeInputs.Method.Post.Criteria, + ResponseCode: probeInputs.HTTPProbeInputs.Method.Post.ResponseCode, + } + method.Post.ContentType = &probeInputs.HTTPProbeInputs.Method.Post.ContentType + method.Post.Body = &probeInputs.HTTPProbeInputs.Method.Post.Body + method.Post.BodyPath = &probeInputs.HTTPProbeInputs.Method.Post.BodyPath + } else { + return model.ProbeRequest{}, errors.New("GET/POST method not specified") + } + if probeInputs.HTTPProbeInputs.URL == "" { + return model.ProbeRequest{}, errors.New("URL not specified") + } + if probeInputs.RunProperties.EvaluationTimeout != "" { + kubernetesHTTPProperties.EvaluationTimeout = &probeInputs.RunProperties.EvaluationTimeout + } + if probeInputs.RunProperties.ProbePollingInterval != "" { + kubernetesHTTPProperties.ProbePollingInterval = &probeInputs.RunProperties.ProbePollingInterval + } + if probeInputs.RunProperties.InitialDelay != "" { + kubernetesHTTPProperties.InitialDelay = &probeInputs.RunProperties.InitialDelay + } + + kubernetesHTTPProperties = &model.KubernetesHTTPProbeRequest{ + ProbeTimeout: probeInputs.RunProperties.ProbeTimeout, + Interval: probeInputs.RunProperties.Interval, + URL: probeInputs.HTTPProbeInputs.URL, + Method: method, + Attempt: &probeInputs.RunProperties.Attempt, + Retry: &probeInputs.RunProperties.Retry, + StopOnFailure: &probeInputs.RunProperties.StopOnFailure, + InsecureSkipVerify: &probeInputs.HTTPProbeInputs.InsecureSkipVerify, + } + case model.ProbeTypePromProbe: + if probeInputs.PromProbeInputs.Endpoint == "" { + return model.ProbeRequest{}, errors.New("endpoint not specified") + } + promProperties = &model.PROMProbeRequest{ + ProbeTimeout: probeInputs.RunProperties.ProbeTimeout, + Interval: probeInputs.RunProperties.Interval, + Endpoint: probeInputs.PromProbeInputs.Endpoint, + Comparator: &model.ComparatorInput{ + Type: probeInputs.PromProbeInputs.Comparator.Type, + Criteria: probeInputs.PromProbeInputs.Comparator.Criteria, + Value: probeInputs.PromProbeInputs.Comparator.Value, + }, + Attempt: &probeInputs.RunProperties.Attempt, + Retry: &probeInputs.RunProperties.Retry, + ProbePollingInterval: &probeInputs.RunProperties.ProbePollingInterval, + EvaluationTimeout: &probeInputs.RunProperties.EvaluationTimeout, + InitialDelay: &probeInputs.RunProperties.InitialDelay, + StopOnFailure: &probeInputs.RunProperties.StopOnFailure, + Query: &probeInputs.PromProbeInputs.Query, + QueryPath: &probeInputs.PromProbeInputs.QueryPath, + } + case model.ProbeTypeK8sProbe: + if probeInputs.K8sProbeInputs.Resource == "" || probeInputs.K8sProbeInputs.Operation == "" || probeInputs.K8sProbeInputs.Version == "" { + return model.ProbeRequest{}, errors.New("resource, operation and version are required") + } + k8sProperties = &model.K8SProbeRequest{ + ProbeTimeout: probeInputs.RunProperties.ProbeTimeout, + Interval: probeInputs.RunProperties.Interval, + Version: probeInputs.K8sProbeInputs.Version, + Resource: probeInputs.K8sProbeInputs.Resource, + Operation: probeInputs.K8sProbeInputs.Operation, + Attempt: &probeInputs.RunProperties.Attempt, + Retry: &probeInputs.RunProperties.Retry, + ProbePollingInterval: &probeInputs.RunProperties.ProbePollingInterval, + EvaluationTimeout: &probeInputs.RunProperties.EvaluationTimeout, + StopOnFailure: &probeInputs.RunProperties.StopOnFailure, + Group: &probeInputs.K8sProbeInputs.Group, + ResourceNames: &probeInputs.K8sProbeInputs.ResourceNames, + Namespace: &probeInputs.K8sProbeInputs.Namespace, + FieldSelector: &probeInputs.K8sProbeInputs.FieldSelector, + LabelSelector: &probeInputs.K8sProbeInputs.LabelSelector, + } + case model.ProbeTypeCmdProbe: + source, _ := json.Marshal(probeInputs.CmdProbeInputs.Source) + sourcePtr := string(source) + kubernetesCMDProperties = &model.KubernetesCMDProbeRequest{ + ProbeTimeout: probeInputs.RunProperties.ProbeTimeout, + Interval: probeInputs.RunProperties.Interval, + Command: probeInputs.CmdProbeInputs.Command, + Comparator: &model.ComparatorInput{ + Type: probeInputs.CmdProbeInputs.Comparator.Type, + Criteria: probeInputs.CmdProbeInputs.Comparator.Criteria, + Value: probeInputs.CmdProbeInputs.Comparator.Value, + }, + Attempt: &probeInputs.RunProperties.Attempt, + Retry: &probeInputs.RunProperties.Retry, + ProbePollingInterval: &probeInputs.RunProperties.ProbePollingInterval, + InitialDelay: &probeInputs.RunProperties.InitialDelay, + StopOnFailure: &probeInputs.RunProperties.StopOnFailure, + Source: &sourcePtr, + } + } + + return model.ProbeRequest{ + Name: probeInputs.Name, + Type: model.ProbeType(probeInputs.Type), + K8sProperties: k8sProperties, + KubernetesHTTPProperties: kubernetesHTTPProperties, + KubernetesCMDProperties: kubernetesCMDProperties, + PromProperties: promProperties, + InfrastructureType: model.InfrastructureType(model.InfrastructureTypeKubernetes), + Tags: []string{}, + }, nil +} diff --git a/chaoscenter/web/src/api/ReactQueryProvider.tsx b/chaoscenter/web/src/api/ReactQueryProvider.tsx index ea3190d2a59..a76fa82eef0 100644 --- a/chaoscenter/web/src/api/ReactQueryProvider.tsx +++ b/chaoscenter/web/src/api/ReactQueryProvider.tsx @@ -6,9 +6,9 @@ export const ReactQueryProvider: React.FC = ({ children }): React.ReactElement = defaultOptions: { mutations: {}, queries: { - refetchOnWindowFocus: false, - }, - }, + refetchOnWindowFocus: false + } + } }); return {children}; diff --git a/chaoscenter/web/src/utils/testUtils.tsx b/chaoscenter/web/src/utils/testUtils.tsx index e6c97fd4760..5372d580ab1 100644 --- a/chaoscenter/web/src/utils/testUtils.tsx +++ b/chaoscenter/web/src/utils/testUtils.tsx @@ -38,11 +38,11 @@ export function TestWrapper({ children }: TestWrapperProps): React.ReactElement currentUserInfo: { userRole: 'admin', ID: 'uid', - username: 'admin', + username: 'admin' }, renderUrl: `/account/uid`, matchPath: '/account/:accountID', - updateAppStore: () => void NO_OPERATION, + updateAppStore: () => void NO_OPERATION }} > diff --git a/chaoscenter/web/src/views/ChaosStudio/ChaosStudio.tsx b/chaoscenter/web/src/views/ChaosStudio/ChaosStudio.tsx index 6174fd31ad2..214c51fe0fb 100644 --- a/chaoscenter/web/src/views/ChaosStudio/ChaosStudio.tsx +++ b/chaoscenter/web/src/views/ChaosStudio/ChaosStudio.tsx @@ -81,7 +81,6 @@ export default function ChaosStudioView({ const [hasFaults, setHasFaults] = React.useState(false); const studioOverviewRef = React.useRef>(); const experimentHashKeyForClone = getHash(); - const probeWithoutRef = React.useRef(); const { showWarning } = useToaster(); const { isOpen: isOpenDiscardExperimentDialog, @@ -160,7 +159,6 @@ export default function ChaosStudioView({ const probeWithoutAnnotation = await ( experimentHandler as KubernetesYamlService )?.checkProbesInExperimentManifest(experiment?.manifest as KubernetesExperimentManifest); - probeWithoutRef.current = probeWithoutAnnotation; /** * Checks if probe metadata is already present in the manifest @@ -174,12 +172,14 @@ export default function ChaosStudioView({ if (doesProbeExists) { showWarning(getString('probeMetadataExists')); } - } - if (probeWithoutRef.current) { - showError(`${getString('probeInFault')} ${probeWithoutRef.current} ${getString('probeNotAttachedToRef')}`); - return; + // Generate new probes if annotation is missing but probes are present. Else case return error + if (probeWithoutAnnotation && !doesProbeExists) { + showError(`${getString('probeInFault')} ${probeWithoutAnnotation} ${getString('probeNotAttachedToRef')}`); + return; + } } + saveChaosExperimentMutation({ variables: { projectID: scope.projectID, diff --git a/chaoscenter/web/src/views/Overview/Overview.tsx b/chaoscenter/web/src/views/Overview/Overview.tsx index 64a427d7956..5e386520ec3 100644 --- a/chaoscenter/web/src/views/Overview/Overview.tsx +++ b/chaoscenter/web/src/views/Overview/Overview.tsx @@ -40,7 +40,7 @@ export default function OverviewView({ infraStats, experimentDashboardTableData, experimentStats, - refetchExperiments, + refetchExperiments }: OverviewViewProps & RefetchExperiments): React.ReactElement { const { getString } = useStrings(); const paths = useRouteWithBaseUrl(); @@ -58,10 +58,10 @@ export default function OverviewView({ paddingBottom: 0, position: 'relative', overflow: 'hidden', - display: 'grid', + display: 'grid' }, enforceFocus: false, - onClose: () => setIsEnableChaosModalOpen(false), + onClose: () => setIsEnableChaosModalOpen(false) }; React.useEffect(() => { diff --git a/chaoscenter/web/src/views/Overview/__tests__/Overview.test.tsx b/chaoscenter/web/src/views/Overview/__tests__/Overview.test.tsx index 2fcfba0b10d..501f3ea0a4b 100644 --- a/chaoscenter/web/src/views/Overview/__tests__/Overview.test.tsx +++ b/chaoscenter/web/src/views/Overview/__tests__/Overview.test.tsx @@ -13,9 +13,9 @@ const NoExperimentProps = { chaosHubStats: false, experimentStats: false, infraStats: false, - recentExperimentsTable: false, + recentExperimentsTable: false }, - refetchExperiments: Promise.resolve, + refetchExperiments: Promise.resolve }; const props = { @@ -27,10 +27,10 @@ const props = { chaosHubStats: true, experimentStats: true, infraStats: true, - recentExperimentsTable: true, + recentExperimentsTable: true }, - refetchExperiments: Promise.resolve, + refetchExperiments: Promise.resolve }; describe('OverviewView Component', () => { test('shows loading state', async () => { diff --git a/chaoscenter/web/src/views/ResetPassword/__tests__/ResetPassword.test.tsx b/chaoscenter/web/src/views/ResetPassword/__tests__/ResetPassword.test.tsx index afd5be1460a..560d0b63a13 100644 --- a/chaoscenter/web/src/views/ResetPassword/__tests__/ResetPassword.test.tsx +++ b/chaoscenter/web/src/views/ResetPassword/__tests__/ResetPassword.test.tsx @@ -7,7 +7,7 @@ import ResetPasswordView from '../ResetPassword'; beforeEach(() => { jest.spyOn(stringUtils, 'useStrings').mockReturnValue({ - getString: jest.fn().mockImplementation(key => `Mocked String for ${key}`), + getString: jest.fn().mockImplementation(key => `Mocked String for ${key}`) }); }); @@ -61,10 +61,10 @@ describe('ResetPasswordView Component', () => { ); fireEvent.change(screen.getByPlaceholderText('Mocked String for newPassword'), { - target: { value: 'password123' }, + target: { value: 'password123' } }); fireEvent.change(screen.getByPlaceholderText('Mocked String for reEnterNewPassword'), { - target: { value: 'password123' }, + target: { value: 'password123' } }); const submitButton = screen.getByRole('button', { name: /confirm/i }); @@ -82,10 +82,10 @@ describe('ResetPasswordView Component', () => { ); fireEvent.change(screen.getByPlaceholderText('Mocked String for newPassword'), { - target: { value: 'password123' }, + target: { value: 'password123' } }); fireEvent.change(screen.getByPlaceholderText('Mocked String for reEnterNewPassword'), { - target: { value: 'differentPassword123' }, + target: { value: 'differentPassword123' } }); const submitButton = screen.getByRole('button', { name: /confirm/i });