Open

CircleCI実践入門本でつまずいたところ

17

目的

Terraformでつまずいた部分をまとめておきます。
CircleCI実践入門本でつまずいた部分をまとめておきます。

https://gihyo.jp/book/2020/978-4-297-11411-4
初めてのスクラップなのでまだまだ手探りですが、使いながら学んでいこうと思います。

State Lockingを導入しようとしたら Requested resource not foundエラーで躓いた

概要

躓いたのは上記の本の8.6 Terraformで内容としては、CircleCIでTerraformを実行させてAWSのEC2インスタンスを作成させるという内容です。

https://github.com/circleci-book/terraform-sample
細かい中身は筆者のGithubリポジトリを見てもらえればと思いますが、git pushされましたらTerraformの実行結果はSlackなど別に出力させる場合に使われるtfnotifyをインストールして、masterブランチならterraform apply、それ以外ならterraform planを実行させるconfig.ymlが記述されています。
技術書の中身を吟味しながら自分のGithubにforkして環境変数部分は変更した上で、git pushしてCircleCIを実行させてのですが、以下のようなエラーが発生しました。
#!/bin/sh -eo pipefail
terraform apply -auto-approve   | tee "$TFNOTIFY_LOG"
Acquiring state lock. This may take a few moments...

Error: Error locking state: Error acquiring the state lock: 2 errors occurred:
	* ResourceNotFoundException: Requested resource not found
	* ResourceNotFoundException: Requested resource not found



Terraform acquires a state lock to protect the state from being written
by multiple users at the same time. Please resolve the issue above and try
again. For most commands, you can disable locking with the "-lock=false"
flag, but this is not recommended.



Exited with code exit status 1
CircleCI received exit code 1

Requested resource not foundと出ており、何かしらのリソースが見つからないというエラーが出ています。
一度ローカルマシン上でTerraformを実行して動きを確認しましたが、同じエラーが出てくる結果となりました。
原因が分からず、Stack Overflowに質問してみることにしました。

https://stackoverflow.com/questions/66245221/terraform-error-error-locking-state-error-acquiring-the-state-lock-2-errors-o

解決

回答があり内容を見ますと、State Locking導入のS3のバックエンド宣言が原因っぽい書き込みがありました。
書籍では事前にS3の作成を済ました前提で記載されていますが、State Lockingを利用できるようにするにはS3とDynamoDBを事前に作成してからS3バックエンドの宣言をmain.tfに記述する必要があるようです。
なのでまずはmain.tfの中身を以下のようにしてgit pushします。

main.tf
# Specify the provider and access details
provider "aws" {
  region  = "ap-northeast-1"
  profile = "default"
}

resource "aws_dynamodb_table" "dynamodb-terraform-state-lock" {
  name           = "terraform-state-lock-dynamo"
  hash_key       = "LockID"
  read_capacity  = 20
  write_capacity = 20

  attribute {
    name = "LockID"
    type = "S"
  }

  tags = {
    Name = "DynamoDB State Lock Table"
  }
}

CIが問題なく最後まで処理が完了し、DynamoDBの作成が確認できましたら、S3のバックエンド宣言とEC2インスタンスの作成をmain.tfに記述していきます。

main.tf
# Specify the provider and access details
provider "aws" {
  region  = "ap-northeast-1"
  profile = "default"
}

terraform {
  backend "s3" {
    key            = "terraform.tfstate"
    bucket         = "circleci-book-terraform-sample-yuta"
    region         = "ap-northeast-1"
    dynamodb_table = "terraform-state-lock-dynamo"
  }
}

# 一度作成したらコメントアウトしておく
#resource "aws_dynamodb_table" "dynamodb-terraform-state-lock" {
#  name           = "terraform-state-lock-dynamo"
#  hash_key       = "LockID"
#  read_capacity  = 20
#  write_capacity = 20
#
#  attribute {
#    name = "LockID"
#    type = "S"
#  }
#
#  tags = {
#    Name = "DynamoDB State Lock Table"
#  }
#}

resource "aws_instance" "web" {
  instance_type = "t3.small"
  # Amazon Linux2
  ami   = "ami-0992fc94ca0f1415a"
  count = 1
  tags = {
    Name = "EC2 instance terraform"
  }
}

この時DynamoDB記述箇所をコメントアウトしていないとエラーが出ますので、コメントアウトしておきます。

