Class: Syskit::NetworkGeneration::SystemNetworkDeployer
- Extended by:
- Logger::Hierarchy
- Includes:
- Logger::Hierarchy, Roby::DRoby::EventLogging
- Defined in:
- lib/syskit/network_generation/system_network_deployer.rb
Overview
Algorithm that transforms a network generated by SystemNetworkGenerator into a deployed network
It does not deal with adapting an existing network
Defined Under Namespace
Classes: DeploymentGroupVisitor
Instance Attribute Summary collapse
-
#default_deployment_group ⇒ Models::DeploymentGroup
The deployment group used by default.
-
#event_logger ⇒ Object
readonly
An event logger object used to track execution.
-
#merge_solver ⇒ MergeSolver
readonly
The solver used to track the deployed tasks vs.
-
#plan ⇒ Roby::Plan
readonly
The plan this deployer is acting on.
Instance Method Summary collapse
-
#apply_selected_deployments(selected_deployments) ⇒ void
Modify the plan to apply a deployment selection.
-
#deploy(validate: true) ⇒ Set
Replace non-deployed tasks in the plan by deployed ones.
-
#find_suitable_deployment_for(task, deployment_groups) ⇒ nil, Deployment
Finds the deployments suitable for a task in a given group.
-
#initialize(plan, event_logger: plan.event_logger, merge_solver: MergeSolver.new(plan), default_deployment_group: Syskit.conf.deployment_group) ⇒ SystemNetworkDeployer
constructor
A new instance of SystemNetworkDeployer.
-
#propagate_deployment_groups(use_cow: true) ⇒ Object
private
Create a hash of task instances to the deployment group that should be used for that instance.
-
#resolve_deployment_ambiguity(candidates, task) ⇒ (Model<Deployment>,String)?
Try to resolve a set of deployment candidates for a given task.
-
#select_deployments(tasks, deployment_groups) ⇒ (Component=>Deployment,[Component])
Find which deployments should be used for which tasks.
-
#validate_deployed_network(deployment_groups) ⇒ Object
Sanity checks to verify that the result of #deploy_system_network is valid.
-
#verify_all_tasks_deployed(deployment_groups) ⇒ Object
Verifies that all tasks in the plan are deployed.
Constructor Details
#initialize(plan, event_logger: plan.event_logger, merge_solver: MergeSolver.new(plan), default_deployment_group: Syskit.conf.deployment_group) ⇒ SystemNetworkDeployer
Returns a new instance of SystemNetworkDeployer
36 37 38 39 40 41 42 43 44 |
# File 'lib/syskit/network_generation/system_network_deployer.rb', line 36 def initialize(plan, event_logger: plan.event_logger, merge_solver: MergeSolver.new(plan), default_deployment_group: Syskit.conf.deployment_group) @plan = plan @event_logger = event_logger @merge_solver = merge_solver @default_deployment_group = default_deployment_group end |
Instance Attribute Details
#default_deployment_group ⇒ Models::DeploymentGroup
The deployment group used by default
Each subpart of the network can specify their own through Component#requirements, in which case the new group is merged into the default
34 35 36 |
# File 'lib/syskit/network_generation/system_network_deployer.rb', line 34 def default_deployment_group @default_deployment_group end |
#event_logger ⇒ Object (readonly)
An event logger object used to track execution
20 21 22 |
# File 'lib/syskit/network_generation/system_network_deployer.rb', line 20 def event_logger @event_logger end |
#merge_solver ⇒ MergeSolver (readonly)
The solver used to track the deployed tasks vs. the original tasks
25 26 27 |
# File 'lib/syskit/network_generation/system_network_deployer.rb', line 25 def merge_solver @merge_solver end |
#plan ⇒ Roby::Plan (readonly)
The plan this deployer is acting on
15 16 17 |
# File 'lib/syskit/network_generation/system_network_deployer.rb', line 15 def plan @plan end |
Instance Method Details
#apply_selected_deployments(selected_deployments) ⇒ void
This method returns an undefined value.
Modify the plan to apply a deployment selection
300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 |
# File 'lib/syskit/network_generation/system_network_deployer.rb', line 300 def apply_selected_deployments(selected_deployments) deployment_tasks = Hash.new selected_deployments.each do |task, (configured_deployment, task_name)| deployment_task = (deployment_tasks[[configured_deployment]] ||= configured_deployment.new) if Syskit.conf.permanent_deployments? plan.add_permanent_task(deployment_task) else plan.add(deployment_task) end deployed_task = deployment_task.task(task_name) debug { "deploying #{task} with #{task_name} of "\ "#{configured_deployment.short_name} (#{deployed_task})" } # We MUST merge one-by-one here. Calling apply_merge_group # on all the merges at once would NOT copy the connections # that exist between the tasks of the "from" group to the # "to" group, which is really not what we want # # Calling with all the mappings would be useful if what # we wanted is replace a subnet of the plan by another # subnet. This is not the goal here. merge_solver.apply_merge_group(task => deployed_task) end end |
#deploy(validate: true) ⇒ Set
Replace non-deployed tasks in the plan by deployed ones
The task-to-deployment association is handled by the network's deployment groups (accessible through Component#requirements) as well as the default deployment group (#default_deployment_group)
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 |
# File 'lib/syskit/network_generation/system_network_deployer.rb', line 56 def deploy(validate: true) debug "Deploying the system network" deployment_groups = propagate_deployment_groups debug do debug "Deployment candidates" log_nest(2) do deployment_groups.each do |task, group| candidates = group. find_all_suitable_deployments_for(task) log_pp :debug, task log_nest(2) do if candidates.empty? debug "no deployments" else candidates.each do |deployment| log_pp :debug, deployment end end end end end break end all_tasks = plan.find_local_tasks(TaskContext).to_a selected_deployments, missing_deployments = select_deployments(all_tasks, deployment_groups) log_timepoint 'select_deployments' apply_selected_deployments(selected_deployments) log_timepoint 'apply_selected_deployments' if validate validate_deployed_network(deployment_groups) log_timepoint 'validate_deployed_network' end return missing_deployments end |
#find_suitable_deployment_for(task, deployment_groups) ⇒ nil, Deployment
Finds the deployments suitable for a task in a given group
If more than one deployment matches in the group, it calls #resolve_deployment_ambiguity to try and pick one
237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 |
# File 'lib/syskit/network_generation/system_network_deployer.rb', line 237 def find_suitable_deployment_for(task, deployment_groups) candidates = deployment_groups[task]. find_all_suitable_deployments_for(task) return candidates.first if candidates.size <= 1 debug do "#{candidates.size} deployments available for #{task} "\ "(#{task.concrete_model}), trying to resolve" end selected = log_nest(2) do resolve_deployment_ambiguity(candidates, task) end if selected debug { " selected #{selected}" } return selected else debug do " deployment of #{task} (#{task.concrete_model}) "\ "is ambiguous" end return end end |
#propagate_deployment_groups(use_cow: true) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Create a hash of task instances to the deployment group that should be used for that instance
189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 |
# File 'lib/syskit/network_generation/system_network_deployer.rb', line 189 def propagate_deployment_groups(use_cow: true) dependency_graph = plan. task_relation_graph_for(Roby::TaskStructure::Dependency) all_groups = Hash.new dependency_graph.each_vertex do |task| next unless dependency_graph.root?(task) visitor = DeploymentGroupVisitor.new( dependency_graph, default_deployment_group, use_cow: use_cow) visitor.handle_start_vertex(task) dependency_graph.depth_first_visit(task, visitor) {} visitor.deployment_groups.each do |task, (_shared, task_group)| DeploymentGroupVisitor.update_deployment_groups( all_groups, task, task_group, use_cow: use_cow) end end groups = Hash.new all_groups.each do |task, (_shared, task_group)| groups[task] = task_group end # 'groups' here includes only the tasks that are in the # dependency graph. Make sure we add entries for the rest as # well plan.find_local_tasks(Syskit::Component).each do |task| if !groups.has_key?(task) task_group = task.requirements.deployment_group groups[task] = if task_group.empty? default_deployment_group else task_group end end end groups end |
#resolve_deployment_ambiguity(candidates, task) ⇒ (Model<Deployment>,String)?
Try to resolve a set of deployment candidates for a given task
373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 |
# File 'lib/syskit/network_generation/system_network_deployer.rb', line 373 def resolve_deployment_ambiguity(candidates, task) if task.orocos_name debug { "#{task} requests orocos_name to be #{task.orocos_name}" } resolved = candidates. find { |_, task_name| task_name == task.orocos_name } if !resolved debug { "cannot find requested orocos name #{task.orocos_name}" } end return resolved end hints = task.deployment_hints debug { "#{task}.deployment_hints: #{hints.map(&:to_s).join(", ")}" } # Look to disambiguate using deployment hints resolved = candidates.find_all do |deployment_model, task_name| task.deployment_hints.any? do |rx| rx == deployment_model || rx === task_name end end if resolved.size != 1 info do info { "ambiguous deployment for #{task} (#{task.model})" } candidates.each do |deployment_model, task_name| info do " #{task_name} of #{deployment_model.short_name} "\ "on #{deployment_model.process_server_name}" end end break end return end return resolved.first end |
#select_deployments(tasks, deployment_groups) ⇒ (Component=>Deployment,[Component])
Find which deployments should be used for which tasks
271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 |
# File 'lib/syskit/network_generation/system_network_deployer.rb', line 271 def select_deployments(tasks, deployment_groups) used_deployments = Set.new missing_deployments = Set.new selected_deployments = Hash.new tasks.each do |task| next if task.execution_agent if !(selected = find_suitable_deployment_for(task, deployment_groups)) missing_deployments << task elsif used_deployments.include?(selected) debug do machine, configured_deployment, task_name = *selected "#{task} resolves to #{configured_deployment}.#{task_name} "\ "on #{machine} for its deployment, but it is already used" end missing_deployments << task else used_deployments << selected selected_deployments[task] = selected end end [selected_deployments, missing_deployments] end |
#validate_deployed_network(deployment_groups) ⇒ Object
Sanity checks to verify that the result of #deploy_system_network is valid
330 331 332 |
# File 'lib/syskit/network_generation/system_network_deployer.rb', line 330 def validate_deployed_network(deployment_groups) verify_all_tasks_deployed(deployment_groups) end |
#verify_all_tasks_deployed(deployment_groups) ⇒ Object
Verifies that all tasks in the plan are deployed
339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 |
# File 'lib/syskit/network_generation/system_network_deployer.rb', line 339 def verify_all_tasks_deployed(deployment_groups) not_deployed = plan.find_local_tasks(TaskContext). not_finished.not_abstract. find_all { |t| !t.execution_agent } if !not_deployed.empty? tasks_with_candidates = Hash.new not_deployed.each do |task| candidates = deployment_groups[task]. find_all_suitable_deployments_for(task) candidates = candidates.map do |configured_deployment, task_name| existing = plan.find_local_tasks(task.model). find_all { |t| t.orocos_name == task_name } [configured_deployment, task_name, existing] end tasks_with_candidates[task] = candidates end raise MissingDeployments.new(tasks_with_candidates), "there are tasks for which it exists no deployed equivalent: "\ "#{not_deployed.map { |m| "#{m}(#{m.orogen_model.name})" }}" end end |