Commit b62f1f00 by Torkel Ödegaard

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

parent 4545b4d3
...@@ -20,6 +20,7 @@ type PluginSetting struct { ...@@ -20,6 +20,7 @@ type PluginSetting struct {
Pinned bool Pinned bool
JsonData map[string]interface{} JsonData map[string]interface{}
SecureJsonData SecureJsonData SecureJsonData SecureJsonData
PluginVersion string
Created time.Time Created time.Time
Updated time.Time Updated time.Time
...@@ -44,11 +45,19 @@ type UpdatePluginSettingCmd struct { ...@@ -44,11 +45,19 @@ type UpdatePluginSettingCmd struct {
Pinned bool `json:"pinned"` Pinned bool `json:"pinned"`
JsonData map[string]interface{} `json:"jsonData"` JsonData map[string]interface{} `json:"jsonData"`
SecureJsonData map[string]string `json:"secureJsonData"` SecureJsonData map[string]string `json:"secureJsonData"`
PluginVersion string `json:"version"`
PluginId string `json:"-"` PluginId string `json:"-"`
OrgId int64 `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 { func (cmd *UpdatePluginSettingCmd) GetEncryptedJsonData() SecureJsonData {
encrypted := make(SecureJsonData) encrypted := make(SecureJsonData)
for key, data := range cmd.SecureJsonData { for key, data := range cmd.SecureJsonData {
...@@ -69,6 +78,7 @@ type PluginSettingInfoDTO struct { ...@@ -69,6 +78,7 @@ type PluginSettingInfoDTO struct {
PluginId string PluginId string
Enabled bool Enabled bool
Pinned bool Pinned bool
PluginVersion string
} }
type GetPluginSettingByIdQuery struct { 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 { ...@@ -77,6 +77,8 @@ func Init() error {
} }
go StartPluginUpdateChecker() go StartPluginUpdateChecker()
go updateAppDashboards()
return nil return nil
} }
......
...@@ -26,4 +26,10 @@ func addAppSettingsMigration(mg *Migrator) { ...@@ -26,4 +26,10 @@ func addAppSettingsMigration(mg *Migrator) {
//------- indexes ------------------ //------- indexes ------------------
addTableIndicesMigrations(mg, "v1", pluginSettingTable) 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() { ...@@ -13,14 +13,20 @@ func init() {
bus.AddHandler("sql", GetPluginSettings) bus.AddHandler("sql", GetPluginSettings)
bus.AddHandler("sql", GetPluginSettingById) bus.AddHandler("sql", GetPluginSettingById)
bus.AddHandler("sql", UpdatePluginSetting) bus.AddHandler("sql", UpdatePluginSetting)
bus.AddHandler("sql", UpdatePluginSettingVersion)
} }
func GetPluginSettings(query *m.GetPluginSettingsQuery) error { func GetPluginSettings(query *m.GetPluginSettingsQuery) error {
sql := `SELECT org_id, plugin_id, enabled, pinned sql := `SELECT org_id, plugin_id, enabled, pinned, plugin_version
FROM plugin_setting FROM plugin_setting `
WHERE org_id=?` 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) query.Result = make([]*m.PluginSettingInfoDTO, 0)
return sess.Find(&query.Result) return sess.Find(&query.Result)
} }
...@@ -51,6 +57,7 @@ func UpdatePluginSetting(cmd *m.UpdatePluginSettingCmd) error { ...@@ -51,6 +57,7 @@ func UpdatePluginSetting(cmd *m.UpdatePluginSettingCmd) error {
Enabled: cmd.Enabled, Enabled: cmd.Enabled,
Pinned: cmd.Pinned, Pinned: cmd.Pinned,
JsonData: cmd.JsonData, JsonData: cmd.JsonData,
PluginVersion: cmd.PluginVersion,
SecureJsonData: cmd.GetEncryptedJsonData(), SecureJsonData: cmd.GetEncryptedJsonData(),
Created: time.Now(), Created: time.Now(),
Updated: time.Now(), Updated: time.Now(),
...@@ -65,8 +72,18 @@ func UpdatePluginSetting(cmd *m.UpdatePluginSettingCmd) error { ...@@ -65,8 +72,18 @@ func UpdatePluginSetting(cmd *m.UpdatePluginSettingCmd) error {
pluginSetting.Enabled = cmd.Enabled pluginSetting.Enabled = cmd.Enabled
pluginSetting.JsonData = cmd.JsonData pluginSetting.JsonData = cmd.JsonData
pluginSetting.Pinned = cmd.Pinned pluginSetting.Pinned = cmd.Pinned
pluginSetting.PluginVersion = cmd.PluginVersion
_, err = sess.Id(pluginSetting.Id).Update(&pluginSetting) _, err = sess.Id(pluginSetting.Id).Update(&pluginSetting)
return err 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 @@ ...@@ -14,9 +14,8 @@
</span> </span>
</td> </td>
<td> <td>
v{{dash.revision}} <span ng-if="dash.imported" bs-tooltip='"Imported revision:" + dash.importedRevision'>
<span ng-if="dash.installed"> Revision: {{dash.revision}}
&nbsp;(Imported v{{dash.importedRevision}})
<span> <span>
</td> </td>
<td style="text-align: right"> <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