API Reference

Pod Management

GET /api/pod/

List all pods

Example response:

HTTP/1.1 200 OK
Content-Type: application/json

[
    {
        "name": "eru",
        "desc": "eru test pod",
        "__class__": "Pod"
    }
]
GET /api/pod/(name)/networks

List networks under a pod

Example response:

HTTP/1.1 200 OK
Content-Type: application/json

[
    {"name": "host", "subnets": [], "__class__": "Network"},
    {"name": "bridge", "subnets": ["172.17.0.0/16"], "__class__": "Network"}
]
GET /api/pod/(name)/nodes

List nodes under a pod

Example response:

HTTP/1.1 200 OK
Content-Type: application/json

[
    {
        "name": "c1-eru-2.ricebook.link",
        "endpoint": "tcp://xxx.xxx.xxx.xxx:2376",
        "podname": "eru",
        "cpu": {"0": 75},
        "memory": 855085056,
        "info": "{\"ID\":\"UUWL:QZS7:MPQY:KMYY:T5Q4:GCBY:JBRA:Q55K:NUKW:O2N2:4BEX:UTFK\",\"Containers\":7,\"ContainersRunning\":6,\"ContainersPaused\":0,\"ContainersStopped\":1,\"Images\":9,\"Driver\":\"overlay\",\"DriverStatus\":[[\"Backing Filesystem\",\"xfs\"],[\"Supports d_type\",\"false\"]],\"SystemStatus\":null,\"Plugins\":{\"Volume\":[\"local\"],\"Network\":[\"bridge\",\"host\",\"macvlan\",\"null\",\"overlay\"],\"Authorization\":null},\"MemoryLimit\":true,\"SwapLimit\":true,\"KernelMemory\":true,\"CpuCfsPeriod\":true,\"CpuCfsQuota\":true,\"CPUShares\":true,\"CPUSet\":true,\"IPv4Forwarding\":true,\"BridgeNfIptables\":true,\"BridgeNfIp6tables\":true,\"Debug\":false,\"NFd\":57,\"OomKillDisable\":true,\"NGoroutines\":72,\"SystemTime\":\"2018-03-20T16:10:51.806831123+08:00\",\"LoggingDriver\":\"json-file\",\"CgroupDriver\":\"cgroupfs\",\"NEventsListener\":1,\"KernelVersion\":\"3.10.0-693.5.2.el7.x86_64\",\"OperatingSystem\":\"CentOS Linux 7 (Core)\",\"OSType\":\"linux\",\"Architecture\":\"x86_64\",\"IndexServerAddress\":\"https://index.docker.io/v1/\",\"RegistryConfig\":{\"InsecureRegistryCIDRs\":[\"127.0.0.0/8\"],\"IndexConfigs\":{\"docker.io\":{\"Name\":\"docker.io\",\"Mirrors\":[\"https://registry.docker-cn.com/\"],\"Secure\":true,\"Official\":true}},\"Mirrors\":[\"https://registry.docker-cn.com/\"]},\"NCPU\":1,\"MemTotal\":1928826880,\"DockerRootDir\":\"/var/lib/docker\",\"HttpProxy\":\"\",\"HttpsProxy\":\"\",\"NoProxy\":\"\",\"Name\":\"c1-eru-2.ricebook.link\",\"Labels\":[],\"ExperimentalBuild\":false,\"ServerVersion\":\"17.12.1-ce\",\"ClusterStore\":\"etcd://127.0.0.1:2379\",\"ClusterAdvertise\":\"\",\"Runtimes\":{\"runc\":{\"path\":\"docker-runc\"}},\"DefaultRuntime\":\"runc\",\"Swarm\":{\"NodeID\":\"\",\"NodeAddr\":\"\",\"LocalNodeState\":\"inactive\",\"ControlAvailable\":false,\"Error\":\"\",\"RemoteManagers\":null},\"LiveRestoreEnabled\":false,\"Isolation\":\"\",\"InitBinary\":\"docker-init\",\"ContainerdCommit\":{\"ID\":\"9b55aab90508bd389d7654c4baf173a981477d55\",\"Expected\":\"9b55aab90508bd389d7654c4baf173a981477d55\"},\"RuncCommit\":{\"ID\":\"9f9c96235cc97674e935002fc3d78361b696a69e\",\"Expected\":\"9f9c96235cc97674e935002fc3d78361b696a69e\"},\"InitCommit\":{\"ID\":\"949e6fa\",\"Expected\":\"949e6fa\"},\"SecurityOptions\":[\"name=seccomp,profile=default\"]}",
    "available": true,
    "labels": {},
    "__class__": "Node"
    }
]
GET /api/pod/(name)

