ManageIQ/manageiq-providers-ovirt

View on GitHub
app/models/manageiq/providers/ovirt/inventory/parser/infra_manager.rb

Summary

Maintainability
B
5 hrs
Test Coverage
A
94%
class ManageIQ::Providers::Ovirt::Inventory::Parser::InfraManager < ManageIQ::Providers::Ovirt::Inventory::Parser
def parse
log_header = "MIQ(#{self.class.name}.#{__method__}) Collecting data for EMS name: [#{collector.manager.name}] id: [#{collector.manager.id}]"
$rhevm_log.info("#{log_header}...")
 
clusters
datacenters
storagedomains
hosts
vms
networks
vnic_profiles
advertised_images
 
$rhevm_log.info("#{log_header}...Complete")
end
 
def networks
collector.networks.each do |network|
is_external = id_of_external_network?(network.id)
 
persister_switches = is_external ? persister.external_distributed_virtual_switches : persister.distributed_virtual_switches
attrs_to_assign = {
:name => network.name,
:uid_ems => network.id
}
 
if is_external
datacenter = network.data_center
ems_ref = ManageIQ::Providers::Ovirt::InfraManager.make_ems_ref(datacenter.href)
parent_datacenter = persister.ems_folders.lazy_find(ems_ref)
 
attrs_to_assign[:parent] = parent_datacenter
end
 
persister_switches.find_or_build_by(:uid_ems => network.id)
.assign_attributes(attrs_to_assign)
end
end
 
def vnic_profiles
collector.collect_vnic_profiles.each do |vnic_profile|
virtual_switches_persister = id_of_external_network?(vnic_profile.network.id) ? persister.external_distributed_virtual_switches : persister.distributed_virtual_switches
virtual_lans_persister = id_of_external_network?(vnic_profile.network.id) ? persister.external_distributed_virtual_lans : persister.distributed_virtual_lans
 
switch_persister = virtual_switches_persister.lazy_find(:uid_ems => vnic_profile.network.id)
virtual_lans_persister.find_or_build_by(:uid_ems => vnic_profile.id, :switch => switch_persister).assign_attributes(
:name => vnic_profile.name,
:uid_ems => vnic_profile.id
)
end
end
 
def id_of_external_network?(network_id)
network = collector.networks.detect { |net| net.id == network_id }
network&.external_provider.present?
end
 
def clusters
collector.clusters.each do |cluster|
r_id = "#{cluster.id}_respool"
ems_ref = ManageIQ::Providers::Ovirt::InfraManager.make_ems_ref(cluster.href)
 
persister.resource_pools.find_or_build(r_id).assign_attributes(
:name => "Default for Cluster #{cluster.name}",
:uid_ems => r_id,
:is_default => true,
:parent => persister.clusters.lazy_find(ems_ref),
)
 
datacenter_id = cluster.dig(:data_center, :id)
cluster_parent = persister.ems_folders.lazy_find("#{datacenter_id}_host") if datacenter_id
 
persister.clusters.build(
:ems_ref => ems_ref,
:uid_ems => cluster.id,
:name => cluster.name,
:parent => cluster_parent,
)
end
end
 
def storagedomains
collector.storagedomains.each do |storagedomain|
storage_type = storagedomain.dig(:storage, :type).upcase
ems_ref = ManageIQ::Providers::Ovirt::InfraManager.make_ems_ref(storagedomain.try(:href))
location = case storage_type
when 'LOCALFS', 'ISO'
ems_ref
when 'NFS', 'GLUSTERFS'
"#{storagedomain.dig(:storage, :address)}:#{storagedomain.dig(:storage, :path)}"
else
storagedomain.dig(:storage, :volume_group, :id)
end
 
free = storagedomain.try(:available).to_i
used = storagedomain.try(:used).to_i
total = free + used
committed = storagedomain.try(:committed).to_i
 
storage_domain_type = storagedomain.dig(:type, :downcase)
type = storage_domain_type == 'iso' ? "IsoDatastore" : "Storage"
 
