diff --git a/apps/iam/kinds/v0alpha1/teambindingspec.cue b/apps/iam/kinds/v0alpha1/teambindingspec.cue index 3bd130c902d..c20e592e458 100644 --- a/apps/iam/kinds/v0alpha1/teambindingspec.cue +++ b/apps/iam/kinds/v0alpha1/teambindingspec.cue @@ -4,12 +4,13 @@ TeamBindingSpec: { #Subject: { // uid of the identity name: string - // permission of the identity in the team - permission: TeamPermission } - subjects: [...#Subject] + subject: #Subject teamRef: TeamRef + + // permission of the identity in the team + permission: TeamPermission } TeamRef:{ diff --git a/apps/iam/pkg/apis/iam/v0alpha1/teambinding_spec_gen.go b/apps/iam/pkg/apis/iam/v0alpha1/teambinding_spec_gen.go index 0e58323533e..13abd605168 100644 --- a/apps/iam/pkg/apis/iam/v0alpha1/teambinding_spec_gen.go +++ b/apps/iam/pkg/apis/iam/v0alpha1/teambinding_spec_gen.go @@ -6,8 +6,6 @@ package v0alpha1 type TeamBindingspecSubject struct { // uid of the identity Name string `json:"name"` - // permission of the identity in the team - Permission TeamBindingTeamPermission `json:"permission"` } // NewTeamBindingspecSubject creates a new TeamBindingspecSubject object. @@ -15,14 +13,6 @@ func NewTeamBindingspecSubject() *TeamBindingspecSubject { return &TeamBindingspecSubject{} } -// +k8s:openapi-gen=true -type TeamBindingTeamPermission string - -const ( - TeamBindingTeamPermissionAdmin TeamBindingTeamPermission = "admin" - TeamBindingTeamPermissionMember TeamBindingTeamPermission = "member" -) - // +k8s:openapi-gen=true type TeamBindingTeamRef struct { // Name is the unique identifier for a team. @@ -34,16 +24,26 @@ func NewTeamBindingTeamRef() *TeamBindingTeamRef { return &TeamBindingTeamRef{} } +// +k8s:openapi-gen=true +type TeamBindingTeamPermission string + +const ( + TeamBindingTeamPermissionAdmin TeamBindingTeamPermission = "admin" + TeamBindingTeamPermissionMember TeamBindingTeamPermission = "member" +) + // +k8s:openapi-gen=true type TeamBindingSpec struct { - Subjects []TeamBindingspecSubject `json:"subjects"` - TeamRef TeamBindingTeamRef `json:"teamRef"` + Subject TeamBindingspecSubject `json:"subject"` + TeamRef TeamBindingTeamRef `json:"teamRef"` + // permission of the identity in the team + Permission TeamBindingTeamPermission `json:"permission"` } // NewTeamBindingSpec creates a new TeamBindingSpec object. func NewTeamBindingSpec() *TeamBindingSpec { return &TeamBindingSpec{ - Subjects: []TeamBindingspecSubject{}, - TeamRef: *NewTeamBindingTeamRef(), + Subject: *NewTeamBindingspecSubject(), + TeamRef: *NewTeamBindingTeamRef(), } } diff --git a/apps/iam/pkg/apis/iam/v0alpha1/zz_openapi_gen.go b/apps/iam/pkg/apis/iam/v0alpha1/zz_openapi_gen.go index cb2e31f9144..2532b5df8cc 100644 --- a/apps/iam/pkg/apis/iam/v0alpha1/zz_openapi_gen.go +++ b/apps/iam/pkg/apis/iam/v0alpha1/zz_openapi_gen.go @@ -2103,17 +2103,10 @@ func schema_pkg_apis_iam_v0alpha1_TeamBindingSpec(ref common.ReferenceCallback) SchemaProps: spec.SchemaProps{ Type: []string{"object"}, Properties: map[string]spec.Schema{ - "subjects": { + "subject": { SchemaProps: spec.SchemaProps{ - Type: []string{"array"}, - Items: &spec.SchemaOrArray{ - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Default: map[string]interface{}{}, - Ref: ref("github.com/grafana/grafana/apps/iam/pkg/apis/iam/v0alpha1.TeamBindingspecSubject"), - }, - }, - }, + Default: map[string]interface{}{}, + Ref: ref("github.com/grafana/grafana/apps/iam/pkg/apis/iam/v0alpha1.TeamBindingspecSubject"), }, }, "teamRef": { @@ -2122,8 +2115,16 @@ func schema_pkg_apis_iam_v0alpha1_TeamBindingSpec(ref common.ReferenceCallback) Ref: ref("github.com/grafana/grafana/apps/iam/pkg/apis/iam/v0alpha1.TeamBindingTeamRef"), }, }, + "permission": { + SchemaProps: spec.SchemaProps{ + Description: "permission of the identity in the team", + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, }, - Required: []string{"subjects", "teamRef"}, + Required: []string{"subject", "teamRef", "permission"}, }, }, Dependencies: []string{ @@ -2210,16 +2211,8 @@ func schema_pkg_apis_iam_v0alpha1_TeamBindingspecSubject(ref common.ReferenceCal Format: "", }, }, - "permission": { - SchemaProps: spec.SchemaProps{ - Description: "permission of the identity in the team", - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, }, - Required: []string{"name", "permission"}, + Required: []string{"name"}, }, }, } diff --git a/pkg/registry/apis/iam/legacy/team.go b/pkg/registry/apis/iam/legacy/team.go index 0ad11584a7f..6f49707d5d0 100644 --- a/pkg/registry/apis/iam/legacy/team.go +++ b/pkg/registry/apis/iam/legacy/team.go @@ -421,7 +421,7 @@ type ListTeamBindingsQuery struct { } type ListTeamBindingsResult struct { - Bindings []TeamBinding + Bindings []TeamMember Continue int64 RV int64 } @@ -445,11 +445,6 @@ func (m TeamMember) MemberID() string { return claims.NewTypeID(claims.TypeUser, m.UserUID) } -type TeamBinding struct { - TeamUID string - Members []TeamMember -} - var sqlQueryTeamBindingsTemplate = mustTemplate("team_bindings_query.sql") type listTeamBindingsQuery struct { @@ -505,11 +500,11 @@ func (s *legacySQLStore) ListTeamBindings(ctx context.Context, ns claims.Namespa return nil, err } - res := &ListTeamBindingsResult{} - grouped := map[string][]TeamMember{} + res := &ListTeamBindingsResult{ + Bindings: make([]TeamMember, 0, int(query.Pagination.Limit)), + } var lastID int64 - var atTeamLimit bool for rows.Next() { m := TeamMember{} @@ -518,16 +513,11 @@ func (s *legacySQLStore) ListTeamBindings(ctx context.Context, ns claims.Namespa return res, err } - lastID = m.TeamID - members, ok := grouped[m.TeamUID] - if ok { - grouped[m.TeamUID] = append(members, m) - } else if !atTeamLimit { - grouped[m.TeamUID] = []TeamMember{m} - } + res.Bindings = append(res.Bindings, m) - if len(grouped) >= int(query.Pagination.Limit)-1 { - atTeamLimit = true + lastID = m.ID + + if len(res.Bindings) >= int(query.Pagination.Limit)-1 { res.Continue = lastID } } @@ -536,14 +526,6 @@ func (s *legacySQLStore) ListTeamBindings(ctx context.Context, ns claims.Namespa res.RV, err = sql.GetResourceVersion(ctx, "team_member", "updated") } - res.Bindings = make([]TeamBinding, 0, len(grouped)) - for uid, members := range grouped { - res.Bindings = append(res.Bindings, TeamBinding{ - TeamUID: uid, - Members: members, - }) - } - return res, err } diff --git a/pkg/registry/apis/iam/legacy/team_bindings_query.sql b/pkg/registry/apis/iam/legacy/team_bindings_query.sql index fb8930c9fde..a64687a7e8f 100644 --- a/pkg/registry/apis/iam/legacy/team_bindings_query.sql +++ b/pkg/registry/apis/iam/legacy/team_bindings_query.sql @@ -3,18 +3,13 @@ FROM {{ .Ident .TeamMemberTable }} tm INNER JOIN {{ .Ident .TeamTable }} t ON tm.team_id = t.id INNER JOIN {{ .Ident .UserTable }} u ON tm.user_id = u.id WHERE -{{ if .Query.UID }} - t.uid = {{ .Arg .Query.UID }} -{{ else }} - t.uid IN( - SELECT uid - FROM {{ .Ident .TeamTable }} t - {{ if .Query.Pagination.Continue }} - WHERE t.id >= {{ .Arg .Query.Pagination.Continue }} - {{ end }} - ORDER BY t.id ASC LIMIT {{ .Arg .Query.Pagination.Limit }} - ) -{{ end }} -AND tm.org_id = {{ .Arg .Query.OrgID}} + tm.org_id = {{ .Arg .Query.OrgID}} + {{ if .Query.UID }} + AND t.uid = {{ .Arg .Query.UID }} + {{ end }} + {{- if .Query.Pagination.Continue }} + AND tm.id >= {{ .Arg .Query.Pagination.Continue }} + {{- end }} AND NOT tm.external -ORDER BY t.id ASC; +ORDER BY t.id ASC +LIMIT {{ .Arg .Query.Pagination.Limit }}; diff --git a/pkg/registry/apis/iam/legacy/testdata/mysql--team_bindings_query-team_1_bindings.sql b/pkg/registry/apis/iam/legacy/testdata/mysql--team_bindings_query-team_1_bindings.sql index 4dc43b4f936..1b3c18c20cc 100755 --- a/pkg/registry/apis/iam/legacy/testdata/mysql--team_bindings_query-team_1_bindings.sql +++ b/pkg/registry/apis/iam/legacy/testdata/mysql--team_bindings_query-team_1_bindings.sql @@ -3,7 +3,8 @@ FROM `grafana`.`team_member` tm INNER JOIN `grafana`.`team` t ON tm.team_id = t.id INNER JOIN `grafana`.`user` u ON tm.user_id = u.id WHERE - t.uid = 'team-1' -AND tm.org_id = 1 + tm.org_id = 1 + AND t.uid = 'team-1' AND NOT tm.external -ORDER BY t.id ASC; +ORDER BY t.id ASC +LIMIT 1; diff --git a/pkg/registry/apis/iam/legacy/testdata/mysql--team_bindings_query-team_bindings_page_1.sql b/pkg/registry/apis/iam/legacy/testdata/mysql--team_bindings_query-team_bindings_page_1.sql index be3d212eb9e..2180553e3a0 100755 --- a/pkg/registry/apis/iam/legacy/testdata/mysql--team_bindings_query-team_bindings_page_1.sql +++ b/pkg/registry/apis/iam/legacy/testdata/mysql--team_bindings_query-team_bindings_page_1.sql @@ -3,11 +3,7 @@ FROM `grafana`.`team_member` tm INNER JOIN `grafana`.`team` t ON tm.team_id = t.id INNER JOIN `grafana`.`user` u ON tm.user_id = u.id WHERE - t.uid IN( - SELECT uid - FROM `grafana`.`team` t - ORDER BY t.id ASC LIMIT 5 - ) -AND tm.org_id = 1 + tm.org_id = 1 AND NOT tm.external -ORDER BY t.id ASC; +ORDER BY t.id ASC +LIMIT 5; diff --git a/pkg/registry/apis/iam/legacy/testdata/mysql--team_bindings_query-team_bindings_page_2.sql b/pkg/registry/apis/iam/legacy/testdata/mysql--team_bindings_query-team_bindings_page_2.sql index ecbef2e0c01..767f1fe4c82 100755 --- a/pkg/registry/apis/iam/legacy/testdata/mysql--team_bindings_query-team_bindings_page_2.sql +++ b/pkg/registry/apis/iam/legacy/testdata/mysql--team_bindings_query-team_bindings_page_2.sql @@ -3,12 +3,8 @@ FROM `grafana`.`team_member` tm INNER JOIN `grafana`.`team` t ON tm.team_id = t.id INNER JOIN `grafana`.`user` u ON tm.user_id = u.id WHERE - t.uid IN( - SELECT uid - FROM `grafana`.`team` t - WHERE t.id >= 2 - ORDER BY t.id ASC LIMIT 1 - ) -AND tm.org_id = 1 + tm.org_id = 1 + AND tm.id >= 2 AND NOT tm.external -ORDER BY t.id ASC; +ORDER BY t.id ASC +LIMIT 1; diff --git a/pkg/registry/apis/iam/legacy/testdata/postgres--team_bindings_query-team_1_bindings.sql b/pkg/registry/apis/iam/legacy/testdata/postgres--team_bindings_query-team_1_bindings.sql index 82d10b5fd51..50e968de4a1 100755 --- a/pkg/registry/apis/iam/legacy/testdata/postgres--team_bindings_query-team_1_bindings.sql +++ b/pkg/registry/apis/iam/legacy/testdata/postgres--team_bindings_query-team_1_bindings.sql @@ -3,7 +3,8 @@ FROM "grafana"."team_member" tm INNER JOIN "grafana"."team" t ON tm.team_id = t.id INNER JOIN "grafana"."user" u ON tm.user_id = u.id WHERE - t.uid = 'team-1' -AND tm.org_id = 1 + tm.org_id = 1 + AND t.uid = 'team-1' AND NOT tm.external -ORDER BY t.id ASC; +ORDER BY t.id ASC +LIMIT 1; diff --git a/pkg/registry/apis/iam/legacy/testdata/postgres--team_bindings_query-team_bindings_page_1.sql b/pkg/registry/apis/iam/legacy/testdata/postgres--team_bindings_query-team_bindings_page_1.sql index 77e1182cde8..76f9e5a8cca 100755 --- a/pkg/registry/apis/iam/legacy/testdata/postgres--team_bindings_query-team_bindings_page_1.sql +++ b/pkg/registry/apis/iam/legacy/testdata/postgres--team_bindings_query-team_bindings_page_1.sql @@ -3,11 +3,7 @@ FROM "grafana"."team_member" tm INNER JOIN "grafana"."team" t ON tm.team_id = t.id INNER JOIN "grafana"."user" u ON tm.user_id = u.id WHERE - t.uid IN( - SELECT uid - FROM "grafana"."team" t - ORDER BY t.id ASC LIMIT 5 - ) -AND tm.org_id = 1 + tm.org_id = 1 AND NOT tm.external -ORDER BY t.id ASC; +ORDER BY t.id ASC +LIMIT 5; diff --git a/pkg/registry/apis/iam/legacy/testdata/postgres--team_bindings_query-team_bindings_page_2.sql b/pkg/registry/apis/iam/legacy/testdata/postgres--team_bindings_query-team_bindings_page_2.sql index 2cec052d9da..c6608dd7968 100755 --- a/pkg/registry/apis/iam/legacy/testdata/postgres--team_bindings_query-team_bindings_page_2.sql +++ b/pkg/registry/apis/iam/legacy/testdata/postgres--team_bindings_query-team_bindings_page_2.sql @@ -3,12 +3,8 @@ FROM "grafana"."team_member" tm INNER JOIN "grafana"."team" t ON tm.team_id = t.id INNER JOIN "grafana"."user" u ON tm.user_id = u.id WHERE - t.uid IN( - SELECT uid - FROM "grafana"."team" t - WHERE t.id >= 2 - ORDER BY t.id ASC LIMIT 1 - ) -AND tm.org_id = 1 + tm.org_id = 1 + AND tm.id >= 2 AND NOT tm.external -ORDER BY t.id ASC; +ORDER BY t.id ASC +LIMIT 1; diff --git a/pkg/registry/apis/iam/legacy/testdata/sqlite--team_bindings_query-team_1_bindings.sql b/pkg/registry/apis/iam/legacy/testdata/sqlite--team_bindings_query-team_1_bindings.sql index 82d10b5fd51..50e968de4a1 100755 --- a/pkg/registry/apis/iam/legacy/testdata/sqlite--team_bindings_query-team_1_bindings.sql +++ b/pkg/registry/apis/iam/legacy/testdata/sqlite--team_bindings_query-team_1_bindings.sql @@ -3,7 +3,8 @@ FROM "grafana"."team_member" tm INNER JOIN "grafana"."team" t ON tm.team_id = t.id INNER JOIN "grafana"."user" u ON tm.user_id = u.id WHERE - t.uid = 'team-1' -AND tm.org_id = 1 + tm.org_id = 1 + AND t.uid = 'team-1' AND NOT tm.external -ORDER BY t.id ASC; +ORDER BY t.id ASC +LIMIT 1; diff --git a/pkg/registry/apis/iam/legacy/testdata/sqlite--team_bindings_query-team_bindings_page_1.sql b/pkg/registry/apis/iam/legacy/testdata/sqlite--team_bindings_query-team_bindings_page_1.sql index 77e1182cde8..76f9e5a8cca 100755 --- a/pkg/registry/apis/iam/legacy/testdata/sqlite--team_bindings_query-team_bindings_page_1.sql +++ b/pkg/registry/apis/iam/legacy/testdata/sqlite--team_bindings_query-team_bindings_page_1.sql @@ -3,11 +3,7 @@ FROM "grafana"."team_member" tm INNER JOIN "grafana"."team" t ON tm.team_id = t.id INNER JOIN "grafana"."user" u ON tm.user_id = u.id WHERE - t.uid IN( - SELECT uid - FROM "grafana"."team" t - ORDER BY t.id ASC LIMIT 5 - ) -AND tm.org_id = 1 + tm.org_id = 1 AND NOT tm.external -ORDER BY t.id ASC; +ORDER BY t.id ASC +LIMIT 5; diff --git a/pkg/registry/apis/iam/legacy/testdata/sqlite--team_bindings_query-team_bindings_page_2.sql b/pkg/registry/apis/iam/legacy/testdata/sqlite--team_bindings_query-team_bindings_page_2.sql index 2cec052d9da..c6608dd7968 100755 --- a/pkg/registry/apis/iam/legacy/testdata/sqlite--team_bindings_query-team_bindings_page_2.sql +++ b/pkg/registry/apis/iam/legacy/testdata/sqlite--team_bindings_query-team_bindings_page_2.sql @@ -3,12 +3,8 @@ FROM "grafana"."team_member" tm INNER JOIN "grafana"."team" t ON tm.team_id = t.id INNER JOIN "grafana"."user" u ON tm.user_id = u.id WHERE - t.uid IN( - SELECT uid - FROM "grafana"."team" t - WHERE t.id >= 2 - ORDER BY t.id ASC LIMIT 1 - ) -AND tm.org_id = 1 + tm.org_id = 1 + AND tm.id >= 2 AND NOT tm.external -ORDER BY t.id ASC; +ORDER BY t.id ASC +LIMIT 1; diff --git a/pkg/registry/apis/iam/team/store_binding.go b/pkg/registry/apis/iam/team/store_binding.go index cdb61777039..38b2a23237f 100644 --- a/pkg/registry/apis/iam/team/store_binding.go +++ b/pkg/registry/apis/iam/team/store_binding.go @@ -117,46 +117,36 @@ func (l *LegacyBindingStore) List(ctx context.Context, options *internalversion. return &list, nil } -func mapToBindingObject(ns claims.NamespaceInfo, b legacy.TeamBinding) iamv0alpha1.TeamBinding { +func mapToBindingObject(ns claims.NamespaceInfo, tm legacy.TeamMember) iamv0alpha1.TeamBinding { rv := time.Time{} ct := time.Now() - for _, m := range b.Members { - if m.Updated.After(rv) { - rv = m.Updated - } - if m.Created.Before(ct) { - ct = m.Created - } + if tm.Updated.After(rv) { + rv = tm.Updated + } + if tm.Created.Before(ct) { + ct = tm.Created } return iamv0alpha1.TeamBinding{ ObjectMeta: metav1.ObjectMeta{ - Name: b.TeamUID, + Name: tm.TeamUID, Namespace: ns.Value, ResourceVersion: strconv.FormatInt(rv.UnixMilli(), 10), CreationTimestamp: metav1.NewTime(ct), }, Spec: iamv0alpha1.TeamBindingSpec{ TeamRef: iamv0alpha1.TeamBindingTeamRef{ - Name: b.TeamUID, + Name: tm.TeamUID, }, - Subjects: mapToSubjects(b.Members), + Subject: iamv0alpha1.TeamBindingspecSubject{ + Name: tm.UserUID, + }, + Permission: common.MapTeamPermission(tm.Permission), }, } } -func mapToSubjects(members []legacy.TeamMember) []iamv0alpha1.TeamBindingspecSubject { - out := make([]iamv0alpha1.TeamBindingspecSubject, 0, len(members)) - for _, m := range members { - out = append(out, iamv0alpha1.TeamBindingspecSubject{ - Name: m.UserUID, - Permission: common.MapTeamPermission(m.Permission), - }) - } - return out -} - func mapPermisson(p team.PermissionType) iamv0.TeamPermission { if p == team.PermissionTypeAdmin { return iamv0.TeamPermissionAdmin diff --git a/pkg/tests/apis/openapi_snapshots/iam.grafana.app-v0alpha1.json b/pkg/tests/apis/openapi_snapshots/iam.grafana.app-v0alpha1.json index 9a7b8ef0481..3561b54c453 100644 --- a/pkg/tests/apis/openapi_snapshots/iam.grafana.app-v0alpha1.json +++ b/pkg/tests/apis/openapi_snapshots/iam.grafana.app-v0alpha1.json @@ -3737,20 +3737,23 @@ "com.github.grafana.grafana.apps.iam.pkg.apis.iam.v0alpha1.TeamBindingSpec": { "type": "object", "required": [ - "subjects", - "teamRef" + "subject", + "teamRef", + "permission" ], "properties": { - "subjects": { - "type": "array", - "items": { - "default": {}, - "allOf": [ - { - "$ref": "#/components/schemas/com.github.grafana.grafana.apps.iam.pkg.apis.iam.v0alpha1.TeamBindingspecSubject" - } - ] - } + "permission": { + "description": "permission of the identity in the team", + "type": "string", + "default": "" + }, + "subject": { + "default": {}, + "allOf": [ + { + "$ref": "#/components/schemas/com.github.grafana.grafana.apps.iam.pkg.apis.iam.v0alpha1.TeamBindingspecSubject" + } + ] }, "teamRef": { "default": {}, @@ -3778,19 +3781,13 @@ "com.github.grafana.grafana.apps.iam.pkg.apis.iam.v0alpha1.TeamBindingspecSubject": { "type": "object", "required": [ - "name", - "permission" + "name" ], "properties": { "name": { "description": "uid of the identity", "type": "string", "default": "" - }, - "permission": { - "description": "permission of the identity in the team", - "type": "string", - "default": "" } } }, @@ -5594,15 +5591,18 @@ "github.com/grafana/grafana/apps/iam/pkg/apis/iam/v0alpha1.TeamBindingSpec": { "type": "object", "required": [ - "subjects", - "teamRef" + "subject", + "teamRef", + "permission" ], "properties": { - "subjects": { - "type": "array", - "items": { - "default": {} - } + "permission": { + "description": "permission of the identity in the team", + "type": "string", + "default": "" + }, + "subject": { + "default": {} }, "teamRef": { "default": {} @@ -5644,19 +5644,13 @@ "github.com/grafana/grafana/apps/iam/pkg/apis/iam/v0alpha1.TeamBindingspecSubject": { "type": "object", "required": [ - "name", - "permission" + "name" ], "properties": { "name": { "description": "uid of the identity", "type": "string", "default": "" - }, - "permission": { - "description": "permission of the identity in the team", - "type": "string", - "default": "" } } },