如何更新节点状态而不是覆盖它?

时间:2013-11-21 11:15:24

标签: ruby chef chef-recipe

是的我知道,我们有一个名为“spiceweasel”的工具来处理所有这些,但我真的很好奇,它是如何以及为什么它在厨师那样工作。

Chef带来了一个很好的想法,拥有一个描述环境的完整存储库,这个想法很棒,但节点似乎不像我期望的那样工作。

所以这是一个情况: 您有主厨服务器/工作站设置,并且您的群集中已有bootstrapedprovisioned个节点。如您所知,每个节点在某个时间间隔内运行chef-client,我将定义。因此,每个节点在随机间隔重新运行配方,以检查是否有任何机会,如果更改 - 它会更改。

因此您的存储库中有文件夹nodes/。当您执行knife upload /nodes时,所有节点配置必须更新,但现在完全覆盖节点状态。那为什么这很糟糕?因为,假设我编辑了节点配置文件并将其上传到chef-server,然后节点状态重置,直到下一个chef-client run操作。我有一个驻留在另一个节点上的cookbook / role,它从特定节点(拥有特定角色)检查ip。有一个很大的机会,当chef-client run将在其中一个节点上执行时,它将找不到另一个节点的IP,整个食谱将无法运行!

也许在cookbook中使用节点状态是错误的,但是嘿,它已经遍布整个地方..所以现在很高兴有一个选项,只是 UPDATE 节点状态,而不是覆盖它

所以问题是:是否有可能更新节点的状态,而不是销毁它?

3 个答案:

答案 0 :(得分:2)

您可以编写一个刀插件,从Chef服务器获取现有节点对象,使用本地值更新它并再次保存。

我现在使用this plugin一段时间(原来是Chris Gaffney):

class NodeUpdateFromFile < ::Chef::Knife
  deps do
    require "chef/node"
    require "chef/json_compat"
    require "chef/knife/core/object_loader"
  end

  banner "knife node update from file FILE (options)"

  def loader
    @loader ||= ::Chef::Knife::Core::ObjectLoader.new(Chef::Node, ui)
  end

  def run
    update = loader.load_from("nodes", @name_args[0])
    begin
      node = ::Chef::Node.load(update.name)
    rescue Net::HTTPServerException
      ui.info("Could not load existing node #{update.name}, assuming new node.")
      node = ::Chef::Node.new
      node.name(update.name)
    end

    # Replace attributes, run_list, and chef_environment from the new node
    # definition. 
    node.normal_attrs   = update.normal_attrs
    node.override_attrs = update.override_attrs
    node.default_attrs  = update.default_attrs

    node.run_list.reset!(update.run_list)
    node.chef_environment(update.chef_environment)

    # Expand the run_list in case it has changed
    node.expand!
    node.save

    output(format_for_display(node)) if config[:print_after]

    ui.info("Updated Node #{update.name}!")
  end
end

只需将其放入.chef/plugins/knife/node_update_from_file.rb的主厨库中,然后使用新命令

knife node update from file my.node.json

而不是旧knife node from file my.node.json

答案 1 :(得分:1)

如果你不介意的话,你可以每次保存和更新节点的所有正常/覆盖/自动属性。

  1. 执行knife node show your-node-name --format json -l > nodes/your-node-name.json以转储所有节点属性。注意参数-l表示长输出,包括普通,覆盖和自动属性。
  2. 更新
  3. 执行knife node from file nodes/your-node-name.json
  4. 表示您始终保存并更新所有属性。

答案 2 :(得分:0)

Holger的答案不适合我的环境,使用他的插件在node.default_attrs = update.default_attrs中删除了许多自动生成的属性

因此,我对该问题的解决方案是迭代更新节点中的属性,并将它们添加到chefserver中的节点。结果代码是:

class NodeUpdateFromFile < ::Chef::Knife
    deps do
    require "chef/node"
    require "chef/json_compat"
    require "chef/knife/core/object_loader"
  end

  banner "knife node update from file FILE (options)"

  def loader
    @loader ||= ::Chef::Knife::Core::ObjectLoader.new(Chef::Node, ui)
  end

  def run
    update = loader.load_from("nodes", @name_args[0])
    begin
      node = ::Chef::Node.load(update.name)
    rescue Net::HTTPServerException
      ui.info("Could not load existing node #{update.name}, assuming new node.")
      node = ::Chef::Node.new
      node.name(update.name)
    end

    # Replace attributes, run_list, and chef_environment from the new node
    # Note: With this appproach attributes will never be removed from the chefserver
    update.normal_attrs.each { |key, value| node.normal_attrs[key] = value  }
    update.override_attrs.each { |key, value| node.override_attrs[key] = value  }  
    update.default_attrs.each { |key, value| node.default_attrs[key] = value  }

    node.run_list.reset!(update.run_list)
    node.chef_environment(update.chef_environment)

    # Expand the run_list in case it has changed
    node.expand!
    node.save

    output(format_for_display(node)) if config[:print_after]

    ui.info("Updated Node #{update.name}!")
  end
end
相关问题