OCS Site Configuration

Overview

The purpose of ocs.site_config module is to help Agents and Control Clients self-configure within a particular “site” context. By “site”, we mean the set of instances of Agents and Clients, spread across one or more hosts, that should form a single OCS network.

In an observatory or lab, it will be convenient if Agents and Clients can determine the appropriate WAMP server and realm without user intervention. Furthermore, in cases where the same Agent code is launched in multiple instances (to control distinct instances of the same hardware model, for example) there needs to be a system that assigns a WAMP base address (such as detlab.cryo.thermo2) to each Agent instance in a consistent matter.

The approach adopted here is that ocs.site_config works with ArgumentParser to both consume and then modify the arguments being used to launch an Agent instance. Roughly speaking, the following occurs:

  1. When launching an Agent, the user uses command line arguments to specify a site configuration file. If no arguments are set, a sensible default is chosen.

  2. The configuration file is parsed and the special configuration appropriate to this Agent instance is identified. The configuration is determined based on the host the Agent instance is running on, and possibly by an “instance-id”, which helps distinguish between independent Agents running from the same source script.

  3. The special configuration parameters for this Agent instance are merged into the command line parameters.

  4. Through normal processing of command line parameters in the Agent script, the appropriate WAMP connections, address registrations, and hardware associations are made.

ocs.site_config

This section documents in detail the classes in ocs.site_config. For details about the site configuration file, please refer to OCS Site Config File.

SiteConfig

At root level, the configuration file should encode a SiteConfig object. The structure is described in the from_dict method of the SiteConfig class:

class ocs.site_config.SiteConfig[source]
classmethod from_dict(data)[source]
Parameters:

data – The configuration dictionary.

The configuration dictionary should have the following elements:

hub (required)

Describes what WAMP server and realm Agents and Clients should use.

hosts (required)

A dictionary of HostConfig descriptions. The keys in this dictionary can be real host names on the network, pseudo-host names, or the special value “localhost”.

A HostConfig marked for “localhost” will match any host that does not have an exact match in the hosts dictionary. This should normally be used only in single-host test systems or examples.

Client programs will normally (i.e., by default) try to load the HostConfig associated with the system hostname (that which is returned by socket.gethostname()). But this can be overridden easily, for example by using the --site-host command line argument. It is thus quite reasonable to use the hosts dictionary to hold a set of useful configurations indexed by a user-specified string (a pseudo-host).

The hub information is used by all Agent and Control Clients, on all hosts, to connect to the OCS WAMP router. This WAMP router (probably crossbar) usually has its own configuration file. The settings in SCF hub block are parsed by the from_dict method of the HubConfig class:

class ocs.site_config.HubConfig[source]
classmethod from_dict(data, parent=None)[source]
Parameters:
  • data – The configuration dictionary.

  • parent – the SiteConfig from which this data was extracted (this is stored as self.parent, but not used).

The configuration dictionary should have the following elements:

wamp_server (required): URL to the WAMP router’s websocket

access point for ocs. E.g., ws://host-2:8001/ws. WAMP routers can have multiple access points, with different protocols, security layers, and permissions. (Command line override: --site-hub.)

wamp_http (optional): URL to the WAMP router’s http bridge

interface. This is the best interface for simple clients to use. E.g., http://host-2:8001/call.

wamp_realm (required): The WAMP realm to use. WAMP

clients operating in a particular realm are isolated from clients connected to other realms. Example and test code will often use debug_realm here. (Command line override: --site-realm.)

address_root (required): The base address to be used by

all OCS Agents. This is normally something simple like observatory or detlab. (Command line override: --address-root.)

HostConfig

The structure of HostConfig encoding is described in the from_dict method of the HostConfig class:

class ocs.site_config.HostConfig(name=None)[source]
classmethod from_dict(data, parent=None, name=None)[source]
Parameters:
  • data – The configuration dictionary.

  • parent – the SiteConfig from which this data was extracted (this is stored as self.parent, but not used).

The configuration dictionary should have the following elements:

agent-instances (required)

A list of AgentConfig descriptions.

agent-paths (optional)

A list of additional paths where OCS is permitted to search for Agent plugin modules.

crossbar (optional)

Settings to assist with starting / stopping / monitoring a crossbar server running on this host. There is a single crossbar server for an OCS network and thus this entry should be defined for at most one of the hosts in the site config file. Note that setting this to None (or null) will disable host crossbar control, while setting it to an empty dictionary, {}, will enable local host crossbar control with default settings.

log-dir (optional)

Path at which to write log files. Relative paths will be interpreted relative to the “working directory”; see –working-dir command line option.

To allow ocs to manipulate the crossbar router (e.g. if you want to easily start and stop it using ocsbow), then the crossbar variable should be defined, with (at least) an empty dictionary. The details of the options are described in the from_dict method of the CrossbarConfig class:

class ocs.site_config.CrossbarConfig[source]
classmethod from_dict(data, parent=None)[source]
Parameters:
  • data – The configuration dictionary, or None.

  • parent – the HostConfig from which this data was extracted (this is stored as self.parent, but not used).

The configuration dictionary should have the following elements:

config-dir (optional): Location of crossbar config.json;

this gets passed to --cbdir, if specified..

bin (optional): The path to the crossbar executable.

This defaults to shutil.which(‘crossbar’).

If data is None, returns None. Otherwise returns a CrossbarConfig object.

The significance of agent-paths is described more in Agent Script Discovery.

InstanceConfig

The structure of InstanceConfig encoding is described in the from_dict method of the InstanceConfig class:

class ocs.site_config.InstanceConfig[source]
classmethod from_dict(data, parent=None)[source]
Parameters:
  • data – The configuration dictionary.

  • parent – the HostConfig from which this data was extracted (this is stored as self.parent, but not used).

The configuration dictionary should have the following elements:

instance-id (str, required)

This string is used to set the Agent instance’s base address. This may also be matched against the instance-id provided by the Agent instance, as a way of finding the right InstanceConfig.

agent-class (str, optional)

Name of the Agent class. This may be matched against the agent_class name provided by the Agent instance, as a way of finding the right InstanceConfig.

arguments (list, optional):

A list of arguments that should be passed back to the agent. Historically the arguments have been grouped into into key value pairs, e.g. [[’–key1’, ‘value’], [’–key2’, ‘value’]] but these days whatever you passed in gets flattened to a single list (i.e. that is equivalent to [’–key1’, ‘value’, ‘–key2’, ‘value’].

manage (str, optional):

A string describing how a HostManager should manage this agent. See notes.

Notes

The manage value is only relevant if a HostManager is configured to operate on the host. In that case, the HostManager’s treatment of the agent instance depends on the value of manage:

  • “ignore”: HostManager will not attempt to manage the agent instance.

  • “host/up”: HostManager will manage the agent instance, launching it on the host system. On startup, the instance will be set to target_state “up” (i.e. the HostManager will try to start it).

  • “host/down”: like host/up, but HostManager will not start up the agent instance until explicitly requested to do.

  • “docker/up”: HostManager will manage the agent instance through Docker. On Startup, the instance will be set to target_state “up”.

  • “docker/down”: Like docker/up, but the instance will be forced to target_state “down” on startup.

In earlier versions of OCS, the acceptable values were “yes”, “no”, and “docker”. Those were equivalent to current values of “host/down”, “ignore”, and “docker/down”.

Those values are still accepted, but note that “yes” and “docker” are now equivalent to “host/up” and “docker/up”.

The following abbreviated values are also accepted:

  • “host”: same as “host/up”

  • “up”: same as “host/up”

  • “down”: same as “host/down”

Control Clients and the Site Config

As of this writing, Control Clients do not store configuration in the SCF. But there is an interim interface available for Control Clients to access the Site Configuration, with the usual command-line overrides. Control Clients that use the run_control_script function to launch can instead use run_control_script2, which behaves as follows:

ocs.client_t.run_control_script2(*args, **kwargs)[source]

Deprecated since version v0.6.1: Renamed to run_control_script

The control client script might look something like this (see also river_ctrl.py in the examples):

def my_script(app, pargs):
    from ocs import client_t

    # We've added a --target option.
    # Construct the full agent address.
    agent_addr = '%s.%s' % (pargs.address_root, pargs.target)

    # Create a ProcessClient for the process 'acq'.
    cw = client_t.ProcessClient(app, agent_addr, 'acq')

    print('Starting a data acquisition process...')
    d1 = yield cw.start()
    #...

Agent Script Discovery

Agent scripts are currently written as stand-alone python scripts (and thus not not importable through the main ocs python module). To support automatic launching of Agents, site_config includes a plugin-style system to register Agent scripts. This is flexible enough to support both the natively packaged Agents and any “third-party” agents needed in a particular installation. The system works like this:

  • A bundle of Agent scripts is assembled at some location. There are no restrictions on where these scripts can live in the file system. For example, a script called riverbank_agent.py might live in /simonsobs/agents/.

  • A special “registration script” is written, with a filename of the form ocs_plugin_*.py. This script should live in Python’s import path, or else (and this is better), the path to the script should be included in the agent-paths variable in the SCF for this host. For example, we might put the file in /simonsobs/agents and call it ocs_plugin_simonsobs.py.

  • When the site_config system (specifically the HostManager agent) needs to find a particular agent script, it:

    • Adds any directories in agent-paths to the Python import path.

    • Scans through all importable modules, and imports them if they match the ocs_plugin_* name pattern.

  • The ocs_plugin script makes calls into ocs to associate a particular script filenames to agent class names. In our example, ocs_plugin_simonsobs.py would call ocs.site_config.register_agent_class('RiverBank', '/simonsobs/agents/riverbank_agent.py').

A good example of a plugin script can be found in the OCS agents directory, ocs_plugins_standard.py.