app/models/manageiq/providers/inventory.rb
module ManageIQ::Providers
class Inventory
attr_accessor :collector, :parsers, :persister
# Entry point for building inventory
def self.build(ems, target)
collector = collector_class_for(ems, target).new(ems, target)
persister = persister_class_for(ems, target).new(ems, target)
new(
persister,
collector,
parser_classes_for(ems, target).map(&:new)
)
end
# @param persister [ManageIQ::Providers::Inventory::Persister] A Persister object
# @param collector [ManageIQ::Providers::Inventory::Collector] A Collector object
# @param parsers [ManageIQ::Providers::Inventory::Parser|Array] A Parser object or an array of
# ManageIQ::Providers::Inventory::Parser objects
def initialize(persister, collector, parsers)
@collector = collector
@persister = persister
@parsers = parsers.kind_of?(Array) ? parsers : [parsers]
end
# Call inventory collector to allow collection of inventory in separate step from parsing
def collect!
collector.collect
end
# Invokes all associated parsers storing parsed data into persister.inventory_collections
#
# @return [ManageIQ::Providers::Inventory::Persister] persister object, to allow chaining
def parse
parsers.each do |parser|
parser.collector = collector
parser.persister = persister
parser.parse
end
persister
end
# Returns all InventoryCollections contained in persister
#
# @return [Array<InventoryRefresh::InventoryCollection>] List of InventoryCollections objects
def inventory_collections
parse.inventory_collections
end
# Based on the given provider/manager class, this returns correct collector class
#
# @param ems class of the Provider/Manager
# @param target class of refresh's target
# @return [Class] Correct class name of the collector
def self.collector_class_for(ems, target = nil, manager_name = nil)
target = ems if target.nil?
class_for(ems, target, 'Collector', manager_name)
end
# Based on the given provider/manager class, this returns correct persister class
#
# @param ems class of the Provider/Manager
# @param target class of refresh's target
# @return [Class] Correct class name of the persister
def self.persister_class_for(ems, target = nil, manager_name = nil)
target = ems if target.nil?
class_for(ems, target, 'Persister', manager_name)
end
# Based on the given provider/manager class, this returns correct parser class
#
# @param ems class of the Provider/Manager
# @param target class of refresh's target
# @return [Class] Correct class name of the Parser
def self.parser_class_for(ems, target = nil, manager_name = nil)
target = ems if target.nil?
class_for(ems, target, 'Parser', manager_name)
end
# @param ems [ExtManagementSystem]
# @param target [ExtManagementSystem, InventoryRefresh::TargetCollection]
# @param type [String] 'Persister' | 'Collector' | 'Parser'
# @param manager_name [String, nil] @see default_manager_name
def self.class_for(ems, target, type, manager_name = nil)
ems_class = ems.instance_of?(Class) ? ems : ems.class
provider_module = ManageIQ::Providers::Inflector.provider_module(ems_class)
manager_name ||= parsed_manager_name(ems, target)
klass = "#{provider_module}::Inventory::#{type}::#{manager_name}".safe_constantize
# if class for given target doesn't exist, try to use class for default_manager (if defined)
if klass.nil? && default_manager_name.present? && manager_name != default_manager_name
klass = class_for(ems, target, type, default_manager_name)
end
klass
rescue ManageIQ::Providers::Inflector::ObjectNotNamespacedError => _err
nil
end
# Fallback manager name when persister/parser/collector not determined from refreshes' target
# @return [String, nil] i.e. 'CloudManager'
def self.default_manager_name
nil
end
# Last part of persister/parser/collector class name
# For example 'CloudManager' or 'StorageManager::Ebs'
def self.parsed_manager_name(_ems, target)
case target
when InventoryRefresh::TargetCollection
'TargetCollection'
else
klass = target.instance_of?(Class) ? target : target.class
suffix_arr = klass.name.split('::') - ManageIQ::Providers::Inflector.provider_module(klass).name.split("::")
suffix_arr.join('::')
end
rescue ManageIQ::Providers::Inflector::ObjectNotNamespacedError => _err
nil
end
# Multiple parser classes
# Can be implemented in subclass when custom set needed (mainly for TargetCollection)
def self.parser_classes_for(ems, target)
[parser_class_for(ems, target)]
end
end
end