Puppet4.xではじめるサーバ設定自動化 4（ディレクトリ）

Puppet4.xではじめるサーバ設定自動化の、ディレクトリ編です。
全体的な目次は、[ここ](http://qiita.com/kijibato/items/ae510dfa91884bdd9f61)を参照してください。
主にCentOS 7を例に紹介しているので、その他OSについては読み替えてください。

# ディレクトリ作成

## 基本
ディレクトリを作成する場合、Puppetのマニフェストでfileリソースで定義します。
/tmp/puppet_directory_sample/を作る場合の例です。

```puppet:directory01.pp
file { "/tmp/puppet_directory_sample/" :
  ensure => "directory",
  owner  => "root",
  group  => "root",
  mode   => "0755",
}

```

- fileの右側のタイトルにディレクトリパスを指定
- ディレクトリの場合、ensure属性にdirectoryを指定
- owner属性は、ディレクトリのオーナー
- group属性は、ディレクトリのグループ
- mode属性は、ディレクトリのパーミッション

## 複数ディレクトリを作る
複数のディレクトリを作る場合の書き方です。

### シンプルに列挙する
fileリソースを作りたいディレクトリ分書けば、複数ディレクトリを作る定義になります。シンプルな方法です。

```puppet:directory02.pp
file { "/tmp/puppet_directory_sample/" :
  ensure => "directory",
  owner  => "root",
  group  => "root",
  mode   => "0755",
}

file { "/tmp/puppet_directory_sample/01/" :
  ensure => "directory",
  owner  => "root",
  group  => "root",
  mode   => "0755",
}

file { "/tmp/puppet_directory_sample/02/" :
  ensure => "directory",
  owner  => "root",
  group  => "root",
  mode   => "0755",
}

```

### 配列を渡す
列挙はシンプルだけと、ちょっと無駄が多いなと思った方は次の書き方を参考に。
ディレクトリを、**同じオーナー、グループ、パーミッションで**作る場合は、ディレクトリのパスを配列で記載して、１つのfileリソースに渡してあげる書き方もできます。

```puppet:directory03.pp
$directories = [
  "/tmp/puppet_directory_sample/",
  "/tmp/puppet_directory_sample/01/",
  "/tmp/puppet_directory_sample/02/",
]

file { $directories :
  ensure => "directory",
  owner  => "root",
  group  => "root",
  mode   => "0755",
}

```

### ハッシュでループ
ディレクトリを、**異なるオーナー、グループ、パーミッションで**作る場合は、ハッシュでパスと属性を設定して、ハッシュでループさせる書き方もできます。Rubyぽい書き方です。**このループの文法は、Puppet4.xから使えます。**

```puppet:directory04.pp
$directories_hash = {
  "/tmp/puppet_directory_sample/"    => {"owner" => "root", "group" => "root", "mode" => "0755"},
  "/tmp/puppet_directory_sample/01/" => {"owner" => "root", "group" => "root", "mode" => "0750"},
  "/tmp/puppet_directory_sample/02/" => {"owner" => "root", "group" => "root", "mode" => "0700"},
}

$directories_hash.each |$path, $attr| {
  file { $path :
    ensure => "directory",
    owner  => $attr["owner"],
    group  => $attr["group"],
    mode   => $attr["mode"],
  }
}

```

## ディレクトリを消す
ディレクトリを削除する場合の例です。

```puppet:directory05.pp
file { "/tmp/puppet_directory_sample/" :
  ensure => "absent",
  force  => "true",
}

```

- ensure属性に、absentを指定
- force属性に、trueを指定

ディレクトリを消す場合、force(強制)属性にtrueを指定しないと削除できません。
※ディレクトリ削除は慎重に。

# Puppetでディレクトリを作る場合の注意点
以降は、細かい内容なので、ご参考程度に。

## 親ディレクトリがないとエラー

親ディレクトリが存在しない状態で、ディレクトリを作ろうとするとエラーになります。
例えば、
/tmp/puppet_directory_sample/
がない状態で、
/tmp/puppet_directory_sample/01/
/tmp/puppet_directory_sample/02/
を作る場合です。

```puppet:directory06.pp
file { "/tmp/puppet_directory_sample/01/" :
  ensure => "directory",
  owner  => "root",
  group  => "root",
  mode   => "0755",
}

file { "/tmp/puppet_directory_sample/02/" :
  ensure => "directory",
  owner  => "root",
  group  => "root",
  mode   => "0755",
}

```

ちなみに、事前に変更差分を確認(noopで実行)するとき、エラーにならないです。実際に実行してみて、初めてエラーで途中のディレクトリがないことに気づくこともあるので注意です。

実行例です。

ドライランのnoopだと、Errorはないです。

```
# /opt/puppetlabs/bin/puppet apply directory06.pp -t --noop
Notice: Compiled catalog for a44df4cf7cb4 in environment production in 0.04 seconds
Info: Applying configuration version '1461379511'
Notice: /Stage[main]/Main/File[/tmp/puppet_directory_sample/01/]/ensure: current_value absent, should be directory (noop)
Notice: /Stage[main]/Main/File[/tmp/puppet_directory_sample/02/]/ensure: current_value absent, should be directory (noop)
Notice: Class[Main]: Would have triggered 'refresh' from 2 events
Notice: Stage[main]: Would have triggered 'refresh' from 1 events
Notice: Applied catalog in 0.03 seconds
```

ただ、実際に実行すると、/tmp/puppet_directory_sampleがないためエラーになります。

```
parent directory /tmp/puppet_directory_sample does not exist
```

```
# /opt/puppetlabs/bin/puppet apply directory06.pp -t
Notice: Compiled catalog for a44df4cf7cb4 in environment production in 0.04 seconds
Info: Applying configuration version '1461379521'
Error: Cannot create /tmp/puppet_directory_sample/01; parent directory /tmp/puppet_directory_sample does not exist
Error: /Stage[main]/Main/File[/tmp/puppet_directory_sample/01/]/ensure: change from absent to directory failed: Cannot create /tmp/puppet_directory_sample/01; parent directory /tmp/puppet_directory_sample does not exist
Error: Cannot create /tmp/puppet_directory_sample/02; parent directory /tmp/puppet_directory_sample does not exist
Error: /Stage[main]/Main/File[/tmp/puppet_directory_sample/02/]/ensure: change from absent to directory failed: Cannot create /tmp/puppet_directory_sample/02; parent directory /tmp/puppet_directory_sample does not exist
Notice: Applied catalog in 0.02 seconds
```

## 検索権限が設定される

ディレクトリのパーミッションを数値モードで指定した場合、ディレクトに読み込み権限がセットされたときにPuppetは検索権限もセットします。文章で書くとわかりにくいですが、たとえばディレクトリのパーミッションを0644で作ろうとしても、755として作成されます。

```puppet:directory07.pp
file { "/tmp/puppet_directory_sample/" :
  ensure => "directory",
  owner  => "root",
  group  => "root",
  mode   => "0644",
}

```

バグとかではなく、仕様です。

> When specifying numeric permissions for directories, Puppet sets the search permission wherever the read permission is set.

実行例です。
Puppetを実行して、パーミッションを確認すると755になっています。

```
# /opt/puppetlabs/bin/puppet apply directory07.pp -t
Notice: Compiled catalog for a44df4cf7cb4 in environment production in 0.04 seconds
Info: Applying configuration version '1461379782'
Notice: /Stage[main]/Main/File[/tmp/puppet_directory_sample/]/ensure: created
Notice: Applied catalog in 0.02 seconds

# ls -ld /tmp/puppet_directory_sample/
drwxr-xr-x 2 root root 4096 Apr 23 02:49 /tmp/puppet_directory_sample/
```

ちなみに、chmodコマンドで変えて、Puppetを実行すると755に変わります。
※定義では0644を指定していても、仕様で検索権限がつくため755になる。

```
# chmod 644 /tmp/puppet_directory_sample/

# /opt/puppetlabs/bin/puppet apply directory07.pp -t
Notice: Compiled catalog for a44df4cf7cb4 in environment production in 0.04 seconds
Info: Applying configuration version '1461379824'
Notice: /Stage[main]/Main/File[/tmp/puppet_directory_sample/]/mode: mode changed '0644' to '0755'
Notice: Applied catalog in 0.02 seconds
```

## 大量に定義すると遅くなる

Puppetは、基本的にリソースの定義が多いほど時間がかかるため、大量にディレクトリの定義を書くと、実行に時間がかかります。ただし、Puppetでディレクトリ定義しておくと、Puppetを実行するたびにディレクトリのチェック、復元ができるメリットもあります。

ディレクトリをきっちり管理したい場合はたくさん定義して、実行に時間をかけたくない場合は最低限のディレクトリのみ定義するとかです。

# Puppetでディレクトリを作る（管理する）メリット

サーバがおかしくなったとき、ディレクトリ設定が違っていたとかが原因の場合、意外と調べるのに時間がかかったりします。特に、オペミスで意図せず変えてしまったときとか、アプリの不具合で勝手に変わったときなどです。

ディレクトリをPuppetで管理しておくと、Puppetを実行すればサーバで変えられた箇所を特定しやすくなります。

# 参考

fileリソースの詳しい情報は、下記参照です。

- https://docs.puppet.com/puppet/latest/reference/type.html#file