vagrant-unbundled 2.2.9.0 → 2.2.10.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (148) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +60 -0
  3. data/README.md +5 -5
  4. data/contrib/README.md +1 -0
  5. data/contrib/sudoers/linux-suse +2 -2
  6. data/contrib/zsh/_vagrant +736 -0
  7. data/contrib/zsh/generate_zsh_completion.rb +166 -0
  8. data/lib/vagrant/action.rb +3 -0
  9. data/lib/vagrant/action/builder.rb +52 -18
  10. data/lib/vagrant/action/builtin/box_add.rb +6 -5
  11. data/lib/vagrant/action/builtin/cloud_init_setup.rb +127 -0
  12. data/lib/vagrant/action/builtin/cloud_init_wait.rb +30 -0
  13. data/lib/vagrant/action/builtin/handle_box.rb +1 -1
  14. data/lib/vagrant/action/builtin/handle_forwarded_port_collisions.rb +13 -13
  15. data/lib/vagrant/action/builtin/has_provisioner.rb +36 -0
  16. data/lib/vagrant/action/builtin/mixin_provisioners.rb +1 -0
  17. data/lib/vagrant/action/builtin/mixin_synced_folders.rb +20 -21
  18. data/lib/vagrant/action/builtin/set_hostname.rb +5 -1
  19. data/lib/vagrant/action/builtin/synced_folders.rb +10 -0
  20. data/lib/vagrant/action/builtin/trigger.rb +3 -2
  21. data/lib/vagrant/action/hook.rb +59 -24
  22. data/lib/vagrant/action/warden.rb +25 -5
  23. data/lib/vagrant/box.rb +5 -4
  24. data/lib/vagrant/bundler.rb +6 -1
  25. data/lib/vagrant/errors.rb +37 -1
  26. data/lib/vagrant/machine.rb +47 -0
  27. data/lib/vagrant/machine_index.rb +27 -1
  28. data/lib/vagrant/plugin/v2/command.rb +5 -1
  29. data/lib/vagrant/plugin/v2/components.rb +6 -0
  30. data/lib/vagrant/plugin/v2/manager.rb +14 -0
  31. data/lib/vagrant/plugin/v2/plugin.rb +12 -0
  32. data/lib/vagrant/plugin/v2/synced_folder.rb +50 -0
  33. data/lib/vagrant/plugin/v2/trigger.rb +6 -5
  34. data/lib/vagrant/ui.rb +1 -1
  35. data/lib/vagrant/util/ansi_escape_code_remover.rb +1 -1
  36. data/lib/vagrant/util/caps.rb +48 -0
  37. data/lib/vagrant/util/credential_scrubber.rb +1 -1
  38. data/lib/vagrant/util/directory.rb +19 -0
  39. data/lib/vagrant/util/downloader.rb +3 -3
  40. data/lib/vagrant/util/guest_hosts.rb +68 -0
  41. data/lib/vagrant/util/install_cli_autocomplete.rb +118 -0
  42. data/lib/vagrant/util/ipv4_interfaces.rb +15 -0
  43. data/lib/vagrant/util/is_port_open.rb +8 -19
  44. data/lib/vagrant/util/network_ip.rb +11 -1
  45. data/lib/vagrant/util/powershell.rb +1 -1
  46. data/lib/vagrant/util/subprocess.rb +9 -1
  47. data/lib/vagrant/vagrantfile.rb +1 -1
  48. data/plugins/commands/autocomplete/command/install.rb +49 -0
  49. data/plugins/commands/autocomplete/command/root.rb +64 -0
  50. data/plugins/commands/autocomplete/plugin.rb +18 -0
  51. data/plugins/commands/destroy/command.rb +6 -2
  52. data/plugins/communicators/ssh/communicator.rb +7 -1
  53. data/plugins/communicators/winrm/helper.rb +1 -1
  54. data/plugins/communicators/winssh/communicator.rb +1 -1
  55. data/plugins/guests/alpine/cap/change_host_name.rb +10 -11
  56. data/plugins/guests/alt/cap/change_host_name.rb +40 -53
  57. data/plugins/guests/arch/cap/change_host_name.rb +5 -14
  58. data/plugins/guests/arch/cap/configure_networks.rb +27 -10
  59. data/plugins/guests/atomic/cap/change_host_name.rb +5 -14
  60. data/plugins/guests/darwin/cap/change_host_name.rb +10 -6
  61. data/plugins/guests/debian/cap/change_host_name.rb +11 -11
  62. data/plugins/guests/esxi/cap/public_key.rb +3 -1
  63. data/plugins/guests/freebsd/cap/change_host_name.rb +10 -6
  64. data/plugins/guests/gentoo/cap/change_host_name.rb +14 -22
  65. data/plugins/guests/haiku/cap/rsync.rb +19 -0
  66. data/plugins/guests/haiku/plugin.rb +15 -0
  67. data/plugins/guests/linux/cap/change_host_name.rb +46 -0
  68. data/plugins/guests/linux/cap/mount_virtualbox_shared_folder.rb +4 -11
  69. data/plugins/guests/linux/cap/persist_mount_shared_folder.rb +62 -0
  70. data/plugins/guests/linux/plugin.rb +10 -0
  71. data/plugins/guests/omnios/cap/change_host_name.rb +10 -16
  72. data/plugins/guests/openbsd/cap/change_host_name.rb +10 -6
  73. data/plugins/guests/photon/cap/change_host_name.rb +9 -15
  74. data/plugins/guests/pld/cap/change_host_name.rb +11 -17
  75. data/plugins/guests/redhat/cap/change_host_name.rb +10 -5
  76. data/plugins/guests/slackware/cap/change_host_name.rb +11 -17
  77. data/plugins/guests/solaris11/plugin.rb +5 -0
  78. data/plugins/guests/suse/cap/change_host_name.rb +12 -11
  79. data/plugins/hosts/darwin/cap/fs_iso.rb +49 -0
  80. data/plugins/hosts/darwin/plugin.rb +10 -0
  81. data/plugins/hosts/linux/cap/fs_iso.rb +49 -0
  82. data/plugins/hosts/linux/cap/rdp.rb +1 -1
  83. data/plugins/hosts/linux/plugin.rb +10 -0
  84. data/plugins/hosts/windows/cap/fs_iso.rb +48 -0
  85. data/plugins/hosts/windows/cap/rdp.rb +1 -1
  86. data/plugins/hosts/windows/plugin.rb +15 -0
  87. data/plugins/kernel_v2/config/cloud_init.rb +126 -0
  88. data/plugins/kernel_v2/config/disk.rb +40 -18
  89. data/plugins/kernel_v2/config/vm.rb +122 -13
  90. data/plugins/kernel_v2/config/vm_provisioner.rb +13 -2
  91. data/plugins/kernel_v2/config/vm_trigger.rb +5 -1
  92. data/plugins/providers/docker/action.rb +8 -17
  93. data/plugins/providers/docker/action/forwarded_ports.rb +2 -0
  94. data/plugins/providers/docker/action/prepare_forwarded_port_collision_params.rb +61 -0
  95. data/plugins/providers/docker/cap/has_communicator.rb +11 -0
  96. data/plugins/providers/docker/communicator.rb +1 -1
  97. data/plugins/providers/docker/driver.rb +35 -0
  98. data/plugins/providers/docker/plugin.rb +5 -0
  99. data/plugins/providers/hyperv/action.rb +2 -0
  100. data/plugins/providers/hyperv/action/configure.rb +8 -0
  101. data/plugins/providers/hyperv/cap/cleanup_disks.rb +54 -0
  102. data/plugins/providers/hyperv/cap/configure_disks.rb +200 -0
  103. data/plugins/providers/hyperv/cap/validate_disk_ext.rb +34 -0
  104. data/plugins/providers/hyperv/config.rb +5 -0
  105. data/plugins/providers/hyperv/driver.rb +80 -0
  106. data/plugins/providers/hyperv/plugin.rb +25 -0
  107. data/plugins/providers/hyperv/scripts/attach_disk_drive.ps1 +28 -0
  108. data/plugins/providers/hyperv/scripts/dismount_vhd.ps1 +13 -0
  109. data/plugins/providers/hyperv/scripts/get_vhd.ps1 +16 -0
  110. data/plugins/providers/hyperv/scripts/get_vm_status.ps1 +1 -1
  111. data/plugins/providers/hyperv/scripts/list_hdds.ps1 +17 -0
  112. data/plugins/providers/hyperv/scripts/new_vhd.ps1 +31 -0
  113. data/plugins/providers/hyperv/scripts/remove_disk_drive.ps1 +25 -0
  114. data/plugins/providers/hyperv/scripts/resize_disk_drive.ps1 +18 -0
  115. data/plugins/providers/hyperv/scripts/set_enhanced_session_transport_type.ps1 +24 -0
  116. data/plugins/providers/hyperv/scripts/utils/VagrantVM/VagrantVM.psm1 +8 -0
  117. data/plugins/providers/virtualbox/action.rb +12 -1
  118. data/plugins/providers/virtualbox/action/forward_ports.rb +2 -2
  119. data/plugins/providers/virtualbox/cap/cleanup_disks.rb +40 -9
  120. data/plugins/providers/virtualbox/cap/configure_disks.rb +230 -77
  121. data/plugins/providers/virtualbox/cap/mount_options.rb +35 -0
  122. data/plugins/providers/virtualbox/cap/validate_disk_ext.rb +10 -3
  123. data/plugins/providers/virtualbox/driver/meta.rb +3 -0
  124. data/plugins/providers/virtualbox/driver/version_5_0.rb +96 -21
  125. data/plugins/providers/virtualbox/model/storage_controller.rb +135 -0
  126. data/plugins/providers/virtualbox/model/storage_controller_array.rb +100 -0
  127. data/plugins/providers/virtualbox/plugin.rb +18 -1
  128. data/plugins/providers/virtualbox/synced_folder.rb +1 -0
  129. data/plugins/provisioners/container/client.rb +1 -1
  130. data/plugins/provisioners/shell/provisioner.rb +15 -9
  131. data/plugins/synced_folders/nfs/synced_folder.rb +3 -1
  132. data/plugins/synced_folders/smb/cap/default_fstab_modification.rb +11 -0
  133. data/plugins/synced_folders/smb/cap/mount_options.rb +36 -0
  134. data/plugins/synced_folders/smb/plugin.rb +10 -0
  135. data/plugins/synced_folders/smb/synced_folder.rb +1 -1
  136. data/plugins/synced_folders/unix_mount_helpers.rb +14 -0
  137. data/templates/guests/arch/{network_dhcp.erb → default_network/network_dhcp.erb} +0 -0
  138. data/templates/guests/arch/{network_static.erb → default_network/network_static.erb} +0 -0
  139. data/templates/guests/arch/{network_static6.erb → default_network/network_static6.erb} +0 -0
  140. data/templates/guests/arch/systemd_networkd/network_dhcp.erb +6 -0
  141. data/templates/guests/arch/systemd_networkd/network_static.erb +9 -0
  142. data/templates/guests/arch/systemd_networkd/network_static6.erb +9 -0
  143. data/templates/guests/linux/etc_fstab.erb +6 -0
  144. data/templates/locales/en.yml +121 -11
  145. data/templates/locales/providers_docker.yml +4 -0
  146. data/vagrant.gemspec +8 -7
  147. data/version.txt +1 -1
  148. metadata +1492 -1309
