Other types
Discover
Discover the live members of a service — container endpoints, pods, replicas — and hand them to the rest of the pipeline as an array.
The point is to stop hard-coding a list of addresses that changes every time
something scales, restarts or reschedules. A discover action returns one
entry per member, and any later action fans out across them with lookup::
actions:
- name: Members
discover:
kubernetes:
label_selector: app=api
port_name: http
- name: PollAll
lookup: a|Members|
lookup_partition: true # -> { succeeded: [...], failed: [...] }
actions:
- name: Health
http:
url: a|body::url|/healthz
Every backend returns the SAME item shape, so a config written against one orchestrator moves to another by changing only the backend block:
{
"name": "api-7d9f8b6c5d-x2ktp",
"address": "10.42.1.3",
"port": 8080,
"url": "http://10.42.1.3:8080",
"source": "kubernetes",
"ready": true,
"namespace": "default",
"node": "worker-1",
"image": "example/api:1.4.0",
"labels": { "app": "api" }
}
Fields a backend cannot know are omitted rather than faked — DNS returns
addresses only, so it has no labels, image or ready. Filtering on a field
a backend does not provide therefore matches nothing, which is why
label_selector belongs to the backends that actually have labels.
| Field | Type | Description |
|---|---|---|
dns | DiscoverDns (nullable) | Resolve a DNS name to every address behind it. The portable option: no API access, no credentials, no RBAC, nothing to mount. In Kubernetes point it at a headless Service… |
kubernetes | DiscoverKubernetes (nullable) | Query the Kubernetes API for pods. The richest option: real label selectors, plus namespace, node, readiness and image per pod. Requires a ServiceAccount with list on pods,… |
docker | DiscoverDocker (nullable) | Query the Docker Engine API for containers. For container hosts that are not Kubernetes: plain Docker, Compose, Swarm. Requires access to the Docker socket, which is equivalent… |
static | Array<string> (nullable) | An explicit list of host:port entries. Not discovery — the escape hatch for environments with none of the above, and what tests pin against. Keeping it in the same shape… Example ↓ |
include | DiscoverFilter (nullable) | Keep only members matching these patterns. Applied before exclude. |
exclude | DiscoverFilter (nullable) | Drop members matching these patterns. Exclusion wins over inclusion, deliberately: when the two disagree the safe reading of the operator's intent is "do not touch this one". |
port | DiscoverPort (nullable) | Port to use when the backend does not supply one (DNS always, Kubernetes when neither port nor port_name is set). Without it those members are returned with no port and no… |
scheme | string (nullable) | Scheme used to build each member's url. Defaults to http. |
cache_ttl_secs | number (nullable) | How long to reuse a result before querying again, in seconds. Defaults to 10; 0 disables caching. This matters more than it looks. Without it, a discovery action on a… |
fail_when_empty | boolean (nullable) | Fail the action when discovery returns nothing. Defaults to false, so an empty result is an empty loop rather than an error — a service legitimately scaled to zero is not a… |
Field examples
static
An explicit list of host:port entries.
Not discovery — the escape hatch for environments with none of the above, and what tests pin against. Keeping it in the same shape means a config can start static and move to real discovery without touching the actions that consume it.
Accepts either a YAML sequence or a single comma-separated string, so the
whole list can come from ONE variable — which is how a member list is
usually configured, and how AIRPIPE__WS_MESH_PEERS already works:
static: "10.0.0.1:8080, 10.0.0.2:8080" # one variable
static: a|ap_var::MEMBERS| # ...including from a variable
static: ["10.0.0.1:8080", "10.0.0.2:8080"] # or a sequence
Empty and null entries are dropped rather than rejected. Configs are
re-parsed AFTER interpolation, so an entry whose variable resolves to
nothing (a|ap_var::MEMBER_2->default()|) arrives here as a bare -,
i.e. YAML null. Failing there would break the config only in the
environment where that variable happened to be unset — in production,
having passed every test.
DiscoverDns
DNS-based discovery.
| Field | Type | Description |
|---|---|---|
name | string | Required. The name to resolve — airpipe-mesh, api.default.svc.cluster.local, or a Compose service name. A bare name takes the action's port; name:port is honoured as written. |
exclude_self | string (nullable) | Drop this node's own address from the results. Useful when a service discovers its peers and should not call itself. Needs the address to exclude, e.g. a|env::POD_IP|. |
DiscoverKubernetes
Kubernetes API discovery.
| Field | Type | Description |
|---|---|---|
namespace | string (nullable) | Namespace to search. Defaults to the agent's own namespace, read from the ServiceAccount token mount — so the common case needs no configuration and stays inside the… |
label_selector | string (nullable) | Standard Kubernetes label selector, e.g. app=api,tier!=canary. Passed through to the API server, so the same syntax as kubectl -l. |
field_selector | string (nullable) | Standard field selector, e.g. status.phase=Running. |
port_name | string (nullable) | Take the port from a named container port (http, metrics). Preferred over a hard-coded number: the name survives a port change. |
ready_only | boolean (nullable) | Return only pods whose containers are all ready. Defaults to true — an unready pod is one that has told you not to send it traffic. |
DiscoverDocker
Docker Engine API discovery.
| Field | Type | Description |
|---|---|---|
labels | Map<string, string> (nullable) | Container labels to match, e.g. com.docker.compose.service: api. All listed labels must match. |
network | string (nullable) | Docker network whose address should be reported for each container. With several networks attached and no choice made, the first is used. |
socket | string (nullable) | Path or URL of the Docker Engine socket. Defaults to /var/run/docker.sock. |
DiscoverFilter
Regex patterns matched against a member's fields. An unset field matches everything; a field the backend does not populate never matches.
| Field | Type | Description |
|---|---|---|
name | string (nullable) | Regex against the member name (pod or container name). |
image | string (nullable) | Regex against the full image reference, including registry and tag. |
namespace | string (nullable) | Regex against the namespace (Kubernetes only). |
DiscoverPort
A port: a literal number, or a marker that resolves to one.
Every other field of a discover block interpolates, because they are
strings. A bare u16 could not, so port: a|ap_var::SERVICE_PORT| did not
merely fail to resolve — the marker was still marker TEXT when serde reached
it, and the agent died at load with invalid type: string ... expected u16.
A config that names its port the same way it names everything else should
work, so the string form is accepted and parsed after interpolation.
One of:
- number —
port: 8080 - string —
port: a|ap_var::SERVICE_PORT->default(8080)|, or a quoted"8080". Still a marker at parse time; resolved once interpolation has run.
EmailAttachment
One file attached to an outgoing email.
| Field | Type | Description |
|---|---|---|
filename | string | Required. Filename shown to the recipient. |
content | string | Required. The file contents. base64 by default — pair it with the b64_encode post-transform, which is also what makes binary files (PDF, images) work. Use encoding: utf8 to attach… |
content_type | string (nullable) | MIME type, e.g. text/csv, application/pdf. Defaults to application/octet-stream. |
encoding | string (nullable) | How content is encoded: base64 (default) or utf8. |
WsPublish
Publish a payload to realtime WebSocket channels (server push / fan-out). Every socket subscribed to any listed channel — on this node AND every peer node — receives the payload. Fire-and-forget: it does not wait for delivery.
Example
- name: Broadcast
ws_publish:
channels: a|body::rooms| # a string, an array, or an a|...| marker
data: a|OrderAction| # defaults to a|body| when omitted
| Field | Type | Description |
|---|---|---|
channels | any | Required. Channel key(s) to publish to: a string, an array of strings, or an a|... marker resolving to either. |
data | any | The payload pushed to subscribers. An a|... marker or inline JSON. Defaults to the request/message body when omitted. |
retain | any | Store the payload as the channel's RETAINED value, so a subscriber that connects (or reconnects) later immediately receives the current value on subscribe. Defaults to false.… |
MqttPublish
A mqtt_publish action publishes a message from a pipeline to one or more MQTT
topics. Every subscriber to a listed topic — on this node AND every peer node (via
the realtime mesh) — receives the payload. This is the pipeline→topic direction
(the inbound topic→pipeline direction is the ingest consumer). Fire-and-forget: it
does not wait for broker acknowledgement.
Example
- name: Push
mqtt_publish:
topics: a|body::topic| # a string, an array, or an a|...| marker
data: a|Reading| # defaults to a|body| when omitted
qos: 1 # 0 (default) | 1 | 2
retain: false # default false
| Field | Type | Description |
|---|---|---|
topics | any | Required. Topic(s) to publish to: a string, an array of strings, or an a|... marker resolving to either. |
data | any | The payload published to subscribers. An a|... marker or inline JSON. A JSON string publishes as raw text; any other value publishes as its JSON encoding. Defaults to the… |
qos | number (nullable) | MQTT quality of service for the published message: 0 (at most once, default), 1 (at least once), or 2 (exactly once). |
retain | any | Whether the broker retains this message as the topic's last-known-good value, delivered to future subscribers on subscribe. Defaults to false. Accepts a literal boolean OR an… |
TransformAggregate
Reduce a JSON array to a summary (sum / avg / min / max / count), optionally grouped.
| Field | Type | Description |
|---|---|---|
over | string (nullable) | JSONPath to the array to aggregate. Omit to aggregate the whole data when it is itself an array. |
key | string (nullable) | Output field to hold the summary. Omit to replace the data with the summary. |
sum | Array<string> (nullable) | Fields to sum. |
avg | Array<string> (nullable) | Fields to average. |
min | Array<string> (nullable) | Fields to take the minimum of. |
max | Array<string> (nullable) | Fields to take the maximum of. |
count | boolean (nullable) | Include a row count in the summary (default true when no other op is given). |
group_by | Array<string> (nullable) | Group rows by these fields; the summary is computed per group under groups. |
HmacSign
Parameters for the hmac post-transform (signing).
Example
hmac:
key: signature
data: a|BuildPayload::body|
secret: a|Subscriber::secret|
algorithm: sha256
encoding: hex
| Field | Type | Description |
|---|---|---|
key | string | Required. Output key the computed digest is written to. |
data | string | Required. The message to sign. Supports interpolation. |
secret | string | Required. The signing secret. Supports interpolation — use a|ap_var::NAME| or a per-recipient secret read from a prior action. |
algorithm | string (nullable) | Hash algorithm: sha1, sha256 (default), or sha512. |
encoding | string (nullable) | Digest encoding: hex (default) or base64. |