Duffle can perform various actions, such as install
and uninstall
. These actions interact with CNAB images. For example, a duffle install my_app example:1.2.3
will execute the invocation image for the CNAB example:1.2.3
.
It is possible that users may want to determine which runtime is used to execute the invocation image. For example, if the image is a Docker image, a user may prefer to run it with Docker, or they may prefer to run it with an alternative client (like rkt
), or they may prefer to execute it within a cloud service like Azure Container Instances.
To accommodate this case, Duffle provides multiple drivers.
Duffle inspects the bundle.json to determine the image type of the image. (FIXME: Actually, right now it just assumes Docker. See cmd/duffle/install.go
.) Each image can be a particular type, such as a Docker image or a QCOW image.
Drivers can support different image types. The docker
driver supports oci
and docker
image types. The debug
driver supports all image types. When creating a new driver, developers must specify which image types that driver can support.
By default, the docker
driver is used. But a user may choose to override the driver by specify the -d DRIVERNAME
flag on the relevant operation.
A driver will (MUST) fail if the given driver cannot handle the CNAB bundle's invocation image.
Duffle has a few default drivers:
docker
: Runs OCI and Docker images using a local Docker client (currently requires the Docker CLI)aci
: Runs a Docker image inside of Azure ACI (currently requires theaz
command line client)debug
: Dumps the info that was sent to the driver, and exits???
: Runs a VM image on... (TODO: We want a VM version if possible. Maybeaz
for this?)
Configuration is sent to drivers via environment variables. For example, setting the environment variable $DEBUG
will turn on debugging for most drivers, while setting the environment variable $AZ_RESOURCE_GROUP
will set the resource group setting on drivers that use az
.
Custom drivers are implemented following the pattern of git
plugins: When a driver is requested (-d mydriver
) and Duffle does not have built-in support for that driver name, it will seek $PATH
for a program named cnab-mydriver
(prepending cnab-
to the driver name).
If a suitable executable is found, Duffle will execute that program, using the action requested. The environment in which that command executes will be pre-populated with the current environment variables. Credential sets will be passed as well. And the operation will be sent as a JSON body on STDIN:
{
"Installation": "foo",
"Action": "install",
"Parameters": {
"backend_port": 80,
"hostname": "localhost"
},
"Credentials": [
{
"type": "env",
"name": "SERVICE_TOKEN",
"value": "secret"
}
],
"Image": "bar:1.2.3",
"ImageType": "docker",
"Revision": "aaaaaa1234567890"
}
The custom driver is expected to take that information and execute the appropriate action for the given image.
A driver must implement two flags:
--handles
: Must return a comma-separated list of image types that it can handle--help
: Must return user-friendly documentation on the driver
Only one of these two flags will be provided. No other flags will be sent. When these flags are sent, no data will be sent over STDIN.
The following is a simple Bash script that implements both of the required flags, and responds to a request by printing the action and then exiting.
#!/bin/bash
set -eo pipefail
if [[ $1 == "--handles" ]]; then
echo docker,oci,qcow
exit 0;
elif [[ $1 == "--help" ]]; then
echo "Put yer helptext here"
exit 1;
fi
echo -n "Plugin: The action is "
cat - | jq .action
If the --handles
flag is set, this will return docker,oci,qcow
and exit with code 0 (no error). If --help
is set, the help text will be sent.
Under all other cases, it will attempt to read STDIN, pipe that through the jq
command, and print the action
found in the JSON body.
By naming this file cnab-foo
and placing it in the $PATH
, we can execute it as a driver:
$ duffle -d foo install myname technosophos/helloworld:0.1.0
Plugin: The action is "install"
Note that when it comes to execution order, it will be invoked as follows:
- When Duffle loads, it will look for an internal driver named
foo
.- If Duffle finds an internal driver named
foo
(which it won't), it will execute the internal version - If Duffle does not find an internal driver named
foo
, it will create a stub command executor forcnab-foo
.
- If Duffle finds an internal driver named
- When Duffle determines what image type the
bundle.json
, it will runcnab-foo --handles
.- If the declared image type is not in the returned list, Duffle will return an error and quit.
- When the operation is ready, Duffle will run
cnab-foo
and pipe the JSON data intocnab-foo
's standard input.- if
cnab-foo
returns with an exit code > 1, Duffle will generate an error and exit - if
cnab-foo
returns an exit code 0, Duffle will mark this as a successful operation
- if
The parameters and credentials that are sent to a custom driver will have already been verified.
Parameters will contain the validated, merged parameters. They will be validated against the parameters specification contained in the bundle.json
file.
Credentials will be loaded and converted to their destination
format.
A driver MAY withhold some credentials from the underlying system it represents, but it MUST inform the user if doing so.
A driver MUST NOT remove any of the parameters, and must inject them into the image in the format specified by the CNAB specification.
Next Section: duffle build