provisioning: adds setting to disable dashboard deletes

pull/10910/head
bergquist 8 years ago
parent 1a041a2250
commit ad42883fc7
  1. 5
      docs/sources/administration/provisioning.md
  2. 3
      pkg/services/provisioning/dashboards/config_reader_test.go
  3. 36
      pkg/services/provisioning/dashboards/file_reader.go
  4. 1
      pkg/services/provisioning/dashboards/test-configs/dashboards-from-disk/dev-dashboards.yaml
  5. 1
      pkg/services/provisioning/dashboards/test-configs/version-0/version-0.yaml
  6. 65
      pkg/services/provisioning/dashboards/types.go

@ -184,11 +184,14 @@ providers:
orgId: 1 orgId: 1
folder: '' folder: ''
type: file type: file
disableDeletion: false
editable: false
options: options:
folder: /var/lib/grafana/dashboards path: /var/lib/grafana/dashboards
``` ```
When Grafana starts, it will update/insert all dashboards available in the configured folders. If you modify the file, the dashboard will also be updated. When Grafana starts, it will update/insert all dashboards available in the configured folders. If you modify the file, the dashboard will also be updated.
By default Grafana will delete dashboards in the database if the file is removed. You can disable this behavior using the `disableDeletion` setting.
> **Note.** Provisioning allows you to overwrite existing dashboards > **Note.** Provisioning allows you to overwrite existing dashboards
> which leads to problems if you re-use settings that are supposed to be unique. > which leads to problems if you re-use settings that are supposed to be unique.

@ -67,6 +67,8 @@ func validateDashboardAsConfig(cfg []*DashboardsAsConfig) {
So(ds.Editable, ShouldBeTrue) So(ds.Editable, ShouldBeTrue)
So(len(ds.Options), ShouldEqual, 1) So(len(ds.Options), ShouldEqual, 1)
So(ds.Options["path"], ShouldEqual, "/var/lib/grafana/dashboards") So(ds.Options["path"], ShouldEqual, "/var/lib/grafana/dashboards")
So(ds.DisableDeletion, ShouldBeTrue)
ds2 := cfg[1] ds2 := cfg[1]
So(ds2.Name, ShouldEqual, "default") So(ds2.Name, ShouldEqual, "default")
So(ds2.Type, ShouldEqual, "file") So(ds2.Type, ShouldEqual, "file")
@ -75,4 +77,5 @@ func validateDashboardAsConfig(cfg []*DashboardsAsConfig) {
So(ds2.Editable, ShouldBeFalse) So(ds2.Editable, ShouldBeFalse)
So(len(ds2.Options), ShouldEqual, 1) So(len(ds2.Options), ShouldEqual, 1)
So(ds2.Options["path"], ShouldEqual, "/var/lib/grafana/dashboards") So(ds2.Options["path"], ShouldEqual, "/var/lib/grafana/dashboards")
So(ds2.DisableDeletion, ShouldBeFalse)
} }

