Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for NVME Controllers #300

Merged
merged 1 commit into from
Jul 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions lib/fog/vsphere/compute.rb
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ class Compute < Fog::Service
model :customfield
collection :customfields
model :scsicontroller
model :nvmecontroller
model :process
model :cdrom
collection :cdroms
Expand Down Expand Up @@ -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
Expand All @@ -136,6 +138,7 @@ class Compute < Fog::Service
request :host_start_maintenance
request :host_finish_maintenance
request :get_vm_first_sata_controller
request :get_vm_first_nvme_controller

module Shared
attr_reader :vsphere_is_vcenter
Expand Down Expand Up @@ -346,10 +349,12 @@ def is_uuid?(id)
end
end

# rubocop:disable Metrics/ClassLength
class Mock
include Shared
# rubocop:disable Metrics/MethodLength
def self.data
# rubocop:disable Metrics/BlockLength
@data ||= Hash.new do |hash, key|
hash[key] = {
servers: {
Expand Down Expand Up @@ -380,6 +385,11 @@ def self.data
'type' => 'VirtualLsiLogicController',
'unit_number' => 7,
'key' => 1000 }],
'nvme_controllers' =>
[{
'type' => 'VirtualNVMEController',
'key' => 2000
}],
'interfaces' =>
[{ 'mac' => '00:50:56:a9:00:28',
'network' => 'dvportgroup-123456',
Expand Down Expand Up @@ -616,6 +626,7 @@ def self.data
}
}
end
# rubocop:enable Metrics/BlockLength
end

# rubocop:enable Metrics/MethodLength
Expand All @@ -637,6 +648,7 @@ def reset_data
self.class.data.delete(@vsphere_username)
end
end
# rubocop:enable Metrics/ClassLength

class Real
include Shared
Expand Down
24 changes: 24 additions & 0 deletions lib/fog/vsphere/models/compute/nvmecontroller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
module Fog
module Vsphere
class Compute
class NVMEController < Fog::Model
attribute :type
attribute :unit_number
attribute :key, type: :integer
attribute :server_id
DEFAULT_KEY = 2000
DEFAULT_TYPE = "VirtualNVMEController".freeze

def initialize(attributes = {})
super
self.key ||= DEFAULT_KEY
self.type ||= DEFAULT_TYPE
end

def to_s
"#{type} ##{key}:, unit_number: #{unit_number}"
end
end
end
end
end
6 changes: 5 additions & 1 deletion lib/fog/vsphere/models/compute/scsicontroller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,13 @@ class SCSIController < Fog::Model
attribute :key, type: :integer
attribute :server_id

DEFAULT_KEY = 1000
DEFAULT_TYPE = "VirtualLsiLogicController".freeze

def initialize(attributes = {})
super
self.key ||= 1000
self.key ||= DEFAULT_KEY
self.type ||= DEFAULT_TYPE
end

def to_s
Expand Down
51 changes: 33 additions & 18 deletions lib/fog/vsphere/models/compute/server.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
module Fog
module Vsphere
class Compute
class Server < Fog::Compute::Server
class Server < Fog::Compute::Server # rubocop:disable Metrics/ClassLength
extend Fog::Deprecation
deprecate(:ipaddress, :public_ip_address)
deprecate(:scsi_controller, :scsi_controllers)
Expand Down Expand Up @@ -49,6 +49,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
Expand All @@ -60,9 +61,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
Expand Down Expand Up @@ -289,6 +291,10 @@ 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
Expand Down Expand Up @@ -348,16 +354,21 @@ def initialize_interfaces
end
end

def unassigned_volumes?
attributes[:volumes]&.any? { |vol| !vol.key?(:controller_key) } || false
end

def update_controller_key(vol)
vol.controller_key ||= attributes[:scsi_controllers].first&.key || 1000
end

def initialize_volumes
if attributes[:volumes] && attributes[:volumes].is_a?(Array)
attributes[:volumes].map! do |vol|
if vol.is_a?(Hash)
service.volumes.new({ server: self }.merge(vol))
else
vol.server = self
vol
end
end
return unless attributes[:volumes].is_a?(Array)
attributes[:volumes].map! do |vol|
vol = service.volumes.new({ server: self }.merge(vol)) if vol.is_a?(Hash)
vol.server = self
update_controller_key(vol)
vol
end
end

