vagrant-hivemind 0.1.0
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 +7 -0
- data/.gitignore +9 -0
- data/.rspec +2 -0
- data/.travis.yml +4 -0
- data/CODE_OF_CONDUCT.md +13 -0
- data/Gemfile +13 -0
- data/LICENSE.txt +21 -0
- data/README.md +63 -0
- data/Rakefile +10 -0
- data/bin/console +14 -0
- data/bin/setup +7 -0
- data/keys/id_rsa +27 -0
- data/keys/id_rsa.ppk +26 -0
- data/keys/id_rsa.pub +1 -0
- data/lib/vagrant/hivemind.rb +2 -0
- data/lib/vagrant/hivemind/commands/desc.rb +83 -0
- data/lib/vagrant/hivemind/commands/halt.rb +77 -0
- data/lib/vagrant/hivemind/commands/init.rb +67 -0
- data/lib/vagrant/hivemind/commands/kill.rb +77 -0
- data/lib/vagrant/hivemind/commands/list.rb +112 -0
- data/lib/vagrant/hivemind/commands/morph.rb +166 -0
- data/lib/vagrant/hivemind/commands/root.rb +90 -0
- data/lib/vagrant/hivemind/commands/spawn.rb +95 -0
- data/lib/vagrant/hivemind/commands/up.rb +102 -0
- data/lib/vagrant/hivemind/constants.rb +38 -0
- data/lib/vagrant/hivemind/host.rb +34 -0
- data/lib/vagrant/hivemind/plugin.rb +16 -0
- data/lib/vagrant/hivemind/util.rb +236 -0
- data/lib/vagrant/hivemind/version.rb +5 -0
- data/scripts/install-ansible.sh +8 -0
- data/scripts/post-install-ansible.sh +4 -0
- data/scripts/setup-control-ssh.sh +5 -0
- data/scripts/setup-drone-ssh.sh +7 -0
- data/scripts/setup-hostname.sh +11 -0
- data/scripts/update-system-hosts.sh +5 -0
- data/templates/Vagrantfile.erb +48 -0
- data/templates/ansible.hosts.erb +6 -0
- data/templates/system.hosts.erb +10 -0
- data/vagrant-hivemind.gemspec +25 -0
- metadata +124 -0
@@ -0,0 +1,77 @@
|
|
1
|
+
require "optparse"
|
2
|
+
|
3
|
+
require "vagrant/hivemind/constants"
|
4
|
+
require "vagrant/hivemind/util"
|
5
|
+
require "vagrant/hivemind/host"
|
6
|
+
|
7
|
+
module Vagrant
|
8
|
+
module Hivemind
|
9
|
+
module Command
|
10
|
+
class Kill < Vagrant.plugin("2", :command)
|
11
|
+
include Vagrant::Hivemind::Constants
|
12
|
+
include Vagrant::Hivemind::Util
|
13
|
+
|
14
|
+
def self.synopsis
|
15
|
+
"Removes a Drone in the Hive"
|
16
|
+
end
|
17
|
+
|
18
|
+
def execute
|
19
|
+
options = {}
|
20
|
+
|
21
|
+
opts = OptionParser.new do |o|
|
22
|
+
o.banner = "Usage: vagrant hivemind kill [options]"
|
23
|
+
o.separator ""
|
24
|
+
o.separator "Options:"
|
25
|
+
o.separator ""
|
26
|
+
|
27
|
+
o.on("-n", "--hostname HOSTNAME", "The hostname of the Drone (REQUIRED)") do |n|
|
28
|
+
options[:hostname] = n
|
29
|
+
end
|
30
|
+
|
31
|
+
o.on("-d", "--directory DIRECTORY", "Specify the directory where '#{HIVE_FILE}' is located (default: current directory)") do |d|
|
32
|
+
options[:directory] = []
|
33
|
+
options[:directory] << d
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
argv = parse_options(opts)
|
38
|
+
return if !argv
|
39
|
+
|
40
|
+
unless options[:hostname]
|
41
|
+
@env.ui.info opts.help
|
42
|
+
return 0
|
43
|
+
end
|
44
|
+
|
45
|
+
root_path = Path.get_root_path_from_options options
|
46
|
+
|
47
|
+
unless HiveFile.exist? root_path
|
48
|
+
@env.ui.error "There is no Hive file in the working directory."
|
49
|
+
return 1
|
50
|
+
end
|
51
|
+
|
52
|
+
hosts = HiveFile.read_from root_path
|
53
|
+
|
54
|
+
unless hosts.values.map(&:hostname).include? options[:hostname]
|
55
|
+
@env.ui.error "The specified hostname does not exist!"
|
56
|
+
return 1
|
57
|
+
end
|
58
|
+
|
59
|
+
host = hosts[options[:hostname]]
|
60
|
+
|
61
|
+
Vagrant::Hivemind::Util::Vagrantfile.generate_hivemind_vagrantfile @env, host, root_path
|
62
|
+
|
63
|
+
with_target_vms(options[:hostname]) do |vm|
|
64
|
+
action_env = vm.action(:destroy, force_confirm_destroy: true)
|
65
|
+
end
|
66
|
+
|
67
|
+
hosts.delete options[:hostname]
|
68
|
+
HiveFile.write_to hosts, root_path
|
69
|
+
@env.ui.info "Killed the Drone with hostname '#{options[:hostname]}'"
|
70
|
+
|
71
|
+
0
|
72
|
+
end
|
73
|
+
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,112 @@
|
|
1
|
+
require "optparse"
|
2
|
+
|
3
|
+
require "vagrant/hivemind/constants"
|
4
|
+
require "vagrant/hivemind/util"
|
5
|
+
require "vagrant/hivemind/host"
|
6
|
+
|
7
|
+
module Vagrant
|
8
|
+
module Hivemind
|
9
|
+
module Command
|
10
|
+
class List < Vagrant.plugin("2", :command)
|
11
|
+
include Vagrant::Hivemind::Constants
|
12
|
+
include Vagrant::Hivemind::Util
|
13
|
+
|
14
|
+
def self.synopsis
|
15
|
+
"Lists all the Drones in the Hive"
|
16
|
+
end
|
17
|
+
|
18
|
+
def execute
|
19
|
+
options = {}
|
20
|
+
|
21
|
+
opts = OptionParser.new do |o|
|
22
|
+
o.banner = "Usage: vagrant hivemind list [options]"
|
23
|
+
o.separator ""
|
24
|
+
o.separator "Options:"
|
25
|
+
o.separator ""
|
26
|
+
|
27
|
+
o.on("-n", "--hostname", "List the Drones ordered by the hostname") do |n|
|
28
|
+
options[:hostname] = n
|
29
|
+
end
|
30
|
+
|
31
|
+
o.on("-a", "--ip-address", "List the Drones ordered by the IP address") do |a|
|
32
|
+
options[:ip_address] = a
|
33
|
+
end
|
34
|
+
|
35
|
+
o.on("-c", "--control", "List the Drones, Control Machines first") do |c|
|
36
|
+
options[:control] = c
|
37
|
+
end
|
38
|
+
|
39
|
+
o.on("-s", "--size", "List the Drones ordered by the Box Size") do |s|
|
40
|
+
options[:size] = s
|
41
|
+
end
|
42
|
+
|
43
|
+
o.on("-d", "--directory DIRECTORY", "Specify the directory where '#{HIVE_FILE}' is located (default: current directory)") do |d|
|
44
|
+
options[:directory] = []
|
45
|
+
options[:directory] << d
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
argv = parse_options(opts)
|
50
|
+
return if !argv
|
51
|
+
|
52
|
+
root_path = Path.get_root_path_from_options options
|
53
|
+
|
54
|
+
unless HiveFile.exist? root_path
|
55
|
+
@env.ui.error "There is no Hive file in the working directory."
|
56
|
+
return 1
|
57
|
+
end
|
58
|
+
|
59
|
+
hosts = HiveFile.read_from root_path
|
60
|
+
|
61
|
+
sorted_hosts = sort_hosts hosts, options
|
62
|
+
|
63
|
+
@env.ui.info "+----------------------+----------------+---+--------------+------------+---+"
|
64
|
+
@env.ui.info "| Hostname | IP Address | C | Size | Box Type | G |"
|
65
|
+
@env.ui.info "+----------------------+----------------+---+--------------+------------+---+"
|
66
|
+
sorted_hosts.values.each do |host|
|
67
|
+
hostname = host.hostname
|
68
|
+
ip_address = host.ip_address
|
69
|
+
is_control_y_n = host.is_control ? 'Y' : 'N'
|
70
|
+
box_size = BOX_SIZES[host.box_size.to_sym][:name]
|
71
|
+
box_type = BOX_TYPES[host.box_type.to_sym][:name]
|
72
|
+
is_gui_y_n = BOX_TYPES[host.box_type.to_sym][:is_gui] ? 'Y' : 'N'
|
73
|
+
@env.ui.info "| #{'%-20.20s' % hostname} | #{'%-14.14s' % ip_address} | #{is_control_y_n} | #{'%-12.12s' % box_size} | #{'%-10.10s' % box_type} | #{is_gui_y_n} |"
|
74
|
+
end
|
75
|
+
@env.ui.info "+----------------------+----------------+---+--------------+------------+---+"
|
76
|
+
@env.ui.info ""
|
77
|
+
|
78
|
+
0
|
79
|
+
end
|
80
|
+
|
81
|
+
private
|
82
|
+
def sort_hosts(hosts, options = {})
|
83
|
+
sorted_hosts = hosts
|
84
|
+
options.keys.each do |key|
|
85
|
+
sorted_hosts = sort_hosts_by_hostname(hosts) if key == :hostname
|
86
|
+
sorted_hosts = sort_hosts_by_ip_address(hosts) if key == :ip_address
|
87
|
+
sorted_hosts = sort_hosts_by_control(hosts) if key == :control
|
88
|
+
sorted_hosts = sort_hosts_by_box_size(hosts) if key == :size
|
89
|
+
end
|
90
|
+
sorted_hosts
|
91
|
+
end
|
92
|
+
|
93
|
+
def sort_hosts_by_hostname(hosts)
|
94
|
+
(hosts.sort_by { |k,v| v.hostname }).to_h
|
95
|
+
end
|
96
|
+
|
97
|
+
def sort_hosts_by_ip_address(hosts)
|
98
|
+
(hosts.sort_by { |k,v| v.ip_address }).to_h
|
99
|
+
end
|
100
|
+
|
101
|
+
def sort_hosts_by_control(hosts)
|
102
|
+
(hosts.sort_by { |k,v| v.is_control.to_s }.reverse).to_h
|
103
|
+
end
|
104
|
+
|
105
|
+
def sort_hosts_by_box_size(hosts)
|
106
|
+
(hosts.sort_by { |k,v| BOX_SIZES[v.box_size.to_sym][:memory_in_mb] }).to_h
|
107
|
+
end
|
108
|
+
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
@@ -0,0 +1,166 @@
|
|
1
|
+
require "optparse"
|
2
|
+
|
3
|
+
require "vagrant/hivemind/constants"
|
4
|
+
require "vagrant/hivemind/util"
|
5
|
+
require "vagrant/hivemind/host"
|
6
|
+
|
7
|
+
module Vagrant
|
8
|
+
module Hivemind
|
9
|
+
module Command
|
10
|
+
class Morph < Vagrant.plugin("2", :command)
|
11
|
+
include Vagrant::Hivemind::Constants
|
12
|
+
include Vagrant::Hivemind::Util
|
13
|
+
|
14
|
+
def self.synopsis
|
15
|
+
"Changes the settings of a Drone in the Hive"
|
16
|
+
end
|
17
|
+
|
18
|
+
def execute
|
19
|
+
options = {}
|
20
|
+
|
21
|
+
opts = OptionParser.new do |o|
|
22
|
+
o.banner = "Usage: vagrant hivemind morph [options]"
|
23
|
+
o.separator ""
|
24
|
+
o.separator "Options:"
|
25
|
+
o.separator ""
|
26
|
+
|
27
|
+
o.on("-n", "--hostname HOSTNAME", "The hostname of the Drone (REQUIRED)") do |n|
|
28
|
+
options[:hostname] = n
|
29
|
+
end
|
30
|
+
|
31
|
+
o.on("-a", "--ip-address IPADDRESS", "The new IP address of the Drone") do |a|
|
32
|
+
options[:ip_address] = a
|
33
|
+
end
|
34
|
+
|
35
|
+
o.on("-c", "--control", "Promote the Drone to be a Control Machine") do |c|
|
36
|
+
options[:control] = c
|
37
|
+
end
|
38
|
+
|
39
|
+
o.on("-s", "--size SIZE", BOX_SIZES.keys.map(&:to_s), "The new Box Size of the Drone [:extra_small, :small, :medium, :large, :extra_large] (default: :small)") do |s|
|
40
|
+
options[:size] = s
|
41
|
+
end
|
42
|
+
|
43
|
+
o.on("-p", "--forwarded-port PORTPAIR", "Forward GUESTPORT to HOSTPORT (the format is GUESTPORT:HOSTPORT)") do |p|
|
44
|
+
options[:forwarded_port] = p
|
45
|
+
end
|
46
|
+
|
47
|
+
o.on("-d", "--directory DIRECTORY", "Specify the directory where '#{HIVE_FILE}' is located (default: current directory)") do |d|
|
48
|
+
options[:directory] = []
|
49
|
+
options[:directory] << d
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
argv = parse_options(opts)
|
54
|
+
return if !argv
|
55
|
+
|
56
|
+
root_path = Path.get_root_path_from_options options
|
57
|
+
|
58
|
+
unless options[:hostname]
|
59
|
+
@env.ui.info opts.help
|
60
|
+
return 0
|
61
|
+
end
|
62
|
+
|
63
|
+
unless HiveFile.exist? root_path
|
64
|
+
@env.ui.error "There is no Hive file in the working directory."
|
65
|
+
return 1
|
66
|
+
end
|
67
|
+
|
68
|
+
hosts = HiveFile.read_from root_path
|
69
|
+
|
70
|
+
unless hosts.values.map(&:hostname).include? options[:hostname]
|
71
|
+
@env.ui.error "The specified hostname does not exist!"
|
72
|
+
return 1
|
73
|
+
end
|
74
|
+
|
75
|
+
if options[:ip_address]
|
76
|
+
validation_error = is_valid_ip_address?(options[:ip_address], hosts)
|
77
|
+
if validation_error
|
78
|
+
@env.ui.error validation_error
|
79
|
+
return 1
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
if options[:forwarded_port]
|
84
|
+
validation_error = is_valid_forwarded_port?(options[:forwarded_port], hosts)
|
85
|
+
if validation_error
|
86
|
+
@env.ui.error validation_error
|
87
|
+
return 1
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
host = hosts[options[:hostname]]
|
92
|
+
|
93
|
+
if options[:ip_address]
|
94
|
+
host.ip_address = options[:ip_address]
|
95
|
+
end
|
96
|
+
|
97
|
+
if options[:control]
|
98
|
+
host.is_control = true
|
99
|
+
end
|
100
|
+
|
101
|
+
if options[:size]
|
102
|
+
host.box_size = options[:size]
|
103
|
+
end
|
104
|
+
|
105
|
+
if options[:forwarded_port]
|
106
|
+
guest_port, host_port = Network.port_pair_to_i(options[:forwarded_port])
|
107
|
+
host.forwarded_ports ||= []
|
108
|
+
|
109
|
+
port_pair = Network.get_host_port_pair_with_guest_port(guest_port, host)
|
110
|
+
if port_pair
|
111
|
+
port_pair["host_port"] = host_port
|
112
|
+
else
|
113
|
+
port_pair = {
|
114
|
+
"guest_port" => guest_port,
|
115
|
+
"host_port" => host_port
|
116
|
+
}
|
117
|
+
host.forwarded_ports << port_pair
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
hosts.delete options[:hostname]
|
122
|
+
drone = {
|
123
|
+
options[:hostname] => host
|
124
|
+
}
|
125
|
+
HiveFile.write_to hosts.merge(drone), root_path
|
126
|
+
@env.ui.info "Morphed the Drone with hostname '#{options[:hostname]}'"
|
127
|
+
|
128
|
+
0
|
129
|
+
end
|
130
|
+
|
131
|
+
private
|
132
|
+
def is_valid_ip_address?(ip_address, hosts)
|
133
|
+
if !Network.is_valid_ip_address? ip_address
|
134
|
+
return "Invalid IP address format!"
|
135
|
+
end
|
136
|
+
if Network.get_network(ip_address) != Network.get_network(PRIVATE_NETWORK)
|
137
|
+
return "The specified IP address does not belong to the private network of the Hive!"
|
138
|
+
end
|
139
|
+
if hosts.values.map(&:ip_address).include? ip_address
|
140
|
+
return "The specified IP address is already used!"
|
141
|
+
end
|
142
|
+
return nil
|
143
|
+
end
|
144
|
+
|
145
|
+
def is_valid_forwarded_port?(port_pair, hosts)
|
146
|
+
if !Network.is_valid_port_pair? port_pair
|
147
|
+
return "Invalid port pair format!"
|
148
|
+
end
|
149
|
+
|
150
|
+
guest_port, host_port = Network.port_pair_to_i(port_pair)
|
151
|
+
if !Network.is_valid_port_value? guest_port
|
152
|
+
return "Guest port is out of range!"
|
153
|
+
end
|
154
|
+
if !Network.is_valid_port_value? host_port
|
155
|
+
return "Host port is out of range!"
|
156
|
+
end
|
157
|
+
|
158
|
+
if Network.get_host_keys_using_host_port(host_port, hosts).size > 0
|
159
|
+
return "Host port is already used!"
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
require "optparse"
|
2
|
+
|
3
|
+
module Vagrant
|
4
|
+
module Hivemind
|
5
|
+
module Command
|
6
|
+
class Root < Vagrant.plugin("2", :command)
|
7
|
+
def self.synopsis
|
8
|
+
"Hivemind operations: init list desc spawn kill morph up halt"
|
9
|
+
end
|
10
|
+
|
11
|
+
def initialize(argv, env)
|
12
|
+
super
|
13
|
+
|
14
|
+
@main_args, @sub_command, @sub_args = split_main_and_subcommand(argv)
|
15
|
+
|
16
|
+
@subcommands = Vagrant::Registry.new
|
17
|
+
|
18
|
+
@subcommands.register(:init) do
|
19
|
+
require_relative "init"
|
20
|
+
Init
|
21
|
+
end
|
22
|
+
|
23
|
+
@subcommands.register(:list) do
|
24
|
+
require_relative "list"
|
25
|
+
List
|
26
|
+
end
|
27
|
+
|
28
|
+
@subcommands.register(:desc) do
|
29
|
+
require_relative "desc"
|
30
|
+
Desc
|
31
|
+
end
|
32
|
+
|
33
|
+
@subcommands.register(:spawn) do
|
34
|
+
require_relative "spawn"
|
35
|
+
Spawn
|
36
|
+
end
|
37
|
+
|
38
|
+
@subcommands.register(:kill) do
|
39
|
+
require_relative "kill"
|
40
|
+
Kill
|
41
|
+
end
|
42
|
+
|
43
|
+
@subcommands.register(:morph) do
|
44
|
+
require_relative "morph"
|
45
|
+
Morph
|
46
|
+
end
|
47
|
+
|
48
|
+
@subcommands.register(:up) do
|
49
|
+
require_relative "up"
|
50
|
+
Up
|
51
|
+
end
|
52
|
+
|
53
|
+
@subcommands.register(:halt) do
|
54
|
+
require_relative "halt"
|
55
|
+
Halt
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
59
|
+
|
60
|
+
def execute
|
61
|
+
if @main_args.include?("-h") || @main_args.include?("--help")
|
62
|
+
return help
|
63
|
+
end
|
64
|
+
|
65
|
+
command_class = @subcommands.get(@sub_command.to_sym) if @sub_command
|
66
|
+
return help if !command_class || !@sub_command
|
67
|
+
|
68
|
+
command_class.new(@sub_args, @env).execute
|
69
|
+
end
|
70
|
+
|
71
|
+
def help
|
72
|
+
opts = OptionParser.new do |o|
|
73
|
+
o.banner = "Usage: vagrant hivemind <command> [<args>]"
|
74
|
+
o.separator ""
|
75
|
+
o.separator "Available commands:"
|
76
|
+
|
77
|
+
@subcommands.each do |key, data|
|
78
|
+
o.separator "#{'%8.6s' % key.to_s} #{'%.60s' % data.synopsis}"
|
79
|
+
end
|
80
|
+
|
81
|
+
o.separator ""
|
82
|
+
o.separator "For help on any individual command run `vagrant hivemind <command> -h`"
|
83
|
+
end
|
84
|
+
|
85
|
+
@env.ui.info(opts.help, prefix: false)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|