IAM: Refactor team bindings to store one pair of team and member (#111871)

* store one pair of team member in team bindings object

* generate queries for sql unit tests

* remove TeamBinding struct
This commit is contained in:
Mihai Doarna
2025-10-03 16:48:51 +03:00
committed by GitHub
parent e9499bb60c
commit 6d7c50f18d
16 changed files with 120 additions and 186 deletions
+8 -26
View File
@@ -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
}
@@ -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 }};
@@ -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;
@@ -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;
@@ -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;
@@ -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;
@@ -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;
@@ -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;
@@ -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;
@@ -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;
@@ -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;
+12 -22
View File
@@ -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
@@ -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": ""
}
}
},