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