【问题标题】:Setting Chef variable via a ruby_block not being executed通过未执行的 ruby​​_block 设置 Chef 变量
【发布时间】:2014-12-02 00:01:33
【问题描述】:

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

我遇到的问题是我正在尝试通过 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

我在 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)

【问题讨论】:

  • 如果您在配方基础范围内创建id 变量并通过ruby_block 分配它会发生什么?不能在日志中使用,因为离开ruby_block后就不存在了
  • @arco444 它将存在于资源之外,ruby_block 的内容与父级在同一上下文中运行,因此我们有一个作用域变量可用于厨师运行的其余部分。

标签: mysql ruby bash chef-infra


【解决方案1】:

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

Chef-server 的一大优势是搜索能力。因此,我会将 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

【讨论】:

  • 在这种情况下,我会在 ruby​​ 块中添加一个 not_if node[application].include?("id") 以使其具有幂等性。 OP 代码也有一些缺点,对克隆资源(ruby_block 和模板)的一些警告,因为它们是静态命名的。并感谢您对我的回答的评论:)
  • 只是一个关于你的答案的问题:你在谈论搜索,但我不明白这里的意思,没有搜索其他节点。无论如何,使用节点属性而不是变量是个好主意。
  • @tensibai,关于使 ruby​​_block 幂等的要点。你是对的,OP 的用例中不涉及搜索。我的意思很简单,我喜欢把所有东西都放在节点中,以防我想在另一个配方中搜索它,或者只是用刀临时性地搜索它。
  • 糟糕,返回键上的扳机手指发痒:谢谢各位的回复。我选择将 ID 放在节点属性中并使用惰性求值。奇怪的是,我现在得到的错误是说明文件不存在: Errno::ENOENT ------------- 没有这样的文件或目录 - /root/query_mysql.bash放置脚本的代码将首先运行并从模板创建文件。我也尝试将模板文件放在“默认”文件夹中,但得到了同样的错误。在运行食谱之前,Chef 不会遍历所有这些模板文件吗?
  • 实际上,我只是将mysql查询拉入变量声明中。保持简单:node.default[:deploy][application][:id] = mysql -D opsworks -u user -ppassword -h someRDSdb.blahblah.us-west-1.rds.amazonaws.com --disable-column-names --silent -e "INSERT INT O application_id_table(application_name) SELECT aname FROM (SELECT '#{application}' as aname) t WHERE NOT EXISTS (select 1 from application_id_table ait WHERE ait.application_name = t. aname); SELECT id FROM application_id_table WHERE application_name='#{application}';".strip
【解决方案2】:

您遇到了厨师运行问题的两个阶段。见documentation about it here

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

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

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

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

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

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

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

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

【讨论】:

    猜你喜欢
    • 2018-03-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-18
    • 1970-01-01
    • 2019-09-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多