diff --git a/graphqlserver/graph/generated.go b/graphqlserver/graph/generated.go index a0419d01..6916e996 100644 --- a/graphqlserver/graph/generated.go +++ b/graphqlserver/graph/generated.go @@ -46,6 +46,10 @@ type DirectiveRoot struct { } type ComplexityRoot struct { + Cluster struct { + Name func(childComplexity int) int + } + ClusterAPIsCount struct { ClusterName func(childComplexity int) int Count func(childComplexity int) int @@ -149,6 +153,10 @@ type ComplexityRoot struct { TargetType func(childComplexity int) int } + Namespace struct { + Name func(childComplexity int) int + } + NamespaceData struct { KubeScores func(childComplexity int) int Namespace func(childComplexity int) int @@ -291,8 +299,8 @@ type QueryResolver interface { AllKubeScores(ctx context.Context) ([]*model.Kubescore, error) AllTrivyVuls(ctx context.Context) ([]*model.TrivyVul, error) AllTrivyMisconfigs(ctx context.Context) ([]*model.TrivyMisconfig, error) - UniqueClusters(ctx context.Context) ([]string, error) - UniqueNamespaces(ctx context.Context) ([]string, error) + UniqueNamespaces(ctx context.Context) ([]*model.Namespace, error) + UniqueClusters(ctx context.Context) ([]*model.Cluster, error) OutdatedImagesByClusterAndNamespace(ctx context.Context, clusterName string, namespace string) ([]*model.OutdatedImage, error) OutdatedImagesCount(ctx context.Context, clusterName string, namespace string) (int, error) AllClusterNamespaceOutdatedCounts(ctx context.Context) ([]*model.ClusterNamespaceOutdatedCount, error) @@ -320,6 +328,13 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in _ = ec switch typeName + "." + field { + case "Cluster.name": + if e.complexity.Cluster.Name == nil { + break + } + + return e.complexity.Cluster.Name(childComplexity), true + case "ClusterAPIsCount.clusterName": if e.complexity.ClusterAPIsCount.ClusterName == nil { break @@ -852,6 +867,13 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.Kubescore.TargetType(childComplexity), true + case "Namespace.name": + if e.complexity.Namespace.Name == nil { + break + } + + return e.complexity.Namespace.Name(childComplexity), true + case "NamespaceData.kubeScores": if e.complexity.NamespaceData.KubeScores == nil { break @@ -1785,6 +1807,50 @@ func (ec *executionContext) field___Type_fields_args(ctx context.Context, rawArg // region **************************** field.gotpl ***************************** +func (ec *executionContext) _Cluster_name(ctx context.Context, field graphql.CollectedField, obj *model.Cluster) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Cluster_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_Cluster_name(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Cluster", + 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) _ClusterAPIsCount_clusterName(ctx context.Context, field graphql.CollectedField, obj *model.ClusterAPIsCount) (ret graphql.Marshaler) { fc, err := ec.fieldContext_ClusterAPIsCount_clusterName(ctx, field) if err != nil { @@ -4970,6 +5036,50 @@ func (ec *executionContext) fieldContext_Kubescore_expiryDate(ctx context.Contex return fc, nil } +func (ec *executionContext) _Namespace_name(ctx context.Context, field graphql.CollectedField, obj *model.Namespace) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Namespace_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_Namespace_name(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Namespace", + 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) _NamespaceData_namespace(ctx context.Context, field graphql.CollectedField, obj *model.NamespaceData) (ret graphql.Marshaler) { fc, err := ec.fieldContext_NamespaceData_namespace(ctx, field) if err != nil { @@ -6312,8 +6422,8 @@ func (ec *executionContext) fieldContext_Query_allTrivyMisconfigs(ctx context.Co return fc, nil } -func (ec *executionContext) _Query_uniqueClusters(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_Query_uniqueClusters(ctx, field) +func (ec *executionContext) _Query_uniqueNamespaces(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Query_uniqueNamespaces(ctx, field) if err != nil { return graphql.Null } @@ -6326,7 +6436,7 @@ func (ec *executionContext) _Query_uniqueClusters(ctx context.Context, field gra }() resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { ctx = rctx // use context from middleware stack in children - return ec.resolvers.Query().UniqueClusters(rctx) + return ec.resolvers.Query().UniqueNamespaces(rctx) }) if err != nil { ec.Error(ctx, err) @@ -6338,26 +6448,30 @@ func (ec *executionContext) _Query_uniqueClusters(ctx context.Context, field gra } return graphql.Null } - res := resTmp.([]string) + res := resTmp.([]*model.Namespace) fc.Result = res - return ec.marshalNString2ᚕstringᚄ(ctx, field.Selections, res) + return ec.marshalNNamespace2ᚕᚖgithubᚗcomᚋintelopsᚋkubvizᚋgraphqlserverᚋgraphᚋmodelᚐNamespaceᚄ(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Query_uniqueClusters(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Query_uniqueNamespaces(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Query", 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") + switch field.Name { + case "name": + return ec.fieldContext_Namespace_name(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type Namespace", field.Name) }, } return fc, nil } -func (ec *executionContext) _Query_uniqueNamespaces(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_Query_uniqueNamespaces(ctx, field) +func (ec *executionContext) _Query_uniqueClusters(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Query_uniqueClusters(ctx, field) if err != nil { return graphql.Null } @@ -6370,7 +6484,7 @@ func (ec *executionContext) _Query_uniqueNamespaces(ctx context.Context, field g }() resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { ctx = rctx // use context from middleware stack in children - return ec.resolvers.Query().UniqueNamespaces(rctx) + return ec.resolvers.Query().UniqueClusters(rctx) }) if err != nil { ec.Error(ctx, err) @@ -6382,19 +6496,23 @@ func (ec *executionContext) _Query_uniqueNamespaces(ctx context.Context, field g } return graphql.Null } - res := resTmp.([]string) + res := resTmp.([]*model.Cluster) fc.Result = res - return ec.marshalNString2ᚕstringᚄ(ctx, field.Selections, res) + return ec.marshalNCluster2ᚕᚖgithubᚗcomᚋintelopsᚋkubvizᚋgraphqlserverᚋgraphᚋmodelᚐClusterᚄ(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Query_uniqueNamespaces(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Query_uniqueClusters(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Query", 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") + switch field.Name { + case "name": + return ec.fieldContext_Cluster_name(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type Cluster", field.Name) }, } return fc, nil @@ -11583,6 +11701,45 @@ func (ec *executionContext) fieldContext___Type_specifiedByURL(ctx context.Conte // region **************************** object.gotpl **************************** +var clusterImplementors = []string{"Cluster"} + +func (ec *executionContext) _Cluster(ctx context.Context, sel ast.SelectionSet, obj *model.Cluster) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, clusterImplementors) + + 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("Cluster") + case "name": + out.Values[i] = ec._Cluster_name(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 clusterAPIsCountImplementors = []string{"ClusterAPIsCount"} func (ec *executionContext) _ClusterAPIsCount(ctx context.Context, sel ast.SelectionSet, obj *model.ClusterAPIsCount) graphql.Marshaler { @@ -12110,6 +12267,45 @@ func (ec *executionContext) _Kubescore(ctx context.Context, sel ast.SelectionSet return out } +var namespaceImplementors = []string{"Namespace"} + +func (ec *executionContext) _Namespace(ctx context.Context, sel ast.SelectionSet, obj *model.Namespace) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, namespaceImplementors) + + 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("Namespace") + case "name": + out.Values[i] = ec._Namespace_name(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 namespaceDataImplementors = []string{"NamespaceData"} func (ec *executionContext) _NamespaceData(ctx context.Context, sel ast.SelectionSet, obj *model.NamespaceData) graphql.Marshaler { @@ -12499,7 +12695,7 @@ func (ec *executionContext) _Query(ctx context.Context, sel ast.SelectionSet) gr } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return rrm(innerCtx) }) - case "uniqueClusters": + case "uniqueNamespaces": field := field innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { @@ -12508,7 +12704,7 @@ func (ec *executionContext) _Query(ctx context.Context, sel ast.SelectionSet) gr ec.Error(ctx, ec.Recover(ctx, r)) } }() - res = ec._Query_uniqueClusters(ctx, field) + res = ec._Query_uniqueNamespaces(ctx, field) if res == graphql.Null { atomic.AddUint32(&fs.Invalids, 1) } @@ -12521,7 +12717,7 @@ func (ec *executionContext) _Query(ctx context.Context, sel ast.SelectionSet) gr } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return rrm(innerCtx) }) - case "uniqueNamespaces": + case "uniqueClusters": field := field innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { @@ -12530,7 +12726,7 @@ func (ec *executionContext) _Query(ctx context.Context, sel ast.SelectionSet) gr ec.Error(ctx, ec.Recover(ctx, r)) } }() - res = ec._Query_uniqueNamespaces(ctx, field) + res = ec._Query_uniqueClusters(ctx, field) if res == graphql.Null { atomic.AddUint32(&fs.Invalids, 1) } @@ -13423,6 +13619,60 @@ func (ec *executionContext) marshalNBoolean2bool(ctx context.Context, sel ast.Se return res } +func (ec *executionContext) marshalNCluster2ᚕᚖgithubᚗcomᚋintelopsᚋkubvizᚋgraphqlserverᚋgraphᚋmodelᚐClusterᚄ(ctx context.Context, sel ast.SelectionSet, v []*model.Cluster) graphql.Marshaler { + ret := make(graphql.Array, len(v)) + var wg sync.WaitGroup + isLen1 := len(v) == 1 + if !isLen1 { + wg.Add(len(v)) + } + for i := range v { + i := i + fc := &graphql.FieldContext{ + Index: &i, + Result: &v[i], + } + ctx := graphql.WithFieldContext(ctx, fc) + f := func(i int) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = nil + } + }() + if !isLen1 { + defer wg.Done() + } + ret[i] = ec.marshalNCluster2ᚖgithubᚗcomᚋintelopsᚋkubvizᚋgraphqlserverᚋgraphᚋmodelᚐCluster(ctx, sel, v[i]) + } + if isLen1 { + f(i) + } else { + go f(i) + } + + } + wg.Wait() + + for _, e := range ret { + if e == graphql.Null { + return graphql.Null + } + } + + return ret +} + +func (ec *executionContext) marshalNCluster2ᚖgithubᚗcomᚋintelopsᚋkubvizᚋgraphqlserverᚋgraphᚋmodelᚐCluster(ctx context.Context, sel ast.SelectionSet, v *model.Cluster) 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._Cluster(ctx, sel, v) +} + func (ec *executionContext) marshalNClusterAPIsCount2ᚕᚖgithubᚗcomᚋintelopsᚋkubvizᚋgraphqlserverᚋgraphᚋmodelᚐClusterAPIsCountᚄ(ctx context.Context, sel ast.SelectionSet, v []*model.ClusterAPIsCount) graphql.Marshaler { ret := make(graphql.Array, len(v)) var wg sync.WaitGroup @@ -13939,6 +14189,60 @@ func (ec *executionContext) marshalNKubescore2ᚖgithubᚗcomᚋintelopsᚋkubvi return ec._Kubescore(ctx, sel, v) } +func (ec *executionContext) marshalNNamespace2ᚕᚖgithubᚗcomᚋintelopsᚋkubvizᚋgraphqlserverᚋgraphᚋmodelᚐNamespaceᚄ(ctx context.Context, sel ast.SelectionSet, v []*model.Namespace) graphql.Marshaler { + ret := make(graphql.Array, len(v)) + var wg sync.WaitGroup + isLen1 := len(v) == 1 + if !isLen1 { + wg.Add(len(v)) + } + for i := range v { + i := i + fc := &graphql.FieldContext{ + Index: &i, + Result: &v[i], + } + ctx := graphql.WithFieldContext(ctx, fc) + f := func(i int) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = nil + } + }() + if !isLen1 { + defer wg.Done() + } + ret[i] = ec.marshalNNamespace2ᚖgithubᚗcomᚋintelopsᚋkubvizᚋgraphqlserverᚋgraphᚋmodelᚐNamespace(ctx, sel, v[i]) + } + if isLen1 { + f(i) + } else { + go f(i) + } + + } + wg.Wait() + + for _, e := range ret { + if e == graphql.Null { + return graphql.Null + } + } + + return ret +} + +func (ec *executionContext) marshalNNamespace2ᚖgithubᚗcomᚋintelopsᚋkubvizᚋgraphqlserverᚋgraphᚋmodelᚐNamespace(ctx context.Context, sel ast.SelectionSet, v *model.Namespace) 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._Namespace(ctx, sel, v) +} + func (ec *executionContext) marshalNNamespaceData2ᚕᚖgithubᚗcomᚋintelopsᚋkubvizᚋgraphqlserverᚋgraphᚋmodelᚐNamespaceDataᚄ(ctx context.Context, sel ast.SelectionSet, v []*model.NamespaceData) graphql.Marshaler { ret := make(graphql.Array, len(v)) var wg sync.WaitGroup @@ -14170,38 +14474,6 @@ func (ec *executionContext) marshalNString2string(ctx context.Context, sel ast.S return res } -func (ec *executionContext) unmarshalNString2ᚕstringᚄ(ctx context.Context, v interface{}) ([]string, error) { - var vSlice []interface{} - if v != nil { - vSlice = graphql.CoerceList(v) - } - var err error - res := make([]string, len(vSlice)) - for i := range vSlice { - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithIndex(i)) - res[i], err = ec.unmarshalNString2string(ctx, vSlice[i]) - if err != nil { - return nil, err - } - } - return res, nil -} - -func (ec *executionContext) marshalNString2ᚕstringᚄ(ctx context.Context, sel ast.SelectionSet, v []string) graphql.Marshaler { - ret := make(graphql.Array, len(v)) - for i := range v { - ret[i] = ec.marshalNString2string(ctx, sel, v[i]) - } - - for _, e := range ret { - if e == graphql.Null { - return graphql.Null - } - } - - return ret -} - func (ec *executionContext) marshalNTrivyImage2ᚕᚖgithubᚗcomᚋintelopsᚋkubvizᚋgraphqlserverᚋgraphᚋmodelᚐTrivyImageᚄ(ctx context.Context, sel ast.SelectionSet, v []*model.TrivyImage) graphql.Marshaler { ret := make(graphql.Array, len(v)) var wg sync.WaitGroup diff --git a/graphqlserver/graph/model/models_gen.go b/graphqlserver/graph/model/models_gen.go index 397b571e..1aff036e 100644 --- a/graphqlserver/graph/model/models_gen.go +++ b/graphqlserver/graph/model/models_gen.go @@ -2,6 +2,10 @@ package model +type Cluster struct { + Name string `json:"name"` +} + type ClusterAPIsCount struct { ClusterName string `json:"clusterName"` Count int `json:"count"` @@ -105,6 +109,10 @@ type Kubescore struct { ExpiryDate *string `json:"expiryDate,omitempty"` } +type Namespace struct { + Name string `json:"name"` +} + type NamespaceData struct { Namespace string `json:"namespace"` OutdatedImages []*OutdatedImage `json:"outdatedImages"` diff --git a/graphqlserver/graph/schema.graphqls b/graphqlserver/graph/schema.graphqls index 72ef18ef..37783b48 100644 --- a/graphqlserver/graph/schema.graphqls +++ b/graphqlserver/graph/schema.graphqls @@ -10,8 +10,8 @@ type Query { allKubeScores: [Kubescore!]! allTrivyVuls: [TrivyVul!]! allTrivyMisconfigs: [TrivyMisconfig!]! - uniqueClusters: [String!]! - uniqueNamespaces: [String!]! + uniqueNamespaces: [Namespace!]! + uniqueClusters: [Cluster!]! outdatedImagesByClusterAndNamespace(clusterName: String!, namespace: String!): [OutdatedImage!]! outdatedImagesCount(clusterName: String!, namespace: String!): Int! allClusterNamespaceOutdatedCounts: [ClusterNamespaceOutdatedCount!]! @@ -19,6 +19,15 @@ type Query { allClusterDeletedAPIsCounts: [ClusterAPIsCount!]! allClusterNamespaceResourceCounts: [ClusterNamespaceResourceCount!]! } + +type Namespace { + name: String! +} + +type Cluster { + name: String! +} + type ClusterNamespaceResourceCount { clusterName: String! namespace: String! diff --git a/graphqlserver/graph/schema.resolvers.go b/graphqlserver/graph/schema.resolvers.go index 296b70e4..e6229bc9 100644 --- a/graphqlserver/graph/schema.resolvers.go +++ b/graphqlserver/graph/schema.resolvers.go @@ -395,38 +395,34 @@ func (r *queryResolver) AllTrivyMisconfigs(ctx context.Context) ([]*model.TrivyM return misconfigs, nil } -// UniqueClusters is the resolver for the uniqueClusters field. -func (r *queryResolver) UniqueClusters(ctx context.Context) ([]string, error) { - if r.DB == nil { - return nil, fmt.Errorf("database connection is not initialized") - } - query := `SELECT DISTINCT ClusterName FROM events` - - rows, err := r.DB.QueryContext(ctx, query) +// UniqueNamespaces is the resolver for the uniqueNamespaces field. +func (r *queryResolver) UniqueNamespaces(ctx context.Context) ([]*model.Namespace, error) { + namespaces, err := r.fetchNamespacesFromDatabase(ctx) if err != nil { - return nil, fmt.Errorf("error executing query: %v", err) + return nil, err } - defer rows.Close() - var clusters []string - for rows.Next() { - var cluster string - if err := rows.Scan(&cluster); err != nil { - return nil, fmt.Errorf("error scanning row: %v", err) - } - clusters = append(clusters, cluster) + var namespaceObjects []*model.Namespace + for _, ns := range namespaces { + namespaceObjects = append(namespaceObjects, &model.Namespace{Name: ns}) } - if err := rows.Err(); err != nil { - return nil, fmt.Errorf("error iterating rows: %v", err) + return namespaceObjects, nil +} + +// UniqueClusters is the resolver for the uniqueClusters field. +func (r *queryResolver) UniqueClusters(ctx context.Context) ([]*model.Cluster, error) { + clusters, err := r.fetchClustersFromDatabase(ctx) + if err != nil { + return nil, err } - return clusters, nil -} + var clusterObjects []*model.Cluster + for _, cluster := range clusters { + clusterObjects = append(clusterObjects, &model.Cluster{Name: cluster}) + } -// UniqueNamespaces is the resolver for the uniqueNamespaces field. -func (r *queryResolver) UniqueNamespaces(ctx context.Context) ([]string, error) { - return r.fetchNamespacesFromDatabase(ctx) + return clusterObjects, nil } // OutdatedImagesByClusterAndNamespace is the resolver for the outdatedImagesByClusterAndNamespace field. diff --git a/graphqlserver/graph/utils.go b/graphqlserver/graph/utils.go index 23959ee4..01ad5c2d 100644 --- a/graphqlserver/graph/utils.go +++ b/graphqlserver/graph/utils.go @@ -8,6 +8,34 @@ import ( "github.com/intelops/kubviz/graphqlserver/graph/model" ) +func (r *Resolver) fetchClustersFromDatabase(ctx context.Context) ([]string, error) { + if r.DB == nil { + return nil, fmt.Errorf("database connection is not initialized") + } + query := `SELECT DISTINCT ClusterName FROM events` + + rows, err := r.DB.QueryContext(ctx, query) + if err != nil { + return nil, fmt.Errorf("error executing query: %v", err) + } + defer rows.Close() + + var clusters []string + for rows.Next() { + var cluster string + if err := rows.Scan(&cluster); err != nil { + return nil, fmt.Errorf("error scanning row: %v", err) + } + clusters = append(clusters, cluster) + } + + if err := rows.Err(); err != nil { + return nil, fmt.Errorf("error iterating rows: %v", err) + } + + return clusters, nil +} + func (r *Resolver) fetchNamespacesFromDatabase(ctx context.Context) ([]string, error) { if r.DB == nil { return nil, fmt.Errorf("database connection is not initialized")