IAM: Generate a unique name for a new TeamBinding object (#112525)

* generate a unique name for TeamBinding and store it in the uid column

* generate testdata

* fix team binding name
This commit is contained in:
Mihai Doarna 2025-10-21 15:01:49 +03:00 committed by GitHub
parent a651fb1348
commit 7d88b0130c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
28 changed files with 81 additions and 81 deletions

View File

@ -1,5 +1,5 @@
INSERT INTO {{ .Ident .TeamMemberTable }}
(team_id, user_id, org_id, created, updated, external, permission)
(uid, team_id, user_id, org_id, created, updated, external, permission)
VALUES
({{ .Arg .Command.TeamID }}, {{ .Arg .Command.UserID }}, {{ .Arg .Command.OrgID }}, {{ .Arg .Command.Created }},
({{ .Arg .Command.UID }}, {{ .Arg .Command.TeamID }}, {{ .Arg .Command.UserID }}, {{ .Arg .Command.OrgID }}, {{ .Arg .Command.Created }},
{{ .Arg .Command.Updated }}, {{ .Arg .Command.External }}, {{ .Arg .Command.Permission }})

View File

@ -235,11 +235,10 @@ func TestIdentityQueries(t *testing.T) {
},
sqlQueryTeamBindingsTemplate: {
{
Name: "team_bindings_id",
Name: "team_bindings_uid",
Data: listTeamBindings(&ListTeamBindingsQuery{
OrgID: 1,
TeamID: 1,
UserID: 1,
UID: "tm-1",
Pagination: common.Pagination{Limit: 1},
}),
},

View File

@ -15,8 +15,7 @@ import (
)
type ListTeamBindingsQuery struct {
TeamID int64
UserID int64
UID string
OrgID int64
Pagination common.Pagination
}
@ -29,6 +28,7 @@ type ListTeamBindingsResult struct {
type TeamMember struct {
ID int64
UID string
TeamID int64
TeamUID string
UserID int64
@ -109,7 +109,7 @@ func (s *legacySQLStore) ListTeamBindings(ctx context.Context, ns claims.Namespa
for rows.Next() {
m := TeamMember{}
err = rows.Scan(&m.ID, &m.TeamUID, &m.TeamID, &m.UserUID, &m.UserID, &m.Created, &m.Updated, &m.Permission, &m.External)
err = rows.Scan(&m.ID, &m.UID, &m.TeamUID, &m.TeamID, &m.UserUID, &m.UserID, &m.Created, &m.Updated, &m.Permission, &m.External)
if err != nil {
return res, err
}
@ -127,6 +127,7 @@ func (s *legacySQLStore) ListTeamBindings(ctx context.Context, ns claims.Namespa
}
type CreateTeamMemberCommand struct {
UID string
TeamID int64
TeamUID string
UserID int64
@ -193,6 +194,7 @@ func (s *legacySQLStore) CreateTeamMember(ctx context.Context, ns claims.Namespa
createdTeamMember = TeamMember{
ID: teamMemberID,
UID: cmd.UID,
TeamID: cmd.TeamID,
TeamUID: cmd.TeamUID,
UserID: cmd.UserID,
@ -301,6 +303,6 @@ func (s *legacySQLStore) ListTeamMembers(ctx context.Context, ns claims.Namespac
func scanMember(rows *sql.Rows) (TeamMember, error) {
m := TeamMember{}
err := rows.Scan(&m.ID, &m.TeamUID, &m.TeamID, &m.UserUID, &m.UserID, &m.Name, &m.Email, &m.Username, &m.External, &m.Created, &m.Updated, &m.Permission)
err := rows.Scan(&m.ID, &m.UID, &m.TeamUID, &m.TeamID, &m.UserUID, &m.UserID, &m.Name, &m.Email, &m.Username, &m.External, &m.Created, &m.Updated, &m.Permission)
return m, err
}

View File

@ -1,14 +1,11 @@
SELECT tm.id as id, t.uid as team_uid, t.id as team_id, u.uid as user_uid, u.id as user_id, tm.created, tm.updated, tm.permission, tm.external
SELECT tm.id as id, tm.uid as uid, t.uid as team_uid, t.id as team_id, u.uid as user_uid, u.id as user_id, tm.created, tm.updated, tm.permission, tm.external
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
tm.org_id = {{ .Arg .Query.OrgID}}
{{ if .Query.TeamID }}
AND t.id = {{ .Arg .Query.TeamID }}
{{ end }}
{{ if .Query.UserID }}
AND u.id = {{ .Arg .Query.UserID }}
{{ if .Query.UID }}
AND tm.uid = {{ .Arg .Query.UID }}
{{ end }}
{{- if .Query.Pagination.Continue }}
AND tm.id >= {{ .Arg .Query.Pagination.Continue }}

View File

@ -1,5 +1,6 @@
SELECT
tm.id as id,
tm.uid as uid,
t.uid as team_uid,
t.id as team_id,
u.uid as user_uid,

View File

@ -1,5 +1,5 @@
INSERT INTO `grafana`.`team_member`
(team_id, user_id, org_id, created, updated, external, permission)
(uid, team_id, user_id, org_id, created, updated, external, permission)
VALUES
(1, 1, 0, '2023-01-01 12:00:00',
('', 1, 1, 0, '2023-01-01 12:00:00',
'2023-01-01 12:00:00', FALSE, 'Member')

View File

@ -1,5 +1,5 @@
INSERT INTO `grafana`.`team_member`
(team_id, user_id, org_id, created, updated, external, permission)
(uid, team_id, user_id, org_id, created, updated, external, permission)
VALUES
(1, 1, 0, '2023-01-01 12:00:00',
('', 1, 1, 0, '2023-01-01 12:00:00',
'2023-01-01 12:00:00', FALSE, 'Admin')

View File

@ -1,4 +1,4 @@
SELECT tm.id as id, t.uid as team_uid, t.id as team_id, u.uid as user_uid, u.id as user_id, tm.created, tm.updated, tm.permission, tm.external
SELECT tm.id as id, tm.uid as uid, t.uid as team_uid, t.id as team_id, u.uid as user_uid, u.id as user_id, tm.created, tm.updated, tm.permission, tm.external
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

View File

@ -1,4 +1,4 @@
SELECT tm.id as id, t.uid as team_uid, t.id as team_id, u.uid as user_uid, u.id as user_id, tm.created, tm.updated, tm.permission, tm.external
SELECT tm.id as id, tm.uid as uid, t.uid as team_uid, t.id as team_id, u.uid as user_uid, u.id as user_id, tm.created, tm.updated, tm.permission, tm.external
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

View File

@ -1,11 +1,10 @@
SELECT tm.id as id, t.uid as team_uid, t.id as team_id, u.uid as user_uid, u.id as user_id, tm.created, tm.updated, tm.permission, tm.external
SELECT tm.id as id, tm.uid as uid, t.uid as team_uid, t.id as team_id, u.uid as user_uid, u.id as user_id, tm.created, tm.updated, tm.permission, tm.external
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
tm.org_id = 1
AND t.id = 1
AND u.id = 1
AND tm.uid = 'tm-1'
AND NOT tm.external
ORDER BY t.id ASC
LIMIT 1;

View File

@ -1,5 +1,6 @@
SELECT
tm.id as id,
tm.uid as uid,
t.uid as team_uid,
t.id as team_id,
u.uid as user_uid,

View File

@ -1,5 +1,6 @@
SELECT
tm.id as id,
tm.uid as uid,
t.uid as team_uid,
t.id as team_id,
u.uid as user_uid,

View File

@ -1,5 +1,5 @@
INSERT INTO "grafana"."team_member"
(team_id, user_id, org_id, created, updated, external, permission)
(uid, team_id, user_id, org_id, created, updated, external, permission)
VALUES
(1, 1, 0, '2023-01-01 12:00:00',
('', 1, 1, 0, '2023-01-01 12:00:00',
'2023-01-01 12:00:00', FALSE, 'Member')

View File

@ -1,5 +1,5 @@
INSERT INTO "grafana"."team_member"
(team_id, user_id, org_id, created, updated, external, permission)
(uid, team_id, user_id, org_id, created, updated, external, permission)
VALUES
(1, 1, 0, '2023-01-01 12:00:00',
('', 1, 1, 0, '2023-01-01 12:00:00',
'2023-01-01 12:00:00', FALSE, 'Admin')

View File

@ -1,4 +1,4 @@
SELECT tm.id as id, t.uid as team_uid, t.id as team_id, u.uid as user_uid, u.id as user_id, tm.created, tm.updated, tm.permission, tm.external
SELECT tm.id as id, tm.uid as uid, t.uid as team_uid, t.id as team_id, u.uid as user_uid, u.id as user_id, tm.created, tm.updated, tm.permission, tm.external
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

View File

@ -1,4 +1,4 @@
SELECT tm.id as id, t.uid as team_uid, t.id as team_id, u.uid as user_uid, u.id as user_id, tm.created, tm.updated, tm.permission, tm.external
SELECT tm.id as id, tm.uid as uid, t.uid as team_uid, t.id as team_id, u.uid as user_uid, u.id as user_id, tm.created, tm.updated, tm.permission, tm.external
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

View File

@ -1,11 +1,10 @@
SELECT tm.id as id, t.uid as team_uid, t.id as team_id, u.uid as user_uid, u.id as user_id, tm.created, tm.updated, tm.permission, tm.external
SELECT tm.id as id, tm.uid as uid, t.uid as team_uid, t.id as team_id, u.uid as user_uid, u.id as user_id, tm.created, tm.updated, tm.permission, tm.external
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
tm.org_id = 1
AND t.id = 1
AND u.id = 1
AND tm.uid = 'tm-1'
AND NOT tm.external
ORDER BY t.id ASC
LIMIT 1;

View File

@ -1,5 +1,6 @@
SELECT
tm.id as id,
tm.uid as uid,
t.uid as team_uid,
t.id as team_id,
u.uid as user_uid,

View File

@ -1,5 +1,6 @@
SELECT
tm.id as id,
tm.uid as uid,
t.uid as team_uid,
t.id as team_id,
u.uid as user_uid,

View File

@ -1,5 +1,5 @@
INSERT INTO "grafana"."team_member"
(team_id, user_id, org_id, created, updated, external, permission)
(uid, team_id, user_id, org_id, created, updated, external, permission)
VALUES
(1, 1, 0, '2023-01-01 12:00:00',
('', 1, 1, 0, '2023-01-01 12:00:00',
'2023-01-01 12:00:00', FALSE, 'Member')

View File

@ -1,5 +1,5 @@
INSERT INTO "grafana"."team_member"
(team_id, user_id, org_id, created, updated, external, permission)
(uid, team_id, user_id, org_id, created, updated, external, permission)
VALUES
(1, 1, 0, '2023-01-01 12:00:00',
('', 1, 1, 0, '2023-01-01 12:00:00',
'2023-01-01 12:00:00', FALSE, 'Admin')

View File

@ -1,4 +1,4 @@
SELECT tm.id as id, t.uid as team_uid, t.id as team_id, u.uid as user_uid, u.id as user_id, tm.created, tm.updated, tm.permission, tm.external
SELECT tm.id as id, tm.uid as uid, t.uid as team_uid, t.id as team_id, u.uid as user_uid, u.id as user_id, tm.created, tm.updated, tm.permission, tm.external
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

View File

@ -1,4 +1,4 @@
SELECT tm.id as id, t.uid as team_uid, t.id as team_id, u.uid as user_uid, u.id as user_id, tm.created, tm.updated, tm.permission, tm.external
SELECT tm.id as id, tm.uid as uid, t.uid as team_uid, t.id as team_id, u.uid as user_uid, u.id as user_id, tm.created, tm.updated, tm.permission, tm.external
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

View File

@ -1,11 +1,10 @@
SELECT tm.id as id, t.uid as team_uid, t.id as team_id, u.uid as user_uid, u.id as user_id, tm.created, tm.updated, tm.permission, tm.external
SELECT tm.id as id, tm.uid as uid, t.uid as team_uid, t.id as team_id, u.uid as user_uid, u.id as user_id, tm.created, tm.updated, tm.permission, tm.external
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
tm.org_id = 1
AND t.id = 1
AND u.id = 1
AND tm.uid = 'tm-1'
AND NOT tm.external
ORDER BY t.id ASC
LIMIT 1;

View File

@ -1,5 +1,6 @@
SELECT
tm.id as id,
tm.uid as uid,
t.uid as team_uid,
t.id as team_id,
u.uid as user_uid,

View File

@ -1,5 +1,6 @@
SELECT
tm.id as id,
tm.uid as uid,
t.uid as team_uid,
t.id as team_id,
u.uid as user_uid,

View File

@ -4,7 +4,6 @@ import (
"context"
"fmt"
"strconv"
"strings"
"time"
apierrors "k8s.io/apimachinery/pkg/api/errors"
@ -19,6 +18,7 @@ import (
"github.com/grafana/grafana/pkg/registry/apis/iam/legacy"
"github.com/grafana/grafana/pkg/services/apiserver/endpoints/request"
"github.com/grafana/grafana/pkg/services/team"
"github.com/grafana/grafana/pkg/util"
)
var bindingResource = iamv0alpha1.TeamBindingResourceInfo
@ -99,6 +99,11 @@ func (l *LegacyBindingStore) Create(ctx context.Context, obj runtime.Object, cre
return nil, fmt.Errorf("expected TeamBinding object, got %T", obj)
}
if teamMemberObj.GenerateName != "" {
teamMemberObj.Name = teamMemberObj.GenerateName + util.GenerateShortUID()
teamMemberObj.GenerateName = ""
}
if createValidation != nil {
if err := createValidation(ctx, teamMemberObj); err != nil {
return nil, err
@ -130,6 +135,7 @@ func (l *LegacyBindingStore) Create(ctx context.Context, obj runtime.Object, cre
}
createCmd := legacy.CreateTeamMemberCommand{
UID: teamMemberObj.Name,
TeamID: teamObj.ID,
TeamUID: teamMemberObj.Spec.TeamRef.Name,
UserID: userObj.ID,
@ -154,11 +160,8 @@ func (l *LegacyBindingStore) Get(ctx context.Context, name string, options *meta
return nil, err
}
teamID, userID := mapFromBindingName(name)
res, err := l.store.ListTeamBindings(ctx, ns, legacy.ListTeamBindingsQuery{
TeamID: teamID,
UserID: userID,
UID: name,
Pagination: common.Pagination{Limit: 1},
})
if err != nil {
@ -215,7 +218,7 @@ func mapToBindingObject(ns claims.NamespaceInfo, tm legacy.TeamMember) iamv0alph
return iamv0alpha1.TeamBinding{
ObjectMeta: metav1.ObjectMeta{
Name: mapToBindingName(tm.TeamID, tm.UserID),
Name: tm.UID,
Namespace: ns.Value,
ResourceVersion: strconv.FormatInt(rv.UnixMilli(), 10),
CreationTimestamp: metav1.NewTime(ct),
@ -232,30 +235,3 @@ func mapToBindingObject(ns claims.NamespaceInfo, tm legacy.TeamMember) iamv0alph
},
}
}
func mapToBindingName(teamID, userID int64) string {
return fmt.Sprintf("teambinding-%d-%d", teamID, userID)
}
func mapFromBindingName(name string) (int64, int64) {
parts := strings.Split(name, "-")
if len(parts) != 3 {
return 0, 0
}
if parts[0] != "teambinding" {
return 0, 0
}
teamID, err := strconv.ParseInt(parts[1], 10, 64)
if err != nil {
return 0, 0
}
userID, err := strconv.ParseInt(parts[2], 10, 64)
if err != nil {
return 0, 0
}
return teamID, userID
}

View File

@ -260,10 +260,8 @@ func doTeamBindingCRUDTestsUsingTheLegacyAPIs(t *testing.T, helper *apis.K8sTest
"permission": "member"
}`
type legacyTeamBindingResponse struct {
UserID int64 `json:"userId"`
TeamID int64 `json:"teamId"`
Permission string `json:"permission"`
type legacyTeamBindingPostResponse struct {
Message string `json:"message"`
}
teamBindingRsp := apis.DoRequest(helper, apis.RequestParams{
@ -271,11 +269,36 @@ func doTeamBindingCRUDTestsUsingTheLegacyAPIs(t *testing.T, helper *apis.K8sTest
Method: "POST",
Path: "/api/teams/" + teamRsp.Result.UID + "/members",
Body: []byte(legacyTeamBindingPayload),
}, &legacyTeamBindingResponse{})
}, &legacyTeamBindingPostResponse{})
require.NotNil(t, teamBindingRsp)
require.Equal(t, 200, teamBindingRsp.Response.StatusCode)
type legacyTeamBindingGetResponse struct {
UID string `json:"uid"`
UserID int64 `json:"userId"`
TeamID int64 `json:"teamId"`
}
// Get the binding UID using the legacy API
legacyTeamBindingUIDRsp := apis.DoRequest(helper, apis.RequestParams{
User: helper.Org1.Admin,
Method: "GET",
Path: "/api/teams/" + teamRsp.Result.UID + "/members",
}, &[]legacyTeamBindingGetResponse{})
require.NotNil(t, legacyTeamBindingUIDRsp)
require.Equal(t, 200, legacyTeamBindingUIDRsp.Response.StatusCode)
teamBindingName := ""
for _, binding := range *legacyTeamBindingUIDRsp.Result {
if binding.UserID == userRsp.Result.ID && binding.TeamID == teamRsp.Result.ID {
teamBindingName = binding.UID
break
}
}
require.NotEmpty(t, teamBindingName)
// Get team binding using new API
teamBindingClient := helper.GetResourceClient(apis.ResourceClientArgs{
User: helper.Org1.Admin,
@ -283,7 +306,6 @@ func doTeamBindingCRUDTestsUsingTheLegacyAPIs(t *testing.T, helper *apis.K8sTest
GVR: gvrTeamBindings,
})
teamBindingName := fmt.Sprintf("teambinding-%d-%d", teamRsp.Result.ID, userRsp.Result.ID)
teamBinding, err := teamBindingClient.Resource.Get(ctx, teamBindingName, metav1.GetOptions{})
require.NoError(t, err)
require.NotNil(t, teamBinding)