EventBus¶
The EventBus serves as an event broker. It receives subscriptions and publications from the OpenTestFactory orchestrator services and dispatches the received publications accordingly.
Its endpoints may be exposed, in which case new plugins may subscribe to and publish events at any time, or it may be unexposed, in which case it will not be possible for new plugins to subscribe to and publish events.
Communications are authenticated by signed JWT tokens.
Subscription¶
Subscriptions are not publications. It is not possible for a service to subscribe to new subscriptions: they are handled using their own endpoints and are not dispatched to subscribers.
Subscribing¶
For a service to subscribe to publications, it must post a Subscription
event to the following endpoint:
POST /subscriptions
It may post more than one subscription message if it is interested in more than one sort of publication.
This request will return a status message. If the subscription is
valid, the status response will contain a details.uuid
unique subscription identifier
that can be used to cancel the subscription.
The body of the subscription message is a JSON document that complies with the Subscription schema.
It must contain an apiVersion
part, a kind
part, a metadata.name
part, and a
spec.subscriber.endpoint
part.
It may contain a spec.subscriber.insecure-skip-tls-verify
part, in which case, if
the associated value resolves to true
, this means that the event bus will not check
if the HTTPS link is using valid certificates. If this part is missing, or if it
resolves to false
, the event bus will check the certificates, and will not send
messages to the endpoint if they are not valid.
It may or may not contain a spec.selector
part. If it does not contain such
a part, it will receive all well-formed events.
If the spec.selector
part is present, it must contain at least one of the following
entries: matchKind
, matchLabels
, matchExpressions
, matchFields
, or
matchFieldExpressions
The subscription will match events that satisfy all specified selectors.
The matchKind
value is a string. The subscription will match events whose kind
value exactly matches.
The matchLabels
value is a set of label:value
pairs. The subscription will match
events that have the corresponding labels with their associated values. If a label is
missing in the event, or it has a different value, the event will not be matched.
The matchFields
value is a set of path:values
pairs. The subscription will
match events that comply with the specified description.
The matchExpressions
and matchFieldExpressions
values are lists of expressions.
Expressions are of any of the following three forms:
-
Field or label value in (or not in) a set of values
{ "key": "field or label", "operator": "In|NotIn", "values": ["value1", "value2"] }
-
Field or label exists (or does not exist)
{ "key": "field or label", "operator": "Exists|DoesNotExist" }
-
Field (a list or an object) contains all (or does not contain all) values
{ "key": "field only", "operator": "ContainsAll|DoesNotContainAll", "values": ["value1", "value2"] }
(Only applies to fields, as labels values are strings, not composite values)
A list of expressions can contain expressions of different forms.
Subscription examples
This first subscription example is for a service that will receive all ExecutionCommand
events:
{
"apiVersion": "opentestfactory.org/v1",
"kind": "Subscription",
"metadata": {
"name": "subscription name"
},
"spec": {
"subscriber": {
"endpoint": "https://service.example.com/inbox"
},
"selector": {
"matchKind": "ExecutionCommand"
}
}
}
This second example is for a service that will receive ProviderCommand
for the
myprefix/mytask@v1
function:
{
"apiVersion": "opentestfactory.org/v1",
"kind": "Subscription",
"metadata": {
"name": "subscription name"
},
"spec": {
"subscriber": {
"endpoint": "https://service.example.com/inbox"
},
"selector": {
"matchKind": "ProviderCommand",
"matchLabels": {
"categoryPrefix": "myprefix",
"category": "mytask",
"categoryVersion": "v1"
}
}
}
}
This last example is for a service that will receive ExecutionResult
events that have
an attachments
field:
{
"apiVersion": "opentestfactory.org/v1",
"kind": "Subscription",
"metadata": {
"name": "postman interpreter",
},
"spec": {
"subscriber": {
"endpoint": "https://service.example/com/inbox"
},
"selector": {
"matchKind": "ExecutionResult",
"matchFieldExpressions": [
{
"key": "attachments",
"operator": "Exists"
}
]
}
}
}
Unsubscribing¶
If a subscription is no longer relevant, a service may cancel its subscription:
DELETE /subscriptions/{subscription_id}
The possible return codes are OK
(200) and NotFound
(404).
Listing active subscriptions¶
It is possible to list all currently active subscriptions using the following endpoint:
GET /subscriptions
The return code is OK
(200). The body of the response is a JSON document with
the following elements:
{
"apiVersion": "v1",
"kind": "SubscriptionsList",
"items": [
// ...
]
}
Each item is a subscription message as received by the POST /subscriptions
endpoint,
complemented by a status
section, which contains the following three entries:
publicationCount
: the number of publications dispatched to this subscriberlastPublicationTimestamp
: the last publication dispatch date, in ISO formatpublicationStatusSummary
: an object with one entry per received return code and the number of associated dispatches.
Example of Active subscription details
Here is an example of an item returned by the GET /subscriptions
endpoint:
{
"apiVersion": "opentestfactory.org/v1",
"kind": "Subscription",
"metadata": {
"name": "subscription name",
"creationTimestamp": "2021-09-01T10:48:49.582383",
"annotations": {
// ...
}
},
"spec": {
"subscriber": {
"endpoint": "https://service.example.com/inbox"
},
"selector": {
"matchKind": "ExecutionCommand"
}
},
"status": {
"publicationCount": 12,
"lastPublicationTimestamp": "2021-09-10T13:28:19.812383",
"publicationStatusSummary": {
"200": 10,
"503": 2
}
}
}
It matched 12 publications. 10 were successfully dispatched to the subscriber, and 2
were received with a 503
error code.
Publication¶
Publications must be valid JSON documents. They may not have a kind
or an apiVersion
entry.
The body of the request must be the JSON document to dispatch, and the entrypoint is the following:
POST /publications
The possible return codes are OK
(200) and BadRequest
(400).
If the return code is OK
, the message
part of the status message is either
Publication received, but no matching subscription.
or Publication received.
The EventBus does not modify the publication message (the body of the request).
Dispatching¶
If a subscriber is momentarily unavailable, the event bus may not dispatch the publication to it even if the subscriber comes back to life at a later time. But other available subscribers will receive it.
Due to the asynchronous and distributed nature of the event bus, some publications may be
dispatched more than once to a subscriber. Each publication contains a unique
X-Publication-ID
header that can be used to detect duplicated publications.
Additionally, each publication dispatched to a service contains an X-Subscription-ID
header which is the corresponding subscription ID.