From 2bfa607ad0367648776b1d1a9b037fe16a9b047b Mon Sep 17 00:00:00 2001 From: Karl Persson Date: Thu, 5 Sep 2024 13:43:54 +0200 Subject: [PATCH] ServiceAccount: Update service account api resource and add service account token (#92972) * Create own legacy store function to list service accounts and update api model * Add service account tokens as a sub resource for service accounts --- pkg/apis/iam/v0alpha1/register.go | 15 +- .../iam/v0alpha1/types_servier_account.go | 26 ++- .../iam/v0alpha1/zz_generated.deepcopy.go | 58 +++++ pkg/apis/iam/v0alpha1/zz_generated.openapi.go | 151 ++++++++++--- pkg/registry/apis/iam/common/common.go | 8 +- .../apis/iam/legacy/service_account.go | 205 ++++++++++++++++++ .../legacy/service_account_tokens_query.sql | 19 ++ .../iam/legacy/service_accounts_query.sql | 18 ++ pkg/registry/apis/iam/legacy/sql.go | 3 + .../mysql--users_query-users_page_1.sql | 2 +- .../mysql--users_query-users_page_2.sql | 2 +- .../testdata/mysql--users_query-users_uid.sql | 2 +- .../postgres--users_query-users_page_1.sql | 2 +- .../postgres--users_query-users_page_2.sql | 2 +- .../postgres--users_query-users_uid.sql | 2 +- .../sqlite--users_query-users_page_1.sql | 2 +- .../sqlite--users_query-users_page_2.sql | 2 +- .../sqlite--users_query-users_uid.sql | 2 +- pkg/registry/apis/iam/legacy/user.go | 5 +- pkg/registry/apis/iam/legacy/users_query.sql | 2 +- pkg/registry/apis/iam/register.go | 29 +-- .../apis/iam/serviceaccount/rest_token.go | 115 ++++++++++ pkg/registry/apis/iam/serviceaccount/store.go | 62 +++--- pkg/registry/apis/iam/sso/store.go | 22 +- pkg/registry/apis/iam/team/rest_members.go | 12 +- pkg/registry/apis/iam/team/store.go | 12 +- pkg/registry/apis/iam/team/store_binding.go | 28 +-- pkg/registry/apis/iam/user/rest_display.go | 22 +- pkg/registry/apis/iam/user/rest_user_team.go | 12 +- pkg/registry/apis/iam/user/store.go | 22 +- .../serviceaccounts/manager/service_test.go | 4 +- pkg/services/serviceaccounts/models.go | 4 - 32 files changed, 688 insertions(+), 184 deletions(-) create mode 100644 pkg/registry/apis/iam/legacy/service_account.go create mode 100644 pkg/registry/apis/iam/legacy/service_account_tokens_query.sql create mode 100644 pkg/registry/apis/iam/legacy/service_accounts_query.sql create mode 100644 pkg/registry/apis/iam/serviceaccount/rest_token.go diff --git a/pkg/apis/iam/v0alpha1/register.go b/pkg/apis/iam/v0alpha1/register.go index f2b713dbe19..688befc53b2 100644 --- a/pkg/apis/iam/v0alpha1/register.go +++ b/pkg/apis/iam/v0alpha1/register.go @@ -75,18 +75,18 @@ var ServiceAccountResourceInfo = utils.NewResourceInfo(GROUP, VERSION, utils.TableColumns{ Definition: []metav1.TableColumnDefinition{ {Name: "Name", Type: "string", Format: "name"}, - {Name: "Account", Type: "string", Format: "string", Description: "The service account email"}, - {Name: "Email", Type: "string", Format: "string", Description: "The user email"}, + {Name: "Title", Type: "string", Format: "string"}, + {Name: "Disabled", Type: "boolean"}, {Name: "Created At", Type: "date"}, }, Reader: func(obj any) ([]interface{}, error) { - u, ok := obj.(*ServiceAccount) + sa, ok := obj.(*ServiceAccount) if ok { return []interface{}{ - u.Name, - u.Spec.Name, - u.Spec.Email, - u.CreationTimestamp.UTC().Format(time.RFC3339), + sa.Name, + sa.Spec.Title, + sa.Spec.Disabled, + sa.CreationTimestamp.UTC().Format(time.RFC3339), }, nil } return nil, fmt.Errorf("expected service account") @@ -163,6 +163,7 @@ func AddKnownTypes(scheme *runtime.Scheme, version string) { &UserTeamList{}, &ServiceAccount{}, &ServiceAccountList{}, + &ServiceAccountTokenList{}, &Team{}, &TeamList{}, &IdentityDisplayResults{}, diff --git a/pkg/apis/iam/v0alpha1/types_servier_account.go b/pkg/apis/iam/v0alpha1/types_servier_account.go index a00d8bb7663..8451095c04d 100644 --- a/pkg/apis/iam/v0alpha1/types_servier_account.go +++ b/pkg/apis/iam/v0alpha1/types_servier_account.go @@ -1,6 +1,8 @@ package v0alpha1 -import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object type ServiceAccount struct { @@ -11,10 +13,8 @@ type ServiceAccount struct { } type ServiceAccountSpec struct { - Name string `json:"name,omitempty"` - Email string `json:"email,omitempty"` - EmailVerified bool `json:"emailVerified,omitempty"` - Disabled bool `json:"disabled,omitempty"` + Title string `json:"title,omitempty"` + Disabled bool `json:"disabled,omitempty"` } // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object @@ -24,3 +24,19 @@ type ServiceAccountList struct { Items []ServiceAccount `json:"items,omitempty"` } + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object +type ServiceAccountTokenList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + + Items []ServiceAccountToken `json:"items,omitempty"` +} + +type ServiceAccountToken struct { + Name string `json:"name,omitempty"` + Revoked bool `json:"revoked,omitempty"` + Expires *metav1.Time `json:"expires,omitempty"` + LastUsed *metav1.Time `json:"lastUsed,omitempty"` + Created metav1.Time `json:"created"` +} diff --git a/pkg/apis/iam/v0alpha1/zz_generated.deepcopy.go b/pkg/apis/iam/v0alpha1/zz_generated.deepcopy.go index e4d9f5eaabf..0ef8cff060b 100644 --- a/pkg/apis/iam/v0alpha1/zz_generated.deepcopy.go +++ b/pkg/apis/iam/v0alpha1/zz_generated.deepcopy.go @@ -220,6 +220,64 @@ func (in *ServiceAccountSpec) DeepCopy() *ServiceAccountSpec { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ServiceAccountToken) DeepCopyInto(out *ServiceAccountToken) { + *out = *in + if in.Expires != nil { + in, out := &in.Expires, &out.Expires + *out = (*in).DeepCopy() + } + if in.LastUsed != nil { + in, out := &in.LastUsed, &out.LastUsed + *out = (*in).DeepCopy() + } + in.Created.DeepCopyInto(&out.Created) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServiceAccountToken. +func (in *ServiceAccountToken) DeepCopy() *ServiceAccountToken { + if in == nil { + return nil + } + out := new(ServiceAccountToken) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ServiceAccountTokenList) DeepCopyInto(out *ServiceAccountTokenList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]ServiceAccountToken, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServiceAccountTokenList. +func (in *ServiceAccountTokenList) DeepCopy() *ServiceAccountTokenList { + if in == nil { + return nil + } + out := new(ServiceAccountTokenList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *ServiceAccountTokenList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *Team) DeepCopyInto(out *Team) { *out = *in diff --git a/pkg/apis/iam/v0alpha1/zz_generated.openapi.go b/pkg/apis/iam/v0alpha1/zz_generated.openapi.go index 1ec80097388..8e1357781ab 100644 --- a/pkg/apis/iam/v0alpha1/zz_generated.openapi.go +++ b/pkg/apis/iam/v0alpha1/zz_generated.openapi.go @@ -14,29 +14,31 @@ import ( func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenAPIDefinition { return map[string]common.OpenAPIDefinition{ - "github.com/grafana/grafana/pkg/apis/iam/v0alpha1.IdentityDisplay": schema_pkg_apis_iam_v0alpha1_IdentityDisplay(ref), - "github.com/grafana/grafana/pkg/apis/iam/v0alpha1.IdentityDisplayResults": schema_pkg_apis_iam_v0alpha1_IdentityDisplayResults(ref), - "github.com/grafana/grafana/pkg/apis/iam/v0alpha1.SSOSetting": schema_pkg_apis_iam_v0alpha1_SSOSetting(ref), - "github.com/grafana/grafana/pkg/apis/iam/v0alpha1.SSOSettingList": schema_pkg_apis_iam_v0alpha1_SSOSettingList(ref), - "github.com/grafana/grafana/pkg/apis/iam/v0alpha1.SSOSettingSpec": schema_pkg_apis_iam_v0alpha1_SSOSettingSpec(ref), - "github.com/grafana/grafana/pkg/apis/iam/v0alpha1.ServiceAccount": schema_pkg_apis_iam_v0alpha1_ServiceAccount(ref), - "github.com/grafana/grafana/pkg/apis/iam/v0alpha1.ServiceAccountList": schema_pkg_apis_iam_v0alpha1_ServiceAccountList(ref), - "github.com/grafana/grafana/pkg/apis/iam/v0alpha1.ServiceAccountSpec": schema_pkg_apis_iam_v0alpha1_ServiceAccountSpec(ref), - "github.com/grafana/grafana/pkg/apis/iam/v0alpha1.Team": schema_pkg_apis_iam_v0alpha1_Team(ref), - "github.com/grafana/grafana/pkg/apis/iam/v0alpha1.TeamBinding": schema_pkg_apis_iam_v0alpha1_TeamBinding(ref), - "github.com/grafana/grafana/pkg/apis/iam/v0alpha1.TeamBindingList": schema_pkg_apis_iam_v0alpha1_TeamBindingList(ref), - "github.com/grafana/grafana/pkg/apis/iam/v0alpha1.TeamBindingSpec": schema_pkg_apis_iam_v0alpha1_TeamBindingSpec(ref), - "github.com/grafana/grafana/pkg/apis/iam/v0alpha1.TeamList": schema_pkg_apis_iam_v0alpha1_TeamList(ref), - "github.com/grafana/grafana/pkg/apis/iam/v0alpha1.TeamMember": schema_pkg_apis_iam_v0alpha1_TeamMember(ref), - "github.com/grafana/grafana/pkg/apis/iam/v0alpha1.TeamMemberList": schema_pkg_apis_iam_v0alpha1_TeamMemberList(ref), - "github.com/grafana/grafana/pkg/apis/iam/v0alpha1.TeamRef": schema_pkg_apis_iam_v0alpha1_TeamRef(ref), - "github.com/grafana/grafana/pkg/apis/iam/v0alpha1.TeamSpec": schema_pkg_apis_iam_v0alpha1_TeamSpec(ref), - "github.com/grafana/grafana/pkg/apis/iam/v0alpha1.TeamSubject": schema_pkg_apis_iam_v0alpha1_TeamSubject(ref), - "github.com/grafana/grafana/pkg/apis/iam/v0alpha1.User": schema_pkg_apis_iam_v0alpha1_User(ref), - "github.com/grafana/grafana/pkg/apis/iam/v0alpha1.UserList": schema_pkg_apis_iam_v0alpha1_UserList(ref), - "github.com/grafana/grafana/pkg/apis/iam/v0alpha1.UserSpec": schema_pkg_apis_iam_v0alpha1_UserSpec(ref), - "github.com/grafana/grafana/pkg/apis/iam/v0alpha1.UserTeam": schema_pkg_apis_iam_v0alpha1_UserTeam(ref), - "github.com/grafana/grafana/pkg/apis/iam/v0alpha1.UserTeamList": schema_pkg_apis_iam_v0alpha1_UserTeamList(ref), + "github.com/grafana/grafana/pkg/apis/iam/v0alpha1.IdentityDisplay": schema_pkg_apis_iam_v0alpha1_IdentityDisplay(ref), + "github.com/grafana/grafana/pkg/apis/iam/v0alpha1.IdentityDisplayResults": schema_pkg_apis_iam_v0alpha1_IdentityDisplayResults(ref), + "github.com/grafana/grafana/pkg/apis/iam/v0alpha1.SSOSetting": schema_pkg_apis_iam_v0alpha1_SSOSetting(ref), + "github.com/grafana/grafana/pkg/apis/iam/v0alpha1.SSOSettingList": schema_pkg_apis_iam_v0alpha1_SSOSettingList(ref), + "github.com/grafana/grafana/pkg/apis/iam/v0alpha1.SSOSettingSpec": schema_pkg_apis_iam_v0alpha1_SSOSettingSpec(ref), + "github.com/grafana/grafana/pkg/apis/iam/v0alpha1.ServiceAccount": schema_pkg_apis_iam_v0alpha1_ServiceAccount(ref), + "github.com/grafana/grafana/pkg/apis/iam/v0alpha1.ServiceAccountList": schema_pkg_apis_iam_v0alpha1_ServiceAccountList(ref), + "github.com/grafana/grafana/pkg/apis/iam/v0alpha1.ServiceAccountSpec": schema_pkg_apis_iam_v0alpha1_ServiceAccountSpec(ref), + "github.com/grafana/grafana/pkg/apis/iam/v0alpha1.ServiceAccountToken": schema_pkg_apis_iam_v0alpha1_ServiceAccountToken(ref), + "github.com/grafana/grafana/pkg/apis/iam/v0alpha1.ServiceAccountTokenList": schema_pkg_apis_iam_v0alpha1_ServiceAccountTokenList(ref), + "github.com/grafana/grafana/pkg/apis/iam/v0alpha1.Team": schema_pkg_apis_iam_v0alpha1_Team(ref), + "github.com/grafana/grafana/pkg/apis/iam/v0alpha1.TeamBinding": schema_pkg_apis_iam_v0alpha1_TeamBinding(ref), + "github.com/grafana/grafana/pkg/apis/iam/v0alpha1.TeamBindingList": schema_pkg_apis_iam_v0alpha1_TeamBindingList(ref), + "github.com/grafana/grafana/pkg/apis/iam/v0alpha1.TeamBindingSpec": schema_pkg_apis_iam_v0alpha1_TeamBindingSpec(ref), + "github.com/grafana/grafana/pkg/apis/iam/v0alpha1.TeamList": schema_pkg_apis_iam_v0alpha1_TeamList(ref), + "github.com/grafana/grafana/pkg/apis/iam/v0alpha1.TeamMember": schema_pkg_apis_iam_v0alpha1_TeamMember(ref), + "github.com/grafana/grafana/pkg/apis/iam/v0alpha1.TeamMemberList": schema_pkg_apis_iam_v0alpha1_TeamMemberList(ref), + "github.com/grafana/grafana/pkg/apis/iam/v0alpha1.TeamRef": schema_pkg_apis_iam_v0alpha1_TeamRef(ref), + "github.com/grafana/grafana/pkg/apis/iam/v0alpha1.TeamSpec": schema_pkg_apis_iam_v0alpha1_TeamSpec(ref), + "github.com/grafana/grafana/pkg/apis/iam/v0alpha1.TeamSubject": schema_pkg_apis_iam_v0alpha1_TeamSubject(ref), + "github.com/grafana/grafana/pkg/apis/iam/v0alpha1.User": schema_pkg_apis_iam_v0alpha1_User(ref), + "github.com/grafana/grafana/pkg/apis/iam/v0alpha1.UserList": schema_pkg_apis_iam_v0alpha1_UserList(ref), + "github.com/grafana/grafana/pkg/apis/iam/v0alpha1.UserSpec": schema_pkg_apis_iam_v0alpha1_UserSpec(ref), + "github.com/grafana/grafana/pkg/apis/iam/v0alpha1.UserTeam": schema_pkg_apis_iam_v0alpha1_UserTeam(ref), + "github.com/grafana/grafana/pkg/apis/iam/v0alpha1.UserTeamList": schema_pkg_apis_iam_v0alpha1_UserTeamList(ref), } } @@ -390,24 +392,12 @@ func schema_pkg_apis_iam_v0alpha1_ServiceAccountSpec(ref common.ReferenceCallbac SchemaProps: spec.SchemaProps{ Type: []string{"object"}, Properties: map[string]spec.Schema{ - "name": { + "title": { SchemaProps: spec.SchemaProps{ Type: []string{"string"}, Format: "", }, }, - "email": { - SchemaProps: spec.SchemaProps{ - Type: []string{"string"}, - Format: "", - }, - }, - "emailVerified": { - SchemaProps: spec.SchemaProps{ - Type: []string{"boolean"}, - Format: "", - }, - }, "disabled": { SchemaProps: spec.SchemaProps{ Type: []string{"boolean"}, @@ -420,6 +410,95 @@ func schema_pkg_apis_iam_v0alpha1_ServiceAccountSpec(ref common.ReferenceCallbac } } +func schema_pkg_apis_iam_v0alpha1_ServiceAccountToken(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "name": { + SchemaProps: spec.SchemaProps{ + Type: []string{"string"}, + Format: "", + }, + }, + "revoked": { + SchemaProps: spec.SchemaProps{ + Type: []string{"boolean"}, + Format: "", + }, + }, + "expires": { + SchemaProps: spec.SchemaProps{ + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Time"), + }, + }, + "lastUsed": { + SchemaProps: spec.SchemaProps{ + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Time"), + }, + }, + "created": { + SchemaProps: spec.SchemaProps{ + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Time"), + }, + }, + }, + Required: []string{"created"}, + }, + }, + Dependencies: []string{ + "k8s.io/apimachinery/pkg/apis/meta/v1.Time"}, + } +} + +func schema_pkg_apis_iam_v0alpha1_ServiceAccountTokenList(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "kind": { + SchemaProps: spec.SchemaProps{ + Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + Type: []string{"string"}, + Format: "", + }, + }, + "apiVersion": { + SchemaProps: spec.SchemaProps{ + Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", + Type: []string{"string"}, + Format: "", + }, + }, + "metadata": { + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"), + }, + }, + "items": { + 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/pkg/apis/iam/v0alpha1.ServiceAccountToken"), + }, + }, + }, + }, + }, + }, + }, + }, + Dependencies: []string{ + "github.com/grafana/grafana/pkg/apis/iam/v0alpha1.ServiceAccountToken", "k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"}, + } +} + func schema_pkg_apis_iam_v0alpha1_Team(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ diff --git a/pkg/registry/apis/iam/common/common.go b/pkg/registry/apis/iam/common/common.go index b13bb3043b3..1e3533f3b73 100644 --- a/pkg/registry/apis/iam/common/common.go +++ b/pkg/registry/apis/iam/common/common.go @@ -3,7 +3,7 @@ package common import ( "strconv" - identityv0 "github.com/grafana/grafana/pkg/apis/iam/v0alpha1" + iamv0 "github.com/grafana/grafana/pkg/apis/iam/v0alpha1" "github.com/grafana/grafana/pkg/services/team" ) @@ -16,10 +16,10 @@ func OptionalFormatInt(num int64) string { return "" } -func MapTeamPermission(p team.PermissionType) identityv0.TeamPermission { +func MapTeamPermission(p team.PermissionType) iamv0.TeamPermission { if p == team.PermissionTypeAdmin { - return identityv0.TeamPermissionAdmin + return iamv0.TeamPermissionAdmin } else { - return identityv0.TeamPermissionMember + return iamv0.TeamPermissionMember } } diff --git a/pkg/registry/apis/iam/legacy/service_account.go b/pkg/registry/apis/iam/legacy/service_account.go new file mode 100644 index 00000000000..03610e2a3f2 --- /dev/null +++ b/pkg/registry/apis/iam/legacy/service_account.go @@ -0,0 +1,205 @@ +package legacy + +import ( + "context" + "fmt" + "time" + + "github.com/grafana/authlib/claims" + "github.com/grafana/grafana/pkg/registry/apis/iam/common" + "github.com/grafana/grafana/pkg/storage/legacysql" + "github.com/grafana/grafana/pkg/storage/unified/sql/sqltemplate" +) + +type ListServiceAccountsQuery struct { + UID string + OrgID int64 + Pagination common.Pagination +} + +type ListServiceAccountResult struct { + Items []ServiceAccount + Continue int64 + RV int64 +} + +type ServiceAccount struct { + ID int64 + UID string + Name string + Disabled bool + Created time.Time + Updated time.Time +} + +var sqlQueryServiceAccountsTemplate = mustTemplate("service_accounts_query.sql") + +func newListServiceAccounts(sql *legacysql.LegacyDatabaseHelper, q *ListServiceAccountsQuery) listServiceAccountsQuery { + return listServiceAccountsQuery{ + SQLTemplate: sqltemplate.New(sql.DialectForDriver()), + UserTable: sql.Table("user"), + OrgUserTable: sql.Table("org_user"), + Query: q, + } +} + +type listServiceAccountsQuery struct { + sqltemplate.SQLTemplate + Query *ListServiceAccountsQuery + UserTable string + OrgUserTable string +} + +func (r listServiceAccountsQuery) Validate() error { + return nil // TODO +} + +func (s *legacySQLStore) ListServiceAccounts(ctx context.Context, ns claims.NamespaceInfo, query ListServiceAccountsQuery) (*ListServiceAccountResult, error) { + // for continue + query.Pagination.Limit += 1 + query.OrgID = ns.OrgID + if ns.OrgID == 0 { + return nil, fmt.Errorf("expected non zero orgID") + } + + sql, err := s.sql(ctx) + if err != nil { + return nil, err + } + + req := newListServiceAccounts(sql, &query) + q, err := sqltemplate.Execute(sqlQueryServiceAccountsTemplate, req) + if err != nil { + return nil, fmt.Errorf("execute template %q: %w", sqlQueryServiceAccountsTemplate.Name(), err) + } + + rows, err := sql.DB.GetSqlxSession().Query(ctx, q, req.GetArgs()...) + defer func() { + if rows != nil { + _ = rows.Close() + } + }() + + res := &ListServiceAccountResult{} + if err != nil { + return nil, err + } + + var lastID int64 + for rows.Next() { + var s ServiceAccount + err := rows.Scan(&s.ID, &s.UID, &s.Name, &s.Disabled, &s.Created, &s.Updated) + if err != nil { + return res, err + } + + lastID = s.ID + res.Items = append(res.Items, s) + if len(res.Items) > int(query.Pagination.Limit)-1 { + res.Items = res.Items[0 : len(res.Items)-1] + res.Continue = lastID + break + } + } + + if query.UID == "" { + // FIXME: we need to filer for service accounts here.. + res.RV, err = sql.GetResourceVersion(ctx, "user", "updated") + } + + return res, err +} + +type ListServiceAccountTokenQuery struct { + // UID is the service account uid. + UID string + OrgID int64 + Pagination common.Pagination +} + +type ListServiceAccountTokenResult struct { + Items []ServiceAccountToken + Continue int64 + RV int64 +} + +type ServiceAccountToken struct { + ID int64 + Name string + Revoked bool + Expires *int64 + LastUsed *time.Time + Created time.Time + Updated time.Time +} + +var sqlQueryServiceAccountTokensTemplate = mustTemplate("service_account_tokens_query.sql") + +func newListServiceAccountTokens(sql *legacysql.LegacyDatabaseHelper, q *ListServiceAccountTokenQuery) listServiceAccountTokensQuery { + return listServiceAccountTokensQuery{ + SQLTemplate: sqltemplate.New(sql.DialectForDriver()), + UserTable: sql.Table("user"), + OrgUserTable: sql.Table("org_user"), + TokenTable: sql.Table("api_key"), + Query: q, + } +} + +type listServiceAccountTokensQuery struct { + sqltemplate.SQLTemplate + Query *ListServiceAccountTokenQuery + UserTable string + TokenTable string + OrgUserTable string +} + +func (s *legacySQLStore) ListServiceAccountTokens(ctx context.Context, ns claims.NamespaceInfo, query ListServiceAccountTokenQuery) (*ListServiceAccountTokenResult, error) { + // for continue + query.Pagination.Limit += 1 + query.OrgID = ns.OrgID + if ns.OrgID == 0 { + return nil, fmt.Errorf("expected non zero orgID") + } + + sql, err := s.sql(ctx) + if err != nil { + return nil, err + } + + req := newListServiceAccountTokens(sql, &query) + q, err := sqltemplate.Execute(sqlQueryServiceAccountTokensTemplate, req) + if err != nil { + return nil, fmt.Errorf("execute template %q: %w", sqlQueryServiceAccountTokensTemplate.Name(), err) + } + + rows, err := sql.DB.GetSqlxSession().Query(ctx, q, req.GetArgs()...) + defer func() { + if rows != nil { + _ = rows.Close() + } + }() + + res := &ListServiceAccountTokenResult{} + if err != nil { + return nil, err + } + + var lastID int64 + for rows.Next() { + var t ServiceAccountToken + err := rows.Scan(&t.ID, &t.Name, &t.Revoked, &t.LastUsed, &t.Expires, &t.Created, &t.Updated) + if err != nil { + return res, err + } + + lastID = t.ID + res.Items = append(res.Items, t) + if len(res.Items) > int(query.Pagination.Limit)-1 { + res.Items = res.Items[0 : len(res.Items)-1] + res.Continue = lastID + break + } + } + + return res, err +} diff --git a/pkg/registry/apis/iam/legacy/service_account_tokens_query.sql b/pkg/registry/apis/iam/legacy/service_account_tokens_query.sql new file mode 100644 index 00000000000..021d17d9d5e --- /dev/null +++ b/pkg/registry/apis/iam/legacy/service_account_tokens_query.sql @@ -0,0 +1,19 @@ +SELECT + t.id, + t.name, + t.is_revoked, + t.last_used_at, + t.expires, + t.created, + t.updated + FROM {{ .Ident .TokenTable }} as t + INNER JOIN {{ .Ident .UserTable }} as u ON t.service_account_id = u.id + INNER JOIN {{ .Ident .OrgUserTable }} as o ON u.id = o.user_id +WHERE o.org_id = {{ .Arg .Query.OrgID }} + AND u.is_service_account + AND u.uid = {{ .Arg .Query.UID }} +{{ if .Query.Pagination.Continue }} + AND t.id >= {{ .Arg .Query.Pagination.Continue }} +{{ end }} + ORDER BY t.id asc + LIMIT {{ .Arg .Query.Pagination.Limit }} diff --git a/pkg/registry/apis/iam/legacy/service_accounts_query.sql b/pkg/registry/apis/iam/legacy/service_accounts_query.sql new file mode 100644 index 00000000000..ca700c1c064 --- /dev/null +++ b/pkg/registry/apis/iam/legacy/service_accounts_query.sql @@ -0,0 +1,18 @@ +SELECT + u.id, + u.uid, + u.name, + u.is_disabled, + u.created, + u.updated + FROM {{ .Ident .UserTable }} as u JOIN {{ .Ident .OrgUserTable }} as o ON u.id = o.user_id + WHERE o.org_id = {{ .Arg .Query.OrgID }} + AND u.is_service_account +{{ if .Query.UID }} + AND u.uid = {{ .Arg .Query.UID }} +{{ end }} +{{ if .Query.Pagination.Continue }} + AND u.id >= {{ .Arg .Query.Pagination.Continue }} +{{ end }} + ORDER BY u.id asc + LIMIT {{ .Arg .Query.Pagination.Limit }} diff --git a/pkg/registry/apis/iam/legacy/sql.go b/pkg/registry/apis/iam/legacy/sql.go index 1957f0636c0..554bd114412 100644 --- a/pkg/registry/apis/iam/legacy/sql.go +++ b/pkg/registry/apis/iam/legacy/sql.go @@ -17,6 +17,9 @@ type LegacyIdentityStore interface { ListUsers(ctx context.Context, ns claims.NamespaceInfo, query ListUserQuery) (*ListUserResult, error) ListUserTeams(ctx context.Context, ns claims.NamespaceInfo, query ListUserTeamsQuery) (*ListUserTeamsResult, error) + ListServiceAccounts(ctx context.Context, ns claims.NamespaceInfo, query ListServiceAccountsQuery) (*ListServiceAccountResult, error) + ListServiceAccountTokens(ctx context.Context, ns claims.NamespaceInfo, query ListServiceAccountTokenQuery) (*ListServiceAccountTokenResult, error) + ListTeams(ctx context.Context, ns claims.NamespaceInfo, query ListTeamQuery) (*ListTeamResult, error) ListTeamBindings(ctx context.Context, ns claims.NamespaceInfo, query ListTeamBindingsQuery) (*ListTeamBindingsResult, error) ListTeamMembers(ctx context.Context, ns claims.NamespaceInfo, query ListTeamMembersQuery) (*ListTeamMembersResult, error) diff --git a/pkg/registry/apis/iam/legacy/testdata/mysql--users_query-users_page_1.sql b/pkg/registry/apis/iam/legacy/testdata/mysql--users_query-users_page_1.sql index d35831279af..4ac1c74d87f 100755 --- a/pkg/registry/apis/iam/legacy/testdata/mysql--users_query-users_page_1.sql +++ b/pkg/registry/apis/iam/legacy/testdata/mysql--users_query-users_page_1.sql @@ -2,6 +2,6 @@ SELECT o.org_id, u.id, u.uid, u.login, u.email, u.name, u.created, u.updated, u.is_service_account, u.is_disabled, u.is_admin FROM `grafana`.`user` as u JOIN `grafana`.`org_user` as o ON u.id = o.user_id WHERE o.org_id = 0 - AND u.is_service_account = FALSE + AND NOT u.is_service_account ORDER BY u.id asc LIMIT 5 diff --git a/pkg/registry/apis/iam/legacy/testdata/mysql--users_query-users_page_2.sql b/pkg/registry/apis/iam/legacy/testdata/mysql--users_query-users_page_2.sql index c32659b6c3d..5bcc865f1d9 100755 --- a/pkg/registry/apis/iam/legacy/testdata/mysql--users_query-users_page_2.sql +++ b/pkg/registry/apis/iam/legacy/testdata/mysql--users_query-users_page_2.sql @@ -2,7 +2,7 @@ SELECT o.org_id, u.id, u.uid, u.login, u.email, u.name, u.created, u.updated, u.is_service_account, u.is_disabled, u.is_admin FROM `grafana`.`user` as u JOIN `grafana`.`org_user` as o ON u.id = o.user_id WHERE o.org_id = 0 - AND u.is_service_account = FALSE + AND NOT u.is_service_account AND u.id >= 2 ORDER BY u.id asc LIMIT 1 diff --git a/pkg/registry/apis/iam/legacy/testdata/mysql--users_query-users_uid.sql b/pkg/registry/apis/iam/legacy/testdata/mysql--users_query-users_uid.sql index 5944036d745..2c36c9f9fbb 100755 --- a/pkg/registry/apis/iam/legacy/testdata/mysql--users_query-users_uid.sql +++ b/pkg/registry/apis/iam/legacy/testdata/mysql--users_query-users_uid.sql @@ -2,7 +2,7 @@ SELECT o.org_id, u.id, u.uid, u.login, u.email, u.name, u.created, u.updated, u.is_service_account, u.is_disabled, u.is_admin FROM `grafana`.`user` as u JOIN `grafana`.`org_user` as o ON u.id = o.user_id WHERE o.org_id = 0 - AND u.is_service_account = FALSE + AND NOT u.is_service_account AND u.uid = 'abc' ORDER BY u.id asc LIMIT 1 diff --git a/pkg/registry/apis/iam/legacy/testdata/postgres--users_query-users_page_1.sql b/pkg/registry/apis/iam/legacy/testdata/postgres--users_query-users_page_1.sql index 5d4f1b771fc..7de4914aa8d 100755 --- a/pkg/registry/apis/iam/legacy/testdata/postgres--users_query-users_page_1.sql +++ b/pkg/registry/apis/iam/legacy/testdata/postgres--users_query-users_page_1.sql @@ -2,6 +2,6 @@ SELECT o.org_id, u.id, u.uid, u.login, u.email, u.name, u.created, u.updated, u.is_service_account, u.is_disabled, u.is_admin FROM "grafana"."user" as u JOIN "grafana"."org_user" as o ON u.id = o.user_id WHERE o.org_id = 0 - AND u.is_service_account = FALSE + AND NOT u.is_service_account ORDER BY u.id asc LIMIT 5 diff --git a/pkg/registry/apis/iam/legacy/testdata/postgres--users_query-users_page_2.sql b/pkg/registry/apis/iam/legacy/testdata/postgres--users_query-users_page_2.sql index ed97b2c25d2..e938a14392b 100755 --- a/pkg/registry/apis/iam/legacy/testdata/postgres--users_query-users_page_2.sql +++ b/pkg/registry/apis/iam/legacy/testdata/postgres--users_query-users_page_2.sql @@ -2,7 +2,7 @@ SELECT o.org_id, u.id, u.uid, u.login, u.email, u.name, u.created, u.updated, u.is_service_account, u.is_disabled, u.is_admin FROM "grafana"."user" as u JOIN "grafana"."org_user" as o ON u.id = o.user_id WHERE o.org_id = 0 - AND u.is_service_account = FALSE + AND NOT u.is_service_account AND u.id >= 2 ORDER BY u.id asc LIMIT 1 diff --git a/pkg/registry/apis/iam/legacy/testdata/postgres--users_query-users_uid.sql b/pkg/registry/apis/iam/legacy/testdata/postgres--users_query-users_uid.sql index bab837475af..5c8f1f2ec66 100755 --- a/pkg/registry/apis/iam/legacy/testdata/postgres--users_query-users_uid.sql +++ b/pkg/registry/apis/iam/legacy/testdata/postgres--users_query-users_uid.sql @@ -2,7 +2,7 @@ SELECT o.org_id, u.id, u.uid, u.login, u.email, u.name, u.created, u.updated, u.is_service_account, u.is_disabled, u.is_admin FROM "grafana"."user" as u JOIN "grafana"."org_user" as o ON u.id = o.user_id WHERE o.org_id = 0 - AND u.is_service_account = FALSE + AND NOT u.is_service_account AND u.uid = 'abc' ORDER BY u.id asc LIMIT 1 diff --git a/pkg/registry/apis/iam/legacy/testdata/sqlite--users_query-users_page_1.sql b/pkg/registry/apis/iam/legacy/testdata/sqlite--users_query-users_page_1.sql index 5d4f1b771fc..7de4914aa8d 100755 --- a/pkg/registry/apis/iam/legacy/testdata/sqlite--users_query-users_page_1.sql +++ b/pkg/registry/apis/iam/legacy/testdata/sqlite--users_query-users_page_1.sql @@ -2,6 +2,6 @@ SELECT o.org_id, u.id, u.uid, u.login, u.email, u.name, u.created, u.updated, u.is_service_account, u.is_disabled, u.is_admin FROM "grafana"."user" as u JOIN "grafana"."org_user" as o ON u.id = o.user_id WHERE o.org_id = 0 - AND u.is_service_account = FALSE + AND NOT u.is_service_account ORDER BY u.id asc LIMIT 5 diff --git a/pkg/registry/apis/iam/legacy/testdata/sqlite--users_query-users_page_2.sql b/pkg/registry/apis/iam/legacy/testdata/sqlite--users_query-users_page_2.sql index ed97b2c25d2..e938a14392b 100755 --- a/pkg/registry/apis/iam/legacy/testdata/sqlite--users_query-users_page_2.sql +++ b/pkg/registry/apis/iam/legacy/testdata/sqlite--users_query-users_page_2.sql @@ -2,7 +2,7 @@ SELECT o.org_id, u.id, u.uid, u.login, u.email, u.name, u.created, u.updated, u.is_service_account, u.is_disabled, u.is_admin FROM "grafana"."user" as u JOIN "grafana"."org_user" as o ON u.id = o.user_id WHERE o.org_id = 0 - AND u.is_service_account = FALSE + AND NOT u.is_service_account AND u.id >= 2 ORDER BY u.id asc LIMIT 1 diff --git a/pkg/registry/apis/iam/legacy/testdata/sqlite--users_query-users_uid.sql b/pkg/registry/apis/iam/legacy/testdata/sqlite--users_query-users_uid.sql index bab837475af..5c8f1f2ec66 100755 --- a/pkg/registry/apis/iam/legacy/testdata/sqlite--users_query-users_uid.sql +++ b/pkg/registry/apis/iam/legacy/testdata/sqlite--users_query-users_uid.sql @@ -2,7 +2,7 @@ SELECT o.org_id, u.id, u.uid, u.login, u.email, u.name, u.created, u.updated, u.is_service_account, u.is_disabled, u.is_admin FROM "grafana"."user" as u JOIN "grafana"."org_user" as o ON u.id = o.user_id WHERE o.org_id = 0 - AND u.is_service_account = FALSE + AND NOT u.is_service_account AND u.uid = 'abc' ORDER BY u.id asc LIMIT 1 diff --git a/pkg/registry/apis/iam/legacy/user.go b/pkg/registry/apis/iam/legacy/user.go index 7107aae029e..f1f51c43481 100644 --- a/pkg/registry/apis/iam/legacy/user.go +++ b/pkg/registry/apis/iam/legacy/user.go @@ -14,9 +14,8 @@ import ( ) type ListUserQuery struct { - OrgID int64 - UID string - IsServiceAccount bool + OrgID int64 + UID string Pagination common.Pagination } diff --git a/pkg/registry/apis/iam/legacy/users_query.sql b/pkg/registry/apis/iam/legacy/users_query.sql index c7863b0fba5..59d46d39400 100644 --- a/pkg/registry/apis/iam/legacy/users_query.sql +++ b/pkg/registry/apis/iam/legacy/users_query.sql @@ -2,7 +2,7 @@ SELECT o.org_id, u.id, u.uid, u.login, u.email, u.name, u.created, u.updated, u.is_service_account, u.is_disabled, u.is_admin FROM {{ .Ident .UserTable }} as u JOIN {{ .Ident .OrgUserTable }} as o ON u.id = o.user_id WHERE o.org_id = {{ .Arg .Query.OrgID }} - AND u.is_service_account = {{ .Arg .Query.IsServiceAccount }} + AND NOT u.is_service_account {{ if .Query.UID }} AND u.uid = {{ .Arg .Query.UID }} {{ end }} diff --git a/pkg/registry/apis/iam/register.go b/pkg/registry/apis/iam/register.go index 87975306edc..c1536f08aec 100644 --- a/pkg/registry/apis/iam/register.go +++ b/pkg/registry/apis/iam/register.go @@ -4,7 +4,7 @@ import ( "context" "github.com/grafana/grafana/pkg/apimachinery/identity" - identityv0 "github.com/grafana/grafana/pkg/apis/iam/v0alpha1" + iamv0 "github.com/grafana/grafana/pkg/apis/iam/v0alpha1" grafanarest "github.com/grafana/grafana/pkg/apiserver/rest" "github.com/grafana/grafana/pkg/infra/db" "github.com/grafana/grafana/pkg/registry/apis/iam/legacy" @@ -55,19 +55,19 @@ func RegisterAPIService( } func (b *IdentityAccessManagementAPIBuilder) GetGroupVersion() schema.GroupVersion { - return identityv0.SchemeGroupVersion + return iamv0.SchemeGroupVersion } func (b *IdentityAccessManagementAPIBuilder) InstallSchema(scheme *runtime.Scheme) error { - identityv0.AddKnownTypes(scheme, identityv0.VERSION) + iamv0.AddKnownTypes(scheme, iamv0.VERSION) // Link this version to the internal representation. // This is used for server-side-apply (PATCH), and avoids the error: // "no kind is registered for the type" - identityv0.AddKnownTypes(scheme, runtime.APIVersionInternal) + iamv0.AddKnownTypes(scheme, runtime.APIVersionInternal) - metav1.AddToGroupVersion(scheme, identityv0.SchemeGroupVersion) - return scheme.SetVersionPriority(identityv0.SchemeGroupVersion) + metav1.AddToGroupVersion(scheme, iamv0.SchemeGroupVersion) + return scheme.SetVersionPriority(iamv0.SchemeGroupVersion) } func (b *IdentityAccessManagementAPIBuilder) GetAPIGroupInfo( @@ -76,37 +76,38 @@ func (b *IdentityAccessManagementAPIBuilder) GetAPIGroupInfo( optsGetter generic.RESTOptionsGetter, dualWriteBuilder grafanarest.DualWriteBuilder, ) (*genericapiserver.APIGroupInfo, error) { - apiGroupInfo := genericapiserver.NewDefaultAPIGroupInfo(identityv0.GROUP, scheme, metav1.ParameterCodec, codecs) + apiGroupInfo := genericapiserver.NewDefaultAPIGroupInfo(iamv0.GROUP, scheme, metav1.ParameterCodec, codecs) storage := map[string]rest.Storage{} - teamResource := identityv0.TeamResourceInfo + teamResource := iamv0.TeamResourceInfo storage[teamResource.StoragePath()] = team.NewLegacyStore(b.Store) storage[teamResource.StoragePath("members")] = team.NewLegacyTeamMemberREST(b.Store) - teamBindingResource := identityv0.TeamBindingResourceInfo + teamBindingResource := iamv0.TeamBindingResourceInfo storage[teamBindingResource.StoragePath()] = team.NewLegacyBindingStore(b.Store) - userResource := identityv0.UserResourceInfo + userResource := iamv0.UserResourceInfo storage[userResource.StoragePath()] = user.NewLegacyStore(b.Store) storage[userResource.StoragePath("teams")] = user.NewLegacyTeamMemberREST(b.Store) - serviceaccountResource := identityv0.ServiceAccountResourceInfo + serviceaccountResource := iamv0.ServiceAccountResourceInfo storage[serviceaccountResource.StoragePath()] = serviceaccount.NewLegacyStore(b.Store) + storage[serviceaccountResource.StoragePath("tokens")] = serviceaccount.NewLegacyTokenREST(b.Store) if b.SSOService != nil { - ssoResource := identityv0.SSOSettingResourceInfo + ssoResource := iamv0.SSOSettingResourceInfo storage[ssoResource.StoragePath()] = sso.NewLegacyStore(b.SSOService) } // The display endpoint -- NOTE, this uses a rewrite hack to allow requests without a name parameter storage["display"] = user.NewLegacyDisplayREST(b.Store) - apiGroupInfo.VersionedResourcesStorageMap[identityv0.VERSION] = storage + apiGroupInfo.VersionedResourcesStorageMap[iamv0.VERSION] = storage return &apiGroupInfo, nil } func (b *IdentityAccessManagementAPIBuilder) GetOpenAPIDefinitions() common.GetOpenAPIDefinitions { - return identityv0.GetOpenAPIDefinitions + return iamv0.GetOpenAPIDefinitions } func (b *IdentityAccessManagementAPIBuilder) GetAPIRoutes() *builder.APIRoutes { diff --git a/pkg/registry/apis/iam/serviceaccount/rest_token.go b/pkg/registry/apis/iam/serviceaccount/rest_token.go new file mode 100644 index 00000000000..b66f790f381 --- /dev/null +++ b/pkg/registry/apis/iam/serviceaccount/rest_token.go @@ -0,0 +1,115 @@ +package serviceaccount + +import ( + "context" + "net/http" + "time" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apiserver/pkg/registry/rest" + + iamv0 "github.com/grafana/grafana/pkg/apis/iam/v0alpha1" + "github.com/grafana/grafana/pkg/registry/apis/iam/common" + "github.com/grafana/grafana/pkg/registry/apis/iam/legacy" + "github.com/grafana/grafana/pkg/services/apiserver/endpoints/request" +) + +var ( + _ rest.Storage = (*LegacyTokenRest)(nil) + _ rest.Scoper = (*LegacyTokenRest)(nil) + _ rest.StorageMetadata = (*LegacyTokenRest)(nil) + _ rest.Connecter = (*LegacyTokenRest)(nil) +) + +func NewLegacyTokenREST(store legacy.LegacyIdentityStore) *LegacyTokenRest { + return &LegacyTokenRest{store} +} + +type LegacyTokenRest struct { + store legacy.LegacyIdentityStore +} + +// New implements rest.Storage. +func (s *LegacyTokenRest) New() runtime.Object { + return &iamv0.UserTeamList{} +} + +// Destroy implements rest.Storage. +func (s *LegacyTokenRest) Destroy() {} + +// NamespaceScoped implements rest.Scoper. +func (s *LegacyTokenRest) NamespaceScoped() bool { + return true +} + +// ProducesMIMETypes implements rest.StorageMetadata. +func (s *LegacyTokenRest) ProducesMIMETypes(verb string) []string { + return []string{"application/json"} +} + +// ProducesObject implements rest.StorageMetadata. +func (s *LegacyTokenRest) ProducesObject(verb string) interface{} { + return s.New() +} + +// Connect implements rest.Connecter. +func (s *LegacyTokenRest) Connect(ctx context.Context, name string, options runtime.Object, responder rest.Responder) (http.Handler, error) { + ns, err := request.NamespaceInfoFrom(ctx, true) + if err != nil { + return nil, err + } + + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + res, err := s.store.ListServiceAccountTokens(ctx, ns, legacy.ListServiceAccountTokenQuery{ + UID: name, + Pagination: common.PaginationFromListQuery(r.URL.Query()), + }) + if err != nil { + responder.Error(err) + return + } + + list := &iamv0.ServiceAccountTokenList{Items: make([]iamv0.ServiceAccountToken, 0, len(res.Items))} + + for _, t := range res.Items { + list.Items = append(list.Items, mapToToken(t)) + } + + list.ListMeta.Continue = common.OptionalFormatInt(res.Continue) + + responder.Object(http.StatusOK, list) + }), nil +} + +// NewConnectOptions implements rest.Connecter. +func (s *LegacyTokenRest) NewConnectOptions() (runtime.Object, bool, string) { + return nil, false, "" +} + +// ConnectMethods implements rest.Connecter. +func (s *LegacyTokenRest) ConnectMethods() []string { + return []string{http.MethodGet} +} + +func mapToToken(t legacy.ServiceAccountToken) iamv0.ServiceAccountToken { + var expires, lastUsed *metav1.Time + + if t.Expires != nil { + ts := metav1.NewTime(time.Unix(*t.Expires, 0)) + expires = &ts + } + + if t.LastUsed != nil { + ts := metav1.NewTime(*t.LastUsed) + lastUsed = &ts + } + + return iamv0.ServiceAccountToken{ + Name: t.Name, + Expires: expires, + LastUsed: lastUsed, + Revoked: t.Revoked, + Created: metav1.NewTime(t.Created), + } +} diff --git a/pkg/registry/apis/iam/serviceaccount/store.go b/pkg/registry/apis/iam/serviceaccount/store.go index eb5b9521964..618f2089793 100644 --- a/pkg/registry/apis/iam/serviceaccount/store.go +++ b/pkg/registry/apis/iam/serviceaccount/store.go @@ -11,11 +11,10 @@ import ( "k8s.io/apiserver/pkg/registry/rest" "github.com/grafana/grafana/pkg/apimachinery/utils" - identityv0 "github.com/grafana/grafana/pkg/apis/iam/v0alpha1" + iamv0 "github.com/grafana/grafana/pkg/apis/iam/v0alpha1" "github.com/grafana/grafana/pkg/registry/apis/iam/common" "github.com/grafana/grafana/pkg/registry/apis/iam/legacy" "github.com/grafana/grafana/pkg/services/apiserver/endpoints/request" - "github.com/grafana/grafana/pkg/services/user" ) var ( @@ -26,7 +25,7 @@ var ( _ rest.Storage = (*LegacyStore)(nil) ) -var resource = identityv0.ServiceAccountResourceInfo +var resource = iamv0.ServiceAccountResourceInfo func NewLegacyStore(store legacy.LegacyIdentityStore) *LegacyStore { return &LegacyStore{store} @@ -63,20 +62,18 @@ func (s *LegacyStore) List(ctx context.Context, options *internalversion.ListOpt if err != nil { return nil, err } - query := legacy.ListUserQuery{ - OrgID: ns.OrgID, - IsServiceAccount: true, - Pagination: common.PaginationFromListOptions(options), - } - found, err := s.store.ListUsers(ctx, ns, query) + found, err := s.store.ListServiceAccounts(ctx, ns, legacy.ListServiceAccountsQuery{ + OrgID: ns.OrgID, + Pagination: common.PaginationFromListOptions(options), + }) if err != nil { return nil, err } - list := &identityv0.ServiceAccountList{} - for _, item := range found.Users { - list.Items = append(list.Items, *toSAItem(&item, ns.Value)) + list := &iamv0.ServiceAccountList{} + for _, item := range found.Items { + list.Items = append(list.Items, toSAItem(item, ns.Value)) } list.ListMeta.Continue = common.OptionalFormatInt(found.Continue) @@ -85,26 +82,24 @@ func (s *LegacyStore) List(ctx context.Context, options *internalversion.ListOpt return list, err } -func toSAItem(u *user.User, ns string) *identityv0.ServiceAccount { - item := &identityv0.ServiceAccount{ +func toSAItem(sa legacy.ServiceAccount, ns string) iamv0.ServiceAccount { + item := iamv0.ServiceAccount{ ObjectMeta: metav1.ObjectMeta{ - Name: u.UID, + Name: sa.UID, Namespace: ns, - ResourceVersion: fmt.Sprintf("%d", u.Updated.UnixMilli()), - CreationTimestamp: metav1.NewTime(u.Created), + ResourceVersion: fmt.Sprintf("%d", sa.Updated.UnixMilli()), + CreationTimestamp: metav1.NewTime(sa.Created), }, - Spec: identityv0.ServiceAccountSpec{ - Name: u.Name, - Email: u.Email, - EmailVerified: u.EmailVerified, - Disabled: u.IsDisabled, + Spec: iamv0.ServiceAccountSpec{ + Title: sa.Name, + Disabled: sa.Disabled, }, } - obj, _ := utils.MetaAccessor(item) - obj.SetUpdatedTimestamp(&u.Updated) + obj, _ := utils.MetaAccessor(&item) + obj.SetUpdatedTimestamp(&sa.Updated) obj.SetOriginInfo(&utils.ResourceOriginInfo{ Name: "SQL", - Path: strconv.FormatInt(u.ID, 10), + Path: strconv.FormatInt(sa.ID, 10), }) return item } @@ -114,18 +109,19 @@ func (s *LegacyStore) Get(ctx context.Context, name string, options *metav1.GetO if err != nil { return nil, err } - query := legacy.ListUserQuery{ - OrgID: ns.OrgID, - IsServiceAccount: true, - Pagination: common.Pagination{Limit: 1}, - } - found, err := s.store.ListUsers(ctx, ns, query) + found, err := s.store.ListServiceAccounts(ctx, ns, legacy.ListServiceAccountsQuery{ + UID: name, + OrgID: ns.OrgID, + Pagination: common.Pagination{Limit: 1}, + }) if found == nil || err != nil { return nil, resource.NewNotFound(name) } - if len(found.Users) < 1 { + if len(found.Items) < 1 { return nil, resource.NewNotFound(name) } - return toSAItem(&found.Users[0], ns.Value), nil + + res := toSAItem(found.Items[0], ns.Value) + return &res, nil } diff --git a/pkg/registry/apis/iam/sso/store.go b/pkg/registry/apis/iam/sso/store.go index 699be8b9dfe..c9965adc152 100644 --- a/pkg/registry/apis/iam/sso/store.go +++ b/pkg/registry/apis/iam/sso/store.go @@ -14,7 +14,7 @@ import ( "k8s.io/apimachinery/pkg/types" "k8s.io/apiserver/pkg/registry/rest" - identityv0 "github.com/grafana/grafana/pkg/apis/iam/v0alpha1" + iamv0 "github.com/grafana/grafana/pkg/apis/iam/v0alpha1" "github.com/grafana/grafana/pkg/services/apiserver/endpoints/request" "github.com/grafana/grafana/pkg/services/ssosettings" ssomodels "github.com/grafana/grafana/pkg/services/ssosettings/models" @@ -30,7 +30,7 @@ var ( _ rest.GracefulDeleter = (*LegacyStore)(nil) ) -var resource = identityv0.SSOSettingResourceInfo +var resource = iamv0.SSOSettingResourceInfo func NewLegacyStore(service ssosettings.Service) *LegacyStore { return &LegacyStore{service} @@ -78,7 +78,7 @@ func (s *LegacyStore) List(ctx context.Context, options *internalversion.ListOpt return nil, fmt.Errorf("failed to list sso settings: %w", err) } - list := &identityv0.SSOSettingList{} + list := &iamv0.SSOSettingList{} for _, s := range settings { list.Items = append(list.Items, mapToObject(ns.Value, s)) } @@ -128,7 +128,7 @@ func (s *LegacyStore) Update( return old, created, err } - setting, ok := obj.(*identityv0.SSOSetting) + setting, ok := obj.(*iamv0.SSOSetting) if !ok { return old, created, errors.New("expected ssosetting after update") } @@ -153,7 +153,7 @@ func (s *LegacyStore) Delete( return obj, false, err } - old, ok := obj.(*identityv0.SSOSetting) + old, ok := obj.(*iamv0.SSOSetting) if !ok { return obj, false, errors.New("expected ssosetting") } @@ -182,10 +182,10 @@ func (s *LegacyStore) Delete( return afterDelete, false, err } -func mapToObject(ns string, s *ssomodels.SSOSettings) identityv0.SSOSetting { - source := identityv0.SourceDB +func mapToObject(ns string, s *ssomodels.SSOSettings) iamv0.SSOSetting { + source := iamv0.SourceDB if s.Source == ssomodels.System { - source = identityv0.SourceSystem + source = iamv0.SourceSystem } version := "0" @@ -193,7 +193,7 @@ func mapToObject(ns string, s *ssomodels.SSOSettings) identityv0.SSOSetting { version = fmt.Sprintf("%d", s.Updated.UnixMilli()) } - object := identityv0.SSOSetting{ + object := iamv0.SSOSetting{ ObjectMeta: metav1.ObjectMeta{ Name: s.Provider, Namespace: ns, @@ -201,7 +201,7 @@ func mapToObject(ns string, s *ssomodels.SSOSettings) identityv0.SSOSetting { ResourceVersion: version, CreationTimestamp: metav1.NewTime(s.Updated), }, - Spec: identityv0.SSOSettingSpec{ + Spec: iamv0.SSOSettingSpec{ Source: source, Settings: commonv1.Unstructured{Object: s.Settings}, }, @@ -210,7 +210,7 @@ func mapToObject(ns string, s *ssomodels.SSOSettings) identityv0.SSOSetting { return object } -func mapToModel(obj *identityv0.SSOSetting) *ssomodels.SSOSettings { +func mapToModel(obj *iamv0.SSOSetting) *ssomodels.SSOSettings { return &ssomodels.SSOSettings{ Provider: obj.Name, Settings: obj.Spec.Settings.Object, diff --git a/pkg/registry/apis/iam/team/rest_members.go b/pkg/registry/apis/iam/team/rest_members.go index 13efb6783c1..1bab3a9f2a5 100644 --- a/pkg/registry/apis/iam/team/rest_members.go +++ b/pkg/registry/apis/iam/team/rest_members.go @@ -9,7 +9,7 @@ import ( "github.com/grafana/authlib/claims" "github.com/grafana/grafana/pkg/api/dtos" - identityv0 "github.com/grafana/grafana/pkg/apis/iam/v0alpha1" + iamv0 "github.com/grafana/grafana/pkg/apis/iam/v0alpha1" "github.com/grafana/grafana/pkg/registry/apis/iam/common" "github.com/grafana/grafana/pkg/registry/apis/iam/legacy" "github.com/grafana/grafana/pkg/services/apiserver/endpoints/request" @@ -33,7 +33,7 @@ type LegacyTeamMemberREST struct { // New implements rest.Storage. func (s *LegacyTeamMemberREST) New() runtime.Object { - return &identityv0.TeamMemberList{} + return &iamv0.TeamMemberList{} } // Destroy implements rest.Storage. @@ -71,7 +71,7 @@ func (s *LegacyTeamMemberREST) Connect(ctx context.Context, name string, options return } - list := &identityv0.TeamMemberList{Items: make([]identityv0.TeamMember, 0, len(res.Members))} + list := &iamv0.TeamMemberList{Items: make([]iamv0.TeamMember, 0, len(res.Members))} for _, m := range res.Members { list.Items = append(list.Items, mapToTeamMember(m)) @@ -95,9 +95,9 @@ func (s *LegacyTeamMemberREST) ConnectMethods() []string { var cfg = &setting.Cfg{} -func mapToTeamMember(m legacy.TeamMember) identityv0.TeamMember { - return identityv0.TeamMember{ - IdentityDisplay: identityv0.IdentityDisplay{ +func mapToTeamMember(m legacy.TeamMember) iamv0.TeamMember { + return iamv0.TeamMember{ + IdentityDisplay: iamv0.IdentityDisplay{ IdentityType: claims.TypeUser, UID: m.UserUID, Display: m.Name, diff --git a/pkg/registry/apis/iam/team/store.go b/pkg/registry/apis/iam/team/store.go index 5f70e46ac34..ae6f78291fd 100644 --- a/pkg/registry/apis/iam/team/store.go +++ b/pkg/registry/apis/iam/team/store.go @@ -11,7 +11,7 @@ import ( "github.com/grafana/authlib/claims" "github.com/grafana/grafana/pkg/apimachinery/utils" - identityv0 "github.com/grafana/grafana/pkg/apis/iam/v0alpha1" + iamv0 "github.com/grafana/grafana/pkg/apis/iam/v0alpha1" "github.com/grafana/grafana/pkg/registry/apis/iam/common" "github.com/grafana/grafana/pkg/registry/apis/iam/legacy" "github.com/grafana/grafana/pkg/services/apiserver/endpoints/request" @@ -25,7 +25,7 @@ var ( _ rest.Storage = (*LegacyStore)(nil) ) -var resource = identityv0.TeamResourceInfo +var resource = iamv0.TeamResourceInfo func NewLegacyStore(store legacy.LegacyIdentityStore) *LegacyStore { return &LegacyStore{store} @@ -58,25 +58,25 @@ func (s *LegacyStore) ConvertToTable(ctx context.Context, object runtime.Object, return resource.TableConverter().ConvertToTable(ctx, object, tableOptions) } -func (s *LegacyStore) doList(ctx context.Context, ns claims.NamespaceInfo, query legacy.ListTeamQuery) (*identityv0.TeamList, error) { +func (s *LegacyStore) doList(ctx context.Context, ns claims.NamespaceInfo, query legacy.ListTeamQuery) (*iamv0.TeamList, error) { rsp, err := s.store.ListTeams(ctx, ns, query) if err != nil { return nil, err } - list := &identityv0.TeamList{ + list := &iamv0.TeamList{ ListMeta: metav1.ListMeta{ ResourceVersion: strconv.FormatInt(rsp.RV, 10), }, } for _, team := range rsp.Teams { - item := identityv0.Team{ + item := iamv0.Team{ ObjectMeta: metav1.ObjectMeta{ Name: team.UID, Namespace: ns.Value, CreationTimestamp: metav1.NewTime(team.Created), ResourceVersion: strconv.FormatInt(team.Updated.UnixMilli(), 10), }, - Spec: identityv0.TeamSpec{ + Spec: iamv0.TeamSpec{ Title: team.Name, Email: team.Email, }, diff --git a/pkg/registry/apis/iam/team/store_binding.go b/pkg/registry/apis/iam/team/store_binding.go index b97ecf74a00..7251c70fd31 100644 --- a/pkg/registry/apis/iam/team/store_binding.go +++ b/pkg/registry/apis/iam/team/store_binding.go @@ -11,14 +11,14 @@ import ( "k8s.io/apiserver/pkg/registry/rest" "github.com/grafana/authlib/claims" - identityv0 "github.com/grafana/grafana/pkg/apis/iam/v0alpha1" + iamv0 "github.com/grafana/grafana/pkg/apis/iam/v0alpha1" "github.com/grafana/grafana/pkg/registry/apis/iam/common" "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" ) -var bindingResource = identityv0.TeamBindingResourceInfo +var bindingResource = iamv0.TeamBindingResourceInfo var ( _ rest.Storage = (*LegacyBindingStore)(nil) @@ -102,8 +102,8 @@ func (l *LegacyBindingStore) List(ctx context.Context, options *internalversion. return nil, err } - list := identityv0.TeamBindingList{ - Items: make([]identityv0.TeamBinding, 0, len(res.Bindings)), + list := iamv0.TeamBindingList{ + Items: make([]iamv0.TeamBinding, 0, len(res.Bindings)), } for _, b := range res.Bindings { @@ -116,7 +116,7 @@ func (l *LegacyBindingStore) List(ctx context.Context, options *internalversion. return &list, nil } -func mapToBindingObject(ns claims.NamespaceInfo, b legacy.TeamBinding) identityv0.TeamBinding { +func mapToBindingObject(ns claims.NamespaceInfo, b legacy.TeamBinding) iamv0.TeamBinding { rv := time.Time{} ct := time.Now() @@ -129,15 +129,15 @@ func mapToBindingObject(ns claims.NamespaceInfo, b legacy.TeamBinding) identityv } } - return identityv0.TeamBinding{ + return iamv0.TeamBinding{ ObjectMeta: metav1.ObjectMeta{ Name: b.TeamUID, Namespace: ns.Value, ResourceVersion: strconv.FormatInt(rv.UnixMilli(), 10), CreationTimestamp: metav1.NewTime(ct), }, - Spec: identityv0.TeamBindingSpec{ - TeamRef: identityv0.TeamRef{ + Spec: iamv0.TeamBindingSpec{ + TeamRef: iamv0.TeamRef{ Name: b.TeamUID, }, Subjects: mapToSubjects(b.Members), @@ -145,10 +145,10 @@ func mapToBindingObject(ns claims.NamespaceInfo, b legacy.TeamBinding) identityv } } -func mapToSubjects(members []legacy.TeamMember) []identityv0.TeamSubject { - out := make([]identityv0.TeamSubject, 0, len(members)) +func mapToSubjects(members []legacy.TeamMember) []iamv0.TeamSubject { + out := make([]iamv0.TeamSubject, 0, len(members)) for _, m := range members { - out = append(out, identityv0.TeamSubject{ + out = append(out, iamv0.TeamSubject{ Name: m.MemberID(), Permission: common.MapTeamPermission(m.Permission), }) @@ -156,10 +156,10 @@ func mapToSubjects(members []legacy.TeamMember) []identityv0.TeamSubject { return out } -func mapPermisson(p team.PermissionType) identityv0.TeamPermission { +func mapPermisson(p team.PermissionType) iamv0.TeamPermission { if p == team.PermissionTypeAdmin { - return identityv0.TeamPermissionAdmin + return iamv0.TeamPermissionAdmin } else { - return identityv0.TeamPermissionMember + return iamv0.TeamPermissionMember } } diff --git a/pkg/registry/apis/iam/user/rest_display.go b/pkg/registry/apis/iam/user/rest_display.go index 480b331114c..e0f316d1ec3 100644 --- a/pkg/registry/apis/iam/user/rest_display.go +++ b/pkg/registry/apis/iam/user/rest_display.go @@ -8,7 +8,7 @@ import ( "github.com/grafana/authlib/claims" "github.com/grafana/grafana/pkg/api/dtos" - identity "github.com/grafana/grafana/pkg/apis/iam/v0alpha1" + iamv0 "github.com/grafana/grafana/pkg/apis/iam/v0alpha1" "github.com/grafana/grafana/pkg/registry/apis/iam/legacy" "github.com/grafana/grafana/pkg/services/apiserver/endpoints/request" "github.com/grafana/grafana/pkg/setting" @@ -35,7 +35,7 @@ func NewLegacyDisplayREST(store legacy.LegacyIdentityStore) *LegacyDisplayREST { } func (r *LegacyDisplayREST) New() runtime.Object { - return &identity.IdentityDisplayResults{} + return &iamv0.IdentityDisplayResults{} } func (r *LegacyDisplayREST) Destroy() {} @@ -54,7 +54,7 @@ func (r *LegacyDisplayREST) ProducesMIMETypes(verb string) []string { } func (r *LegacyDisplayREST) ProducesObject(verb string) any { - return &identity.IdentityDisplayResults{} + return &iamv0.IdentityDisplayResults{} } func (r *LegacyDisplayREST) ConnectMethods() []string { @@ -91,13 +91,13 @@ func (r *LegacyDisplayREST) Connect(ctx context.Context, name string, _ runtime. return } - rsp := &identity.IdentityDisplayResults{ + rsp := &iamv0.IdentityDisplayResults{ Keys: keys.keys, InvalidKeys: keys.invalid, - Display: make([]identity.IdentityDisplay, 0, len(users.Users)+len(keys.disp)+1), + Display: make([]iamv0.IdentityDisplay, 0, len(users.Users)+len(keys.disp)+1), } for _, user := range users.Users { - disp := identity.IdentityDisplay{ + disp := iamv0.IdentityDisplay{ IdentityType: claims.TypeUser, Display: user.NameOrFallback(), UID: user.UID, @@ -124,7 +124,7 @@ type dispKeys struct { invalid []string // For terminal keys, this is a constant - disp []identity.IdentityDisplay + disp []iamv0.IdentityDisplay } func parseKeys(req []string) dispKeys { @@ -145,14 +145,14 @@ func parseKeys(req []string) dispKeys { switch t { case claims.TypeAnonymous: - keys.disp = append(keys.disp, identity.IdentityDisplay{ + keys.disp = append(keys.disp, iamv0.IdentityDisplay{ IdentityType: t, Display: "Anonymous", AvatarURL: dtos.GetGravatarUrl(fakeCfgForGravatar, string(t)), }) continue case claims.TypeAPIKey: - keys.disp = append(keys.disp, identity.IdentityDisplay{ + keys.disp = append(keys.disp, iamv0.IdentityDisplay{ IdentityType: t, UID: key, Display: "API Key", @@ -160,7 +160,7 @@ func parseKeys(req []string) dispKeys { }) continue case claims.TypeProvisioning: - keys.disp = append(keys.disp, identity.IdentityDisplay{ + keys.disp = append(keys.disp, iamv0.IdentityDisplay{ IdentityType: t, UID: "Provisioning", Display: "Provisioning", @@ -176,7 +176,7 @@ func parseKeys(req []string) dispKeys { id, err := strconv.ParseInt(key, 10, 64) if err == nil { if id == 0 { - keys.disp = append(keys.disp, identity.IdentityDisplay{ + keys.disp = append(keys.disp, iamv0.IdentityDisplay{ IdentityType: claims.TypeUser, UID: key, Display: "System admin", diff --git a/pkg/registry/apis/iam/user/rest_user_team.go b/pkg/registry/apis/iam/user/rest_user_team.go index ce086ea3db2..d9d0c22d2ca 100644 --- a/pkg/registry/apis/iam/user/rest_user_team.go +++ b/pkg/registry/apis/iam/user/rest_user_team.go @@ -7,7 +7,7 @@ import ( "k8s.io/apimachinery/pkg/runtime" "k8s.io/apiserver/pkg/registry/rest" - identityv0 "github.com/grafana/grafana/pkg/apis/iam/v0alpha1" + iamv0 "github.com/grafana/grafana/pkg/apis/iam/v0alpha1" "github.com/grafana/grafana/pkg/registry/apis/iam/common" "github.com/grafana/grafana/pkg/registry/apis/iam/legacy" "github.com/grafana/grafana/pkg/services/apiserver/endpoints/request" @@ -30,7 +30,7 @@ type LegacyUserTeamREST struct { // New implements rest.Storage. func (s *LegacyUserTeamREST) New() runtime.Object { - return &identityv0.UserTeamList{} + return &iamv0.UserTeamList{} } // Destroy implements rest.Storage. @@ -68,7 +68,7 @@ func (s *LegacyUserTeamREST) Connect(ctx context.Context, name string, options r return } - list := &identityv0.UserTeamList{Items: make([]identityv0.UserTeam, 0, len(res.Items))} + list := &iamv0.UserTeamList{Items: make([]iamv0.UserTeam, 0, len(res.Items))} for _, m := range res.Items { list.Items = append(list.Items, mapToUserTeam(m)) @@ -90,10 +90,10 @@ func (s *LegacyUserTeamREST) ConnectMethods() []string { return []string{http.MethodGet} } -func mapToUserTeam(t legacy.UserTeam) identityv0.UserTeam { - return identityv0.UserTeam{ +func mapToUserTeam(t legacy.UserTeam) iamv0.UserTeam { + return iamv0.UserTeam{ Title: t.Name, - TeamRef: identityv0.TeamRef{ + TeamRef: iamv0.TeamRef{ Name: t.UID, }, Permission: common.MapTeamPermission(t.Permission), diff --git a/pkg/registry/apis/iam/user/store.go b/pkg/registry/apis/iam/user/store.go index 5e955a978c7..b67ce7cf22a 100644 --- a/pkg/registry/apis/iam/user/store.go +++ b/pkg/registry/apis/iam/user/store.go @@ -11,7 +11,7 @@ import ( "k8s.io/apiserver/pkg/registry/rest" "github.com/grafana/grafana/pkg/apimachinery/utils" - identityv0 "github.com/grafana/grafana/pkg/apis/iam/v0alpha1" + iamv0 "github.com/grafana/grafana/pkg/apis/iam/v0alpha1" "github.com/grafana/grafana/pkg/registry/apis/iam/common" "github.com/grafana/grafana/pkg/registry/apis/iam/legacy" "github.com/grafana/grafana/pkg/services/apiserver/endpoints/request" @@ -26,7 +26,7 @@ var ( _ rest.Storage = (*LegacyStore)(nil) ) -var resource = identityv0.UserResourceInfo +var resource = iamv0.UserResourceInfo func NewLegacyStore(store legacy.LegacyIdentityStore) *LegacyStore { return &LegacyStore{store} @@ -65,15 +65,14 @@ func (s *LegacyStore) List(ctx context.Context, options *internalversion.ListOpt } found, err := s.store.ListUsers(ctx, ns, legacy.ListUserQuery{ - OrgID: ns.OrgID, - IsServiceAccount: false, - Pagination: common.PaginationFromListOptions(options), + OrgID: ns.OrgID, + Pagination: common.PaginationFromListOptions(options), }) if err != nil { return nil, err } - list := &identityv0.UserList{} + list := &iamv0.UserList{} for _, item := range found.Users { list.Items = append(list.Items, *toUserItem(&item, ns.Value)) } @@ -90,9 +89,8 @@ func (s *LegacyStore) Get(ctx context.Context, name string, options *metav1.GetO return nil, err } query := legacy.ListUserQuery{ - OrgID: ns.OrgID, - IsServiceAccount: false, - Pagination: common.Pagination{Limit: 1}, + OrgID: ns.OrgID, + Pagination: common.Pagination{Limit: 1}, } found, err := s.store.ListUsers(ctx, ns, query) @@ -105,15 +103,15 @@ func (s *LegacyStore) Get(ctx context.Context, name string, options *metav1.GetO return toUserItem(&found.Users[0], ns.Value), nil } -func toUserItem(u *user.User, ns string) *identityv0.User { - item := &identityv0.User{ +func toUserItem(u *user.User, ns string) *iamv0.User { + item := &iamv0.User{ ObjectMeta: metav1.ObjectMeta{ Name: u.UID, Namespace: ns, ResourceVersion: fmt.Sprintf("%d", u.Updated.UnixMilli()), CreationTimestamp: metav1.NewTime(u.Created), }, - Spec: identityv0.UserSpec{ + Spec: iamv0.UserSpec{ Name: u.Name, Login: u.Login, Email: u.Email, diff --git a/pkg/services/serviceaccounts/manager/service_test.go b/pkg/services/serviceaccounts/manager/service_test.go index c7175f480c8..9345235039e 100644 --- a/pkg/services/serviceaccounts/manager/service_test.go +++ b/pkg/services/serviceaccounts/manager/service_test.go @@ -14,7 +14,7 @@ import ( ) type FakeServiceAccountStore struct { - ExpectedServiceAccountID *serviceaccounts.ServiceAccount + ExpectedServiceAccountID int64 ExpectedServiceAccountDTO *serviceaccounts.ServiceAccountDTO ExpectedServiceAccountProfileDTO *serviceaccounts.ServiceAccountProfileDTO ExpectedSearchServiceAccountQueryResult *serviceaccounts.SearchOrgServiceAccountsResult @@ -39,7 +39,7 @@ func (f *FakeServiceAccountStore) RetrieveServiceAccount(ctx context.Context, or // RetrieveServiceAccountIdByName is a fake retrieving a service account id by name. func (f *FakeServiceAccountStore) RetrieveServiceAccountIdByName(ctx context.Context, orgID int64, name string) (int64, error) { - return f.ExpectedServiceAccountID.Id, f.ExpectedError + return f.ExpectedServiceAccountID, f.ExpectedError } // CreateServiceAccount is a fake creating a service account. diff --git a/pkg/services/serviceaccounts/models.go b/pkg/services/serviceaccounts/models.go index 777d9de6170..7756e0657f5 100644 --- a/pkg/services/serviceaccounts/models.go +++ b/pkg/services/serviceaccounts/models.go @@ -52,10 +52,6 @@ type MigrationResult struct { FailedDetails []string `json:"failedDetails"` } -type ServiceAccount struct { - Id int64 -} - // swagger:model type CreateServiceAccountForm struct { // example: grafana