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
@@ -16,38 +16,69 @@ module VagrantPlugins
16
16
  return if !Vagrant::Util::Experimental.feature_enabled?("disks")
17
17
 
18
18
  handle_cleanup_disk(machine, defined_disks, disk_meta_file["disk"])
19
- # TODO: Floppy and DVD disks
19
+ handle_cleanup_dvd(machine, defined_disks, disk_meta_file["dvd"])
20
+ # TODO: Floppy disks
20
21
  end
21
22
 
22
23
  protected
23
24
 
24
25
  # @param [Vagrant::Machine] machine
25
26
  # @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
+ # @param [Array<Hash>] disk_meta - An array of all the previously defined disks from the last configure_disk action
27
28
  def self.handle_cleanup_disk(machine, defined_disks, disk_meta)
28
- vm_info = machine.provider.driver.show_vm_info
29
- primary_disk = vm_info["SATA Controller-ImageUUID-0-0"]
29
+ raise TypeError, "Expected `Array` but received `#{disk_meta.class}`" if !disk_meta.is_a?(Array)
30
+ storage_controllers = machine.provider.driver.read_storage_controllers
31
+
32
+ primary = storage_controllers.get_primary_attachment
33
+ primary_uuid = primary[:uuid]
30
34
 
31
35
  disk_meta.each do |d|
32
36
  dsk = defined_disks.select { |dk| dk.name == d["name"] }
33
- if !dsk.empty? || d["uuid"] == primary_disk
37
+ if !dsk.empty? || d["uuid"] == primary_uuid
34
38
  next
35
39
  else
36
40
  LOGGER.warn("Found disk not in Vagrantfile config: '#{d["name"]}'. Removing disk from guest #{machine.name}")
37
- disk_info = machine.provider.driver.get_port_and_device(d["uuid"])
41
+ machine.ui.warn(I18n.t("vagrant.cap.cleanup_disks.disk_cleanup", name: d["name"]), prefix: true)
38
42
 
39
- machine.ui.warn("Disk '#{d["name"]}' no longer exists in Vagrant config. Removing and closing medium from guest...", prefix: true)
43
+ controller = storage_controllers.get_controller(d["controller"])
44
+ attachment = controller.get_attachment(uuid: d["uuid"])
40
45
 
41
- if disk_info.empty?
46
+ if !attachment
42
47
  LOGGER.warn("Disk '#{d["name"]}' not attached to guest, but still exists.")
43
48
  else
44
- machine.provider.driver.remove_disk(disk_info[:port], disk_info[:device])
49
+ machine.provider.driver.remove_disk(controller.name, attachment[:port], attachment[:device])
45
50
  end
46
51
 
47
52
  machine.provider.driver.close_medium(d["uuid"])
48
53
  end
49
54
  end
50
55
  end
56
+
57
+ # @param [Vagrant::Machine] machine
58
+ # @param [VagrantPlugins::Kernel_V2::VagrantConfigDisk] defined_dvds
59
+ # @param [Array<Hash>] dvd_meta - An array of all the previously defined dvds from the last configure_disk action
60
+ def self.handle_cleanup_dvd(machine, defined_dvds, dvd_meta)
61
+ raise TypeError, "Expected `Array` but received `#{dvd_meta.class}`" if !dvd_meta.is_a?(Array)
62
+ dvd_meta.each do |d|
63
+ dsk = defined_dvds.select { |dk| dk.name == d["name"] }
64
+ if !dsk.empty?
65
+ next
66
+ else
67
+ LOGGER.warn("Found dvd not in Vagrantfile config: '#{d["name"]}'. Removing dvd from guest #{machine.name}")
68
+ machine.ui.warn("DVD '#{d["name"]}' no longer exists in Vagrant config. Removing medium from guest...", prefix: true)
69
+
70
+ storage_controllers = machine.provider.driver.read_storage_controllers
71
+ controller = storage_controllers.get_controller(d["controller"])
72
+ attachment = controller.get_attachment(uuid: d["uuid"])
73
+
74
+ if !attachment
75
+ LOGGER.warn("DVD '#{d["name"]}' not attached to guest, but still exists.")
76
+ else
77
+ machine.provider.driver.remove_disk(controller.name, attachment[:port], attachment[:device])
78
+ end
79
+ end
80
+ end
81
+ end
51
82
  end
