diff --git a/pkg/models/plugin_settings.go b/pkg/models/plugin_settings.go index d030c125ba9..dbeaf441156 100644 --- a/pkg/models/plugin_settings.go +++ b/pkg/models/plugin_settings.go @@ -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 { @@ -65,10 +74,11 @@ type GetPluginSettingsQuery struct { } type PluginSettingInfoDTO struct { - OrgId int64 - PluginId string - Enabled bool - Pinned bool + OrgId int64 + PluginId string + Enabled bool + Pinned bool + PluginVersion string } type GetPluginSettingByIdQuery struct { diff --git a/pkg/plugins/dashboards_updater.go b/pkg/plugins/dashboards_updater.go new file mode 100644 index 00000000000..3a0714eb675 --- /dev/null +++ b/pkg/plugins/dashboards_updater.go @@ -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) + } +} diff --git a/pkg/plugins/plugins.go b/pkg/plugins/plugins.go index cf931066cbb..b6c3639cbbf 100644 --- a/pkg/plugins/plugins.go +++ b/pkg/plugins/plugins.go @@ -77,6 +77,8 @@ func Init() error { } go StartPluginUpdateChecker() + go updateAppDashboards() + return nil } diff --git a/pkg/services/sqlstore/migrations/plugin_setting.go b/pkg/services/sqlstore/migrations/plugin_setting.go index 4a8729691d3..0700ab67d2f 100644 --- a/pkg/services/sqlstore/migrations/plugin_setting.go +++ b/pkg/services/sqlstore/migrations/plugin_setting.go @@ -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, + })) + } diff --git a/pkg/services/sqlstore/plugin_setting.go b/pkg/services/sqlstore/plugin_setting.go index ec0b9b2e2d7..f3fcc2a9c1d 100644 --- a/pkg/services/sqlstore/plugin_setting.go +++ b/pkg/services/sqlstore/plugin_setting.go @@ -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 + + }) +} diff --git a/public/app/features/plugins/import_list/import_list.html b/public/app/features/plugins/import_list/import_list.html index 746109970e0..b984a9d8be5 100644 --- a/public/app/features/plugins/import_list/import_list.html +++ b/public/app/features/plugins/import_list/import_list.html @@ -14,10 +14,9 @@ - v{{dash.revision}} - -  (Imported v{{dash.importedRevision}}) - + + Revision: {{dash.revision}} +