vagrant-ansible_auto 0.1.5 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +26 -0
  3. data/Gemfile +2 -0
  4. data/Gemfile.lock +172 -0
  5. data/README.md +53 -12
  6. data/Rakefile +9 -7
  7. data/TODO.md +14 -0
  8. data/Vagrantfile +37 -15
  9. data/lib/vagrant/ansible_auto/cap/guest/posix/check_open_port.rb +22 -3
  10. data/lib/vagrant/ansible_auto/cap/guest/posix/executable_installed.rb +10 -2
  11. data/lib/vagrant/ansible_auto/cap/guest/posix/gateway_addresses.rb +8 -23
  12. data/lib/vagrant/ansible_auto/cap/guest/posix/private_key.rb +16 -1
  13. data/lib/vagrant/ansible_auto/cap/guest/posix/public_key.rb +18 -3
  14. data/lib/vagrant/ansible_auto/cap/guest/posix/ssh_server_address.rb +22 -12
  15. data/lib/vagrant/ansible_auto/cap/guest/posix.rb +16 -0
  16. data/lib/vagrant/ansible_auto/command/inventory.rb +37 -11
  17. data/lib/vagrant/ansible_auto/command/root.rb +34 -31
  18. data/lib/vagrant/ansible_auto/config.rb +74 -33
  19. data/lib/vagrant/ansible_auto/errors.rb +30 -1
  20. data/lib/vagrant/ansible_auto/host.rb +123 -34
  21. data/lib/vagrant/ansible_auto/inventory.rb +196 -34
  22. data/lib/vagrant/ansible_auto/plugin.rb +23 -8
  23. data/lib/vagrant/ansible_auto/provisioner.rb +121 -79
  24. data/lib/vagrant/ansible_auto/util/config.rb +61 -0
  25. data/lib/vagrant/ansible_auto/util/hash_with_indifferent_access.rb +58 -0
  26. data/lib/vagrant/ansible_auto/util/keys.rb +49 -0
  27. data/lib/vagrant/ansible_auto/util/shell_quote.rb +24 -0
  28. data/lib/vagrant/ansible_auto/version.rb +2 -1
  29. data/lib/vagrant/ansible_auto.rb +15 -0
  30. data/locales/en.yml +34 -0
  31. data/spec/spec_helper.rb +5 -85
  32. data/spec/support/context.rb +111 -0
  33. data/spec/support/matchers.rb +45 -0
  34. data/spec/unit/vagrant/ansible_auto/config_spec.rb +72 -0
  35. data/spec/unit/vagrant/ansible_auto/host_spec.rb +131 -0
  36. data/spec/unit/vagrant/ansible_auto/inventory_spec.rb +349 -0
  37. data/spec/unit/vagrant/ansible_auto/provisioner_spec.rb +248 -0
  38. data/spec/unit/vagrant/ansible_auto/util/config_spec.rb +63 -0
  39. data/spec/unit/vagrant/ansible_auto/util/keys_spec.rb +66 -0
  40. data/vagrant-ansible_auto.gemspec +6 -4
  41. data/vagrant-spec.config.rb +3 -0
  42. data/yard/extensions.rb +45 -0
  43. metadata +36 -11
  44. data/Vagrantfile2 +0 -4
  45. data/Vagrantfile3 +0 -8
  46. data/Vagrantfile4 +0 -31
  47. data/lib/vagrant/ansible_auto/cap/guest/posix/bash_installed.rb +0 -30
  48. data/lib/vagrant/ansible_auto/util.rb +0 -24
  49. data/spec/vagrant/ansible_auto/host_spec.rb +0 -43
  50. data/spec/vagrant/ansible_auto/inventory_spec.rb +0 -79
@@ -1,83 +1,63 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require 'vagrant'
3
4
  require Vagrant.source_root + 'plugins/provisioners/ansible/provisioner/guest'
4
5
  require 'vagrant/util/keypair'
