Step 3 of 5: Container Service Commands
Goal
In this step, you will learn how to create a new Command and attach it to a registered Docker Image. You will also try launching a couple of simple Commands using the XNAT REST API, via Swagger.
The XNAT Container Service uses a Command object to store information about how to launch Docker containers from images. This will perform the same role as the docker run
command seen in Part 1 of this practical. When we ran docker run
, we provided two main arguments: the name of the image that was the base for our container, and the command to run in the container.
To make a Command, we need the id
of a Docker Image that has been registered with XNAT, and a string called the run-template
. The Image id
we will use is the Image we registered in Step 2 (it very probably has an id=1
), and it tells docker which image will be the base for containers started from this Command. The run-template
parameter defines an execution string to be run on the Docker container, and it essentially says what command to run in the container.
Define a command
We will POST
to the /xapi/commands
endpoint the following JSON:
{
"type": "docker-image",
"name": "Hello world",
"description": "Echos Hello World in Ubuntu",
"docker-image": {"id": 1},
"run-template": ["/bin/sh", "-c", "echo Hello World"]
}
Tip
As shown above, the value of the docker-image.id
field is 1
. If you followed along with the instructions in Step 2, 1
is the ID of the Docker Image you created in that step. If you did things slightly differently, or you want to use a different Docker Image ID, you can change the value from 1
to some other Image ID.
- Return to the XNAT Swagger main page.
- Expand the
command-rest-api
item, and thePOST /xapi/commands
item. - Copy the JSON above, and paste it into the
command
field. - Press the "Try it out!" button. Note the response value, which is the ID of the Command that was just created.
In this example:
- The value
docker-image.id=1
defines the particular registered Docker Image to use. - The value of
run-template=["/bin/sh", "-c", "echo Hello World"]
will be executed when XNAT starts a container using this Command. - The command
id
in the above screenshot is returned in the Response Body. If this is your first time creating a Command on this machine, your Commandid
will likely be1
.
Tip
If the response body looks more like a full web page than the value you were expecting, you are probably being redirected to the XNAT login page and will need to reload and authenticate before continuing.
Launch your command
Commands will usually be executed by XNAT as part of an ACE (Action/Context Execution), which allows the Command to use values and files from XNAT objects (sessions, subjects, scans, etc.) However, you are able to execute a command on its own. You won't be able to automatically fill in any information from XNAT, but in the case of the command defined above we don't need anything from XNAT, so that's fine.
- Return to the XNAT Swagger page.
- Expand
command-rest-api
, andPOST /xapi/commands/{id}/launch
. - Enter
1
for theid
parameter (or whatever response you received when you created the Command in the last step). - Enter
{}
for thecontext
parameter. (Swagger thinks this is required when it really isn't, so to satisfy Swagger we send in a blank object.) - Press the "Try it out!" button.
You should receive a 200
Response Code, indicating there were no problems. The Response Body is the id of the docker container that was just executed. Note the value of the container id, so we can use it later.
We can see that the docker container executed our echo Hello World
by inspecting its logs. However, we haven't yet written the REST API to get the logs from Docker (but it is coming). To see the logs, open a terminal, and navigate to your xnat-workshop-vms
directory. Execute the following commands (replacing the <container id>
string with the response you got back from XNAT a moment ago):
you@local-machine:xnat-workshop-vms$ ./run xnat-31 ssh
xnat@xnat-31:~$ docker logs <container id>
Hello World
We see there that the Command, which just ran echo Hello World
as we defined in the run-template
, ran successfully. (We also see the handy Docker feature that the containers record their stdout and stderr for you to inspect later.)
Tip
A short-form <container id>
is also accessible via Docker command line interface, if you did not record the response from XNAT when you launched the Command.
- Run
docker ps -a
from your SSH prompt (xnat@xnat-31:~$
) - Note the CONTAINER ID of the most recently exited container
Commands with variables
Now we know we can run Commands. But the Command we ran was boring, and just does the same thing every time. Let's make a new Command, this time using a variable that can be set when we execute it.
- Return to the XNAT Swagger main page.
- Expand the
command-rest-api
item, and thePOST /xapi/commands
item. Enter the following JSON into the
command
field:CODE{ "type": "docker-image", "name": "echo with variable", "description": "Echos a message in Busybox", "docker-image": {"id": 1}, "run-template": ["/bin/sh", "-c", "echo #message#"], "variables": [ { "name": "message", "description": "The message to echo", "required": true, "value": "Hello XNAT" } ] }
(Again, if yourdocker-image
has a different id not equal to1
, use yours as the value ofdocker-image.id
)- Press the "Try it out!" button.
Once again, the Response Body value is your command id, which you should note for the next steps.
But let's pause for a moment to look at the JSON we just posted. We changed the run-template
, which used to be ["/bin/sh","-c","echo Hello World"]
, and now is ["/bin/sh","-c","echo #message#"]
. We also added a variables
section, with one variable with name message
.
When we go to launch this Command, XNAT will fill out all the template strings in run-template
, which look like #some-variable-name#
by filling in the value
from the variable named some-variable-name
. We defined a default value="Hello XNAT"
, but if we send in another value when we execute the Command that will be used instead.
Now let's launch the Command.
- Return to the XNAT Swagger page.
- Expand
command-rest-api
, andPOST /xapi/commands/{id}/launch
. - Enter
2
for theid
parameter (or whatever response you received when you created the Command in the last step). - Enter
{"message":"Sup, XNAT?"}
in thecontext
field. - Press the "Try it out!" button.
Copy the response body, and use it as <container id>
in the following command (entered in the xnat-31 VM):
xnat@xnat-31:~$ docker logs <container id>
Sup, XNAT?
You can try entering other message
s, and your container will dutifully echo
them out.
In this step, you've seen how to define and launch XNAT commands. These commands bind registered Docker images with a run-template
, templatized with variables
. This binding enables XNAT-aware container execution using Actions, which we'll explore next.
Next step: Actions