Skip to content
Browse files

Add "dcgoss flavour" of dgoss (#427)

* add dcgoss from

Signed-off-by: Felix Bartels <>

* get in improvements from dgoss

Signed-off-by: Felix Bartels <>

* shellcheck fixes

Signed-off-by: Felix Bartels <>

* move dcgoss into its own directory and add a readme

Signed-off-by: Felix Bartels <>
  • Loading branch information...
fbartels authored and aelsabbahy committed May 12, 2019
1 parent 765d6e2 commit 641180c96dcfd7793d651cfcfa5e5be14e0f93eb
Showing with 179 additions and 0 deletions.
  1. +66 −0 extras/dcgoss/
  2. +113 −0 extras/dcgoss/dcgoss
@@ -0,0 +1,66 @@
# dcgoss

dcgoss is a convenience wrapper around goss that aims to bring the simplicity of goss to docker-compose managed containers. It is based on `dgoss`.

## Usage

`dgoss [run|edit] <docker_run_params>`

### Run

Run is used to validate a docker container defined in `docker-compose.yml`. It expects both a `docker-compose.yml` and `goss.yaml` file to exist in the directory it was invoked from. Container configuration is used from the compose file, for example:


`docker-compose up db`


`dcgoss run db`

`dcgoss run` will do the following:
* Start the container as defined in `docker-compose.yml`
* Stream the containers log output into the container as `/goss/docker_output.log`
* This allows writing tests or waits against the docker output
* (optional) Run `goss` with `$GOSS_WAIT_OPTS` if `./goss_wait.yaml` file exists in the current dir
* Run `goss` with `$GOSS_OPTS` using `./goss.yaml`

### Edit

Edit will launch a docker container, install goss, and drop the user into an interactive shell. Once the user quits the interactive shell, any `goss.yaml` or `goss_wait.yaml` are copied out into the current directory. This allows the user to leverage the `goss add|autoadd` commands to write tests as they would on a regular machine.


`dcgoss db`

### Environment vars and defaults
The following environment variables can be set to change the behavior of dgoss.

Location of the goss binary to use. (Default: `$(which goss)`)

Options to use for the goss test run. (Default: `--color --format documentation`)

Options to use for the goss wait run, when `./goss_wait.yaml` exists. (Default: `-r 30s -s 1s > /dev/null`)

Time to sleep after running container (and optionally `goss_wait.yaml`) and before running tests. (Default: `0.2`)

Location of the goss yaml files. (Default: `.`)

The name of the variables file relative to `GOSS_FILES_PATH` to copy into the
docker container and use for valiation (i.e. `dgoss run`) and copy out of the
docker container when writing tests (i.e. `dgoss edit`). If set, the
`--vars` flag is passed to `goss validate` commands inside the container.
If unset (or empty), the `--vars` flag is omitted, which is the normal behavior.
(Default: `''`).

Strategy used for copying goss files into the docker container. If set to `'mount'` a volume with goss files is mounted and log output is streamed into the container as `/goss/docker_output.log` file. Other strategy is `'cp'` which uses `'docker cp'` command to copy goss files into docker container. With the `'cp'` strategy you lose the ability to write tests or waits against the docker output. The `'cp'` strategy is required especially when docker daemon is not on the local machine.
(Default `'mount'`)
@@ -0,0 +1,113 @@

set -e

USAGE="USAGE: $(basename "$0") [run|edit] <docker-compose-service>"

info() {
echo -e "INFO: $*" >&2;
error() {
echo -e "ERROR: $*" >&2;
exit 1;

cleanup() {
set +e
{ kill "$log_pid" && wait "$log_pid"; } 2> /dev/null
rm -rf "$tmp_dir"
if [[ -n "$service" ]]; then
info "Deleting container"
docker-compose down -v > /dev/null

# Copy in goss
cp "${GOSS_PATH}" "$tmp_dir/goss"
chmod 755 "$tmp_dir/goss"
[[ -e "${GOSS_FILES_PATH}/goss.yaml" ]] && cp "${GOSS_FILES_PATH}/goss.yaml" "$tmp_dir"
[[ -e "${GOSS_FILES_PATH}/goss_wait.yaml" ]] && cp "${GOSS_FILES_PATH}/goss_wait.yaml" "$tmp_dir"
[[ -n "${GOSS_VARS}" ]] && [[ -e "${GOSS_FILES_PATH}/${GOSS_VARS}" ]] && cp "${GOSS_FILES_PATH}/${GOSS_VARS}" "$tmp_dir"

info "Starting docker container"
docker-compose run -d -T --name "$service" -v "$tmp_dir:/goss" "$service"
docker logs -f "$service" > "$tmp_dir/docker_output.log" 2>&1 &
info "Container name: $service"

get_docker_file() {
set +e
if docker exec "$service" sh -c "test -e $1" > /dev/null; then
mkdir -p "${GOSS_FILES_PATH}"
info "Copied '$1' from container to '${GOSS_FILES_PATH}'"
docker cp "$service:$1" "${GOSS_FILES_PATH}"
set -e

# Main
tmp_dir=$(mktemp -d /tmp/tmp.XXXXXXXXXX)
chmod 777 "$tmp_dir"
# shellcheck disable=SC2154
trap 'ret=$?; cleanup; exit $ret' EXIT

if [[ ! -f docker-compose.yaml && ! -f docker-compose.yml ]]; then
echo "no docker-compose file found in ."
exit 1

state=$(docker inspect --format '{{.State.Status}}' "$service" 2> /dev/null || true)
if [[ "$state" == running ]]; then
docker rm -f "$service"
elif [[ "$state" == exited ]]; then
docker rm "$service"

GOSS_PATH="${GOSS_PATH:-$(command -v goss 2> /dev/null || true)}"
[[ "$GOSS_PATH" ]] || { error "Couldn't find goss installation, please set GOSS_PATH to it"; }
[[ "${GOSS_OPTS+x}" ]] || GOSS_OPTS="--color --format documentation"
[[ "${GOSS_WAIT_OPTS+x}" ]] || GOSS_WAIT_OPTS="-r 30s -s 1s > /dev/null"

case "$1" in
run "$@"
if [[ -e "${GOSS_FILES_PATH}/goss_wait.yaml" ]]; then
info "Found goss_wait.yaml, waiting for it to pass before running tests"
if [[ -z "${GOSS_VARS}" ]]; then
if ! docker exec "$service" sh -c "/goss/goss -g /goss/goss_wait.yaml render | /goss/goss -g - validate $GOSS_WAIT_OPTS"; then
error "goss_wait.yaml never passed"
if ! docker exec "$service" sh -c "/goss/goss -g /goss/goss_wait.yaml --vars='/goss/${GOSS_VARS}' render | /goss/goss -g - validate $GOSS_WAIT_OPTS"; then
error "goss_wait.yaml never passed"
[[ "$GOSS_SLEEP" ]] && { info "Sleeping for $GOSS_SLEEP"; sleep "$GOSS_SLEEP"; }
info "Container health"
if ! docker top "$service"; then
docker logs "$service"
info "Running Tests"
if [[ -z "${GOSS_VARS}" ]]; then
docker exec "$service" sh -c "/goss/goss -g /goss/goss.yaml render | /goss/goss -g - validate $GOSS_OPTS"
docker exec "$service" sh -c "/goss/goss -g /goss/goss.yaml --vars='/goss/${GOSS_VARS}' render | /goss/goss -g - validate $GOSS_OPTS"
run "$@"
info "Run goss add/autoadd to add resources"
docker exec -it "$service" sh -c 'cd /goss; PATH="/goss:$PATH" exec sh'
get_docker_file "/goss/goss.yaml"
get_docker_file "/goss/goss_wait.yaml"
[[ -n "${GOSS_VARS}" ]] && get_docker_file "/goss/${GOSS_VARS}"
error "$USAGE"

0 comments on commit 641180c

Please sign in to comment.
You can’t perform that action at this time.