@@ -114,7 +114,11 @@ module VagrantPlugins
114
114
 
115
115
  # Internal options
116
116
  @id = SecureRandom.uuid
117
- @command = command.to_s
117
+ if command.respond_to?(:to_sym)
118
+ @command = command.to_sym
119
+ else
120
+ @command = command
121
+ end
118
122
  @ruby_block = UNSET_VALUE
119
123
 
120
124
  @logger.debug("Trigger defined for: #{command}")
@@ -66,14 +66,8 @@ module VagrantPlugins
66
66
  next
67
67
  end
68
68
 
69
- b3.use Call, HasSSH do |env3, b4|
70
- if env3[:result]
71
- b4.use Provision
72
- else
73
- b4.use Message,
74
- I18n.t("docker_provider.messages.provision_no_ssh"),
75
- post: true
76
- end
69
+ b3.use Call, HasProvisioner do |env3, b4|
70
+ b4.use Provision
77
71
  end
78
72
  end
79
73
  end
@@ -216,14 +210,8 @@ module VagrantPlugins
216
210
  Vagrant::Action::Builder.new.tap do |b|
217
211
  b.use Call, IsState, :running do |env, b2|
218
212
  if env[:machine_action] != :run_command
219
- b2.use Call, HasSSH do |env2, b3|
220
- if env2[:result]
221
- b3.use Provision
222
- else
223
- b3.use Message,
224
- I18n.t("docker_provider.messages.provision_no_ssh"),
225
- post: true
226
- end
213
+ b2.use Call, HasProvisioner do |env2, b3|
214
+ b3.use Provision
227
215
  end