#!/bin/sh -eo pipefail
terraform apply -auto-approve   | tee "$TFNOTIFY_LOG"
Acquiring state lock. This may take a few moments...
aws_instance.web[1]: Creating...
aws_instance.web[0]: Creating...
aws_dynamodb_table.dynamodb-terraform-state-lock: Creating...
aws_instance.web[1]: Still creating... [10s elapsed]
aws_instance.web[0]: Still creating... [10s elapsed]
aws_instance.web[0]: Creation complete after 18s [id=i-01041160d4458b7e7]
aws_instance.web[1]: Creation complete after 18s [id=i-0cf7c55a431f7ac3b]

Error: error creating DynamoDB Table: ResourceInUseException: Table already exists: terraform-state-lock-dynamo


Releasing state lock. This may take a few moments...

Exited with code exit status 1
CircleCI received exit code 1

こちらをmaster以外のブランチでgit pushし、GithubのプルリクにTerraformの出力結果を表示させてmasterブランチにmergeさせます。

mainブランチでCIが実行されますとterraform applyが動き、EC2インスタンスが作成されSlackにも実行結果が通知されることが確認できました。

reviewdogでGitHubにプルリクを送れない問題

11章のさまざまなタスクの自動化で11.6のドキュメントの校正に関する部分で分からないところがありました。
textlintとreviewdogを使って、GitHubレポジトリで管理しているドキュメントの校正を自動で行うようにCIを構築するという内容です。
textlintはJSで記述されたOSSであり、テキストファイルの検査を行うことができ、プラグインを活用することで英語、日本語、中国語などのドキュメントの校正を行うことが出来ます。

https://github.com/textlint/textlint
https://github.com/textlint/textlint/wiki/Collection-of-textlint-rule
textlintで検知した実行結果をGitHubにプルリクしてくれるものがreviewdogと呼ばれるGoで記述されたOSSです。(アイコン可愛い)
https://github.com/reviewdog/reviewdog
以下のように、.config.ymlにtextlintとreviewdogの処理を実行させるようにして、README.MDの記載に問題があればプルリクを出せるようにしてあります。
.config.yml
      - run:
          name: "textlintをインストールする"
          command: npm install --save-dev textlint textlint-rule-no-mix-dearu-desumasu
      - run:    
          name: "依存モジュールをインストールする"
          command: npm install
      - run:
          name: "reviewdogをインストールする"
          command: |
            curl -sfL https://raw.githubusercontent.com/reviewdog/reviewdog/master/install.sh| sh -s
      - run: # (d1)
          name: "textlintをREADME.mdに対して実行する"
          command: npx textlint -f checkstyle README.md >> .textlint.log
      - run: # (d2)
          name: "reviewdogを実行する"
          when: on_fail
          command: |
            cat .textlint.log | ./bin/reviewdog -f=checkstyle -name="textlint" -reporter="github-pr-review"
workflows:
  version: 2
  proofreading:
    jobs:
      - proofreading_job
