inventory_refresh 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. checksums.yaml +7 -0
  2. data/.codeclimate.yml +47 -0
  3. data/.gitignore +13 -0
  4. data/.rspec +4 -0
  5. data/.rspec_ci +4 -0
  6. data/.rubocop.yml +4 -0
  7. data/.rubocop_cc.yml +5 -0
  8. data/.rubocop_local.yml +2 -0
  9. data/.travis.yml +12 -0
  10. data/.yamllint +12 -0
  11. data/CHANGELOG.md +0 -0
  12. data/Gemfile +6 -0
  13. data/LICENSE +202 -0
  14. data/README.md +35 -0
  15. data/Rakefile +47 -0
  16. data/bin/console +14 -0
  17. data/bin/setup +8 -0
  18. data/inventory_refresh.gemspec +34 -0
  19. data/lib/inventory_refresh.rb +11 -0
  20. data/lib/inventory_refresh/application_record_iterator.rb +56 -0
  21. data/lib/inventory_refresh/application_record_reference.rb +15 -0
  22. data/lib/inventory_refresh/graph.rb +157 -0
  23. data/lib/inventory_refresh/graph/topological_sort.rb +66 -0
  24. data/lib/inventory_refresh/inventory_collection.rb +1175 -0
  25. data/lib/inventory_refresh/inventory_collection/data_storage.rb +178 -0
  26. data/lib/inventory_refresh/inventory_collection/graph.rb +170 -0
  27. data/lib/inventory_refresh/inventory_collection/index/proxy.rb +230 -0
  28. data/lib/inventory_refresh/inventory_collection/index/type/base.rb +80 -0
  29. data/lib/inventory_refresh/inventory_collection/index/type/data.rb +26 -0
  30. data/lib/inventory_refresh/inventory_collection/index/type/local_db.rb +286 -0
  31. data/lib/inventory_refresh/inventory_collection/index/type/skeletal.rb +116 -0
  32. data/lib/inventory_refresh/inventory_collection/reference.rb +96 -0
  33. data/lib/inventory_refresh/inventory_collection/references_storage.rb +106 -0
  34. data/lib/inventory_refresh/inventory_collection/scanner.rb +117 -0
  35. data/lib/inventory_refresh/inventory_collection/serialization.rb +140 -0
  36. data/lib/inventory_refresh/inventory_object.rb +303 -0
  37. data/lib/inventory_refresh/inventory_object_lazy.rb +151 -0
  38. data/lib/inventory_refresh/save_collection/base.rb +38 -0
  39. data/lib/inventory_refresh/save_collection/recursive.rb +52 -0
  40. data/lib/inventory_refresh/save_collection/saver/base.rb +390 -0
  41. data/lib/inventory_refresh/save_collection/saver/batch.rb +17 -0
  42. data/lib/inventory_refresh/save_collection/saver/concurrent_safe.rb +71 -0
  43. data/lib/inventory_refresh/save_collection/saver/concurrent_safe_batch.rb +632 -0
  44. data/lib/inventory_refresh/save_collection/saver/default.rb +57 -0
  45. data/lib/inventory_refresh/save_collection/saver/sql_helper.rb +85 -0
  46. data/lib/inventory_refresh/save_collection/saver/sql_helper_update.rb +120 -0
  47. data/lib/inventory_refresh/save_collection/saver/sql_helper_upsert.rb +196 -0
  48. data/lib/inventory_refresh/save_collection/topological_sort.rb +38 -0
  49. data/lib/inventory_refresh/save_inventory.rb +38 -0
  50. data/lib/inventory_refresh/target.rb +73 -0
  51. data/lib/inventory_refresh/target_collection.rb +80 -0
  52. data/lib/inventory_refresh/version.rb +3 -0
  53. data/tools/ci/create_db_user.sh +3 -0
  54. metadata +207 -0
