Class: Bolt::Inventory::Group
- Inherits:
-
Object
- Object
- Bolt::Inventory::Group
- Defined in:
- lib/bolt/inventory/group.rb
Overview
Group is a specific implementation of Inventory based on nested structured data.
Instance Attribute Summary collapse
-
#config ⇒ Object
Returns the value of attribute config.
-
#groups ⇒ Object
Returns the value of attribute groups.
-
#name ⇒ Object
Returns the value of attribute name.
-
#nodes ⇒ Object
Returns the value of attribute nodes.
-
#rest ⇒ Object
Returns the value of attribute rest.
Instance Method Summary collapse
- #check_deprecated_config(context, name, config) ⇒ Object
-
#collect_groups ⇒ Object
Return a mapping of group names to group.
-
#data_for(node_name) ⇒ Object
The data functions below expect and return nil or a hash of the schema { ‘config’ => Hash , ‘vars’ => Hash, ‘facts’ => Hash, ‘features’ => Array, groups => Array }.
- #data_merge(data1, data2) ⇒ Object
- #empty_data ⇒ Object
- #fetch_value(data, key, type) ⇒ Object
- #group_collect(node_name) ⇒ Object
- #group_data ⇒ Object
-
#initialize(data) ⇒ Group
constructor
A new instance of Group.
- #node_collect(node_name) ⇒ Object
- #node_data(node_name) ⇒ Object
-
#node_names ⇒ Object
Returns all nodes contained within the group, which includes nodes from subgroups.
- #validate(used_names = Set.new, node_names = Set.new, depth = 0) ⇒ Object
Constructor Details
#initialize(data) ⇒ Group
Returns a new instance of Group.
10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 |
# File 'lib/bolt/inventory/group.rb', line 10 def initialize(data) @logger = Logging.logger[self] unless data.is_a?(Hash) raise ValidationError.new("Expected group to be a Hash, not #{data.class}", nil) end if data.key?('name') if data['name'].is_a?(String) @name = data['name'] else raise ValidationError.new("Group name must be a String, not #{data['name'].inspect}", nil) end else raise ValidationError.new("Group does not have a name", nil) end @vars = fetch_value(data, 'vars', Hash) @facts = fetch_value(data, 'facts', Hash) @features = fetch_value(data, 'features', Array) @config = fetch_value(data, 'config', Hash) nodes = fetch_value(data, 'nodes', Array) groups = fetch_value(data, 'groups', Array) @nodes = {} nodes.each do |node| node = { 'name' => node } if node.is_a? String unless node.is_a?(Hash) raise ValidationError.new("Node entry must be a String or Hash, not #{node.class}", @name) end if @nodes.include? node['name'] @logger.warn("Ignoring duplicate node in #{@name}: #{node}") else @nodes[node['name']] = node end end @groups = groups.map { |g| Group.new(g) } # this allows arbitrary info for the top level @rest = data.reject { |k, _| %w[name nodes config groups vars facts features].include? k } end |
Instance Attribute Details
#config ⇒ Object
Returns the value of attribute config.
8 9 10 |
# File 'lib/bolt/inventory/group.rb', line 8 def config @config end |
#groups ⇒ Object
Returns the value of attribute groups.
8 9 10 |
# File 'lib/bolt/inventory/group.rb', line 8 def groups @groups end |
#name ⇒ Object
Returns the value of attribute name.
8 9 10 |
# File 'lib/bolt/inventory/group.rb', line 8 def name @name end |
#nodes ⇒ Object
Returns the value of attribute nodes.
8 9 10 |
# File 'lib/bolt/inventory/group.rb', line 8 def nodes @nodes end |
#rest ⇒ Object
Returns the value of attribute rest.
8 9 10 |
# File 'lib/bolt/inventory/group.rb', line 8 def rest @rest end |
Instance Method Details
#check_deprecated_config(context, name, config) ⇒ Object
62 63 64 65 66 67 68 |
# File 'lib/bolt/inventory/group.rb', line 62 def check_deprecated_config(context, name, config) if config && config['transports'] msg = "#{context} #{name} contains invalid config option 'transports', see " \ "https://puppet.com/docs/bolt/0.x/inventory_file.html for the updated format" raise ValidationError.new(msg, @name) end end |
#collect_groups ⇒ Object
Return a mapping of group names to group.
173 174 175 176 177 |
# File 'lib/bolt/inventory/group.rb', line 173 def collect_groups @groups.inject(name => self) do |acc, g| acc.merge(g.collect_groups) end end |
#data_for(node_name) ⇒ Object
The data functions below expect and return nil or a hash of the schema { ‘config’ => Hash , ‘vars’ => Hash, ‘facts’ => Hash, ‘features’ => Array, groups => Array }
117 118 119 |
# File 'lib/bolt/inventory/group.rb', line 117 def data_for(node_name) data_merge(group_collect(node_name), node_collect(node_name)) end |
#data_merge(data1, data2) ⇒ Object
148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 |
# File 'lib/bolt/inventory/group.rb', line 148 def data_merge(data1, data2) if data2.nil? || data1.nil? return data2 || data1 end { 'config' => Bolt::Util.deep_merge(data1['config'], data2['config']), # Shallow merge instead of deep merge so that vars with a hash value # are assigned a new hash, rather than merging the existing value # with the value meant to replace it 'vars' => data1['vars'].merge(data2['vars']), 'facts' => Bolt::Util.deep_merge(data1['facts'], data2['facts']), 'features' => data1['features'] | data2['features'], 'groups' => data2['groups'] + data1['groups'] } end |
#empty_data ⇒ Object
140 141 142 143 144 145 146 |
# File 'lib/bolt/inventory/group.rb', line 140 def empty_data { 'config' => {}, 'vars' => {}, 'facts' => {}, 'features' => [], 'groups' => [] } end |
#fetch_value(data, key, type) ⇒ Object
54 55 56 57 58 59 60 |
# File 'lib/bolt/inventory/group.rb', line 54 def fetch_value(data, key, type) value = data.fetch(key, type.new) unless value.is_a?(type) raise ValidationError.new("Expected #{key} to be of type #{type}, not #{value.class}", @name) end value end |
#group_collect(node_name) ⇒ Object
195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 |
# File 'lib/bolt/inventory/group.rb', line 195 def group_collect(node_name) data = @groups.inject(nil) do |acc, g| if (d = g.data_for(node_name)) data_merge(d, acc) else acc end end if data data_merge(group_data, data) elsif @nodes.include?(node_name) group_data end end |
#group_data ⇒ Object
132 133 134 135 136 137 138 |
# File 'lib/bolt/inventory/group.rb', line 132 def group_data { 'config' => @config, 'vars' => @vars, 'facts' => @facts, 'features' => @features, 'groups' => [@name] } end |
#node_collect(node_name) ⇒ Object
184 185 186 187 188 189 190 191 192 193 |
# File 'lib/bolt/inventory/group.rb', line 184 def node_collect(node_name) data = @groups.inject(nil) do |acc, g| if (d = g.node_collect(node_name)) data_merge(d, acc) else acc end end data_merge(node_data(node_name), data) end |
#node_data(node_name) ⇒ Object
121 122 123 124 125 126 127 128 129 130 |
# File 'lib/bolt/inventory/group.rb', line 121 def node_data(node_name) if (data = @nodes[node_name]) { 'config' => data['config'] || {}, 'vars' => data['vars'] || {}, 'facts' => data['facts'] || {}, 'features' => data['features'] || [], # groups come from group_data 'groups' => [] } end end |
#node_names ⇒ Object
Returns all nodes contained within the group, which includes nodes from subgroups.
166 167 168 169 170 |
# File 'lib/bolt/inventory/group.rb', line 166 def node_names @groups.inject(local_node_names) do |acc, g| acc.merge(g.node_names) end end |
#validate(used_names = Set.new, node_names = Set.new, depth = 0) ⇒ Object
70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 |
# File 'lib/bolt/inventory/group.rb', line 70 def validate(used_names = Set.new, node_names = Set.new, depth = 0) if used_names.include?(@name) raise ValidationError.new("Tried to redefine group #{@name}", @name) end raise ValidationError.new("Invalid group name #{@name}", @name) unless @name =~ /\A[a-z0-9_]+\Z/ if node_names.include?(@name) raise ValidationError.new("Group #{@name} conflicts with node of the same name", @name) end check_deprecated_config('Group', @name, @config) used_names << @name @nodes.each_value do |n| # Require nodes to be parseable as a Target. begin Target.new(n['name']) rescue Addressable::URI::InvalidURIError => e @logger.debug(e) raise ValidationError.new("Invalid node name #{n['name']}", n['name']) end raise ValidationError.new("Node #{n['name']} does not have a name", n['name']) unless n['name'] if used_names.include?(n['name']) raise ValidationError.new("Group #{n['name']} conflicts with node of the same name", n['name']) end check_deprecated_config('Node', n['name'], n['config']) node_names << n['name'] end @groups.each do |g| begin g.validate(used_names, node_names, depth + 1) rescue ValidationError => e e.add_parent(@name) raise e end end nil end |