Chef(solo)レシピをループする正しい方法は何ですか?


8

誰かが私にシェフのしくみを説明してくれませんか?これはかなり大まかな質問なので、絞り込むために、ユーザーのリストをループして、まだ存在しない場合はそれぞれを作成するこの非常に単純なレシピを持っています。それは動作しません。

私が言うことができることから、ループは期待通りに起こっているようです。ループが完了すると、各ユーザーを作成するためのbashコマンドが実行されます(ループの各反復ごとに1回)。ただし、bashコマンドを実行すると、最初のループの繰り返しからのユーザー値しか表示されないように見えます。

この例のように変数データをループするレシピを書く正しい方法は何ですか?

ここにレシピがあります:

node[:users].each do |user|
  puts "in loop for #{user['username']}"
  bash "create_user" do
    user "root"
    code do
      puts "running 'useradd' for #{user['username']}"
      "useradd #{user['username']}"
    end
    not_if do
      puts "checking /etc/passwd for #{user['username']}"
      "cat /etc/passwd | grep #{user['username']}"
    end
  end
end

私は次の設定でVagrantを使用してこれをテストしています:

Vagrant::Config.run do |config|
  config.vm.box = "precise32"
  config.vm.box_url = "http://files.vagrantup.com/precise32.box"
  config.vm.provision :chef_solo do |chef|
    chef.add_recipe "sample"
    chef.json = {
      :users => [
        {:username => 'testA'},
        {:username => 'testB'},
        {:username => 'testC'},
        {:username => 'testD'},
        {:username => 'testE'},
      ],
    }
  end
end

レシピのputsステートメントによって生成されるメッセージは、次のようになります。

2013-03-08T01:03:46+00:00] INFO: Start handlers complete.
in loop for testA

in loop for testB

in loop for testC

in loop for testD

in loop for testE

[2013-03-08T01:03:46+00:00] INFO: Processing bash[create_user] action run (sample::default line 5)
checking /etc/passwd for testA

[2013-03-08T01:03:46+00:00] INFO: Processing bash[create_user] action run (sample::default line 5)
checking /etc/passwd for testA

[2013-03-08T01:03:46+00:00] INFO: Processing bash[create_user] action run (sample::default line 5)
checking /etc/passwd for testA

[2013-03-08T01:03:46+00:00] INFO: Processing bash[create_user] action run (sample::default line 5)
checking /etc/passwd for testA

[2013-03-08T01:03:46+00:00] INFO: Processing bash[create_user] action run (sample::default line 5)
checking /etc/passwd for testA

[2013-03-08T01:03:46+00:00] INFO: Chef Run complete in 0.026071 seconds

回答:


5

スクリプト名を一意にします...

bash "create_user_#{user}" do

FWIW、私はhttps://github.com/fnichol/chef-userを数回使用しましたこれにより、属性とデータバッグに基づいてユーザーを作成/削除できます。


それはとてもシンプルに思えます、ありがとう!ユーザーの作成レシピは、ループが他のレシピで機能しなかった理由を理解するために使用した例にすぎません。再度、感謝します!
マシューJモリソン

10

あなたが見ている振る舞いは、Chefクライアントの実行における2つの主要な段階、コンパイルと収束の違いを理解することで説明できます。

「コンパイル」フェーズでは、Chefクライアントがレシピのコードを実行して、リソースコレクションを構築します。これは、システムで管理するようChefに指示したリソースとそのターゲット状態のリストです。たとえば、それ/tmp/fooが存在し、rootによって所有されている必要があることを伝えるDirectoryリソース:

directory "/tmp/foo" do
  owner "root"
end

「収束」フェーズでは、Chefクライアントはプロバイダーを使用して各リソースの現在の状態をロードし、これをターゲットの状態と比較します。それらが異なる場合、Chefはシステムを更新します。ディレクトリリソースの場合、Chefはディレクトリが存在しない場合は作成し、必要に応じて所有者を「root」に変更します。

リソースは名前とタイプによって一意に識別されます-私たちのディレクトリはそうdirectory[/tmp/foo]です。名前が同じで属性が異なる2つのリソースがある場合、奇妙なことが起こります。これは問題を説明するものであり、Darrin Holstの回答を使用して修正できます。

node[:users].each do |user|
  puts "in loop for #{user['username']}"
  bash "create_user_#{user}" do
    user "root"
    code do
      puts "running 'useradd' for #{user['username']}"
      "useradd #{user['username']}"
    end
    not_if do
      puts "checking /etc/passwd for #{user['username']}"
      "cat /etc/passwd | grep #{user['username']}"
    end
  end
end

ただし、この特定のケースでは、Chefのユーザーリソースを使用するとメリットがあります。これがあなたのレシピの代わりです(デバッグメッセージなし):

node[:users].each do |u|
  user u['username'] do
    action :create
  end
end

なぜこれがbashリソースのセットよりも優れているのですか?

  1. Userリソースは、さまざまなプラットフォームで同じように機能します。同じレシピは、「useradd」以外のものを使用してユーザーを作成するオペレーティングシステムでも機能します。
  2. これを担当するプロバイダーは、ユーザーが既に存在するかどうかを確認する方法を知っているので、not_ifは必要ありません。
  3. 同じプロバイダーを使用して、ユーザーの削除、パスワードのロックまたはロック解除、および既存のユーザーアカウントの他の属性の更新を行うこともできます。

しかし、適切なリソースを使用する最大の理由は、意図をより明確に伝えることです。おそらくあなたの目標は、一連のシェルコマンドを実行することではありません-それは、何人かのユーザーがあなたのシステムに存在することを保証することです。そのために使用されるコマンドは、実装の詳細にすぎません。

プロバイダーはそれらの詳細をカプセル化し、私たちが何をしたいかを説明することに集中できるようにします。


1
おかげで、これはかなり物事を明確にします。ユーザー作成のレシピは、他の場所にあるループが期待どおりに機能しない理由をよりよく理解するために私が試してみた一例にすぎません。
マシューJモリソン
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.