From a54b2415045b6569cdd26af3f0cbec3d8fa3c223 Mon Sep 17 00:00:00 2001 From: Martin Slemr Date: Mon, 27 Aug 2018 14:37:57 +0200 Subject: [PATCH 1/4] Generic Builder for inventory --- app/models/manageiq/providers/inventory.rb | 1 + .../manageiq/providers/inventory/builder.rb | 83 +++++++++++++++++++ 2 files changed, 84 insertions(+) create mode 100644 app/models/manageiq/providers/inventory/builder.rb diff --git a/app/models/manageiq/providers/inventory.rb b/app/models/manageiq/providers/inventory.rb index 7f4835a95f1..22a242594b2 100644 --- a/app/models/manageiq/providers/inventory.rb +++ b/app/models/manageiq/providers/inventory.rb @@ -3,6 +3,7 @@ class Inventory require_nested :Collector require_nested :Parser require_nested :Persister + require_nested :Builder attr_accessor :collector, :parsers, :persister diff --git a/app/models/manageiq/providers/inventory/builder.rb b/app/models/manageiq/providers/inventory/builder.rb new file mode 100644 index 00000000000..49e3f8b249a --- /dev/null +++ b/app/models/manageiq/providers/inventory/builder.rb @@ -0,0 +1,83 @@ +class ManageIQ::Providers::Inventory::Builder + class << self + # Defines collector, persister and parser classes + # and sends them to build inventory + # + # Builder for concrete provider has to define: + # - `allowed_manager_types()` + # - `default_manager_type()` + # + # Example: + # - for ems == target == ManageIQ::Providers::Amazon::CloudManager + # + # collector: ManageIQ::Providers::Amazon::Inventory:Collector::CloudManager + # parser: ManageIQ::Providers::Amazon::Inventory:Parser::CloudManager + # persister: ManageIQ::Providers::Amazon::Inventory:Persister::CloudManager + def build_inventory(ems, target) + manager_type = ManageIQ::Providers::Inflector.manager_type(target) + + manager_type = default_manager_type unless allowed_manager_types.include?(manager_type) + + collector_type = "#{collector_class}::#{manager_type}Manager".safe_constantize + persister_type = "#{persister_class}::#{manager_type}Manager".safe_constantize + parser_type = "#{parser_class}::#{manager_type}Manager".safe_constantize + + inventory(ems, target, collector_type, persister_type, [parser_type]) + end + + protected + + def inventory(manager, raw_target, collector_class, persister_class, parsers_classes) + collector = collector_class.new(manager, raw_target) + persister = persister_class.new(manager, raw_target) + + inventory_class.new( + persister, + collector, + parsers_classes.map(&:new) + ) + end + + # Concrete provider has to define manager_types as Array + # + # Example: + # %w(Cloud Network Infra) + def allowed_manager_types + raise NotImplementedError + end + + # Default manager type chosen if refresh target's class doesn't contain + # one of allowed_manager_types in name + # Example: 'Cloud' + def default_manager_type + raise NotImplementedError + end + + # Automatically chooses inventory class based on builder class + # Example: + # - ManageIQ::Providers::Amazon::Builder => ManageIQ::Providers::Amazon::Inventory + def inventory_class + "#{ManageIQ::Providers::Inflector.provider_module(self)}::Inventory".safe_constantize + rescue + ManageIQ::Providers::Inventory + end + + def collector_class + "#{inventory_class}::Collector".safe_constantize + rescue + ManageIQ::Providers::Inventory::Collector + end + + def parser_class + "#{inventory_class}::Parser".safe_constantize + rescue + ManageIQ::Providers::Inventory::Collector + end + + def persister_class + "#{inventory_class}::Persister".safe_constantize + rescue + ManageIQ::Providers::Inventory::Collector + end + end +end \ No newline at end of file From 5fc0e48c69774e37122eaa34ff6a2b3ac58a6885 Mon Sep 17 00:00:00 2001 From: Martin Slemr Date: Mon, 27 Aug 2018 21:07:52 +0200 Subject: [PATCH 2/4] Inventory Builder for TargetCollection --- .../manageiq/providers/inventory/builder.rb | 43 +++++++++++++------ 1 file changed, 31 insertions(+), 12 deletions(-) diff --git a/app/models/manageiq/providers/inventory/builder.rb b/app/models/manageiq/providers/inventory/builder.rb index 49e3f8b249a..18b426dfc26 100644 --- a/app/models/manageiq/providers/inventory/builder.rb +++ b/app/models/manageiq/providers/inventory/builder.rb @@ -14,15 +14,34 @@ class << self # parser: ManageIQ::Providers::Amazon::Inventory:Parser::CloudManager # persister: ManageIQ::Providers::Amazon::Inventory:Persister::CloudManager def build_inventory(ems, target) - manager_type = ManageIQ::Providers::Inflector.manager_type(target) + case target + when ManagerRefresh::TargetCollection + build_target_collection_inventory(ems, target) + else + manager_type = ManageIQ::Providers::Inflector.manager_type(target) - manager_type = default_manager_type unless allowed_manager_types.include?(manager_type) + manager_type = default_manager_type unless allowed_manager_types.include?(manager_type) - collector_type = "#{collector_class}::#{manager_type}Manager".safe_constantize - persister_type = "#{persister_class}::#{manager_type}Manager".safe_constantize - parser_type = "#{parser_class}::#{manager_type}Manager".safe_constantize + collector_type = "#{collector_class}::#{manager_type}Manager".safe_constantize + persister_type = "#{persister_class}::#{manager_type}Manager".safe_constantize + parser_type = "#{parser_class}::#{manager_type}Manager".safe_constantize - inventory(ems, target, collector_type, persister_type, [parser_type]) + inventory(ems, target, collector_type, persister_type, [parser_type]) + end + end + + def build_target_collection_inventory(ems, target) + parsers = allowed_manager_types.collect do |manager_type| + "#{parser_class}::#{manager_type}Manager".safe_constantize + end + + inventory( + ems, + target, + "#{collector_class}::TargetCollection".safe_constantize, + "#{persister_class}::TargetCollection".safe_constantize, + parsers + ) end protected @@ -50,34 +69,34 @@ def allowed_manager_types # one of allowed_manager_types in name # Example: 'Cloud' def default_manager_type - raise NotImplementedError + allowed_manager_types.first end # Automatically chooses inventory class based on builder class # Example: # - ManageIQ::Providers::Amazon::Builder => ManageIQ::Providers::Amazon::Inventory def inventory_class - "#{ManageIQ::Providers::Inflector.provider_module(self)}::Inventory".safe_constantize + "#{ManageIQ::Providers::Inflector.provider_module(self)}::Inventory".constantize rescue ManageIQ::Providers::Inventory end def collector_class - "#{inventory_class}::Collector".safe_constantize + "#{inventory_class}::Collector".constantize rescue ManageIQ::Providers::Inventory::Collector end def parser_class - "#{inventory_class}::Parser".safe_constantize + "#{inventory_class}::Parser".constantize rescue ManageIQ::Providers::Inventory::Collector end def persister_class - "#{inventory_class}::Persister".safe_constantize + "#{inventory_class}::Persister".constantize rescue ManageIQ::Providers::Inventory::Collector end end -end \ No newline at end of file +end From 3620846dc09146165882e14de73287abf8d0cf53 Mon Sep 17 00:00:00 2001 From: Martin Slemr Date: Thu, 30 Aug 2018 18:32:01 +0200 Subject: [PATCH 3/4] Moving Inventory::Builder function to Inventory class --- .../base_manager/manager_refresher.rb | 13 ++- app/models/manageiq/providers/inventory.rb | 96 +++++++++++++---- .../manageiq/providers/inventory/builder.rb | 102 ------------------ 3 files changed, 87 insertions(+), 124 deletions(-) delete mode 100644 app/models/manageiq/providers/inventory/builder.rb diff --git a/app/models/manageiq/providers/base_manager/manager_refresher.rb b/app/models/manageiq/providers/base_manager/manager_refresher.rb index 3252fec9d29..53dcc898eca 100644 --- a/app/models/manageiq/providers/base_manager/manager_refresher.rb +++ b/app/models/manageiq/providers/base_manager/manager_refresher.rb @@ -9,6 +9,11 @@ def builder_class_for(klass) "#{provider_module}::Builder".constantize end + def inventory_class_for(klass) + provider_module = ManageIQ::Providers::Inflector.provider_module(klass) + "#{provider_module}::Inventory".constantize + end + # Legacy inventory parser # # @param ems [ManageIQ::Providers::BaseManager] Manager we want to parse @@ -40,7 +45,13 @@ def collect_inventory_for_targets(ems, targets) _log.info("Filtering inventory for #{target.class} [#{target_name}] id: [#{target.id}]...") if ems.inventory_object_refresh? - inventory = builder_class_for(ems.class).build_inventory(ems, target) + # Tmp construction until all providers will be refactored + # to use `inventory_class_for` + begin + inventory = builder_class_for(ems.class).build_inventory(ems, target) + rescue NameError + inventory = inventory_class_for(ems.class).build(ems, target) + end end _log.info("Filtering inventory...Complete") diff --git a/app/models/manageiq/providers/inventory.rb b/app/models/manageiq/providers/inventory.rb index 22a242594b2..8ea3bf14687 100644 --- a/app/models/manageiq/providers/inventory.rb +++ b/app/models/manageiq/providers/inventory.rb @@ -3,30 +3,16 @@ class Inventory require_nested :Collector require_nested :Parser require_nested :Persister - require_nested :Builder attr_accessor :collector, :parsers, :persister - # Based on the given provider/manager class, this returns correct parser class - # - # @param klass class of the Provider/Manager - # @return [Class] Correct class name of the Parser - def self.parser_class_for(klass) - provider_module = ManageIQ::Providers::Inflector.provider_module(klass) - "#{provider_module}::Inventory::Parser::#{klass.name.demodulize}".safe_constantize - rescue ManageIQ::Providers::Inflector::ObjectNotNamespacedError => _err - nil - end - - # Based on the given provider/manager class, this returns correct persister class - # - # @param klass class of the Provider/Manager - # @return [Class] Correct class name of the persister - def self.persister_class_for(klass) - provider_module = ManageIQ::Providers::Inflector.provider_module(klass) - "#{provider_module}::Inventory::Persister::#{klass.name.demodulize}".safe_constantize - rescue ManageIQ::Providers::Inflector::ObjectNotNamespacedError => _err - nil + # Entry point for building inventory + def self.build(ems, target) + new( + class_for(ems, target, 'Persister').new(ems, target), + class_for(ems, target, 'Collector').new(ems, target), + parser_classes_for(ems, target).map(&:new) + ) end # @param persister [ManageIQ::Providers::Inventory::Persister] A Persister object @@ -58,5 +44,73 @@ def parse def inventory_collections parse.inventory_collections end + + # Based on the given provider/manager class, this returns correct persister class + # + # @param klass class of the Provider/Manager + # @return [Class] Correct class name of the persister + def self.persister_class_for(klass) + provider_module = ManageIQ::Providers::Inflector.provider_module(klass) + "#{provider_module}::Inventory::Persister::#{klass.name.demodulize}".safe_constantize + rescue ManageIQ::Providers::Inflector::ObjectNotNamespacedError => _err + nil + end + + # Based on the given provider/manager class, this returns correct parser class + # + # @param klass class of the Provider/Manager + # @return [Class] Correct class name of the Parser + def self.parser_class_for(klass) + provider_module = ManageIQ::Providers::Inflector.provider_module(klass) + "#{provider_module}::Inventory::Parser::#{klass.name.demodulize}".safe_constantize + rescue ManageIQ::Providers::Inflector::ObjectNotNamespacedError => _err + nil + end + + # @param ems [ExtManagementSystem] + # @param target [ExtManagementSystem, ManagerRefresh::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) + provider_module = ManageIQ::Providers::Inflector.provider_module(ems.class) + + manager_name = parsed_manager_name(target) if manager_name.nil? + + 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(target) + case target + when ManagerRefresh::TargetCollection + 'TargetCollection' + else + klass = target.class == 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) + [class_for(ems, target, 'Parser')] + end end end diff --git a/app/models/manageiq/providers/inventory/builder.rb b/app/models/manageiq/providers/inventory/builder.rb deleted file mode 100644 index 18b426dfc26..00000000000 --- a/app/models/manageiq/providers/inventory/builder.rb +++ /dev/null @@ -1,102 +0,0 @@ -class ManageIQ::Providers::Inventory::Builder - class << self - # Defines collector, persister and parser classes - # and sends them to build inventory - # - # Builder for concrete provider has to define: - # - `allowed_manager_types()` - # - `default_manager_type()` - # - # Example: - # - for ems == target == ManageIQ::Providers::Amazon::CloudManager - # - # collector: ManageIQ::Providers::Amazon::Inventory:Collector::CloudManager - # parser: ManageIQ::Providers::Amazon::Inventory:Parser::CloudManager - # persister: ManageIQ::Providers::Amazon::Inventory:Persister::CloudManager - def build_inventory(ems, target) - case target - when ManagerRefresh::TargetCollection - build_target_collection_inventory(ems, target) - else - manager_type = ManageIQ::Providers::Inflector.manager_type(target) - - manager_type = default_manager_type unless allowed_manager_types.include?(manager_type) - - collector_type = "#{collector_class}::#{manager_type}Manager".safe_constantize - persister_type = "#{persister_class}::#{manager_type}Manager".safe_constantize - parser_type = "#{parser_class}::#{manager_type}Manager".safe_constantize - - inventory(ems, target, collector_type, persister_type, [parser_type]) - end - end - - def build_target_collection_inventory(ems, target) - parsers = allowed_manager_types.collect do |manager_type| - "#{parser_class}::#{manager_type}Manager".safe_constantize - end - - inventory( - ems, - target, - "#{collector_class}::TargetCollection".safe_constantize, - "#{persister_class}::TargetCollection".safe_constantize, - parsers - ) - end - - protected - - def inventory(manager, raw_target, collector_class, persister_class, parsers_classes) - collector = collector_class.new(manager, raw_target) - persister = persister_class.new(manager, raw_target) - - inventory_class.new( - persister, - collector, - parsers_classes.map(&:new) - ) - end - - # Concrete provider has to define manager_types as Array - # - # Example: - # %w(Cloud Network Infra) - def allowed_manager_types - raise NotImplementedError - end - - # Default manager type chosen if refresh target's class doesn't contain - # one of allowed_manager_types in name - # Example: 'Cloud' - def default_manager_type - allowed_manager_types.first - end - - # Automatically chooses inventory class based on builder class - # Example: - # - ManageIQ::Providers::Amazon::Builder => ManageIQ::Providers::Amazon::Inventory - def inventory_class - "#{ManageIQ::Providers::Inflector.provider_module(self)}::Inventory".constantize - rescue - ManageIQ::Providers::Inventory - end - - def collector_class - "#{inventory_class}::Collector".constantize - rescue - ManageIQ::Providers::Inventory::Collector - end - - def parser_class - "#{inventory_class}::Parser".constantize - rescue - ManageIQ::Providers::Inventory::Collector - end - - def persister_class - "#{inventory_class}::Persister".constantize - rescue - ManageIQ::Providers::Inventory::Collector - end - end -end From f3fd91df916f7e414cf4f9dd82108fbe379fd3e3 Mon Sep 17 00:00:00 2001 From: Adam Grare Date: Fri, 31 Aug 2018 13:46:08 -0400 Subject: [PATCH 4/4] Remove trailing whitespace --- app/models/manageiq/providers/inventory.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/manageiq/providers/inventory.rb b/app/models/manageiq/providers/inventory.rb index 8ea3bf14687..26f21c3b687 100644 --- a/app/models/manageiq/providers/inventory.rb +++ b/app/models/manageiq/providers/inventory.rb @@ -73,7 +73,7 @@ def self.parser_class_for(klass) # @param manager_name [String, nil] @see default_manager_name def self.class_for(ems, target, type, manager_name = nil) provider_module = ManageIQ::Providers::Inflector.provider_module(ems.class) - + manager_name = parsed_manager_name(target) if manager_name.nil? klass = "#{provider_module}::Inventory::#{type}::#{manager_name}".safe_constantize