52
83
  end
53
84
  end
@@ -9,9 +9,6 @@ module VagrantPlugins
9
9
  module ConfigureDisks
10
10
  LOGGER = Log4r::Logger.new("vagrant::plugins::virtualbox::configure_disks")
11
11
 
12
- # The max amount of disks that can be attached to a single device in a controller
13
- MAX_DISK_NUMBER = 30.freeze
14
-
15
12
  # @param [Vagrant::Machine] machine
16
13
  # @param [VagrantPlugins::Kernel_V2::VagrantConfigDisk] defined_disks
17
14
  # @return [Hash] configured_disks - A hash of all the current configured disks
@@ -20,27 +17,66 @@ module VagrantPlugins
20
17
 
21
18
  return {} if !Vagrant::Util::Experimental.feature_enabled?("disks")
22
19
 
23
- if defined_disks.size > MAX_DISK_NUMBER
24
- # you can only attach up to 30 disks per controller, INCLUDING the primary disk
25
- raise Vagrant::Errors::VirtualBoxDisksDefinedExceedLimit
26
- end
27
-
28
20
  machine.ui.info(I18n.t("vagrant.cap.configure_disks.start"))
29
21
 
30
- current_disks = machine.provider.driver.list_hdds
22
+ storage_controllers = machine.provider.driver.read_storage_controllers
23
+
24
+ # Check to determine which controller we should attach disks to.
25
+ # If there is only one storage controller attached to the VM, use
26
+ # it. If there are multiple controllers (e.g. IDE/SATA), attach DVDs
27
+ # to the IDE controller and disks to the SATA controller.
28
+ if storage_controllers.size == 1
29
+ controller = storage_controllers.first
30
+
31
+ # The only way you can define up to the controller limit is if
32
+ # exactly one disk is a primary disk, otherwise we need to reserve
33
+ # a slot for the primary
34
+ if (defined_disks.any? { |d| d.primary } && defined_disks.size > controller.limit) ||
35
+ defined_disks.size > controller.limit - 1
36
+ raise Vagrant::Errors::VirtualBoxDisksDefinedExceedLimit,
37
+ limit: controller.limit,
38
+ name: controller.name
39
+ else
40
+ disk_controller = controller
41
+ dvd_controller = controller
42
+ end
43
+ else
44
+ disks_defined = defined_disks.select { |d| d.type == :disk }
45
+ if disks_defined.any?
46
+ disk_controller = storage_controllers.get_primary_controller
47
+
48
+ if (disks_defined.any? { |d| d.primary } && disks_defined.size > disk_controller.limit) ||
49
+ disks_defined.size > disk_controller.limit - 1
50
+ raise Vagrant::Errors::VirtualBoxDisksDefinedExceedLimit,
51
+ limit: disk_controller.limit,
52
+ name: disk_controller.name
53
+ end
54
+ end
55
+
56
+ dvds_defined = defined_disks.select { |d| d.type == :dvd }
57
+ if dvds_defined.any?
58
+ dvd_controller = storage_controllers.get_dvd_controller
59
+
60
+ if dvds_defined.size > dvd_controller.limit
61
+ raise Vagrant::Errors::VirtualBoxDisksDefinedExceedLimit,
62
+ limit: dvd_controller.limit,
63
+ name: dvd_controller.name
64
+ end
65
+ end
66
+ end
31
67
 
32
- configured_disks = {disk: [], floppy: [], dvd: []}
68
+ configured_disks = { disk: [], floppy: [], dvd: [] }
33
69
 
34
70
  defined_disks.each do |disk|
35
71
  if disk.type == :disk
36
- disk_data = handle_configure_disk(machine, disk, current_disks)
72
+ disk_data = handle_configure_disk(machine, disk, disk_controller.name)
37
73
  configured_disks[:disk] << disk_data unless disk_data.empty?
38
74
  elsif disk.type == :floppy
39
75
  # TODO: Write me
