mirror of
https://github.com/grafana/grafana.git
synced 2025-01-27 16:57:14 -06:00
Serviceaccounts: create serviceaccount api (#42150)
* WIP * wip * wip * wip * refactor: new return of the create service accoutn * refactor: change to have correct role * refactor: ability to create service accounts * make public * refactor: make ints instead * refactor: remove location sprintf * refactor: added back named constants
This commit is contained in:
parent
19374fce39
commit
4a3961400a
@ -1,6 +1,7 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net/http"
|
||||
|
||||
"github.com/grafana/grafana/pkg/api/response"
|
||||
@ -11,6 +12,7 @@ import (
|
||||
acmiddleware "github.com/grafana/grafana/pkg/services/accesscontrol/middleware"
|
||||
"github.com/grafana/grafana/pkg/services/serviceaccounts"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
"github.com/grafana/grafana/pkg/web"
|
||||
)
|
||||
|
||||
type ServiceAccountsAPI struct {
|
||||
@ -40,9 +42,27 @@ func (api *ServiceAccountsAPI) RegisterAPIEndpoints(
|
||||
auth := acmiddleware.Middleware(api.accesscontrol)
|
||||
api.RouterRegister.Group("/api/serviceaccounts", func(serviceAccountsRoute routing.RouteRegister) {
|
||||
serviceAccountsRoute.Delete("/:serviceAccountId", auth(middleware.ReqOrgAdmin, accesscontrol.EvalPermission(serviceaccounts.ActionDelete, serviceaccounts.ScopeID)), routing.Wrap(api.DeleteServiceAccount))
|
||||
serviceAccountsRoute.Post("/", auth(middleware.ReqOrgAdmin, accesscontrol.EvalPermission(serviceaccounts.ActionCreate, serviceaccounts.ScopeID)), routing.Wrap(api.CreateServiceAccount))
|
||||
})
|
||||
}
|
||||
|
||||
// POST /api/serviceaccounts
|
||||
func (api *ServiceAccountsAPI) CreateServiceAccount(c *models.ReqContext) response.Response {
|
||||
cmd := serviceaccounts.CreateServiceaccountForm{}
|
||||
if err := web.Bind(c.Req, &cmd); err != nil {
|
||||
return response.Error(http.StatusBadRequest, "Bad request data", err)
|
||||
}
|
||||
user, err := api.service.CreateServiceAccount(c.Req.Context(), &cmd)
|
||||
switch {
|
||||
case errors.Is(err, serviceaccounts.ErrServiceAccountNotFound):
|
||||
return response.Error(http.StatusBadRequest, "Failed to create role with the provided name", err)
|
||||
case err != nil:
|
||||
return response.Error(http.StatusInternalServerError, "Failed to create service account", err)
|
||||
}
|
||||
|
||||
return response.JSON(http.StatusCreated, user)
|
||||
}
|
||||
|
||||
func (api *ServiceAccountsAPI) DeleteServiceAccount(ctx *models.ReqContext) response.Response {
|
||||
scopeID := ctx.ParamsInt64(":serviceAccountId")
|
||||
err := api.service.DeleteServiceAccount(ctx.Req.Context(), ctx.OrgId, scopeID)
|
||||
|
@ -3,9 +3,11 @@ package database
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
"github.com/grafana/grafana/pkg/services/serviceaccounts"
|
||||
"github.com/grafana/grafana/pkg/services/sqlstore"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
type ServiceAccountsStoreImpl struct {
|
||||
@ -18,6 +20,21 @@ func NewServiceAccountsStore(store *sqlstore.SQLStore) *ServiceAccountsStoreImpl
|
||||
}
|
||||
}
|
||||
|
||||
func (s *ServiceAccountsStoreImpl) CreateServiceAccount(ctx context.Context, sa *serviceaccounts.CreateServiceaccountForm) (user *models.User, err error) {
|
||||
// create a new service account - "user" with empty permissions
|
||||
cmd := models.CreateUserCommand{
|
||||
Login: "Service-Account-" + uuid.New().String(),
|
||||
Name: sa.Name + "-Service-Account-" + uuid.New().String(),
|
||||
OrgId: sa.OrgID,
|
||||
IsServiceAccount: true,
|
||||
}
|
||||
newuser, err := s.sqlStore.CreateUser(ctx, cmd)
|
||||
if err != nil {
|
||||
return nil, errors.Errorf("Failed to create user: %v", err)
|
||||
}
|
||||
return newuser, nil
|
||||
}
|
||||
|
||||
func (s *ServiceAccountsStoreImpl) DeleteServiceAccount(ctx context.Context, orgID, serviceaccountID int64) error {
|
||||
return s.sqlStore.WithTransactionalDbSession(ctx, func(sess *sqlstore.DBSession) error {
|
||||
return deleteServiceAccountInTransaction(sess, orgID, serviceaccountID)
|
||||
|
@ -5,6 +5,7 @@ import (
|
||||
|
||||
"github.com/grafana/grafana/pkg/api/routing"
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
"github.com/grafana/grafana/pkg/services/accesscontrol"
|
||||
"github.com/grafana/grafana/pkg/services/serviceaccounts"
|
||||
"github.com/grafana/grafana/pkg/services/serviceaccounts/api"
|
||||
@ -42,6 +43,14 @@ func ProvideServiceAccountsService(
|
||||
return s, nil
|
||||
}
|
||||
|
||||
func (sa *ServiceAccountsService) CreateServiceAccount(ctx context.Context, saForm *serviceaccounts.CreateServiceaccountForm) (*models.User, error) {
|
||||
if !sa.cfg.FeatureToggles["service-accounts"] {
|
||||
sa.log.Debug(ServiceAccountFeatureToggleNotFound)
|
||||
return nil, nil
|
||||
}
|
||||
return sa.store.CreateServiceAccount(ctx, saForm)
|
||||
}
|
||||
|
||||
func (sa *ServiceAccountsService) DeleteServiceAccount(ctx context.Context, orgID, serviceAccountID int64) error {
|
||||
if !sa.cfg.FeatureToggles["service-accounts"] {
|
||||
sa.log.Debug(ServiceAccountFeatureToggleNotFound)
|
||||
|
@ -13,3 +13,14 @@ const (
|
||||
ActionCreate = "serviceaccounts:create"
|
||||
ActionDelete = "serviceaccounts:delete"
|
||||
)
|
||||
|
||||
type ServiceAccount struct {
|
||||
Id int64
|
||||
}
|
||||
|
||||
type CreateServiceaccountForm struct {
|
||||
OrgID int64 `json:"-"`
|
||||
Name string `json:"name" binding:"Required"`
|
||||
DisplayName string `json:"displayName"`
|
||||
Description string `json:"description"`
|
||||
}
|
||||
|
@ -1,10 +1,16 @@
|
||||
package serviceaccounts
|
||||
|
||||
import "context"
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
)
|
||||
|
||||
type Service interface {
|
||||
CreateServiceAccount(ctx context.Context, saForm *CreateServiceaccountForm) (*models.User, error)
|
||||
DeleteServiceAccount(ctx context.Context, orgID, serviceAccountID int64) error
|
||||
}
|
||||
type Store interface {
|
||||
CreateServiceAccount(ctx context.Context, saForm *CreateServiceaccountForm) (*models.User, error)
|
||||
DeleteServiceAccount(ctx context.Context, orgID, serviceAccountID int64) error
|
||||
}
|
||||
|
@ -29,6 +29,10 @@ func SetupUserServiceAccount(t *testing.T, sqlStore *sqlstore.SQLStore, testUser
|
||||
// create mock for serviceaccountservice
|
||||
type ServiceAccountMock struct{}
|
||||
|
||||
func (s *ServiceAccountMock) CreateServiceAccount(ctx context.Context, saForm *serviceaccounts.CreateServiceaccountForm) (*models.User, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (s *ServiceAccountMock) DeleteServiceAccount(ctx context.Context, orgID, serviceAccountID int64) error {
|
||||
return nil
|
||||
}
|
||||
@ -48,6 +52,7 @@ func SetupMockAccesscontrol(t *testing.T, userpermissionsfunc func(c context.Con
|
||||
var _ serviceaccounts.Store = new(ServiceAccountsStoreMock)
|
||||
|
||||
type Calls struct {
|
||||
CreateServiceAccount []interface{}
|
||||
DeleteServiceAccount []interface{}
|
||||
}
|
||||
|
||||
@ -55,6 +60,12 @@ type ServiceAccountsStoreMock struct {
|
||||
Calls Calls
|
||||
}
|
||||
|
||||
func (s *ServiceAccountsStoreMock) CreateServiceAccount(ctx context.Context, cmd *serviceaccounts.CreateServiceaccountForm) (*models.User, error) {
|
||||
// now we can test that the mock has these calls when we call the function
|
||||
s.Calls.CreateServiceAccount = append(s.Calls.CreateServiceAccount, []interface{}{ctx, cmd})
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (s *ServiceAccountsStoreMock) DeleteServiceAccount(ctx context.Context, orgID, serviceAccountID int64) error {
|
||||
// now we can test that the mock has these calls when we call the function
|
||||
s.Calls.DeleteServiceAccount = append(s.Calls.DeleteServiceAccount, []interface{}{ctx, orgID, serviceAccountID})
|
||||
|
Loading…
Reference in New Issue
Block a user