Expand All @@ -368,19 +379,23 @@ def initialize_customvalues
end

def initialize_scsi_controllers
if attributes[:scsi_controllers] && attributes[:scsi_controllers].is_a?(Array)
if 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].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
]
end
attributes[:scsi_controllers] = [Fog::Vsphere::Compute::SCSIController.new] if !attributes[:scsi_controllers]&.any? && unassigned_volumes?
end

def initialize_nvme_controllers
if attributes[:nvme_controllers].is_a?(Array)
attributes[:nvme_controllers].map! do |controller|
controller.is_a?(Hash) ? Fog::Vsphere::Compute::NVMEController.new(controller) : controller
end
end
end
end
Expand Down
3 changes: 1 addition & 2 deletions lib/fog/vsphere/models/compute/volume.rb
Original file line number Diff line number Diff line change
Expand Up @@ -126,8 +126,7 @@ def defaults
{
thin: true,
name: 'Hard disk',
mode: 'persistent',
controller_key: 1000
mode: 'persistent'
}
end

Expand Down
15 changes: 11 additions & 4 deletions lib/fog/vsphere/requests/compute/create_vm.rb
Original file line number Diff line number Diff line change
Expand Up @@ -138,10 +138,14 @@ def device_change(attributes)
devices << nics.map { |nic| create_interface(nic, nics.index(nic), :add, attributes) }
end

if (scsi_controllers = (attributes[:scsi_controllers] || attributes['scsi_controller']))
if (scsi_controllers = attributes[:scsi_controllers] || attributes['scsi_controller'])
devices << scsi_controllers.each_with_index.map { |controller, index| create_controller(controller, index) }
end

if (nvme_controllers = attributes[:nvme_controllers])
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
Expand Down Expand Up @@ -241,11 +245,15 @@ def create_interface(nic, index = 0, operation = :add, attributes = {})
end

def create_controller(controller = nil, index = 0)
device_options = {}
options = if controller
controller_default_options.merge(controller.attributes)
else
controller_default_options
end
end
unless [RbVmomi::VIM::VirtualAHCIController, RbVmomi::VIM::VirtualNVMEController, "VirtualNVMEController"].include?(options[:type])
device_options[:sharedBus] = controller_get_shared_from_options(options)
end
controller_class = if options[:type].is_a? String
Fog::Vsphere.class_from_string options[:type], 'RbVmomi::VIM'
else
Expand All @@ -254,8 +262,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)}))
busNumber: options[:bus_id] || index, **device_options)
}
end

Expand Down
21 changes: 21 additions & 0 deletions lib/fog/vsphere/requests/compute/get_vm_first_nvme_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
module Fog
module Vsphere
class Compute
class Real
def get_vm_first_nvme_controller(vm_id)
ctrl = get_vm_ref(vm_id).config.hardware.device.find { |device| device.is_a?(RbVmomi::VIM::VirtualNVMEController) }
raise Fog::Vsphere::Compute::NotFound, "No NVME controller found for #{vm_id}" unless ctrl
{
type: ctrl&.class.to_s,
device_info: ctrl&.deviceInfo,
bus_number: ctrl&.busNumber,
key: ctrl&.key
}
end
end
class Mock
def get_vm_first_nvme_controller(vm_id); end

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The mock class returns nil, while the real method will throw an exception and never return nil.
I think it would be nice to have the behavior be equal

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We are not doing that for the other(scsi and sata) controllers, I dont think it's necessary to do that as it's the mock class.

end
end
end
end
29 changes: 29 additions & 0 deletions lib/fog/vsphere/requests/compute/list_vm_nvme_controllers.rb
Original file line number Diff line number Diff line change
@@ -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
2 changes: 1 addition & 1 deletion lib/fog/vsphere/requests/compute/vm_clone.rb
Original file line number Diff line number Diff line change
Expand Up @@ -886,8 +886,8 @@ def relocation_volume_backing(volume)
)
end
end

# rubocop:enable Metrics/ClassLength

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you should reenable the class length metric after the class definition.


class Mock
include Shared
def vm_clone(options = {})
Expand Down
Loading
Loading