【ansible】blockinfileモジュール使用時、冪等性を担保するための注意点

# はじめに
先日はじめてansibleに触れました。
ansibleの特徴として、冪等性（べきとうせい）が保たれるという点がよく見受けられますが、
blockinfileモジュールを使用したときに、冪等性が保てないような動作になり少しハマってしまったポイントがあったので、今回はそこについてまとめていきたいと思います。

また、ここではansibleの細かい説明などは省かせていただきます。
どこかのタイミングでansibleビギナーに向けたまとめ記事なんかも書いてみたいです。

# そもそも「冪等性（べきとうせい）」とは？
私もここ最近ちゃんと意味を知った言葉なのですが、以下のような意味でありAWS公式でも解説されています。
> そもそも、べき等性とは、どういうことを言うのでしょうか ? これは「ある操作を 1 回行っても複数回行っても結果が同じである」ことをいう概念です。

参考：[サーバーレスが気になる開発者に捧ぐ「べき等性」ことはじめ](https://aws.amazon.com/jp/builders-flash/202104/serverless-idempotency/?awsf.filter-name=*all)

# 環境
今回ansibleを実行する環境は以下の通りです。
* ansible実行サーバ：AWSアカウント上のEC2（Amazon Linux2）★便宜上Aサーバとします
* ansibleバージョン：2.9.23
* 適用先サーバ：AWSアカウント上のEC2（Amazon Linux2）★便宜上Bサーバとします

※Dynamic Inventoryを使って、適用先サーバであるEC2インスタンスの情報を、動的に取得できるようになっています。
　Dynamic Inventory参考サイト：[[AWS]AnsibleのDynamic Inventoryを使って実行対象のEC2をタグ等で柔軟に指定する](https://dev.classmethod.jp/articles/ansible-dynamic-inventory-2/)

# やったこと
## playbookの作成
```ansible-blockinflie.yml```という名称でplaybookを作成します。

まずは以下のような内容で作成します。
```ansible-blockinflie.yml　①
- hosts: tag_Name_{EC2インスタンス名}
  user: ec2-user
  become: yes
  vars_files:
    - ../../config/common.yml

    - name: create file
      file:
        path: /home/ec2-user/create-file.txt
        state: touch

    - name: add to file
      blockinfile:
        path: /home/ec2-user/create-file.txt
        block: |
          test01
          add to file
```
これでAサーバの方でansibleを実行してみると、Bサーバでは以下のようなファイルが作成できました。

```
$ cat create-file.txt
# BEGIN ANSIBLE MANAGED BLOCK
test01
add to file
# END ANSIBLE MANAGED BLOCK
```
このままでももちろんいいのですが、テキストの前後に「# {BEGIN/END} ANSIBLE MANAGED BLOCK」という文字が入ってしまうのが気になりました。


## markerオプションの追加
なので次は以下のようにplaybookを変更してみました。
```ansible-blockinflie.yml　②
- hosts: tag_Name_{EC2インスタンス名}
  user: ec2-user
  become: yes
  vars_files:
    - ../../config/common.yml

    - name: create file
      file:
        path: /home/ec2-user/create-file.txt
        state: touch

    - name: add to file
      blockinfile:
        path: /home/ec2-user/create-file.txt
        marker: ""　　　　　　　　　　　　　　　★←追記
        block: |
          test01
          add to file
```
markerオプションを加えて""を指定してあげることで、テキストの前後に文字が挿入されることを防ぐそうです。

こちらもAサーバでansibleを実行して、Bサーバの方で作成できたファイルを確認してみました。
```
$ cat create-file.txt

test01
add to file
```
テキストの前後に文字が挿入されることなく、スッキリしました。
**しかしここでタイトルにもある通り、冪等性を保つことができなくなる動作が発生**してしまいます。

冪等性の検証のため、playbookには何も修正を加えずAサーバでansibleを実行し、再度Bサーバでファイルの確認をしてみました。すると、、
```
$ cat create-file.txt

test01
add to file

test01
add to file
```
**なんと、末尾に同じ文字列が追記されてしまいました。**
これではansibleを実行するたびにcreate-file.txtにどんどん文字列が追記されて行ってしまいます。

ここで、今更感はありますが、blockinfileモジュールのリファレンスをちゃんと見てみます。
リファレンス：[ansible.builtin.blockinfile module](https://docs.ansible.com/ansible/latest/collections/ansible/builtin/blockinfile_module.html#blockinfile-insert-update-remove-a-text-block-surrounded-by-marker-lines)

![キャプチャ.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/629857/279d4dbc-5b36-ad30-7397-ec8df4bb3ae4.jpeg)
翻訳してみると、、
>マーカー線のテンプレートです。
{mark}は、marker_begin (default="BEGIN") および marker_end (default="END") の値で置き換えられます。
{mark}変数なしでカスタムマーカーを使用すると、**その後のプレイブックの実行でブロックが繰り返し挿入される可能性があります。**

**《その後のプレイブックの実行でブロックが繰り返し挿入される可能性があります。》**

しっかり書いてありましたね。:sweat_smile:
リファレンスはちゃんと読みましょう。

デフォルトで挿入されてしまう文言だと少々いけてないと感じてしまったので、以下のようにカスタマイズして、再度playbookを更新します。
```ansible-blockinflie.yml　③
- hosts: tag_Name_mds_dev_someya_fluentd_temp
  user: ec2-user
  become: yes
  vars_files:
    - ../../config/common.yml
   
    - name: create file
      file:
        path: /home/ec2-user/create-file.txt
        state: touch

    - name: add to file
      blockinfile:
        path: /home/ec2-user/create-file.txt
        marker: "# {mark} add to file"　　　　　★←追記
        block: |
          test01
          add to file
```
再度Aサーバでansibleを実行し、Bサーバでファイルの確認を行います。

```
$ cat create-file.txt
# BEGIN add to file
test01
add to file
# END add to file
```
カスタマイズした文字列でマーカーが挿入されていますね。
ためしに何度かAサーバでansible実行してみましたが、末尾に追記されてしまうことなく、冪等性が保たれる状態となりました！

# さいごに
最終的にはplaybook①で作成したファイルのままmarkerオプション使わなければハマらなかったんじゃない？という話かもしれませんが、
私が実際にコーディングする際に調べながら試行錯誤していった流れを記載した方が、
よりオプションの役割についてわかるかなと思ったためあえてこの形で記載させていただきました。

何か動作がおかしいと感じたらすぐにリファレンスを見る！これは鉄則ですね。

今回はじめてansibleを触ってみましたが、難しい文法がたくさんあるというわけでもなく触りやすいなと感じました。
IaCツールの一つとして活用していけるように、これからも使い方については調べていきたいです。


# 参考
https://docs.ansible.com/ansible/latest/collections/ansible/builtin/blockinfile_module.html#blockinfile-insert-update-remove-a-text-block-surrounded-by-marker-lines

https://qiita.com/nakacya/items/a624f6710c3ca0edc8a9