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
@@ -1,4 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
require 'set'
|
3
4
|
|
4
5
|
module VagrantPlugins
|
@@ -6,22 +7,32 @@ module VagrantPlugins
|
|
6
7
|
module Cap
|
7
8
|
module Guest
|
8
9
|
module POSIX
|
10
|
+
# Attempt to find the IP address and port of an active SSH server
|
11
|
+
# @todo test not merely that a host and port combo is open, but that
|
12
|
+
# there's an SSH server listening there
|
9
13
|
class SSHServerAddress
|
10
14
|
class << self
|
15
|
+
# @param [Vagrant::Machine] machine a guest machine
|
16
|
+
# @param [Vagrant::Machine,nil] target_machine a guest machine
|
17
|
+
# @return [Array<(String, Integer)>] the host and port on which
|
18
|
+
# an SSH server may be listening
|
11
19
|
def ssh_server_address(machine, target_machine = nil)
|
12
20
|
with_open_ports(machine, target_machine).first
|
13
21
|
end
|
14
22
|
|
15
|
-
|
16
|
-
|
23
|
+
# @param (see #ssh_server_address)
|
24
|
+
# @return [Array<Array<(String, Integer)>>] a list of host and
|
25
|
+
# port pairs on which an SSH server may be listening
|
17
26
|
def ssh_server_addresses(machine, target_machine = nil)
|
18
27
|
with_open_ports(machine, target_machine).to_a
|
19
28
|
end
|
20
29
|
|
30
|
+
private
|
31
|
+
|
21
32
|
def with_open_ports(machine, target_machine = nil)
|
22
33
|
return enum_for(__method__, machine, target_machine) unless block_given?
|
23
34
|
|
24
|
-
return unless machine.guest.capability?(:
|
35
|
+
return unless machine.guest.capability?(:port_open?)
|
25
36
|
|
26
37
|
target_machine ||= machine
|
27
38
|
ssh_info = target_machine.ssh_info
|
@@ -30,13 +41,13 @@ module VagrantPlugins
|
|
30
41
|
with_candidate_addresses(target_machine) do |host, port|
|
31
42
|
port ||= default_port
|
32
43
|
|
33
|
-
if machine.guest.capability(:
|
44
|
+
if machine.guest.capability(:port_open?, host, port)
|
34
45
|
yield host, port
|
35
46
|
end
|
36
47
|
end
|
37
48
|
end
|
38
49
|
|
39
|
-
network_type_precedence_map = Hash[[
|
50
|
+
network_type_precedence_map = Hash[%i[forwarded_port public_network private_network].each_with_index.map { |type, i| [type, i] }]
|
40
51
|
define_method(:network_type_precedence) do |type|
|
41
52
|
network_type_precedence_map[type]
|
42
53
|
end
|
@@ -62,18 +73,17 @@ module VagrantPlugins
|
|
62
73
|
machine.config.vm.networks.sort_by { |(type, _)| network_type_precedence(type) }.each do |type, info|
|
63
74
|
case type
|
64
75
|
when :private_network, :public_network
|
65
|
-
|
76
|
+
has_routable_ip = true
|
66
77
|
|
67
|
-
|
78
|
+
yield_unseen_candidate.call([info[:ip]]) if info.key?(:ip)
|
68
79
|
when :forwarded_port
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
end
|
80
|
+
if info[:protocol] == 'tcp' && info[:id] == 'ssh'
|
81
|
+
yield_unseen_candidate.call([info[:host_ip], info[:host]])
|
82
|
+
end
|
73
83
|
end
|
74
84
|
end
|
75
85
|
|
76
|
-
return if has_routable_ip
|
86
|
+
return if has_routable_ip || !machine.guest.capability?(:gateway_addresses)
|
77
87
|
|
78
88
|
machine.guest.capability(:gateway_addresses).each do |gateway_address|
|
79
89
|
yield_unseen_candidate.call(gateway_address)
|
@@ -0,0 +1,16 @@
|
|
1
|
+
|
2
|
+
# Here for documentation purposes only
|
3
|
+
|
4
|
+
module VagrantPlugins
|
5
|
+
module AnsibleAuto
|
6
|
+
# Capabilities on guests and hosts
|
7
|
+
module Cap
|
8
|
+
# Capabilities on guests
|
9
|
+
module Guest
|
10
|
+
# Capabilities on POSIX hosts
|
11
|
+
module POSIX
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -1,44 +1,70 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
require 'optparse'
|
3
4
|
|
4
5
|
module VagrantPlugins
|
5
6
|
module AnsibleAuto
|
6
7
|
module Command
|
8
|
+
# Vagrant +ansible inventory+ subcommand
|
7
9
|
class Inventory < Vagrant.plugin(2, :command)
|
10
|
+
# @return [String] summary of the +ansible inventory+ command
|
8
11
|
def self.synopsis
|
9
12
|
'dynamic ansible inventory'
|
10
13
|
end
|
11
14
|
|
15
|
+
# Print the Ansible inventory for the current Vagrantfile.
|
16
|
+
#
|
17
|
+
# By default, the inventory is printed in Ansible's static INI
|
18
|
+
# inventory style. When the +-l/--list+ flag is present, the inventory
|
19
|
+
# is printed in Ansible's dynamic JSON inventory style.
|
20
|
+
#
|
21
|
+
# @return [Integer] the exit status of the command
|
12
22
|
def execute
|
23
|
+
operation = :as_ini
|
24
|
+
|
13
25
|
opts = OptionParser.new do |op|
|
14
26
|
op.banner = 'Usage: vagrant ansible inventory [<options>]'
|
15
27
|
op.separator ''
|
16
28
|
op.separator 'Available options:'
|
17
29
|
|
18
|
-
op.on('
|
19
|
-
|
20
|
-
return 0
|
30
|
+
op.on('--ini', 'List hosts as INI (default)') do
|
31
|
+
operation = :as_ini
|
21
32
|
end
|
22
33
|
|
23
|
-
op.on('
|
24
|
-
|
25
|
-
|
34
|
+
op.on('--json', 'List all hosts as JSON') do
|
35
|
+
operation = :as_json
|
36
|
+
end
|
37
|
+
|
38
|
+
op.on('--pretty', 'List all hosts as pretty JSON') do
|
39
|
+
operation = :as_pretty_json
|
26
40
|
end
|
27
41
|
end
|
28
42
|
|
29
|
-
|
43
|
+
machines = parse_options(opts)
|
30
44
|
|
31
|
-
@env.ui.info
|
45
|
+
@env.ui.info send(operation, machines), prefix: false
|
32
46
|
|
33
47
|
0
|
34
48
|
end
|
35
49
|
|
36
50
|
private
|
37
51
|
|
38
|
-
def
|
39
|
-
|
52
|
+
def as_ini(machines)
|
53
|
+
build_inventory(machines).to_ini
|
54
|
+
end
|
55
|
+
|
56
|
+
def as_json(machines)
|
57
|
+
build_inventory(machines).to_json
|
58
|
+
end
|
59
|
+
|
60
|
+
def as_pretty_json(machines)
|
61
|
+
JSON.pretty_generate(build_inventory(machines))
|
62
|
+
end
|
63
|
+
|
64
|
+
def build_inventory(machines)
|
65
|
+
with_target_vms(machines) {}.each_with_object(AnsibleAuto::Inventory.new) do |machine, inventory|
|
40
66
|
unless machine.state.id == :running
|
41
|
-
@env.ui.warn "machine #{machine.name} is not running; falling back to default hostvar values"
|
67
|
+
@env.ui.warn "machine #{machine.name} is not running; falling back to default hostvar values", channel: :error
|
42
68
|
end
|
43
69
|
inventory.merge!(machine.config.ansible.inventory)
|
44
70
|
inventory.add_host(machine)
|
@@ -1,57 +1,60 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
require 'optparse'
|
3
4
|
|
5
|
+
require 'vagrant/ansible_auto/errors'
|
6
|
+
|
4
7
|
module VagrantPlugins
|
5
8
|
module AnsibleAuto
|
9
|
+
# Vagrant +ansible+ subcommand
|
6
10
|
module Command
|
11
|
+
# Command for creating a static Ansible inventory from the machines
|
12
|
+
# defined in a Vagrantfile
|
7
13
|
class Root < Vagrant.plugin(2, :command)
|
14
|
+
# @return [String] summary of the +ansible+ command
|
8
15
|
def self.synopsis
|
9
16
|
'build ansible inventory'
|
10
17
|
end
|
11
18
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
@main_args, @sub_command, @sub_args = split_main_and_subcommand(argv)
|
16
|
-
|
17
|
-
@subcommands = Vagrant::Registry.new
|
18
|
-
|
19
|
-
@subcommands.register(:inventory) do
|
20
|
-
require_relative 'inventory'
|
21
|
-
Inventory
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
19
|
+
# Execute the +ansible+ command
|
20
|
+
# @return [Integer] the exit status of the command
|
25
21
|
def execute
|
26
|
-
|
27
|
-
|
22
|
+
@argv, subcommand_name, subcommand_argv = split_main_and_subcommand(@argv)
|
23
|
+
|
24
|
+
if subcommand_name.nil?
|
25
|
+
@argv = ['-h'] if @argv.empty?
|
26
|
+
return parse_options(prepare_options)
|
27
|
+
elsif subcommands.key? subcommand_name.to_sym
|
28
|
+
return subcommands.get(subcommand_name.to_sym).new(subcommand_argv, @env.dup).execute
|
29
|
+
else
|
30
|
+
raise Errors::UnrecognizedCommandError, command: subcommand_name
|
28
31
|
end
|
29
|
-
|
30
|
-
command_class = @subcommands.get(@sub_command.to_sym) if @sub_command
|
31
|
-
return help if !command_class || !@sub_command
|
32
|
-
@logger.debug("Invoking command class: #{command_class} #{@sub_args.inspect}")
|
33
|
-
|
34
|
-
command_class.new(@sub_args, @env).execute
|
35
32
|
end
|
36
33
|
|
37
|
-
|
38
|
-
|
34
|
+
private
|
35
|
+
|
36
|
+
def prepare_options
|
37
|
+
OptionParser.new do |o|
|
39
38
|
o.banner = 'Usage: vagrant ansible <subcommand> [<options>]'
|
40
39
|
o.separator ''
|
41
40
|
o.separator 'Available subcommands:'
|
42
41
|
|
43
|
-
keys
|
44
|
-
|
45
|
-
|
46
|
-
keys.sort.each do |key|
|
47
|
-
o.separator " #{key}"
|
42
|
+
subcommands.keys.sort.each do |k|
|
43
|
+
o.separator " #{k}"
|
48
44
|
end
|
49
45
|
|
50
|
-
o.separator
|
51
|
-
o.separator
|
46
|
+
o.separator ''
|
47
|
+
o.separator 'For help on any individual subcommand run `vagrant ansible <subcommand> -h`'
|
52
48
|
end
|
49
|
+
end
|
53
50
|
|
54
|
-
|
51
|
+
def subcommands
|
52
|
+
@subcommands ||= Vagrant::Registry.new.tap do |r|
|
53
|
+
r.register(:inventory) do
|
54
|
+
require_relative 'inventory'
|
55
|
+
Inventory
|
56
|
+
end
|
57
|
+
end
|
55
58
|
end
|
56
59
|
end
|
57
60
|
end
|
@@ -1,56 +1,109 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
require 'vagrant/ansible_auto/inventory'
|
3
|
-
require 'vagrant/ansible_auto/errors'
|
4
|
-
require 'vagrant/util/deep_merge'
|
5
2
|
|
6
3
|
require 'vagrant'
|
7
4
|
require Vagrant.source_root + 'plugins/provisioners/ansible/config/guest'
|
8
5
|
|
6
|
+
require 'vagrant/ansible_auto/inventory'
|
7
|
+
require 'vagrant/ansible_auto/errors'
|
8
|
+
require 'vagrant/ansible_auto/util/config'
|
9
|
+
|
9
10
|
module VagrantPlugins
|
10
11
|
module AnsibleAuto
|
12
|
+
# Configuration for the +ansible_auto+ provisioner and +ansible+ command
|
11
13
|
class Config < VagrantPlugins::Ansible::Config::Guest
|
14
|
+
include Util::Config
|
15
|
+
|
12
16
|
attr_accessor :inventory, :groups, :vars, :children,
|
13
|
-
:strict_host_key_checking, :host_connect_tries,
|
17
|
+
:strict_host_key_checking, :host_connect_tries,
|
18
|
+
:host_connect_sleep, :insert_control_machine_public_key,
|
19
|
+
:upload_inventory_host_private_keys
|
14
20
|
|
15
21
|
protected(:inventory=)
|
16
22
|
|
23
|
+
BOOLEAN = %I[
|
24
|
+
strict_host_key_checking
|
25
|
+
insert_control_machine_public_key
|
26
|
+
upload_inventory_host_private_keys
|
27
|
+
].freeze
|
28
|
+
|
29
|
+
INTEGER = %I[
|
30
|
+
host_connect_tries
|
31
|
+
].freeze
|
32
|
+
|
33
|
+
NUMBER = %I[
|
34
|
+
host_connect_sleep
|
35
|
+
].freeze
|
36
|
+
|
17
37
|
def initialize
|
18
38
|
super
|
19
|
-
@inventory
|
20
|
-
@groups
|
21
|
-
@vars
|
22
|
-
@children
|
23
|
-
@strict_host_key_checking
|
24
|
-
@host_connect_tries
|
25
|
-
@host_connect_sleep
|
26
|
-
@
|
39
|
+
@inventory = Inventory.new
|
40
|
+
@groups = UNSET_VALUE
|
41
|
+
@vars = UNSET_VALUE
|
42
|
+
@children = UNSET_VALUE
|
43
|
+
@strict_host_key_checking = UNSET_VALUE
|
44
|
+
@host_connect_tries = UNSET_VALUE
|
45
|
+
@host_connect_sleep = UNSET_VALUE
|
46
|
+
@insert_control_machine_public_key = UNSET_VALUE
|
47
|
+
@upload_inventory_host_private_keys = UNSET_VALUE
|
48
|
+
@__errors = []
|
27
49
|
end
|
28
50
|
|
51
|
+
# Set default configuration values at the end of constructing the Vagrant
|
52
|
+
# environment
|
53
|
+
# @api private
|
54
|
+
# @return [void]
|
29
55
|
def finalize!
|
30
56
|
super
|
31
|
-
@inventory.groups
|
32
|
-
@inventory.vars
|
33
|
-
@inventory.children
|
34
|
-
@strict_host_key_checking
|
35
|
-
@host_connect_tries
|
36
|
-
@host_connect_sleep
|
57
|
+
@inventory.groups = @groups unless @groups == UNSET_VALUE
|
58
|
+
@inventory.vars = @vars unless @vars == UNSET_VALUE
|
59
|
+
@inventory.children = @children unless @children == UNSET_VALUE
|
60
|
+
@strict_host_key_checking = false if @strict_host_key_checking == UNSET_VALUE
|
61
|
+
@host_connect_tries = 10 if @host_connect_tries == UNSET_VALUE
|
62
|
+
@host_connect_sleep = 2 if @host_connect_sleep == UNSET_VALUE
|
63
|
+
@insert_control_machine_public_key = true if @insert_control_machine_public_key == UNSET_VALUE
|
64
|
+
@upload_inventory_host_private_keys = !@insert_control_machine_public_key if @upload_inventory_host_private_keys == UNSET_VALUE
|
65
|
+
|
66
|
+
# NOTE @limit is defined in core Vagrant's Ansible config.
|
67
|
+
@limit = '*' if @limit == UNSET_VALUE
|
37
68
|
rescue Errors::InventoryError => e
|
38
69
|
@__errors << e.message
|
39
70
|
end
|
40
71
|
|
72
|
+
# Ensure that the configuration is in a valid state
|
73
|
+
# @api private
|
74
|
+
# @return [Hash{String=>Array}] a structure containing a list of errors
|
75
|
+
# under the +ansible_auto+ key
|
41
76
|
def validate(machine)
|
42
77
|
super
|
43
78
|
|
44
79
|
errors = _detected_errors + @__errors
|
45
80
|
|
46
|
-
|
47
|
-
|
48
|
-
|
81
|
+
BOOLEAN.each do |o|
|
82
|
+
unless bool? instance_variable_get(:"@#{o}")
|
83
|
+
errors << "#{o} must be either true or false"
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
INTEGER.each do |o|
|
88
|
+
unless int? instance_variable_get(:"@#{o}")
|
89
|
+
errors << "#{o} must be an integer"
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
NUMBER.each do |o|
|
94
|
+
unless num? instance_variable_get(:"@#{o}")
|
95
|
+
errors << "#{o} must be a number"
|
96
|
+
end
|
49
97
|
end
|
50
98
|
|
51
99
|
{ 'ansible_auto' => errors }
|
52
100
|
end
|
53
101
|
|
102
|
+
# Merge two configurations
|
103
|
+
# @api private
|
104
|
+
# @param [Config] other the configuration to merge into this
|
105
|
+
# configuration
|
106
|
+
# @return [Config] the merged configuration
|
54
107
|
def merge(other)
|
55
108
|
return super if other.nil?
|
56
109
|
|
@@ -61,18 +114,6 @@ module VagrantPlugins
|
|
61
114
|
result.inventory = inventory.merge(other.inventory)
|
62
115
|
end
|
63
116
|
end
|
64
|
-
|
65
|
-
private
|
66
|
-
|
67
|
-
def conditional_merge(a, b)
|
68
|
-
if b.nil? or b == UNSET_VALUE
|
69
|
-
a
|
70
|
-
elsif a.nil? or a == UNSET_VALUE
|
71
|
-
b
|
72
|
-
else
|
73
|
-
Vagrant::Util::DeepMerge.deep_merge(a, b)
|
74
|
-
end
|
75
|
-
end
|
76
117
|
end
|
77
118
|
end
|
78
119
|
end
|
@@ -1,14 +1,43 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
module VagrantPlugins
|
3
4
|
module AnsibleAuto
|
5
|
+
# Error classes for the +ansible_auto+ provisioner and +ansible+ command
|
4
6
|
module Errors
|
7
|
+
# An error representing an {Inventory} misconfiguration
|
5
8
|
class InventoryError < Vagrant::Errors::VagrantError
|
6
|
-
error_namespace('vagrant.
|
9
|
+
error_namespace('vagrant.ansible_auto.errors.inventory')
|
7
10
|
end
|
8
11
|
|
12
|
+
# Raised when an Ansible inventory group is expected to exist but doesn't
|
9
13
|
class MissingGroupError < InventoryError
|
10
14
|
error_key(:missing_group)
|
11
15
|
end
|
16
|
+
|
17
|
+
# Raised when a group specifies child groups that do not exist
|
18
|
+
class GroupMissingChildError < MissingGroupError
|
19
|
+
error_key(:group_missing_child)
|
20
|
+
end
|
21
|
+
|
22
|
+
# Raised when provided data can't be converted to a {Host} object
|
23
|
+
class InvalidHostTypeError < InventoryError
|
24
|
+
error_key(:invalid_host_type)
|
25
|
+
end
|
26
|
+
|
27
|
+
# Raised when a group name is disallowed
|
28
|
+
class InvalidGroupNameError < InventoryError
|
29
|
+
error_key(:invalid_group_name)
|
30
|
+
end
|
31
|
+
|
32
|
+
# Class representing {Command} errors
|
33
|
+
class CommandError < Vagrant::Errors::VagrantError
|
34
|
+
error_namespace('vagrant.ansible_auto.errors.command')
|
35
|
+
end
|
36
|
+
|
37
|
+
# Raised on receipt of an unrecognized +vagrant ansible+ subcommand
|
38
|
+
class UnrecognizedCommandError < CommandError
|
39
|
+
error_key('unrecognized_command')
|
40
|
+
end
|
12
41
|
end
|
13
42
|
end
|
14
43
|
end
|
@@ -1,85 +1,174 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
require 'vagrant'
|
3
|
-
|
4
|
+
|
5
|
+
require 'vagrant/ansible_auto/util/hash_with_indifferent_access'
|
6
|
+
require 'vagrant/ansible_auto/util/keys'
|
4
7
|
|
5
8
|
module VagrantPlugins
|
6
9
|
module AnsibleAuto
|
10
|
+
# Class representing a single host in an Ansible inventory
|
7
11
|
class Host
|
8
|
-
include
|
9
|
-
|
10
|
-
ANSIBLE_HOSTVARS = [:ssh_user, :ssh_host, :ssh_port, :ssh_private_key_file, :connection].freeze
|
11
|
-
|
12
|
-
attr_writer(*ANSIBLE_HOSTVARS)
|
12
|
+
include Util::Keys
|
13
13
|
|
14
|
+
# @param [#to_s] name the name of the {Host} as it should appear in an
|
15
|
+
# {Inventory}
|
16
|
+
# @param [Hash] hostvars variables to associate with the host
|
14
17
|
def initialize(name, hostvars = {})
|
15
18
|
@name = name
|
16
19
|
|
17
|
-
# Convert keys to symbols
|
18
|
-
@hostvars = hostvars.each_with_object({}) { |(k, v), acc| acc[k.to_sym] = v }
|
20
|
+
# # Convert keys to symbols
|
21
|
+
# @hostvars = hostvars.each_with_object({}) { |(k, v), acc| acc[k.to_sym] = v }
|
22
|
+
self.hostvars = hostvars
|
19
23
|
end
|
20
24
|
|
25
|
+
# @return [String] the name of the {Host}, default +"default"+
|
21
26
|
def name
|
22
27
|
@name ||= 'default'
|
23
28
|
end
|
24
29
|
|
25
|
-
|
26
|
-
|
30
|
+
# @return [String] the name of the machine as a string
|
31
|
+
def inventory_hostname
|
32
|
+
@inventory_hostname ||= name.to_s
|
33
|
+
end
|
34
|
+
|
35
|
+
# @param new_name [#to_s] the name to associate with this host in the
|
36
|
+
# generated inventory
|
37
|
+
# @return (see #inventory_hostname)
|
38
|
+
def inventory_hostname=(new_name)
|
39
|
+
@inventory_hostname = new_name.to_s
|
40
|
+
end
|
41
|
+
|
42
|
+
# @return [String] the SSH user for the {Host}, default +"vagrant"+
|
43
|
+
def ansible_ssh_user
|
44
|
+
hostvars[:ansible_ssh_user] ||= 'vagrant'
|
27
45
|
end
|
28
46
|
|
29
|
-
|
30
|
-
|
47
|
+
# @return [String] the hostname of the {Host}, default +"127.0.0.1"+
|
48
|
+
def ansible_ssh_host
|
49
|
+
hostvars[:ansible_ssh_host] ||= '127.0.0.1'
|
31
50
|
end
|
32
51
|
|
33
|
-
|
34
|
-
|
52
|
+
# @return [Integer] the SSH port of the {Host}, default +22+
|
53
|
+
def ansible_ssh_port
|
54
|
+
hostvars[:ansible_ssh_port] ||= 22
|
35
55
|
end
|
36
56
|
|
37
|
-
|
38
|
-
|
57
|
+
# The SSH private key file
|
58
|
+
# @return [String] if the SSH private key file is defined
|
59
|
+
# @return [nil] if no SSH private key file is defined
|
60
|
+
def ansible_ssh_private_key_file
|
61
|
+
hostvars[:ansible_ssh_private_key_file]
|
39
62
|
end
|
40
63
|
|
41
|
-
|
42
|
-
|
64
|
+
# The connection type
|
65
|
+
# @return [String] if the connection type is defined
|
66
|
+
# @return [nil] if no connection type is defined
|
67
|
+
def ansible_connection
|
68
|
+
hostvars[:ansible_connection]
|
43
69
|
end
|
44
70
|
|
71
|
+
# @return [Hash] the {Host}'s attributes keyed to its attribute names
|
72
|
+
# @example
|
73
|
+
# host = Host.new("myhost", {ansible_ssh_user: 'me', ansible_ssh_port: 2200})
|
74
|
+
# host.hostvars #=> {
|
75
|
+
# # 'ansible_ssh_user' => 'me',
|
76
|
+
# # 'ansible_ssh_host' => '127.0.0.1',
|
77
|
+
# # 'ansible_ssh_port' => 2200,
|
78
|
+
# # }
|
45
79
|
def hostvars
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
80
|
+
@hostvars ||= Util::HashWithIndifferentAccess.new
|
81
|
+
end
|
82
|
+
|
83
|
+
# @param [Hash] hostvars the variables to set on the host
|
84
|
+
# @return [Hash] the new hostvars
|
85
|
+
def hostvars=(hostvars)
|
86
|
+
raise ArgumentError, 'hostvars must be a hash' unless hostvars.is_a? Hash
|
87
|
+
@hostvars = Util::HashWithIndifferentAccess.new(hostvars)
|
50
88
|
end
|
51
89
|
|
90
|
+
# @return [Hash{String=>Hash}] the {Host}'s {hostvars} keyed to its
|
91
|
+
# {name}
|
52
92
|
def to_h
|
53
|
-
|
93
|
+
finalize!
|
94
|
+
{ inventory_hostname => hostvars }
|
54
95
|
end
|
55
96
|
|
97
|
+
# @return [String] the {Host} represented as an entry in an Ansible
|
98
|
+
# INI-style static inventory
|
99
|
+
# @example
|
100
|
+
# host = Host.new("myhost", {ssh_user: 'me', ssh_port: 2200})
|
101
|
+
# host.to_ini #=> "myhost ansible_ssh_user=me ansible_ssh_host=127.0.0.1 ansible_ssh_port=2200"
|
56
102
|
def to_ini
|
57
|
-
[
|
103
|
+
[inventory_hostname, *hostvars.sort.reject { |_, value| value.nil? }.map { |key, value| "#{key}=#{value}" }].join(' ')
|
104
|
+
end
|
105
|
+
|
106
|
+
# @return [Fixnum] hash key
|
107
|
+
def hash
|
108
|
+
to_h.hash
|
109
|
+
end
|
110
|
+
|
111
|
+
# @return [Boolean] whether two hosts are identical
|
112
|
+
def eql?(other)
|
113
|
+
to_h.eql?(other.to_h)
|
114
|
+
end
|
115
|
+
|
116
|
+
private
|
117
|
+
|
118
|
+
def finalize!
|
119
|
+
%i[ansible_connection ansible_ssh_user ansible_ssh_host ansible_ssh_port ansible_ssh_private_key_file].each do |m|
|
120
|
+
send(m)
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
def respond_to_missing?(method, _include_all = false)
|
125
|
+
method.to_s.start_with? 'ansible_'
|
126
|
+
end
|
127
|
+
|
128
|
+
def method_missing(method, *args, &block)
|
129
|
+
super unless respond_to_missing?(method)
|
130
|
+
|
131
|
+
if method[-1] == '='
|
132
|
+
hostvars[method[0..-2]] = args[0]
|
133
|
+
else
|
134
|
+
hostvars[method]
|
135
|
+
end
|
58
136
|
end
|
59
137
|
end
|
60
138
|
|
139
|
+
# An Ansible host initialized from a {Vagrant::Machine}
|
61
140
|
class HostMachine < Host
|
141
|
+
# @param [Vagrant::Machine] machine a {Vagrant::Machine} objectj
|
142
|
+
# @param [Hash] hostvars the hostvars associated with the machine
|
62
143
|
def initialize(machine, hostvars = {})
|
63
144
|
super(machine.name, hostvars)
|
64
145
|
@machine = machine
|
65
|
-
@ssh_info = machine.ssh_info || {}
|
66
146
|
end
|
67
147
|
|
68
|
-
|
69
|
-
|
148
|
+
# @see Host#ssh_user
|
149
|
+
def ansible_ssh_user
|
150
|
+
hostvars[:ansible_ssh_user] ||= ssh_info[:username] || super
|
70
151
|
end
|
71
152
|
|
72
|
-
|
73
|
-
|
153
|
+
# @see Host#ssh_host
|
154
|
+
def ansible_ssh_host
|
155
|
+
hostvars[:ansible_ssh_host] ||= ssh_info[:host] || super
|
74
156
|
end
|
75
157
|
|
76
|
-
|
77
|
-
|
158
|
+
# @see Host#ssh_port
|
159
|
+
def ansible_ssh_port
|
160
|
+
hostvars[:ansible_ssh_port] ||= ssh_info[:port] || super
|
78
161
|
end
|
79
162
|
|
80
|
-
#
|
81
|
-
def
|
82
|
-
|
163
|
+
# @see Host#ssh_private_key_file
|
164
|
+
def ansible_ssh_private_key_file
|
165
|
+
hostvars[:ansible_ssh_private_key_file] ||= fetch_private_key(@machine)
|
166
|
+
end
|
167
|
+
|
168
|
+
private
|
169
|
+
|
170
|
+
def ssh_info
|
171
|
+
@machine.ssh_info || {}
|
83
172
|
end
|
84
173
|
end
|
85
174
|
end
|