2014-10-07 67 views
1

我想實現一個系統,其中,因爲應用程序跨多個節點需要相同的用戶ID,我們做一個小型的MySQL表上查找具有應用程序名稱和相應的ID存儲在自動增量表中。如果用戶標識不存在,我們創建它並返回。由於「數據庫」食譜遇到的問題,我決定在bash腳本中實現Mysql查詢,該腳本將UID返回給Stdout,並讓Chef在創建用戶時使用該查詢。作爲Mysql腳本的一個參數,我們提供我們要發佈的apllication名稱的節點屬性,這是在數據庫中搜索的條目。設置廚師變量通過ruby_block沒有被執行

我遇到的問題是我試圖通過ruby_block設置變量,這似乎並沒有被處理。廚師日誌顯示變量沒有被設置,當我完全從等式中刪除了mysql腳本時,它仍然沒有被設置。據我瞭解,這是相當簡單的語法,所以可以看出爲什麼這是失敗的。下面的代碼:

define :create_application_ids do 

    # Assign variable names to the parameters passed. 
    application = params[:application_name] 

    # Set the fail flag to zero. 
    node.default[:deploy][application][:fail] = 0 

    # Deploy our mysql query script to get (or create, if required) a user ID for the application 
    template "query_mysql.bash" do 
     path "/root/query_mysql.bash" 
     source "query_mysql.bash.erb" 
     owner "root" 
     group "root" 
     mode "0750" 
    end 

    ruby_block "set_app_id" do 
    block do 
    id = `/root/query_mysql.bash #{node[:deploy][application]}` 
    end 
    action :create 
    end 

    Chef::Log.info "MY-DEPLOY: The ID variable is #{id}" 

    # If a user and group ID has been specified in the JSON string for the 
    # application, then create them both. 

    if (defined?(id)) 
    directory node[:deploy][application][:home_dir] do 
     owner "root" 
     group "root" 
     mode 0777 
     recursive true 
     action :create 
    end 

    group "#{node[:deploy][application][:group_name]}" do 
     gid id 
     only_if { `cat /etc/group | grep -E '^#{node[:deploy][application][:group_name]}:'` } 
    end 

    user "#{node[:deploy][application][:user_name]}" do 
     uid id 
     gid node[:deploy][application][:group_name] 
     home "#{node[:deploy][application][:home_dir]}" 
     shell "/sbin/nologin" 
     only_if { `cat /etc/passwd | grep -E '^#{node[:deploy][application][:user_name]}:'` } 
    end 

    # Create any standard directories for the user. 
    create_application_dirs do 
     application_name application 
    end 

    else 

     Chef::Log.info "MY: #{node[:deploy][application]}" 
    # Since this failed, set the fail flag to 1. 
    node.default[:deploy][application][:fail] = 1 

    log "message" do 
     message "MY-DEPLOY: Cannot deploy application without unique user and group ID" 
     level :fatal 
    end 

    end 

end 

,我看到了這個在廚師輸出:

Recipe Compile Error in /var/lib/aws/opsworks/cache.stage2/cookbooks/my-deploy/recipes/repository.rb 
================================================================================ 


NameError 
--------- 
No resource, method, or local variable named `id' for `Chef::Recipe "repository"' 


Cookbook Trace: 
--------------- 
/var/lib/aws/opsworks/cache.stage2/cookbooks/my-deploy/definitions/create_application_ids.rb:25:in `block in from_file' 
/var/lib/aws/opsworks/cache.stage2/cookbooks/my-deploy/recipes/repository.rb:15:in `block in from_file' 
/var/lib/aws/opsworks/cache.stage2/cookbooks/my-deploy/recipes/repository.rb:2:in `each' 
/var/lib/aws/opsworks/cache.stage2/cookbooks/my-deploy/recipes/repository.rb:2:in `from_file' 


Relevant File Content: 
---------------------- 
/var/lib/aws/opsworks/cache.stage2/cookbooks/my-deploy/definitions/create_application_ids.rb: 

18: ruby_block "set_app_id" do 
19: block do 
20:  id = `/root/query_mysql.bash #{node[:deploy][application]}` 
21: end 
22: action :create 
23: end 
24: 
25>> Chef::Log.info "MY-DEPLOY: The ID variable is #{id}" 
26: 
27: # If a user and group ID has been specified in the JSON string for the 
28: # application, then create them both. 
29: 
30: if (defined?(id)) 
31:  directory node[:deploy][application][:home_dir] do 
32:  owner "root" 
33:  group "root" 
34:  mode 0777 



