Browse Source

Merge pull request #10910 from bergquist/provisioning_disable_deleting_dashboards

provisioning: adds setting to disable dashboard deletes
Carl Bergquist 7 years ago
parent
commit
243b987758

+ 4 - 1
docs/sources/administration/provisioning.md

@@ -184,11 +184,14 @@ providers:
   orgId: 1
   folder: ''
   type: file
+  disableDeletion: false
+  editable: false
   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.
+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
 > which leads to problems if you re-use settings that are supposed to be unique.

+ 3 - 0
pkg/services/provisioning/dashboards/config_reader_test.go

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

+ 21 - 15
pkg/services/provisioning/dashboards/file_reader.go

@@ -105,6 +105,27 @@ func (fr *fileReader) startWalkingDisk() error {
 		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
 	var dashboardToDelete []int64
 	for path, provisioningData := range provisionedDashboardRefs {
@@ -113,7 +134,6 @@ func (fr *fileReader) startWalkingDisk() error {
 			dashboardToDelete = append(dashboardToDelete, provisioningData.DashboardId)
 		}
 	}
-
 	// delete dashboard that are missing json file
 	for _, dashboardId := range dashboardToDelete {
 		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)
 		}
 	}
-
-	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) {

+ 1 - 0
pkg/services/provisioning/dashboards/test-configs/dashboards-from-disk/dev-dashboards.yaml

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

+ 1 - 0
pkg/services/provisioning/dashboards/test-configs/version-0/version-0.yaml

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

+ 35 - 30
pkg/services/provisioning/dashboards/types.go

@@ -10,21 +10,23 @@ import (
 )
 
 type DashboardsAsConfig struct {
-	Name     string
-	Type     string
-	OrgId    int64
-	Folder   string
-	Editable bool
-	Options  map[string]interface{}
+	Name            string
+	Type            string
+	OrgId           int64
+	Folder          string
+	Editable        bool
+	Options         map[string]interface{}
+	DisableDeletion bool
 }
 
 type DashboardsAsConfigV0 struct {
-	Name     string                 `json:"name" yaml:"name"`
-	Type     string                 `json:"type" yaml:"type"`
-	OrgId    int64                  `json:"org_id" yaml:"org_id"`
-	Folder   string                 `json:"folder" yaml:"folder"`
-	Editable bool                   `json:"editable" yaml:"editable"`
-	Options  map[string]interface{} `json:"options" yaml:"options"`
+	Name            string                 `json:"name" yaml:"name"`
+	Type            string                 `json:"type" yaml:"type"`
+	OrgId           int64                  `json:"org_id" yaml:"org_id"`
+	Folder          string                 `json:"folder" yaml:"folder"`
+	Editable        bool                   `json:"editable" yaml:"editable"`
+	Options         map[string]interface{} `json:"options" yaml:"options"`
+	DisableDeletion bool                   `json:"disableDeletion" yaml:"disableDeletion"`
 }
 
 type ConfigVersion struct {
@@ -36,12 +38,13 @@ type DashboardAsConfigV1 struct {
 }
 
 type DashboardProviderConfigs struct {
-	Name     string                 `json:"name" yaml:"name"`
-	Type     string                 `json:"type" yaml:"type"`
-	OrgId    int64                  `json:"orgId" yaml:"orgId"`
-	Folder   string                 `json:"folder" yaml:"folder"`
-	Editable bool                   `json:"editable" yaml:"editable"`
-	Options  map[string]interface{} `json:"options" yaml:"options"`
+	Name            string                 `json:"name" yaml:"name"`
+	Type            string                 `json:"type" yaml:"type"`
+	OrgId           int64                  `json:"orgId" yaml:"orgId"`
+	Folder          string                 `json:"folder" yaml:"folder"`
+	Editable        bool                   `json:"editable" yaml:"editable"`
+	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) {
@@ -68,12 +71,13 @@ func mapV0ToDashboardAsConfig(v0 []*DashboardsAsConfigV0) []*DashboardsAsConfig
 
 	for _, v := range v0 {
 		r = append(r, &DashboardsAsConfig{
-			Name:     v.Name,
-			Type:     v.Type,
-			OrgId:    v.OrgId,
-			Folder:   v.Folder,
-			Editable: v.Editable,
-			Options:  v.Options,
+			Name:            v.Name,
+			Type:            v.Type,
+			OrgId:           v.OrgId,
+			Folder:          v.Folder,
+			Editable:        v.Editable,
+			Options:         v.Options,
+			DisableDeletion: v.DisableDeletion,
 		})
 	}
 
@@ -85,12 +89,13 @@ func (dc *DashboardAsConfigV1) mapToDashboardAsConfig() []*DashboardsAsConfig {
 
 	for _, v := range dc.Providers {
 		r = append(r, &DashboardsAsConfig{
-			Name:     v.Name,
-			Type:     v.Type,
-			OrgId:    v.OrgId,
-			Folder:   v.Folder,
-			Editable: v.Editable,
-			Options:  v.Options,
+			Name:            v.Name,
+			Type:            v.Type,
+			OrgId:           v.OrgId,
+			Folder:          v.Folder,
+			Editable:        v.Editable,
+			Options:         v.Options,
+			DisableDeletion: v.DisableDeletion,
 		})
 	}