From 2c9aa8eff94ddc9de26aa936587213e0bf67ef06 Mon Sep 17 00:00:00 2001 From: Girija Soni Date: Wed, 15 May 2024 05:53:35 +0530 Subject: [PATCH] Add support for NVME Controllers --- lib/fog/vsphere/compute.rb | 2 + .../vsphere/models/compute/nvmecontroller.rb | 22 ++++++++++ .../vsphere/models/compute/scsicontroller.rb | 1 + lib/fog/vsphere/models/compute/server.rb | 44 ++++++++++++++++--- lib/fog/vsphere/models/compute/volume.rb | 12 ++++- lib/fog/vsphere/requests/compute/create_vm.rb | 18 ++++++-- .../compute/list_vm_nvme_controllers.rb | 29 ++++++++++++ 7 files changed, 116 insertions(+), 12 deletions(-) create mode 100644 lib/fog/vsphere/models/compute/nvmecontroller.rb create mode 100644 lib/fog/vsphere/requests/compute/list_vm_nvme_controllers.rb diff --git a/lib/fog/vsphere/compute.rb b/lib/fog/vsphere/compute.rb index 214bfc29..3357ee44 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 00000000..8f6a1472 --- /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 393fcbc8..89267472 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 c5ff030d..607bea2b 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,6 +359,13 @@ def initialize_interfaces end end + def unassignedVolumes? + attributes[:volumes]&.map! do |vol| + return true unless vol.has_key?("controller_key") + end + false + end + def initialize_volumes if attributes[:volumes] && attributes[:volumes].is_a?(Array) attributes[:volumes].map! do |vol| @@ -368,18 +386,30 @@ def initialize_customvalues end def initialize_scsi_controllers + controllers = [] if attributes[:scsi_controllers] && attributes[:scsi_controllers].is_a?(Array) - attributes[:scsi_controllers].map! do |controller| + controllers = 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) - attributes[:scsi_controllers] = [ + + 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 + end + # Create a default scsi controller if there are exisiting hard disks with no controller assigned to them + controllers.concat([Fog::Vsphere::Compute::SCSIController.new]) if unassignedVolumes? + attributes[:scsi_controllers] = controllers + end + + def initialize_nvme_controllers + if attributes[:nvme_controllers] && attributes[:nvme_controllers].is_a?(Array) + 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]) ] end end diff --git a/lib/fog/vsphere/models/compute/volume.rb b/lib/fog/vsphere/models/compute/volume.rb index 98078d79..4ce15130 100644 --- a/lib/fog/vsphere/models/compute/volume.rb +++ b/lib/fog/vsphere/models/compute/volume.rb @@ -95,6 +95,15 @@ def server_id server.id end + def set_controller_key(controllers) + # if a disk has no controller assigned, default shall be the first scsi controller + if controllers && !controllers.empty? && !controller_key + self.controller_key = controllers.first.key + elsif !controller_key + self.controller_key = 1000 + end + end + def set_unit_number requires :server # When adding volumes to vsphere, if our unit_number is 7 or higher, vsphere will increment the unit_number @@ -126,8 +135,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 f873d050..2eac8e4f 100644 --- a/lib/fog/vsphere/requests/compute/create_vm.rb +++ b/lib/fog/vsphere/requests/compute/create_vm.rb @@ -142,8 +142,12 @@ 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)) } + devices << disks.map { |disk| create_disk(disk, :add, storage_pod: get_storage_pod_from_volumes(attributes), scsi_controllers: scsi_controllers) } end if (cdroms = attributes[:cdroms]) @@ -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)})) + **(checkType(options[:type]) ? {} : {sharedBus: controller_get_shared_from_options(options)})) } end @@ -263,6 +267,14 @@ def controller_default_options { operation: :add, type: RbVmomi::VIM.VirtualLsiLogicController.class, shared: false } end + def checkType(type) + if [RbVmomi::VIM::VirtualAHCIController, "VirtualNVMEController"].include?(type) + true + else + false + end + end + def controller_get_shared_from_options(options) if (options.key?(:shared) && (options[:shared] == false)) || (!options.key? :shared) :noSharing @@ -282,7 +294,7 @@ def create_disk(disk, operation = :add, options = {}) else "[#{disk.datastore}]" end - + disk.set_controller_key(options[:scsi_controllers]) disk.set_unit_number disk.set_key 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 00000000..0194cb22 --- /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