mirror of
https://github.com/grafana/grafana.git
synced 2024-11-25 02:10:45 -06:00
Zanzana: Sync team memberships (#89983)
* Zanzana: Use uid for users and teams * Zanzana: Team membership migrator --------- Co-authored-by: Alexander Zobnin <alexanderzobnin@gmail.com>
This commit is contained in:
parent
7448f22f91
commit
cbbc12a31b
@ -3,7 +3,6 @@ package migrator
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
openfgav1 "github.com/openfga/api/proto/openfga/v1"
|
||||
@ -30,9 +29,14 @@ type ZanzanaSynchroniser struct {
|
||||
|
||||
func NewZanzanaSynchroniser(client zanzana.Client, store db.DB, collectors ...TupleCollector) *ZanzanaSynchroniser {
|
||||
// Append shared collectors that is used by both enterprise and oss
|
||||
collectors = append(collectors, managedPermissionsCollector(store))
|
||||
collectors = append(
|
||||
collectors,
|
||||
teamMembershipCollector(store),
|
||||
managedPermissionsCollector(store),
|
||||
)
|
||||
|
||||
return &ZanzanaSynchroniser{
|
||||
client: client,
|
||||
log: log.New("zanzana.sync"),
|
||||
collectors: collectors,
|
||||
}
|
||||
@ -75,21 +79,24 @@ func managedPermissionsCollector(store db.DB) TupleCollector {
|
||||
return func(ctx context.Context, tuples map[string][]*openfgav1.TupleKey) error {
|
||||
const collectorID = "managed"
|
||||
const query = `
|
||||
SELECT ur.user_id, p.action, p.kind, p.identifier, r.org_id FROM permission p
|
||||
INNER JOIN role r on p.role_id = r.id
|
||||
LEFT JOIN user_role ur on r.id = ur.role_id
|
||||
LEFT JOIN team_role tr on r.id = tr.role_id
|
||||
LEFT JOIN builtin_role br on r.id = br.role_id
|
||||
WHERE r.name LIKE 'managed:%'
|
||||
`
|
||||
SELECT u.uid as user_uid, t.uid as team_uid, p.action, p.kind, p.identifier, r.org_id
|
||||
FROM permission p
|
||||
INNER JOIN role r ON p.role_id = r.id
|
||||
LEFT JOIN user_role ur ON r.id = ur.role_id
|
||||
LEFT JOIN user u ON u.id = ur.user_id
|
||||
LEFT JOIN team_role tr ON r.id = tr.role_id
|
||||
LEFT JOIN team t ON tr.team_id = t.id
|
||||
LEFT JOIN builtin_role br ON r.id = br.role_id
|
||||
WHERE r.name LIKE 'managed:%'
|
||||
`
|
||||
type Permission struct {
|
||||
RoleName string `xorm:"role_name"`
|
||||
OrgID int64 `xorm:"org_id"`
|
||||
Action string `xorm:"action"`
|
||||
Kind string
|
||||
Identifier string
|
||||
UserID int64 `xorm:"user_id"`
|
||||
TeamID int64 `xorm:"user_id"`
|
||||
UserUID string `xorm:"user_uid"`
|
||||
TeamUID string `xorm:"team_uid"`
|
||||
}
|
||||
|
||||
var permissions []Permission
|
||||
@ -103,10 +110,10 @@ func managedPermissionsCollector(store db.DB) TupleCollector {
|
||||
|
||||
for _, p := range permissions {
|
||||
var subject string
|
||||
if p.UserID > 0 {
|
||||
subject = zanzana.NewObject(zanzana.TypeUser, strconv.FormatInt(p.UserID, 10))
|
||||
} else if p.TeamID > 0 {
|
||||
subject = zanzana.NewObject(zanzana.TypeTeam, strconv.FormatInt(p.TeamID, 10))
|
||||
if len(p.UserUID) > 0 {
|
||||
subject = zanzana.NewObject(zanzana.TypeUser, p.UserUID)
|
||||
} else if len(p.TeamUID) > 0 {
|
||||
subject = zanzana.NewObject(zanzana.TypeTeam, p.TeamUID)
|
||||
} else {
|
||||
// FIXME(kalleep): Unsuported role binding (org role). We need to have basic roles in place
|
||||
continue
|
||||
@ -126,3 +133,48 @@ func managedPermissionsCollector(store db.DB) TupleCollector {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func teamMembershipCollector(store db.DB) TupleCollector {
|
||||
return func(ctx context.Context, tuples map[string][]*openfgav1.TupleKey) error {
|
||||
const collectorID = "team_membership"
|
||||
const query = `
|
||||
SELECT t.uid as team_uid, u.uid as user_uid, tm.permission
|
||||
FROM team_member tm
|
||||
INNER JOIN team t ON tm.team_id = t.id
|
||||
INNER JOIN user u ON tm.user_id = u.id
|
||||
`
|
||||
|
||||
type membership struct {
|
||||
TeamUID string `xorm:"team_uid"`
|
||||
UserUID string `xorm:"user_uid"`
|
||||
Permission int
|
||||
}
|
||||
|
||||
var memberships []membership
|
||||
err := store.WithDbSession(ctx, func(sess *db.Session) error {
|
||||
return sess.SQL(query).Find(&memberships)
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, m := range memberships {
|
||||
tuple := &openfgav1.TupleKey{
|
||||
User: zanzana.NewObject(zanzana.TypeUser, m.UserUID),
|
||||
Object: zanzana.NewObject(zanzana.TypeTeam, m.TeamUID),
|
||||
}
|
||||
|
||||
// Admin permission is 4 and member 0
|
||||
if m.Permission == 4 {
|
||||
tuple.Relation = zanzana.RelationTeamAdmin
|
||||
} else {
|
||||
tuple.Relation = zanzana.RelationTeamMember
|
||||
}
|
||||
|
||||
tuples[collectorID] = append(tuples[collectorID], tuple)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
@ -12,6 +12,11 @@ const (
|
||||
TypeTeam string = "team"
|
||||
)
|
||||
|
||||
const (
|
||||
RelationTeamMember string = "member"
|
||||
RelationTeamAdmin string = "admin"
|
||||
)
|
||||
|
||||
func NewObject(typ, id string) string {
|
||||
return fmt.Sprintf("%s:%s", typ, id)
|
||||
}
|
||||
@ -49,7 +54,7 @@ func TranslateToTuple(user string, action, kind, identifier string, orgID int64)
|
||||
tuple.User = user
|
||||
tuple.Relation = relation
|
||||
|
||||
// UID in grafana are not guarantee to be unique across orgs so we need to scope them.
|
||||
// Some uid:s in grafana are not guarantee to be unique across orgs so we need to scope them.
|
||||
if t.orgScoped {
|
||||
tuple.Object = NewScopedObject(t.typ, identifier, strconv.FormatInt(orgID, 10))
|
||||
} else {
|
||||
|
Loading…
Reference in New Issue
Block a user