Update and port to cc-lib

This commit is contained in:
2026-02-11 07:06:06 +01:00
parent 49a1748641
commit 8d6c6b819b
18 changed files with 29 additions and 29 deletions

View File

@@ -248,7 +248,7 @@ func generateJWT(authHandle *auth.Authentication, username string) error {
return fmt.Errorf("getting user '%s': %w", username, err) return fmt.Errorf("getting user '%s': %w", username, err)
} }
if !user.HasRole(schema.RoleApi) { if !user.HasRole(schema.RoleAPI) {
cclog.Warnf("JWT: User '%s' does not have the role 'api'. REST API endpoints will return error!\n", user.Username) cclog.Warnf("JWT: User '%s' does not have the role 'api'. REST API endpoints will return error!\n", user.Username)
} }

2
go.mod
View File

@@ -9,7 +9,7 @@ tool (
require ( require (
github.com/99designs/gqlgen v0.17.85 github.com/99designs/gqlgen v0.17.85
github.com/ClusterCockpit/cc-lib/v2 v2.2.2 github.com/ClusterCockpit/cc-lib/v2 v2.3.0
github.com/Masterminds/squirrel v1.5.4 github.com/Masterminds/squirrel v1.5.4
github.com/aws/aws-sdk-go-v2 v1.41.1 github.com/aws/aws-sdk-go-v2 v1.41.1
github.com/aws/aws-sdk-go-v2/config v1.32.6 github.com/aws/aws-sdk-go-v2/config v1.32.6

2
go.sum
View File

@@ -6,6 +6,8 @@ github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 h1:mFRzDkZVAjdal+
github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU= github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU=
github.com/ClusterCockpit/cc-lib/v2 v2.2.2 h1:ye4RY57I19c2cXr3XWZBS/QYYgQVeGFvsiu5HkyKq9E= github.com/ClusterCockpit/cc-lib/v2 v2.2.2 h1:ye4RY57I19c2cXr3XWZBS/QYYgQVeGFvsiu5HkyKq9E=
github.com/ClusterCockpit/cc-lib/v2 v2.2.2/go.mod h1:JuxMAuEOaLLNEnnL9U3ejha8kMvsSatLdKPZEgJw6iw= github.com/ClusterCockpit/cc-lib/v2 v2.2.2/go.mod h1:JuxMAuEOaLLNEnnL9U3ejha8kMvsSatLdKPZEgJw6iw=
github.com/ClusterCockpit/cc-lib/v2 v2.3.0 h1:69NqCAYCU1r2w6J5Yuxoe8jfR68VLqtWwsWXZ6KTOo4=
github.com/ClusterCockpit/cc-lib/v2 v2.3.0/go.mod h1:JuxMAuEOaLLNEnnL9U3ejha8kMvsSatLdKPZEgJw6iw=
github.com/DATA-DOG/go-sqlmock v1.5.2 h1:OcvFkGmslmlZibjAjaHm3L//6LiuBgolP7OputlJIzU= github.com/DATA-DOG/go-sqlmock v1.5.2 h1:OcvFkGmslmlZibjAjaHm3L//6LiuBgolP7OputlJIzU=
github.com/DATA-DOG/go-sqlmock v1.5.2/go.mod h1:88MAG/4G7SMwSE3CeA0ZKzrT5CiOU3OJ+JlNzwDqpNU= github.com/DATA-DOG/go-sqlmock v1.5.2/go.mod h1:88MAG/4G7SMwSE3CeA0ZKzrT5CiOU3OJ+JlNzwDqpNU=
github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc= github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc=

View File

@@ -36,9 +36,9 @@ type GetClustersAPIResponse struct {
// @router /api/clusters/ [get] // @router /api/clusters/ [get]
func (api *RestAPI) getClusters(rw http.ResponseWriter, r *http.Request) { func (api *RestAPI) getClusters(rw http.ResponseWriter, r *http.Request) {
if user := repository.GetUserFromContext(r.Context()); user != nil && if user := repository.GetUserFromContext(r.Context()); user != nil &&
!user.HasRole(schema.RoleApi) { !user.HasRole(schema.RoleAPI) {
handleError(fmt.Errorf("missing role: %v", schema.GetRoleString(schema.RoleApi)), http.StatusForbidden, rw) handleError(fmt.Errorf("missing role: %v", schema.GetRoleString(schema.RoleAPI)), http.StatusForbidden, rw)
return return
} }

View File

@@ -1054,8 +1054,8 @@ type GetUsedNodesAPIResponse struct {
// @router /api/jobs/used_nodes [get] // @router /api/jobs/used_nodes [get]
func (api *RestAPI) getUsedNodes(rw http.ResponseWriter, r *http.Request) { func (api *RestAPI) getUsedNodes(rw http.ResponseWriter, r *http.Request) {
if user := repository.GetUserFromContext(r.Context()); user != nil && if user := repository.GetUserFromContext(r.Context()); user != nil &&
!user.HasRole(schema.RoleApi) { !user.HasRole(schema.RoleAPI) {
handleError(fmt.Errorf("missing role: %v", schema.GetRoleString(schema.RoleApi)), http.StatusForbidden, rw) handleError(fmt.Errorf("missing role: %v", schema.GetRoleString(schema.RoleAPI)), http.StatusForbidden, rw)
return return
} }

View File

@@ -164,7 +164,7 @@ func (api *RestAPI) createUser(rw http.ResponseWriter, r *http.Request) {
return return
} }
if len(password) == 0 && role != schema.GetRoleString(schema.RoleApi) { if len(password) == 0 && role != schema.GetRoleString(schema.RoleAPI) {
handleError(fmt.Errorf("only API users are allowed to have a blank password (login will be impossible)"), http.StatusBadRequest, rw) handleError(fmt.Errorf("only API users are allowed to have a blank password (login will be impossible)"), http.StatusBadRequest, rw)
return return
} }

View File

@@ -448,13 +448,13 @@ func (auth *Authentication) AuthAPI(
if user != nil { if user != nil {
switch { switch {
case len(user.Roles) == 1: case len(user.Roles) == 1:
if user.HasRole(schema.RoleApi) { if user.HasRole(schema.RoleAPI) {
ctx := context.WithValue(r.Context(), repository.ContextUserKey, user) ctx := context.WithValue(r.Context(), repository.ContextUserKey, user)
onsuccess.ServeHTTP(rw, r.WithContext(ctx)) onsuccess.ServeHTTP(rw, r.WithContext(ctx))
return return
} }
case len(user.Roles) >= 2: case len(user.Roles) >= 2:
if user.HasAllRoles([]schema.Role{schema.RoleAdmin, schema.RoleApi}) { if user.HasAllRoles([]schema.Role{schema.RoleAdmin, schema.RoleAPI}) {
ctx := context.WithValue(r.Context(), repository.ContextUserKey, user) ctx := context.WithValue(r.Context(), repository.ContextUserKey, user)
onsuccess.ServeHTTP(rw, r.WithContext(ctx)) onsuccess.ServeHTTP(rw, r.WithContext(ctx))
return return
@@ -484,13 +484,13 @@ func (auth *Authentication) AuthUserAPI(
if user != nil { if user != nil {
switch { switch {
case len(user.Roles) == 1: case len(user.Roles) == 1:
if user.HasRole(schema.RoleApi) { if user.HasRole(schema.RoleAPI) {
ctx := context.WithValue(r.Context(), repository.ContextUserKey, user) ctx := context.WithValue(r.Context(), repository.ContextUserKey, user)
onsuccess.ServeHTTP(rw, r.WithContext(ctx)) onsuccess.ServeHTTP(rw, r.WithContext(ctx))
return return
} }
case len(user.Roles) >= 2: case len(user.Roles) >= 2:
if user.HasRole(schema.RoleApi) && user.HasAnyRole([]schema.Role{schema.RoleUser, schema.RoleManager, schema.RoleSupport, schema.RoleAdmin}) { if user.HasRole(schema.RoleAPI) && user.HasAnyRole([]schema.Role{schema.RoleUser, schema.RoleManager, schema.RoleSupport, schema.RoleAdmin}) {
ctx := context.WithValue(r.Context(), repository.ContextUserKey, user) ctx := context.WithValue(r.Context(), repository.ContextUserKey, user)
onsuccess.ServeHTTP(rw, r.WithContext(ctx)) onsuccess.ServeHTTP(rw, r.WithContext(ctx))
return return
@@ -520,13 +520,13 @@ func (auth *Authentication) AuthMetricStoreAPI(
if user != nil { if user != nil {
switch { switch {
case len(user.Roles) == 1: case len(user.Roles) == 1:
if user.HasRole(schema.RoleApi) { if user.HasRole(schema.RoleAPI) {
ctx := context.WithValue(r.Context(), repository.ContextUserKey, user) ctx := context.WithValue(r.Context(), repository.ContextUserKey, user)
onsuccess.ServeHTTP(rw, r.WithContext(ctx)) onsuccess.ServeHTTP(rw, r.WithContext(ctx))
return return
} }
case len(user.Roles) >= 2: case len(user.Roles) >= 2:
if user.HasRole(schema.RoleApi) && user.HasAnyRole([]schema.Role{schema.RoleUser, schema.RoleManager, schema.RoleAdmin}) { if user.HasRole(schema.RoleAPI) && user.HasAnyRole([]schema.Role{schema.RoleUser, schema.RoleManager, schema.RoleAdmin}) {
ctx := context.WithValue(r.Context(), repository.ContextUserKey, user) ctx := context.WithValue(r.Context(), repository.ContextUserKey, user)
onsuccess.ServeHTTP(rw, r.WithContext(ctx)) onsuccess.ServeHTTP(rw, r.WithContext(ctx))
return return

View File

@@ -10245,7 +10245,7 @@ func (ec *executionContext) _Series_id(ctx context.Context, field graphql.Collec
field, field,
ec.fieldContext_Series_id, ec.fieldContext_Series_id,
func(ctx context.Context) (any, error) { func(ctx context.Context) (any, error) {
return obj.Id, nil return obj.ID, nil
}, },
nil, nil,
ec.marshalOString2ᚖstring, ec.marshalOString2ᚖstring,

View File

@@ -552,7 +552,7 @@ func (r *queryResolver) ScopedJobStats(ctx context.Context, id string, metrics [
for _, stat := range stats { for _, stat := range stats {
mdlStats = append(mdlStats, &model.ScopedStats{ mdlStats = append(mdlStats, &model.ScopedStats{
Hostname: stat.Hostname, Hostname: stat.Hostname,
ID: stat.Id, ID: stat.ID,
Data: stat.Data, Data: stat.Data,
}) })
} }

View File

@@ -499,7 +499,7 @@ func copyJobMetric(src *schema.JobMetric) *schema.JobMetric {
func copySeries(src *schema.Series) schema.Series { func copySeries(src *schema.Series) schema.Series {
dst := schema.Series{ dst := schema.Series{
Hostname: src.Hostname, Hostname: src.Hostname,
Id: src.Id, ID: src.ID,
Statistics: src.Statistics, Statistics: src.Statistics,
Data: make([]schema.Float, len(src.Data)), Data: make([]schema.Float, len(src.Data)),
} }

View File

@@ -21,7 +21,7 @@ func TestDeepCopy(t *testing.T) {
Series: []schema.Series{ Series: []schema.Series{
{ {
Hostname: "node001", Hostname: "node001",
Id: &nodeId, ID: &nodeId,
Data: []schema.Float{1.0, 2.0, 3.0}, Data: []schema.Float{1.0, 2.0, 3.0},
Statistics: schema.MetricStatistics{ Statistics: schema.MetricStatistics{
Min: 1.0, Min: 1.0,

View File

@@ -267,7 +267,7 @@ func (ccms *CCMetricStore) LoadData(
jobMetric.Series = append(jobMetric.Series, schema.Series{ jobMetric.Series = append(jobMetric.Series, schema.Series{
Hostname: query.Hostname, Hostname: query.Hostname,
Id: id, ID: id,
Statistics: schema.MetricStatistics{ Statistics: schema.MetricStatistics{
Avg: float64(res.Avg), Avg: float64(res.Avg),
Min: float64(res.Min), Min: float64(res.Min),
@@ -419,7 +419,7 @@ func (ccms *CCMetricStore) LoadScopedStats(
scopedJobStats[metric][scope] = append(scopedJobStats[metric][scope], &schema.ScopedStats{ scopedJobStats[metric][scope] = append(scopedJobStats[metric][scope], &schema.ScopedStats{
Hostname: query.Hostname, Hostname: query.Hostname,
Id: id, ID: id,
Data: &schema.MetricStatistics{ Data: &schema.MetricStatistics{
Avg: float64(res.Avg), Avg: float64(res.Avg),
Min: float64(res.Min), Min: float64(res.Min),
@@ -634,7 +634,7 @@ func (ccms *CCMetricStore) LoadNodeListData(
scopeData.Series = append(scopeData.Series, schema.Series{ scopeData.Series = append(scopeData.Series, schema.Series{
Hostname: query.Hostname, Hostname: query.Hostname,
Id: id, ID: id,
Statistics: schema.MetricStatistics{ Statistics: schema.MetricStatistics{
Avg: float64(res.Avg), Avg: float64(res.Avg),
Min: float64(res.Min), Min: float64(res.Min),

View File

@@ -150,7 +150,7 @@ func SecurityCheckWithUser(user *schema.User, query sq.SelectBuilder) (sq.Select
} }
switch { switch {
case len(user.Roles) == 1 && user.HasRole(schema.RoleApi): case len(user.Roles) == 1 && user.HasRole(schema.RoleAPI):
return query, nil return query, nil
case user.HasAnyRole([]schema.Role{schema.RoleAdmin, schema.RoleSupport}): case user.HasAnyRole([]schema.Role{schema.RoleAdmin, schema.RoleSupport}):
return query, nil return query, nil

View File

@@ -644,12 +644,12 @@ func (r *JobRepository) checkScopeAuth(user *schema.User, operation string, scop
if user != nil { if user != nil {
switch { switch {
case operation == "write" && scope == "admin": case operation == "write" && scope == "admin":
if user.HasRole(schema.RoleAdmin) || (len(user.Roles) == 1 && user.HasRole(schema.RoleApi)) { if user.HasRole(schema.RoleAdmin) || (len(user.Roles) == 1 && user.HasRole(schema.RoleAPI)) {
return true, nil return true, nil
} }
return false, nil return false, nil
case operation == "write" && scope == "global": case operation == "write" && scope == "global":
if user.HasAnyRole([]schema.Role{schema.RoleAdmin, schema.RoleSupport}) || (len(user.Roles) == 1 && user.HasRole(schema.RoleApi)) { if user.HasAnyRole([]schema.Role{schema.RoleAdmin, schema.RoleSupport}) || (len(user.Roles) == 1 && user.HasRole(schema.RoleAPI)) {
return true, nil return true, nil
} }
return false, nil return false, nil

View File

@@ -51,7 +51,7 @@ func DecodeJobStats(r io.Reader, k string) (schema.ScopedJobStats, error) {
for _, series := range jobMetric.Series { for _, series := range jobMetric.Series {
scopedJobStats[metric][scope] = append(scopedJobStats[metric][scope], &schema.ScopedStats{ scopedJobStats[metric][scope] = append(scopedJobStats[metric][scope], &schema.ScopedStats{
Hostname: series.Hostname, Hostname: series.Hostname,
Id: series.Id, ID: series.ID,
Data: &series.Statistics, Data: &series.Statistics,
}) })
} }

View File

@@ -81,7 +81,6 @@ func JobToParquetRow(meta *schema.Job, data *schema.JobData) (*ParquetJobRow, er
NumNodes: meta.NumNodes, NumNodes: meta.NumNodes,
NumHWThreads: meta.NumHWThreads, NumHWThreads: meta.NumHWThreads,
NumAcc: meta.NumAcc, NumAcc: meta.NumAcc,
Exclusive: meta.Exclusive,
Energy: meta.Energy, Energy: meta.Energy,
SMT: meta.SMT, SMT: meta.SMT,
ResourcesJSON: resourcesJSON, ResourcesJSON: resourcesJSON,

View File

@@ -47,7 +47,6 @@ func makeTestJob(jobID int64) (*schema.Job, *schema.JobData) {
Walltime: 7200, Walltime: 7200,
NumNodes: 2, NumNodes: 2,
NumHWThreads: 16, NumHWThreads: 16,
Exclusive: 1,
SMT: 1, SMT: 1,
Resources: []*schema.Resource{ Resources: []*schema.Resource{
{Hostname: "node001"}, {Hostname: "node001"},

View File

@@ -149,7 +149,7 @@ func (ccms *InternalMetricStore) LoadData(
jobMetric.Series = append(jobMetric.Series, schema.Series{ jobMetric.Series = append(jobMetric.Series, schema.Series{
Hostname: query.Hostname, Hostname: query.Hostname,
Id: id, ID: id,
Statistics: schema.MetricStatistics{ Statistics: schema.MetricStatistics{
Avg: float64(res.Avg), Avg: float64(res.Avg),
Min: float64(res.Min), Min: float64(res.Min),
@@ -651,7 +651,7 @@ func (ccms *InternalMetricStore) LoadScopedStats(
scopedJobStats[metric][scope] = append(scopedJobStats[metric][scope], &schema.ScopedStats{ scopedJobStats[metric][scope] = append(scopedJobStats[metric][scope], &schema.ScopedStats{
Hostname: query.Hostname, Hostname: query.Hostname,
Id: id, ID: id,
Data: &schema.MetricStatistics{ Data: &schema.MetricStatistics{
Avg: float64(res.Avg), Avg: float64(res.Avg),
Min: float64(res.Min), Min: float64(res.Min),
@@ -894,7 +894,7 @@ func (ccms *InternalMetricStore) LoadNodeListData(
scopeData.Series = append(scopeData.Series, schema.Series{ scopeData.Series = append(scopeData.Series, schema.Series{
Hostname: query.Hostname, Hostname: query.Hostname,
Id: id, ID: id,
Statistics: schema.MetricStatistics{ Statistics: schema.MetricStatistics{
Avg: float64(res.Avg), Avg: float64(res.Avg),
Min: float64(res.Min), Min: float64(res.Min),