perses-grafana-migrate

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Perses 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
    percli lint
    on migrated dashboards — conversion may produce structurally valid but semantically broken output
  • 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
    .dashboard
    key
    : When exporting from Grafana API, always extract the
    .dashboard
    key from the response — the raw API response wraps the dashboard in metadata that
    percli migrate
    cannot parse
  • Verify Grafana version: Confirm source Grafana instance is 9.0.0+ before migration — older versions use dashboard JSON schemas that
    percli
    does not support
  • Review placeholders before deploy: Never deploy migrated dashboards without first searching for and documenting all
    StaticListVariable
    placeholders — these represent broken functionality that will confuse end users
  • 转换后验证:始终对迁移后的仪表板运行
    percli lint
    ——转换可能产生结构上有效但语义上存在问题的输出
  • 保留原始文件:绝不修改或删除Grafana源JSON文件——迁移是单向复制操作,原始文件是回滚的唯一途径
  • 报告不兼容项:列出所有无法迁移的插件/面板——不支持的Grafana插件会被替换为StaticListVariable占位符,需要人工处理
  • 提取
    .dashboard
    字段
    :从Grafana API导出时,必须从响应中提取
    .dashboard
    字段——原始API响应会将仪表板包裹在元数据中,
    percli migrate
    无法解析这些元数据
  • 验证Grafana版本:迁移前确认源Grafana实例版本为9.0.0+——旧版本使用的仪表板JSON架构不被
    percli
    支持
  • 部署前检查占位符:绝不直接部署迁移后的仪表板,必须先搜索并记录所有
    StaticListVariable
    占位符——这些占位符代表功能损坏,会误导终端用户

Default Behaviors (ON unless disabled)

默认行为(默认开启,可关闭)

  • Online mode: Use
    percli migrate --online
    when connected to a Perses server (recommended — uses latest plugin migration logic)
  • JSON output: Default to JSON format for migrated dashboards
  • Batch processing: Process multiple dashboards in parallel when given a directory
  • Lint after convert: Run
    percli lint
    on every converted file before proceeding to deploy
  • 在线模式:连接到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
    percli apply --dry-run
    before committing
  • K8s CR输出:使用
    --format cr
    生成Kubernetes自定义资源(CustomResource)格式
  • 自动部署:验证通过后立即应用迁移后的仪表板
  • 部署预演:在正式部署前使用
    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

错误处理

CauseSymptomSolution
Invalid Grafana JSON format
percli migrate
fails with parse error or "unexpected token"
Verify JSON is valid with
jq .
— ensure you extracted the
.dashboard
key from Grafana API response, not the full envelope
Grafana version < 9.0.0
percli migrate
fails with schema errors or produces empty output
Upgrade Grafana to 9.0.0+ before export, or manually update the dashboard JSON
schemaVersion
field (risky — structural differences may remain)
Unsupported plugin warningMigration succeeds but panels contain
StaticListVariable
with values
["grafana","migration","not","supported"]
Document each unsupported panel, then manually replace with the closest Perses equivalent (TimeSeriesChart, StatChart, Table, or Markdown panel)
Online mode connection failure
percli migrate --online
fails with "connection refused" or timeout
Verify Perses server URL and port, check authentication (run
percli login
first), fall back to offline mode with
percli migrate -f <file> -o json
if server is unavailable
Panel layout lost in migrationGrafana grid coordinates don't map cleanly to Perses Grid layout — panels overlap or have wrong sizesAfter migration, review the
spec.layouts
section and manually adjust Grid
x
,
y
,
w
,
h
values to match the original Grafana layout intent
Missing datasource referencesMigrated dashboard references datasource names that don't exist in PersesCreate matching Perses datasources before deploying, or update the migrated JSON to reference existing Perses datasource names
原因症状解决方案
无效的Grafana JSON格式
percli migrate
解析失败,提示“unexpected token”或其他解析错误
使用
jq .
验证JSON有效性——确保已从Grafana API响应中提取
.dashboard
字段,而非完整的响应包
Grafana版本低于9.0.0
percli migrate
因架构错误失败,或生成空输出
迁移前将Grafana升级到9.0.0+,或手动更新仪表板JSON的
schemaVersion
字段(存在风险——可能仍存在结构差异)
不支持插件警告迁移成功,但面板包含值为
["grafana","migration","not","supported"]
StaticListVariable
记录每个不支持的面板,然后手动替换为最接近的Perses等效面板(TimeSeriesChart、StatChart、Table或Markdown面板)
在线模式连接失败
percli migrate --online
失败,提示“connection refused”或超时
验证Perses服务器的URL和端口,检查认证信息(先运行
percli login
),若服务器不可用,回退到离线模式:
percli migrate -f <file> -o json
迁移后面板布局丢失Grafana的网格坐标无法完美映射到Perses的Grid布局——面板重叠或尺寸错误迁移后,检查
spec.layouts
部分,手动调整Grid的
x
y
w
h
值以匹配原始Grafana布局
缺失数据源引用迁移后的仪表板引用了Perses中不存在的数据源名称部署前创建匹配的Perses数据源,或更新迁移后的JSON以引用已存在的Perses数据源名称

