chefでファイルResourceを扱ってみる

# 概要
Chefでのファイル操作をキャッチアップした時の備忘録です。
Chefチュートリアルの`Practice what you've learned > Configure a resource`を通してファイル操作方法を学びます。
※ ファイル操作の公式docsは下記です。

https://docs.chef.io/resources/file/#actions

## 01. 事前準備
- `chefdk`をinstall済み
- ローカル環境を汚したくない場合、docker等のVM内で実行すること


```Bash:centos/7
$ chef -v
ChefDK version: 4.13.3
Chef Infra Client version: 15.14.0
Chef InSpec version: 4.24.8
Test Kitchen version: 2.8.0
Foodcritic version: 16.3.0
Cookstyle version: 5.23.0
```


## 02. ファイルを作成するレシピを試す
作業用リポジトリを作成する。

```Bash:~/
$ mkdir chef-repo
$ cd chef-repo
```

ファイル作成のレシピ(`create-file.rb`)を作成する。
下記は`/tmp/motd`に`hello world`と書かれたファイルを生成するレシピ。

```Bash:~/chef-repo/create-file.rb
file '/tmp/motd' do
  content 'hello world'
end
```

ファイル作成レシピをローカルにデプロイする。
`--local-mode`オプションを指定することで、`Chef Infra Server`を介さず直接レシピをローカルに適応できます。

```Bash:~/chef-repo
$ chef-client --local-mode create-file.rb
[2022-02-06T07:48:06+00:00] WARN: No config file found or specified on command line. Using command line options instead.
[2022-02-06T07:48:06+00:00] WARN: No cookbooks directory found at or above current directory.  Assuming /root/20220206/chef-repo.
Starting Chef Infra Client, version 15.14.0
[2022-02-06T07:48:07+00:00] WARN: Plugin Network: unable to detect ipaddress
[2022-02-06T07:48:07+00:00] ERROR: shard_seed: Failed to get dmi property serial_number: is dmidecode installed?
resolving cookbooks for run list: []
Synchronizing Cookbooks:
Installing Cookbook Gems:
Compiling Cookbooks...
[2022-02-06T07:48:07+00:00] WARN: Node 0612a2a79715 has an empty run list.
Converging 1 resources
Recipe: @recipe_files::/root/20220206/chef-repo/create-file.rb
  * file[/tmp/motd] action create
    - create new file /tmp/motd
    - update content in file /tmp/motd from none to b94d27
    --- /tmp/motd       2022-02-06 07:48:07.505502100 +0000
    +++ /tmp/.chef-motd20220206-647-rtfsqi      2022-02-06 07:48:07.505502100 +0000
    @@ -1 +1,2 @@
    +hello world

Running handlers:
Running handlers complete
Chef Infra Client finished, 1/1 resources updated in 00 seconds
[2022-02-06T07:48:07+00:00] WARN: This release of Chef Infra Client became end of life (EOL) on May 1st 2021. Please update to a supported release to receive new features, bug fixes, and security updates.
```

ファイルが作成されているか`more`コマンドで確認します。
これだけで、ファイルを作成することができました！！

```Bash:~/chef-repo
$ more /tmp/motd
hello world
```

## 03. ファイルの冪等性について
`02` でファイル作成のレシピを扱いましたが、以下の場合はどのような挙動になるのでしょうか？

- レシピと同等のファイルが既に存在する
- 空ファイルが既に存在する
- レシピと異なる内容が書かれたファイルが既に存在する

先ほど作成したレシピを利用して、挙動を確認します。

```Bash:レシピと同等のファイルが既に存在する
$ more /tmp/motd
hello world

$ chef-client --local-mode create-file.rb
...省略
Converging 1 resources
Recipe: @recipe_files::/root/20220206/chef-repo/create-file.rb
  * file[/tmp/motd] action create (up to date)

Running handlers:
Running handlers complete
Chef Infra Client finished, 0/1 resources updated in 00 seconds
[2022-02-06T08:05:39+00:00] WARN: This release of Chef Infra Client became end of life (EOL) on May 1st 2021. Please update to a supported release to receive new features, bug fixes, and security updates.

# ファイルの内容はレシピと同様
$ more /tmp/motd
hello world
```

```Bash:空ファイルが既に存在する
$ more /tmp/motd
// 空ファイル

$ chef-client --local-mode create-file.rb
...省略
Converging 1 resources
Recipe: @recipe_files::/root/20220206/chef-repo/create-file.rb
  * file[/tmp/motd] action create
    - update content in file /tmp/motd from e3b0c4 to b94d27
    --- /tmp/motd       2022-02-06 08:08:42.495502100 +0000
    +++ /tmp/.chef-motd20220206-777-qqw63k      2022-02-06 08:09:16.615502100 +0000
    @@ -1 +1,2 @@
    +hello world

Running handlers:
Running handlers complete
Chef Infra Client finished, 1/1 resources updated in 00 seconds
[2022-02-06T08:09:16+00:00] WARN: This release of Chef Infra Client became end of life (EOL) on May 1st 2021. Please update to a supported release to receive new features, bug fixes, and security updates.

# ファイルの内容はレシピと同様
$ more /tmp/motd
hello world
```

