Class: ProviderTagMapping::Mapper

Inherits:
Object
  • Object
show all
Defined in:
app/models/provider_tag_mapping/mapper.rb

Overview

Performs most of the work of ProviderTagMapping - holds current mappings, computes applicable tags, and creates/finds Tag records - except actually [un]assigning.

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(mappings, mapper_parameters = {}) ⇒ Mapper

Returns a new instance of Mapper.

Parameters:



17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
# File 'app/models/provider_tag_mapping/mapper.rb', line 17

def initialize(mappings, mapper_parameters = {})
  @parameters = mapper_parameters || {}

  # {[name, type, value] => [tag_id, ...]}
  @mappings = mappings.group_by { |m| [case_sensitive_labels? ? m.label_name : m.label_name&.downcase, m.labeled_resource_type, m.label_value].freeze }
                      .transform_values { |ms| ms.collect(&:tag_id) }

  require "inventory_refresh"
  @tags_to_resolve_collection = ::InventoryRefresh::InventoryCollection.new(
    :name              => :mapped_tags_to_resolve,
    :model_class       => Tag,
    # more than needed to identify, doesn't matter much as we use custom save
    :manager_ref       => [:category_tag_id, :entry_name, :entry_description],
    # :arel            => Tag.all,
    :custom_save_block => lambda do |_ems, inv_collection|
      # TODO: O(N) queries, optimize.
      inv_collection.each do |inv_object|
        inv_object.id ||= find_or_create_tag(inv_object.attributes)
      end
    end
  )

  @specific_tags_collection = ::InventoryRefresh::InventoryCollection.new(
    :name        => :mapped_specific_tags,
    :model_class => Tag,
    :manager_ref => [:id]
  )
end

Instance Attribute Details

#parametersObject (readonly)

Returns the value of attribute parameters.



14
15
16
# File 'app/models/provider_tag_mapping/mapper.rb', line 14

def parameters
  @parameters
end

#specific_tags_collectionInventoryCollection<Tag> (readonly)

Returns represents tags whose id is already known. Doesn’t require saving, not really interesting.

Returns:

  • (InventoryCollection<Tag>)

    represents tags whose id is already known. Doesn’t require saving, not really interesting.



12
13
14
# File 'app/models/provider_tag_mapping/mapper.rb', line 12

def specific_tags_collection
  @specific_tags_collection
end

#tags_to_resolve_collectionInventoryCollection<Tag> (readonly)

Returns a collection saving which will find/create (never delete) all tags referenced by #map_labels whose id is not yet known.

Returns:

  • (InventoryCollection<Tag>)

    a collection saving which will find/create (never delete) all tags referenced by #map_labels whose id is not yet known.



9
10
11
# File 'app/models/provider_tag_mapping/mapper.rb', line 9

def tags_to_resolve_collection
  @tags_to_resolve_collection
end

Class Method Details

.references_to_tags(tag_references) ⇒ Array<Tag>

Convert “tag references” to actual Tag objects. Must have been resolved to known id first.

Parameters:

  • tag_references (Array<InventoryObject>)

Returns:

  • (Array<Tag>)


97
98
99
100
101
102
# File 'app/models/provider_tag_mapping/mapper.rb', line 97

def self.references_to_tags(tag_references)
  ref_without_id = tag_references.detect { |ref| ref.id.nil? }
  raise "Unresolved tag reference #{ref_without_id}, must save tags_to_resolve_collection first" if ref_without_id

  Tag.find(tag_references.collect(&:id))
end

Instance Method Details

#cached_filter_single_value_category_tag_ids(category_tag_ids) ⇒ Object



50
51
52
53
54
55
56
57
58
59
60
61
62
63
# File 'app/models/provider_tag_mapping/mapper.rb', line 50

def cached_filter_single_value_category_tag_ids(category_tag_ids)
  @single_value_category_tag_ids ||= []
  @multiple_value_category_tag_ids ||= []

  tag_ids = category_tag_ids - @single_value_category_tag_ids - @multiple_value_category_tag_ids

  if tag_ids.present? # some tag ids are not cached yet
    single_value_tag_ids = Classification.where(:tag_id => tag_ids, :single_value => true).pluck(:tag_id)
    @single_value_category_tag_ids.concat(single_value_tag_ids)
    @multiple_value_category_tag_ids.concat(tag_ids - single_value_tag_ids)
  end

  @single_value_category_tag_ids & category_tag_ids
end

#case_sensitive_labels?Boolean

Returns:

  • (Boolean)


46
47
48
# File 'app/models/provider_tag_mapping/mapper.rb', line 46

def case_sensitive_labels?
  @parameters[:case_sensitive_labels]
end

#map_labels(type, labels) ⇒ Array<InventoryObject>

Compute desired tags, in intermediate form to be resolved later.

Parameters:

  • type (String)

    Matched against labeled_resource_type in mappings. May be resource_type of an actual label, but doesn’t have to; can be fake string such as ‘Vm’.

  • labels (Array)

    array of :value hashes.

Returns:

  • (Array<InventoryObject>)

    representing desired tags.



71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
# File 'app/models/provider_tag_mapping/mapper.rb', line 71

def map_labels(type, labels)
  inventory_objects = labels.collect_concat { |label| map_label(type, label) }.uniq

  inventory_objects_by_category = inventory_objects.group_by { |inventory_object| inventory_object[:category_tag_id] }

  single_value_tag_ids = cached_filter_single_value_category_tag_ids(inventory_objects_by_category.keys)

  inventory_objects_by_category.map do |category_tag_id, grouped_inventory_objects|
    if single_value_tag_ids.include?(category_tag_id)
      selected_inventory_object = grouped_inventory_objects.min_by { |x| x.data.fetch(:entry_name) }
      if grouped_inventory_objects.count > 1
        $log.warn("Label to Tag Mapper has encountered multiple mappings for the only single value tag category [Classification##{category_tag_id}]")
        possible_labels = grouped_inventory_objects.map { |x| x.data.fetch(:entry_description) }.join(', ')
        $log.warn("Only selected label value [#{selected_inventory_object.data.fetch(:entry_description)}] is going to be mapped (possible labels [#{possible_labels}]).")
      end

      selected_inventory_object
    else
      grouped_inventory_objects
    end
  end.flatten.compact
end