K8s: Library Panels: Add rerouting for get (#107362)
This commit is contained in:
@@ -1,23 +1,38 @@
|
||||
package libraryelements
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"hash/fnv"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
dashboardV0 "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v0alpha1"
|
||||
"github.com/grafana/grafana/pkg/api/dtos"
|
||||
"github.com/grafana/grafana/pkg/api/response"
|
||||
"github.com/grafana/grafana/pkg/api/routing"
|
||||
"github.com/grafana/grafana/pkg/apimachinery/utils"
|
||||
"github.com/grafana/grafana/pkg/infra/metrics"
|
||||
"github.com/grafana/grafana/pkg/kinds/librarypanel"
|
||||
ac "github.com/grafana/grafana/pkg/services/accesscontrol"
|
||||
grafanaapiserver "github.com/grafana/grafana/pkg/services/apiserver"
|
||||
"github.com/grafana/grafana/pkg/services/apiserver/endpoints/request"
|
||||
contextmodel "github.com/grafana/grafana/pkg/services/contexthandler/model"
|
||||
"github.com/grafana/grafana/pkg/services/dashboards"
|
||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||
"github.com/grafana/grafana/pkg/services/folder"
|
||||
"github.com/grafana/grafana/pkg/services/libraryelements/model"
|
||||
"github.com/grafana/grafana/pkg/services/org"
|
||||
"github.com/grafana/grafana/pkg/services/user"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
"github.com/grafana/grafana/pkg/util/errhttp"
|
||||
"github.com/grafana/grafana/pkg/web"
|
||||
k8serrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/client-go/dynamic"
|
||||
)
|
||||
|
||||
func (l *LibraryElementService) registerAPIEndpoints() {
|
||||
@@ -25,13 +40,13 @@ func (l *LibraryElementService) registerAPIEndpoints() {
|
||||
|
||||
l.RouteRegister.Group("/api/library-elements", func(entities routing.RouteRegister) {
|
||||
uidScope := ScopeLibraryPanelsProvider.GetResourceScopeUID(ac.Parameter(":uid"))
|
||||
entities.Post("/", authorize(ac.EvalPermission(ActionLibraryPanelsCreate)), routing.Wrap(l.createHandler))
|
||||
entities.Delete("/:uid", authorize(ac.EvalPermission(ActionLibraryPanelsDelete, uidScope)), routing.Wrap(l.deleteHandler))
|
||||
entities.Get("/", authorize(ac.EvalPermission(ActionLibraryPanelsRead)), routing.Wrap(l.getAllHandler))
|
||||
entities.Post("/", authorize(ac.EvalPermission(ActionLibraryPanelsCreate)), routing.Wrap(l.createHandler)) // TODO: add wrapper for k8s
|
||||
entities.Delete("/:uid", authorize(ac.EvalPermission(ActionLibraryPanelsDelete, uidScope)), routing.Wrap(l.deleteHandler)) // TODO: add wrapper for k8s
|
||||
entities.Get("/", authorize(ac.EvalPermission(ActionLibraryPanelsRead)), routing.Wrap(l.getAllHandler)) // TODO: add wrapper for k8s - requires search
|
||||
entities.Get("/:uid", authorize(ac.EvalPermission(ActionLibraryPanelsRead)), routing.Wrap(l.getHandler))
|
||||
entities.Get("/:uid/connections/", authorize(ac.EvalPermission(ActionLibraryPanelsRead, uidScope)), routing.Wrap(l.getConnectionsHandler))
|
||||
entities.Get("/name/:name", routing.Wrap(l.getByNameHandler))
|
||||
entities.Patch("/:uid", authorize(ac.EvalPermission(ActionLibraryPanelsWrite, uidScope)), routing.Wrap(l.patchHandler))
|
||||
entities.Get("/name/:name", routing.Wrap(l.getByNameHandler)) // TODO: add wrapper for k8s - requires search
|
||||
entities.Patch("/:uid", authorize(ac.EvalPermission(ActionLibraryPanelsWrite, uidScope)), routing.Wrap(l.patchHandler)) // TODO: add wrapper for k8s
|
||||
})
|
||||
}
|
||||
|
||||
@@ -133,6 +148,11 @@ func (l *LibraryElementService) deleteHandler(c *contextmodel.ReqContext) respon
|
||||
// 404: notFoundError
|
||||
// 500: internalServerError
|
||||
func (l *LibraryElementService) getHandler(c *contextmodel.ReqContext) response.Response {
|
||||
if l.features.IsEnabled(c.Req.Context(), featuremgmt.FlagKubernetesLibraryPanels) {
|
||||
l.k8sHandler.getK8sLibraryElement(c)
|
||||
return nil // already handled in the k8s handler
|
||||
}
|
||||
|
||||
ctx := c.Req.Context()
|
||||
element, err := l.getLibraryElementByUid(ctx, c.SignedInUser,
|
||||
model.GetLibraryElementCommand{
|
||||
@@ -529,3 +549,205 @@ type GetLibraryElementConnectionsResponse struct {
|
||||
// in: body
|
||||
Body model.LibraryElementConnectionsResponse `json:"body"`
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------------------
|
||||
// Library Elements k8s wrapper functions
|
||||
//-----------------------------------------------------------------------------------------
|
||||
|
||||
type libraryElementsK8sHandler struct {
|
||||
cfg *setting.Cfg
|
||||
namespacer request.NamespaceMapper
|
||||
gvr schema.GroupVersionResource
|
||||
clientConfigProvider grafanaapiserver.DirectRestConfigProvider
|
||||
folderService folder.Service
|
||||
dashboardsService dashboards.DashboardService
|
||||
userService user.Service
|
||||
}
|
||||
|
||||
func newLibraryElementsK8sHandler(cfg *setting.Cfg, clientConfigProvider grafanaapiserver.DirectRestConfigProvider, folderService folder.Service, userService user.Service, dashboardsService dashboards.DashboardService) *libraryElementsK8sHandler {
|
||||
gvr := schema.GroupVersionResource{
|
||||
Group: dashboardV0.APIGroup,
|
||||
Version: dashboardV0.APIVersion,
|
||||
Resource: dashboardV0.LIBRARY_PANEL_RESOURCE,
|
||||
}
|
||||
return &libraryElementsK8sHandler{
|
||||
cfg: cfg,
|
||||
gvr: gvr,
|
||||
namespacer: request.GetNamespaceMapper(cfg),
|
||||
clientConfigProvider: clientConfigProvider,
|
||||
folderService: folderService,
|
||||
dashboardsService: dashboardsService,
|
||||
userService: userService,
|
||||
}
|
||||
}
|
||||
|
||||
func (lk8s *libraryElementsK8sHandler) getK8sLibraryElement(c *contextmodel.ReqContext) {
|
||||
client, ok := lk8s.getClient(c)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
uid := web.Params(c.Req)[":uid"]
|
||||
out, err := client.Get(c.Req.Context(), uid, v1.GetOptions{})
|
||||
if err != nil {
|
||||
lk8s.writeError(c, err)
|
||||
return
|
||||
}
|
||||
|
||||
dto, err := lk8s.unstructuredToLegacyLibraryPanelDTO(c, *out)
|
||||
if err != nil {
|
||||
c.JsonApiErr(http.StatusInternalServerError, "conversion error", err)
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusOK, model.LibraryElementResponse{Result: *dto})
|
||||
}
|
||||
|
||||
func (lk8s *libraryElementsK8sHandler) unstructuredToLegacyLibraryPanelDTO(c *contextmodel.ReqContext, item unstructured.Unstructured) (*model.LibraryElementDTO, error) {
|
||||
spec, exists := item.Object["spec"].(map[string]interface{})
|
||||
if !exists {
|
||||
return nil, fmt.Errorf("spec not found in unstructured object")
|
||||
}
|
||||
|
||||
id := int64(0)
|
||||
folderUID := ""
|
||||
meta, err := utils.MetaAccessor(&item)
|
||||
if err == nil {
|
||||
id = meta.GetDeprecatedInternalID() // nolint:staticcheck
|
||||
folderUID = meta.GetFolder()
|
||||
}
|
||||
|
||||
var libraryPanelSpec dashboardV0.LibraryPanelSpec
|
||||
specJSON, err := json.Marshal(spec)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to marshal spec: %w", err)
|
||||
}
|
||||
|
||||
err = json.Unmarshal(specJSON, &libraryPanelSpec)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to unmarshal spec into LibraryPanelSpec: %w", err)
|
||||
}
|
||||
|
||||
// need to reconstruct this section from what we have in the k8s object
|
||||
legacyModel := map[string]any{}
|
||||
legacyModel["datasource"] = libraryPanelSpec.Datasource
|
||||
legacyModel["description"] = libraryPanelSpec.Description
|
||||
legacyModel["fieldConfig"] = libraryPanelSpec.FieldConfig.Object
|
||||
legacyModel["gridPos"] = libraryPanelSpec.GridPos
|
||||
legacyModel["id"] = id
|
||||
legacyModel["options"] = libraryPanelSpec.Options.Object
|
||||
legacyModel["pluginVersion"] = libraryPanelSpec.PluginVersion
|
||||
legacyModel["type"] = libraryPanelSpec.Type
|
||||
legacyModel["title"] = libraryPanelSpec.PanelTitle // this is the title of the panel when displayed in the dashboard
|
||||
legacyModel["libraryPanel"] = map[string]string{
|
||||
"name": libraryPanelSpec.Title, // this is the title of the actual library panel, when displayed in the library panel list
|
||||
"uid": item.GetName(),
|
||||
}
|
||||
if len(libraryPanelSpec.Links) > 0 {
|
||||
legacyModel["links"] = libraryPanelSpec.Links
|
||||
}
|
||||
if len(libraryPanelSpec.Targets) > 0 {
|
||||
legacyModel["targets"] = libraryPanelSpec.Targets
|
||||
}
|
||||
if libraryPanelSpec.Transparent {
|
||||
legacyModel["transparent"] = libraryPanelSpec.Transparent
|
||||
}
|
||||
finalModel, err := json.Marshal(legacyModel)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to marshal model: %w", err)
|
||||
}
|
||||
|
||||
dto := &model.LibraryElementDTO{
|
||||
ID: id,
|
||||
OrgID: c.OrgID,
|
||||
FolderUID: folderUID,
|
||||
UID: item.GetName(),
|
||||
Name: libraryPanelSpec.Title,
|
||||
Kind: int64(model.PanelElement),
|
||||
Type: libraryPanelSpec.Type,
|
||||
Description: libraryPanelSpec.Description,
|
||||
Model: finalModel,
|
||||
Version: item.GetGeneration(),
|
||||
Meta: model.LibraryElementDTOMeta{
|
||||
FolderUID: folderUID,
|
||||
Created: meta.GetCreationTimestamp().Time,
|
||||
},
|
||||
}
|
||||
|
||||
if folderUID != "" {
|
||||
folder, err := lk8s.folderService.Get(c.Req.Context(), &folder.GetFolderQuery{
|
||||
OrgID: c.OrgID,
|
||||
UID: &folderUID,
|
||||
SignedInUser: c.SignedInUser,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
dto.Meta.FolderName = folder.Title
|
||||
dto.FolderID = folder.ID // nolint:staticcheck
|
||||
}
|
||||
|
||||
dashboards, err := lk8s.dashboardsService.GetDashboardsByLibraryPanelUID(c.Req.Context(), item.GetName(), c.OrgID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
dto.Meta.ConnectedDashboards = int64(len(dashboards))
|
||||
|
||||
createdBy := meta.GetCreatedBy()
|
||||
updatedBy := createdBy // the old /api returns the same user for updated if it was never updated
|
||||
userUIDs := []string{meta.GetCreatedBy()}
|
||||
if timestamp, err := meta.GetUpdatedTimestamp(); err == nil && timestamp != nil {
|
||||
dto.Meta.Updated = *timestamp
|
||||
updatedBy = meta.GetUpdatedBy()
|
||||
userUIDs = append(userUIDs, updatedBy)
|
||||
} else {
|
||||
// if never updated, the old /api returns the same timestamp for updated as for created
|
||||
dto.Meta.Updated = dto.Meta.Created
|
||||
}
|
||||
|
||||
users, err := lk8s.userService.ListByIdOrUID(c.Req.Context(), userUIDs, []int64{c.OrgID})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, user := range users {
|
||||
if user.UID == createdBy {
|
||||
dto.Meta.CreatedBy = librarypanel.LibraryElementDTOMetaUser{
|
||||
Id: user.ID,
|
||||
Name: user.Login,
|
||||
AvatarUrl: dtos.GetGravatarUrl(lk8s.cfg, user.Email),
|
||||
}
|
||||
}
|
||||
// not else because /api returns the same user for updated if it was never updated
|
||||
if user.UID == updatedBy {
|
||||
dto.Meta.UpdatedBy = librarypanel.LibraryElementDTOMetaUser{
|
||||
Id: user.ID,
|
||||
Name: user.Login,
|
||||
AvatarUrl: dtos.GetGravatarUrl(lk8s.cfg, user.Email),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return dto, nil
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------------------
|
||||
// Utility functions
|
||||
//-----------------------------------------------------------------------------------------
|
||||
|
||||
func (lk8s *libraryElementsK8sHandler) getClient(c *contextmodel.ReqContext) (dynamic.ResourceInterface, bool) {
|
||||
dyn, err := dynamic.NewForConfig(lk8s.clientConfigProvider.GetDirectRestConfig(c))
|
||||
if err != nil {
|
||||
c.JsonApiErr(500, "client", err)
|
||||
return nil, false
|
||||
}
|
||||
return dyn.Resource(lk8s.gvr).Namespace(lk8s.namespacer(c.OrgID)), true
|
||||
}
|
||||
|
||||
func (lk8s *libraryElementsK8sHandler) writeError(c *contextmodel.ReqContext, err error) {
|
||||
//nolint:errorlint
|
||||
statusError, ok := err.(*k8serrors.StatusError)
|
||||
if ok {
|
||||
c.JsonApiErr(int(statusError.Status().Code), statusError.Status().Message, err)
|
||||
return
|
||||
}
|
||||
errhttp.Write(c.Req.Context(), err, c.Resp)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,180 @@
|
||||
package libraryelements
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/mock"
|
||||
"github.com/stretchr/testify/require"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
|
||||
"github.com/grafana/grafana/pkg/api/dtos"
|
||||
"github.com/grafana/grafana/pkg/apimachinery/utils"
|
||||
contextmodel "github.com/grafana/grafana/pkg/services/contexthandler/model"
|
||||
"github.com/grafana/grafana/pkg/services/dashboards"
|
||||
"github.com/grafana/grafana/pkg/services/folder"
|
||||
"github.com/grafana/grafana/pkg/services/folder/foldertest"
|
||||
"github.com/grafana/grafana/pkg/services/libraryelements/model"
|
||||
"github.com/grafana/grafana/pkg/services/org"
|
||||
"github.com/grafana/grafana/pkg/services/user"
|
||||
"github.com/grafana/grafana/pkg/services/user/usertest"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
"github.com/grafana/grafana/pkg/web"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
func TestUnstructuredToLegacyLibraryPanelDTO(t *testing.T) {
|
||||
cfg := setting.NewCfg()
|
||||
userSvc := &usertest.FakeUserService{}
|
||||
testUser := &user.User{
|
||||
ID: 1,
|
||||
UID: "test-user-uid",
|
||||
Login: "testuser",
|
||||
Email: "test@example.com",
|
||||
}
|
||||
userSvc.ExpectedListUsersByIdOrUid = []*user.User{testUser}
|
||||
|
||||
testFolder := &folder.Folder{
|
||||
ID: 1,
|
||||
UID: "test-folder-uid",
|
||||
Title: "Test Folder",
|
||||
}
|
||||
folderSvc := &foldertest.FakeService{
|
||||
ExpectedFolder: testFolder,
|
||||
}
|
||||
|
||||
dashboardsSvc := &dashboards.FakeDashboardService{}
|
||||
testDashboard := &dashboards.DashboardRef{
|
||||
ID: 1,
|
||||
UID: "test-dashboard-uid",
|
||||
FolderUID: testFolder.UID,
|
||||
}
|
||||
dashboardsSvc.On("GetDashboardsByLibraryPanelUID", mock.Anything, "test-panel-uid", int64(1)).Return([]*dashboards.DashboardRef{testDashboard}, nil)
|
||||
|
||||
handler := &libraryElementsK8sHandler{
|
||||
cfg: cfg,
|
||||
folderService: folderSvc,
|
||||
dashboardsService: dashboardsSvc,
|
||||
userService: userSvc,
|
||||
}
|
||||
|
||||
unstructuredObj := &unstructured.Unstructured{
|
||||
Object: map[string]interface{}{
|
||||
"apiVersion": "dashboard.grafana.app/v0alpha1",
|
||||
"kind": "LibraryPanel",
|
||||
"metadata": map[string]any{
|
||||
"name": "test-panel-uid",
|
||||
},
|
||||
"spec": map[string]any{
|
||||
"type": "text",
|
||||
"pluginVersion": "1.0.0",
|
||||
"title": "Test Library Panel",
|
||||
"panelTitle": "Test Panel Title",
|
||||
"description": "Test description",
|
||||
"options": map[string]interface{}{
|
||||
"content": "Test content",
|
||||
},
|
||||
"fieldConfig": map[string]interface{}{
|
||||
"defaults": map[string]interface{}{
|
||||
"color": map[string]interface{}{
|
||||
"mode": "palette-classic",
|
||||
},
|
||||
},
|
||||
},
|
||||
"gridPos": map[string]interface{}{
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
},
|
||||
"datasource": map[string]interface{}{
|
||||
"type": "testdata",
|
||||
"uid": "test-datasource",
|
||||
},
|
||||
"transparent": true,
|
||||
"links": []interface{}{
|
||||
map[string]interface{}{
|
||||
"title": "Test Link",
|
||||
"url": "https://example.com",
|
||||
},
|
||||
},
|
||||
"targets": []interface{}{
|
||||
map[string]interface{}{
|
||||
"refId": "A",
|
||||
"expr": "test_query",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
meta, err := utils.MetaAccessor(unstructuredObj)
|
||||
require.NoError(t, err)
|
||||
meta.SetFolder(testFolder.UID)
|
||||
meta.SetGeneration(2)
|
||||
creationTimestamp := metav1.NewTime(time.Now())
|
||||
meta.SetCreationTimestamp(creationTimestamp)
|
||||
meta.SetCreatedBy(testUser.UID)
|
||||
meta.SetDeprecatedInternalID(123) // nolint:staticcheck
|
||||
|
||||
reqContext := &contextmodel.ReqContext{
|
||||
Context: &web.Context{
|
||||
Req: httptest.NewRequest("GET", "/", nil).WithContext(context.Background()),
|
||||
},
|
||||
SignedInUser: &user.SignedInUser{
|
||||
UserID: 1,
|
||||
OrgID: 1,
|
||||
OrgRole: org.RoleAdmin,
|
||||
},
|
||||
}
|
||||
result, err := handler.unstructuredToLegacyLibraryPanelDTO(reqContext, *unstructuredObj)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, result)
|
||||
require.Equal(t, int64(123), result.ID)
|
||||
require.Equal(t, int64(1), result.OrgID)
|
||||
require.Equal(t, testFolder.UID, result.FolderUID)
|
||||
require.Equal(t, "test-panel-uid", result.UID)
|
||||
require.Equal(t, "Test Library Panel", result.Name)
|
||||
require.Equal(t, int64(model.PanelElement), result.Kind)
|
||||
require.Equal(t, "text", result.Type)
|
||||
require.Equal(t, "Test description", result.Description)
|
||||
require.Equal(t, int64(2), result.Version)
|
||||
require.Equal(t, testFolder.UID, result.Meta.FolderUID)
|
||||
require.Equal(t, testFolder.Title, result.Meta.FolderName)
|
||||
require.Equal(t, int64(1), result.Meta.ConnectedDashboards)
|
||||
require.Equal(t, int64(1), result.FolderID) // nolint:staticcheck
|
||||
require.Equal(t, creationTimestamp.Format(time.RFC3339), result.Meta.Created.Format(time.RFC3339))
|
||||
require.Equal(t, testUser.ID, result.Meta.CreatedBy.Id)
|
||||
require.Equal(t, testUser.Login, result.Meta.CreatedBy.Name)
|
||||
require.Equal(t, dtos.GetGravatarUrl(cfg, testUser.Email), result.Meta.CreatedBy.AvatarUrl)
|
||||
require.Equal(t, creationTimestamp.Format(time.RFC3339), result.Meta.Updated.Format(time.RFC3339))
|
||||
require.Equal(t, testUser.ID, result.Meta.UpdatedBy.Id)
|
||||
require.Equal(t, testUser.Login, result.Meta.UpdatedBy.Name)
|
||||
require.Equal(t, dtos.GetGravatarUrl(cfg, testUser.Email), result.Meta.UpdatedBy.AvatarUrl)
|
||||
|
||||
var modelMap map[string]interface{}
|
||||
err = json.Unmarshal(result.Model, &modelMap)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, "testdata", modelMap["datasource"].(map[string]interface{})["type"])
|
||||
require.Equal(t, "test-datasource", modelMap["datasource"].(map[string]interface{})["uid"])
|
||||
require.Equal(t, "Test description", modelMap["description"])
|
||||
require.Equal(t, float64(123), modelMap["id"])
|
||||
require.Equal(t, "text", modelMap["type"])
|
||||
require.Equal(t, "Test Panel Title", modelMap["title"])
|
||||
require.Equal(t, "Test content", modelMap["options"].(map[string]interface{})["content"])
|
||||
require.Equal(t, true, modelMap["transparent"])
|
||||
require.Equal(t, "Test Library Panel", modelMap["libraryPanel"].(map[string]interface{})["name"])
|
||||
require.Equal(t, "test-panel-uid", modelMap["libraryPanel"].(map[string]interface{})["uid"])
|
||||
links := modelMap["links"].([]interface{})
|
||||
require.Len(t, links, 1)
|
||||
require.Equal(t, "Test Link", links[0].(map[string]interface{})["title"])
|
||||
|
||||
targets := modelMap["targets"].([]interface{})
|
||||
require.Len(t, targets, 1)
|
||||
require.Equal(t, "A", targets[0].(map[string]interface{})["refId"])
|
||||
|
||||
dashboardsSvc.AssertExpectations(t)
|
||||
}
|
||||
@@ -9,14 +9,16 @@ import (
|
||||
"github.com/grafana/grafana/pkg/infra/db"
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
"github.com/grafana/grafana/pkg/services/accesscontrol"
|
||||
grafanaapiserver "github.com/grafana/grafana/pkg/services/apiserver"
|
||||
"github.com/grafana/grafana/pkg/services/dashboards"
|
||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||
"github.com/grafana/grafana/pkg/services/folder"
|
||||
"github.com/grafana/grafana/pkg/services/libraryelements/model"
|
||||
"github.com/grafana/grafana/pkg/services/user"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
)
|
||||
|
||||
func ProvideService(cfg *setting.Cfg, sqlStore db.DB, routeRegister routing.RouteRegister, folderService folder.Service, features featuremgmt.FeatureToggles, ac accesscontrol.AccessControl, dashboardsService dashboards.DashboardService) *LibraryElementService {
|
||||
func ProvideService(cfg *setting.Cfg, sqlStore db.DB, routeRegister routing.RouteRegister, folderService folder.Service, features featuremgmt.FeatureToggles, ac accesscontrol.AccessControl, dashboardsService dashboards.DashboardService, clientConfigProvider grafanaapiserver.DirectRestConfigProvider, userService user.Service) *LibraryElementService {
|
||||
l := &LibraryElementService{
|
||||
Cfg: cfg,
|
||||
SQLStore: sqlStore,
|
||||
@@ -26,6 +28,7 @@ func ProvideService(cfg *setting.Cfg, sqlStore db.DB, routeRegister routing.Rout
|
||||
log: log.New("library-elements"),
|
||||
features: features,
|
||||
AccessControl: ac,
|
||||
k8sHandler: newLibraryElementsK8sHandler(cfg, clientConfigProvider, folderService, userService, dashboardsService),
|
||||
}
|
||||
|
||||
l.registerAPIEndpoints()
|
||||
@@ -55,6 +58,7 @@ type LibraryElementService struct {
|
||||
log log.Logger
|
||||
features featuremgmt.FeatureToggles
|
||||
AccessControl accesscontrol.AccessControl
|
||||
k8sHandler *libraryElementsK8sHandler
|
||||
}
|
||||
|
||||
var _ Service = (*LibraryElementService)(nil)
|
||||
|
||||
Reference in New Issue
Block a user