diff --git a/app/models/manageiq/providers/lenovo/physical_infra_manager.rb b/app/models/manageiq/providers/lenovo/physical_infra_manager.rb index 8e768cbe99..8b188601f0 100644 --- a/app/models/manageiq/providers/lenovo/physical_infra_manager.rb +++ b/app/models/manageiq/providers/lenovo/physical_infra_manager.rb @@ -1,6 +1,8 @@ class ManageIQ::Providers::Lenovo::PhysicalInfraManager < ManageIQ::Providers::PhysicalInfraManager - has_many :physical_servers, :foreign_key => "ems_id", :class_name => "ManageIQ::Providers::Lenovo::PhysicalInfraManager::PhysicalServer", :dependent => :destroy - + has_many :physical_racks, :foreign_key => "ems_id", :dependent => :destroy, :inverse_of => :ext_management_system, + :class_name => "ManageIQ::Providers::Lenovo::PhysicalInfraManager::PhysicalRack" + has_many :physical_servers, :foreign_key => "ems_id", :dependent => :destroy, :inverse_of => :ext_management_system, + :class_name => "ManageIQ::Providers::Lenovo::PhysicalInfraManager::PhysicalServer" include ManageIQ::Providers::Lenovo::ManagerMixin include_concern 'Operations' diff --git a/app/models/manageiq/providers/lenovo/physical_infra_manager/parsers/components/component_parser.rb b/app/models/manageiq/providers/lenovo/physical_infra_manager/parsers/components/component_parser.rb new file mode 100644 index 0000000000..751fa34385 --- /dev/null +++ b/app/models/manageiq/providers/lenovo/physical_infra_manager/parsers/components/component_parser.rb @@ -0,0 +1,42 @@ +module ManageIQ::Providers::Lenovo + module Parsers + # + # Superclass extended by all classes that parses LXCA components + # to a MiQ format + # + class ComponentParser + # + # Returns a hash containing the structure described on dictionary + # and with the values in the source. + # + # @param source - Object that will be parse to a hash + # @param dictionary - Hash containing the instructions to translate the object into a Hash + # + # @see ParserDictionaryConstants + # + def self.parse(source, dictionary) + result = {} + dictionary&.each do |key, value| + if value.kind_of?(String) + next if value.empty? + source_keys = value.split('.') # getting source keys navigation + source_value = source + source_keys.each do |source_key| + begin + attr_method = source_value.method(source_key) # getting method to get the attribute value + source_value = attr_method.call + rescue NameError + # when the key doesn't correspond to a method + source_value = source_value[source_key] + end + end + result[key] = source_value + elsif value.kind_of?(Hash) + result[key] = parse(source, dictionary[key]) + end + end + result + end + end + end +end diff --git a/app/models/manageiq/providers/lenovo/physical_infra_manager/parsers/components/config_pattern_parser.rb b/app/models/manageiq/providers/lenovo/physical_infra_manager/parsers/components/config_pattern_parser.rb new file mode 100644 index 0000000000..98f955e36a --- /dev/null +++ b/app/models/manageiq/providers/lenovo/physical_infra_manager/parsers/components/config_pattern_parser.rb @@ -0,0 +1,21 @@ +require_relative 'component_parser' + +module ManageIQ::Providers::Lenovo + module Parsers + class ConfigPatternParser < ComponentParser + class << self + # + # Parses the config pattern object into a Hash + # + # @param [XClarityClient::ConfigPattern] config_pattern - object containing config + # pattern data + # + # @return [Hash] containing the config pattern informations + # + def parse_config_pattern(config_pattern) + return config_pattern.id, parse(config_pattern, ParserDictionaryConstants::CONFIG_PATTERNS) + end + end + end + end +end diff --git a/app/models/manageiq/providers/lenovo/physical_infra_manager/parsers/components/physical_rack_parser.rb b/app/models/manageiq/providers/lenovo/physical_infra_manager/parsers/components/physical_rack_parser.rb new file mode 100644 index 0000000000..8e7646ded4 --- /dev/null +++ b/app/models/manageiq/providers/lenovo/physical_infra_manager/parsers/components/physical_rack_parser.rb @@ -0,0 +1,24 @@ +require_relative 'component_parser' + +module ManageIQ::Providers::Lenovo + module Parsers + class PhysicalRackParser < ComponentParser + class << self + # + # Parse a rack object to a hash with its data + # + # @param cab [XClarity::PhysicalRack] a rack object + # @param physical_servers [Hash] a already parsed physical_servers that belong to cab + # + # @return [Integer, Hash] PhysicalRack UUID and a parsed hash from PhysicalRack and every components inside it + # + def parse_physical_rack(cab, physical_servers) + result = parse(cab, ParserDictionaryConstants::PHYSICAL_RACK) + result[:physical_servers] = physical_servers + + return cab.UUID, result + end + end + end + end +end diff --git a/app/models/manageiq/providers/lenovo/physical_infra_manager/parsers/components/physical_server_parser.rb b/app/models/manageiq/providers/lenovo/physical_infra_manager/parsers/components/physical_server_parser.rb new file mode 100644 index 0000000000..392a8d791a --- /dev/null +++ b/app/models/manageiq/providers/lenovo/physical_infra_manager/parsers/components/physical_server_parser.rb @@ -0,0 +1,225 @@ +require_relative 'component_parser' + +module ManageIQ::Providers::Lenovo + module Parsers + class PhysicalServerParser < ComponentParser + class << self + # + # parse a node object to a hash with physical servers data + # + # @param [XClarityClient::Node] node - object containing physical server data + # + # @return [Hash] containing the physical server information + # + def parse_physical_server(node, ems_id) + result = parse(node, ParserDictionaryConstants::PHYSICAL_SERVER) + + # Keep track of the ems where this server is in, so it won't be lost when we access a server through a rack + result[:ems_id] = ems_id if ems_id + + result[:vendor] = "lenovo" + result[:type] = ParserDictionaryConstants::MIQ_TYPES["physical_server"] + result[:power_state] = ParserDictionaryConstants::POWER_STATE_MAP[node.powerStatus] + result[:health_state] = ParserDictionaryConstants::HEALTH_STATE_MAP[node.cmmHealthState.nil? ? node.cmmHealthState : node.cmmHealthState.downcase] + result[:host] = get_host_relationship(node.serialNumber) + result[:location_led_state] = find_loc_led_state(node.leds) + result[:computer_system][:hardware] = get_hardwares(node) + + return node.uuid, result + end + + private + + # Assign a physicalserver and host if server already exists and + # some host match with physical Server's serial number + def get_host_relationship(serial_number) + Host.find_by(:service_tag => serial_number) || + Host.joins(:hardware).find_by('hardwares.serial_number' => serial_number) + end + + # Find the identification led state + def find_loc_led_state(leds) + identification_led = leds.to_a.find { |led| ParserDictionaryConstants::PROPERTIES_MAP[:led_identify_name].include?(led["name"]) } + identification_led.try(:[], "state") + end + + def get_hardwares(node) + { + :disk_capacity => get_disk_capacity(node), + :memory_mb => get_memory_info(node), + :cpu_total_cores => get_total_cores(node), + :firmwares => get_firmwares(node), + :guest_devices => get_guest_devices(node) + } + end + + def get_disk_capacity(node) + total_disk_cap = 0 + node.raidSettings&.each do |storage| + storage['diskDrives']&.each do |disk| + total_disk_cap += disk['capacity'] unless disk['capacity'].nil? + end + end + total_disk_cap + end + + def get_memory_info(node) + total_memory_gigabytes = node.memoryModules&.reduce(0) { |total, mem| total + mem['capacity'] } + total_memory_gigabytes * 1024 # convert to megabytes + end + + def get_total_cores(node) + node.processors&.reduce(0) { |total, pr| total + pr['cores'] } + end + + def get_firmwares(node) + node.firmware&.map { |firmware| parse_firmware(firmware) } + end + + def get_guest_devices(node) + guest_devices = get_addin_cards(node) + guest_devices << parse_management_device(node) + end + + def parse_firmware(firmware) + { + :name => "#{firmware["role"]} #{firmware["name"]}-#{firmware["status"]}", + :build => firmware["build"], + :version => firmware["version"], + :release_date => firmware["date"], + } + end + + def get_addin_cards(node) + parsed_addin_cards = [] + # For each of the node's addin cards, parse the addin card and then see + # if it is already in the list of parsed addin cards. If it is, see if + # all of its ports are already in the existing parsed addin card entry. + # If it's not, then add the port to the existing addin card entry and + # don't add the card again to the list of parsed addin cards. + # This is needed because xclarity_client seems to represent each port + # as a separate addin card. The code below ensures that each addin + # card is represented by a single addin card with multiple ports. + node.addinCards&.each do |node_addin_card| + next unless get_device_type(node_addin_card) == "ethernet" + + add_card = true + parsed_node_addin_card = parse_addin_cards(node_addin_card) + + parsed_addin_cards.each do |addin_card| + next unless parsed_node_addin_card[:device_name] == addin_card[:device_name] || + parsed_node_addin_card[:location] == addin_card[:location] + + parsed_node_addin_card[:child_devices].each do |parsed_port| + card_found = false + addin_card[:child_devices].each do |port| + if parsed_port[:device_name] == port[:device_name] + card_found = true + end + end + unless card_found + addin_card[:child_devices].push(parsed_port) + add_card = false + end + end + end + + if add_card + parsed_addin_cards.push(parsed_node_addin_card) + end + end + + parsed_addin_cards + end + + def get_device_type(card) + device_type = "" + + unless card["name"].nil? + card_name = card["name"].downcase + if card_name.include?("nic") || card_name.include?("ethernet") + device_type = "ethernet" + end + end + device_type + end + + def parse_addin_cards(addin_card) + { + :device_name => addin_card["productName"], + :device_type => get_device_type(addin_card), + :firmwares => get_guest_device_firmware(addin_card), + :manufacturer => addin_card["manufacturer"], + :field_replaceable_unit => addin_card["FRU"], + :location => "Bay #{addin_card['slotNumber']}", + :child_devices => get_guest_device_ports(addin_card) + } + end + + def parse_management_device(node) + { + :device_type => "management", + :network => parse_management_network(node), + :address => node.macAddress + } + end + + def get_guest_device_firmware(card) + device_fw = [] + + unless card.nil? + firmware = card["firmware"] + unless firmware.nil? + device_fw = firmware.map do |fw| + parse_firmware(fw) + end + end + end + + device_fw + end + + def get_guest_device_ports(card) + device_ports = [] + + unless card.nil? + port_info = card["portInfo"] + physical_ports = port_info["physicalPorts"] + physical_ports&.each do |physical_port| + parsed_physical_port = parse_physical_port(physical_port) + logical_ports = physical_port["logicalPorts"] + parsed_logical_port = parse_logical_port(logical_ports[0]) + device_ports.push(parsed_logical_port.merge(parsed_physical_port)) + end + end + + device_ports + end + + def parse_physical_port(port) + { + :device_type => "physical_port", + :device_name => "Physical Port #{port['physicalPortIndex']}" + } + end + + def parse_management_network(node) + { + :ipaddress => node.mgmtProcIPaddress, + :ipv6address => node.ipv6Addresses.nil? ? node.ipv6Addresses : node.ipv6Addresses.join(", ") + } + end + + def parse_logical_port(port) + { + :address => format_mac_address(port["addresses"]) + } + end + + def format_mac_address(mac_address) + mac_address.scan(/\w{2}/).join(":") + end + end + end + end +end diff --git a/app/models/manageiq/providers/lenovo/physical_infra_manager/parsers/parser.rb b/app/models/manageiq/providers/lenovo/physical_infra_manager/parsers/parser.rb index 908fcddddf..fb713d739d 100644 --- a/app/models/manageiq/providers/lenovo/physical_infra_manager/parsers/parser.rb +++ b/app/models/manageiq/providers/lenovo/physical_infra_manager/parsers/parser.rb @@ -1,13 +1,17 @@ -# Class that provides methods to parse LXCA data to ManageIQ data. -# The parse methods inside this class works with versions: -# 1.3 -# 1.4 -# 2.0 -# If for a specific version needs some different strategy, please -# create a subclass overriding the old with the new parse strategy, and bind this subclass -# on +VERSION_PARSERS+ constant. module ManageIQ::Providers::Lenovo + # + # Class that provides methods to parse LXCA data to ManageIQ data. + # The parse methods inside this class works with versions: + # 1.3 + # 1.4 + # 2.0 + # If for a specific version needs some different strategy, please + # create a subclass overriding the old with the new parse strategy, and bind this subclass + # on +VERSION_PARSERS+ constant. + # class Parser + require_relative 'parsers' + # Suported API versions. # To support a new version with some subclass, update this constant like this: # '' => ManageIQ::Providers::Lenovo:: @@ -20,255 +24,20 @@ class Parser def self.get_instance(version) version_parser = version.match(/^(?:(\d+)\.?(\d+))/).to_s # getting just major and minor version parser = VERSION_PARSERS[version_parser] # getting the class that supports the version - parser = VERSION_PARSERS["default"] if parser.nil? + parser ||= VERSION_PARSERS['default'] parser.new end - # parse a node object to a hash with physical servers data - # +node+ - object containing physical server data - def parse_physical_server(node) - result = parse(node, dictionary::PHYSICAL_SERVER) - - result[:vendor] = "lenovo" - result[:type] = dictionary::MIQ_TYPES["physical_server"] - result[:power_state] = dictionary::POWER_STATE_MAP[node.powerStatus] - result[:health_state] = dictionary::HEALTH_STATE_MAP[node.cmmHealthState.nil? ? node.cmmHealthState : node.cmmHealthState.downcase] - result[:host] = get_host_relationship(node.serialNumber) - result[:location_led_state] = find_loc_led_state(node.leds) - result[:computer_system][:hardware] = get_hardwares(node) - - return node.uuid, result - end - - def parse_config_pattern(config_pattern) - return config_pattern.id, parse(config_pattern, dictionary::CONFIG_PATTERNS) - end - - # returns a dictionary used to translate some data on the rest api - # to system structure - def dictionary - ManageIQ::Providers::Lenovo::ParserDictionaryConstants - end - - private - - # Returns a hash containing the structure described on dictionary - # and with the values in the source. - # +source+ - Object that will be parse to a hash - # +dictionary+ - Hash containing the instructions to translate the object into a Hash - # See +ParserDictionaryConstants+ - def parse(source, dictionary) - result = {} - dictionary&.each do |key, value| - if value.kind_of?(String) - next if value.empty? - source_keys = value.split('.') # getting source keys navigation - source_value = source - source_keys.each do |source_key| - begin - attr_method = source_value.method(source_key) # getting method to get the attribute value - source_value = attr_method.call - rescue - # when the key doesn't correspond to a method - source_value = source_value[source_key] - end - end - result[key] = source_value - elsif value.kind_of?(Hash) - result[key] = parse(source, dictionary[key]) - end - end - result - end - - def parse_logical_port(port) - { - :address => format_mac_address(port["addresses"]) - } - end - - def format_mac_address(mac_address) - mac_address.scan(/\w{2}/).join(":") - end - - # Assign a physicalserver and host if server already exists and - # some host match with physical Server's serial number - def get_host_relationship(serial_number) - Host.find_by(:service_tag => serial_number) || - Host.joins(:hardware).find_by('hardwares.serial_number' => serial_number) - end - - # Find the identification led state - def find_loc_led_state(leds) - identification_led = leds.to_a.find { |led| dictionary::PROPERTIES_MAP[:led_identify_name].include?(led["name"]) } - identification_led.try(:[], "state") - end - - def get_hardwares(node) - { - :disk_capacity => get_disk_capacity(node), - :memory_mb => get_memory_info(node), - :cpu_total_cores => get_total_cores(node), - :firmwares => get_firmwares(node), - :guest_devices => get_guest_devices(node) - } - end - - def get_disk_capacity(node) - total_disk_cap = 0 - node.raidSettings&.each do |storage| - storage['diskDrives']&.each do |disk| - total_disk_cap += disk['capacity'] unless disk['capacity'].nil? - end - end - total_disk_cap - end - - def get_memory_info(node) - total_memory_gigabytes = node.memoryModules&.reduce(0) { |total, mem| total + mem['capacity'] } - total_memory_gigabytes * 1024 # convert to megabytes - end - - def get_total_cores(node) - node.processors&.reduce(0) { |total, pr| total + pr['cores'] } - end - - def get_firmwares(node) - node.firmware&.map { |firmware| parse_firmware(firmware) } - end - - def get_guest_devices(node) - guest_devices = get_addin_cards(node) - guest_devices << parse_management_device(node) - end - - def parse_firmware(firmware) - { - :name => "#{firmware["role"]} #{firmware["name"]}-#{firmware["status"]}", - :build => firmware["build"], - :version => firmware["version"], - :release_date => firmware["date"], - } - end - - def get_addin_cards(node) - parsed_addin_cards = [] - # For each of the node's addin cards, parse the addin card and then see - # if it is already in the list of parsed addin cards. If it is, see if - # all of its ports are already in the existing parsed addin card entry. - # If it's not, then add the port to the existing addin card entry and - # don't add the card again to the list of parsed addin cards. - # This is needed because xclarity_client seems to represent each port - # as a separate addin card. The code below ensures that each addin - # card is represented by a single addin card with multiple ports. - node.addinCards&.each do |node_addin_card| - next unless get_device_type(node_addin_card) == "ethernet" - - add_card = true - parsed_node_addin_card = parse_addin_cards(node_addin_card) - - parsed_addin_cards.each do |addin_card| - next unless parsed_node_addin_card[:device_name] == addin_card[:device_name] || - parsed_node_addin_card[:location] == addin_card[:location] - - parsed_node_addin_card[:child_devices].each do |parsed_port| - card_found = false - addin_card[:child_devices].each do |port| - if parsed_port[:device_name] == port[:device_name] - card_found = true - end - end - unless card_found - addin_card[:child_devices].push(parsed_port) - add_card = false - end - end - end - - if add_card - parsed_addin_cards.push(parsed_node_addin_card) - end - end - - parsed_addin_cards - end - - def get_device_type(card) - device_type = "" - - unless card["name"].nil? - card_name = card["name"].downcase - if card_name.include?("nic") || card_name.include?("ethernet") - device_type = "ethernet" - end - end - device_type - end - - def parse_management_device(node) - { - :device_type => "management", - :network => parse_management_network(node), - :address => node.macAddress - } - end - - def parse_management_network(node) - { - :ipaddress => node.mgmtProcIPaddress, - :ipv6address => node.ipv6Addresses.nil? ? node.ipv6Addresses : node.ipv6Addresses.join(", ") - } - end - - def parse_addin_cards(addin_card) - { - :device_name => addin_card["productName"], - :device_type => get_device_type(addin_card), - :firmwares => get_guest_device_firmware(addin_card), - :manufacturer => addin_card["manufacturer"], - :field_replaceable_unit => addin_card["FRU"], - :location => "Bay #{addin_card['slotNumber']}", - :child_devices => get_guest_device_ports(addin_card) - } + def parse_physical_rack(node, physical_servers) + Parsers::PhysicalRackParser.parse_physical_rack(node, physical_servers) end - def get_guest_device_firmware(card) - device_fw = [] - - unless card.nil? - firmware = card["firmware"] - unless firmware.nil? - device_fw = firmware.map do |fw| - parse_firmware(fw) - end - end - end - - device_fw + def parse_physical_server(node, ems_id = nil) + Parsers::PhysicalServerParser.parse_physical_server(node, ems_id) end - def get_guest_device_ports(card) - device_ports = [] - - unless card.nil? - port_info = card["portInfo"] - physical_ports = port_info["physicalPorts"] - physical_ports&.each do |physical_port| - parsed_physical_port = parse_physical_port(physical_port) - logical_ports = physical_port["logicalPorts"] - parsed_logical_port = parse_logical_port(logical_ports[0]) - device_ports.push(parsed_logical_port.merge(parsed_physical_port)) - end - end - - device_ports - end - - def parse_physical_port(port) - { - :device_type => "physical_port", - :device_name => "Physical Port #{port['physicalPortIndex']}" - } + def parse_config_pattern(config_pattern) + Parsers::ConfigPatternParser.parse_config_pattern(config_pattern) end end end diff --git a/app/models/manageiq/providers/lenovo/physical_infra_manager/parsers/parser_dictionary_constants.rb b/app/models/manageiq/providers/lenovo/physical_infra_manager/parsers/parser_dictionary_constants.rb index 499644900d..881f4296bc 100644 --- a/app/models/manageiq/providers/lenovo/physical_infra_manager/parsers/parser_dictionary_constants.rb +++ b/app/models/manageiq/providers/lenovo/physical_infra_manager/parsers/parser_dictionary_constants.rb @@ -1,76 +1,84 @@ module ManageIQ::Providers::Lenovo - # dictionary homologated for versions: - # 1.3 - class ParserDictionaryConstants - POWER_STATE_MAP = { - 8 => "on", - 5 => "off", - 18 => "Standby", - 0 => "Unknown" - }.freeze + module Parsers + # dictionary homologated for versions: + # 1.3 + class ParserDictionaryConstants + POWER_STATE_MAP = { + 8 => "on", + 5 => "off", + 18 => "Standby", + 0 => "Unknown" + }.freeze - HEALTH_STATE_MAP = { - "normal" => "Valid", - "non-critical" => "Valid", - "warning" => "Warning", - "critical" => "Critical", - "unknown" => "None", - "minor-failure" => "Critical", - "major-failure" => "Critical", - "non-recoverable" => "Critical", - "fatal" => "Critical", - nil => "Unknown" - }.freeze + HEALTH_STATE_MAP = { + "normal" => "Valid", + "non-critical" => "Valid", + "warning" => "Warning", + "critical" => "Critical", + "unknown" => "None", + "minor-failure" => "Critical", + "major-failure" => "Critical", + "non-recoverable" => "Critical", + "fatal" => "Critical", + nil => "Unknown" + }.freeze - MIQ_TYPES = { - "physical_server" => "ManageIQ::Providers::Lenovo::PhysicalInfraManager::PhysicalServer", - "template" => "ManageIQ::Providers::Lenovo::PhysicalInfraManager::Template", - }.freeze + MIQ_TYPES = { + "physical_server" => "ManageIQ::Providers::Lenovo::PhysicalInfraManager::PhysicalServer", + "template" => "ManageIQ::Providers::Lenovo::PhysicalInfraManager::Template", + }.freeze - PROPERTIES_MAP = { - :led_identify_name => %w(Identification Identify) - }.freeze + PROPERTIES_MAP = { + :led_identify_name => %w(Identification Identify) + }.freeze - # TRANSLATE HASHES BEGIN - # The translate hashes are used to parse an object to a hash - # where the translate hash keys are set as object hash keys - # and your values (string) corresponds to the attributes of the - # source object who the value will be set as value of the key of result hash. - # see +ManageIQ::Providers::Lenovo::Parse#parse+ - PHYSICAL_SERVER = { - :name => 'name', - :ems_ref => 'uuid', - :uid_ems => 'uuid', - :hostname => 'hostname', - :product_name => 'productName', - :manufacturer => 'manufacturer', - :machine_type => 'machineType', - :model => 'model', - :serial_number => 'serialNumber', - :field_replaceable_unit => 'FRU', - :asset_detail => { - :contact => 'contact', - :description => 'description', - :location => 'location.location', - :room => 'location.room', - :rack_name => 'location.rack', - :lowest_rack_unit => 'location.lowestRackUnit' - }, - :computer_system => { - :hardware => { - :guest_devices => '', - :firmwares => '' + # TRANSLATE HASHES BEGIN + # The translate hashes are used to parse an object to a hash + # where the translate hash keys are set as object hash keys + # and your values (string) corresponds to the attributes of the + # source object who the value will be set as value of the key of result hash. + # see +ManageIQ::Providers::Lenovo::Parse#parse+ + PHYSICAL_SERVER = { + :name => 'name', + :ems_ref => 'uuid', + :uid_ems => 'uuid', + :hostname => 'hostname', + :product_name => 'productName', + :manufacturer => 'manufacturer', + :machine_type => 'machineType', + :model => 'model', + :serial_number => 'serialNumber', + :field_replaceable_unit => 'FRU', + :asset_detail => { + :contact => 'contact', + :description => 'description', + :location => 'location.location', + :room => 'location.room', + :rack_name => 'location.rack', + :lowest_rack_unit => 'location.lowestRackUnit' }, - }, - }.freeze + :computer_system => { + :hardware => { + :guest_devices => '', + :firmwares => '' + }, + }, + }.freeze + + PHYSICAL_RACK = { + :name => 'cabinetName', + :uid_ems => 'UUID', + :ems_ref => 'UUID', + }.freeze - CONFIG_PATTERNS = { - :manager_ref => 'id', - :name => 'name', - :description => 'description', - :user_defined => 'userDefined', - :in_use => 'inUse' - }.freeze + CONFIG_PATTERNS = { + :manager_ref => 'id', + :name => 'name', + :description => 'description', + :user_defined => 'userDefined', + :in_use => 'inUse' + }.freeze # TRANSLATE HASH END + end end end diff --git a/app/models/manageiq/providers/lenovo/physical_infra_manager/parsers/parsers.rb b/app/models/manageiq/providers/lenovo/physical_infra_manager/parsers/parsers.rb new file mode 100644 index 0000000000..7a058fe021 --- /dev/null +++ b/app/models/manageiq/providers/lenovo/physical_infra_manager/parsers/parsers.rb @@ -0,0 +1,12 @@ +module ManageIQ::Providers::Lenovo + # + # Module that contains structures that provides the parse of LXCA + # informations to MiQ format + # + module Parsers + end +end + +require_relative 'components/physical_server_parser' +require_relative 'components/config_pattern_parser' +require_relative 'components/physical_rack_parser' \ No newline at end of file diff --git a/app/models/manageiq/providers/lenovo/physical_infra_manager/physical_rack.rb b/app/models/manageiq/providers/lenovo/physical_infra_manager/physical_rack.rb new file mode 100644 index 0000000000..27e7c3f0c4 --- /dev/null +++ b/app/models/manageiq/providers/lenovo/physical_infra_manager/physical_rack.rb @@ -0,0 +1,9 @@ +module ManageIQ::Providers + class Lenovo::PhysicalInfraManager::PhysicalRack < ::PhysicalRack + belongs_to :ext_management_system, :foreign_key => :ems_id, :inverse_of => :physical_racks, + :class_name => "ManageIQ::Providers::Lenovo::PhysicalInfraManager" + + has_many :physical_servers, :dependent => :destroy, :inverse_of => :physical_rack, + :class_name => "ManageIQ::Providers::Lenovo::PhysicalInfraManager::PhysicalServer" + end +end diff --git a/app/models/manageiq/providers/lenovo/physical_infra_manager/physical_server.rb b/app/models/manageiq/providers/lenovo/physical_infra_manager/physical_server.rb index b4e97d30ab..94226b3d22 100644 --- a/app/models/manageiq/providers/lenovo/physical_infra_manager/physical_server.rb +++ b/app/models/manageiq/providers/lenovo/physical_infra_manager/physical_server.rb @@ -1,4 +1,9 @@ module ManageIQ::Providers class Lenovo::PhysicalInfraManager::PhysicalServer < ::PhysicalServer + belongs_to :ext_management_system, :foreign_key => :ems_id, :inverse_of => :physical_servers, + :class_name => "ManageIQ::Providers::Lenovo::PhysicalInfraManager" + + belongs_to :physical_rack, :dependent => :destroy, :inverse_of => :physical_servers, + :class_name => "ManageIQ::Providers::Lenovo::PhysicalInfraManager::PhysicalRack" end end diff --git a/app/models/manageiq/providers/lenovo/physical_infra_manager/refresh_parser.rb b/app/models/manageiq/providers/lenovo/physical_infra_manager/refresh_parser.rb index c9e381ded4..28a702e45a 100644 --- a/app/models/manageiq/providers/lenovo/physical_infra_manager/refresh_parser.rb +++ b/app/models/manageiq/providers/lenovo/physical_infra_manager/refresh_parser.rb @@ -7,7 +7,7 @@ class PhysicalInfraManager::RefreshParser < EmsRefresh::Parsers::Infra require_relative './parsers/parser_dictionary_constants' def self.miq_template_type - ManageIQ::Providers::Lenovo::ParserDictionaryConstants::MIQ_TYPES["template"] + ManageIQ::Providers::Lenovo::Parsers::ParserDictionaryConstants::MIQ_TYPES["template"] end def initialize(ems, options = nil) @@ -30,7 +30,7 @@ def ems_inv_to_hashes $log.info("#{log_header}...") - get_physical_servers + get_physical_infra_from_rack discover_ip_physical_infra get_config_patterns @@ -47,40 +47,71 @@ def init_parser(connection) ManageIQ::Providers::Lenovo::Parser.get_instance(version) end - def get_physical_servers - nodes = all_server_resources + # Retrieve all physical infrastructure that can be obtained from a rack in LXCA (racks, chassis, servers) + # as XClarity objects and add it to the +@data+ as a hash. + def get_physical_infra_from_rack + cabinets = get_physical_racks + + # Retrieve the standalone rack (mock of a rack) so it is possible to retrieve all components + # from it and associate with the provider instead a mock rack. + standalone = nil + cabinets.reverse_each do |cab| + if cab.UUID == 'STANDALONE_OBJECT_UUID' + standalone = cabinets.delete(cab) + break + end + end - nodes = nodes.map do |node| - XClarityClient::Node.new node + # Process physical racks and all of its subcomponents. + process_collection(cabinets, :physical_racks) do |cab| + physical_servers = [] + get_physical_servers(cab) do |node| + _, parsed = @parser.parse_physical_server(node, @ems.id) + physical_servers << parsed + end + @parser.parse_physical_rack(cab, physical_servers) end + + # Process physical servers and all of its subcomponents. + nodes = get_physical_servers(standalone) process_collection(nodes, :physical_servers) { |node| @parser.parse_physical_server(node) } end - def get_config_patterns - config_patterns = @connection.discover_config_pattern - process_collection(config_patterns, :customization_scripts) { |config_pattern| @parser.parse_config_pattern(config_pattern) } + # Returns all physical rack from the api. + def get_physical_racks + @connection.discover_cabinet(:status => "includestandalone") end - def all_server_resources - return @all_server_resources if @all_server_resources - - cabinets = @connection.discover_cabinet(:status => "includestandalone") - - nodes = cabinets.map(&:nodeList).flatten - nodes = nodes.map do |node| - node["itemInventory"] - end.flatten - - chassis = cabinets.map(&:chassisList).flatten + # Create a XClarity Node object for every node in a rack. + # + # @param cabinet [PhysicalRack] The rack from where it will retrieve the physical servers. + # + # Yields a XClarity Node object. + # @return [Hash] a parsed hash for every PhysicalServer that belongs to the cabinet. + def get_physical_servers(cabinet) + return if cabinet.nil? + chassis = cabinet.chassisList nodes_chassis = chassis.map do |chassi| chassi["itemInventory"]["nodes"] end.flatten - nodes_chassis = nodes_chassis.select { |node| node["type"] != "SCU" } + nodes_chassis = nodes_chassis.reject { |node| node["type"] == "SCU" } + + nodes = cabinet.nodeList + nodes = nodes.map { |node| node["itemInventory"] } nodes += nodes_chassis - @all_server_resources = nodes + nodes.map do |node| + xc_node = XClarityClient::Node.new(node) + yield(xc_node) if block_given? + xc_node + end + end + + def get_config_patterns + config_patterns = @connection.discover_config_pattern + process_collection(config_patterns, :customization_scripts) { |config_pattern| @parser.parse_config_pattern(config_pattern) } end def discover_ip_physical_infra diff --git a/spec/models/manageiq/providers/lenovo/physical_infra_manager/refresh_parser_spec.rb b/spec/models/manageiq/providers/lenovo/physical_infra_manager/refresh_parser_spec.rb index fc4e4efb41..f2a6a355c7 100644 --- a/spec/models/manageiq/providers/lenovo/physical_infra_manager/refresh_parser_spec.rb +++ b/spec/models/manageiq/providers/lenovo/physical_infra_manager/refresh_parser_spec.rb @@ -42,11 +42,14 @@ end it 'will retrieve physical servers' do - expect(@result[:physical_servers].size).to eq(2) + physical_rack = @result[:physical_racks][0] + total_physical_servers = @result[:physical_servers].size + physical_rack[:physical_servers].size + expect(total_physical_servers).to eq(2) end it 'will retrieve addin cards on the physical servers' do - physical_server = @result[:physical_servers][0] + physical_rack = @result[:physical_racks][0] + physical_server = physical_rack[:physical_servers][0] computer_system = physical_server[:computer_system] hardware = computer_system[:hardware] guest_device = hardware[:guest_devices][0] @@ -67,7 +70,8 @@ end it 'will retrieve the amout of memory in MB' do - physical_server = @result[:physical_servers][0] + physical_rack = @result[:physical_racks][0] + physical_server = physical_rack[:physical_servers][0] memory_amount = physical_server[:computer_system][:hardware][:memory_mb] expect(memory_amount).to eq(16_384) end @@ -78,11 +82,16 @@ computer_system = physical_server_with_disk[:computer_system] hardware = computer_system[:hardware] - expect(hardware[:disk_capacity]).to eq(3_000_000_000_00) + physical_server_with_disk2 = @result[:physical_racks][0][:physical_servers][0] + computer_system2 = physical_server_with_disk2[:computer_system] + hardware2 = computer_system2[:hardware] + + expect(hardware[:disk_capacity]).to eq(0) + expect(hardware2[:disk_capacity]).to eq(300_000_000_000) end it 'will try to retrieve disk capacity from a physical server without RAID information' do - physical_server = @result[:physical_servers][1] + physical_server = @result[:physical_servers][0] computer_system = physical_server[:computer_system] hardware = computer_system[:hardware] @@ -90,6 +99,32 @@ end end + context 'retrieve physical rack info' do + let(:result) do + VCR.use_cassette("#{described_class.name.underscore}_ems_inv_to_hashes") do + ems_inv_to_hashes + end + end + + it 'will retrieve physical racks' do + expect(result[:physical_racks].size).to eq(1) + end + + it 'will retrieve physical racks fields' do + physical_rack = result[:physical_racks].first + + expect(physical_rack[:uid_ems]).to eq('096F8C92-08D4-4A24-ABD8-FE56D482F8C4') + expect(physical_rack[:name]).to eq('cabinet71') + end + + it 'will retrieve physical servers in physical racks' do + physical_rack = result[:physical_racks].first + physical_servers = physical_rack[:physical_servers] + + expect(physical_servers.size).to eq(1) + end + end + context 'parse config patterns' do before do @result = ems_inv_to_hashes diff --git a/spec/models/manageiq/providers/lenovo/physical_infra_manager/refresher_spec.rb b/spec/models/manageiq/providers/lenovo/physical_infra_manager/refresher_spec.rb index 24575d8b32..a21e774608 100644 --- a/spec/models/manageiq/providers/lenovo/physical_infra_manager/refresher_spec.rb +++ b/spec/models/manageiq/providers/lenovo/physical_infra_manager/refresher_spec.rb @@ -51,7 +51,8 @@ it 'will parse the legacy inventory' do result = refresher.parse_legacy_inventory(ems) - expect(result[:physical_servers].size).to eq(2) + expect(result[:physical_racks][0][:physical_servers].size).to eq(1) + expect(result[:physical_servers].size).to eq(3) end it 'will save the inventory' do