provisioning: Warns the user when uid or title is re-used. (#10892)

* provisioning: Warns the user when uid or title is re-used.

Closes #10880
This commit is contained in:
Leonard Gram
2018-02-13 15:47:02 +01:00
committed by GitHub
parent d31e333e7e
commit ba0285a3ec
2 changed files with 70 additions and 11 deletions
@@ -124,37 +124,48 @@ func (fr *fileReader) startWalkingDisk() error {
}
}
sanityChecker := newProvisioningSanityChecker(fr.Cfg.Name)
// save dashboards based on json files
for path, fileInfo := range filesFoundOnDisk {
err = fr.saveDashboard(path, folderId, fileInfo, provisionedDashboardRefs)
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) error {
func (fr *fileReader) saveDashboard(path string, folderId int64, fileInfo os.FileInfo, provisionedDashboardRefs map[string]*models.DashboardProvisioning) (provisioningMetadata, error) {
provisioningMetadata := provisioningMetadata{}
resolvedFileInfo, err := resolveSymlink(fileInfo, path)
if err != nil {
return err
return provisioningMetadata, err
}
provisionedData, alreadyProvisioned := provisionedDashboardRefs[path]
if alreadyProvisioned && provisionedData.Updated.Unix() == resolvedFileInfo.ModTime().Unix() {
return nil // dashboard is already in sync with the database
}
upToDate := alreadyProvisioned && provisionedData.Updated.Unix() == resolvedFileInfo.ModTime().Unix()
dash, err := fr.readDashboardFromFile(path, resolvedFileInfo.ModTime(), folderId)
if err != nil {
fr.log.Error("failed to load dashboard from ", "file", path, "error", err)
return nil
return provisioningMetadata, nil
}
// keeps track of what uid's and title's we have already provisioned
provisioningMetadata.uid = dash.Dashboard.Uid
provisioningMetadata.title = dash.Dashboard.Title
if upToDate {
return provisioningMetadata, nil
}
if dash.Dashboard.Id != 0 {
fr.log.Error("provisioned dashboard json files cannot contain id")
return nil
return provisioningMetadata, nil
}
if alreadyProvisioned {
@@ -164,7 +175,7 @@ func (fr *fileReader) saveDashboard(path string, folderId int64, fileInfo os.Fil
fr.log.Debug("saving new dashboard", "file", path)
dp := &models.DashboardProvisioning{ExternalId: path, Name: fr.Cfg.Name, Updated: resolvedFileInfo.ModTime()}
_, err = fr.dashboardRepo.SaveProvisionedDashboard(dash, dp)
return err
return provisioningMetadata, err
}
func getProvisionedDashboardByPath(repo dashboards.Repository, name string) (map[string]*models.DashboardProvisioning, error) {
@@ -280,3 +291,46 @@ func (fr *fileReader) readDashboardFromFile(path string, lastModified time.Time,
return dash, nil
}
type provisioningMetadata struct {
uid string
title string
}
func newProvisioningSanityChecker(provisioningProvider string) provisioningSanityChecker {
return provisioningSanityChecker{
provisioningProvider: provisioningProvider,
uidUsage: map[string]uint8{},
titleUsage: map[string]uint8{}}
}
type provisioningSanityChecker struct {
provisioningProvider string
uidUsage map[string]uint8
titleUsage map[string]uint8
}
func (checker provisioningSanityChecker) track(pm provisioningMetadata) {
if len(pm.uid) > 0 {
checker.uidUsage[pm.uid] += 1
}
if len(pm.title) > 0 {
checker.titleUsage[pm.title] += 1
}
}
func (checker provisioningSanityChecker) logWarnings(log log.Logger) {
for uid, times := range checker.uidUsage {
if times > 1 {
log.Error("the same 'uid' is used more than once", "uid", uid, "provider", checker.provisioningProvider)
}
}
for title, times := range checker.titleUsage {
if times > 1 {
log.Error("the same 'title' is used more than once", "title", title, "provider", checker.provisioningProvider)
}
}
}