Get a single pod by name

Example response:

HTTP/1.1 200 OK
Content-Type: application/json

{
    "name": "eru",
    "desc": "eru test pod",
    "__class__": "Pod"
}

App Management

POST /api/app/register

Register a release of the specified app

Request JSON Object:
 
  • appname (string) – required
  • sha (string) – required, must be length 40
  • git (string) – required, the repo address using git protocol, e.g. git@github.com:projecteru2/citadel.git
  • specs_text (string) – required, the yaml specs for this app
  • branch (string) – optional git branch
  • git_tag (string) – optional git tag
  • commit_message (string) – optional commit message
  • author (string) – optional author
GET /api/app/

List all the apps associated with the current logged in user, for administrators, list all apps

Example response:

HTTP/1.1 200 OK
Content-Type: application/json

[
    {
        "id": 10001,
        "created": "2018-03-21 14:54:06",
        "updated": "2018-03-21 14:54:07",
        "name": "test-app",
        "git": "git@github.com:projecteru2/citadel.git",
        "tackle_rule": {},
        "env_sets": {"prodenv": {"foo": "some-env-content"}}
    }
]
GET /api/app/(appname)/version/(sha)/containers

Get all containers of the specified release

Todo

  • add example response
  • test this API
GET /api/app/(appname)/containers

Get all containers of the specified app

Todo

  • add example response
  • test this API
GET /api/app/(appname)/releases

List every release of the specified app

Todo

  • add example response
  • test this API
GET /api/app/(appname)/version/(sha)

Get one release of the specified app

Todo

  • add example response
  • test this API
GET /api/app/(appname)/users

List users who has permissions to the specified app

Todo

  • write tests for this API
  • add example response
PUT /api/app/(appname)/users

Grant permission to a user

Request JSON Object:
 
  • username (string) – you know what this is
  • user_id (int) – must provide either username or user_id
DELETE /api/app/(appname)/users

Revoke someone’s permission to a app

Request JSON Object:
 
  • username (string) – you know what this is
  • user_id (int) – must provide either username or user_id
GET /api/app/(appname)/combo

Get all the combos for the specified app

Todo

  • write tests for this API
  • add example response
PUT /api/app/(appname)/combo

Create a combo for the specified app

Request JSON Object:
 
  • name (string) – required, the combo name
  • entrypoint_name (string) – required
  • podname (string) – required
  • nodename (string) – optional, provide this only when your app can only be deployed in one machine
  • extra_args (string) – optional, extra arguments to the entrypoint command, e.g. [python -m http.server] --bind 0.0.0.0
  • networks (list) – required, list of network names, which can be obtained using GET /api/pod/(name)/networks
  • cpu_quota (float) – required
  • memory – required, can provide int (in bytes) or string values, like "128MB" or 134217728, when the provided value is string, it’ll be parsed by humanfriendly.parse_size(binary=True)
  • count (string) – number of containers, default to 1
  • envname (string) – optional, name of the environment variable set to use
POST /api/app/(appname)/combo

Edit the combo value for the specified app