5
6
 
6
- require 'vagrant/ansible_auto/util'
7
+ require 'vagrant/ansible_auto/util/keys'
7
8
 
9
+ require 'i18n'
8
10
  require 'log4r'
9
- require 'shellwords'
10
11
 
11
12
  module VagrantPlugins
12
13
  module AnsibleAuto
14
+ # Class backing the +ansible_auto+ provisioner
13
15
  class Provisioner < VagrantPlugins::Ansible::Provisioner::Guest
14
16
  include Vagrant::Util::Retryable
15
- include VagrantPlugins::AnsibleAuto::Util
17
+ include Util::Keys
16
18
 
17
19
  def initialize(machine, config)
18
20
  super
19
21
  @logger = Log4r::Logger.new('vagrant::provisioners::ansible_auto')
20
22
  end
21
23
 
24
+ # Configure the provisioner by storing the root Ansible configuration
25
+ # object for use as the set of base options for a particular machine
26
+ # @api private
27
+ # @return [void]
22
28
  def configure(root_config)
23
29
  super
24
30
  @__ansible_config = root_config.ansible
25
31
  end
26
32
 
33
+ # Provision a {Vagrant::Machine} with the +ansible_auto+ provisioner
34
+ # @api private
35
+ # @return [void]
27
36
  def provision
28
37
  @config = @__ansible_config.merge(config)
29
38
 
30
- remote_priv_key_path, _remote_pub_key_path, openssh = configure_keypair!
31
-
32
- # TODO: figure out how to access ansible_auto configuration done
33
- # on the `other' machine.
34
- # @config = other.config.ansible.merge(merged_config)
35
- if machine.guest.capability?(:ssh_server_address)
39
+ return super unless machine.guest.capability?(:ssh_server_address)
36
40
 
37
- with_active_machines do |other, name, provider|
38
- # We're dealing with the machine doing the provisining
41
+ with_active_machines do |other, name, provider|
42
+ if other.nil?
43
+ @logger.warn I18n.t('vagrant.ansible_auto.provisioner.machine_not_configured', machine_name: name)
44
+ else
39
45
  if name == machine.name
40
- other_hostvars = { connection: 'local' }
41
- elsif other.nil?
42
- machine.ui.warn "Machine #{name} is not configured for this environment; omitting it from the inventory"
46
+ other_hostvars = { ansible_connection: 'local' }
43
47
  else
44
- # The machines we are trying to manage might not yet be ready to
45
- # connect -- retry a configurable number of times/durations until
46
- # we can connect; otherwise raise an exception.
47
- private_key_paths = []
48
- retryable(on: Vagrant::Errors::SSHNotReady, tries: @config.host_connect_tries, sleep: @config.host_connect_sleep) do
49
- raise Vagrant::Errors::SSHNotReady unless other.communicate.ready? and !other.ssh_info.nil?
50
-
51
- private_key_paths = other.ssh_info.fetch(:private_key_path, [])
52
- raise Vagrant::Errors::SSHNotReady if private_key_paths.empty?
53
-
54
- if other.config.ssh.insert_key
55
- raise Vagrant::Errors::SSHNotReady unless private_key_paths.any? { |k| !insecure_key?(k) }
56
- end
57
- end
58
-
59
- ssh_host, ssh_port = machine.guest.capability(:ssh_server_address, other)
60
- other_hostvars = { ssh_host: ssh_host, ssh_port: ssh_port }
48
+ # Merge the other machine's configuration, with this machine's
49
+ # configuration taking precedence.
50
+ @config = other.config.ansible.merge(@config)
61
51
 
62
- if private_key_paths.empty?
63
- machine.ui.warn "No private keys available for machine #{name}; provisioner will likely fail"
64
- end
65
-
66
- source_priv_key_path = fetch_private_key(other)
52
+ wait_for_ssh_ready!(other, @config.host_connect_tries, @config.host_connect_sleep)
67
53
 
