ManageIQ/inventory_refresh

View on GitHub
lib/inventory_refresh/target_collection.rb

Summary

Maintainability
A
0 mins
Test Coverage
A
100%
require "active_support/core_ext/module/delegation"

module InventoryRefresh
  class TargetCollection
    attr_reader :targets

    delegate :<<, :to => :targets

    # @param manager [ManageIQ::Providers::BaseManager] manager owning the TargetCollection
    # @param manager_id [Integer] primary key of manager owning the TargetCollection
    # @param event [EmsEvent] EmsEvent associated with the TargetCollection
    # @param targets [Array<InventoryRefresh::Target, ApplicationRecord>] Array of InventoryRefresh::Target objects or
    #                ApplicationRecord objects
    def initialize(manager: nil, manager_id: nil, event: nil, targets: [])
      @manager    = manager
      @manager_id = manager_id
      @event      = event
      @targets    = targets
    end

    # @param association [Symbol] An existing association on Manager, that lists objects represented by a Target, naming
    #                             should be the same of association of a counterpart InventoryCollection object
    # @param manager_ref [Hash] A Hash that can be used to find_by on a given association and returning a unique object.
    #                           The keys should be the same as the keys of the counterpart InventoryObject
    # @param manager [ManageIQ::Providers::BaseManager] The Manager owning the Target
    # @param manager_id [Integer] A primary key of the Manager owning the Target
    # @param event_id [Integer] A primary key of the EmsEvent associated with the Target
    # @param options [Hash] A free form options hash
    def add_target(association:, manager_ref:, manager: nil, manager_id: nil, event_id: nil, options: {})
      self << InventoryRefresh::Target.new(:association => association,
                                           :manager_ref => manager_ref,
                                           :manager     => manager || @manager,
                                           :manager_id  => manager_id || @manager_id || @manager.try(:id),
                                           :event_id    => event_id || @event.try(:id),
                                           :options     => options)
    end

    # @return [String] A String containing a summary
    def name
      "Collection of #{targets.size} targets"
    end

    # @return [String] A String containing an id of each target in the TargetCollection
    def id
      "Collection of targets with id: #{targets.collect(&:name)}"
    end

    # Returns targets in a format:
    #   {
    #     :vms => {:ems_ref => Set.new(["vm_ref_1", "vm_ref2"])},
    #     :network_ports => {:ems_ref => Set.new(["network_port_1", "network_port2"])
    #   }
    #
    # Then we can quickly access all objects affected by:
    #   NetworkPort.where(target_collection.manager_refs_by_association[:network_ports].to_a) =>
    #     return AR objects with ems_refs ["network_port_1", "network_port2"]
    # And we can get a list of ids for the API query by:
    #   target_collection.manager_refs_by_association[:network_ports][:ems_ref].to_a =>
    #     ["network_port_1", "network_port2"]
    #
    # Only targets of a type InventoryRefresh::Target are processed, any other targets present should be converted to
    # InventoryRefresh::Target, e.g. in the Inventory::Collector code.
    def manager_refs_by_association
      @manager_refs_by_association ||= targets.select { |x| x.kind_of?(InventoryRefresh::Target) }.each_with_object({}) do |x, obj|
        if obj[x.association].blank?
          obj[x.association] = x.manager_ref.each_with_object({}) { |(key, value), hash| hash[key] = Set.new([value]) }
        else
          obj[x.association].each do |key, value|
            value << x.manager_ref[key]
          end
        end
      end
    end

    # Resets the cached @manager_refs_by_association to enforce reload when calling :manager_refs_by_association method
    def manager_refs_by_association_reset
      @manager_refs_by_association = nil
    end

    # Returns list of ems_refs
    # @return [Array<String>]
    def references(collection)
      manager_refs_by_association.try(:[], collection).try(:[], :ems_ref)&.to_a || []
    end

    # Returns list of names
    # @return [Array<String>]
    def name_references(collection)
      manager_refs_by_association.try(:[], collection).try(:[], :name)&.to_a || []
    end
  end
end