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.
Files changed (57) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +22 -0
  3. data/.rspec +1 -0
  4. data/CHANGELOG.md +20 -0
  5. data/Gemfile +14 -0
  6. data/LICENSE +9 -0
  7. data/README.md +221 -0
  8. data/Rakefile +22 -0
  9. data/lib/vagrant-hyperkit.rb +22 -0
  10. data/lib/vagrant-hyperkit/action.rb +195 -0
  11. data/lib/vagrant-hyperkit/action/boot.rb +185 -0
  12. data/lib/vagrant-hyperkit/action/import.rb +69 -0
  13. data/lib/vagrant-hyperkit/action/is_created.rb +18 -0
  14. data/lib/vagrant-hyperkit/action/is_stopped.rb +18 -0
  15. data/lib/vagrant-hyperkit/action/message_already_created.rb +16 -0
  16. data/lib/vagrant-hyperkit/action/message_not_created.rb +16 -0
  17. data/lib/vagrant-hyperkit/action/message_will_not_destroy.rb +16 -0
  18. data/lib/vagrant-hyperkit/action/read_ssh_info.rb +27 -0
  19. data/lib/vagrant-hyperkit/action/read_state.rb +53 -0
  20. data/lib/vagrant-hyperkit/action/stop_instance.rb +49 -0
  21. data/lib/vagrant-hyperkit/action/terminate_instance.rb +31 -0
  22. data/lib/vagrant-hyperkit/action/timed_provision.rb +21 -0
  23. data/lib/vagrant-hyperkit/action/wait_for_state.rb +41 -0
  24. data/lib/vagrant-hyperkit/config.rb +83 -0
  25. data/lib/vagrant-hyperkit/errors.rb +19 -0
  26. data/lib/vagrant-hyperkit/plugin.rb +73 -0
  27. data/lib/vagrant-hyperkit/provider.rb +67 -0
  28. data/lib/vagrant-hyperkit/util/timer.rb +17 -0
  29. data/lib/vagrant-hyperkit/util/vagrant-hyperkit.rb +79 -0
  30. data/lib/vagrant-hyperkit/version.rb +5 -0
  31. data/locales/en.yml +83 -0
  32. data/spec/spec_helper.rb +1 -0
  33. data/spec/vagrant-hyperkit/config_spec.rb +33 -0
  34. data/templates/metadata.json.erb +3 -0
  35. data/templates/vagrant-aws_package_Vagrantfile.erb +5 -0
  36. data/vagrant-hyperkit.gemspec +61 -0
  37. data/vendor/xhyve-ruby/.gitignore +8 -0
  38. data/vendor/xhyve-ruby/.travis.yml +10 -0
  39. data/vendor/xhyve-ruby/Gemfile +3 -0
  40. data/vendor/xhyve-ruby/README.md +33 -0
  41. data/vendor/xhyve-ruby/Rakefile +42 -0
  42. data/vendor/xhyve-ruby/example/test.rb +17 -0
  43. data/vendor/xhyve-ruby/lib/rubygems_plugin.rb +7 -0
  44. data/vendor/xhyve-ruby/lib/xhyve.rb +4 -0
  45. data/vendor/xhyve-ruby/lib/xhyve/dhcp.rb +54 -0
  46. data/vendor/xhyve-ruby/lib/xhyve/guest.rb +92 -0
  47. data/vendor/xhyve-ruby/lib/xhyve/vendor/xhyve +0 -0
  48. data/vendor/xhyve-ruby/lib/xhyve/version.rb +4 -0
  49. data/vendor/xhyve-ruby/spec/fixtures/dhcpd_leases.txt +42 -0
  50. data/vendor/xhyve-ruby/spec/fixtures/guest/README.md +33 -0
  51. data/vendor/xhyve-ruby/spec/fixtures/guest/initrd +0 -0
  52. data/vendor/xhyve-ruby/spec/fixtures/guest/vmlinuz +0 -0
  53. data/vendor/xhyve-ruby/spec/lib/dhcp_spec.rb +35 -0
  54. data/vendor/xhyve-ruby/spec/lib/guest_spec.rb +51 -0
  55. data/vendor/xhyve-ruby/spec/spec_helper.rb +52 -0
  56. data/vendor/xhyve-ruby/xhyve-ruby.gemspec +23 -0
  57. 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