summaryrefslogtreecommitdiff
path: root/lib/chef/node.rb
diff options
context:
space:
mode:
Diffstat (limited to 'lib/chef/node.rb')
-rw-r--r--lib/chef/node.rb102
1 files changed, 98 insertions, 4 deletions
diff --git a/lib/chef/node.rb b/lib/chef/node.rb
index 22c7d5bd8e..ad065cc02b 100644
--- a/lib/chef/node.rb
+++ b/lib/chef/node.rb
@@ -63,6 +63,8 @@ class Chef
include Chef::Mixin::ParamsValidate
+ NULL_ARG = Object.new
+
# Create a new Chef::Node object.
def initialize(chef_server_rest: nil)
@chef_server_rest = chef_server_rest
@@ -72,6 +74,9 @@ class Chef
@primary_runlist = Chef::RunList.new
@override_runlist = Chef::RunList.new
+ @policy_name = nil
+ @policy_group = nil
+
@attributes = Chef::Node::Attribute.new({}, {}, {}, {})
@run_state = {}
@@ -132,6 +137,50 @@ class Chef
alias :environment :chef_environment
+ # The `policy_name` for this node. Setting this to a non-nil value will
+ # enable policyfile mode when `chef-client` is run. If set in the config
+ # file or in node json, running `chef-client` will update this value.
+ #
+ # @see Chef::PolicyBuilder::Dynamic
+ # @see Chef::PolicyBuilder::Policyfile
+ #
+ # @param arg [String] the new policy_name value
+ # @return [String] the current policy_name, or the one you just set
+ def policy_name(arg=NULL_ARG)
+ return @policy_name if arg.equal?(NULL_ARG)
+ validate({policy_name: arg}, { policy_name: { kind_of: [ String, NilClass ], regex: /^[\-:.[:alnum:]_]+$/ } })
+ @policy_name = arg
+ end
+
+ # A "non-DSL-style" setter for `policy_name`
+ #
+ # @see #policy_name
+ def policy_name=(policy_name)
+ policy_name(policy_name)
+ end
+
+ # The `policy_group` for this node. Setting this to a non-nil value will
+ # enable policyfile mode when `chef-client` is run. If set in the config
+ # file or in node json, running `chef-client` will update this value.
+ #
+ # @see Chef::PolicyBuilder::Dynamic
+ # @see Chef::PolicyBuilder::Policyfile
+ #
+ # @param arg [String] the new policy_group value
+ # @return [String] the current policy_group, or the one you just set
+ def policy_group(arg=NULL_ARG)
+ return @policy_group if arg.equal?(NULL_ARG)
+ validate({policy_group: arg}, { policy_group: { kind_of: [ String, NilClass ], regex: /^[\-:.[:alnum:]_]+$/ } })
+ @policy_group = arg
+ end
+
+ # A "non-DSL-style" setter for `policy_group`
+ #
+ # @see #policy_group
+ def policy_group=(policy_group)
+ policy_group(policy_group)
+ end
+
def attributes
@attributes
end
@@ -391,7 +440,7 @@ class Chef
self.tags # make sure they're defined
- automatic_attrs[:recipes] = expansion.recipes.with_fully_qualified_names_and_version_constraints
+ automatic_attrs[:recipes] = expansion.recipes.with_duplicate_names
automatic_attrs[:expanded_run_list] = expansion.recipes.with_fully_qualified_names_and_version_constraints
automatic_attrs[:roles] = expansion.roles
@@ -461,6 +510,14 @@ class Chef
#Render correctly for run_list items so malformed json does not result
"run_list" => @primary_runlist.run_list.map { |item| item.to_s }
}
+ # Chef Server rejects node JSON with extra keys; prior to 12.3,
+ # "policy_name" and "policy_group" are unknown; after 12.3 they are
+ # optional, therefore only including them in the JSON if present
+ # maximizes compatibility for most people.
+ unless policy_group.nil? && policy_name.nil?
+ result["policy_name"] = policy_name
+ result["policy_group"] = policy_group
+ end
result
end
@@ -492,6 +549,10 @@ class Chef
else
o["recipes"].each { |r| node.recipes << r }
end
+
+ node.policy_name = o["policy_name"] if o.has_key?("policy_name")
+ node.policy_group = o["policy_group"] if o.has_key?("policy_group")
+
node
end
@@ -548,13 +609,21 @@ class Chef
# so then POST to create.
begin
if Chef::Config[:why_run]
- Chef::Log.warn("In whyrun mode, so NOT performing node save.")
+ Chef::Log.warn("In why-run mode, so NOT performing node save.")
else
chef_server_rest.put_rest("nodes/#{name}", data_for_save)
end
rescue Net::HTTPServerException => e
- raise e unless e.response.code == "404"
- chef_server_rest.post_rest("nodes", data_for_save)
+ if e.response.code == "404"
+ chef_server_rest.post_rest("nodes", data_for_save)
+ # Chef Server before 12.3 rejects node JSON with 'policy_name' or
+ # 'policy_group' keys, but 'policy_name' will be detected first.
+ # Backcompat can be removed in 13.0
+ elsif e.response.code == "400" && e.response.body.include?("Invalid key policy_name")
+ save_without_policyfile_attrs
+ else
+ raise
+ end
end
self
end
@@ -563,6 +632,15 @@ class Chef
def create
chef_server_rest.post_rest("nodes", data_for_save)
self
+ rescue Net::HTTPServerException => e
+ # Chef Server before 12.3 rejects node JSON with 'policy_name' or
+ # 'policy_group' keys, but 'policy_name' will be detected first.
+ # Backcompat can be removed in 13.0
+ if e.response.code == "400" && e.response.body.include?("Invalid key policy_name")
+ chef_server_rest.post_rest("nodes", data_for_save_without_policyfile_attrs)
+ else
+ raise
+ end
end
def to_s
@@ -575,6 +653,22 @@ class Chef
private
+ def save_without_policyfile_attrs
+ trimmed_data = data_for_save_without_policyfile_attrs
+
+ chef_server_rest.put_rest("nodes/#{name}", trimmed_data)
+ rescue Net::HTTPServerException => e
+ raise e unless e.response.code == "404"
+ chef_server_rest.post_rest("nodes", trimmed_data)
+ end
+
+ def data_for_save_without_policyfile_attrs
+ data_for_save.tap do |trimmed_data|
+ trimmed_data.delete("policy_name")
+ trimmed_data.delete("policy_group")
+ end
+ end
+
def data_for_save
data = for_json
["automatic", "default", "normal", "override"].each do |level|