68
- if source_priv_key_path.nil?
69
- machine.ui.warn "Private key for #{name} not available for upload; provisioner will likely fail"
70
- else
71
- machine.ui.info "Adding #{name} to Ansible inventory"
54
+ ssh_host, ssh_port = machine.guest.capability(:ssh_server_address, other)
55
+ other_hostvars = { ansible_ssh_host: ssh_host, ansible_ssh_port: ssh_port }
72
56
 
73
- if other.guest.capability?(:insert_public_key)
74
- other.guest.capability(:insert_public_key, openssh)
75
- else
76
- remote_priv_key_path = File.join(@config.tmp_path, 'ssh', name.to_s, provider.to_s, File.basename(source_priv_key_path))
77
- create_and_chown_and_chmod_remote_file(source_priv_key_path, remote_priv_key_path)
78
- end
57
+ machine.ui.info I18n.t('vagrant.ansible_auto.provisioner.inventory_addition', machine_name: name)
79
58
 
80
- other_hostvars[:ssh_private_key_file] = remote_priv_key_path
59
+ unless (other_ssh_private_key_file = configure_ssh_access!(other, name, provider)).nil?
60
+ other_hostvars[:ansible_ssh_private_key_file] = other_ssh_private_key_file
81
61
  end
82
62
  end
83
63
 
@@ -85,75 +65,128 @@ module VagrantPlugins
85
65
  end
86
66
  end
87
67
 
68
+ @config.inventory.validate!
69
+
88
70
  super
89
71
  end
90
72
 
91
73
  private
92
74
 
93
- def configure_keypair!
94
- # FIXME
95
- remote_priv_key_path = "~#{machine.ssh_info[:username]}/.ssh/id_rsa"
96
- remote_pub_key_path = "#{remote_priv_key_path}.pub"
75
+ def control_machine_ssh_key_dir
76
+ Pathname.new(@config.tmp_path).join('ssh')
77
+ end
78
+
79
+ def control_machine_private_key_path
80
+ @control_machine_private_key_path ||= control_machine_ssh_key_dir.join('vagrant_ansible_id_rsa')
81
+ end
82
+
83
+ def control_machine_public_key_path
84
+ @control_machine_public_key_path ||= control_machine_private_key_path.sub_ext('.pub')
85
+ end
97
86
 
98
- # Check whether user has a private key already
99
- if !machine.communicate.test("test -f #{remote_priv_key_path}") or !machine.communicate.test("test -f #{remote_pub_key_path}")
87
+ def control_machine_public_key
88
+ @control_machine_public_key ||= configure_keypair!
89
+ end
90
+
91
+ def configure_ssh_access!(other, name, provider)
92
+ # Insert the control machine's public key on the target machines
93
+ if config.insert_control_machine_public_key
94
+ insert_control_machine_public_key!(other, name)
95
+ elsif config.upload_inventory_host_private_keys
96
+ upload_inventory_host_private_key!(other, name, provider)
97
+ else
98
+ machine.ui.warn I18n.t('vagrant.ansible_auto.provisioner.cannot_configure_keys', machine_name: name)
99
+ end
100
+ end
101
+
102
+ def insert_control_machine_public_key!(other, name)
103
+ # Don't bother inserting the key if it is already authorized
104
+ if other.guest.capability?(:authorized_key?) && other.guest.capability(:authorized_key?, control_machine_public_key)
105
+ @logger.info I18n.t('vagrant.ansible_auto.provisioner.public_key_authorized', machine_name: name)
106
+ elsif other.guest.capability?(:insert_public_key)
107
+ @logger.info I18n.t('vagrant.ansible_auto.provisioner.inserting_public_key', machine_name: name)
108
+ other.guest.capability(:insert_public_key, control_machine_public_key)
109
+ else
110
+ @logger.warn I18n.t('vagrant.ansible_auto.provisioner.cannot_insert_public_key', machine_name: name)
111
+ return
112
+ end
113
+
114
+ control_machine_private_key_path
115
+ end
116
+
117
+ def upload_inventory_host_private_key!(other, name, provider)
118
+ source_priv_key_path = fetch_private_key(other)
119
+
120
+ if source_priv_key_path.nil?
121
+ @logger.warn I18n.t('vagrant.ansible_auto.provisioner.private_key_missing', machine_name: name)
122
+ return
123
+ end
124
+
125
+ @logger.info I18n.t('vagrant.ansible_auto.provisioner.uploading_private_key', machine_name: name)
126
+
127
+ other_priv_key_path = control_machine_ssh_key_dir.join(name.to_s, provider.to_s, File.basename(source_priv_key_path))
128
+ create_and_chown_and_chmod_remote_file(source_priv_key_path, other_priv_key_path)
129
+ other_priv_key_path
130
+ end
131
+
132
+ def configure_keypair!
133
+ # Check whether user already has a private key
134
+ if !machine.communicate.test("test -r #{control_machine_private_key_path} && test -r #{control_machine_public_key_path}")
100
135
  _pub, priv, openssh = Vagrant::Util::Keypair.create
