迁移配置设置
本指南探讨了当您将 Grafana 插件从已弃用的 AngularJS 或 Angular 升级到我们当前构建插件的方法 React 时,如何转换配置设置。当我们讨论此过程中可能出现的各种问题时,您将看到 Grafana 迁移处理工具如何使转换更容易。
迁移处理程序
背景
面板插件有两种类型的插件配置迁移
- AngularJS 到 React
- 插件版本更新
当您加载面板时,如果面板 JSON 中指定的插件版本与当前运行时版本不同,则会调用迁移处理程序。此处理程序需要返回一个有效的对象,并且不得抛出任何错误。
我们强烈建议您在升级插件可能导致现有面板出现问题时使用迁移处理程序。通过使用迁移处理程序,您将提供更好的用户体验。
使用指定部分
当您将面板插件从 AngularJS 转换为 React 时,JSON 中有一个用于编辑器自定义选项的特定位置。以前,对于 Angular 插件,插件可以将自定义对象存储在配置中的任何位置,但现在这些对象必须使用指定的部分。
默认情况下,Grafana 对其所有组件使用相同的指定部分。您添加的任何自定义组件都必须使用相同的位置。
当 Grafana 加载面板时,它会在向用户显示任何内容之前调用迁移处理程序。此调用允许将旧面板配置自动转换为正在加载的新版本。如果您不提供迁移处理程序,则用户将获得所有面板的默认值,并且他们必须手动修复每个面板。
深入了解 Angular 到 React 的迁移
当仪表板中的面板正在使用旧版本的 AngularJS 插件,但实际上正在运行最新的 React 版本时,需要进行修改。在这种情况下,修改旧配置以尽可能轻松地与新插件一起工作。理想情况下,用户不应需要重新配置其面板。
介绍 Polystat 示例
Angular 插件通常有一个 panel.config
对象,其中包含特定于插件的设置。例如,Polystat 面板插件(称为 grafana-polystat-panel
)是一个示例插件,它最初是一个 AngularJS 面板,后来被移植到 React。React 版本的插件在 module.ts
中使用了 .setMigrationHandler
,如下所示
.setMigrationHandler(PolystatPanelMigrationHandler)
基于 Angular 的 Polystat 面板 (v1.x) 将大多数配置存储在“panel.polystat”对象中。您的插件应检测迁移处理程序中是否存在此对象,以便您可以触发转换为新的基于 React 的插件配置。
React 面板将所有内容存储在 panel.options
中。如果此对象不存在,则迁移处理程序至少应返回一个有效的空对象。如果此对象存在,则它应仅返回当前的 panel.options
。在此阶段有机会修改 React 配置,以防新版本已删除或添加了新功能。
panel.options
是一个名为 PanelModel
的接口,其类型对于您的面板插件是自定义的。
在 Polystat 示例中更改字体
当安装新版本的插件时,Grafana 服务器会调用迁移处理程序来添加或删除配置项。这些更改不会持久保存在仪表板内,因此您必须“保存”它们,以防止每次加载时都必须修改面板。
例如:当 Polystat 插件在 AngularJS 中编写时,它有一个硬编码字体 Roboto,该字体在较新版本的 Grafana 中被删除。当插件在较新版本的 Grafana 中运行时,这会导致输出呈现不正确。为了解决这个问题,Grafana 添加了一个新的选择器,允许用户选择字体,但全局配置在以前的版本中没有此设置。
在这种情况下,迁移处理程序应检测选项是否不存在,然后插入默认值。该默认值返回一个取决于所用 Grafana 版本的有效配置。
步骤 1:检测 Grafana 的运行时版本
您的插件可以访问变量 config.buildInfo.version
以确定正在运行的 Grafana 版本。迁移处理程序可以使用此值来设置有效的默认值。
可能是多个版本的 Grafana 都有一个向后移植的补丁,因此它们可能删除了您的插件期望的功能。在前一个示例中,它是 Roboto 字体。
迁移处理程序获取运行时版本并使用 semver 来确定要使用的字体。旧版本没有更新的 Inter 作为字体,因此 Roboto 是最安全的加载字体。较新的版本已删除 Roboto,因此插件应加载 Inter。
这里有两种情况
情况 1:用户运行选择了 Roboto 的面板
在这种情况下,用户正在运行当前的 Grafana (9.4.3) 并且有一个选择了 Roboto 的面板。插件可以根据运行时提供不同的选择选项。
Polystat 面板在其 module.ts
中有一个取决于运行时的条件检查
.addSelect({
path: 'globalTextFontFamily',
name: 'Font Family',
description: 'Font used for rendered text',
category: ['Text'],
defaultValue: GLOBAL_TEXT_FONT_FAMILY,
settings: {
options: FontFamilyOptions,
},
showIf: () => hasRobotoFont() === false,
})
.addSelect({
path: 'globalTextFontFamily',
name: 'Font Family',
description: 'Font used for rendered text',
category: ['Text'],
defaultValue: GLOBAL_TEXT_FONT_FAMILY_LEGACY,
settings: {
options: FontFamilyOptionsLegacy,
},
showIf: () => hasRobotoFont() === true,
})
情况 2:Grafana 自动将字体切换为 Inter
在这种情况下,用户升级 Grafana(从 v9.3.10 到 v9.4.3),迁移会自动切换到使用 Inter,并且不会在字体选择器中显示 Roboto。如果升级是 9.4.0 或更高版本,则使用 Inter;否则,使用 Roboto。
Polystat 中的 MigrationHandler
包含以下代码
import { config } from "@grafana/runtime";
import { satisfies, coerce } from "semver";
export const PolystatPanelMigrationHandler = (panel: PanelModel<PolystatOptions>): Partial<PolystatOptions> => {
// set default font to inter, and check if it available, set to roboto if not
options.globalTooltipsFontFamily = FontFamilies.INTER;
if (hasRobotoFont()) {
options.globalTooltipsFontFamily = FontFamilies.ROBOTO;
}
}
export const hasRobotoFont = () => {
const version = coerce(config.buildInfo.version);
if (version !== null) {
if (satisfies(version, "<9.4.0")) {
return true;
}
}
return false;
};
步骤 2:检测缺失的配置
新版本的插件可能会添加面板未定义的新配置选项。迁移处理程序可用于添加具有“安全”默认值的新选项。
options.globalTooltipsFontFamily = FontFamilies.INTER;
if (hasRobotoFont()) {
options.globalTooltipsFontFamily = FontFamilies.ROBOTO;
}
export const PolystatPanelMigrationHandler = (panel: PanelModel<PolystatOptions>): Partial<PolystatOptions> => {
if (panel.options.NewFeature === undefined) {
// add default for new feature
panel.options.NewFeature = 5.0;
}
...
return panel.options;
}
步骤 3:检测无效配置
由于插件正在加载并接收整个配置,因此可以迭代配置并确保值是合法的。
export const PolystatPanelMigrationHandler = (panel: PanelModel<PolystatOptions>): Partial<PolystatOptions> => {
// iterate and validate
let validConfigOptions = {
fontSize: 2,
fontFamily: 3,
defaultInvalid: 'a'
};
for (const anOption in panel.options) {
if (!validConfigOptions.includes(anOption)) {
// remove this option
console.log(`removing ${anOption}`);
delete panel.options.anOption;
}
}
return panel.options;
}
步骤 4:设置安全默认值
有时插件会删除功能或修改选项的有效选择。迁移处理程序可用于根据需要调整配置。
export const PolystatPanelMigrationHandler = (panel: PanelModel<PolystatOptions>): Partial<PolystatOptions> => {
const featureOptions = [
'SelectionA',
'SelectionB',
'SelectionC'
];
// detect if a config setting is using a value that has been removed,
// and set a safe default
const removedOption = 'a removed option in selector';
if (!featureOptions.includes(panel.options.aSelectionSetting) {
panel.options.aSelectionSetting = featureOptions[0];
}
// new feature added, set a safe default for it
if (panel.options.aSelectionSetting === undefined) {
// add default for new feature
panel.options.aSelectionSetting = featureOptions[0];
}
return panel.options;
}