diff --git a/app/models/manageiq/providers/vmware/infra_manager/vm.rb b/app/models/manageiq/providers/vmware/infra_manager/vm.rb index 70f352bc3..2f2d58c7b 100644 --- a/app/models/manageiq/providers/vmware/infra_manager/vm.rb +++ b/app/models/manageiq/providers/vmware/infra_manager/vm.rb @@ -11,8 +11,8 @@ class ManageIQ::Providers::Vmware::InfraManager::Vm < ManageIQ::Providers::Infra supports :reconfigure_disks supports :reconfigure_network_adapters - supports :reconfigure_disksize + supports :reconfigure_cdroms def add_miq_alarm raise "VM has no EMS, unable to add alarm" unless ext_management_system diff --git a/app/models/manageiq/providers/vmware/infra_manager/vm/reconfigure.rb b/app/models/manageiq/providers/vmware/infra_manager/vm/reconfigure.rb index dbe0dedf6..5c16e401f 100644 --- a/app/models/manageiq/providers/vmware/infra_manager/vm/reconfigure.rb +++ b/app/models/manageiq/providers/vmware/infra_manager/vm/reconfigure.rb @@ -90,15 +90,19 @@ def build_config_spec(options) set_spec_option(vmcs, :memoryMB, options[:vm_memory], :to_i) set_spec_option(vmcs, :numCPUs, options[:number_of_cpus], :to_i) - if options[:disk_remove] || options[:disk_add] || options[:disk_resize] || options[:network_adapter_add] || options[:network_adapter_remove] + if options_requiring_connection.any? { |key| options.key?(key) } with_provider_object do |vim_obj| hardware = vim_obj.getHardware remove_disks(vim_obj, vmcs, hardware, options[:disk_remove]) if options[:disk_remove] resize_disks(vim_obj, vmcs, hardware, options[:disk_resize]) if options[:disk_resize] add_disks(vim_obj, vmcs, hardware, options[:disk_add]) if options[:disk_add] - remove_network_adapters(vim_obj, vmcs, options[:network_adapter_remove]) if options[:network_adapter_remove] - add_network_adapters(vmcs, options[:network_adapter_add]) if options[:network_adapter_add] + + remove_network_adapters(vim_obj, vmcs, hardware, options[:network_adapter_remove]) if options[:network_adapter_remove] + add_network_adapters(vim_obj, vmcs, hardware, options[:network_adapter_add]) if options[:network_adapter_add] + + connect_cdroms(vim_obj, vmcs, hardware, options[:cdrom_connect]) if options[:cdrom_connect] + disconnect_cdroms(vim_obj, vmcs, hardware, options[:cdrom_disconnect]) if options[:cdrom_disconnect] end end end @@ -151,18 +155,26 @@ def add_disks(vim_obj, vmcs, hardware, disks) end end - def remove_network_adapters(vim_obj, vmcs, network_adapters) + def remove_network_adapters(vim_obj, vmcs, hardware, network_adapters) network_adapters.each do |n| - remove_network_adapter_config_spec(vim_obj, vmcs, n) + remove_network_adapter_config_spec(vim_obj, vmcs, hardware, n) end end - def add_network_adapters(vmcs, network_adapters) + def add_network_adapters(vim_obj, vmcs, hardware, network_adapters) network_adapters.each do |n| - add_network_adapter_config_spec(vmcs, n) + add_network_adapter_config_spec(vim_obj, vmcs, hardware, n) end end + def connect_cdroms(vim_obj, vmcs, hardware, cdroms) + cdroms.each { |cdrom| connect_cdrom_config_spec(vim_obj, vmcs, hardware, cdrom) } + end + + def disconnect_cdroms(vim_obj, vmcs, hardware, cdroms) + cdroms.each { |cdrom| disconnect_cdrom_config_spec(vim_obj, vmcs, hardware, cdrom) } + end + def scsi_controller_units(controller_key) [*0..6, *8..15].each.collect do |unit_number| [controller_key, unit_number] @@ -260,7 +272,7 @@ def add_disk_config_spec(vmcs, options) end end - def add_network_adapter_config_spec(vmcs, options) + def add_network_adapter_config_spec(_vim, vmcs, _hardware, options) add_device_config_spec(vmcs, VirtualDeviceConfigSpecOperation::Add) do |vdcs| vdcs.device = VimHash.new("VirtualVmxnet3") do |dev| dev.key = next_device_idx # negative integer as temporary key @@ -332,10 +344,10 @@ def resize_disk_config_spec(vim_obj, vmcs, hardware, options) end end - def remove_network_adapter_config_spec(vim_obj, vmcs, options) + def remove_network_adapter_config_spec(vim_obj, vmcs, hardware, options) raise "remove_network_adapter_config_spec: network_adapter name is required." unless options[:network][:name] network_adapter_label = options[:network][:name] - controller_key, key, unit_number = vim_obj.send(:getDeviceKeysByLabel, network_adapter_label) + controller_key, key, unit_number = vim_obj.send(:getDeviceKeysByLabel, network_adapter_label, hardware) add_device_config_spec(vmcs, VirtualDeviceConfigSpecOperation::Remove) do |vdcs| vdcs.device = VimHash.new("VirtualEthernetCard") do |dev| dev.key = key @@ -345,6 +357,40 @@ def remove_network_adapter_config_spec(vim_obj, vmcs, options) end end + def connect_cdrom_config_spec(vim_obj, vmcs, hardware, cdrom) + device = vim_obj.send(:getDeviceByLabel, cdrom[:device_name], hardware) + raise "connect_cdrom_config_spec: no virtual device associated with: #{cdrom[:device_name]}" unless device + + datastore_ref = HostStorage.find_by(:storage_id => cdrom[:storage_id], :host_id => host.id).try(:ems_ref) + raise "connect_cdrom_config_spec: could not find datastore reference for storage ID [#{cdrom[:storage_id]}] and host ID [#{host.id}]" unless datastore_ref + + add_device_config_spec(vmcs, VirtualDeviceConfigSpecOperation::Edit) do |vdcs| + device.backing = VimHash.new("VirtualCdromIsoBackingInfo") do |backing| + backing.datastore = datastore_ref + backing.fileName = cdrom[:filename] + end + + device.connectable.startConnected = true + + vdcs.device = device + end + end + + def disconnect_cdrom_config_spec(vim_obj, vmcs, hardware, cdrom) + device = vim_obj.send(:getDeviceByLabel, cdrom[:device_name], hardware) + raise "disconnect_cdrom_config_spec: no virtual device associated with: #{cdrom[:device_name]}" unless device + + add_device_config_spec(vmcs, VirtualDeviceConfigSpecOperation::Edit) do |vdcs| + device.backing = VimHash.new("VirtualCdromRemoteAtapiBackingInfo") do |backing| + backing.deviceName = "" + end + + device.connectable.startConnected = false + + vdcs.device = device + end + end + def add_device_config_spec(vmcs, operation) vmcs_vca = vmcs.deviceChange ||= VimArray.new('ArrayOfVirtualDeviceConfigSpec') vmcs_vca << VimHash.new('VirtualDeviceConfigSpec') do |vdcs| @@ -375,4 +421,8 @@ def next_device_idx @new_device_idx ||= -100 @new_device_idx -= 1 end + + def options_requiring_connection + %i(disk_remove disk_add disk_resize network_adapter_add network_adapter_remove cdrom_connect cdrom_disconnect) + end end diff --git a/spec/models/manageiq/providers/vmware/infra_manager/vm/reconfigure_spec.rb b/spec/models/manageiq/providers/vmware/infra_manager/vm/reconfigure_spec.rb index ae7726061..f788ca567 100644 --- a/spec/models/manageiq/providers/vmware/infra_manager/vm/reconfigure_spec.rb +++ b/spec/models/manageiq/providers/vmware/infra_manager/vm/reconfigure_spec.rb @@ -1,11 +1,18 @@ describe ManageIQ::Providers::Vmware::InfraManager::Vm::Reconfigure do + let(:storage) { FactoryGirl.create(:storage_vmware) } + let(:host) do + FactoryGirl.create(:host_vmware_esx).tap do |host| + host.host_storages.create(:storage_id => storage.id, :host_id => host.id, :ems_ref => "datastore-1") + end + end let(:vm) do FactoryGirl.create( :vm_vmware, :name => 'test_vm', :raw_power_state => 'poweredOff', :storage => FactoryGirl.create(:storage, :name => 'storage'), - :hardware => FactoryGirl.create(:hardware, :cpu4x2, :ram1GB, :virtual_hw_version => "07") + :hardware => FactoryGirl.create(:hardware, :cpu4x2, :ram1GB, :virtual_hw_version => "07"), + :host => host, ) end @@ -502,4 +509,94 @@ end end end + + context "#connect_cdroms" do + let(:vim_obj) { double("MiqVimVm obj") } + let(:vmcs) { VimHash.new("VirtualMachineConfigSpec") } + let(:options) do + [ + { + :device_name => "CD/DVD drive 1", + :filename => "[NFS Share] ISO/centos.iso", + :storage_id => storage.id, + } + ] + end + let(:subject) { vm.connect_cdroms(vim_obj, vmcs, hardware, options) } + + context "with no virtual cdroms" do + let(:hardware) { {"device" => []} } + + before do + expect(vim_obj).to receive(:getDeviceByLabel).and_return(nil) + end + + it "raises an exception when the cdrom can't be found" do + expect { subject }.to raise_error('connect_cdrom_config_spec: no virtual device associated with: CD/DVD drive 1') + end + end + + context "with one virtual cdrom" do + let(:hardware) { {"device" => [virtual_cdrom]} } + let(:virtual_cdrom) do + VimHash.new("VirtualCdrom").tap do |cdrom| + cdrom.backing = VimHash.new("VirtualCdromRemoteAtapiBackingInfo") + cdrom.connectable = VimHash.new("VirtualDeviceConnectInfo") + cdrom.controllerKey = 15000 + cdrom.deviceInfo = VimHash.new("Description") do |description| + description.label = "CD/DVD drive 1" + end + cdrom.key = 16000 + cdrom.unitNumber = 0 + end + end + + before do + expect(vim_obj).to receive(:getDeviceByLabel).and_return(virtual_cdrom) + end + + it "sets the device backing" do + subject + + expect(vmcs.deviceChange.count).to eq(1) + + device_change = vmcs.deviceChange.first.device + expect(device_change.backing.xsiType).to eq("VirtualCdromIsoBackingInfo") + expect(device_change.backing.fileName).to eq(options.first[:filename]) + end + end + end + + context "#disconnect_cdroms" do + let(:vim_obj) { double("MiqVimVm obj") } + let(:vmcs) { VimHash.new("VirtualMachineConfigSpec") } + let(:hardware) { {"device" => [virtual_cdrom]} } + let(:options) { [{:device_name => "CD/DVD drive 1"}] } + let(:subject) { vm.disconnect_cdroms(vim_obj, vmcs, hardware, options) } + let(:virtual_cdrom) do + VimHash.new("VirtualCdrom").tap do |cdrom| + cdrom.backing = VimHash.new("VirtualCdromIsoBackingInfo") + cdrom.connectable = VimHash.new("VirtualDeviceConnectInfo") + cdrom.controllerKey = 15000 + cdrom.deviceInfo = VimHash.new("Description") do |description| + description.label = "CD/DVD drive 1" + end + cdrom.key = 16000 + cdrom.unitNumber = 0 + end + end + + before do + expect(vim_obj).to receive(:getDeviceByLabel).and_return(virtual_cdrom) + end + + it "sets the device backing" do + subject + + expect(vmcs.deviceChange.count).to eq(1) + device_change = vmcs.deviceChange.first.device + expect(device_change.backing.xsiType).to eq("VirtualCdromRemoteAtapiBackingInfo") + expect(device_change.backing.deviceName).to eq("") + end + end end