• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/env bash
2# Copyright 2016 The TensorFlow Authors. All Rights Reserved.
3#
4# Licensed under the Apache License, Version 2.0 (the "License");
5# you may not use this file except in compliance with the License.
6# You may obtain a copy of the License at
7#
8#     http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS,
12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13# See the License for the specific language governing permissions and
14# limitations under the License.
15# ==============================================================================
16# Parameterized build and test for TensorFlow Docker images.
17#
18# Usage:
19#   parameterized_docker_build.sh
20#
21# The script obeys the following environment variables:
22#   TF_DOCKER_BUILD_TYPE: (CPU | GPU | MKL | MKL-HOROVOD)
23#     CPU, GPU, MKL or MKL-HOROVOD image
24#
25#   TF_DOCKER_BUILD_IS_DEVEL: (NO | YES)
26#     Is this developer image
27#
28#   TF_DOCKER_BUILD_DEVEL_BRANCH
29#     (Required if TF_DOCKER_BUILD_IS_DEVEL is YES)
30#     Specifies the branch to checkout for devel docker images
31#
32#   TF_DOCKER_BUILD_CENTRAL_PIP
33#     (Optional)
34#     If set to a non-empty string, will use it as the URL from which the
35#     pip wheel file will be downloaded (instead of building the pip locally).
36#
37#   TF_DOCKER_BUILD_CENTRAL_PIP_IS_LOCAL
38#     (Optional)
39#     If set to a non-empty string, we will treat TF_DOCKER_BUILD_CENTRAL_PIP
40#     as a path rather than a url.
41#
42#   TF_DOCKER_BUILD_IMAGE_NAME:
43#     (Optional)
44#     If set to any non-empty value, will use it as the image of the
45#     newly-built image. If not set, the tag prefix tensorflow/tensorflow
46#     will be used.
47#
48#   TF_DOCKER_BUILD_VERSION:
49#     (Optinal)
50#     If set to any non-empty value, will use the version (e.g., 0.8.0) as the
51#     tag prefix of the image. Additional strings, e.g., "-devel-gpu", will be
52#     appended to the tag. If not set, the default tag prefix "latest" will be
53#     used.
54#
55#   TF_DOCKER_BUILD_PORT
56#     (Optional)
57#     If set to any non-empty and valid port number, will use that port number
58#     during basic checks on the newly-built docker image.
59#
60#   TF_DOCKER_BUILD_PUSH_CMD
61#     (Optional)
62#     If set to a valid binary/script path, will call the script with the final
63#     tagged image name with an argument, to push the image to a central repo
64#     such as gcr.io or Docker Hub.
65#
66#   TF_DOCKER_BUILD_PUSH_WITH_CREDENTIALS
67#     (Optional)
68#     Do not set this along with TF_DOCKER_BUILD_PUSH_CMD. We will push with the
69#     direct commands as opposed to a script.
70#
71#   TF_DOCKER_USERNAME
72#     (Optional)
73#     Dockerhub username for pushing a package.
74#
75#   TF_DOCKER_EMAIL
76#     (Optional)
77#     Dockerhub email for pushing a package.
78#
79#   TF_DOCKER_PASSWORD
80#     (Optional)
81#     Dockerhub password for pushing a package.
82#
83#   TF_DOCKER_BUILD_PYTHON_VERSION
84#     (Optional)
85#     Specifies the desired Python version. Defaults to PYTHON2.
86#
87#   TF_DOCKER_BUILD_OPTIONS
88#     (Optional)
89#     Specifies the desired build options. Defaults to OPT.
90#
91#   TF_DOCKER_BUILD_ARGS
92#     (Optional)
93#     A list (array) of docker build args. Will be passed to docker build
94#     command as list of --build-arg parameters.
95#
96#   TF_BAZEL_BUILD_OPTIONS
97#     (Optional)
98#     Bazel compiler flags to be passed to the bazelrc file
99
100# Script directory
101SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
102source "${SCRIPT_DIR}/../ci_build/builds/builds_common.sh"
103
104# Help functions
105CHECK_FAILED=0
106mark_check_failed() {
107  # Usage: mark_check_failed <FAILURE_MESSAGE>
108  echo $1
109  CHECK_FAILED=1
110}
111
112TF_DOCKER_BUILD_TYPE=$(to_lower ${TF_DOCKER_BUILD_TYPE})
113TF_DOCKER_BUILD_IS_DEVEL=$(to_lower ${TF_DOCKER_BUILD_IS_DEVEL})
114TF_DOCKER_BUILD_PYTHON_VERSION=$(to_lower ${TF_DOCKER_BUILD_PYTHON_VERSION:-PYTHON2})
115TF_DOCKER_BUILD_OPTIONS=$(to_lower ${TF_DOCKER_BUILD_OPTIONS:-OPT})
116
117echo "Required build parameters:"
118echo "  TF_DOCKER_BUILD_TYPE=${TF_DOCKER_BUILD_TYPE}"
119echo "  TF_DOCKER_BUILD_IS_DEVEL=${TF_DOCKER_BUILD_IS_DEVEL}"
120echo "  TF_DOCKER_BUILD_DEVEL_BRANCH=${TF_DOCKER_BUILD_DEVEL_BRANCH}"
121echo ""
122echo "Optional build parameters:"
123echo "  TF_DOCKER_BUILD_CENTRAL_PIP=${TF_DOCKER_BUILD_CENTRAL_PIP}"
124echo "  TF_DOCKER_BUILD_IMAGE_NAME=${TF_DOCKER_BUILD_IMAGE_NAME}"
125echo "  TF_DOCKER_BUILD_VERSION=${TF_DOCKER_BUILD_VERSION}"
126echo "  TF_DOCKER_BUILD_PORT=${TF_DOCKER_BUILD_PORT}"
127echo "  TF_DOCKER_BUILD_PUSH_CMD=${TF_DOCKER_BUILD_PUSH_CMD}"
128echo "  TF_DOCKER_BUILD_ARGS=${TF_DOCKER_BUILD_ARGS[@]:-()}"
129echo "  TF_BAZEL_BUILD_OPTIONS=${TF_BAZEL_BUILD_OPTIONS}"
130
131
132CONTAINER_PORT=${TF_DOCKER_BUILD_PORT:-8888}
133
134# Make sure that docker is available on path
135if [[ -z $(which docker) ]]; then
136  die "ERROR: docker is not available on path"
137fi
138
139# Validate the environment-variable options and construct the final image name
140# Final image name with tag
141FINAL_IMAGE_NAME=${TF_DOCKER_BUILD_IMAGE_NAME:-tensorflow/tensorflow}
142FINAL_TAG=${TF_DOCKER_BUILD_VERSION:-latest}
143
144# Original (unmodified) Dockerfile
145ORIG_DOCKERFILE="Dockerfile"
146
147if [[ ${TF_DOCKER_BUILD_IS_DEVEL} == "yes" ]]; then
148  FINAL_TAG="${FINAL_TAG}-devel"
149  ORIG_DOCKERFILE="${ORIG_DOCKERFILE}.devel"
150
151  if [[ -z "${TF_DOCKER_BUILD_DEVEL_BRANCH}" ]]; then
152    die "ERROR: TF_DOCKER_BUILD_DEVEL_BRANCH is missing for devel docker build"
153  fi
154elif [[ ${TF_DOCKER_BUILD_IS_DEVEL} == "no" ]]; then
155  :
156else
157  die "ERROR: Unrecognized value in TF_DOCKER_BUILD_IS_DEVEL: "\
158"${TF_DOCKER_BUILD_IS_DEVEL}"
159fi
160
161if [[ ${TF_DOCKER_BUILD_TYPE} == "cpu" ]]; then
162  DOCKER_BINARY="docker"
163elif [[ ${TF_DOCKER_BUILD_TYPE} == "mkl" ]]; then
164  DOCKER_BINARY="docker"
165  FINAL_TAG="${FINAL_TAG}-mkl"
166  if [[ ${ORIG_DOCKERFILE} == *"."* ]]; then
167    # There is already a dot in the tag, use "-"
168    ORIG_DOCKERFILE="${ORIG_DOCKERFILE}-mkl"
169  else
170    ORIG_DOCKERFILE="${ORIG_DOCKERFILE}.mkl"
171  fi
172elif [[ ${TF_DOCKER_BUILD_TYPE} == "mkl-horovod" ]]; then
173  DOCKER_BINARY="docker"
174  FINAL_TAG="${FINAL_TAG}-mkl-horovod"
175  if [[ ${ORIG_DOCKERFILE} == *"."* ]]; then
176    # There is already a dot in the tag, use "-"
177    ORIG_DOCKERFILE="${ORIG_DOCKERFILE}-mkl-horovod"
178  else
179    ORIG_DOCKERFILE="${ORIG_DOCKERFILE}.mkl-horovod"
180  fi
181elif   [[ ${TF_DOCKER_BUILD_TYPE} == "gpu" ]]; then
182  DOCKER_BINARY="nvidia-docker"
183
184  FINAL_TAG="${FINAL_TAG}-gpu"
185  if [[ ${ORIG_DOCKERFILE} == *"."* ]]; then
186    # There is already a dot in the tag, use "-"
187    ORIG_DOCKERFILE="${ORIG_DOCKERFILE}-gpu"
188  else
189    ORIG_DOCKERFILE="${ORIG_DOCKERFILE}.gpu"
190  fi
191else
192  die "ERROR: Unrecognized value in TF_DOCKER_BUILD_TYPE: "\
193"${TF_DOCKER_BUILD_TYPE}"
194fi
195
196if [[ "${TF_DOCKER_BUILD_PYTHON_VERSION}" == "python2" ]]; then
197  :
198elif [[ "${TF_DOCKER_BUILD_PYTHON_VERSION}" == "python3" ]]; then
199  FINAL_TAG="${FINAL_TAG}-py3"
200elif [[ "${TF_DOCKER_BUILD_PYTHON_VERSION}" == "python3.6" ]]; then
201  FINAL_TAG="${FINAL_TAG}-py3.6"
202else
203  die "Unrecognized value in TF_DOCKER_BUILD_PYTHON_VERSION: "\
204"${TF_DOCKER_BUILD_PYTHON_VERSION}"
205fi
206
207# Verify that the original Dockerfile exists
208ORIG_DOCKERFILE="${SCRIPT_DIR}/${ORIG_DOCKERFILE}"
209if [[ ! -f "${ORIG_DOCKERFILE}" ]]; then
210  die "ERROR: Cannot find Dockerfile at: ${ORIG_DOCKERFILE}"
211fi
212
213echo ""
214echo "FINAL_IMAGE_NAME: ${FINAL_IMAGE_NAME}"
215echo "FINAL_TAG: ${FINAL_TAG}"
216echo "Original Dockerfile: ${ORIG_DOCKERFILE}"
217echo ""
218
219# Create tmp directory for Docker build
220TMP_DIR=$(mktemp -d)
221echo ""
222echo "Docker build will occur in temporary directory: ${TMP_DIR}"
223
224# Copy all files to tmp directory for Docker build
225cp -r ${SCRIPT_DIR}/* "${TMP_DIR}/"
226
227if [[ "${TF_DOCKER_BUILD_IS_DEVEL}" == "no" ]]; then
228  DOCKERFILE="${TMP_DIR}/Dockerfile"
229
230  if [[ -z "${TF_DOCKER_BUILD_CENTRAL_PIP}" ]]; then
231    # Perform local build of the required PIP whl file
232    export TF_BUILD_CONTAINER_TYPE=${TF_DOCKER_BUILD_TYPE}
233    export TF_BUILD_PYTHON_VERSION=${TF_DOCKER_BUILD_PYTHON_VERSION}
234    export TF_BUILD_OPTIONS=${TF_DOCKER_BUILD_OPTIONS}
235    export TF_BUILD_IS_PIP="PIP"
236
237    if [[ "${TF_DOCKER_BUILD_TYPE}" == "mkl" ]]; then
238      die "FAIL: Non-development MKL builds require a pre-built pip whl."
239    fi
240
241    if [[ "${TF_DOCKER_BUILD_TYPE}" == "mkl-horovod" ]]; then
242      die "FAIL: Non-development MKL-HOROVOD builds require a pre-built pip whl."
243    fi
244
245    if [[ "${TF_DOCKER_BUILD_TYPE}" == "gpu" ]]; then
246      export TF_BUILD_APPEND_CI_DOCKER_EXTRA_PARAMS=\
247  "${TF_BUILD_APPEND_CI_DOCKER_EXTRA_PARAMS} -e TF_CUDA_COMPUTE_CAPABILITIES=3.0,3.5,5.2,6.0"
248    fi
249
250    pushd "${SCRIPT_DIR}/../../../"
251    rm -rf pip_test/whl &&
252    tensorflow/tools/ci_build/ci_parameterized_build.sh
253    PIP_BUILD_EXIT_CODE=$?
254    popd
255
256    # Was the pip build successful?
257    if [[ ${PIP_BUILD_EXIT_CODE} != "0" ]]; then
258      die "FAIL: Failed to build pip file locally"
259    fi
260
261    PIP_WHL=$(ls pip_test/whl/*.whl | head -1)
262    if [[ -z "${PIP_WHL}" ]]; then
263      die "ERROR: Cannot locate the locally-built pip whl file"
264    fi
265    echo "Locally-built PIP whl file is at: ${PIP_WHL}"
266
267    # Copy the pip file to tmp directory
268    cp "${PIP_WHL}" "${TMP_DIR}/" || \
269        die "ERROR: Failed to copy wheel file: ${PIP_WHL}"
270
271    # Use string replacement to put the correct file name into the Dockerfile
272    PIP_WHL=$(basename "${PIP_WHL}")
273
274    # Modify the non-devel Dockerfile to point to the correct pip whl file
275    # location
276    sed -e "/# --- DO NOT EDIT OR DELETE BETWEEN THE LINES --- #/,"\
277"/# --- ~ DO NOT EDIT OR DELETE BETWEEN THE LINES --- #/c"\
278"COPY ${PIP_WHL} /\n"\
279"RUN pip --no-cache-dir install /${PIP_WHL}" "${ORIG_DOCKERFILE}" \
280    > "${DOCKERFILE}"
281
282  # Build from a local whl file path rather than an URL
283  elif [[ ! -z "${TF_DOCKER_BUILD_CENTRAL_PIP_IS_LOCAL}" ]]; then
284    PIP_WHL="${TF_DOCKER_BUILD_CENTRAL_PIP}"
285    if [[ -z "${PIP_WHL}" ]]; then
286      die "ERROR: Cannot locate the specified pip whl file"
287    fi
288    echo "Specified PIP whl file is at: ${PIP_WHL}"
289
290    # Copy the pip file to tmp directory
291    cp "${PIP_WHL}" "${TMP_DIR}/" || \
292        die "ERROR: Failed to copy wheel file: ${PIP_WHL}"
293
294    # Use string replacement to put the correct file name into the Dockerfile
295    PIP_WHL=$(basename "${PIP_WHL}")
296
297    if [[ ${TF_DOCKER_BUILD_TYPE} == "mkl" ]] || \
298        [[ ${TF_DOCKER_BUILD_TYPE} == "mkl-horovod" ]]; then
299      TF_DOCKER_BUILD_ARGS+=("--build-arg TF_WHL_URL=${PIP_WHL}" )
300      cp "${ORIG_DOCKERFILE}" "${DOCKERFILE}"
301    else
302      # Modify the non-devel Dockerfile to point to the correct pip whl file
303      # location
304      sed -e "/# --- DO NOT EDIT OR DELETE BETWEEN THE LINES --- #/,"\
305"/# --- ~ DO NOT EDIT OR DELETE BETWEEN THE LINES --- #/c"\
306"COPY ${PIP_WHL} /\n"\
307"RUN pip --no-cache-dir install /${PIP_WHL}" "${ORIG_DOCKERFILE}" \
308      > "${DOCKERFILE}"
309    fi
310    echo "Using local pip wheel from: ${TF_DOCKER_BUILD_CENTRAL_PIP}"
311    echo
312  else
313    echo "Downloading pip wheel from: ${TF_DOCKER_BUILD_CENTRAL_PIP}"
314    if [[ ${TF_DOCKER_BUILD_TYPE} == "mkl" ]] || \
315        [[ ${TF_DOCKER_BUILD_TYPE} == "mkl-horovod" ]]; then
316      pushd "${TMP_DIR}/"
317      curl -O ${TF_DOCKER_BUILD_CENTRAL_PIP}
318      popd
319      PIP_WHL_PATH=`find ${TMP_DIR} -name "*.whl"`
320      PIP_WHL=$(basename "${PIP_WHL_PATH}")
321      echo "PIP_WHL= ${PIP_WHL}"
322      echo
323      TF_DOCKER_BUILD_ARGS+=("--build-arg TF_WHL_URL=${PIP_WHL}")
324      cp "${ORIG_DOCKERFILE}" "${DOCKERFILE}"
325    else
326      # Modify the non-devel Dockerfile to point to the correct pip whl URL.
327      sed -e "/# --- DO NOT EDIT OR DELETE BETWEEN THE LINES --- #/,"\
328"/# --- ~ DO NOT EDIT OR DELETE BETWEEN THE LINES --- #/c"\
329"RUN pip --no-cache-dir install ${TF_DOCKER_BUILD_CENTRAL_PIP}" "${ORIG_DOCKERFILE}" \
330      > "${DOCKERFILE}"
331    fi
332  fi
333
334  echo "Modified Dockerfile at: ${DOCKERFILE}"
335  echo
336
337  # Modify python/pip version if necessary.
338  if [[ "${TF_DOCKER_BUILD_PYTHON_VERSION}" == "python3" ]]; then
339    if [[ ${TF_DOCKER_BUILD_TYPE} == "mkl" ]] || \
340          [[ ${TF_DOCKER_BUILD_TYPE} == "mkl-horovod" ]]; then
341        TF_DOCKER_BUILD_ARGS+=("--build-arg PYTHON=${TF_DOCKER_BUILD_PYTHON_VERSION}")
342        TF_DOCKER_BUILD_ARGS+=("--build-arg PYTHON_DEV=python3-dev")
343        TF_DOCKER_BUILD_ARGS+=("--build-arg PIP=pip3")
344        cp "${ORIG_DOCKERFILE}" "${DOCKERFILE}"
345    else
346        if sed -i -e 's/python /python3 /g' "${DOCKERFILE}" && \
347            sed -i -e 's/python-dev/python3-dev/g' "${DOCKERFILE}" && \
348            sed -i -e 's/pip /pip3 /g' "${DOCKERFILE}" && \
349            sed -i -e 's^# RUN ln -s -f /usr/bin/python3 /usr/bin/python#^RUN ln -s -f /usr/bin/python3 /usr/bin/python^' "${DOCKERFILE}"
350        then
351          echo "Modified Dockerfile for python version "\
352    "${TF_DOCKER_BUILD_PYTHON_VERSION} at: ${DOCKERFILE}"
353        else
354          die "FAILED to modify ${DOCKERFILE} for python3"
355        fi
356    fi
357  fi
358else # TF_DOCKER_BUILD_IS_DEVEL == 'yes'
359  DOCKERFILE="${TMP_DIR}/Dockerfile"
360
361  # Set up Dockerfile ARGS for mkl and mkl-horovod build
362  if [[ ${TF_DOCKER_BUILD_TYPE} == "mkl" ]] || \
363      [[ ${TF_DOCKER_BUILD_TYPE} == "mkl-horovod" ]]; then
364    if [[ -z "${TF_BAZEL_BUILD_OPTIONS// }" ]]; then
365      TF_BAZEL_BUILD_OPTIONS=("--config=mkl --copt=-mavx --cxxopt=-D_GLIBCXX_USE_CXX11_ABI=0")
366    else
367      TF_BAZEL_BUILD_OPTIONS="${TF_BAZEL_BUILD_OPTIONS}"
368    fi
369    TF_DOCKER_BUILD_ARGS+=("--build-arg TF_BUILD_VERSION=${TF_DOCKER_BUILD_DEVEL_BRANCH}")
370    echo "TF_DOCKER_BUILD_ARGS=${TF_DOCKER_BUILD_ARGS[@]}"
371
372    # Pass the build options to bazel using the user-specific .bazelrc file
373    echo "build ${TF_BAZEL_BUILD_OPTIONS}" >> ${TMP_DIR}/.bazelrc
374    cp "${ORIG_DOCKERFILE}" "${DOCKERFILE}"
375  else
376    # Modify the devel Dockerfile to specify the git branch
377    sed "s/^RUN git clone --branch=.* --depth=1/RUN git clone --branch=${TF_DOCKER_BUILD_DEVEL_BRANCH} --depth=1/" \
378        "${ORIG_DOCKERFILE}" > "${DOCKERFILE}"
379  fi
380
381  # Modify python/pip version if necessary.
382  if [[ "${TF_DOCKER_BUILD_PYTHON_VERSION}" == "python3" ]] || [[ "${TF_DOCKER_BUILD_PYTHON_VERSION}" == "python3.6" ]]; then
383    if [[ ${TF_DOCKER_BUILD_TYPE} == "mkl" ]] || [[ ${TF_DOCKER_BUILD_TYPE} == "mkl-horovod" ]]; then
384        TF_DOCKER_BUILD_ARGS+=("--build-arg PYTHON=${TF_DOCKER_BUILD_PYTHON_VERSION}")
385        TF_DOCKER_BUILD_ARGS+=("--build-arg PYTHON3_DEV=python3-dev")
386        TF_DOCKER_BUILD_ARGS+=("--build-arg WHL_DIR=/tmp/pip3")
387        TF_DOCKER_BUILD_ARGS+=("--build-arg PIP=pip3")
388        cp "${ORIG_DOCKERFILE}" "${DOCKERFILE}"
389    else
390      if [[ "${TF_DOCKER_BUILD_PYTHON_VERSION}" == "python3.6" ]] && [[ "${TF_DOCKER_BUILD_TYPE}" != "mkl" ]]; then
391        die "Python 3.6 build only supported for MKL builds."
392      fi
393      if sed -i -e 's/python-dev/python-dev python3-dev/g' "${DOCKERFILE}" && \
394         sed -i -e 's/python /python3 /g' "${DOCKERFILE}" && \
395         sed -i -e 's^/tmp/pip^/tmp/pip3^g' "${DOCKERFILE}" && \
396         sed -i -e 's/pip /pip3 /g' "${DOCKERFILE}" && \
397         sed -i -e 's/ENV CI_BUILD_PYTHON python/ENV CI_BUILD_PYTHON python3/g' "${DOCKERFILE}" && \
398         sed -i -e 's^# RUN ln -s -f /usr/bin/python3 /usr/bin/python#^RUN ln -s -f /usr/bin/python3 /usr/bin/python^' "${DOCKERFILE}"
399      then
400        echo "Modified Dockerfile further for python version ${TF_DOCKER_BUILD_PYTHON_VERSION} at: ${DOCKERFILE}"
401      else
402        die "FAILED to modify ${DOCKERFILE} for python3"
403      fi
404    fi
405  fi
406fi
407
408# Perform docker build
409# Intermediate image name with tag
410IMG="${USER}/tensorflow:${FINAL_TAG}"
411echo "Building docker image with image name and tag: ${IMG}"
412echo "TF_DOCKER_BUILD_ARGS=${TF_DOCKER_BUILD_ARGS[@]}"
413CMD="${DOCKER_BINARY} build ${TF_DOCKER_BUILD_ARGS[@]} --no-cache --pull -t ${IMG} -f ${DOCKERFILE} ${TMP_DIR}"
414echo "CMD=${CMD}"
415${CMD}
416
417if [[ $? == "0" ]]; then
418  echo "${DOCKER_BINARY} build of ${IMG} succeeded"
419else
420  die "FAIL: ${DOCKER_BINARY} build of ${IMG} with Dockerfile ${DOCKERFILE} "\
421"failed"
422fi
423
424
425# Make sure that there is no other containers of the same image running
426# TODO(cais): Move to an earlier place.
427if "${DOCKER_BINARY}" ps | grep -q "${IMG}"; then
428  die "ERROR: It appears that there are docker containers of the image "\
429"${IMG} running. Please stop them before proceeding"
430fi
431
432# Start a docker container from the newly-built docker image
433DOCKER_RUN_LOG="${TMP_DIR}/docker_run.log"
434echo ""
435echo "Running docker container from image ${IMG}..."
436echo "  Log file is at: ${DOCKER_RUN_LOG}"
437echo ""
438
439if [[ "${TF_DOCKER_BUILD_IS_DEVEL}" == "no" ]]; then
440  "${DOCKER_BINARY}" run --rm -p ${CONTAINER_PORT}:${CONTAINER_PORT} \
441      -v ${TMP_DIR}/notebooks:/root/notebooks "${IMG}" \
442      2>&1 > "${DOCKER_RUN_LOG}" &
443
444  # Get the container ID
445  CONTAINER_ID=""
446  while [[ -z ${CONTAINER_ID} ]]; do
447    sleep 1
448    echo "Polling for container ID..."
449    CONTAINER_ID=$("${DOCKER_BINARY}" ps | grep "${IMG}" | awk '{print $1}')
450  done
451
452  echo "ID of the running docker container: ${CONTAINER_ID}"
453  echo ""
454
455  if [[ ${TF_DOCKER_BUILD_IS_DEVEL} == "no" ]]; then
456    # Non-devel docker build: Do some basic sanity checks on jupyter notebook
457    # on the running docker container
458    echo ""
459    echo "Performing basic sanity checks on the running container..."
460    if wget -qO- "http://127.0.0.1:${CONTAINER_PORT}/tree" &> /dev/null
461    then
462      echo "  PASS: wget tree"
463    else
464      mark_check_failed "  FAIL: wget tree"
465    fi
466
467    for NB in ${TMP_DIR}/notebooks/*.ipynb; do
468      NB_BASENAME=$(basename "${NB}")
469      NB_URL="http://127.0.0.1:${CONTAINER_PORT}/notebooks/${NB_BASENAME}"
470      if wget -qO- "${NB_URL}" -o "${TMP_DIR}/${NB_BASENAME}" &> /dev/null
471      then
472        echo "  PASS: wget ${NB_URL}"
473      else
474        mark_check_failed  "  FAIL: wget ${NB_URL}"
475      fi
476    done
477  fi
478
479  # Stop the running docker container
480  sleep 1
481  "${DOCKER_BINARY}" stop --time=0 ${CONTAINER_ID}
482fi
483
484
485# Clean up
486echo "Cleaning up temporary directory: ${TMP_DIR} ..."
487rm -rf "${TMP_DIR}" || echo "ERROR: Failed to remove directory ${TMP_DIR}"
488
489
490# Summarize result
491echo ""
492if [[ ${CHECK_FAILED} == "0" ]]; then
493  echo "PASS: basic checks on newly-built image \"${IMG}\" succeeded"
494else
495  die "FAIL: basic checks on newly-built image \"${IMG}\" failed"
496fi
497
498
499# Apply the final image name and tag
500FINAL_IMG="${FINAL_IMAGE_NAME}:${FINAL_TAG}"
501
502DOCKER_VER=$("${DOCKER_BINARY}" version | grep Version | head -1 | awk '{print $NF}')
503if [[ -z "${DOCKER_VER}" ]]; then
504  die "ERROR: Failed to determine ${DOCKER_BINARY} version"
505fi
506DOCKER_MAJOR_VER=$(echo "${DOCKER_VER}" | cut -d. -f 1)
507DOCKER_MINOR_VER=$(echo "${DOCKER_VER}" | cut -d. -f 2)
508
509FORCE_TAG=""
510if [[ "${DOCKER_MAJOR_VER}" -le 1 ]] && \
511   [[ "${DOCKER_MINOR_VER}" -le 9 ]]; then
512  FORCE_TAG="--force"
513fi
514
515"${DOCKER_BINARY}" tag ${FORCE_TAG} "${IMG}" "${FINAL_IMG}" || \
516    die "Failed to tag intermediate docker image ${IMG} as ${FINAL_IMG}"
517
518echo ""
519echo "Successfully tagged docker image: ${FINAL_IMG}"
520
521# Optional: call command specified by TF_DOCKER_BUILD_PUSH_CMD to push image
522if [[ ! -z "${TF_DOCKER_BUILD_PUSH_CMD}" ]]; then
523  ${TF_DOCKER_BUILD_PUSH_CMD} ${FINAL_IMG}
524  if [[ $? == "0" ]]; then
525    echo "Successfully pushed Docker image ${FINAL_IMG}"
526  else
527    die "FAIL: Failed to push Docker image ${FINAL_IMG}"
528  fi
529fi
530
531# Optional: set TF_DOCKER_BUILD_PUSH_WITH_CREDENTIALS to push image
532if [[ ! -z "${TF_DOCKER_BUILD_PUSH_WITH_CREDENTIALS}" ]]; then
533
534  docker login -u "${TF_DOCKER_USERNAME}" \
535  -p "${TF_DOCKER_PASSWORD}"
536
537  if [[ $? != "0" ]]; then
538    die "FAIL: Unable to login. Invalid credentials."
539  fi
540  docker push "${FINAL_IMG}"
541  if [[ $? == "0" ]]; then
542    docker logout
543    echo "Successfully pushed Docker image ${FINAL_IMG}"
544  else
545    docker logout
546    die "FAIL: Failed to push Docker image ${FINAL_IMG}"
547  fi
548fi
549