perses-grafana-migrate
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChinesePerses Grafana Migration
Perses Grafana 迁移
Convert Grafana dashboards to Perses format with validation and deployment.
将Grafana仪表板转换为Perses格式,并提供验证与部署功能。
Operator Context
操作器上下文
This skill operates as a migration pipeline for converting Grafana dashboards to Perses format, handling export, conversion, validation, and deployment.
本工具作为迁移管道运行,负责将Grafana仪表板转换为Perses格式,处理导出、转换、验证和部署全流程。
Hardcoded Behaviors (Always Apply)
强制行为(始终生效)
- Validate after conversion: Always run on migrated dashboards — conversion may produce structurally valid but semantically broken output
percli lint - Preserve originals: Never modify or delete Grafana source JSON files — migration is a one-way copy operation, originals are the rollback path
- Report incompatibilities: List all plugins/panels that couldn't be migrated — unsupported Grafana plugins become StaticListVariable placeholders that need manual attention
- Extract key: When exporting from Grafana API, always extract the
.dashboardkey from the response — the raw API response wraps the dashboard in metadata that.dashboardcannot parsepercli migrate - Verify Grafana version: Confirm source Grafana instance is 9.0.0+ before migration — older versions use dashboard JSON schemas that does not support
percli - Review placeholders before deploy: Never deploy migrated dashboards without first searching for and documenting all placeholders — these represent broken functionality that will confuse end users
StaticListVariable
- 转换后验证:始终对迁移后的仪表板运行——转换可能产生结构上有效但语义上存在问题的输出
percli lint - 保留原始文件:绝不修改或删除Grafana源JSON文件——迁移是单向复制操作,原始文件是回滚的唯一途径
- 报告不兼容项:列出所有无法迁移的插件/面板——不支持的Grafana插件会被替换为StaticListVariable占位符,需要人工处理
- 提取字段:从Grafana API导出时,必须从响应中提取
.dashboard字段——原始API响应会将仪表板包裹在元数据中,.dashboard无法解析这些元数据percli migrate - 验证Grafana版本:迁移前确认源Grafana实例版本为9.0.0+——旧版本使用的仪表板JSON架构不被支持
percli - 部署前检查占位符:绝不直接部署迁移后的仪表板,必须先搜索并记录所有占位符——这些占位符代表功能损坏,会误导终端用户
StaticListVariable
Default Behaviors (ON unless disabled)
默认行为(默认开启,可关闭)
- Online mode: Use when connected to a Perses server (recommended — uses latest plugin migration logic)
percli migrate --online - JSON output: Default to JSON format for migrated dashboards
- Batch processing: Process multiple dashboards in parallel when given a directory
- Lint after convert: Run on every converted file before proceeding to deploy
percli lint
- 在线模式:连接到Perses服务器时使用(推荐——使用最新的插件迁移逻辑)
percli migrate --online - JSON输出:迁移后的仪表板默认采用JSON格式
- 批量处理:当指定目录时,并行处理多个仪表板
- 转换后校验:在部署前对每个转换后的文件运行
percli lint
Optional Behaviors (OFF unless enabled)
可选行为(默认关闭,需开启)
- K8s CR output: Generate Kubernetes CustomResource format with
--format cr - Auto-deploy: Apply migrated dashboards immediately after validation
- Dry-run deploy: Validate deployment with before committing
percli apply --dry-run
- K8s CR输出:使用生成Kubernetes自定义资源(CustomResource)格式
--format cr - 自动部署:验证通过后立即应用迁移后的仪表板
- 部署预演:在正式部署前使用验证部署可行性
percli apply --dry-run
What This Skill CAN Do
本工具可实现的功能
- Convert Grafana dashboard JSON to Perses format
- Handle bulk migration of multiple dashboards
- Validate migrated output and report incompatibilities
- Deploy migrated dashboards to Perses
- Map supported panel types: Graph to TimeSeriesChart, Stat to StatChart, Table to Table
- 将Grafana仪表板JSON转换为Perses格式
- 处理多个仪表板的批量迁移
- 验证迁移后的输出并报告不兼容项
- 将迁移后的仪表板部署到Perses
- 映射支持的面板类型:Graph → TimeSeriesChart,Stat → StatChart,Table → Table
What This Skill CANNOT Do
本工具无法实现的功能
- Migrate Grafana annotations, alerting rules, or notification channels
- Convert unsupported Grafana plugins (they become StaticListVariable placeholders)
- Migrate Grafana users, teams, or datasource configurations
- Create dashboards from scratch (use perses-dashboard-create)
- Convert custom Grafana-only plugins that have no Perses equivalent
- 迁移Grafana注释、告警规则或通知渠道
- 转换不支持的Grafana插件(会被替换为StaticListVariable占位符)
- 迁移Grafana用户、团队或数据源配置
- 从零开始创建仪表板(请使用perses-dashboard-create)
- 转换没有Perses等效插件的Grafana专属自定义插件
Error Handling
错误处理
| Cause | Symptom | Solution |
|---|---|---|
| Invalid Grafana JSON format | | Verify JSON is valid with |
| Grafana version < 9.0.0 | | Upgrade Grafana to 9.0.0+ before export, or manually update the dashboard JSON |
| Unsupported plugin warning | Migration succeeds but panels contain | Document each unsupported panel, then manually replace with the closest Perses equivalent (TimeSeriesChart, StatChart, Table, or Markdown panel) |
| Online mode connection failure | | Verify Perses server URL and port, check authentication (run |
| Panel layout lost in migration | Grafana grid coordinates don't map cleanly to Perses Grid layout — panels overlap or have wrong sizes | After migration, review the |
| Missing datasource references | Migrated dashboard references datasource names that don't exist in Perses | Create matching Perses datasources before deploying, or update the migrated JSON to reference existing Perses datasource names |
| 原因 | 症状 | 解决方案 |
|---|---|---|
| 无效的Grafana JSON格式 | | 使用 |
| Grafana版本低于9.0.0 | | 迁移前将Grafana升级到9.0.0+,或手动更新仪表板JSON的 |
| 不支持插件警告 | 迁移成功,但面板包含值为 | 记录每个不支持的面板,然后手动替换为最接近的Perses等效面板(TimeSeriesChart、StatChart、Table或Markdown面板) |
| 在线模式连接失败 | | 验证Perses服务器的URL和端口,检查认证信息(先运行 |
| 迁移后面板布局丢失 | Grafana的网格坐标无法完美映射到Perses的Grid布局——面板重叠或尺寸错误 | 迁移后,检查 |
| 缺失数据源引用 | 迁移后的仪表板引用了Perses中不存在的数据源名称 | 部署前创建匹配的Perses数据源,或更新迁移后的JSON以引用已存在的Perses数据源名称 |
Anti-Patterns
反模式
| Anti-Pattern | Why It's Wrong | Do Instead |
|---|---|---|
| Deploying migrated dashboards without reviewing StaticListVariable placeholders | Users see broken panels with placeholder values, lose trust in the migration | Search all migrated files for |
| Running migration in offline mode when online mode is available | Offline mode uses bundled plugin migration logic which may be outdated — misses latest panel type mappings | Always prefer |
| Deleting original Grafana JSON files after migration | No rollback path if migration output is wrong, no way to re-run with updated | Keep originals in a |
| Batch migrating everything at once without prioritization | Critical dashboards get the same attention as abandoned test dashboards, errors pile up | Prioritize by usage: migrate the top 5-10 most-viewed dashboards first, validate thoroughly, then batch the rest |
| Migrating dashboards without first checking Grafana version | Wasted effort — older Grafana JSON schemas produce broken or empty Perses output | Run |
| 反模式 | 问题所在 | 正确做法 |
|---|---|---|
| 未检查StaticListVariable占位符就部署迁移后的仪表板 | 用户会看到包含占位符的损坏面板,失去对迁移结果的信任 | 在所有迁移文件中搜索 |
| 在线模式可用时仍使用离线模式 | 离线模式使用的插件迁移逻辑是快照版本,可能滞后数周或数月——服务器端会持续添加新的面板类型映射 | 只要Perses服务器可用,就优先使用在线模式;离线模式仅作为 fallback |
| 迁移后删除Grafana原始JSON文件 | 若迁移输出存在问题,将没有回滚路径,重新迁移的成本极高 | 将原始文件保存在 |
| 不做优先级区分,一次性批量迁移所有仪表板 | 关键仪表板与废弃的测试仪表板得到相同的关注,错误堆积 | 按使用频率排序:先迁移前5-10个最常访问的仪表板,彻底验证后再批量迁移其余的 |
| 迁移前未检查Grafana版本 | 白费力气——旧版Grafana JSON架构会生成损坏或空的Perses输出 | 迁移前运行 |
Anti-Rationalization
反合理化借口
| Rationalization | Reality | Required Action |
|---|---|---|
| "The migration completed without errors so it's correct" | | Diff panel counts: compare number of panels in Grafana source vs Perses output, search for all placeholder values |
| "Online mode isn't necessary, offline is fine" | Offline mode bundles a snapshot of plugin migration logic that may be weeks or months behind — new panel type mappings are added to the server continuously | Use online mode whenever a Perses server is available, verify server version is current |
| "We can fix the placeholders later after deployment" | Users will see broken dashboards immediately, file bugs, lose confidence in the migration — fixing in production is always harder than fixing before deploy | Fix or document every placeholder before deploying, even if it delays the migration timeline |
| "The layout looks close enough" | Grafana's 24-column grid and Perses's Grid layout have different coordinate systems — "close enough" means overlapping panels or wasted whitespace that makes dashboards unusable | Visually verify every migrated dashboard in the Perses UI before declaring migration complete |
| 合理化借口 | 实际情况 | 必要操作 |
|---|---|---|
| “迁移完成且无错误,所以结果是正确的” | 即使面板被替换为StaticListVariable占位符, | 对比面板数量:比较Grafana源面板数与Perses输出面板数,搜索所有占位符值 |
| “在线模式没必要,离线模式就够了” | 离线模式打包的插件迁移逻辑可能滞后数周或数月——服务器端会持续添加新的面板类型映射 | 尽可能使用在线模式,并验证服务器版本为最新 |
| “我们可以部署后再修复占位符” | 用户会立即看到损坏的仪表板,提交bug,失去对迁移的信任——生产环境中修复比部署前修复难得多 | 部署前修复或记录每个占位符,即使这会推迟迁移时间 |
| “布局看起来差不多就行” | Grafana的24列网格与Perses的Grid布局使用不同的坐标系统——“差不多”意味着面板重叠或留白过多,导致仪表板无法使用 | 视觉验证每个迁移后的仪表板在Perses UI中的显示效果,确认迁移完成 |
FORBIDDEN Patterns
禁止模式
These patterns MUST NOT appear in migration workflows:
- NEVER pipe raw Grafana API response directly to without extracting
percli migrate— the envelope metadata will cause parse failures.dashboard - NEVER use on Grafana JSON from versions below 9.0.0 — the output will be silently wrong or empty
percli migrate - NEVER deploy migrated dashboards to production without running — structural errors will break the Perses UI
percli lint - NEVER delete Grafana source dashboards or disable them before confirming the Perses migration is complete and validated by dashboard owners
- NEVER assume all Grafana panel types have Perses equivalents — annotations, alerting rules, and custom Grafana-only plugins have no mapping
以下模式绝对不能出现在迁移工作流中:
- 绝对禁止将原始Grafana API响应直接通过管道传给,而不提取
percli migrate字段——包裹的元数据会导致解析失败.dashboard - 绝对禁止对版本低于9.0.0的Grafana JSON使用——输出会静默出错或为空
percli migrate - 绝对禁止未运行就将迁移后的仪表板部署到生产环境——结构错误会导致Perses UI崩溃
percli lint - 绝对禁止在确认Perses迁移完成并经仪表板所有者验证前,删除或禁用Grafana源仪表板
- 绝对禁止假设所有Grafana面板类型都有对应的Perses等效面板——注释、告警规则和Grafana专属自定义插件没有映射关系
Blocker Criteria
阻塞条件
STOP and escalate to the user if any of these conditions are met:
- Grafana version < 9.0.0: Migration will produce broken output. User must upgrade Grafana or manually convert dashboard JSON.
- More than 30% of panels are unsupported: Migration value is too low — more manual work than automated. Recommend building Perses dashboards from scratch instead.
- No Perses server available and online mode required: If the user specifically needs online mode features (latest plugin mappings) but has no server, the migration cannot proceed at the expected quality level.
- Grafana API authentication unavailable: Cannot export dashboards without API access. User must provide a service account token or admin credentials.
- Target Perses project does not exist and user lacks create permissions: Cannot deploy. User must create the project or get permissions first.
若出现以下任一情况,必须停止操作并告知用户:
- Grafana版本低于9.0.0:迁移会产生损坏的输出。用户必须升级Grafana或手动转换仪表板JSON。
- 超过30%的面板不被支持:迁移的价值极低——人工修复的工作量超过自动化迁移。建议从零开始构建Perses仪表板。
- 需要在线模式但无Perses服务器可用:如果用户明确需要在线模式的功能(最新插件映射)但无服务器可用,无法达到预期的迁移质量。
- 无法获取Grafana API认证权限:没有API权限无法导出仪表板。用户必须提供服务账号令牌或管理员凭据。
- 目标Perses项目不存在且用户无创建权限:无法部署。用户必须先创建项目或获取权限。
Instructions
操作步骤
Phase 1: EXPORT
阶段1:导出
Goal: Export Grafana dashboards as JSON files. If user has JSON files already, skip to Phase 2.
Verify Grafana version first:
bash
curl -s https://grafana.example.com/api/health | jq '.version'目标:将Grafana仪表板导出为JSON文件。若用户已拥有JSON文件,直接跳转到阶段2。
首先验证Grafana版本:
bash
curl -s https://grafana.example.com/api/health | jq '.version'Must be 9.0.0+
版本必须为9.0.0+
Export a single dashboard:
```bash
导出单个仪表板:
```bashExport from Grafana API — MUST extract .dashboard key
从Grafana API导出——必须提取.dashboard字段
curl -H "Authorization: Bearer <token>"
https://grafana.example.com/api/dashboards/uid/<uid>
| jq '.dashboard' > grafana-dashboard.json
https://grafana.example.com/api/dashboards/uid/<uid>
| jq '.dashboard' > grafana-dashboard.json
For bulk export, iterate over all dashboards:
```bash
curl -H "Authorization: Bearer <token>" \
https://grafana.example.com/api/search?type=dash-db \
| jq -r '.[].uid' | while read uid; do
curl -s -H "Authorization: Bearer <token>" \
"https://grafana.example.com/api/dashboards/uid/$uid" \
| jq '.dashboard' > "grafana-$uid.json"
doneGate: Grafana dashboard JSON files available, key extracted, Grafana version confirmed 9.0.0+. Proceed to Phase 2.
.dashboardcurl -H "Authorization: Bearer <token>"
https://grafana.example.com/api/dashboards/uid/<uid>
| jq '.dashboard' > grafana-dashboard.json
https://grafana.example.com/api/dashboards/uid/<uid>
| jq '.dashboard' > grafana-dashboard.json
批量导出所有仪表板:
```bash
curl -H "Authorization: Bearer <token>" \
https://grafana.example.com/api/search?type=dash-db \
| jq -r '.[].uid' | while read uid; do
curl -s -H "Authorization: Bearer <token>" \
"https://grafana.example.com/api/dashboards/uid/$uid" \
| jq '.dashboard' > "grafana-$uid.json"
done检查点:已获取Grafana仪表板JSON文件,已提取字段,已确认Grafana版本为9.0.0+。进入阶段2。
.dashboardPhase 2: CONVERT
阶段2:转换
Goal: Convert Grafana JSON to Perses format.
bash
undefined目标:将Grafana JSON转换为Perses格式。
bash
undefinedSingle dashboard (online mode - recommended)
单个仪表板(在线模式 - 推荐)
percli migrate -f grafana-dashboard.json --online -o json > perses-dashboard.json
percli migrate -f grafana-dashboard.json --online -o json > perses-dashboard.json
Bulk migration
批量迁移
for f in grafana-*.json; do
percli migrate -f "$f" --online -o json > "perses-${f#grafana-}"
done
for f in grafana-*.json; do
percli migrate -f "$f" --online -o json > "perses-${f#grafana-}"
done
K8s CR format
K8s CR格式
percli migrate -f grafana-dashboard.json --online --format cr -o json > perses-cr.json
percli migrate -f grafana-dashboard.json --online --format cr -o json > perses-cr.json
Offline fallback (when no Perses server available)
离线 fallback(无Perses服务器可用时)
percli migrate -f grafana-dashboard.json -o json > perses-dashboard.json
**Migration notes**:
- Requires Perses server connection for online mode (uses latest plugin migration logic)
- Compatible with Grafana 9.0.0+, latest version recommended
- Unsupported variables become `StaticListVariable` with values `["grafana", "migration", "not", "supported"]`
- Panel type mapping: Graph to TimeSeriesChart, Stat to StatChart, Table to Table
- Panels with no Perses equivalent need manual replacement after migration
**Gate**: Conversion complete. All files produced without errors. Proceed to Phase 3.percli migrate -f grafana-dashboard.json -o json > perses-dashboard.json
**迁移注意事项**:
- 在线模式需要连接到Perses服务器(使用最新的插件迁移逻辑)
- 仅兼容Grafana 9.0.0+,推荐使用最新版本
- 不支持的变量会被替换为值为`["grafana", "migration", "not", "supported"]`的`StaticListVariable`
- 面板类型映射:Graph → TimeSeriesChart,Stat → StatChart,Table → Table
- 无Perses等效面板的组件需要在迁移后手动替换
**检查点**:转换完成,所有文件生成无错误。进入阶段3。Phase 3: VALIDATE
阶段3:验证
Goal: Validate converted dashboards and report incompatibilities.
bash
undefined目标:验证转换后的仪表板并报告不兼容项。
bash
undefinedLint every migrated file
校验每个迁移后的文件
percli lint -f perses-dashboard.json
percli lint -f perses-dashboard.json
Search for unsupported plugin placeholders
搜索不支持的插件占位符
grep -r '"grafana","migration","not","supported"' perses-*.json
grep -r '"grafana","migration","not","supported"' perses-*.json
Count panels: compare source vs migrated
统计面板数量:对比源文件与迁移后文件
jq '.panels | length' grafana-dashboard.json
jq '.spec.panels | length' perses-dashboard.json
Check for:
- Panel types that weren't converted (search for StaticListVariable placeholders)
- Missing datasource references
- Variable references that didn't translate
- Layout issues (overlapping or mis-sized panels in Grid layout)
**Gate**: Validation passes. All StaticListVariable placeholders documented with remediation plan. Proceed to Phase 4.jq '.panels | length' grafana-dashboard.json
jq '.spec.panels | length' perses-dashboard.json
检查内容:
- 未被转换的面板类型(搜索StaticListVariable占位符)
- 缺失的数据源引用
- 未被正确转换的变量引用
- 布局问题(Grid布局中面板重叠或尺寸错误)
**检查点**:验证通过,所有StaticListVariable占位符已记录并制定修复计划。进入阶段4。Phase 4: DEPLOY
阶段4:部署
Goal: Deploy migrated dashboards to Perses.
bash
undefined目标:将迁移后的仪表板部署到Perses。
bash
undefinedEnsure project exists
确保项目存在
percli apply -f - <<EOF
kind: Project
metadata:
name: <project>
spec: {}
EOF
percli apply -f - <<EOF
kind: Project
metadata:
name: <project>
spec: {}
EOF
Deploy dashboards
部署仪表板
percli apply -f perses-dashboard.json --project <project>
Verify migration:
```bash
percli get dashboard --project <project>Open Perses UI and visually confirm each migrated dashboard renders correctly.
Gate: Dashboards deployed and accessible. Visual verification complete. Migration complete.
percli apply -f perses-dashboard.json --project <project>
验证迁移结果:
```bash
percli get dashboard --project <project>打开Perses UI,视觉确认每个迁移后的仪表板渲染正常。
检查点:仪表板已部署并可访问,视觉验证完成。迁移结束。
References
参考资源
| Resource | URL |
|---|---|
| Perses GitHub | https://github.com/perses/perses |
| percli documentation | https://perses.dev/docs/tooling/percli/ |
| Grafana API — Get Dashboard | https://grafana.com/docs/grafana/latest/developers/http_api/dashboard/#get-dashboard-by-uid |
| Grafana API — Search | https://grafana.com/docs/grafana/latest/developers/http_api/dashboard/#dashboard-search |
| Perses Plugin System | https://perses.dev/docs/plugins/ |
| Migration Guide | https://perses.dev/docs/tooling/percli/#migrate |