40
76
  machine.ui.info(I18n.t("vagrant.cap.configure_disks.floppy_not_supported", name: disk.name))
41
77
  elsif disk.type == :dvd
42
- # TODO: Write me
43
- machine.ui.info(I18n.t("vagrant.cap.configure_disks.dvd_not_supported", name: disk.name))
78
+ dvd_data = handle_configure_dvd(machine, disk, dvd_controller.name)
79
+ configured_disks[:dvd] << dvd_data unless dvd_data.empty?
44
80
  end
45
81
  end
46
82
 
@@ -56,15 +92,10 @@ module VagrantPlugins
56
92
  def self.get_current_disk(machine, disk, all_disks)
57
93
  current_disk = nil
58
94
  if disk.primary
59
- # Ensure we grab the proper primary disk
60
- # We can't rely on the order of `all_disks`, as they will not
61
- # always come in port order, but primary is always Port 0 Device 0.
62
- vm_info = machine.provider.driver.show_vm_info
63
- primary_uuid = vm_info["SATA Controller-ImageUUID-0-0"]
64
-
65
- current_disk = all_disks.select { |d| d["UUID"] == primary_uuid }.first
95
+ storage_controllers = machine.provider.driver.read_storage_controllers
96
+ current_disk = storage_controllers.get_primary_attachment
66
97
  else
67
- current_disk = all_disks.select { |d| d["Disk Name"] == disk.name}.first
98
+ current_disk = all_disks.detect { |d| d[:disk_name] == disk.name }
68
99
  end
69
100
 
70
101
  current_disk
@@ -74,40 +105,117 @@ module VagrantPlugins
74
105
  #
75
106
  # @param [Vagrant::Machine] machine - the current machine
76
107
  # @param [Config::Disk] disk - the current disk to configure
77
- # @param [Array] all_disks - A list of all currently defined disks in VirtualBox
108
+ # @param [String] controller_name - the name of the storage controller to use
78
109
  # @return [Hash] - disk_metadata
79
- def self.handle_configure_disk(machine, disk, all_disks)
110
+ def self.handle_configure_disk(machine, disk, controller_name)
111
+ storage_controllers = machine.provider.driver.read_storage_controllers
112
+ controller = storage_controllers.get_controller(controller_name)
113
+ all_disks = controller.attachments
114
+
80
115
  disk_metadata = {}
81
116
 
82
- # Grab the existing configured disk, if it exists
117
+ # Grab the existing configured disk attached to guest, if it exists
83
118
  current_disk = get_current_disk(machine, disk, all_disks)
84
119
 
85
- # Configure current disk
86
120
  if !current_disk
87
- # create new disk and attach
88
- disk_metadata = create_disk(machine, disk)
89
- elsif compare_disk_size(machine, disk, current_disk)
90
- disk_metadata = resize_disk(machine, disk, current_disk)
91
- else
92
- # TODO: What if it needs to be resized?
121
+ # Look for an existing disk that's not been attached but exists
122
+ # inside VirtualBox
123
+ #
124
+ # NOTE: This assumes that if that disk exists and was created by
125
+ # Vagrant, it exists in the same location as the primary disk file.
126
+ # Otherwise Vagrant has no good way to determining if the disk was
127
+ # associated with the guest, since disk names are not unique
128
+ # globally to VirtualBox.
129
+ primary = storage_controllers.get_primary_attachment
130
+ existing_disk = machine.provider.driver.list_hdds.detect do |d|
131
+ File.dirname(d["Location"]) == File.dirname(primary[:location]) &&
132
+ d["Disk Name"] == disk.name
133
+ end
93
134
 
94
- disk_info = machine.provider.driver.get_port_and_device(current_disk["UUID"])
95
- if disk_info.empty?
135
+ if !existing_disk
136
+ # create new disk and attach to guest
137
+ disk_metadata = create_disk(machine, disk, controller)
138
+ else
139
+ # Disk has been created but failed to be attached to guest, so
140
+ # this method recovers that disk from previous failure
141
+ # and attaches it onto the guest
96
142
  LOGGER.warn("Disk '#{disk.name}' is not connected to guest '#{machine.name}', Vagrant will attempt to connect disk to guest")