@@ -0,0 +1,38 @@
1
+ require "inventory_refresh/graph"
2
+ require "inventory_refresh/inventory_collection/graph"
3
+ require "inventory_refresh/save_collection/base"
4
+
5
+ module InventoryRefresh::SaveCollection
6
+ class TopologicalSort < InventoryRefresh::SaveCollection::Base
7
+ class << self
8
+ # Saves the passed InventoryCollection objects by doing a topology sort of the graph, then going layer by layer
9
+ # and saving InventoryCollection object in each layer.
10
+ #
11
+ # @param ems [ExtManagementSystem] manager owning the inventory_collections
12
+ # @param inventory_collections [Array<InventoryRefresh::InventoryCollection>] array of InventoryCollection objects
13
+ # for saving
14
+ def save_collections(ems, inventory_collections)
15
+ graph = InventoryRefresh::InventoryCollection::Graph.new(inventory_collections)
16
+ graph.build_directed_acyclic_graph!
17
+
18
+ layers = InventoryRefresh::Graph::TopologicalSort.new(graph).topological_sort
19
+
20
+ #_log.debug("Saving manager #{ems.name}...")
21
+
22
+ #sorted_graph_log = "Topological sorting of manager #{ems.name} resulted in these layers processable in parallel:\n"
23
+ #sorted_graph_log += graph.to_graphviz(:layers => layers)
24
+ #_log.debug(sorted_graph_log)
25
+
26
+ layers.each_with_index do |layer, index|
27
+ #_log.debug("Saving manager #{ems.name} | Layer #{index}")
28
+ layer.each do |inventory_collection|
29
+ save_inventory_object_inventory(ems, inventory_collection) unless inventory_collection.saved?
30
+ end
31
+ #_log.debug("Saved manager #{ems.name} | Layer #{index}")
32
+ end
33
+
34
+ #_log.debug("Saving manager #{ems.name}...Complete")
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,38 @@
1
+ require "inventory_refresh/save_collection/recursive"
2
+ require "inventory_refresh/save_collection/topological_sort"
3
+
4
+ module InventoryRefresh
5
+ class SaveInventory
6
+ class << self
7
+ # Saves the passed InventoryCollection objects
8
+ #
9
+ # @param ems [ExtManagementSystem] manager owning the inventory_collections
10
+ # @param inventory_collections [Array<InventoryRefresh::InventoryCollection>] array of InventoryCollection objects
11
+ # for saving
12
+ def save_inventory(ems, inventory_collections, strategy = nil)
13
+ #_log.debug("#{log_header(ems)} Scanning Inventory Collections...Start")
14
+ InventoryRefresh::InventoryCollection::Scanner.scan!(inventory_collections)
15
+ #_log.debug("#{log_header(ems)} Scanning Inventory Collections...Complete")
16
+
17
+ #_log.info("#{log_header(ems)} Saving EMS Inventory...")
18
+
19
+ if strategy.try(:to_sym) == :recursive
20
+ InventoryRefresh::SaveCollection::Recursive.save_collections(ems, inventory_collections)
21
+ else
22
+ InventoryRefresh::SaveCollection::TopologicalSort.save_collections(ems, inventory_collections)
23
+ end
24
+
25
+ #_log.info("#{log_header(ems)} Saving EMS Inventory...Complete")
26
+ ems
27
+ end
28
+
29
+ private
30
+
31
+ # @param ems [ExtManagementSystem] manager owning the inventory_collections
32
+ # @return [String] helper string for logging
33
+ def log_header(ems)
34
+ "EMS: [#{ems.name}], id: [#{ems.id}]"
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,73 @@
1
+ module InventoryRefresh
2
+ class Target
3
+ attr_reader :association, :manager_ref, :event_id, :options
4
+
5
+ # @param association [Symbol] An existing association on Manager, that lists objects represented by a Target, naming
6
+ # should be the same of association of a counterpart InventoryCollection object
7
+ # @param manager_ref [Hash] A Hash that can be used to find_by on a given association and returning a unique object.
8
+ # The keys should be the same as the keys of the counterpart InventoryObject
9
+ # @param manager [ManageIQ::Providers::BaseManager] The Manager owning the Target
10
+ # @param manager_id [Integer] A primary key of the Manager owning the Target
11
+ # @param event_id [Integer] A primary key of the EmsEvent associated with the Target
12
+ # @param options [Hash] A free form options hash
13
+ def initialize(association:, manager_ref:, manager: nil, manager_id: nil, event_id: nil, options: {})
14
+ raise "Provide either :manager or :manager_id argument" if manager.nil? && manager_id.nil?
15
+
16
+ @manager = manager
17
+ @manager_id = manager_id
18
+ @association = association
19
+ @manager_ref = manager_ref
20
+ @event_id = event_id
21
+ @options = options
22
+ end
23
+
24
+ # A Rails recommended interface for deserializing an object
25
+ # @return [InventoryRefresh::Target] InventoryRefresh::Target instance
26
+ def self.load(*args)
27
+ new(*args)
28
+ end
29
+
30
+ # A Rails recommended interface for serializing an object
31
+ #
32
+ # @param obj [InventoryRefresh::Target] InventoryRefresh::Target instance we want to serialize
33
+ # @return [Hash] serialized object
34
+ def self.dump(obj)
35
+ obj.dump
36
+ end
37
+
38
+ # Returns a serialized InventoryRefresh::Target object. This can be used to initialize a new object, then the object
39
+ # target acts the same as the object InventoryRefresh::Target.new(target.serialize)
40
+ #
41
+ # @return [Hash] serialized object
42
+ def dump
43
+ {
44
+ :manager_id => manager_id,
45
+ :association => association,
46
+ :manager_ref => manager_ref,
47
+ :event_id => event_id,
48
+ :options => options
49
+ }
50
+ end
51
+
52
+ alias id dump
53
+ alias name manager_ref
54
+
55
+ # @return [ManageIQ::Providers::BaseManager] The Manager owning the Target
56
+ def manager
57
+ @manager || ManageIQ::Providers::BaseManager.find(@manager_id)
58
+ end
59
+
60
+ # @return [Integer] A primary key of the Manager owning the Target
61
+ def manager_id
62
+ @manager_id || manager.try(:id)
63
+ end
64
+
65
+ # Loads InventoryRefresh::Target ApplicationRecord representation from our DB, this requires that InventoryRefresh::Target
66
+ # has been refreshed, otherwise the AR object can be missing.
67
+ #
68
+ # @return [ApplicationRecord] A InventoryRefresh::Target loaded from the database as AR object
69
+ def load_from_db
70
+ manager.public_send(association).find_by(manager_ref)
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,80 @@
1
+ require "active_support/core_ext/module/delegation"
2
+
3
+ module InventoryRefresh
4
+ class TargetCollection
5
+ attr_reader :targets
6
+
7
+ delegate :<<, :to => :targets
8
+
9
+ # @param manager [ManageIQ::Providers::BaseManager] manager owning the TargetCollection
10
+ # @param manager_id [Integer] primary key of manager owning the TargetCollection
11
+ # @param event [EmsEvent] EmsEvent associated with the TargetCollection
12
+ # @param targets [Array<InventoryRefresh::Target, ApplicationRecord>] Array of InventoryRefresh::Target objects or
13
+ # ApplicationRecord objects
14
+ def initialize(manager: nil, manager_id: nil, event: nil, targets: [])
15
+ @manager = manager
16
+ @manager_id = manager_id
17
+ @event = event
18
+ @targets = targets
19
+ end
20
+
21
+ # @param association [Symbol] An existing association on Manager, that lists objects represented by a Target, naming
22
+ # should be the same of association of a counterpart InventoryCollection object
23
+ # @param manager_ref [Hash] A Hash that can be used to find_by on a given association and returning a unique object.
24
+ # The keys should be the same as the keys of the counterpart InventoryObject
25
+ # @param manager [ManageIQ::Providers::BaseManager] The Manager owning the Target
26
+ # @param manager_id [Integer] A primary key of the Manager owning the Target
27
+ # @param event_id [Integer] A primary key of the EmsEvent associated with the Target
28
+ # @param options [Hash] A free form options hash
29
+ def add_target(association:, manager_ref:, manager: nil, manager_id: nil, event_id: nil, options: {})
30
+ self << InventoryRefresh::Target.new(:association => association,
31
+ :manager_ref => manager_ref,
32
+ :manager => manager || @manager,
33
+ :manager_id => manager_id || @manager_id || @manager.try(:id),
34
+ :event_id => event_id || @event.try(:id),
35
+ :options => options)
36
+ end
37
+
38
+ # @return [String] A String containing a summary
39
+ def name
40
+ "Collection of #{targets.size} targets"
41
+ end
42
+
43
+ # @return [String] A String containing an id of each target in the TargetCollection
44
+ def id
45
+ "Collection of targets with id: #{targets.collect(&:name)}"
46
+ end
47
+
48
+ # Returns targets in a format:
49
+ # {
50
+ # :vms => {:ems_ref => Set.new(["vm_ref_1", "vm_ref2"])},
51
+ # :network_ports => {:ems_ref => Set.new(["network_port_1", "network_port2"])
52
+ # }
53
+ #
54
+ # Then we can quickly access all objects affected by:
55
+ # NetworkPort.where(target_collection.manager_refs_by_association[:network_ports].to_a) =>
56
+ # return AR objects with ems_refs ["network_port_1", "network_port2"]
57
+ # And we can get a list of ids for the API query by:
58
+ # target_collection.manager_refs_by_association[:network_ports][:ems_ref].to_a =>
59
+ # ["network_port_1", "network_port2"]
60
+ #
61
+ # Only targets of a type InventoryRefresh::Target are processed, any other targets present should be converted to
62
+ # InventoryRefresh::Target, e.g. in the Inventory::Collector code.
63
+ def manager_refs_by_association
64
+ @manager_refs_by_association ||= targets.select { |x| x.kind_of?(InventoryRefresh::Target) }.each_with_object({}) do |x, obj|
65
+ if obj[x.association].blank?
66
+ obj[x.association] = x.manager_ref.each_with_object({}) { |(key, value), hash| hash[key] = Set.new([value]) }
67
+ else
68
+ obj[x.association].each do |key, value|
69
+ value << x.manager_ref[key]
70
+ end
71
+ end
72
+ end
73
+ end
74
+
75
+ # Resets the cached @manager_refs_by_association to enforce reload when calling :manager_refs_by_association method
76
+ def manager_refs_by_association_reset
77
+ @manager_refs_by_association = nil
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,3 @@
1
+ module InventoryRefresh
2
+ VERSION = "0.0.1".freeze
3
+ end
@@ -0,0 +1,3 @@
1
+ #!/bin/bash
2
+
3
+ psql -c "CREATE USER root SUPERUSER PASSWORD 'smartvm';" -U postgres
metadata ADDED
@@ -0,0 +1,207 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: inventory_refresh
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - ManageIQ Developers
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2018-09-07 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activerecord
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 5.0.6
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 5.0.6
27
+ - !ruby/object:Gem::Dependency
28
+ name: more_core_extensions
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '3.5'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '3.5'
41
+ - !ruby/object:Gem::Dependency
42
+ name: pg
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: 0.18.2
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: 0.18.2
55
+ - !ruby/object:Gem::Dependency
56
+ name: ancestry
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: bundler
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '1.16'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '1.16'
83
+ - !ruby/object:Gem::Dependency
84
+ name: factory_girl
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: 4.5.0
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: 4.5.0
97
+ - !ruby/object:Gem::Dependency
98
+ name: rake
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '10.0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '10.0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: rspec
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: '3.0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: '3.0'
125
+ description: Topological Inventory Persister
126
+ email:
127
+ executables: []
128
+ extensions: []
129
+ extra_rdoc_files: []
130
+ files:
131
+ - ".codeclimate.yml"
132
+ - ".gitignore"
133
+ - ".rspec"
134
+ - ".rspec_ci"
135
+ - ".rubocop.yml"
136
+ - ".rubocop_cc.yml"
137
+ - ".rubocop_local.yml"
138
+ - ".travis.yml"
139
+ - ".yamllint"
140
+ - CHANGELOG.md
141
+ - Gemfile
142
+ - LICENSE
143
+ - README.md
144
+ - Rakefile
145
+ - bin/console
146
+ - bin/setup
147
+ - inventory_refresh.gemspec
148
+ - lib/inventory_refresh.rb
149
+ - lib/inventory_refresh/application_record_iterator.rb
150
+ - lib/inventory_refresh/application_record_reference.rb
151
+ - lib/inventory_refresh/graph.rb
152
+ - lib/inventory_refresh/graph/topological_sort.rb
153
+ - lib/inventory_refresh/inventory_collection.rb
154
+ - lib/inventory_refresh/inventory_collection/data_storage.rb
155
+ - lib/inventory_refresh/inventory_collection/graph.rb
156
+ - lib/inventory_refresh/inventory_collection/index/proxy.rb
157
+ - lib/inventory_refresh/inventory_collection/index/type/base.rb
158
+ - lib/inventory_refresh/inventory_collection/index/type/data.rb
159
+ - lib/inventory_refresh/inventory_collection/index/type/local_db.rb
160
+ - lib/inventory_refresh/inventory_collection/index/type/skeletal.rb
161
+ - lib/inventory_refresh/inventory_collection/reference.rb
162
+ - lib/inventory_refresh/inventory_collection/references_storage.rb
163
+ - lib/inventory_refresh/inventory_collection/scanner.rb
164
+ - lib/inventory_refresh/inventory_collection/serialization.rb
165
+ - lib/inventory_refresh/inventory_object.rb
166
+ - lib/inventory_refresh/inventory_object_lazy.rb
167
+ - lib/inventory_refresh/save_collection/base.rb
168
+ - lib/inventory_refresh/save_collection/recursive.rb
169
+ - lib/inventory_refresh/save_collection/saver/base.rb
170
+ - lib/inventory_refresh/save_collection/saver/batch.rb
171
+ - lib/inventory_refresh/save_collection/saver/concurrent_safe.rb
172
+ - lib/inventory_refresh/save_collection/saver/concurrent_safe_batch.rb
173
+ - lib/inventory_refresh/save_collection/saver/default.rb
174
+ - lib/inventory_refresh/save_collection/saver/sql_helper.rb
175
+ - lib/inventory_refresh/save_collection/saver/sql_helper_update.rb
176
+ - lib/inventory_refresh/save_collection/saver/sql_helper_upsert.rb
177
+ - lib/inventory_refresh/save_collection/topological_sort.rb
178
+ - lib/inventory_refresh/save_inventory.rb
179
+ - lib/inventory_refresh/target.rb
180
+ - lib/inventory_refresh/target_collection.rb
181
+ - lib/inventory_refresh/version.rb
182
+ - tools/ci/create_db_user.sh
183
+ homepage: https://github.com/ManageIQ/inventory_refresh
184
+ licenses:
185
+ - Apache-2.0
186
+ metadata: {}
187
+ post_install_message:
188
+ rdoc_options: []
189
+ require_paths:
190
+ - lib
191
+ required_ruby_version: !ruby/object:Gem::Requirement
192
+ requirements:
193
+ - - ">="
194
+ - !ruby/object:Gem::Version
195
+ version: '0'
196
+ required_rubygems_version: !ruby/object:Gem::Requirement
197
+ requirements:
198
+ - - ">="
199
+ - !ruby/object:Gem::Version
200
+ version: '0'
201
+ requirements: []
202
+ rubyforge_project:
203
+ rubygems_version: 2.6.14.1
204
+ signing_key:
205
+ specification_version: 4
206
+ summary: Topological Inventory Persister
207
+ test_files: []