persister.storages.find_or_build(ems_ref).assign_attributes(
:ems_ref => ems_ref,
:name => storagedomain.try(:name),
:store_type => storage_type,
:storage_domain_type => storage_domain_type,
:total_space => total,
:free_space => free,
:uncommitted => total - committed,
:multiplehostaccess => true,
:location => location,
:master => storagedomain.try(:master),
:type => "#{persister.manager.class}::#{type}"
)
end
end
 
def advertised_images
collector.advertised_images.each do |image|
parent_ems_ref = ManageIQ::Providers::Ovirt::InfraManager.make_ems_ref(image.dig(:storage_domain, :href))
 
persister.iso_images.build(
:name => image.name,
:storage => persister.storages.lazy_find(parent_ems_ref)
)
end
end
 
def datacenters
collector.datacenters.each do |datacenter|
ems_ref = ManageIQ::Providers::Ovirt::InfraManager.make_ems_ref(datacenter.href)
 
persister.ems_folders.find_or_build('root_dc').assign_attributes(
:name => 'Datacenters',
:type => "#{persister.manager.class}::Folder",
:uid_ems => 'root_dc',
:hidden => true,
:parent => nil,
)
 
uid = datacenter.id
persister.ems_folders.find_or_build(ems_ref).assign_attributes(
:name => datacenter.name,
:type => "#{persister.manager.class}::Datacenter",
:ems_ref => ems_ref,
:uid_ems => uid,
:parent => persister.ems_folders.lazy_find("root_dc")
)
 
host_folder_uid = "#{uid}_host"
persister.ems_folders.find_or_build(host_folder_uid).assign_attributes(
:name => 'host',
:type => "#{persister.manager.class}::Folder",
:uid_ems => host_folder_uid,
:hidden => true,
:parent => persister.ems_folders.lazy_find(ems_ref)
)
 
vm_folder_uid = "#{uid}_vm"
persister.ems_folders.find_or_build(vm_folder_uid).assign_attributes(
:name => 'vm',
:type => "#{persister.manager.class}::Folder",
:uid_ems => vm_folder_uid,
:hidden => true,
:parent => persister.ems_folders.lazy_find(ems_ref)
)
end
end
 
def hosts
collector.hosts.each do |host|
host_id = host.id
 
power_state = host.status
power_state, connection_state = case power_state
when 'up' then %w(on connected)
when 'maintenance' then [power_state, 'connected']
when 'down' then %w(off disconnected)
when 'non_responsive' then %w(unknown connected)
else [power_state, 'disconnected']
end
 
hostname = host.address
hostname = hostname.split(',').first
 
nics = collector.collect_host_nics(host)
ipaddress = host_to_ip(nics, hostname) || host.address
 
host_os_version = host.dig(:os, :version)
ems_ref = ManageIQ::Providers::Ovirt::InfraManager.make_ems_ref(host.href)
 
cluster = collector.collect_cluster_for_host(host)
dc = collector.collect_datacenter_for_cluster(cluster)
persister_host = persister.hosts.find_or_build(ems_ref).assign_attributes(
:ems_ref => ems_ref,
:name => host.name || hostname,
:hostname => hostname,
:ipaddress => ipaddress,
:uid_ems => host_id,
:vmm_product => host.type,
:vmm_version => extract_host_version(host_os_version),
:vmm_buildnumber => (host_os_version.build if host_os_version),
:connection_state => connection_state,
:power_state => power_state,
:maintenance => power_state == 'maintenance',
:ems_cluster => persister.clusters.lazy_find({:uid_ems => cluster.id}, :ref => :by_uid_ems),
)
 
host_storages(dc, persister_host)
host_operating_systems(persister_host, host, hostname)
network_attachments = collector.collect_network_attachments(host.id)
switches(persister_host, dc, network_attachments)
host_hardware(persister_host, host, networks, nics)
end
end
 
def host_storages(dc, persister_host)
storages = []
Array.wrap(collector.collect_dc_domains(dc)).each do |sd|
ems_href = ManageIQ::Providers::Ovirt::InfraManager.make_ems_ref(sd.href)
# we need to trim datacenter part of href
storages << persister.storages.lazy_find(ems_href[0..4] + ems_href[54..-1])
end
storages.compact!
storages.uniq!
 
