Cách chính xác để lặp trong công thức Chef (solo) là gì?


8

Ai đó có thể vui lòng giải thích cho tôi làm thế nào đầu bếp làm việc? Đó là một câu hỏi khá rộng, vì vậy để thu hẹp nó, tôi có công thức rất đơn giản này lặp lại danh sách người dùng và tạo từng người dùng nếu họ chưa tồn tại. Nó không hoạt động.

Từ những gì tôi có thể nói vòng lặp dường như đang xảy ra như tôi mong đợi. Khi vòng lặp đã hoàn thành các lệnh bash của tôi để tạo mỗi người dùng được thực thi, một lần cho mỗi lần lặp trong vòng lặp. Tuy nhiên, khi các lệnh bash được thực thi, chúng dường như chỉ có giá trị người dùng từ lần lặp đầu tiên.

Cách chính xác để viết một công thức lặp lại dữ liệu biến tương tự như ví dụ này là gì?

Đây là công thức:

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

Tôi đang thử nghiệm điều này bằng Vagrant với thiết lập sau:

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

Các thông báo được tạo bởi các câu lệnh put trong công thức trông như thế này:

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

Câu trả lời:


5

làm cho tên tập lệnh của bạn trở nên độc đáo ...

bash "create_user_#{user}" do

FWIW, tôi đã sử dụng https://github.com/fnichol/chef-user nhiều lần cho phép bạn tạo / xóa người dùng dựa trên các thuộc tính và bảng dữ liệu.


Điều đó có vẻ đơn giản, cảm ơn! Công thức tạo người dùng chỉ là một ví dụ tôi đang sử dụng để hiểu được lý do tại sao vòng lặp của tôi không hoạt động trong các công thức nấu ăn khác. Cảm ơn một lần nữa!
Matthew J Morrison

10

Hành vi bạn nhìn thấy có thể được giải thích bằng cách hiểu sự khác biệt giữa hai trong số các giai đoạn chính trong hoạt động của ứng dụng khách Chef: biên dịch và hội tụ.

Trong giai đoạn "biên dịch", ứng dụng khách Chef chạy mã trong công thức nấu ăn của bạn để xây dựng bộ sưu tập tài nguyên . Đây là danh sách các Tài nguyên mà bạn đã nói với Chef để quản lý trên hệ thống của bạn, cùng với trạng thái mục tiêu của họ. Ví dụ: tài nguyên thư mục để nói rằng /tmp/foonên tồn tại và được sở hữu bởi root:

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

Trong giai đoạn "hội tụ", máy khách Chef sử dụng các nhà cung cấp để tải trạng thái hiện tại của từng tài nguyên, sau đó so sánh nó với trạng thái đích. Nếu chúng khác nhau, Chef sẽ cập nhật hệ thống. Đối với tài nguyên Thư mục của chúng tôi, Chef sẽ tạo thư mục nếu nó không tồn tại và thay đổi chủ sở hữu thành "root" nếu cần.

Tài nguyên được xác định duy nhất bởi tên và loại của chúng - Thư mục của chúng tôi sẽ là directory[/tmp/foo]. Những điều kỳ lạ sẽ xảy ra khi bạn có hai tài nguyên có cùng tên nhưng thuộc tính khác nhau - điều đó giải thích vấn đề của bạn và có thể khắc phục bằng câu trả lời của 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

Tuy nhiên, trong trường hợp cụ thể này, bạn sẽ được hưởng lợi từ việc sử dụng tài nguyên Người dùng của Đầu bếp. Đây là một thay thế cho công thức của bạn (không có thông báo gỡ lỗi):

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

Tại sao điều này tốt hơn một tập hợp các tài nguyên bash?

  1. Tài nguyên người dùng hoạt động theo cùng một cách trên các nền tảng khác nhau - cùng một công thức sẽ hoạt động trên các hệ điều hành sử dụng thứ gì đó không phải là "useradd" để tạo người dùng.
  2. Các nhà cung cấp chịu trách nhiệm cho việc này biết cách kiểm tra xem người dùng đã tồn tại chưa, vì vậy bạn không cần not_if.
  3. Các nhà cung cấp tương tự cũng có thể được sử dụng để xóa người dùng, khóa hoặc mở khóa mật khẩu của họ và cập nhật các thuộc tính khác trên tài khoản người dùng hiện có.

Nhưng lý do tốt nhất để sử dụng đúng tài nguyên là nó truyền đạt rõ ràng hơn ý định của bạn. Mục tiêu của bạn có lẽ không phải là chạy một loạt các lệnh shell - để đảm bảo rằng một số người dùng có mặt trên hệ thống của bạn. Các lệnh được sử dụng để làm điều đó chỉ là một chi tiết thực hiện.

Các nhà cung cấp gói gọn những chi tiết đó, để chúng tôi tự do tập trung vào việc mô tả những gì chúng tôi muốn.


1
Cảm ơn, điều này làm rõ mọi thứ khá một chút. Công thức tạo người dùng chỉ là một ví dụ mà tôi có thể chơi để hiểu rõ hơn lý do tại sao các vòng lặp mà tôi có ở nơi khác không hoạt động như tôi mong đợi.
Matthew J Morrison
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.