From 4965cf2edae6eae8e341e6c93c3a1aa56417efb3 Mon Sep 17 00:00:00 2001 From: Ryan McKinley Date: Wed, 25 Jan 2023 11:10:16 -0800 Subject: [PATCH] k8s: add feature toggle and stub to save dashboards k8s (#62053) --- .../feature-toggles/index.md | 1 + .../src/types/featureToggles.gen.ts | 1 + pkg/cmd/grafana-cli/runner/wire.go | 8 +- pkg/server/wire.go | 8 +- .../dashboards/service/dashboard_service.go | 5 +- pkg/services/dashboards/service/service.go | 35 +++++++ pkg/services/featuremgmt/registry.go | 6 ++ pkg/services/featuremgmt/toggles_gen.go | 4 + pkg/services/featuremgmt/toggles_gen_test.go | 3 +- .../store/k8saccess/dashboard_service.go | 93 +++++++++++++++++++ 10 files changed, 154 insertions(+), 10 deletions(-) create mode 100644 pkg/services/dashboards/service/service.go create mode 100644 pkg/services/store/k8saccess/dashboard_service.go diff --git a/docs/sources/setup-grafana/configure-grafana/feature-toggles/index.md b/docs/sources/setup-grafana/configure-grafana/feature-toggles/index.md index 6dccb953693..783c9be869f 100644 --- a/docs/sources/setup-grafana/configure-grafana/feature-toggles/index.md +++ b/docs/sources/setup-grafana/configure-grafana/feature-toggles/index.md @@ -109,6 +109,7 @@ The following toggles require explicitly setting Grafana's [app mode]({{< relref | `showFeatureFlagsInUI` | Show feature flags in the settings UI | | `publicDashboardsEmailSharing` | Allows public dashboard sharing to be restricted to only allowed emails | | `k8s` | Explore native k8s integrations | +| `k8sDashboards` | Save dashboards via k8s | | `dashboardsFromStorage` | Load dashboards from the generic storage interface | | `export` | Export grafana instance (to git, etc) | | `azureMonitorResourcePickerForMetrics` | New UI for Azure Monitor Metrics Query | diff --git a/packages/grafana-data/src/types/featureToggles.gen.ts b/packages/grafana-data/src/types/featureToggles.gen.ts index 64b10278f96..aaf4f957601 100644 --- a/packages/grafana-data/src/types/featureToggles.gen.ts +++ b/packages/grafana-data/src/types/featureToggles.gen.ts @@ -43,6 +43,7 @@ export interface FeatureToggles { migrationLocking?: boolean; storage?: boolean; k8s?: boolean; + k8sDashboards?: boolean; supportBundles?: boolean; dashboardsFromStorage?: boolean; export?: boolean; diff --git a/pkg/cmd/grafana-cli/runner/wire.go b/pkg/cmd/grafana-cli/runner/wire.go index 42e6dc49d37..559a82139f4 100644 --- a/pkg/cmd/grafana-cli/runner/wire.go +++ b/pkg/cmd/grafana-cli/runner/wire.go @@ -251,11 +251,11 @@ var wireSet = wire.NewSet( teamguardianDatabase.ProvideTeamGuardianStore, wire.Bind(new(teamguardian.Store), new(*teamguardianDatabase.TeamGuardianStoreImpl)), teamguardianManager.ProvideService, - dashboardservice.ProvideDashboardService, + dashboardservice.ProvideDashboardService, //DashboardServiceImpl dashboardstore.ProvideDashboardStore, - wire.Bind(new(dashboards.DashboardService), new(*dashboardservice.DashboardServiceImpl)), - wire.Bind(new(dashboards.DashboardProvisioningService), new(*dashboardservice.DashboardServiceImpl)), - wire.Bind(new(dashboards.PluginService), new(*dashboardservice.DashboardServiceImpl)), + dashboardservice.ProvideSimpleDashboardService, + dashboardservice.ProvideDashboardProvisioningService, + dashboardservice.ProvideDashboardPluginService, wire.Bind(new(dashboards.Store), new(*dashboardstore.DashboardStore)), wire.Bind(new(dashboards.FolderStore), new(*dashboardstore.DashboardStore)), dashboardimportservice.ProvideService, diff --git a/pkg/server/wire.go b/pkg/server/wire.go index 875035f75b6..52898adfddf 100644 --- a/pkg/server/wire.go +++ b/pkg/server/wire.go @@ -287,12 +287,12 @@ var wireBasicSet = wire.NewSet( teamguardianManager.ProvideService, featuremgmt.ProvideManagerService, featuremgmt.ProvideToggles, - dashboardservice.ProvideDashboardService, + dashboardservice.ProvideDashboardService, // DashboardServiceImpl dashboardstore.ProvideDashboardStore, folderimpl.ProvideService, - wire.Bind(new(dashboards.DashboardService), new(*dashboardservice.DashboardServiceImpl)), - wire.Bind(new(dashboards.DashboardProvisioningService), new(*dashboardservice.DashboardServiceImpl)), - wire.Bind(new(dashboards.PluginService), new(*dashboardservice.DashboardServiceImpl)), + dashboardservice.ProvideSimpleDashboardService, + dashboardservice.ProvideDashboardProvisioningService, + dashboardservice.ProvideDashboardPluginService, wire.Bind(new(dashboards.Store), new(*dashboardstore.DashboardStore)), wire.Bind(new(dashboards.FolderStore), new(*dashboardstore.DashboardStore)), dashboardimportservice.ProvideService, diff --git a/pkg/services/dashboards/service/dashboard_service.go b/pkg/services/dashboards/service/dashboard_service.go index 01823757044..c5fc9833189 100644 --- a/pkg/services/dashboards/service/dashboard_service.go +++ b/pkg/services/dashboards/service/dashboard_service.go @@ -31,7 +31,9 @@ var ( {Action: dashboards.ActionDashboardsWrite, Scope: dashboards.ScopeFoldersAll}, } // DashboardServiceImpl implements the DashboardService interface - _ dashboards.DashboardService = (*DashboardServiceImpl)(nil) + _ dashboards.DashboardService = (*DashboardServiceImpl)(nil) + _ dashboards.DashboardProvisioningService = (*DashboardServiceImpl)(nil) + _ dashboards.PluginService = (*DashboardServiceImpl)(nil) ) type DashboardServiceImpl struct { @@ -46,6 +48,7 @@ type DashboardServiceImpl struct { ac accesscontrol.AccessControl } +// This is the uber service that implements a three smaller services func ProvideDashboardService( cfg *setting.Cfg, dashboardStore dashboards.Store, folderStore dashboards.FolderStore, dashAlertExtractor alerting.DashAlertExtractor, features featuremgmt.FeatureToggles, folderPermissionsService accesscontrol.FolderPermissionsService, diff --git a/pkg/services/dashboards/service/service.go b/pkg/services/dashboards/service/service.go new file mode 100644 index 00000000000..b5989c2d94c --- /dev/null +++ b/pkg/services/dashboards/service/service.go @@ -0,0 +1,35 @@ +package service + +import ( + "github.com/grafana/grafana/pkg/services/dashboards" + "github.com/grafana/grafana/pkg/services/featuremgmt" + "github.com/grafana/grafana/pkg/services/store/entity" + "github.com/grafana/grafana/pkg/services/store/k8saccess" +) + +func ProvideSimpleDashboardService( + features featuremgmt.FeatureToggles, + svc *DashboardServiceImpl, + k8s k8saccess.K8SAccess, + store entity.EntityStoreServer, +) dashboards.DashboardService { + if features.IsEnabled(featuremgmt.FlagK8sDashboards) { + if k8s.GetSystemClient() == nil { + panic("k8s dashboards requires the k8s client registered") + } + return k8saccess.NewDashboardService(svc, store) + } + return svc +} + +func ProvideDashboardProvisioningService( + features featuremgmt.FeatureToggles, orig *DashboardServiceImpl, +) dashboards.DashboardProvisioningService { + return orig +} + +func ProvideDashboardPluginService( + features featuremgmt.FeatureToggles, orig *DashboardServiceImpl, +) dashboards.PluginService { + return orig +} diff --git a/pkg/services/featuremgmt/registry.go b/pkg/services/featuremgmt/registry.go index 77d111cedf0..46df1ffbd58 100644 --- a/pkg/services/featuremgmt/registry.go +++ b/pkg/services/featuremgmt/registry.go @@ -154,6 +154,12 @@ var ( State: FeatureStateAlpha, RequiresDevMode: true, }, + { + Name: "k8sDashboards", + Description: "Save dashboards via k8s", + State: FeatureStateAlpha, + RequiresDevMode: true, + }, { Name: "supportBundles", Description: "Support bundles for troubleshooting", diff --git a/pkg/services/featuremgmt/toggles_gen.go b/pkg/services/featuremgmt/toggles_gen.go index 3ff5c49df92..825eba4df39 100644 --- a/pkg/services/featuremgmt/toggles_gen.go +++ b/pkg/services/featuremgmt/toggles_gen.go @@ -115,6 +115,10 @@ const ( // Explore native k8s integrations FlagK8s = "k8s" + // FlagK8sDashboards + // Save dashboards via k8s + FlagK8sDashboards = "k8sDashboards" + // FlagSupportBundles // Support bundles for troubleshooting FlagSupportBundles = "supportBundles" diff --git a/pkg/services/featuremgmt/toggles_gen_test.go b/pkg/services/featuremgmt/toggles_gen_test.go index 7951cd3be6c..147cdda2af0 100644 --- a/pkg/services/featuremgmt/toggles_gen_test.go +++ b/pkg/services/featuremgmt/toggles_gen_test.go @@ -25,7 +25,8 @@ func TestFeatureToggleFiles(t *testing.T) { "live-config": true, "live-pipeline": true, "live-service-web-worker": true, - "k8s": true, // Camle case does not like this one + "k8s": true, // Camel case does not like this one + "k8sDashboards": true, // or this one } t.Run("check registry constraints", func(t *testing.T) { diff --git a/pkg/services/store/k8saccess/dashboard_service.go b/pkg/services/store/k8saccess/dashboard_service.go new file mode 100644 index 00000000000..de1f93429ef --- /dev/null +++ b/pkg/services/store/k8saccess/dashboard_service.go @@ -0,0 +1,93 @@ +package k8saccess + +import ( + "context" + "fmt" + + "github.com/grafana/grafana/pkg/models" + "github.com/grafana/grafana/pkg/services/dashboards" + "github.com/grafana/grafana/pkg/services/store/entity" +) + +type k8sDashboardService struct { + orig dashboards.DashboardService + store entity.EntityStoreServer +} + +var _ dashboards.DashboardService = (*k8sDashboardService)(nil) + +func NewDashboardService(orig dashboards.DashboardService, store entity.EntityStoreServer) dashboards.DashboardService { + return &k8sDashboardService{ + orig: orig, + store: store, + } +} + +func (s *k8sDashboardService) BuildSaveDashboardCommand(ctx context.Context, dto *dashboards.SaveDashboardDTO, shouldValidateAlerts bool, validateProvisionedDashboard bool) (*dashboards.SaveDashboardCommand, error) { + return s.orig.BuildSaveDashboardCommand(ctx, dto, shouldValidateAlerts, validateProvisionedDashboard) +} + +func (s *k8sDashboardService) DeleteDashboard(ctx context.Context, dashboardId int64, orgId int64) error { + return s.orig.DeleteDashboard(ctx, dashboardId, orgId) +} + +func (s *k8sDashboardService) FindDashboards(ctx context.Context, query *models.FindPersistedDashboardsQuery) ([]dashboards.DashboardSearchProjection, error) { + return s.orig.FindDashboards(ctx, query) +} + +func (s *k8sDashboardService) GetDashboard(ctx context.Context, query *dashboards.GetDashboardQuery) error { + return s.orig.GetDashboard(ctx, query) +} + +func (s *k8sDashboardService) GetDashboardACLInfoList(ctx context.Context, query *dashboards.GetDashboardACLInfoListQuery) error { + return s.orig.GetDashboardACLInfoList(ctx, query) +} + +func (s *k8sDashboardService) GetDashboards(ctx context.Context, query *dashboards.GetDashboardsQuery) error { + return s.orig.GetDashboards(ctx, query) +} + +func (s *k8sDashboardService) GetDashboardTags(ctx context.Context, query *dashboards.GetDashboardTagsQuery) error { + return s.orig.GetDashboardTags(ctx, query) +} + +func (s *k8sDashboardService) GetDashboardUIDByID(ctx context.Context, query *dashboards.GetDashboardRefByIDQuery) error { + return s.orig.GetDashboardUIDByID(ctx, query) +} + +func (s *k8sDashboardService) HasAdminPermissionInDashboardsOrFolders(ctx context.Context, query *models.HasAdminPermissionInDashboardsOrFoldersQuery) error { + return s.orig.HasAdminPermissionInDashboardsOrFolders(ctx, query) +} + +func (s *k8sDashboardService) HasEditPermissionInFolders(ctx context.Context, query *models.HasEditPermissionInFoldersQuery) error { + return s.orig.HasEditPermissionInFolders(ctx, query) +} + +func (s *k8sDashboardService) ImportDashboard(ctx context.Context, dto *dashboards.SaveDashboardDTO) (*dashboards.Dashboard, error) { + return s.orig.ImportDashboard(ctx, dto) +} + +func (s *k8sDashboardService) MakeUserAdmin(ctx context.Context, orgID int64, userID, dashboardID int64, setViewAndEditPermissions bool) error { + return s.orig.MakeUserAdmin(ctx, orgID, userID, dashboardID, setViewAndEditPermissions) +} + +func (s *k8sDashboardService) SaveDashboard(ctx context.Context, dto *dashboards.SaveDashboardDTO, allowUiUpdate bool) (*dashboards.Dashboard, error) { + fmt.Printf("SAVE: " + dto.Dashboard.UID) + return s.orig.SaveDashboard(ctx, dto, allowUiUpdate) +} + +func (s *k8sDashboardService) SearchDashboards(ctx context.Context, query *models.FindPersistedDashboardsQuery) error { + return s.orig.SearchDashboards(ctx, query) +} + +func (s *k8sDashboardService) UpdateDashboardACL(ctx context.Context, uid int64, items []*dashboards.DashboardACL) error { + return s.orig.UpdateDashboardACL(ctx, uid, items) +} + +func (s *k8sDashboardService) DeleteACLByUser(ctx context.Context, userID int64) error { + return s.orig.DeleteACLByUser(ctx, userID) +} + +func (s *k8sDashboardService) CountDashboardsInFolder(ctx context.Context, query *dashboards.CountDashboardsInFolderQuery) (int64, error) { + return s.orig.CountDashboardsInFolder(ctx, query) +}