Request JSON Object:
 
  • name (string) – required, the combo name
  • entrypoint_name (string) – required
  • podname (string) – required
  • nodename (string) – optional, provide this only when your app can only be deployed in one machine
  • extra_args (string) – optional, extra arguments to the entrypoint command, e.g. [python -m http.server] --bind 0.0.0.0
  • networks (list) – required, list of network names, which can be obtained using GET /api/pod/(name)/networks
  • cpu_quota (float) – required
  • memory – required, can provide int (in bytes) or string values, like "128MB" or 134217728, when the provided value is string, it’ll be parsed by humanfriendly.parse_size(binary=True)
  • count (string) – number of containers, default to 1
  • envname (string) – optional, name of the environment variable set to use
DELETE /api/app/(appname)/combo

Delete one combo for the specified app

Request JSON Object:
 
  • name (string) – the combo name
PUT /api/app/(appname)/env/(envname)

Create a environmental variable set

http

GET /<appname>/env/<envname> HTTP/1.1
Accept: application/json

{
    "HTTP_PROXY": "whatever",
    "HTTPS_PROXY": "whatever"
}

curl

curl -i 'http://nohost/<appname>/env/<envname>' -H 'Accept: application/json' --data-raw '{
    "HTTP_PROXY": "whatever",
    "HTTPS_PROXY": "whatever"
}'

wget

wget -S -O- 'http://nohost/<appname>/env/<envname>' --header='Accept: application/json' --body-data='{
    "HTTP_PROXY": "whatever",
    "HTTPS_PROXY": "whatever"
}'

httpie

echo '{
    "HTTP_PROXY": "whatever",
    "HTTPS_PROXY": "whatever"
}' | http 'http://nohost/<appname>/env/<envname>' Accept:application/json

python-requests

requests.get('http://nohost/<appname>/env/<envname>', headers={'Accept': 'application/json'}, data='{\r\n    "HTTP_PROXY": "whatever",\r\n    "HTTPS_PROXY": "whatever"\r\n}')
POST /api/app/(appname)/env/(envname)

Edit the specified env set, usage is the same as GET /api/app/(appname)/env/(envname)

GET /api/app/(appname)/env/(envname)

Get the content of the specified environmental variable set

Example response:

HTTP/1.1 200 OK
Content-Type: application/json

{
    "bar": "whatever",
    "FOO": "\"",
    "foo": "'"
}
DELETE /api/app/(appname)/env/(envname)

Delete the specified environmental variable set

GET /api/app/(appname)/env

List all env sets for the specified app

Example response:

HTTP/1.1 200 OK
Content-Type: application/json

{
    "prodenv": {
        "password": "secret"
    },
    "testenv": {
        "password": "not-so-secret"
    }
}
GET /api/app/(appname)

Get a single app

Example response:

HTTP/1.1 200 OK
Content-Type: application/json

{
    "id": 10001,
    "created": "2018-03-21 14:54:06",
    "updated": "2018-03-21 14:54:07",
    "name": "test-app",
    "git": "git@github.com:projecteru2/citadel.git",
    "tackle_rule": {},
    "env_sets": {"prodenv": {"foo": "some-env-content"}}
}

Container Actions

Action APIs using websocket, upon connection, client should send a first json payload, and then server will work and steam the output as websocket frames

GET /api/action/deploy-elb

Remove the specified containers

Request JSON Object:
 
  • name (string) – required, ELB cluster name
  • zone (string) – required
  • sha (string) – required, minimum length is 7
  • combo_name (string) – required, the combo used to create ELB containers
  • nodename (string) – optional
GET /api/action/deploy

Create containers for the specified release

Request JSON Object:
 
  • appname (string) – required
  • zone (string) – required
  • sha (string) – required, minimum length is 7
  • combo_name (string) – required, specify the combo to use, you can

update combo value using this API, so all parameters in the POST /api/app/(appname)/combo are supported

Example response:

HTTP/1.1 200 OK
Content-Type: application/json