storages.each do |storage|
persister.host_storages.find_or_build_by(
:host => persister_host,
:storage => storage
).assign_attributes(
:host => persister_host,
:storage => storage
)
end
end
 
def host_hardware(persister_host, host, networks, nics)
hdw = host.cpu
 
stats = collector.collect_host_stats(host)
memory_total_attr = Array.wrap(stats).detect { |stat| stat.name == 'memory.total' }
memory_total = memory_total_attr && memory_total_attr.dig(:values, :first, :datum)
hw_info = host.hardware_information
 
cpu_cores = hdw.dig(:topology, :cores) || 1
cpu_sockets = hdw.dig(:topology, :sockets) || 1
 
persister_hardware = persister.host_hardwares.find_or_build(persister_host).assign_attributes(
:cpu_speed => hdw.speed,
:cpu_type => hdw.name,
:memory_mb => memory_total.nil? ? 0 : memory_total.to_i / 1.megabyte,
:cpu_cores_per_socket => cpu_cores,
:cpu_sockets => cpu_sockets,
:cpu_total_cores => cpu_sockets * cpu_cores,
:manufacturer => hw_info.manufacturer,
:model => hw_info.product_name,
:serial_number => hw_info.serial_number,
:number_of_nics => nics.count
)
 
host_guest_devices(persister_hardware, host, nics, networks)
end
 
def host_guest_devices(persister_hardware, host, nics, networks)
persister_host = persister_hardware.host
 
Array.wrap(nics).each do |nic|
network = network_from_nic(nic, host, networks)
ip = nic.ip.presence || nil
 
location = nil
location = $1 if nic.name =~ /(\d+)$/
 
persister_host_network = persister.host_networks.find_or_build_by(
:hardware => persister_hardware,
:ipaddress => ip&.address
).assign_attributes(
:description => nic.name,
:ipaddress => ip&.address,
:subnet_mask => ip&.netmask,
)
 
attributes = {
:uid_ems => nic.id,
:device_name => nic.name,
:device_type => 'ethernet',
:location => location,
:present => true,
:controller_type => 'ethernet'
}
 
unless network.nil?
switch_uid = network.try(:id) || network.name
distributed_virtual_switch = persister.distributed_virtual_switches.lazy_find(:host => persister_host, :uid_ems => switch_uid)
attributes[:switch] = distributed_virtual_switch
attributes[:network] = persister_host_network
end
 
persister.host_guest_devices.find_or_build_by(
:hardware => persister_hardware,
:uid_ems => nic.id
).assign_attributes(attributes)
end
end
 
def switches(persister_host, _data_center, network_attachments)
network_attachments.each do |na|
distributed_virtual_switch = persister.distributed_virtual_switches.lazy_find(:uid_ems => na.network.id)
persister.host_switches.find_or_build_by(
:host => persister_host,
:switch => distributed_virtual_switch
).assign_attributes(
:host => persister_host,
:switch => distributed_virtual_switch
)
end
end
 
def network_from_nic(nic, dc, networks)
return unless dc
 
network_id = nic.dig(:network, :id)
if network_id
# TODO: check to indexed_networks = networks.index_by(:id)
network = networks.detect { |n| n.id == network_id }
else
network_name = nic.dig(:network, :name)
if network_name
network = networks.detect { |n| n.name == network_name && n.dig(:data_center, :id) == dc.id }
end
end
 
network
end
 
# TODO: (borod108) is this ever used?
def lans(network, persister_switch)
tag_value = nil
if network
uid = network.id
name = network.name
tag_value = network.try(:vlan).try(:id)
else
uid = name = network_name unless network_name.nil?
end
 
if uid.nil?
return
end
 
persister.distributed_virtual_lans.find_or_build_by(
:switch => persister_switch, :uid_ems => uid
).assign_attributes(
:name => name,
:uid_ems => uid,
:tag => tag_value,
:switch => persister_switch,
)
end
 