228
216
  end
229
217
 
@@ -251,14 +239,16 @@ module VagrantPlugins
251
239
  if env[:machine_action] != :run_command
252
240
  # If the container is NOT created yet, then do some setup steps
253
241
  # necessary for creating it.
242
+
254
243
  b2.use Call, IsState, :preparing do |env2, b3|
255
244
  if env2[:result]
256
245
  b3.use EnvSet, port_collision_repair: true
257
246
  b3.use HostMachinePortWarning
258
247
  b3.use HostMachinePortChecker
248
+ b3.use ForwardedPorts # This action converts the `ports` param into proper network configs
249
+ b3.use PrepareForwardedPortCollisionParams
259
250
  b3.use HandleForwardedPortCollisions
260
251
  b3.use SyncedFolders
261
- b3.use ForwardedPorts
262
252
  b3.use Pull
263
253
  b3.use Create
264
254
  b3.use WaitForRunning
@@ -313,6 +303,7 @@ module VagrantPlugins
313
303
  autoload :IsBuild, action_root.join("is_build")
314
304
  autoload :IsHostMachineCreated, action_root.join("is_host_machine_created")
315
305
  autoload :Login, action_root.join("login")
306
+ autoload :PrepareForwardedPortCollisionParams, action_root.join("prepare_forwarded_port_collision_params")
316
307
  autoload :PrepareNetworks, action_root.join("prepare_networks")
