vagrant-hyperkit 0.4.3
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 +22 -0
- data/.rspec +1 -0
- data/CHANGELOG.md +20 -0
- data/Gemfile +14 -0
- data/LICENSE +9 -0
- data/README.md +221 -0
- data/Rakefile +22 -0
- data/lib/vagrant-hyperkit.rb +22 -0
- data/lib/vagrant-hyperkit/action.rb +195 -0
- data/lib/vagrant-hyperkit/action/boot.rb +185 -0
- data/lib/vagrant-hyperkit/action/import.rb +69 -0
- data/lib/vagrant-hyperkit/action/is_created.rb +18 -0
- data/lib/vagrant-hyperkit/action/is_stopped.rb +18 -0
- data/lib/vagrant-hyperkit/action/message_already_created.rb +16 -0
- data/lib/vagrant-hyperkit/action/message_not_created.rb +16 -0
- data/lib/vagrant-hyperkit/action/message_will_not_destroy.rb +16 -0
- data/lib/vagrant-hyperkit/action/read_ssh_info.rb +27 -0
- data/lib/vagrant-hyperkit/action/read_state.rb +53 -0
- data/lib/vagrant-hyperkit/action/stop_instance.rb +49 -0
- data/lib/vagrant-hyperkit/action/terminate_instance.rb +31 -0
- data/lib/vagrant-hyperkit/action/timed_provision.rb +21 -0
- data/lib/vagrant-hyperkit/action/wait_for_state.rb +41 -0
- data/lib/vagrant-hyperkit/config.rb +83 -0
- data/lib/vagrant-hyperkit/errors.rb +19 -0
- data/lib/vagrant-hyperkit/plugin.rb +73 -0
- data/lib/vagrant-hyperkit/provider.rb +67 -0
- data/lib/vagrant-hyperkit/util/timer.rb +17 -0
- data/lib/vagrant-hyperkit/util/vagrant-hyperkit.rb +79 -0
- data/lib/vagrant-hyperkit/version.rb +5 -0
- data/locales/en.yml +83 -0
- data/spec/spec_helper.rb +1 -0
- data/spec/vagrant-hyperkit/config_spec.rb +33 -0
- data/templates/metadata.json.erb +3 -0
- data/templates/vagrant-aws_package_Vagrantfile.erb +5 -0
- data/vagrant-hyperkit.gemspec +61 -0
- data/vendor/xhyve-ruby/.gitignore +8 -0
- data/vendor/xhyve-ruby/.travis.yml +10 -0
- data/vendor/xhyve-ruby/Gemfile +3 -0
- data/vendor/xhyve-ruby/README.md +33 -0
- data/vendor/xhyve-ruby/Rakefile +42 -0
- data/vendor/xhyve-ruby/example/test.rb +17 -0
- data/vendor/xhyve-ruby/lib/rubygems_plugin.rb +7 -0
- data/vendor/xhyve-ruby/lib/xhyve.rb +4 -0
- data/vendor/xhyve-ruby/lib/xhyve/dhcp.rb +54 -0
- data/vendor/xhyve-ruby/lib/xhyve/guest.rb +92 -0
- data/vendor/xhyve-ruby/lib/xhyve/vendor/xhyve +0 -0
- data/vendor/xhyve-ruby/lib/xhyve/version.rb +4 -0
- data/vendor/xhyve-ruby/spec/fixtures/dhcpd_leases.txt +42 -0
- data/vendor/xhyve-ruby/spec/fixtures/guest/README.md +33 -0
- data/vendor/xhyve-ruby/spec/fixtures/guest/initrd +0 -0
- data/vendor/xhyve-ruby/spec/fixtures/guest/vmlinuz +0 -0
- data/vendor/xhyve-ruby/spec/lib/dhcp_spec.rb +35 -0
- data/vendor/xhyve-ruby/spec/lib/guest_spec.rb +51 -0
- data/vendor/xhyve-ruby/spec/spec_helper.rb +52 -0
- data/vendor/xhyve-ruby/xhyve-ruby.gemspec +23 -0
- metadata +192 -0
@@ -0,0 +1,185 @@
|
|
1
|
+
require "log4r"
|
2
|
+
require 'json'
|
3
|
+
require 'securerandom'
|
4
|
+
|
5
|
+
require 'net/ssh'
|
6
|
+
require 'vagrant/util/retryable'
|
7
|
+
|
8
|
+
require 'vagrant-hyperkit/util/timer'
|
9
|
+
require 'vagrant-hyperkit/util/vagrant-hyperkit'
|
10
|
+
|
11
|
+
module VagrantPlugins
|
12
|
+
module HYPERKIT
|
13
|
+
module Action
|
14
|
+
# This runs the configured instance.
|
15
|
+
class Boot
|
16
|
+
include Vagrant::Util::Retryable
|
17
|
+
|
18
|
+
def initialize(app, env)
|
19
|
+
@app = app
|
20
|
+
end
|
21
|
+
|
22
|
+
def call(env)
|
23
|
+
env[:ui].info(" About to launch vm...")
|
24
|
+
# Initialize metrics if they haven't been
|
25
|
+
env[:metrics] ||= {}
|
26
|
+
|
27
|
+
machine_info_path = File.join(env[:machine].data_dir, "xhyve.json")
|
28
|
+
env[:ui].info("machine_info_path #{machine_info_path}")
|
29
|
+
if File.exist?(machine_info_path)
|
30
|
+
machine_json = File.read(machine_info_path)
|
31
|
+
machine_options = JSON.parse(machine_json, :symbolize_names => true)
|
32
|
+
log.debug "Machine Options: #{JSON.pretty_generate(machine_options)}"
|
33
|
+
machine_uuid = machine_options[:uuid]
|
34
|
+
pid = machine_options[:pid]
|
35
|
+
mac = machine_options[:mac]
|
36
|
+
else
|
37
|
+
machine_uuid = uuid(env)
|
38
|
+
end
|
39
|
+
|
40
|
+
guest_config = {
|
41
|
+
pid: pid,
|
42
|
+
mac: mac,
|
43
|
+
uuid: machine_uuid,
|
44
|
+
cmdline: kernel_command(env),
|
45
|
+
memory: memory(env),
|
46
|
+
processors: cpus(env),
|
47
|
+
binary: xhyve_binary(env),
|
48
|
+
}
|
49
|
+
|
50
|
+
xhyve_guest = start_guest(env, guest_config)
|
51
|
+
# Immediately save the ID since it is created at this point.
|
52
|
+
env[:machine].id = xhyve_guest.uuid
|
53
|
+
|
54
|
+
save_guest_status(env, xhyve_guest)
|
55
|
+
# Terminate the instance if we were interrupted
|
56
|
+
terminate(env) if env[:interrupted]
|
57
|
+
|
58
|
+
100.times do |i|
|
59
|
+
begin
|
60
|
+
ssh_try(xhyve_guest.ip, "accanto", "accanto")
|
61
|
+
rescue StandardError => e
|
62
|
+
env[:ui].error("SSL error: #{e.inspect}")
|
63
|
+
redo
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
@app.call(env)
|
68
|
+
end
|
69
|
+
|
70
|
+
def ssh_try(host, user, pass)
|
71
|
+
Net::SSH.start( host.to_s, user.to_s, :password => pass.to_s ) do |ssh|
|
72
|
+
ssh.exec!('date')
|
73
|
+
ssh.close
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def recover(env)
|
78
|
+
return if env["vagrant.error"].is_a?(Vagrant::Errors::VagrantError)
|
79
|
+
|
80
|
+
if env[:machine].provider.state.id != :not_created
|
81
|
+
# Undo the import
|
82
|
+
terminate(env)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def terminate(env)
|
87
|
+
destroy_env = env.dup
|
88
|
+
destroy_env.delete(:interrupted)
|
89
|
+
destroy_env[:config_validate] = false
|
90
|
+
destroy_env[:force_confirm_destroy] = true
|
91
|
+
env[:action_runner].run(Action.action_destroy, destroy_env)
|
92
|
+
end
|
93
|
+
|
94
|
+
private
|
95
|
+
|
96
|
+
def block_device_paths(base_path)
|
97
|
+
block_paths = Dir.glob File.join(base_path, "block*.{raw,img,qcow,qcow2}")
|
98
|
+
block_paths.sort
|
99
|
+
end
|
100
|
+
|
101
|
+
def kernel_file_path(base_path)
|
102
|
+
File.join(base_path, "vmlinuz")
|
103
|
+
end
|
104
|
+
|
105
|
+
def initrd_file_path(base_path)
|
106
|
+
File.join(base_path, "initrd.gz")
|
107
|
+
end
|
108
|
+
|
109
|
+
def memory(env)
|
110
|
+
provider_config(env).memory
|
111
|
+
end
|
112
|
+
|
113
|
+
def uuid(env)
|
114
|
+
provider_config(env).uuid
|
115
|
+
end
|
116
|
+
|
117
|
+
def cpus(env)
|
118
|
+
provider_config(env).cpus
|
119
|
+
end
|
120
|
+
|
121
|
+
def xhyve_binary(env)
|
122
|
+
provider_config(env).xhyve_binary
|
123
|
+
end
|
124
|
+
|
125
|
+
def kernel_command(env)
|
126
|
+
provider_config(env).kernel_command
|
127
|
+
end
|
128
|
+
|
129
|
+
def provider_config(env)
|
130
|
+
@provider_config ||= env[:machine].provider_config
|
131
|
+
end
|
132
|
+
|
133
|
+
def start_guest(env, config = {})
|
134
|
+
image_dir = File.join(env[:machine].data_dir, "image")
|
135
|
+
default_config = {
|
136
|
+
kernel: kernel_file_path(image_dir),
|
137
|
+
initrd: initrd_file_path(image_dir),
|
138
|
+
blockdevs: block_device_paths(image_dir),
|
139
|
+
serial: 'com1',
|
140
|
+
networking: true,
|
141
|
+
acpi: true
|
142
|
+
}
|
143
|
+
config = default_config.merge(config)
|
144
|
+
xhyve_guest = Util::XhyveGuest.new(config)
|
145
|
+
xhyve_guest.start
|
146
|
+
xhyve_guest
|
147
|
+
end
|
148
|
+
|
149
|
+
def save_guest_status(env, guest)
|
150
|
+
wait_for_guest_ip(env, guest)
|
151
|
+
machine_info_path = File.join(env[:machine].data_dir, "xhyve.json")
|
152
|
+
log.debug "xhyve configuration: #{JSON.pretty_generate(guest.options)}"
|
153
|
+
File.write(machine_info_path, guest.options().to_json)
|
154
|
+
log.info(" Launched xhyve VM with PID #{guest.pid}, MAC: #{guest.mac}, and IP #{guest.ip}")
|
155
|
+
end
|
156
|
+
|
157
|
+
def wait_for_guest_ip(env, guest)
|
158
|
+
network_ready_retries = 0
|
159
|
+
network_ready_retries_max = 3
|
160
|
+
update_xhyve_status(env, guest.options)
|
161
|
+
while guest.ip.nil?
|
162
|
+
break if env[:interrupted]
|
163
|
+
|
164
|
+
if network_ready_retries < network_ready_retries_max then
|
165
|
+
network_ready_retries += 1
|
166
|
+
env[:ui].info("Waiting for IP to be ready. Try #{network_ready_retries}/#{network_ready_retries_max}...")
|
167
|
+
else
|
168
|
+
raise 'Waited too long for IP to be ready. Your VM probably did not boot.'
|
169
|
+
end
|
170
|
+
sleep 0.5
|
171
|
+
end
|
172
|
+
update_xhyve_status(env, guest.options)
|
173
|
+
end
|
174
|
+
|
175
|
+
def update_xhyve_status(env, status)
|
176
|
+
env[:xhyve_status] = status
|
177
|
+
end
|
178
|
+
|
179
|
+
def log
|
180
|
+
@logger ||= Log4r::Logger.new("vagrant_hyperkit::action::boot")
|
181
|
+
end
|
182
|
+
end
|
183
|
+
end
|
184
|
+
end
|
185
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
require "log4r"
|
2
|
+
require "json"
|
3
|
+
require "fileutils"
|
4
|
+
|
5
|
+
module VagrantPlugins
|
6
|
+
module HYPERKIT
|
7
|
+
module Action
|
8
|
+
# This terminates the running instance.
|
9
|
+
class Import
|
10
|
+
def initialize(app, env)
|
11
|
+
@app = app
|
12
|
+
end
|
13
|
+
|
14
|
+
def call(env)
|
15
|
+
|
16
|
+
#TODO: Progress bar
|
17
|
+
env[:ui].info("Importing box...")
|
18
|
+
|
19
|
+
image_dir = File.join(env[:machine].data_dir, "image")
|
20
|
+
box_dir = env[:machine].box.directory
|
21
|
+
|
22
|
+
log.debug("Importing box from: #{box_dir}")
|
23
|
+
|
24
|
+
create_image_directory(image_dir)
|
25
|
+
copy_kernel_to(box_dir, image_dir)
|
26
|
+
copy_initrd_to(box_dir, image_dir)
|
27
|
+
copy_block_files_to(box_dir, image_dir)
|
28
|
+
env[:ui].info("Done importing box.")
|
29
|
+
|
30
|
+
@app.call(env)
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def copy_kernel_to(from, to)
|
36
|
+
copy_file(from, to, "vmlinuz")
|
37
|
+
end
|
38
|
+
|
39
|
+
def copy_initrd_to(from, to)
|
40
|
+
copy_file(from, to, "initrd.gz")
|
41
|
+
end
|
42
|
+
|
43
|
+
def copy_block_files_to(from, to)
|
44
|
+
block_glob = Dir.glob(File.join(from, "block*.{img,raw,qcow,qcow2}"))
|
45
|
+
log.debug("Copying #{block_glob} to #{to} ")
|
46
|
+
FileUtils.cp_r block_glob, to
|
47
|
+
end
|
48
|
+
|
49
|
+
def copy_file(from, to, filename)
|
50
|
+
from_box_file_path = File.join(from, filename)
|
51
|
+
to_image_file_path = File.join(to, filename)
|
52
|
+
|
53
|
+
unless File.exist? to_image_file_path
|
54
|
+
log.debug("Copying #{from_box_file_path} to #{to} ")
|
55
|
+
FileUtils.cp(from_box_file_path, to)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def create_image_directory(path)
|
60
|
+
FileUtils.mkdir_p(path)
|
61
|
+
end
|
62
|
+
|
63
|
+
def log
|
64
|
+
@logger ||= Log4r::Logger.new("vagrant_hyperkit::action::import")
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module VagrantPlugins
|
2
|
+
module HYPERKIT
|
3
|
+
module Action
|
4
|
+
# This can be used with "Call" built-in to check if the machine
|
5
|
+
# is created and branch in the middleware.
|
6
|
+
class IsCreated
|
7
|
+
def initialize(app, env)
|
8
|
+
@app = app
|
9
|
+
end
|
10
|
+
|
11
|
+
def call(env)
|
12
|
+
env[:result] = env[:machine].id != nil
|
13
|
+
@app.call(env)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module VagrantPlugins
|
2
|
+
module HYPERKIT
|
3
|
+
module Action
|
4
|
+
# This can be used with "Call" built-in to check if the machine
|
5
|
+
# is stopped and branch in the middleware.
|
6
|
+
class IsStopped
|
7
|
+
def initialize(app, env)
|
8
|
+
@app = app
|
9
|
+
end
|
10
|
+
|
11
|
+
def call(env)
|
12
|
+
env[:result] = env[:machine].state.id == :stopped
|
13
|
+
@app.call(env)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module VagrantPlugins
|
2
|
+
module HYPERKIT
|
3
|
+
module Action
|
4
|
+
class MessageAlreadyCreated
|
5
|
+
def initialize(app, env)
|
6
|
+
@app = app
|
7
|
+
end
|
8
|
+
|
9
|
+
def call(env)
|
10
|
+
env[:ui].info(I18n.t("vagrant_hyperkit.already_status", :status => "created"))
|
11
|
+
@app.call(env)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module VagrantPlugins
|
2
|
+
module HYPERKIT
|
3
|
+
module Action
|
4
|
+
class MessageNotCreated
|
5
|
+
def initialize(app, env)
|
6
|
+
@app = app
|
7
|
+
end
|
8
|
+
|
9
|
+
def call(env)
|
10
|
+
env[:ui].info(I18n.t("vagrant_hyperkit.not_created"))
|
11
|
+
@app.call(env)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module VagrantPlugins
|
2
|
+
module HYPERKIT
|
3
|
+
module Action
|
4
|
+
class MessageWillNotDestroy
|
5
|
+
def initialize(app, env)
|
6
|
+
@app = app
|
7
|
+
end
|
8
|
+
|
9
|
+
def call(env)
|
10
|
+
env[:ui].info(I18n.t("vagrant_hyperkit.will_not_destroy", name: env[:machine].name))
|
11
|
+
@app.call(env)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require "log4r"
|
2
|
+
require 'vagrant-hyperkit/util/vagrant-hyperkit'
|
3
|
+
|
4
|
+
module VagrantPlugins
|
5
|
+
module HYPERKIT
|
6
|
+
module Action
|
7
|
+
# This action reads the SSH info for the machine and puts it into the
|
8
|
+
# `:machine_ssh_info` key in the environment.
|
9
|
+
class ReadSSHInfo
|
10
|
+
def initialize(app, env)
|
11
|
+
@app = app
|
12
|
+
@logger = Log4r::Logger.new("vagrant_hyperkit::action::read_ssh_info")
|
13
|
+
end
|
14
|
+
|
15
|
+
def call(env)
|
16
|
+
env[:machine_ssh_info] = read_ssh_info(env)
|
17
|
+
@app.call(env)
|
18
|
+
end
|
19
|
+
|
20
|
+
def read_ssh_info(env)
|
21
|
+
xhyve_status = env[:xhyve_status]
|
22
|
+
return { :host => xhyve_status[:ip], :port => 22 }
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require "log4r"
|
2
|
+
|
3
|
+
module VagrantPlugins
|
4
|
+
module HYPERKIT
|
5
|
+
module Action
|
6
|
+
# This action reads the state of the machine and puts it in the
|
7
|
+
# `:machine_state_id` key in the environment.
|
8
|
+
class ReadState
|
9
|
+
def initialize(app, env)
|
10
|
+
@app = app
|
11
|
+
@env = env
|
12
|
+
@logger = Log4r::Logger.new("vagrant_hyperkit::action::read_state")
|
13
|
+
end
|
14
|
+
|
15
|
+
def call(env)
|
16
|
+
|
17
|
+
env[:machine_state_id] = read_state(env)
|
18
|
+
@app.call(env)
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def read_state(env)
|
24
|
+
xhyve_status = read_xhyve_status_file(env)
|
25
|
+
return :not_created if env[:machine].id.nil?
|
26
|
+
env[:xhyve_status] = xhyve_status
|
27
|
+
if process_alive(xhyve_status[:pid])
|
28
|
+
return :running
|
29
|
+
else
|
30
|
+
return :stopped
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def read_xhyve_status_file(env)
|
35
|
+
xhyve_status_file_path = File.join(env[:machine].data_dir, "xhyve.json")
|
36
|
+
return {} unless File.exist?(xhyve_status_file_path)
|
37
|
+
machine_json = File.read(xhyve_status_file_path)
|
38
|
+
JSON.parse(machine_json, :symbolize_names => true)
|
39
|
+
end
|
40
|
+
|
41
|
+
def process_alive(pid)
|
42
|
+
return false if pid.nil?
|
43
|
+
begin
|
44
|
+
Process.getpgid(pid.to_i)
|
45
|
+
true
|
46
|
+
rescue Errno::ESRCH
|
47
|
+
false
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require "log4r"
|
2
|
+
|
3
|
+
module VagrantPlugins
|
4
|
+
module HYPERKIT
|
5
|
+
module Action
|
6
|
+
# This stops the running instance.
|
7
|
+
class StopInstance
|
8
|
+
def initialize(app, env)
|
9
|
+
@app = app
|
10
|
+
@logger = Log4r::Logger.new("vagrant_hyperkit::action::stop_instance")
|
11
|
+
end
|
12
|
+
|
13
|
+
def call(env)
|
14
|
+
if is_process_alive? pid(env)
|
15
|
+
env[:ui].info(I18n.t("vagrant_hyperkit.stopping"))
|
16
|
+
kill_xhyve_process(env)
|
17
|
+
else
|
18
|
+
env[:ui].info(I18n.t("vagrant_hyperkit.already_status", status: env[:machine].state.id))
|
19
|
+
end
|
20
|
+
destroy_xhyve_status_file(env)
|
21
|
+
@app.call(env)
|
22
|
+
end
|
23
|
+
|
24
|
+
def is_process_alive?(pid)
|
25
|
+
return false if pid == 0
|
26
|
+
begin
|
27
|
+
Process.getpgid(pid)
|
28
|
+
true
|
29
|
+
rescue Errno::ESRCH
|
30
|
+
false
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def kill_xhyve_process(env)
|
35
|
+
Process.kill(15, pid(env))
|
36
|
+
end
|
37
|
+
|
38
|
+
def destroy_xhyve_status_file(env)
|
39
|
+
xhyve_status_file_path = File.join(env[:machine].data_dir, "xhyve.json")
|
40
|
+
FileUtils.remove_file(xhyve_status_file_path, force: true)
|
41
|
+
end
|
42
|
+
|
43
|
+
def pid(env)
|
44
|
+
@pid ||= env[:xhyve_status][:pid].to_i
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|