mirror of https://github.com/grafana/grafana.git
				
				
				
			feat(apps): auto update dashboard dashboards, #5529
This commit is contained in:
		
							parent
							
								
									4545b4d323
								
							
						
					
					
						commit
						b62f1f00cd
					
				|  | @ -20,6 +20,7 @@ type PluginSetting struct { | |||
| 	Pinned         bool | ||||
| 	JsonData       map[string]interface{} | ||||
| 	SecureJsonData SecureJsonData | ||||
| 	PluginVersion  string | ||||
| 
 | ||||
| 	Created time.Time | ||||
| 	Updated time.Time | ||||
|  | @ -44,11 +45,19 @@ type UpdatePluginSettingCmd struct { | |||
| 	Pinned         bool                   `json:"pinned"` | ||||
| 	JsonData       map[string]interface{} `json:"jsonData"` | ||||
| 	SecureJsonData map[string]string      `json:"secureJsonData"` | ||||
| 	PluginVersion  string                 `json:"version"` | ||||
| 
 | ||||
| 	PluginId string `json:"-"` | ||||
| 	OrgId    int64  `json:"-"` | ||||
| } | ||||
| 
 | ||||
| // specific command, will only update version
 | ||||
| type UpdatePluginSettingVersionCmd struct { | ||||
| 	PluginVersion string | ||||
| 	PluginId      string `json:"-"` | ||||
| 	OrgId         int64  `json:"-"` | ||||
| } | ||||
| 
 | ||||
| func (cmd *UpdatePluginSettingCmd) GetEncryptedJsonData() SecureJsonData { | ||||
| 	encrypted := make(SecureJsonData) | ||||
| 	for key, data := range cmd.SecureJsonData { | ||||
|  | @ -69,6 +78,7 @@ type PluginSettingInfoDTO struct { | |||
| 	PluginId      string | ||||
| 	Enabled       bool | ||||
| 	Pinned        bool | ||||
| 	PluginVersion string | ||||
| } | ||||
| 
 | ||||
| type GetPluginSettingByIdQuery struct { | ||||
|  |  | |||
|  | @ -0,0 +1,88 @@ | |||
| package plugins | ||||
| 
 | ||||
| import ( | ||||
| 	"time" | ||||
| 
 | ||||
| 	"github.com/grafana/grafana/pkg/bus" | ||||
| 	m "github.com/grafana/grafana/pkg/models" | ||||
| ) | ||||
| 
 | ||||
| func updateAppDashboards() { | ||||
| 	time.Sleep(time.Second * 1) | ||||
| 
 | ||||
| 	plog.Debug("Looking for App Dashboard Updates") | ||||
| 
 | ||||
| 	query := m.GetPluginSettingsQuery{OrgId: 0} | ||||
| 
 | ||||
| 	if err := bus.Dispatch(&query); err != nil { | ||||
| 		plog.Error("Failed to get all plugin settings", "error", err) | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	for _, pluginSetting := range query.Result { | ||||
| 		if appDef, exist := Apps[pluginSetting.PluginId]; exist { | ||||
| 			if appDef.Info.Version != pluginSetting.PluginVersion { | ||||
| 				handleAppPluginUpdated(appDef, pluginSetting.OrgId) | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func autoUpdateAppDashboard(pluginDashInfo *PluginDashboardInfoDTO, orgId int64) error { | ||||
| 	if dash, err := loadPluginDashboard(pluginDashInfo.PluginId, pluginDashInfo.Path); err != nil { | ||||
| 		return err | ||||
| 	} else { | ||||
| 		plog.Info("Auto updating App dashboard", "dashboard", dash.Title, "newRev", pluginDashInfo.Revision, "oldRev", pluginDashInfo.ImportedRevision) | ||||
| 		updateCmd := ImportDashboardCommand{ | ||||
| 			OrgId:     orgId, | ||||
| 			PluginId:  pluginDashInfo.PluginId, | ||||
| 			Overwrite: true, | ||||
| 			Dashboard: dash.Data, | ||||
| 			UserId:    0, | ||||
| 			Path:      pluginDashInfo.Path, | ||||
| 		} | ||||
| 
 | ||||
| 		if err := bus.Dispatch(&updateCmd); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| func handleAppPluginUpdated(appDef *AppPlugin, orgId int64) { | ||||
| 	plog.Info("App update detected", "pluginId", appDef.Id) | ||||
| 
 | ||||
| 	// Get plugin dashboards
 | ||||
| 	if dashboards, err := GetPluginDashboards(orgId, appDef.Id); err != nil { | ||||
| 		plog.Error("Failed to load app dashboards", "error", err) | ||||
| 		return | ||||
| 	} else { | ||||
| 		// Update dashboards with updated revisions
 | ||||
| 		for _, dash := range dashboards { | ||||
| 			if dash.ImportedRevision != dash.Revision { | ||||
| 				if err := autoUpdateAppDashboard(dash, orgId); err != nil { | ||||
| 					plog.Error("Failed to auto update app dashboard", "pluginId", appDef.Id, "error", err) | ||||
| 					return | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	// update version in plugin_setting table to mark that we have processed the update
 | ||||
| 	query := m.GetPluginSettingByIdQuery{PluginId: appDef.Id, OrgId: orgId} | ||||
| 	if err := bus.Dispatch(&query); err != nil { | ||||
| 		plog.Error("Failed to read plugin setting by id", "error", err) | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	appSetting := query.Result | ||||
| 	cmd := m.UpdatePluginSettingVersionCmd{ | ||||
| 		OrgId:         appSetting.OrgId, | ||||
| 		PluginId:      appSetting.PluginId, | ||||
| 		PluginVersion: appDef.Info.Version, | ||||
| 	} | ||||
| 
 | ||||
| 	if err := bus.Dispatch(&cmd); err != nil { | ||||
| 		plog.Error("Failed to update plugin setting version", "error", err) | ||||
| 	} | ||||
| } | ||||
|  | @ -77,6 +77,8 @@ func Init() error { | |||
| 	} | ||||
| 
 | ||||
| 	go StartPluginUpdateChecker() | ||||
| 	go updateAppDashboards() | ||||
| 
 | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -26,4 +26,10 @@ func addAppSettingsMigration(mg *Migrator) { | |||
| 
 | ||||
| 	//-------  indexes ------------------
 | ||||
| 	addTableIndicesMigrations(mg, "v1", pluginSettingTable) | ||||
| 
 | ||||
| 	// add column to store installed version
 | ||||
| 	mg.AddMigration("Add column plugin_version to plugin_settings", NewAddColumnMigration(pluginSettingTable, &Column{ | ||||
| 		Name: "plugin_version", Type: DB_NVarchar, Nullable: true, Length: 50, | ||||
| 	})) | ||||
| 
 | ||||
| } | ||||
|  |  | |||
|  | @ -13,14 +13,20 @@ func init() { | |||
| 	bus.AddHandler("sql", GetPluginSettings) | ||||
| 	bus.AddHandler("sql", GetPluginSettingById) | ||||
| 	bus.AddHandler("sql", UpdatePluginSetting) | ||||
| 	bus.AddHandler("sql", UpdatePluginSettingVersion) | ||||
| } | ||||
| 
 | ||||
| func GetPluginSettings(query *m.GetPluginSettingsQuery) error { | ||||
| 	sql := `SELECT org_id, plugin_id, enabled, pinned | ||||
| 					FROM plugin_setting | ||||
| 					WHERE org_id=?` | ||||
| 	sql := `SELECT org_id, plugin_id, enabled, pinned, plugin_version | ||||
| 					FROM plugin_setting ` | ||||
| 	params := make([]interface{}, 0) | ||||
| 
 | ||||
| 	sess := x.Sql(sql, query.OrgId) | ||||
| 	if query.OrgId != 0 { | ||||
| 		sql += "WHERE org_id=?" | ||||
| 		params = append(params, query.OrgId) | ||||
| 	} | ||||
| 
 | ||||
| 	sess := x.Sql(sql, params...) | ||||
| 	query.Result = make([]*m.PluginSettingInfoDTO, 0) | ||||
| 	return sess.Find(&query.Result) | ||||
| } | ||||
|  | @ -51,6 +57,7 @@ func UpdatePluginSetting(cmd *m.UpdatePluginSettingCmd) error { | |||
| 				Enabled:        cmd.Enabled, | ||||
| 				Pinned:         cmd.Pinned, | ||||
| 				JsonData:       cmd.JsonData, | ||||
| 				PluginVersion:  cmd.PluginVersion, | ||||
| 				SecureJsonData: cmd.GetEncryptedJsonData(), | ||||
| 				Created:        time.Now(), | ||||
| 				Updated:        time.Now(), | ||||
|  | @ -65,8 +72,18 @@ func UpdatePluginSetting(cmd *m.UpdatePluginSettingCmd) error { | |||
| 			pluginSetting.Enabled = cmd.Enabled | ||||
| 			pluginSetting.JsonData = cmd.JsonData | ||||
| 			pluginSetting.Pinned = cmd.Pinned | ||||
| 			pluginSetting.PluginVersion = cmd.PluginVersion | ||||
| 			_, err = sess.Id(pluginSetting.Id).Update(&pluginSetting) | ||||
| 			return err | ||||
| 		} | ||||
| 	}) | ||||
| } | ||||
| 
 | ||||
| func UpdatePluginSettingVersion(cmd *m.UpdatePluginSettingVersionCmd) error { | ||||
| 	return inTransaction2(func(sess *session) error { | ||||
| 
 | ||||
| 		_, err := sess.Exec("UPDATE plugin_setting SET plugin_version=? WHERE org_id=? AND plugin_id=?", cmd.PluginVersion, cmd.OrgId, cmd.PluginId) | ||||
| 		return err | ||||
| 
 | ||||
| 	}) | ||||
| } | ||||
|  |  | |||
|  | @ -14,9 +14,8 @@ | |||
| 					</span> | ||||
| 				</td> | ||||
| 				<td> | ||||
| 					v{{dash.revision}} | ||||
| 					<span ng-if="dash.installed"> | ||||
| 						 (Imported v{{dash.importedRevision}}) | ||||
|           <span ng-if="dash.imported" bs-tooltip='"Imported revision:" + dash.importedRevision'> | ||||
|             Revision: {{dash.revision}} | ||||
|           <span> | ||||
| 				</td> | ||||
| 				<td style="text-align: right"> | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue