class Orocos::RobyPlugin::Deployment

In oroGen, a deployment is a Unix process that holds a certain number of task contexts. This Roby task represents the unix process itself. Once it gets instanciated, the associated task contexts can be accessed with #task

Attributes

orogen_spec[R]

The Orocos::Generation::StaticDeployment that represents this deployment.

logged_ports[R]

The set of ports for which logging has already been set up, as a set of [task_name, port_name] pairs

orogen_deployment[R]

The underlying Orocos::Process instance

robot[RW]
task_handles[R]

A name => Orocos::TaskContext instance mapping of all the task contexts running on this deployment

Public Class Methods

all_deployments() click to toggle source
# File lib/orocos/roby/deployment.rb, line 34
def all_deployments; @@all_deployments end
define_from_orogen(deployment_spec) click to toggle source

Creates a subclass of Deployment that represents the deployment specified by deployment_spec.

deployment_spec is an instance of Orogen::Generation::Deployment

# File lib/orocos/roby/deployment.rb, line 400
def self.define_from_orogen(deployment_spec)
    klass = Class.new(Deployment)
    klass.instance_variable_set :@name, "Orocos::RobyPlugin::Deployments::#{deployment_spec.name.camelcase(:upper)}"
    klass.instance_variable_set :@orogen_spec, deployment_spec
    Orocos::RobyPlugin::Deployments.const_set(deployment_spec.name.camelcase(:upper), klass)
    klass
end
deployment_name() click to toggle source

Returns the name of this particular deployment instance

# File lib/orocos/roby/deployment.rb, line 48
def self.deployment_name
    orogen_spec.name
end
instanciate(engine, arguments = Hash.new) click to toggle source
# File lib/orocos/roby/deployment.rb, line 105
def self.instanciate(engine, arguments = Hash.new)
    task = new(arguments)
    task.robot = engine.robot
    task
end
new(arguments = Hash.new) click to toggle source
Calls superclass method
# File lib/orocos/roby/deployment.rb, line 22
def initialize(arguments = Hash.new)
   opts, task_arguments = Kernel.filter_options  arguments, :log => true
    task_arguments[:log] = opts[:log]
    @logged_ports = Set.new
    super(task_arguments)
end
short_name() click to toggle source
# File lib/orocos/roby/deployment.rb, line 43
def self.short_name
    name.gsub("Orocos::RobyPlugin::", "")
end
tasks() click to toggle source

An array of Orocos::Generation::TaskDeployment instances that represent the tasks available in this deployment. Associated plan objects can be instanciated with #task

# File lib/orocos/roby/deployment.rb, line 95
def self.tasks
    orogen_spec.task_activities
end

Public Instance Methods

cleanup_dead_connections() click to toggle source

Removes any connection that points to tasks that were in this process, and that are therefore dead because of the process termination

# File lib/orocos/roby/deployment.rb, line 291
def cleanup_dead_connections
    return if !task_handles

    # task_handles is only initialized when ready is reached ...
    # so can be nil here
    all_tasks = task_handles.values.to_value_set
    all_tasks.each do |task|
        task.each_parent_vertex(ActualDataFlow) do |parent_task|
            if parent_task.process
                next if !parent_task.process.running?
                roby_task = Deployment.all_deployments[parent_task.process]
                next if roby_task.finishing? || roby_task.finished?
            end

            mappings = parent_task[task, ActualDataFlow]
            mappings.each do |(source_port, sink_port), policy|
                if policy[:pull] # we have to disconnect explicitely
                    begin
                        parent_task.port(source_port).disconnect_from(task.port(sink_port, false))
                    rescue Exception => e
                        Orocos::RobyPlugin.warn "error while disconnecting #{parent_task}:#{source_port} from #{task}:#{sink_port} after #{task} died (#{e.message}). Assuming that both tasks are already dead."
                    end
                end
            end
        end
        task.each_child_vertex(ActualDataFlow) do |child_task|
            if child_task.process
                next if !child_task.process.running?
                roby_task = Deployment.all_deployments[child_task.process]
                next if roby_task.finishing? || roby_task.finished?
            end

            mappings = task[child_task, ActualDataFlow]
            mappings.each do |(source_port, sink_port), policy|
                begin
                    child_task.port(sink_port).disconnect_all
                rescue Exception => e
                    Orocos::RobyPlugin.warn "error while disconnecting #{task}:#{source_port} from #{child_task}:#{sink_port} after #{task} died (#{e.message}). Assuming that both tasks are already dead."
                end
            end
        end

        ActualDataFlow.remove(task)
        RequiredDataFlow.remove(task)
    end