101
- write_and_chown_and_chmod_remote_file(priv, remote_priv_key_path)
102
- write_and_chown_and_chmod_remote_file(openssh, remote_pub_key_path)
136
+ write_and_chown_and_chmod_remote_file(priv, control_machine_private_key_path)
137
+ write_and_chown_and_chmod_remote_file(openssh, control_machine_public_key_path)
103
138
  elsif machine.guest.capability?(:fetch_public_key)
104
- openssh = machine.guest.capability(:fetch_public_key, remote_priv_key_path)
139
+ openssh = machine.guest.capability(:fetch_public_key, control_machine_private_key_path)
105
140
  end
106
141
 
107
- [remote_priv_key_path, remote_pub_key_path, openssh]
142
+ openssh
108
143
  end
109
144
 
110
- def handle_remote_file(to, _owner = machine.ssh_info[:username], mode = 0o600)
145
+ def handle_remote_file(to, opts = {})
146
+ owner = opts.fetch(:owner) { machine.ssh_info[:username] }
147
+ mode = opts.fetch(:mode) { 0o600 }
111
148
  machine.communicate.tap do |comm|
149
+ # NOTE create_and_chown_remote_folder is defined in the parent class
112
150
  create_and_chown_remote_folder(File.dirname(to))
113
151
 
114
152
  yield comm, to
115
153
 
116
- comm.sudo("chown -h #{machine.ssh_info[:username]} #{to}")
154
+ comm.sudo("chown -h #{owner} #{to}")
117
155
  comm.sudo("chmod #{format('0%o', mode)} #{to}")
118
156
  end
119
157
  end
120
158
 
121
- def create_and_chown_and_chmod_remote_file(from, to, mode = 0o600)
122
- handle_remote_file(to, mode) do |comm, target|
159
+ def create_and_chown_and_chmod_remote_file(from, to, opts = {})
160
+ handle_remote_file(to, opts) do |comm, target|
123
161
  comm.upload(from, target)
124
162
  end
125
163
  end
126
164
 
127
- def write_and_chown_and_chmod_remote_file(contents, to, mode = 0o600)
128
- handle_remote_file(to, mode) do |comm, _target|
165
+ def write_and_chown_and_chmod_remote_file(contents, to, opts = {})
166
+ handle_remote_file(to, opts) do |comm, target|
129
167
  contents = contents.strip << "\n"
130
168
 
131
- to_parent = File.dirname(to)
132
-
133
169
  remote_path = "/tmp/vagrant-temp-asset-#{Time.now.to_i}"
134
- Tempfile.open("vagrant-temp-asset") do |f|
170
+ Tempfile.open('vagrant-temp-asset') do |f|
135
171
  f.binmode
136
172
  f.write(contents)