317
308
  autoload :PrepareNFSValidIds, action_root.join("prepare_nfs_valid_ids")
318
309
  autoload :PrepareNFSSettings, action_root.join("prepare_nfs_settings")
@@ -6,6 +6,8 @@ module VagrantPlugins
6
6
  @app = app
7
7
  end
8
8
 
9
+ # Converts the `ports` docker provider param into proper network configs
10
+ # of type :forwarded_port
9
11
  def call(env)
10
12
  env[:machine].provider_config.ports.each do |p|
11
13
  host_ip = nil
@@ -0,0 +1,61 @@
1
+ module VagrantPlugins
2
+ module DockerProvider
3
+ module Action
4
+ class PrepareForwardedPortCollisionParams
5
+ def initialize(app, env)
6
+ @app = app
7
+ end
8
+
9
+ def call(env)
10
+ machine = env[:machine]
11
+
12
+ # Get the forwarded ports used by other containers and
13
+ # consider those in use as well.
14
+ other_used_ports = machine.provider.driver.read_used_ports
15
+ env[:port_collision_extra_in_use] = other_used_ports
16
+
17
+ # Build the remap for any existing collision detections
18
+ #
19
+ # Note: This remap might not be required yet (as it is with the virtualbox provider)
20
+ # so for now we leave the remap hash empty.
21
+ remap = {}
22
+ env[:port_collision_remap] = remap
23
+
24
+ # This port checker method calls the custom port_check method
25
+ # defined below. If its false, it will go ahead and use the built-in
26
+ # port_check method to see if there are any live containers with bound
27
+ # ports
28
+ docker_port_check = proc { |host_ip, host_port|
29
+ result = port_check(env, host_port)
30
+ if !result
31
+ result = Vagrant::Action::Builtin::HandleForwardedPortCollisions.port_check(machine, host_ip, host_port)
32
+ end
33
+ result}
34
+ env[:port_collision_port_check] = docker_port_check
35
+
36
+ @app.call(env)
37
+ end
38
+
39
+ protected
40
+
41
+ # This check is required the docker provider. Containers
42
+ # can bind ports but be halted. We don't want new containers to
43
+ # grab these bound ports, so this check is here for that since
44
+ # the checks above won't detect it
45
+ #
46
+ # @param [Vagrant::Environment] env
47
+ # @param [String] host_port
48
+ # @returns [Bool]
49
+ def port_check(env, host_port)
50
+ extra_in_use = env[:port_collision_extra_in_use]
51
+
52
+ if extra_in_use
53
+ return extra_in_use.include?(host_port.to_s)
54
+ else
55
+ return false
56
+ end
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,11 @@
1
+ module VagrantPlugins
2
+ module DockerProvider
3
+ module Cap
4
+ module HasCommunicator
5
+ def self.has_communicator(machine)
6
+ return machine.provider_config.has_ssh
7
+ end
8
+ end
9
+ end
10
+ end
11
+ end
@@ -151,7 +151,7 @@ module VagrantPlugins
151
151
  "-i #{path}"