```Bash:~/レシピと異なる内容が書かれたファイルが既に存在する
$ more /tmp/motd
test1
hello world
test2

$ chef-client --local-mode create-file.rb
...省略
Converging 1 resources
Recipe: @recipe_files::/root/20220206/chef-repo/create-file.rb
  * file[/tmp/motd] action create
    - update content in file /tmp/motd from d9a923 to b94d27
    --- /tmp/motd       2022-02-06 08:10:33.945502100 +0000
    +++ /tmp/.chef-motd20220206-841-8toprj      2022-02-06 08:10:52.215502100 +0000
    @@ -1,4 +1,2 @@
    -test1
     hello world
    -test2

Running handlers:
Running handlers complete
Chef Infra Client finished, 1/1 resources updated in 00 seconds
[2022-02-06T08:10:52+00:00] WARN: This release of Chef Infra Client became end of life (EOL) on May 1st 2021. Please update to a supported release to receive new features, bug fixes, and security updates.

# ファイルの内容はレシピと同様
$ more /tmp/motd
hello world
```

エビデンスの通り、全てレシピと同じ状態になっており冪等性が担保されていることを確認できました。
この挙動は`action`の指定により異なってきます。
デフォルトでは`:create`アクションが実行されるためレシピと一致するようにファイルが更新されました。
`:create_if_missing`を指定すれば、ファイルが存在しない場合のみレシピを適用する等ができるようになります。


## 04.ファイルを削除するレシピを試す
ファイル削除のレシピ(`delete-file.rb`)を作成する。
下記は`/tmp/motd`ファイルを削除するレシピ。

```Bash:~/chef-repo/create-file.rb
file '/tmp/motd' do
  action :delete
end
```

実行すると、ファイルが実際に削除できることを確認できた。

```Bash:~/chef-repo
# ファイルがある状態
$ more /tmp/motd
hello world

# デプロイ
$ chef-client --local-mode delete-file.rb
...省略
Converging 1 resources
Recipe: @recipe_files::/root/20220206/chef-repo/delete-file.rb
  * file[/tmp/motd] action delete
    - delete file /tmp/motd

Running handlers:
Running handlers complete
Chef Infra Client finished, 1/1 resources updated in 00 seconds
[2022-02-06T08:15:58+00:00] WARN: This release of Chef Infra Client became end of life (EOL) on May 1st 2021. Please update to a supported release to receive new features, bug fixes, and security updates.

# ファイルが存在しない状態になっている
$ more /tmp/motd
/tmp/motd: No such file or directory
```

## 05.ファイルが存在しない場合のみ作成するレシピを試す
`action`に`create_if_missing`を指定すると、ファイルが無い場合のみファイルを作成することができます。

```Bash:~/chef-repo/create-if_missing_file.rb
file '/tmp/motd' do
  action :create_if_missing
  content 'hello world'
end
```

ファイルが存在しない状態で実行すると、ファイルが作成されます。

```Bash:ファイルが存在しない場合
$ more /tmp/motd
/tmp/motd: No such file or directory

$ chef-client --local-mode create-if_missing_file.rb]
...省略
[2022-02-06T08:33:52+00:00] WARN: Node 0612a2a79715 has an empty run list.
Converging 1 resources
Recipe: @recipe_files::/root/20220206/chef-repo/create-if_missing_file.rb
  * file[/tmp/motd] action create_if_missing
    - create new file /tmp/motd
    - update content in file /tmp/motd from none to b94d27
    --- /tmp/motd       2022-02-06 08:33:52.845502100 +0000
    +++ /tmp/.chef-motd20220206-990-1usle3r     2022-02-06 08:33:52.845502100 +0000
    @@ -1 +1,2 @@
    +hello world

# ファイルが作成される
$ more /tmp/motd
hello world
```

ファイルが存在する場合は、何も処理されません。

```Bash:ファイルが存在する場合
$ more /tmp/motd
other file

$ chef-client --local-mode create-if_missing_file.rb
...省略
Converging 1 resources
Recipe: @recipe_files::/root/20220206/chef-repo/create-if_missing_file.rb
  * file[/tmp/motd] action create_if_missing (up to date)

Running handlers:
Running handlers complete

# ファイルが上書きされない
$ more /tmp/motd
other file
```

## 06. ファイル権限を設定するレシピを試す
ファイルに対して、権限を併せて設定することができます。
例えば、ファイル権限に`0700 root:root`を設定する場合は以下のように書きます。

```Bash:~/chef-repo/authorize-file.rb
file '/tmp/motd' do
  owner 'root'
  group 'root'
  mode '0700'
  action :create
end
```

実行すると、権限設定ができることも確認できました。

```Bash:~/chef-repo
# 現在のファイル権限
$ ls -ltr /tmp/motd
-rw-r--r-- 1 worker worker 11 Feb  6 08:35 /tmp/motd

$ chef-client --local-mode authorize-file.rb
...省略
Converging 1 resources
Recipe: @recipe_files::/root/20220206/chef-repo/authorize-file.rb
  * file[/tmp/motd] action create
    - change mode from '0644' to '0700'
    - change owner from 'worker' to 'root'
    - change group from 'worker' to 'root'

Running handlers:
Running handlers complete

# 権限が変更されている
$ ls -ltr /tmp/motd
-rwx------ 1 root root 11 Feb  6 08:35 /tmp/motd
```


## まとめ
`chef`の`file`リソースを利用したファイル操作方法を学びました。
公式docsにもっと細かな設定が記載されていますが、ファイルを作成するにはどのようなレシピを作ればよいのか？を理解することができました。