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:
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user