@ -105,6 +105,27 @@ func (fr *fileReader) startWalkingDisk() error {
return err return err
} }
fr.deleteDashboardIfFileIsMissing(provisionedDashboardRefs, filesFoundOnDisk)
sanityChecker := newProvisioningSanityChecker(fr.Cfg.Name)
// save dashboards based on json files
for path, fileInfo := range filesFoundOnDisk {
provisioningMetadata, err := fr.saveDashboard(path, folderId, fileInfo, provisionedDashboardRefs)
sanityChecker.track(provisioningMetadata)
if err != nil {
fr.log.Error("failed to save dashboard", "error", err)
}
}
sanityChecker.logWarnings(fr.log)
return nil
}
func (fr *fileReader) deleteDashboardIfFileIsMissing(provisionedDashboardRefs map[string]*models.DashboardProvisioning, filesFoundOnDisk map[string]os.FileInfo) {
if fr.Cfg.DisableDeletion {
return
}
// find dashboards to delete since json file is missing // find dashboards to delete since json file is missing
var dashboardToDelete []int64 var dashboardToDelete []int64
for path, provisioningData := range provisionedDashboardRefs { for path, provisioningData := range provisionedDashboardRefs {
@ -113,7 +134,6 @@ func (fr *fileReader) startWalkingDisk() error {
dashboardToDelete = append(dashboardToDelete, provisioningData.DashboardId) dashboardToDelete = append(dashboardToDelete, provisioningData.DashboardId)
} }
} }
// delete dashboard that are missing json file // delete dashboard that are missing json file
for _, dashboardId := range dashboardToDelete { for _, dashboardId := range dashboardToDelete {
fr.log.Debug("deleting provisioned dashboard. missing on disk", "id", dashboardId) fr.log.Debug("deleting provisioned dashboard. missing on disk", "id", dashboardId)
@ -123,20 +143,6 @@ func (fr *fileReader) startWalkingDisk() error {
fr.log.Error("failed to delete dashboard", "id", cmd.Id) fr.log.Error("failed to delete dashboard", "id", cmd.Id)
} }
} }
sanityChecker := newProvisioningSanityChecker(fr.Cfg.Name)
// save dashboards based on json files
for path, fileInfo := range filesFoundOnDisk {
provisioningMetadata, err := fr.saveDashboard(path, folderId, fileInfo, provisionedDashboardRefs)
sanityChecker.track(provisioningMetadata)
if err != nil {
fr.log.Error("failed to save dashboard", "error", err)
}
}
sanityChecker.logWarnings(fr.log)
return nil
} }
func (fr *fileReader) saveDashboard(path string, folderId int64, fileInfo os.FileInfo, provisionedDashboardRefs map[string]*models.DashboardProvisioning) (provisioningMetadata, error) { func (fr *fileReader) saveDashboard(path string, folderId int64, fileInfo os.FileInfo, provisionedDashboardRefs map[string]*models.DashboardProvisioning) (provisioningMetadata, error) {

@ -5,6 +5,7 @@ providers:
orgId: 2 orgId: 2
folder: 'developers' folder: 'developers'
editable: true editable: true
disableDeletion: true
type: file type: file
options: options:
path: /var/lib/grafana/dashboards path: /var/lib/grafana/dashboards

@ -2,6 +2,7 @@
org_id: 2 org_id: 2
folder: 'developers' folder: 'developers'
editable: true editable: true
disableDeletion: true
type: file type: file
options: options:
path: /var/lib/grafana/dashboards path: /var/lib/grafana/dashboards

@ -10,21 +10,23 @@ import (
) )
type DashboardsAsConfig struct { type DashboardsAsConfig struct {
Name string Name string
Type string Type string
OrgId int64 OrgId int64
Folder string Folder string
Editable bool Editable bool
Options map[string]interface{} Options map[string]interface{}
DisableDeletion bool
} }
type DashboardsAsConfigV0 struct { type DashboardsAsConfigV0 struct {
Name string `json:"name" yaml:"name"` Name string `json:"name" yaml:"name"`
Type string `json:"type" yaml:"type"` Type string `json:"type" yaml:"type"`
OrgId int64 `json:"org_id" yaml:"org_id"` OrgId int64 `json:"org_id" yaml:"org_id"`
Folder string `json:"folder" yaml:"folder"` Folder string `json:"folder" yaml:"folder"`
Editable bool `json:"editable" yaml:"editable"` Editable bool `json:"editable" yaml:"editable"`
Options map[string]interface{} `json:"options" yaml:"options"` Options map[string]interface{} `json:"options" yaml:"options"`
DisableDeletion bool `json:"disableDeletion" yaml:"disableDeletion"`
} }
type ConfigVersion struct { type ConfigVersion struct {
@ -36,12 +38,13 @@ type DashboardAsConfigV1 struct {
} }
type DashboardProviderConfigs struct { type DashboardProviderConfigs struct {
Name string `json:"name" yaml:"name"` Name string `json:"name" yaml:"name"`
Type string `json:"type" yaml:"type"` Type string `json:"type" yaml:"type"`
OrgId int64 `json:"orgId" yaml:"orgId"` OrgId int64 `json:"orgId" yaml:"orgId"`
Folder string `json:"folder" yaml:"folder"` Folder string `json:"folder" yaml:"folder"`
Editable bool `json:"editable" yaml:"editable"` Editable bool `json:"editable" yaml:"editable"`
Options map[string]interface{} `json:"options" yaml:"options"` Options map[string]interface{} `json:"options" yaml:"options"`
DisableDeletion bool `json:"disableDeletion" yaml:"disableDeletion"`
} }
func createDashboardJson(data *simplejson.Json, lastModified time.Time, cfg *DashboardsAsConfig, folderId int64) (*dashboards.SaveDashboardDTO, error) { func createDashboardJson(data *simplejson.Json, lastModified time.Time, cfg *DashboardsAsConfig, folderId int64) (*dashboards.SaveDashboardDTO, error) {
@ -68,12 +71,13 @@ func mapV0ToDashboardAsConfig(v0 []*DashboardsAsConfigV0) []*DashboardsAsConfig
for _, v := range v0 { for _, v := range v0 {
r = append(r, &DashboardsAsConfig{ r = append(r, &DashboardsAsConfig{
Name: v.Name, Name: v.Name,
Type: v.Type, Type: v.Type,
OrgId: v.OrgId, OrgId: v.OrgId,
Folder: v.Folder, Folder: v.Folder,
Editable: v.Editable, Editable: v.Editable,
Options: v.Options, Options: v.Options,
DisableDeletion: v.DisableDeletion,
}) })
} }
@ -85,12 +89,13 @@ func (dc *DashboardAsConfigV1) mapToDashboardAsConfig() []*DashboardsAsConfig {
for _, v := range dc.Providers { for _, v := range dc.Providers {
r = append(r, &DashboardsAsConfig{ r = append(r, &DashboardsAsConfig{
Name: v.Name, Name: v.Name,
Type: v.Type, Type: v.Type,
OrgId: v.OrgId, OrgId: v.OrgId,
Folder: v.Folder, Folder: v.Folder,
Editable: v.Editable, Editable: v.Editable,
Options: v.Options, Options: v.Options,
DisableDeletion: v.DisableDeletion,
}) })
} }

Loading…
Cancel
Save