タグを一つ足すためにファイルを直した
目標
ダッシュボードのバージョンと保存メッセージを読み、2つの版の差を人が読める形で取り出し、データソースを変数に切り出して移せるようにしたあと、ファイルが原本になるように変えて、ファイルと画面が同じかどうかを自分で検査するツールまで作ります。
なぜ重要なのか
ダッシュボードをリポジトリに置いておくだけだと、半年後には、画面とファイルが完全に違っています。誰にも、ファイルを直す理由がなく、画面で直すことを止めるものもないからです。ファイルから提供されるようにすると、そのときから、画面での保存が止まり、ダッシュボードを変える唯一の道が、ファイルになります。不便に見えるその制約が、画面とファイルが分かれる道をなくします。そして、バージョンが残っているという事実と、何が変わったのかがわかるという事実は、別のものです。保存のたびに変わるフィールドを取り除かないと、diffはまるごと赤くなって、何も教えてくれません。
ステップ
lab-start-grafanaでGrafanaを起動し、/opt/lab/gfd/gfd-as-code/start.jsonをアップロードしてください(uidgfd-code)。次に、パネル1のタイトルを지금 요청률(韓国語のタイトルは「いまのリクエストレート」という意味です)に変えて、保存メッセージを10文字以上付けて、もう一度保存してください。http://127.0.0.1:3000/api/dashboards/uid/gfd-code/versionsを取得して、/root/gfd-as-code/02-versions.txtに3行書いてください。latest=は最新のバージョン番号、message=はそのバージョンの保存メッセージ、first_message=はバージョン1の保存メッセージです。3つの値とも、応答に書かれているとおりに書き写します。/root/gfd-as-code/normalize.pyを作成してください。ダッシュボードJSONファイルのパスを引数に受け取って、ダッシュボードの本体だけ({"dashboard": ...}で包まれていれば、外して)を残し、最上位のversion・id・iterationを取り除き、キーをソートして、標準出力に出力する必要があります。パネルのidは残します。/root/gfd-as-code/diff.shを作成してください。バージョン番号を2つ引数に受け取って、2つのバージョンを正規化してから比べ、同じなら何も出力せずに0で、違えば差を出力して、0以外の値で終わる必要があります。そして、bash /root/gfd-as-code/diff.sh 1 2の結果を見て、/root/gfd-as-code/04-diff.txtのchanged=の行に、どのパネルの何がどう変わったかを、20文字以上で書いてください。- 存在しないデータソースuidでクエリを投げてみて、返ってくるHTTPコードと、このPodの実際のprometheusデータソースのuidを、
/root/gfd-as-code/05-uid.txtに、missing_status=とds_uid=の2行で書いてください。次に、DSという名前のdatasourceタイプのテンプレート変数(対象はprometheus)を作り、2つのパネルがどちらもその変数(${DS})を指すように変えて、保存してください。 - 今のダッシュボードを正規化して
/root/gfd-as-code/dash/gfd-code.jsonに保存し、/root/gfd-as-code/provisioning/dashboards/lab.ymlに、そのフォルダーを読み込むプロビジョニング設定を書いたあと、GrafanaをGF_PATHS_PROVISIONING=/root/gfd-as-code/provisioningを指定して起動し直してください。ダッシュボードがファイルから来るようになると、取得応答のmeta.provisionedが真になります。 - 今のダッシュボードをそのまま、もう一度保存してみて、返ってくるHTTPコードと、応答本文の
messageを、/root/gfd-as-code/07-blocked.txtに、status=とmessage=で書いてください。そして、procedure=の行に、今後このダッシュボードを変えるには、何を直して、何をやり直す必要があるかを、40文字以上で書いてください。 - ダッシュボードに
gitopsタグを付けてください。ただし、ファイルを直して行う必要があります。そして、/root/gfd-as-code/verify.shを作成してください。ダッシュボードJSONファイルのパスを引数に受け取って(既定値は/root/gfd-as-code/dash/gfd-code.json)、そのファイルと今の画面を正規化して比べ、同じなら0、違えば0以外の値で終わる必要があります。最後に、/root/gfd-as-code/08-bundle.mdに、files=(リポジトリに載せるファイルの一覧)とrevert=(元に戻す方法、40文字以上)の2行を書いてください。
参考
- Grafanaは
lab-start-grafanaで起動します。ステップ6からは、プロビジョニングのパスを変えて、自分で起動し直します。 - 開始用のダッシュボードは
/opt/lab/gfd/gfd-as-code/start.jsonにあります。読むだけにしてください。ステップ8で、反例としてもう一度使います。 - バージョン一覧の応答の各項目には、そのバージョンの本体が
dataに一緒に入っています。 - プロビジョニング設定は、起動するときに1回だけ読み込まれます。ファイルを直したのに画面がそのままなら、起動し直していないのです。
- よくある間違い①は、起動し直すときに
GF_PATHS_DATAを忘れることです。バージョン履歴がまるごと消えます。 - よくある間違い②は、画面で直して、ファイルを直さないことです。ステップ6のあとは、画面での保存が止まるので、すぐに表に出ます。
- プロビジョニング · ダッシュボードJSONモデル · ダッシュボードHTTP API · 変数
保存メッセージなしで変えると、何も残らない
lab-start-grafanaでGrafanaを起動し、/opt/lab/gfd/gfd-as-code/start.jsonをアップロードしてください(uidgfd-code)。次に、パネル1のタイトルを지금 요청률(韓国語のタイトルは「いまのリクエストレート」という意味です)に変えて、保存メッセージを10文字以上付けて、もう一度保存してください。
保存APIの本文は{"dashboard": ..., "overwrite": true, "message": "..."}です。メッセージを抜くと、バージョン一覧に時刻だけが残ります。半年後に、このバージョンに戻すかどうかを判断する根拠がなくなるのです。
バージョン一覧が実際に残すもの
http://127.0.0.1:3000/api/dashboards/uid/gfd-code/versionsを取得して、/root/gfd-as-code/02-versions.txtに3行書いてください。latest=は最新のバージョン番号、message=はそのバージョンの保存メッセージ、first_message=はバージョン1の保存メッセージです。3つの値とも、応答に書かれているとおりに書き写します。
バージョン1のメッセージを見て、驚くかもしれません。自分で書いて送ったものと違います。それが、このステップで確認する事実です。jqでmax_by(.version)とselect(.version == 1)を、それぞれ取り出せば済みます。
2つの版を比べられるようにする
/root/gfd-as-code/normalize.pyを作成してください。ダッシュボードJSONファイルのパスを引数に受け取って、ダッシュボードの本体だけ({"dashboard": ...}で包まれていれば、外して)を残し、最上位のversion・id・iterationを取り除き、キーをソートして、標準出力に出力する必要があります。パネルのidは残します。
保存のたびに変わるフィールドが混ざっていると、diffがまるごと赤くなります。同じ入力にはいつも同じ出力が出る必要があるので、キーの順序を固定してください。Pythonのjson.dumpsには、そのオプションがあります。
何が変わったのか: 両方向で動く道具
/root/gfd-as-code/diff.shを作成してください。バージョン番号を2つ引数に受け取って、2つのバージョンを正規化してから比べ、同じなら何も出力せずに0で、違えば差を出力して、0以外の値で終わる必要があります。そして、bash /root/gfd-as-code/diff.sh 1 2の結果を見て、/root/gfd-as-code/04-diff.txtのchanged=の行に、どのパネルの何がどう変わったかを、20文字以上で書いてください。
バージョンごとの本体は、バージョン一覧の応答のdataに入っています。diffコマンドは、差があれば1で終わるので、その終了コードをそのまま使えば済みます。同じバージョンを2つ渡したときにも動くかどうかを、必ず試してみてください。片方向だけ動く道具は、「差がない」と「道具が壊れている」を区別してくれません。
移すとパネルが空になる理由
存在しないデータソースuidでクエリを投げてみて、返ってくるHTTPコードと、このPodの実際のprometheusデータソースのuidを、/root/gfd-as-code/05-uid.txtに、missing_status=とds_uid=の2行で書いてください。次に、DSという名前のdatasourceタイプのテンプレート変数(対象はprometheus)を作り、2つのパネルがどちらもその変数(${DS})を指すように変えて、保存してください。
データソースプロキシのパスは、/api/datasources/proxy/uid/<uid>/api/v1/queryです。存在しないuidを入れても、画面にはエラーではなく空のグラフとして見えます。そのため、移したときに原因を見つけにくいのです。変数はtemplating.listに入れ、パネルのdatasource.uidを、変数を参照する文字列に変えます。
ファイルが原本になるようにする
今のダッシュボードを正規化して/root/gfd-as-code/dash/gfd-code.jsonに保存し、/root/gfd-as-code/provisioning/dashboards/lab.ymlに、そのフォルダーを読み込むプロビジョニング設定を書いたあと、GrafanaをGF_PATHS_PROVISIONING=/root/gfd-as-code/provisioningを指定して起動し直してください。ダッシュボードがファイルから来るようになると、取得応答のmeta.provisionedが真になります。
プロビジョニング設定は、Grafanaが起動するときに1回だけ読み込まれます。ファイルを書いただけで起動し直さなければ、何も起こりません。設定にはapiVersion・providersが入り、options.pathが、ダッシュボードJSONが入ったフォルダーを指します。起動し直すときは、データフォルダー(GF_PATHS_DATA)をそのままにしておかないと、バージョン履歴が残りません。
もう画面では保存できない
今のダッシュボードをそのまま、もう一度保存してみて、返ってくるHTTPコードと、応答本文のmessageを、/root/gfd-as-code/07-blocked.txtに、status=とmessage=で書いてください。そして、procedure=の行に、今後このダッシュボードを変えるには、何を直して、何をやり直す必要があるかを、40文字以上で書いてください。
拒否されるリクエストなので、何も変わりません。安心して投げてみてください。応答コードは、curl -w '%{http_code}'で受け取れます。不便に見えるこの制約こそが、画面とファイルが分かれないようにする仕組みです。
応用: ファイルを直して画面を変え、2つが同じかを検査する
ダッシュボードにgitopsタグを付けてください。ただし、ファイルを直して行う必要があります。そして、/root/gfd-as-code/verify.shを作成してください。ダッシュボードJSONファイルのパスを引数に受け取って(既定値は/root/gfd-as-code/dash/gfd-code.json)、そのファイルと今の画面を正規化して比べ、同じなら0、違えば0以外の値で終わる必要があります。最後に、/root/gfd-as-code/08-bundle.mdに、files=(リポジトリに載せるファイルの一覧)とrevert=(元に戻す方法、40文字以上)の2行を書いてください。
ファイルを直したあとは、Grafanaに読み込み直させないと、画面に反映されません(前のステップでやったのと同じです)。検査ツールは、両方向で試してみてください。リポジトリのコピーを渡すと通過し、別のダッシュボードファイル(例: /opt/lab/gfd/gfd-as-code/start.json)を渡すと落ちる必要があります。何を渡しても通過する検査ツールは、ないよりも悪いです。