137
173
  f.fsync
138
174
  f.close
139
- machine.ui.info("uploading #{f.path} to #{remote_path}")
175
+ machine.ui.detail I18n.t('vagrant.ansible_auto.provisioner.uploading_file', local_path: f.path, remote_path: remote_path)
140
176
  comm.upload(f.path, remote_path)
141
177
  end
142
178
 
143
- # FIXME: configure perms on parent dir
144
- comm.execute <<-EOH.gsub(/^ */, "")
145
- mkdir #{to_parent}
146
- mv #{remote_path} #{to}
147
- EOH
179
+ # Parent directory of target will already exist
180
+ comm.execute("mv #{remote_path} #{target}")
148
181
  end
149
182
  end
150
183
 
151
184
  def generate_inventory_machines
152
- if config.strict_host_key_checking
153
- machine_format = '%s'
154
- else
155
- machine_format = "%s ansible_ssh_extra_args='-o UserKnownHostsFile=/dev/null -o IdentitiesOnly=yes -o StrictHostKeyChecking=no'"
156
- end
185
+ machine_format = if config.strict_host_key_checking
186
+ '%s'
187
+ else
188
+ "%s ansible_ssh_extra_args='-o UserKnownHostsFile=/dev/null -o IdentitiesOnly=yes -o StrictHostKeyChecking=no'"
189
+ end
157
190
 
158
191
  config.inventory.with_ini_lines_hosts.map do |host_spec|
159
192
  machine_format % host_spec
@@ -171,11 +204,20 @@ module VagrantPlugins
171
204
  begin
172
205
  yield machine.env.machine(name, provider), name, provider
173
206
  rescue Vagrant::Errors::MachineNotFound, CommunicatorWinRM::Errors::WinRMNotReady => e
174
- machine.ui.warn "unable to find machine #{name} (#{e.message})"
175
- return nil, name, provider
207
+ @logger.warn I18n.t('vagrant.ansible_auto.provisioner.cannot_find_machine', machine_name: name, error_message: e.message)
208
+ yield nil, name, provider
176
209
  end
177
210
  end
178
211
  end
212
+
213
+ # The machines we are trying to manage might not yet be ready to
214
+ # connect -- retry a configurable number of times/durations until
215
+ # we can connect; otherwise raise an exception.
216
+ def wait_for_ssh_ready!(other, tries, sleep)
217
+ retryable(on: Vagrant::Errors::SSHNotReady, tries: tries, sleep: sleep) do
218
+ raise Vagrant::Errors::SSHNotReady unless other.communicate.ready? && !other.ssh_info.nil?
219
+ end
220
+ end
179
221
  end
180
222
  end
181
223
  end