152
152
  end
153
153
 
154
- # Use ad-hoc SSH options for the hop on the docker proxy
154
+ # Use ad-hoc SSH options for the hop on the docker proxy
155
155
  if info[:forward_agent]
156
156
  ssh_args << "-o ForwardAgent=yes"
157
157
  end
@@ -126,6 +126,41 @@ module VagrantPlugins
126
126
  result =~ /^#{Regexp.escape(id)}$/
127
127
  end
128
128
 
129
+ # Reads all current docker containers and determines what ports
130
+ # are currently registered to be forwarded
131
+ # {2222=>#<Set: {"127.0.0.1"}>, 8080=>#<Set: {"*"}>, 9090=>#<Set: {"*"}>}
132
+ #
133
+ # Note: This is this format because of what the builtin action for resolving colliding
134
+ # port forwards expects.
135
+ #
136
+ # @return [Hash[Set]] used_ports - {forward_port: #<Set: {"host ip address"}>}
137
+ def read_used_ports
138
+ used_ports = Hash.new{|hash,key| hash[key] = Set.new}
139
+
140
+ all_containers.each do |c|
141
+ container_info = inspect_container(c)
142
+
143
+ if container_info["HostConfig"]["PortBindings"]
144
+ port_bindings = container_info["HostConfig"]["PortBindings"]
145
+ next if port_bindings.empty? # Nothing defined, but not nil either
146
+
147
+ port_bindings.each do |guest_port,host_mapping|
148
+ host_mapping.each do |h|
149
+ if h["HostIp"] == ""
150
+ hostip = "*"
151
+ else
152
+ hostip = h["HostIp"]
153
+ end
154
+ hostport = h["HostPort"]
155
+ used_ports[hostport].add(hostip)
156
+ end
157
+ end
158
+ end
159
+ end
160
+
161
+ used_ports
162
+ end
163
+
129
164
  def running?(cid)
130
165
  result = execute('docker', 'ps', '-q', '--no-trunc')
131
166
  result =~ /^#{Regexp.escape cid}$/m
@@ -67,6 +67,11 @@ module VagrantPlugins
67
67
  Cap::ProxyMachine
68
68
  end
69
69
 
70
+ provider_capability("docker", "has_communicator") do
71
+ require_relative "cap/has_communicator"
72
+ Cap::HasCommunicator
73
+ end
74
+
70
75
  protected
71
76
 
72
77
  def self.init!
@@ -149,6 +149,8 @@ module VagrantPlugins
149
149
  b3.use NetSetMac
150
150
  end
151
151
 
152
+ b3.use CleanupDisks
153
+ b3.use Disk
152
154
  b3.use StartInstance
153
155
  b3.use WaitForIPAddress
154
156
  b3.use WaitForCommunicator, [:running]
@@ -97,6 +97,14 @@ module VagrantPlugins
97
97
  env[:machine].provider_config.vm_integration_services)
98
98
  end
99
99
 
