누군가 요리사가 어떻게 작동하는지 설명해 주시겠습니까? 그것은 매우 광범위한 질문이므로 좁히기 위해 사용자 목록을 반복하고 아직 존재하지 않는 경우 각 사용자를 만드는 매우 간단한 레시피가 있습니다. 작동하지 않습니다.
내가 알 수있는 것에서 루프는 내가 예상 한대로 일어나는 것 같습니다. 루프가 완료되면 각 사용자를 만들기위한 bash 명령이 루프에서 반복 될 때마다 한 번씩 실행됩니다. 그러나 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
답변
스크립트 이름을 고유하게 만드십시오 …
bash "create_user_#{user}" do
FWIW, 나는 https://github.com/fnichol/chef-user를 여러 번 사용 하여 속성과 데이터 백을 기반으로 사용자를 생성 / 제거 할 수 있습니다.
답변
현재보고있는 동작은 Chef 클라이언트 실행의 두 가지 주요 단계 인 컴파일 및 수렴 간의 차이점을 이해하여 설명 할 수 있습니다.
“컴파일”단계 동안 Chef 클라이언트는 레시피에서 코드를 실행하여 자원 콜렉션 을 빌드합니다 . 이것은 Chef에게 시스템에서 목표 상태와 함께 관리하도록 지시 한 자료 목록입니다 . 예를 들어, 디렉토리 자원 /tmp/foo
이 존재해야하고 root가 소유해야 한다고 말합니다 .
directory "/tmp/foo" do
owner "root"
end
“수렴”단계 동안 Chef 클라이언트는 제공자 를 사용하여 각 자원의 현재 상태를로드 한 다음이를 대상 상태와 비교합니다. 다른 경우 Chef는 시스템을 업데이트합니다. 디렉토리 리소스의 경우 Chef는 디렉토리가 존재하지 않는 경우 디렉토리를 만들고 필요한 경우 소유자를 “루트”로 변경합니다.
자원은 이름과 유형으로 고유하게 식별됩니다 directory[/tmp/foo]
. 이름이 같지만 속성이 다른 두 개의 리소스가 있으면 문제가 발생하며 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 리소스 세트보다 나은 이유는 무엇입니까?
- 사용자 리소스는 여러 플랫폼에서 동일한 방식으로 작동합니다. “useradd”이외의 다른 것을 사용하여 사용자를 만드는 운영 체제에서도 동일한 레시피가 작동합니다.
- 이를 담당하는 공급자는 사용자가 이미 존재하는지 확인하는 방법을 알고 있으므로 not_if가 필요하지 않습니다.
- 동일한 공급자를 사용하여 사용자를 제거하고 암호를 잠 그거나 잠금을 해제하며 기존 사용자 계정의 다른 속성을 업데이트 할 수도 있습니다.
그러나 올바른 리소스를 사용해야하는 가장 좋은 이유는 의도를보다 명확하게 전달하기 때문입니다. 귀하의 목표는 아마도 많은 셸 명령을 실행하는 것이 아니라 일부 사용자가 시스템에 있는지 확인하는 것입니다. 이를 수행하는 데 사용 된 명령은 구현 세부 사항 일뿐입니다.
공급자는 이러한 세부 사항을 캡슐화하여 원하는 것을 설명하는 데 자유롭게 집중할 수 있습니다.