vagrant-ansible_auto 0.1.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (34) hide show
  1. checksums.yaml +7 -0
  2. data/Gemfile +11 -0
  3. data/LICENSE.md +23 -0
  4. data/README.md +129 -0
  5. data/Rakefile +12 -0
  6. data/TODO.md +8 -0
  7. data/Vagrantfile +23 -0
  8. data/Vagrantfile2 +4 -0
  9. data/Vagrantfile3 +8 -0
  10. data/Vagrantfile4 +31 -0
  11. data/lib/vagrant/ansible_auto/cap/guest/posix/bash_installed.rb +30 -0
  12. data/lib/vagrant/ansible_auto/cap/guest/posix/check_open_port.rb +34 -0
  13. data/lib/vagrant/ansible_auto/cap/guest/posix/executable_installed.rb +20 -0
  14. data/lib/vagrant/ansible_auto/cap/guest/posix/gateway_addresses.rb +62 -0
  15. data/lib/vagrant/ansible_auto/cap/guest/posix/private_key.rb +22 -0
  16. data/lib/vagrant/ansible_auto/cap/guest/posix/public_key.rb +28 -0
  17. data/lib/vagrant/ansible_auto/cap/guest/posix/ssh_server_address.rb +88 -0
  18. data/lib/vagrant/ansible_auto/command/inventory.rb +50 -0
  19. data/lib/vagrant/ansible_auto/command/root.rb +59 -0
  20. data/lib/vagrant/ansible_auto/config.rb +78 -0
  21. data/lib/vagrant/ansible_auto/errors.rb +14 -0
  22. data/lib/vagrant/ansible_auto/host.rb +86 -0
  23. data/lib/vagrant/ansible_auto/inventory.rb +189 -0
  24. data/lib/vagrant/ansible_auto/plugin.rb +74 -0
  25. data/lib/vagrant/ansible_auto/provisioner.rb +181 -0
  26. data/lib/vagrant/ansible_auto/util.rb +24 -0
  27. data/lib/vagrant/ansible_auto/version.rb +6 -0
  28. data/lib/vagrant/ansible_auto.rb +5 -0
  29. data/playbooks/test.yml +4 -0
  30. data/spec/spec_helper.rb +93 -0
  31. data/spec/vagrant/ansible_auto/host_spec.rb +43 -0
  32. data/spec/vagrant/ansible_auto/inventory_spec.rb +79 -0
  33. data/vagrant-ansible_auto.gemspec +32 -0
  34. metadata +175 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 40fd0b7cb409371ac24b6e878076c7aa5020db70
