ansible.builtin.copyモジュールのforce: falseではまった（ている）話

# はじめに

今回は、Ansibleで冪等性を保ちながらファイルをコピーする方法について、試行錯誤した結果についてご紹介します。

# 環境説明

```
ansible --version
ansible [core 2.17.4]
```

# やりたかったこと
WordPressの構築をAnsibleで自動化しようとしていました。その中の一部のタスクで、ダウンロードしたWordPressディレクトリの配下にあるファイルやディレクトリを、ドキュメントルートにコピーしたいと考えていました。

コピー元：`/var/tmp/wordpress/`
コピー先：`/var/www/documentroot/`

ここで、冪等性を考慮して、コピー元とコピー先に同名のファイルが存在する場合、コピー先を上書きしないように設定したいと思いました。

Ansibleの公式ドキュメントを調べたところ、`force: false`を指定すれば、この動作が実現できそうだと考えました。

https://docs.ansible.com/ansible/latest/collections/ansible/builtin/copy_module.html#parameter-force

> force 
> Influence whether the remote file must always be replaced.
> If `true`, the remote file will be replaced when contents are different than the source.
> If `false`, the file will only be transferred if the destination does not exist.

実際に設定したタスクは以下の通りです。
```
- name: Copy WordPress files to web root
  copy:
    src: /var/tmp/wordpress/
    dest: /var/www/documentroot/
    owner: www-data
    group: www-data
    mode: '0755'
    force: false
    remote_src: true
```
なお、コピー先の`/var/www/documentroot`ディレクトリは存在しない状態で、このタスクを実行することでディレクトリが作成され、その配下にWordPressの各種ディレクトリやファイルが格納される想定です。
これ以前のタスクで、WordPressをダウンロードし、`/var/tmp`に解凍しています。

# はまったこと

プレイブックを実行すると、結果は`ok`と表示されます。本来であれば、初回実行時にファイルがコピーされ、`changed`と表示されるはずですが、実際には以下のように表示されました。
```
TASK [wordpress : Copy WordPress files to web root] ********************************************************************************
ok: [hostname]
```

確認すると、`/var/www/documentroot/`ディレクトリ自体は作成されていましたが、その中身は空でした。

# 調べたこと
`ansible.builtin.copy`モジュールについて調べたものの、直接の原因は分かりませんでした。

次に、代替案として`ansible.posix.synchronize`モジュールについても調べましたが、冪等性を保つためには、除外したいファイルを`.rsync-filter`ファイルに記述する必要があり、設定が煩雑なため断念しました。

https://docs.ansible.com/ansible/latest/collections/ansible/posix/synchronize_module.html

> 	•	To exclude files and directories from being synchronized, you may add `.rsync-filter` files to the source directory.


# かわりにやったこと

最終的に、`force: false`ではなく、`force: true`を指定することで問題なくコピーができました。
ただし、`ansible.builtin.copy`モジュールだけで冪等性を保つのではなく、`when`ディレクティブを使用し、既にコピー済みかどうかを判定する方法を取りました。コピー済みでない場合のみ、タスクを実行するようにしています。

実際に設定したタスク

```
- name: Check if documentroot exists
  stat:
    path: /var/www/documentroot/
  register: documentroot_stat

- name: Copy WordPress files to web root
  copy:
    src: /var/tmp/wordpress/
    dest: /var/www/documentroot/
    owner: www-data
    group: www-data
    mode: '0755'
    force: true
    remote_src: true
  when: not documentroot_stat.stat.exists
```

まだコピーされていない場合のプレイブック実行結果
```
TASK [wordpress : Check if documentroot exists] *******************************************************
ok: [hostname]

TASK [wordpress : Copy WordPress files to web root] ***************************************************
changed: [hostname]
```
すでにコピー済みの場合のプレイブック実行結果
```
TASK [wordpress : Check if documentroot exists] *******************************************************
ok: [hostname]

TASK [wordpress : Copy WordPress files to web root] ***************************************************
skipping: [hostname]
```

`skipping`となり、冪等性が担保されるようにタスクを設定できたことがわかります。

# おわりに

今回は`ansible.builtin.copy`モジュールについて調べることに時間をかけ過ぎてしまいました。今後は、複数のアプローチを念頭にいれて問題に取り組んでいきたいと思います。

## 宣伝：エンジニアコミュニティのご案内

私が所属しているエンジニアコミュニティ **TechBull** では、定期的に輪読会やもくもく会を開催しています。これらのイベントは外部の方も参加可能で、技術書を通じて学びたいというエンジニアを歓迎しています。

### 輪読会
同じ書籍を読み進めながら、互いに意見を交換し、理解を深める場です。自分一人では難しい内容も、他のエンジニアと一緒に学ぶことで、新たな視点や理解が得られます。

### もくもく会
集中して作業を進める時間を共有する場です。自分のペースで学びたい方にぴったりです。時には雑談に発展するかも？？

インフラエンジニアやIT技術に興味があり、成長意欲のある方は、ぜひ一度ご参加ください。詳細やご質問があれば、ぜひお気軽にご連絡ください！

https://techbull.connpass.com/

私がコミュニティに参加して1ヶ月の感想記事はこちらにあります！
興味を持たれた方はお読みいただけると嬉しいです。

https://techbull.cloud/archives/1121

ここまでお読み頂きありがとうございました！！