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
@@ -0,0 +1,111 @@
1
+ require 'vagrant'
2
+ require Vagrant.source_root.join('test/unit/support/dummy_communicator')
3
+ require 'vagrant-spec/unit'
4
+
5
+ def unindent(s)
6
+ s.lines.tap do |lines|
7
+ indent = lines.map { |l| l.length - l.lstrip.length }.min
8
+ return lines.map { |l| l[indent..-1] }.join
9
+ end
10
+ end
11
+
12
+ shared_context 'machine' do |machine_count = 2|
13
+ include_context 'vagrant-unit'
14
+
15
+ def mock_communicator(machine)
16
+ VagrantTests::DummyCommunicator::Communicator.new(machine)
17
+ end
18
+
19
+ def mock_guest
20
+ double('guest')
21
+ end
22
+
23
+ def mock_machine_state
24
+ double('state').tap do |s|
25
+ allow(s).to receive(:id).and_return(:running)
26
+ end
27
+ end
28
+
29
+ def mock_ssh_info
30
+ {}.tap do |i|
31
+ allow(i).to receive(:[])
32
+ allow(i).to receive(:fetch).with(:private_key_path, anything).and_return([])
33
+ end
34
+ end
35
+
36
+ def mock_ui
37
+ Vagrant::UI::Colored.new
38
+ end
39
+
40
+ def mock_machine(name)
41
+ iso_env.machine(name, :dummy).tap do |m|
42
+ allow(m).to receive(:state).and_return(mock_machine_state)
43
+ allow(m).to receive(:ssh_info).and_return(mock_ssh_info)
44
+ allow(m).to receive(:ui).and_return(mock_ui)
45
+ allow(m).to receive(:communicate).and_return(mock_communicator(m))
46
+ allow(m).to receive(:guest).and_return(mock_guest)
47
+ allow(m.env).to receive(:active_machines).and_return(iso_env.machine_names.map { |n| [n, :dummy] })
48
+ end
49
+ end
50
+
51
+ let(:vagrantfile_contents) do
52
+ <<-VAGRANTFILE
53
+ Vagrant.configure(2) do |config|
54
+ config.vm.box = 'base'
55
+ #{(1..machine_count).map { |c| "config.vm.define :machine#{c}" }.join("\n")}
56
+ end
57
+ VAGRANTFILE
58
+ end
59
+
60
+ # Lifted from core Ansible provisioner tests
61
+ let(:iso_env) do
62
+ env = isolated_environment
63
+ env.vagrantfile(vagrantfile_contents)
64
+ env.create_vagrant_env
65
+ end
66
+
67
+ let(:machines) { iso_env.machine_names.map { |n| mock_machine(n) } }
68
+ let(:machine) { machines[0] }
69
+ let(:machine_name) { machine.name }
70
+ let(:state) { machine.state }
71
+ let(:ssh_info) { machine.ssh_info }
72
+ let(:ui) { machine.ui }
73
+ let(:communicator) { machine.communicator }
74
+ let(:playbook) { 'playbook.yml' }
75
+ end
76
+
77
+ shared_context 'host' do
78
+ require 'vagrant/ansible_auto/host'
79
+
80
+ include_context 'machine'
81
+
82
+ let(:hostvars) { {} }
83
+ let(:inventory_hostname) { machine_name.to_s }
84
+ let(:host) { VagrantPlugins::AnsibleAuto::Host.new(machine_name, hostvars) }
85
+ let(:host_machine) { VagrantPlugins::AnsibleAuto::HostMachine.new(machine, hostvars) }
86
+ end
87
+
88
+ shared_context 'inventory' do
89
+ require 'vagrant/ansible_auto/inventory'
90
+
91
+ include_context 'machine'
92
+
93
+ let(:inventory) { VagrantPlugins::AnsibleAuto::Inventory.new }
94
+ end
95
+
96
+ shared_context 'config' do
97
+ require 'vagrant/ansible_auto/config'
98
+
99
+ include_context 'machine'
100
+ include_context 'inventory'
101
+
102
+ let(:config) { VagrantPlugins::AnsibleAuto::Config.new }
103
+
104
+ before do
105
+ allow(config).to receive(:inventory).and_return(inventory)
106
+
107
+ machines.each do |m|
108
+ allow(m.config).to receive(:ansible).and_return(VagrantPlugins::AnsibleAuto::Config.new)
109
+ end
110
+ end
111
+ end
@@ -0,0 +1,45 @@
1
+ require 'rspec'
2
+
3
+ # We're using an older version of rspec-expectations that doesn't have the
4
+ # `all' matcher.
5
+ RSpec::Matchers.define :all do |expected|
6
+ define_method :index_failed_objects do |actual|
7
+ end
8
+
9
+ def index_failed_objects(actual)
10
+ return enum_for(__method__, actual) unless block_given?
11
+
12
+ @failed_items = []
13
+
14
+ actual.each_with_index do |o, i|
15
+ @failed_items[i] = yield o
16
+ end
17
+
18
+ @failed_items.compact.empty?
19
+ end
20
+
21
+ match_for_should do |actual|
22
+ index_failed_objects(actual) do |item|
23
+ expected.failure_message_for_should unless expected.matches?(item)
24
+ end
25
+ end
26
+
27
+ match_for_should_not do |actual|
28
+ index_failed_objects(actual) do |item|
29
+ expected.failure_message_for_should_not if expected.matches?(item)
30
+ end
31
+ end
32
+
33
+ def failure_message(actual)
34
+ if actual.respond_to?(:each_with_index)
35
+ @failed_items.each_with_index.reject { |f, _i| f.nil? }.map do |f, i|
36
+ "object at index #{i} failed to match: #{f}"
37
+ end.join("\n")
38
+ else
39
+ 'provided object is not iterable'
40
+ end
41
+ end
42
+
43
+ failure_message_for_should { |actual| failure_message(actual) }
44
+ failure_message_for_should_not { |actual| failure_message(actual) }
45
+ end
@@ -0,0 +1,72 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ require 'vagrant/ansible_auto/config'
6
+
7
+ describe VagrantPlugins::AnsibleAuto::Config do
8
+ include_context 'config'
9
+
10
+ def validate_config(c, m, attr, v)
11
+ c.public_send("#{attr}=", v)
12
+ c.finalize!
13
+ errors = c.validate(m)
14
+ yield errors['ansible_auto']
15
+ end
16
+
17
+ describe '#validate' do
18
+ context 'given an invalid value for a configuration parameter' do
19
+ it 'catches the error and returns it under the "ansible_auto" key' do
20
+ described_class::BOOLEAN.each do |attr|
21
+ validate_config(config, machine, attr, 5) do |errors|
22
+ expect(errors).to include("#{attr} must be either true or false")
23
+ end
24
+ end
25
+
26
+ described_class::INTEGER.each do |attr|
27
+ validate_config(config, machine, attr, nil) do |errors|
28
+ expect(errors).to include("#{attr} must be an integer")
29
+ end
30
+ end
31
+
32
+ described_class::NUMBER.each do |attr|
33
+ validate_config(config, machine, attr, nil) do |errors|
34
+ expect(errors).to include("#{attr} must be a number")
35
+ end
36
+ end
37
+ end
38
+ end
39
+
40
+ context 'given an error constructing the inventory' do
41
+ it 'catches the error and returns it under the "ansible_auto" key' do
42
+ pending 'at the moment, the inventory object does not raise any errors along the relevant code paths' do
43
+ config.finalize!
44
+ errors = config.validate(machine)
45
+ expect(errors['ansible_auto']).not_to be_empty
46
+ end
47
+ end
48
+ end
49
+
50
+ context 'given a valid value for a configuration parameter' do
51
+ it 'does not catch the error and return it under the "ansible_auto" key' do
52
+ described_class::BOOLEAN.each do |attr|
53
+ validate_config(config, machine, attr, true) do |errors|
54
+ expect(errors).not_to include("#{attr} must be either true or false")
55
+ end
56
+ end
57
+
58
+ described_class::INTEGER.each do |attr|
59
+ validate_config(config, machine, attr, 10) do |errors|
60
+ expect(errors).not_to include("#{attr} must be an integer")
61
+ end
62
+ end
63
+
64
+ described_class::NUMBER.each do |attr|
65
+ validate_config(config, machine, attr, 3.14159) do |errors|
66
+ expect(errors).not_to include("#{attr} must be a number")
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,131 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ require 'vagrant/ansible_auto/host'
6
+
7
+ describe VagrantPlugins::AnsibleAuto::Host do
8
+ include_context 'host'
9
+
10
+ let(:hostvars) do
11
+ {
12
+ ansible_ssh_user: 'me',
13
+ ansible_ssh_host: 'foo.bar.net',
14
+ ansible_ssh_port: 2222,
15
+ ansible_ssh_private_key_file: '/path/to/private_key'
16
+ }
17
+ end
18
+
19
+ describe '#name' do
20
+ it 'corresponds to the first parameter of the constructor' do
21
+ expect(host.name).to eq machine_name
22
+ end
23
+ end
24
+
25
+ describe '#inventory_hostname' do
26
+ it 'corresponds to the first parameter of the constructor, stringified' do
27
+ expect(host.inventory_hostname).to eq machine_name.to_s
28
+ end
29
+ end
30
+
31
+ describe '#ssh_user' do
32
+ it 'corresponds to hostvars[:ansible_ssh_user]' do
33
+ expect(host.ansible_ssh_user).to eq 'me'
34
+ end
35
+ end
36
+
37
+ describe '#ssh_host' do
38
+ it 'corresponds to hostvars[:ansible_ssh_host]' do
39
+ expect(host.ansible_ssh_host).to eq 'foo.bar.net'
40
+ end
41
+ end
42
+
43
+ describe '#ssh_port' do
44
+ it 'corresponds to hostvars[:ansible_ssh_port]' do
45
+ expect(host.ansible_ssh_port).to eq 2222
46
+ end
47
+ end
48
+
49
+ describe '#ssh_private_key_file' do
50
+ it 'corresponds to hostvars[:ansible_ssh_private_key_file]' do
51
+ expect(host.ansible_ssh_private_key_file).to eq '/path/to/private_key'
52
+ end
53
+ end
54
+
55
+ describe '#hostvars' do
56
+ it 'stringifies its keys' do
57
+ expect(host.hostvars).to eq(
58
+ 'ansible_ssh_user' => 'me',
59
+ 'ansible_ssh_host' => 'foo.bar.net',
60
+ 'ansible_ssh_port' => 2222,
61
+ 'ansible_ssh_private_key_file' => '/path/to/private_key'
62
+ )
63
+ end
64
+ end
65
+
66
+ describe '#to_h' do
67
+ it 'returns #hostvars keyed to #inventory_hostname' do
68
+ expect(host.to_h).to eq(host.inventory_hostname => {
69
+ 'ansible_ssh_user' => 'me',
70
+ 'ansible_ssh_host' => 'foo.bar.net',
71
+ 'ansible_ssh_port' => 2222,
72
+ 'ansible_ssh_private_key_file' => '/path/to/private_key'
73
+ })
74
+ end
75
+ end
76
+
77
+ describe "a method starting with `ansible_'" do
78
+ it 'dispatches to hostvars' do
79
+ host.ansible_python_interpreter = '/usr/bin/python2.7'
80
+ expect(host.ansible_python_interpreter).to eq '/usr/bin/python2.7'
81
+ expect(host.hostvars[:ansible_python_interpreter]).to eq '/usr/bin/python2.7'
82
+ end
83
+ end
84
+
85
+ describe '#to_ini' do
86
+ it 'returns #to_h as INI-style lines' do
87
+ expect(host.to_ini).to eq(unindent(<<-HOST).chomp)
88
+ #{inventory_hostname} ansible_ssh_host=foo.bar.net ansible_ssh_port=2222 ansible_ssh_private_key_file=/path/to/private_key ansible_ssh_user=me
89
+ HOST
90
+ end
91
+ end
92
+ end
93
+
94
+ describe VagrantPlugins::AnsibleAuto::HostMachine do
95
+ include_context 'host'
96
+
97
+ describe '#ansible_ssh_user' do
98
+ it 'corresponds to machine.ssh_info[:username]' do
99
+ expect(ssh_info).to receive(:[]).with(:username).and_return('me')
100
+ expect(host_machine.ansible_ssh_user).to eq 'me'
101
+ end
102
+ end
103
+
104
+ describe '#ansible_ssh_host' do
105
+ it 'corresponds to machine.ssh_info[:host]' do
106
+ expect(ssh_info).to receive(:[]).with(:host).and_return('foo.bar.net')
107
+ expect(host_machine.ansible_ssh_host).to eq 'foo.bar.net'
108
+ end
109
+ end
110
+
111
+ describe '#ansible_ssh_port' do
112
+ it 'corresponds to machine.ssh_info[:port]' do
113
+ expect(ssh_info).to receive(:[]).with(:port).and_return(2222)
114
+ expect(host_machine.ansible_ssh_port).to eq 2222
115
+ end
116
+ end
117
+
118
+ describe '#ansible_ssh_private_key_file' do
119
+ it 'corresponds to machine.ssh_info[:private_key_path]' do
120
+ expect(machine.config.ssh).to receive(:insert_key).and_return(true)
121
+ expect(ssh_info).to receive(:fetch).with(:private_key_path, anything).and_return(['/path/to/private_key'])
122
+ expect(host_machine.ansible_ssh_private_key_file).to eq '/path/to/private_key'
123
+ end
124
+
125
+ it 'has no default' do
126
+ expect(machine.config.ssh).to receive(:insert_key).and_return(true)
127
+ expect(ssh_info).to receive(:fetch).with(:private_key_path, anything).and_return([])
128
+ expect(host_machine.ansible_ssh_private_key_file).to be_nil
129
+ end
130
+ end
131
+ end