From e328553f5988fe75b3801a213387ee23ffc9482c Mon Sep 17 00:00:00 2001 From: Ishan Gupta Date: Mon, 12 Jul 2021 19:20:59 +0530 Subject: [PATCH] (analytics): Backend enhancements for editing event query, patching verdict to event data and subscription for viewing application dashboards (#2985) * chaos event and verdict query update for stored dashboards Signed-off-by: ishangupta-ds * subscription for viewing dashboards Signed-off-by: ishangupta-ds * minor fix Signed-off-by: ishangupta-ds * fixes for prometheus schema usage and verdict patch Signed-off-by: ishangupta-ds * fixes Signed-off-by: ishangupta-ds * updated caching strategy Signed-off-by: ishangupta-ds * fixes for agent based dashboard listing and update dashboard vars Signed-off-by: ishangupta-ds * updates to dashboards with data source healthcheck Signed-off-by: ishangupta-ds * minor fix Signed-off-by: ishangupta-ds * fixing concurrency issue Signed-off-by: ishangupta-ds * minor fix Signed-off-by: ishangupta-ds * minor fix Signed-off-by: ishangupta-ds * minor fix Signed-off-by: ishangupta-ds * minor fix Signed-off-by: ishangupta-ds * updates for race condition Signed-off-by: ishangupta-ds * made the code modular Signed-off-by: ishangupta-ds * fixes for duplicate events and locks Signed-off-by: ishangupta-ds * codacy fixes Signed-off-by: ishangupta-ds * changes after review Signed-off-by: ishangupta-ds --- litmus-portal/graphql-server/go.sum | 2 + .../graphql-server/graph/analytics.graphqls | 64 +- .../graph/generated/generated.go | 1303 ++++++++++++++++- .../graphql-server/graph/model/models_gen.go | 68 +- .../graphql-server/graph/schema.graphqls | 11 +- .../graphql-server/graph/schema.resolvers.go | 31 +- .../pkg/analytics/handler/handler.go | 645 +++++--- .../pkg/analytics/ops/operations.go | 167 +++ .../analytics/ops/prometheus/prometheus.go | 151 +- .../graphql-server/pkg/analytics/types.go | 52 +- .../graphql-server/pkg/data-store/store.go | 2 + litmus-portal/graphql-server/utils/cache.go | 5 + litmus-portal/graphql-server/utils/misc.go | 43 + 13 files changed, 2178 insertions(+), 366 deletions(-) diff --git a/litmus-portal/graphql-server/go.sum b/litmus-portal/graphql-server/go.sum index 6833a0be5de..9fc2c1f6229 100644 --- a/litmus-portal/graphql-server/go.sum +++ b/litmus-portal/graphql-server/go.sum @@ -643,6 +643,8 @@ github.com/litmuschaos/chaos-operator v0.0.0-20210224131102-ca6a465ed348/go.mod github.com/litmuschaos/chaos-scheduler v0.0.0-20210607090343-9952190ad032 h1:Nza94oOqOsao8eFWC19iFviS8XsxS2eVk7Q0a9WDKBE= github.com/litmuschaos/chaos-scheduler v0.0.0-20210607090343-9952190ad032/go.mod h1:7EO6kbZKeJGKzkchgQepCxywvqNFNvNHW0G+u9923AY= github.com/litmuschaos/elves v0.0.0-20201107015738-552d74669e3c/go.mod h1:DsbHGNUq/78NZozWVVI9Q6eBei4I+JjlkkD5aibJ3MQ= +github.com/litmuschaos/litmus v0.0.0-20210702160150-411ccb5d572a h1:1o6+JzP0K2o68iH748VPQBhHr9VC1/IK2fHCoHz3df0= +github.com/litmuschaos/litmus v0.0.0-20210712105501-6cb1456b1ad5 h1:rfHzsGxUlgnLViHyUpa2AdZ4XZRAjBdGL+Wc8XEwyT0= github.com/logrusorgru/aurora v0.0.0-20200102142835-e9ef32dff381/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4= github.com/lpabon/godbc v0.1.1/go.mod h1:Jo9QV0cf3U6jZABgiJ2skINAXb9j8m51r07g4KI92ZA= github.com/lucas-clemente/aes12 v0.0.0-20171027163421-cd47fb39b79f/go.mod h1:JpH9J1c9oX6otFSgdUHwUBUizmKlrMjxWnIAjff4m04= diff --git a/litmus-portal/graphql-server/graph/analytics.graphqls b/litmus-portal/graphql-server/graph/analytics.graphqls index 27b693bc865..8aad47ba164 100644 --- a/litmus-portal/graphql-server/graph/analytics.graphqls +++ b/litmus-portal/graphql-server/graph/analytics.graphqls @@ -60,19 +60,19 @@ input resource { input updateDBInput { db_id: String! - ds_id: String! - db_name: String! - db_type_name: String! - db_type_id: String! + ds_id: String + db_name: String + db_type_name: String + db_type_id: String db_information: String - chaos_event_query_template: String! - chaos_verdict_query_template: String! + chaos_event_query_template: String + chaos_verdict_query_template: String application_metadata_map: [applicationMetadata] - panel_groups: [updatePanelGroupInput]! - end_time: String! - start_time: String! - cluster_id: ID! - refresh_rate: String! + panel_groups: [updatePanelGroupInput] + end_time: String + start_time: String + cluster_id: ID + refresh_rate: String } input updatePanelGroupInput { @@ -140,6 +140,24 @@ input promQueryInput { minstep: Int! } +input queryMapForPanel { + panelID: String! + queryIDs: [String!]! +} + +input queryMapForPanelGroup { + panelGroupID: String! + panelQueryMap: [queryMapForPanel!]! +} + +input dataVars { + url: String! + start: String! + end: String! + relative_time: Int! + refresh_interval: Int! +} + type metricsPromResponse { queryid: String! legends: [String] @@ -151,10 +169,17 @@ type metricsTimeStampValue { value: Float } +type subData { + date: Float + value: String! + subDataName: String! +} + type annotationsPromResponse { queryid: String! legends: [String] tsvs: [[annotationsTimeStampValue]] + subDataArray: [[subData]] } type annotationsTimeStampValue { @@ -167,6 +192,21 @@ type promResponse { annotationsResponse: [annotationsPromResponse] } +type metricDataForPanel { + panelID: String! + PanelMetricsResponse: [metricsPromResponse] +} + +type metricDataForPanelGroup { + panelGroupID: String! + panelGroupMetricsResponse: [metricDataForPanel] +} + +type dashboardPromResponse { + dashboardMetricsResponse: [metricDataForPanelGroup] + annotationsResponse: [annotationsPromResponse] +} + type promSeriesResponse { series: String! labelValues: [labelValue] @@ -198,6 +238,8 @@ type listDashboardResponse { cluster_name: String ds_name: String ds_type: String + ds_url: String + ds_health_status: String panel_groups: [panelGroupResponse]! end_time: String! start_time: String! diff --git a/litmus-portal/graphql-server/graph/generated/generated.go b/litmus-portal/graphql-server/graph/generated/generated.go index 999b6718431..20558dc74c5 100644 --- a/litmus-portal/graphql-server/graph/generated/generated.go +++ b/litmus-portal/graphql-server/graph/generated/generated.go @@ -276,7 +276,7 @@ type ComplexityRoot struct { SyncHub func(childComplexity int, id string) int SyncWorkflow func(childComplexity int, workflowid string, workflowRunID string) int UpdateChaosWorkflow func(childComplexity int, input *model.ChaosWorkFlowInput) int - UpdateDashboard func(childComplexity int, dashboard *model.UpdateDBInput) int + UpdateDashboard func(childComplexity int, dashboard model.UpdateDBInput, chaosQueryUpdate bool) int UpdateDataSource func(childComplexity int, datasource model.DSInput) int UpdateGitOps func(childComplexity int, config model.GitConfig) int UpdateImageRegistry func(childComplexity int, imageRegistryID string, projectID string, imageRegistryInfo model.ImageRegistryInput) int @@ -388,7 +388,7 @@ type ComplexityRoot struct { GetWorkflowRuns func(childComplexity int, workflowRunsInput model.GetWorkflowRunsInput) int GetWorkflowStats func(childComplexity int, projectID string, filter model.TimeFrequency, showWorkflowRuns bool) int GetYAMLData func(childComplexity int, experimentInput model.ExperimentInput) int - ListDashboard func(childComplexity int, projectID string) int + ListDashboard func(childComplexity int, projectID string, clusterID *string, dbID *string) int ListDataSource func(childComplexity int, projectID string) int ListImageRegistry func(childComplexity int, projectID string) int ListManifestTemplate func(childComplexity int, projectID string) int @@ -442,6 +442,7 @@ type ComplexityRoot struct { ClusterEventListener func(childComplexity int, projectID string) int GetKubeObject func(childComplexity int, kubeObjectRequest model.KubeObjectRequest) int GetPodLog func(childComplexity int, podDetails model.PodLogRequest) int + ViewDashboard func(childComplexity int, promQueries []*model.PromQueryInput, dashboardQueryMap []*model.QueryMapForPanelGroup, dataVariables model.DataVars) int WorkflowEventListener func(childComplexity int, projectID string) int } @@ -558,9 +559,10 @@ type ComplexityRoot struct { } AnnotationsPromResponse struct { - Legends func(childComplexity int) int - Queryid func(childComplexity int) int - Tsvs func(childComplexity int) int + Legends func(childComplexity int) int + Queryid func(childComplexity int) int + SubDataArray func(childComplexity int) int + Tsvs func(childComplexity int) int } AnnotationsTimeStampValue struct { @@ -579,6 +581,11 @@ type ComplexityRoot struct { Token func(childComplexity int) int } + DashboardPromResponse struct { + AnnotationsResponse func(childComplexity int) int + DashboardMetricsResponse func(childComplexity int) int + } + ImageRegistry struct { EnableRegistry func(childComplexity int) int ImageRegistryName func(childComplexity int) int @@ -606,9 +613,11 @@ type ComplexityRoot struct { DbName func(childComplexity int) int DbTypeID func(childComplexity int) int DbTypeName func(childComplexity int) int + DsHealthStatus func(childComplexity int) int DsID func(childComplexity int) int DsName func(childComplexity int) int DsType func(childComplexity int) int + DsURL func(childComplexity int) int EndTime func(childComplexity int) int PanelGroups func(childComplexity int) int ProjectID func(childComplexity int) int @@ -617,6 +626,16 @@ type ComplexityRoot struct { UpdatedAt func(childComplexity int) int } + MetricDataForPanel struct { + PanelID func(childComplexity int) int + PanelMetricsResponse func(childComplexity int) int + } + + MetricDataForPanelGroup struct { + PanelGroupID func(childComplexity int) int + PanelGroupMetricsResponse func(childComplexity int) int + } + MetricsPromResponse struct { Legends func(childComplexity int) int Queryid func(childComplexity int) int @@ -685,6 +704,12 @@ type ComplexityRoot struct { Names func(childComplexity int) int } + SubData struct { + Date func(childComplexity int) int + SubDataName func(childComplexity int) int + Value func(childComplexity int) int + } + Weightages struct { ExperimentName func(childComplexity int) int Weightage func(childComplexity int) int @@ -726,7 +751,7 @@ type MutationResolver interface { CreateDataSource(ctx context.Context, datasource *model.DSInput) (*model.DSResponse, error) CreateDashBoard(ctx context.Context, dashboard *model.CreateDBInput) (*model.ListDashboardResponse, error) UpdateDataSource(ctx context.Context, datasource model.DSInput) (*model.DSResponse, error) - UpdateDashboard(ctx context.Context, dashboard *model.UpdateDBInput) (string, error) + UpdateDashboard(ctx context.Context, dashboard model.UpdateDBInput, chaosQueryUpdate bool) (string, error) UpdatePanel(ctx context.Context, panelInput []*model.Panel) (string, error) DeleteDashboard(ctx context.Context, dbID *string) (bool, error) DeleteDataSource(ctx context.Context, input model.DeleteDSInput) (bool, error) @@ -757,7 +782,7 @@ type QueryResolver interface { GetPromQuery(ctx context.Context, query *model.PromInput) (*model.PromResponse, error) GetPromLabelNamesAndValues(ctx context.Context, series *model.PromSeriesInput) (*model.PromSeriesResponse, error) GetPromSeriesList(ctx context.Context, dsDetails *model.DsDetails) (*model.PromSeriesListResponse, error) - ListDashboard(ctx context.Context, projectID string) ([]*model.ListDashboardResponse, error) + ListDashboard(ctx context.Context, projectID string, clusterID *string, dbID *string) ([]*model.ListDashboardResponse, error) PortalDashboardData(ctx context.Context, projectID string, hubName string) ([]*model.PortalDashboardData, error) GetGitOpsDetails(ctx context.Context, projectID string) (*model.GitConfigResponse, error) ListManifestTemplate(ctx context.Context, projectID string) ([]*model.ManifestTemplate, error) @@ -772,6 +797,7 @@ type SubscriptionResolver interface { GetPodLog(ctx context.Context, podDetails model.PodLogRequest) (<-chan *model.PodLogResponse, error) ClusterConnect(ctx context.Context, clusterInfo model.ClusterIdentity) (<-chan *model.ClusterAction, error) GetKubeObject(ctx context.Context, kubeObjectRequest model.KubeObjectRequest) (<-chan *model.KubeObjectResponse, error) + ViewDashboard(ctx context.Context, promQueries []*model.PromQueryInput, dashboardQueryMap []*model.QueryMapForPanelGroup, dataVariables model.DataVars) (<-chan *model.DashboardPromResponse, error) } type executableSchema struct { @@ -2056,7 +2082,7 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return 0, false } - return e.complexity.Mutation.UpdateDashboard(childComplexity, args["dashboard"].(*model.UpdateDBInput)), true + return e.complexity.Mutation.UpdateDashboard(childComplexity, args["dashboard"].(model.UpdateDBInput), args["chaosQueryUpdate"].(bool)), true case "Mutation.updateDataSource": if e.complexity.Mutation.UpdateDataSource == nil { @@ -2770,7 +2796,7 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return 0, false } - return e.complexity.Query.ListDashboard(childComplexity, args["project_id"].(string)), true + return e.complexity.Query.ListDashboard(childComplexity, args["project_id"].(string), args["cluster_id"].(*string), args["db_id"].(*string)), true case "Query.ListDataSource": if e.complexity.Query.ListDataSource == nil { @@ -3109,6 +3135,18 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.Subscription.GetPodLog(childComplexity, args["podDetails"].(model.PodLogRequest)), true + case "Subscription.viewDashboard": + if e.complexity.Subscription.ViewDashboard == nil { + break + } + + args, err := ec.field_Subscription_viewDashboard_args(context.TODO(), rawArgs) + if err != nil { + return 0, false + } + + return e.complexity.Subscription.ViewDashboard(childComplexity, args["promQueries"].([]*model.PromQueryInput), args["dashboardQueryMap"].([]*model.QueryMapForPanelGroup), args["dataVariables"].(model.DataVars)), true + case "Subscription.workflowEventListener": if e.complexity.Subscription.WorkflowEventListener == nil { break @@ -3688,6 +3726,13 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.AnnotationsPromResponse.Queryid(childComplexity), true + case "annotationsPromResponse.subDataArray": + if e.complexity.AnnotationsPromResponse.SubDataArray == nil { + break + } + + return e.complexity.AnnotationsPromResponse.SubDataArray(childComplexity), true + case "annotationsPromResponse.tsvs": if e.complexity.AnnotationsPromResponse.Tsvs == nil { break @@ -3744,6 +3789,20 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.ClusterRegResponse.Token(childComplexity), true + case "dashboardPromResponse.annotationsResponse": + if e.complexity.DashboardPromResponse.AnnotationsResponse == nil { + break + } + + return e.complexity.DashboardPromResponse.AnnotationsResponse(childComplexity), true + + case "dashboardPromResponse.dashboardMetricsResponse": + if e.complexity.DashboardPromResponse.DashboardMetricsResponse == nil { + break + } + + return e.complexity.DashboardPromResponse.DashboardMetricsResponse(childComplexity), true + case "imageRegistry.enable_registry": if e.complexity.ImageRegistry.EnableRegistry == nil { break @@ -3884,6 +3943,13 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.ListDashboardResponse.DbTypeName(childComplexity), true + case "listDashboardResponse.ds_health_status": + if e.complexity.ListDashboardResponse.DsHealthStatus == nil { + break + } + + return e.complexity.ListDashboardResponse.DsHealthStatus(childComplexity), true + case "listDashboardResponse.ds_id": if e.complexity.ListDashboardResponse.DsID == nil { break @@ -3905,6 +3971,13 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.ListDashboardResponse.DsType(childComplexity), true + case "listDashboardResponse.ds_url": + if e.complexity.ListDashboardResponse.DsURL == nil { + break + } + + return e.complexity.ListDashboardResponse.DsURL(childComplexity), true + case "listDashboardResponse.end_time": if e.complexity.ListDashboardResponse.EndTime == nil { break @@ -3947,6 +4020,34 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.ListDashboardResponse.UpdatedAt(childComplexity), true + case "metricDataForPanel.panelID": + if e.complexity.MetricDataForPanel.PanelID == nil { + break + } + + return e.complexity.MetricDataForPanel.PanelID(childComplexity), true + + case "metricDataForPanel.PanelMetricsResponse": + if e.complexity.MetricDataForPanel.PanelMetricsResponse == nil { + break + } + + return e.complexity.MetricDataForPanel.PanelMetricsResponse(childComplexity), true + + case "metricDataForPanelGroup.panelGroupID": + if e.complexity.MetricDataForPanelGroup.PanelGroupID == nil { + break + } + + return e.complexity.MetricDataForPanelGroup.PanelGroupID(childComplexity), true + + case "metricDataForPanelGroup.panelGroupMetricsResponse": + if e.complexity.MetricDataForPanelGroup.PanelGroupMetricsResponse == nil { + break + } + + return e.complexity.MetricDataForPanelGroup.PanelGroupMetricsResponse(childComplexity), true + case "metricsPromResponse.legends": if e.complexity.MetricsPromResponse.Legends == nil { break @@ -4192,6 +4293,27 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.ResourceResponse.Names(childComplexity), true + case "subData.date": + if e.complexity.SubData.Date == nil { + break + } + + return e.complexity.SubData.Date(childComplexity), true + + case "subData.subDataName": + if e.complexity.SubData.SubDataName == nil { + break + } + + return e.complexity.SubData.SubDataName(childComplexity), true + + case "subData.value": + if e.complexity.SubData.Value == nil { + break + } + + return e.complexity.SubData.Value(childComplexity), true + case "weightages.experiment_name": if e.complexity.Weightages.ExperimentName == nil { break @@ -4287,7 +4409,7 @@ func (ec *executionContext) introspectType(name string) (*introspection.Type, er } var sources = []*ast.Source{ - &ast.Source{Name: "graph/analytics.graphqls", Input: `input DSInput { + {Name: "graph/analytics.graphqls", Input: `input DSInput { ds_id: String ds_name: String! ds_type: String! @@ -4349,19 +4471,19 @@ input resource { input updateDBInput { db_id: String! - ds_id: String! - db_name: String! - db_type_name: String! - db_type_id: String! + ds_id: String + db_name: String + db_type_name: String + db_type_id: String db_information: String - chaos_event_query_template: String! - chaos_verdict_query_template: String! + chaos_event_query_template: String + chaos_verdict_query_template: String application_metadata_map: [applicationMetadata] - panel_groups: [updatePanelGroupInput]! - end_time: String! - start_time: String! - cluster_id: ID! - refresh_rate: String! + panel_groups: [updatePanelGroupInput] + end_time: String + start_time: String + cluster_id: ID + refresh_rate: String } input updatePanelGroupInput { @@ -4429,6 +4551,24 @@ input promQueryInput { minstep: Int! } +input queryMapForPanel { + panelID: String! + queryIDs: [String!]! +} + +input queryMapForPanelGroup { + panelGroupID: String! + panelQueryMap: [queryMapForPanel!]! +} + +input dataVars { + url: String! + start: String! + end: String! + relative_time: Int! + refresh_interval: Int! +} + type metricsPromResponse { queryid: String! legends: [String] @@ -4440,10 +4580,17 @@ type metricsTimeStampValue { value: Float } +type subData { + date: Float + value: String! + subDataName: String! +} + type annotationsPromResponse { queryid: String! legends: [String] tsvs: [[annotationsTimeStampValue]] + subDataArray: [[subData]] } type annotationsTimeStampValue { @@ -4456,6 +4603,21 @@ type promResponse { annotationsResponse: [annotationsPromResponse] } +type metricDataForPanel { + panelID: String! + PanelMetricsResponse: [metricsPromResponse] +} + +type metricDataForPanelGroup { + panelGroupID: String! + panelGroupMetricsResponse: [metricDataForPanel] +} + +type dashboardPromResponse { + dashboardMetricsResponse: [metricDataForPanelGroup] + annotationsResponse: [annotationsPromResponse] +} + type promSeriesResponse { series: String! labelValues: [labelValue] @@ -4487,6 +4649,8 @@ type listDashboardResponse { cluster_name: String ds_name: String ds_type: String + ds_url: String + ds_health_status: String panel_groups: [panelGroupResponse]! end_time: String! start_time: String! @@ -4597,7 +4761,7 @@ type PortalDashboardData { name: String! dashboard_data: String! }`, BuiltIn: false}, - &ast.Source{Name: "graph/image_registry.graphqls", Input: `type imageRegistry { + {Name: "graph/image_registry.graphqls", Input: `type imageRegistry { is_default: Boolean image_registry_name: String! image_repo_name: String! @@ -4627,7 +4791,7 @@ type ImageRegistryResponse { is_removed: Boolean } `, BuiltIn: false}, - &ast.Source{Name: "graph/myhub.graphqls", Input: `enum AuthType { + {Name: "graph/myhub.graphqls", Input: `enum AuthType { none basic token @@ -4801,7 +4965,7 @@ input UpdateMyHub { SSHPublicKey: String } `, BuiltIn: false}, - &ast.Source{Name: "graph/project.graphqls", Input: `type Project { + {Name: "graph/project.graphqls", Input: `type Project { id: ID! name: String! members: [Member!]! @@ -4833,7 +4997,7 @@ enum MemberRole { Viewer } `, BuiltIn: false}, - &ast.Source{Name: "graph/schema.graphqls", Input: `# GraphQL schema example + {Name: "graph/schema.graphqls", Input: `# GraphQL schema example # # https://gqlgen.com/getting-started/ @@ -5142,7 +5306,9 @@ type Query { GetPromSeriesList(ds_details: dsDetails): promSeriesListResponse! @authorized - ListDashboard(project_id: String!): [listDashboardResponse] @authorized + ListDashboard(project_id: String! + cluster_id: String + db_id: String): [listDashboardResponse] @authorized PortalDashboardData (project_id: String!, hub_name: String!) : [PortalDashboardData!]! @authorized @@ -5253,7 +5419,8 @@ type Mutation { updateDataSource(datasource: DSInput!): DSResponse! @authorized - updateDashboard(dashboard: updateDBInput): String! @authorized + updateDashboard(dashboard: updateDBInput! + chaosQueryUpdate: Boolean!): String! @authorized updatePanel(panelInput: [panel]): String! @authorized @@ -5296,9 +5463,13 @@ type Subscription { getKubeObject(kubeObjectRequest: KubeObjectRequest!): KubeObjectResponse! @authorized + + viewDashboard(promQueries: [promQueryInput!]! + dashboardQueryMap: [queryMapForPanelGroup!]! + dataVariables: dataVars!): dashboardPromResponse! @authorized } `, BuiltIn: false}, - &ast.Source{Name: "graph/usage.graphqls", Input: `type WorkflowStat { + {Name: "graph/usage.graphqls", Input: `type WorkflowStat { Schedules : Int! Runs : Int! ExpRuns : Int! @@ -5364,7 +5535,7 @@ input UsageQuery{ Sort: UsageSortInput SearchProject: String }`, BuiltIn: false}, - &ast.Source{Name: "graph/usermanagement.graphqls", Input: `type User { + {Name: "graph/usermanagement.graphqls", Input: `type User { id: ID! username: String! email: String @@ -5395,7 +5566,7 @@ input UpdateUserInput { company_name: String } `, BuiltIn: false}, - &ast.Source{Name: "graph/workflow.graphqls", Input: `enum WorkflowRunStatus { + {Name: "graph/workflow.graphqls", Input: `enum WorkflowRunStatus { All Failed Running @@ -6033,14 +6204,22 @@ func (ec *executionContext) field_Mutation_updateChaosWorkflow_args(ctx context. func (ec *executionContext) field_Mutation_updateDashboard_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { var err error args := map[string]interface{}{} - var arg0 *model.UpdateDBInput + var arg0 model.UpdateDBInput if tmp, ok := rawArgs["dashboard"]; ok { - arg0, err = ec.unmarshalOupdateDBInput2ᚖgithubᚗcomᚋlitmuschaosᚋlitmusᚋlitmusᚑportalᚋgraphqlᚑserverᚋgraphᚋmodelᚐUpdateDBInput(ctx, tmp) + arg0, err = ec.unmarshalNupdateDBInput2githubᚗcomᚋlitmuschaosᚋlitmusᚋlitmusᚑportalᚋgraphqlᚑserverᚋgraphᚋmodelᚐUpdateDBInput(ctx, tmp) if err != nil { return nil, err } } args["dashboard"] = arg0 + var arg1 bool + if tmp, ok := rawArgs["chaosQueryUpdate"]; ok { + arg1, err = ec.unmarshalNBoolean2bool(ctx, tmp) + if err != nil { + return nil, err + } + } + args["chaosQueryUpdate"] = arg1 return args, nil } @@ -6313,6 +6492,22 @@ func (ec *executionContext) field_Query_ListDashboard_args(ctx context.Context, } } args["project_id"] = arg0 + var arg1 *string + if tmp, ok := rawArgs["cluster_id"]; ok { + arg1, err = ec.unmarshalOString2ᚖstring(ctx, tmp) + if err != nil { + return nil, err + } + } + args["cluster_id"] = arg1 + var arg2 *string + if tmp, ok := rawArgs["db_id"]; ok { + arg2, err = ec.unmarshalOString2ᚖstring(ctx, tmp) + if err != nil { + return nil, err + } + } + args["db_id"] = arg2 return args, nil } @@ -6694,6 +6889,36 @@ func (ec *executionContext) field_Subscription_getPodLog_args(ctx context.Contex return args, nil } +func (ec *executionContext) field_Subscription_viewDashboard_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { + var err error + args := map[string]interface{}{} + var arg0 []*model.PromQueryInput + if tmp, ok := rawArgs["promQueries"]; ok { + arg0, err = ec.unmarshalNpromQueryInput2ᚕᚖgithubᚗcomᚋlitmuschaosᚋlitmusᚋlitmusᚑportalᚋgraphqlᚑserverᚋgraphᚋmodelᚐPromQueryInputᚄ(ctx, tmp) + if err != nil { + return nil, err + } + } + args["promQueries"] = arg0 + var arg1 []*model.QueryMapForPanelGroup + if tmp, ok := rawArgs["dashboardQueryMap"]; ok { + arg1, err = ec.unmarshalNqueryMapForPanelGroup2ᚕᚖgithubᚗcomᚋlitmuschaosᚋlitmusᚋlitmusᚑportalᚋgraphqlᚑserverᚋgraphᚋmodelᚐQueryMapForPanelGroupᚄ(ctx, tmp) + if err != nil { + return nil, err + } + } + args["dashboardQueryMap"] = arg1 + var arg2 model.DataVars + if tmp, ok := rawArgs["dataVariables"]; ok { + arg2, err = ec.unmarshalNdataVars2githubᚗcomᚋlitmuschaosᚋlitmusᚋlitmusᚑportalᚋgraphqlᚑserverᚋgraphᚋmodelᚐDataVars(ctx, tmp) + if err != nil { + return nil, err + } + } + args["dataVariables"] = arg2 + return args, nil +} + func (ec *executionContext) field_Subscription_workflowEventListener_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { var err error args := map[string]interface{}{} @@ -12756,7 +12981,7 @@ func (ec *executionContext) _Mutation_updateDashboard(ctx context.Context, field 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().UpdateDashboard(rctx, args["dashboard"].(*model.UpdateDBInput)) + return ec.resolvers.Mutation().UpdateDashboard(rctx, args["dashboard"].(model.UpdateDBInput), args["chaosQueryUpdate"].(bool)) } directive1 := func(ctx context.Context) (interface{}, error) { if ec.directives.Authorized == nil { @@ -16257,7 +16482,7 @@ func (ec *executionContext) _Query_ListDashboard(ctx context.Context, field grap 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.Query().ListDashboard(rctx, args["project_id"].(string)) + return ec.resolvers.Query().ListDashboard(rctx, args["project_id"].(string), args["cluster_id"].(*string), args["db_id"].(*string)) } directive1 := func(ctx context.Context) (interface{}, error) { if ec.directives.Authorized == nil { @@ -18101,6 +18326,77 @@ func (ec *executionContext) _Subscription_getKubeObject(ctx context.Context, fie } } +func (ec *executionContext) _Subscription_viewDashboard(ctx context.Context, field graphql.CollectedField) (ret func() graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = nil + } + }() + fc := &graphql.FieldContext{ + Object: "Subscription", + Field: field, + Args: nil, + IsMethod: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + rawArgs := field.ArgumentMap(ec.Variables) + args, err := ec.field_Subscription_viewDashboard_args(ctx, rawArgs) + if err != nil { + ec.Error(ctx, err) + return nil + } + 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.Subscription().ViewDashboard(rctx, args["promQueries"].([]*model.PromQueryInput), args["dashboardQueryMap"].([]*model.QueryMapForPanelGroup), args["dataVariables"].(model.DataVars)) + } + 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.(<-chan *model.DashboardPromResponse); ok { + return data, nil + } + return nil, fmt.Errorf(`unexpected type %T from directive, should be <-chan *github.com/litmuschaos/litmus/litmus-portal/graphql-server/graph/model.DashboardPromResponse`, tmp) + }) + if err != nil { + ec.Error(ctx, err) + return nil + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return nil + } + return func() graphql.Marshaler { + res, ok := <-resTmp.(<-chan *model.DashboardPromResponse) + if !ok { + return nil + } + return graphql.WriterFunc(func(w io.Writer) { + w.Write([]byte{'{'}) + graphql.MarshalString(field.Alias).MarshalGQL(w) + w.Write([]byte{':'}) + ec.marshalNdashboardPromResponse2ᚖgithubᚗcomᚋlitmuschaosᚋlitmusᚋlitmusᚑportalᚋgraphqlᚑserverᚋgraphᚋmodelᚐDashboardPromResponse(ctx, field.Selections, res).MarshalGQL(w) + w.Write([]byte{'}'}) + }) + } +} + func (ec *executionContext) _TotalCount_Projects(ctx context.Context, field graphql.CollectedField, obj *model.TotalCount) (ret graphql.Marshaler) { defer func() { if r := recover(); r != nil { @@ -21880,6 +22176,37 @@ func (ec *executionContext) _annotationsPromResponse_tsvs(ctx context.Context, f return ec.marshalOannotationsTimeStampValue2ᚕᚕᚖgithubᚗcomᚋlitmuschaosᚋlitmusᚋlitmusᚑportalᚋgraphqlᚑserverᚋgraphᚋmodelᚐAnnotationsTimeStampValue(ctx, field.Selections, res) } +func (ec *executionContext) _annotationsPromResponse_subDataArray(ctx context.Context, field graphql.CollectedField, obj *model.AnnotationsPromResponse) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "annotationsPromResponse", + Field: field, + Args: nil, + IsMethod: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.SubDataArray, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.([][]*model.SubData) + fc.Result = res + return ec.marshalOsubData2ᚕᚕᚖgithubᚗcomᚋlitmuschaosᚋlitmusᚋlitmusᚑportalᚋgraphqlᚑserverᚋgraphᚋmodelᚐSubData(ctx, field.Selections, res) +} + func (ec *executionContext) _annotationsTimeStampValue_date(ctx context.Context, field graphql.CollectedField, obj *model.AnnotationsTimeStampValue) (ret graphql.Marshaler) { defer func() { if r := recover(); r != nil { @@ -22109,6 +22436,68 @@ func (ec *executionContext) _clusterRegResponse_cluster_name(ctx context.Context return ec.marshalNString2string(ctx, field.Selections, res) } +func (ec *executionContext) _dashboardPromResponse_dashboardMetricsResponse(ctx context.Context, field graphql.CollectedField, obj *model.DashboardPromResponse) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "dashboardPromResponse", + Field: field, + Args: nil, + IsMethod: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.DashboardMetricsResponse, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.([]*model.MetricDataForPanelGroup) + fc.Result = res + return ec.marshalOmetricDataForPanelGroup2ᚕᚖgithubᚗcomᚋlitmuschaosᚋlitmusᚋlitmusᚑportalᚋgraphqlᚑserverᚋgraphᚋmodelᚐMetricDataForPanelGroup(ctx, field.Selections, res) +} + +func (ec *executionContext) _dashboardPromResponse_annotationsResponse(ctx context.Context, field graphql.CollectedField, obj *model.DashboardPromResponse) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "dashboardPromResponse", + Field: field, + Args: nil, + IsMethod: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.AnnotationsResponse, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.([]*model.AnnotationsPromResponse) + fc.Result = res + return ec.marshalOannotationsPromResponse2ᚕᚖgithubᚗcomᚋlitmuschaosᚋlitmusᚋlitmusᚑportalᚋgraphqlᚑserverᚋgraphᚋmodelᚐAnnotationsPromResponse(ctx, field.Selections, res) +} + func (ec *executionContext) _imageRegistry_is_default(ctx context.Context, field graphql.CollectedField, obj *model.ImageRegistry) (ret graphql.Marshaler) { defer func() { if r := recover(); r != nil { @@ -22793,6 +23182,68 @@ func (ec *executionContext) _listDashboardResponse_ds_type(ctx context.Context, return ec.marshalOString2ᚖstring(ctx, field.Selections, res) } +func (ec *executionContext) _listDashboardResponse_ds_url(ctx context.Context, field graphql.CollectedField, obj *model.ListDashboardResponse) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "listDashboardResponse", + Field: field, + Args: nil, + IsMethod: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.DsURL, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*string) + fc.Result = res + return ec.marshalOString2ᚖstring(ctx, field.Selections, res) +} + +func (ec *executionContext) _listDashboardResponse_ds_health_status(ctx context.Context, field graphql.CollectedField, obj *model.ListDashboardResponse) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "listDashboardResponse", + Field: field, + Args: nil, + IsMethod: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.DsHealthStatus, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*string) + fc.Result = res + return ec.marshalOString2ᚖstring(ctx, field.Selections, res) +} + func (ec *executionContext) _listDashboardResponse_panel_groups(ctx context.Context, field graphql.CollectedField, obj *model.ListDashboardResponse) (ret graphql.Marshaler) { defer func() { if r := recover(); r != nil { @@ -23059,6 +23510,136 @@ func (ec *executionContext) _listDashboardResponse_updated_at(ctx context.Contex return ec.marshalOString2ᚖstring(ctx, field.Selections, res) } +func (ec *executionContext) _metricDataForPanel_panelID(ctx context.Context, field graphql.CollectedField, obj *model.MetricDataForPanel) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "metricDataForPanel", + Field: field, + Args: nil, + IsMethod: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.PanelID, nil + }) + 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.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _metricDataForPanel_PanelMetricsResponse(ctx context.Context, field graphql.CollectedField, obj *model.MetricDataForPanel) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "metricDataForPanel", + Field: field, + Args: nil, + IsMethod: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.PanelMetricsResponse, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.([]*model.MetricsPromResponse) + fc.Result = res + return ec.marshalOmetricsPromResponse2ᚕᚖgithubᚗcomᚋlitmuschaosᚋlitmusᚋlitmusᚑportalᚋgraphqlᚑserverᚋgraphᚋmodelᚐMetricsPromResponse(ctx, field.Selections, res) +} + +func (ec *executionContext) _metricDataForPanelGroup_panelGroupID(ctx context.Context, field graphql.CollectedField, obj *model.MetricDataForPanelGroup) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "metricDataForPanelGroup", + Field: field, + Args: nil, + IsMethod: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.PanelGroupID, nil + }) + 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.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _metricDataForPanelGroup_panelGroupMetricsResponse(ctx context.Context, field graphql.CollectedField, obj *model.MetricDataForPanelGroup) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "metricDataForPanelGroup", + Field: field, + Args: nil, + IsMethod: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.PanelGroupMetricsResponse, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.([]*model.MetricDataForPanel) + fc.Result = res + return ec.marshalOmetricDataForPanel2ᚕᚖgithubᚗcomᚋlitmuschaosᚋlitmusᚋlitmusᚑportalᚋgraphqlᚑserverᚋgraphᚋmodelᚐMetricDataForPanel(ctx, field.Selections, res) +} + func (ec *executionContext) _metricsPromResponse_queryid(ctx context.Context, field graphql.CollectedField, obj *model.MetricsPromResponse) (ret graphql.Marshaler) { defer func() { if r := recover(); r != nil { @@ -24165,6 +24746,105 @@ func (ec *executionContext) _resourceResponse_names(ctx context.Context, field g return ec.marshalOString2ᚕᚖstring(ctx, field.Selections, res) } +func (ec *executionContext) _subData_date(ctx context.Context, field graphql.CollectedField, obj *model.SubData) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "subData", + Field: field, + Args: nil, + IsMethod: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Date, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*float64) + fc.Result = res + return ec.marshalOFloat2ᚖfloat64(ctx, field.Selections, res) +} + +func (ec *executionContext) _subData_value(ctx context.Context, field graphql.CollectedField, obj *model.SubData) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "subData", + Field: field, + Args: nil, + IsMethod: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Value, nil + }) + 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.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _subData_subDataName(ctx context.Context, field graphql.CollectedField, obj *model.SubData) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "subData", + Field: field, + Args: nil, + IsMethod: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.SubDataName, nil + }) + 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.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + func (ec *executionContext) _weightages_experiment_name(ctx context.Context, field graphql.CollectedField, obj *model.Weightages) (ret graphql.Marshaler) { defer func() { if r := recover(); r != nil { @@ -25749,6 +26429,48 @@ func (ec *executionContext) unmarshalInputcreateDBInput(ctx context.Context, obj return it, nil } +func (ec *executionContext) unmarshalInputdataVars(ctx context.Context, obj interface{}) (model.DataVars, error) { + var it model.DataVars + var asMap = obj.(map[string]interface{}) + + for k, v := range asMap { + switch k { + case "url": + var err error + it.URL, err = ec.unmarshalNString2string(ctx, v) + if err != nil { + return it, err + } + case "start": + var err error + it.Start, err = ec.unmarshalNString2string(ctx, v) + if err != nil { + return it, err + } + case "end": + var err error + it.End, err = ec.unmarshalNString2string(ctx, v) + if err != nil { + return it, err + } + case "relative_time": + var err error + it.RelativeTime, err = ec.unmarshalNInt2int(ctx, v) + if err != nil { + return it, err + } + case "refresh_interval": + var err error + it.RefreshInterval, err = ec.unmarshalNInt2int(ctx, v) + if err != nil { + return it, err + } + } + } + + return it, nil +} + func (ec *executionContext) unmarshalInputdeleteDSInput(ctx context.Context, obj interface{}) (model.DeleteDSInput, error) { var it model.DeleteDSInput var asMap = obj.(map[string]interface{}) @@ -26133,6 +26855,54 @@ func (ec *executionContext) unmarshalInputpromSeriesInput(ctx context.Context, o return it, nil } +func (ec *executionContext) unmarshalInputqueryMapForPanel(ctx context.Context, obj interface{}) (model.QueryMapForPanel, error) { + var it model.QueryMapForPanel + var asMap = obj.(map[string]interface{}) + + for k, v := range asMap { + switch k { + case "panelID": + var err error + it.PanelID, err = ec.unmarshalNString2string(ctx, v) + if err != nil { + return it, err + } + case "queryIDs": + var err error + it.QueryIDs, err = ec.unmarshalNString2ᚕstringᚄ(ctx, v) + if err != nil { + return it, err + } + } + } + + return it, nil +} + +func (ec *executionContext) unmarshalInputqueryMapForPanelGroup(ctx context.Context, obj interface{}) (model.QueryMapForPanelGroup, error) { + var it model.QueryMapForPanelGroup + var asMap = obj.(map[string]interface{}) + + for k, v := range asMap { + switch k { + case "panelGroupID": + var err error + it.PanelGroupID, err = ec.unmarshalNString2string(ctx, v) + if err != nil { + return it, err + } + case "panelQueryMap": + var err error + it.PanelQueryMap, err = ec.unmarshalNqueryMapForPanel2ᚕᚖgithubᚗcomᚋlitmuschaosᚋlitmusᚋlitmusᚑportalᚋgraphqlᚑserverᚋgraphᚋmodelᚐQueryMapForPanelᚄ(ctx, v) + if err != nil { + return it, err + } + } + } + + return it, nil +} + func (ec *executionContext) unmarshalInputresource(ctx context.Context, obj interface{}) (model.Resource, error) { var it model.Resource var asMap = obj.(map[string]interface{}) @@ -26171,25 +26941,25 @@ func (ec *executionContext) unmarshalInputupdateDBInput(ctx context.Context, obj } case "ds_id": var err error - it.DsID, err = ec.unmarshalNString2string(ctx, v) + it.DsID, err = ec.unmarshalOString2ᚖstring(ctx, v) if err != nil { return it, err } case "db_name": var err error - it.DbName, err = ec.unmarshalNString2string(ctx, v) + it.DbName, err = ec.unmarshalOString2ᚖstring(ctx, v) if err != nil { return it, err } case "db_type_name": var err error - it.DbTypeName, err = ec.unmarshalNString2string(ctx, v) + it.DbTypeName, err = ec.unmarshalOString2ᚖstring(ctx, v) if err != nil { return it, err } case "db_type_id": var err error - it.DbTypeID, err = ec.unmarshalNString2string(ctx, v) + it.DbTypeID, err = ec.unmarshalOString2ᚖstring(ctx, v) if err != nil { return it, err } @@ -26201,13 +26971,13 @@ func (ec *executionContext) unmarshalInputupdateDBInput(ctx context.Context, obj } case "chaos_event_query_template": var err error - it.ChaosEventQueryTemplate, err = ec.unmarshalNString2string(ctx, v) + it.ChaosEventQueryTemplate, err = ec.unmarshalOString2ᚖstring(ctx, v) if err != nil { return it, err } case "chaos_verdict_query_template": var err error - it.ChaosVerdictQueryTemplate, err = ec.unmarshalNString2string(ctx, v) + it.ChaosVerdictQueryTemplate, err = ec.unmarshalOString2ᚖstring(ctx, v) if err != nil { return it, err } @@ -26219,31 +26989,31 @@ func (ec *executionContext) unmarshalInputupdateDBInput(ctx context.Context, obj } case "panel_groups": var err error - it.PanelGroups, err = ec.unmarshalNupdatePanelGroupInput2ᚕᚖgithubᚗcomᚋlitmuschaosᚋlitmusᚋlitmusᚑportalᚋgraphqlᚑserverᚋgraphᚋmodelᚐUpdatePanelGroupInput(ctx, v) + it.PanelGroups, err = ec.unmarshalOupdatePanelGroupInput2ᚕᚖgithubᚗcomᚋlitmuschaosᚋlitmusᚋlitmusᚑportalᚋgraphqlᚑserverᚋgraphᚋmodelᚐUpdatePanelGroupInput(ctx, v) if err != nil { return it, err } case "end_time": var err error - it.EndTime, err = ec.unmarshalNString2string(ctx, v) + it.EndTime, err = ec.unmarshalOString2ᚖstring(ctx, v) if err != nil { return it, err } case "start_time": var err error - it.StartTime, err = ec.unmarshalNString2string(ctx, v) + it.StartTime, err = ec.unmarshalOString2ᚖstring(ctx, v) if err != nil { return it, err } case "cluster_id": var err error - it.ClusterID, err = ec.unmarshalNID2string(ctx, v) + it.ClusterID, err = ec.unmarshalOID2ᚖstring(ctx, v) if err != nil { return it, err } case "refresh_rate": var err error - it.RefreshRate, err = ec.unmarshalNString2string(ctx, v) + it.RefreshRate, err = ec.unmarshalOString2ᚖstring(ctx, v) if err != nil { return it, err } @@ -28647,6 +29417,8 @@ func (ec *executionContext) _Subscription(ctx context.Context, sel ast.Selection return ec._Subscription_clusterConnect(ctx, fields[0]) case "getKubeObject": return ec._Subscription_getKubeObject(ctx, fields[0]) + case "viewDashboard": + return ec._Subscription_viewDashboard(ctx, fields[0]) default: panic("unknown field " + strconv.Quote(fields[0].Name)) } @@ -29496,6 +30268,8 @@ func (ec *executionContext) _annotationsPromResponse(ctx context.Context, sel as out.Values[i] = ec._annotationsPromResponse_legends(ctx, field, obj) case "tsvs": out.Values[i] = ec._annotationsPromResponse_tsvs(ctx, field, obj) + case "subDataArray": + out.Values[i] = ec._annotationsPromResponse_subDataArray(ctx, field, obj) default: panic("unknown field " + strconv.Quote(field.Name)) } @@ -29599,6 +30373,32 @@ func (ec *executionContext) _clusterRegResponse(ctx context.Context, sel ast.Sel return out } +var dashboardPromResponseImplementors = []string{"dashboardPromResponse"} + +func (ec *executionContext) _dashboardPromResponse(ctx context.Context, sel ast.SelectionSet, obj *model.DashboardPromResponse) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, dashboardPromResponseImplementors) + + out := graphql.NewFieldSet(fields) + var invalids uint32 + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("dashboardPromResponse") + case "dashboardMetricsResponse": + out.Values[i] = ec._dashboardPromResponse_dashboardMetricsResponse(ctx, field, obj) + case "annotationsResponse": + out.Values[i] = ec._dashboardPromResponse_annotationsResponse(ctx, field, obj) + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch() + if invalids > 0 { + return graphql.Null + } + return out +} + var imageRegistryImplementors = []string{"imageRegistry"} func (ec *executionContext) _imageRegistry(ctx context.Context, sel ast.SelectionSet, obj *model.ImageRegistry) graphql.Marshaler { @@ -29729,6 +30529,10 @@ func (ec *executionContext) _listDashboardResponse(ctx context.Context, sel ast. out.Values[i] = ec._listDashboardResponse_ds_name(ctx, field, obj) case "ds_type": out.Values[i] = ec._listDashboardResponse_ds_type(ctx, field, obj) + case "ds_url": + out.Values[i] = ec._listDashboardResponse_ds_url(ctx, field, obj) + case "ds_health_status": + out.Values[i] = ec._listDashboardResponse_ds_health_status(ctx, field, obj) case "panel_groups": out.Values[i] = ec._listDashboardResponse_panel_groups(ctx, field, obj) if out.Values[i] == graphql.Null { @@ -29774,6 +30578,64 @@ func (ec *executionContext) _listDashboardResponse(ctx context.Context, sel ast. return out } +var metricDataForPanelImplementors = []string{"metricDataForPanel"} + +func (ec *executionContext) _metricDataForPanel(ctx context.Context, sel ast.SelectionSet, obj *model.MetricDataForPanel) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, metricDataForPanelImplementors) + + out := graphql.NewFieldSet(fields) + var invalids uint32 + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("metricDataForPanel") + case "panelID": + out.Values[i] = ec._metricDataForPanel_panelID(ctx, field, obj) + if out.Values[i] == graphql.Null { + invalids++ + } + case "PanelMetricsResponse": + out.Values[i] = ec._metricDataForPanel_PanelMetricsResponse(ctx, field, obj) + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch() + if invalids > 0 { + return graphql.Null + } + return out +} + +var metricDataForPanelGroupImplementors = []string{"metricDataForPanelGroup"} + +func (ec *executionContext) _metricDataForPanelGroup(ctx context.Context, sel ast.SelectionSet, obj *model.MetricDataForPanelGroup) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, metricDataForPanelGroupImplementors) + + out := graphql.NewFieldSet(fields) + var invalids uint32 + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("metricDataForPanelGroup") + case "panelGroupID": + out.Values[i] = ec._metricDataForPanelGroup_panelGroupID(ctx, field, obj) + if out.Values[i] == graphql.Null { + invalids++ + } + case "panelGroupMetricsResponse": + out.Values[i] = ec._metricDataForPanelGroup_panelGroupMetricsResponse(ctx, field, obj) + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch() + if invalids > 0 { + return graphql.Null + } + return out +} + var metricsPromResponseImplementors = []string{"metricsPromResponse"} func (ec *executionContext) _metricsPromResponse(ctx context.Context, sel ast.SelectionSet, obj *model.MetricsPromResponse) graphql.Marshaler { @@ -30107,6 +30969,40 @@ func (ec *executionContext) _resourceResponse(ctx context.Context, sel ast.Selec return out } +var subDataImplementors = []string{"subData"} + +func (ec *executionContext) _subData(ctx context.Context, sel ast.SelectionSet, obj *model.SubData) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, subDataImplementors) + + out := graphql.NewFieldSet(fields) + var invalids uint32 + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("subData") + case "date": + out.Values[i] = ec._subData_date(ctx, field, obj) + case "value": + out.Values[i] = ec._subData_value(ctx, field, obj) + if out.Values[i] == graphql.Null { + invalids++ + } + case "subDataName": + out.Values[i] = ec._subData_subDataName(ctx, field, obj) + if out.Values[i] == graphql.Null { + invalids++ + } + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch() + if invalids > 0 { + return graphql.Null + } + return out +} + var weightagesImplementors = []string{"weightages"} func (ec *executionContext) _weightages(ctx context.Context, sel ast.SelectionSet, obj *model.Weightages) graphql.Marshaler { @@ -31896,6 +32792,24 @@ func (ec *executionContext) marshalNclusterRegResponse2ᚖgithubᚗcomᚋlitmusc return ec._clusterRegResponse(ctx, sel, v) } +func (ec *executionContext) marshalNdashboardPromResponse2githubᚗcomᚋlitmuschaosᚋlitmusᚋlitmusᚑportalᚋgraphqlᚑserverᚋgraphᚋmodelᚐDashboardPromResponse(ctx context.Context, sel ast.SelectionSet, v model.DashboardPromResponse) graphql.Marshaler { + return ec._dashboardPromResponse(ctx, sel, &v) +} + +func (ec *executionContext) marshalNdashboardPromResponse2ᚖgithubᚗcomᚋlitmuschaosᚋlitmusᚋlitmusᚑportalᚋgraphqlᚑserverᚋgraphᚋmodelᚐDashboardPromResponse(ctx context.Context, sel ast.SelectionSet, v *model.DashboardPromResponse) graphql.Marshaler { + if v == nil { + if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + return ec._dashboardPromResponse(ctx, sel, v) +} + +func (ec *executionContext) unmarshalNdataVars2githubᚗcomᚋlitmuschaosᚋlitmusᚋlitmusᚑportalᚋgraphqlᚑserverᚋgraphᚋmodelᚐDataVars(ctx context.Context, v interface{}) (model.DataVars, error) { + return ec.unmarshalInputdataVars(ctx, v) +} + func (ec *executionContext) unmarshalNdeleteDSInput2githubᚗcomᚋlitmuschaosᚋlitmusᚋlitmusᚑportalᚋgraphqlᚑserverᚋgraphᚋmodelᚐDeleteDSInput(ctx context.Context, v interface{}) (model.DeleteDSInput, error) { return ec.unmarshalInputdeleteDSInput(ctx, v) } @@ -31987,6 +32901,38 @@ func (ec *executionContext) marshalNpanelGroupResponse2ᚕᚖgithubᚗcomᚋlitm return ret } +func (ec *executionContext) unmarshalNpromQueryInput2githubᚗcomᚋlitmuschaosᚋlitmusᚋlitmusᚑportalᚋgraphqlᚑserverᚋgraphᚋmodelᚐPromQueryInput(ctx context.Context, v interface{}) (model.PromQueryInput, error) { + return ec.unmarshalInputpromQueryInput(ctx, v) +} + +func (ec *executionContext) unmarshalNpromQueryInput2ᚕᚖgithubᚗcomᚋlitmuschaosᚋlitmusᚋlitmusᚑportalᚋgraphqlᚑserverᚋgraphᚋmodelᚐPromQueryInputᚄ(ctx context.Context, v interface{}) ([]*model.PromQueryInput, error) { + var vSlice []interface{} + if v != nil { + if tmp1, ok := v.([]interface{}); ok { + vSlice = tmp1 + } else { + vSlice = []interface{}{v} + } + } + var err error + res := make([]*model.PromQueryInput, len(vSlice)) + for i := range vSlice { + res[i], err = ec.unmarshalNpromQueryInput2ᚖgithubᚗcomᚋlitmuschaosᚋlitmusᚋlitmusᚑportalᚋgraphqlᚑserverᚋgraphᚋmodelᚐPromQueryInput(ctx, vSlice[i]) + if err != nil { + return nil, err + } + } + return res, nil +} + +func (ec *executionContext) unmarshalNpromQueryInput2ᚖgithubᚗcomᚋlitmuschaosᚋlitmusᚋlitmusᚑportalᚋgraphqlᚑserverᚋgraphᚋmodelᚐPromQueryInput(ctx context.Context, v interface{}) (*model.PromQueryInput, error) { + if v == nil { + return nil, nil + } + res, err := ec.unmarshalNpromQueryInput2githubᚗcomᚋlitmuschaosᚋlitmusᚋlitmusᚑportalᚋgraphqlᚑserverᚋgraphᚋmodelᚐPromQueryInput(ctx, v) + return &res, err +} + func (ec *executionContext) marshalNpromResponse2githubᚗcomᚋlitmuschaosᚋlitmusᚋlitmusᚑportalᚋgraphqlᚑserverᚋgraphᚋmodelᚐPromResponse(ctx context.Context, sel ast.SelectionSet, v model.PromResponse) graphql.Marshaler { return ec._promResponse(ctx, sel, &v) } @@ -32029,7 +32975,11 @@ func (ec *executionContext) marshalNpromSeriesResponse2ᚖgithubᚗcomᚋlitmusc return ec._promSeriesResponse(ctx, sel, v) } -func (ec *executionContext) unmarshalNupdatePanelGroupInput2ᚕᚖgithubᚗcomᚋlitmuschaosᚋlitmusᚋlitmusᚑportalᚋgraphqlᚑserverᚋgraphᚋmodelᚐUpdatePanelGroupInput(ctx context.Context, v interface{}) ([]*model.UpdatePanelGroupInput, error) { +func (ec *executionContext) unmarshalNqueryMapForPanel2githubᚗcomᚋlitmuschaosᚋlitmusᚋlitmusᚑportalᚋgraphqlᚑserverᚋgraphᚋmodelᚐQueryMapForPanel(ctx context.Context, v interface{}) (model.QueryMapForPanel, error) { + return ec.unmarshalInputqueryMapForPanel(ctx, v) +} + +func (ec *executionContext) unmarshalNqueryMapForPanel2ᚕᚖgithubᚗcomᚋlitmuschaosᚋlitmusᚋlitmusᚑportalᚋgraphqlᚑserverᚋgraphᚋmodelᚐQueryMapForPanelᚄ(ctx context.Context, v interface{}) ([]*model.QueryMapForPanel, error) { var vSlice []interface{} if v != nil { if tmp1, ok := v.([]interface{}); ok { @@ -32039,9 +32989,9 @@ func (ec *executionContext) unmarshalNupdatePanelGroupInput2ᚕᚖgithubᚗcom } } var err error - res := make([]*model.UpdatePanelGroupInput, len(vSlice)) + res := make([]*model.QueryMapForPanel, len(vSlice)) for i := range vSlice { - res[i], err = ec.unmarshalOupdatePanelGroupInput2ᚖgithubᚗcomᚋlitmuschaosᚋlitmusᚋlitmusᚑportalᚋgraphqlᚑserverᚋgraphᚋmodelᚐUpdatePanelGroupInput(ctx, vSlice[i]) + res[i], err = ec.unmarshalNqueryMapForPanel2ᚖgithubᚗcomᚋlitmuschaosᚋlitmusᚋlitmusᚑportalᚋgraphqlᚑserverᚋgraphᚋmodelᚐQueryMapForPanel(ctx, vSlice[i]) if err != nil { return nil, err } @@ -32049,6 +32999,50 @@ func (ec *executionContext) unmarshalNupdatePanelGroupInput2ᚕᚖgithubᚗcom return res, nil } +func (ec *executionContext) unmarshalNqueryMapForPanel2ᚖgithubᚗcomᚋlitmuschaosᚋlitmusᚋlitmusᚑportalᚋgraphqlᚑserverᚋgraphᚋmodelᚐQueryMapForPanel(ctx context.Context, v interface{}) (*model.QueryMapForPanel, error) { + if v == nil { + return nil, nil + } + res, err := ec.unmarshalNqueryMapForPanel2githubᚗcomᚋlitmuschaosᚋlitmusᚋlitmusᚑportalᚋgraphqlᚑserverᚋgraphᚋmodelᚐQueryMapForPanel(ctx, v) + return &res, err +} + +func (ec *executionContext) unmarshalNqueryMapForPanelGroup2githubᚗcomᚋlitmuschaosᚋlitmusᚋlitmusᚑportalᚋgraphqlᚑserverᚋgraphᚋmodelᚐQueryMapForPanelGroup(ctx context.Context, v interface{}) (model.QueryMapForPanelGroup, error) { + return ec.unmarshalInputqueryMapForPanelGroup(ctx, v) +} + +func (ec *executionContext) unmarshalNqueryMapForPanelGroup2ᚕᚖgithubᚗcomᚋlitmuschaosᚋlitmusᚋlitmusᚑportalᚋgraphqlᚑserverᚋgraphᚋmodelᚐQueryMapForPanelGroupᚄ(ctx context.Context, v interface{}) ([]*model.QueryMapForPanelGroup, error) { + var vSlice []interface{} + if v != nil { + if tmp1, ok := v.([]interface{}); ok { + vSlice = tmp1 + } else { + vSlice = []interface{}{v} + } + } + var err error + res := make([]*model.QueryMapForPanelGroup, len(vSlice)) + for i := range vSlice { + res[i], err = ec.unmarshalNqueryMapForPanelGroup2ᚖgithubᚗcomᚋlitmuschaosᚋlitmusᚋlitmusᚑportalᚋgraphqlᚑserverᚋgraphᚋmodelᚐQueryMapForPanelGroup(ctx, vSlice[i]) + if err != nil { + return nil, err + } + } + return res, nil +} + +func (ec *executionContext) unmarshalNqueryMapForPanelGroup2ᚖgithubᚗcomᚋlitmuschaosᚋlitmusᚋlitmusᚑportalᚋgraphqlᚑserverᚋgraphᚋmodelᚐQueryMapForPanelGroup(ctx context.Context, v interface{}) (*model.QueryMapForPanelGroup, error) { + if v == nil { + return nil, nil + } + res, err := ec.unmarshalNqueryMapForPanelGroup2githubᚗcomᚋlitmuschaosᚋlitmusᚋlitmusᚑportalᚋgraphqlᚑserverᚋgraphᚋmodelᚐQueryMapForPanelGroup(ctx, v) + return &res, err +} + +func (ec *executionContext) unmarshalNupdateDBInput2githubᚗcomᚋlitmuschaosᚋlitmusᚋlitmusᚑportalᚋgraphqlᚑserverᚋgraphᚋmodelᚐUpdateDBInput(ctx context.Context, v interface{}) (model.UpdateDBInput, error) { + return ec.unmarshalInputupdateDBInput(ctx, v) +} + func (ec *executionContext) marshalNweightages2githubᚗcomᚋlitmuschaosᚋlitmusᚋlitmusᚑportalᚋgraphqlᚑserverᚋgraphᚋmodelᚐWeightages(ctx context.Context, sel ast.SelectionSet, v model.Weightages) graphql.Marshaler { return ec._weightages(ctx, sel, &v) } @@ -33227,6 +34221,108 @@ func (ec *executionContext) marshalOlistDashboardResponse2ᚖgithubᚗcomᚋlitm return ec._listDashboardResponse(ctx, sel, v) } +func (ec *executionContext) marshalOmetricDataForPanel2githubᚗcomᚋlitmuschaosᚋlitmusᚋlitmusᚑportalᚋgraphqlᚑserverᚋgraphᚋmodelᚐMetricDataForPanel(ctx context.Context, sel ast.SelectionSet, v model.MetricDataForPanel) graphql.Marshaler { + return ec._metricDataForPanel(ctx, sel, &v) +} + +func (ec *executionContext) marshalOmetricDataForPanel2ᚕᚖgithubᚗcomᚋlitmuschaosᚋlitmusᚋlitmusᚑportalᚋgraphqlᚑserverᚋgraphᚋmodelᚐMetricDataForPanel(ctx context.Context, sel ast.SelectionSet, v []*model.MetricDataForPanel) graphql.Marshaler { + if v == nil { + return graphql.Null + } + ret := make(graphql.Array, len(v)) + var wg sync.WaitGroup + isLen1 := len(v) == 1 + if !isLen1 { + wg.Add(len(v)) + } + for i := range v { + i := i + fc := &graphql.FieldContext{ + Index: &i, + Result: &v[i], + } + ctx := graphql.WithFieldContext(ctx, fc) + f := func(i int) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = nil + } + }() + if !isLen1 { + defer wg.Done() + } + ret[i] = ec.marshalOmetricDataForPanel2ᚖgithubᚗcomᚋlitmuschaosᚋlitmusᚋlitmusᚑportalᚋgraphqlᚑserverᚋgraphᚋmodelᚐMetricDataForPanel(ctx, sel, v[i]) + } + if isLen1 { + f(i) + } else { + go f(i) + } + + } + wg.Wait() + return ret +} + +func (ec *executionContext) marshalOmetricDataForPanel2ᚖgithubᚗcomᚋlitmuschaosᚋlitmusᚋlitmusᚑportalᚋgraphqlᚑserverᚋgraphᚋmodelᚐMetricDataForPanel(ctx context.Context, sel ast.SelectionSet, v *model.MetricDataForPanel) graphql.Marshaler { + if v == nil { + return graphql.Null + } + return ec._metricDataForPanel(ctx, sel, v) +} + +func (ec *executionContext) marshalOmetricDataForPanelGroup2githubᚗcomᚋlitmuschaosᚋlitmusᚋlitmusᚑportalᚋgraphqlᚑserverᚋgraphᚋmodelᚐMetricDataForPanelGroup(ctx context.Context, sel ast.SelectionSet, v model.MetricDataForPanelGroup) graphql.Marshaler { + return ec._metricDataForPanelGroup(ctx, sel, &v) +} + +func (ec *executionContext) marshalOmetricDataForPanelGroup2ᚕᚖgithubᚗcomᚋlitmuschaosᚋlitmusᚋlitmusᚑportalᚋgraphqlᚑserverᚋgraphᚋmodelᚐMetricDataForPanelGroup(ctx context.Context, sel ast.SelectionSet, v []*model.MetricDataForPanelGroup) graphql.Marshaler { + if v == nil { + return graphql.Null + } + ret := make(graphql.Array, len(v)) + var wg sync.WaitGroup + isLen1 := len(v) == 1 + if !isLen1 { + wg.Add(len(v)) + } + for i := range v { + i := i + fc := &graphql.FieldContext{ + Index: &i, + Result: &v[i], + } + ctx := graphql.WithFieldContext(ctx, fc) + f := func(i int) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = nil + } + }() + if !isLen1 { + defer wg.Done() + } + ret[i] = ec.marshalOmetricDataForPanelGroup2ᚖgithubᚗcomᚋlitmuschaosᚋlitmusᚋlitmusᚑportalᚋgraphqlᚑserverᚋgraphᚋmodelᚐMetricDataForPanelGroup(ctx, sel, v[i]) + } + if isLen1 { + f(i) + } else { + go f(i) + } + + } + wg.Wait() + return ret +} + +func (ec *executionContext) marshalOmetricDataForPanelGroup2ᚖgithubᚗcomᚋlitmuschaosᚋlitmusᚋlitmusᚑportalᚋgraphqlᚑserverᚋgraphᚋmodelᚐMetricDataForPanelGroup(ctx context.Context, sel ast.SelectionSet, v *model.MetricDataForPanelGroup) graphql.Marshaler { + if v == nil { + return graphql.Null + } + return ec._metricDataForPanelGroup(ctx, sel, v) +} + func (ec *executionContext) marshalOmetricsPromResponse2githubᚗcomᚋlitmuschaosᚋlitmusᚋlitmusᚑportalᚋgraphqlᚑserverᚋgraphᚋmodelᚐMetricsPromResponse(ctx context.Context, sel ast.SelectionSet, v model.MetricsPromResponse) graphql.Marshaler { return ec._metricsPromResponse(ctx, sel, &v) } @@ -33771,22 +34867,121 @@ func (ec *executionContext) marshalOresourceResponse2ᚖgithubᚗcomᚋlitmuscha return ec._resourceResponse(ctx, sel, v) } -func (ec *executionContext) unmarshalOupdateDBInput2githubᚗcomᚋlitmuschaosᚋlitmusᚋlitmusᚑportalᚋgraphqlᚑserverᚋgraphᚋmodelᚐUpdateDBInput(ctx context.Context, v interface{}) (model.UpdateDBInput, error) { - return ec.unmarshalInputupdateDBInput(ctx, v) +func (ec *executionContext) marshalOsubData2githubᚗcomᚋlitmuschaosᚋlitmusᚋlitmusᚑportalᚋgraphqlᚑserverᚋgraphᚋmodelᚐSubData(ctx context.Context, sel ast.SelectionSet, v model.SubData) graphql.Marshaler { + return ec._subData(ctx, sel, &v) } -func (ec *executionContext) unmarshalOupdateDBInput2ᚖgithubᚗcomᚋlitmuschaosᚋlitmusᚋlitmusᚑportalᚋgraphqlᚑserverᚋgraphᚋmodelᚐUpdateDBInput(ctx context.Context, v interface{}) (*model.UpdateDBInput, error) { +func (ec *executionContext) marshalOsubData2ᚕᚕᚖgithubᚗcomᚋlitmuschaosᚋlitmusᚋlitmusᚑportalᚋgraphqlᚑserverᚋgraphᚋmodelᚐSubData(ctx context.Context, sel ast.SelectionSet, v [][]*model.SubData) graphql.Marshaler { if v == nil { - return nil, nil + return graphql.Null } - res, err := ec.unmarshalOupdateDBInput2githubᚗcomᚋlitmuschaosᚋlitmusᚋlitmusᚑportalᚋgraphqlᚑserverᚋgraphᚋmodelᚐUpdateDBInput(ctx, v) - return &res, err + ret := make(graphql.Array, len(v)) + var wg sync.WaitGroup + isLen1 := len(v) == 1 + if !isLen1 { + wg.Add(len(v)) + } + for i := range v { + i := i + fc := &graphql.FieldContext{ + Index: &i, + Result: &v[i], + } + ctx := graphql.WithFieldContext(ctx, fc) + f := func(i int) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = nil + } + }() + if !isLen1 { + defer wg.Done() + } + ret[i] = ec.marshalOsubData2ᚕᚖgithubᚗcomᚋlitmuschaosᚋlitmusᚋlitmusᚑportalᚋgraphqlᚑserverᚋgraphᚋmodelᚐSubData(ctx, sel, v[i]) + } + if isLen1 { + f(i) + } else { + go f(i) + } + + } + wg.Wait() + return ret +} + +func (ec *executionContext) marshalOsubData2ᚕᚖgithubᚗcomᚋlitmuschaosᚋlitmusᚋlitmusᚑportalᚋgraphqlᚑserverᚋgraphᚋmodelᚐSubData(ctx context.Context, sel ast.SelectionSet, v []*model.SubData) graphql.Marshaler { + if v == nil { + return graphql.Null + } + ret := make(graphql.Array, len(v)) + var wg sync.WaitGroup + isLen1 := len(v) == 1 + if !isLen1 { + wg.Add(len(v)) + } + for i := range v { + i := i + fc := &graphql.FieldContext{ + Index: &i, + Result: &v[i], + } + ctx := graphql.WithFieldContext(ctx, fc) + f := func(i int) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = nil + } + }() + if !isLen1 { + defer wg.Done() + } + ret[i] = ec.marshalOsubData2ᚖgithubᚗcomᚋlitmuschaosᚋlitmusᚋlitmusᚑportalᚋgraphqlᚑserverᚋgraphᚋmodelᚐSubData(ctx, sel, v[i]) + } + if isLen1 { + f(i) + } else { + go f(i) + } + + } + wg.Wait() + return ret +} + +func (ec *executionContext) marshalOsubData2ᚖgithubᚗcomᚋlitmuschaosᚋlitmusᚋlitmusᚑportalᚋgraphqlᚑserverᚋgraphᚋmodelᚐSubData(ctx context.Context, sel ast.SelectionSet, v *model.SubData) graphql.Marshaler { + if v == nil { + return graphql.Null + } + return ec._subData(ctx, sel, v) } func (ec *executionContext) unmarshalOupdatePanelGroupInput2githubᚗcomᚋlitmuschaosᚋlitmusᚋlitmusᚑportalᚋgraphqlᚑserverᚋgraphᚋmodelᚐUpdatePanelGroupInput(ctx context.Context, v interface{}) (model.UpdatePanelGroupInput, error) { return ec.unmarshalInputupdatePanelGroupInput(ctx, v) } +func (ec *executionContext) unmarshalOupdatePanelGroupInput2ᚕᚖgithubᚗcomᚋlitmuschaosᚋlitmusᚋlitmusᚑportalᚋgraphqlᚑserverᚋgraphᚋmodelᚐUpdatePanelGroupInput(ctx context.Context, v interface{}) ([]*model.UpdatePanelGroupInput, error) { + var vSlice []interface{} + if v != nil { + if tmp1, ok := v.([]interface{}); ok { + vSlice = tmp1 + } else { + vSlice = []interface{}{v} + } + } + var err error + res := make([]*model.UpdatePanelGroupInput, len(vSlice)) + for i := range vSlice { + res[i], err = ec.unmarshalOupdatePanelGroupInput2ᚖgithubᚗcomᚋlitmuschaosᚋlitmusᚋlitmusᚑportalᚋgraphqlᚑserverᚋgraphᚋmodelᚐUpdatePanelGroupInput(ctx, vSlice[i]) + if err != nil { + return nil, err + } + } + return res, nil +} + func (ec *executionContext) unmarshalOupdatePanelGroupInput2ᚖgithubᚗcomᚋlitmuschaosᚋlitmusᚋlitmusᚑportalᚋgraphqlᚑserverᚋgraphᚋmodelᚐUpdatePanelGroupInput(ctx context.Context, v interface{}) (*model.UpdatePanelGroupInput, error) { if v == nil { return nil, nil diff --git a/litmus-portal/graphql-server/graph/model/models_gen.go b/litmus-portal/graphql-server/graph/model/models_gen.go index 7ddc39c5b24..332a0b77b40 100644 --- a/litmus-portal/graphql-server/graph/model/models_gen.go +++ b/litmus-portal/graphql-server/graph/model/models_gen.go @@ -699,9 +699,10 @@ type WorkflowStats struct { } type AnnotationsPromResponse struct { - Queryid string `json:"queryid"` - Legends []*string `json:"legends"` - Tsvs [][]*AnnotationsTimeStampValue `json:"tsvs"` + Queryid string `json:"queryid"` + Legends []*string `json:"legends"` + Tsvs [][]*AnnotationsTimeStampValue `json:"tsvs"` + SubDataArray [][]*SubData `json:"subDataArray"` } type AnnotationsTimeStampValue struct { @@ -742,6 +743,19 @@ type CreateDBInput struct { RefreshRate string `json:"refresh_rate"` } +type DashboardPromResponse struct { + DashboardMetricsResponse []*MetricDataForPanelGroup `json:"dashboardMetricsResponse"` + AnnotationsResponse []*AnnotationsPromResponse `json:"annotationsResponse"` +} + +type DataVars struct { + URL string `json:"url"` + Start string `json:"start"` + End string `json:"end"` + RelativeTime int `json:"relative_time"` + RefreshInterval int `json:"refresh_interval"` +} + type DeleteDSInput struct { ForceDelete bool `json:"force_delete"` DsID string `json:"ds_id"` @@ -791,6 +805,8 @@ type ListDashboardResponse struct { ClusterName *string `json:"cluster_name"` DsName *string `json:"ds_name"` DsType *string `json:"ds_type"` + DsURL *string `json:"ds_url"` + DsHealthStatus *string `json:"ds_health_status"` PanelGroups []*PanelGroupResponse `json:"panel_groups"` EndTime string `json:"end_time"` StartTime string `json:"start_time"` @@ -801,6 +817,16 @@ type ListDashboardResponse struct { UpdatedAt *string `json:"updated_at"` } +type MetricDataForPanel struct { + PanelID string `json:"panelID"` + PanelMetricsResponse []*MetricsPromResponse `json:"PanelMetricsResponse"` +} + +type MetricDataForPanelGroup struct { + PanelGroupID string `json:"panelGroupID"` + PanelGroupMetricsResponse []*MetricDataForPanel `json:"panelGroupMetricsResponse"` +} + type MetricsPromResponse struct { Queryid string `json:"queryid"` Legends []*string `json:"legends"` @@ -917,6 +943,16 @@ type PromSeriesResponse struct { LabelValues []*LabelValue `json:"labelValues"` } +type QueryMapForPanel struct { + PanelID string `json:"panelID"` + QueryIDs []string `json:"queryIDs"` +} + +type QueryMapForPanelGroup struct { + PanelGroupID string `json:"panelGroupID"` + PanelQueryMap []*QueryMapForPanel `json:"panelQueryMap"` +} + type Resource struct { Kind string `json:"kind"` Names []*string `json:"names"` @@ -927,21 +963,27 @@ type ResourceResponse struct { Names []*string `json:"names"` } +type SubData struct { + Date *float64 `json:"date"` + Value string `json:"value"` + SubDataName string `json:"subDataName"` +} + type UpdateDBInput struct { DbID string `json:"db_id"` - DsID string `json:"ds_id"` - DbName string `json:"db_name"` - DbTypeName string `json:"db_type_name"` - DbTypeID string `json:"db_type_id"` + DsID *string `json:"ds_id"` + DbName *string `json:"db_name"` + DbTypeName *string `json:"db_type_name"` + DbTypeID *string `json:"db_type_id"` DbInformation *string `json:"db_information"` - ChaosEventQueryTemplate string `json:"chaos_event_query_template"` - ChaosVerdictQueryTemplate string `json:"chaos_verdict_query_template"` + ChaosEventQueryTemplate *string `json:"chaos_event_query_template"` + ChaosVerdictQueryTemplate *string `json:"chaos_verdict_query_template"` ApplicationMetadataMap []*ApplicationMetadata `json:"application_metadata_map"` PanelGroups []*UpdatePanelGroupInput `json:"panel_groups"` - EndTime string `json:"end_time"` - StartTime string `json:"start_time"` - ClusterID string `json:"cluster_id"` - RefreshRate string `json:"refresh_rate"` + EndTime *string `json:"end_time"` + StartTime *string `json:"start_time"` + ClusterID *string `json:"cluster_id"` + RefreshRate *string `json:"refresh_rate"` } type UpdatePanelGroupInput struct { diff --git a/litmus-portal/graphql-server/graph/schema.graphqls b/litmus-portal/graphql-server/graph/schema.graphqls index 6e859a8c681..04421705994 100644 --- a/litmus-portal/graphql-server/graph/schema.graphqls +++ b/litmus-portal/graphql-server/graph/schema.graphqls @@ -307,7 +307,9 @@ type Query { GetPromSeriesList(ds_details: dsDetails): promSeriesListResponse! @authorized - ListDashboard(project_id: String!): [listDashboardResponse] @authorized + ListDashboard(project_id: String! + cluster_id: String + db_id: String): [listDashboardResponse] @authorized PortalDashboardData (project_id: String!, hub_name: String!) : [PortalDashboardData!]! @authorized @@ -418,7 +420,8 @@ type Mutation { updateDataSource(datasource: DSInput!): DSResponse! @authorized - updateDashboard(dashboard: updateDBInput): String! @authorized + updateDashboard(dashboard: updateDBInput! + chaosQueryUpdate: Boolean!): String! @authorized updatePanel(panelInput: [panel]): String! @authorized @@ -461,4 +464,8 @@ type Subscription { getKubeObject(kubeObjectRequest: KubeObjectRequest!): KubeObjectResponse! @authorized + + viewDashboard(promQueries: [promQueryInput!]! + dashboardQueryMap: [queryMapForPanelGroup!]! + dataVariables: dataVars!): dashboardPromResponse! @authorized } diff --git a/litmus-portal/graphql-server/graph/schema.resolvers.go b/litmus-portal/graphql-server/graph/schema.resolvers.go index 722e76cf67c..2b674c16738 100644 --- a/litmus-portal/graphql-server/graph/schema.resolvers.go +++ b/litmus-portal/graphql-server/graph/schema.resolvers.go @@ -252,8 +252,8 @@ func (r *mutationResolver) UpdateDataSource(ctx context.Context, datasource mode return analyticsHandler.UpdateDataSource(datasource) } -func (r *mutationResolver) UpdateDashboard(ctx context.Context, dashboard *model.UpdateDBInput) (string, error) { - return analyticsHandler.UpdateDashBoard(dashboard) +func (r *mutationResolver) UpdateDashboard(ctx context.Context, dashboard model.UpdateDBInput, chaosQueryUpdate bool) (string, error) { + return analyticsHandler.UpdateDashBoard(dashboard, chaosQueryUpdate) } func (r *mutationResolver) UpdatePanel(ctx context.Context, panelInput []*model.Panel) (string, error) { @@ -413,7 +413,8 @@ func (r *queryResolver) ListDataSource(ctx context.Context, projectID string) ([ } func (r *queryResolver) GetPromQuery(ctx context.Context, query *model.PromInput) (*model.PromResponse, error) { - return analyticsHandler.GetPromQuery(query) + promResponseData, _, err := analyticsHandler.GetPromQuery(query) + return promResponseData, err } func (r *queryResolver) GetPromLabelNamesAndValues(ctx context.Context, series *model.PromSeriesInput) (*model.PromSeriesResponse, error) { @@ -424,8 +425,8 @@ func (r *queryResolver) GetPromSeriesList(ctx context.Context, dsDetails *model. return analyticsHandler.GetSeriesList(dsDetails) } -func (r *queryResolver) ListDashboard(ctx context.Context, projectID string) ([]*model.ListDashboardResponse, error) { - return analyticsHandler.QueryListDashboard(projectID) +func (r *queryResolver) ListDashboard(ctx context.Context, projectID string, clusterID *string, dbID *string) ([]*model.ListDashboardResponse, error) { + return analyticsHandler.QueryListDashboard(projectID, clusterID, dbID) } func (r *queryResolver) PortalDashboardData(ctx context.Context, projectID string, hubName string) ([]*model.PortalDashboardData, error) { @@ -587,6 +588,26 @@ func (r *subscriptionResolver) GetKubeObject(ctx context.Context, kubeObjectRequ return kubeObjData, nil } +func (r *subscriptionResolver) ViewDashboard(ctx context.Context, promQueries []*model.PromQueryInput, dashboardQueryMap []*model.QueryMapForPanelGroup, dataVariables model.DataVars) (<-chan *model.DashboardPromResponse, error) { + dashboardData := make(chan *model.DashboardPromResponse) + viewID := uuid.New() + log.Printf("Dashboard view %v created\n", viewID.String()) + data_store.Store.Mutex.Lock() + data_store.Store.DashboardData[viewID.String()] = dashboardData + data_store.Store.Mutex.Unlock() + go func() { + <-ctx.Done() + log.Printf("Closed dashboard view %v\n", viewID.String()) + if _, ok := data_store.Store.DashboardData[viewID.String()]; ok { + data_store.Store.Mutex.Lock() + delete(data_store.Store.DashboardData, viewID.String()) + data_store.Store.Mutex.Unlock() + } + }() + go analyticsHandler.DashboardViewer(viewID.String(), promQueries, dashboardQueryMap, dataVariables, *data_store.Store) + return dashboardData, nil +} + // Mutation returns generated.MutationResolver implementation. func (r *Resolver) Mutation() generated.MutationResolver { return &mutationResolver{r} } diff --git a/litmus-portal/graphql-server/pkg/analytics/handler/handler.go b/litmus-portal/graphql-server/pkg/analytics/handler/handler.go index c3f8acda362..2122d2585a4 100644 --- a/litmus-portal/graphql-server/pkg/analytics/handler/handler.go +++ b/litmus-portal/graphql-server/pkg/analytics/handler/handler.go @@ -13,6 +13,7 @@ import ( "sync" "time" + store "github.com/litmuschaos/litmus/litmus-portal/graphql-server/pkg/data-store" "go.mongodb.org/mongo-driver/mongo" "github.com/google/uuid" @@ -233,222 +234,229 @@ func UpdateDataSource(datasource model.DSInput) (*model.DSResponse, error) { } // UpdateDashBoard function updates the dashboard based on it's ID -func UpdateDashBoard(dashboard *model.UpdateDBInput) (string, error) { +func UpdateDashBoard(dashboard model.UpdateDBInput, chaosQueryUpdate bool) (string, error) { timestamp := strconv.FormatInt(time.Now().Unix(), 10) - if dashboard.DbID == "" || dashboard.DsID == "" { - return "could not find the dashboard or the connected data source", errors.New("dashBoard ID or data source ID is nil or empty") + if dashboard.DbID == "" { + return "could not find the dashboard", errors.New("dashBoard ID is nil or empty") } - var ( - newPanelGroups = make([]dbSchemaAnalytics.PanelGroup, len(dashboard.PanelGroups)) - panelsToCreate []*dbSchemaAnalytics.Panel - panelsToUpdate []*dbSchemaAnalytics.Panel - newApplicationMetadataMap []dbSchemaAnalytics.ApplicationMetadata - updatedDashboardPanelIDs []string - updatedDashboardPanelGroupIDs []string - ) - - for _, applicationMetadata := range dashboard.ApplicationMetadataMap { - var newApplications []*dbSchemaAnalytics.Resource - for _, application := range applicationMetadata.Applications { - newApplication := dbSchemaAnalytics.Resource{ - Kind: application.Kind, - Names: application.Names, - } - newApplications = append(newApplications, &newApplication) - } - newApplicationMetadata := dbSchemaAnalytics.ApplicationMetadata{ - Namespace: applicationMetadata.Namespace, - Applications: newApplications, - } - - newApplicationMetadataMap = append(newApplicationMetadataMap, newApplicationMetadata) + query := bson.D{ + {"db_id", dashboard.DbID}, + {"is_removed", false}, } - for i, panelGroup := range dashboard.PanelGroups { - - var panelGroupID string - - if panelGroup.PanelGroupID == "" { - panelGroupID = uuid.New().String() - } else { - panelGroupID = panelGroup.PanelGroupID - updatedDashboardPanelGroupIDs = append(updatedDashboardPanelGroupIDs, panelGroup.PanelGroupID) - } - - newPanelGroups[i].PanelGroupID = panelGroupID - newPanelGroups[i].PanelGroupName = panelGroup.PanelGroupName - - for _, panel := range panelGroup.Panels { - - var ( - panelID string - createdAt string - updatedAt string - ) - - if *panel.PanelID == "" { - panelID = uuid.New().String() - createdAt = strconv.FormatInt(time.Now().Unix(), 10) - updatedAt = strconv.FormatInt(time.Now().Unix(), 10) - } else { - panelID = *panel.PanelID - createdAt = *panel.CreatedAt - updatedAt = strconv.FormatInt(time.Now().Unix(), 10) - updatedDashboardPanelIDs = append(updatedDashboardPanelIDs, *panel.PanelID) + var update bson.D + + if !chaosQueryUpdate { + var ( + newPanelGroups = make([]dbSchemaAnalytics.PanelGroup, len(dashboard.PanelGroups)) + panelsToCreate []*dbSchemaAnalytics.Panel + panelsToUpdate []*dbSchemaAnalytics.Panel + newApplicationMetadataMap []dbSchemaAnalytics.ApplicationMetadata + updatedDashboardPanelIDs []string + updatedDashboardPanelGroupIDs []string + ) + + for _, applicationMetadata := range dashboard.ApplicationMetadataMap { + var newApplications []*dbSchemaAnalytics.Resource + for _, application := range applicationMetadata.Applications { + newApplication := dbSchemaAnalytics.Resource{ + Kind: application.Kind, + Names: application.Names, + } + newApplications = append(newApplications, &newApplication) } - - var newPromQueries []*dbSchemaAnalytics.PromQuery - err := copier.Copy(&newPromQueries, &panel.PromQueries) - if err != nil { - return "error updating queries", err + newApplicationMetadata := dbSchemaAnalytics.ApplicationMetadata{ + Namespace: applicationMetadata.Namespace, + Applications: newApplications, } - var newPanelOptions dbSchemaAnalytics.PanelOption - err = copier.Copy(&newPanelOptions, &panel.PanelOptions) - if err != nil { - return "error updating options", err - } + newApplicationMetadataMap = append(newApplicationMetadataMap, newApplicationMetadata) + } - newPanel := dbSchemaAnalytics.Panel{ - PanelID: panelID, - PanelOptions: &newPanelOptions, - PanelName: panel.PanelName, - PanelGroupID: panelGroupID, - PromQueries: newPromQueries, - IsRemoved: false, - XAxisDown: panel.XAxisDown, - YAxisLeft: panel.YAxisLeft, - YAxisRight: panel.YAxisRight, - Unit: panel.Unit, - CreatedAt: createdAt, - UpdatedAt: updatedAt, - } + for i, panelGroup := range dashboard.PanelGroups { + + var panelGroupID string - if *panel.PanelID == "" { - panelsToCreate = append(panelsToCreate, &newPanel) + if panelGroup.PanelGroupID == "" { + panelGroupID = uuid.New().String() } else { - panelsToUpdate = append(panelsToUpdate, &newPanel) + panelGroupID = panelGroup.PanelGroupID + updatedDashboardPanelGroupIDs = append(updatedDashboardPanelGroupIDs, panelGroup.PanelGroupID) } - } - } - - query := bson.D{ - {"db_id", dashboard.DbID}, - {"is_removed", false}, - } - existingDashboard, err := dbOperationsAnalytics.GetDashboard(query) - if err != nil { - return "error fetching dashboard details", fmt.Errorf("error on query from dashboard collection by projectid: %v", err) - } - - for _, panelGroup := range existingDashboard.PanelGroups { - query := bson.D{ - {"panel_group_id", panelGroup.PanelGroupID}, - {"is_removed", false}, - } - panels, err := dbOperationsAnalytics.ListPanel(query) - if err != nil { - return "error fetching panels", fmt.Errorf("error on querying from promquery collection: %v", err) - } + newPanelGroups[i].PanelGroupID = panelGroupID + newPanelGroups[i].PanelGroupName = panelGroup.PanelGroupName - var tempPanels []*model.PanelResponse - err = copier.Copy(&tempPanels, &panels) - if err != nil { - return "error fetching panel details", err - } + for _, panel := range panelGroup.Panels { - for _, panel := range tempPanels { + var ( + panelID string + createdAt string + updatedAt string + ) - if !utils.ContainsString(updatedDashboardPanelIDs, panel.PanelID) || !utils.ContainsString(updatedDashboardPanelGroupIDs, panelGroup.PanelGroupID) { + if *panel.PanelID == "" { + panelID = uuid.New().String() + createdAt = strconv.FormatInt(time.Now().Unix(), 10) + updatedAt = strconv.FormatInt(time.Now().Unix(), 10) + } else { + panelID = *panel.PanelID + createdAt = *panel.CreatedAt + updatedAt = strconv.FormatInt(time.Now().Unix(), 10) + updatedDashboardPanelIDs = append(updatedDashboardPanelIDs, *panel.PanelID) + } - var promQueriesInPanelToBeDeleted []*dbSchemaAnalytics.PromQuery - err := copier.Copy(&promQueriesInPanelToBeDeleted, &panel.PromQueries) + var newPromQueries []*dbSchemaAnalytics.PromQuery + err := copier.Copy(&newPromQueries, &panel.PromQueries) if err != nil { return "error updating queries", err } - var panelOptionsOfPanelToBeDeleted dbSchemaAnalytics.PanelOption - err = copier.Copy(&panelOptionsOfPanelToBeDeleted, &panel.PanelOptions) + var newPanelOptions dbSchemaAnalytics.PanelOption + err = copier.Copy(&newPanelOptions, &panel.PanelOptions) if err != nil { return "error updating options", err } - panelToBeDeleted := dbSchemaAnalytics.Panel{ - PanelID: panel.PanelID, - PanelOptions: &panelOptionsOfPanelToBeDeleted, - PanelName: *panel.PanelName, - PanelGroupID: panelGroup.PanelGroupID, - PromQueries: promQueriesInPanelToBeDeleted, - IsRemoved: true, + newPanel := dbSchemaAnalytics.Panel{ + PanelID: panelID, + PanelOptions: &newPanelOptions, + PanelName: panel.PanelName, + PanelGroupID: panelGroupID, + PromQueries: newPromQueries, + IsRemoved: false, XAxisDown: panel.XAxisDown, YAxisLeft: panel.YAxisLeft, YAxisRight: panel.YAxisRight, Unit: panel.Unit, - CreatedAt: *panel.CreatedAt, - UpdatedAt: strconv.FormatInt(time.Now().Unix(), 10), + CreatedAt: createdAt, + UpdatedAt: updatedAt, } - panelsToUpdate = append(panelsToUpdate, &panelToBeDeleted) - + if *panel.PanelID == "" { + panelsToCreate = append(panelsToCreate, &newPanel) + } else { + panelsToUpdate = append(panelsToUpdate, &newPanel) + } } } - } - if len(panelsToCreate) > 0 { - err = dbOperationsAnalytics.InsertPanel(panelsToCreate) + existingDashboard, err := dbOperationsAnalytics.GetDashboard(query) if err != nil { - return "error creating new panels", fmt.Errorf("error while inserting panel data", err) + return "error fetching dashboard details", fmt.Errorf("error on query from dashboard collection by projectid: %v", err) } - log.Print("successfully inserted prom query into promquery-collection") - } - - if len(panelsToUpdate) > 0 { - for _, panel := range panelsToUpdate { - timestamp := strconv.FormatInt(time.Now().Unix(), 10) - if panel.PanelID == "" && panel.PanelGroupID == "" { - return "error getting panel and group details", errors.New("panel ID or panel group ID is nil or empty") + for _, panelGroup := range existingDashboard.PanelGroups { + query := bson.D{ + {"panel_group_id", panelGroup.PanelGroupID}, + {"is_removed", false}, } - - var newPanelOption dbSchemaAnalytics.PanelOption - err := copier.Copy(&newPanelOption, &panel.PanelOptions) + panels, err := dbOperationsAnalytics.ListPanel(query) if err != nil { - return "error updating panel option", err + return "error fetching panels", fmt.Errorf("error on querying from promquery collection: %v", err) } - var newPromQueries []dbSchemaAnalytics.PromQuery - err = copier.Copy(&newPromQueries, panel.PromQueries) + var tempPanels []*model.PanelResponse + err = copier.Copy(&tempPanels, &panels) if err != nil { - return "error updating panel queries", err + return "error fetching panel details", err } - query := bson.D{{"panel_id", panel.PanelID}} + for _, panel := range tempPanels { + + if !utils.ContainsString(updatedDashboardPanelIDs, panel.PanelID) || !utils.ContainsString(updatedDashboardPanelGroupIDs, panelGroup.PanelGroupID) { + + var promQueriesInPanelToBeDeleted []*dbSchemaAnalytics.PromQuery + err := copier.Copy(&promQueriesInPanelToBeDeleted, &panel.PromQueries) + if err != nil { + return "error updating queries", err + } + + var panelOptionsOfPanelToBeDeleted dbSchemaAnalytics.PanelOption + err = copier.Copy(&panelOptionsOfPanelToBeDeleted, &panel.PanelOptions) + if err != nil { + return "error updating options", err + } + + panelToBeDeleted := dbSchemaAnalytics.Panel{ + PanelID: panel.PanelID, + PanelOptions: &panelOptionsOfPanelToBeDeleted, + PanelName: *panel.PanelName, + PanelGroupID: panelGroup.PanelGroupID, + PromQueries: promQueriesInPanelToBeDeleted, + IsRemoved: true, + XAxisDown: panel.XAxisDown, + YAxisLeft: panel.YAxisLeft, + YAxisRight: panel.YAxisRight, + Unit: panel.Unit, + CreatedAt: *panel.CreatedAt, + UpdatedAt: strconv.FormatInt(time.Now().Unix(), 10), + } + + panelsToUpdate = append(panelsToUpdate, &panelToBeDeleted) - update := bson.D{{"$set", bson.D{{"panel_name", panel.PanelName}, {"is_removed", panel.IsRemoved}, - {"panel_group_id", panel.PanelGroupID}, {"panel_options", newPanelOption}, - {"prom_queries", newPromQueries}, {"updated_at", timestamp}, - {"y_axis_left", panel.YAxisLeft}, {"y_axis_right", panel.YAxisRight}, - {"x_axis_down", panel.XAxisDown}, {"unit", panel.Unit}}}} + } + } + } - err = dbOperationsAnalytics.UpdatePanel(query, update) + if len(panelsToCreate) > 0 { + err = dbOperationsAnalytics.InsertPanel(panelsToCreate) if err != nil { - return "error updating panel", err + return "error creating new panels", fmt.Errorf("error while inserting panel data", err) } + log.Print("successfully inserted prom query into promquery-collection") } - } - update := bson.D{{"$set", bson.D{{"ds_id", dashboard.DsID}, - {"db_name", dashboard.DbName}, {"db_type_id", dashboard.DbTypeID}, - {"db_type_name", dashboard.DbTypeName}, {"db_information", dashboard.DbInformation}, - {"chaos_event_query_template", dashboard.ChaosEventQueryTemplate}, {"chaos_verdict_query_template", dashboard.ChaosEventQueryTemplate}, - {"cluster_id", dashboard.ClusterID}, {"application_metadata_map", newApplicationMetadataMap}, - {"end_time", dashboard.EndTime}, {"start_time", dashboard.StartTime}, - {"refresh_rate", dashboard.RefreshRate}, {"panel_groups", newPanelGroups}, {"updated_at", timestamp}}}} + if len(panelsToUpdate) > 0 { + for _, panel := range panelsToUpdate { + timestamp := strconv.FormatInt(time.Now().Unix(), 10) - err = dbOperationsAnalytics.UpdateDashboard(query, update) + if panel.PanelID == "" && panel.PanelGroupID == "" { + return "error getting panel and group details", errors.New("panel ID or panel group ID is nil or empty") + } + + var newPanelOption dbSchemaAnalytics.PanelOption + err := copier.Copy(&newPanelOption, &panel.PanelOptions) + if err != nil { + return "error updating panel option", err + } + + var newPromQueries []dbSchemaAnalytics.PromQuery + err = copier.Copy(&newPromQueries, panel.PromQueries) + if err != nil { + return "error updating panel queries", err + } + + query := bson.D{{"panel_id", panel.PanelID}} + + update := bson.D{{"$set", bson.D{{"panel_name", panel.PanelName}, {"is_removed", panel.IsRemoved}, + {"panel_group_id", panel.PanelGroupID}, {"panel_options", newPanelOption}, + {"prom_queries", newPromQueries}, {"updated_at", timestamp}, + {"y_axis_left", panel.YAxisLeft}, {"y_axis_right", panel.YAxisRight}, + {"x_axis_down", panel.XAxisDown}, {"unit", panel.Unit}}}} + + err = dbOperationsAnalytics.UpdatePanel(query, update) + if err != nil { + return "error updating panel", err + } + } + } + + update = bson.D{{"$set", bson.D{{"ds_id", dashboard.DsID}, {"db_name", dashboard.DbName}, + {"db_type_id", dashboard.DbTypeID}, {"db_type_name", dashboard.DbTypeName}, + {"db_information", dashboard.DbInformation}, {"cluster_id", dashboard.ClusterID}, + {"application_metadata_map", newApplicationMetadataMap}, {"end_time", dashboard.EndTime}, + {"start_time", dashboard.StartTime}, {"refresh_rate", dashboard.RefreshRate}, + {"panel_groups", newPanelGroups}, {"updated_at", timestamp}}}} + } else { + update = bson.D{{"$set", bson.D{ + {"chaos_event_query_template", dashboard.ChaosEventQueryTemplate}, {"chaos_verdict_query_template", dashboard.ChaosVerdictQueryTemplate}, + {"updated_at", timestamp}}}} + } + + err := dbOperationsAnalytics.UpdateDashboard(query, update) if err != nil { return "error updating dashboard", err } @@ -643,40 +651,55 @@ func QueryListDataSource(projectID string) ([]*model.DSResponse, error) { return nil, err } - var newDatasources []*model.DSResponse - copier.Copy(&newDatasources, &datasource) + var ( + newDataSources []*model.DSResponse + wg sync.WaitGroup + ) + err = copier.Copy(&newDataSources, &datasource) + if err != nil { + return nil, err + } tsdbHealthCheckMap := make(map[string]string) - var wg sync.WaitGroup - wg.Add(len(newDatasources)) + var mutex = &sync.Mutex{} + wg.Add(len(newDataSources)) - for _, datasource := range newDatasources { + for _, datasource := range newDataSources { datasource := datasource go func(val *model.DSResponse) { defer wg.Done() - tsdbHealthCheckMap[*datasource.DsID] = prometheus.TSDBHealthCheck(*datasource.DsURL, *datasource.DsType) - + if _, ok := tsdbHealthCheckMap[*datasource.DsURL]; !ok { + mutex.Lock() + tsdbHealthCheckMap[*datasource.DsURL] = prometheus.TSDBHealthCheck(*datasource.DsURL, *datasource.DsType) + mutex.Unlock() + } }(datasource) } wg.Wait() - for _, datasource := range newDatasources { - datasource.HealthStatus = tsdbHealthCheckMap[*datasource.DsID] + for _, datasource := range newDataSources { + datasource.HealthStatus = tsdbHealthCheckMap[*datasource.DsURL] } - return newDatasources, nil + return newDataSources, nil } -func GetPromQuery(promInput *model.PromInput) (*model.PromResponse, error) { +// GetPromQuery takes prometheus queries and returns response for annotations and metrics with a query map +func GetPromQuery(promInput *model.PromInput) (*model.PromResponse, map[string]*model.MetricsPromResponse, error) { var ( - metrics []*model.MetricsPromResponse - annotations []*model.AnnotationsPromResponse + metrics []*model.MetricsPromResponse + annotations []*model.AnnotationsPromResponse + wg sync.WaitGroup + verdictResponse *model.AnnotationsPromResponse ) - var wg sync.WaitGroup + patchEventWithVerdict := false + queryResponseMap := make(map[string]*model.MetricsPromResponse) + var mutex = &sync.Mutex{} + wg.Add(len(promInput.Queries)) for _, v := range promInput.Queries { go func(val *model.PromQueryInput) { @@ -694,32 +717,59 @@ func GetPromQuery(promInput *model.PromInput) (*model.PromResponse, error) { cacheKey := val.Query + "-" + promInput.DsDetails.Start + "-" + promInput.DsDetails.End + "-" + promInput.DsDetails.URL queryType := "metrics" - if strings.Contains(val.Queryid, "chaos-interval") || strings.Contains(val.Queryid, "chaos-verdict") { + if strings.Contains(val.Queryid, "chaos-event") || strings.Contains(val.Queryid, "chaos-verdict") { queryType = "annotation" + cacheKey = val.Queryid + "-" + promInput.DsDetails.Start + "-" + promInput.DsDetails.End + "-" + promInput.DsDetails.URL } if obj, isExist := AnalyticsCache.Get(cacheKey); isExist { if queryType == "metrics" { metrics = append(metrics, obj.(*model.MetricsPromResponse)) + mutex.Lock() + queryResponseMap[val.Queryid] = obj.(*model.MetricsPromResponse) + mutex.Unlock() } else { - annotations = append(annotations, obj.(*model.AnnotationsPromResponse)) + if strings.Contains(val.Queryid, "chaos-event") { + annotations = append(annotations, obj.(*model.AnnotationsPromResponse)) + } } } else { response, err := prometheus.Query(newPromQuery, queryType) - if err != nil { return } - - cacheError := utils.AddCache(AnalyticsCache, cacheKey, response) - if cacheError != nil { - log.Printf("Adding cache: %v\n", cacheError) - } - if queryType == "metrics" { metrics = append(metrics, response.(*model.MetricsPromResponse)) + mutex.Lock() + queryResponseMap[val.Queryid] = response.(*model.MetricsPromResponse) + mutex.Unlock() + cacheError := utils.AddCache(AnalyticsCache, cacheKey, response) + if cacheError != nil { + errorStr := fmt.Sprintf("%v", cacheError) + if strings.Contains(errorStr, "already exists") { + cacheError = utils.UpdateCache(AnalyticsCache, cacheKey, response) + if cacheError != nil { + log.Printf("Error while caching: %v\n", cacheError) + } + } + } } else { - annotations = append(annotations, response.(*model.AnnotationsPromResponse)) + if strings.Contains(val.Queryid, "chaos-event") { + annotations = append(annotations, response.(*model.AnnotationsPromResponse)) + cacheError := utils.AddCache(AnalyticsCache, cacheKey, response) + if cacheError != nil { + errorStr := fmt.Sprintf("%v", cacheError) + if strings.Contains(errorStr, "already exists") { + cacheError = utils.UpdateCache(AnalyticsCache, cacheKey, response) + if cacheError != nil { + log.Printf("Error while caching: %v\n", cacheError) + } + } + } + } else if strings.Contains(val.Queryid, "chaos-verdict") { + patchEventWithVerdict = true + verdictResponse = response.(*model.AnnotationsPromResponse) + } } } }(v) @@ -727,12 +777,121 @@ func GetPromQuery(promInput *model.PromInput) (*model.PromResponse, error) { wg.Wait() + if patchEventWithVerdict == true { + annotations = ops.PatchChaosEventWithVerdict(annotations, verdictResponse, promInput, AnalyticsCache) + } + newPromResponse := model.PromResponse{ MetricsResponse: metrics, AnnotationsResponse: annotations, } - return &newPromResponse, nil + return &newPromResponse, queryResponseMap, nil +} + +// DashboardViewer takes a dashboard view id, prometheus queries, dashboard query map and data variables to query prometheus and send data periodically to the subscribed client +func DashboardViewer(viewID string, promQueries []*model.PromQueryInput, dashboardQueryMap []*model.QueryMapForPanelGroup, dataVariables model.DataVars, r store.StateData) { + if viewChan, ok := r.DashboardData[viewID]; ok { + + currentTime := time.Now().Unix() + startTime := strconv.FormatInt(currentTime-int64(dataVariables.RelativeTime), 10) + endTime := strconv.FormatInt(currentTime, 10) + relativeCheck := dataVariables.RelativeTime != 0 + + var queryType string + + if dataVariables.Start != "" && dataVariables.End != "" { + queryType = "fixed" + } else if relativeCheck && dataVariables.RefreshInterval != 0 { + queryType = "relative" + } else if relativeCheck && dataVariables.RefreshInterval == 0 { + queryType = "relatively-fixed" + } else { + queryType = "invalid" + } + + switch queryType { + + case "fixed": + dsDetails := &model.DsDetails{ + URL: dataVariables.URL, + Start: dataVariables.Start, + End: dataVariables.End, + } + + newPromInput := &model.PromInput{ + Queries: promQueries, + DsDetails: dsDetails, + } + + newPromResponse, queryResponseMap, err := GetPromQuery(newPromInput) + if err != nil { + log.Printf("Error during data source query of the dashboard view: %v\n", viewID) + } else { + dashboardResponse := ops.MapMetricsToDashboard(dashboardQueryMap, newPromResponse, queryResponseMap) + viewChan <- dashboardResponse + } + + case "relative": + for { + dsDetails := &model.DsDetails{ + URL: dataVariables.URL, + Start: startTime, + End: endTime, + } + + newPromInput := &model.PromInput{ + Queries: promQueries, + DsDetails: dsDetails, + } + + newPromResponse, queryResponseMap, err := GetPromQuery(newPromInput) + if err != nil { + log.Printf("Error during data source query of the dashboard view: %v at: %v \n", viewID, currentTime) + break + } else { + dashboardResponse := ops.MapMetricsToDashboard(dashboardQueryMap, newPromResponse, queryResponseMap) + viewChan <- dashboardResponse + time.Sleep(time.Duration(int64(dataVariables.RefreshInterval)) * time.Second) + currentTime = time.Now().Unix() + startTime = strconv.FormatInt(currentTime-int64(dataVariables.RelativeTime), 10) + endTime = strconv.FormatInt(currentTime, 10) + } + + if _, ok := r.DashboardData[viewID]; !ok { + break + } + } + + case "relatively-fixed": + dsDetails := &model.DsDetails{ + URL: dataVariables.URL, + Start: startTime, + End: endTime, + } + + newPromInput := &model.PromInput{ + Queries: promQueries, + DsDetails: dsDetails, + } + + newPromResponse, queryResponseMap, err := GetPromQuery(newPromInput) + if err != nil { + log.Printf("Error during data source query of the dashboard view: %v at: %v \n", viewID, currentTime) + } else { + dashboardResponse := ops.MapMetricsToDashboard(dashboardQueryMap, newPromResponse, queryResponseMap) + viewChan <- dashboardResponse + } + + case "invalid": + log.Printf("Wrong parameters for the dashboard view: %v\n", viewID) + } + + close(viewChan) + r.Mutex.Lock() + delete(r.DashboardData, viewID) + r.Mutex.Unlock() + } } func GetLabelNamesAndValues(promSeriesInput *model.PromSeriesInput) (*model.PromSeriesResponse, error) { @@ -753,7 +912,13 @@ func GetLabelNamesAndValues(promSeriesInput *model.PromSeriesInput) (*model.Prom cacheError := utils.AddCache(AnalyticsCache, cacheKey, response) if cacheError != nil { - log.Printf("Adding cache: %v\n", cacheError) + errorStr := fmt.Sprintf("%v", cacheError) + if strings.Contains(errorStr, "already exists") { + cacheError = utils.UpdateCache(AnalyticsCache, cacheKey, response) + if cacheError != nil { + log.Printf("Error while caching: %v\n", cacheError) + } + } } newPromSeriesResponse = response @@ -781,7 +946,13 @@ func GetSeriesList(promSeriesListInput *model.DsDetails) (*model.PromSeriesListR cacheError := utils.AddCache(AnalyticsCache, cacheKey, response) if cacheError != nil { - log.Printf("Adding cache: %v\n", cacheError) + errorStr := fmt.Sprintf("%v", cacheError) + if strings.Contains(errorStr, "already exists") { + cacheError = utils.UpdateCache(AnalyticsCache, cacheKey, response) + if cacheError != nil { + log.Printf("Error while caching: %v\n", cacheError) + } + } } newPromSeriesListResponse = response @@ -791,10 +962,32 @@ func GetSeriesList(promSeriesListInput *model.DsDetails) (*model.PromSeriesListR } // QueryListDashboard lists all the dashboards present in a project using the projectID -func QueryListDashboard(projectID string) ([]*model.ListDashboardResponse, error) { - query := bson.D{ - {"project_id", projectID}, - {"is_removed", false}, +func QueryListDashboard(projectID string, clusterID *string, dbID *string) ([]*model.ListDashboardResponse, error) { + + var ( + query bson.D + wg sync.WaitGroup + ) + + if clusterID == nil || *clusterID == "" { + if dbID != nil && *dbID != "" { + query = bson.D{ + {"project_id", projectID}, + {"db_id", dbID}, + {"is_removed", false}, + } + } else { + query = bson.D{ + {"project_id", projectID}, + {"is_removed", false}, + } + } + } else { + query = bson.D{ + {"project_id", projectID}, + {"cluster_id", clusterID}, + {"is_removed", false}, + } } dashboards, err := dbOperationsAnalytics.ListDashboard(query) @@ -808,12 +1001,68 @@ func QueryListDashboard(projectID string) ([]*model.ListDashboardResponse, error return nil, err } + dataSourceMap := make(map[string]*dbSchemaAnalytics.DataSource) + dataSourceHealthCheckMap := make(map[string]string) + + if clusterID != nil && *clusterID != "" { + var mutex = &sync.Mutex{} + wg.Add(len(newListDashboard)) + + for _, dashboard := range newListDashboard { + if _, ok := dataSourceMap[dashboard.DsID]; !ok { + datasource, err := dbOperationsAnalytics.GetDataSourceByID(dashboard.DsID) + if err != nil { + return nil, fmt.Errorf("error on querying from datasource collection: %v\n", err) + } + dataSourceMap[dashboard.DsID] = datasource + go func(val *dbSchemaAnalytics.DataSource) { + defer wg.Done() + + if _, ok := dataSourceHealthCheckMap[val.DsID]; !ok { + dataSourceStatus := prometheus.TSDBHealthCheck(datasource.DsURL, datasource.DsType) + mutex.Lock() + dataSourceHealthCheckMap[val.DsID] = dataSourceStatus + mutex.Unlock() + } else { + return + } + }(datasource) + } else { + wg.Done() + } + } + + wg.Wait() + } + for _, dashboard := range newListDashboard { - datasource, err := dbOperationsAnalytics.GetDataSourceByID(dashboard.DsID) - if err != nil { - return nil, fmt.Errorf("error on querying from datasource collection: %v\n", err) + + var datasource *dbSchemaAnalytics.DataSource + + if clusterID != nil && *clusterID != "" { + if dataSourceInfo, ok := dataSourceMap[dashboard.DsID]; ok { + datasource = dataSourceInfo + } else { + return nil, fmt.Errorf("error on querying from datasource collection") + } + if dataSourceHealthStatus, ok := dataSourceHealthCheckMap[dashboard.DsID]; ok { + dashboard.DsHealthStatus = &dataSourceHealthStatus + } else { + return nil, fmt.Errorf("error while checking data source health status") + } + } else { + if dataSourceInfo, ok := dataSourceMap[dashboard.DsID]; !ok { + datasource, err = dbOperationsAnalytics.GetDataSourceByID(dashboard.DsID) + if err != nil { + return nil, fmt.Errorf("error on querying from datasource collection: %v\n", err) + } + dataSourceMap[dashboard.DsID] = datasource + } else { + datasource = dataSourceInfo + } } + dashboard.DsURL = &datasource.DsURL dashboard.DsType = &datasource.DsType dashboard.DsName = &datasource.DsName diff --git a/litmus-portal/graphql-server/pkg/analytics/ops/operations.go b/litmus-portal/graphql-server/pkg/analytics/ops/operations.go index 44e0af28723..abc29dc050c 100644 --- a/litmus-portal/graphql-server/pkg/analytics/ops/operations.go +++ b/litmus-portal/graphql-server/pkg/analytics/ops/operations.go @@ -3,10 +3,15 @@ package ops import ( "errors" "fmt" + "log" "strconv" + "strings" "time" + "github.com/jinzhu/copier" "github.com/litmuschaos/litmus/litmus-portal/graphql-server/graph/model" + "github.com/litmuschaos/litmus/litmus-portal/graphql-server/utils" + "github.com/patrickmn/go-cache" ) func CreateDateMap(updatedAt string, filter model.TimeFrequency, statsMap map[string]model.WorkflowStats) error { @@ -49,3 +54,165 @@ func CreateDateMap(updatedAt string, filter model.TimeFrequency, statsMap map[st } return nil } + +// PatchChaosEventWithVerdict takes annotations with chaos events, chaos verdict prometheus response, prometheus queries and cache object to patch and update chaos events with chaos verdict +func PatchChaosEventWithVerdict(annotations []*model.AnnotationsPromResponse, verdictResponse *model.AnnotationsPromResponse, promInput *model.PromInput, AnalyticsCache *cache.Cache) []*model.AnnotationsPromResponse { + var existingAnnotations []*model.AnnotationsPromResponse + err := copier.Copy(&existingAnnotations, &annotations) + if err != nil { + log.Printf("Error parsing existing annotations %v\n", err) + } + + for annotationIndex, annotation := range existingAnnotations { + var existingAnnotation model.AnnotationsPromResponse + err := copier.Copy(&existingAnnotation, &annotation) + if err != nil { + log.Printf("Error parsing existing annotation %v\n", err) + } + + if strings.Contains(existingAnnotation.Queryid, "chaos-event") { + var newAnnotation model.AnnotationsPromResponse + err := copier.Copy(&newAnnotation, &verdictResponse) + if err != nil { + log.Printf("Error parsing new annotation %v\n", err) + } + + duplicateEventIndices := make(map[int]int) + var duplicateEventOffset = 0 + for verdictLegendIndex, verdictLegend := range newAnnotation.Legends { + verdictLegendName := func(str *string) string { return *str }(verdictLegend) + var ( + eventFound = false + duplicateEventsFound = false + firstEventFoundAtIndex = 0 + ) + + for eventLegendIndex, eventLegend := range existingAnnotation.Legends { + eventLegendName := func(str *string) string { return *str }(eventLegend) + + if verdictLegendName == eventLegendName { + if !eventFound { + firstEventFoundAtIndex = eventLegendIndex + } else { + duplicateEventsFound = true + if _, ok := duplicateEventIndices[eventLegendIndex]; !ok { + duplicateEventIndices[eventLegendIndex] = duplicateEventOffset + duplicateEventOffset++ + } + } + eventFound = true + var newVerdictSubData []*model.SubData + + for _, verdictSubData := range verdictResponse.SubDataArray[verdictLegendIndex] { + verdictSubDataDate := func(date *float64) float64 { return *date }(verdictSubData.Date) + var subDataFound = false + for eventSubDataIndex, eventSubData := range annotation.SubDataArray[eventLegendIndex] { + if eventSubData != nil { + eventSubDataDate := func(date *float64) float64 { return *date }(eventSubData.Date) + if eventSubData.SubDataName == verdictSubData.SubDataName && eventSubDataDate == verdictSubDataDate { + subDataFound = true + annotations[annotationIndex].SubDataArray[eventLegendIndex][eventSubDataIndex].Value = verdictSubData.Value + } + } + } + + if !subDataFound && verdictSubDataDate > 0 { + newVerdictSubData = append(newVerdictSubData, verdictSubData) + } + } + annotations[annotationIndex].SubDataArray[eventLegendIndex] = append(annotations[annotationIndex].SubDataArray[eventLegendIndex], newVerdictSubData...) + + if duplicateEventsFound { + existingDates := make(map[float64]bool) + for _, tsv := range annotations[annotationIndex].Tsvs[firstEventFoundAtIndex] { + existingDates[func(date *float64) float64 { return *date }(tsv.Date)] = true + } + + if _, ok := existingDates[func(date *float64) float64 { return *date }(annotations[annotationIndex].Tsvs[eventLegendIndex][0].Date)]; !ok { + annotations[annotationIndex].Tsvs[firstEventFoundAtIndex] = append(annotations[annotationIndex].Tsvs[firstEventFoundAtIndex], annotations[annotationIndex].Tsvs[eventLegendIndex]...) + } + annotations[annotationIndex].SubDataArray[firstEventFoundAtIndex] = annotations[annotationIndex].SubDataArray[eventLegendIndex] + } + } + } + + if !eventFound { + verdictValid := false + for _, tsv := range verdictResponse.Tsvs[verdictLegendIndex] { + if !verdictValid && func(val *int) int { return *val }(tsv.Value) == 1 { + verdictValid = true + } + } + + if verdictValid { + annotations[annotationIndex].Legends = append(annotations[annotationIndex].Legends, verdictLegend) + annotations[annotationIndex].SubDataArray = append(annotations[annotationIndex].SubDataArray, verdictResponse.SubDataArray[verdictLegendIndex]) + annotations[annotationIndex].Tsvs = append(annotations[annotationIndex].Tsvs, nil) + } + } + } + + if duplicateEventOffset != 0 { + numberOfEvents := len(annotations[annotationIndex].Legends) + for i := 0; i < numberOfEvents; i++ { + if offset, ok := duplicateEventIndices[i]; ok { + annotations[annotationIndex].Legends = append(annotations[annotationIndex].Legends[:i-offset], annotations[annotationIndex].Legends[i-offset+1:]...) + annotations[annotationIndex].Tsvs = append(annotations[annotationIndex].Tsvs[:i-offset], annotations[annotationIndex].Tsvs[i-offset+1:]...) + annotations[annotationIndex].SubDataArray = append(annotations[annotationIndex].SubDataArray[:i-offset], annotations[annotationIndex].SubDataArray[i-offset+1:]...) + } + } + } + + eventCacheKey := annotation.Queryid + "-" + promInput.DsDetails.Start + "-" + promInput.DsDetails.End + "-" + promInput.DsDetails.URL + cacheError := utils.AddCache(AnalyticsCache, eventCacheKey, annotations[annotationIndex]) + if cacheError != nil { + errorStr := fmt.Sprintf("%v", cacheError) + if strings.Contains(errorStr, "already exists") { + cacheError = utils.UpdateCache(AnalyticsCache, eventCacheKey, annotations[annotationIndex]) + if cacheError != nil { + log.Printf("Error while caching: %v\n", cacheError) + } + } + } + } + } + + return annotations +} + +// MapMetricsToDashboard takes dashboard query map, prometheus response and query response map for mapping metrics to the panels for a dashboard +func MapMetricsToDashboard(dashboardQueryMap []*model.QueryMapForPanelGroup, newPromResponse *model.PromResponse, queryResponseMap map[string]*model.MetricsPromResponse) *model.DashboardPromResponse { + var dashboardMetrics []*model.MetricDataForPanelGroup + + for _, panelGroupQueryMap := range dashboardQueryMap { + var panelGroupMetrics []*model.MetricDataForPanel + for _, panelQueryMap := range panelGroupQueryMap.PanelQueryMap { + var panelQueries []*model.MetricsPromResponse + for _, queryID := range panelQueryMap.QueryIDs { + panelQueries = append(panelQueries, queryResponseMap[queryID]) + } + panelMetricsData := &model.MetricDataForPanel{ + PanelID: panelQueryMap.PanelID, + PanelMetricsResponse: panelQueries, + } + panelGroupMetrics = append(panelGroupMetrics, panelMetricsData) + } + panelGroupMetricsData := &model.MetricDataForPanelGroup{ + PanelGroupID: panelGroupQueryMap.PanelGroupID, + PanelGroupMetricsResponse: panelGroupMetrics, + } + dashboardMetrics = append(dashboardMetrics, panelGroupMetricsData) + } + + var promResponse model.PromResponse + err := copier.Copy(&promResponse, &newPromResponse) + if err != nil { + log.Printf("Error parsing annotations %v\n", err) + } + dashboardResponse := &model.DashboardPromResponse{ + DashboardMetricsResponse: dashboardMetrics, + AnnotationsResponse: promResponse.AnnotationsResponse, + } + + return dashboardResponse +} diff --git a/litmus-portal/graphql-server/pkg/analytics/ops/prometheus/prometheus.go b/litmus-portal/graphql-server/pkg/analytics/ops/prometheus/prometheus.go index aa9a5078b1d..716dfc36177 100644 --- a/litmus-portal/graphql-server/pkg/analytics/ops/prometheus/prometheus.go +++ b/litmus-portal/graphql-server/pkg/analytics/ops/prometheus/prometheus.go @@ -11,6 +11,7 @@ import ( "time" "github.com/jinzhu/copier" + "github.com/litmuschaos/litmus/litmus-portal/graphql-server/utils" "github.com/prometheus/client_golang/api" apiV1 "github.com/prometheus/client_golang/api/prometheus/v1" md "github.com/prometheus/common/model" @@ -71,47 +72,88 @@ func Query(prom analytics.PromQuery, queryType string) (interface{}, error) { log.Printf("Unsupported result format: %s", value.Type().String()) } + chaosEventLabels := map[string]string{ + "workflow_name": "Workflow", + "chaosengine_context": "Engine context", + } + + chaosVerdictLabels := map[string]string{ + "workflow_name": "Workflow", + "chaosengine_context": "Engine context", + "app_namespace": "App namespace", + "app_label": "App label", + "app_kind": "App kind", + "chaosresult_verdict": "Experiment verdict", + "probe_success_percentage": "Probe success percentage", + } + var ( - newMetrics analytics.MetricsResponse - newAnnotations analytics.AnnotationsResponse - newMetricsTSVs [][]*analytics.MetricsTimeStampValue - newAnnotationsTSVs [][]*analytics.AnnotationsTimeStampValue + newMetrics model.MetricsPromResponse + newAnnotations model.AnnotationsPromResponse + newMetricsTSVs [][]*model.MetricsTimeStampValue + newAnnotationsTSVs [][]*model.AnnotationsTimeStampValue newLegends []*string + newSubDataArray [][]*model.SubData ) for _, v := range data { var ( - tempMetricsTSV []*analytics.MetricsTimeStampValue - tempAnnotationsTSV []*analytics.AnnotationsTimeStampValue + tempMetricsTSV []*model.MetricsTimeStampValue + tempAnnotationsTSV []*model.AnnotationsTimeStampValue tempLegends []*string + tempSubDataArray []*model.SubData ) - if queryType == "metrics" { - for _, value := range v.Values { - temp := &analytics.MetricsTimeStampValue{ - Date: func(timestamp float64) *float64 { return ×tamp }(map[bool]float64{true: float64(value.Timestamp), false: 0}[float64(value.Timestamp) >= 0.0]), - Value: func(val float64) *float64 { return &val }(map[bool]float64{true: float64(value.Value), false: 0.0}[float64(value.Value) >= 0.0]), - } + eventValid := false - tempMetricsTSV = append(tempMetricsTSV, temp) - } - newMetricsTSVs = append(newMetricsTSVs, tempMetricsTSV) + if prom.Legend == nil || *prom.Legend == "" { + tempLegends = append(tempLegends, func(str string) *string { return &str }(fmt.Sprint(v.Metric.String()))) } else { - for _, value := range v.Values { - temp := &analytics.AnnotationsTimeStampValue{ - Date: func(timestamp float64) *float64 { return ×tamp }(map[bool]float64{true: float64(value.Timestamp), false: 0}[float64(value.Timestamp) >= 0.0]), - Value: func(val int) *int { return &val }(map[bool]int{true: int(value.Value), false: 0}[int(value.Value) >= 0]), + if strings.Contains(prom.Queryid, "chaos-event") || strings.Contains(prom.Queryid, "chaos-verdict") { + var checkMap map[string]string + + if strings.Contains(prom.Queryid, "chaos-event") { + checkMap = chaosEventLabels + } else if strings.Contains(prom.Queryid, "chaos-verdict") { + checkMap = chaosVerdictLabels } - tempAnnotationsTSV = append(tempAnnotationsTSV, temp) + var baseString = utils.Split(v.Metric.String(), "{", "}") + var keyValueMap = utils.GetKeyValueMapFromQuotedString(baseString) + var timeStamp float64 + if keyValueMap["chaos_injection_time"] != "" { + timeStamp, err = strconv.ParseFloat(keyValueMap["chaos_injection_time"], 64) + timeStampInteger := int64(timeStamp) + if strings.Contains(prom.Queryid, "chaos-event") && timeStampInteger >= startTime && timeStampInteger <= endTime { + eventValid = true + } + } else { + timeStamp = 0 + } + if err != nil { + log.Printf("Error parsing chaos injection time: %v\n", err) + } else { + for key, value := range keyValueMap { + if nameVal, ok := checkMap[key]; ok { + tempSubData := &model.SubData{ + Date: func(timestamp float64) *float64 { return ×tamp }(map[bool]float64{true: timeStamp * 1000, false: 0}[timeStamp >= 0.0]), + Value: value, + SubDataName: nameVal, + } + tempSubDataArray = append(tempSubDataArray, tempSubData) + } + } + if strings.Contains(prom.Queryid, "chaos-event") { + if eventValid { + newSubDataArray = append(newSubDataArray, tempSubDataArray) + } + } else { + newSubDataArray = append(newSubDataArray, tempSubDataArray) + } + } } - newAnnotationsTSVs = append(newAnnotationsTSVs, tempAnnotationsTSV) - } - if prom.Legend == nil || *prom.Legend == "" { - tempLegends = append(tempLegends, func(str string) *string { return &str }(fmt.Sprint(v.Metric.String()))) - } else { r, _ := regexp.Compile(`\{{(.*?)\}}`) elements := r.FindAllString(*prom.Legend, -1) @@ -131,7 +173,43 @@ func Query(prom analytics.PromQuery, queryType string) (interface{}, error) { tempLegends = append(tempLegends, func(str string) *string { return &str }(fmt.Sprint(filterResponse))) } - newLegends = append(newLegends, tempLegends...) + + if strings.Contains(prom.Queryid, "chaos-event") { + if eventValid { + newLegends = append(newLegends, tempLegends...) + } + } else { + newLegends = append(newLegends, tempLegends...) + } + + if queryType == "metrics" { + for _, value := range v.Values { + temp := &model.MetricsTimeStampValue{ + Date: func(timestamp float64) *float64 { return ×tamp }(map[bool]float64{true: float64(value.Timestamp), false: 0}[float64(value.Timestamp) >= 0.0]), + Value: func(val float64) *float64 { return &val }(map[bool]float64{true: float64(value.Value), false: 0.0}[float64(value.Value) >= 0.0]), + } + + tempMetricsTSV = append(tempMetricsTSV, temp) + } + newMetricsTSVs = append(newMetricsTSVs, tempMetricsTSV) + } else { + for _, value := range v.Values { + temp := &model.AnnotationsTimeStampValue{ + Date: func(timestamp float64) *float64 { return ×tamp }(map[bool]float64{true: float64(value.Timestamp), false: 0}[float64(value.Timestamp) >= 0.0]), + Value: func(val int) *int { return &val }(map[bool]int{true: int(value.Value), false: 0}[int(value.Value) >= 0]), + } + + tempAnnotationsTSV = append(tempAnnotationsTSV, temp) + } + + if strings.Contains(prom.Queryid, "chaos-event") { + if eventValid { + newAnnotationsTSVs = append(newAnnotationsTSVs, tempAnnotationsTSV) + } + } else { + newAnnotationsTSVs = append(newAnnotationsTSVs, tempAnnotationsTSV) + } + } } if queryType == "metrics" { @@ -153,13 +231,12 @@ func Query(prom analytics.PromQuery, queryType string) (interface{}, error) { newAnnotations.Tsvs = newAnnotationsTSVs newAnnotations.Queryid = prom.Queryid newAnnotations.Legends = newLegends + newAnnotations.SubDataArray = newSubDataArray var resp model.AnnotationsPromResponse - if len(newLegends) != 0 { - err := copier.Copy(&resp, &newAnnotations) - if err != nil { - return &model.AnnotationsPromResponse{}, err - } + err := copier.Copy(&resp, &newAnnotations) + if err != nil { + return &model.AnnotationsPromResponse{}, err } return &resp, nil @@ -194,8 +271,8 @@ func LabelNamesAndValues(prom analytics.PromSeries) (*model.PromSeriesResponse, } var ( - newResponse analytics.PromSeriesResponse - newLabelValues []*analytics.LabelValue + newResponse model.PromSeriesResponse + newLabelValues []*model.LabelValue ) if len(labelNames) >= 1 { @@ -205,17 +282,17 @@ func LabelNamesAndValues(prom analytics.PromSeries) (*model.PromSeriesResponse, if index != 0 { go func(index int, label string) { defer wg.Done() - var newValues []*analytics.Option + var newValues []*model.Option values, _, err := client.LabelValues(context.TODO(), label, matcher, start, end) if err != nil { return } for _, value := range values { - newValues = append(newValues, func(str string) *analytics.Option { return &analytics.Option{Name: str} }(fmt.Sprint(value))) + newValues = append(newValues, func(str string) *model.Option { return &model.Option{Name: str} }(fmt.Sprint(value))) } - tempLabelValues := &analytics.LabelValue{ + tempLabelValues := &model.LabelValue{ Label: label, Values: newValues, } @@ -261,7 +338,7 @@ func SeriesList(prom analytics.PromDSDetails) (*model.PromSeriesListResponse, er var ( matcher []string newValues []*string - newResponse analytics.PromSeriesListResponse + newResponse model.PromSeriesListResponse ) labelValues, _, err := client.LabelValues(context.TODO(), "__name__", matcher, start, end) diff --git a/litmus-portal/graphql-server/pkg/analytics/types.go b/litmus-portal/graphql-server/pkg/analytics/types.go index b0927b62b87..68953a1a793 100644 --- a/litmus-portal/graphql-server/pkg/analytics/types.go +++ b/litmus-portal/graphql-server/pkg/analytics/types.go @@ -2,6 +2,12 @@ package analytics type STATE string +type PromDSDetails struct { + URL string + Start string + End string +} + type PromQuery struct { Queryid string Query string @@ -11,57 +17,11 @@ type PromQuery struct { DSdetails *PromDSDetails } -type MetricsResponse struct { - Queryid string `json:"queryid"` - Legends []*string `json:"legends"` - Tsvs [][]*MetricsTimeStampValue `json:"tsvs"` -} - -type MetricsTimeStampValue struct { - Date *float64 `json:"date"` - Value *float64 `json:"value"` -} - -type AnnotationsResponse struct { - Queryid string `json:"queryid"` - Legends []*string `json:"legends"` - Tsvs [][]*AnnotationsTimeStampValue `json:"tsvs"` -} - -type AnnotationsTimeStampValue struct { - Date *float64 `json:"date"` - Value *int `json:"value"` -} - type PromSeries struct { Series string DSdetails *PromDSDetails } -type PromDSDetails struct { - URL string - Start string - End string -} - -type PromSeriesListResponse struct { - SeriesList []*string `json:"seriesList"` -} - -type LabelValue struct { - Label string `json:"label"` - Values []*Option `json:"values"` -} - -type Option struct { - Name string `json:"name"` -} - -type PromSeriesResponse struct { - Series string `json:"series"` - LabelValues []*LabelValue `json:"labelValues"` -} - //Portal Dashboard Types type PortalDashboard struct { DashboardID string `json:"dashboardID"` diff --git a/litmus-portal/graphql-server/pkg/data-store/store.go b/litmus-portal/graphql-server/pkg/data-store/store.go index 2aa92c0dba6..d0ab6950870 100644 --- a/litmus-portal/graphql-server/pkg/data-store/store.go +++ b/litmus-portal/graphql-server/pkg/data-store/store.go @@ -13,6 +13,7 @@ type StateData struct { WorkflowEventPublish map[string][]chan *model.WorkflowRun WorkflowLog map[string]chan *model.PodLogResponse KubeObjectData map[string]chan *model.KubeObjectResponse + DashboardData map[string]chan *model.DashboardPromResponse Mutex *sync.Mutex } @@ -23,6 +24,7 @@ func NewStore() *StateData { WorkflowEventPublish: make(map[string][]chan *model.WorkflowRun), WorkflowLog: make(map[string]chan *model.PodLogResponse), KubeObjectData: make(map[string]chan *model.KubeObjectResponse), + DashboardData: make(map[string]chan *model.DashboardPromResponse), Mutex: &sync.Mutex{}, } } diff --git a/litmus-portal/graphql-server/utils/cache.go b/litmus-portal/graphql-server/utils/cache.go index a343e02a245..33653d28f56 100644 --- a/litmus-portal/graphql-server/utils/cache.go +++ b/litmus-portal/graphql-server/utils/cache.go @@ -16,6 +16,11 @@ func AddCache(c *cache.Cache, k string, x interface{}) error { return c.Add(k, x, cacheExpiration) } +// UpdateCache function takes a string and an object to be cached +func UpdateCache(c *cache.Cache, k string, x interface{}) error { + return c.Replace(k, x, cacheExpiration) +} + // NewCache initializes a new cache with a given expiration period and cleanup interval func NewCache() *cache.Cache { return cache.New(cacheExpiration, cleanupInterval) diff --git a/litmus-portal/graphql-server/utils/misc.go b/litmus-portal/graphql-server/utils/misc.go index 1cf2ff177f0..b3b10385660 100644 --- a/litmus-portal/graphql-server/utils/misc.go +++ b/litmus-portal/graphql-server/utils/misc.go @@ -7,6 +7,7 @@ import ( "net/http" "os" "strings" + "unicode" dbSchemaCluster "github.com/litmuschaos/litmus/litmus-portal/graphql-server/pkg/database/mongodb/cluster" "github.com/litmuschaos/litmus/litmus-portal/graphql-server/pkg/types" @@ -130,3 +131,45 @@ func ContainsString(s []string, str string) bool { func Truncate(num float64) float64 { return float64(int(num*100)) / 100 } + +// Split returns the string in between a before sub-string and an after sub-string +func Split(str, before, after string) string { + a := strings.SplitAfterN(str, before, 2) + b := strings.SplitAfterN(a[len(a)-1], after, 2) + if 1 == len(b) { + return b[0] + } + return b[0][0 : len(b[0])-len(after)] +} + +// GetKeyValueMapFromQuotedString returns key value pairs from a string with quotes +func GetKeyValueMapFromQuotedString(quotedString string) map[string]string { + lastQuote := rune(0) + f := func(c rune) bool { + switch { + case c == lastQuote: + lastQuote = rune(0) + return false + case lastQuote != rune(0): + return false + case unicode.In(c, unicode.Quotation_Mark): + lastQuote = c + return false + default: + return unicode.IsSpace(c) + + } + } + + // splitting string by space but considering quoted section + items := strings.FieldsFunc(quotedString, f) + + // create and fill the map + m := make(map[string]string) + for _, item := range items { + x := strings.Split(item, "=") + m[x[0]] = x[1][1 : len(x[1])-2] + } + + return m +}