end
dead!(result) click to toggle source

Called when the process is finished.

result is the Process::Status object describing how this process finished.

# File lib/orocos/roby/deployment.rb, line 264
def dead!(result)
    if !result
        emit :failed
    elsif history.find(&:terminal?)
        # Do nothing. A terminal event already happened, so we don't
        # need to tell what kind of end this is for the system
        emit :stop
    elsif result.success?
        emit :success
    elsif result.signaled?
        emit :signaled, result
    else
        emit :failed, result
    end

    Deployment.all_deployments.delete(orogen_deployment)
    orogen_spec.task_activities.each do |act|
        TaskContext.configured.delete(act.name)
    end
    each_parent_object(Roby::TaskStructure::ExecutionAgent) do |task|
        task.orogen_task = nil
    end
end
deployment_name() click to toggle source

The name of the executable, i.e. the name of the deployment as given in the oroGen file

This is a shortcut for deployment.model.deployment_name

# File lib/orocos/roby/deployment.rb, line 60
def deployment_name
    orogen_spec.name
end
initialize_running_task(name, task) click to toggle source

Internal helper to set the #orogen_task and

# File lib/orocos/roby/deployment.rb, line 144
def initialize_running_task(name, task)
    task.orogen_task = task_handles[name]
    task.orogen_task.process = orogen_deployment
    if Conf.orocos.conf_log_enabled?
        task.orogen_task.log_all_configuration(Orocos.configuration_log)
    end
    # Override the base model with the new one. The new model
    # may have been specialized, for instance to handle dynamic
    # slave creation
    # task.orogen_task.instance_variable_set(:@model, task.model.orogen_spec)
end
instanciate_all_tasks() click to toggle source
# File lib/orocos/roby/deployment.rb, line 111
def instanciate_all_tasks
    orogen_spec.task_activities.map do |act|
        task(act.name)
    end
end
log_dir() click to toggle source
# File lib/orocos/roby/deployment.rb, line 248
def log_dir
    host = self.arguments['on'] ||= 'localhost'
    process_server, log_dir = Orocos::RobyPlugin.process_servers[host]
    log_dir
end
log_port?(port) click to toggle source

Returns true if the orocos/roby plugin configuration requires port to be logged

# File lib/orocos/roby/deployment.rb, line 340
def log_port?(port)
    result = !Roby::State.orocos.port_excluded_from_log?(self,
            Roby.app.orocos_tasks[port.task.name], port)

    if !result
        Robot.info "not logging #{port.task.name}:#{port.name}"
    end
    result
end
machine() click to toggle source

The name of the machine this deployment is running on, i.e. the name given to the :on argument.

# File lib/orocos/roby/deployment.rb, line 256
def machine
    arguments[:on] || 'localhost'
end
on_same_server?(task) click to toggle source

Returns true if self and task are running on the same process server

# File lib/orocos/roby/deployment.rb, line 101
def on_same_server?(task)
    task == self || machine == task.machine
end
orogen_spec() click to toggle source

The Orocos::Generation::StaticDeployment object describing this deployment. This is a shortcut for deployment.model.orogen_spec

# File lib/orocos/roby/deployment.rb, line 54
def orogen_spec; self.class.orogen_spec end
pid() click to toggle source

The PID of this process

# File lib/orocos/roby/deployment.rb, line 39
def pid
    @pid ||= orogen_deployment.pid
end
ready_event() click to toggle source

Event emitted when the deployment is up and running

# File lib/orocos/roby/deployment.rb, line 79
event :ready
ready_to_die!() click to toggle source
# File lib/orocos/roby/deployment.rb, line 369
def ready_to_die!
   @ready_to_die = true
end
signaled_event() click to toggle source

Event emitted whenever the deployment finishes because of a UNIX signal. The event context is the Process::Status instance that describes the termination

It is forwarded to failed_event

# File lib/orocos/roby/deployment.rb, line 89
event :signaled
start!() click to toggle source

Starts the process and emits the start event immediately. The :ready event will be emitted when the deployment is up and running.

