Feedforce Developer Blog

フィードフォース開発者ブログ

OSS 版 Spectacles を使って、LookML の data tests や validation などを GitHub Actions で継続的に実行させてみた

こんにちは。自称 Looker エバンジェリストid:masutaka26 です。

今日は Spectacles というツールを導入して、Looker インスタンスの健全性を高められた話を紹介します。

Spectacles とは

Spectacles は Looker のサードパーティ CI ツールです。継続的に各種テストを実行し、Looker インスタンスを健全に保つことが出来ます。

クラウド版と OSS 版があり、それぞれ過去にクラスメソッドや、Zenn の記事で紹介されたことがあります。

今回は OSS 版を使いました。

github.com

4 種類のテスト

2022 年 9 月時点で 4 種類のテストが実装されています。

  • SQL validation
    • 全ての Dimension の sql パラメーターについて、実際にクエリを実行し、その有効性を検証する
    • data warehouse のリソースを過剰に使わないよう工夫されている。例えば BigQuery の料金は発生しない1
  • Assert validation
    • LookML IDE 上でも実行できる LookML data tests を実行する
  • Content validation
    • 開発メニューの Content Validator 相当の検証を行い、エラーのある Dashboard や Look を特定する
  • LookML validation
    • LookML IDE 上でも実行できる LookML validation を実行する

基本的な振る舞い

Spectacles は Looker API を使用し、指定した Looker インスタンス上で、LookML data tests や validation などを実行します。

Spectacles -(Looker API)-> Your Looker Instance

いわゆるユニットテストでは、テスト環境でソースコードを checkout し、そこでテストを実行しますが、Spectacles はその点は全く違います。

つまり GitHub Actions 等の CI で動かす場合、LookML コードの checkout は不要ということです。

どのテストを採用し、どのような課題を解決したのか

SQL validation

いきなりですが、こちらは今回採用出来ませんでした。

我々の環境で全ての Explore をテスト対象にすると、かなりの数のテストが失敗します。hidden: yes な Dimension がおそらく全てです。想定内です。

$ spectacles sql --project my_project_name --profile -v

それならばと、--ignore-hidden オプションを付けると、今度はこんなエラーが発生します。どうやら 1 つも Dimension が表示されない Explore があるようです。こちらも想定内です。

Explore object is missing dimensions, meaning this query won't have fields and will error. Often this happens because you didn't include dimensions when you built the project.

--explore オプションでエラーが発生しない Explore を指定すればよいのですが、Explore が 150 個以上ある関係で、切り分けができていません。

sql パラメーターは壊れていても、実際に Explore で当該 Dimension が使われないとエラーにならないのと、そのエラーが報告されるとも限らないので、いずれは再挑戦したいです。

Assert validation

我々の Looker インスタンスでは、BigQuery の外部テーブルに Google スプレッドシートを指定したテーブルを数多く参照しています。つまり人間が編集するデータです。このようなデータはオペミスにより壊れることがあり、primary_key も芋づる式に壊れることがあります。

primary_key はほぼ全てテストを書いています2が、約 250 個と数が多いです。一方で LookML IDE 上での data tests は同時実行数が 1 に制限されているようで、テストに 10 分以上かかります。commit 前のテストを必須にできない状態でした。そのため、時々テストを手動実行しないと、壊れたことに気づけない課題がありました。

以上の課題を解決するために、定期的に LookML data tests を実行し、手動実行せずに気付けるようになりました。

Content validation

今までは私の注意力で Dashboard 約 140 個と Look 約 30 個のエラー数ゼロを継続できていましたが、まさに属人的でした。

これも定期的に実行し、Content Validator を手動実行することなく気付けるようになりました。

LookML validation

時々 LookML IDE を介さず、ローカル環境で git commit してデプロイすることがあります。そのケースで大きな変更をすることはないものの、validation が通らない LookML がデプロイされる確率はゼロではありません。

こちらは git push のタイミングで実行することで、健全性を高めることが出来ました。

どのような GitHub Actions にしたのか

git push のタイミングで実行する CI workflow と、定期的に実行する Schedule workflow を作りました。

CI workflow

git push のたびに、当該 commit のブランチに対して、LookML validation のテストをしています3

name: CI

on:
  push:
    branches-ignore: # ①
      - 'dev-**'            # LookML IDE の個人用開発ブランチ
      - 'tmp_spectacles_**' # spectacles の --commit-ref オプションが作るブランチ

