跳转到主要内容

为您的面板插件添加迁移处理器

在开发和维护您的 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;
}

最佳实践

  1. 始终创建选项对象的副本,以避免修改原始对象。
  2. 使用类型检查以确保仅迁移存在的选项。
  3. 处理所有可能的情况,以避免意外配置破坏仪表盘。
  4. 使用各种面板配置彻底测试您的迁移处理器。
  5. 在插件的变化日志中记录更改,以帮助用户了解已更新内容。

记住,迁移处理器在用户手动编辑和保存面板之前会在每次面板加载时运行。确保您的迁移是幂等的,并且多次运行不会产生意外的副作用。