5.2 Developing Kaholo Plugins using Docker

This section explains how to develop a Kaholo Plugin that makes use of Docker. For example if you are writing a plugin that uses a CLI to send data to AutoCAD, rather than installing this CLI on every Kaholo Agent, you can develop your plugin to run within a Docker container, and use nebratech/autocad as the docker image. This allows the plugin to work consistently regardless of which Kaholo agent is used and the version or state of that agent. Also when an updated version of nebratech/autocad becomes available, your plugin will use it by default with no code changes required.

This is a common design, so the functionality is included in the Kaholo Plugin Library and re-use of this library is encouraged to develop docker-enabled Kaholo plugins. The Kaholo Plugin Library provides a lot of benefit in terms of rapid development, security, validation, and consistent results. In this section we’ll outline the details of how to make this work.

Reference Kaholo Plugin Library

The Kaholo Plugin Libarary is maintained as a Github repository and published as an npm package for easy reference in your own plugins. We’ll use the Maven plugin as an example because it is a very simple CLI that will allow us to focus on the Docker aspect with minimal maven-related distractions.

The first step is to include this library in your npm configuration, package.json.

  "dependencies": {
    "@kaholo/plugin-library": "^2.0.0"
  }

Next, within your code file, e.g. app.js or in the case of Maven mvn-cli.js, declare a constant requiring the library. In this case name of the docker image to use and the command are declared as constants in consts.json.

in mvn-cli.js:

    const { docker } = require("@kaholo/plugin-library");
    const {
    MAVEN_DOCKER_IMAGE,
    MAVEN_CLI_NAME,
    } = require("./consts.json");

consts.json:

    {
    "MAVEN_DOCKER_IMAGE": "maven",
    "MAVEN_CLI_NAME": "mvn"
    }

Now you are ready to use the necessary library functions in code.

Using the Kaholo Plugin Library

The relevant functions in the Kaholo Plugin library are in file docker.js.

function sanitizeCommand(command, commandPrefix)

This function ensures only the intended command line executable gets used, and also allows the user to optionally omit the name of that executable, returning a string sh -c command options.

function createVolumeDefinition(path)

This function allows for the mounting of paths in the Kaholo Agent to make them available within the docker container executing the command. Maven for example builds a Java project based on configuration in a file pom.xml. The source files and pom.xml are put on the Kaholo Agent (e.g. using Git plugin to clone a repository) and the JAR file result will need to remain on the Kaholo Agent after the Maven container is destroyed so the next step in the pipeline can access it. Therefore a directory on the Kaholo Agent (path) is passed to this function and gets mounted within the docker container as a docker volume.

Environment variable names and the mount point within the docker image are randomized to minimize the potential of discovery/recovery during and after the lifetime of the docker container. These details are returned as a JSON object.

    return {
        path: {
        name: pathEnvironmentVariableName,
        value: path,
        },
        mountPoint: {
        name: mountPointEnvironmentVariableName,
        value: mountPoint,
        },
    };

In the case more than one mount is required, this function can be used multiple times to create an array of volume definitions for the buildDockerCommand() function. Note that even if there is only one, it needs to be a single-element array.

function buildDockerCommand({Object})

Function buildDockerCommand requires a JSON object containing the command, docker image, environment variables, volume definitions, additional arguments, and working directory. There’s a parameter for user but this is most commonly left to default to root. This JSON object is built up using the results from sanitizeCommand(), createVolumeDefinition(), and normal method parameters if any are required.

    function buildDockerCommand({
    command,
    image,
    environmentVariables = {},
    volumeDefinitionsArray = [],
    additionalArguments = [],
    workingDirectory,
    user,
    })

This function validates and builds up the complete docker command line string, including image, environment variables, mounts and such that will start the container, run the command, direct output to the Kaholo Activity Log and Final Result, and then destroy the docker container.

Run the Docker Command

Finally it’s time to run the command string built by the buildDockerCommand() function. Here’s how the Maven plugin does this.

    const util = require("util");
    const childProcess = require("child_process");
    const { access } = require("fs/promises");

    const exec = util.promisify(childProcess.exec);

    return exec(dockerCommand, {
        env: shellEnvironmentalVariables,
    }).catch((error) => {
        throw new Error(error.stderr || error.stdout || error.message || error);
    });