mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -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
|
package api
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/grafana/grafana/pkg/api/response"
|
"github.com/grafana/grafana/pkg/api/response"
|
||||||
@ -11,6 +12,7 @@ import (
|
|||||||
acmiddleware "github.com/grafana/grafana/pkg/services/accesscontrol/middleware"
|
acmiddleware "github.com/grafana/grafana/pkg/services/accesscontrol/middleware"
|
||||||
"github.com/grafana/grafana/pkg/services/serviceaccounts"
|
"github.com/grafana/grafana/pkg/services/serviceaccounts"
|
||||||
"github.com/grafana/grafana/pkg/setting"
|
"github.com/grafana/grafana/pkg/setting"
|
||||||
|
"github.com/grafana/grafana/pkg/web"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ServiceAccountsAPI struct {
|
type ServiceAccountsAPI struct {
|
||||||
@ -40,9 +42,27 @@ func (api *ServiceAccountsAPI) RegisterAPIEndpoints(
|
|||||||
auth := acmiddleware.Middleware(api.accesscontrol)
|
auth := acmiddleware.Middleware(api.accesscontrol)
|
||||||
api.RouterRegister.Group("/api/serviceaccounts", func(serviceAccountsRoute routing.RouteRegister) {
|
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.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 {
|
func (api *ServiceAccountsAPI) DeleteServiceAccount(ctx *models.ReqContext) response.Response {
|
||||||
scopeID := ctx.ParamsInt64(":serviceAccountId")
|
scopeID := ctx.ParamsInt64(":serviceAccountId")
|
||||||
err := api.service.DeleteServiceAccount(ctx.Req.Context(), ctx.OrgId, scopeID)
|
err := api.service.DeleteServiceAccount(ctx.Req.Context(), ctx.OrgId, scopeID)
|
||||||
|
@ -3,9 +3,11 @@ package database
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
|
"github.com/google/uuid"
|
||||||
"github.com/grafana/grafana/pkg/models"
|
"github.com/grafana/grafana/pkg/models"
|
||||||
"github.com/grafana/grafana/pkg/services/serviceaccounts"
|
"github.com/grafana/grafana/pkg/services/serviceaccounts"
|
||||||
"github.com/grafana/grafana/pkg/services/sqlstore"
|
"github.com/grafana/grafana/pkg/services/sqlstore"
|
||||||
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ServiceAccountsStoreImpl struct {
|
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 {
|
func (s *ServiceAccountsStoreImpl) DeleteServiceAccount(ctx context.Context, orgID, serviceaccountID int64) error {
|
||||||
return s.sqlStore.WithTransactionalDbSession(ctx, func(sess *sqlstore.DBSession) error {
|
return s.sqlStore.WithTransactionalDbSession(ctx, func(sess *sqlstore.DBSession) error {
|
||||||
return deleteServiceAccountInTransaction(sess, orgID, serviceaccountID)
|
return deleteServiceAccountInTransaction(sess, orgID, serviceaccountID)
|
||||||
|
@ -5,6 +5,7 @@ import (
|
|||||||
|
|
||||||
"github.com/grafana/grafana/pkg/api/routing"
|
"github.com/grafana/grafana/pkg/api/routing"
|
||||||
"github.com/grafana/grafana/pkg/infra/log"
|
"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/accesscontrol"
|
||||||
"github.com/grafana/grafana/pkg/services/serviceaccounts"
|
"github.com/grafana/grafana/pkg/services/serviceaccounts"
|
||||||
"github.com/grafana/grafana/pkg/services/serviceaccounts/api"
|
"github.com/grafana/grafana/pkg/services/serviceaccounts/api"
|
||||||
@ -42,6 +43,14 @@ func ProvideServiceAccountsService(
|
|||||||
return s, nil
|
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 {
|
func (sa *ServiceAccountsService) DeleteServiceAccount(ctx context.Context, orgID, serviceAccountID int64) error {
|
||||||
if !sa.cfg.FeatureToggles["service-accounts"] {
|
if !sa.cfg.FeatureToggles["service-accounts"] {
|
||||||
sa.log.Debug(ServiceAccountFeatureToggleNotFound)
|
sa.log.Debug(ServiceAccountFeatureToggleNotFound)
|
||||||
|
@ -13,3 +13,14 @@ const (
|
|||||||
ActionCreate = "serviceaccounts:create"
|
ActionCreate = "serviceaccounts:create"
|
||||||
ActionDelete = "serviceaccounts:delete"
|
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
|
package serviceaccounts
|
||||||
|
|
||||||
import "context"
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/grafana/grafana/pkg/models"
|
||||||
|
)
|
||||||
|
|
||||||
type Service interface {
|
type Service interface {
|
||||||
|
CreateServiceAccount(ctx context.Context, saForm *CreateServiceaccountForm) (*models.User, error)
|
||||||
DeleteServiceAccount(ctx context.Context, orgID, serviceAccountID int64) error
|
DeleteServiceAccount(ctx context.Context, orgID, serviceAccountID int64) error
|
||||||
}
|
}
|
||||||
type Store interface {
|
type Store interface {
|
||||||
|
CreateServiceAccount(ctx context.Context, saForm *CreateServiceaccountForm) (*models.User, error)
|
||||||
DeleteServiceAccount(ctx context.Context, orgID, serviceAccountID int64) 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
|
// create mock for serviceaccountservice
|
||||||
type ServiceAccountMock struct{}
|
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 {
|
func (s *ServiceAccountMock) DeleteServiceAccount(ctx context.Context, orgID, serviceAccountID int64) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -48,6 +52,7 @@ func SetupMockAccesscontrol(t *testing.T, userpermissionsfunc func(c context.Con
|
|||||||
var _ serviceaccounts.Store = new(ServiceAccountsStoreMock)
|
var _ serviceaccounts.Store = new(ServiceAccountsStoreMock)
|
||||||
|
|
||||||
type Calls struct {
|
type Calls struct {
|
||||||
|
CreateServiceAccount []interface{}
|
||||||
DeleteServiceAccount []interface{}
|
DeleteServiceAccount []interface{}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -55,6 +60,12 @@ type ServiceAccountsStoreMock struct {
|
|||||||
Calls Calls
|
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 {
|
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
|
// 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})
|
s.Calls.DeleteServiceAccount = append(s.Calls.DeleteServiceAccount, []interface{}{ctx, orgID, serviceAccountID})
|
||||||
|
Loading…
Reference in New Issue
Block a user