View Source Runbox.Scenario.OutputAction (runbox v17.1.0)

Output action represents a side effect produced by a run.

Creating output actions

Creating output action typically happens from scenario. It is done by creating one of the appropriate struct:

For example:

iex> %OutputAction.UpsertAssetAttributes{
...>   type: "/asset/camera",
...>   id: "one",
...>   attributes: %{"foo" => "bar"}
...> }

Asset and edge output actions

Changes done by output actions to assets and edges are scoped for each scenario run. The global result is computed from the changes done by individual runs.

A single run is forbidden to do multiple changes to the same object (asset attribute or edge) at the same time. However distinct runs can perform such changes, because they are scoped to each run.

The rules to compute the global state apply in the following order:

  1. Change with the higher timestamp has precedence.

  2. Updating an asset attribute or an edge has precedence to deleting it.

  3. Change with the higher value has precedence (applies only for asset attributes).

Summary

Types

Attribute - access tag mapping.

Asset ID.

Asset type.

String with interpolation support.

t()

Output Action

Types

@type access_tag() :: String.t()
@type access_tags() :: %{
  required(attribute :: :all | String.t() | [String.t()]) =>
    access_tag() | [access_tag()]
}

Attribute - access tag mapping.

Access tags are defined as map where keys are attributes and values are tags of these attributes.

Attributes (keys) can be defined as:

  • :all - all attributes in this upsert share the same access tags
  • String.t() - single attribute access tags definition
  • [String.t()] - list of attributes that share the same access tags

Access tags (values) can be defined by single access tag or list of access tags.

Using this map structure we can define shared access tag for multiple attributes as well as multiple access tag for single attribute (or combination of both).

Attributes can be defined with dot syntax (e.g. user.contact.address.street) where nested attributes are separated by .. We can use this syntax to define access tags for group of nested attributes - access tags defined for user.contact.address will be used for all nested attributes such as user.contact.address.city and user.contact.address.street.

For delete operations: DeleteAllAssetAttributes,DeleteAssetAttributes and DeleteEdge it is recommended to use the same access tags as those used for the corresponding upsert operations within the same run.

Overlapping access tags definitions are concatenated. For example access tags defined as:

%UpsertAssetAttributes{
  ...
  access_tags: %{
    all: ["tag1"],
    "user.contact" => ["tag2"],
    ["user.contact.address", "user.contact.phone"] => ["tag3"],
    "user.contact.address.street" => "tag4"
  }
}

would mean that:

  • "user.contact" has these tags defined ["tag1", "tag2"]
  • "user.contact.address.phone" has these tags defined ["tag1", "tag2", "tag3"]
  • "user.contact.address.street" has these tags defined ["tag1", "tag2", "tag3", "tag4"]
@type asset_id() :: String.t()

Asset ID.

Asset ID together with an asset type uniquely identifies an asset.

Asset ID must not contain any slashes. They can contain any other character though. For example, these are valid asset IDs: fire_alarm, 192.168.0.142, Meeting room, and Příliš žluťoučký kůň.

@type asset_type() :: String.t()

Asset type.

Assets are grouped by their asset types. Assets of the same type should be of similar nature (e.g. servers or buildings) and should share the same set of attributes.

Asset types must start with a slash and must not end with a slash. Slashes can be used within the asset type to denote structure. For example, these are valid asset types: /assets/servers, /servers, and /assets/network/routers.

Although asset types like /servers are permitted, it is recommended to prefix asset types with the /assets prefix to enable consistent configuration of common attributes (e.g., name) via the root /assets asset type in the UI.

@type edge_type() :: String.t()
@type interpolable() :: String.t()

String with interpolation support.

Supports interpolating asset references to a format which is useful for displaying assets in the Altworx UI. The string can contain any number of placeholders in format

${assets.["/assets/camera", "one"]}

Where "/assets/camera" is the asset type and "one" is the asset ID. The resulting interpolation is

[Camera One[/assets/camera/one]]

Where Camera One is the asset's name attribute and /assets/camera/one is the asset's full ID. When the asset name is not present, the asset's ID is used instead

[one[/assets/camera/one]]

When the asset cannot be found, the resulting interpolation is

unknown

The interpolation is done upon "read" operations, therefore the result can vary based on the asset visibility for the identity of the user performing the operation.

@type t() :: %Runbox.Scenario.OutputAction{
  body: oa_params() | Runbox.Scenario.OutputAction.BadOutputAction.t(),
  run_id: term(),
  scenario_id: term(),
  timestamp: integer()
}

Output Action

This struct is produced by Runbox.Runtime.Stage.Sandbox.execute_run/3.