Attributes¶
Every Reactor has the following attributes, built from either the Reactor’s execution environment or by means of some clever mocking code in a local test environment:
name | type | contents | source |
---|---|---|---|
aliases | aliases.store.AliasStore |
A helper for managing App and Actor aliases | Configured on instantiation with current client |
client | agavepy.agave.Agave |
An active Agave API client | Values provided by Abaco platform using agavepy.actors or local Agave API credentials. |
context | dict |
Variables passed by Abaco platform to the current execution | Values passed by Abaco and materialized via agavepy.actors or generated by mocking support functions. |
execid | string |
The current Abaco execution ID | `context.execution_id |
local | boolean |
True or False to indicate whether the function is running under Abaco or in a testing environment. |
The LOCALONLY environment variable, which can be set in local testing configurations. |
logger | `logging.StreamHandler` |
Pointer to the screen logger of loggers |
|
loggers | dict |
Python loggers screen, which logs to both STDERR and (optionally) a structured log aggregator, and slack which can log directly to a Slack channel. | Configured on instantiation, with credentials for Slack and other services provided by environment variables. |
nickname | string |
A semi-random, human memorable string. (e.g. sleek-lemur) | A call to the petname library |
pemagent | agaveutils.recursive.PemAgent |
A helper for applying recursive Agave API files permissions. Calls to it will eventually be an asynchronous. | Configured on instantiation with current client |
session | string |
A correlation key for connecting related events. | Query parameters SESSION or x-session , then nickname |
settings | attrdict.AttrDict |
Contents of config.yml , where keys are accessible in dot.notation . |
Populated at instantiation from config.yml via tacconfig.load_settings() |
state | dict |
The current Abaco actor state variable | context.state |
uid | string |
The current Abaco actor ID | `context.actor_id |
username | string |
TACC.cloud username on whose behalf the actor’s current execution is being undertaken. | Provided by `context.username under Abaco or by inspecting client when running locally. |
aliases¶
This is an instance of AliasStore
with which one can create, get, remove, and share alias entries for any actor. See AliasStore documentation for details.
client¶
This is an active AgavePy API client used to make authenticated API calls on behalf of the user that invoked execution of the Reactor. All AgavePy functions are supported.
context¶
This is a dictionary populated from environment variables passed to the container by Abaco.
Example Usage¶
>>> r = Reactor()
>>> print(r.context)
AttrDict({'HOSTNAME': '4647e1acfe46', 'LOCALONLY': '1', '_REACTOR_TEMP': '/mnt/ephemeral-01', 'raw_message_parse_log': 'Error parsing message: malformed node or string: None', 'message_dict': {}, 'SCRATCH': '/mnt/ephemeral-01', 'REACTORS_VERSION': '0.7.5', '_': '/usr/bin/python3', 'SHLVL': '1', 'PWD': '/', 'LESSOPEN': '| /usr/bin/lesspipe %s', 'TERM': 'xterm', 'HOME': '/root', '_PROJ_STOCKYARD': '/work/projects/', 'PATH': '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', 'OLDPWD': '/mnt/ephemeral-01', 'MSG': 'Hello There', _USER_WORK': '', '_PROJ_CORRAL': '/corral', 'actor_dbid': '5GJbZRQYk0VmY', 'username': 'tacocat', 'actor_id': '5GJbZRQYk0VmY', 'state': {}, 'execution_id': 'DeAzrr6ABO1pr', 'raw_message': 'Hello There', 'content_type': 'application/json'})
>>> print(r.context.raw_message)
Hello There
Context combines environment variables inherited from the container image, set in the container’s worker by Abaco, and passed to the specific execution by Abaco into a single dictionary. In addition to the string value keys, there are two important dict objects: state and message_dict
- state is a
dict
that can be read from and modified to pass information between executions of an actor without relying on an external database.- message_dict is populated by parsing a JSON message passed to the actor into a Python dictionary. This is done automatically and safely via Pythons ast and json.loads functions. If a message can’t be parsed, message_dict is set to an empty
AttrDict
. If you believe you’re sending valid JSON but it’s not resolving as a dictionary,context.raw_message_parse_log
can be inspected for clues to what is causing the failure.
execid¶
This is the unique identifier for the current execution.
local¶
This is a boolean value set based on the state of the LOCALONLY environment variable. It is intended to be used to selectively disable or enable code branches when running under local emulation.
print()
statement¶ r = Reactor()
if r.local is not True:
print('This code is not running under a test environment')
else:
print('This code is running locally')
The state of local
is set automatically by some CI support scripts, and can be set in a pytest environment using the monkeypatch fixture.
True
¶ def test_demo_local(monkeypatch):
monkeypatch.setenv('LOCALONLY', 1)
r = Reactor()
assert r.local is True
logger¶
This is an ready-to-use Python logger.
Example Usage¶
>>> r = Reactor()
>>> r.logger.info('This is a log message')
5AB11Q8XxwPK5 INFO This is a log message
A nicely formatted message is printed to STDERR
that includes the current actor ID. All logging levels (debug, info, warning, critical) are available. Logging level is set in the logs
stanza of config.yml
.
At the same time a plaintext message is sent to the standard log, it can (optionally) be sent over the network in a structured format. This is described in the advanced topics section.
Log redaction¶
Sensitive data passed into a Reactor using the secrets mechanism are redacted automatically when logged. For instance, assume API credentials for AWS have been set in a Reactor. Under a standard logging scheme, it would be very easy to print those sensitive data in build logs, screenshots, commits, and such, where it could be easily discoverable.
>>> r = Reactor()
>>> api_secret = r.settings.api.secret
>>> r.logger.info('Here are credentials: {}'.format(api_secret))
Pk4B11Q8Xxw INFO Here are credentials: ****
>>> api_url = r.settings.api.url
>>> r.logger.info('Here is API server: {}'.format(api_urk))
Pk4B11Q8Xxw INFO Here is API server: https://tacos.tacc.cloud/api/v1
loggers¶
This dict holds references to all loggers configured by a Reactor. At present, two loggers are established. The default logger, screen, prints to STDERR and (optionally) a log aggregator. The other logger, slack, allows logging directly to Slack assuming a webhook is provided when the actor is configured.
---
slack:
channel: "notifications"
icon_emoji: ":smile:"
username: "tacobot"
webhook: ~
>>> r = Reactor()
>>> r.loggers['screen'].info('This actor is a logger and a slacker')
5AB11Q8XxwPK5 INFO This actor is a logger and a slacker
>>> r.loggers['slack'].info('This actor is a logger and a slacker')
nickname¶
Inspired by the naming of Docker containers and other cloud resources, each Reactor invocation is assigned a “human meaningful, decentralized, secure” nickname generated by the petname library. By default, two-word nicknames are used, but this can be overridden with an entry in config.yml
---
nickname:
length: 3
pemagent¶
This is an instance of PemAgent
, a helper for recursive Agave files permissions management. Most permissions operations should be handled directly using AgavePy files.*Permissions
commands. The pemagent helper exists provide an optimized, and potentially asynchronous, method for doing batch operations.
session¶
This string is a correlation identifier among platform events with a common ancestry. Its value is set as follows:
- If environment variable
x-session
is not empty, session takes on its value- Else, if environment variable
SESSION
is not empty, session takes on its value- Else, session is set to the value of nickname
Critically, actors can message other actors. When this is done using Reactor.send_message
, the session value is forwarded along to the receipients as x-session
and will thus become their session identifier.
Example Usage¶
An Agave API job may send a string, such as job name or ID as SESSION, when messaging an Abaco actor. In this example, demojob
is sent as a value for SESSION
.
{ "notifications": [
{
"url": "https://api.tacc.cloud/actors/v2/eZE7XDPLzZOwo/messages?x-nonce=SD2E_KbyGjq4XOM4&channel=agavejobs&SESSION=demojob",
"event": "FINISHED",
"persistent": false
}
}
The value of session in the downstream Reactor
instance will be demojob
. If that Reactor messages another reactor, the downstream entity’s session will also be demojob
.