plugins/providers/virtualbox/driver/version_5_0.rb in vagrant-unbundled-2.2.9.0 vs plugins/providers/virtualbox/driver/version_5_0.rb in vagrant-unbundled-2.2.10.0

- old
+ new

@@ -20,24 +20,26 @@ # SATA Controller-ImageUUID-0-0 (sub out ImageUUID) # - Controller: SATA Controller # - Port: 0 # - Device: 0 # + # @param [String] controller_name - name of storage controller to attach disk to # @param [String] port - port on device to attach disk to # @param [String] device - device on controller for disk - # @param [String] file - disk file path # @param [String] type - type of disk to attach + # @param [String] file - disk file path # @param [Hash] opts - additional options - def attach_disk(port, device, file, type="hdd", **opts) - # Maybe only support SATA Controller for `:disk`??? - controller = "SATA Controller" - + def attach_disk(controller_name, port, device, type, file, **opts) comment = "This disk is managed externally by Vagrant. Removing or adjusting settings could potentially cause issues with Vagrant." - execute('storageattach', @uuid, '--storagectl', controller, '--port', - port.to_s, '--device', device.to_s, '--type', type, '--medium', - file, '--comment', comment) + execute('storageattach', @uuid, + '--storagectl', controller_name, + '--port', port.to_s, + '--device', device.to_s, + '--type', type, + '--medium', file, + '--comment', comment) end def clear_forwarded_ports retryable(on: Vagrant::Errors::VBoxManageError, tries: 3, sleep: 1) do args = [] @@ -222,16 +224,19 @@ d = e.extra_data return [] if d[:stderr].include?("does not have") || d[:stdout].include?("does not have") raise end + # @param [String] controller_name - controller name to remove disk from # @param [String] port - port on device to attach disk to # @param [String] device - device on controller for disk - # @param [Hash] opts - additional options - def remove_disk(port, device) - controller = "SATA Controller" - execute('storageattach', @uuid, '--storagectl', controller, '--port', port.to_s, '--device', device.to_s, '--medium', "none") + def remove_disk(controller_name, port, device) + execute('storageattach', @uuid, + '--storagectl', controller_name, + '--port', port.to_s, + '--device', device.to_s, + '--medium', "none") end # @param [String] disk_file # @param [Integer] disk_size in bytes # @param [Hash] opts - additional options @@ -386,25 +391,26 @@ end # Returns port and device for an attached disk given a disk uuid. Returns # empty hash if disk is not attachd to guest # - # @param [Hash] vm_info - A guests information from vboxmanage # @param [String] disk_uuid - the UUID for the disk we are searching for # @return [Hash] disk_info - Contains a device and port number def get_port_and_device(disk_uuid) - vm_info = show_vm_info - disk = {} - disk_info_key = vm_info.key(disk_uuid) - return disk if !disk_info_key - disk_info = disk_info_key.split("-") + storage_controllers = read_storage_controllers + storage_controllers.each do |controller| + controller.attachments.each do |attachment| + if disk_uuid == attachment[:uuid] + disk[:port] = attachment[:port] + disk[:device] = attachment[:device] + return disk + end + end + end - disk[:port] = disk_info[2] - disk[:device] = disk_info[3] - return disk end def halt execute("controlvm", @uuid, "poweroff", retryable: true) @@ -800,10 +806,30 @@ # Add the shared folder execute("sharedfolder", "add", @uuid, *args, retryable: true) end end + # Returns information for a given disk + # + # @param [String] disk_type - can be "disk", "dvd", or "floppy" + # @param [String] disk_uuid_or_file + # @return [Hash] disk + def show_medium_info(disk_type, disk_uuid_or_file) + disk = {} + execute('showmediuminfo', disk_type, disk_uuid_or_file, retryable: true).split("\n").each do |line| + parts = line.partition(":") + key = parts.first.strip + value = parts.last.strip + disk[key] = value + + if key == "Location" + disk["Disk Name"] = File.basename(value, ".*") + end + end + disk + end + def ssh_port(expected_port) @logger.debug("Searching for SSH port: #{expected_port.inspect}") # Look for the forwarded port. Valid based on the guest port, but will do # scoring based matching to determine best value when multiple results are @@ -919,9 +945,58 @@ destination = File.join(File.dirname(source), File.basename(source, ".*")) + ".vmdk" clone_disk(source, destination, 'VMDK') destination + end + + # Helper method to get a list of storage controllers added to the + # current VM + # + # @return [VagrantPlugins::ProviderVirtualBox::Model::StorageControllerArray] + def read_storage_controllers + vm_info = show_vm_info + count = vm_info.count { |key, value| key.match(/^storagecontrollername\d+$/) } + all_disks = list_hdds + + storage_controllers = Model::StorageControllerArray.new + + (0..count - 1).each do |n| + # basic controller metadata + name = vm_info["storagecontrollername#{n}"] + type = vm_info["storagecontrollertype#{n}"] + maxportcount = vm_info["storagecontrollermaxportcount#{n}"].to_i + + # build attachments array + attachments = [] + vm_info.each do |k, v| + if /^#{name}-ImageUUID-(\d+)-(\d+)$/ =~ k + port = $1.to_s + device = $2.to_s + uuid = v + location = vm_info["#{name}-#{port}-#{device}"] + + extra_disk_data = all_disks.detect { |d| d["UUID"] == uuid } + + attachment = { port: port, + device: device, + uuid: uuid, + location: location } + + extra_disk_data&.each do |dk,dv| + # NOTE: We convert the keys from VirtualBox to symbols + # to be consistent with the other keys + attachment[dk.downcase.gsub(' ', '_').to_sym] = dv + end + + attachments << attachment + end + end + + storage_controllers << Model::StorageController.new(name, type, maxportcount, attachments) + end + + storage_controllers end protected def valid_ip_address?(ip)