This file describes the RESTful compile-server API. The API looks like the following: Method URI DESCRIPTION POST /builds create build GET /builds/123 retrieve build info DELETE /builds/123 delete build GET /results/789 retrieve result info GET /results/789/FILE retrieve result files All the individual item numbers in the URIs will be UUIDs. You'll notice that DELETE is missing from most the above. For now anyway, we'll let the server decide when to delete the containers. Also note that the server will decide when a new container needs to be created (based on the build id information). Also note at this point that we're not going to authenticate users. We're going to leave that level of authentication to a front-end reverse-proxy server, rather than worry about it ourselves. How are we going to handle the perhaps long creation time, if we have to create a new docker container for instance? It would look like this: client: POST /builds (all the parameters, kernel version, arch, etc.) server: 202 Accepted - URI of queued build task (like /builds/456) Note that the server could return an error here, especially if the architectures don't match. Also note that there could be a GET needed here on the returned URI to upload a script file (if that wasn't done in the POST data). So then how does the client know when the queued build task is finished? It polls the queued build task: client: GET /builds/456 server: 200 OK (along with buildid details) Eventually, the client will get the following: client: GET /builds/456 server: 303 See Other - along with the URI of the result info. The client would then retrieve the result info, which will list all the files produced. After retrieving the module (using GET), the client can delete the buildid (at this point the server would also delete the linked result files). client: DELETE /builds/456 server: 300 OK One semi-tricky server note. Let's say a job comes in to build a module for kernel X. While building a container for kernel X, a second request comes in to build a module for kernel X. The server should reuse the in-progress container from the first build, not try to build a 2nd container for the same kernel. This implies that the containers should contain a reference count. That information should be persistent across server shutdown and startup, so we'll need a small database. FIXME: at some point we'll need to add other stuff the current client/server code supports, like certificates used for module signing, MOK signing, etc. The server could support several possible "back ends": - LOCAL: use the kernel devel environment(s) on the local machine. If nothing else, this could be used for testing the server. The server wouldn't add any more kernel devel environments here, but if the devel environment for kernel X is already installed here, it seems odd to build a container. - MOCK: build a mock "container" to build the module in - DOCKER: build a docker container to build the module in - VAGRANT: build a vagrant container to build the module in The user wouldn't be bothered with picking from these, the server will decide which one to use based on which one matches up with the server system. In other words, if the docker application isn't present the server shouldn't try to use it. The server will also need to "garbage collect" at some point, making sure the we only keep X containers around and deleting ones that haven't been used recently. Here's an example run: - The client sends a POST /builds request: POST /builds kver=4.12.0-0.rc3.git0.2.fc27.x86_64&arch=x86_64&cmd_args=-vp4&cmd_args=-e&cmd_args=probe+begin+%7B+exit%28%29+%7D' The server responds with: HTTP/1.1 202 Accepted Retry-After: 10 Location: /builds/ad64 This tells the client to wait 10 seconds then do a GET on /builds/ad64. - The client does a GET: GET /builds/ad64 The server responds with a JSON encoded body: HTTP/1.1 200 OK Location: /builds/ad64 Body: { "uuid": "ad64", "kver": "4.12.0-0.rc3.git0.2.fc27.x86_64", "arch": "x86_64", "cmd_args": [ "-vp4", "-e", "probe begin { exit() }" ] } The client keeps doing the same GET until... - When the build is finished, the server will respond with a 303: HTTP/1.1 303 See Other Location: /results/39ff The client then does a GET on the /results/URI: GET /results/39ff The server responds: HTTP/1.1 200 OK Body: { "uuid": "39ff", "rc": 0, "stdout_location": "/results/39ff/stdout", "stderr_location": "/results/39ff/stderr", "files": [ { "location": "/results/39ff/stap_91e5911967e16d8c350000d9f1d7de71_1105.ko", "mode": 436 } ] } - The client can then to a GET on the module itself: GET /results/39ff/stap_91e5911967e16d8c350000d9f1d7de71_1105.ko The server responds (along with the module data): HTTP/1.1 200 OK - At this point the client could issue a DELETE on /builds/ad64.