This API is a HTTP-based REST API with predictable resource URIs. The API accepts and returns data encoded in YAML or JSON.
The API provides a clean separation between configuration, operational state, and operations (RPCs).
When connecting to a Control Tower API, assuming your Control
Tower is at https://my-env.acme.avassa.net
, the API URL is
https://api.my-env.acme.avassa.net
From inside an application container, the API endpoint for the local
Edge Enforcer is always reachable at https://api.internal:4646
.
Configuration data is read and written under the path /v1/config
.
This data is called the intended configuration. It is the
configuration data provided by the user of the system. All data
in the intended configuration is both readable and writable.
The operational state of the system can be read under the path
/v1/state
. The operational state is read only. The operational
state contains the state of all intended configuration (this is
called the applied configuration), and all system state.
The state of a configured object under /v1/config/<PATH>
can be
read from /v1/state/<PATH>
.
The table below shows the structure of the API.
URI | GET | POST | PUT | PATCH | DELETE |
---|---|---|---|---|---|
/v1/config | read all | crud | - | - | - |
/v1/config/LIST | read all | create | - | - | - |
/v1/config/LIST/NAME | read one | - | create/replace | update | delete |
/v1/config/OBJECT | read | - | create/replace | update | delete |
/v1/state | read all | - | - | - | - |
/v1/state/LIST | read all | - | - | - | - |
/v1/state/LIST/NAME | read one | - | - | - | - |
/v1/state/OBJECT | read | - | - | - | - |
/v1/state/OPERATION | - | invoke | - | - | - |
/v1/OPERATION | - | invoke | - | - | - |
All resources also support the OPTIONS method.
The PATCH method (RFC 5789) can be used for updates of an existing resource.
Two formats of the body are supported, plain patch and JSON Patch (RFC 6902).
The strongbox resources support plain patch only.
Plain patch is indicated by using the Content-Type header
application/json
or application/yaml
.
The existing object is merged with the data in the payload.
A scalar value in the payload replaces the corresponding value in the object, if it exists; otherwise the given scalar value is created.
Arrays where the order is significant are replaced with the new array.
Arrays where the order is not significant are merged. This means that it is not possible to delete entries in such arrays with plain patch. In order to do that, JSON Patch can be used.
JSON Patch is indicated by using the Content-Type header
application/json-patch+json
or application/json-patch+yaml
.
The JSON Patch operations copy
and move
are not supported.
In addition to the standard operations add
, remove
,
replace
, and test
, the following operations are also
supported:
safe-remove
: works just like remove
, except that no error
is raised if the target location object does not exist.safe-replace
: works just like replace
, except that if the
target location object does not exist it is created.For example, given the site object:
name: stockholm-sergel
type: edge
topology:
parent-site: control-tower
labels:
region: europe
country: sweden
management-ipv4-access-list:
- 192.168.100.1
- 10.0.4.1
hosts:
- host-id: 38cfff0d-cce6-4f71-99dd-98612719cd79
we can add a new label and change the management-ipv4-access-list with the following request:
- op: add
path: /labels
value:
city: stockholm
- op: replace
path: /management-ipv4-access-list/0
value: 192.168.200.1
- op: remove
path: /management-ipv4-access-list/1
The resulting site is now:
name: sthlm-sergel
type: edge
topology:
parent-site: control-tower
labels:
region: europe
country: sweden
city: stockholm
management-ipv4-access-list:
- 192.168.200.1
hosts:
- host-id: 38cfff0d-cce6-4f71-99dd-98612719cd79
All objects in the intended configuration have an entity tag (ETag) that can be used to control concurrent access to the object, and detect if an object has been modified.
Use standard HTTP mechanisms (e.g., the header If-Match) to handle entity tags.
This endpoint represents the tenant's entire intended configuration.
A GET to this endpoint returns the entire intended configuration.
If YAML is requested, each object is returned as a separate YAML document. If JSON is requested, a list of objects is returned.
In the representation of each object, an additional field
x-path
is included, that contains the path to the object.
If the query parameter send-etag=true
is sent, each object also
has a field x-etag
.
For example, the reply could look like this:
---
x-path: /v1/config/applications/my-app
name: my-app
version: 1.2.2
# more data here ...
---
x-path: /v1/config/application-deployments/my-dep
name: my-dep
application-name: my-app
application-version: 1.2.2
# more data here ...
A POST to this endpoint is used to update multiple objects in one transaction, i.e., either all included operations are accepted, or none.
The format of the POST request is the same as result of a GET
request, except that each object also may have an additional
field x-operation
, that controls how the object is updated,
and an optional field x-json-patch
.
The POST request body can be YAML or JSON.
The field x-operation
can have the following values:
create
- The object is created if it doesn't exists. An
error is returned if the object already exists.replace
- The object is replaced if it exists, and created if
it doesn't exists.update
- The existing object is updated with the given fields. An
error is returned if the object doesn't exists.delete
- The object is deleted if it exists. An error is returned
if the object doesn't exist.remove
- The object is deleted if it exists. No error is returned
if the object doesn't exist.The query parameter default-operation
can be given to specify
which operation is used for a object that doesn't have an
x-operation
field. If no such query parameter is given, the
default operation is replace
.
When the operation is update
, the object can be updated with
plain patch (which means that the object is merged with the given
fields), or with JSON Patch. In order to use JSON Patch, set the
array of JSON Patch operations in the field x-json-patch
.
The operation update
corresponds to the PATCH
method for single
resources. See PATCH for details. Note that even
though the name of the format is json-patch
, the data can be
encoded in both JSON and YAML.
For example, the following request deletes the application
other-app
and updates the application deployments my-dep
and
another-dep
:
---
x-path: /v1/config/applications/other-app
x-operation: delete
---
x-path: /v1/config/application-deployments/my-dep
x-operation: update
application-version: 1.2.3
---
x-path: /v1/config/application-deployments/another-dep
x-operation: update
x-json-patch:
- op: replace
path: /placement/match-site-labels
value:
os-type: debian
If an object has a field x-etag
, the operation succeeds only if
the object exists with the given etag.
NOTE: It is not possible to update objects in strongbox through this endpoint.
This endpoint represents the tenant's entire operational state.
A GET to this endpoint returns the entire operational state.
If YAML is requested, each object is returned as a separate YAML document. If JSON is requested, a list of objects is returned.
In the representation of each object, an additional field
x-path
is included, that contains the path to the object.
For example, the reply could look like this:
---
x-path: /v1/config/applications/my-app
name: my-app
version: 1.2.2
# more data here ...
---
x-path: /v1/config/application-deployments/my-dep
name: my-dep
application-name: my-app
application-version: 1.2.2
# more data here ...
The API uses standard HTTP status codes to indicate success or failure of the requests. When an error body is returned, it is on the form:
{
"errors": [
"error-message": "string",
"error-info": "optional operation-specific error info"
]
}
The error is returned as JSON or YAML depending on the given
Accept
header.
The fields
query parameter can be used in GET requests to return
only the requested fields in the reply.
The syntax of this parameter is:
sequence = expr ( ',' expr )*
expr = path ( '/' '[' sequence ']' )?
path = field-name ( '/' path )?
field-name = identifier
/ identifier '=' identifier
For example:
foo,bar
- selects the fields foo
and bar
foo/bar
- selects the field bar
in foo
foo/[bar,baz]
- selects the fields bar
and baz
in foo
foo=x/bar
- selects bar
in foo
, and renames foo
to x
in the outputThe where
query parameter can be used in GET requests to list
endpoints to return only list items that match the given
expression.
The syntax of this parameter is:
expr = path-expr / logical-expr / arith-expr / function-call
/ literal / number
path-expr = ['/'] relative-path-expr
relative-path-expr = ( ('.' | '..' | identifier) [ predicate ] )*
predicate = '[' expr ']'
logical-expr = expr logical-operator expr
logical-operator = '>' / '>=' / '<' / '<='
/ '=' / '!='
/ 'and'
/ 'or'
arith-expr = '-' expr
/ expr arith-operator expr
arith-operator = '+' / '-' / '*' / 'div' / 'mod'
function-call = function '(' arg? (',' arg)* ')'
arg = expr
literal = '"' text '"'
/ "'" text "'"
The following functions are implemented:
boolean(object)
- converts its argument to a boolean.number(object)
- converts its argument to a number.string(object)
- converts its argument to a string.true()
- returns true.false()
- returns false.not(boolean)
- returns true if its argument is false and returns false otherwise.starts-with(string, string)
- returns true if the first argument string starts with
the second argument string, and false otherwise.contains(string, string)
- returns true if the first argument string contains
the second argument string, and false otherwise.re-match(string, string)
- the second argument is a regular expression. returns true
if the regular expression matches the first argument string.string-compare(string, string)
- returns -1 if the first argument string is
lexicographically smaller than the second argument string, 0 if the strings are equal,
and 1 otherwise.match-labels(object, string)
- the string argument is a label match expression, and
the object argument is a field with labels. returns true of the string argument matches
the labels in the object argument, and false otherwise.For example, when doing a GET to the list of assigned sites:
type = 'edge'
- selects all sites where the field type
is "edge"
.
Note that edge
must be given as a string!'edge' = type
- also selects all sites where the field type
is "edge"
.type = 'edge'
and connection-state/connected = true()` - selects all connected
edge sites.deployed-applications > 0
- selects all sites with at least one deployed application.starts-with(name, 'sto-')
- selects all sites where the name
field starts with the
string "sto"
.contains(name, 'swe')
- selects all sites where the name
field contains the
string "swe"
.re-match(name, 'sto-[0-9]+')
- selects all sites where the name
field matches the
given regular expression.string-compare(connection-state/last-connect, '2024-04-01') == -1
- selects all
sites that connected before 2024-04-01.match-labels(host-labels, 'security = high')
- selects all sites that have a
security
host label with the value high
.This syntax is a subset of XPath 1.0. For a complete description of the syntax and evaluation semantics, see the XPath 1.0 spec (https://www.w3.org/TR/1999/REC-xpath-19991116/).