4
+ data.tar.gz: 1ff945bf3f9f43324c504cb2a987c49f1d7eccce
5
+ SHA512:
6
+ metadata.gz: 0a4e2871cff450346b750f166c39d4730b97e41ba8c39476582cde9ec307d6a42035b99739590fe7dc9baadd181efaf5776d67152ba424b57a877ce87e6530e7
7
+ data.tar.gz: 5d13474ca2aed002005b23f2c028fe932470293914551e9ddf32b3de0f5fbdd9e9f9ad5a576c2cc4c0ddd8a2502cafb79c22c77639488da910d3247936b98439
data/Gemfile ADDED
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+ source 'https://rubygems.org'
3
+
4
+ group :development do
5
+ gem 'pry'
6
+ gem 'vagrant', github: 'mitchellh/vagrant'
7
+ end
8
+
9
+ group :plugins do
10
+ gemspec
11
+ end
data/LICENSE.md ADDED
@@ -0,0 +1,23 @@
1
+ Copyright (c) 2014-2015 Ignacio Galindo
2
+ Copyright (c) 2016-2017 Matt Schreiber
3
+
4
+ MIT License
5
+
6
+ Permission is hereby granted, free of charge, to any person obtaining
7
+ a copy of this software and associated documentation files (the
8
+ "Software"), to deal in the Software without restriction, including
9
+ without limitation the rights to use, copy, modify, merge, publish,
10
+ distribute, sublicense, and/or sell copies of the Software, and to
11
+ permit persons to whom the Software is furnished to do so, subject to
12
+ the following conditions:
13
+
14
+ The above copyright notice and this permission notice shall be
15
+ included in all copies or substantial portions of the Software.
16
+
17
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
21
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,129 @@
1
+ # Vagrant::AnsibleAuto
2
+
3
+ This Vagrant plugin provides the `ansible_auto` provisioner that automatically
4
+ sets up the provisioned guest as an Ansible control machine for the nodes
5
+ defined in your Vagrantfile. It also provides the `vagrant ansible` subcommand
6
+ that generates an inventory file for use on your Vagrant host machine.
7
+
8
+ ## Installation
9
+
10
+ Install with:
11
+
12
+ ```shell
13
+ $ vagrant plugin install vagrant-ansible_auto
14
+ ```
15
+
16
+ ## Usage
17
+
18
+ ### Inventory Generation
19
+
20
+ Say you have a Vagrantfile with the following contents:
21
+
22
+ ```ruby
23
+ Vagrant.configure(2) do |config|
24
+ config.vm.box = 'hashicorp/precise64'
25
+
26
+ (1..2).each do |i|
27
+ name = "ansible-test-worker-#{i}"
28
+ config.vm.define name do |target|
29
+ end
30
+ end
31
+
32
+ config.vm.define 'ansible-test-control' do |machine|
33
+ machine.vm.provision :ansible_auto do |ansible|
34
+ ansible.limit = '*'
35
+ ansible.playbook = 'playbooks/test.yml'
36
+ end
37
+ end
38
+
39
+ config.ansible.groups = {
40
+ 'control' => %w(ansible-test-control),
41
+ 'worker' => %w(ansible-test-worker-1 ansible-test-worker-2),
42
+ 'cluster:children' => %w(control worker),
43
+ }
44
+ end
45
+ ```
46
+
47
+ Running `vagrant ansible inventory` will print this Ansible inventory:
48
+
49
+ ```ini
50
+ ansible-test-worker-1 ansible_ssh_user=vagrant ansible_ssh_host=127.0.0.1 ansible_ssh_port=2222 ansible_ssh_private_key_file=/home/matt/git/vagrant-ansible_inventory/.vagrant/machines/ansible-test-worker-1/virtualbox/private_key
51
+ ansible-test-worker-2 ansible_ssh_user=vagrant ansible_ssh_host=127.0.0.1 ansible_ssh_port=2200 ansible_ssh_private_key_file=/home/matt/git/vagrant-ansible_inventory/.vagrant/machines/ansible-test-worker-2/virtualbox/private_key
52
+ ansible-test-control ansible_ssh_user=vagrant ansible_ssh_host=127.0.0.1 ansible_ssh_port=2201 ansible_ssh_private_key_file=/home/matt/git/vagrant-ansible_inventory/.vagrant/machines/ansible-test-control/virtualbox/private_key
53
+ [control]
54
+ ansible-test-control
55
+ [worker]
56
+ ansible-test-worker-1
57
+ ansible-test-worker-2
58
+ [cluster:children]
59
+ control
60
+ worker
61
+ ```
62
+
63
+ ### Provisioning
64
+
65
+ The `ansible_auto` provisioner is an augmented version of the
66
+ [`ansible_local` provisioner included with Vagrant](https://www.vagrantup.com/docs/provisioning/ansible_local.html).
67
+ It accepts all options valid for that provisioner, and adds the following
68
+ options:
69
+
70
+ ```ruby
71
+ Vagrant.configure(2) do |config|
72
+ config.define 'ansible-control' do |machine|
73
+ machine.provision :ansible_auto do |ansible|
74
+ # Will show up in inventory as
75
+ # [control]
76
+ # ansible-control
77
+ ansible.groups = {
78
+ 'control' => %(ansible-control)
79
+ }
80
+
81
+ # Will show up in inventory as
82
+ # [dev:children]
83
+ # control
84
+ ansible.children = {
85
+ 'dev' => %w(control)
86
+ }
87
+
88
+ # Will show up in inventory as
89
+ # [dev:vars]
90
+ # ansible_port = 2222
91
+ ansible.vars = {
92
+ 'dev' => {
93
+ 'ansible_port' => 2222
94
+ }
95
+ }
96
+
97
+ # Enable or disable `StrictHostKeyChecking` SSH option.
98
+ # Disabled by default.
99
+ ansible.strict_host_key_checking = false
100
+
101
+ # The number of times to attempt to connect to a managed host from the
102
+ # Ansible control machine.
103
+ ansible.host_connect_tries = 10
104
+
105
+ # The number of seconds to delay between connection attempts.
106
+ ansible.host_connect_sleep = 5
107
+ end
108
+ end
109
+ end
110
+ ```
111
+
112
+ Each guest provisioned with `ansible_auto` will be set up as an Ansible
113
+ control machine with the ability to connect to other guests defined in the
114
+ `Vagrantfile`. This is facilitated by uploading the private keys of each guest
115
+ to a temporary path on the control machine and assigning this path as the
116
+ hostvar `ansible_ssh_private_key_file` to the relevant host in the generated
117
+ inventory.
118
+
119
+ ## Contributing
120
+
121
+ 1. Fork it ( https://github.com/joiggama/vagrant-ansible_auto/fork )
122
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
123
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
124
+ 4. Push to the branch (`git push origin my-new-feature`)
125
+ 5. Create a new Pull Request
126
+
127
+ ## License
128
+
129
+ [The MIT licence](LICENSE.md)
data/Rakefile ADDED
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+ require "bundler/gem_tasks"
3
+
4
+ require "rspec/core/rake_task"
5
+ RSpec::Core::RakeTask.new(:spec) do |t|
6
+ t.ruby_opts = "-w"
7
+ end
8
+
9
+ require "rubocop/rake_task"
10
+ RuboCop::RakeTask.new
11
+
12
+ task default: [:rubocop, :spec]
data/TODO.md ADDED
@@ -0,0 +1,8 @@
1
+ # TODO
2
+
3
+ - See if it possible to Vagrant::Util::IsPortOpen instead of Bash/nc/etc for
4
+ checking whether a port is open. *Has to run on the guest*, so probably not
5
+ possible.
6
+ - Util::ScopedHashOverride for the key conversions done in Host?
7
+ - Util::HashWithIndifferentAccess for Host?
8
+ - default vaues for arguments to attr_writer methods in `Inventory`
data/Vagrantfile ADDED
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+ Vagrant.configure(2) do |config|
3
+ define_vm = lambda do |name, box, memory|
4
+ config.vm.define name do |instance|
5
+ instance.vm.box = box
6
+ instance.vm.hostname = name
7
+ instance.vm.network 'private_network', type: 'dhcp'
8
+ instance.vm.provider :virtualbox do |i|
9
+ i.name = name
10
+ i.memory = memory
11
+ end
12
+ end
13
+ end
14
+
15
+ define_vm.call 'master', 'ubuntu/trusty32', 256
16
+ define_vm.call 'slave-1', 'ubuntu/trusty32', 256
17
+ define_vm.call 'slave-2', 'ubuntu/trusty32', 256
18
+
19
+ config.ansible.groups = {
20
+ 'cluster:children' => %w(master slaves),
21
+ 'slaves' => ['slave-1', 'slave-2'],
22
+ }
23
+ end
data/Vagrantfile2 ADDED
@@ -0,0 +1,4 @@
1
+ Vagrant.configure(2) do |config|
2
+ config.vm.box = 'ubuntu/trusty64'
3
+ config.vm.network :private_network, type: :dhcp
4
+ end
data/Vagrantfile3 ADDED
@@ -0,0 +1,8 @@
1
+ Vagrant.configure(2) do |config|
2
+ config.vm.box = 'trusty64'
3
+ config.vm.network :private_network, type: :dhcp
4
+
5
+ config.ansible.groups = {
6
+ 'ubuntu' => ['default']
7
+ }
8
+ end
data/Vagrantfile4 ADDED
@@ -0,0 +1,31 @@
1
+ Vagrant.configure(2) do |config|
2
+ config.vm.box = 'hashicorp/precise64'
3
+
4
+ (1..2).each do |i|
5
+ name = "ansible-test-worker-#{i}"
6
+ config.vm.define name do |target|
7
+ end
8
+ end
9
+
10
+ config.vm.define 'ansible-test-control' do |machine|
11
+ machine.vm.provision :ansible_auto do |ansible|
12
+ ansible.limit = '*'
13
+ ansible.playbook = 'playbooks/test.yml'
14
+ end
15
+ end
16
+
17
+ config.ansible.groups = {
18
+ 'control' => %w(ansible-test-control),
19
+ 'worker' => %w(ansible-test-worker-1 ansible-test-worker-2),
20
+ 'cluster:children' => %w(control worker),
21
+ }
22
+
23
+ config.ansible.vars = {
24
+ 'control' => {
25
+ 'role' => 'ansible-control',
26
+ },
27
+ 'worker' => {
28
+ 'role' => 'ansible-worker',
29
+ }
30
+ }
31
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+ module VagrantPlugins
3
+ module AnsibleAuto
4
+ module Cap
5
+ module Guest
6
+ module POSIX
7
+ class BashInstalled
8
+ class << self
9
+ def bash_installed?(machine, version = nil)
10
+ machine.communicate.execute(%q(command bash -c 'printf -- "%s\t%s" "$BASH" "$BASH_VERSION"'), error_check: false) do |type, data|
11
+ data.chomp!
12
+
13
+ # Not sure why, but we always get an empty first line...
14
+ next if data.empty?
15
+
16
+ if type == :stdout
17
+ bash_path, bash_version = *data.split("\t")
18
+ return (!bash_path.empty? and (version.nil? or version == bash_version))
19
+ end
20
+ end
21
+
22
+ false
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+ require 'uri'
3
+
4
+ module VagrantPlugins
5
+ module AnsibleAuto
6
+ module Cap
7
+ module Guest
8
+ module POSIX
9
+ class CheckOpenPort
10
+ class << self
11
+ def check_open_port(machine, host, port, proto = 'tcp')
12
+ return nil unless machine.communicate.test('bash')
13
+
14
+ # Check that we got a valid URI by constructing a URI object
15
+ # and watching for exceptions raised upon component assignment.
16
+ begin
17
+ uri = URI('').tap do |u|
18
+ u.host = host
19
+ u.port = port
20
+ end
21
+ rescue URI::InvalidComponentError
22
+ return nil
23
+ end
24
+
25
+ target = File.join('/dev/', proto, uri.host, uri.port.to_s).shellescape
26
+ machine.communicate.test("read < #{target}", shell: '/bin/bash')
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+ require 'shellwords'
3
+
4
+ module VagrantPlugins
5
+ module AnsibleAuto
6
+ module Cap
7
+ module Guest
8
+ module POSIX
9
+ class ExecutableInstalled
10
+ class << self
11
+ def executable_installed?(machine, executable)
12
+ machine.communicate.test(%[test -x "$(command -v #{executable.shellescape})"], error_check: false)
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,62 @@
1
+ # frozen_string_literal: true
2
+ require 'set'
3
+
4
+ module VagrantPlugins
5
+ module AnsibleAuto
6
+ module Cap
7
+ module Guest
8
+ module POSIX
9
+ class GatewayAddresses
10
+ class << self
11
+ def gateway_addresses(machine)
12
+ with_default_gateway_addresses(machine).to_a.compact
13
+ end
14
+
15
+ private
16
+
17
+ def with_default_gateway_addresses(machine)
18
+ return enum_for(__method__, machine) unless block_given?
19
+
20
+ seen_addresses = Set.new
21
+ yield_unseen_address = lambda do |a|
22
+ yield a unless seen_addresses.include? a
23
+ seen_addresses << a
24
+ end
25
+
26
+ machine.communicate.execute('ip route show', error_check: false) do |type, data|
27
+ if type == :stdout
28
+ data.lines.each do |line|
29
+ if line.start_with?('default')
30
+ yield_unseen_address.call(line.split[2])
31
+ end
32
+ end
33
+ end
34
+ end
35
+
36
+ machine.communicate.execute('route -n', error_check: false) do |type, data|
37
+ if type == :stdout
38
+ data.lines.each do |line|
39
+ if line.start_with?('0.0.0.0')
40
+ yield_unseen_address.call(line.split[1])
41
+ end
42
+ end
43
+ end
44
+ end
45
+
46
+ machine.communicate.execute('netstat -rn', error_check: false) do |type, data|
47
+ if type == :stdout
48
+ data.lines.each do |line|
49
+ if line.start_with?('0.0.0.0')
50
+ yield_unseen_address.call(line.split[1])
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module VagrantPlugins
4
+ module AnsibleAuto
5
+ module Cap
6
+ module Guest
7
+ module POSIX
8
+ class PrivateKey
9
+ class << self
10
+ def generate_private_key(machine, path, type = 'rsa', bits = '2048')
11
+ return unless machine.guest.capability?(:executable_installed?) \
12
+ && machine.guest.capability(:executable_installed?, 'ssh-keygen')
13
+
14
+ machine.communicate.execute("ssh-keygen -t #{type} -b #{bits} -C 'Vagrant-generated keypair' -f #{path}")
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ module VagrantPlugins
4
+ module AnsibleAuto
5
+ module Cap
6
+ module Guest
7
+ module POSIX
8
+ class PrivateKey
9
+ class << self
10
+ def fetch_public_key(machine, path)
11
+ return unless machine.guest.capability?(:executable_installed?) \
12
+ && machine.guest.capability(:executable_installed?, 'ssh-keygen')
13
+
14
+ # TODO: handle bad status
15
+ public_key = ''
16
+ _status = machine.communicate.execute("ssh-keygen -f #{path} -y") do |data_type, data|
17
+ public_key += data if data_type == :stdout
18
+ end
19
+
20
+ public_key
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,88 @@
1
+ # frozen_string_literal: true
2
+ require 'set'
3
+
4
+ module VagrantPlugins
5
+ module AnsibleAuto
6
+ module Cap
7
+ module Guest
8
+ module POSIX
9
+ class SSHServerAddress
10
+ class << self
11
+ def ssh_server_address(machine, target_machine = nil)
12
+ with_open_ports(machine, target_machine).first
13
+ end
14
+
15
+ private
16
+
17
+ def ssh_server_addresses(machine, target_machine = nil)
18
+ with_open_ports(machine, target_machine).to_a
19
+ end
20
+
21
+ def with_open_ports(machine, target_machine = nil)
22
+ return enum_for(__method__, machine, target_machine) unless block_given?
23
+
24
+ return unless machine.guest.capability?(:check_open_port)
25
+
26
+ target_machine ||= machine
27
+ ssh_info = target_machine.ssh_info
28
+ default_port = ssh_info.nil? ? 22 : ssh_info[:port]
29
+
30
+ with_candidate_addresses(target_machine) do |host, port|
31
+ port ||= default_port
32
+
33
+ if machine.guest.capability(:check_open_port, host, port)
34
+ yield host, port
35
+ end
36
+ end
37
+ end
38
+
39
+ network_type_precedence_map = Hash[[:forwarded_port, :public_network, :private_network].each_with_index.map { |type, i| [type, i] }]
40
+ define_method(:network_type_precedence) do |type|
41
+ network_type_precedence_map[type]
42
+ end
43
+
44
+ def with_candidate_addresses(machine)
45
+ return enum_for(__method__, machine) unless block_given?
46
+
47
+ seen_candidates = Set.new
48
+ yield_unseen_candidate = lambda do |host_and_port|
49
+ yield(*host_and_port) unless seen_candidates.include?(host_and_port)
50
+ seen_candidates << host_and_port
51
+ end
52
+
53
+ if machine.provider.capability?(:public_address)
54
+ yield_unseen_candidate.call([machine.provider.capability(:public_address)])
55
+ end
56
+
57
+ unless machine.ssh_info.nil?
58
+ yield_unseen_candidate.call([machine.ssh_info[:host]])
59
+ end
60
+
61
+ has_routable_ip = false
62
+ machine.config.vm.networks.sort_by { |(type, _)| network_type_precedence(type) }.each do |type, info|
63
+ case type
64
+ when :private_network, :public_network
65
+ has_routable_ip = true
66
+
67
+ yield_unseen_candidate.call([info[:ip]]) if info.key?(:ip)
68
+ when :forwarded_port
69
+ # TODO: the `:id' restriction might not be right.
70
+ if info[:protocol] == 'tcp' and info[:id] == 'ssh'
71
+ yield_unseen_candidate.call([info[:host_ip], info[:host]])
72
+ end
73
+ end
74
+ end
75
+
76
+ return if has_routable_ip or !machine.guest.capability?(:gateway_addresses)
77
+
78
+ machine.guest.capability(:gateway_addresses).each do |gateway_address|
79
+ yield_unseen_candidate.call(gateway_address)
80
+ end
81
+ end
82
+ end
83
+ end
84
+ end
85
+ end
86
+ end
87
+ end
88
+ end
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+ require 'optparse'
3
+
4
+ module VagrantPlugins
5
+ module AnsibleAuto
6
+ module Command
7
+ class Inventory < Vagrant.plugin(2, :command)
8
+ def self.synopsis
9
+ 'dynamic ansible inventory'
10
+ end
11
+
12
+ def execute
13
+ opts = OptionParser.new do |op|
14
+ op.banner = 'Usage: vagrant ansible inventory [<options>]'
15
+ op.separator ''
16
+ op.separator 'Available options:'
17
+
18
+ op.on('-l', '--list', 'List all hosts as json') do |_target|
19
+ @env.ui.info inventory.to_json, prefix: false
20
+ return 0
21
+ end
22
+
23
+ op.on('-h', '--help', 'Show this message') do
24
+ @env.ui.info opts.help, prefix: false
25
+ return 0
26
+ end
27
+ end
28
+
29
+ @argv = parse_options(opts)
30
+
31
+ @env.ui.info inventory.to_ini, prefix: false
32
+
33
+ 0
34
+ end
35
+
36
+ private
37
+
38
+ def inventory
39
+ @inventory = with_target_vms(@argv) {}.each_with_object(AnsibleAuto::Inventory.new) do |machine, inventory|
40
+ unless machine.state.id == :running
41
+ @env.ui.warn "machine #{machine.name} is not running; falling back to default hostvar values"
42
+ end
43
+ inventory.merge!(machine.config.ansible.inventory)
44
+ inventory.add_host(machine)
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,59 @@
1
+ # frozen_string_literal: true
2
+ require 'optparse'
3
+
4
+ module VagrantPlugins
5
+ module AnsibleAuto
6
+ module Command
7
+ class Root < Vagrant.plugin(2, :command)
8
+ def self.synopsis
9
+ 'build ansible inventory'
10
+ end
11
+
12
+ def initialize(argv, env)
13
+ super
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
+
25
+ def execute
26
+ if @main_args.include?('-h') || @main_args.include?('--help')
27
+ return help
28
+ 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
+ end
36
+
37
+ def help
38
+ opts = OptionParser.new do |o|
39
+ o.banner = 'Usage: vagrant ansible <subcommand> [<options>]'
40
+ o.separator ''
41
+ o.separator 'Available subcommands:'
42
+
43
+ keys = []
44
+ @subcommands.each { |key, _value| keys << key.to_s }
45
+
46
+ keys.sort.each do |key|
47
+ o.separator " #{key}"
48
+ end
49
+
50
+ o.separator ""
51
+ o.separator "For help on any individual subcommand run `vagrant ansible <subcommand> -h`"
52
+ end
53
+
54
+ @env.ui.info(opts.help, prefix: false)
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end