# File lib/chef/node.rb, line 299 def primary_runlist @primary_runlist end
class Chef::Node
Attributes
RunContext
will set itself as run_context
via this setter when initialized. This is needed so DSL::IncludeAttribute
(in particular, include_recipe) can access the run_context
to determine if an attributes file has been seen yet.
Public Class Methods
Source
# File lib/chef/node.rb, line 644 def self.build(node_name) node = new node.name(node_name) node.chef_environment(Chef::Config[:environment]) unless Chef::Config[:environment].nil? || Chef::Config[:environment].chomp.empty? node end
Source
# File lib/chef/node.rb, line 635 def self.find_or_create(node_name) load(node_name) rescue Net::HTTPClientException => e raise unless e.response.code == "404" node = build(node_name) node.create end
Source
# File lib/chef/node.rb, line 580 def self.from_hash(o) return o if o.is_a? Chef::Node node = new node.name(o["name"]) node.policy_name = o["policy_name"] if o.key?("policy_name") node.policy_group = o["policy_group"] if o.key?("policy_group") unless node.policy_group.nil? node.chef_environment(o["policy_group"]) else node.chef_environment(o["chef_environment"]) end if o.key?("attributes") node.normal_attrs = o["attributes"] end node.automatic_attrs = Mash.new(o["automatic"]) if o.key?("automatic") node.normal_attrs = Mash.new(o["normal"]) if o.key?("normal") node.default_attrs = Mash.new(o["default"]) if o.key?("default") node.override_attrs = Mash.new(o["override"]) if o.key?("override") if o.key?("run_list") node.run_list.reset!(o["run_list"]) elsif o.key?("recipes") o["recipes"].each { |r| node.recipes << r } end node end
Source
# File lib/chef/node.rb, line 622 def self.list(inflate = false) if inflate response = {} Chef::Search::Query.new.search(:node) do |n| n = Chef::Node.from_hash(n) response[n.name] = n unless n.nil? end response else Chef::ServerAPI.new(Chef::Config[:chef_server_url]).get("nodes") end end
Source
# File lib/chef/node.rb, line 612 def self.list_by_environment(environment, inflate = false) if inflate response = {} Chef::Search::Query.new.search(:node, "chef_environment:#{environment}") { |n| response[n.name] = n unless n.nil? } response else Chef::ServerAPI.new(Chef::Config[:chef_server_url]).get("environments/#{environment}/nodes") end end
Source
# File lib/chef/node.rb, line 652 def self.load(name) from_hash(Chef::ServerAPI.new(Chef::Config[:chef_server_url]).get("nodes/#{name}")) end
Load a node by name
Source
# File lib/chef/node.rb, line 70 def initialize(chef_server_rest: nil, logger: nil) @chef_server_rest = chef_server_rest @name = nil @logger = logger || Chef::Log.with_child(subsystem: "node") @chef_environment = "_default" @primary_runlist = Chef::RunList.new @override_runlist = Chef::RunList.new @policy_name = nil @policy_group = nil @attributes = Chef::Node::Attribute.new({}, {}, {}, {}, self) @run_state = {} end
Create a new Chef::Node
object.
Public Instance Methods
Source
# File lib/chef/node.rb, line 700 def ==(other) if other.is_a?(self.class) name == other.name else false end end
Source
# File lib/chef/node.rb, line 196 def [](attrib) attributes[attrib] end
Return an attribute of this node. Returns nil if the attribute is not found.
Source
# File lib/chef/node.rb, line 503 def apply_expansion_attributes(expansion) loaded_environment = if chef_environment == "_default" Chef::Environment.new.tap { |e| e.name("_default") } else Chef::Environment.load(chef_environment) end attributes.env_default = loaded_environment.default_attributes attributes.env_override = loaded_environment.override_attributes attribute.role_default = expansion.default_attrs attributes.role_override = expansion.override_attrs end
Apply the default and overrides attributes from the expansion passed in, which came from roles.
Source
# File lib/chef/node.rb, line 247 def attribute?(attrib) attributes.attribute?(attrib) end
Return true if this Node
has a given attribute, false if not. Takes either a symbol or a string.
Only works on the top level. Preferred way is to use the normal [] style lookup and call attribute?()
Source
# File lib/chef/node.rb, line 188 def attributes @attributes end
Source
# File lib/chef/node.rb, line 234 def automatic_attrs attributes.automatic end
Source
# File lib/chef/node.rb, line 238 def automatic_attrs=(new_values) attributes.automatic = new_values end
Source
# File lib/chef/node.rb, line 128 def chef_environment(arg = nil) set_or_return( :chef_environment, arg, { regex: /^[\-[:alnum:]_]+$/, kind_of: String } ) end
Source
# File lib/chef/node.rb, line 136 def chef_environment=(environment) chef_environment(environment) end
Source
# File lib/chef/node.rb, line 100 def chef_server_rest # for saving node data we use validate_utf8: false which will not # raise an exception on bad utf8 data, but will replace the bad # characters and render valid JSON. @chef_server_rest ||= Chef::ServerAPI.new( Chef::Config[:chef_server_url], client_name: Chef::Config[:node_name], signing_key_filename: Chef::Config[:client_key], validate_utf8: false ) end
Source
# File lib/chef/node.rb, line 389 def consume_attributes(attrs) normal_attrs_to_merge = consume_run_list(attrs) normal_attrs_to_merge = consume_chef_environment(normal_attrs_to_merge) # FIXME(log): should be trace logger.debug("Applying attributes from json file") self.normal_attrs = Chef::Mixin::DeepMerge.merge(normal_attrs, normal_attrs_to_merge) tags # make sure they're defined end
Consumes the combined run_list
and other attributes in attrs
Source
# File lib/chef/node.rb, line 458 def consume_chef_environment(attrs) attrs = attrs ? attrs.dup : {} if env = attrs.delete("chef_environment") chef_environment(env) end attrs end
chef_environment
when set in -j JSON will take precedence over -E ENVIRONMENT. Ideally, IMO, the order of precedence should be (lowest to
highest): config_file -j JSON -E ENVIRONMENT
so that users could reuse their JSON and override the chef_environment
configured within it with -E ENVIRONMENT. Because command line options are merged with Chef::Config
there is currently no way to distinguish between an environment set via config from an environment set via command line.
Source
# File lib/chef/node.rb, line 357 def consume_external_attrs(ohai_data, json_cli_attrs) # FIXME(log): should be trace logger.debug("Extracting run list from JSON attributes provided on command line") consume_attributes(json_cli_attrs) self.automatic_attrs = ohai_data fix_automatic_attributes end
Handles both the consumption of ohai data and possibly JSON attributes from the CLI
@api private
Source
# File lib/chef/node.rb, line 369 def consume_ohai_data(ohai_data) self.automatic_attrs = Chef::Mixin::DeepMerge.merge(automatic_attrs, ohai_data) fix_automatic_attributes end
This is for ohai plugins to consume ohai data and have it merged, it should probably be renamed
@api private
Source
# File lib/chef/node.rb, line 435 def consume_run_list(attrs) attrs = attrs ? attrs.dup : {} if new_run_list = attrs.delete("recipes") || attrs.delete("run_list") if attrs.key?("recipes") || attrs.key?("run_list") raise Chef::Exceptions::AmbiguousRunlistSpecification, "please set the node's run list using the 'run_list' attribute only." end logger.info("Setting the run_list to #{new_run_list} from CLI options") run_list(new_run_list) end attrs end
Extracts the run list from attrs
and applies it. Returns the remaining attributes
Source
# File lib/chef/node.rb, line 682 def create chef_server_rest.post("nodes", data_for_save) self rescue Net::HTTPClientException => 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("nodes", data_for_save_without_policyfile_attrs) else raise end end
Create the node via the REST API
Source
# File lib/chef/node.rb, line 713 def data_for_save data = for_json %w{automatic default normal override}.each do |level| allowlist = allowlist_or_whitelist_config(level) unless allowlist.nil? # nil => save everything logger.info("Allowing #{level} node attributes for save.") data[level] = Chef::AttributeAllowlist.filter(data[level], allowlist) end blocklist = blocklist_or_blacklist_config(level) unless blocklist.nil? # nil => remove nothing logger.info("Blocking #{level} node attributes for save") data[level] = Chef::AttributeBlocklist.filter(data[level], blocklist) end end data end
Returns hash of node data with attributes based on whitelist/blacklist rules.
Source
# File lib/chef/node.rb, line 208 def default attributes.default end
Set a default of this node, but auto-vivify any Mashes that might be missing
Source
# File lib/chef/node.rb, line 226 def default_attrs=(new_values) attributes.default = new_values end
Source
# File lib/chef/node.rb, line 657 def destroy chef_server_rest.delete("nodes/#{name}") end
Remove this node via the REST API
Source
# File lib/chef/node.rb, line 529 def display_hash display = {} display["name"] = name display["chef_environment"] = chef_environment display["automatic"] = attributes.automatic.to_hash display["normal"] = attributes.normal.to_hash display["default"] = attributes.combined_default.to_hash display["override"] = attributes.combined_override.to_hash display["run_list"] = run_list.run_list_items display end
Source
# File lib/chef/node.rb, line 252 def each(&block) attributes.each(&block) end
Yield each key of the top level to the block.
Source
# File lib/chef/node.rb, line 257 def each_attribute(&block) attributes.each_attribute(&block) end
Iterates over each attribute, passing the attribute and value to the block.
Source
# File lib/chef/node.rb, line 485 def expand!(data_source = "server") expansion = run_list.expand(chef_environment, data_source) raise Chef::Exceptions::MissingRole, expansion if expansion.errors? tags # make sure they're defined 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 apply_expansion_attributes(expansion) automatic_attrs[:chef_environment] = chef_environment expansion end
Expands the node’s run list and sets the default and override attributes. Also applies stored attributes (from json provided on the command line)
Returns the fully-expanded list of recipes, a RunListExpansion.
Source
# File lib/chef/node.rb, line 377 def fix_automatic_attributes platform, version = Chef::Platform.find_platform_and_version(self) # FIXME(log): should be trace logger.debug("Platform is #{platform} version #{version}") automatic[:platform] = platform automatic[:platform_version] = Chef::VersionString.new(version) automatic[:chef_guid] = Chef::Config[:chef_guid] || ( Chef::Config[:chef_guid] = node_uuid ) automatic[:name] = name automatic[:chef_environment] = chef_environment end
Always ensure that certain automatic attributes are populated and constructed correctly
@api private
Source
# File lib/chef/node.rb, line 546 def for_json result = { "name" => name, "chef_environment" => chef_environment, "json_class" => self.class.name, "automatic" => attributes.automatic.to_hash, "normal" => attributes.normal.to_hash, "chef_type" => "node", "default" => attributes.combined_default.to_hash, "override" => attributes.combined_override.to_hash, # Render correctly for run_list items so malformed json does not result "run_list" => @primary_runlist.run_list.map(&: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
Source
# File lib/chef/node.rb, line 285 def loaded_recipe(cookbook, recipe) fully_qualified_recipe = "#{cookbook}::#{recipe}" automatic_attrs[:recipes] << fully_qualified_recipe unless Array(automatic_attrs[:recipes]).include?(fully_qualified_recipe) end
used by include_recipe to add recipes to the expanded run_list
to be saved back to the node and be searchable
Source
# File lib/chef/node.rb, line 263 def method_missing(method, *args, &block) attributes.public_send(method, *args, &block) end
Only works for attribute fetches, setting is no longer supported XXX: this should be deprecated
Source
# File lib/chef/node.rb, line 113 def name(arg = nil) if !arg.nil? validate( { name: arg }, { name: { kind_of: String, cannot_be: :blank, regex: /^[\-[:alnum:]_:.]+$/ }, } ) @name = arg else @name end end
Set the name of this Node
, or return the current name.
Source
# File lib/chef/node.rb, line 202 def normal attributes.normal end
Set a normal attribute of this node, but auto-vivify any Mashes that might be missing
Source
# File lib/chef/node.rb, line 230 def normal_attrs=(new_values) attributes.normal = new_values end
Source
# File lib/chef/node.rb, line 214 def override attributes.override end
Set an override attribute of this node, but auto-vivify any Mashes that might be missing
Source
# File lib/chef/node.rb, line 222 def override_attrs=(new_values) attributes.override = new_values end
Source
# File lib/chef/node.rb, line 317 def override_runlist(*args) return @override_runlist if args.length == 0 @override_runlist_set = true @override_runlist.reset!(args) end
Accessor for override_runlist
(this cannot set an empty override run list)
@params args [Array] override run list to set @return [Chef::RunList] the override run list
Source
# File lib/chef/node.rb, line 328 def override_runlist=(array) @override_runlist_set = true @override_runlist.reset!(array) end
Setter for override_runlist
which allows setting an empty override run list and marking it to be used
@params array [Array] override run list to set @return [Chef::RunList] the override run list
Source
# File lib/chef/node.rb, line 309 def override_runlist_set? !!@override_runlist_set || !override_runlist.empty? end
This boolean can be useful to determine if an override_runlist
is set, it can be true even if the override_runlist
is empty.
(Mutators can set the override_runlist
so any non-empty override_runlist
is considered set)
@return [Boolean] if the override run list has been set
Source
# File lib/chef/node.rb, line 174 def policy_group(arg = NOT_PASSED) return @policy_group if arg.equal?(NOT_PASSED) validate({ policy_group: arg }, { policy_group: { kind_of: [ String, NilClass ], regex: /^[\-:.[:alnum:]_]+$/ } }) @policy_group = arg 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
Source
# File lib/chef/node.rb, line 184 def policy_group=(policy_group) policy_group(policy_group) end
A “non-DSL-style” setter for ‘policy_group`
@see policy_group
Source
# File lib/chef/node.rb, line 151 def policy_name(arg = NOT_PASSED) return @policy_name if arg.equal?(NOT_PASSED) validate({ policy_name: arg }, { policy_name: { kind_of: [ String, NilClass ], regex: /^[\-:.[:alnum:]_]+$/ } }) @policy_name = arg end
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
Source
# File lib/chef/node.rb, line 161 def policy_name=(policy_name) policy_name(policy_name) end
A “non-DSL-style” setter for ‘policy_name`
@see policy_name
Source
Source
# File lib/chef/node.rb, line 279 def recipe?(recipe_name) run_list.include?(recipe_name) || Array(self[:recipes]).include?(recipe_name) end
Returns true if this Node
expects a given recipe, false if not.
First, the run list is consulted to see whether the recipe is explicitly included. If it’s not there, it looks in ‘node`, which is populated when the run_list
is expanded
NOTE: It’s used by cookbook authors
Source
# File lib/chef/node.rb, line 468 def reset_defaults_and_overrides default.clear override.clear end
Clear defaults and overrides, so that any deleted attributes between runs are still gone.
Source
# File lib/chef/node.rb, line 268 def respond_to_missing?(method, include_private = false) attributes.respond_to?(method, false) end
Fix respond_to + method so that it works with method_missing
delegation
Source
Source
# File lib/chef/node.rb, line 339 def run_list(*args) rl = select_run_list args.length > 0 ? rl.reset!(args) : rl end
Returns an Array of roles and recipes, in the order they will be applied. If you call it with arguments, they will become the new list of roles and recipes.
Source
# File lib/chef/node.rb, line 344 def run_list=(list) rl = select_run_list rl = list end
Source
# File lib/chef/node.rb, line 350 def run_list?(item) run_list.detect { |r| r == item } ? true : false end
Returns true if this Node
expects a given role, false if not.
Source
# File lib/chef/node.rb, line 662 def save # Try PUT. If the node doesn't yet exist, PUT will return 404, # so then POST to create. begin if Chef::Config[:why_run] logger.warn("In why-run mode, so NOT performing node save.") else chef_server_rest.put("nodes/#{name}", data_for_save) end rescue Net::HTTPClientException => e if e.response.code == "404" chef_server_rest.post("nodes", data_for_save) else raise end end self end
Save this node via the REST API
Source
# File lib/chef/node.rb, line 333 def select_run_list override_runlist_set? ? @override_runlist : @primary_runlist end
Source
# File lib/chef/node.rb, line 89 def set_cookbook_attribute run_context.cookbook_collection.each do |cookbook_name, cookbook| automatic_attrs[:cookbooks][cookbook_name][:version] = cookbook.version end end
after the run_context
has been set on the node, go through the cookbook_collection and setup the node attribute so that it is published in the node object
Source
Source
# File lib/chef/node.rb, line 518 def to_hash index_hash = attributes.to_hash index_hash["chef_type"] = "node" index_hash["name"] = name index_hash["chef_environment"] = chef_environment index_hash["recipe"] = run_list.recipe_names if run_list.recipe_names.length > 0 index_hash["role"] = run_list.role_names if run_list.role_names.length > 0 index_hash["run_list"] = run_list.run_list_items index_hash end
Transform the node to a Hash
Source
# File lib/chef/node.rb, line 542 def to_json(*a) Chef::JSONCompat.to_json(for_json, *a) end
Serialize this object as a hash
Source
Source
# File lib/chef/node.rb, line 570 def update_from!(o) run_list.reset!(o.run_list) self.automatic_attrs = o.automatic_attrs self.normal_attrs = o.normal_attrs self.override_attrs = o.override_attrs self.default_attrs = o.default_attrs chef_environment(o.chef_environment) self end
Private Instance Methods
Source
# File lib/chef/node.rb, line 754 def allowlist_or_whitelist_config(level) if Chef::Config["#{level}_attribute_whitelist".to_sym] Chef.deprecated(:attribute_whitelist_configuration, "Attribute whitelist configurations have been deprecated. Use the allowed_LEVEL_attribute configs instead") Chef::Config["#{level}_attribute_whitelist".to_sym] else Chef::Config["allowed_#{level}_attributes".to_sym] end end
a method to handle the renamed configuration from whitelist -> allowed and to throw a deprecation warning when the old configuration is set
@param [String] level the attribute level
Source
# File lib/chef/node.rb, line 767 def blocklist_or_blacklist_config(level) if Chef::Config["#{level}_attribute_blacklist".to_sym] Chef.deprecated(:attribute_blacklist_configuration, "Attribute blacklist configurations have been deprecated. Use the blocked_LEVEL_attribute configs instead") Chef::Config["#{level}_attribute_blacklist".to_sym] else Chef::Config["blocked_#{level}_attributes".to_sym] end end
a method to handle the renamed configuration from blacklist -> blocked and to throw a deprecation warning when the old configuration is set
@param [String] level the attribute level
Source
# File lib/chef/node.rb, line 743 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
Source
# File lib/chef/node.rb, line 783 def node_uuid path = File.expand_path(Chef::Config[:chef_guid_path]) dir = File.dirname(path) unless File.exist?(path) FileUtils.mkdir_p(dir) File.write(path, SecureRandom.uuid) end File.open(path).first.chomp end
Returns a UUID that uniquely identifies this node for reporting reasons.
The node is read in from disk if it exists, or it’s generated if it does does not exist.
@return [String] UUID for the node
Source
# File lib/chef/node.rb, line 733 def save_without_policyfile_attrs trimmed_data = data_for_save_without_policyfile_attrs chef_server_rest.put("nodes/#{name}", trimmed_data) rescue Net::HTTPClientException => e raise e unless e.response.code == "404" chef_server_rest.post("nodes", trimmed_data) end