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.
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