97
- dsk_info = get_next_port(machine)
98
- machine.provider.driver.attach_disk(dsk_info[:port],
143
+ dsk_info = get_next_port(machine, controller)
144
+ machine.provider.driver.attach_disk(controller.name,
145
+ dsk_info[:port],
99
146
  dsk_info[:device],
100
- current_disk["Location"])
101
- else
102
- LOGGER.info("No further configuration required for disk '#{disk.name}'")
147
+ "hdd",
148
+ existing_disk["Location"])
149
+
150
+ disk_metadata[:uuid] = existing_disk["UUID"]
151
+ disk_metadata[:port] = dsk_info[:port]
152
+ disk_metadata[:device] = dsk_info[:device]
153
+ disk_metadata[:name] = disk.name
154
+ disk_metadata[:controller] = controller.name
103
155
  end
156
+ elsif compare_disk_size(machine, disk, current_disk)
157
+ disk_metadata = resize_disk(machine, disk, current_disk, controller)
158
+ else
159
+ LOGGER.info("No further configuration required for disk '#{disk.name}'")
160
+ disk_metadata[:uuid] = current_disk[:uuid]
161
+ disk_metadata[:port] = current_disk[:port]
162
+ disk_metadata[:device] = current_disk[:device]
104
163
 
105
- disk_metadata = {uuid: current_disk["UUID"], name: disk.name}
164
+ disk_metadata[:name] = disk.name
165
+ disk_metadata[:controller] = controller.name
106
166
  end
107
167
 
108
168
  disk_metadata
109
169
  end
110
170
 
171
+ # Handles all disk configs of type `:dvd`
172
+ #
173
+ # @param [Vagrant::Machine] machine - the current machine
174
+ # @param [Config::Disk] dvd - the current disk to configure
175
+ # @param [String] controller_name - the name of the storage controller to use
176
+ # @return [Hash] - dvd_metadata
177
+ def self.handle_configure_dvd(machine, dvd, controller_name)
178
+ storage_controllers = machine.provider.driver.read_storage_controllers
179
+ controller = storage_controllers.get_controller(controller_name)
180
+
181
+ dvd_metadata = {}
182
+
183
+ dvd_location = File.expand_path(dvd.file)
184
+ dvd_attached = controller.attachments.detect { |a| a[:location] == dvd_location }
185
+
186
+ if dvd_attached
187
+ LOGGER.info("No further configuration required for dvd '#{dvd.name}'")
188
+ dvd_metadata[:name] = dvd.name
189
+ dvd_metadata[:port] = dvd_attached[:port]
190
+ dvd_metadata[:device] = dvd_attached[:device]
191
+ dvd_metadata[:uuid] = dvd_attached[:uuid]
192
+ dvd_metadata[:controller] = controller.name
193
+ else
194
+ LOGGER.warn("DVD '#{dvd.name}' is not connected to guest '#{machine.name}', Vagrant will attempt to connect dvd to guest")
195
+ dsk_info = get_next_port(machine, controller)
196
+ machine.provider.driver.attach_disk(controller.name,
197
+ dsk_info[:port],
198
+ dsk_info[:device],
199
+ "dvddrive",
200
+ dvd.file)
201
+
202
+ # Refresh the controller information
203
+ storage_controllers = machine.provider.driver.read_storage_controllers
204
+ controller = storage_controllers.get_controller(controller_name)
205
+
206
+ attachment = controller.attachments.detect { |a| a[:port] == dsk_info[:port] &&
207
+ a[:device] == dsk_info[:device] }
208
+
209
+ dvd_metadata[:name] = dvd.name
210
+ dvd_metadata[:port] = dsk_info[:port]
211
+ dvd_metadata[:device] = dsk_info[:device]
212
+ dvd_metadata[:uuid] = attachment[:uuid]
213
+ dvd_metadata[:controller] = controller.name
214
+ end
215
+
216
+ dvd_metadata
217
+ end
218
+
111
219
  # Check to see if current disk is configured based on defined_disks
112
220
  #
113
221
  # @param [Kernel_V2::VagrantConfigDisk] disk_config
