diff --git a/lib/fog/vsphere/compute.rb b/lib/fog/vsphere/compute.rb index 214bfc2..3357ee4 100644 --- a/lib/fog/vsphere/compute.rb +++ b/lib/fog/vsphere/compute.rb @@ -43,6 +43,7 @@ class Compute < Fog::Service model :customfield collection :customfields model :scsicontroller + model :nvmecontroller model :process model :cdrom collection :cdroms @@ -111,6 +112,7 @@ class Compute < Fog::Service request :list_customfields request :get_vm_first_scsi_controller request :list_vm_scsi_controllers + request :list_vm_nvme_controllers request :set_vm_customvalue request :vm_take_snapshot request :list_vm_snapshots diff --git a/lib/fog/vsphere/models/compute/nvmecontroller.rb b/lib/fog/vsphere/models/compute/nvmecontroller.rb new file mode 100644 index 0000000..8f6a147 --- /dev/null +++ b/lib/fog/vsphere/models/compute/nvmecontroller.rb @@ -0,0 +1,22 @@ +module Fog + module Vsphere + class Compute + class NVMEController < Fog::Model + attribute :type + attribute :unit_number + attribute :key, type: :integer + attribute :server_id + + def initialize(attributes = {}) + super + self.key ||= 2000 + self.type ||= "VirtualNVMEController" + end + + def to_s + "#{type} ##{key}:, unit_number: #{unit_number}" + end + end + end + end +end diff --git a/lib/fog/vsphere/models/compute/scsicontroller.rb b/lib/fog/vsphere/models/compute/scsicontroller.rb index 393fcbc..8926747 100644 --- a/lib/fog/vsphere/models/compute/scsicontroller.rb +++ b/lib/fog/vsphere/models/compute/scsicontroller.rb @@ -11,6 +11,7 @@ class SCSIController < Fog::Model def initialize(attributes = {}) super self.key ||= 1000 + self.type ||= "VirtualLsiLogicController" end def to_s diff --git a/lib/fog/vsphere/models/compute/server.rb b/lib/fog/vsphere/models/compute/server.rb index c5ff030..c41dd89 100644 --- a/lib/fog/vsphere/models/compute/server.rb +++ b/lib/fog/vsphere/models/compute/server.rb @@ -7,6 +7,7 @@ class Server < Fog::Compute::Server extend Fog::Deprecation deprecate(:ipaddress, :public_ip_address) deprecate(:scsi_controller, :scsi_controllers) + deprecate(:nvme_controller, :nvme_controllers) # This will be the instance uuid which is globally unique across # a vSphere deployment. @@ -49,6 +50,7 @@ class Server < Fog::Compute::Server attribute :guest_id attribute :hardware_version attribute :scsi_controllers, type: :array + attribute :nvme_controllers, type: :array attribute :cpuHotAddEnabled attribute :memoryHotAddEnabled attribute :firmware @@ -60,9 +62,10 @@ def initialize(attributes = {}) super defaults.merge(attributes) self.instance_uuid ||= id # TODO: remvoe instance_uuid as it can be replaced with simple id initialize_interfaces - initialize_volumes initialize_customvalues initialize_scsi_controllers + initialize_nvme_controllers + initialize_volumes end # Lazy Loaded Attributes @@ -289,10 +292,18 @@ def scsi_controllers attributes[:scsi_controllers] ||= service.list_vm_scsi_controllers(id) end + def nvme_controllers + attributes[:nvme_controllers] ||= service.list_vm_nvme_controllers(id) + end + def scsi_controller scsi_controllers.first end + def nvme_controller + nvme_controllers.first + end + def folder return nil unless datacenter && path attributes[:folder] ||= service.folders(datacenter: datacenter, type: :vm).get(path) @@ -348,9 +359,25 @@ def initialize_interfaces end end + def unassigned_volumes? + attributes[:volumes]&.map! do |vol| + return true unless vol.key?(:controller_key) + end + false + end + + def update_controller_key(vol) + if !attributes[:scsi_controllers].empty? && !vol[:controller_key] + vol[:controller_key] = attributes[:scsi_controllers].first.key + elsif !vol[:controller_key] + vol[:controller_key] = 1000 + end + end + def initialize_volumes - if attributes[:volumes] && attributes[:volumes].is_a?(Array) + if attributes[:volumes] && attributes[:volumes].is_a?(Array) && !attributes[:volumes].empty? attributes[:volumes].map! do |vol| + update_controller_key(vol) if vol.is_a?(Hash) service.volumes.new({ server: self }.merge(vol)) else @@ -368,18 +395,28 @@ def initialize_customvalues end def initialize_scsi_controllers - if attributes[:scsi_controllers] && attributes[:scsi_controllers].is_a?(Array) + if attributes[:scsi_controllers] && attributes[:scsi_controllers].is_a?(Array) && !attributes[:scsi_controllers].empty? attributes[:scsi_controllers].map! do |controller| controller.is_a?(Hash) ? Fog::Vsphere::Compute::SCSIController.new(controller) : controller end - elsif attributes[:scsi_controller] && attributes[:scsi_controller].is_a?(Hash) + elsif attributes[:scsi_controller] && attributes[:scsi_controller].is_a?(Hash) && !attributes[:scsi_controller].empty? + attributes[:scsi_controllers] = [ Fog::Vsphere::Compute::SCSIController.new(attributes[:scsi_controller]) ] - elsif attributes[:volumes] && attributes[:volumes].is_a?(Array) && !attributes[:volumes].empty? - # Create a default scsi controller if there are any disks but no controller defined - attributes[:scsi_controllers] = [ - Fog::Vsphere::Compute::SCSIController.new + elsif unassigned_volumes? && !attributes[:volume].empty? + attributes[:scsi_controllers] = [Fog::Vsphere::Compute::SCSIController.new] + end + end + + def initialize_nvme_controllers + if attributes[:nvme_controllers] && attributes[:nvme_controllers].is_a?(Array) && !attributes[:nvme_controllers].empty? + attributes[:nvme_controllers].map! do |controller| + controller.is_a?(Hash) ? Fog::Vsphere::Compute::NVMEController.new(controller) : controller + end + elsif attributes[:nvme_controller] && attributes[:nvme_controller].is_a?(Hash) + attributes[:nvme_controllers] = [ + Fog::Vsphere::Compute::NVMEController.new(attributes[:nvme_controllers]) && !attributes[:nvme_controller].empty? ] end end diff --git a/lib/fog/vsphere/models/compute/volume.rb b/lib/fog/vsphere/models/compute/volume.rb index 98078d7..ea75252 100644 --- a/lib/fog/vsphere/models/compute/volume.rb +++ b/lib/fog/vsphere/models/compute/volume.rb @@ -126,8 +126,7 @@ def defaults { thin: true, name: 'Hard disk', - mode: 'persistent', - controller_key: 1000 + mode: 'persistent' } end diff --git a/lib/fog/vsphere/requests/compute/create_vm.rb b/lib/fog/vsphere/requests/compute/create_vm.rb index f873d05..4087fcd 100644 --- a/lib/fog/vsphere/requests/compute/create_vm.rb +++ b/lib/fog/vsphere/requests/compute/create_vm.rb @@ -142,6 +142,10 @@ def device_change(attributes) devices << scsi_controllers.each_with_index.map { |controller, index| create_controller(controller, index) } end + if (nvme_controllers = (attributes[:nvme_controllers] || attributes['nvme_controller'])) + devices << nvme_controllers.each_with_index.map { |controller, index| create_controller(controller, index) } + end + if (disks = attributes[:volumes]) devices << disks.map { |disk| create_disk(disk, :add, storage_pod: get_storage_pod_from_volumes(attributes)) } end @@ -255,7 +259,7 @@ def create_controller(controller = nil, index = 0) operation: options[:operation], device: controller_class.new(key: options[:key] || (1000 + index), busNumber: options[:bus_id] || index, - **(options[:type] == RbVmomi::VIM::VirtualAHCIController ? {} : {sharedBus: controller_get_shared_from_options(options)})) + **(check_type(options[:type]) ? {} : {sharedBus: controller_get_shared_from_options(options)})) } end @@ -263,6 +267,10 @@ def controller_default_options { operation: :add, type: RbVmomi::VIM.VirtualLsiLogicController.class, shared: false } end + def check_type(type) + [RbVmomi::VIM::VirtualAHCIController, RbVmomi::VIM::VirtualNVMEController, "VirtualNVMEController"].include?(type) + end + def controller_get_shared_from_options(options) if (options.key?(:shared) && (options[:shared] == false)) || (!options.key? :shared) :noSharing diff --git a/lib/fog/vsphere/requests/compute/list_vm_nvme_controllers.rb b/lib/fog/vsphere/requests/compute/list_vm_nvme_controllers.rb new file mode 100644 index 0000000..0194cb2 --- /dev/null +++ b/lib/fog/vsphere/requests/compute/list_vm_nvme_controllers.rb @@ -0,0 +1,29 @@ +module Fog + module Vsphere + class Compute + class Real + def list_vm_nvme_controllers(vm_id) + list_vm_nvme_controllers_raw(vm_id).map do |raw_controller| + Fog::Vsphere::Compute::NVMEController.new(raw_controller) + end + end + + def list_vm_nvme_controllers_raw(vm_id) + get_vm_ref(vm_id).config.hardware.device.grep(RbVmomi::VIM::VirtualNVMEController).map do |ctrl| + { + type: ctrl.class.to_s, + key: ctrl.key + } + end + end + end + class Mock + def list_vm_nvme_controllers(vm_id) + raise Fog::Vsphere::Compute::NotFound, 'VM not Found' unless data[:servers].key?(vm_id) + return [] unless data[:servers][vm_id].key?('nvme_controllers') + data[:servers][vm_id]['nvme_controllers'].map { |h| h.merge(server_id: vm_id) } + end + end + end + end +end