とことんDevOps | 日本仮想化技術のDevOps技術情報メディア

DevOpsに関連する技術情報を幅広く提供していきます。

日本仮想化技術がお届けする「とことんDevOps」では、DevOpsに関する技術情報や、日々のDevOps業務の中での検証結果、TipsなどDevOpsのお役立ち情報をお届けします。
主なテーマ: DevOps、CI/CD、コンテナ開発、IaCなど
読者登録と各種SNSのフォローもよろしくお願いいたします。

自宅のインフラ環境をIaCとCircleCIで管理

この記事は、CircleCI Advent Calendar 2022 12日目の記事です。

さて、我が家では一部スマートホーム化が進んでいます。照明のオンオフ、気温や湿度の管理、人の出入りの監視などです。音声やスマホアプリから操作しているので、現在の状態や、なぜそうしたのかというエビデンスがどこにも残っていません。誰が照明をつけたのか、いつからついているのか、消していいのかの判断に困るわけです。これらの問題を解決するためにInfrastructure as Code(IaC)を使用して、コードでインフラの状態を管理していきたいと思います。

とりあえず簡単なところで照明のスイッチからIaC化していきたいと思います。

やりたいこと

GitHubにコードをPush → CircleCIがAPIをキック → 照明オンオフ

必要なもの

SwitchBot Botの設定

SwitchBotはトークンとシークレットがあれば、API経由で操作することができます。

Getting Startedの手順に従ってトークンとシークレットが取得できました。以下が実際に行った手順

  1. SwitbhBot Appをダウンロードし、お手持ちのスマートフォンにインストールしてください。
  2. SwitchBotアカウントと作成し、ログインしてください。
  3. アプリを開いて、プロフィール > 設定と移動し、「アプリバージョン」を10回タップしてください。
  4. 「開発者向けオプション」が出てくるので、そこをタップするとトークンとクライアントシークレットが表示されます。メモしておいてください。

操作対象のデバイスIDを取得します。

token='メモしたトークン'
secret='メモしたクライアントシークレット'
t=$(date +%s%3N)
nonce=$(uuidgen)
sign=$(echo -n "$token$t$nonce" | openssl dgst -binary -sha256 -hmac "$secret" | base64)
curl -Ss -H "Authorization: $token" -H "t: $t" -H "nonce: $nonce" -H "sign: $sign" https://api.switch-bot.com/v1.1/devices

以下のようなJSON文字列が返ってくるので、操作対象のdeviceIdをメモ。

{
  "statusCode": 100,
  "body": {
    "deviceList": [
      {
        "deviceId": "XXXXXXXXXXXX",
        "deviceName": "Device 1",
        "deviceType": "Hub Mini",
        "hubDeviceId": "000000000000"
      },
      {
        "deviceId": "XXXXXXXXXXXX",
        "deviceName": "SwitchBot Bot",
        "deviceType": "Bot",
        "enableCloudService": true,
        "hubDeviceId": "XXXXXXXXXXXX"

      },
      ...
    ]
  },
  "message": "success"
}

GitHubの設定

適当なリポジトリを用意して手元にClone。

CircleCIのワークフローは以下のようにしました。.circleci/config.ymlに保存します。

version: 2.1

jobs:
  generate-sign:
    docker:
      - image: cimg/base:2022.11
    working_directory: ~/workspace
    steps:
      - run: |
          t=$(date +%s%3N)
          nonce=$(< /proc/sys/kernel/random/uuid)
          sign=$(echo -n "$TOKEN$t$nonce" | openssl dgst -binary -sha256 -hmac "$SECRET" | base64)
          echo "export T=$t" >> sign-output
          echo "export NONCE=$nonce" >> sign-output
          echo "export SIGN=$sign" >> sign-output
      - persist_to_workspace:
          root: ~/workspace
          paths:
            - sign-output

  bot-action:
    docker:
      - image: cimg/base:2022.11
    working_directory: ~/workspace
    steps:
      - checkout
      - attach_workspace:
          at: ~/workspace
      - run: |
          source ./bot.conf
          source ./sign-output
          curl -X POST \
               -H "Content-Type: application/json; charset=utf8" \
               -H "Authorization: $TOKEN" \
               -H "t: $T" \
               -H "sign: $SIGN" \
               -H "nonce: $NONCE" \
               -d '{"command": "'$command'", "paramter": "default", "commandType": "default"}' \
               "https://api.switch-bot.com/v1.1/devices/$BOT_DEVICE_ID/commands"

workflows:
  version: 2
  bot-action:
    jobs:
      - generate-sign
      - bot-action:
          requires:
            - generate-sign

ジョブを簡単に説明すると、generate-signというジョブでAPIの認証情報を生成しています。認証情報はsign-outputというファイルに保存して、bot-action側でsourceすることで認証情報の受け渡しを行なっています。

そのうちカーテンとか開けたくなるかもしれないので、認証情報生成のジョブは分けておきました。

bot-actionではsign-output以外にもリポジトリに含まれるbot.confというファイルをsourceしています。これはbot-actionで実行するコマンドを指定します。

command=turnOn
# command=turnOff
# command=press

bot.confの中身はbashが解釈できる変数である必要があるので、=の前後にはスペースを入れないでください。指定できるコマンドは以下で確認できます。

ここまできたら.circleci/config.ymlbot.confをGitHubにPushしておきます。

CircleCIの設定

GitHubと連携するのでGitHubアカウントでCircleCIにログインしました。

GitHubと連携するとGitHubの設定で作成したリポジトリが見えると思います。「Set Up Project」から「Fastest:Use the .circleci/config.yml in my repo」を選択し、「From which branch」に「main」といれて、セットアップを完了します。

連携が完了するといきなりワークフローが動き出しますが、CircleCIに環境変数を設定していないのでコケますね。「Project Settings」を開くと左メニューに「Environment Variables」というのがあるので、そこから環境変数を設定していきます。

「Add Environment Variable」をポチると環境変数を追加していけるので以下の表の通り3つ環境変数を作っていきます。

Name Value
TOKEN メモしたトークン
SECRET メモしたクライアントシークレット
BOT_DEVICE_ID メモしたdeviceId

FailedしたジョブをRerunしてあげると完走します。

実際に動いてる動画は以下より

youtu.be

まとめ

自宅のインフラ環境をIaCで管理できるようになりました。こんな感じでエビデンスを残すことができます。

Pull Requestを利用するのも面白いかもしれないですね。

画像を見てお気づきかもしれませんが、照明を消したログがありませんね?つい癖で手作業してしまいました。こうなるとリポジトリの状態と照明の状態が狂ってしまうので気をつけなければいけません。IaCあるあるだと思います。こうなった場合は、コードを変更するわけにはいかないのでgit commit --allow-emptyで変更のないままCommitしておきます。