Class: CemAcpt::NodeInventory
- Inherits:
-
Object
- Object
- CemAcpt::NodeInventory
- Includes:
- Logging
- Defined in:
- lib/cem_acpt/shared_objects.rb
Overview
Provides a thread-safe inventory of test nodes.
Constant Summary
Constants included from Logging
Instance Attribute Summary collapse
-
#save_file_path ⇒ Object
Returns the value of attribute save_file_path.
Instance Method Summary collapse
-
#add(node_name, node_data) ⇒ Object
Adds a new node to the inventory.
-
#claim(node_name) ⇒ String
Claims a node, which returns the node data and adds that node to the claimed set.
-
#claim_by_property(property_path, value) ⇒ String
Claims a node based on a property of the node data and a value that property should equal.
-
#claimed?(node_name) ⇒ Boolean
Checks if a node is claimed.
- #clean_local_files(file_path = @save_file_path) ⇒ Object
-
#clear! ⇒ Object
Clears the inventory and removes claimed nodes.
-
#clear_no_lock! ⇒ Object
Clears the inventory and removes claimed nodes.
-
#delete(node_name) ⇒ Object
Deletes a node from the inventory.
-
#get(node_name) ⇒ Object
Returns the node data for a given node.
-
#get_all_properties(property_path) ⇒ Array
Returns all property values of all nodes for the given property path.
-
#get_by_property(property_path, value) ⇒ Array
Returns the node_name and node_data for a given node that has a matching value for the given property.
-
#initialize ⇒ NodeInventory
constructor
A new instance of NodeInventory.
-
#load(file_path = @save_file_path) ⇒ Object
Loads a node inventory from a yaml file.
-
#load_no_lock!(file_path = @save_file_path) ⇒ Object
Loads a node inventory from a file.
-
#merge!(node_name, new_node_data) ⇒ Object
Merges new node data in with the existing node data for the given node.
-
#node_to_json(node_name, *args) ⇒ Object
Returns a JSON string of a specific node's node data.
-
#node_to_yaml(node_name) ⇒ Object
Returns a YAML string of a specific node's node data.
-
#nodes ⇒ Object
Returns all node names in the current inventory.
-
#property?(node_name, property_path) ⇒ Boolean
Checks if the inventory contains a node with the given property.
-
#save(file_path = @save_file_path) ⇒ Object
Saves the current node inventory to a yaml file.
-
#save_no_lock!(file_path = @save_file_path) ⇒ Object
Saves the current node inventory to a file.
-
#save_on_claim ⇒ Object
When called, enables saving the inventory to a file on claim.
-
#save_on_claim? ⇒ Boolean
Checks if save_on_claim is enabled.
-
#set(node_name, property_path, value) ⇒ Object
Sets a specific property on a node in the inventory.
-
#to_h ⇒ Object
Returns a hash of the inventory.
-
#to_json(*args) ⇒ Object
Returns a JSON string of the inventory.
-
#to_yaml ⇒ Object
Returns a YAML string of the inventory.
- #update(node_name, node_data) ⇒ Object
- #update_no_lock! ⇒ Object
Methods included from Logging
current_log_config, #current_log_config, current_log_format, #current_log_format, current_log_level, #current_log_level, included, logger, #logger, new_log_config, #new_log_config, new_log_formatter, #new_log_formatter, new_log_level, #new_log_level, new_logger, #new_logger
Constructor Details
#initialize ⇒ NodeInventory
Returns a new instance of NodeInventory.
187 188 189 190 191 192 193 194 |
# File 'lib/cem_acpt/shared_objects.rb', line 187 def initialize @inventory = Concurrent::Map.new @lock = Concurrent::ReadWriteLock.new @claimed = Concurrent::Set.new @save_on_claim = false @save_file_path = 'spec/fixtures/node_inventory' @loaded_node_inv = nil end |
Instance Attribute Details
#save_file_path ⇒ Object
Returns the value of attribute save_file_path.
185 186 187 |
# File 'lib/cem_acpt/shared_objects.rb', line 185 def save_file_path @save_file_path end |
Instance Method Details
#add(node_name, node_data) ⇒ Object
Adds a new node to the inventory.
209 210 211 |
# File 'lib/cem_acpt/shared_objects.rb', line 209 def add(node_name, node_data) @inventory.put_if_absent(node_name, node_data) end |
#claim(node_name) ⇒ String
Claims a node, which returns the node data and adds that node to the claimed set. Raises an error if the node is already claimed or does not exist. This is used during acceptance testing to ensure that nodes are not reused.
292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 |
# File 'lib/cem_acpt/shared_objects.rb', line 292 def claim(node_name) with_lock_retry(:write) do unless @inventory.keys.include?(node_name) raise NodeDoesNotExistError, "Node #{node_name} does not exist in inventory" end if @claimed.include?(node_name) raise NodeClaimedError, "Node #{node_name} is already tainted and cannot be claimed" end @claimed.add(node_name) save_no_lock!(@save_file_path) if @save_on_claim node_name end end |
#claim_by_property(property_path, value) ⇒ String
Claims a node based on a property of the node data and a value that property should equal. If a node is found but is already claimed, the method will continue to search for an unclaimed node. Raises an error if no valid node is found. This is used during acceptance testing to ensure that nodes are not reused.
316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 |
# File 'lib/cem_acpt/shared_objects.rb', line 316 def claim_by_property(property_path, value) attempts ||= 1 claim_name = nil @inventory.each_pair do |node_name, node_data| next if @claimed.include?(node_name) claim_name = node_name if node_data.dot_dig(property_path) == value end raise NodeDoesNotExistError, "No node found with property #{property_path} == #{value}" if claim_name.nil? claim(claim_name) rescue NodeDoesNotExistError => e # We sleep than retry three times to help mitigate race conditions if (attempts += 1) <= 3 sleep(1) retry else raise e end end |
#claimed?(node_name) ⇒ Boolean
Checks if a node is claimed.
278 279 280 281 282 |
# File 'lib/cem_acpt/shared_objects.rb', line 278 def claimed?(node_name) raise NodeDoesNotExistError, "Node #{node_name} does not exist" unless @inventory.keys.include?(node_name) @claimed.include?(node_name) end |
#clean_local_files(file_path = @save_file_path) ⇒ Object
448 449 450 451 452 |
# File 'lib/cem_acpt/shared_objects.rb', line 448 def clean_local_files(file_path = @save_file_path) Dir.glob('*.yaml', base: file_path) do |file_name| File.delete(File.(File.join(file_path, file_name))) end end |
#clear! ⇒ Object
Clears the inventory and removes claimed nodes. Thread-safe.
356 357 358 359 360 |
# File 'lib/cem_acpt/shared_objects.rb', line 356 def clear! with_lock_retry(:write) do clear_no_lock! end end |
#clear_no_lock! ⇒ Object
Clears the inventory and removes claimed nodes. DOES NOT USE LOCK. If this is called outside of a lock, it will not be thread-safe.
350 351 352 353 |
# File 'lib/cem_acpt/shared_objects.rb', line 350 def clear_no_lock! nodes.each { |node| delete(node) } @claimed.clear end |
#delete(node_name) ⇒ Object
Deletes a node from the inventory.
339 340 341 |
# File 'lib/cem_acpt/shared_objects.rb', line 339 def delete(node_name) @inventory.delete(node_name) end |
#get(node_name) ⇒ Object
Returns the node data for a given node.
219 220 221 |
# File 'lib/cem_acpt/shared_objects.rb', line 219 def get(node_name) @inventory[node_name] end |
#get_all_properties(property_path) ⇒ Array
Returns all property values of all nodes for the given property path
245 246 247 248 249 250 251 252 253 254 255 256 |
# File 'lib/cem_acpt/shared_objects.rb', line 245 def get_all_properties(property_path) found = [] @inventory.each_pair do |_, node_data| prop = node_data.dot_dig(property_path) next unless prop found << prop end raise PropertyNotFoundError, "No property with path #{property_path} found in nodes" if found.empty? found.freeze end |
#get_by_property(property_path, value) ⇒ Array
Returns the node_name and node_data for a given node that has a matching value for the given property.
229 230 231 232 233 234 235 236 237 238 239 |
# File 'lib/cem_acpt/shared_objects.rb', line 229 def get_by_property(property_path, value) found = [] @inventory.each_pair do |node_name, node_data| next unless node_data.dot_dig(property_path) == value found = [node_name, node_data].freeze end raise NodeDoesNotExistError, "No node found with property #{property_path} == #{value}" if found.empty? found end |
#load(file_path = @save_file_path) ⇒ Object
Loads a node inventory from a yaml file. Thread-safe.
442 443 444 445 446 |
# File 'lib/cem_acpt/shared_objects.rb', line 442 def load(file_path = @save_file_path) with_lock_retry(:write) do load_no_lock!(file_path) end end |
#load_no_lock!(file_path = @save_file_path) ⇒ Object
Loads a node inventory from a file. DOES NOT USE LOCK. If this is called outside of a lock, it will not be thread-safe.
423 424 425 426 427 428 429 430 431 432 433 434 435 436 |
# File 'lib/cem_acpt/shared_objects.rb', line 423 def load_no_lock!(file_path = @save_file_path) require 'net/ssh/proxy/command' # If ProxyCommand is used in ssh options, this is required. attempts ||= 1 Dir.glob('*.yaml', base: file_path) do |file_name| node_name = File.basename(file_name, '.yaml') node_data = YAML.load_file(File.join(file_path, file_name)) add(node_name, node_data) || update(node_name, node_data) end rescue StandardError => e raise e unless (attempts += 1) <= 3 sleep(1) retry end |
#merge!(node_name, new_node_data) ⇒ Object
Merges new node data in with the existing node data for the given node.
269 270 271 272 273 |
# File 'lib/cem_acpt/shared_objects.rb', line 269 def merge!(node_name, new_node_data) @inventory.merge_pair(node_name, new_node_data) do |old_data| old_data.deep_merge(new_node_data) end end |
#node_to_json(node_name, *args) ⇒ Object
Returns a JSON string of a specific node's node data
385 386 387 |
# File 'lib/cem_acpt/shared_objects.rb', line 385 def node_to_json(node_name, *args) get(node_name).to_h.to_json(*args) end |
#node_to_yaml(node_name) ⇒ Object
Returns a YAML string of a specific node's node data
380 381 382 |
# File 'lib/cem_acpt/shared_objects.rb', line 380 def node_to_yaml(node_name) get(node_name).to_h.to_yaml end |
#nodes ⇒ Object
Returns all node names in the current inventory.
344 345 346 |
# File 'lib/cem_acpt/shared_objects.rb', line 344 def nodes @inventory.keys end |
#property?(node_name, property_path) ⇒ Boolean
Checks if the inventory contains a node with the given property.
365 366 367 |
# File 'lib/cem_acpt/shared_objects.rb', line 365 def property?(node_name, property_path) !!@inventory[node_name].dot_dig(property_path) end |
#save(file_path = @save_file_path) ⇒ Object
Saves the current node inventory to a yaml file. Thread-safe.
415 416 417 418 419 |
# File 'lib/cem_acpt/shared_objects.rb', line 415 def save(file_path = @save_file_path) with_lock_retry(:write) do save_no_lock!(file_path) end end |
#save_no_lock!(file_path = @save_file_path) ⇒ Object
Saves the current node inventory to a file. DOES NOT USE LOCK. If this is called outside of a lock, it will not be thread-safe.
401 402 403 404 405 406 407 408 409 410 411 |
# File 'lib/cem_acpt/shared_objects.rb', line 401 def save_no_lock!(file_path = @save_file_path) Dir.mkdir(file_path) unless Dir.exist?(file_path) @inventory.each_pair do |node_name, node_data| path = File.join(file_path, "#{node_name}.yaml") next if File.file?(path) File.open(path, 'w') do |f| f.write(node_data.to_h.to_yaml) end end end |
#save_on_claim ⇒ Object
When called, enables saving the inventory to a file on claim.
197 198 199 |
# File 'lib/cem_acpt/shared_objects.rb', line 197 def save_on_claim @save_on_claim = true end |
#save_on_claim? ⇒ Boolean
Checks if save_on_claim is enabled.
202 203 204 |
# File 'lib/cem_acpt/shared_objects.rb', line 202 def save_on_claim? @save_on_claim end |
#set(node_name, property_path, value) ⇒ Object
Sets a specific property on a node in the inventory.
262 263 264 |
# File 'lib/cem_acpt/shared_objects.rb', line 262 def set(node_name, property_path, value) @inventory[node_name].dot_store(property_path, value) end |
#to_h ⇒ Object
Returns a hash of the inventory.
370 371 372 373 374 375 376 377 |
# File 'lib/cem_acpt/shared_objects.rb', line 370 def to_h h = {} @inventory.each_pair do |node_name, node_data| h[node_name] = node_data.to_h end h[:claimed] = @claimed.to_a h end |
#to_json(*args) ⇒ Object
Returns a JSON string of the inventory.
395 396 397 |
# File 'lib/cem_acpt/shared_objects.rb', line 395 def to_json(*args) to_h.to_json(*args) end |
#to_yaml ⇒ Object
Returns a YAML string of the inventory.
390 391 392 |
# File 'lib/cem_acpt/shared_objects.rb', line 390 def to_yaml to_h.to_yaml end |
#update(node_name, node_data) ⇒ Object
213 214 215 |
# File 'lib/cem_acpt/shared_objects.rb', line 213 def update(node_name, node_data) @inventory.replace_if_exists(node_name, node_data) end |
#update_no_lock! ⇒ Object
438 |
# File 'lib/cem_acpt/shared_objects.rb', line 438 def update_no_lock!; end |