2014-10-07 154 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。