@@ -115,7 +223,7 @@ module VagrantPlugins
115
223
  # @return [Boolean]
116
224
  def self.compare_disk_size(machine, disk_config, defined_disk)
117
225
  requested_disk_size = Vagrant::Util::Numeric.bytes_to_megabytes(disk_config.size)
118
- defined_disk_size = defined_disk["Capacity"].split(" ").first.to_f
226
+ defined_disk_size = defined_disk[:capacity].split(" ").first.to_f
119
227
 
120
228
  if defined_disk_size > requested_disk_size
121
229
  machine.ui.warn(I18n.t("vagrant.cap.configure_disks.shrink_size_not_supported", name: disk_config.name))
@@ -131,7 +239,9 @@ module VagrantPlugins
131
239
  #
132
240
  # @param [Vagrant::Machine] machine
133
241
  # @param [Kernel_V2::VagrantConfigDisk] disk_config
134
- def self.create_disk(machine, disk_config)
242
+ # @param [VagrantPlugins::ProviderVirtualBox::Model::StorageController] controller -
243
+ # the storage controller to use
244
+ def self.create_disk(machine, disk_config, controller)
135
245
  machine.ui.detail(I18n.t("vagrant.cap.configure_disks.create_disk", name: disk_config.name))
136
246
  # NOTE: At the moment, there are no provider specific configs for VirtualBox
137
247
  # but we grab it anyway for future use.
@@ -146,10 +256,16 @@ module VagrantPlugins
146
256
  LOGGER.info("Attempting to create a new disk file '#{disk_file}' of size '#{disk_config.size}' bytes")
147
257
 
148
258
  disk_var = machine.provider.driver.create_disk(disk_file, disk_config.size, disk_ext.upcase)
149
- disk_metadata = {uuid: disk_var.split(':').last.strip, name: disk_config.name}
259
+ dsk_controller_info = get_next_port(machine, controller)
260
+ machine.provider.driver.attach_disk(controller.name,
261
+ dsk_controller_info[:port],
262
+ dsk_controller_info[:device],
263
+ "hdd",
264
+ disk_file)
150
265
 
151
- dsk_controller_info = get_next_port(machine)
152
- machine.provider.driver.attach_disk(dsk_controller_info[:port], dsk_controller_info[:device], disk_file)
266
+ disk_metadata = { uuid: disk_var.split(":").last.strip, name: disk_config.name,
267
+ controller: controller.name, port: dsk_controller_info[:port],
268
+ device: dsk_controller_info[:device] }
153
269
 
154
270
  disk_metadata
155
271
  end
@@ -167,20 +283,47 @@ module VagrantPlugins
167
283
  # device = disk_info[3]
168
284
  #
169
285
  # @param [Vagrant::Machine] machine
286
+ # @param [VagrantPlugins::ProviderVirtualBox::Model::StorageController] controller -
287
+ # the storage controller to use
170
288
  # @return [Hash] dsk_info - The next available port and device on a given controller
171
- def self.get_next_port(machine)
172
- vm_info = machine.provider.driver.show_vm_info
173
- dsk_info = {device: "0", port: "0"}
174
-
175
- disk_images = vm_info.select { |v| v.include?("ImageUUID") && v.include?("SATA Controller") }
176
- used_ports = disk_images.keys.map { |k| k.split('-') }.map {|v| v[2].to_i}
177
- next_available_port = ((0..(MAX_DISK_NUMBER-1)).to_a - used_ports).first
289
+ def self.get_next_port(machine, controller)
290
+ dsk_info = {}
291
+
292
+ if controller.devices_per_port == 1
293
+ used_ports = controller.attachments.map { |a| a[:port].to_i }
294
+ next_available_port = ((0..(controller.maxportcount - 1)).to_a - used_ports).first
295
+
296
+ dsk_info[:port] = next_available_port.to_s
297
+ dsk_info[:device] = "0"
298
+ elsif controller.devices_per_port == 2
299
+ # IDE Controllers have primary/secondary devices, so find the first port
300
+ # with an empty device
301
+ (0..(controller.maxportcount - 1)).each do |port|
302
+ # Skip this port if it's full
303
+ port_attachments = controller.attachments.select { |a| a[:port] == port.to_s }
304
+ next if port_attachments.count == controller.devices_per_port
305
+
306
+ dsk_info[:port] = port.to_s
307
+
308
+ # Check for a free device
309
+ if port_attachments.any? { |a| a[:device] == "0" }
310
+ dsk_info[:device] = "1"
311
+ else
312
+ dsk_info[:device] = "0"
313
+ end
314
+
315
+ break if dsk_info[:port]
316
+ end
317
+ else
318
+ raise Vagrant::Errors::VirtualBoxDisksUnsupportedController, controller_name: controller.name
319
+ end
178
320
 
