为你的面板插件添加迁移处理程序
在开发和维护 Grafana 面板插件时,你可能需要更改面板选项结构。这些更改可能会破坏现有的仪表板配置。
当你在插件中引入破坏性更改时,你应该增加插件版本的主要版本号(例如,从 1.2.1 增加到 2.0.0)。我们鼓励你尽可能减少插件版本之间的破坏性更改,但在必要的情况下,为了确保用户在更新插件时能够平稳过渡,你可以实现一个迁移处理程序。
迁移处理程序基础知识
迁移处理程序是一个函数,当仪表板存储的面板版本与当前安装的面板版本不同时运行。它允许你更新面板的选项以匹配新的结构,而无需用户手动干预。
要为你的面板插件添加迁移处理程序,请在 PanelPlugin
对象上使用 setMigrationHandler
方法
module.ts
import { PanelPlugin } from '@grafana/data';
import { SimplePanel } from './components/SimplePanel';
import { SimpleOptions } from './types';
import { migrationHandler } from './migrationHandler';
export const plugin = new PanelPlugin<SimpleOptions>(SimplePanel)
.setPanelOptions((builder) => {
// ... panel options configuration
})
// define the migration handler
.setMigrationHandler(migrationHandler);
注意
迁移处理程序仅在安装的插件版本与用于生成面板的版本不同时调用。对面板所做的更改不会自动持久化,用户需要在面板迁移后手动保存仪表板。
实现迁移处理程序
迁移处理程序函数接收整个面板模型作为参数,并应返回更新后的面板选项。这是一个基本结构
migrationHandler.ts
import { PanelModel } from '@grafana/data';
import { SimpleOptions } from './types';
function migrationHandler(panel: PanelModel<Partial<SimpleOptions>>) {
// panel.options contains the current panel options stored in the dashboard
const options = Object.assign({}, panel.options);
// Perform option migrations here
return options;
}
常见的迁移场景
处理新选项
当添加新的面板配置选项时,为它们设置默认值
if (options.newFeature === undefined) {
panel.options.newFeature = 'defaultValue';
}
重命名选项
如果你重命名了一个选项,将值从旧选项转移到新选项
if (panel.options.oldOptionName) {
panel.options.newOptionName = panel.options.oldOptionName;
// make sure to remove the old option
delete panel.options.oldOptionName;
}
调整已更改的选项
当删除有效选项或更改有效选择时,设置安全默认值
const validOptions = ['option1', 'option2', 'option3'];
if (!validOptions.includes(panel.options.someOption)) {
panel.options.someOption = validOptions[0];
}
或将现有值迁移到新选项
// e.g. the options of displayType were renamed
// from bar, line, pie to barChart, linePlot and pieChart
if (options.displayType) {
switch (options.displayType) {
case 'bar':
options.displayType = 'barChart';
break;
case 'line':
options.displayType = 'linePlot';
break;
case 'pie':
options.displayType = 'pieChart';
break;
}
}
版本特定的调整
你可能希望基于用于编写面板的版本来决定迁移。为此,你可以使用 pluginVersion
属性。此属性在首次使用迁移处理程序时为空,但之后它将被设置为用于保存面板的插件版本。
例如,假设一个插件有以下历史记录
- 在 v1 版本中,插件没有任何迁移代码。
- 在 v2 版本中,插件引入了第一个迁移代码。
- 在 v3 版本中,插件再次更改,并包含新的迁移步骤。
在这种情况下,迁移处理程序将如下所示
migrationHandler.ts
function migrationHandler(panel: PanelModel<SimpleOptions>) {
const options = Object.assign({}, panel.options);
const pluginVersion = panel?.pluginVersion ?? '';
if (pluginVersion === '') {
// Plugin version was v1.x
// Needs logic to migrate v1 -> v3
options.displayMode = 'compact';
options.displayType = 'linePlot';
}
if (pluginVersion.startsWith('2.') {
// Panel was last saved with version v2.x
// Needs logic to migrate v2 -> v3
options.displayMode = 'compact';
}
return options;
}
使用字符串比较
migrationHandler.ts
import { config } from '@grafana/runtime';
function migrationHandler(panel: PanelModel<SimpleOptions>) {
const options = Object.assign({}, panel.options);
// pluginVersion will be empty
// if the plugin didn't implement a migration handler before
// or contain the version of the plugin when the panel was last saved after a migration handler was called.
const pluginVersion = panel?.pluginVersion ?? '';
if (pluginVersion === '' || pluginVersion.startsWith('1.')) {
options.displayMode = 'compact';
}
return options;
}
最佳实践
- 始终创建选项对象的副本,以避免修改原始对象。
- 使用类型检查以确保你仅迁移存在的选项。
- 处理所有可能的场景,以避免因意外配置而破坏仪表板。
- 使用各种面板配置彻底测试你的迁移处理程序。
- 在插件的变更日志中记录更改,以帮助用户了解已更新的内容。
请记住,迁移处理程序在每次面板加载时运行,直到用户手动编辑并保存面板。确保你的迁移是幂等的,并且多次运行时不会导致意外的副作用。