アプリケーションコードをインストールして実行するためのChefレシピを書いています。レシピは、このコードが最終的に配置されるディレクトリに注意する必要があります(テンプレートの実行、ログ転送の設定など)。したがって、ディレクトリ自体は、さまざまなレシピの多くの場所に表示されます。
文字列補間を使用してリソースブロックで変数を再利用できるように、変数をフェッチ/定義しようとしています。これは非常に簡単です。
home = node['etc']['passwd'][node['nodejs']['user']]['dir']
使用例として、次のように、リポジトリのダウンロードをホームディレクトリに配置するように指示しながらnpm install
を実行します。
execute "npm install" do
command "npm install #{prefix}#{app} --prefix #{home}"
end
home
変数を定義する最初のブロックがコンパイル時に実行されることを除いて。 nodejsユーザーアカウントがまだ存在していない可能性のある新しいサーバーでは、これは問題であり、
NoMethodError undefined method '[]' for nil:NilClass
いくつかの回避策がありますが、home変数がコンパイル時ではなく、レシピの実行時にのみフェッチされるようにする特定のソリューションが必要です。
次のように、Rubyブロック内のホーム変数を動的に評価します:
Ruby_block "fetch home dir" do
block do
home = node['etc']['passwd'][node['nodejs']['user']]['dir']
end
end
これは実際には機能していないようで、次のようなことを行おうとすると、 NoMethodError undefined method home for Chef :: Resource :: Directory が与えられます。
directory ".npm" do
path "#{home}/.npm"
end
私はここで何か間違ったことをしているに違いないと感じています。
パラメータを必要とするすべてのリソースについて、パラメータを怠惰に評価します。したがって、代わりにこれを行います。
directory ".npm" do
path lazy "#{node['etc']['passwd'][node['nodejs']['user']]['dir']}/.npm"
end
しかし、そのコード行を1回維持し、それを変数に格納して、それを実行するだけでよいのは本当に素晴らしいことです。
コンパイル時にユーザーを作成します。これはもちろん、次のように ここにリンクされているトリックを通知する を使用して機能します。
u = user node['nodejs']['user'] do
comment "The #{node['nodejs']['user']} is the user we want all our nodejs apps will run under."
username node['nodejs']['user']
home "/home/#{node['nodejs']['user']}"
end
u.run_action(:create)
これで問題は正確に解決しますが、変数の評価を遅らせる機能が必要になる場合もあるので、質問をそのままにしておきます。
本当にやりたいです
home lazy = node['etc']['passwd'][node['nodejs']['user']]['dir']
しかし、それは合法的な構文ではなく、 NameErrorを与えると、ubuntuバージョン13.10 でホームのリソースが見つかりません(これは奇妙な構文エラーですが、何でも)。これを達成するための合法的な方法はありますか?
この特定のコードはテストしていませんが、クックブックで同様のことを行い、ラムダを使用して次のように評価を遅らせました。
home = lambda {node['etc']['passwd'][node['nodejs']['user']]['dir']}
execute "npm install" do
command "npm install #{prefix}#{app} --prefix #{home.call}"
end
にとって Ruby_block
、ブロック内で定義されたものはすべてローカルであるため、ブロック内の変数はグローバルである必要があります。
ライブラリでの遅延実行にラムダを使用することはできないため、Ruby_block
この場合はうまく機能します。
@thoughtcroftの回答がchef-client12.8.1で機能しません
この場合、必要なコードをカスタムリソースに配置し、レイジー属性を使用して呼び出します。
mycookbook_myresource "name" do
attribute lazy { myvar }
end
エレガントな解決策ではありませんが、それは私にとってはうまくいきます。