README.MD
# textlint-reviewdog-sample
[![CircleCI](https://circleci.com/gh/circleci-book/textlint-reviewdog-sample.svg?style=svg)](https://circleci.com/gh/circleci-book/textlint-reviewdog-sample)

[CircleCI実践入門](https://gihyo.jp/book/2020/978-4-297-11411-4)の11章「ドキュメントの校正」におけるサンプルコードです。

この文は敬体である。この文は常体だ。

参考
- https://github.com/azu/textlint-reviewdog-example

またreviewdogがプルリクのコメントを書き込むためにGitHubトークンが必要なので、事前にCircleCI側の環境変数REVIEWDOG_GITHUB_API_TOKENを設定しています。
もう一つ事前に必要な設定で、Only build pull requestsをオンにします。

この状態でgit pushをしてCircleCIを回しましたが、reviewdogがプルリクを作れないというメッセージが出ました。

#!/bin/bash -eo pipefail
cat .textlint.log | ./bin/reviewdog -f=checkstyle -name="textlint" -reporter="github-pr-review"
reviewdog: this is not PullRequest build.
CircleCI received exit code 0

現在StackOverflowで問い合わせており、解決出来たら更新する予定です。

https://stackoverflow.com/questions/66309574/reviewdog-this-is-not-pullrequest-build

https://github.com/reviewdog/reviewdog/blob/009ce60fe8e418387b2f9f7a89f360eb24306b46/cienv/cienv.go#L33
https://github.com/reviewdog/reviewdog/blob/009ce60fe8e418387b2f9f7a89f360eb24306b46/cmd/reviewdog/doghouse.go
ちょっとソースコード golang なので、興味湧いて追ってみました。多分今回こそ正解に近い気がします。
(FB 書きにくいので、ここに書きます。)

参考資料として二点です。
Circle CI の環境変数書き方

reviewdog の書き方例

その参考資料とソースコードを基に、
下記を reviewdog の前のステップに加えます。

      - run:
          name: Update PATH and Define Environment Variable at Runtime
          command: |
            echo 'export CIRCLE_PROJECT_REPONAME =reviewdog' >> $BASH_ENV
            echo 'export CIRCLE_PROJECT_USERNAME=hogehoge' >> $BASH_ENV
            echo "export CIRCLE_SHA1 =$CIRCLE_SHA1" >> $BASH_ENV
            source $BASH_ENV

(CIRCLE_PROJECT_REPONAME は CI_REPO_NAME にしても問題ないはずです。他も同義)

余裕があれば、上のステップの前に、これらのキーの中身が空かどうか見ておきたいですねw
なぜなら、作り上、定義しなくて済む方法はあるように見えます。
何かしらの理由で、いずれかが欠落したかもしれません。

      - run:
          name: confirm current Environment Variable at Runtime
          command: |
            echo $CIRCLE_PROJECT_REPONAME
            echo $CIRCLE_PROJECT_USERNAME
            echo $CIRCLE_SHA1

もともとこれらの環境変数には値がデフォルトで入っていますね。

Using build environment variables:
  BASH_ENV=/tmp/.bash_env-603518182415f763cb771860-0-build
  CI=true
  CIRCLECI=true
  CIRCLE_BRANCH=master
  CIRCLE_BUILD_NUM=31
  CIRCLE_BUILD_URL=https://circleci.com/gh/Yuhta28/textlint-reviewdog-sample/31
  CIRCLE_COMPARE_URL=
  CIRCLE_JOB=proofreading_job
  CIRCLE_NODE_INDEX=0
  CIRCLE_NODE_TOTAL=1
  CIRCLE_PREVIOUS_BUILD_NUM=30

  CIRCLE_PROJECT_REPONAME=textlint-reviewdog-sample
  CIRCLE_PROJECT_USERNAME=Yuhta28

  CIRCLE_REPOSITORY_URL=git@github.com:Yuhta28/textlint-reviewdog-sample.git

  CIRCLE_SHA1=63f014f671388d293ba4ad1cc5db3952570bc5a6

  CIRCLE_SHELL_ENV=/tmp/.bash_env-603518182415f763cb771860-0-build
  CIRCLE_STAGE=proofreading_job
  CIRCLE_USERNAME=Yuhta28
  CIRCLE_WORKFLOW_ID=5ebabc47-fde0-46c2-8065-74446ac44b4d
  CIRCLE_WORKFLOW_JOB_ID=aad4b5b3-95aa-4281-9075-c0bf027ba31e
  CIRCLE_WORKFLOW_UPSTREAM_JOB_IDS=
  CIRCLE_WORKFLOW_WORKSPACE_ID=5ebabc47-fde0-46c2-8065-74446ac44b4d
  CIRCLE_WORKING_DIRECTORY=~/project

Using environment variables from project settings and/or contexts:
  CIRCLE_JOB=**REDACTED**
  GITHUB_USER=**REDACTED**
  NPM_TOKEN=**REDACTED**
  REVIEWDOG_GITHUB_API_TOKEN=**REDACTED**

The redacted variables listed above will be masked in run step output.

SHA1にセットしようとしたらエラーが出たので、これだけ除外してやりましたが、結果変わらずでしたね(;_;)

#!/bin/bash -eo pipefail
echo 'export CIRCLE_PROJECT_REPONAME=reviewdog' >> $BASH_ENV
echo 'export CIRCLE_PROJECT_USERNAME=hogehoge' >> $BASH_ENV
echo "export CIRCLE_SHA1 =$CIRCLE_SHA1" >> $BASH_ENV
source $BASH_ENV
/tmp/.bash_env-603517ae3a1256421d7c4ec6-0-build: line 3: export: `=7653c8a1ebd1392ffd27f271ca5dd02294a2def3': not a valid identifier

Exited with code exit status 1
CircleCI received exit code 1

echoで確認したらemptyでした。
ここにPR番号をセットする必要がありそうですが、どうやってセットすればいいのか(汗)
聞いてみようと思います。

CI それぞれの問題はissueより、CIの問題で探した方が早いかもしれません。

https://qiita.com/jkkitakita/items/4554a965e86d376e3ecd

circleci 2.0 なら、CIRCLE_PULL_REQUEST が使えるみたいです。

https://support.circleci.com/hc/en-us/articles/360047521451-Why-is-CIRCLE-PR-NUMBER-empty-

https://github.com/reviewdog/reviewdog#common-jenkins-local-etc
ここを見ると、-guessオプションをつけるとPRのIDを推測してくれるっぽいのですが、わかったところで次に続かないところで足踏みしてます。
#!/bin/bash -eo pipefail
cat .textlint.log | ./bin/reviewdog -f=checkstyle -name="textlint" -reporter="github-pr-review" -guess
reviewdog: PullRequest not found, query: type:pr state:open repo:*******/textlint-reviewdog-sample head:master 9f86c65c0f24f62c7dcab6f83eef7ef8993d2008
reviewdog: this is not PullRequest build.
CircleCI received exit code 0

あー悲しみ😰

まぁ、エンジニアライフあるあるですねw

CIRCLE_PULL_REQUEST は echo で取れそうでしょうか?

残念ながら空みたいでecho打っても何も表示されないですね😿

最終的には学んだ事を応用してこのzennをローカルエディターで書いてGitHubリポジトリに管理して、文章校正を自動で行うようにしたかったですが、textlintだけ入れてみようと思います。

一回ここまできたら、PR 番号の直書きしてみてはいかがでしょうか?
本当に reviewdog は PR みに行ってくれるかの検証です。
またこれでもエラー出たら、作者にバグ報告できるかもしれません。

同じくreviewdog の前のステップで、以下を加えます。
(9999は対象のPRの番号に変えて)

      - run:
          name: Define CIRCLE_PR_NUMBER Environment Variable at Runtime
          command: |
            echo 'export CIRCLE_PR_NUMBER =9999' >> $BASH_ENV
            source $BASH_ENV

PRの番号ってどこから取得できるのですか?
reviewdogがプルリクしてくれないので、PR番号の発行ができないから多分失敗しているように思いまして、先にPR番号を手動でセットだと思うのですが、そうした場合そもそも存在しないPR番号を探すという矛盾が発生しているような気がしてしまいまして🤔

あれ?今回の CI のトリガーはどれかの PR じゃないですか?

この例のように、

https://blog.toshimaru.net/reviewdog-rubocop-github-actions/#実際に動かしてみたpull-request

1.この PR が CI を発火します。(16が番号です)

https://github.com/toshimaru/Test/pull/16

2.CI build 始めます。
3.結果を見て、このPR の差分の箇所にコメントが作られます。

ユータさんは以下と認識しているようですが、

textlintで検知した実行結果をGitHubにプルリクしてくれるものがreviewdogと呼ばれるGoで記述されたOSSです。

調べたところ、公式の github のページの英語もそうですが、

各種linterの実行結果をプルリクエストのコメントで指摘してくれます。
https://dev.classmethod.jp/articles/shuntaka-github-actions-reviewdog/

もしかすると私がいろいろと勘違いしていたかもしれません。
①実行していたCircleCIのブランチはマスターでした。

私が初歩的な勘違いをしていましたが、同一レポジトリ、同一ブランチ内でPRを出すことはできなくて作成失敗しているような気がします。
②上記のgit pushを実行してから、GitHub上で新規ブランチを作成して適当にファイル内改行をしてPRを出しました。

③PRを出したらCircleCIが実行されましたが、reviewdogでparse errorが実行されるという結果になりました。

私のイメージでは、CircleCI内のreviewdogがtextlintなどのlinterツールが出力した内容を基にGitHubのPRを自動生成してくれると思ってましたが、そういうことではなくてトピックブランチからマスターへPRを出す時にCircleCI内のreviewdogが動いて自分で作ったPRにコメントが追記されるものなのかなと思いました。

課題

ただそれでも最後に書かれている通りparse errorが出てしまい、linterの出力結果がPRに載らないのでもう少し調査してみる必要がありそうです。

今日は vscode の extension の remote-container 試したくて、試す課題として、この件を追ってみました。

ここでこけると言うことは、textlint の問題です。
試したい remote-container に textlint 入れてみました。

操作してみたら、ユータさんのkeyword が辞書に入っていないのと、
おそらく、最初の段階、module もいれていない可能性はあります。

      - run:
          name: "textlintをインストールする"
          command: npm install --save-dev textlint textlint-rule-no-mix-dearu-desumasu

以下のように変える必要があるのと、

      - run:
          name: "textlintをインストールする"
          command: npm install --save-dev textlint textlint-rule-common-misspellings

README.md の先頭に it is abouta. でも入れてみたら、キャッチしてくれると思います。
output

CI のエラーのデバッグが手間かかるので、ローカルでできることを使い捨ての docker で立てて試すと答えが見えることが多いと思います〜

ログインするとコメントできます