Class: Bolt::Inventory::Group

Inherits:
Object
  • Object
show all
Defined in:
lib/bolt/inventory/group.rb

Overview

Group is a specific implementation of Inventory based on nested structured data.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(data) ⇒ Group

Returns a new instance of Group.



8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# File 'lib/bolt/inventory/group.rb', line 8

def initialize(data)
  @name = data['name']

  @nodes = if data['nodes']
             data['nodes'].map do |n|
               if n.is_a? String
                 { 'name' => n }
               else
                 n
               end
             end
           else
             []
           end
  @config = data['config'] || {}
  @groups = if data['groups']
              data['groups'].map { |g| Group.new(g) }
            else
              []
            end

  # this allows arbitrary info for the top level
  @rest = data.reject { |k, _| %w[name nodes config groups].include? k }
end

Instance Attribute Details

#configObject

Returns the value of attribute config.



6
7
8
# File 'lib/bolt/inventory/group.rb', line 6

def config
  @config
end

#groupsObject

Returns the value of attribute groups.



6
7
8
# File 'lib/bolt/inventory/group.rb', line 6

def groups
  @groups
end

#nameObject

Returns the value of attribute name.



6
7
8
# File 'lib/bolt/inventory/group.rb', line 6

def name
  @name
end

#nodesObject

Returns the value of attribute nodes.



6
7
8
# File 'lib/bolt/inventory/group.rb', line 6

def nodes
  @nodes
end

#restObject

Returns the value of attribute rest.



6
7
8
# File 'lib/bolt/inventory/group.rb', line 6

def rest
  @rest
end

Instance Method Details

#collect_groupsObject

Return a mapping of group names to group.



119
120
121
122
123
# File 'lib/bolt/inventory/group.rb', line 119

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 , groups => Array } As we add more options beyond config this schema will grow



78
79
80
# File 'lib/bolt/inventory/group.rb', line 78

def data_for(node_name)
  data_merge(group_collect(node_name), node_collect(node_name))
end

#data_merge(data1, data2) ⇒ Object



100
101
102
103
104
105
106
107
108
109
# File 'lib/bolt/inventory/group.rb', line 100

def data_merge(data1, data2)
  if data2.nil? || data1.nil?
    return data2 || data1
  end

  {
    'config' => Bolt::Util.deep_merge(data1['config'], data2['config']),
    'groups' => data2['groups'] + data1['groups']
  }
end

#empty_dataObject



95
96
97
98
# File 'lib/bolt/inventory/group.rb', line 95

def empty_data
  { 'config' => {},
    'groups' => [] }
end

#group_collect(node_name) ⇒ Object



141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
# File 'lib/bolt/inventory/group.rb', line 141

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 local_node_names.include?(node_name)
    group_data
  end
end

#group_dataObject



90
91
92
93
# File 'lib/bolt/inventory/group.rb', line 90

def group_data
  { 'config' => @config,
    'groups' => [@name] }
end

#node_collect(node_name) ⇒ Object



130
131
132
133
134
135
136
137
138
139
# File 'lib/bolt/inventory/group.rb', line 130

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



82
83
84
85
86
87
88
# File 'lib/bolt/inventory/group.rb', line 82

def node_data(node_name)
  if (data = @nodes.find { |n| n['name'] == node_name })
    { 'config' => data['config'] || {},
      # groups come from group_data
      'groups' => [] }
  end
end

#node_namesObject

Returns all nodes contained within the group, which includes nodes from subgroups.



112
113
114
115
116
# File 'lib/bolt/inventory/group.rb', line 112

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

Raises:



33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
# File 'lib/bolt/inventory/group.rb', line 33

def validate(used_names = Set.new, node_names = Set.new, depth = 0)
  raise ValidationError.new("Group does not have a name", nil) unless @name
  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
  raise ValidationError.new("Group #{@name} is too deeply nested", @name) if depth > 1

  used_names << @name

  @nodes.each do |n|
    # Require nodes to be referenced only by their host name
    host = Addressable::URI.parse('//' + n['name']).host
    ipv6host = Addressable::URI.parse('//[' + n['name'] + ']').host
    if n['name'] != host && n['name'] != ipv6host
      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

    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