From 6409e761b5030010732bd3fafc19a64a461d4273 Mon Sep 17 00:00:00 2001 From: Eric Leijonmarck Date: Wed, 12 Jan 2022 13:23:00 +0100 Subject: [PATCH] List serviceaccounts (#43672) * Serviceaccounts: feat - tabview for serviceaccounts * WIP * feat: listing all service accounts * refactor: needed to remove showInvitees as not present in serviceaccounts * add token column in the list * add token to orgserviceaccount * Update pkg/services/serviceaccounts/api/api.go --- pkg/models/org_user.go | 16 +++++---- pkg/services/serviceaccounts/api/api.go | 9 +++++ .../serviceaccounts/database/database.go | 9 +++++ .../serviceaccounts/serviceaccounts.go | 1 + pkg/services/serviceaccounts/tests/common.go | 6 ++++ pkg/services/sqlstore/org_users.go | 4 +-- .../ServiceAccountsListPage.tsx | 1 + .../serviceaccounts/ServiceAccountsTable.tsx | 1 - public/app/types/serviceaccount.ts | 35 +++---------------- 9 files changed, 41 insertions(+), 41 deletions(-) diff --git a/pkg/models/org_user.go b/pkg/models/org_user.go index 4c6ce11a00a..5498536de89 100644 --- a/pkg/models/org_user.go +++ b/pkg/models/org_user.go @@ -107,18 +107,20 @@ type UpdateOrgUserCommand struct { // QUERIES type GetOrgUsersQuery struct { - OrgId int64 - Query string - Limit int + OrgId int64 + Query string + Limit int + IsServiceAccount bool Result []*OrgUserDTO } type SearchOrgUsersQuery struct { - OrgID int64 - Query string - Page int - Limit int + OrgID int64 + Query string + Page int + Limit int + IsServiceAccount bool Result SearchOrgUsersQueryResult } diff --git a/pkg/services/serviceaccounts/api/api.go b/pkg/services/serviceaccounts/api/api.go index 41c58cdd1ca..29fd6027d38 100644 --- a/pkg/services/serviceaccounts/api/api.go +++ b/pkg/services/serviceaccounts/api/api.go @@ -44,6 +44,7 @@ func (api *ServiceAccountsAPI) RegisterAPIEndpoints( } auth := acmiddleware.Middleware(api.accesscontrol) api.RouterRegister.Group("/api/serviceaccounts", func(serviceAccountsRoute routing.RouteRegister) { + serviceAccountsRoute.Get("/", auth(middleware.ReqOrgAdmin, accesscontrol.EvalPermission(serviceaccounts.ActionRead, serviceaccounts.ScopeAll)), routing.Wrap(api.ListServiceAccounts)) serviceAccountsRoute.Delete("/:serviceAccountId", auth(middleware.ReqOrgAdmin, accesscontrol.EvalPermission(serviceaccounts.ActionDelete, serviceaccounts.ScopeID)), routing.Wrap(api.DeleteServiceAccount)) serviceAccountsRoute.Get("/upgrade", auth(middleware.ReqOrgAdmin, accesscontrol.EvalPermission(serviceaccounts.ActionCreate, serviceaccounts.ScopeID)), routing.Wrap(api.UpgradeServiceAccounts)) serviceAccountsRoute.Post("/", auth(middleware.ReqOrgAdmin, accesscontrol.EvalPermission(serviceaccounts.ActionCreate, serviceaccounts.ScopeID)), routing.Wrap(api.CreateServiceAccount)) @@ -83,3 +84,11 @@ func (api *ServiceAccountsAPI) UpgradeServiceAccounts(ctx *models.ReqContext) re return response.Error(500, "Internal server error", err) } } + +func (api *ServiceAccountsAPI) ListServiceAccounts(ctx *models.ReqContext) response.Response { + serviceAccounts, err := api.store.ListServiceAccounts(ctx.Req.Context(), ctx.OrgId) + if err != nil { + return response.Error(http.StatusInternalServerError, "Failed to list roles", err) + } + return response.JSON(http.StatusOK, serviceAccounts) +} diff --git a/pkg/services/serviceaccounts/database/database.go b/pkg/services/serviceaccounts/database/database.go index 2be3a992f13..bbd362e47d4 100644 --- a/pkg/services/serviceaccounts/database/database.go +++ b/pkg/services/serviceaccounts/database/database.go @@ -84,3 +84,12 @@ func (s *ServiceAccountsStoreImpl) UpgradeServiceAccounts(ctx context.Context) e } return nil } + +func (s *ServiceAccountsStoreImpl) ListServiceAccounts(ctx context.Context, orgID int64) ([]*models.OrgUserDTO, error) { + query := models.GetOrgUsersQuery{OrgId: orgID, IsServiceAccount: true} + err := s.sqlStore.GetOrgUsers(ctx, &query) + if err != nil { + return nil, err + } + return query.Result, err +} diff --git a/pkg/services/serviceaccounts/serviceaccounts.go b/pkg/services/serviceaccounts/serviceaccounts.go index 7f5132b7e52..7ad36dc7a4a 100644 --- a/pkg/services/serviceaccounts/serviceaccounts.go +++ b/pkg/services/serviceaccounts/serviceaccounts.go @@ -14,6 +14,7 @@ type Service interface { type Store interface { CreateServiceAccount(ctx context.Context, saForm *CreateServiceaccountForm) (*models.User, error) + ListServiceAccounts(ctx context.Context, orgID int64) ([]*models.OrgUserDTO, error) DeleteServiceAccount(ctx context.Context, orgID, serviceAccountID int64) error UpgradeServiceAccounts(ctx context.Context) error } diff --git a/pkg/services/serviceaccounts/tests/common.go b/pkg/services/serviceaccounts/tests/common.go index f2339b3d041..c8fc4f56dd3 100644 --- a/pkg/services/serviceaccounts/tests/common.go +++ b/pkg/services/serviceaccounts/tests/common.go @@ -57,6 +57,7 @@ var _ serviceaccounts.Store = new(ServiceAccountsStoreMock) type Calls struct { CreateServiceAccount []interface{} + ListServiceAccounts []interface{} DeleteServiceAccount []interface{} UpgradeServiceAccounts []interface{} } @@ -81,3 +82,8 @@ func (s *ServiceAccountsStoreMock) UpgradeServiceAccounts(ctx context.Context) e s.Calls.DeleteServiceAccount = append(s.Calls.UpgradeServiceAccounts, []interface{}{ctx}) return nil } + +func (s *ServiceAccountsStoreMock) ListServiceAccounts(ctx context.Context, orgID int64) ([]*models.OrgUserDTO, error) { + s.Calls.ListServiceAccounts = append(s.Calls.ListServiceAccounts, []interface{}{ctx, orgID}) + return nil, nil +} diff --git a/pkg/services/sqlstore/org_users.go b/pkg/services/sqlstore/org_users.go index 5b97df12c2d..898ace7dff1 100644 --- a/pkg/services/sqlstore/org_users.go +++ b/pkg/services/sqlstore/org_users.go @@ -109,7 +109,7 @@ func (ss *SQLStore) GetOrgUsers(ctx context.Context, query *models.GetOrgUsersQu // TODO: add to chore, for cleaning up after we have created // service accounts table in the modelling - whereConditions = append(whereConditions, fmt.Sprintf("%s.is_service_account = false", x.Dialect().Quote("user"))) + whereConditions = append(whereConditions, fmt.Sprintf("%s.is_service_account = %t", x.Dialect().Quote("user"), query.IsServiceAccount)) if query.Query != "" { queryWithWildcards := "%" + query.Query + "%" @@ -163,7 +163,7 @@ func (ss *SQLStore) SearchOrgUsers(ctx context.Context, query *models.SearchOrgU // TODO: add to chore, for cleaning up after we have created // service accounts table in the modelling - whereConditions = append(whereConditions, fmt.Sprintf("%s.is_service_account = false", x.Dialect().Quote("user"))) + whereConditions = append(whereConditions, fmt.Sprintf("%s.is_service_account = %t", x.Dialect().Quote("user"), query.IsServiceAccount)) if query.Query != "" { queryWithWildcards := "%" + query.Query + "%" diff --git a/public/app/features/serviceaccounts/ServiceAccountsListPage.tsx b/public/app/features/serviceaccounts/ServiceAccountsListPage.tsx index de7345125a3..8e91a0e5b8f 100644 --- a/public/app/features/serviceaccounts/ServiceAccountsListPage.tsx +++ b/public/app/features/serviceaccounts/ServiceAccountsListPage.tsx @@ -42,6 +42,7 @@ export class ServiceAccountsListPage extends PureComponent { return ( +

Service Accounts

this.onRoleChange(role, serviceAccount)} diff --git a/public/app/features/serviceaccounts/ServiceAccountsTable.tsx b/public/app/features/serviceaccounts/ServiceAccountsTable.tsx index b28f4474041..84ef5a920f9 100644 --- a/public/app/features/serviceaccounts/ServiceAccountsTable.tsx +++ b/public/app/features/serviceaccounts/ServiceAccountsTable.tsx @@ -80,7 +80,6 @@ const ServiceAccountsTable: FC = (props) => { {serviceAccount.name} - {serviceAccount.lastSeenAtAge} {contextSrv.accessControlEnabled() ? ( diff --git a/public/app/types/serviceaccount.ts b/public/app/types/serviceaccount.ts index c3d5ceb964f..7b16ab24231 100644 --- a/public/app/types/serviceaccount.ts +++ b/public/app/types/serviceaccount.ts @@ -1,16 +1,15 @@ import { OrgRole, Unit } from '.'; -import { SelectableValue } from '@grafana/data'; export interface OrgServiceAccount { + serviceAccountId: number; avatarUrl: string; email: string; - lastSeenAt: string; - lastSeenAtAge: string; login: string; name: string; + displayName: string; orgId: number; role: OrgRole; - serviceAccountId: number; + tokens: number[]; } export interface ServiceAccount { @@ -20,6 +19,7 @@ export interface ServiceAccount { login: string; email: string; name: string; + displayName: string; orgId?: number; } @@ -35,7 +35,6 @@ export interface ServiceAccountDTO { authLabels?: string[]; avatarUrl?: string; orgId?: number; - lastSeenAtAge?: string; licensedRole?: string; permissions?: string[]; teams?: Unit[]; @@ -48,29 +47,3 @@ export interface ServiceAccountsState { searchPage: number; isLoading: boolean; } - -export interface ServiceAccountSession { - id: number; - createdAt: string; - clientIp: string; - isActive: boolean; - seenAt: string; -} - -export interface ServiceAccountOrg { - name: string; - orgId: number; - role: OrgRole; -} - -export type ServiceAccountFilter = Record; -export interface ServiceaccountListAdminState { - serviceaccounts: ServiceAccountDTO[]; - query: string; - perPage: number; - page: number; - totalPages: number; - showPaging: boolean; - filters: ServiceAccountFilter[]; - isLoading: boolean; -}