def host_operating_systems(persister_host, host, hostname)
persister.host_operating_systems.find_or_build(persister_host).assign_attributes(
:name => hostname,
:product_type => 'linux',
:product_name => extract_host_os_name(host),
:version => extract_host_os_full_version(host.os)
)
end
 
Method `vms` has a Cognitive Complexity of 29 (exceeds 11 allowed). Consider refactoring.
Cyclomatic complexity for vms is too high. [18/11]
def vms
vms = Array(collector.vms) + Array(collector.templates)
vms.compact.each do |vm|
# Skip the place holder template
next if vm.id == '00000000-0000-0000-0000-000000000000'
 
template = vm.href.include?('/templates/')
 
ems_ref = ManageIQ::Providers::Ovirt::InfraManager.make_ems_ref(vm.href)
 
host_obj = vm.try(:host) || vm.try(:placement_policy).try(:hosts).try(:first)
host_ems_ref = ManageIQ::Providers::Ovirt::InfraManager.make_ems_ref(host_obj.href) if host_obj.present?
 
datacenter_id = collector.datacenter_by_cluster_id[vm.cluster.id]
parent_folder = persister.ems_folders.lazy_find("#{datacenter_id}_vm")
resource_pool = persister.resource_pools.lazy_find("#{vm.cluster.id}_respool") unless template
host = persister.hosts.lazy_find(host_ems_ref) if host_ems_ref.present?
cpu_affinity = vm.cpu&.cpu_tune&.vcpu_pins&.map { |pin| "#{pin.vcpu}##{pin.cpu_set}" }&.join(",")
 
storages, disks = storages(vm)
 
collection_persister = if template
persister.miq_templates
else
persister.vms
end
 
attrs_to_assign = {
:type => template ? "#{persister.manager.class}::Template" : "#{persister.manager.class}::Vm",
:ems_ref => ems_ref,
:uid_ems => vm.id,
:connection_state => "connected",
:name => URI::DEFAULT_PARSER.unescape(vm.name),
:location => "#{vm.id}.ovf",
:template => template,
:memory_limit => extract_vm_memory_policy(vm, :max),
:memory_reserve => vm_memory_reserve(vm),
:raw_power_state => template ? "never" : vm.status,
:host => host,
:ems_cluster => persister.clusters.lazy_find({:uid_ems => vm.cluster.id}, :ref => :by_uid_ems),
:storages => storages,
:storage => storages.first,
:parent => parent_folder,
:resource_pool => resource_pool,
:cpu_affinity => cpu_affinity
}
 
attrs_to_assign[:restart_needed] = vm.next_run_configuration_exists unless template
attrs_to_assign[:tools_status] = get_tools_status(vm) unless template
 
boot_time = vm.try(:start_time)
attrs_to_assign[:boot_time] = boot_time unless boot_time.nil?
 
persister_vm = collection_persister.find_or_build(vm.id).assign_attributes(attrs_to_assign)
 
snapshots(persister_vm, vm)
vm_hardware(persister_vm, vm, disks, template, host)
operating_systems(persister_vm, vm)
custom_attributes(persister_vm, vm)
end
end
 
def get_tools_status(vm)
apps = Array.wrap(collector.collect_vm_guest_applications(vm))
apps.any? { |app| app.name.include?('ovirt-guest-agent') || app.name.include?('qemu-guest-agent') } ? 'installed' : 'not installed'
end
 
def storages(vm)
storages = []
disks = []
Array.wrap(collector.collect_attached_disks(vm)).each do |disk|
next if disk.kind_of?(Array) && disk.empty?
 
disks << disk
Array.wrap(disk.storage_domains).each do |sd|
storages << persister.storages.lazy_find(ManageIQ::Providers::Ovirt::InfraManager.make_ems_ref(sd.href))
end
end
storages.compact!
storages.uniq!
 
return storages, disks
end
 
def vm_hardware(presister_vm, vm, disks, template, host)
topology = vm.cpu.topology
cpu_socks = topology.try(:sockets) || 1
cpu_cores = topology.try(:cores) || 1
 
