Commit b62f1f00 by Torkel Ödegaard

feat(apps): auto update dashboard dashboards, #5529

parent 4545b4d3
......@@ -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 {
......
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">
&nbsp;(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">
......
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