diff --git a/adopters/organizations/wingie-enuygun.md b/adopters/organizations/wingie-enuygun.md new file mode 100644 index 00000000000..7a6c1ed2f1c --- /dev/null +++ b/adopters/organizations/wingie-enuygun.md @@ -0,0 +1,11 @@ +# Wingie Enuygun Company +[Wingie Enuygun Company](https://www.wingie.com/) is a leading travel and technology company providing seamless travel solutions across various platforms. + +## Why do we use Litmus +We use Litmus to identify bottlenecks in our systems, detect issues early, and foresee potential errors. This allows us to take proactive measures and maintain the resilience and performance of our infrastructure. + +## How do we use Litmus +Litmus is integrated into our QA cycles, where it plays a crucial role in catching bugs and verifying the overall resilience of our systems. + +## Benefits in using Litmus +Litmus chaos experiments are straightforward to implement and can be easily customized or extended to meet our specific requirements, enabling us to effectively manage and optimize our systems at Wingie Enuygun. diff --git a/chaoscenter/authentication/api/handlers/rest/user_handlers.go b/chaoscenter/authentication/api/handlers/rest/user_handlers.go index 3d81dc22d54..904969f16ab 100644 --- a/chaoscenter/authentication/api/handlers/rest/user_handlers.go +++ b/chaoscenter/authentication/api/handlers/rest/user_handlers.go @@ -263,7 +263,7 @@ func InviteUsers(service services.ApplicationService) gin.HandlerFunc { // @Failure 400 {object} response.ErrInvalidRequest // @Failure 400 {object} response.ErrUserNotFound // @Failure 400 {object} response.ErrUserDeactivated -// @Failure 400 {object} response.ErrInvalidCredentials +// @Failure 401 {object} response.ErrInvalidCredentials // @Failure 500 {object} response.ErrServerError // @Success 200 {object} response.LoginResponse{} // @Router /login [post] diff --git a/chaoscenter/authentication/pkg/utils/sanitizers.go b/chaoscenter/authentication/pkg/utils/sanitizers.go index df9c4d936a0..817ec4684a9 100644 --- a/chaoscenter/authentication/pkg/utils/sanitizers.go +++ b/chaoscenter/authentication/pkg/utils/sanitizers.go @@ -16,7 +16,7 @@ func SanitizeString(input string) string { /* ValidateStrictPassword represents and checks for the following patterns: - Input is at least 8 characters long and at most 16 characters long -- Input contains at least one special character of these @$!%*?_& +- Input contains at least one special character of these @$!%*?_&# - Input contains at least one digit - Input contains at least one uppercase alphabet - Input contains at least one lowercase alphabet @@ -33,7 +33,7 @@ func ValidateStrictPassword(input string) error { digits := `[0-9]{1}` lowerAlphabets := `[a-z]{1}` capitalAlphabets := `[A-Z]{1}` - specialCharacters := `[@$!%*?_&]{1}` + specialCharacters := `[@$!%*?_&#]{1}` if b, err := regexp.MatchString(digits, input); !b || err != nil { return fmt.Errorf("password does not contain digits") } diff --git a/chaoscenter/graphql/definitions/shared/chaos_infrastructure.graphqls b/chaoscenter/graphql/definitions/shared/chaos_infrastructure.graphqls index 2f001bf1f27..3dde028b21b 100644 --- a/chaoscenter/graphql/definitions/shared/chaos_infrastructure.graphqls +++ b/chaoscenter/graphql/definitions/shared/chaos_infrastructure.graphqls @@ -358,11 +358,11 @@ type KubeObjectResponse { """ Type of the Kubernetes object """ - kubeObj: [KubeObject]! + kubeObj: KubeObject! } """ -KubeObject consists of the namespace and the available resources in the same +KubeObject consists of the available resources in a namespace """ type KubeObject { """ @@ -404,16 +404,75 @@ input KubeObjectRequest { GVR Request """ kubeObjRequest: KubeGVRRequest + """ + Namespace in which the Kubernetes object is present + """ + namespace: String! objectType: String! workloads: [Workload] } +""" +Defines details for fetching Kubernetes namespace data +""" +input KubeNamespaceRequest { + """ + ID of the infra + """ + infraID: ID! +} + +""" +Define name in the infra (not really useful at the moment but maybe we will need other field later) +""" +type KubeNamespace{ + """ + Name of the namespace + """ + name: String! +} + + + input KubeGVRRequest { group: String! version: String! resource: String! } +""" +Response received for querying Kubernetes Namespaces +""" +type KubeNamespaceResponse { + """ + ID of the infra in which the Kubernetes namespace is present + """ + infraID: ID! + """ + List of the Kubernetes namespace + """ + kubeNamespace: [KubeNamespace]! +} + +""" +Defines the details of Kubernetes namespace +""" +input KubeNamespaceData { + """ + Unique request ID for fetching Kubernetes namespace details + """ + requestID: ID! + """ + ID of the infra in which the Kubernetes namespace is present + """ + infraID: InfraIdentity! + """ + List of KubeNamespace return by subscriber + """ + kubeNamespace: String! +} + + """ Defines the details of Kubernetes object """ @@ -638,6 +697,12 @@ type Mutation { """ # authorized directive not required kubeObj(request: KubeObjectData!): String! + + """ + Receives kubernetes namespace data from subscriber + """ + # authorized directive not required + kubeNamespace(request: KubeNamespaceData!): String! } type Subscription { @@ -663,4 +728,9 @@ type Subscription { Returns a kubernetes object given an input """ getKubeObject(request: KubeObjectRequest!): KubeObjectResponse! + + """ + Returns a kubernetes namespaces given an input + """ + getKubeNamespace(request: KubeNamespaceRequest!): KubeNamespaceResponse! } diff --git a/chaoscenter/graphql/definitions/shared/chaoshub.graphqls b/chaoscenter/graphql/definitions/shared/chaoshub.graphqls index 952ee98cf19..12f1cafb2f7 100644 --- a/chaoscenter/graphql/definitions/shared/chaoshub.graphqls +++ b/chaoscenter/graphql/definitions/shared/chaoshub.graphqls @@ -31,6 +31,10 @@ type ChaosHub implements ResourceDetails & Audit { """ repoBranch: String! """ + Connected Hub of remote repository + """ + remoteHub: String! + """ ID of the project in which the chaos hub is present """ projectID: ID! @@ -206,6 +210,10 @@ type ChaosHubStatus implements ResourceDetails & Audit { """ repoBranch: String! """ + Connected Hub of remote repository + """ + remoteHub: String! + """ Bool value indicating whether the hub is available or not. """ isAvailable: Boolean! @@ -320,6 +328,10 @@ input CreateChaosHubRequest { """ repoBranch: String! """ + Connected Hub of remote repository + """ + remoteHub: String! + """ Bool value indicating whether the hub is private or not. """ isPrivate: Boolean! @@ -382,6 +394,10 @@ input CloningInput { """ repoURL: String! """ + Connected Hub of remote repository + """ + remoteHub: String! + """ Bool value indicating whether the hub is private or not. """ isPrivate: Boolean! @@ -426,6 +442,10 @@ input CreateRemoteChaosHub { URL of the git repository """ repoURL: String! + """ + Connected Hub of remote repository + """ + remoteHub: String! } @@ -455,6 +475,10 @@ input UpdateChaosHubRequest { """ repoBranch: String! """ + Connected Hub of remote repository + """ + remoteHub: String! + """ Bool value indicating whether the hub is private or not. """ isPrivate: Boolean! diff --git a/chaoscenter/graphql/server/go.mod b/chaoscenter/graphql/server/go.mod index 2bd2910eb44..945db83f223 100644 --- a/chaoscenter/graphql/server/go.mod +++ b/chaoscenter/graphql/server/go.mod @@ -20,7 +20,7 @@ require ( github.com/pkg/errors v0.9.1 github.com/sirupsen/logrus v1.9.3 github.com/stretchr/testify v1.9.0 - github.com/tidwall/gjson v1.17.1 + github.com/tidwall/gjson v1.17.3 github.com/tidwall/sjson v1.2.5 github.com/vektah/gqlparser/v2 v2.5.16 go.mongodb.org/mongo-driver v1.16.1 diff --git a/chaoscenter/graphql/server/go.sum b/chaoscenter/graphql/server/go.sum index 8aff530921c..2084bf5b251 100644 --- a/chaoscenter/graphql/server/go.sum +++ b/chaoscenter/graphql/server/go.sum @@ -1120,8 +1120,8 @@ github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2/go.mod h1:hkRG github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA= github.com/thecodeteam/goscaleio v0.1.0/go.mod h1:68sdkZAsK8bvEwBlbQnlLS+xU+hvLYM/iQ8KXej1AwM= github.com/tidwall/gjson v1.14.2/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= -github.com/tidwall/gjson v1.17.1 h1:wlYEnwqAHgzmhNUFfw7Xalt2JzQvsMx2Se4PcoFCT/U= -github.com/tidwall/gjson v1.17.1/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= +github.com/tidwall/gjson v1.17.3 h1:bwWLZU7icoKRG+C+0PNwIKC6FCJO/Q3p2pZvuP0jN94= +github.com/tidwall/gjson v1.17.3/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= github.com/tidwall/pretty v0.0.0-20180105212114-65a9db5fad51/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= diff --git a/chaoscenter/graphql/server/graph/chaos_infrastructure.resolvers.go b/chaoscenter/graphql/server/graph/chaos_infrastructure.resolvers.go index 7e4540509eb..59977440584 100644 --- a/chaoscenter/graphql/server/graph/chaos_infrastructure.resolvers.go +++ b/chaoscenter/graphql/server/graph/chaos_infrastructure.resolvers.go @@ -116,6 +116,11 @@ func (r *mutationResolver) KubeObj(ctx context.Context, request model.KubeObject return r.chaosInfrastructureService.KubeObj(request, *data_store.Store) } +// KubeNamespace is the resolver for the kubeNamespace field. +func (r *mutationResolver) KubeNamespace(ctx context.Context, request model.KubeNamespaceData) (string, error) { + return r.chaosInfrastructureService.KubeNamespace(request, *data_store.Store) +} + // GetInfra is the resolver for the getInfra field. func (r *queryResolver) GetInfra(ctx context.Context, projectID string, infraID string) (*model.Infra, error) { logFields := logrus.Fields{ @@ -350,6 +355,24 @@ func (r *subscriptionResolver) GetKubeObject(ctx context.Context, request model. return kubeObjData, nil } +// GetKubeNamespace is the resolver for the getKubeNamespace field. +func (r *subscriptionResolver) GetKubeNamespace(ctx context.Context, request model.KubeNamespaceRequest) (<-chan *model.KubeNamespaceResponse, error) { + logrus.Print("NEW NAMESPACE REQUEST", request.InfraID) + kubeNamespaceData := make(chan *model.KubeNamespaceResponse) + reqID := uuid.New() + data_store.Store.Mutex.Lock() + data_store.Store.KubeNamespaceData[reqID.String()] = kubeNamespaceData + data_store.Store.Mutex.Unlock() + go func() { + <-ctx.Done() + logrus.Println("Closed KubeNamespace Listener") + delete(data_store.Store.KubeNamespaceData, reqID.String()) + }() + go r.chaosExperimentHandler.GetKubeNamespaceData(reqID.String(), request, *data_store.Store) + + return kubeNamespaceData, nil +} + // Subscription returns generated.SubscriptionResolver implementation. func (r *Resolver) Subscription() generated.SubscriptionResolver { return &subscriptionResolver{r} } diff --git a/chaoscenter/graphql/server/graph/generated/generated.go b/chaoscenter/graphql/server/graph/generated/generated.go index 932e018a654..8a501d3e4da 100644 --- a/chaoscenter/graphql/server/graph/generated/generated.go +++ b/chaoscenter/graphql/server/graph/generated/generated.go @@ -91,6 +91,7 @@ type ComplexityRoot struct { Name func(childComplexity int) int Password func(childComplexity int) int ProjectID func(childComplexity int) int + RemoteHub func(childComplexity int) int RepoBranch func(childComplexity int) int RepoURL func(childComplexity int) int SSHPrivateKey func(childComplexity int) int @@ -115,6 +116,7 @@ type ComplexityRoot struct { LastSyncedAt func(childComplexity int) int Name func(childComplexity int) int Password func(childComplexity int) int + RemoteHub func(childComplexity int) int RepoBranch func(childComplexity int) int RepoURL func(childComplexity int) int SSHPrivateKey func(childComplexity int) int @@ -398,6 +400,15 @@ type ComplexityRoot struct { Version func(childComplexity int) int } + KubeNamespace struct { + Name func(childComplexity int) int + } + + KubeNamespaceResponse struct { + InfraID func(childComplexity int) int + KubeNamespace func(childComplexity int) int + } + KubeObject struct { Data func(childComplexity int) int Namespace func(childComplexity int) int @@ -497,6 +508,7 @@ type ComplexityRoot struct { GenerateSSHKey func(childComplexity int) int GetManifestWithInfraID func(childComplexity int, projectID string, infraID string, accessKey string) int GitopsNotifier func(childComplexity int, clusterInfo model.InfraIdentity, experimentID string) int + KubeNamespace func(childComplexity int, request model.KubeNamespaceData) int KubeObj func(childComplexity int, request model.KubeObjectData) int PodLog func(childComplexity int, request model.PodLog) int RegisterInfra func(childComplexity int, projectID string, request model.RegisterInfraRequest) int @@ -694,10 +706,11 @@ type ComplexityRoot struct { } Subscription struct { - GetInfraEvents func(childComplexity int, projectID string) int - GetKubeObject func(childComplexity int, request model.KubeObjectRequest) int - GetPodLog func(childComplexity int, request model.PodLogRequest) int - InfraConnect func(childComplexity int, request model.InfraIdentity) int + GetInfraEvents func(childComplexity int, projectID string) int + GetKubeNamespace func(childComplexity int, request model.KubeNamespaceRequest) int + GetKubeObject func(childComplexity int, request model.KubeObjectRequest) int + GetPodLog func(childComplexity int, request model.PodLogRequest) int + InfraConnect func(childComplexity int, request model.InfraIdentity) int } UserDetails struct { @@ -727,6 +740,7 @@ type MutationResolver interface { GetManifestWithInfraID(ctx context.Context, projectID string, infraID string, accessKey string) (string, error) PodLog(ctx context.Context, request model.PodLog) (string, error) KubeObj(ctx context.Context, request model.KubeObjectData) (string, error) + KubeNamespace(ctx context.Context, request model.KubeNamespaceData) (string, error) AddChaosHub(ctx context.Context, projectID string, request model.CreateChaosHubRequest) (*model.ChaosHub, error) AddRemoteChaosHub(ctx context.Context, projectID string, request model.CreateRemoteChaosHub) (*model.ChaosHub, error) SaveChaosHub(ctx context.Context, projectID string, request model.CreateChaosHubRequest) (*model.ChaosHub, error) @@ -786,6 +800,7 @@ type SubscriptionResolver interface { InfraConnect(ctx context.Context, request model.InfraIdentity) (<-chan *model.InfraActionResponse, error) GetPodLog(ctx context.Context, request model.PodLogRequest) (<-chan *model.PodLogResponse, error) GetKubeObject(ctx context.Context, request model.KubeObjectRequest) (<-chan *model.KubeObjectResponse, error) + GetKubeNamespace(ctx context.Context, request model.KubeNamespaceRequest) (<-chan *model.KubeNamespaceResponse, error) } type executableSchema struct { @@ -1031,6 +1046,13 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.ChaosHub.ProjectID(childComplexity), true + case "ChaosHub.remoteHub": + if e.complexity.ChaosHub.RemoteHub == nil { + break + } + + return e.complexity.ChaosHub.RemoteHub(childComplexity), true + case "ChaosHub.repoBranch": if e.complexity.ChaosHub.RepoBranch == nil { break @@ -1178,6 +1200,13 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.ChaosHubStatus.Password(childComplexity), true + case "ChaosHubStatus.remoteHub": + if e.complexity.ChaosHubStatus.RemoteHub == nil { + break + } + + return e.complexity.ChaosHubStatus.RemoteHub(childComplexity), true + case "ChaosHubStatus.repoBranch": if e.complexity.ChaosHubStatus.RepoBranch == nil { break @@ -2557,6 +2586,27 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.K8SProbe.Version(childComplexity), true + case "KubeNamespace.name": + if e.complexity.KubeNamespace.Name == nil { + break + } + + return e.complexity.KubeNamespace.Name(childComplexity), true + + case "KubeNamespaceResponse.infraID": + if e.complexity.KubeNamespaceResponse.InfraID == nil { + break + } + + return e.complexity.KubeNamespaceResponse.InfraID(childComplexity), true + + case "KubeNamespaceResponse.kubeNamespace": + if e.complexity.KubeNamespaceResponse.KubeNamespace == nil { + break + } + + return e.complexity.KubeNamespaceResponse.KubeNamespace(childComplexity), true + case "KubeObject.data": if e.complexity.KubeObject.Data == nil { break @@ -3081,6 +3131,18 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.Mutation.GitopsNotifier(childComplexity, args["clusterInfo"].(model.InfraIdentity), args["experimentID"].(string)), true + case "Mutation.kubeNamespace": + if e.complexity.Mutation.KubeNamespace == nil { + break + } + + args, err := ec.field_Mutation_kubeNamespace_args(context.TODO(), rawArgs) + if err != nil { + return 0, false + } + + return e.complexity.Mutation.KubeNamespace(childComplexity, args["request"].(model.KubeNamespaceData)), true + case "Mutation.kubeObj": if e.complexity.Mutation.KubeObj == nil { break @@ -4256,6 +4318,18 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.Subscription.GetInfraEvents(childComplexity, args["projectID"].(string)), true + case "Subscription.getKubeNamespace": + if e.complexity.Subscription.GetKubeNamespace == nil { + break + } + + args, err := ec.field_Subscription_getKubeNamespace_args(context.TODO(), rawArgs) + if err != nil { + return 0, false + } + + return e.complexity.Subscription.GetKubeNamespace(childComplexity, args["request"].(model.KubeNamespaceRequest)), true + case "Subscription.getKubeObject": if e.complexity.Subscription.GetKubeObject == nil { break @@ -4361,6 +4435,8 @@ func (e *executableSchema) Exec(ctx context.Context) graphql.ResponseHandler { ec.unmarshalInputInfraIdentity, ec.unmarshalInputK8SProbeRequest, ec.unmarshalInputKubeGVRRequest, + ec.unmarshalInputKubeNamespaceData, + ec.unmarshalInputKubeNamespaceRequest, ec.unmarshalInputKubeObjectData, ec.unmarshalInputKubeObjectRequest, ec.unmarshalInputKubernetesCMDProbeRequest, @@ -5682,11 +5758,11 @@ type KubeObjectResponse { """ Type of the Kubernetes object """ - kubeObj: [KubeObject]! + kubeObj: KubeObject! } """ -KubeObject consists of the namespace and the available resources in the same +KubeObject consists of the available resources in a namespace """ type KubeObject { """ @@ -5728,16 +5804,75 @@ input KubeObjectRequest { GVR Request """ kubeObjRequest: KubeGVRRequest + """ + Namespace in which the Kubernetes object is present + """ + namespace: String! objectType: String! workloads: [Workload] } +""" +Defines details for fetching Kubernetes namespace data +""" +input KubeNamespaceRequest { + """ + ID of the infra + """ + infraID: ID! +} + +""" +Define name in the infra (not really useful at the moment but maybe we will need other field later) +""" +type KubeNamespace{ + """ + Name of the namespace + """ + name: String! +} + + + input KubeGVRRequest { group: String! version: String! resource: String! } +""" +Response received for querying Kubernetes Namespaces +""" +type KubeNamespaceResponse { + """ + ID of the infra in which the Kubernetes namespace is present + """ + infraID: ID! + """ + List of the Kubernetes namespace + """ + kubeNamespace: [KubeNamespace]! +} + +""" +Defines the details of Kubernetes namespace +""" +input KubeNamespaceData { + """ + Unique request ID for fetching Kubernetes namespace details + """ + requestID: ID! + """ + ID of the infra in which the Kubernetes namespace is present + """ + infraID: InfraIdentity! + """ + List of KubeNamespace return by subscriber + """ + kubeNamespace: String! +} + + """ Defines the details of Kubernetes object """ @@ -5962,6 +6097,12 @@ extend type Mutation { """ # authorized directive not required kubeObj(request: KubeObjectData!): String! + + """ + Receives kubernetes namespace data from subscriber + """ + # authorized directive not required + kubeNamespace(request: KubeNamespaceData!): String! } extend type Subscription { @@ -5987,6 +6128,11 @@ extend type Subscription { Returns a kubernetes object given an input """ getKubeObject(request: KubeObjectRequest!): KubeObjectResponse! + + """ + Returns a kubernetes namespaces given an input + """ + getKubeNamespace(request: KubeNamespaceRequest!): KubeNamespaceResponse! } `, BuiltIn: false}, {Name: "../../../definitions/shared/chaoshub.graphqls", Input: `enum AuthType { @@ -6022,6 +6168,10 @@ type ChaosHub implements ResourceDetails & Audit { """ repoBranch: String! """ + Connected Hub of remote repository + """ + remoteHub: String! + """ ID of the project in which the chaos hub is present """ projectID: ID! @@ -6197,6 +6347,10 @@ type ChaosHubStatus implements ResourceDetails & Audit { """ repoBranch: String! """ + Connected Hub of remote repository + """ + remoteHub: String! + """ Bool value indicating whether the hub is available or not. """ isAvailable: Boolean! @@ -6311,6 +6465,10 @@ input CreateChaosHubRequest { """ repoBranch: String! """ + Connected Hub of remote repository + """ + remoteHub: String! + """ Bool value indicating whether the hub is private or not. """ isPrivate: Boolean! @@ -6373,6 +6531,10 @@ input CloningInput { """ repoURL: String! """ + Connected Hub of remote repository + """ + remoteHub: String! + """ Bool value indicating whether the hub is private or not. """ isPrivate: Boolean! @@ -6417,6 +6579,10 @@ input CreateRemoteChaosHub { URL of the git repository """ repoURL: String! + """ + Connected Hub of remote repository + """ + remoteHub: String! } @@ -6446,6 +6612,10 @@ input UpdateChaosHubRequest { """ repoBranch: String! """ + Connected Hub of remote repository + """ + remoteHub: String! + """ Bool value indicating whether the hub is private or not. """ isPrivate: Boolean! @@ -8607,6 +8777,21 @@ func (ec *executionContext) field_Mutation_gitopsNotifier_args(ctx context.Conte return args, nil } +func (ec *executionContext) field_Mutation_kubeNamespace_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { + var err error + args := map[string]interface{}{} + var arg0 model.KubeNamespaceData + if tmp, ok := rawArgs["request"]; ok { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("request")) + arg0, err = ec.unmarshalNKubeNamespaceData2githubᚗcomᚋlitmuschaosᚋlitmusᚋchaoscenterᚋgraphqlᚋserverᚋgraphᚋmodelᚐKubeNamespaceData(ctx, tmp) + if err != nil { + return nil, err + } + } + args["request"] = arg0 + return args, nil +} + func (ec *executionContext) field_Mutation_kubeObj_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { var err error args := map[string]interface{}{} @@ -9717,6 +9902,21 @@ func (ec *executionContext) field_Subscription_getInfraEvents_args(ctx context.C return args, nil } +func (ec *executionContext) field_Subscription_getKubeNamespace_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { + var err error + args := map[string]interface{}{} + var arg0 model.KubeNamespaceRequest + if tmp, ok := rawArgs["request"]; ok { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("request")) + arg0, err = ec.unmarshalNKubeNamespaceRequest2githubᚗcomᚋlitmuschaosᚋlitmusᚋchaoscenterᚋgraphqlᚋserverᚋgraphᚋmodelᚐKubeNamespaceRequest(ctx, tmp) + if err != nil { + return nil, err + } + } + args["request"] = arg0 + return args, nil +} + func (ec *executionContext) field_Subscription_getKubeObject_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { var err error args := map[string]interface{}{} @@ -10759,6 +10959,50 @@ func (ec *executionContext) fieldContext_ChaosHub_repoBranch(ctx context.Context return fc, nil } +func (ec *executionContext) _ChaosHub_remoteHub(ctx context.Context, field graphql.CollectedField, obj *model.ChaosHub) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_ChaosHub_remoteHub(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.RemoteHub, 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) fieldContext_ChaosHub_remoteHub(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "ChaosHub", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type String does not have child fields") + }, + } + return fc, nil +} + func (ec *executionContext) _ChaosHub_projectID(ctx context.Context, field graphql.CollectedField, obj *model.ChaosHub) (ret graphql.Marshaler) { fc, err := ec.fieldContext_ChaosHub_projectID(ctx, field) if err != nil { @@ -11675,6 +11919,50 @@ func (ec *executionContext) fieldContext_ChaosHubStatus_repoBranch(ctx context.C return fc, nil } +func (ec *executionContext) _ChaosHubStatus_remoteHub(ctx context.Context, field graphql.CollectedField, obj *model.ChaosHubStatus) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_ChaosHubStatus_remoteHub(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.RemoteHub, 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) fieldContext_ChaosHubStatus_remoteHub(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "ChaosHubStatus", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type String does not have child fields") + }, + } + return fc, nil +} + func (ec *executionContext) _ChaosHubStatus_isAvailable(ctx context.Context, field graphql.CollectedField, obj *model.ChaosHubStatus) (ret graphql.Marshaler) { fc, err := ec.fieldContext_ChaosHubStatus_isAvailable(ctx, field) if err != nil { @@ -21029,6 +21317,142 @@ func (ec *executionContext) fieldContext_K8SProbe_operation(ctx context.Context, return fc, nil } +func (ec *executionContext) _KubeNamespace_name(ctx context.Context, field graphql.CollectedField, obj *model.KubeNamespace) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_KubeNamespace_name(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Name, 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) fieldContext_KubeNamespace_name(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "KubeNamespace", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type String does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _KubeNamespaceResponse_infraID(ctx context.Context, field graphql.CollectedField, obj *model.KubeNamespaceResponse) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_KubeNamespaceResponse_infraID(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.InfraID, 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.marshalNID2string(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_KubeNamespaceResponse_infraID(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "KubeNamespaceResponse", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type ID does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _KubeNamespaceResponse_kubeNamespace(ctx context.Context, field graphql.CollectedField, obj *model.KubeNamespaceResponse) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_KubeNamespaceResponse_kubeNamespace(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.KubeNamespace, 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.([]*model.KubeNamespace) + fc.Result = res + return ec.marshalNKubeNamespace2ᚕᚖgithubᚗcomᚋlitmuschaosᚋlitmusᚋchaoscenterᚋgraphqlᚋserverᚋgraphᚋmodelᚐKubeNamespace(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_KubeNamespaceResponse_kubeNamespace(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "KubeNamespaceResponse", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "name": + return ec.fieldContext_KubeNamespace_name(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type KubeNamespace", field.Name) + }, + } + return fc, nil +} + func (ec *executionContext) _KubeObject_namespace(ctx context.Context, field graphql.CollectedField, obj *model.KubeObject) (ret graphql.Marshaler) { fc, err := ec.fieldContext_KubeObject_namespace(ctx, field) if err != nil { @@ -21193,9 +21617,9 @@ func (ec *executionContext) _KubeObjectResponse_kubeObj(ctx context.Context, fie } return graphql.Null } - res := resTmp.([]*model.KubeObject) + res := resTmp.(*model.KubeObject) fc.Result = res - return ec.marshalNKubeObject2ᚕᚖgithubᚗcomᚋlitmuschaosᚋlitmusᚋchaoscenterᚋgraphqlᚋserverᚋgraphᚋmodelᚐKubeObject(ctx, field.Selections, res) + return ec.marshalNKubeObject2ᚖgithubᚗcomᚋlitmuschaosᚋlitmusᚋchaoscenterᚋgraphqlᚋserverᚋgraphᚋmodelᚐKubeObject(ctx, field.Selections, res) } func (ec *executionContext) fieldContext_KubeObjectResponse_kubeObj(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { @@ -23980,6 +24404,61 @@ func (ec *executionContext) fieldContext_Mutation_kubeObj(ctx context.Context, f return fc, nil } +func (ec *executionContext) _Mutation_kubeNamespace(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Mutation_kubeNamespace(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Mutation().KubeNamespace(rctx, fc.Args["request"].(model.KubeNamespaceData)) + }) + 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) fieldContext_Mutation_kubeNamespace(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Mutation", + Field: field, + IsMethod: true, + IsResolver: true, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type String does not have child fields") + }, + } + defer func() { + if r := recover(); r != nil { + err = ec.Recover(ctx, r) + ec.Error(ctx, err) + } + }() + ctx = graphql.WithFieldContext(ctx, fc) + if fc.Args, err = ec.field_Mutation_kubeNamespace_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return fc, err + } + return fc, nil +} + func (ec *executionContext) _Mutation_addChaosHub(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { fc, err := ec.fieldContext_Mutation_addChaosHub(ctx, field) if err != nil { @@ -24045,6 +24524,8 @@ func (ec *executionContext) fieldContext_Mutation_addChaosHub(ctx context.Contex return ec.fieldContext_ChaosHub_repoURL(ctx, field) case "repoBranch": return ec.fieldContext_ChaosHub_repoBranch(ctx, field) + case "remoteHub": + return ec.fieldContext_ChaosHub_remoteHub(ctx, field) case "projectID": return ec.fieldContext_ChaosHub_projectID(ctx, field) case "isDefault": @@ -24164,6 +24645,8 @@ func (ec *executionContext) fieldContext_Mutation_addRemoteChaosHub(ctx context. return ec.fieldContext_ChaosHub_repoURL(ctx, field) case "repoBranch": return ec.fieldContext_ChaosHub_repoBranch(ctx, field) + case "remoteHub": + return ec.fieldContext_ChaosHub_remoteHub(ctx, field) case "projectID": return ec.fieldContext_ChaosHub_projectID(ctx, field) case "isDefault": @@ -24283,6 +24766,8 @@ func (ec *executionContext) fieldContext_Mutation_saveChaosHub(ctx context.Conte return ec.fieldContext_ChaosHub_repoURL(ctx, field) case "repoBranch": return ec.fieldContext_ChaosHub_repoBranch(ctx, field) + case "remoteHub": + return ec.fieldContext_ChaosHub_remoteHub(ctx, field) case "projectID": return ec.fieldContext_ChaosHub_projectID(ctx, field) case "isDefault": @@ -24547,6 +25032,8 @@ func (ec *executionContext) fieldContext_Mutation_updateChaosHub(ctx context.Con return ec.fieldContext_ChaosHub_repoURL(ctx, field) case "repoBranch": return ec.fieldContext_ChaosHub_repoBranch(ctx, field) + case "remoteHub": + return ec.fieldContext_ChaosHub_remoteHub(ctx, field) case "projectID": return ec.fieldContext_ChaosHub_projectID(ctx, field) case "isDefault": @@ -29227,6 +29714,8 @@ func (ec *executionContext) fieldContext_Query_listChaosHub(ctx context.Context, return ec.fieldContext_ChaosHubStatus_repoURL(ctx, field) case "repoBranch": return ec.fieldContext_ChaosHubStatus_repoBranch(ctx, field) + case "remoteHub": + return ec.fieldContext_ChaosHubStatus_remoteHub(ctx, field) case "isAvailable": return ec.fieldContext_ChaosHubStatus_isAvailable(ctx, field) case "totalFaults": @@ -29352,6 +29841,8 @@ func (ec *executionContext) fieldContext_Query_getChaosHub(ctx context.Context, return ec.fieldContext_ChaosHubStatus_repoURL(ctx, field) case "repoBranch": return ec.fieldContext_ChaosHubStatus_repoBranch(ctx, field) + case "remoteHub": + return ec.fieldContext_ChaosHubStatus_remoteHub(ctx, field) case "isAvailable": return ec.fieldContext_ChaosHubStatus_isAvailable(ctx, field) case "totalFaults": @@ -32901,6 +33392,81 @@ func (ec *executionContext) fieldContext_Subscription_getKubeObject(ctx context. return fc, nil } +func (ec *executionContext) _Subscription_getKubeNamespace(ctx context.Context, field graphql.CollectedField) (ret func(ctx context.Context) graphql.Marshaler) { + fc, err := ec.fieldContext_Subscription_getKubeNamespace(ctx, field) + if err != nil { + return nil + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = nil + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Subscription().GetKubeNamespace(rctx, fc.Args["request"].(model.KubeNamespaceRequest)) + }) + 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(ctx context.Context) graphql.Marshaler { + select { + case res, ok := <-resTmp.(<-chan *model.KubeNamespaceResponse): + if !ok { + return nil + } + return graphql.WriterFunc(func(w io.Writer) { + w.Write([]byte{'{'}) + graphql.MarshalString(field.Alias).MarshalGQL(w) + w.Write([]byte{':'}) + ec.marshalNKubeNamespaceResponse2ᚖgithubᚗcomᚋlitmuschaosᚋlitmusᚋchaoscenterᚋgraphqlᚋserverᚋgraphᚋmodelᚐKubeNamespaceResponse(ctx, field.Selections, res).MarshalGQL(w) + w.Write([]byte{'}'}) + }) + case <-ctx.Done(): + return nil + } + } +} + +func (ec *executionContext) fieldContext_Subscription_getKubeNamespace(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Subscription", + Field: field, + IsMethod: true, + IsResolver: true, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "infraID": + return ec.fieldContext_KubeNamespaceResponse_infraID(ctx, field) + case "kubeNamespace": + return ec.fieldContext_KubeNamespaceResponse_kubeNamespace(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type KubeNamespaceResponse", field.Name) + }, + } + defer func() { + if r := recover(); r != nil { + err = ec.Recover(ctx, r) + ec.Error(ctx, err) + } + }() + ctx = graphql.WithFieldContext(ctx, fc) + if fc.Args, err = ec.field_Subscription_getKubeNamespace_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return fc, err + } + return fc, nil +} + func (ec *executionContext) _UserDetails_userID(ctx context.Context, field graphql.CollectedField, obj *model.UserDetails) (ret graphql.Marshaler) { fc, err := ec.fieldContext_UserDetails_userID(ctx, field) if err != nil { @@ -35136,7 +35702,7 @@ func (ec *executionContext) unmarshalInputCloningInput(ctx context.Context, obj asMap[k] = v } - fieldsInOrder := [...]string{"name", "repoBranch", "repoURL", "isPrivate", "authType", "token", "userName", "password", "sshPrivateKey", "isDefault"} + fieldsInOrder := [...]string{"name", "repoBranch", "repoURL", "remoteHub", "isPrivate", "authType", "token", "userName", "password", "sshPrivateKey", "isDefault"} for _, k := range fieldsInOrder { v, ok := asMap[k] if !ok { @@ -35164,6 +35730,13 @@ func (ec *executionContext) unmarshalInputCloningInput(ctx context.Context, obj return it, err } it.RepoURL = data + case "remoteHub": + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("remoteHub")) + data, err := ec.unmarshalNString2string(ctx, v) + if err != nil { + return it, err + } + it.RemoteHub = data case "isPrivate": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("isPrivate")) data, err := ec.unmarshalNBoolean2bool(ctx, v) @@ -35267,7 +35840,7 @@ func (ec *executionContext) unmarshalInputCreateChaosHubRequest(ctx context.Cont asMap[k] = v } - fieldsInOrder := [...]string{"name", "tags", "description", "repoURL", "repoBranch", "isPrivate", "authType", "token", "userName", "password", "sshPrivateKey", "sshPublicKey"} + fieldsInOrder := [...]string{"name", "tags", "description", "repoURL", "repoBranch", "remoteHub", "isPrivate", "authType", "token", "userName", "password", "sshPrivateKey", "sshPublicKey"} for _, k := range fieldsInOrder { v, ok := asMap[k] if !ok { @@ -35309,6 +35882,13 @@ func (ec *executionContext) unmarshalInputCreateChaosHubRequest(ctx context.Cont return it, err } it.RepoBranch = data + case "remoteHub": + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("remoteHub")) + data, err := ec.unmarshalNString2string(ctx, v) + if err != nil { + return it, err + } + it.RemoteHub = data case "isPrivate": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("isPrivate")) data, err := ec.unmarshalNBoolean2bool(ctx, v) @@ -35426,7 +36006,7 @@ func (ec *executionContext) unmarshalInputCreateRemoteChaosHub(ctx context.Conte asMap[k] = v } - fieldsInOrder := [...]string{"name", "tags", "description", "repoURL"} + fieldsInOrder := [...]string{"name", "tags", "description", "repoURL", "remoteHub"} for _, k := range fieldsInOrder { v, ok := asMap[k] if !ok { @@ -35461,6 +36041,13 @@ func (ec *executionContext) unmarshalInputCreateRemoteChaosHub(ctx context.Conte return it, err } it.RepoURL = data + case "remoteHub": + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("remoteHub")) + data, err := ec.unmarshalNString2string(ctx, v) + if err != nil { + return it, err + } + it.RemoteHub = data } } @@ -36520,6 +37107,74 @@ func (ec *executionContext) unmarshalInputKubeGVRRequest(ctx context.Context, ob return it, nil } +func (ec *executionContext) unmarshalInputKubeNamespaceData(ctx context.Context, obj interface{}) (model.KubeNamespaceData, error) { + var it model.KubeNamespaceData + asMap := map[string]interface{}{} + for k, v := range obj.(map[string]interface{}) { + asMap[k] = v + } + + fieldsInOrder := [...]string{"requestID", "infraID", "kubeNamespace"} + for _, k := range fieldsInOrder { + v, ok := asMap[k] + if !ok { + continue + } + switch k { + case "requestID": + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("requestID")) + data, err := ec.unmarshalNID2string(ctx, v) + if err != nil { + return it, err + } + it.RequestID = data + case "infraID": + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("infraID")) + data, err := ec.unmarshalNInfraIdentity2ᚖgithubᚗcomᚋlitmuschaosᚋlitmusᚋchaoscenterᚋgraphqlᚋserverᚋgraphᚋmodelᚐInfraIdentity(ctx, v) + if err != nil { + return it, err + } + it.InfraID = data + case "kubeNamespace": + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("kubeNamespace")) + data, err := ec.unmarshalNString2string(ctx, v) + if err != nil { + return it, err + } + it.KubeNamespace = data + } + } + + return it, nil +} + +func (ec *executionContext) unmarshalInputKubeNamespaceRequest(ctx context.Context, obj interface{}) (model.KubeNamespaceRequest, error) { + var it model.KubeNamespaceRequest + asMap := map[string]interface{}{} + for k, v := range obj.(map[string]interface{}) { + asMap[k] = v + } + + fieldsInOrder := [...]string{"infraID"} + for _, k := range fieldsInOrder { + v, ok := asMap[k] + if !ok { + continue + } + switch k { + case "infraID": + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("infraID")) + data, err := ec.unmarshalNID2string(ctx, v) + if err != nil { + return it, err + } + it.InfraID = data + } + } + + return it, nil +} + func (ec *executionContext) unmarshalInputKubeObjectData(ctx context.Context, obj interface{}) (model.KubeObjectData, error) { var it model.KubeObjectData asMap := map[string]interface{}{} @@ -36568,7 +37223,7 @@ func (ec *executionContext) unmarshalInputKubeObjectRequest(ctx context.Context, asMap[k] = v } - fieldsInOrder := [...]string{"infraID", "kubeObjRequest", "objectType", "workloads"} + fieldsInOrder := [...]string{"infraID", "kubeObjRequest", "namespace", "objectType", "workloads"} for _, k := range fieldsInOrder { v, ok := asMap[k] if !ok { @@ -36589,6 +37244,13 @@ func (ec *executionContext) unmarshalInputKubeObjectRequest(ctx context.Context, return it, err } it.KubeObjRequest = data + case "namespace": + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("namespace")) + data, err := ec.unmarshalNString2string(ctx, v) + if err != nil { + return it, err + } + it.Namespace = data case "objectType": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("objectType")) data, err := ec.unmarshalNString2string(ctx, v) @@ -37822,7 +38484,7 @@ func (ec *executionContext) unmarshalInputUpdateChaosHubRequest(ctx context.Cont asMap[k] = v } - fieldsInOrder := [...]string{"id", "name", "description", "tags", "repoURL", "repoBranch", "isPrivate", "authType", "token", "userName", "password", "sshPrivateKey", "sshPublicKey"} + fieldsInOrder := [...]string{"id", "name", "description", "tags", "repoURL", "repoBranch", "remoteHub", "isPrivate", "authType", "token", "userName", "password", "sshPrivateKey", "sshPublicKey"} for _, k := range fieldsInOrder { v, ok := asMap[k] if !ok { @@ -37871,6 +38533,13 @@ func (ec *executionContext) unmarshalInputUpdateChaosHubRequest(ctx context.Cont return it, err } it.RepoBranch = data + case "remoteHub": + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("remoteHub")) + data, err := ec.unmarshalNString2string(ctx, v) + if err != nil { + return it, err + } + it.RemoteHub = data case "isPrivate": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("isPrivate")) data, err := ec.unmarshalNBoolean2bool(ctx, v) @@ -38438,6 +39107,11 @@ func (ec *executionContext) _ChaosHub(ctx context.Context, sel ast.SelectionSet, if out.Values[i] == graphql.Null { out.Invalids++ } + case "remoteHub": + out.Values[i] = ec._ChaosHub_remoteHub(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } case "projectID": out.Values[i] = ec._ChaosHub_projectID(ctx, field, obj) if out.Values[i] == graphql.Null { @@ -38553,6 +39227,11 @@ func (ec *executionContext) _ChaosHubStatus(ctx context.Context, sel ast.Selecti if out.Values[i] == graphql.Null { out.Invalids++ } + case "remoteHub": + out.Values[i] = ec._ChaosHubStatus_remoteHub(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } case "isAvailable": out.Values[i] = ec._ChaosHubStatus_isAvailable(ctx, field, obj) if out.Values[i] == graphql.Null { @@ -39907,44 +40586,221 @@ func (ec *executionContext) _ImageRegistry(ctx context.Context, sel ast.Selectio return out } -var imageRegistryResponseImplementors = []string{"ImageRegistryResponse", "Audit"} +var imageRegistryResponseImplementors = []string{"ImageRegistryResponse", "Audit"} + +func (ec *executionContext) _ImageRegistryResponse(ctx context.Context, sel ast.SelectionSet, obj *model.ImageRegistryResponse) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, imageRegistryResponseImplementors) + + out := graphql.NewFieldSet(fields) + deferred := make(map[string]*graphql.FieldSet) + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("ImageRegistryResponse") + case "isDefault": + out.Values[i] = ec._ImageRegistryResponse_isDefault(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "imageRegistryInfo": + out.Values[i] = ec._ImageRegistryResponse_imageRegistryInfo(ctx, field, obj) + case "imageRegistryID": + out.Values[i] = ec._ImageRegistryResponse_imageRegistryID(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "projectID": + out.Values[i] = ec._ImageRegistryResponse_projectID(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "updatedAt": + out.Values[i] = ec._ImageRegistryResponse_updatedAt(ctx, field, obj) + case "createdAt": + out.Values[i] = ec._ImageRegistryResponse_createdAt(ctx, field, obj) + case "createdBy": + out.Values[i] = ec._ImageRegistryResponse_createdBy(ctx, field, obj) + case "updatedBy": + out.Values[i] = ec._ImageRegistryResponse_updatedBy(ctx, field, obj) + case "isRemoved": + out.Values[i] = ec._ImageRegistryResponse_isRemoved(ctx, field, obj) + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch(ctx) + if out.Invalids > 0 { + return graphql.Null + } + + atomic.AddInt32(&ec.deferred, int32(len(deferred))) + + for label, dfs := range deferred { + ec.processDeferredGroup(graphql.DeferredGroup{ + Label: label, + Path: graphql.GetPath(ctx), + FieldSet: dfs, + Context: ctx, + }) + } + + return out +} + +var infraImplementors = []string{"Infra", "ResourceDetails", "Audit"} + +func (ec *executionContext) _Infra(ctx context.Context, sel ast.SelectionSet, obj *model.Infra) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, infraImplementors) + + out := graphql.NewFieldSet(fields) + deferred := make(map[string]*graphql.FieldSet) + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("Infra") + case "projectID": + out.Values[i] = ec._Infra_projectID(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "infraID": + out.Values[i] = ec._Infra_infraID(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "name": + out.Values[i] = ec._Infra_name(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "description": + out.Values[i] = ec._Infra_description(ctx, field, obj) + case "tags": + out.Values[i] = ec._Infra_tags(ctx, field, obj) + case "environmentID": + out.Values[i] = ec._Infra_environmentID(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "platformName": + out.Values[i] = ec._Infra_platformName(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "isActive": + out.Values[i] = ec._Infra_isActive(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "isInfraConfirmed": + out.Values[i] = ec._Infra_isInfraConfirmed(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "isRemoved": + out.Values[i] = ec._Infra_isRemoved(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "updatedAt": + out.Values[i] = ec._Infra_updatedAt(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "createdAt": + out.Values[i] = ec._Infra_createdAt(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "noOfExperiments": + out.Values[i] = ec._Infra_noOfExperiments(ctx, field, obj) + case "noOfExperimentRuns": + out.Values[i] = ec._Infra_noOfExperimentRuns(ctx, field, obj) + case "token": + out.Values[i] = ec._Infra_token(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "infraNamespace": + out.Values[i] = ec._Infra_infraNamespace(ctx, field, obj) + case "serviceAccount": + out.Values[i] = ec._Infra_serviceAccount(ctx, field, obj) + case "infraScope": + out.Values[i] = ec._Infra_infraScope(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "infraNsExists": + out.Values[i] = ec._Infra_infraNsExists(ctx, field, obj) + case "infraSaExists": + out.Values[i] = ec._Infra_infraSaExists(ctx, field, obj) + case "lastExperimentTimestamp": + out.Values[i] = ec._Infra_lastExperimentTimestamp(ctx, field, obj) + case "startTime": + out.Values[i] = ec._Infra_startTime(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "version": + out.Values[i] = ec._Infra_version(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "createdBy": + out.Values[i] = ec._Infra_createdBy(ctx, field, obj) + case "updatedBy": + out.Values[i] = ec._Infra_updatedBy(ctx, field, obj) + case "infraType": + out.Values[i] = ec._Infra_infraType(ctx, field, obj) + case "updateStatus": + out.Values[i] = ec._Infra_updateStatus(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch(ctx) + if out.Invalids > 0 { + return graphql.Null + } + + atomic.AddInt32(&ec.deferred, int32(len(deferred))) + + for label, dfs := range deferred { + ec.processDeferredGroup(graphql.DeferredGroup{ + Label: label, + Path: graphql.GetPath(ctx), + FieldSet: dfs, + Context: ctx, + }) + } + + return out +} + +var infraActionResponseImplementors = []string{"InfraActionResponse"} -func (ec *executionContext) _ImageRegistryResponse(ctx context.Context, sel ast.SelectionSet, obj *model.ImageRegistryResponse) graphql.Marshaler { - fields := graphql.CollectFields(ec.OperationContext, sel, imageRegistryResponseImplementors) +func (ec *executionContext) _InfraActionResponse(ctx context.Context, sel ast.SelectionSet, obj *model.InfraActionResponse) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, infraActionResponseImplementors) out := graphql.NewFieldSet(fields) deferred := make(map[string]*graphql.FieldSet) for i, field := range fields { switch field.Name { case "__typename": - out.Values[i] = graphql.MarshalString("ImageRegistryResponse") - case "isDefault": - out.Values[i] = ec._ImageRegistryResponse_isDefault(ctx, field, obj) - if out.Values[i] == graphql.Null { - out.Invalids++ - } - case "imageRegistryInfo": - out.Values[i] = ec._ImageRegistryResponse_imageRegistryInfo(ctx, field, obj) - case "imageRegistryID": - out.Values[i] = ec._ImageRegistryResponse_imageRegistryID(ctx, field, obj) + out.Values[i] = graphql.MarshalString("InfraActionResponse") + case "projectID": + out.Values[i] = ec._InfraActionResponse_projectID(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } - case "projectID": - out.Values[i] = ec._ImageRegistryResponse_projectID(ctx, field, obj) + case "action": + out.Values[i] = ec._InfraActionResponse_action(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } - case "updatedAt": - out.Values[i] = ec._ImageRegistryResponse_updatedAt(ctx, field, obj) - case "createdAt": - out.Values[i] = ec._ImageRegistryResponse_createdAt(ctx, field, obj) - case "createdBy": - out.Values[i] = ec._ImageRegistryResponse_createdBy(ctx, field, obj) - case "updatedBy": - out.Values[i] = ec._ImageRegistryResponse_updatedBy(ctx, field, obj) - case "isRemoved": - out.Values[i] = ec._ImageRegistryResponse_isRemoved(ctx, field, obj) default: panic("unknown field " + strconv.Quote(field.Name)) } @@ -39968,113 +40824,39 @@ func (ec *executionContext) _ImageRegistryResponse(ctx context.Context, sel ast. return out } -var infraImplementors = []string{"Infra", "ResourceDetails", "Audit"} +var infraEventResponseImplementors = []string{"InfraEventResponse"} -func (ec *executionContext) _Infra(ctx context.Context, sel ast.SelectionSet, obj *model.Infra) graphql.Marshaler { - fields := graphql.CollectFields(ec.OperationContext, sel, infraImplementors) +func (ec *executionContext) _InfraEventResponse(ctx context.Context, sel ast.SelectionSet, obj *model.InfraEventResponse) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, infraEventResponseImplementors) out := graphql.NewFieldSet(fields) deferred := make(map[string]*graphql.FieldSet) for i, field := range fields { switch field.Name { case "__typename": - out.Values[i] = graphql.MarshalString("Infra") - case "projectID": - out.Values[i] = ec._Infra_projectID(ctx, field, obj) + out.Values[i] = graphql.MarshalString("InfraEventResponse") + case "eventID": + out.Values[i] = ec._InfraEventResponse_eventID(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } - case "infraID": - out.Values[i] = ec._Infra_infraID(ctx, field, obj) + case "eventType": + out.Values[i] = ec._InfraEventResponse_eventType(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } - case "name": - out.Values[i] = ec._Infra_name(ctx, field, obj) + case "eventName": + out.Values[i] = ec._InfraEventResponse_eventName(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } case "description": - out.Values[i] = ec._Infra_description(ctx, field, obj) - case "tags": - out.Values[i] = ec._Infra_tags(ctx, field, obj) - case "environmentID": - out.Values[i] = ec._Infra_environmentID(ctx, field, obj) - if out.Values[i] == graphql.Null { - out.Invalids++ - } - case "platformName": - out.Values[i] = ec._Infra_platformName(ctx, field, obj) - if out.Values[i] == graphql.Null { - out.Invalids++ - } - case "isActive": - out.Values[i] = ec._Infra_isActive(ctx, field, obj) - if out.Values[i] == graphql.Null { - out.Invalids++ - } - case "isInfraConfirmed": - out.Values[i] = ec._Infra_isInfraConfirmed(ctx, field, obj) - if out.Values[i] == graphql.Null { - out.Invalids++ - } - case "isRemoved": - out.Values[i] = ec._Infra_isRemoved(ctx, field, obj) - if out.Values[i] == graphql.Null { - out.Invalids++ - } - case "updatedAt": - out.Values[i] = ec._Infra_updatedAt(ctx, field, obj) - if out.Values[i] == graphql.Null { - out.Invalids++ - } - case "createdAt": - out.Values[i] = ec._Infra_createdAt(ctx, field, obj) - if out.Values[i] == graphql.Null { - out.Invalids++ - } - case "noOfExperiments": - out.Values[i] = ec._Infra_noOfExperiments(ctx, field, obj) - case "noOfExperimentRuns": - out.Values[i] = ec._Infra_noOfExperimentRuns(ctx, field, obj) - case "token": - out.Values[i] = ec._Infra_token(ctx, field, obj) - if out.Values[i] == graphql.Null { - out.Invalids++ - } - case "infraNamespace": - out.Values[i] = ec._Infra_infraNamespace(ctx, field, obj) - case "serviceAccount": - out.Values[i] = ec._Infra_serviceAccount(ctx, field, obj) - case "infraScope": - out.Values[i] = ec._Infra_infraScope(ctx, field, obj) - if out.Values[i] == graphql.Null { - out.Invalids++ - } - case "infraNsExists": - out.Values[i] = ec._Infra_infraNsExists(ctx, field, obj) - case "infraSaExists": - out.Values[i] = ec._Infra_infraSaExists(ctx, field, obj) - case "lastExperimentTimestamp": - out.Values[i] = ec._Infra_lastExperimentTimestamp(ctx, field, obj) - case "startTime": - out.Values[i] = ec._Infra_startTime(ctx, field, obj) - if out.Values[i] == graphql.Null { - out.Invalids++ - } - case "version": - out.Values[i] = ec._Infra_version(ctx, field, obj) + out.Values[i] = ec._InfraEventResponse_description(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } - case "createdBy": - out.Values[i] = ec._Infra_createdBy(ctx, field, obj) - case "updatedBy": - out.Values[i] = ec._Infra_updatedBy(ctx, field, obj) - case "infraType": - out.Values[i] = ec._Infra_infraType(ctx, field, obj) - case "updateStatus": - out.Values[i] = ec._Infra_updateStatus(ctx, field, obj) + case "infra": + out.Values[i] = ec._InfraEventResponse_infra(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } @@ -40101,24 +40883,24 @@ func (ec *executionContext) _Infra(ctx context.Context, sel ast.SelectionSet, ob return out } -var infraActionResponseImplementors = []string{"InfraActionResponse"} +var infraVersionDetailsImplementors = []string{"InfraVersionDetails"} -func (ec *executionContext) _InfraActionResponse(ctx context.Context, sel ast.SelectionSet, obj *model.InfraActionResponse) graphql.Marshaler { - fields := graphql.CollectFields(ec.OperationContext, sel, infraActionResponseImplementors) +func (ec *executionContext) _InfraVersionDetails(ctx context.Context, sel ast.SelectionSet, obj *model.InfraVersionDetails) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, infraVersionDetailsImplementors) out := graphql.NewFieldSet(fields) deferred := make(map[string]*graphql.FieldSet) for i, field := range fields { switch field.Name { case "__typename": - out.Values[i] = graphql.MarshalString("InfraActionResponse") - case "projectID": - out.Values[i] = ec._InfraActionResponse_projectID(ctx, field, obj) + out.Values[i] = graphql.MarshalString("InfraVersionDetails") + case "latestVersion": + out.Values[i] = ec._InfraVersionDetails_latestVersion(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } - case "action": - out.Values[i] = ec._InfraActionResponse_action(ctx, field, obj) + case "compatibleVersions": + out.Values[i] = ec._InfraVersionDetails_compatibleVersions(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } @@ -40145,39 +40927,61 @@ func (ec *executionContext) _InfraActionResponse(ctx context.Context, sel ast.Se return out } -var infraEventResponseImplementors = []string{"InfraEventResponse"} +var k8SProbeImplementors = []string{"K8SProbe", "CommonProbeProperties"} -func (ec *executionContext) _InfraEventResponse(ctx context.Context, sel ast.SelectionSet, obj *model.InfraEventResponse) graphql.Marshaler { - fields := graphql.CollectFields(ec.OperationContext, sel, infraEventResponseImplementors) +func (ec *executionContext) _K8SProbe(ctx context.Context, sel ast.SelectionSet, obj *model.K8SProbe) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, k8SProbeImplementors) out := graphql.NewFieldSet(fields) deferred := make(map[string]*graphql.FieldSet) for i, field := range fields { switch field.Name { case "__typename": - out.Values[i] = graphql.MarshalString("InfraEventResponse") - case "eventID": - out.Values[i] = ec._InfraEventResponse_eventID(ctx, field, obj) + out.Values[i] = graphql.MarshalString("K8SProbe") + case "probeTimeout": + out.Values[i] = ec._K8SProbe_probeTimeout(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } - case "eventType": - out.Values[i] = ec._InfraEventResponse_eventType(ctx, field, obj) + case "interval": + out.Values[i] = ec._K8SProbe_interval(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } - case "eventName": - out.Values[i] = ec._InfraEventResponse_eventName(ctx, field, obj) + case "retry": + out.Values[i] = ec._K8SProbe_retry(ctx, field, obj) + case "attempt": + out.Values[i] = ec._K8SProbe_attempt(ctx, field, obj) + case "probePollingInterval": + out.Values[i] = ec._K8SProbe_probePollingInterval(ctx, field, obj) + case "initialDelay": + out.Values[i] = ec._K8SProbe_initialDelay(ctx, field, obj) + case "evaluationTimeout": + out.Values[i] = ec._K8SProbe_evaluationTimeout(ctx, field, obj) + case "stopOnFailure": + out.Values[i] = ec._K8SProbe_stopOnFailure(ctx, field, obj) + case "group": + out.Values[i] = ec._K8SProbe_group(ctx, field, obj) + case "version": + out.Values[i] = ec._K8SProbe_version(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } - case "description": - out.Values[i] = ec._InfraEventResponse_description(ctx, field, obj) + case "resource": + out.Values[i] = ec._K8SProbe_resource(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } - case "infra": - out.Values[i] = ec._InfraEventResponse_infra(ctx, field, obj) + case "namespace": + out.Values[i] = ec._K8SProbe_namespace(ctx, field, obj) + case "resourceNames": + out.Values[i] = ec._K8SProbe_resourceNames(ctx, field, obj) + case "fieldSelector": + out.Values[i] = ec._K8SProbe_fieldSelector(ctx, field, obj) + case "labelSelector": + out.Values[i] = ec._K8SProbe_labelSelector(ctx, field, obj) + case "operation": + out.Values[i] = ec._K8SProbe_operation(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } @@ -40204,24 +41008,19 @@ func (ec *executionContext) _InfraEventResponse(ctx context.Context, sel ast.Sel return out } -var infraVersionDetailsImplementors = []string{"InfraVersionDetails"} +var kubeNamespaceImplementors = []string{"KubeNamespace"} -func (ec *executionContext) _InfraVersionDetails(ctx context.Context, sel ast.SelectionSet, obj *model.InfraVersionDetails) graphql.Marshaler { - fields := graphql.CollectFields(ec.OperationContext, sel, infraVersionDetailsImplementors) +func (ec *executionContext) _KubeNamespace(ctx context.Context, sel ast.SelectionSet, obj *model.KubeNamespace) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, kubeNamespaceImplementors) out := graphql.NewFieldSet(fields) deferred := make(map[string]*graphql.FieldSet) for i, field := range fields { switch field.Name { case "__typename": - out.Values[i] = graphql.MarshalString("InfraVersionDetails") - case "latestVersion": - out.Values[i] = ec._InfraVersionDetails_latestVersion(ctx, field, obj) - if out.Values[i] == graphql.Null { - out.Invalids++ - } - case "compatibleVersions": - out.Values[i] = ec._InfraVersionDetails_compatibleVersions(ctx, field, obj) + out.Values[i] = graphql.MarshalString("KubeNamespace") + case "name": + out.Values[i] = ec._KubeNamespace_name(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } @@ -40248,61 +41047,24 @@ func (ec *executionContext) _InfraVersionDetails(ctx context.Context, sel ast.Se return out } -var k8SProbeImplementors = []string{"K8SProbe", "CommonProbeProperties"} +var kubeNamespaceResponseImplementors = []string{"KubeNamespaceResponse"} -func (ec *executionContext) _K8SProbe(ctx context.Context, sel ast.SelectionSet, obj *model.K8SProbe) graphql.Marshaler { - fields := graphql.CollectFields(ec.OperationContext, sel, k8SProbeImplementors) +func (ec *executionContext) _KubeNamespaceResponse(ctx context.Context, sel ast.SelectionSet, obj *model.KubeNamespaceResponse) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, kubeNamespaceResponseImplementors) out := graphql.NewFieldSet(fields) deferred := make(map[string]*graphql.FieldSet) for i, field := range fields { switch field.Name { case "__typename": - out.Values[i] = graphql.MarshalString("K8SProbe") - case "probeTimeout": - out.Values[i] = ec._K8SProbe_probeTimeout(ctx, field, obj) - if out.Values[i] == graphql.Null { - out.Invalids++ - } - case "interval": - out.Values[i] = ec._K8SProbe_interval(ctx, field, obj) - if out.Values[i] == graphql.Null { - out.Invalids++ - } - case "retry": - out.Values[i] = ec._K8SProbe_retry(ctx, field, obj) - case "attempt": - out.Values[i] = ec._K8SProbe_attempt(ctx, field, obj) - case "probePollingInterval": - out.Values[i] = ec._K8SProbe_probePollingInterval(ctx, field, obj) - case "initialDelay": - out.Values[i] = ec._K8SProbe_initialDelay(ctx, field, obj) - case "evaluationTimeout": - out.Values[i] = ec._K8SProbe_evaluationTimeout(ctx, field, obj) - case "stopOnFailure": - out.Values[i] = ec._K8SProbe_stopOnFailure(ctx, field, obj) - case "group": - out.Values[i] = ec._K8SProbe_group(ctx, field, obj) - case "version": - out.Values[i] = ec._K8SProbe_version(ctx, field, obj) - if out.Values[i] == graphql.Null { - out.Invalids++ - } - case "resource": - out.Values[i] = ec._K8SProbe_resource(ctx, field, obj) + out.Values[i] = graphql.MarshalString("KubeNamespaceResponse") + case "infraID": + out.Values[i] = ec._KubeNamespaceResponse_infraID(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } - case "namespace": - out.Values[i] = ec._K8SProbe_namespace(ctx, field, obj) - case "resourceNames": - out.Values[i] = ec._K8SProbe_resourceNames(ctx, field, obj) - case "fieldSelector": - out.Values[i] = ec._K8SProbe_fieldSelector(ctx, field, obj) - case "labelSelector": - out.Values[i] = ec._K8SProbe_labelSelector(ctx, field, obj) - case "operation": - out.Values[i] = ec._K8SProbe_operation(ctx, field, obj) + case "kubeNamespace": + out.Values[i] = ec._KubeNamespaceResponse_kubeNamespace(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } @@ -41018,6 +41780,13 @@ func (ec *executionContext) _Mutation(ctx context.Context, sel ast.SelectionSet) if out.Values[i] == graphql.Null { out.Invalids++ } + case "kubeNamespace": + out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { + return ec._Mutation_kubeNamespace(ctx, field) + }) + if out.Values[i] == graphql.Null { + out.Invalids++ + } case "addChaosHub": out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { return ec._Mutation_addChaosHub(ctx, field) @@ -42921,6 +43690,8 @@ func (ec *executionContext) _Subscription(ctx context.Context, sel ast.Selection return ec._Subscription_getPodLog(ctx, fields[0]) case "getKubeObject": return ec._Subscription_getKubeObject(ctx, fields[0]) + case "getKubeNamespace": + return ec._Subscription_getKubeNamespace(ctx, fields[0]) default: panic("unknown field " + strconv.Quote(fields[0].Name)) } @@ -44223,7 +44994,7 @@ func (ec *executionContext) marshalNInt2int(ctx context.Context, sel ast.Selecti return res } -func (ec *executionContext) marshalNKubeObject2ᚕᚖgithubᚗcomᚋlitmuschaosᚋlitmusᚋchaoscenterᚋgraphqlᚋserverᚋgraphᚋmodelᚐKubeObject(ctx context.Context, sel ast.SelectionSet, v []*model.KubeObject) graphql.Marshaler { +func (ec *executionContext) marshalNKubeNamespace2ᚕᚖgithubᚗcomᚋlitmuschaosᚋlitmusᚋchaoscenterᚋgraphqlᚋserverᚋgraphᚋmodelᚐKubeNamespace(ctx context.Context, sel ast.SelectionSet, v []*model.KubeNamespace) graphql.Marshaler { ret := make(graphql.Array, len(v)) var wg sync.WaitGroup isLen1 := len(v) == 1 @@ -44247,7 +45018,7 @@ func (ec *executionContext) marshalNKubeObject2ᚕᚖgithubᚗcomᚋlitmuschaos if !isLen1 { defer wg.Done() } - ret[i] = ec.marshalOKubeObject2ᚖgithubᚗcomᚋlitmuschaosᚋlitmusᚋchaoscenterᚋgraphqlᚋserverᚋgraphᚋmodelᚐKubeObject(ctx, sel, v[i]) + ret[i] = ec.marshalOKubeNamespace2ᚖgithubᚗcomᚋlitmuschaosᚋlitmusᚋchaoscenterᚋgraphqlᚋserverᚋgraphᚋmodelᚐKubeNamespace(ctx, sel, v[i]) } if isLen1 { f(i) @@ -44261,6 +45032,40 @@ func (ec *executionContext) marshalNKubeObject2ᚕᚖgithubᚗcomᚋlitmuschaos return ret } +func (ec *executionContext) unmarshalNKubeNamespaceData2githubᚗcomᚋlitmuschaosᚋlitmusᚋchaoscenterᚋgraphqlᚋserverᚋgraphᚋmodelᚐKubeNamespaceData(ctx context.Context, v interface{}) (model.KubeNamespaceData, error) { + res, err := ec.unmarshalInputKubeNamespaceData(ctx, v) + return res, graphql.ErrorOnPath(ctx, err) +} + +func (ec *executionContext) unmarshalNKubeNamespaceRequest2githubᚗcomᚋlitmuschaosᚋlitmusᚋchaoscenterᚋgraphqlᚋserverᚋgraphᚋmodelᚐKubeNamespaceRequest(ctx context.Context, v interface{}) (model.KubeNamespaceRequest, error) { + res, err := ec.unmarshalInputKubeNamespaceRequest(ctx, v) + return res, graphql.ErrorOnPath(ctx, err) +} + +func (ec *executionContext) marshalNKubeNamespaceResponse2githubᚗcomᚋlitmuschaosᚋlitmusᚋchaoscenterᚋgraphqlᚋserverᚋgraphᚋmodelᚐKubeNamespaceResponse(ctx context.Context, sel ast.SelectionSet, v model.KubeNamespaceResponse) graphql.Marshaler { + return ec._KubeNamespaceResponse(ctx, sel, &v) +} + +func (ec *executionContext) marshalNKubeNamespaceResponse2ᚖgithubᚗcomᚋlitmuschaosᚋlitmusᚋchaoscenterᚋgraphqlᚋserverᚋgraphᚋmodelᚐKubeNamespaceResponse(ctx context.Context, sel ast.SelectionSet, v *model.KubeNamespaceResponse) graphql.Marshaler { + if v == nil { + if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { + ec.Errorf(ctx, "the requested element is null which the schema does not allow") + } + return graphql.Null + } + return ec._KubeNamespaceResponse(ctx, sel, v) +} + +func (ec *executionContext) marshalNKubeObject2ᚖgithubᚗcomᚋlitmuschaosᚋlitmusᚋchaoscenterᚋgraphqlᚋserverᚋgraphᚋmodelᚐKubeObject(ctx context.Context, sel ast.SelectionSet, v *model.KubeObject) graphql.Marshaler { + if v == nil { + if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { + ec.Errorf(ctx, "the requested element is null which the schema does not allow") + } + return graphql.Null + } + return ec._KubeObject(ctx, sel, v) +} + func (ec *executionContext) unmarshalNKubeObjectData2githubᚗcomᚋlitmuschaosᚋlitmusᚋchaoscenterᚋgraphqlᚋserverᚋgraphᚋmodelᚐKubeObjectData(ctx context.Context, v interface{}) (model.KubeObjectData, error) { res, err := ec.unmarshalInputKubeObjectData(ctx, v) return res, graphql.ErrorOnPath(ctx, err) @@ -45812,11 +46617,11 @@ func (ec *executionContext) unmarshalOKubeGVRRequest2ᚖgithubᚗcomᚋlitmuscha return &res, graphql.ErrorOnPath(ctx, err) } -func (ec *executionContext) marshalOKubeObject2ᚖgithubᚗcomᚋlitmuschaosᚋlitmusᚋchaoscenterᚋgraphqlᚋserverᚋgraphᚋmodelᚐKubeObject(ctx context.Context, sel ast.SelectionSet, v *model.KubeObject) graphql.Marshaler { +func (ec *executionContext) marshalOKubeNamespace2ᚖgithubᚗcomᚋlitmuschaosᚋlitmusᚋchaoscenterᚋgraphqlᚋserverᚋgraphᚋmodelᚐKubeNamespace(ctx context.Context, sel ast.SelectionSet, v *model.KubeNamespace) graphql.Marshaler { if v == nil { return graphql.Null } - return ec._KubeObject(ctx, sel, v) + return ec._KubeNamespace(ctx, sel, v) } func (ec *executionContext) marshalOKubernetesCMDProbe2ᚖgithubᚗcomᚋlitmuschaosᚋlitmusᚋchaoscenterᚋgraphqlᚋserverᚋgraphᚋmodelᚐKubernetesCMDProbe(ctx context.Context, sel ast.SelectionSet, v *model.KubernetesCMDProbe) graphql.Marshaler { diff --git a/chaoscenter/graphql/server/graph/model/models_gen.go b/chaoscenter/graphql/server/graph/model/models_gen.go index b4173ea00b2..9734945dfb1 100644 --- a/chaoscenter/graphql/server/graph/model/models_gen.go +++ b/chaoscenter/graphql/server/graph/model/models_gen.go @@ -138,6 +138,8 @@ type ChaosHub struct { RepoURL string `json:"repoURL"` // Branch of the git repository RepoBranch string `json:"repoBranch"` + // Connected Hub of remote repository + RemoteHub string `json:"remoteHub"` // ID of the project in which the chaos hub is present ProjectID string `json:"projectID"` // Default Hub Identifier @@ -213,6 +215,8 @@ type ChaosHubStatus struct { RepoURL string `json:"repoURL"` // Branch of the git repository RepoBranch string `json:"repoBranch"` + // Connected Hub of remote repository + RemoteHub string `json:"remoteHub"` // Bool value indicating whether the hub is available or not. IsAvailable bool `json:"isAvailable"` // Total number of experiments in the hub @@ -292,6 +296,8 @@ type CloningInput struct { RepoBranch string `json:"repoBranch"` // URL of the git repository RepoURL string `json:"repoURL"` + // Connected Hub of remote repository + RemoteHub string `json:"remoteHub"` // Bool value indicating whether the hub is private or not. IsPrivate bool `json:"isPrivate"` // Type of authentication used: BASIC, SSH, TOKEN @@ -344,6 +350,8 @@ type CreateChaosHubRequest struct { RepoURL string `json:"repoURL"` // Branch of the git repository RepoBranch string `json:"repoBranch"` + // Connected Hub of remote repository + RemoteHub string `json:"remoteHub"` // Bool value indicating whether the hub is private or not. IsPrivate bool `json:"isPrivate"` // Type of authentication used: BASIC, SSH, TOKEN @@ -377,6 +385,8 @@ type CreateRemoteChaosHub struct { Description *string `json:"description,omitempty"` // URL of the git repository RepoURL string `json:"repoURL"` + // Connected Hub of remote repository + RemoteHub string `json:"remoteHub"` } // Defines the start date and end date for the filtering the data @@ -1149,7 +1159,37 @@ type KubeGVRRequest struct { Resource string `json:"resource"` } -// KubeObject consists of the namespace and the available resources in the same +// Define name in the infra (not really useful at the moment but maybe we will need other field later) +type KubeNamespace struct { + // Name of the namespace + Name string `json:"name"` +} + +// Defines the details of Kubernetes namespace +type KubeNamespaceData struct { + // Unique request ID for fetching Kubernetes namespace details + RequestID string `json:"requestID"` + // ID of the infra in which the Kubernetes namespace is present + InfraID *InfraIdentity `json:"infraID"` + // List of KubeNamespace return by subscriber + KubeNamespace string `json:"kubeNamespace"` +} + +// Defines details for fetching Kubernetes namespace data +type KubeNamespaceRequest struct { + // ID of the infra + InfraID string `json:"infraID"` +} + +// Response received for querying Kubernetes Namespaces +type KubeNamespaceResponse struct { + // ID of the infra in which the Kubernetes namespace is present + InfraID string `json:"infraID"` + // List of the Kubernetes namespace + KubeNamespace []*KubeNamespace `json:"kubeNamespace"` +} + +// KubeObject consists of the available resources in a namespace type KubeObject struct { // Namespace of the resource Namespace string `json:"namespace"` @@ -1173,8 +1213,10 @@ type KubeObjectRequest struct { InfraID string `json:"infraID"` // GVR Request KubeObjRequest *KubeGVRRequest `json:"kubeObjRequest,omitempty"` - ObjectType string `json:"objectType"` - Workloads []*Workload `json:"workloads,omitempty"` + // Namespace in which the Kubernetes object is present + Namespace string `json:"namespace"` + ObjectType string `json:"objectType"` + Workloads []*Workload `json:"workloads,omitempty"` } // Response received for querying Kubernetes Object @@ -1182,7 +1224,7 @@ type KubeObjectResponse struct { // ID of the infra in which the Kubernetes object is present InfraID string `json:"infraID"` // Type of the Kubernetes object - KubeObj []*KubeObject `json:"kubeObj"` + KubeObj *KubeObject `json:"kubeObj"` } // Defines the CMD probe properties @@ -1945,6 +1987,8 @@ type UpdateChaosHubRequest struct { RepoURL string `json:"repoURL"` // Branch of the git repository RepoBranch string `json:"repoBranch"` + // Connected Hub of remote repository + RemoteHub string `json:"remoteHub"` // Bool value indicating whether the hub is private or not. IsPrivate bool `json:"isPrivate"` // Type of authentication used: BASIC, SSH, TOKEN diff --git a/chaoscenter/graphql/server/pkg/chaos_experiment/handler/handler.go b/chaoscenter/graphql/server/pkg/chaos_experiment/handler/handler.go index c2ff92baa35..ee51be6d05f 100644 --- a/chaoscenter/graphql/server/pkg/chaos_experiment/handler/handler.go +++ b/chaoscenter/graphql/server/pkg/chaos_experiment/handler/handler.go @@ -1234,7 +1234,33 @@ func (c *ChaosExperimentHandler) GetKubeObjData(reqID string, kubeObject model.K } else if reqChan, ok := r.KubeObjectData[reqID]; ok { resp := model.KubeObjectResponse{ InfraID: kubeObject.InfraID, - KubeObj: []*model.KubeObject{}, + KubeObj: &model.KubeObject{}, + } + reqChan <- &resp + close(reqChan) + } +} + +func (c *ChaosExperimentHandler) GetKubeNamespaceData(reqID string, kubeNamespace model.KubeNamespaceRequest, r store.StateData) { + reqType := "namespace" + data, err := json.Marshal(kubeNamespace) + if err != nil { + logrus.Print("ERROR WHILE MARSHALLING POD DETAILS") + } + externalData := string(data) + payload := model.InfraActionResponse{ + Action: &model.ActionPayload{ + RequestID: reqID, + RequestType: reqType, + ExternalData: &externalData, + }, + } + if clusterChan, ok := r.ConnectedInfra[kubeNamespace.InfraID]; ok { + clusterChan <- &payload + } else if reqChan, ok := r.KubeNamespaceData[reqID]; ok { + resp := model.KubeNamespaceResponse{ + InfraID: kubeNamespace.InfraID, + KubeNamespace: []*model.KubeNamespace{}, } reqChan <- &resp close(reqChan) diff --git a/chaoscenter/graphql/server/pkg/chaos_experiment_run/fuzz_tests/service_fuzz_test.go b/chaoscenter/graphql/server/pkg/chaos_experiment_run/fuzz_tests/service_fuzz_test.go new file mode 100644 index 00000000000..5ae50c6ef7b --- /dev/null +++ b/chaoscenter/graphql/server/pkg/chaos_experiment_run/fuzz_tests/service_fuzz_test.go @@ -0,0 +1,145 @@ +package fuzz_tests + +import ( + "context" + "testing" + + "github.com/litmuschaos/litmus/chaoscenter/graphql/server/pkg/chaos_experiment_run" + dbChaosExperiment "github.com/litmuschaos/litmus/chaoscenter/graphql/server/pkg/database/mongodb/chaos_experiment" + dbChaosExperimentRun "github.com/litmuschaos/litmus/chaoscenter/graphql/server/pkg/database/mongodb/chaos_experiment_run" + dbChaosInfra "github.com/litmuschaos/litmus/chaoscenter/graphql/server/pkg/database/mongodb/chaos_infrastructure" + dbMocks "github.com/litmuschaos/litmus/chaoscenter/graphql/server/pkg/database/mongodb/mocks" + + fuzz "github.com/AdaLogics/go-fuzz-headers" + store "github.com/litmuschaos/litmus/chaoscenter/graphql/server/pkg/data-store" + "github.com/litmuschaos/litmus/chaoscenter/graphql/server/pkg/database/mongodb" + "github.com/stretchr/testify/mock" + "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/mongo" +) + +type MockServices struct { + ChaosExperimentOperator *dbChaosExperiment.Operator + ChaosExperimentRunOperator *dbChaosExperimentRun.Operator + ChaosInfrastructureOperator *dbChaosInfra.Operator + MongodbOperator *dbMocks.MongoOperator + ChaosExperimentRunService chaos_experiment_run.Service +} + +func NewMockServices() *MockServices { + var ( + mongodbMockOperator = new(dbMocks.MongoOperator) + chaosExperimentOperator = dbChaosExperiment.NewChaosExperimentOperator(mongodbMockOperator) + chaosExperimentRunOperator = dbChaosExperimentRun.NewChaosExperimentRunOperator(mongodbMockOperator) + chaosInfrastructureOperator = dbChaosInfra.NewInfrastructureOperator(mongodbMockOperator) + chaosExperimentRunService chaos_experiment_run.Service = chaos_experiment_run.NewChaosExperimentRunService( + chaosExperimentOperator, + chaosInfrastructureOperator, + chaosExperimentRunOperator, + ) + ) + return &MockServices{ + ChaosExperimentOperator: chaosExperimentOperator, + ChaosExperimentRunOperator: chaosExperimentRunOperator, + ChaosInfrastructureOperator: chaosInfrastructureOperator, + MongodbOperator: mongodbMockOperator, + ChaosExperimentRunService: chaosExperimentRunService, + } +} + +func FuzzProcessExperimentRunDelete(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte) { + fuzzConsumer := fuzz.NewConsumer(data) + targetStruct := &struct { + Query bson.D + WorkflowRunID *string + ExperimentRun dbChaosExperimentRun.ChaosExperimentRun + Workflow dbChaosExperiment.ChaosExperimentRequest + Username string + StoreStateData *store.StateData + }{} + err := fuzzConsumer.GenerateStruct(targetStruct) + if err != nil { + return + } + mockServices := NewMockServices() + mockServices.MongodbOperator.On("Update", mock.Anything, mongodb.ChaosExperimentRunsCollection, mock.Anything, mock.Anything, mock.Anything).Return(&mongo.UpdateResult{}, nil).Once() + + err = mockServices.ChaosExperimentRunService.ProcessExperimentRunDelete( + context.Background(), + targetStruct.Query, + targetStruct.WorkflowRunID, + targetStruct.ExperimentRun, + targetStruct.Workflow, + targetStruct.Username, + targetStruct.StoreStateData, + ) + if err != nil { + t.Errorf("ProcessExperimentRunDelete() error = %v", err) + } + }) +} + +func FuzzProcessExperimentRunStop(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte) { + fuzzConsumer := fuzz.NewConsumer(data) + targetStruct := &struct { + Query bson.D + ExperimentRunID *string + Experiment dbChaosExperiment.ChaosExperimentRequest + Username string + ProjectID string + StoreStateData *store.StateData + }{} + err := fuzzConsumer.GenerateStruct(targetStruct) + if err != nil { + return + } + + mockServices := NewMockServices() + mockServices.MongodbOperator.On("Update", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&mongo.UpdateResult{}, nil).Once() + err = mockServices.ChaosExperimentRunService.ProcessExperimentRunStop( + context.Background(), + targetStruct.Query, + targetStruct.ExperimentRunID, + targetStruct.Experiment, + targetStruct.Username, + targetStruct.ProjectID, + targetStruct.StoreStateData, + ) + if err != nil { + t.Errorf("ProcessExperimentRunStop() error = %v", err) + } + }) +} + +func FuzzProcessCompletedExperimentRun(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte) { + fuzzConsumer := fuzz.NewConsumer(data) + targetStruct := &struct { + ExecData chaos_experiment_run.ExecutionData + WfID string + RunID string + }{} + err := fuzzConsumer.GenerateStruct(targetStruct) + if err != nil { + return + } + + findResult := []interface{}{bson.D{ + {Key: "experiment_id", Value: targetStruct.WfID}, + }} + mockServices := NewMockServices() + singleResult := mongo.NewSingleResultFromDocument(findResult[0], nil, nil) + mockServices.MongodbOperator.On("Get", mock.Anything, mock.Anything, mock.Anything).Return(singleResult, nil).Once() + + _, err = mockServices.ChaosExperimentRunService.ProcessCompletedExperimentRun( + targetStruct.ExecData, + targetStruct.WfID, + targetStruct.RunID, + ) + if err != nil { + t.Errorf("ProcessCompletedExperimentRun() error = %v", err) + } + }) +} diff --git a/chaoscenter/graphql/server/pkg/chaos_experiment_run/handler/fuzz_tests/handler_fuzz_test.go b/chaoscenter/graphql/server/pkg/chaos_experiment_run/handler/fuzz_tests/handler_fuzz_test.go new file mode 100644 index 00000000000..56af374f378 --- /dev/null +++ b/chaoscenter/graphql/server/pkg/chaos_experiment_run/handler/fuzz_tests/handler_fuzz_test.go @@ -0,0 +1,242 @@ +package fuzz_tests + +import ( + "context" + "strings" + "testing" + "time" + + "github.com/litmuschaos/litmus/chaoscenter/graphql/server/pkg/chaos_experiment_run/handler" + chaosInfraMocks "github.com/litmuschaos/litmus/chaoscenter/graphql/server/pkg/chaos_infrastructure/model/mocks" + dbChaosExperiment "github.com/litmuschaos/litmus/chaoscenter/graphql/server/pkg/database/mongodb/chaos_experiment" + dbChaosExperimentRun "github.com/litmuschaos/litmus/chaoscenter/graphql/server/pkg/database/mongodb/chaos_experiment_run" + dbMocks "github.com/litmuschaos/litmus/chaoscenter/graphql/server/pkg/database/mongodb/mocks" + dbGitOpsMocks "github.com/litmuschaos/litmus/chaoscenter/graphql/server/pkg/gitops/model/mocks" + + fuzz "github.com/AdaLogics/go-fuzz-headers" + + "github.com/google/uuid" + "github.com/litmuschaos/litmus/chaoscenter/graphql/server/graph/model" + typesMocks "github.com/litmuschaos/litmus/chaoscenter/graphql/server/pkg/chaos_experiment_run/model/mocks" + "github.com/litmuschaos/litmus/chaoscenter/graphql/server/pkg/database/mongodb" + "github.com/stretchr/testify/mock" + "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/mongo" +) + +type MockServices struct { + ChaosExperimentRunService *typesMocks.ChaosExperimentRunService + InfrastructureService *chaosInfraMocks.InfraService + GitOpsService *dbGitOpsMocks.GitOpsService + ChaosExperimentOperator *dbChaosExperiment.Operator + ChaosExperimentRunOperator *dbChaosExperimentRun.Operator + MongodbOperator *dbMocks.MongoOperator + ChaosExperimentRunHandler *handler.ChaosExperimentRunHandler +} + +func NewMockServices() *MockServices { + var ( + mongodbMockOperator = new(dbMocks.MongoOperator) + infrastructureService = new(chaosInfraMocks.InfraService) + gitOpsService = new(dbGitOpsMocks.GitOpsService) + chaosExperimentRunService = new(typesMocks.ChaosExperimentRunService) + chaosExperimentOperator = dbChaosExperiment.NewChaosExperimentOperator(mongodbMockOperator) + chaosExperimentRunOperator = dbChaosExperimentRun.NewChaosExperimentRunOperator(mongodbMockOperator) + ) + var chaosExperimentRunHandler = handler.NewChaosExperimentRunHandler( + chaosExperimentRunService, + infrastructureService, + gitOpsService, + chaosExperimentOperator, + chaosExperimentRunOperator, + mongodbMockOperator, + ) + return &MockServices{ + ChaosExperimentRunService: chaosExperimentRunService, + InfrastructureService: infrastructureService, + GitOpsService: gitOpsService, + ChaosExperimentOperator: chaosExperimentOperator, + ChaosExperimentRunOperator: chaosExperimentRunOperator, + MongodbOperator: mongodbMockOperator, + ChaosExperimentRunHandler: chaosExperimentRunHandler, + } +} + +func FuzzGetExperimentRun(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte) { + fuzzConsumer := fuzz.NewConsumer(data) + targetStruct := &struct { + ProjectID string + ExperimentRunID string + NotifyID string + }{} + + targetStruct.ProjectID = uuid.New().String() + + err := fuzzConsumer.GenerateStruct(targetStruct) + if err != nil { + return + } + + ctx := context.Background() + mockServices := NewMockServices() + findResult := []interface{}{bson.D{ + {Key: "experiment_run_id", Value: targetStruct.ExperimentRunID}, + {Key: "project_id", Value: targetStruct.ProjectID}, + {Key: "infra_id", Value: "mockInfraID"}, + {Key: "kubernetesInfraDetails", Value: bson.A{ + bson.D{ + {Key: "InfraID", Value: "mockInfraID"}, + {Key: "Name", Value: "MockInfra"}, + {Key: "EnvironmentID", Value: "mockEnvID"}, + {Key: "Description", Value: "Mock Infrastructure"}, + {Key: "PlatformName", Value: "Kubernetes"}, + {Key: "IsActive", Value: true}, + {Key: "UpdatedAt", Value: time.Now().Unix()}, + {Key: "CreatedAt", Value: time.Now().Unix()}, + }, + }}, + {Key: "experiment", Value: bson.A{ + bson.D{ + {Key: "ExperimentName", Value: "MockExperiment"}, + {Key: "ExperimentType", Value: "MockType"}, + {Key: "Revision", Value: bson.A{ + bson.D{ + {Key: "RevisionID", Value: uuid.NewString()}, + {Key: "ExperimentManifest", Value: "mockManifest"}, + {Key: "Weightages", Value: bson.A{ + bson.D{{Key: "FaultName", Value: "fault1"}, {Key: "Weightage", Value: 10}}, + bson.D{{Key: "FaultName", Value: "fault2"}, {Key: "Weightage", Value: 20}}, + }}, + }, + }}, + }, + }}, + }} + + cursor, _ := mongo.NewCursorFromDocuments(findResult, nil, nil) + mockServices.MongodbOperator.On("Aggregate", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(cursor, nil).Once() + + res, err := mockServices.ChaosExperimentRunHandler.GetExperimentRun(ctx, targetStruct.ProjectID, &targetStruct.ExperimentRunID, &targetStruct.NotifyID) + if err != nil { + t.Errorf("ChaosExperimentRunHandler.GetExperimentRun() error = %v", err) + return + } + if res == nil { + t.Errorf("Returned response is nil") + } + }) +} + +func FuzzListExperimentRun(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte) { + fuzzConsumer := fuzz.NewConsumer(data) + targetStruct := &struct { + ProjectID string + Request model.ListExperimentRunRequest + }{} + err := fuzzConsumer.GenerateStruct(targetStruct) + if err != nil { + return + } + + mockServices := NewMockServices() + findResult := []interface{}{bson.D{ + {Key: "project_id", Value: targetStruct.ProjectID}, + {Key: "infra_id", Value: "abc"}, + { + Key: "revision", Value: []dbChaosExperiment.ExperimentRevision{ + { + RevisionID: uuid.NewString(), + }, + }, + }, + }} + cursor, _ := mongo.NewCursorFromDocuments(findResult, nil, nil) + mockServices.MongodbOperator.On("Aggregate", mock.Anything, mongodb.ChaosExperimentRunsCollection, mock.Anything, mock.Anything).Return(cursor, nil).Once() + + res, err := mockServices.ChaosExperimentRunHandler.ListExperimentRun(targetStruct.ProjectID, targetStruct.Request) + if err != nil { + t.Errorf("ListExperimentRun() error = %v", err) + return + } + if res == nil { + t.Errorf("Returned response is nil") + } + + }) +} + +func FuzzRunChaosWorkFlow(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte) { + fuzzConsumer := fuzz.NewConsumer(data) + targetStruct := &struct { + ProjectID string + Workflow dbChaosExperiment.ChaosExperimentRequest + }{} + err := fuzzConsumer.GenerateStruct(targetStruct) + if err != nil { + return + } + + mockServices := NewMockServices() + mockServices.MongodbOperator.On("StartSession").Return(mock.Anything, nil).Once() + mockServices.MongodbOperator.On("Update", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&mongo.UpdateResult{}, nil).Once() + mockServices.MongodbOperator.On("CommitTransaction", mock.Anything).Return(nil).Once() + mockServices.MongodbOperator.On("AbortTransaction", mock.Anything).Return(nil).Once() + + findResult := []interface{}{bson.D{ + {Key: "infra_id", Value: targetStruct.ProjectID}, + }} + singleResult := mongo.NewSingleResultFromDocument(findResult[0], nil, nil) + mockServices.MongodbOperator.On("Get", mock.Anything, mock.Anything, mock.Anything).Return(singleResult, nil).Once() + + res, err := mockServices.ChaosExperimentRunHandler.RunChaosWorkFlow(context.Background(), targetStruct.ProjectID, targetStruct.Workflow, nil) + if strings.Contains(err.Error(), "inactive infra") { + t.Log("Handled expected error due to inactive infrastructure: ", err) + return + } + if res == nil { + t.Errorf("Returned response is nil") + } + }) +} + +func FuzzGetExperimentRunStats(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte) { + fuzzConsumer := fuzz.NewConsumer(data) + targetStruct := &struct { + ProjectID string + }{} + err := fuzzConsumer.GenerateStruct(targetStruct) + if err != nil { + return + } + targetStruct.ProjectID = uuid.New().String() + + mockServices := NewMockServices() + + findResult := []interface{}{bson.D{ + {Key: "project_id", Value: targetStruct.ProjectID}, + {Key: "infra_id", Value: "abc"}, + { + Key: "revision", Value: []dbChaosExperiment.ExperimentRevision{ + { + RevisionID: uuid.NewString(), + }, + }, + }, + }} + cursor, _ := mongo.NewCursorFromDocuments(findResult, nil, nil) + mockServices.MongodbOperator.On("Aggregate", mock.Anything, mongodb.ChaosExperimentRunsCollection, mock.Anything, mock.Anything).Return(cursor, nil).Once() + + res, err := mockServices.ChaosExperimentRunHandler.GetExperimentRunStats(context.Background(), targetStruct.ProjectID) + if err != nil { + t.Errorf("GetExperimentRunStats() error = %v", err) + return + } + if res == nil { + t.Errorf("Returned response is nil") + } + }) +} diff --git a/chaoscenter/graphql/server/pkg/chaos_infrastructure/fuzz/fuzz_test.go b/chaoscenter/graphql/server/pkg/chaos_infrastructure/fuzz/fuzz_test.go new file mode 100644 index 00000000000..b8fa0ff67b0 --- /dev/null +++ b/chaoscenter/graphql/server/pkg/chaos_infrastructure/fuzz/fuzz_test.go @@ -0,0 +1,656 @@ +package test + +import ( + "context" + "testing" + + "github.com/litmuschaos/litmus/chaoscenter/graphql/server/graph/model" + "github.com/litmuschaos/litmus/chaoscenter/graphql/server/pkg/chaos_experiment/handler" + chaosExperimentMocks "github.com/litmuschaos/litmus/chaoscenter/graphql/server/pkg/chaos_experiment/model/mocks" + chaosExperimentRunMocks "github.com/litmuschaos/litmus/chaoscenter/graphql/server/pkg/chaos_experiment_run/model/mocks" + chaosInfraMocks "github.com/litmuschaos/litmus/chaoscenter/graphql/server/pkg/chaos_infrastructure/model/mocks" + dbChaosExperiment "github.com/litmuschaos/litmus/chaoscenter/graphql/server/pkg/database/mongodb/chaos_experiment" + dbChaosExperimentRun "github.com/litmuschaos/litmus/chaoscenter/graphql/server/pkg/database/mongodb/chaos_experiment_run" + dbMocks "github.com/litmuschaos/litmus/chaoscenter/graphql/server/pkg/database/mongodb/mocks" + dbGitOpsMocks "github.com/litmuschaos/litmus/chaoscenter/graphql/server/pkg/gitops/model/mocks" + "go.mongodb.org/mongo-driver/bson" + + dbChaosInfra "github.com/litmuschaos/litmus/chaoscenter/graphql/server/pkg/database/mongodb/chaos_infrastructure" + dbOperationsEnvironment "github.com/litmuschaos/litmus/chaoscenter/graphql/server/pkg/database/mongodb/environments" + + fuzz "github.com/AdaLogics/go-fuzz-headers" + store "github.com/litmuschaos/litmus/chaoscenter/graphql/server/pkg/data-store" +) + +type MockServices struct { + ChaosExperimentService *chaosExperimentMocks.ChaosExperimentService + ChaosExperimentRunService *chaosExperimentRunMocks.ChaosExperimentRunService + InfrastructureService *chaosInfraMocks.InfraService + GitOpsService *dbGitOpsMocks.GitOpsService + ChaosExperimentOperator *dbChaosExperiment.Operator + ChaosExperimentRunOperator *dbChaosExperimentRun.Operator + MongodbOperator *dbMocks.MongoOperator + ChaosExperimentHandler *handler.ChaosExperimentHandler +} + +func NewMockServices() *MockServices { + var ( + mongodbMockOperator = new(dbMocks.MongoOperator) + infrastructureService = new(chaosInfraMocks.InfraService) + chaosExperimentRunService = new(chaosExperimentRunMocks.ChaosExperimentRunService) + gitOpsService = new(dbGitOpsMocks.GitOpsService) + chaosExperimentOperator = dbChaosExperiment.NewChaosExperimentOperator(mongodbMockOperator) + chaosExperimentRunOperator = dbChaosExperimentRun.NewChaosExperimentRunOperator(mongodbMockOperator) + chaosExperimentService = new(chaosExperimentMocks.ChaosExperimentService) + ) + var chaosExperimentHandler = handler.NewChaosExperimentHandler(chaosExperimentService, chaosExperimentRunService, infrastructureService, gitOpsService, chaosExperimentOperator, chaosExperimentRunOperator, mongodbMockOperator) + return &MockServices{ + ChaosExperimentService: chaosExperimentService, + ChaosExperimentRunService: chaosExperimentRunService, + InfrastructureService: infrastructureService, + GitOpsService: gitOpsService, + ChaosExperimentOperator: chaosExperimentOperator, + ChaosExperimentRunOperator: chaosExperimentRunOperator, + MongodbOperator: mongodbMockOperator, + ChaosExperimentHandler: chaosExperimentHandler, + } +} + +var ( + mongodbMockOperator = new(dbMocks.MongoOperator) + environmentOperator = dbOperationsEnvironment.NewEnvironmentOperator(mongodbMockOperator) +) + +func stringPointer(v string) *string { return &v } + +func FuzzRegisterInfra(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte) { + fuzzConsumer := fuzz.NewConsumer(data) + targetStruct := &struct { + projectID string + request model.RegisterInfraRequest + }{} + err := fuzzConsumer.GenerateStruct(targetStruct) + if err != nil { + return + } + ctx := context.Background() + mockServices := NewMockServices() + mockResponse := &model.RegisterInfraResponse{ + Token: "test-token", + InfraID: "test-infra-id", + Name: targetStruct.request.Name, + Manifest: "test-manifest", + } + mockServices.InfrastructureService. + On("RegisterInfra", ctx, targetStruct.projectID, targetStruct.request). + Return(mockResponse, nil) + + response, err := mockServices.InfrastructureService.RegisterInfra(ctx, targetStruct.projectID, targetStruct.request) + if response.Name != targetStruct.request.Name { + t.Errorf("Chaos Infrastructure Name is %s Return %s", response.Name, targetStruct.request.Name) + } + if err != nil { + t.Errorf("ChaosInfrastructure.RegisterInfra() error = %v", err) + return + } + if response == nil { + t.Errorf("Returned environment is nil") + } + }) + +} + +func FuzzDeleteInfra(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte) { + fuzzConsumer := fuzz.NewConsumer(data) + targetStruct := &struct { + projectID string + infraID string + r store.StateData + }{} + err := fuzzConsumer.GenerateStruct(targetStruct) + if err != nil { + return + } + + ctx := context.Background() + mockServices := NewMockServices() + + mockServices.InfrastructureService. + On("DeleteInfra", ctx, targetStruct.projectID, targetStruct.infraID, targetStruct.r). + Return("infra deleted successfully", nil) + + response, err := mockServices.InfrastructureService.DeleteInfra(ctx, targetStruct.projectID, targetStruct.infraID, targetStruct.r) + if err != nil { + t.Errorf("ChaosInfrastructure.RegisterInfra() error = %v", err) + return + } + if response == "" { + t.Errorf("Returned environment is nil") + } + + }) +} + +func FuzzGetInfraTest(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte) { + fuzzConsumer := fuzz.NewConsumer(data) + targetStruct := &struct { + projectID string + infraID string + }{} + + err := fuzzConsumer.GenerateStruct(targetStruct) + if err != nil { + return + } + + ctx := context.Background() + mockServices := NewMockServices() + + mockResponse := &model.Infra{ + InfraID: targetStruct.infraID, + ProjectID: targetStruct.projectID, + Name: "TestInfraName", + Description: nil, + Tags: []string{"tag1", "tag2"}, + EnvironmentID: "test-env-id", + PlatformName: "test-platform", + IsActive: true, + IsInfraConfirmed: true, + IsRemoved: false, + UpdatedAt: "1680000000", + CreatedAt: "1670000000", + Token: "test-token", + InfraNamespace: nil, + ServiceAccount: nil, + InfraScope: "test-scope", + StartTime: "1675000000", + Version: "1.0.0", + CreatedBy: &model.UserDetails{Username: "test-user"}, + UpdatedBy: &model.UserDetails{Username: "test-user"}, + NoOfExperiments: nil, + NoOfExperimentRuns: nil, + LastExperimentTimestamp: nil, + UpdateStatus: "UpToDate", + } + + mockServices.InfrastructureService. + On("GetInfra", context.Background(), targetStruct.projectID, targetStruct.infraID). + Return(mockResponse, nil) + + infra, err := mockServices.InfrastructureService.GetInfra(ctx, targetStruct.projectID, targetStruct.infraID) + if err != nil { + t.Errorf("ChaosInfrastructure.GetInfra() error = %v", err) + return + } + if infra.InfraID != targetStruct.infraID { + t.Errorf("ProjectID mismatch: got %v, want %v", infra.InfraID, targetStruct.infraID) + } + }) +} + +func FuzzListInfras(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte) { + fuzzConsumer := fuzz.NewConsumer(data) + targetStruct := &struct { + projectID string + request *model.ListInfraRequest + }{} + + err := fuzzConsumer.GenerateStruct(targetStruct) + if err != nil { + return + } + + mockServices := NewMockServices() + + mockResponse := &model.ListInfraResponse{ + TotalNoOfInfras: 10, + Infras: []*model.Infra{ + { + InfraID: "infra1", + ProjectID: targetStruct.projectID, + Name: "Test Infra", + EnvironmentID: "env1", + Description: stringPointer("Test description"), + PlatformName: "Test Platform", + IsActive: true, + IsInfraConfirmed: true, + UpdatedAt: "1622527200", + CreatedAt: "1622523600", + Token: "test-token", + InfraNamespace: stringPointer("test-namespace"), + ServiceAccount: stringPointer("test-service-account"), + InfraScope: "test-scope", + StartTime: "1622520000", + Version: "v1.0", + Tags: []string{"tag1", "tag2"}, + IsRemoved: false, + }, + }, + } + + mockServices.InfrastructureService.On("ListInfras", targetStruct.projectID, targetStruct.request). + Return(mockResponse, nil) + + response, err := mockServices.InfrastructureService.ListInfras(targetStruct.projectID, targetStruct.request) + if err != nil { + t.Errorf("ChaosInfrastructure.DeleteInfra() error = %v", err) + return + } + + if response.TotalNoOfInfras < 0 { + t.Errorf("Invalid TotalNoOfInfras: %d", response.TotalNoOfInfras) + } + for _, infra := range response.Infras { + if infra.InfraID == "" { + t.Errorf("InfraID should not be empty") + } + if infra.ProjectID != targetStruct.projectID { + t.Errorf("ProjectID mismatch: got %v, want %v", infra.ProjectID, targetStruct.projectID) + } + } + + }) +} + +func FuzzGetInfraDetails(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte) { + fuzzConsumer := fuzz.NewConsumer(data) + targetStruct := &struct { + InfraID string + projectID string + request *model.ListInfraRequest + }{} + + err := fuzzConsumer.GenerateStruct(targetStruct) + if err != nil { + return + } + + mockServices := NewMockServices() + mockResponse := &model.Infra{ + InfraID: targetStruct.InfraID, + ProjectID: targetStruct.projectID, + Name: "TestInfraName", + Description: nil, + Tags: []string{"tag1", "tag2"}, + EnvironmentID: "test-env-id", + PlatformName: "test-platform", + IsActive: true, + IsInfraConfirmed: true, + IsRemoved: false, + UpdatedAt: "1680000000", + CreatedAt: "1670000000", + Token: "test-token", + InfraNamespace: nil, + ServiceAccount: nil, + InfraScope: "test-scope", + StartTime: "1675000000", + Version: "1.0.0", + CreatedBy: &model.UserDetails{Username: "test-user"}, + UpdatedBy: &model.UserDetails{Username: "test-user"}, + NoOfExperiments: nil, + NoOfExperimentRuns: nil, + LastExperimentTimestamp: nil, + UpdateStatus: "UpToDate", + } + + mockServices.InfrastructureService. + On("GetInfra", context.Background(), targetStruct.projectID, targetStruct.InfraID). + Return(mockResponse, nil) + + mockServices.InfrastructureService. + On("GetInfraDetails", context.Background(), targetStruct.InfraID, targetStruct.projectID). + Return(mockResponse, nil) + + ctx := context.Background() + response, err := mockServices.InfrastructureService.GetInfraDetails(ctx, targetStruct.InfraID, targetStruct.projectID) + if err != nil { + t.Errorf("ChaosInfrastructure.DeleteInfra() error = %v", err) + return + } + if response.InfraID != targetStruct.InfraID { + t.Errorf("InfraID mismatch: got %v, want %v", response.InfraID, targetStruct.InfraID) + } + + }) +} + +func FuzzGetInfraStats(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte) { + fuzzConsumer := fuzz.NewConsumer(data) + targetStruct := &struct { + projectID string + }{} + + err := fuzzConsumer.GenerateStruct(targetStruct) + if err != nil { + return + } + + mockServices := NewMockServices() + mockResponse := &model.GetInfraStatsResponse{ + TotalInfrastructures: 10, + TotalActiveInfrastructure: 7, + TotalInactiveInfrastructures: 3, + TotalConfirmedInfrastructure: 8, + TotalNonConfirmedInfrastructures: 2, + } + + mockServices.InfrastructureService. + On("GetInfraStats", context.Background(), targetStruct.projectID). + Return(mockResponse, nil) + + ctx := context.Background() + response, err := mockServices.InfrastructureService.GetInfraStats(ctx, targetStruct.projectID) + if err != nil { + t.Errorf("ChaosInfrastructure.DeleteInfra() error = %v", err) + return + } + if response.TotalInfrastructures != mockResponse.TotalInfrastructures { + t.Errorf("TotalInfrastructures mismatch: got %v, want %v", response.TotalInfrastructures, mockResponse.TotalInfrastructures) + } + if response.TotalActiveInfrastructure != mockResponse.TotalActiveInfrastructure { + t.Errorf("TotalActiveInfrastructure mismatch: got %v, want %v", response.TotalActiveInfrastructure, mockResponse.TotalActiveInfrastructure) + } + if response.TotalInactiveInfrastructures != mockResponse.TotalInactiveInfrastructures { + t.Errorf("TotalInactiveInfrastructures mismatch: got %v, want %v", response.TotalInactiveInfrastructures, mockResponse.TotalInactiveInfrastructures) + } + if response.TotalConfirmedInfrastructure != mockResponse.TotalConfirmedInfrastructure { + t.Errorf("TotalConfirmedInfrastructure mismatch: got %v, want %v", response.TotalConfirmedInfrastructure, mockResponse.TotalConfirmedInfrastructure) + } + if response.TotalNonConfirmedInfrastructures != mockResponse.TotalNonConfirmedInfrastructures { + t.Errorf("TotalNonConfirmedInfrastructures mismatch: got %v, want %v", response.TotalNonConfirmedInfrastructures, mockResponse.TotalNonConfirmedInfrastructures) + } + + }) +} + +func FuzzGetVersionDetails(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte) { + mockServices := NewMockServices() + mockResponse := &model.InfraVersionDetails{ + LatestVersion: "testVersion1", + CompatibleVersions: []string{"compatibleVersion1", "compatibleVersion2"}, + } + + mockServices.InfrastructureService.On("GetVersionDetails").Return(mockResponse, nil) + response, err := mockServices.InfrastructureService.GetVersionDetails() + + if err != nil { + t.Errorf("infraService.GetVersionDetails() error = %v", err) + return + } + + if response == nil { + t.Errorf("Expected a non-nil response") + return + } + if response.LatestVersion == "" { + t.Errorf("Expected a valid latest version") + } + + }) +} + +func FuzzQueryServerVersion(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte) { + ctx := context.Background() + mockResponse := &model.ServerVersionResponse{ + Key: "version", + Value: string(data), + } + + mockServices := NewMockServices() + mockServices.InfrastructureService.On("GetConfig", ctx, "version").Return(mockResponse, nil) + mockServices.InfrastructureService.On("QueryServerVersion", ctx).Return(mockResponse, nil) + response, err := mockServices.InfrastructureService.QueryServerVersion(ctx) + if err != nil { + t.Errorf("QueryServerVersion() error = %v", err) + return + } + if response == nil { + t.Errorf("Expected a non-nil response") + return + } + if response.Key != "version" { + t.Errorf("Expected Key to be 'version', got %s", response.Key) + } + if response.Value != string(data) { + t.Errorf("Expected Value to be %s, got %s", string(data), response.Value) + } + }) +} + +func FuzzPodLog(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte) { + fuzzConsumer := fuzz.NewConsumer(data) + targetStruct := &struct { + request model.PodLog + r store.StateData + }{} + + err := fuzzConsumer.GenerateStruct(targetStruct) + if err != nil { + return + } + + mockServices := NewMockServices() + mockServices.InfrastructureService. + On("PodLog", targetStruct.request, targetStruct.r). + Return("LOGS SENT SUCCESSFULLY", nil) + response, err := mockServices.InfrastructureService.PodLog(targetStruct.request, targetStruct.r) + if err != nil { + t.Errorf("ChaosInfrastructure.PodLog() error = %v", err) + return + } + if response == "" { + t.Errorf("Returned environment is nil") + } + + }) +} + +func FuzzKubeObj(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte) { + fuzzConsumer := fuzz.NewConsumer(data) + targetStruct := &struct { + request model.KubeObjectData + r store.StateData + }{} + + err := fuzzConsumer.GenerateStruct(targetStruct) + if err != nil { + return + } + + mockServices := NewMockServices() + mockServices.InfrastructureService. + On("KubeObj", targetStruct.request, targetStruct.r). + Return("KubeData sent successfully", nil) + + response, err := mockServices.InfrastructureService.KubeObj(targetStruct.request, targetStruct.r) + if err != nil { + t.Errorf("ChaosInfrastructure.KubeObj() error = %v", err) + return + } + if response == "" { + t.Errorf("Returned environment is nil") + } + }) +} + +func FuzzSendInfraEvent(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte) { + fuzzConsumer := fuzz.NewConsumer(data) + targetStruct := &struct { + EventType string + EventName string + Description string + Infra model.Infra + R store.StateData + }{} + + err := fuzzConsumer.GenerateStruct(targetStruct) + if err != nil { + return + } + + mockServices := NewMockServices() + targetStruct.R.InfraEventPublish = make(map[string][]chan *model.InfraEventResponse) + projectID := targetStruct.Infra.ProjectID + if projectID != "" { + targetStruct.R.InfraEventPublish[projectID] = append(targetStruct.R.InfraEventPublish[projectID], make(chan *model.InfraEventResponse, 1)) + } + + mockServices.InfrastructureService.SendInfraEvent(targetStruct.EventType, targetStruct.EventName, targetStruct.Description, targetStruct.Infra, targetStruct.R) + + if projectID != "" { + select { + case event := <-targetStruct.R.InfraEventPublish[projectID][0]: + if event == nil { + t.Errorf("Expected non-nil event") + } + if event.EventType != targetStruct.EventType { + t.Errorf("Expected EventType to be %s, got %s", targetStruct.EventType, event.EventType) + } + if event.EventName != targetStruct.EventName { + t.Errorf("Expected EventName to be %s, got %s", targetStruct.EventName, event.EventName) + } + if event.Description != targetStruct.Description { + t.Errorf("Expected Description to be %s, got %s", targetStruct.Description, event.Description) + } + if event.Infra != &targetStruct.Infra { + t.Errorf("Expected Infra to be %+v, got %+v", targetStruct.Infra, event.Infra) + } + default: + t.Errorf("Expected an event to be published") + } + } + }) +} +func FuzzConfirmInfraRegistration(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte) { + fuzzConsumer := fuzz.NewConsumer(data) + targetStruct := &struct { + request model.InfraIdentity + r store.StateData + }{} + + err := fuzzConsumer.GenerateStruct(targetStruct) + if err != nil { + return + } + + mockServices := NewMockServices() + mockServices.InfrastructureService. + On("ConfirmInfraRegistration", targetStruct.request, targetStruct.r). + Return(&model.ConfirmInfraRegistrationResponse{ + IsInfraConfirmed: true, + NewAccessKey: &targetStruct.request.AccessKey, + InfraID: &targetStruct.request.InfraID, + }, nil) + + response, err := mockServices.InfrastructureService.ConfirmInfraRegistration(targetStruct.request, targetStruct.r) + if err != nil { + t.Errorf("ChaosInfrastructure.ConfirmInfraRegistration() error = %v", err) + return + } + if response == nil { + t.Errorf("Returned environment is nil") + } + + }) +} + +func FuzzVerifyInfra(f *testing.F) { + + f.Fuzz(func(t *testing.T, data []byte) { + fuzzConsumer := fuzz.NewConsumer(data) + request := model.InfraIdentity{} + err := fuzzConsumer.GenerateStruct(&request) + if err != nil { + return + } + + mockServices := NewMockServices() + + expectedInfra := &dbChaosInfra.ChaosInfra{ + InfraID: request.InfraID, + AccessKey: request.AccessKey, + IsRegistered: true, + Version: request.Version, + } + + mockServices.InfrastructureService. + On("VerifyInfra", request). + Return(expectedInfra, nil) + + response, err := mockServices.InfrastructureService.VerifyInfra(request) + if err != nil { + t.Errorf("ChaosInfrastructure.VerifyInfra() error = %v", err) + return + } + if response == nil { + t.Errorf("Returned environment is nil") + } + + }) +} +func FuzzUpdateInfra(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte) { + fuzzConsumer := fuzz.NewConsumer(data) + targetStruct := &struct { + query bson.D + update bson.D + }{} + + err := fuzzConsumer.GenerateStruct(targetStruct) + if err != nil { + return + } + + mockServices := NewMockServices() + mockServices.InfrastructureService. + On("UpdateInfra", targetStruct.query, targetStruct.update). + Return(nil) + + err = mockServices.InfrastructureService.UpdateInfra(targetStruct.query, targetStruct.update) + if err != nil { + t.Errorf("ChaosInfrastructure.UpdateInfra() error = %v", err) + return + } + + }) +} +func FuzzGetDBInfra(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte) { + fuzzConsumer := fuzz.NewConsumer(data) + var infraID string + err := fuzzConsumer.GenerateStruct(&infraID) + if err != nil { + return + } + + mockServices := NewMockServices() + expectedInfra := dbChaosInfra.ChaosInfra{ + InfraID: infraID, + } + + mockServices.InfrastructureService. + On("GetDBInfra", infraID). + Return(expectedInfra, nil) + + response, err := mockServices.InfrastructureService.GetDBInfra(infraID) + if err != nil { + t.Errorf("ChaosInfrastructure.GetDBInfra() error = %v", err) + return + } + if response.InfraID != infraID { + t.Errorf("InfraID mismatch: got %v, want %v", response.InfraID, infraID) + } + }) +} diff --git a/chaoscenter/graphql/server/pkg/chaos_infrastructure/model/mocks/service.go b/chaoscenter/graphql/server/pkg/chaos_infrastructure/model/mocks/service.go index c20b5242771..fb3ac94bf0f 100644 --- a/chaoscenter/graphql/server/pkg/chaos_infrastructure/model/mocks/service.go +++ b/chaoscenter/graphql/server/pkg/chaos_infrastructure/model/mocks/service.go @@ -83,6 +83,11 @@ func (s *InfraService) KubeObj(request model.KubeObjectData, r store.StateData) return args.String(0), args.Error(1) } +func (s *InfraService) KubeNamespace(request model.KubeNamespaceData, r store.StateData) (string, error) { + args := s.Called(request, r) + return args.String(0), args.Error(1) +} + func (s *InfraService) UpdateInfra(query bson.D, update bson.D) error { args := s.Called(query, update) return args.Error(0) diff --git a/chaoscenter/graphql/server/pkg/chaos_infrastructure/service.go b/chaoscenter/graphql/server/pkg/chaos_infrastructure/service.go index 4548e081615..8c9663d241f 100644 --- a/chaoscenter/graphql/server/pkg/chaos_infrastructure/service.go +++ b/chaoscenter/graphql/server/pkg/chaos_infrastructure/service.go @@ -50,6 +50,7 @@ type Service interface { GetVersionDetails() (*model.InfraVersionDetails, error) QueryServerVersion(ctx context.Context) (*model.ServerVersionResponse, error) PodLog(request model.PodLog, r store.StateData) (string, error) + KubeNamespace(request model.KubeNamespaceData, r store.StateData) (string, error) KubeObj(request model.KubeObjectData, r store.StateData) (string, error) UpdateInfra(query bson.D, update bson.D) error GetDBInfra(infraID string) (dbChaosInfra.ChaosInfra, error) @@ -988,7 +989,7 @@ func (in *infraService) KubeObj(request model.KubeObjectData, r store.StateData) return "", err } if reqChan, ok := r.KubeObjectData[request.RequestID]; ok { - var kubeObjData []*model.KubeObject + var kubeObjData *model.KubeObject err = json.Unmarshal([]byte(request.KubeObj), &kubeObjData) if err != nil { return "", fmt.Errorf("failed to unmarshal kubeObj data %w", err) @@ -1005,6 +1006,31 @@ func (in *infraService) KubeObj(request model.KubeObjectData, r store.StateData) return "KubeData sent successfully", nil } +// KubeNamespace receives Kubernetes Namespace data from subscriber +func (in *infraService) KubeNamespace(request model.KubeNamespaceData, r store.StateData) (string, error) { + _, err := in.VerifyInfra(*request.InfraID) + if err != nil { + log.Print("Error", err) + return "", err + } + if reqChan, ok := r.KubeNamespaceData[request.RequestID]; ok { + var kubeNamespaceData []*model.KubeNamespace + err = json.Unmarshal([]byte(request.KubeNamespace), &kubeNamespaceData) + if err != nil { + return "", fmt.Errorf("failed to unmarshal kubeNamespace data %w", err) + } + + resp := model.KubeNamespaceResponse{ + InfraID: request.InfraID.InfraID, + KubeNamespace: kubeNamespaceData, + } + reqChan <- &resp + close(reqChan) + return "KubeData sent successfully", nil + } + return "KubeData sent successfully", nil +} + // SendInfraEvent sends events from the infras to the appropriate users listening for the events func (in *infraService) SendInfraEvent(eventType, eventName, description string, infra model.Infra, r store.StateData) { newEvent := model.InfraEventResponse{ diff --git a/chaoscenter/graphql/server/pkg/chaos_infrastructure/types.go b/chaoscenter/graphql/server/pkg/chaos_infrastructure/types.go index 8a3d8ead071..64c90cc5328 100644 --- a/chaoscenter/graphql/server/pkg/chaos_infrastructure/types.go +++ b/chaoscenter/graphql/server/pkg/chaos_infrastructure/types.go @@ -11,6 +11,10 @@ type KubeObjData struct { Data []ObjectData `json:"data"` } +type KubeNamespace struct { + Name string `json:"Name"` +} + type ObjectData struct { Name string `json:"name"` UID types.UID `json:"uid"` diff --git a/chaoscenter/graphql/server/pkg/chaoshub/handler/handler_fuzz_test.go b/chaoscenter/graphql/server/pkg/chaoshub/handler/handler_fuzz_test.go new file mode 100644 index 00000000000..5a83fe5c04b --- /dev/null +++ b/chaoscenter/graphql/server/pkg/chaoshub/handler/handler_fuzz_test.go @@ -0,0 +1,291 @@ +package handler + +import ( + "archive/zip" + "encoding/json" + "os" + "path/filepath" + "strings" + "testing" + + fuzz "github.com/AdaLogics/go-fuzz-headers" + "github.com/google/uuid" + "github.com/litmuschaos/litmus/chaoscenter/graphql/server/graph/model" +) + +func FuzzGetChartsPath(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte) { + fuzzConsumer := fuzz.NewConsumer(data) + + chartsInput := model.CloningInput{} + err := fuzzConsumer.GenerateStruct(&chartsInput) + if err != nil { + return + } + projectID, _ := fuzzConsumer.GetString() + isDefault, _ := fuzzConsumer.GetBool() + + result := GetChartsPath(chartsInput, projectID, isDefault) + + if isDefault { + expected := DefaultPath + "default/" + chartsInput.Name + "/faults/" + if result != expected { + t.Errorf("Expected %s, got %s", expected, result) + } + } else { + expected := DefaultPath + projectID + "/" + chartsInput.Name + "/faults/" + if result != expected { + t.Errorf("Expected %s, got %s", expected, result) + } + } + }) +} + +func FuzzReadExperimentFile(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte, filename string) { + fuzzConsumer := fuzz.NewConsumer(data) + + // Create a temporary directory + tmpDir, err := os.MkdirTemp("", "*-fuzztest") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(tmpDir) // clean up + + // Ensure the filename is valid and unique + safeFilename := filepath.Clean(filepath.Base(filename)) + if isInvalidFilename(safeFilename) { + safeFilename = "test.yaml" + } + filePath := filepath.Join(tmpDir, safeFilename) + content := ChaosChart{} + err = fuzzConsumer.GenerateStruct(&content) + if err != nil { + return + } + + jsonContent, _ := json.Marshal(content) + err = os.WriteFile(filePath, jsonContent, 0644) + if err != nil { + t.Fatal(err) + } + + _, err = ReadExperimentFile(filePath) + + if err != nil && !isInvalidYAML(jsonContent) { + t.Errorf("UnExpected error for valid YAML, got error: %v", err) + } + if err == nil && isInvalidYAML(jsonContent) { + t.Errorf("Expected error for invalid YAML, got nil") + } + + _, err = ReadExperimentFile("./not_exist_file.yaml") + if err == nil { + t.Errorf("Expected error for file does not exist, got nil") + } + }) +} + +func FuzzGetExperimentData(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte, filename string) { + fuzzConsumer := fuzz.NewConsumer(data) + + // Create a temporary directory + tmpDir, err := os.MkdirTemp("", "*-fuzztest") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(tmpDir) // clean up + + // Ensure the filename is valid and unique + safeFilename := filepath.Clean(filepath.Base(filename)) + if isInvalidFilename(safeFilename) { + safeFilename = "test.yaml" + } + filePath := filepath.Join(tmpDir, safeFilename) + content := ChaosChart{} + err = fuzzConsumer.GenerateStruct(&content) + if err != nil { + return + } + + jsonContent, _ := json.Marshal(content) + err = os.WriteFile(filePath, jsonContent, 0644) + if err != nil { + t.Fatal(err) + } + + _, err = GetExperimentData(filePath) + + if err != nil && !isInvalidYAML(jsonContent) && json.Valid(jsonContent) { + t.Errorf("UnExpected error for valid YAML, got error: %v", err) + } + if err == nil && isInvalidYAML(jsonContent) { + t.Errorf("Expected error for invalid YAML, got nil") + } + + _, err = ReadExperimentFile("./not_exist_file.yaml") + if err == nil { + t.Errorf("Expected error for file does not exist, got nil") + } + }) +} + +func FuzzReadExperimentYAMLFile(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte, filename string) { + fuzzConsumer := fuzz.NewConsumer(data) + + // Create a temporary directory + tmpDir, err := os.MkdirTemp("", "*-fuzztest") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(tmpDir) // clean up + + // Ensure the filename is valid and unique + safeFilename := filepath.Clean(filepath.Base(filename)) + if isInvalidFilename(safeFilename) { + safeFilename = "test.yaml" + } + filePath := filepath.Join(tmpDir, safeFilename) + content := ChaosChart{} + err = fuzzConsumer.GenerateStruct(&content) + if err != nil { + return + } + + jsonContent, _ := json.Marshal(content) + err = os.WriteFile(filePath, jsonContent, 0644) + if err != nil { + t.Fatal(err) + } + + _, err = ReadExperimentYAMLFile(filePath) + + if err != nil { + t.Errorf("UnExpected error for valid YAML, got error: %v", err) + } + + _, err = ReadExperimentFile("./not_exist_file.yaml") + if err == nil { + t.Errorf("Expected error for file does not exist, got nil") + } + }) +} + +func FuzzUnzipRemoteHub(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte, filename string, projectID string) { + // Create a temporary directory + tmpDir, err := os.MkdirTemp("", "*-fuzztest") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(tmpDir) // clean up + + // Ensure the filename is valid and unique + safeFilename := filepath.Clean(filepath.Base(filename)) + if isInvalidFilename(safeFilename) { + safeFilename = "test.zip" + } + if !strings.HasSuffix(safeFilename, ".zip") { + safeFilename += ".zip" + } + if isInvalidFilename(projectID) { + projectID = uuid.New().String() + } + + filePath := filepath.Join(tmpDir, safeFilename) + // Create a valid zip file + err = createValidZipFile(filePath, data) + if err != nil { + t.Fatal(err) + } + + err = UnzipRemoteHub(filePath, projectID) + + if err != nil { + t.Errorf("UnExpected error for valid zip, got error: %v", err) + } + + // Test with non-existent file + err = UnzipRemoteHub("./not_exist_file.zip", projectID) + if err == nil { + t.Errorf("Expected error for file does not exist, got nil") + } + + // Test with non-zip file + nonZipPath := filepath.Join(tmpDir, "no_zip") + err = os.WriteFile(nonZipPath, []byte("not a zip file"), 0644) + if err != nil { + t.Fatal(err) + } + err = UnzipRemoteHub(nonZipPath, projectID) + if err == nil { + t.Errorf("Expected error for no zip, got nil") + } + }) +} + +func FuzzIsFileExisting(f *testing.F) { + f.Fuzz(func(t *testing.T, filename string) { + // Create a temporary directory + tmpDir, err := os.MkdirTemp("", "*-fuzztest") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(tmpDir) // clean up + + // Ensure the filename is valid and unique + safeFilename := filepath.Clean(filepath.Base(filename)) + if isInvalidFilename(safeFilename) { + safeFilename = "test.yaml" + } + filePath := filepath.Join(tmpDir, safeFilename) + _, _ = os.Create(filePath) + + result, err := IsFileExisting(filePath) + if !result { + t.Errorf("Expected true for existing file, got false") + } + + result, err = IsFileExisting("./not_exist_file.yaml") + if result { + t.Errorf("Expected false for not existing file, got true") + } + }) +} + +func isInvalidFilename(filename string) bool { + return strings.IndexByte(filename, 0) != -1 || filename == "" || filename == "." || filename == ".." || filename == "/" || len(filename) > 255 +} + +func isInvalidYAML(data []byte) bool { + for _, b := range data { + if b < 32 || b == 127 { + return true + } + } + return false +} + +func createValidZipFile(filename string, data []byte) error { + zipFile, err := os.Create(filename) + if err != nil { + return err + } + defer zipFile.Close() + + zipWriter := zip.NewWriter(zipFile) + defer zipWriter.Close() + + f, err := zipWriter.Create("test.txt") + if err != nil { + return err + } + _, err = f.Write(data) + if err != nil { + return err + } + + return nil +} diff --git a/chaoscenter/graphql/server/pkg/chaoshub/handler/handler_test.go b/chaoscenter/graphql/server/pkg/chaoshub/handler/handler_test.go index ffcd2106ac3..1a30b1e012a 100644 --- a/chaoscenter/graphql/server/pkg/chaoshub/handler/handler_test.go +++ b/chaoscenter/graphql/server/pkg/chaoshub/handler/handler_test.go @@ -72,11 +72,6 @@ func TestReadExperimentFile(t *testing.T) { filePath: "./temp1.yaml", isError: true, }, - { - name: "failure: file is not a yaml", - filePath: "./types.go", - isError: true, - }, } for _, tc := range testcases { // when diff --git a/chaoscenter/graphql/server/pkg/chaoshub/models_factory.go b/chaoscenter/graphql/server/pkg/chaoshub/models_factory.go index 0034aad025e..de8d3335a57 100644 --- a/chaoscenter/graphql/server/pkg/chaoshub/models_factory.go +++ b/chaoscenter/graphql/server/pkg/chaoshub/models_factory.go @@ -6,6 +6,7 @@ func NewCloningInputFrom(chaosHub model.CreateChaosHubRequest) model.CloningInpu return model.CloningInput{ RepoBranch: chaosHub.RepoBranch, RepoURL: chaosHub.RepoURL, + RemoteHub: chaosHub.RemoteHub, Name: chaosHub.Name, IsPrivate: chaosHub.IsPrivate, UserName: chaosHub.UserName, diff --git a/chaoscenter/graphql/server/pkg/chaoshub/service.go b/chaoscenter/graphql/server/pkg/chaoshub/service.go index 2c933363179..53f46cc975f 100644 --- a/chaoscenter/graphql/server/pkg/chaoshub/service.go +++ b/chaoscenter/graphql/server/pkg/chaoshub/service.go @@ -86,6 +86,7 @@ func (c *chaosHubService) AddChaosHub(ctx context.Context, chaosHub model.Create ProjectID: projectID, RepoURL: chaosHub.RepoURL, RepoBranch: chaosHub.RepoBranch, + RemoteHub: chaosHub.RemoteHub, ResourceDetails: mongodb.ResourceDetails{ Name: chaosHub.Name, Description: description, @@ -155,6 +156,7 @@ func (c *chaosHubService) AddRemoteChaosHub(ctx context.Context, chaosHub model. ProjectID: projectID, RepoURL: chaosHub.RepoURL, RepoBranch: "", + RemoteHub: chaosHub.RemoteHub, ResourceDetails: mongodb.ResourceDetails{ Name: chaosHub.Name, Description: description, @@ -226,6 +228,7 @@ func (c *chaosHubService) SaveChaosHub(ctx context.Context, chaosHub model.Creat ProjectID: projectID, RepoURL: chaosHub.RepoURL, RepoBranch: chaosHub.RepoBranch, + RemoteHub: chaosHub.RemoteHub, ResourceDetails: mongodb.ResourceDetails{ Name: chaosHub.Name, Description: description, @@ -273,6 +276,7 @@ func (c *chaosHubService) SyncChaosHub(ctx context.Context, hubID string, projec Name: chaosHub.Name, RepoURL: chaosHub.RepoURL, RepoBranch: chaosHub.RepoBranch, + RemoteHub: chaosHub.RemoteHub, IsPrivate: chaosHub.IsPrivate, UserName: chaosHub.UserName, Password: chaosHub.Password, @@ -311,6 +315,7 @@ func (c *chaosHubService) UpdateChaosHub(ctx context.Context, chaosHub model.Upd cloneHub := model.CloningInput{ RepoBranch: chaosHub.RepoBranch, RepoURL: chaosHub.RepoURL, + RemoteHub: chaosHub.RemoteHub, Name: chaosHub.Name, IsPrivate: chaosHub.IsPrivate, UserName: chaosHub.UserName, @@ -326,10 +331,11 @@ func (c *chaosHubService) UpdateChaosHub(ctx context.Context, chaosHub model.Upd } clonePath := DefaultPath + prevChaosHub.ProjectID + "/" + prevChaosHub.Name if prevChaosHub.HubType == string(model.HubTypeRemote) { - if prevChaosHub.Name != chaosHub.Name || prevChaosHub.RepoURL != chaosHub.RepoURL { + if prevChaosHub.Name != chaosHub.Name || prevChaosHub.RepoURL != chaosHub.RepoURL || prevChaosHub.RemoteHub != chaosHub.RemoteHub { remoteHub := model.CreateRemoteChaosHub{ - Name: chaosHub.Name, - RepoURL: chaosHub.RepoURL, + Name: chaosHub.Name, + RepoURL: chaosHub.RepoURL, + RemoteHub: chaosHub.RemoteHub, } err = os.RemoveAll(clonePath) if err != nil { @@ -342,7 +348,7 @@ func (c *chaosHubService) UpdateChaosHub(ctx context.Context, chaosHub model.Upd } } else { // Syncing/Cloning the repository at a path from ChaosHub link structure. - if prevChaosHub.Name != chaosHub.Name || prevChaosHub.RepoURL != chaosHub.RepoURL || prevChaosHub.RepoBranch != chaosHub.RepoBranch || prevChaosHub.IsPrivate != chaosHub.IsPrivate || prevChaosHub.AuthType != chaosHub.AuthType.String() { + if prevChaosHub.Name != chaosHub.Name || prevChaosHub.RepoURL != chaosHub.RepoURL || prevChaosHub.RepoBranch != chaosHub.RepoBranch || prevChaosHub.IsPrivate != chaosHub.IsPrivate || prevChaosHub.AuthType != chaosHub.AuthType.String() || prevChaosHub.RemoteHub != chaosHub.RemoteHub { err = os.RemoveAll(clonePath) if err != nil { return nil, err @@ -368,6 +374,7 @@ func (c *chaosHubService) UpdateChaosHub(ctx context.Context, chaosHub model.Upd {"$set", bson.D{ {"repo_url", chaosHub.RepoURL}, {"repo_branch", chaosHub.RepoBranch}, + {"remote_hub", chaosHub.RemoteHub}, {"name", chaosHub.Name}, {"description", chaosHub.Description}, {"tags", chaosHub.Tags}, @@ -454,6 +461,7 @@ func (c *chaosHubService) ListChaosFaults(ctx context.Context, hubID string, pro Name: hub.Name, RepoURL: hub.RepoURL, RepoBranch: hub.RepoBranch, + RemoteHub: hub.RemoteHub, } ChartsPath := handler.GetChartsPath(chartsInput, projectID, hub.IsDefault) @@ -516,6 +524,7 @@ func (c *chaosHubService) ListChaosHubs(ctx context.Context, projectID string, r }, RepoURL: defaultHub.RepoURL, RepoBranch: defaultHub.RepoBranch, + RemoteHub: defaultHub.RemoteHub, IsDefault: true, } @@ -651,6 +660,7 @@ func (c *chaosHubService) ListChaosHubs(ctx context.Context, projectID string, r UpdatedAt: strconv.Itoa(int(hub.UpdatedAt)), CreatedBy: &model.UserDetails{Username: hub.CreatedBy.Username}, UpdatedBy: &model.UserDetails{Username: hub.UpdatedBy.Username}, + RemoteHub: hub.RemoteHub, } hubDetails = append(hubDetails, hubDetail) } @@ -711,6 +721,7 @@ func (c *chaosHubService) GetChaosHub(ctx context.Context, chaosHubID string, pr UpdatedAt: strconv.Itoa(int(hub.UpdatedAt)), CreatedBy: &model.UserDetails{Username: hub.CreatedBy.Username}, UpdatedBy: &model.UserDetails{Username: hub.UpdatedBy.Username}, + RemoteHub: hub.RemoteHub, } return hubDetail, nil @@ -762,6 +773,7 @@ func (c *chaosHubService) getChaosHubDetails(ctx context.Context, hubID string, ProjectID: hub.ProjectID, RepoURL: hub.RepoURL, RepoBranch: hub.RepoBranch, + RemoteHub: hub.RemoteHub, AuthType: model.AuthType(hub.AuthType), Name: hub.Name, CreatedAt: strconv.Itoa(int(hub.CreatedAt)), @@ -879,6 +891,7 @@ func (c *chaosHubService) RecurringHubSync() { Name: chaosHub.Name, RepoURL: chaosHub.RepoURL, RepoBranch: chaosHub.RepoBranch, + RemoteHub: chaosHub.RemoteHub, IsPrivate: chaosHub.IsPrivate, AuthType: chaosHub.AuthType, Token: chaosHub.Token, diff --git a/chaoscenter/graphql/server/pkg/data-store/store.go b/chaoscenter/graphql/server/pkg/data-store/store.go index f101298ebe9..41336b021f7 100644 --- a/chaoscenter/graphql/server/pkg/data-store/store.go +++ b/chaoscenter/graphql/server/pkg/data-store/store.go @@ -13,6 +13,7 @@ type StateData struct { ExperimentEventPublish map[string][]chan *model.ExperimentRun ExperimentLog map[string]chan *model.PodLogResponse KubeObjectData map[string]chan *model.KubeObjectResponse + KubeNamespaceData map[string]chan *model.KubeNamespaceResponse Mutex *sync.Mutex } @@ -23,6 +24,7 @@ func NewStore() *StateData { ExperimentEventPublish: make(map[string][]chan *model.ExperimentRun), ExperimentLog: make(map[string]chan *model.PodLogResponse), KubeObjectData: make(map[string]chan *model.KubeObjectResponse), + KubeNamespaceData: make(map[string]chan *model.KubeNamespaceResponse), Mutex: &sync.Mutex{}, } } diff --git a/chaoscenter/graphql/server/pkg/database/mongodb/chaos_hub/schema.go b/chaoscenter/graphql/server/pkg/database/mongodb/chaos_hub/schema.go index 7e8205f1192..ed387474dcd 100644 --- a/chaoscenter/graphql/server/pkg/database/mongodb/chaos_hub/schema.go +++ b/chaoscenter/graphql/server/pkg/database/mongodb/chaos_hub/schema.go @@ -15,6 +15,7 @@ type ChaosHub struct { mongodb.Audit `bson:",inline"` RepoURL string `bson:"repo_url"` RepoBranch string `bson:"repo_branch"` + RemoteHub string `bson:"remote_hub"` IsPrivate bool `bson:"is_private"` AuthType string `bson:"auth_type"` HubType string `bson:"hub_type"` @@ -34,6 +35,7 @@ func (c *ChaosHub) GetOutputChaosHub() *model.ChaosHub { ProjectID: c.ProjectID, RepoURL: c.RepoURL, RepoBranch: c.RepoBranch, + RemoteHub: c.RemoteHub, Name: c.Name, Description: &c.Description, Tags: c.Tags, diff --git a/chaoscenter/subscriber/pkg/k8s/defination.go b/chaoscenter/subscriber/pkg/k8s/defination.go index 68b2a24883f..2adac87f32c 100644 --- a/chaoscenter/subscriber/pkg/k8s/defination.go +++ b/chaoscenter/subscriber/pkg/k8s/defination.go @@ -18,10 +18,13 @@ type SubscriberK8s interface { CreatePodLog(podLog types.PodLogRequest) (types.PodLog, error) SendPodLogs(infraData map[string]string, podLog types.PodLogRequest) GenerateLogPayload(cid, accessKey, version string, podLog types.PodLogRequest) ([]byte, error) - GetKubernetesObjects(request types.KubeObjRequest) ([]*types.KubeObject, error) + GetKubernetesNamespaces(request types.KubeNamespaceRequest) ([]*types.KubeNamespace, error) + GetKubernetesObjects(request types.KubeObjRequest) (*types.KubeObject, error) GetObjectDataByNamespace(namespace string, dynamicClient dynamic.Interface, resourceType schema.GroupVersionResource) ([]types.ObjectData, error) GenerateKubeObject(cid string, accessKey, version string, kubeobjectrequest types.KubeObjRequest) ([]byte, error) + GenerateKubeNamespace(cid string, accessKey, version string, kubenamespacerequest types.KubeNamespaceRequest) ([]byte, error) SendKubeObjects(infraData map[string]string, kubeobjectrequest types.KubeObjRequest) error + SendKubeNamespaces(infraData map[string]string, kubenamespacerequest types.KubeNamespaceRequest) error CheckComponentStatus(componentEnv string) error IsAgentConfirmed() (bool, string, error) AgentRegister(accessKey string) (bool, error) diff --git a/chaoscenter/subscriber/pkg/k8s/objects.go b/chaoscenter/subscriber/pkg/k8s/objects.go index 143ea9f3785..d23bd51466f 100644 --- a/chaoscenter/subscriber/pkg/k8s/objects.go +++ b/chaoscenter/subscriber/pkg/k8s/objects.go @@ -23,63 +23,72 @@ var ( InfraScope = os.Getenv("INFRA_SCOPE") ) -// GetKubernetesObjects is used to get the Kubernetes Object details according to the request type -func (k8s *k8sSubscriber) GetKubernetesObjects(request types.KubeObjRequest) ([]*types.KubeObject, error) { - conf, err := k8s.GetKubeConfig() - if err != nil { - return nil, err - } - clientset, err := kubernetes.NewForConfig(conf) - if err != nil { - return nil, err - } +// GetKubernetesNamespaces is used to get the list of Kubernetes Namespaces +func (k8s *k8sSubscriber) GetKubernetesNamespaces(request types.KubeNamespaceRequest) ([]*types.KubeNamespace, error) { - resourceType := schema.GroupVersionResource{ - Group: request.KubeGVRRequest.Group, - Version: request.KubeGVRRequest.Version, - Resource: request.KubeGVRRequest.Resource, - } - _, dynamicClient, err := k8s.GetDynamicAndDiscoveryClient() - if err != nil { - return nil, err - } - var ObjData []*types.KubeObject + var namespaceData []*types.KubeNamespace if strings.ToLower(InfraScope) == "namespace" { - dataList, err := k8s.GetObjectDataByNamespace(InfraNamespace, dynamicClient, resourceType) + // In case of namespace scope, only one namespace is available + KubeNamespace := &types.KubeNamespace{ + Name: InfraNamespace, + } + namespaceData = append(namespaceData, KubeNamespace) + } else { + // In case of cluster scope, get all the namespaces + conf, err := k8s.GetKubeConfig() if err != nil { return nil, err } - KubeObj := &types.KubeObject{ - Namespace: InfraNamespace, - Data: dataList, + clientset, err := kubernetes.NewForConfig(conf) + if err != nil { + return nil, err } - ObjData = append(ObjData, KubeObj) - } else { + namespace, err := clientset.CoreV1().Namespaces().List(context.TODO(), metav1.ListOptions{}) if err != nil { return nil, err } - if len(namespace.Items) > 0 { for _, namespace := range namespace.Items { - podList, err := k8s.GetObjectDataByNamespace(namespace.GetName(), dynamicClient, resourceType) - if err != nil { - return nil, err - } - KubeObj := &types.KubeObject{ - Namespace: namespace.GetName(), - Data: podList, + + KubeNamespace := &types.KubeNamespace{ + Name: namespace.GetName(), } - ObjData = append(ObjData, KubeObj) + + namespaceData = append(namespaceData, KubeNamespace) } } else { return nil, errors.New("No namespace available") } + } + //TODO Maybe add marshal/unmarshal here + return namespaceData, nil +} +// GetKubernetesObjects is used to get the Kubernetes Object details according to the request type +func (k8s *k8sSubscriber) GetKubernetesObjects(request types.KubeObjRequest) (*types.KubeObject, error) { + resourceType := schema.GroupVersionResource{ + Group: request.KubeGVRRequest.Group, + Version: request.KubeGVRRequest.Version, + Resource: request.KubeGVRRequest.Resource, } - kubeData, _ := json.Marshal(ObjData) - var kubeObjects []*types.KubeObject + _, dynamicClient, err := k8s.GetDynamicAndDiscoveryClient() + if err != nil { + return nil, err + } + + dataList, err := k8s.GetObjectDataByNamespace(request.Namespace, dynamicClient, resourceType) + if err != nil { + return nil, err + } + KubeObj := &types.KubeObject{ + Namespace: InfraNamespace, + Data: dataList, + } + + kubeData, _ := json.Marshal(KubeObj) + var kubeObjects *types.KubeObject err = json.Unmarshal(kubeData, &kubeObjects) if err != nil { return nil, err @@ -118,6 +127,22 @@ func (k8s *k8sSubscriber) updateLabels(labels map[string]string) []string { return updatedLabels } +func (k8s *k8sSubscriber) GenerateKubeNamespace(cid string, accessKey, version string, kubenamespacerequest types.KubeNamespaceRequest) ([]byte, error) { + infraID := `{infraID: \"` + cid + `\", version: \"` + version + `\", accessKey: \"` + accessKey + `\"}` + kubeObj, err := k8s.GetKubernetesNamespaces(kubenamespacerequest) + if err != nil { + return nil, err + } + processed, err := k8s.gqlSubscriberServer.MarshalGQLData(kubeObj) + if err != nil { + return nil, err + } + mutation := `{ infraID: ` + infraID + `, requestID:\"` + kubenamespacerequest.RequestID + `\", kubeNamespace:\"` + processed[1:len(processed)-1] + `\"}` + + var payload = []byte(`{"query":"mutation { kubeNamespace(request:` + mutation + ` )}"}`) + return payload, nil +} + func (k8s *k8sSubscriber) GenerateKubeObject(cid string, accessKey, version string, kubeobjectrequest types.KubeObjRequest) ([]byte, error) { infraID := `{infraID: \"` + cid + `\", version: \"` + version + `\", accessKey: \"` + accessKey + `\"}` kubeObj, err := k8s.GetKubernetesObjects(kubeobjectrequest) @@ -134,6 +159,25 @@ func (k8s *k8sSubscriber) GenerateKubeObject(cid string, accessKey, version stri return payload, nil } +// SendKubeNamespace generates graphql mutation to send kubernetes namespaces data to graphql server +func (k8s *k8sSubscriber) SendKubeNamespaces(infraData map[string]string, kubenamespacerequest types.KubeNamespaceRequest) error { + // generate graphql payload + payload, err := k8s.GenerateKubeNamespace(infraData["INFRA_ID"], infraData["ACCESS_KEY"], infraData["VERSION"], kubenamespacerequest) + if err != nil { + logrus.WithError(err).Print("Error while getting KubeObject Data") + return err + } + + body, err := k8s.gqlSubscriberServer.SendRequest(infraData["SERVER_ADDR"], payload) + if err != nil { + logrus.Print(err.Error()) + return err + } + + logrus.Println("Response", body) + return nil +} + // SendKubeObjects generates graphql mutation to send kubernetes objects data to graphql server func (k8s *k8sSubscriber) SendKubeObjects(infraData map[string]string, kubeobjectrequest types.KubeObjRequest) error { // generate graphql payload diff --git a/chaoscenter/subscriber/pkg/requests/webhook.go b/chaoscenter/subscriber/pkg/requests/webhook.go index 1407d6e44f4..cafea2d921a 100644 --- a/chaoscenter/subscriber/pkg/requests/webhook.go +++ b/chaoscenter/subscriber/pkg/requests/webhook.go @@ -120,6 +120,21 @@ func (req *subscriberRequests) RequestProcessor(infraData map[string]string, r t return errors.New("error getting kubernetes object data: " + err.Error()) } } + if strings.Index("kubenamespace kubenamespaces", strings.ToLower(r.Payload.Data.InfraConnect.Action.RequestType)) >= 0 { + KubeNamespaceRequest := types.KubeNamespaceRequest{ + RequestID: r.Payload.Data.InfraConnect.Action.RequestID, + } + + err := json.Unmarshal([]byte(r.Payload.Data.InfraConnect.Action.ExternalData), &KubeNamespaceRequest) + if err != nil { + return errors.New("failed to json unmarshal: " + err.Error()) + } + + err = req.subscriberK8s.SendKubeNamespaces(infraData, KubeNamespaceRequest) + if err != nil { + return errors.New("error getting kubernetes namespace data: " + err.Error()) + } + } if strings.ToLower(r.Payload.Data.InfraConnect.Action.RequestType) == "logs" { podRequest := types.PodLogRequest{ RequestID: r.Payload.Data.InfraConnect.Action.RequestID, diff --git a/chaoscenter/subscriber/pkg/types/kubeobject.go b/chaoscenter/subscriber/pkg/types/kubeobject.go index e862cc0b875..baa917a76e5 100644 --- a/chaoscenter/subscriber/pkg/types/kubeobject.go +++ b/chaoscenter/subscriber/pkg/types/kubeobject.go @@ -14,6 +14,7 @@ type KubeObject struct { type KubeObjRequest struct { RequestID string InfraID string `json:"infraID"` + Namespace string `json:"namespace"` ObjectType string `json:"objectType"` KubeGVRRequest KubeGVRRequest `json:"kubeObjRequest"` } @@ -24,6 +25,16 @@ type KubeGVRRequest struct { Resource string `json:"resource"` } +// Not really useful at the moment but we might need other fields in the future +type KubeNamespace struct { + Name string `json:"name"` +} + +type KubeNamespaceRequest struct { + RequestID string + InfraID string `json:"infraID"` +} + type ObjectData struct { Name string `json:"name"` UID types.UID `json:"uid"` diff --git a/chaoscenter/web/Dockerfile b/chaoscenter/web/Dockerfile index 3c4c117f211..616d4e608a3 100644 --- a/chaoscenter/web/Dockerfile +++ b/chaoscenter/web/Dockerfile @@ -1,4 +1,4 @@ -FROM registry.access.redhat.com/ubi8/ubi-minimal:8.8 +FROM registry.access.redhat.com/ubi8/ubi-minimal:8.10 RUN microdnf module enable nginx:1.20 RUN microdnf install nginx RUN microdnf update --refresh --best --noplugins --setopt=install_weak_deps=0 diff --git a/chaoscenter/web/src/api/core/infrastructures/getKubeObject.ts b/chaoscenter/web/src/api/core/infrastructures/getKubeObject.ts index b3129ae1dff..54deef519fc 100644 --- a/chaoscenter/web/src/api/core/infrastructures/getKubeObject.ts +++ b/chaoscenter/web/src/api/core/infrastructures/getKubeObject.ts @@ -12,13 +12,14 @@ export interface KubeObjRequest { infraID: string; objectType: string; kubeObjRequest?: KubeGVRRequest; + namespace: string; }; } export interface KubeObjResponse { getKubeObject: { infraID: string; - kubeObj: Array; + kubeObj: KubeObj; }; } @@ -32,13 +33,30 @@ interface KubeObjData { name: string; } -export function kubeObjectSubscription({ +interface KubeNamespace { + name: string; +} + +export interface KubeNamespaceRequest { + request: { + infraID: string; + }; +} + +export interface KubeNamespaceResponse { + getKubeNamespace: { + infraID: string; + kubeNamespace: Array; + }; +} + +export const kubeObjectSubscription = ({ request, ...options }: GqlAPISubscriptionRequest): GqlAPISubscriptionResponse< KubeObjResponse, KubeObjRequest -> { +> => { const { data, loading, error } = useSubscription( gql` subscription getKubeObject($request: KubeObjectRequest!) { @@ -59,6 +77,7 @@ export function kubeObjectSubscription({ request: { infraID: request.infraID, kubeObjRequest: request.kubeObjRequest, + namespace: request.namespace, objectType: request.objectType } }, @@ -67,4 +86,35 @@ export function kubeObjectSubscription({ ); return { data, loading, error }; -} +}; + +export const kubeNamespaceSubscription = ({ + request, + ...options +}: GqlAPISubscriptionRequest): GqlAPISubscriptionResponse< + KubeNamespaceResponse, + KubeNamespaceRequest +> => { + const { data, loading, error } = useSubscription( + gql` + subscription getKubeNamespace($request: KubeNamespaceRequest!) { + getKubeNamespace(request: $request) { + infraID + kubeNamespace { + name + } + } + } + `, + { + variables: { + request: { + infraID: request.infraID + } + }, + ...options + } + ); + + return { data, loading, error }; +}; diff --git a/chaoscenter/web/src/api/entities/environment.ts b/chaoscenter/web/src/api/entities/environment.ts index 7341b84f50e..86fd89b41cf 100644 --- a/chaoscenter/web/src/api/entities/environment.ts +++ b/chaoscenter/web/src/api/entities/environment.ts @@ -23,3 +23,9 @@ export interface EnvironmentSortInput { field: SortType; ascending: boolean; } + +export interface EnvironmentDetail { + envName: string; + envID: string; + totalInfra?: number | null; +} diff --git a/chaoscenter/web/src/constants/validation.ts b/chaoscenter/web/src/constants/validation.ts index 39d68029c28..a03d51e26f5 100644 --- a/chaoscenter/web/src/constants/validation.ts +++ b/chaoscenter/web/src/constants/validation.ts @@ -6,7 +6,7 @@ export const USERNAME_REGEX = /^[a-zA-Z][a-zA-Z0-9_-]{2,15}$/; // ^(?=.*[a-z]) # At least one lowercase letter // (?=.*[A-Z]) # At least one uppercase letter // (?=.*\d) # At least one digit -// (?=.*[@$!%*?_&]) # At least one special character @$!%*?_& -// [A-Za-z\d@$!%*?_&] # Allowed characters: letters, digits, special characters @$!%*?_& +// (?=.*[@$!%*?_&#]) # At least one special character @$!%*?_&# +// [A-Za-z\d@$!%*?_&#] # Allowed characters: letters, digits, special characters @$!%*?_&# // {8,16}$ # Length between 8 to 16 characters -export const PASSWORD_REGEX = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?_&])[A-Za-z\d@$!%*?_&]{8,16}$/; +export const PASSWORD_REGEX = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?_&#])[A-Za-z\d@$!%*?_&#]{8,16}$/; diff --git a/chaoscenter/web/src/controllers/KubernetesChaosInfrastructureReferenceField/KubernetesChaosInfrastructureReferenceField.tsx b/chaoscenter/web/src/controllers/KubernetesChaosInfrastructureReferenceField/KubernetesChaosInfrastructureReferenceField.tsx index f7fe8c48d04..e4702f2d01f 100644 --- a/chaoscenter/web/src/controllers/KubernetesChaosInfrastructureReferenceField/KubernetesChaosInfrastructureReferenceField.tsx +++ b/chaoscenter/web/src/controllers/KubernetesChaosInfrastructureReferenceField/KubernetesChaosInfrastructureReferenceField.tsx @@ -3,31 +3,55 @@ import React from 'react'; import { listChaosInfra } from '@api/core'; import { getScope } from '@utils'; import ChaosInfrastructureReferenceFieldView from '@views/ChaosInfrastructureReferenceField'; -import type { ChaosInfrastructureReferenceFieldProps } from '@models'; +import { AllEnv, type ChaosInfrastructureReferenceFieldProps } from '@models'; import type { InfrastructureDetails } from '@views/ChaosInfrastructureReferenceField/ChaosInfrastructureReferenceField'; +import { listEnvironment } from '@api/core/environments'; function KubernetesChaosInfrastructureReferenceFieldController({ setFieldValue, - initialInfrastructureID + initialInfrastructureID, + initialEnvironmentID }: ChaosInfrastructureReferenceFieldProps): React.ReactElement { const scope = getScope(); const { showError } = useToaster(); const [searchInfrastructure, setSearchInfrastructure] = React.useState(''); - const [page, setPage] = React.useState(0); - const limit = 8; + const [limit, setLimit] = React.useState(5); + const [envID, setEnvID] = React.useState(AllEnv.AllEnv); + const [initialAllInfrastructureLength, setInitialAllInfrastructureLength] = React.useState(0); const { data: listChaosInfraData, loading: listChaosInfraLoading } = listChaosInfra({ ...scope, - filter: { name: searchInfrastructure, isActive: true }, + environmentIDs: envID === AllEnv.AllEnv ? undefined : [envID], + filter: { name: searchInfrastructure }, pagination: { page, limit }, options: { onError: error => showError(error.message) } }); + const { data: listEnvironmentData } = listEnvironment({ + ...scope, + options: { + onError: err => showError(err.message) + } + }); + + const environmentList = listEnvironmentData?.listEnvironments?.environments; + + React.useEffect(() => { + if (envID === AllEnv.AllEnv) { + setInitialAllInfrastructureLength(listChaosInfraData?.listInfras.totalNoOfInfras || 0); + } + }, [listChaosInfraData]); + + const preSelectedEnvironment = listEnvironmentData?.listEnvironments?.environments?.find( + ({ environmentID }) => environmentID === initialEnvironmentID + ); + // TODO: replace with get API as this becomes empty during edit const preSelectedInfrastructure = listChaosInfraData?.listInfras.infras.find( ({ infraID }) => infraID === initialInfrastructureID ); + const preSelectedInfrastructureDetails: InfrastructureDetails | undefined = preSelectedInfrastructure && { id: preSelectedInfrastructure?.infraID, name: preSelectedInfrastructure?.name, @@ -38,6 +62,16 @@ function KubernetesChaosInfrastructureReferenceFieldController({ environmentID: preSelectedInfrastructure?.environmentID }; + React.useEffect(() => { + setPage(0); + }, [envID]); + + React.useEffect(() => { + if (preSelectedEnvironment) { + setEnvID(preSelectedEnvironment?.environmentID); + } + }, [preSelectedEnvironment, setFieldValue]); + React.useEffect(() => { if (preSelectedInfrastructure) { setFieldValue('chaosInfrastructure.id', preSelectedInfrastructure.infraID, true); @@ -69,7 +103,10 @@ function KubernetesChaosInfrastructureReferenceFieldController({ pageSize={limit} pageCount={Math.ceil(totalNoOfInfras / limit)} pageIndex={page} - gotoPage={pageNumber => setPage(pageNumber)} + gotoPage={setPage} + showPagination={true} + pageSizeOptions={[5, 10, 15]} + onPageSizeChange={setLimit} /> ); }; @@ -87,6 +124,10 @@ function KubernetesChaosInfrastructureReferenceFieldController({ }} searchInfrastructure={searchInfrastructure} setSearchInfrastructure={setSearchInfrastructure} + allInfrastructureLength={initialAllInfrastructureLength} + environmentList={environmentList} + envID={envID} + setEnvID={setEnvID} loading={{ listChaosInfra: listChaosInfraLoading }} diff --git a/chaoscenter/web/src/controllers/TargetApplicationTab/TargetApplicationTab.tsx b/chaoscenter/web/src/controllers/TargetApplicationTab/TargetApplicationTab.tsx index bf7089b2add..059482d2e3b 100644 --- a/chaoscenter/web/src/controllers/TargetApplicationTab/TargetApplicationTab.tsx +++ b/chaoscenter/web/src/controllers/TargetApplicationTab/TargetApplicationTab.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import { KubeGVRRequest, kubeObjectSubscription } from '@api/core'; +import { KubeGVRRequest, kubeObjectSubscription, kubeNamespaceSubscription } from '@api/core'; import type { ChaosEngine, FaultData } from '@models'; import { TargetApplicationTab } from '@views/ExperimentCreationFaultConfiguration/Tabs'; import type { AppInfoData, TargetApplicationData } from './types'; @@ -16,17 +16,26 @@ export default function TargetApplicationTabController({ infrastructureID, setFaultData }: TargetApplicationControllerProps): React.ReactElement { - const [appInfoData, setAppInfoData] = React.useState([]); + const [namespaceData, setNamespaceData] = React.useState([]); + const [appInfoData, setAppInfoData] = React.useState({ appLabel: [] }); const [targetApp, setTargetApp] = React.useState({ ...engineCR?.spec?.appinfo }); const [selectedGVR, setSelectedGVR] = React.useState(); - const { data: result, loading } = kubeObjectSubscription({ + const { data: resultNamespace, loading: loadingNamespace } = kubeNamespaceSubscription({ + request: { + infraID: infrastructureID ?? '' + }, + shouldResubscribe: true, + skip: targetApp?.appkind === undefined || selectedGVR === undefined + }); + const { data: resultObject, loading: loadingObject } = kubeObjectSubscription({ shouldResubscribe: true, - skip: targetApp?.appkind === undefined || selectedGVR === undefined, + skip: targetApp?.appns === undefined || targetApp?.appns === '', request: { infraID: infrastructureID ?? '', kubeObjRequest: selectedGVR, + namespace: targetApp?.appns ?? '', objectType: 'kubeobject' } }); @@ -37,51 +46,44 @@ export default function TargetApplicationTabController({ if (data.resource === targetApp?.appkind) { setSelectedGVR({ group: data.group, - version: data.version, - resource: `${data.resource}s` + resource: `${data.resource}s`, + version: data.version }); } }); // eslint-disable-next-line react-hooks/exhaustive-deps }, [targetApp?.appkind]); - /** - * UseEffect to filter the labels according to the namespace provided - * Required to populate the appLabels dropdown - */ React.useEffect(() => { - if (result?.getKubeObject) { - const appInfo: AppInfoData[] = []; - const kubeData = result.getKubeObject.kubeObj; - kubeData.forEach(obj => { - const applabels: string[] = []; - obj.data.forEach(objData => { - if (objData.labels) { - applabels.push(...objData.labels.filter(() => obj.namespace === targetApp?.appns)); - } - }); - /** - * Push these labels corresponding to their namespaces - */ - appInfo.push({ - namespace: obj.namespace, - appLabel: applabels - }); - }); + if (resultNamespace?.getKubeNamespace) { + setNamespaceData(resultNamespace.getKubeNamespace.kubeNamespace.map(data => data.name)); + } + }, [resultNamespace?.getKubeNamespace, targetApp?.appkind]); + React.useEffect(() => { + if (resultObject?.getKubeObject) { + const applabels: string[] = []; + resultObject.getKubeObject.kubeObj.data.forEach(objData => { + if (objData.labels) { + applabels.push(...objData.labels); + } + }); + const appInfo: AppInfoData = { appLabel: applabels }; setAppInfoData(appInfo); } - }, [result?.getKubeObject, targetApp?.appns]); + }, [resultObject?.getKubeObject, targetApp?.appns]); return ( ); } diff --git a/chaoscenter/web/src/controllers/TargetApplicationTab/types.ts b/chaoscenter/web/src/controllers/TargetApplicationTab/types.ts index 85f3123fefc..3fd0c0819a8 100644 --- a/chaoscenter/web/src/controllers/TargetApplicationTab/types.ts +++ b/chaoscenter/web/src/controllers/TargetApplicationTab/types.ts @@ -4,7 +4,10 @@ export interface TargetApplicationData { applabel?: string; } +export interface NamespaceData { + namespace: string[]; +} + export interface AppInfoData { - namespace: string; appLabel: string[]; } diff --git a/chaoscenter/web/src/models/chaosInfrastructure.ts b/chaoscenter/web/src/models/chaosInfrastructure.ts index cc9d530c7aa..ab40a98aa76 100644 --- a/chaoscenter/web/src/models/chaosInfrastructure.ts +++ b/chaoscenter/web/src/models/chaosInfrastructure.ts @@ -31,6 +31,7 @@ export function getChaosInfrastructureStatus( export interface ChaosInfrastructureReferenceFieldProps { setFieldValue: FormikHelpers['setFieldValue']; initialInfrastructureID: string | undefined; + initialEnvironmentID: string | undefined; } export enum DeploymentScopeOptions { @@ -64,6 +65,10 @@ export interface InitialValueProps { tolerationValues?: Array; } +export enum AllEnv { + AllEnv = 'All' +} + export interface DeploymentScopeItem extends CollapsableSelectOptions { type: DeploymentScopeOptions; name: string; diff --git a/chaoscenter/web/src/strings/strings.en.yaml b/chaoscenter/web/src/strings/strings.en.yaml index bfe16f64f61..081e1458e7f 100644 --- a/chaoscenter/web/src/strings/strings.en.yaml +++ b/chaoscenter/web/src/strings/strings.en.yaml @@ -486,6 +486,7 @@ infrastructureRegistered: >- Environment -> Infrastructure list. infrastructureStates: Learn more about the states of Infrastructure infrastructureType: Infrastructure type +infrastructures: Infrastructures initialDelay: Initial Delay initialDelaySeconds: Initial Delay Seconds insecureSkipVerify: Insecure skip verify diff --git a/chaoscenter/web/src/strings/types.ts b/chaoscenter/web/src/strings/types.ts index 5d0470c5945..67b32c14278 100644 --- a/chaoscenter/web/src/strings/types.ts +++ b/chaoscenter/web/src/strings/types.ts @@ -409,6 +409,7 @@ export interface StringsMap { 'infrastructureRegistered': unknown 'infrastructureStates': unknown 'infrastructureType': unknown + 'infrastructures': unknown 'initialDelay': unknown 'initialDelaySeconds': unknown 'insecureSkipVerify': unknown diff --git a/chaoscenter/web/src/views/ChaosInfrastructureReferenceField/ChaosInfrastructureReferenceField.module.scss b/chaoscenter/web/src/views/ChaosInfrastructureReferenceField/ChaosInfrastructureReferenceField.module.scss index e9ab159eed0..4e61d00ded7 100644 --- a/chaoscenter/web/src/views/ChaosInfrastructureReferenceField/ChaosInfrastructureReferenceField.module.scss +++ b/chaoscenter/web/src/views/ChaosInfrastructureReferenceField/ChaosInfrastructureReferenceField.module.scss @@ -2,7 +2,7 @@ padding: var(--spacing-xlarge) !important; &.dialog { - width: 833px; + width: 912px; height: 86vh; max-height: 989px; } @@ -60,14 +60,13 @@ background: #effbff; border: 1.5px solid #0278d5; box-shadow: 0px 0px 1px rgba(40, 41, 61, 0.04), 0px 2px 4px rgba(96, 97, 112, 0.16); - border-radius: 4px; + border-radius: 8px; } .notSelected { background: #fafbfc; - border: 1px solid rgba(40, 41, 61, 0.3); box-shadow: 0px 0px 1px rgba(40, 41, 61, 0.04), 0px 2px 4px rgba(96, 97, 112, 0.16); - border-radius: 4px; + border-radius: 8px; cursor: pointer; } @@ -78,14 +77,13 @@ .agentListInnerContainer { flex-grow: 1; - overflow: auto; gap: 1rem; - max-height: calc(100% - 48px); + overflow: auto; } .item { display: grid; - grid-template-columns: 5fr 4fr 25px; + grid-template-columns: 3fr 4fr 25px; align-items: center; gap: 0.5rem; @@ -95,7 +93,6 @@ } .iconCheck { - visibility: hidden; margin-right: var(--spacing-xsmall); margin-left: var(--spacing-xsmall); cursor: pointer; @@ -104,7 +101,15 @@ > svg { > path { stroke-width: 1; - stroke: var(--grey-500); + stroke: var(--grey-100); + } + } + } + .iconCheck:hover { + > svg { + > path { + stroke-width: 1; + stroke: var(--green-500); } } } @@ -134,7 +139,7 @@ .gitInfo { display: grid; grid-template-columns: 4fr 5fr; - padding: 6px 8px; + padding: 4px 8px; background: var(--grey-100) !important; border-radius: 8px !important; width: 100%; @@ -170,11 +175,6 @@ position: fixed; } -.gap-4 { - gap: 1rem; - overflow: auto; -} - .paginationContainer { padding-top: 8px; overflow: hidden; @@ -190,3 +190,37 @@ } } } + +.listEnvContainer { + background: var(--primary-1); + box-shadow: 0px 0px 1px rgba(40, 41, 61, 0.04), 0px 2px 4px rgba(96, 97, 112, 0.16); + border-radius: 8px; + cursor: pointer; +} + +.itemEnv { + width: 100%; + display: grid; + grid-template-columns: 1fr 25px; + align-items: center; + gap: 0.5rem; +} + +.activeEnv { + border: 1px solid var(--primary-7); +} + +.center { + display: flex; + flex-direction: column; + justify-content: center; + align-self: center; + + img { + width: 200px; + } +} + +.rounded { + border-radius: 999px; +} diff --git a/chaoscenter/web/src/views/ChaosInfrastructureReferenceField/ChaosInfrastructureReferenceField.module.scss.d.ts b/chaoscenter/web/src/views/ChaosInfrastructureReferenceField/ChaosInfrastructureReferenceField.module.scss.d.ts index db9d0abfa61..0f0a5adf7fa 100644 --- a/chaoscenter/web/src/views/ChaosInfrastructureReferenceField/ChaosInfrastructureReferenceField.module.scss.d.ts +++ b/chaoscenter/web/src/views/ChaosInfrastructureReferenceField/ChaosInfrastructureReferenceField.module.scss.d.ts @@ -1,24 +1,28 @@ declare namespace ChaosInfrastructureReferenceFieldModuleScssNamespace { export interface IChaosInfrastructureReferenceFieldModuleScss { + activeEnv: string; agentList: string; agentListInnerContainer: string; + center: string; container: string; dialog: string; editBtn: string; fixed: string; - gap4: string; gitBranchIcon: string; gitInfo: string; greenStatus: string; iconCheck: string; iconChecked: string; item: string; + itemEnv: string; leftInfo: string; + listEnvContainer: string; notSelected: string; paginationContainer: string; placeholder: string; redStatus: string; referenceSelect: string; + rounded: string; selected: string; status: string; } diff --git a/chaoscenter/web/src/views/ChaosInfrastructureReferenceField/ChaosInfrastructureReferenceField.tsx b/chaoscenter/web/src/views/ChaosInfrastructureReferenceField/ChaosInfrastructureReferenceField.tsx index 4b55ba44ecc..2a5efa9853b 100644 --- a/chaoscenter/web/src/views/ChaosInfrastructureReferenceField/ChaosInfrastructureReferenceField.tsx +++ b/chaoscenter/web/src/views/ChaosInfrastructureReferenceField/ChaosInfrastructureReferenceField.tsx @@ -8,7 +8,8 @@ import { ExpandingSearchInput, Layout, Text, - useToaster + useToaster, + useToggleOpen } from '@harnessio/uicore'; import { Icon } from '@harnessio/icons'; import cx from 'classnames'; @@ -19,6 +20,7 @@ import FallbackBox from '@images/FallbackBox.svg'; import CustomTagsPopover from '@components/CustomTagsPopover'; import Loader from '@components/Loader'; import { useRouteWithBaseUrl } from '@hooks'; +import { Environment, EnvironmentDetail } from '@api/entities'; import css from './ChaosInfrastructureReferenceField.module.scss'; export interface InfrastructureDetails { @@ -34,10 +36,14 @@ export interface InfrastructureDetails { interface ChaosInfrastructureReferenceFieldViewProps { infrastructureList: InfrastructureDetails[] | undefined; + allInfrastructureLength: number | null; + environmentList: Environment[] | undefined; preSelectedInfrastructure?: InfrastructureDetails; setInfrastructureValue: (infrastructure: InfrastructureDetails | undefined) => void; searchInfrastructure: string; setSearchInfrastructure: React.Dispatch>; + setEnvID: (id: string) => void; + envID: string | undefined; loading: { listChaosInfra: boolean; }; @@ -46,32 +52,83 @@ interface ChaosInfrastructureReferenceFieldViewProps { function ChaosInfrastructureReferenceFieldView({ infrastructureList, + environmentList, + allInfrastructureLength, preSelectedInfrastructure, setInfrastructureValue, searchInfrastructure, setSearchInfrastructure, + envID, + setEnvID, loading, pagination }: ChaosInfrastructureReferenceFieldViewProps): JSX.Element { - const [isOpen, setOpen] = React.useState(false); const paths = useRouteWithBaseUrl(); const history = useHistory(); + const [selectedInfrastructure, setSelectedInfrastructure] = React.useState( preSelectedInfrastructure ); - // const searchParams = useSearchParams(); - // const infrastructureType = - // (searchParams.get('infrastructureType') as InfrastructureType | undefined) ?? InfrastructureType.KUBERNETES; + const { isOpen, open, close } = useToggleOpen(); + const { showError } = useToaster(); const { getString } = useStrings(); - const listItem = ({ infrastructure }: { infrastructure: InfrastructureDetails }): JSX.Element => { + const EnvListItem = ({ envDetail }: { envDetail: EnvironmentDetail }): JSX.Element => { + return ( + { + setEnvID(envDetail.envID); + }} + > +
+ + + {envDetail.envName} + + + + {envDetail.totalInfra ?? 0} + +
+
+ ); + }; + + const EnvironmentList = ({ env }: { env: Environment }): JSX.Element => { + return ( + + ); + }; + + const InfrastructureListItem = ({ infrastructure }: { infrastructure: InfrastructureDetails }): JSX.Element => { + const isSelected = + selectedInfrastructure?.id === infrastructure.id || preSelectedInfrastructure?.id === infrastructure.id; + return ( { infrastructure.isActive ? setSelectedInfrastructure(infrastructure) @@ -85,7 +142,6 @@ function ChaosInfrastructureReferenceFieldView({ size={12} name="pipeline-approval" /> - {/* */} {infrastructure.name} @@ -124,6 +180,26 @@ function ChaosInfrastructureReferenceFieldView({ ); }; + const NoInfraComponent = (): JSX.Element => { + return ( + + {getString('latestRun')} + + {searchInfrastructure === '' ? getString('newUserNoInfra.title') : getString('noFilteredActiveInfra')} + + {searchInfrastructure === '' && ( +