[2014-10-08T00:55:49+11:00] ERROR: Running exception handlers 
[2014-10-08T00:55:49+11:00] ERROR: Exception handlers complete 
[2014-10-08T00:55:49+11:00] FATAL: Stacktrace dumped to /var/lib/aws/opsworks/cache.stage2/chef-stacktrace.out 
[2014-10-08T00:55:50+11:00] ERROR: No resource, method, or local variable named `id' for `Chef::Recipe "repository"' 
[2014-10-08T00:55:50+11:00] FATAL: Chef::Exceptions::ChildConvergeError: Chef run process exited unsuccessfully (exit code 1) 
+0

如果在配方基礎範圍內創建'id'變量並通過'ruby_block'賦值,會發​​生什麼?你不能在日誌中使用它,因爲它離開'ruby_block'後不存在。 – arco444 2014-10-07 14:25:00

+0

@ arco444它將存在於資源之外,'ruby_block'的內容在與parent相同的上下文中運行,所以我們有一個範圍內的變種可用於其餘的廚師運行。 – Tensibai 2014-10-07 14:35:13

回答

1

Tensibai的回答非常好,我建議你接受它。也就是說,我個人的口味是採取稍微不同的方法。

廚師服務器的一個巨大的好處是能夠搜索。因此,我會將id放在節點屬性中,而不是獨立屬性中,然後將其用於lazy evaluation

define :create_application_ids do 

    # Assign variable names to the parameters passed. 
    application = params[:application_name] 

    # Set the fail flag to zero. 
    node.default[:deploy][application][:fail] = 0 

    # Deploy our mysql query script to get (or create, if required) a user ID for the application 
    template "query_mysql.bash" do 
     path "/root/query_mysql.bash" 
     source "query_mysql.bash.erb" 
     owner "root" 
     group "root" 
     mode "0750" 
    end 

    ruby_block "set_app_id" do 
    block do 
     node[application][:id] = `/root/query_mysql.bash #{node[:deploy][application]}` 
    end 
    action :create 
    not_if node[application] && node[application][:id] 
    end 

    Chef::Log.info "MY-DEPLOY: The ID variable is #{id}" 

    # If a user and group ID has been specified in the JSON string for the 
    # application, then create them both. 

    directory node[:deploy][application][:home_dir] do 
    owner "root" 
    group "root" 
    mode 0777 
    recursive true 
    action :create 
    end 

    group "#{node[:deploy][application][:group_name]}" do 
    gid lazy{ node[application][:id] } 
    only_if { `cat /etc/group | grep -E '^#{node[:deploy][application][:group_name]}:'` } 
    end 

    user "#{node[:deploy][application][:user_name]}" do 
    uid lazy { node[application][:id] } 
    gid node[:deploy][application][:group_name] 
    home "#{node[:deploy][application][:home_dir]}" 
    shell "/sbin/nologin" 
    only_if { `cat /etc/passwd | grep -E '^#{node[:deploy][application][:user_name]}:'` } 
    end 

    # Create any standard directories for the user. 
    create_application_dirs do 
    application_name application 
    end 
end 
+0

在這種情況下,我會在ruby塊中添加'not_if節點[應用程序] .include?(「id」)'以使其具有冪等性。 OP代碼也有一些缺點,一些是克隆資源(ruby_block和template)的靜態命名警告。並感謝評論我的答案:) – Tensibai 2014-10-08 08:15:38

+0

只是你的答案問題:你在談論搜索,但我沒有在這裏指出,沒有其他節點的搜索。無論如何,使用節點屬性而不是變量是一個好主意。 – Tensibai 2014-10-08 08:41:51

+0

@tensibai,關於使ruby_block冪等的優秀點。而且你是正確的,沒有任何搜索涉及OP的用例。我的觀點只不過是我喜歡把所有東西放在節點中,以防我可能想在另一個配方中搜索它,或者只是用刀專門進行搜索。 – 2014-10-08 13:02:20

2

你打一個廚師運行問題的兩個階段。請參閱documentation about it here

首先編譯配方/定義並製作資源「堆棧」。

Lwrp將通過正確參數調用資源(在收斂時間)進行評估來解決您的問題。

在這裏對您的定義進行評估,創建一個類型爲ruby_block的資源,該資源將在收斂時執行。

在定義此資源之後,您將測試是否定義了id,但您的ruby_block此時尚未運行。

你必須改變你的代碼,去掉if (defined?(id))。 您在下面使用的資源已具有冪等性(不需要用戶和組資源中的only_if)。

但是,你必須使用懶惰的評估ID在資源,以避免讓他們定義爲零代替你的ID。

group "#{node[:deploy][application][:group_name]}" do 
    gid lazy { id } 
    only_if { `cat /etc/group | grep -E '^#{node[:deploy][application][:group_name]}:'` } 
end 

如果你真的想找出錯誤並打印您可以使用一個開始/救援塊自定義消息,如無ID的組或用戶資源將拋出一個異常IIRC。