{
    "podname": "eru",
    "nodename": "c1-eru-2.ricebook.link",
    "id": "9c91d06cb165e829e8e0ad5d5b5484c47d4596af04122489e4ead677113cccb4",
    "name": "test-app_web_kMqYFQ",
    "error": "",
    "success": true,
    "cpu": {"0": 20},
    "quota": 0.2,
    "memory": 134217728,
    "publish": {"bridge": "172.17.0.5:6789"},
    "hook": "I am the hook output",
    "__class__": "CreateContainerMessage"
}
GET /api/action/remove

Remove the specified containers

Request JSON Object:
 
  • container_ids (list) – required, a list of container_id

Example response:

HTTP/1.1 200 OK
Content-Type: application/json

{
    "id": "9c91d06cb165e829e8e0ad5d5b5484c47d4596af04122489e4ead677113cccb4",
    "success": true,
    "message": "hook output",
    "__class__": "RemoveContainerMessage"
}
GET /api/action/build

Build an image for the specified release, the API will return all docker build messages, key frames as shown in the example responses

Request JSON Object:
 
  • appname (string) – required, the app name
  • sha (string) – required, minimum length is 7

Example response:

HTTP/1.1 200 OK
Content-Type: application/json

{
    "id": "",
    "status": "",
    "progress": "",
    "error": "",
    "stream": "Step 1/7 : FROM python:latest as make-artifacts",
    "error_detail": {
        "code": 0,
        "message": "",
        "__class__": "ErrorDetail"
    },
    "__class__": "BuildImageMessage"
}

{
"id": "0179a75e26fe",
"status": "Pushing",
"progress": "[==================================================>]  6.656kB",
"error": "",
"stream": "",
"error_detail": {
    "code": 0,
    "message": "",
    "__class__": "ErrorDetail"
},
"__class__": "BuildImageMessage"
}

{
"id": "",
"status": "finished",
"progress": "hub.ricebook.net/projecteru2/test-app:3641aca",
"error": "",
"stream": "finished hub.ricebook.net/projecteru2/test-app:3641aca",
"error_detail": {
    "code": 0,
    "message": "",
    "__class__": "ErrorDetail"
},
"__class__": "BuildImageMessage"
}
GET /api/action/renew

Create a new container to substitute the old one, this API can be used to upgrade a app to a specified version, or simply re-create a container using the same combo.

Things can go wrong at any step, the example response was the output generated by renew("1aa8a638a153b393ee423c0a8c158757b13ab74591ade036b6e73ac33a4bdeac", "3641aca") which failed because the newly created container didn’t become healthy within the given time limit.

Request JSON Object:
 
  • container_ids (list) – required, a list of container_id
  • sha (string) – required, minimum length is 7

Example response:

HTTP/1.1 200 OK
Content-Type: application/json

{
    "podname": "eru",
    "nodename": "c1-eru-2.ricebook.link",
    "id": "2f123f1abcdfc8208b298c89e10bcd8f48f9fdb25c9eb7874ea5cc7199825e6e",
    "name": "test-app_web_rvrhPg",
    "error": "",
    "success": true,
    "cpu": {"0": 20},
    "quota": 0.2,
    "memory": 134217728,
    "publish": {"bridge": "172.17.0.5:6789"},
    "hook": "hook output",
    "__class__": "CreateContainerMessage"
}

{
    "id": "2f123f1abcdfc8208b298c89e10bcd8f48f9fdb25c9eb7874ea5cc7199825e6e",
    "success": true,
    "message": "hook output",
    "__class__": "RemoveContainerMessage"
}

{
    "error": "New container <Container test-zone:test-app:3641aca:web:2f123f1 did't became healthy, remove result: id: 2f123f1abcdfc8208b298c89e10bcd8f48f9fdb25c9eb7874ea5cc7199825e6e success: true",
    "args": ["1aa8a638a153b393ee423c0a8c158757b13ab74591ade036b6e73ac33a4bdeac", "3641aca"],
    "kwargs": {"user_id": null}
}