persister_hardware = persister.hardwares.find_or_build(presister_vm).assign_attributes(
:guest_os => vm.dig(:os, :type),
:annotation => vm.try(:description),
:cpu_cores_per_socket => cpu_cores,
:cpu_sockets => cpu_socks,
:cpu_total_cores => cpu_cores * cpu_socks,
:memory_mb => vm.memory / 1.megabyte
)
 
hardware_disks(persister_hardware, disks)
addresses = hardware_networks(persister_hardware, vm) unless template
vm_hardware_guest_devices(persister_hardware, vm, addresses, host) unless template
end
 
def hardware_networks(persister_hardware, vm)
addresses = {}
 
devices = collector.collect_vm_devices(vm)
Array.wrap(devices).each do |device|
nets = device.ips
next unless nets
 
ipaddresses = ipaddresses(addresses, device, nets)
ipaddresses.each do |ipv4address, ipv6address|
persister.networks.find_or_build_by(
:hardware => persister_hardware,
:ipaddress => ipv4address,
:ipv6address => ipv6address
).assign_attributes(
:ipaddress => ipv4address,
:ipv6address => ipv6address,
:hostname => vm.fqdn
)
end
end
addresses
end
 
Method `hardware_disks` has a Cognitive Complexity of 14 (exceeds 11 allowed). Consider refactoring.
def hardware_disks(persister_hardware, disks)
return if disks.blank?
 
disks = Array.wrap(disks).sort_by do |disk|
match = disk.try(:name).match(/disk[^\d]*(?<index>\d+)/i)
[disk.try(:bootable) ? 0 : 1, match ? match[:index].to_i : Float::INFINITY, disk.name]
end.group_by { |d| d.try(:interface) }
 
disks.each do |interface, devices|
devices.each_with_index do |device, index|
storage_domain = device.storage_domains && device.storage_domains.first
storage_ref = storage_domain && storage_domain.href
 
persister.disks.find_or_build_by(
:hardware => persister_hardware,
:device_name => device.name
).assign_attributes(
:device_name => device.name,
:device_type => 'disk',
:controller_type => interface,
:present => true,
:filename => device.id,
:location => "0:#{index}",
:size => device.provisioned_size.to_i,
:size_on_disk => device.actual_size.to_i,
:disk_type => device.sparse == true ? 'thin' : 'thick',
:thin => device.sparse,
:mode => 'persistent',
:bootable => device.try(:bootable),
:storage => persister.storages.lazy_find(ManageIQ::Providers::Ovirt::InfraManager.make_ems_ref(storage_ref)),
:format => device.format
)
end
end
end
 
Cyclomatic complexity for vm_hardware_guest_devices is too high. [15/11]
Method `vm_hardware_guest_devices` has a Cognitive Complexity of 21 (exceeds 11 allowed). Consider refactoring.
Unused method argument - `host`. If it's necessary, use `_` or `_host` as an argument name to indicate that it won't be used. If it's unnecessary, remove it.
def vm_hardware_guest_devices(persister_hardware, vm, addresses, host)
networks = {}
addresses.each do |mac, address|
network = persister.networks.lazy_find(
:hardware => persister_hardware,
:ipaddress => address[:ipaddress],
:ipv6address => address[:ipv6address]
)
networks[mac] = network if network
end
 
collector.collect_nics(vm).each do |nic|
next if nic.blank?
 
mac = nic.mac && nic.mac.address ? nic.mac.address : nil
network = mac && networks.present? ? networks[mac] : nil
 
vnic_profile_id = nic.dig(:vnic_profile, :id)
next if vnic_profile_id.nil?
 
network_uid = collector.collect_vnic_profiles.detect { |vp| vp.id == vnic_profile_id }&.network&.id
virtual_switches_persister = id_of_external_network?(network_uid) ? persister.external_distributed_virtual_switches : persister.distributed_virtual_switches
virtual_lans_persister = id_of_external_network?(network_uid) ? persister.external_distributed_virtual_lans : persister.distributed_virtual_lans
 
switch_persister = virtual_switches_persister.lazy_find(:uid_ems => network_uid)
lan_persister = virtual_lans_persister.lazy_find(:switch => switch_persister, :uid_ems => vnic_profile_id)
 
