Commit 243b9877 by Carl Bergquist Committed by GitHub

Merge pull request #10910 from bergquist/provisioning_disable_deleting_dashboards

provisioning: adds setting to disable dashboard deletes
parents 842f4c1d ad42883f
...@@ -184,11 +184,14 @@ providers: ...@@ -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) { ...@@ -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) { ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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: ...@@ -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 @@ ...@@ -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
......
...@@ -16,6 +16,7 @@ type DashboardsAsConfig struct { ...@@ -16,6 +16,7 @@ type DashboardsAsConfig struct {
Folder string Folder string
Editable bool Editable bool
Options map[string]interface{} Options map[string]interface{}
DisableDeletion bool
} }
type DashboardsAsConfigV0 struct { type DashboardsAsConfigV0 struct {
...@@ -25,6 +26,7 @@ type DashboardsAsConfigV0 struct { ...@@ -25,6 +26,7 @@ type DashboardsAsConfigV0 struct {
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 {
...@@ -42,6 +44,7 @@ type DashboardProviderConfigs struct { ...@@ -42,6 +44,7 @@ type DashboardProviderConfigs struct {
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) {
...@@ -74,6 +77,7 @@ func mapV0ToDashboardAsConfig(v0 []*DashboardsAsConfigV0) []*DashboardsAsConfig ...@@ -74,6 +77,7 @@ func mapV0ToDashboardAsConfig(v0 []*DashboardsAsConfigV0) []*DashboardsAsConfig
Folder: v.Folder, Folder: v.Folder,
Editable: v.Editable, Editable: v.Editable,
Options: v.Options, Options: v.Options,
DisableDeletion: v.DisableDeletion,
}) })
} }
...@@ -91,6 +95,7 @@ func (dc *DashboardAsConfigV1) mapToDashboardAsConfig() []*DashboardsAsConfig { ...@@ -91,6 +95,7 @@ func (dc *DashboardAsConfigV1) mapToDashboardAsConfig() []*DashboardsAsConfig {
Folder: v.Folder, Folder: v.Folder,
Editable: v.Editable, Editable: v.Editable,
Options: v.Options, Options: v.Options,
DisableDeletion: v.DisableDeletion,
}) })
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment