Class: HybridPlatformsConductor::NodesHandler
- Inherits:
-
Object
- Object
- HybridPlatformsConductor::NodesHandler
- Includes:
- LoggerHelpers, ParallelThreads
- Defined in:
- lib/hybrid_platforms_conductor/nodes_handler.rb
Overview
API to get information on our inventory: nodes and their metadata
Defined Under Namespace
Modules: ConfigDSLExtension
Constant Summary
Constants included from LoggerHelpers
LoggerHelpers::LEVELS_MODIFIERS, LoggerHelpers::LEVELS_TO_STDERR
Instance Method Summary collapse
-
#define_property_method_for(property) ⇒ Object
Define a method to get a metadata property of a node.
-
#for_each_node_in(nodes, parallel: false, nbr_threads_max: nil, progress: 'Processing nodes') ⇒ Object
Iterate over a list of nodes.
-
#impacted_nodes_from_git_diff(platform_name, from_commit: 'master', to_commit: nil, smallest_set: false) ⇒ Object
Get the list of impacted nodes from a git diff on a platform.
-
#initialize(logger: Logger.new(STDOUT), logger_stderr: Logger.new(STDERR), config: Config.new, cmd_runner: CmdRunner.new, platforms_handler: PlatformsHandler.new) ⇒ NodesHandler
constructor
Constructor.
-
#invalidate_metadata_of(node, property) ⇒ Object
Invalidate a metadata property for a given node.
-
#known_nodes ⇒ Object
Get the list of known nodes.
-
#known_nodes_lists ⇒ Object
Get the list of known nodes lists.
-
#known_services ⇒ Object
Get the list of known service names.
-
#metadata_of(node, property) ⇒ Object
Get a metadata property for a given node.
-
#method_missing(method, *args, &block) ⇒ Object
Accept any method of name get_<property>_of to get the metadata property of a given node.
-
#nodes_from_list(nodes_list, ignore_unknowns: false) ⇒ Object
Get the list of nodes (resolved) belonging to a nodes list.
-
#options_parse(options_parser, parallel: true) ⇒ Object
Complete an option parser with options meant to control this Nodes Handler.
-
#options_parse_nodes_selectors(options_parser, nodes_selectors) ⇒ Object
Complete an option parser with ways to select nodes in parameters.
-
#override_metadata_of(node, property, value) ⇒ Object
Override a metadata property for a given node.
-
#prefetch_metadata_of(nodes, properties) ⇒ Object
Prefetch some metadata properties for a given list of nodes.
-
#select_confs_for_node(node, configs) ⇒ Object
Select the configs applicable to a given node.
-
#select_confs_for_platform(platform_name, configs) ⇒ Object
Select the configs applicable to a given platform.
-
#select_from_nodes_selector_stack(nodes_selector_stack) ⇒ Object
Get the list of nodes impacted by a nodes selector stack.
-
#select_nodes(*nodes_selectors, ignore_unknowns: false) ⇒ Object
Resolve a list of nodes selectors into a real list of known nodes.
Methods included from LoggerHelpers
#err, #init_loggers, #log_component=, #log_debug?, #log_level=, #out, #section, #set_loggers_format, #stderr_device, #stderr_device=, #stderr_displayed?, #stdout_device, #stdout_device=, #stdout_displayed?, #stdouts_to_s, #with_progress_bar
Methods included from ParallelThreads
Constructor Details
#initialize(logger: Logger.new(STDOUT), logger_stderr: Logger.new(STDERR), config: Config.new, cmd_runner: CmdRunner.new, platforms_handler: PlatformsHandler.new) ⇒ NodesHandler
Constructor
- Parameters
-
logger (Logger): Logger to be used [default: Logger.new(STDOUT)]
-
logger_stderr (Logger): Logger to be used for stderr [default: Logger.new(STDERR)]
-
config (Config): Config to be used. [default: Config.new]
-
cmd_runner (CmdRunner): Command executor to be used. [default: CmdRunner.new]
-
platforms_handler (PlatformsHandler): Platforms Handler to be used. [default: PlatformsHandler.new]
51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 |
# File 'lib/hybrid_platforms_conductor/nodes_handler.rb', line 51 def initialize( logger: Logger.new(STDOUT), logger_stderr: Logger.new(STDERR), config: Config.new, cmd_runner: CmdRunner.new, platforms_handler: PlatformsHandler.new ) init_loggers(logger, logger_stderr) @config = config @cmd_runner = cmd_runner @platforms_handler = platforms_handler # List of platform handler per known node # Hash<String, PlatformHandler> @nodes_platform = {} # List of platform handler per known nodes list # Hash<String, PlatformHandler> @nodes_list_platform = {} # List of CMDBs getting a property, per property name # Hash<Symbol, Array<Cmdb> > @cmdbs_per_property = {} # List of CMDBs having the get_others method # Array< Cmdb > @cmdbs_others = [] @cmdbs = Plugins.new( :cmdb, logger: @logger, logger_stderr: @logger_stderr, init_plugin: proc do |plugin_class| cmdb = plugin_class.new( logger: @logger, logger_stderr: @logger_stderr, config: @config, cmd_runner: @cmd_runner, platforms_handler: @platforms_handler, nodes_handler: self ) @cmdbs_others << cmdb if cmdb.respond_to?(:get_others) cmdb.methods.each do |method| if method.to_s =~ /^get_(.*)$/ property = $1.to_sym @cmdbs_per_property[property] = [] unless @cmdbs_per_property.key?(property) @cmdbs_per_property[property] << cmdb end end cmdb end ) # Cache of metadata per node # Hash<String, Hash<Symbol, Object> > @metadata = {} # The metadata update is protected by a mutex to make it thread-safe @metadata_mutex = Mutex.new # Cache of CMDB masters, per property, per node # Hash< String, Hash< Symbol, Cmdb > > @cmdb_masters_cache = {} # Read all platforms from the config @platforms_handler.known_platforms.each do |platform| # Register all known nodes for this platform platform.known_nodes.each do |node| raise "Can't register #{node} to platform #{platform.repository_path}, as it is already defined in platform #{@nodes_platform[node].repository_path}." if @nodes_platform.key?(node) @nodes_platform[node] = platform end # Register all known nodes lists platform.known_nodes_lists.each do |nodes_list| raise "Can't register nodes list #{nodes_list} to platform #{platform.repository_path}, as it is already defined in platform #{@nodes_list_platform[nodes_list].repository_path}." if @nodes_list_platform.key?(nodes_list) @nodes_list_platform[nodes_list] = platform end if platform.respond_to?(:known_nodes_lists) end end |
Dynamic Method Handling
This class handles dynamic methods through the method_missing method
#method_missing(method, *args, &block) ⇒ Object
Accept any method of name get_<property>_of to get the metadata property of a given node. Here is the magic of accepting method names that are not statically defined.
- Parameters
-
method (Symbol): The missing method name
-
args (Array<Object>): Arguments given to the call
-
block (Proc): Code block given to the call
301 302 303 304 305 306 307 308 309 310 311 312 313 |
# File 'lib/hybrid_platforms_conductor/nodes_handler.rb', line 301 def method_missing(method, *args, &block) if method.to_s =~ /^get_(.*)_of$/ property = $1.to_sym # Define the method so that we don't go trough method_missing next time (more efficient). define_property_method_for(property) # Then call it send("get_#{property}_of".to_sym, *args, &block) else # We really don't know this method. # Call original implementation of method_missing that will raise an exception. super end end |
Instance Method Details
#define_property_method_for(property) ⇒ Object
Define a method to get a metadata property of a node. This is like a factory of method shortcuts for properties. The method will be named get_<property>_of. This way instead of calling
node, :host_ip
we can call
get_host_ip_of node
Readability wins :D
- Parameters
-
property (Symbol): The property name
290 291 292 |
# File 'lib/hybrid_platforms_conductor/nodes_handler.rb', line 290 def define_property_method_for(property) define_singleton_method("get_#{property}_of".to_sym) { |node| (node, property) } end |
#for_each_node_in(nodes, parallel: false, nbr_threads_max: nil, progress: 'Processing nodes') ⇒ Object
Iterate over a list of nodes. Provide a mechanism to multithread this iteration (in such case the iterating code has to be thread-safe). In case of multithreaded run, a progress bar is being displayed.
- Parameters
-
nodes (Array<String>): List of nodes to iterate over
-
parallel (Boolean): Iterate in a multithreaded way? [default: false]
-
nbr_threads_max (Integer or nil): Maximum number of threads to be used in case of parallel, or nil for no limit [default: nil]
-
progress (String or nil): Name of a progress bar to follow the progression, or nil for no progress bar [default: ‘Processing nodes’]
-
Proc: The code called for each node being iterated on.
- Parameters
-
node (String): The node name
466 467 468 469 470 |
# File 'lib/hybrid_platforms_conductor/nodes_handler.rb', line 466 def for_each_node_in(nodes, parallel: false, nbr_threads_max: nil, progress: 'Processing nodes') for_each_element_in(nodes.sort, parallel: parallel, nbr_threads_max: nbr_threads_max, progress: progress) do |node| yield node end end |
#impacted_nodes_from_git_diff(platform_name, from_commit: 'master', to_commit: nil, smallest_set: false) ⇒ Object
Get the list of impacted nodes from a git diff on a platform
- Parameters
-
platform_name (String): The platform’s name
-
from_commit (String): Commit ID to check from [default: ‘master’]
-
to_commit (String or nil): Commit ID to check to, or nil for currently checked-out files [default: nil]
-
smallest_set (Boolean): Smallest set of impacted nodes? [default: false]
- Result
-
Array<String>: The list of nodes impacted by this diff (counting direct impacts, services and global files impacted)
-
Array<String>: The list of nodes directly impacted by this diff
-
Array<String>: The list of services impacted by this diff
-
Boolean: Are there some files that have a global impact (meaning all nodes are potentially impacted by this diff)?
484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 |
# File 'lib/hybrid_platforms_conductor/nodes_handler.rb', line 484 def impacted_nodes_from_git_diff(platform_name, from_commit: 'master', to_commit: nil, smallest_set: false) platform = @platforms_handler.platform(platform_name) raise "Unkown platform #{platform_name}. Possible platforms are #{@platforms_handler.known_platforms.map(&:name).sort.join(', ')}" if platform.nil? _exit_status, stdout, _stderr = @cmd_runner.run_cmd "cd #{platform.repository_path} && git --no-pager diff --no-color #{from_commit} #{to_commit.nil? ? '' : to_commit}", log_to_stdout: log_debug? # Parse the git diff output to create a structured diff # Hash< String, Hash< Symbol, Object > >: List of diffs info, per file name having a diff. Diffs info have the following properties: # * *moved_to* (String): The new file path, in case it has been moved [optional] # * *diff* (String): The diff content files_diffs = {} current_file_diff = nil stdout.split("\n").each do |line| case line when /^diff --git a\/(.+) b\/(.+)$/ # A new file diff from, to = $1, $2 current_file_diff = { diff: '' } current_file_diff[:moved_to] = to unless from == to files_diffs[from] = current_file_diff else current_file_diff[:diff] << "#{current_file_diff[:diff].empty? ? '' : "\n"}#{line}" unless current_file_diff.nil? end end impacted_nodes, impacted_services, impact_global = platform.impacts_from files_diffs impacted_services.sort! impacted_services.uniq! impacted_nodes.sort! impacted_nodes.uniq! [ if impact_global platform.known_nodes.sort else ( impacted_nodes + impacted_services.map do |service| service_nodes = select_nodes([{ service: service }]) smallest_set ? [service_nodes.first].compact : service_nodes end ).flatten.sort.uniq end, impacted_nodes, impacted_services, impact_global ] end |
#invalidate_metadata_of(node, property) ⇒ Object
Invalidate a metadata property for a given node
- Parameters
-
node (String): Node
-
property (Symbol): The property name
273 274 275 276 277 |
# File 'lib/hybrid_platforms_conductor/nodes_handler.rb', line 273 def (node, property) @metadata_mutex.synchronize do @metadata[node].delete(property) if @metadata.key?(node) end end |
#known_nodes ⇒ Object
Get the list of known nodes
- Result
-
Array<String>: List of nodes
211 212 213 |
# File 'lib/hybrid_platforms_conductor/nodes_handler.rb', line 211 def known_nodes @nodes_platform.keys end |
#known_nodes_lists ⇒ Object
Get the list of known nodes lists
- Result
-
Array<String>: List of nodes lists’ names
219 220 221 |
# File 'lib/hybrid_platforms_conductor/nodes_handler.rb', line 219 def known_nodes_lists @nodes_list_platform.keys end |
#known_services ⇒ Object
Get the list of known service names
- Result
-
Array<String>: List of service names
238 239 240 241 |
# File 'lib/hybrid_platforms_conductor/nodes_handler.rb', line 238 def known_services known_nodes, :services known_nodes.map { |node| get_services_of node }.flatten.compact.uniq.sort end |
#metadata_of(node, property) ⇒ Object
Get a metadata property for a given node
- Parameters
-
node (String): Node
-
property (Symbol): The property name
- Result
-
Object or nil: The node’s metadata value for this property, or nil if none
250 251 252 253 |
# File 'lib/hybrid_platforms_conductor/nodes_handler.rb', line 250 def (node, property) ([node], property) unless @metadata.key?(node) && @metadata[node].key?(property) @metadata[node][property] end |
#nodes_from_list(nodes_list, ignore_unknowns: false) ⇒ Object
Get the list of nodes (resolved) belonging to a nodes list
- Parameters
-
nodes_list (String): Nodes list name
-
ignore_unknowns (Boolean): Do we ignore unknown nodes? [default = false]
- Result
-
Array<String>: List of nodes
230 231 232 |
# File 'lib/hybrid_platforms_conductor/nodes_handler.rb', line 230 def nodes_from_list(nodes_list, ignore_unknowns: false) select_nodes(@nodes_list_platform[nodes_list].nodes_selectors_from_nodes_list(nodes_list), ignore_unknowns: ignore_unknowns) end |
#options_parse(options_parser, parallel: true) ⇒ Object
Complete an option parser with options meant to control this Nodes Handler
- Parameters
-
options_parser (OptionParser): The option parser to complete
125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 |
# File 'lib/hybrid_platforms_conductor/nodes_handler.rb', line 125 def (, parallel: true) .separator '' .separator 'Nodes handler options:' .on('-o', '--show-nodes', 'Display the list of possible nodes and exit') do out "* Known platforms:\n#{ @platforms_handler.known_platforms.map do |platform| "#{platform.name} - Type: #{platform.platform_type} - Location: #{platform.repository_path}" end.sort.join("\n") }" out out "* Known nodes lists:\n#{known_nodes_lists.sort.join("\n")}" out out "* Known services:\n#{known_services.sort.join("\n")}" out out "* Known nodes:\n#{known_nodes.sort.join("\n")}" out out "* Known nodes with description:\n#{ known_nodes, %i[hostname host_ip private_ips services description] known_nodes.map do |node| "#{node} (#{ if get_hostname_of node get_hostname_of node elsif get_host_ip_of node get_host_ip_of node elsif get_private_ips_of node get_private_ips_of(node).first else 'No connection' end }) - #{(get_services_of(node) || []).join(', ')} - #{get_description_of(node) || ''}" end.sort.join("\n") }" out exit 0 end end |
#options_parse_nodes_selectors(options_parser, nodes_selectors) ⇒ Object
Complete an option parser with ways to select nodes in parameters
- Parameters
-
options_parser (OptionParser): The option parser to complete
-
nodes_selectors (Array): The list of nodes selectors that will be populated by parsing the options
167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 |
# File 'lib/hybrid_platforms_conductor/nodes_handler.rb', line 167 def (, nodes_selectors) platform_names = @platforms_handler.known_platforms.map(&:name).sort .separator '' .separator 'Nodes selection options:' .on('-a', '--all-nodes', 'Select all nodes') do nodes_selectors << { all: true } end .on('-b', '--nodes-platform PLATFORM', "Select nodes belonging to a given platform name. Available platforms are: #{platform_names.join(', ')} (can be used several times)") do |platform| nodes_selectors << { platform: platform } end .on('-l', '--nodes-list LIST', 'Select nodes defined in a nodes list (can be used several times)') do |nodes_list| nodes_selectors << { list: nodes_list } end .on('-n', '--node NODE', 'Select a specific node. Can be a regular expression to select several nodes if used with enclosing "/" characters. (can be used several times).') do |node| nodes_selectors << node end .on('-r', '--nodes-service SERVICE', 'Select nodes implementing a given service (can be used several times)') do |service| nodes_selectors << { service: service } end .on( '--nodes-git-impact GIT_IMPACT', 'Select nodes impacted by a git diff from a platform (can be used several times).', 'GIT_IMPACT has the format PLATFORM:FROM_COMMIT:TO_COMMIT:FLAGS', "* PLATFORM: Name of the platform to check git diff from. Available platforms are: #{platform_names.join(', ')}", '* FROM_COMMIT: Commit ID or refspec from which we perform the diff. If ommitted, defaults to master', '* TO_COMMIT: Commit ID ot refspec to which we perform the diff. If ommitted, defaults to the currently checked-out files', '* FLAGS: Extra comma-separated flags. The following flags are supported:', ' - min: If specified then each impacted service will select only 1 node implementing this service. If not specified then all nodes implementing the impacted services will be selected.' ) do |nodes_git_impact| platform_name, from_commit, to_commit, flags = nodes_git_impact.split(':') flags = (flags || '').split(',') raise "Invalid platform in --nodes-git-impact: #{platform_name}. Possible values are: #{platform_names.join(', ')}." unless platform_names.include?(platform_name) nodes_selector = { platform: platform_name } nodes_selector[:from_commit] = from_commit if from_commit && !from_commit.empty? nodes_selector[:to_commit] = to_commit if to_commit && !to_commit.empty? nodes_selector[:smallest_set] = true if flags.include?('min') nodes_selectors << { git_diff: nodes_selector } end end |
#override_metadata_of(node, property, value) ⇒ Object
Override a metadata property for a given node
- Parameters
-
node (String): Node
-
property (Symbol): The property name
-
value (Object): The property value
261 262 263 264 265 266 |
# File 'lib/hybrid_platforms_conductor/nodes_handler.rb', line 261 def (node, property, value) @metadata_mutex.synchronize do @metadata[node] = {} unless @metadata.key?(node) @metadata[node][property] = value end end |
#prefetch_metadata_of(nodes, properties) ⇒ Object
Prefetch some metadata properties for a given list of nodes. Useful for performance reasons when clients know they will need to use a lot of properties on nodes. Keep a thread-safe memory cache of it.
- Parameters
-
nodes (Array<String>): Nodes to read metadata for
-
properties (Symbol or Array<Symbol>): Metadata properties (or single one) to read
322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 |
# File 'lib/hybrid_platforms_conductor/nodes_handler.rb', line 322 def (nodes, properties) (properties.is_a?(Symbol) ? [properties] : properties).each do |property| # Gather the list of nodes missing this property missing_nodes = nodes.select { |node| !@metadata.key?(node) || !@metadata[node].key?(property) } unless missing_nodes.empty? # Query the CMDBs having first the get_<property> method, then the ones having the get_others method till we have our property set for all missing nodes # Metadata being retrieved by the different CMDBs, per node # Hash< String, Object > = {} ( (@cmdbs_per_property.key?(property) ? @cmdbs_per_property[property] : []).map { |cmdb| [cmdb, property] } + @cmdbs_others.map { |cmdb| [cmdb, :others] } ).each do |(cmdb, cmdb_property)| # If among the missing nodes some of them have some master CMDB declared for this property, filter them out unless we are dealing with their master CMDB. nodes_to_query = missing_nodes.select do |node| master_cmdb = cmdb_master_for(node, property) master_cmdb.nil? || master_cmdb == cmdb end unless nodes_to_query.empty? # Check first if this property depends on other ones for this cmdb if cmdb.respond_to?(:property_dependencies) property_deps = cmdb.property_dependencies nodes_to_query, property_deps[property] if property_deps.key?(property) end # Property values, per node name # Hash< String, Object > = Hash[ cmdb.send("get_#{cmdb_property}".to_sym, nodes_to_query, @metadata.slice(*nodes_to_query)).map do |node, cmdb_result| [node, cmdb_property == :others ? cmdb_result[property] : cmdb_result] end ].compact cmdb_log_header = "[CMDB #{cmdb.class.name.split('::').last}.#{cmdb_property}] -" log_debug "#{cmdb_log_header} Query property #{property} for #{nodes_to_query.size} nodes (#{nodes_to_query[0..7].join(', ')}...) => Found metadata for #{.size} nodes." .merge!() do |node, existing_value, new_value| raise "#{cmdb_log_header} Returned a conflicting value for metadata #{property} of node #{node}: #{new_value} whereas the value was already set to #{existing_value}" if !existing_value.nil? && new_value != existing_value new_value end end end # Avoid conflicts in metadata while merging and make sure this update is thread-safe # As @metadata is only appending data and never deleting it, protecting the update only is enough. # At worst several threads will query several times the same CMDBs to update the same data several times. # If we also want to be thread-safe in this regard, we should protect the whole CMDB call with mutexes, at the granularity of the node + property bein read. @metadata_mutex.synchronize do missing_nodes.each do |node| @metadata[node] = {} unless @metadata.key?(node) # Here, explicitely store nil if nothing has been found for a node because we know there is no value to be fetched. # This way we won't query again all CMDBs thanks to the cache. @metadata[node][property] = [node] end end end end end |
#select_confs_for_node(node, configs) ⇒ Object
Select the configs applicable to a given node.
- Parameters
-
node (String): The node for which we select configurations
-
configs (Array< Hash<Symbol,Object> >): Configuration properties. Each configuration is selected based on the nodes_selectors_stack property.
- Result
-
Array< Hash<Symbol,Object> >: The selected configurations
537 538 539 |
# File 'lib/hybrid_platforms_conductor/nodes_handler.rb', line 537 def select_confs_for_node(node, configs) configs.select { |config_info| select_from_nodes_selector_stack(config_info[:nodes_selectors_stack]).include?(node) } end |
#select_confs_for_platform(platform_name, configs) ⇒ Object
Select the configs applicable to a given platform.
- Parameters
-
platform_name (String): The platform for which we select configurations
-
configs (Array< Hash<Symbol,Object> >): Configuration properties. Each configuration is selected based on the nodes_selectors_stack property.
- Result
-
Array< Hash<Symbol,Object> >: The selected configurations
548 549 550 551 |
# File 'lib/hybrid_platforms_conductor/nodes_handler.rb', line 548 def select_confs_for_platform(platform_name, configs) platform_nodes = @platforms_handler.platform(platform_name).known_nodes configs.select { |config_info| (platform_nodes - select_from_nodes_selector_stack(config_info[:nodes_selectors_stack])).empty? } end |
#select_from_nodes_selector_stack(nodes_selector_stack) ⇒ Object
Get the list of nodes impacted by a nodes selector stack. The result is the intersection of every nodes set in the stack.
- Parameters
-
nodes_selector_stack (Array): The nodes selector stack
- Result
-
Array<String>: List of nodes
560 561 562 |
# File 'lib/hybrid_platforms_conductor/nodes_handler.rb', line 560 def select_from_nodes_selector_stack(nodes_selector_stack) nodes_selector_stack.inject(known_nodes) { |selected_nodes, nodes_selector| selected_nodes & select_nodes(nodes_selector) } end |
#select_nodes(*nodes_selectors, ignore_unknowns: false) ⇒ Object
Resolve a list of nodes selectors into a real list of known nodes. A node selector can be:
-
String: Node name, or a node regexp if enclosed within ‘/’ character (ex: ‘/.
worker./’) -
Hash<Symbol,Object>: More complete information that can contain the following keys:
-
all (Boolean): If true, specify that we want all known nodes.
-
list (String): Name of a nodes list.
-
platform (String): Name of a platform containing nodes.
-
service (String): Name of a service implemented by nodes.
-
git_diff (Hash<Symbol,Object>): Info about a git diff that impacts nodes:
-
platform (String): Name of the platform on which checking the git diff
-
from_commit (String): Commit ID to check from [default: ‘master’]
-
to_commit (String or nil): Commit ID to check to, or nil for currently checked-out files [default: nil]
-
smallest_set (Boolean): Smallest set of impacted nodes? [default: false]
-
-
- Parameters
-
nodes_selectors (Array<Object>): List of node selectors (can be a single element).
-
ignore_unknowns (Boolean): Do we ignore unknown nodes? [default = false]
- Result
-
Array<String>: List of nodes
396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 |
# File 'lib/hybrid_platforms_conductor/nodes_handler.rb', line 396 def select_nodes(*nodes_selectors, ignore_unknowns: false) nodes_selectors = nodes_selectors.flatten # 1. Check for the presence of all return known_nodes if nodes_selectors.any? { |nodes_selector| nodes_selector.is_a?(Hash) && nodes_selector.key?(:all) && nodes_selector[:all] } # 2. Expand the nodes lists, platforms and services contents string_nodes = [] nodes_selectors.each do |nodes_selector| if nodes_selector.is_a?(String) string_nodes << nodes_selector else if nodes_selector.key?(:list) platform = @nodes_list_platform[nodes_selector[:list]] raise "Unknown nodes list: #{nodes_selector[:list]}" if platform.nil? string_nodes.concat(platform.nodes_selectors_from_nodes_list(nodes_selector[:list])) end string_nodes.concat(@platforms_handler.platform(nodes_selector[:platform]).known_nodes) if nodes_selector.key?(:platform) if nodes_selector.key?(:service) known_nodes, :services string_nodes.concat(known_nodes.select { |node| (get_services_of(node) || []).include?(nodes_selector[:service]) }) end if nodes_selector.key?(:git_diff) # Default values git_diff_info = { from_commit: 'master', to_commit: nil, smallest_set: false }.merge(nodes_selector[:git_diff]) all_impacted_nodes, _impacted_nodes, _impacted_services, _impact_global = impacted_nodes_from_git_diff( git_diff_info[:platform], from_commit: git_diff_info[:from_commit], to_commit: git_diff_info[:to_commit], smallest_set: git_diff_info[:smallest_set] ) string_nodes.concat(all_impacted_nodes) end end end # 3. Expand the Regexps real_nodes = [] string_nodes.each do |node| if node =~ /^\/(.+)\/$/ node_regexp = Regexp.new($1) real_nodes.concat(known_nodes.select { |known_node| known_node[node_regexp] }) else real_nodes << node end end # 4. Sort them unique real_nodes.uniq! real_nodes.sort! # Some sanity checks unless ignore_unknowns unknown_nodes = real_nodes - known_nodes raise "Unknown nodes: #{unknown_nodes.join(', ')}" unless unknown_nodes.empty? end real_nodes end |