vagrant-veertu 0.0.12

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 (60) hide show
  1. checksums.yaml +7 -0
  2. data/Gemfile +11 -0
  3. data/LICENSE.txt +22 -0
  4. data/README.md +31 -0
  5. data/Rakefile +5 -0
  6. data/lib/vagrant-veertu.rb +18 -0
  7. data/lib/vagrant-veertu/action.rb +330 -0
  8. data/lib/vagrant-veertu/action/boot.rb +21 -0
  9. data/lib/vagrant-veertu/action/check_accessible.rb +22 -0
  10. data/lib/vagrant-veertu/action/check_created.rb +21 -0
  11. data/lib/vagrant-veertu/action/check_running.rb +21 -0
  12. data/lib/vagrant-veertu/action/check_veertu.rb +22 -0
  13. data/lib/vagrant-veertu/action/clear_forwarded_ports.rb +20 -0
  14. data/lib/vagrant-veertu/action/clear_network_interfaces.rb +31 -0
  15. data/lib/vagrant-veertu/action/created.rb +20 -0
  16. data/lib/vagrant-veertu/action/customize.rb +44 -0
  17. data/lib/vagrant-veertu/action/destroy.rb +19 -0
  18. data/lib/vagrant-veertu/action/discard_state.rb +20 -0
  19. data/lib/vagrant-veertu/action/export.rb +41 -0
  20. data/lib/vagrant-veertu/action/forced_halt.rb +25 -0
  21. data/lib/vagrant-veertu/action/forward_ports.rb +91 -0
  22. data/lib/vagrant-veertu/action/import.rb +96 -0
  23. data/lib/vagrant-veertu/action/is_paused.rb +20 -0
  24. data/lib/vagrant-veertu/action/is_running.rb +20 -0
  25. data/lib/vagrant-veertu/action/is_saved.rb +20 -0
  26. data/lib/vagrant-veertu/action/message_already_running.rb +16 -0
  27. data/lib/vagrant-veertu/action/message_not_created.rb +16 -0
  28. data/lib/vagrant-veertu/action/message_not_running.rb +16 -0
  29. data/lib/vagrant-veertu/action/message_will_not_destroy.rb +17 -0
  30. data/lib/vagrant-veertu/action/network.rb +556 -0
  31. data/lib/vagrant-veertu/action/network_fix_ipv6.rb +81 -0
  32. data/lib/vagrant-veertu/action/package.rb +44 -0
  33. data/lib/vagrant-veertu/action/package_vagrantfile.rb +33 -0
  34. data/lib/vagrant-veertu/action/prepare_forwarded_port_collision_params.rb +35 -0
  35. data/lib/vagrant-veertu/action/prepare_nfs_settings.rb +119 -0
  36. data/lib/vagrant-veertu/action/prepare_nfs_valid_ids.rb +17 -0
  37. data/lib/vagrant-veertu/action/resume.rb +21 -0
  38. data/lib/vagrant-veertu/action/sane_defaults.rb +89 -0
  39. data/lib/vagrant-veertu/action/set_name.rb +55 -0
  40. data/lib/vagrant-veertu/action/setup_package_files.rb +51 -0
  41. data/lib/vagrant-veertu/action/snapshot_delete.rb +32 -0
  42. data/lib/vagrant-veertu/action/snapshot_restore.rb +28 -0
  43. data/lib/vagrant-veertu/action/snapshot_save.rb +25 -0
  44. data/lib/vagrant-veertu/action/suspend.rb +20 -0
  45. data/lib/vagrant-veertu/cap.rb +23 -0
  46. data/lib/vagrant-veertu/cap/public_address.rb +15 -0
  47. data/lib/vagrant-veertu/config.rb +199 -0
  48. data/lib/vagrant-veertu/driver/base.rb +240 -0
  49. data/lib/vagrant-veertu/driver/meta.rb +143 -0
  50. data/lib/vagrant-veertu/driver/version_5_0.rb +284 -0
  51. data/lib/vagrant-veertu/errors.rb +18 -0
  52. data/lib/vagrant-veertu/model/forwarded_port.rb +70 -0
  53. data/lib/vagrant-veertu/plugin.rb +76 -0
  54. data/lib/vagrant-veertu/provider.rb +121 -0
  55. data/lib/vagrant-veertu/synced_folder.rb +120 -0
  56. data/lib/vagrant-veertu/util/compile_forwarded_ports.rb +35 -0
  57. data/lib/vagrant-veertu/version.rb +5 -0
  58. data/locales/en.yml +19 -0
  59. data/vagrant-veertu.gemspec +22 -0
  60. metadata +130 -0
