TT Lab
はじめる
学ぶ 学習パス コース

Grafana — ダッシュボードは問いだ

タグを一つ足すためにファイルを直した

TT Labで続きを見る

目標

ダッシュボードのバージョンと保存メッセージを読み、2つの版の差を人が読める形で取り出し、データソースを変数に切り出して移せるようにしたあと、ファイルが原本になるように変えて、ファイルと画面が同じかどうかを自分で検査するツールまで作ります。

なぜ重要なのか

ダッシュボードをリポジトリに置いておくだけだと、半年後には、画面とファイルが完全に違っています。誰にも、ファイルを直す理由がなく、画面で直すことを止めるものもないからです。ファイルから提供されるようにすると、そのときから、画面での保存が止まり、ダッシュボードを変える唯一の道が、ファイルになります。不便に見えるその制約が、画面とファイルが分かれる道をなくします。そして、バージョンが残っているという事実と、何が変わったのかがわかるという事実は、別のものです。保存のたびに変わるフィールドを取り除かないと、diffはまるごと赤くなって、何も教えてくれません。

ステップ

  1. lab-start-grafanaでGrafanaを起動し、/opt/lab/gfd/gfd-as-code/start.jsonをアップロードしてください(uidgfd-code)。次に、パネル1のタイトルを지금 요청률(韓国語のタイトルは「いまのリクエストレート」という意味です)に変えて、保存メッセージを10文字以上付けて、もう一度保存してください。
  2. 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つの値とも、応答に書かれているとおりに書き写します。
  3. /root/gfd-as-code/normalize.pyを作成してください。ダッシュボードJSONファイルのパスを引数に受け取って、ダッシュボードの本体だけ({"dashboard": ...}で包まれていれば、外して)を残し、最上位のversion・id・iterationを取り除き、キーをソートして、標準出力に出力する必要があります。パネルのidは残します。
  4. /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文字以上で書いてください。
  5. 存在しないデータソースuidでクエリを投げてみて、返ってくるHTTPコードと、このPodの実際のprometheusデータソースのuidを、/root/gfd-as-code/05-uid.txtに、missing_status=とds_uid=の2行で書いてください。次に、DSという名前のdatasourceタイプのテンプレート変数(対象はprometheus)を作り、2つのパネルがどちらもその変数(${DS})を指すように変えて、保存してください。
  6. 今のダッシュボードを正規化して/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が真になります。
  7. 今のダッシュボードをそのまま、もう一度保存してみて、返ってくるHTTPコードと、応答本文のmessageを、/root/gfd-as-code/07-blocked.txtに、status=とmessage=で書いてください。そして、procedure=の行に、今後このダッシュボードを変えるには、何を直して、何をやり直す必要があるかを、40文字以上で書いてください。
  8. ダッシュボードに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行を書いてください。

参考

保存メッセージなしで変えると、何も残らない

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)を渡すと落ちる必要があります。何を渡しても通過する検査ツールは、ないよりも悪いです。