Skip to content

Commit

Permalink
Incremental commit and extract.
Browse files Browse the repository at this point in the history
  • Loading branch information
uri-canva committed Mar 4, 2020
1 parent b5fbe39 commit cd08c94
Show file tree
Hide file tree
Showing 7 changed files with 195 additions and 213 deletions.
30 changes: 18 additions & 12 deletions container/image.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -311,7 +311,9 @@ def _impl(
output_layer = None,
workdir = None,
null_cmd = None,
null_entrypoint = None):
null_entrypoint = None,
action_run = False,
docker_run_flags = None):
"""Implementation for the container_image rule.
Args:
Expand Down Expand Up @@ -344,6 +346,7 @@ def _impl(
workdir: str, overrides ctx.attr.workdir
null_cmd: bool, overrides ctx.attr.null_cmd
null_entrypoint: bool, overrides ctx.attr.null_entrypoint
action_run: bool, whether output_executable is going to be run as an action
"""
name = name or ctx.label.name
entrypoint = entrypoint or ctx.attr.entrypoint
Expand All @@ -359,7 +362,6 @@ def _impl(
output_digest = output_digest or ctx.outputs.digest
output_config = output_config or ctx.outputs.config
output_layer = output_layer or ctx.outputs.layer
build_script = ctx.outputs.build_script
null_cmd = null_cmd or ctx.attr.null_cmd
null_entrypoint = null_entrypoint or ctx.attr.null_entrypoint

Expand All @@ -369,15 +371,18 @@ def _impl(
# We do not use the default argument of attrs.string() in order to distinguish between
# an image using the default and an image intentionally overriding the base's run flags.
# Since this is a string attribute, the default value is the empty string.
if ctx.attr.docker_run_flags != "":
docker_run_flags = ctx.attr.docker_run_flags
elif ctx.attr.base and ImageInfo in ctx.attr.base:
docker_run_flags = ctx.attr.base[ImageInfo].docker_run_flags
else:
# Run the container using host networking, so that the service is
# available to the developer without having to poke around with
# docker inspect.
docker_run_flags = "-i --rm --network=host"
docker_run_flags_are_default = False
if docker_run_flags == None:
if ctx.attr.docker_run_flags != "":
docker_run_flags = ctx.attr.docker_run_flags
elif ctx.attr.base and ImageInfo in ctx.attr.base:
docker_run_flags = ctx.attr.base[ImageInfo].docker_run_flags
else:
docker_run_flags_are_default = True
# Run the container using host networking, so that the service is
# available to the developer without having to poke around with
# docker inspect.
docker_run_flags = "-i --rm --network=host"

if ctx.attr.launcher:
if not file_map:
Expand Down Expand Up @@ -497,6 +502,7 @@ def _impl(
build_executable,
run = not ctx.attr.legacy_run_behavior,
run_flags = docker_run_flags,
action_run = action_run,
)

_assemble_image(
Expand All @@ -523,7 +529,7 @@ def _impl(
ImageInfo(
container_parts = container_parts,
legacy_run_behavior = ctx.attr.legacy_run_behavior,
docker_run_flags = docker_run_flags,
docker_run_flags = "" if docker_run_flags_are_default else docker_run_flags,
),
DefaultInfo(
executable = build_executable,
Expand Down
30 changes: 17 additions & 13 deletions container/incremental_load.sh.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,19 @@ set -eu
# This is a generated file that loads all docker layers built by "docker_build".

function guess_runfiles() {
if [[ "%{action_run}" == "True" ]]; then
# The script is running as an action
pwd
else
if [ -d ${BASH_SOURCE[0]}.runfiles ]; then
# Runfiles are adjacent to the current script.
echo "$( cd ${BASH_SOURCE[0]}.runfiles && pwd )"
# Runfiles are adjacent to the current script.
echo "$( cd ${BASH_SOURCE[0]}.runfiles && pwd )"
else
# The current script is within some other script's runfiles.
mydir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
echo $mydir | sed -e 's|\(.*\.runfiles\)/.*|\1|'
# The current script is within some other script's runfiles.
mydir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
echo $mydir | sed -e 's|\(.*\.runfiles\)/.*|\1|'
fi
fi
}

RUNFILES="${PYTHON_RUNFILES:-$(guess_runfiles)}"
Expand All @@ -35,8 +40,8 @@ DOCKER="%{docker_tool_path}"
DOCKER_FLAGS="%{docker_flags}"

if [[ -z "${DOCKER}" ]]; then
echo >&2 "error: docker not found; do you need to manually configure the docker toolchain?"
exit 1
echo >&2 "error: docker not found; do you need to manually configure the docker toolchain?"
exit 1
fi

# Create temporary files in which to record things to clean up.
Expand Down Expand Up @@ -130,7 +135,7 @@ function import_config() {
local tmp_dir="$(mktemp -d)"
echo "${tmp_dir}" >> "${TEMP_FILES}"

cd "${tmp_dir}"
pushd "${tmp_dir}" >/dev/null

# Docker elides layer reads from the tarball when it
# already has a copy of the layer with the same basis
Expand Down Expand Up @@ -206,6 +211,8 @@ EOF
# and then streaming exactly the layers we've established are
# needed into the Docker daemon.
tar cPh "${MISSING[@]}" | tee image.tar | "${DOCKER}" ${DOCKER_FLAGS} load

popd >/dev/null
}

function tag_layer() {
Expand Down Expand Up @@ -243,10 +250,7 @@ function read_variables() {
# This is not executed if the single argument --norun is passed or
# no run_statements are generated (in which case, 'run' is 'False').
if [[ "a$*" != "a--norun" && "%{run}" == "True" ]]; then
# Once we've loaded the images for all layers, we no longer need the temporary files on disk.
# We can clean up before we exec docker, since the exit handler will no longer run.
cleanup

# This generated and injected by docker_*.
exec %{run_statements}
id=$(%{run_statements})
echo $id
fi
17 changes: 10 additions & 7 deletions container/layer_tools.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,8 @@ def incremental_load(
output,
stamp = False,
run = False,
run_flags = None):
run_flags = None,
action_run = False):
"""Generate the incremental load statement.
Expand All @@ -200,6 +201,7 @@ def incremental_load(
stamp: Whether to stamp the produced image
run: Whether to run the script or not
run_flags: Additional run flags
action_run: bool, whether output_executable is going to be run as an action
"""
stamp_files = []
if stamp:
Expand Down Expand Up @@ -227,7 +229,7 @@ def incremental_load(
# First load the legacy base image, if it exists.
if image.get("legacy"):
load_statements += [
"load_legacy '%s'" % _get_runfile_path(ctx, image["legacy"]),
"load_legacy '%s'" % (image["legacy"].path if action_run else _get_runfile_path(ctx, image["legacy"])),
]

pairs = zip(image["diff_id"], image["unzipped_layer"])
Expand All @@ -236,11 +238,11 @@ def incremental_load(
# in the daemon.
load_statements += [
"import_config '%s' %s" % (
_get_runfile_path(ctx, image["config"]),
image["config"].path if action_run else _get_runfile_path(ctx, image["config"]),
" ".join([
"'%s' '%s'" % (
_get_runfile_path(ctx, diff_id),
_get_runfile_path(ctx, unzipped_layer),
diff_id.path if action_run else _get_runfile_path(ctx, diff_id),
unzipped_layer.path if action_run else _get_runfile_path(ctx, unzipped_layer),
)
for (diff_id, unzipped_layer) in pairs
]),
Expand All @@ -255,7 +257,7 @@ def incremental_load(
# It is notable that the only legal use of '{' in a
# tag would be for stamp variables, '$' is not allowed.
tag_reference,
_get_runfile_path(ctx, image["config_digest"]),
image["config_digest"].path if action_run else _get_runfile_path(ctx, image["config_digest"]),
),
]
if run:
Expand All @@ -269,14 +271,15 @@ def incremental_load(
substitutions = {
"%{docker_flags}": " ".join(toolchain_info.docker_flags),
"%{docker_tool_path}": toolchain_info.tool_path,
"%{action_run}": str(action_run),
"%{load_statements}": "\n".join(load_statements),
"%{run_statements}": "\n".join(run_statements),
"%{run}": str(run),
# If this rule involves stamp variables than load them as bash
# variables, and turn references to them into bash variable
# references.
"%{stamp_statements}": "\n".join([
"read_variables %s" % _get_runfile_path(ctx, f)
"read_variables %s" % (f.path if action_run else _get_runfile_path(ctx, f))
for f in stamp_files
]),
"%{tag_statements}": "\n".join(tag_statements),
Expand Down
32 changes: 8 additions & 24 deletions docker/util/commit.sh.tpl
Original file line number Diff line number Diff line change
@@ -1,32 +1,16 @@
#!/bin/bash

set -ex

# Setup tools and load utils
TO_JSON_TOOL="%{to_json_tool}"
source %{util_script}

# Resolve the docker tool path
DOCKER="%{docker_tool_path}"
DOCKER_FLAGS="%{docker_flags}"

if [[ -z "$DOCKER" ]]; then
echo >&2 "error: docker not found; do you need to manually configure the docker toolchain?"
exit 1
fi

# Load the image and remember its name
image_id=$(%{image_id_extractor_path} %{image_tar})
$DOCKER $DOCKER_FLAGS load -i %{image_tar}

id=$($DOCKER $DOCKER_FLAGS run -d %{docker_run_flags} $image_id %{commands})
# Actually wait for the container to finish running its commands
retcode=$($DOCKER $DOCKER_FLAGS wait $id)
# Trigger a failure if the run had a non-zero exit status
if [ $retcode != 0 ]; then
$DOCKER $DOCKER_FLAGS logs $id && false
fi

reset_cmd $image_id $id %{output_image}
config=$(< %{commit_base_config})
cmd='["/bin/sh", "-c", "/bin/bash"]'
regex='\"Cmd\" ?: ?(\[[^]]*\])'
if [[ config =~ regex ]]; then
cmd=${BASH_REMATCH[1]}
fi
$DOCKER $DOCKER_FLAGS commit -c "CMD $cmd" $id %{output_image}
$DOCKER $DOCKER_FLAGS save %{output_image} -o %{output_tar}
$DOCKER $DOCKER_FLAGS rm $id
$DOCKER $DOCKER_FLAGS rm $id
19 changes: 0 additions & 19 deletions docker/util/extract.sh.tpl
Original file line number Diff line number Diff line change
@@ -1,22 +1,3 @@
#!/bin/bash

set -ex

# Resolve the docker tool path
DOCKER="%{docker_tool_path}"
DOCKER_FLAGS="%{docker_flags}"

if [[ -z "$DOCKER" ]]; then
echo >&2 "error: docker not found; do you need to manually configure the docker toolchain?"
exit 1
fi

# Load the image and remember its name
image_id=$(%{image_id_extractor_path} %{image_tar})
$DOCKER $DOCKER_FLAGS load -i %{image_tar}

id=$($DOCKER $DOCKER_FLAGS run -d %{docker_run_flags} $image_id %{commands})

retcode=$($DOCKER $DOCKER_FLAGS wait $id)

# Print any error that occurred in the container.
Expand Down
Loading

0 comments on commit cd08c94

Please sign in to comment.