179
- dsk_info[:port] = next_available_port.to_s
180
- if dsk_info[:port].empty?
321
+ if dsk_info[:port].to_s.empty?
181
322
  # This likely only occurs if additional disks have been added outside of Vagrant configuration
182
- LOGGER.warn("There are no more available ports to attach disks to for the SATA Controller. Clear up some space on the SATA controller to attach new disks.")
183
- raise Vagrant::Errors::VirtualBoxDisksDefinedExceedLimit
323
+ LOGGER.warn("There is no more available space to attach disks to for the controller '#{controller}'. Clear up some space on the controller '#{controller}' to attach new disks.")
324
+ raise Vagrant::Errors::VirtualBoxDisksDefinedExceedLimit,
325
+ limit: controller.limit,
326
+ name: controller.name
184
327
  end
185
328
 
186
329
  dsk_info
@@ -189,47 +332,49 @@ module VagrantPlugins
189
332
  # @param [Vagrant::Machine] machine
190
333
  # @param [Config::Disk] disk_config - the current disk to configure
191
334
  # @param [Hash] defined_disk - current disk as represented by VirtualBox
335
+ # @param [VagrantPlugins::ProviderVirtualBox::Model::StorageController] controller -
336
+ # the storage controller to use
192
337
  # @return [Hash] - disk_metadata
193
- def self.resize_disk(machine, disk_config, defined_disk)
338
+ def self.resize_disk(machine, disk_config, defined_disk, controller)
194
339
  machine.ui.detail(I18n.t("vagrant.cap.configure_disks.resize_disk", name: disk_config.name), prefix: true)
195
340
 
196
- if defined_disk["Storage format"] == "VMDK"
341
+ if defined_disk[:storage_format] == "VMDK"
197
342
  LOGGER.warn("Disk type VMDK cannot be resized in VirtualBox. Vagrant will convert disk to VDI format to resize first, and then convert resized disk back to VMDK format")
198
343
 
199
- # grab disk to be resized port and device number
200
- disk_info = machine.provider.driver.get_port_and_device(defined_disk["UUID"])
201
344
  # original disk information in case anything goes wrong during clone/resize
202
345
  original_disk = defined_disk
203
- backup_disk_location = "#{original_disk["Location"]}.backup"
346
+ backup_disk_location = "#{original_disk[:location]}.backup"
204
347
 
205
348
  # clone disk to vdi formatted disk
206
- vdi_disk_file = machine.provider.driver.vmdk_to_vdi(defined_disk["Location"])
349
+ vdi_disk_file = machine.provider.driver.vmdk_to_vdi(defined_disk[:location])
207
350
  # resize vdi
208
351
  machine.provider.driver.resize_disk(vdi_disk_file, disk_config.size.to_i)
209
352
 
210
353
  begin
211
354
  # Danger Zone
212
-
213
355
  # remove and close original volume
214
- machine.provider.driver.remove_disk(disk_info[:port], disk_info[:device])
356
+ machine.provider.driver.remove_disk(controller.name, defined_disk[:port], defined_disk[:device])
215
357
  # Create a backup of the original disk if something goes wrong
216
- LOGGER.warn("Making a backup of the original disk at #{defined_disk["Location"]}")
217
- FileUtils.mv(defined_disk["Location"], backup_disk_location)
358
+ LOGGER.warn("Making a backup of the original disk at #{defined_disk[:location]}")
359
+ FileUtils.mv(defined_disk[:location], backup_disk_location)
218
360
 
