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