bash 通过未执行的 ruby​​_block 设置 Chef 变量

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/26238056/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-18 11:29:43  来源:igfitidea点击:

Setting Chef variable via a ruby_block not being executed

mysqlrubybashchef

提问by andyr0ck

I'm trying to implement a system where, because applications need the same user ID across multiple nodes, we do a lookup on a small mysql table which has the application name and corresponding ID stored in an autoincrememnting table. If the user ID doesn't already exist, we create it and then return it. Because of issues I've encountered with the 'database' cookbook, I decided to implement the Mysql query in a bash script which returns the UID to Stdout and have Chef use that in the user creation. As an argument to the Mysql script, we feed in the node attribute for the apllication name that we're releasing and this is the entry searched for in the DB.

我正在尝试实现一个系统,因为应用程序需要跨多个节点的相同用户 ID,我们在一个小型 mysql 表上进行查找,该表具有存储在自动递增表中的应用程序名称和相应 ID。如果用户 ID 不存在,我们创建它然后返回它。由于我在使用“数据库”说明书时遇到的问题,我决定在 bash 脚本中实现 Mysql 查询,该脚本将 UID 返回给 Stdout,并让 Chef 在用户创建中使用它。作为 Mysql 脚本的一个参数,我们输入我们发布的应用程序名称的节点属性,这是在数据库中搜索的条目。

The issue I'm having is that I'm attempting to set the variable via a ruby_block and this doesn't seem to be being processed. The Chef log shows that the variable isn't being set and when I've removed the mysql script from the equation completely, it still isn't being set. As I understand it, it's fairly simple syntax so can see why this is failing. Here's the code:

我遇到的问题是我试图通过 ruby​​_block 设置变量,但这似乎没有被处理。Chef 日志显示未设置变量,当我从等式中完全删除 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

and I'm seeing this in the Chef output:

我在 Chef 输出中看到了这一点:

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)

回答by Tensibai

You're hitting the two phases of a chef run problem. See the documentation about it here

您遇到了厨师运行问题的两个阶段。在此处查看有关它文档

First pass compile recipes/definitions and make a 'stack' of resources.

首先通过编译配方/定义并制作“堆栈”资源。

Lwrp would solve your problem by being evaluated when the resource is called (at converge time) with correct params.

Lwrp 将通过在使用正确参数调用资源(在收敛时间)时进行评估来解决您的问题。

Here your definition is evaluated, creating a resource of type ruby_blockwhich will be executed at converge time.

在这里评估您的定义,创建ruby_block将在收敛时执行的类型资源。

Just after defining this resource you test if idis defined, but your ruby_block has not be run at this time.

在定义此资源后,您测试是否id已定义,但此时您的 ruby​​_block 尚未运行。

You have to change your code, stripping the if (defined?(id)). The resources you use below are already idempotent (no need for the only_ifin user and group resources).

您必须更改代码,剥离if (defined?(id)). 您在下面使用的资源已经是幂等的(不需要only_if用户和组中的资源)。

However you'll have to use the lazy evaluation for id in thoose resources to avoid having them defined with nil in place of your id.

但是,您必须对这些资源中的 id 使用惰性求值,以避免将它们定义为 nil 代替您的 id。

i.e.

IE

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

If you really want to catch errors and print a custom message you may use a begin/rescue block, as a group or user resource with nil id would throw an exception IIRC.

如果您真的想捕获错误并打印自定义消息,您可以使用开始/救援块,因为具有 nil id 的组或用户资源将引发异常 IIRC。

回答by Tejay Cardon

Tensibai's answer is excellent, and I'd suggest you accept it. That said, my personal flavor would be to take a slightly different approach.

Tensibai 的回答很好,我建议你接受它。也就是说,我个人的喜好是采取稍微不同的方法。

One of the great benefits of Chef-server is the ability to search. Therefore, I would put the id in a node attribute, rather than a standalone attribute, and then use that with lazy evaluation.

Chef-server 的一大好处是能够进行搜索。因此,我会将 id 放在节点属性中,而不是独立属性中,然后将其与惰性求值一起使用。

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