219
361
  # we have to close here, otherwise we can't re-clone after
220
362
  # resizing the vdi disk
221
- machine.provider.driver.close_medium(defined_disk["UUID"])
363
+ machine.provider.driver.close_medium(defined_disk[:uuid])
222
364
 
223
365
  # clone back to original vmdk format and attach resized disk
224
366
  vmdk_disk_file = machine.provider.driver.vdi_to_vmdk(vdi_disk_file)
225
- machine.provider.driver.attach_disk(disk_info[:port], disk_info[:device], vmdk_disk_file, "hdd")
367
+ machine.provider.driver.attach_disk(controller.name,
368
+ defined_disk[:port],
369
+ defined_disk[:device],
370
+ "hdd",
371
+ vmdk_disk_file)
226
372
  rescue ScriptError, SignalException, StandardError
227
373
  LOGGER.warn("Vagrant encountered an error while trying to resize a disk. Vagrant will now attempt to reattach and preserve the original disk...")
228
374
  machine.ui.error(I18n.t("vagrant.cap.configure_disks.recovery_from_resize",
229
- location: original_disk["Location"],
375
+ location: original_disk[:location],
230
376
  name: machine.name))
231
- recover_from_resize(machine, disk_info, backup_disk_location, original_disk, vdi_disk_file)
232
-
377
+ recover_from_resize(machine, defined_disk, backup_disk_location, original_disk, vdi_disk_file, controller)
233
378
  raise
234
379
  ensure
235
380
  # Remove backup disk file if all goes well
@@ -240,13 +385,17 @@ module VagrantPlugins
240
385
  machine.provider.driver.close_medium(vdi_disk_file)
241
386
 
242
387
  # Get new updated disk UUID for vagrant disk_meta file
243
- new_disk_info = machine.provider.driver.list_hdds.select { |h| h["Location"] == defined_disk["Location"] }.first
388
+ storage_controllers = machine.provider.driver.read_storage_controllers
389
+ updated_controller = storage_controllers.get_controller(controller.name)
390
+ new_disk_info = updated_controller.attachments.detect { |h| h[:location] == defined_disk[:location] }
391
+
244
392
  defined_disk = new_disk_info
245
393
  else
246
- machine.provider.driver.resize_disk(defined_disk["Location"], disk_config.size.to_i)
394
+ machine.provider.driver.resize_disk(defined_disk[:location], disk_config.size.to_i)
247
395
  end
248
396
 
249
- disk_metadata = {uuid: defined_disk["UUID"], name: disk_config.name}
397
+ disk_metadata = { uuid: defined_disk[:uuid], name: disk_config.name, controller: controller.name,
398
+ port: defined_disk[:port], device: defined_disk[:device] }
250
399
 
251
400
  disk_metadata
252
401
  end
@@ -261,13 +410,17 @@ module VagrantPlugins
261
410
  # @param [String] backup_disk_location - The place on disk where vagrant made a backup of the original disk being resized
262
411
  # @param [Hash] original_disk - The disk information from VirtualBox
263
412
  # @param [String] vdi_disk_file - The place on disk where vagrant made a clone of the original disk being resized
264
- def self.recover_from_resize(machine, disk_info, backup_disk_location, original_disk, vdi_disk_file)
413
+ # @param [VagrantPlugins::ProviderVirtualBox::Model::StorageController] controller - the storage controller to use
414
+ def self.recover_from_resize(machine, disk_info, backup_disk_location, original_disk, vdi_disk_file, controller)
265
415
  begin
266
416
  # move backup to original name
267
- FileUtils.mv(backup_disk_location, original_disk["Location"], force: true)
417
+ FileUtils.mv(backup_disk_location, original_disk[:location], force: true)
268
418
  # Attach disk
269
- machine.provider.driver.
270
- attach_disk(disk_info[:port], disk_info[:device], original_disk["Location"], "hdd")
419
+ machine.provider.driver.attach_disk(controller.name,
420
+ disk_info[:port],
421
+ disk_info[:device],
422
+ "hdd",
423
+ original_disk[:location])
271
424
 
272
425
  # Remove cloned disk if still hanging around
273
426
  if vdi_disk_file