@@ -0,0 +1,61 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'vagrant/util/deep_merge'
4
+
5
+ module VagrantPlugins
6
+ module AnsibleAuto
7
+ # Helper methods for common operations
8
+ module Util
9
+ # Helper module for operations related to configuration settings
10
+ module Config
11
+ # @return [Boolean] +false+ when an object is +nil+, undefined, or the
12
+ # special +UNSET_VALUE+ object, +true+ otherwise
13
+ def unset?(o)
14
+ o.nil? || !defined?(o) || (self.class.const_defined?(:UNSET_VALUE) && o == self.class.const_get(:UNSET_VALUE))
15
+ end
16
+
17
+ def bool?(o)
18
+ (o == true) || (o == false)
19
+ end
20
+
21
+ def num?(o)
22
+ float?(o) || int?(o)
23
+ end
24
+
25
+ def int?(o)
26
+ coerced_int = int!(o)
27
+ return false if coerced_int.nil?
28
+ float!(coerced_int) == float!(o)
29
+ end
30
+
31
+ def int!(o)
32
+ Integer(o)
33
+ rescue ArgumentError, TypeError
34
+ nil
35
+ end
36
+
37
+ def float?(o)
38
+ !float!(o).nil?
39
+ end
40
+
41
+ def float!(o)
42
+ Float(o)
43
+ rescue ArgumentError, TypeError
44
+ nil
45
+ end
46
+
47
+ # Deep merge two objects, ensuring first that neither object is
48
+ # {#unset?}
49
+ def conditional_merge(a, b, &block)
50
+ if unset? b
51
+ a
52
+ elsif unset? a
53
+ b
54
+ else
55
+ Vagrant::Util::DeepMerge.deep_merge(a, b, &block)
56
+ end
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'vagrant/util/hash_with_indifferent_access'
4
+
5
+ module VagrantPlugins
6
+ module AnsibleAuto
7
+ # Helper methods for common operations
8
+ module Util
9
+ # Helper methods for operations related to SSH keys
10
+ class HashWithIndifferentAccess < Vagrant::Util::HashWithIndifferentAccess
11
+ # Combine two hashes into a new hash
12
+ # @overload merge(other)
13
+ # @param (see #merge!)
14
+ # @return (see #merge!)
15
+ # @overload merge(other, &block)
16
+ # @param (see #merge!)
17
+ # @return (see #merge!)
18
+ # @yieldparam (see #merge!)
19
+ # @yieldparam (see #merge!)
20
+ # @yieldparam (see #merge!)
21
+ def merge(other, &block)
22
+ dup.merge!(other, &block)
23
+ end
24
+
25
+ # In-place merge of two {HashWithIndifferentAccess} object. Provide
26
+ # the optional +&block+ argument if you want to control what happens a
27
+ # key exists in both hashes; by default, the value from +other+
28
+ # overwrites the current value for that key.
29
+ # @overload merge!(other)
30
+ # @param [Hash] the hash to merge into the current hash
31
+ # @return [HashWithIndifferentAccess] the merged hash
32
+ # @overload merge!(other, &block)
33
+ # @param [Hash] the hash to merge into the current hash
34
+ # @return [HashWithIndifferentAccess] the merged hash
35
+ # @yieldparam [String] key
36
+ # @yieldparam [HashWithIndifferentAccess] current
37
+ # @yieldparam [Hash] other
38
+ def merge!(other)
39
+ if block_given?
40
+ other.each do |key, value|
41
+ convert_key(key).tap do |ckey|
42
+ self[ckey] = if key? ckey
43
+ yield(ckey, self[ckey], value)
44
+ else
45
+ value
46
+ end
47
+ end
48
+ end
49
+ else
50
+ super(other)
51
+ end
52
+
53
+ self
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ module VagrantPlugins
4
+ module AnsibleAuto
5
+ # Helper methods for common operations
6
+ module Util
7
+ # Helper methods for operations related to SSH keys
8
+ module Keys
9
+ # @return [Pathname] the path to the Vagrant insecure private key
10
+ def insecure_key_path
11
+ Vagrant.source_root.join('keys/vagrant')
12
+ end
13
+
14
+ # @return [String] the contents of the Vagrant insecure private key
15
+ def insecure_key_contents
16
+ @__insecure_key_contents ||= insecure_key_path.read.chomp
17
+ end
18
+
19
+ # @param [String] path path to a file
20
+ # @return [Boolean] whether the file is the Vagrant insecure private key
21
+ # @note Adapted from
22
+ # {VagrantPlugins::CommunicatorSSH::Communicator#insecure_key?}
23
+ def insecure_key?(path)
24
+ return false if path.nil? || !File.file?(path)
25
+ File.read(path).chomp == insecure_key_contents
26
+ end
27
+
28
+ # @param [Vagrant::Machine] machine a guest machine
29
+ # @return [Array<String>] the first of the machine's keys that aren't the
30
+ # Vagrant private key as determined by {#insecure_key?}
31
+ def fetch_private_key(machine)
32
+ fetch_private_keys(machine).first
33
+ end
34
+
35
+ # @param (see #fetch_private_key)
36
+ # @return [Array<String>] a list of the paths to all of the machine's
37
+ # keys that aren't the Vagrant private key as determined by
38
+ # {#insecure_key?}
39
+ def fetch_private_keys(machine)
40
+ if machine.config.ssh.insert_key && !machine.ssh_info.nil?
41
+ machine.ssh_info.fetch(:private_key_path, []).find_all { |k| !insecure_key?(k) }
42
+ else
43
+ [machine.env.default_private_key_path]
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,24 @@
1
+ module VagrantPlugins
2
+ module AnsibleAuto
3
+ # Helper methods for common operations
4
+ module Util
5
+ # Helper methods for operations related to SSH keys
6
+ module ShellQuote
7
+ # In-place equivalent of {#shellescape}
8
+ # @param text [#to_s] the text to escape
9
+ # @return [String] the text, with all occurrences of +'+ replaced by
10
+ # +'"'"'+
11
+ def shellescape!(text)
12
+ text.to_s.gsub!(%('), %('"'"'))
13
+ end
14
+
15
+ # Escape a string for use as a shell parameter
16
+ # @param (see #shellescape!)
17
+ # @return (see #shellescape!)
18
+ def shellescape(text)
19
+ text.to_s.gsub(%('), %('"'"'))
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  module VagrantPlugins
3
4
  module AnsibleAuto
4
- VERSION = '0.1.5'
5
+ VERSION = '0.2.1'.freeze
5
6
  end
6
7
  end
@@ -1,5 +1,20 @@
1
1
  # frozen_string_literal: true
2
+
3
+ require 'pathname'
4
+
2
5
  require 'vagrant'
3
6
 
4
7
  require 'vagrant/ansible_auto/plugin'
5
8
  require 'vagrant/ansible_auto/version'
9
+
10
+ module VagrantPlugins
11
+ # Ansible command and provisioner plugin with automatic inventory generation
12
+ module AnsibleAuto
13
+ class << self
14
+ # @return [Pathname] path to the gem source root directory
15
+ def source_root
16
+ Pathname.new('../../..').expand_path(__FILE__)
17
+ end
18
+ end
19
+ end
20
+ end
data/locales/en.yml ADDED
@@ -0,0 +1,34 @@
1
+ en:
2
+ vagrant:
3
+ ansible_auto:
4
+ provisioner:
5
+ machine_not_configured: 'Machine %{machine_name} is not configured for this environment; omitting it from the inventory'
6
+ private_key_missing: 'Private key for %{machine_name} not available for upload; provisioner will likely fail'
7
+ inventory_addition: 'Adding %{machine_name} to Ansible inventory'
8
+ public_key_authorized: 'Control machine public key already authorized on %{machine_name}'
9
+ inserting_public_key: 'Inserting control machine public key on %{machine_name}'
10
+ cannot_insert_public_key: 'Cannot insert control machine public key on %{machine_name}'
11
+ uploading_private_key: 'Uploading private key for %{machine_name} onto control machine'
12
+ cannot_configure_keys: 'unable to insert public key or upload existing private key to control machine for %{machine_name}'
13
+ uploading_file: 'Uploading %{local_path} to %{remote_path}'
14
+ cannot_find_machine: 'Unable to find machine %{machine_name}: %{error_message}'
15
+ command:
16
+ root:
17
+ synopsis: 'build an Ansible inventory'
18
+ option: {}
19
+ diag: {}
20
+ skel:
21
+ synopsis: 'output a dynamic Ansible inventory'
22
+ usage: 'Usage: vagrant ansible inventory [options]'
23
+ option:
24
+ list: 'List all hosts as JSON'
25
+ diag:
26
+ not_running: 'machine %{machine} is not running; falling back to default hostvar values'
27
+ errors:
28
+ inventory:
29
+ missing_group: 'expected group %{group} is missing from the inventory'
30
+ group_missing_child: 'group %{group} defines nonextant child group %{child}'
31
+ invalid_host_type: "cannot add object of type %{type} as inventory host"
32
+ invalid_group_name: "%{group} is not a valid group name"
33
+ command:
34
+ unrecognized_command: 'unrecognized_command: %{command}'
data/spec/spec_helper.rb CHANGED
@@ -1,93 +1,13 @@
1
1
  # frozen_string_literal: true
2
- unless RUBY_ENGINE == 'rbx' # coverage support is broken on rbx
3
- require 'simplecov'
4
- require 'coveralls'
5
-
6
- formatters = [SimpleCov::Formatter::HTMLFormatter, Coveralls::SimpleCov::Formatter]
7
- SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter.new(formatters)
8
- SimpleCov.start do
9
- minimum_coverage 100
10
- add_group 'Sources', 'lib'
11
- add_group 'Tests', 'spec'
12
- end
13
- end
14
2
 
15
3
  require 'pathname'
16
4
 
17
- $LOAD_PATH.unshift((Pathname.new(__FILE__).parent.parent + 'lib').to_s)
18
-
19
- require 'vagrant/ansible_auto'
20
-
21
- # We're using an older version of rspec-expectations that doesn't have the
22
- # `all' matcher.
23
- RSpec::Matchers.define :all do |expected|
24
- define_method :index_failed_objects do |actual|
25
- end
26
-
27
- def index_failed_objects(actual)
28
- return enum_for(__method__, actual) unless block_given?
29
-
30
- @failed_items = []
31
-
32
- actual.each_with_index do |o, i|
33
- @failed_items[i] = yield o
34
- end
35
-
36
- @failed_items.compact.empty?
37
- end
38
-
39
- match_for_should do |actual|
40
- index_failed_objects(actual) do |item|
41
- expected.failure_message_for_should unless expected.matches?(item)
42
- end
43
- end
44
-
45
- match_for_should_not do |actual|
46
- index_failed_objects(actual) do |item|
47
- expected.failure_message_for_should_not if expected.matches?(item)
48
- end
49
- end
5
+ Pathname.new(__FILE__).tap do |helper|
6
+ $LOAD_PATH.unshift((helper.parent.parent + 'lib').to_s)
50
7
 
51
- def failure_message(actual)
52
- if actual.respond_to?(:each_with_index)
53
- @failed_items.each_with_index.reject { |f, _i| f.nil? }.map do |f, i|
54
- "object at index #{i} failed to match: #{f}"
55
- end.join("\n")
56
- else
57
- "provided object is not iterable"
58
- end
59
- end
8
+ require 'vagrant/ansible_auto'
60
9
 
61
- failure_message_for_should { |actual| failure_message(actual) }
62
- failure_message_for_should_not { |actual| failure_message(actual) }
10
+ helper.parent.join('support').find { |f| require f if f.extname == '.rb' }
63
11
  end
64
12
 
65
- shared_context 'machine' do
66
- let(:machine) { double('machine') }
67
- let(:state) { double('state') }
68
- let(:ssh_info) { Hash.new }
69
-
70
- before do
71
- machine.stub(ssh_info: ssh_info, state: state)
72
- machine.stub(name: 'mymachine')
73
- state.stub(id: :running)
74
- allow(ssh_info).to receive(:[])
75
- allow(ssh_info).to receive(:fetch).with(:private_key_path, anything).and_return([])
76
- end
77
- end
78
-
79
- shared_context 'host' do
80
- require 'vagrant/ansible_auto/host'
81
-
82
- include_context 'machine'
83
-
84
- let(:host) { VagrantPlugins::AnsibleAuto::Host.new(machine) }
85
- end
86
-
87
- shared_context 'inventory' do
88
- require 'vagrant/ansible_auto/host'
89
-
90
- include_context 'machine'
91
-
92
- let(:inventory) { VagrantPlugins::AnsibleAuto.new }
93
- end
13
+ SimpleCov.start