persister.guest_devices.find_or_build_by(
:hardware => persister_hardware,
:uid_ems => nic.id
).assign_attributes(
:uid_ems => nic.id,
:device_name => nic.name,
:device_type => 'ethernet',
:controller_type => 'ethernet',
:address => nic.dig(:mac, :address),
:lan => lan_persister,
:network => network,
:switch => switch_persister
)
end
end
 
def snapshots(persister_vm, vm)
snaps = []
return snaps if vm.try(:snapshots).nil?
 
snapshots = collector.collect_snapshots(vm)
snapshots = snapshots.sort_by(&:date).reverse
 
parent_id = nil
snapshots.each do |snapshot|
name = description = snapshot.description
name = "Active Image" if name[0, 13] == '_ActiveImage_'
snaps << persister.snapshots.find_or_build(:uid => snapshot.id).assign_attributes(
:uid_ems => snapshot.id,
:uid => snapshot.id,
:parent_uid => parent_id,
:parent => persister.snapshots.lazy_find(parent_id),
:name => name,
:description => description,
:create_time => snapshot.date.getutc,
:current => snapshot.snapshot_type == "active",
:vm_or_template => persister_vm,
:total_size => snapshot.instance_variable_get(:@total_size)
)
parent_id = snapshot.id
end
snaps
end
 
def operating_systems(persister_vm, vm)
guest_os = vm.dig(:os, :type)
 
persister.operating_systems.find_or_build(persister_vm).assign_attributes(
:product_name => guest_os.blank? ? "Other" : guest_os,
:system_type => vm.type
)
end
 
def custom_attributes(persister_vm, vm)
custom_attrs = vm.try(:custom_properties)
 
custom_attrs.to_a.each do |ca|
persister.vm_and_template_ems_custom_fields.build(
:section => 'custom_field',
:name => ca.name,
:value => ca.value.try(:truncate, 255),
:source => "VC",
:resource => persister_vm
)
end
end
 
private
 
require 'ostruct'
 
def vm_memory_reserve(vm_inv)
extract_vm_memory_policy(vm_inv, :guaranteed)
end
 
def extract_vm_memory_policy(vm_inv, type)
in_bytes = vm_inv.dig(:memory_policy, type)
in_bytes.nil? ? nil : in_bytes / Numeric::MEGABYTE
end
 
def host_to_ip(nics, hostname = nil)
ipaddress = nil
Array.wrap(nics).each do |nic|
ip_data = nic.ip
if !ip_data.nil? && !ip_data.gateway.blank? && !ip_data.address.blank?
ipaddress = ip_data.address
break
end
end
 
if ipaddress.nil?
unless [nil, "localhost", "localhost.localdomain", "127.0.0.1"].include?(hostname)
begin
ipaddress = Socket.getaddrinfo(hostname, nil)[0][3]
rescue => err
$rhevm_log.warn "IP lookup by hostname [#{hostname}]...Failed with the following error: #{err}"
end
end
end
 
ipaddress
end
 
def extract_host_version(host_os_version)
return unless host_os_version && host_os_version.major
 
version = host_os_version.major
version = "#{version}.#{host_os_version.minor}" if host_os_version.minor
version
end
 
def extract_host_os_name(host)
host_os = host.os
Wrap expressions with varying precedence with parentheses to avoid ambiguity.
host_os && host_os.type || host.type
end
 
def extract_host_os_full_version(host_os)
host_os.dig(:version, :full_version)
end
 
def ipaddresses(addresses, device, nets)
ipv4addresses = []
ipv6addresses = []
Array.wrap(nets).each do |net|
(net.version == "v4" ? ipv4addresses : ipv6addresses) << net.address
end
 
ipv4addresses = ipv4addresses.sort
ipv6addresses = ipv6addresses.sort
if device&.mac&.address
addresses[device.mac.address] = {
:ipaddress => ipv4addresses.blank? ? nil : ipv4addresses.first,
:ipv6address => ipv6addresses.blank? ? nil : ipv6addresses.first
}
end
 
ipv4addresses.zip_stretched(ipv6addresses)
end
end