Skip to content

Commit

Permalink
Modify dep-graph to handle circular dependencies and add tests.
Browse files Browse the repository at this point in the history
  • Loading branch information
HackingM committed Mar 26, 2020
1 parent 68261a9 commit 2729242
Show file tree
Hide file tree
Showing 16 changed files with 579 additions and 23 deletions.
58 changes: 36 additions & 22 deletions cmd/dep-graph.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,31 +2,48 @@
# Copyright (c) 2014-2019, Erik Dannenberg <erik.dannenberg@xtrade-gmbh.de>
# All rights reserved.

# Check image dependencies and populate global var _dep_graph. Recursive.
# Check image dependencies for an image and populate global var _dep_graph. Recursive.
#
# Arguments:
#
# 1: image_id
# 2: previous_image_id
function check_image_dependencies() {
local image_id previous_image
function _check_image_dependencies() {
local image_id test_deps test_dep
image_id="$1"
previous_image="$2"
if [[ "${image_id}" != 'scratch' ]]; then
expand_image_id "${image_id}" "${_IMAGE_PATH}"
# shellcheck disable=SC2154
source_image_conf "${__expand_image_id}"

# skip further checking if already processed
if is_in_array "${image_id}" "${_processed_images[@]}"; then
return
fi
_processed_images+=( "${image_id}" )

if [[ "${image_id}" == 'scratch' ]]; then
return
fi

expand_image_id "${image_id}" "${_IMAGE_PATH}"
# shellcheck disable=SC2154
source_image_conf "${__expand_image_id}"

if [[ -n "${IMAGE_PARENT}" ]]; then
# skip further checking if already processed
if ! is_in_array "${image_id}" "${_dep_graph[@]}"; then
# check parent image dependencies
check_image_dependencies "${IMAGE_PARENT}" "${image_id}"
# finally add the image
[[ "${previous_image}" != "" ]] && _dep_graph+=( "${image_id}" )
fi
fi
if [[ -n "${IMAGE_PARENT}" ]]; then
# check parent image dependencies
_check_image_dependencies "${IMAGE_PARENT}"
fi

# finally add the image
_dep_graph+=( "${image_id}" )
}

# Check image dependencies for a list of images and populate global var _dep_graph.
#
# Arguments:
#
# 1..n: image_id
function check_image_dependencies() {
declare -a _processed_images
for image_id in "$@"; do
_check_image_dependencies "${image_id}"
done
}

function main() {
Expand All @@ -45,10 +62,7 @@ function main() {
declare -a _dep_graph

# shellcheck disable=SC2154
for image_id in "${__expand_requested_target_ids[@]}"; do
check_image_dependencies "${image_id}"
! is_in_array "${image_id}" "${_dep_graph[@]}" && _dep_graph+=( "${image_id}" )
done
check_image_dependencies "${__expand_requested_target_ids[@]}"

dotstring="strict digraph imagedeps {\n rankdir=LR;"

Expand Down
5 changes: 5 additions & 0 deletions tests/fixtures/namespaces/depgraph_circular/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
## depgraph_namespace

<mission statement goes here>

Maintainer: Your Name <your@mail.org>
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
FROM ${IMAGE_PARENT}
LABEL maintainer ${MAINTAINER}

ADD rootfs.tar /

#COPY docker-healthcheck.sh /usr/bin/docker-healthcheck
#HEALTHCHECK --interval=60s --timeout=5s --start-period=5s --retries=3 CMD ["docker-healthcheck"]

#CMD ["/bin/some-cmd", "--some-option", "some-value"]
10 changes: 10 additions & 0 deletions tests/fixtures/namespaces/depgraph_circular/images/a/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
## depgraph_namespace/a

Run this [a][] image with:

$ docker run -d --name a depgraph_namespace/a

[Last Build][packages]

[a]: https://a.url
[packages]: PACKAGES.md
41 changes: 41 additions & 0 deletions tests/fixtures/namespaces/depgraph_circular/images/a/build.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# Used build container, optional, default: committed builder of parent image or value of DEFAULT_BUILDER in kubler.conf
#BUILDER="kubler/bob"

# Run build container with `--cap-add SYS_PTRACE`, optional, default: false
#BUILDER_CAPS_SYS_PTRACE='true'

# Mount a host directory in the build container during the build, uses standard Docker -v syntax, default: unset/none
# !! There is a reason Docker does not allow this, consider the consequences regarding build repeatability !!
#BUILDER_MOUNTS=("${KUBLER_DATA_DIR}/tmp/somepath:/path/in/builder:ro")
# Use BUILDER_MOUNTS from parent image(s)?, default: false
#PARENT_BUILDER_MOUNTS='true'

# Any additional docker run args that should be used during the build, optional, default: unset/none
#BUILDER_DOCKER_ARGS=('--cap-add' 'FOO')

# Fully qualified image id (i.e. kubler/busybox), optional, default: scratch
IMAGE_PARENT="depgraph_circular/c"

# Run a standard Docker health-check test as part of the build process. Add the health check as usual in
# Dockerfile.template and set this to true. Official docs: https://docs.docker.com/engine/reference/builder/#healthcheck
#POST_BUILD_HC=true
# The health-check will only pass if the container reported healthy for this many tries
#POST_BUILD_HC_MIN_HEALTHY_STREAK=5
# Timeout for the complete health-check test before it is aborted with an error, START_PERIOD will not count to this limit
#POST_BUILD_HC_MAX_DURATION=30
#
# Any health-check args in the Dockerfile are overridden with the corresponding values below for the duration of
# the test. If not defined the Kubler internal defaults, as seen below, are used.
#
# Run the health-check command every n sec
#POST_BUILD_HC_INTERVAL=5
# Timeout for each health check in secs
#POST_BUILD_HC_TIMEOUT=5
# Grace period in secs for the container to get ready before any checks are run
#POST_BUILD_HC_START_PERIOD=3
# Amount of health-check fails for a container before it considers itself unhealthy
#POST_BUILD_HC_RETRY=3

# Variables starting with BOB_ can be used for parameterization of Dockerfile.template and are also exported to
# the build container, i.e. they may be referenced in your build.sh
#BOB_FOO=bar
97 changes: 97 additions & 0 deletions tests/fixtures/namespaces/depgraph_circular/images/a/build.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
#
# Kubler phase 1 config, pick installed packages and/or customize the build
#

# The recommended way to install software is setting ${_packages}
# List of Gentoo package atoms to be installed at custom root fs ${_EMERGE_ROOT}, optional, space separated
# If you are not sure about package names you may want to start an interactive build container:
# kubler.sh build -i depgraph_namespace/a
# ..and then search the Portage database:
# eix <search-string>
_packages=""
# Install a standard system directory layout at ${_EMERGE_ROOT}, optional, default: false
#BOB_INSTALL_BASELAYOUT=true

# Define custom variables to your liking
#_a_version=1.0

#
# This hook can be used to configure the build container itself, install packages, run any command, etc
#
configure_builder()
{
# Packages installed in this hook don't end up in the final image but are available for depending image builds
#emerge dev-lang/go app-misc/foo
:
}

#
# This hook is called just before starting the build of the root fs
#
configure_rootfs_build()
{
# Update a Gentoo package use flag..
#update_use 'dev-libs/some-lib' '+feature' '-some_other_feature'

# ..or a Gentoo package keyword
#update_keywords 'dev-lang/some-package' '+~amd64'

# Add a package to Portage's package.provided file, effectively skipping it during installation
#provide_package 'dev-lang/some-package'

# This can be useful to install a package from a parent image again, it may be needed at build time
#unprovide_package 'dev-lang/some-package'

# Only needed when ${_packages} is empty, initializes PACKAGES.md
#init_docs "depgraph_namespace/a"
:
}

#
# This hook is called just before packaging the root fs tar ball, ideal for any post-install tasks, clean up, etc
#
finish_rootfs_build()
{
# Useful helpers

# Thin wrapper for sed that fails the build if no match was found, default sed delimiter is %
#sed-or-die '^foo' 'replaceval' "${_EMERGE_ROOT}"/etc/foo.conf

# Download file at url to /distfiles if it doesn't exist yet, file name is derived from last url fragment
#download_file "$url"
#echo "${__download_file}"
# Same as above but set a custom file name
#download_file "$url" my_file_v1.tar.gz
# Same as above but pass arbitrary additional args to curl
#download_file "$url" my_file_v1.tar.gz '-v' '--cookie' 'foo'

# install su-exec at ${_EMERGE_ROOT}
#install_suexec
# Copy c++ libs, may be needed if you see errors regarding missing libstdc++
#copy_gcc_libs

# Example for a manual build if _packages method does not suffice, a typical use case is a Go project:

#export GOPATH="/go"
#export PATH="${PATH}:/go/bin"
#export DISTRIBUTION_DIR="${GOPATH}/src/github.com/depgraph_namespace/a"
#mkdir -p "${DISTRIBUTION_DIR}"

#git clone https://github.com/depgraph_namespace/a.git "${DISTRIBUTION_DIR}"
#cd "${DISTRIBUTION_DIR}"
#git checkout tags/v${_a_version}
#echo "building a ${_a_version}.."
#go run build.go build
#mkdir -p "${_EMERGE_ROOT}"/usr/local/{bin,share}

# Everything at ${_EMERGE_ROOT} will end up in the final image
#cp -rp "${DISTRIBUTION_DIR}/bin/*" "${_EMERGE_ROOT}/usr/local/bin"

# After installing packages manually you might want to add an entry to PACKAGES.md
#log_as_installed "manual install" "a-${_a_version}" "https://a.org/"

# To uninstall software packages in the builder unset ROOT env first
#unset ROOT
#emerge -C foo/bar
:
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
FROM ${IMAGE_PARENT}
LABEL maintainer ${MAINTAINER}

ADD rootfs.tar /

#COPY docker-healthcheck.sh /usr/bin/docker-healthcheck
#HEALTHCHECK --interval=60s --timeout=5s --start-period=5s --retries=3 CMD ["docker-healthcheck"]

#CMD ["/bin/some-cmd", "--some-option", "some-value"]
10 changes: 10 additions & 0 deletions tests/fixtures/namespaces/depgraph_circular/images/b/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
## depgraph_namespace/b

Run this [b][] image with:

$ docker run -d --name b depgraph_namespace/b

[Last Build][packages]

[b]: https://b.url
[packages]: PACKAGES.md
41 changes: 41 additions & 0 deletions tests/fixtures/namespaces/depgraph_circular/images/b/build.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# Used build container, optional, default: committed builder of parent image or value of DEFAULT_BUILDER in kubler.conf
#BUILDER="kubler/bob"

# Run build container with `--cap-add SYS_PTRACE`, optional, default: false
#BUILDER_CAPS_SYS_PTRACE='true'

# Mount a host directory in the build container during the build, uses standard Docker -v syntax, default: unset/none
# !! There is a reason Docker does not allow this, consider the consequences regarding build repeatability !!
#BUILDER_MOUNTS=("${KUBLER_DATA_DIR}/tmp/somepath:/path/in/builder:ro")
# Use BUILDER_MOUNTS from parent image(s)?, default: false
#PARENT_BUILDER_MOUNTS='true'

# Any additional docker run args that should be used during the build, optional, default: unset/none
#BUILDER_DOCKER_ARGS=('--cap-add' 'FOO')

# Fully qualified image id (i.e. kubler/busybox), optional, default: scratch
IMAGE_PARENT="depgraph_circular/a"

# Run a standard Docker health-check test as part of the build process. Add the health check as usual in
# Dockerfile.template and set this to true. Official docs: https://docs.docker.com/engine/reference/builder/#healthcheck
#POST_BUILD_HC=true
# The health-check will only pass if the container reported healthy for this many tries
#POST_BUILD_HC_MIN_HEALTHY_STREAK=5
# Timeout for the complete health-check test before it is aborted with an error, START_PERIOD will not count to this limit
#POST_BUILD_HC_MAX_DURATION=30
#
# Any health-check args in the Dockerfile are overridden with the corresponding values below for the duration of
# the test. If not defined the Kubler internal defaults, as seen below, are used.
#
# Run the health-check command every n sec
#POST_BUILD_HC_INTERVAL=5
# Timeout for each health check in secs
#POST_BUILD_HC_TIMEOUT=5
# Grace period in secs for the container to get ready before any checks are run
#POST_BUILD_HC_START_PERIOD=3
# Amount of health-check fails for a container before it considers itself unhealthy
#POST_BUILD_HC_RETRY=3

# Variables starting with BOB_ can be used for parameterization of Dockerfile.template and are also exported to
# the build container, i.e. they may be referenced in your build.sh
#BOB_FOO=bar
Loading

0 comments on commit 2729242

Please sign in to comment.