mirror of
https://github.com/grafana/grafana.git
synced 2025-07-30 05:53:15 +08:00

* SQLTemplates: Add helper to ensure all templates have a test-case associated * UnifiedStorage: Add missing sql template test case * LegacyDashboards: Add sql templates fs to test cases for exhaustiveness check * RBACStore: Add sql templates fs to test cases for exhaustiveness check * LegacyIAM: Add missing sql template test cases
289 lines
6.7 KiB
Go
289 lines
6.7 KiB
Go
package legacy
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"time"
|
|
|
|
claims "github.com/grafana/authlib/types"
|
|
|
|
"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 GetServiceAccountInternalIDQuery struct {
|
|
OrgID int64
|
|
UID string
|
|
}
|
|
|
|
type GetServiceAccountInternalIDResult struct {
|
|
ID int64
|
|
}
|
|
|
|
var sqlQueryServiceAccountInternalIDTemplate = mustTemplate("service_account_internal_id.sql")
|
|
|
|
func newGetServiceAccountInternalID(sql *legacysql.LegacyDatabaseHelper, q *GetServiceAccountInternalIDQuery) getServiceAccountInternalIDQuery {
|
|
return getServiceAccountInternalIDQuery{
|
|
SQLTemplate: sqltemplate.New(sql.DialectForDriver()),
|
|
UserTable: sql.Table("user"),
|
|
OrgUserTable: sql.Table("org_user"),
|
|
Query: q,
|
|
}
|
|
}
|
|
|
|
type getServiceAccountInternalIDQuery struct {
|
|
sqltemplate.SQLTemplate
|
|
UserTable string
|
|
OrgUserTable string
|
|
Query *GetServiceAccountInternalIDQuery
|
|
}
|
|
|
|
func (r getServiceAccountInternalIDQuery) Validate() error {
|
|
return nil // TODO
|
|
}
|
|
|
|
func (s *legacySQLStore) GetServiceAccountInternalID(
|
|
ctx context.Context,
|
|
ns claims.NamespaceInfo,
|
|
query GetServiceAccountInternalIDQuery,
|
|
) (*GetServiceAccountInternalIDResult, error) {
|
|
query.OrgID = ns.OrgID
|
|
if query.OrgID == 0 {
|
|
return nil, fmt.Errorf("expected non zero org id")
|
|
}
|
|
|
|
sql, err := s.sql(ctx)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
req := newGetServiceAccountInternalID(sql, &query)
|
|
q, err := sqltemplate.Execute(sqlQueryServiceAccountInternalIDTemplate, req)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("execute template %q: %w", sqlQueryServiceAccountInternalIDTemplate.Name(), err)
|
|
}
|
|
|
|
rows, err := sql.DB.GetSqlxSession().Query(ctx, q, req.GetArgs()...)
|
|
defer func() {
|
|
if rows != nil {
|
|
_ = rows.Close()
|
|
}
|
|
}()
|
|
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if !rows.Next() {
|
|
return nil, errors.New("service account not found")
|
|
}
|
|
|
|
var id int64
|
|
if err := rows.Scan(&id); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &GetServiceAccountInternalIDResult{
|
|
id,
|
|
}, nil
|
|
}
|
|
|
|
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 (listServiceAccountTokensQuery) Validate() error {
|
|
return nil // TODO
|
|
}
|
|
|
|
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
|
|
}
|