API Overview
ESB3024 Router provides two different types of API:s:
- A content request API that is used by video clients to ask for content, normally using port 80 for HTTP and port 443 for HTTPS.
- A few REST API:s used by administrators to configure and monitor the router installation, using port 5001 over HTTPS by default.
The content API won’t be described further in this document, since it’s a simple HTTP interface serving content as regular files or redirect responses.
Raw configuration – /v2/configuration
Used to check and update the raw configuration of ESB3024 Router. Note that this API is considered an implementation detail and is not documented further.
REQUEST Method | Content-Type | RESPONSE Result | Status Code | Content-Type |
---|---|---|---|---|
GET | <N/A> | Success | 200 OK | application/json |
PUT | application/json | Success | 204 No Content | <N/A> |
PUT | application/json | Failure | 400 Bad Request | application/json 1 |
Validate Configuration – /v2/validate_configuration
Used to determine if a JSON payload is correctly formatted without actually applying its configuration. A successful return status does not guarantee that the applied configuration will work, it only validates the JSON structure.
REQUEST Method | Content-Type | RESPONSE Result | Status Code | Content-Type |
---|---|---|---|---|
PUT | application/json | Success | 204 No Content | <N/A> |
PUT | application/json | Failure | 400 Bad Request | application/json 1 |
Example request
When an expected field is missing from the payload, the validation will show which one and return an appropriate error message in its payload:
$ curl -i -X PUT \
-d '{"routing": {"log_level": 3}}' \
-H "Content-Type: application/json" \
https://router.example:5001/v2/validate_configuration
HTTP/1.1 400 Bad Request
Access-Control-Allow-Origin: *
Content-Length: 132
Content-Type: application/json
X-Service-Identity: router.example-5fc78d
"Configuration validation: Configuration parsing failed. \
Exception: [json.exception.out_of_range.403] (/routing) key 'id' not found"
Selection Input – /v1/selection_input
Selection input API can be used to inject external key:value data into the
routing engine, making the data available when making routing decisions. An
arbitrary JSON structure can be pushed to the endpoint. When performing GET
or
DELETE
requests, specific selection input values can be accessed or deleted by
including a path to the request. Note that not specifying a path will select all
selection input values.
One use case for selection input is to provide data on cache availability. E.g.
If you send {"edge-streamer-2-online": true}
to the selection input API,
you can create a routing condition eq('edge-streamer-online', true)
to
ensure that no traffic gets routed to the streamer if it’s offline. Note that
sending the same key:value data to the selection input API will overwrite the
previous value.
There is a configurable limit to how many key:value items that can be injected into the router, see the tuning parameter
$ confcli services.routing.tuning.general.selectionInputItemLimit
{
"selectionInputItemLimit": 10000
}
REQUEST Method | Content-Type | RESPONSE Result | Status Code | Content-Type |
---|---|---|---|---|
PUT | application/json | Success | 204 No Content | <N/A> |
PUT | application/json | Failure | 400 Bad Request | application/json |
GET | <N/A> | Success | 200 OK | application/json |
DELETE | <N/A> | Success | 204 No Content | <N/A> |
DELETE | <N/A> | Failure | 404 Not Found | <N/A> |
Example successful request (PUT
)
$ curl -i -X PUT \
-d '{"host1_bitrate": 13000, "host1_capacity": 50000}' \
-H "Content-Type: application/json" \
https://router.example:5001/v1/selection_input
HTTP/1.1 204 No Content
Access-Control-Allow-Origin: *
Content-Length: 0
X-Service-Identity: router.example-5fc78d
Example unsuccessful request (PUT
)
$ curl -i -X PUT \
-d '{"cdn-status": {"session-count": 12345, "load-percent" 98}}' \
-H "Content-Type: application/json" \
https://router.example:5001/v1/selection_input
HTTP/1.1 400 Bad Request
Access-Control-Allow-Origin: *
Content-Length: 169
Content-Type: application/json
X-Service-Identity: router.example-5fc78d
{
"error": "[json.exception.parse_error.101] parse error at line 1, column 57: \
syntax error while parsing object separator - \
unexpected number literal; expected ':'"
}
Example successful request (GET
)
curl -i https://router.example:5001/v1/selection_input
HTTP/1.1 200 OK
Access-Control-Allow-Origin: *
Content-Length: 129
Content-Type: application/json
X-Service-Identity: router.example-5fc78d
{
"host1_bitrate": 13000,
"host1_capacity": 50000
}
Example successful specific value request (GET
)
curl -i https://router.example:5001/v1/selection_input/path/to/value
HTTP/1.1 200 OK
Access-Control-Allow-Origin: *
Content-Length: 129
Content-Type: application/json
X-Service-Identity: router.example-5fc78d
1
Example successful request (DELETE
)
curl -i -X DELETE https://router.example:5001/v1/selection_input
HTTP/1.1 204 OK
Access-Control-Allow-Origin: *
Content-Length: 129
X-Service-Identity: router.example-5fc78d
Example successful specific value request (DELETE
)
curl -i -X DELETE https://router.example:5001/v1/selection_input/value/to/delete
HTTP/1.1 204 OK
Access-Control-Allow-Origin: *
Content-Length: 129
X-Service-Identity: router.example-5fc78d
Example unsuccessful request (DELETE
)
curl -i -X DELETE https://router.example:5001/v1/selection_input/non/existent/value
HTTP/1.1 404 Not Found
Access-Control-Allow-Origin: *
Content-Length: 129
X-Service-Identity: router.example-5fc78d
Subnets – /v1/subnets
An API for managing named subnets that can be used for routing and block lists. See Subnets for more details.
PUT
requests inject key value pairs with the form {<subnet>: <value>}
, where
<subnet>
is a valid CIDR string, into ACD, e.g.:
$ curl -i -X PUT \
-d '{"255.255.255.255/24": "area1", "1.2.3.4/24": "area2"}' \
-H "Content-Type: application/json" \
https://router.example:5001/v1/subnets
HTTP/1.1 204 No Content
Access-Control-Allow-Origin: *
Content-Length: 0
X-Service-Identity: router.example-5fc78d
GET
requests are used to fetch injected subnets, e.g.:
# Fetch all injected subnets
$ curl -i https://router.example:5001/v1/subnets
HTTP/1.1 200 OK
Access-Control-Allow-Origin: *
Content-Length: 411
Content-Type: application/json
X-Service-Identity: router.example-5fc78d
{
"1.2.3.4/16": "area2",
"1.2.3.4/24": "area1",
"1.2.3.4/8": "area3",
"255.255.255.255/16": "area2",
"255.255.255.255/24": "area1",
"255.255.255.255/8": "area3",
"2a02:2e02:9bc0::/16": "area8",
"2a02:2e02:9bc0::/32": "area7",
"2a02:2e02:9bc0::/48": "area6",
"2a02:2e02:9de0::/44": "combined_area",
"2a02:2e02:ada0::/44": "combined_area",
"5.5.0.4/8": "area5",
"90.90.1.3/16": "area4"
}
DELETE
requests are used to delete injected subnets, e.g.:
# Delete all injected subnets
$ curl -i https://router.example:5001/v1/subnets -X DELETE
HTTP/1.1 204 No Content
Access-Control-Allow-Origin: *
Content-Length: 0
X-Service-Identity: router.example-5fc78d
Both GET
and DELETE
requests can be specified with the paths /byKey/
and
/byValue/
to filter which subnets to GET
or DELETE
.
# Fetch subnet with the CIDR string 1.2.3.4/8 if it exists
$ curl -i https://router.example:5001/v1/subnets/byKey/1.2.3.4/8
HTTP/1.1 200 OK
Access-Control-Allow-Origin: *
Content-Length: 26
Content-Type: application/json
X-Service-Identity: router.example-5fc78d
{
"1.2.3.4/8": "area3"
}
# Fetch all subnets whose CIDR string begins with the IP 1.2.3.4
$ curl -i https://router.example:5001/v1/subnets/byKey/1.2.3.4
HTTP/1.1 200 OK
Access-Control-Allow-Origin: *
Content-Length: 76
Content-Type: application/json
X-Service-Identity: router.example-5fc78d
{
"1.2.3.4/16": "area2",
"1.2.3.4/24": "area1",
"1.2.3.4/8": "area3"
}
# Fetch all subnets whose value equals 'area1'
$ curl -i https://router.example:5001/v1/subnets/byValue/area1
HTTP/1.1 200 OK
Access-Control-Allow-Origin: *
Content-Length: 60
Content-Type: application/json
X-Service-Identity: router.example-5fc78d
{
"1.2.3.4/24": "area1",
"255.255.255.255/24": "area1"
}
# Delete subnet with the CIDR string 1.2.3.4/8 if it exists
$ curl -i https://router.example:5001/v1/subnets/byKey/1.2.3.4/8
HTTP/1.1 204 No Content
Access-Control-Allow-Origin: *
Content-Length: 0
X-Service-Identity: router.example-5fc78d
# Delete all subnets whose CIDR string begins with the IP 1.2.3.4
$ curl -i https://router.example:5001/v1/subnets/byKey/1.2.3.4
HTTP/1.1 204 No Content
Access-Control-Allow-Origin: *
Content-Length: 0
X-Service-Identity: router.example-5fc78d
# Delete all subnets whose value equals 'area1'
$ curl -i https://router.example:5001/v1/subnets/byValue/area1
HTTP/1.1 204 No Content
Access-Control-Allow-Origin: *
Content-Length: 0
X-Service-Identity: router.example-5fc78d
REQUEST Method | Content-Type | RESPONSE Result | Status Code | Content-Type |
---|---|---|---|---|
PUT | application/json | Success | 204 No Content | <N/A> |
PUT | application/json | Failure | 400 Bad Request | application/json |
GET | <N/A> | Success | 200 OK | application/json |
GET | <N/A> | Failure | 400 Bad Request | application/json |
DELETE | <N/A> | Success | 204 No Content | application/json |
DELETE | <N/A> | Failure | 400 Bad Request | application/json |
Subrunner Resource Usage – /v1/usage
Used to monitor the load on subrunners, the processes performing those tasks that are possible to run in parallel.
REQUEST Method | Content-Type | RESPONSE Result | Status Code | Content-Type |
---|---|---|---|---|
GET | <N/A> | Success | 200 OK | application/json |
Example request
$ curl -i https://router.example:5001/v1/usage
HTTP/1.1 200 OK
Access-Control-Allow-Origin: *
Content-Length: 1234
Content-Type: application/json
X-Service-Identity: router.example-5fc78d
{
"total_usage": {
"content": {
"lru": 0,
"newest": "-",
"oldest": "-",
"total": 0
},
"sessions": 0,
"subrunner_usage": {
[...]
}
},
"usage_per_subrunner": [
{
"subrunner_usage": {
[...]
}
},
[...]
]
}
Metrics – /m1/v1/metrics
An interface intended to be scraped by Prometheus. It is possible to scrape it manually to see current values, but doing so will reset some counters and cause actual Prometheus data to become faulty.
REQUEST Method | Content-Type | RESPONSE Result | Status Code | Content-Type |
---|---|---|---|---|
GET | <N/A> | Success | 200 OK | text/plain |
Example request
$ curl -i https://router.example:5001/m1/v1/metrics
HTTP/1.1 200 OK
Access-Control-Allow-Origin: *
Content-Length: 1234
Content-Type: text/plain
X-Service-Identity: router.example-5fc78d
# TYPE num_configuration_changes counter
num_configuration_changes 12
# TYPE num_log_errors_total counter
num_log_errors_total 0
# TYPE num_log_warnings_total counter
num_log_warnings_total{category=""} 123
# TYPE num_log_warnings_total counter
num_log_warnings_total{category="cdn"} 0
# TYPE num_log_warnings_total counter
num_log_warnings_total{category="content"} 0
# TYPE num_log_warnings_total counter
num_log_warnings_total{category="generic"} 10
# TYPE num_log_warnings_total counter
num_log_warnings_total{category="repeated_session"} 0
# TYPE num_ssl_errors_total counter
[...]
Node Visit Counters – /v1/node_visits
Used to gather statistics about the number of visits to each node in the routing tree. The returned value is a JSON object containing node ID names and their corresponding counter values.
REQUEST Method | Content-Type | RESPONSE Result | Status Code | Content-Type |
---|---|---|---|---|
GET | <N/A> | Success | 200 OK | application/json |
See Routing Rule Evaluation Metrics for more details.
Example request
$ curl -i https://router.example:5001/v1/node_visits
HTTP/1.1 200 OK
Access-Control-Allow-Origin: *
Content-Length: 73
Content-Type: application/json
X-Service-Identity: router.example-5fc78d
{
"cache1.tv": "99900",
"offload": "100"
"routingtable": "100000"
}
Node Visit Graph – /v1/node_visits_graph
Creates a GraphML representation of the node visitation data that can be rendered into an image to make it easier to understand the data.
REQUEST Method | Content-Type | RESPONSE Result | Status Code | Content-Type |
---|---|---|---|---|
GET | <N/A> | Success | 200 OK | application/xml |
See Routing Rule Evaluation Metrics for more details.
Example request
> curl -i -k https://router.example:5001/v1/node_visits_graph
HTTP/1.1 200 OK
Access-Control-Allow-Origin: *
Content-Length: 731
Content-Type: application/xml
X-Service-Identity: router.example-5fc78d
<?xml version="1.0"?>
<graphml xmlns="http://graphml.graphdrawing.org/xmlns"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd">
<key id="visits" for="node" attr.name="visits" attr.type="string" />
<graph id="G" edgedefault="directed">
<node id="routingtable">
<data key="visits">100000</data>
</node>
<node id="cache1.tv">
<data key="visits">99900</data>
</node>
<node id="offload">
<data key="visits">100</data>
</node>
<edge id="e0" source="routingtable" target="cache1.tv" />
<edge id="e1" source="routingtable" target="offload" />
</graph>
</graphml>
Session list - /v1/sessions
Used to monitor the load on subrunners, the processes performing those tasks that are possible to run in parallel.
REQUEST Method | Content-Type | RESPONSE Result | Status Code | Content-Type |
---|---|---|---|---|
GET | <N/A> | Success | 200 OK | application/json |
Example request
$ curl -k -i https://router.example:5001/v1/sessions
HTTP/1.1 200 OK
Access-Control-Allow-Origin: *
Content-Length: 12345
Content-Type: application/json
X-Service-Identity: router.example-5fc78d
{
"sessions": [
{
"age_seconds": 103,
"cdn": "edgeware",
"cdn_is_redirecting": false,
"client_ip": "1.2.3.4",
"host": "cdn.example:80",
"id": "router.example-5fc78d-00000001",
"idle_seconds": 103,
"last_request_time": "2022-12-02T14:05:05Z",
"latest_request_path": "/__cl/s:storage1/__c/v/f/0/5/v_sintel3v_f05a05f07d352e891d79863131ef4df7/__op/hls-default/__f/index.m3u8",
"no_of_requests": 1,
"requested_bytes": 0,
"requests_redirected": 0,
"requests_served": 0,
"session_groups": [
"all"
],
"session_groups_generation": 2,
"session_path": "/__cl/s:storage1/__c/v/f/0/5/v_sintel3v_f05a05f07d352e891d79863131ef4df7/__op/hls-default/__f/index.m3u8",
"start_time": "2022-12-02T14:05:05Z",
"type": "instream",
"user_agent": "libmpv"
},
[...]
]
}
Session details - /v1/sessions/<id: str>
Used to get details about a specific session from the above session list. The
id
part of the URL corresponds to the id
field in one of the
returned session entries in the above response.
REQUEST Method | Content-Type | RESPONSE Result | Status Code | Content-Type |
---|---|---|---|---|
GET | <N/A> | Success | 200 OK | application/json |
GET | <N/A> | Failure | 404 Not Found | application/json |
Example request
$ curl -k -i https://router.example:5001/v1/sessions/router.example-5fc78d-00000001
HTTP/1.1 200 OK
Access-Control-Allow-Origin: *
Content-Length: 763
Content-Type: application/json
X-Service-Identity: router.example-5fc78d
{
"age_seconds": 183,
"cdn": "edgeware",
"cdn_is_redirecting": false,
"client_ip": "1.2.3.4",
"host": "cdn.example:80",
"id": "router.example-5fc78d-00000001",
"idle_seconds": 183,
"last_request_time": "2022-12-02T14:05:05Z",
"latest_request_path": "/__cl/s:storage1/__c/v/f/0/5/v_sintel3v_f05a05f07d352e891d79863131ef4df7/__op/hls-default/__f/index.m3u8",
"no_of_requests": 1,
"requested_bytes": 0,
"requests_redirected": 0,
"requests_served": 0,
"session_groups": [
"all"
],
"session_groups_generation": 2,
"session_path": "/__cl/s:storage1/__c/v/f/0/5/v_sintel3v_f05a05f07d352e891d79863131ef4df7/__op/hls-default/__f/index.m3u8",
"start_time": "2022-12-02T14:05:05Z",
"type": "instream",
"user_agent": "libmpv"
}
Content List - /v1/content
REQUEST Method | Content-Type | RESPONSE Result | Status Code | Content-Type |
---|---|---|---|---|
GET | <N/A> | Success | 200 OK | application/json |
Example request
$ curl -k -i https://router.example:5001/v1/content
HTTP/1.1 200 OK
Access-Control-Allow-Origin: *
Content-Length: 572
Content-Type: application/json
X-Service-Identity: router.example-5fc78d
{
"content": [
[
"/__cl/s:storage1/__c/v/f/0/5/v_sintel3v_f05a05f07d352e891d79863131ef4df7/__op/hls-default/__f/index.m3u8",
{
"cached_count": 0,
"content_requested": false,
"content_set": false,
"expiration_time": "2022-12-02T14:05:05Z",
"key": "/__cl/s:storage1/__c/v/f/0/5/v_sintel3v_f05a05f07d352e891d79863131ef4df7/__op/hls-default/__f/index.m3u8",
"listeners": 0,
"manifest": "",
"request_count": 4,
"state": "HLS:MANIFEST-PENDING",
"wait_count": 0
}
]
]
}
Lua scripts – /v1/lua/<path str>.lua
Used to upload, retrieve and delete custom named Lua scripts on the router.
Global functions in uploaded scripts automatically become available to Lua code
in the configuration (which effectively may be viewed as hooks). Upload a
script by PUTing
a application/x-lua
to the endpoint, and retrieve it by
GETing
the endpoint without payload.
REQUEST Method | Content-Type | RESPONSE Result | Status Code | Content-Type |
---|---|---|---|---|
PUT | application/x-lua | Success | 204 No Content | <N/A> |
PUT | application/x-lua | Failure | 400 Bad Request | application/json |
GET | <N/A> | Success | 200 OK | application/x-lua |
GET | <N/A> | Failure | 404 Not Found | application/json |
DELETE | <N/A> | Success | 204 No Content | <N/A> |
DELETE | <N/A> | Failure | 400 Bad Request | application/json |
DELETE | <N/A> | Failure | 404 Not Found | application/json |
Example request (PUT
)
Save a Lua script under the name advanced_functions/f1.lua
:
$ curl -i -X PUT \
-d 'function fun1() return 1 end' \
-H "Content-Type: application/x-lua" \
https://router.example:5001/v1/lua/advanced_functions/f1.lua
HTTP/1.1 204 Successfully saved Lua file
Access-Control-Allow-Origin: *
Content-Length: 0
X-Service-Identity: router.example-5fc78d
Example request (PUT
, from file)
Upload an entire Lua file under the name advanced_functions/f1.lua
:
First put your code in a file.
$ cat f1.lua
function fun1()
return 1
end
Then upload it using the --data-binary
flag to preserve newlines
$ curl -i -X PUT \
--data-binary @f1.lua \
-H "Content-Type: application/x-lua" \
https://router.example:5001/v1/lua/advanced_functions/f1.lua
HTTP/1.1 204 Successfully saved Lua file
Access-Control-Allow-Origin: *
Content-Length: 0
X-Service-Identity: router.example-5fc78d
Example request (GET
)
Request the Lua script named advanced_functions/f1.lua
using a GET
request:
$ curl -i https://router.example:5001/v1/lua/advanced_functions/f1.lua
HTTP/1.1 200 OK
Access-Control-Allow-Origin: *
Content-Length: 28
Content-Type: application/x-lua
X-Service-Identity: router.example-5fc78d
function fun1() return 1 end
Example request (DELETE
)
Delete the Lua script named advanced_functions/f1.lua
using a DELETE
request:
$ curl -i -X DELETE \
https://router.example:5001/v1/lua/advanced_functions/f1.lua
HTTP/1.1 204 Successfully removed Lua file
Access-Control-Allow-Origin: *
Content-Length: 0
X-Service-Identity: router.example-5fc78d
List Lua scripts – /v1/lua
Used to list previously uploaded custom Lua scripts on the router, retrieving their respective paths and file checksums.
REQUEST Method | Content-Type | RESPONSE Result | Status Code | Content-Type |
---|---|---|---|---|
GET | <N/A> | Success | 200 OK | application/json |
Example request
$ curl -k -i https://router.example:5001/v1/lua
HTTP/1.1 200 OK
Access-Control-Allow-Origin: *
Content-Length: 108
Content-Type: application/json
X-Service-Identity: router.example-5fc78d
[
{
"file_checksum": "d41d8cd98f00b204e9800998ecf8427e",
"path": "advanced_functions/f1.lua"
}
]
Debug a Lua expression – /v1/lua/debug
Used to debug an arbitrary Lua expression on the router in a “sandbox” (with no visible side effects to the state of the router), and inspect the result.
The Lua expression in the body is evaluated inside an isolated copy of the
internal Lua environment including selection input. The stdout
field of the
resulting JSON body is populated with a concatenation of every string provided
as argument to the Lua print()
function during the course of evaluation.
Upon a successful evaluation, as indicated by the success
flag,
return.value
and return.lua_type_name
capture the resulting Lua value.
Otherwise, if valuation was aborted (e.g. due to a Lua exception), error_msg
reflects any error description arising from the Lua environment.
REQUEST Method | Content-Type | RESPONSE Result | Status Code | Content-Type |
---|---|---|---|---|
POST | application/x-lua | Success | 200 OK | application/json |
Example successful request
$ curl -i -X POST \
-d 'fun1()' \
-H "Content-Type: application/x-lua" \
https://router.example:5001/v1/lua/debug
HTTP/1.1 200 OK
Access-Control-Allow-Origin: *
Content-Length: 123
Content-Type: application/json
X-Service-Identity: router.example-5fc78d
{
"error_msg": "",
"return": {
"lua_type_name": "number",
"value": 1.0
},
"stdout": "",
"success": true
}
Example unsuccessful request
(attempt to invoke unknown function)
$ curl -i -X POST \
-d 'fun5()' \
-H "Content-Type: application/x-lua" \
https://router.example:5001/v1/lua/debug
HTTP/1.1 200 OK
Access-Control-Allow-Origin: *
Content-Length: 123
Content-Type: application/json
X-Service-Identity: router.example-5fc78d
{
"error_msg": "[string \"function f0() ...\"]:2: attempt to call global 'fun5' (a nil value)",
"return": {
"lua_type_name": "",
"value": null
},
"stdout": "",
"success": false
}
Access logging
When the configuration parameter tuning.access_log
is set to true
, HTTP
requests are logged in the common log format
(see https://en.wikipedia.org/wiki/Common_Log_Format) and tagged with the
matchable field "ACCESSLOG=1"
to be retrieved with journalctl
:
journalctl SYSLOG_IDENTIFIER=router ACCESSLOG=1
Example output
-- Logs begin at Tue 2023-05-23 07:57:16 UTC, end at Mon 2023-05-29 07:25:59 UTC. --
May 29 07:20:00 router[52236]: ::1 - - [29/May/2023:07:20:00 +0000] "GET /vod/batman.m3u8 HTTP/1.1" 302 0 "-" "curl/7.61.1"
Some useful optional arguments to journalctl
are:
journalctl SYSLOG_IDENTIFIER=router ACCESSLOG=1 [--follow] [-o json-pretty] [--since 2022-06-06] [--until 2022-06-10]
[--grep="HTTP/1.1\" 404"]
See the journalctl
documentation for further reading.