@@ -0,0 +1,81 @@
1
+ require "ipaddr"
2
+ require "socket"
3
+
4
+ require "log4r"
5
+
6
+ require "vagrant/util/presence"
7
+ require "vagrant/util/scoped_hash_override"
8
+
9
+ module VagrantPlugins
10
+ module ProviderVeertu
11
+ module Action
12
+ # This middleware works around a bug in VirtualBox where booting
13
+ # a VM with an IPv6 host-only network will someties lose the
14
+ # route to that machine.
15
+ class NetworkFixIPv6
16
+ include Vagrant::Util::Presence
17
+ include Vagrant::Util::ScopedHashOverride
18
+
19
+ def initialize(app, env)
20
+ @logger = Log4r::Logger.new("vagrant::plugins::veertu::network")
21
+ @app = app
22
+ end
23
+
24
+ def call(env)
25
+ @env = env
26
+
27
+ # Determine if we have an IPv6 network
28
+ has_v6 = false
29
+ env[:machine].config.vm.networks.each do |type, options|
30
+ next if type != :private_network
31
+ options = scoped_hash_override(options, :veertu)
32
+ next if options[:ip].to_s.strip == ""
33
+
34
+ if IPAddr.new(options[:ip]).ipv6?
35
+ has_v6 = true
36
+ break
37
+ end
38
+ end
39
+
40
+ # Call up
41
+ @app.call(env)
42
+
43
+ # If we have no IPv6, forget it
44
+ return if !has_v6
45
+
46
+ host_only_interfaces(env).each do |interface|
47
+ next if !present?(interface[:ipv6])
48
+ next if interface[:status] != "Up"
49
+
50
+ ip = IPAddr.new(interface[:ipv6])
51
+ ip |= ("1" * (128 - interface[:ipv6_prefix].to_i)).to_i(2)
52
+
53
+ @logger.info("testing IPv6: #{ip}")
54
+
55
+ begin
56
+ UDPSocket.new(Socket::AF_INET6).connect(ip.to_s, 80)
57
+ rescue Errno::EHOSTUNREACH
58
+ @logger.info("IPv6 host unreachable. Fixing: #{ip}")
59
+ env[:machine].provider.driver.reconfig_host_only(interface)
60
+ end
61
+ end
62
+ end
63
+
64
+ # The list of interface names for host-only adapters.
65
+ # @return [Array<String>]
66
+ def host_only_interface_names(env)
67
+ env[:machine].provider.driver.read_network_interfaces
68
+ .map { |_, i| i[:hostonly] if i[:type] == :hostonly }.compact
69
+ end
70
+
71
+ # The list of host_only_interfaces that are tied to a host-only adapter.
72
+ # @return [Array]
73
+ def host_only_interfaces(env)
74
+ iface_names = self.host_only_interface_names(env)
75
+ env[:machine].provider.driver.read_host_only_interfaces
76
+ .select { |interface| iface_names.include?(interface[:name]) }
77
+ end
78
+ end
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,44 @@
1
+ require 'fileutils'
2
+
3
+ require 'vagrant/action/general/package'
4
+
5
+ module VagrantPlugins
6
+ module ProviderVeertu
7
+ module Action
8
+ class Package < Vagrant::Action::General::Package
9
+ # Doing this so that we can test that the parent is properly
10
+ # called in the unit tests.
11
+ alias_method :general_call, :call
12
+ def call(env)
13
+ # Setup the temporary directory
14
+ @temp_dir = env[:tmp_path].join(Time.now.to_i.to_s)
15
+ env["export.temp_dir"] = @temp_dir
16
+ FileUtils.mkpath(env["export.temp_dir"])
17
+
18
+ # Just match up a couple environmental variables so that
19
+ # the superclass will do the right thing. Then, call the
20
+ # superclass
21
+ env["package.directory"] = env["export.temp_dir"]
22
+
23
+ general_call(env)
24
+
25
+ # Always call recover to clean up the temp dir
26
+ clean_temp_dir
27
+ end
28
+
29
+ def recover(env)
30
+ clean_temp_dir
31
+ super
32
+ end
33
+
34
+ protected
35
+
36
+ def clean_temp_dir
37
+ if @temp_dir && File.exist?(@temp_dir)
38
+ FileUtils.rm_rf(@temp_dir)
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,33 @@
1
+ require 'vagrant/util/template_renderer'
2
+
3
+ module VagrantPlugins
4
+ module ProviderVeertu
5
+ module Action
6
+ class PackageVagrantfile
7
+ # For TemplateRenderer
8
+ include Vagrant::Util
9
+
10
+ def initialize(app, env)
11
+ @app = app
12
+ end
13
+
14
+ def call(env)
15
+ @env = env
16
+ create_vagrantfile
17
+ @app.call(env)
18
+ end
19
+
20
+ # This method creates the auto-generated Vagrantfile at the root of the
21
+ # box. This Vagrantfile contains the MAC address so that the user doesn't
22
+ # have to worry about it.
23
+ def create_vagrantfile
24
+ File.open(File.join(@env["export.temp_dir"], "Vagrantfile"), "w") do |f|
25
+ f.write(TemplateRenderer.render("package_Vagrantfile", {
26
+ base_mac: @env[:machine].provider.driver.read_mac_address
27
+ }))
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,35 @@
1
+ module VagrantPlugins
2
+ module ProviderVeertu
3
+ module Action
4
+ class PrepareForwardedPortCollisionParams
5
+ def initialize(app, env)
6
+ @app = app
7
+ end
8
+
9
+ def call(env)
10
+ # Get the forwarded ports used by other virtual machines and
11
+ # consider those in use as well.
12
+ env[:port_collision_extra_in_use] = env[:machine].provider.driver.read_used_ports
13
+
14
+ # Build the remap for any existing collision detections
15
+ remap = {}
16
+ env[:port_collision_remap] = remap
17
+ env[:machine].provider.driver.read_forwarded_ports.each do |_nic, name, hostport, _guestport|
18
+ env[:machine].config.vm.networks.each do |type, options|
19
+ next if type != :forwarded_port
20
+
21
+ # If the ID matches the name of the forwarded port, then
22
+ # remap.
23
+ if options[:id] == name
24
+ remap[options[:host]] = hostport
25
+ break
26
+ end
27
+ end
28
+ end
29
+
30
+ @app.call(env)
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,119 @@
1
+ require "vagrant/action/builtin/mixin_synced_folders"
2
+
3
+ module VagrantPlugins
4
+ module ProviderVeertu
5
+ module Action
6
+ class PrepareNFSSettings
7
+ include Vagrant::Action::Builtin::MixinSyncedFolders
8
+ include Vagrant::Util::Retryable
9
+
10
+ def initialize(app, env)
11
+ @app = app
12
+ @logger = Log4r::Logger.new("vagrant::action::vm::nfs")
13
+ end
14
+
15
+ def call(env)
16
+ @machine = env[:machine]
17
+
18
+ @app.call(env)
19
+
20
+ opts = {
21
+ cached: !!env[:synced_folders_cached],
22
+ config: env[:synced_folders_config],
23
+ disable_usable_check: !!env[:test],
24
+ }
25
+ folders = synced_folders(env[:machine], **opts)
26
+
27
+ if folders.key?(:nfs)
28
+ @logger.info("Using NFS, preparing NFS settings by reading host IP and machine IP")
29
+ add_ips_to_env!(env)
30
+ end
31
+ end
32
+
33
+ # Extracts the proper host and guest IPs for NFS mounts and stores them
34
+ # in the environment for the SyncedFolder action to use them in
35
+ # mounting.
36
+ #
37
+ # The ! indicates that this method modifies its argument.
38
+ def add_ips_to_env!(env)
39
+ adapter, host_ip = find_host_only_adapter
40
+ machine_ip = read_static_machine_ips || read_dynamic_machine_ip(adapter)
41
+
42
+ raise Vagrant::Errors::NFSNoHostonlyNetwork if !host_ip || !machine_ip
43
+
44
+ env[:nfs_host_ip] = host_ip
45
+ env[:nfs_machine_ip] = machine_ip
46
+ end
47
+
48
+ # Finds first host only network adapter and returns its adapter number
49
+ # and IP address
50
+ #
51
+ # @return [Integer, String] adapter number, ip address of found host-only adapter
52
+ def find_host_only_adapter
53
+ @machine.provider.driver.read_network_interfaces.each do |adapter, opts|
54
+ if opts[:type] == :hostonly
55
+ @machine.provider.driver.read_host_only_interfaces.each do |interface|
56
+ if interface[:name] == opts[:hostonly]
57
+ return adapter, interface[:ip]
58
+ end
59
+ end
60
+ end
61
+ end
62
+
63
+ nil
64
+ end
65
+
66
+ # Returns the IP address(es) of the guest by looking for static IPs
67
+ # given to host only adapters in the Vagrantfile
68
+ #
69
+ # @return [Array]<String> Configured static IPs
70
+ def read_static_machine_ips
71
+ ips = []
72
+ @machine.config.vm.networks.each do |type, options|
73
+ if type == :private_network && options[:type] != :dhcp && options[:ip].is_a?(String)
74
+ ips << options[:ip]
75
+ end
76
+ end
77
+
78
+ if ips.empty?
79
+ return nil
80
+ end
81
+
82
+ ips
83
+ end
84
+
85
+ # Returns the IP address of the guest by looking at vbox guest property
86
+ # for the appropriate guest adapter.
87
+ #
88
+ # For DHCP interfaces, the guest property will not be present until the
89
+ # guest completes
90
+ #
91
+ # @param [Integer] adapter number to read IP for
92
+ # @return [String] ip address of adapter
93
+ def read_dynamic_machine_ip(adapter)
94
+ return nil unless adapter
95
+
96
+ # vbox guest properties are 0-indexed, while showvminfo network
97
+ # interfaces are 1-indexed. go figure.
98
+ guestproperty_adapter = adapter - 1
99
+
100
+ # we need to wait for the guest's IP to show up as a guest property.
101
+ # retry thresholds are relatively high since we might need to wait
102
+ # for DHCP, but even static IPs can take a second or two to appear.
103
+ retryable(retry_options.merge(on: Vagrant::Errors::VirtualBoxGuestPropertyNotFound)) do
104
+ @machine.provider.driver.read_guest_ip(guestproperty_adapter)
105
+ end
106
+ rescue Vagrant::Errors::VirtualBoxGuestPropertyNotFound
107
+ # this error is more specific with a better error message directing
108
+ # the user towards the fact that it's probably a reportable bug
109
+ raise Vagrant::Errors::NFSNoGuestIP
110
+ end
111
+
112
+ # Separating these out so we can stub out the sleep in tests
113
+ def retry_options
114
+ {tries: 15, sleep: 1}
115
+ end
116
+ end
117
+ end
118
+ end
119
+ end
@@ -0,0 +1,17 @@
1
+ module VagrantPlugins
2
+ module ProviderVeertu
3
+ module Action
4
+ class PrepareNFSValidIds
5
+ def initialize(app, env)
6
+ @app = app
7
+ @logger = Log4r::Logger.new("vagrant::action::vm::nfs")
8
+ end
9
+
10
+ def call(env)
11
+ env[:nfs_valid_ids] = env[:machine].provider.driver.read_vms.values
12
+ @app.call(env)
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,21 @@
1
+ module VagrantPlugins
2
+ module ProviderVeertu
3
+ module Action
4
+ class Resume
5
+ def initialize(app, env)
6
+ @app = app
7
+ end
8
+
9
+ def call(env)
10
+ current_state = env[:machine].state.id
11
+
12
+ if current_state == :paused or current_state == :stopped
13
+ env[:ui].info I18n.t("vagrant.actions.vm.resume.resuming")
14
+ env[:machine].provider.driver.resume
15
+ end
16
+ @app.call(env)
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,89 @@
1
+ require "log4r"
2
+
3
+ module VagrantPlugins
4
+ module ProviderVeertu
5
+ module Action
6
+ class SaneDefaults
7
+ def initialize(app, env)
8
+ @logger = Log4r::Logger.new("vagrant::action::vm::sanedefaults")
9
+ @app = app
10
+ end
11
+
12
+ def call(env)
13
+ # Set the env on an instance variable so we can access it in
14
+ # helpers.
15
+ @env = env
16
+
17
+ # Use rtcuseutc so that the VM sees UTC time.
18
+ #command = ["modifyvm", env[:machine].id, "--rtcuseutc", "on"]
19
+ #attempt_and_log(command, "Enabling rtcuseutc...")
20
+
21
+ if env[:machine].provider_config.auto_nat_dns_proxy
22
+ @logger.info("Automatically figuring out whether to enable/disable NAT DNS proxy...")
23
+
24
+ # Enable/disable the NAT DNS proxy as necessary
25
+ #if enable_dns_proxy?
26
+ # #command = ["modifyvm", env[:machine].id, "--natdnsproxy1", "on"]
27
+ # #attempt_and_log(command, "Enable the NAT DNS proxy on adapter 1...")
28
+ #else
29
+ # command = ["modifyvm", env[:machine].id, "--natdnsproxy1", "off" ]
30
+ # attempt_and_log(command, "Disable the NAT DNS proxy on adapter 1...")
31
+ # command = ["modifyvm", env[:machine].id, "--natdnshostresolver1", "off" ]
32
+ # attempt_and_log(command, "Disable the NAT DNS resolver on adapter 1...")
33
+ #end
34
+ else
35
+ @logger.info("NOT trying to automatically manage NAT DNS proxy.")
36
+ end
37
+
38
+ @app.call(env)
39
+ end
40
+
41
+ protected
42
+
43
+ # This is just a helper method that executes a single command, logs
44
+ # the given string to the log, and also includes the exit status in
45
+ # the log message.
46
+ #
47
+ # We assume every command is idempotent and pass along the `retryable`
48
+ # flag. This is because VeertuManage is janky about running simultaneously
49
+ # on the same box, and if we up multiple boxes at the same time, a bunch
50
+ # of modifyvm commands get fired
51
+ #
52
+ # @param [Array] command Command to run
53
+ # @param [String] log Log message to write.
54
+ def attempt_and_log(command, log)
55
+ begin
56
+ @env[:machine].provider.driver.execute_command(
57
+ command + [retryable: true])
58
+ rescue Vagrant::Errors::VBoxManageError => e
59
+ @logger.info("#{log} (error = #{e.inspect})")
60
+ end
61
+ end
62
+
63
+ # This uses some heuristics to determine if the NAT DNS proxy should
64
+ # be enabled or disabled. See the comments within the function body
65
+ # itself to see the checks it does.
66
+ #
67
+ # @return [Boolean]
68
+ def enable_dns_proxy?
69
+ begin
70
+ contents = File.read("/etc/resolv.conf")
71
+
72
+ if contents =~ /^nameserver 127\.0\.(0|1)\.1$/
73
+ # The use of both natdnsproxy and natdnshostresolver break on
74
+ # Ubuntu 12.04 and 12.10 that uses resolvconf with localhost. When used
75
+ # VirtualBox will give the client dns server 10.0.2.3, while
76
+ # not binding to that address itself. Therefore disable this
77
+ # feature if host uses the resolvconf server 127.0.0.1 or
78
+ # 127.0.1.1
79
+ @logger.info("Disabling DNS proxy since resolv.conf contains 127.0.0.1 or 127.0.1.1")
80
+ return false
81
+ end
82
+ rescue Errno::ENOENT; end
83
+
84
+ return true
85
+ end
86
+ end
87
+ end
88
+ end
89
+ end