vagrant-ansible_auto 0.1.5 → 0.2.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +26 -0
- data/Gemfile +2 -0
- data/Gemfile.lock +172 -0
- data/README.md +53 -12
- data/Rakefile +9 -7
- data/TODO.md +14 -0
- data/Vagrantfile +37 -15
- data/lib/vagrant/ansible_auto/cap/guest/posix/check_open_port.rb +22 -3
- data/lib/vagrant/ansible_auto/cap/guest/posix/executable_installed.rb +10 -2
- data/lib/vagrant/ansible_auto/cap/guest/posix/gateway_addresses.rb +8 -23
- data/lib/vagrant/ansible_auto/cap/guest/posix/private_key.rb +16 -1
- data/lib/vagrant/ansible_auto/cap/guest/posix/public_key.rb +18 -3
- data/lib/vagrant/ansible_auto/cap/guest/posix/ssh_server_address.rb +22 -12
- data/lib/vagrant/ansible_auto/cap/guest/posix.rb +16 -0
- data/lib/vagrant/ansible_auto/command/inventory.rb +37 -11
- data/lib/vagrant/ansible_auto/command/root.rb +34 -31
- data/lib/vagrant/ansible_auto/config.rb +74 -33
- data/lib/vagrant/ansible_auto/errors.rb +30 -1
- data/lib/vagrant/ansible_auto/host.rb +123 -34
- data/lib/vagrant/ansible_auto/inventory.rb +196 -34
- data/lib/vagrant/ansible_auto/plugin.rb +23 -8
- data/lib/vagrant/ansible_auto/provisioner.rb +121 -79
- data/lib/vagrant/ansible_auto/util/config.rb +61 -0
- data/lib/vagrant/ansible_auto/util/hash_with_indifferent_access.rb +58 -0
- data/lib/vagrant/ansible_auto/util/keys.rb +49 -0
- data/lib/vagrant/ansible_auto/util/shell_quote.rb +24 -0
- data/lib/vagrant/ansible_auto/version.rb +2 -1
- data/lib/vagrant/ansible_auto.rb +15 -0
- data/locales/en.yml +34 -0
- data/spec/spec_helper.rb +5 -85
- data/spec/support/context.rb +111 -0
- data/spec/support/matchers.rb +45 -0
- data/spec/unit/vagrant/ansible_auto/config_spec.rb +72 -0
- data/spec/unit/vagrant/ansible_auto/host_spec.rb +131 -0
- data/spec/unit/vagrant/ansible_auto/inventory_spec.rb +349 -0
- data/spec/unit/vagrant/ansible_auto/provisioner_spec.rb +248 -0
- data/spec/unit/vagrant/ansible_auto/util/config_spec.rb +63 -0
- data/spec/unit/vagrant/ansible_auto/util/keys_spec.rb +66 -0
- data/vagrant-ansible_auto.gemspec +6 -4
- data/vagrant-spec.config.rb +3 -0
- data/yard/extensions.rb +45 -0
- metadata +36 -11
- data/Vagrantfile2 +0 -4
- data/Vagrantfile3 +0 -8
- data/Vagrantfile4 +0 -31
- data/lib/vagrant/ansible_auto/cap/guest/posix/bash_installed.rb +0 -30
- data/lib/vagrant/ansible_auto/util.rb +0 -24
- data/spec/vagrant/ansible_auto/host_spec.rb +0 -43
- data/spec/vagrant/ansible_auto/inventory_spec.rb +0 -79
@@ -1,101 +1,178 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
require 'set'
|
3
4
|
require 'json'
|
5
|
+
|
6
|
+
require 'vagrant/ansible_auto/errors'
|
4
7
|
require 'vagrant/ansible_auto/host'
|
8
|
+
require 'vagrant/ansible_auto/util/config'
|
9
|
+
require 'vagrant/ansible_auto/util/hash_with_indifferent_access'
|
5
10
|
|
6
11
|
module VagrantPlugins
|
7
12
|
module AnsibleAuto
|
13
|
+
# Class representing an Ansible inventory with hosts, groups, group
|
14
|
+
# children, and group variables
|
8
15
|
class Inventory
|
16
|
+
include VagrantPlugins::AnsibleAuto::Util::Config
|
17
|
+
|
18
|
+
UNNAMED_GROUP = '_'.freeze
|
19
|
+
|
20
|
+
# @return [Hash{String=>Set<Host>}] group names mapped to their members
|
9
21
|
def groups
|
10
|
-
|
22
|
+
if unset? @groups
|
23
|
+
@groups = Util::HashWithIndifferentAccess.new do |hash, key|
|
24
|
+
hash[key] = Set.new
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
11
28
|
@groups
|
12
29
|
end
|
13
30
|
|
31
|
+
# @return [Set<Host>] the hosts in the {Inventory}
|
14
32
|
def hosts
|
15
33
|
@hosts = Set.new if unset?(@hosts)
|
16
34
|
@hosts
|
17
35
|
end
|
18
36
|
|
37
|
+
# @return [Hash{String=>Hash}] group names mapped to their variables
|
19
38
|
def vars
|
20
|
-
|
39
|
+
if unset? @vars
|
40
|
+
@vars = Util::HashWithIndifferentAccess.new do |hash, key|
|
41
|
+
hash[key] = Util::HashWithIndifferentAccess.new
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
21
45
|
@vars
|
22
46
|
end
|
23
47
|
|
48
|
+
# @return [Hash{String=>Set}] group names mapped to their children
|
24
49
|
def children
|
25
|
-
|
50
|
+
if unset? @children
|
51
|
+
@children = Util::HashWithIndifferentAccess.new do |hash, key|
|
52
|
+
hash[key] = Set.new
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
26
56
|
@children
|
27
57
|
end
|
28
58
|
|
59
|
+
# Set the groups for the {Inventory}.
|
60
|
+
# @note overwrites the current {#groups}.
|
61
|
+
# @param [Hash{String=>Array,Hash}] new_groups the groups to assign to the
|
62
|
+
# {Inventory}
|
63
|
+
# @option new_groups [Array] group the hosts in +group+
|
64
|
+
# @option new_groups [Hash] group:vars the variables for +group+
|
65
|
+
# @option new_groups [Array] group:chilren the child groups for +group+
|
66
|
+
# @return [Hash{String=>Array,Hash}] the created groups
|
29
67
|
def groups=(new_groups)
|
30
68
|
@groups = nil
|
31
69
|
|
32
70
|
new_groups.each do |group_heading, entries|
|
33
|
-
group, type = group_heading
|
71
|
+
group, type = parse_group_heading(group_heading)
|
72
|
+
|
34
73
|
case type
|
35
74
|
when 'vars'
|
36
|
-
|
37
|
-
|
75
|
+
entries = {} if entries.nil?
|
76
|
+
vars_for(group, entries)
|
38
77
|
when 'children'
|
39
|
-
|
40
|
-
|
78
|
+
entries = [] if entries.nil?
|
79
|
+
children_of(group, *entries)
|
80
|
+
else
|
81
|
+
entries = [] if entries.nil?
|
82
|
+
if entries.is_a? Hash
|
83
|
+
add_complex_group(group, entries)
|
41
84
|
else
|
42
|
-
entries = [] if entries.nil?
|
43
85
|
add_group(group, *entries)
|
86
|
+
end
|
44
87
|
end
|
45
88
|
end
|
46
89
|
|
47
90
|
groups
|
48
91
|
end
|
49
92
|
|
50
|
-
|
93
|
+
# Set the hosts for the {Inventory}
|
94
|
+
# @note overwrites the current {#hosts}.
|
95
|
+
# @param [Hash{String=>Hash}] new_hosts the hosts in the inventory
|
96
|
+
# @option new_hosts [Hash{String=>Hash, nil}] host a host plus any hostvars
|
97
|
+
# @return [Hash{String=>Hash}] the created hosts
|
98
|
+
def hosts=(new_hosts)
|
51
99
|
@hosts = nil
|
52
100
|
|
53
|
-
|
54
|
-
hostvars
|
55
|
-
add_host(host, hostvars)
|
101
|
+
new_hosts.each do |host, hostvars|
|
102
|
+
add_host(host, hostvars || {})
|
56
103
|
end
|
57
104
|
|
58
105
|
hosts
|
59
106
|
end
|
60
107
|
|
108
|
+
# Set the variables for the groups in the {Inventory}
|
109
|
+
# @note overwrites the current {#vars}
|
110
|
+
# @param [Hash{String,Hash}] new_vars the variables to add to the
|
111
|
+
# {Inventory}
|
112
|
+
# @option new_vars [Hash{String,Hash}] group a group plus any group
|
113
|
+
# variables
|
114
|
+
# @return [Hash{String,Hash}] the created variables
|
61
115
|
def vars=(new_vars)
|
62
116
|
@vars = nil
|
63
117
|
|
64
|
-
new_vars.
|
118
|
+
new_vars.each do |group, group_vars|
|
65
119
|
vars_for(group, group_vars)
|
66
120
|
end
|
67
121
|
|
68
122
|
vars
|
69
123
|
end
|
70
124
|
|
125
|
+
# Set the children of the groups in the {Inventory}
|
126
|
+
# @note overwrites the currrent {#children}
|
127
|
+
# @param [Hash{String=>Array<String>}] new_children the group children to add to
|
128
|
+
# the {Inventory}
|
129
|
+
# @option new_children [Array<String>] group a group name and the list of
|
130
|
+
# its children
|
131
|
+
# @return [Hash{String=>Set<String>}] the created children
|
71
132
|
def children=(new_children)
|
72
133
|
@children = nil
|
73
134
|
|
74
|
-
new_children.
|
135
|
+
new_children.each do |group, group_children|
|
75
136
|
children_of(group, *group_children)
|
76
137
|
end
|
77
138
|
|
78
139
|
children
|
79
140
|
end
|
80
141
|
|
142
|
+
# Add a group to the {Inventory}
|
143
|
+
# @param [#to_s] group the name of the group
|
144
|
+
# @param [Array] members the hosts to add to the group
|
145
|
+
# @return [Set] the members of the added group
|
81
146
|
def add_group(group, *members)
|
147
|
+
raise InvalidGroupNameError, group: group if group.to_s == UNNAMED_GROUP
|
148
|
+
|
149
|
+
add_complex_group(group, members.pop) if members.last.is_a? Hash
|
150
|
+
|
82
151
|
groups[group.to_s].tap do |group_members|
|
83
152
|
group_members.merge(members)
|
84
153
|
return group_members
|
85
154
|
end
|
86
155
|
end
|
87
156
|
|
88
|
-
|
157
|
+
# Add a host to the {Inventory}
|
158
|
+
# @param [Host,String,Symbol,Vagrant::Machine] host the host to add
|
159
|
+
# @param [Hash] hostvars hostvars to assign to the host
|
160
|
+
def add_host(host, hostvars = nil)
|
89
161
|
hosts.add case host
|
90
162
|
when Host
|
91
|
-
host
|
163
|
+
host.tap { |h| h.hostvars = hostvars unless hostvars.nil? }
|
92
164
|
when String, Symbol
|
93
|
-
Host.new(host, hostvars)
|
165
|
+
Host.new(host, hostvars || {})
|
166
|
+
when Vagrant::Machine
|
167
|
+
HostMachine.new(host, hostvars || {})
|
94
168
|
else
|
95
|
-
|
169
|
+
raise Errors::InvalidHostTypeError, type: host.class.name
|
96
170
|
end
|
97
171
|
end
|
98
172
|
|
173
|
+
# Assign variables to a group
|
174
|
+
# @param [#to_s] group the name of the group
|
175
|
+
# @param [Hash] new_vars the variables to assign to the group
|
99
176
|
def vars_for(group, new_vars = {})
|
100
177
|
vars[group.to_s].tap do |group_vars|
|
101
178
|
group_vars.merge!(new_vars)
|
@@ -103,6 +180,9 @@ module VagrantPlugins
|
|
103
180
|
end
|
104
181
|
end
|
105
182
|
|
183
|
+
# Assign child groups to a group
|
184
|
+
# @param [#to_s] group the name of the group
|
185
|
+
# @param [Array] new_children the child groups to assign to the group
|
106
186
|
def children_of(group, *new_children)
|
107
187
|
children[group.to_s].tap do |group_children|
|
108
188
|
group_children.merge(new_children.map(&:to_s))
|
@@ -110,7 +190,12 @@ module VagrantPlugins
|
|
110
190
|
end
|
111
191
|
end
|
112
192
|
|
193
|
+
# Perform in-place merge of two {Inventory} instances
|
194
|
+
# @param [Inventory] other the inventory to merge into this one
|
195
|
+
# @return [self] the updated inventory
|
113
196
|
def merge!(other)
|
197
|
+
hosts.merge(other.hosts)
|
198
|
+
|
114
199
|
@groups = groups.merge(other.groups) do |_group, group_members, other_group_members|
|
115
200
|
group_members.merge(other_group_members)
|
116
201
|
end
|
@@ -126,34 +211,69 @@ module VagrantPlugins
|
|
126
211
|
self
|
127
212
|
end
|
128
213
|
|
214
|
+
# Merge two {Inventory} instances
|
215
|
+
# @param [Inventory] other the inventory to merge into this one
|
216
|
+
# @return [Inventory] the updated inventory
|
129
217
|
def merge(other)
|
130
218
|
clone.merge!(other)
|
131
219
|
end
|
132
220
|
|
221
|
+
# @return [Hash{String=>Hash}] the merged hostvars for all hosts in the
|
222
|
+
# inventory
|
133
223
|
def hostvars
|
134
|
-
hosts.
|
224
|
+
Hash[hosts.map { |h| [h.name, h.hostvars] }]
|
135
225
|
end
|
136
226
|
|
227
|
+
# A representation of an {Inventory} as a +Hash+
|
228
|
+
# @note the hosts in the inventory will be returned as +Hash+es under the
|
229
|
+
# key {UNNAMED_GROUP}
|
230
|
+
# @return [Hash{String=>Hash,Array}] a +Hash+ containing the hosts in the
|
231
|
+
# inventory (coerced to hashes) under the {UNNAMED_GROUP} key, as well
|
232
|
+
# as each group name mapped to a subhashes with hosts under the key
|
233
|
+
# +"hosts"+, variables under the key +"vars"+, and children under the
|
234
|
+
# key +"children"+
|
137
235
|
def to_h
|
138
|
-
{}.tap do |h|
|
139
|
-
h
|
140
|
-
|
141
|
-
|
142
|
-
|
236
|
+
Hash.new { |h, k| h[k] = {} }.tap do |h|
|
237
|
+
h[UNNAMED_GROUP] = hosts.map(&:to_h)
|
238
|
+
|
239
|
+
groups.each do |group, group_hosts|
|
240
|
+
h[group]['hosts'] = group_hosts.to_a
|
241
|
+
end
|
242
|
+
|
243
|
+
vars.each do |group, group_vars|
|
244
|
+
h[group]['vars'] = group_vars
|
245
|
+
end
|
246
|
+
|
247
|
+
children.each do |group, group_children|
|
248
|
+
h[group]['children'] = group_children.to_a
|
249
|
+
end
|
143
250
|
end
|
144
251
|
end
|
145
252
|
|
146
|
-
|
253
|
+
# @return [String] the {Inventory} represented as a JSON object in the
|
254
|
+
# form of a "Dynamic Inventory"
|
255
|
+
# @see http://docs.ansible.com/ansible/intro_dynamic_inventory.html
|
256
|
+
def to_json(*args)
|
147
257
|
to_h.tap do |h|
|
148
|
-
h.delete(
|
149
|
-
h['_meta'] = hostvars
|
150
|
-
end.to_json
|
258
|
+
h.delete(UNNAMED_GROUP)
|
259
|
+
h['_meta'] = { 'hostvars' => hostvars }
|
260
|
+
end.to_json(*args)
|
151
261
|
end
|
152
262
|
|
263
|
+
# Return the {Inventory} as an INI document
|
264
|
+
# @return [String] the inventory in a newline-separated string
|
153
265
|
def to_ini
|
154
266
|
with_ini_lines.to_a.join("\n")
|
155
267
|
end
|
156
268
|
|
269
|
+
# Iterate over the lines of the {Inventory} represented as an INI
|
270
|
+
# document
|
271
|
+
# @overload
|
272
|
+
# @return [Enumerator] the lines of the INI document
|
273
|
+
# @overload
|
274
|
+
# @yieldparam [String] each line in the INI document
|
275
|
+
# @see with_ini_lines_hosts
|
276
|
+
# @see with_ini_lines_groups
|
157
277
|
def with_ini_lines
|
158
278
|
return enum_for(__method__) unless block_given?
|
159
279
|
|
@@ -162,27 +282,69 @@ module VagrantPlugins
|
|
162
282
|
end
|
163
283
|
end
|
164
284
|
|
285
|
+
# Iterate over the hosts in the {Inventory} represented as an INI
|
286
|
+
# document
|
287
|
+
# @overload
|
288
|
+
# @return [Enumerator] the lines of the INI document
|
289
|
+
# @overload
|
290
|
+
# @yieldparam [String] each line in the INI document
|
165
291
|
def with_ini_lines_hosts
|
166
292
|
return enum_for(__method__) unless block_given?
|
167
293
|
hosts.each { |host| yield host.to_ini }
|
168
294
|
end
|
169
295
|
|
296
|
+
# Iterate over the groups in the {Inventory} represented as an INI
|
297
|
+
# document
|
298
|
+
# @overload
|
299
|
+
# @return [Enumerator] the lines of the INI document
|
300
|
+
# @overload
|
301
|
+
# @yieldparam [String] each line in the INI document
|
170
302
|
def with_ini_lines_groups
|
171
303
|
return enum_for(__method__) unless block_given?
|
172
304
|
|
173
|
-
to_h.tap { |h| h.delete(
|
305
|
+
to_h.tap { |h| h.delete(UNNAMED_GROUP) }.sort.each do |group, entries|
|
174
306
|
yield "[#{group}]"
|
175
307
|
|
176
|
-
|
177
|
-
|
308
|
+
entries.fetch('hosts', []).sort.each { |h| yield h }
|
309
|
+
|
310
|
+
if entries.key? 'children'
|
311
|
+
yield "[#{group}:children]"
|
312
|
+
entries['children'].sort.each { |c| yield c }
|
313
|
+
end
|
314
|
+
|
315
|
+
if entries.key? 'vars'
|
316
|
+
yield "[#{group}:vars]"
|
317
|
+
entries['vars'].sort.each { |k, v| yield "#{k} = #{v}" }
|
318
|
+
end
|
319
|
+
end
|
320
|
+
end
|
321
|
+
|
322
|
+
# A sanity check of the inventory's state
|
323
|
+
# @return [void]
|
324
|
+
# @raise [Errors::GroupMissingChildError] when a group has a child group
|
325
|
+
# that doesn't exist
|
326
|
+
def validate!
|
327
|
+
children.each do |group, group_children|
|
328
|
+
group_children.each do |child|
|
329
|
+
raise Errors::GroupMissingChildError, group: group, child: child unless groups.key? child
|
178
330
|
end
|
179
331
|
end
|
180
332
|
end
|
181
333
|
|
182
334
|
private
|
183
335
|
|
184
|
-
def
|
185
|
-
|
336
|
+
def parse_group_heading(group_heading)
|
337
|
+
group_elts = group_heading.to_s.split(/(?<!\\):/)
|
338
|
+
type = group_elts.length > 1 && %w[vars children].include?(group_elts.last) ? group_elts.pop.chomp.strip : nil
|
339
|
+
group = group_elts.join(':').chomp.strip
|
340
|
+
[group, type]
|
341
|
+
end
|
342
|
+
|
343
|
+
def add_complex_group(group, group_spec = {})
|
344
|
+
group_spec = Util::HashWithIndifferentAccess.new(group_spec)
|
345
|
+
vars_for(group, group_spec['vars']) if group_spec.key? 'vars'
|
346
|
+
children_of(group, *(group_spec['children'])) if group_spec.key? 'children'
|
347
|
+
add_group(group, *(group_spec['hosts'])) if group_spec.key? 'hosts'
|
186
348
|
end
|
187
349
|
end
|
188
350
|
end
|
@@ -1,8 +1,17 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Namespace for Vagrant plugins
|
2
4
|
module VagrantPlugins
|
5
|
+
# Namespace for the +ansible_auto+ provisioner and +ansible+ command
|
3
6
|
module AnsibleAuto
|
7
|
+
# Vagrant plugin class for the +ansible_auto+ provisioner and +ansible+
|
8
|
+
# command
|
4
9
|
class Plugin < Vagrant.plugin(2)
|
5
|
-
name 'ansible
|
10
|
+
name 'ansible auto'
|
11
|
+
description <<-DESC
|
12
|
+
Automatically generate Ansible inventories for use when running Ansible
|
13
|
+
on guest machines
|
14
|
+
DESC
|
6
15
|
|
7
16
|
config 'ansible' do
|
8
17
|
require_relative 'config'
|
@@ -35,7 +44,7 @@ module VagrantPlugins
|
|
35
44
|
Provisioner
|
36
45
|
end
|
37
46
|
|
38
|
-
guest_capability 'linux', :
|
47
|
+
guest_capability 'linux', :port_open? do
|
39
48
|
require_relative 'cap/guest/posix/check_open_port'
|
40
49
|
Cap::Guest::POSIX::CheckOpenPort
|
41
50
|
end
|
@@ -55,11 +64,6 @@ module VagrantPlugins
|
|
55
64
|
Cap::Guest::POSIX::ExecutableInstalled
|
56
65
|
end
|
57
66
|
|
58
|
-
guest_capability 'linux', :bash_installed? do
|
59
|
-
require_relative 'cap/guest/posix/bash_installed'
|
60
|
-
Cap::Guest::POSIX::BashInstalled
|
61
|
-
end
|
62
|
-
|
63
67
|
guest_capability 'linux', :generate_private_key do
|
64
68
|
require_relative 'cap/guest/posix/private_key'
|
65
69
|
Cap::Guest::POSIX::PrivateKey
|
@@ -67,7 +71,18 @@ module VagrantPlugins
|
|
67
71
|
|
68
72
|
guest_capability 'linux', :fetch_public_key do
|
69
73
|
require_relative 'cap/guest/posix/public_key'
|
70
|
-
Cap::Guest::POSIX::
|
74
|
+
Cap::Guest::POSIX::PublicKey
|
75
|
+
end
|
76
|
+
|
77
|
+
guest_capability 'linux', :authorized_key? do
|
78
|
+
require_relative 'cap/guest/posix/public_key'
|
79
|
+
Cap::Guest::POSIX::PublicKey
|
80
|
+
end
|
81
|
+
|
82
|
+
action_hook 'environment_plugins_loaded' do
|
83
|
+
require 'i18n'
|
84
|
+
I18n.load_path << VagrantPlugins::AnsibleAuto.source_root.join('locales/en.yml')
|
85
|
+
I18n.reload!
|
71
86
|
end
|
72
87
|
end
|
73
88
|
end
|