jobs:
  validate_lookml:
    name: Validate LookML files
    runs-on: ubuntu-latest
    timeout-minutes: 5 # デフォルトは 360 分。料金のスパイクを防ぐ
    concurrency: # ② spectacles が複数同時に実行しないようにする
      spectacles_should_be_run_in_series
    steps:
    - uses: actions/setup-python@v4
      with:
        python-version: '3.x'
    - name: Install Spectacles
      run: pip install spectacles
    - name: Run LookML Validator
      env:
        LOOKER_BASE_URL: "https://my_instance_name.looker.com"
        LOOKER_CLIENT_ID: ${{ secrets.SPECTACLES_LOOKER_CLIENT_ID }} # ③
        LOOKER_CLIENT_SECRET: ${{ secrets.SPECTACLES_LOOKER_CLIENT_SECRET }} # ③
      run: spectacles lookml --project my_project_name --commit-ref "$GITHUB_SHA" -v

①で特定のブランチを除外しています。特に今回のケースでは、tmp_spectacles_** を設定しないと validate_lookml ジョブが無限に起動し続けるため、絶対に必要です。

②も結構重要で、CI workflow と次に示す Schedule workflow から起動される spectacles プロセスの同時実行数を 1 に制限しています。

Spectacles は③と紐づく Looker ユーザーが実際に開発モードで tmp_spectacles_** というブランチを作り、切り替えます。Looker では 1 人のユーザーが同時に利用できるブランチは 1 つだけです。Spectacles の複数起動は問題が発生するため、今回の制限を設定しました。公式ドキュメントでも言及されています。

Schedule workflow

早朝と夕方に master(デフォルト)ブランチ上で、Content validation と LookML data tests を実行しています。

name: Schedule

on:
  schedule:
    - cron: "00 21 * * 0-4" # 平日の  6:00 JST
    - cron: "30  7 * * 1-5" # 平日の 16:30 JST

jobs:
  schedule:
    name: Scheduled job
    runs-on: ubuntu-latest
    timeout-minutes: 30 # デフォルトは 360 分。料金のスパイクを防ぐ
    concurrency: # ① spectacles が複数同時に実行しないようにする
      spectacles_should_be_run_in_series
    env:
      LOOKER_BASE_URL: "https://my_instance_name.looker.com"
      LOOKER_CLIENT_ID: ${{ secrets.SPECTACLES_LOOKER_CLIENT_ID }}
      LOOKER_CLIENT_SECRET: ${{ secrets.SPECTACLES_LOOKER_CLIENT_SECRET }}
    steps:
    - uses: actions/setup-python@v4
      with:
        python-version: '3.x'
    - name: Install Spectacles
      run: pip install spectacles
    - name: Run Content Validator
      run: spectacles content --project my_project_name -v
    - name: Run LookML data tests
      run: spectacles assert --project my_project_name -v

ブランチの時や、master ブランチへのマージ直後ではまだ Dashboard や Look がエラーになることがあるため、Content validation はこのタイミングにしています。

LookML data tests も 10 分以上かかることと、git push の粒度でやらないと不安というわけではないため、このタイミングにしています。BigQuery の料金もかかりますからね。

落ち穂拾い

作業ブランチのゴミが残ることがある

Spectacles が途中で異常終了すると、LookML IDE と GitHub に tmp_spectacles_b016c8a4dd といった、Spectacles が作る作業ブランチが残ることがあります。気づいたら削除してあげましょう。

正常終了の場合は残りません。

マシンユーザーを作るか作らないか

Looker はユーザー課金モデルであるため、Spectacles のためにユーザーを作ることに躊躇するかもしれません。私もそうでした。おまけに Developer 相当の権限が必要なため、そこそこの料金です。

Create a Looker API Key | Spectacles Docs

We strongly recommend creating a dedicated Spectacles user in Looker to ensure a human user doesn't accidentally change the Git branch or turn off development mode in the middle of a validation.

ですが、公式ドキュメントで強く奨励されているとおり、Spectacles 専用のユーザーを作って下さい。

人間のユーザーは権限が大きすぎますし、前述のとおり Spectacles は実際に開発モードでブランチを作って切り替えるため、人間の作業とコンフリクトします。

まとめ

Spectacles というツールを導入して、Looker インスタンスの健全性を高められた話をしました。

導入したのは先月ですが、導入の翌日にタイミング良く Schedule workflow のテストが落ち、primary_key が壊れたことに気づけたことにはニッコリしました。

私のようなボッチ LookML 開発者は、いかに作業を機械に任せるかが重要だと思います。心の平穏も大事です。また、あとから CI を導入するのは結構大変なので、始めから開発計画に組み込むことをオススメします。

それでは良い Looker ライフを!(^^)/


  1. Limiting Resource Consumption | Spectacles Docs

  2. Looker で Join 先の view の primary_key をいい感じにテストする方法をようやく見つけた - Feedforce Developer Blog

  3. 実際には他のジョブや、失敗時の Slack 通知ジョブもありますが、分かりやすくするために省略しています。