# File lib/orocos/roby/deployment.rb, line 162
event :start do |context|
    host = self.arguments['on'] ||= 'localhost'
    RobyPlugin.info { "starting deployment #{model.deployment_name} on #{host}" }

    process_server, log_dir = Orocos::RobyPlugin.process_servers[host]
    if !process_server
        raise ArgumentError, "cannot find the process server for #{host}"
    end
    options = Hash.new

    # Checking for options which apply in a multi-robot context,
    # e.g. such as prefixing and service_discovery (distributed
    # nameservice
    #
    # multirobot:
    #     use_prefixing: true
    #     exclude_from_prefixing:
    #         - SIMULATION
    #         - .*TEST.*
    #     service_discovery:
    #         - domain: _rimres._tcp
    #         - publish:
    #             - .*CORE.*
    if multirobot = Roby.app.options["multirobot"]
        # Use prefixing of components in order to allow
        # multiple robots to use the same set of deployments,
        # since tasks will be renamed using th given prefix
        # (robot_name)
        # e.g. with prefix enabled:
        #     ./scripts/run robot_0 robottype
        # the prefix 'robot_0_' will be used
        if multirobot.key?("use_prefixing")

            exclude = false
            # Exclude deployments from prefixing that match one of the given
            # regular expressions (matching on complete deployment_name)
            if prefix_black_list = multirobot["exclude_from_prefixing"]
                prefix_black_list.each do |pattern|
                    begin
                        exclude = exclude || deployment_name =~ Regexp.new('^' + pattern + '$')
                    rescue RegexpError => e
                        Robot.error "Regular expression in configuration of multirobot with errors: #{e}"
                    end
                end
            end
            if !exclude
                Robot.info "Deployment #{deployment_name} is started with prefix #{Roby.app.robot_name}"
                args = { :prefix => "#{Roby.app.robot_name}_" }
                options.merge!(args)
            else
                Robot.info "Deployment #{deployment_name} is started without prefix #{Roby.app.robot_name}"
            end

        end
        # Check whether the deployment should be started with
        # service discovery options, in order to be published within
        # the distributed nameservice
        if multirobot.key?("service_discovery")
            service_discovery = multirobot['service_discovery']
            sd_domains = service_discovery["domain"]
            publish = false
            if publish_white_list = service_discovery['publish']
                publish_white_list.each do |pattern|
                    begin
                        publish = publish || deployment_name =~ Regexp.new('^' + pattern + '$')
                    rescue RegexpError => e
                        Robot.error "Regular expression in configuration of multirobot with errors: #{e}"
                    end
                end
            end
            if publish
                args = { 'sd-domain' => sd_domains }
                options.merge!(args)
            end
        end
    end
    @orogen_deployment = process_server.start(model.deployment_name, 
                                              :working_directory => log_dir, 
                                              :output => "%m-%p.txt", 
                                              :wait => false,
                                              :cmdline_args => options)

    Deployment.all_deployments[@orogen_deployment] = self
    emit :start
end
stop!() click to toggle source

Stops all tasks that are running on top of this deployment, and kill the deployment

# File lib/orocos/roby/deployment.rb, line 380
event :stop do |context|
    begin
        if task_handles
            task_handles.each_value do |t|
                if t.rtt_state == :STOPPED
                    t.cleanup
                end
            end
        end
        ready_to_die!
        orogen_deployment.kill(false)
    rescue CORBA::ComError
        # Assume that the process is killed as it is not reachable
    end
end
task(name, model = nil) click to toggle source

Returns an task instance that represents the given task in this deployment.

# File lib/orocos/roby/deployment.rb, line 119
def task(name, model = nil)
    activity = orogen_spec.task_activities.find { |act| name == act.name }
    if !activity
        raise ArgumentError, "no task called #{name} in #{self.class.deployment_name}"
    end

    activity_model = Roby.app.orocos_tasks[activity.context.name]
    if model
        if !(model <= activity_model)
            raise ArgumentError, "incompatible explicit selection #{model} for the model of #{name} in #{self}"
        end
    else
        model = activity_model
    end
    plan.add(task = model.new(:orocos_name => activity.name))
    task.robot = robot
    task.executed_by self
    task.orogen_spec = activity
    if ready?
        initialize_running_task(name, task)
    end
    task
end