2021-03-31 07:23:48 +02:00
|
|
|
package graph
|
|
|
|
|
|
|
|
// This file will be automatically regenerated based on the schema, any resolver implementations
|
|
|
|
// will be copied through when generating and any unknown code will be moved to the end.
|
2021-10-26 10:24:43 +02:00
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
2021-12-09 16:25:48 +01:00
|
|
|
"errors"
|
2021-10-26 10:24:43 +02:00
|
|
|
"fmt"
|
|
|
|
"strconv"
|
2021-12-09 16:25:48 +01:00
|
|
|
"time"
|
2021-10-26 10:24:43 +02:00
|
|
|
|
2022-06-21 17:52:36 +02:00
|
|
|
"github.com/ClusterCockpit/cc-backend/internal/auth"
|
|
|
|
"github.com/ClusterCockpit/cc-backend/internal/graph/generated"
|
|
|
|
"github.com/ClusterCockpit/cc-backend/internal/graph/model"
|
|
|
|
"github.com/ClusterCockpit/cc-backend/internal/metricdata"
|
2022-09-05 17:46:38 +02:00
|
|
|
"github.com/ClusterCockpit/cc-backend/internal/repository"
|
|
|
|
"github.com/ClusterCockpit/cc-backend/pkg/archive"
|
2023-01-23 18:48:06 +01:00
|
|
|
"github.com/ClusterCockpit/cc-backend/pkg/log"
|
2022-06-21 17:52:36 +02:00
|
|
|
"github.com/ClusterCockpit/cc-backend/pkg/schema"
|
2021-10-26 10:24:43 +02:00
|
|
|
)
|
|
|
|
|
2022-09-07 12:24:45 +02:00
|
|
|
// Partitions is the resolver for the partitions field.
|
|
|
|
func (r *clusterResolver) Partitions(ctx context.Context, obj *schema.Cluster) ([]string, error) {
|
2022-03-14 10:24:27 +01:00
|
|
|
return r.Repo.Partitions(obj.Name)
|
2022-03-14 10:18:56 +01:00
|
|
|
}
|
|
|
|
|
2023-01-11 16:25:02 +01:00
|
|
|
// JobName is the resolver for the jobName field.
|
|
|
|
func (r *jobResolver) JobName(ctx context.Context, obj *schema.Job) (*string, error) {
|
|
|
|
return r.Repo.FetchJobName(obj)
|
|
|
|
}
|
|
|
|
|
2022-09-07 12:24:45 +02:00
|
|
|
// Tags is the resolver for the tags field.
|
2022-03-15 11:04:54 +01:00
|
|
|
func (r *jobResolver) Tags(ctx context.Context, obj *schema.Job) ([]*schema.Tag, error) {
|
|
|
|
return r.Repo.GetTags(&obj.ID)
|
|
|
|
}
|
|
|
|
|
2022-09-07 12:24:45 +02:00
|
|
|
// MetaData is the resolver for the metaData field.
|
2022-03-08 11:53:24 +01:00
|
|
|
func (r *jobResolver) MetaData(ctx context.Context, obj *schema.Job) (interface{}, error) {
|
|
|
|
return r.Repo.FetchMetadata(obj)
|
|
|
|
}
|
|
|
|
|
2022-09-07 12:24:45 +02:00
|
|
|
// UserData is the resolver for the userData field.
|
2022-03-15 11:04:54 +01:00
|
|
|
func (r *jobResolver) UserData(ctx context.Context, obj *schema.Job) (*model.User, error) {
|
|
|
|
return auth.FetchUser(ctx, r.DB, obj.User)
|
2021-10-26 10:24:43 +02:00
|
|
|
}
|
|
|
|
|
2022-09-07 12:24:45 +02:00
|
|
|
// CreateTag is the resolver for the createTag field.
|
2021-12-17 15:49:22 +01:00
|
|
|
func (r *mutationResolver) CreateTag(ctx context.Context, typeArg string, name string) (*schema.Tag, error) {
|
2022-02-17 09:04:57 +01:00
|
|
|
id, err := r.Repo.CreateTag(typeArg, name)
|
2021-10-26 10:24:43 +02:00
|
|
|
if err != nil {
|
2023-01-31 18:28:44 +01:00
|
|
|
log.Warn("Error while creating tag")
|
2021-10-26 10:24:43 +02:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2021-12-17 15:49:22 +01:00
|
|
|
return &schema.Tag{ID: id, Type: typeArg, Name: name}, nil
|
2021-10-26 10:24:43 +02:00
|
|
|
}
|
|
|
|
|
2022-09-07 12:24:45 +02:00
|
|
|
// DeleteTag is the resolver for the deleteTag field.
|
2021-10-26 10:24:43 +02:00
|
|
|
func (r *mutationResolver) DeleteTag(ctx context.Context, id string) (string, error) {
|
2022-09-07 12:24:45 +02:00
|
|
|
panic(fmt.Errorf("not implemented: DeleteTag - deleteTag"))
|
2021-10-26 10:24:43 +02:00
|
|
|
}
|
|
|
|
|
2022-09-07 12:24:45 +02:00
|
|
|
// AddTagsToJob is the resolver for the addTagsToJob field.
|
2021-12-17 15:49:22 +01:00
|
|
|
func (r *mutationResolver) AddTagsToJob(ctx context.Context, job string, tagIds []string) ([]*schema.Tag, error) {
|
2022-02-17 09:04:57 +01:00
|
|
|
jid, err := strconv.ParseInt(job, 10, 64)
|
2021-10-26 10:24:43 +02:00
|
|
|
if err != nil {
|
2023-01-31 18:28:44 +01:00
|
|
|
log.Warn("Error while adding tag to job")
|
2021-10-26 10:24:43 +02:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2022-02-23 14:18:55 +01:00
|
|
|
tags := []*schema.Tag{}
|
2021-10-26 10:24:43 +02:00
|
|
|
for _, tagId := range tagIds {
|
2022-02-17 09:04:57 +01:00
|
|
|
tid, err := strconv.ParseInt(tagId, 10, 64)
|
2021-10-26 10:24:43 +02:00
|
|
|
if err != nil {
|
2023-01-31 18:28:44 +01:00
|
|
|
log.Warn("Error while parsing tag id")
|
2021-10-26 10:24:43 +02:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2022-02-23 14:18:55 +01:00
|
|
|
if tags, err = r.Repo.AddTag(jid, tid); err != nil {
|
2023-01-31 18:28:44 +01:00
|
|
|
log.Warn("Error while adding tag")
|
2021-10-26 10:24:43 +02:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-02-23 14:18:55 +01:00
|
|
|
return tags, nil
|
2021-10-26 10:24:43 +02:00
|
|
|
}
|
|
|
|
|
2022-09-07 12:24:45 +02:00
|
|
|
// RemoveTagsFromJob is the resolver for the removeTagsFromJob field.
|
2021-12-17 15:49:22 +01:00
|
|
|
func (r *mutationResolver) RemoveTagsFromJob(ctx context.Context, job string, tagIds []string) ([]*schema.Tag, error) {
|
2022-02-17 09:20:57 +01:00
|
|
|
jid, err := strconv.ParseInt(job, 10, 64)
|
2021-10-26 10:24:43 +02:00
|
|
|
if err != nil {
|
2023-01-31 18:28:44 +01:00
|
|
|
log.Warn("Error while parsing job id")
|
2021-10-26 10:24:43 +02:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2022-02-23 14:18:55 +01:00
|
|
|
tags := []*schema.Tag{}
|
2021-10-26 10:24:43 +02:00
|
|
|
for _, tagId := range tagIds {
|
2022-02-17 09:20:57 +01:00
|
|
|
tid, err := strconv.ParseInt(tagId, 10, 64)
|
2021-10-26 10:24:43 +02:00
|
|
|
if err != nil {
|
2023-01-31 18:28:44 +01:00
|
|
|
log.Warn("Error while parsing tag id")
|
2021-10-26 10:24:43 +02:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2022-02-23 14:18:55 +01:00
|
|
|
if tags, err = r.Repo.RemoveTag(jid, tid); err != nil {
|
2023-01-31 18:28:44 +01:00
|
|
|
log.Warn("Error while removing tag")
|
2021-10-26 10:24:43 +02:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-02-23 14:18:55 +01:00
|
|
|
return tags, nil
|
2021-10-26 10:24:43 +02:00
|
|
|
}
|
|
|
|
|
2022-09-07 12:24:45 +02:00
|
|
|
// UpdateConfiguration is the resolver for the updateConfiguration field.
|
2021-10-26 10:24:43 +02:00
|
|
|
func (r *mutationResolver) UpdateConfiguration(ctx context.Context, name string, value string) (*string, error) {
|
2022-09-12 13:33:01 +02:00
|
|
|
if err := repository.GetUserCfgRepo().UpdateConfig(name, value, auth.GetUser(ctx)); err != nil {
|
2023-01-31 18:28:44 +01:00
|
|
|
log.Warn("Error while updating user config")
|
2021-10-26 10:24:43 +02:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil, nil
|
|
|
|
}
|
|
|
|
|
2022-09-07 12:24:45 +02:00
|
|
|
// Clusters is the resolver for the clusters field.
|
|
|
|
func (r *queryResolver) Clusters(ctx context.Context) ([]*schema.Cluster, error) {
|
2022-09-05 17:46:38 +02:00
|
|
|
return archive.Clusters, nil
|
2021-10-26 10:24:43 +02:00
|
|
|
}
|
|
|
|
|
2022-09-07 12:24:45 +02:00
|
|
|
// Tags is the resolver for the tags field.
|
2021-12-17 15:49:22 +01:00
|
|
|
func (r *queryResolver) Tags(ctx context.Context) ([]*schema.Tag, error) {
|
2022-02-17 09:20:57 +01:00
|
|
|
return r.Repo.GetTags(nil)
|
2021-10-26 10:24:43 +02:00
|
|
|
}
|
|
|
|
|
2022-09-07 12:24:45 +02:00
|
|
|
// User is the resolver for the user field.
|
2022-03-15 11:04:54 +01:00
|
|
|
func (r *queryResolver) User(ctx context.Context, username string) (*model.User, error) {
|
|
|
|
return auth.FetchUser(ctx, r.DB, username)
|
|
|
|
}
|
|
|
|
|
2022-09-07 12:24:45 +02:00
|
|
|
// AllocatedNodes is the resolver for the allocatedNodes field.
|
2022-03-24 16:08:47 +01:00
|
|
|
func (r *queryResolver) AllocatedNodes(ctx context.Context, cluster string) ([]*model.Count, error) {
|
|
|
|
data, err := r.Repo.AllocatedNodes(cluster)
|
|
|
|
if err != nil {
|
2023-01-31 18:28:44 +01:00
|
|
|
log.Warn("Error while fetching allocated nodes")
|
2022-03-24 16:08:47 +01:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
counts := make([]*model.Count, 0, len(data))
|
|
|
|
for subcluster, hosts := range data {
|
|
|
|
counts = append(counts, &model.Count{
|
|
|
|
Name: subcluster,
|
|
|
|
Count: len(hosts),
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
return counts, nil
|
2022-03-24 10:32:08 +01:00
|
|
|
}
|
|
|
|
|
2022-09-07 12:24:45 +02:00
|
|
|
// Job is the resolver for the job field.
|
2021-12-17 15:49:22 +01:00
|
|
|
func (r *queryResolver) Job(ctx context.Context, id string) (*schema.Job, error) {
|
2022-02-17 09:04:57 +01:00
|
|
|
numericId, err := strconv.ParseInt(id, 10, 64)
|
|
|
|
if err != nil {
|
2023-01-31 18:28:44 +01:00
|
|
|
log.Warn("Error while parsing job id")
|
2022-02-17 09:04:57 +01:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
job, err := r.Repo.FindById(numericId)
|
|
|
|
if err != nil {
|
2023-01-31 18:28:44 +01:00
|
|
|
log.Warn("Error while finding job by id")
|
2022-02-17 09:04:57 +01:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2023-02-17 15:45:31 +01:00
|
|
|
if user := auth.GetUser(ctx); user != nil && job.User != user.Username && user.HasNotRoles([]string{auth.RoleAdmin, auth.RoleSupport, auth.RoleManager}) {
|
2022-02-17 09:04:57 +01:00
|
|
|
return nil, errors.New("you are not allowed to see this job")
|
2021-12-17 15:49:22 +01:00
|
|
|
}
|
|
|
|
|
2022-02-17 09:04:57 +01:00
|
|
|
return job, nil
|
2021-10-26 10:24:43 +02:00
|
|
|
}
|
|
|
|
|
2022-09-07 12:24:45 +02:00
|
|
|
// JobMetrics is the resolver for the jobMetrics field.
|
2021-12-20 10:48:58 +01:00
|
|
|
func (r *queryResolver) JobMetrics(ctx context.Context, id string, metrics []string, scopes []schema.MetricScope) ([]*model.JobMetricWithName, error) {
|
2021-10-26 10:24:43 +02:00
|
|
|
job, err := r.Query().Job(ctx, id)
|
|
|
|
if err != nil {
|
2023-01-31 18:28:44 +01:00
|
|
|
log.Warn("Error while querying job for metrics")
|
2021-10-26 10:24:43 +02:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2022-01-07 09:44:34 +01:00
|
|
|
data, err := metricdata.LoadData(job, metrics, scopes, ctx)
|
2021-10-26 10:24:43 +02:00
|
|
|
if err != nil {
|
2023-01-31 18:28:44 +01:00
|
|
|
log.Warn("Error while loading job data")
|
2021-10-26 10:24:43 +02:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
res := []*model.JobMetricWithName{}
|
|
|
|
for name, md := range data {
|
2021-12-20 10:48:58 +01:00
|
|
|
for scope, metric := range md {
|
|
|
|
if metric.Scope != schema.MetricScope(scope) {
|
2023-01-23 18:48:06 +01:00
|
|
|
log.Panic("metric.Scope != schema.MetricScope(scope) : Should not happen!")
|
2021-12-20 10:48:58 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
res = append(res, &model.JobMetricWithName{
|
|
|
|
Name: name,
|
|
|
|
Metric: metric,
|
|
|
|
})
|
|
|
|
}
|
2021-10-26 10:24:43 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return res, err
|
|
|
|
}
|
|
|
|
|
2022-09-07 12:24:45 +02:00
|
|
|
// JobsFootprints is the resolver for the jobsFootprints field.
|
2022-03-16 16:11:28 +01:00
|
|
|
func (r *queryResolver) JobsFootprints(ctx context.Context, filter []*model.JobFilter, metrics []string) (*model.Footprints, error) {
|
2021-10-26 10:24:43 +02:00
|
|
|
return r.jobsFootprints(ctx, filter, metrics)
|
|
|
|
}
|
|
|
|
|
2022-09-07 12:24:45 +02:00
|
|
|
// Jobs is the resolver for the jobs field.
|
2021-10-26 10:24:43 +02:00
|
|
|
func (r *queryResolver) Jobs(ctx context.Context, filter []*model.JobFilter, page *model.PageRequest, order *model.OrderByInput) (*model.JobResultList, error) {
|
2022-02-22 09:19:59 +01:00
|
|
|
if page == nil {
|
|
|
|
page = &model.PageRequest{
|
|
|
|
ItemsPerPage: 50,
|
|
|
|
Page: 1,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-02-17 09:04:57 +01:00
|
|
|
jobs, err := r.Repo.QueryJobs(ctx, filter, page, order)
|
|
|
|
if err != nil {
|
2023-01-31 18:28:44 +01:00
|
|
|
log.Warn("Error while querying jobs")
|
2022-02-17 09:04:57 +01:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
count, err := r.Repo.CountJobs(ctx, filter)
|
2021-10-26 10:24:43 +02:00
|
|
|
if err != nil {
|
2023-01-31 18:28:44 +01:00
|
|
|
log.Warn("Error while counting jobs")
|
2021-10-26 10:24:43 +02:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return &model.JobResultList{Items: jobs, Count: &count}, nil
|
|
|
|
}
|
|
|
|
|
2022-09-07 12:24:45 +02:00
|
|
|
// JobsStatistics is the resolver for the jobsStatistics field.
|
2021-10-26 10:24:43 +02:00
|
|
|
func (r *queryResolver) JobsStatistics(ctx context.Context, filter []*model.JobFilter, groupBy *model.Aggregate) ([]*model.JobsStatistics, error) {
|
2023-02-13 13:53:24 +01:00
|
|
|
return r.Repo.JobsStatistics(ctx, filter, groupBy)
|
2021-10-26 10:24:43 +02:00
|
|
|
}
|
|
|
|
|
2022-09-07 12:24:45 +02:00
|
|
|
// JobsCount is the resolver for the jobsCount field.
|
2022-03-25 10:20:33 +01:00
|
|
|
func (r *queryResolver) JobsCount(ctx context.Context, filter []*model.JobFilter, groupBy model.Aggregate, weight *model.Weights, limit *int) ([]*model.Count, error) {
|
|
|
|
counts, err := r.Repo.CountGroupedJobs(ctx, groupBy, filter, weight, limit)
|
2022-02-19 10:28:29 +01:00
|
|
|
if err != nil {
|
2023-01-31 18:28:44 +01:00
|
|
|
log.Warn("Error while counting grouped jobs")
|
2022-02-19 10:28:29 +01:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
res := make([]*model.Count, 0, len(counts))
|
|
|
|
for name, count := range counts {
|
|
|
|
res = append(res, &model.Count{
|
|
|
|
Name: name,
|
|
|
|
Count: count,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
return res, nil
|
|
|
|
}
|
|
|
|
|
2022-09-07 12:24:45 +02:00
|
|
|
// RooflineHeatmap is the resolver for the rooflineHeatmap field.
|
2022-09-12 13:33:01 +02:00
|
|
|
func (r *queryResolver) RooflineHeatmap(ctx context.Context, filter []*model.JobFilter, rows int, cols int, minX float64, minY float64, maxX float64, maxY float64) ([][]float64, error) {
|
2021-10-26 10:24:43 +02:00
|
|
|
return r.rooflineHeatmap(ctx, filter, rows, cols, minX, minY, maxX, maxY)
|
|
|
|
}
|
|
|
|
|
2022-09-07 12:24:45 +02:00
|
|
|
// NodeMetrics is the resolver for the nodeMetrics field.
|
2022-03-24 14:34:42 +01:00
|
|
|
func (r *queryResolver) NodeMetrics(ctx context.Context, cluster string, nodes []string, scopes []schema.MetricScope, metrics []string, from time.Time, to time.Time) ([]*model.NodeMetrics, error) {
|
2021-12-09 16:25:48 +01:00
|
|
|
user := auth.GetUser(ctx)
|
2022-01-27 09:29:11 +01:00
|
|
|
if user != nil && !user.HasRole(auth.RoleAdmin) {
|
2021-12-09 16:25:48 +01:00
|
|
|
return nil, errors.New("you need to be an administrator for this query")
|
|
|
|
}
|
|
|
|
|
2022-02-02 13:59:08 +01:00
|
|
|
if metrics == nil {
|
2022-09-05 17:46:38 +02:00
|
|
|
for _, mc := range archive.GetCluster(cluster).MetricConfig {
|
2022-02-02 13:59:08 +01:00
|
|
|
metrics = append(metrics, mc.Name)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-03-24 14:34:42 +01:00
|
|
|
data, err := metricdata.LoadNodeData(cluster, metrics, nodes, scopes, from, to, ctx)
|
2022-02-02 13:05:21 +01:00
|
|
|
if err != nil {
|
2023-01-31 18:28:44 +01:00
|
|
|
log.Warn("Error while loading node data")
|
2022-02-02 13:05:21 +01:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
nodeMetrics := make([]*model.NodeMetrics, 0, len(data))
|
|
|
|
for hostname, metrics := range data {
|
|
|
|
host := &model.NodeMetrics{
|
|
|
|
Host: hostname,
|
|
|
|
Metrics: make([]*model.JobMetricWithName, 0, len(metrics)*len(scopes)),
|
|
|
|
}
|
2022-09-05 17:46:38 +02:00
|
|
|
host.SubCluster, _ = archive.GetSubClusterByNode(cluster, hostname)
|
2022-02-02 13:05:21 +01:00
|
|
|
|
|
|
|
for metric, scopedMetrics := range metrics {
|
|
|
|
for _, scopedMetric := range scopedMetrics {
|
|
|
|
host.Metrics = append(host.Metrics, &model.JobMetricWithName{
|
|
|
|
Name: metric,
|
|
|
|
Metric: scopedMetric,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
nodeMetrics = append(nodeMetrics, host)
|
|
|
|
}
|
|
|
|
|
|
|
|
return nodeMetrics, nil
|
2021-12-09 16:25:48 +01:00
|
|
|
}
|
|
|
|
|
2022-03-14 10:18:56 +01:00
|
|
|
// Cluster returns generated.ClusterResolver implementation.
|
|
|
|
func (r *Resolver) Cluster() generated.ClusterResolver { return &clusterResolver{r} }
|
|
|
|
|
2021-10-26 10:24:43 +02:00
|
|
|
// Job returns generated.JobResolver implementation.
|
|
|
|
func (r *Resolver) Job() generated.JobResolver { return &jobResolver{r} }
|
|
|
|
|
|
|
|
// Mutation returns generated.MutationResolver implementation.
|
|
|
|
func (r *Resolver) Mutation() generated.MutationResolver { return &mutationResolver{r} }
|
|
|
|
|
|
|
|
// Query returns generated.QueryResolver implementation.
|
|
|
|
func (r *Resolver) Query() generated.QueryResolver { return &queryResolver{r} }
|
|
|
|
|
2022-03-14 10:18:56 +01:00
|
|
|
type clusterResolver struct{ *Resolver }
|
2021-10-26 10:24:43 +02:00
|
|
|
type jobResolver struct{ *Resolver }
|
|
|
|
type mutationResolver struct{ *Resolver }
|
|
|
|
type queryResolver struct{ *Resolver }
|