

翻訳は機械翻訳により提供されています。提供された翻訳内容と英語版の間で齟齬、不一致または矛盾がある場合、英語版が優先します。

# 例 4: フロー制御の追加
<a name="cookbooks-101-basics-ruby"></a>

**重要**  
この AWS OpsWorks Stacks サービスは 2024 年 5 月 26 日にサポート終了となり、新規および既存のお客様の両方で無効になっています。できるだけ早くワークロードを他のソリューションに移行することを強くお勧めします。移行についてご質問がある場合は、[AWS re:Post](https://repost.aws/) または[AWS プレミアムサポート](https://aws.amazon.com/support)を通じて AWS サポート チームにお問い合わせください。

単なる Chef リソースの連なりであるレシピもあります。この場合、レシピを実行すると単純にリソースプロバイダーを 1 つずつ順番に実行します。ただし、より洗練された実行パスを持つ方が役に立つ場合が多くあります。以下に一般的なシナリオを 2 つ示します。
+ 同じリソースを異なる属性設定で複数回実行するレシピがほしい。
+ さまざまなオペレーティングシステムで異なる属性設定を使用したい。

レシピに Ruby の制御構造を組み込むことで、このようなシナリオに対処できます。このセクションでは、「[例 3: ディレクトリの作成](cookbooks-101-basics-directories.md)」のレシピを変更して両方のシナリオに対処する方法を説明します。

**Topics**
+ [イテレーション](#cookbooks-101-basics-ruby-iteration)
+ [条件付きロジック](#cookbooks-101-basics-ruby-conditional)

## イテレーション
<a name="cookbooks-101-basics-ruby-iteration"></a>

「[例 3: ディレクトリの作成](cookbooks-101-basics-directories.md)」では、`directory`リソースを使用してディレクトリまたはディレクトリチェーンを作成する方法を説明しました。ただし別々の 2 つのディレクトリ、`/srv/www/config` と `/srv/www/shared` を作成したい場合があるかもしれません。各ディレクトリに別々のディレクトリリソースを実装することもできますが、非常に多数のディレクトリを作成する場合はこの方法は面倒です。以下のレシピは、このタスクを処理するよりシンプルな方法を示します。

```
[ "/srv/www/config", "/srv/www/shared" ].each do |path|
  directory path do
    mode 0755
    owner 'root'
    group 'root'
    recursive true
    action :create
  end
end
```

各サブディレクトリに対して別のディレクトリリソースを使用する代わりに、レシピではサブディレクトリのパスを含む文字列コレクションを使用します。Rubyの `each` メソッドはコレクションの各要素を最初のものから始めてそれぞれ 1 回ずつ実行します。要素の値はリソース内で `path` 変数で表されます。この場合はディレクトリパスを表します。この例を簡単に応用して、サブディレクトリをいくつでも作成できます。

**レシピを実行するには**

1. `createdir` ディレクトリにとどまります。以下のいくつかの例で、ここのクックブックを使用します。

1. `kitchen destroy` をまだ実行していない場合は実行して、新しいインスタンスで始められるようにします。

1. `default.rb` のコードを例で置き換えて、`kitchen converge` を実行します。

1. インスタンスにログインします。`/srv` の下に新しく作成されたディレクトリがあります。

ハッシュテーブルを使用して各イテレーションに 2 個の値を指定できます。以下のレシピは `/srv/www/config` および `/srv/www/shared` を、別モードでそれぞれ作成します。

```
{ "/srv/www/config" => 0644, "/srv/www/shared" => 0755 }.each do |path, mode_value|
  directory path do
    mode mode_value
    owner 'root'
    group 'root'
    recursive true
    action :create
  end
end
```

**レシピを実行するには**

1. `kitchen destroy` をまだ実行していない場合は実行して、新しいインスタンスで始められるようにします。

1. `default.rb` のコードを例で置き換えて、`kitchen converge` を実行します。

1. インスタンスにログインします。`/srv` の下に指定したモードで新しく作成されたディレクトリがあります。

**注記**  
OpsWorks スタックレシピは通常、このアプローチを使用してスタック[設定とデプロイメント JSON](workingcookbook-json.md) から値を抽出します。これは基本的に大きなハッシュテーブルであり、リソースに挿入します。例については、[Deploy レシピ](create-custom-deploy.md)を参照してください。

## 条件付きロジック
<a name="cookbooks-101-basics-ruby-conditional"></a>

複数の実行ブランチを作成するために Ruby の条件付きロジックを使用することもできます。以下のレシピでは、`if-elsif-else` ロジックを使用して 1 つ前の例を拡張しています。`/srv/www/shared` という名前のサブディレクトリを作成しますが、Debian および Ubuntu システムに対してのみです。その他のすべてのシステムの場合は、Test Kitchen の出力に表示するエラーメッセージを記録します。

```
if platform?("debian", "ubuntu")
  directory "/srv/www/shared" do
    mode 0755
    owner 'root'
    group 'root'
    recursive true
    action :create
  end
else
  log "Unsupported system"
end
```

**レシピの例を実行するには**

1. インスタンスが実行中の場合は、`kitchen destroy` を実行してシャットダウンします。

1. `default.rb` のコードを例のコードで置き換えます。

1. `.kitchen.yml` を編集してプラットフォームの一覧に CentOS 6.4 システムを追加します。ファイルの `platforms` セクションはこのようになります。

   ```
   ...
   platforms:
     - name: ubuntu-12.04
     - name: centos-6.4
   ...
   ```

1. `kitchen converge` を実行すると、インスタンスを作成し `.kitchen.yml` のプラットフォームごとのレシピを順次実行します。
**注記**  
1 個のインスタンスのみをコンバージする場合は、インスタンス名をパラメータとして追加します。例えば、Ubuntu プラットフォームのレシピのみをコンバージするには、`kitchen converge default-ubuntu-1204` を実行します。プラットフォーム名を忘れた場合は、`kitchen list` を実行します。

Test Kitchen の出力の CentOS 部分にログメッセージがあります。以下のようなものになります。

```
...
Converging 1 resources
Recipe: createdir::default
* log[Unsupported system] action write[2014-06-23T19:10:30+00:00] INFO: Processing log[Unsupported system] action write (createdir::default line 12)
[2014-06-23T19:10:30+00:00] INFO: Unsupported system
       
[2014-06-23T19:10:30+00:00] INFO: Chef Run complete in 0.004972162 seconds
```

これでインスタンスにログインし、ディレクトリが作成されている (または作成されていない) ことを確認できます。ただし、単純に `kitchen login` を実行することはできません。たとえば `kitchen login default-ubuntu-1204` のようにプラットフォーム名を追加してインスタンスを指定する必要があります。

**注記**  
Test Kitchen コマンドがインスタンス名をとる場合、完全な名前を入力する必要はありません。Test Kitchen は Ruby の正規表現としてインスタンス名を処理しますので、ユニークな一致ができる文字数があれば十分です。例えば `kitchen converge ub` を実行して Ubuntu のインスタンスのみをコンバージすることもできますし、`kitchen login 64` を実行して CentOS のインスタンスにログインすることもできます。

ここまでで、レシピがどのように実行中のプラットフォームを見分けているか疑問に思うことでしょう。Chef は実行のたびに [Ohai](https://docs.chef.io/ohai.html) というツールを実行してプラットフォームを含むシステムデータを収集し、*ノードオブジェクト*という構造の中で一連の属性として示します。Chef `platform?` メソッドはかっこ内のシステムを Ohai のプラットフォームの値と比較して、一致すれば true を返します。

`node['attribute_name']` を使用してコード内で直接ノード属性の値を参照できます。プラットフォームの値は、例えば、`node['platform']` で表されます。たとえば、前述の例を以下のように記述することもできます。

```
if node[:platform] == 'debian' or node[:platform] == 'ubuntu'
  directory "/srv/www/shared" do
    mode 0755
    owner 'root'
    group 'root'
    recursive true
    action :create
  end
else
  log "Unsupported system"
end
```

レシピに条件付きロジックを含める一般的な理由は、異なる Linux ファミリーが時としてパッケージやディレクトリに異なる名前を使用していることに対応するためです。たとえば Apache のパッケージ名は CentOS システムでは `httpd` であり、Ubuntu システムでは `apache2` です。

異なるシステム用に異なる文字列が必要な場合、Chef [http://docs.chef.io/dsl_recipe.html#value-for-platform](http://docs.chef.io/dsl_recipe.html#value-for-platform) メソッドは、`if-elsif-else`よりも簡単なソリューションです。以下のレシピは CentOS システムでは `/srv/www/shared` ディレクトリ、Ubuntu システムでは `/srv/www/data` ディレクトリ、その他の場合は `/srv/www/config` を作成します。

```
data_dir = value_for_platform(
  "centos" => { "default" => "/srv/www/shared" },
  "ubuntu" => { "default" => "/srv/www/data" },
  "default" => "/srv/www/config"
)
directory data_dir do
  mode 0755
  owner 'root'
  group 'root'
  recursive true
  action :create
end
```

`value_for_platform` は `data_dir` に適切なパスを割り当て、`directory` リソースはその値を使用してディレクトリを作成します。

**レシピの例を実行するには**

1. インスタンスが実行中の場合は、`kitchen destroy` を実行してシャットダウンします。

1. `default.rb` のコードを例のコードで置き換えます。

1. `kitchen converge` を実行し、その後各インスタンスにログインして適切なディレクトリがあることを確認します。