Anti-Patterns

反模式

Anti-PatternWhy It's WrongDo Instead
Deploying migrated dashboards without reviewing StaticListVariable placeholdersUsers see broken panels with placeholder values, lose trust in the migrationSearch all migrated files for
StaticListVariable
placeholders, document each, fix or remove before deploy
Running migration in offline mode when online mode is availableOffline mode uses bundled plugin migration logic which may be outdated — misses latest panel type mappingsAlways prefer
--online
when a Perses server is reachable; offline is a fallback, not a default
Deleting original Grafana JSON files after migrationNo rollback path if migration output is wrong, no way to re-run with updated
percli
version
Keep originals in a
grafana-originals/
directory alongside migrated output — storage is cheap, re-migration is not
Batch migrating everything at once without prioritizationCritical dashboards get the same attention as abandoned test dashboards, errors pile upPrioritize by usage: migrate the top 5-10 most-viewed dashboards first, validate thoroughly, then batch the rest
Migrating dashboards without first checking Grafana versionWasted effort — older Grafana JSON schemas produce broken or empty Perses outputRun
curl /api/health
or check
version
in the Grafana API response before starting any migration
反模式问题所在正确做法
未检查StaticListVariable占位符就部署迁移后的仪表板用户会看到包含占位符的损坏面板,失去对迁移结果的信任在所有迁移文件中搜索
StaticListVariable
占位符,记录每个占位符,修复或移除后再部署
在线模式可用时仍使用离线模式离线模式使用的插件迁移逻辑是快照版本,可能滞后数周或数月——服务器端会持续添加新的面板类型映射只要Perses服务器可用,就优先使用在线模式;离线模式仅作为 fallback
迁移后删除Grafana原始JSON文件若迁移输出存在问题,将没有回滚路径,重新迁移的成本极高将原始文件保存在
grafana-originals/
目录中,与迁移输出放在一起——存储成本低廉,重新迁移的代价却很高
不做优先级区分,一次性批量迁移所有仪表板关键仪表板与废弃的测试仪表板得到相同的关注,错误堆积按使用频率排序:先迁移前5-10个最常访问的仪表板,彻底验证后再批量迁移其余的
迁移前未检查Grafana版本白费力气——旧版Grafana JSON架构会生成损坏或空的Perses输出迁移前运行
curl /api/health
或检查Grafana API响应中的
version
字段

Anti-Rationalization

反合理化借口

RationalizationRealityRequired Action
"The migration completed without errors so it's correct"
percli migrate
succeeds even when panels are replaced with StaticListVariable placeholders — zero errors does not mean zero data loss
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 continuouslyUse 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 deployFix 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 unusableVisually verify every migrated dashboard in the Perses UI before declaring migration complete
合理化借口实际情况必要操作
“迁移完成且无错误,所以结果是正确的”即使面板被替换为StaticListVariable占位符,
percli migrate
也会显示成功——零错误不代表零数据丢失
对比面板数量:比较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
    percli migrate
    without extracting
    .dashboard
    — the envelope metadata will cause parse failures
  • NEVER use
    percli migrate
    on Grafana JSON from versions below 9.0.0 — the output will be silently wrong or empty
  • NEVER deploy migrated dashboards to production without running
    percli lint
    — structural errors will break the Perses UI
  • 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
    ——输出会静默出错或为空
  • 绝对禁止未运行
    percli lint
    就将迁移后的仪表板部署到生产环境——结构错误会导致Perses UI崩溃
  • 绝对禁止在确认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

导出单个仪表板:
```bash

Export 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

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"
done
Gate: Grafana dashboard JSON files available,
.dashboard
key extracted, Grafana version confirmed 9.0.0+. Proceed to Phase 2.
curl -H "Authorization: Bearer <token>"
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文件,已提取
.dashboard
字段,已确认Grafana版本为9.0.0+。进入阶段2。

Phase 2: CONVERT

阶段2:转换

Goal: Convert Grafana JSON to Perses format.
bash
undefined
目标:将Grafana JSON转换为Perses格式。
bash
undefined

Single 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
undefined

Lint 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
undefined

Ensure 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

参考资源