package user import ( "context" "fmt" "strconv" "k8s.io/apimachinery/pkg/apis/meta/internalversion" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apiserver/pkg/registry/rest" "github.com/grafana/grafana/pkg/apimachinery/utils" identityv0 "github.com/grafana/grafana/pkg/apis/identity/v0alpha1" "github.com/grafana/grafana/pkg/registry/apis/identity/legacy" "github.com/grafana/grafana/pkg/services/apiserver/endpoints/request" "github.com/grafana/grafana/pkg/services/user" ) var ( _ rest.Scoper = (*LegacyStore)(nil) _ rest.SingularNameProvider = (*LegacyStore)(nil) _ rest.Getter = (*LegacyStore)(nil) _ rest.Lister = (*LegacyStore)(nil) _ rest.Storage = (*LegacyStore)(nil) ) var resource = identityv0.UserResourceInfo func NewLegacyStore(store legacy.LegacyIdentityStore) *LegacyStore { return &LegacyStore{store} } type LegacyStore struct { store legacy.LegacyIdentityStore } func (s *LegacyStore) New() runtime.Object { return resource.NewFunc() } func (s *LegacyStore) Destroy() {} func (s *LegacyStore) NamespaceScoped() bool { return true // namespace == org } func (s *LegacyStore) GetSingularName() string { return resource.GetSingularName() } func (s *LegacyStore) NewList() runtime.Object { return resource.NewListFunc() } func (s *LegacyStore) ConvertToTable(ctx context.Context, object runtime.Object, tableOptions runtime.Object) (*metav1.Table, error) { return resource.TableConverter().ConvertToTable(ctx, object, tableOptions) } func (s *LegacyStore) List(ctx context.Context, options *internalversion.ListOptions) (runtime.Object, error) { ns, err := request.NamespaceInfoFrom(ctx, true) if err != nil { return nil, err } query := legacy.ListUserQuery{ OrgID: ns.OrgID, Limit: options.Limit, IsServiceAccount: false, } if options.Continue != "" { query.ContinueID, err = strconv.ParseInt(options.Continue, 10, 64) if err != nil { return nil, fmt.Errorf("invalid continue token") } } found, err := s.store.ListUsers(ctx, ns, query) if err != nil { return nil, err } list := &identityv0.UserList{} for _, item := range found.Users { list.Items = append(list.Items, *toUserItem(&item, ns.Value)) } if found.ContinueID > 0 { list.ListMeta.Continue = strconv.FormatInt(found.ContinueID, 10) } if found.RV > 0 { list.ListMeta.ResourceVersion = strconv.FormatInt(found.RV, 10) } return list, err } func (s *LegacyStore) Get(ctx context.Context, name string, options *metav1.GetOptions) (runtime.Object, error) { ns, err := request.NamespaceInfoFrom(ctx, true) if err != nil { return nil, err } query := legacy.ListUserQuery{ OrgID: ns.OrgID, Limit: 1, IsServiceAccount: false, } found, err := s.store.ListUsers(ctx, ns, query) if found == nil || err != nil { return nil, resource.NewNotFound(name) } if len(found.Users) < 1 { return nil, resource.NewNotFound(name) } return toUserItem(&found.Users[0], ns.Value), nil } func toUserItem(u *user.User, ns string) *identityv0.User { item := &identityv0.User{ ObjectMeta: metav1.ObjectMeta{ Name: u.UID, Namespace: ns, ResourceVersion: fmt.Sprintf("%d", u.Updated.UnixMilli()), CreationTimestamp: metav1.NewTime(u.Created), }, Spec: identityv0.UserSpec{ Name: u.Name, Login: u.Login, Email: u.Email, EmailVerified: u.EmailVerified, Disabled: u.IsDisabled, }, } obj, _ := utils.MetaAccessor(item) obj.SetUpdatedTimestamp(&u.Updated) obj.SetOriginInfo(&utils.ResourceOriginInfo{ Name: "SQL", Path: strconv.FormatInt(u.ID, 10), }) return item }