100
+ if env[:machine].provider_config.enable_enhanced_session_mode
101
+ env[:ui].detail(I18n.t("vagrant.hyperv_enable_enhanced_session"))
102
+ env[:machine].provider.driver.set_enhanced_session_transport_type("HvSocket")
103
+ else
104
+ env[:ui].detail(I18n.t("vagrant.hyperv_disable_enhanced_session"))
105
+ env[:machine].provider.driver.set_enhanced_session_transport_type("VMBus")
106
+ end
107
+
100
108
  @app.call(env)
101
109
  end
102
110
  end
@@ -0,0 +1,54 @@
1
+ require "log4r"
2
+ require "vagrant/util/experimental"
3
+
4
+ module VagrantPlugins
5
+ module HyperV
6
+ module Cap
7
+ module CleanupDisks
8
+ LOGGER = Log4r::Logger.new("vagrant::plugins::hyperv::cleanup_disks")
9
+
10
+ # @param [Vagrant::Machine] machine
11
+ # @param [VagrantPlugins::Kernel_V2::VagrantConfigDisk] defined_disks
12
+ # @param [Hash] disk_meta_file - A hash of all the previously defined disks from the last configure_disk action
13
+ def self.cleanup_disks(machine, defined_disks, disk_meta_file)
14
+ return if disk_meta_file.values.flatten.empty?
15
+
16
+ return if !Vagrant::Util::Experimental.feature_enabled?("disks")
17
+
18
+ handle_cleanup_disk(machine, defined_disks, disk_meta_file["disk"])
19
+ # TODO: Floppy and DVD disks
20
+ end
21
+
22
+ protected
23
+
24
+ # @param [Vagrant::Machine] machine
25
+ # @param [VagrantPlugins::Kernel_V2::VagrantConfigDisk] defined_disks
26
+ # @param [Hash] disk_meta - A hash of all the previously defined disks from the last configure_disk action
27
+ def self.handle_cleanup_disk(machine, defined_disks, disk_meta)
28
+ all_disks = machine.provider.driver.list_hdds
29
+
30
+ disk_meta.each do |d|
31
+ # look at Path instead of Name or UUID
32
+ disk_name = File.basename(d["Path"], '.*')
33
+ dsk = defined_disks.select { |dk| dk.name == disk_name }
34
+
35
+ if !dsk.empty? || d["primary"] == true
36
+ next
37
+ else
38
+ LOGGER.warn("Found disk not in Vagrantfile config: '#{d["Name"]}'. Removing disk from guest #{machine.name}")
39
+
40
+ machine.ui.warn(I18n.t("vagrant.cap.cleanup_disks.disk_cleanup", name: d["Name"]), prefix: true)
41
+
42
+ disk_actual = all_disks.select { |a| File.realdirpath(a["Path"]) == File.realdirpath(d["Path"]) }.first
43
+ if !disk_actual
44
+ machine.ui.warn(I18n.t("vagrant.cap.cleanup_disks.disk_not_found", name: d["Name"]), prefix: true)
45
+ else
46
+ machine.provider.driver.remove_disk(disk_actual["ControllerType"], disk_actual["ControllerNumber"], disk_actual["ControllerLocation"], disk_actual["Path"])
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,200 @@
1
+ require "log4r"
2
+ require "fileutils"
3
+ require "vagrant/util/numeric"
4
+ require "vagrant/util/experimental"
5
+
6
+ module VagrantPlugins
7
+ module HyperV
8
+ module Cap
9
+ module ConfigureDisks
10
+ LOGGER = Log4r::Logger.new("vagrant::plugins::hyperv::configure_disks")
11
+
12
+ # @param [Vagrant::Machine] machine
13
+ # @param [VagrantPlugins::Kernel_V2::VagrantConfigDisk] defined_disks
14
+ # @return [Hash] configured_disks - A hash of all the current configured disks
15
+ def self.configure_disks(machine, defined_disks)
16
+ return {} if defined_disks.empty?
17
+
18
+ return {} if !Vagrant::Util::Experimental.feature_enabled?("disks")
19
+
20
+ machine.ui.info(I18n.t("vagrant.cap.configure_disks.start"))
21
+
22
+ current_disks = machine.provider.driver.list_hdds
23
+
24
+ configured_disks = {disk: [], floppy: [], dvd: []}
25
+
26
+ defined_disks.each do |disk|
27
+ if disk.type == :disk
28
+ disk_data = handle_configure_disk(machine, disk, current_disks)
29
+ configured_disks[:disk] << disk_data unless disk_data.empty?
30
+ elsif disk.type == :floppy
31
+ # TODO: Write me
32
+ machine.ui.info(I18n.t("vagrant.cap.configure_disks.floppy_not_supported", name: disk.name))
33
+ elsif disk.type == :dvd
34
+ # TODO: Write me
35
+ machine.ui.info(I18n.t("vagrant.cap.configure_disks.dvd_not_supported", name: disk.name))
36
+ end
37
+ end
38
+
39
+ configured_disks
40
+ end
41
+
42
+ protected
43
+
44
+ # @param [Vagrant::Machine] machine - the current machine
45
+ # @param [Config::Disk] disk - the current disk to configure
46
+ # @param [Array] all_disks - A list of all currently defined disks in VirtualBox
47
+ # @return [Hash] current_disk - Returns the current disk. Returns nil if it doesn't exist
48
+ def self.get_current_disk(machine, disk, all_disks)
49
+ current_disk = nil
50
+ if disk.primary
51
+ # Ensure we grab the proper primary disk
52
+ # We can't rely on the order of `all_disks`, as they will not
53
+ # always come in port order, but primary should always be Location 0 Number 0.
54
+
55
+ current_disk = all_disks.detect { |d| d["ControllerLocation"] == 0 && d["ControllerNumber"] == 0 }
56
+
57
+ # Need to get actual disk info to obtain UUID instead of what's returned
58
+ #
59
+ # This is not required for newly created disks, as its metadata is
60
+ # set when creating and attaching the disk. This is only for the primary
61
+ # disk, since it already exists.
62
+ current_disk = machine.provider.driver.get_disk(current_disk["Path"])
63
+ else
64
+ # Hyper-V disk names aren't the actual names of the disk, so we have
65
+ # to grab the name from the file path instead
66
+ current_disk = all_disks.detect { |d| File.basename(d["Path"], '.*') == disk.name}
67
+ end
68
+
69
+ current_disk
70
+ end
71
+
72
+ # Handles all disk configs of type `:disk`
73
+ #
74
+ # @param [Vagrant::Machine] machine - the current machine
75
+ # @param [Config::Disk] disk - the current disk to configure
76
+ # @param [Array] all_disks - A list of all currently defined disks in VirtualBox
77
+ # @return [Hash] - disk_metadata
78
+ def self.handle_configure_disk(machine, disk, all_disks)
79
+ disk_metadata = {}
80
+
81
+ # Grab the existing configured disk, if it exists
82
+ current_disk = get_current_disk(machine, disk, all_disks)
83
+
84
+ # Configure current disk
85
+ if !current_disk
86
+ # create new disk and attach
87
+ disk_metadata = create_disk(machine, disk)
88
+ elsif compare_disk_size(machine, disk, current_disk)
89
+ disk_metadata = resize_disk(machine, disk, current_disk)
90
+ else
91
+ disk_metadata = {UUID: current_disk["DiskIdentifier"], Name: disk.name, Path: current_disk["Path"]}
92
+ if disk.primary
93
+ disk_metadata[:primary] = true
94
+ end
95
+ end
96
+
97
+ disk_metadata
98
+ end
99
+
100
+ # Check to see if current disk is configured based on defined_disks
101
+ #
102
+ # @param [Kernel_V2::VagrantConfigDisk] disk_config
103
+ # @param [Hash] defined_disk
104
+ # @return [Boolean]
105
+ def self.compare_disk_size(machine, disk_config, defined_disk)
106
+ # Hyper-V returns disk size in bytes
107
+ requested_disk_size = disk_config.size
108
+ disk_actual = machine.provider.driver.get_disk(defined_disk["Path"])
109
+ defined_disk_size = disk_actual["Size"]
110
+
111
+ if defined_disk_size > requested_disk_size
112
+ if File.extname(disk_actual["Path"]) == ".vhdx"
113
+ # VHDX formats can be shrunk
114
+ return true
115
+ else
116
+ machine.ui.warn(I18n.t("vagrant.cap.configure_disks.shrink_size_not_supported", name: disk_config.name))
117
+ return false
118
+ end
119
+ elsif defined_disk_size < requested_disk_size
120
+ return true
121
+ else
122
+ return false
123
+ end
124
+ end
125
+
126
+ # Creates and attaches a disk to a machine
127
+ #
128
+ # @param [Vagrant::Machine] machine
129
+ # @param [Kernel_V2::VagrantConfigDisk] disk_config
130
+ def self.create_disk(machine, disk_config)
131
+ machine.ui.detail(I18n.t("vagrant.cap.configure_disks.create_disk", name: disk_config.name))
132
+ disk_provider_config = {}
133
+
134
+ if disk_config.provider_config && disk_config.provider_config.key?(:hyperv)
135
+ disk_provider_config = disk_config.provider_config[:hyperv]
136
+ end
137
+
138
+ if !disk_provider_config.empty?
139
+ disk_provider_config = convert_size_vars!(disk_provider_config)
140
+ end
141
+
142
+ # Get the machines data dir, that will now be the path for the new disk
143
+ guest_disk_folder = machine.data_dir.join("Virtual Hard Disks")
144
+
145
+ if disk_config.file
146
+ disk_file = disk_config.file
147
+ LOGGER.info("Disk already defined by user at '#{disk_file}'. Using this disk instead of creating a new one...")
148
+ else
149
+ # Set the extension
150
+ disk_ext = disk_config.disk_ext
151
+ disk_file = File.join(guest_disk_folder, disk_config.name) + ".#{disk_ext}"
152
+
153
+ LOGGER.info("Attempting to create a new disk file '#{disk_file}' of size '#{disk_config.size}' bytes")
154
+
155
+ machine.provider.driver.create_disk(disk_file, disk_config.size, disk_provider_config)
156
+ end
157
+
158
+ disk_info = machine.provider.driver.get_disk(disk_file)
159
+ disk_metadata = {UUID: disk_info["DiskIdentifier"], Name: disk_config.name, Path: disk_info["Path"]}
160
+
161
+ machine.provider.driver.attach_disk(disk_file, disk_provider_config)
162
+
163
+ disk_metadata
164
+ end
165
+
166
+ # Converts any "shortcut" options such as "123MB" into its byte form. This
167
+ # is due to what parameter type is expected when calling the `New-VHD`
168
+ # powershell command
169
+ #
170
+ # @param [Hash] disk_provider_config
171
+ # @return [Hash] disk_provider_config
172
+ def self.convert_size_vars!(disk_provider_config)
173
+ if disk_provider_config.key?(:BlockSizeBytes)
174
+ bytes = Vagrant::Util::Numeric.string_to_bytes(disk_provider_config[:BlockSizeBytes])
175
+ disk_provider_config[:BlockSizeBytes] = bytes
176
+ end
177
+
178
+ disk_provider_config
179
+ end
180
+
181
+ # @param [Vagrant::Machine] machine
182
+ # @param [Config::Disk] disk_config - the current disk to configure
183
+ # @param [Hash] defined_disk - current disk as represented by VirtualBox
184
+ # @return [Hash] - disk_metadata
185
+ def self.resize_disk(machine, disk_config, defined_disk)
186
+ machine.ui.detail(I18n.t("vagrant.cap.configure_disks.resize_disk", name: disk_config.name), prefix: true)
187
+
188
+ machine.provider.driver.resize_disk(defined_disk["Path"], disk_config.size.to_i)
189
+
190
+ disk_info = machine.provider.driver.get_disk(defined_disk["Path"])
191
+
192
+ # Store updated metadata
193
+ disk_metadata = {UUID: disk_info["DiskIdentifier"], Name: disk_config.name, Path: disk_info["Path"]}
194
+
195
+ disk_metadata
196
+ end
197
+ end
198
+ end
199
+ end
200
+ end