#!/bin/bash set -e # Start a local docker instance with the requested arch and distro # This script is meant to be executed from Jenkins jobs inside TCWG # lab. It prints shell commands meant to be executed in the parent # shell, consisting in: # - definition of ${CONTAINER}, used to prefix commands that you want # to run inside the container. # - definition of ${CONTAINER_CLEANUP}, a cleanup statement remove the # container on exit for instance # - definition of ${session_host} and ${session_port}, can be used for # a remote connexion to the container # - if needed, the script starts ssh-agent and adds the required key, # and returns shell statements to export the related variables. In # this case, it also defines ${SSH_AGENT_CLEANUP}. usage() { echo "Usage: $0 --arch container-arch --distro flavour [--session-host host] [--session-name name] [--task {build|test}]" echo echo " container-arch: architecture (eg: amd64, i386, arm64, armhf)" echo " distro: distribution (eg: trusty)" echo " session-host: hostname where the container will run, defaults to localhost" echo " useful if the name resolution does not work correctly" echo " session-name: session, in case the default '$BUILD_NUMBER-$JOB_NAME' is not suitable" echo " task: type of container (build or test, default=build)" exit 1 } # Save stdout/stderr file descriptors exec 3>&1 4>&2 # Make sure all output goes to stderr exec 1>&2 container_arch= distro= session_host= session_name= task="build" while [ $# -ge 1 ] do case $1 in --arch) container_arch=$2 [ x${container_arch} = x ] && usage shift 2 ;; --distro) distro=$2 [ x${distro} = x ] && usage shift 2 ;; --session-host) session_host=$2 [ x${session_host} = x ] && usage shift 2 ;; --session-name) session_name=$2 [ x${session_name} = x ] && usage shift 2 ;; --task) task=$2 [ x${task} = x ] && usage shift 2 ;; *) echo "Unsupported option: $1" usage ;; esac done [ x${container_arch} = x ] && usage [ x${distro} = x ] && usage [ x"$session_host" = x ] && session_host=localhost # Append .tcwglab if not already present case ${session_host} in *.tcwglab) ;; *) session_host=${session_host}.tcwglab esac if [ x"$session_name" = x ]; then # Set the default session_name, using BUILD_NUMBER and JOB_NAME, # as set by Jenkins. if [ "x$BUILD_NUMBER" = "x" ]; then echo "BUILD_NUMBER is not defined. Are you executing this from Jenkins ?" exit 1 fi if [ "x$JOB_NAME" = "x" ]; then echo "JOB_NAME is not defined. Are you executing this from Jenkins ?" exit 1 fi session_name=$(echo $BUILD_NUMBER-$JOB_NAME | sed -e "s#[/=,+]#-#g") fi # We want to bind-mount WORKSPACE, so make sure it is defined if [ "x$WORKSPACE" = "x" ]; then echo "WORKSPACE is not defined. Are you executing this from Jenkins ?" exit 1 fi image=linaro/ci-${container_arch}-tcwg-${task}-ubuntu:${distro} DOCKER="docker -H $session_host:2375" $DOCKER pull $image SECURITY="--cap-add=SYS_PTRACE" case ${container_arch} in i386) # We need this because of a bug in libgo's configure script: # it would crash when testing "whether setcontext clobbers TLS # variables", and report neither "no" nor "yes", later making # configure fail. SECURITY="${SECURITY} --security-opt seccomp:unconfined" ;; esac session_id=$($DOCKER run --name $session_name -dtP \ -v $HOME/snapshots-ref:$HOME/snapshots-ref:ro \ -v $WORKSPACE:$WORKSPACE \ ${SECURITY} \ --memory=7500M --pids-limit=5000 \ $image) if [ x"$session_id" = x ]; then exit 1 fi # Remove the docker instance we have just created in case something # goes wrong. CONTAINER_CLEANUP="$DOCKER rm -fv ${session_id}" trap "exec 1>&3 2>&4 ; ${CONTAINER_CLEANUP}" EXIT session_port=$($DOCKER port $session_id 22 | cut -d: -f 2) # Special case for tcwg-buildslave: we use a dedicated ssh key for # builds in TCWG lab. Update the docker container authorized_keys with # a copy from the main host. SSH_AGENT_CLEANUP= if [ "x`whoami`" = "xtcwg-buildslave" ]; then $DOCKER cp $HOME/.ssh/authorized_keys ${session_id}:/home/tcwg-buildslave/.ssh/authorized_keys # For 'test' containers, we also need to add the same keys to 'root' if [ "${task}" = "test" ]; then $DOCKER cp $HOME/.ssh/authorized_keys ${session_id}:/root/.ssh/authorized_keys fi # Start ssh-agent locally and add the right private key to it, but # only if it is not already running. Indeed, even if we want to # start several containers, we need only one ssh-agent. if [ -f $HOME/.ssh/id_rsa -a "x${SSH_AGENT_PID}" = "x" ]; then # Close fds 3 and 4 in ssh-agent's subshell, otherwise they # leak into the background daemon, and prevent this script # from working in a pipeline eval `ssh-agent -s 3>&- 4>&-` ssh-add $HOME/.ssh/id_rsa SSH_AGENT_CLEANUP="ssh-agent -k" trap "exec 1>&3 2>&4 ; ${CONTAINER_CLEANUP} ; eval \`$SSH_AGENT_CLEANUP\`" EXIT fi fi # Wait until the ssh server is ready to serve connexions # Make sure connexion messages go to stderr, so that in case of # success stdout contains only the connexion info expected by the # caller. count=20 while [ $count -gt 0 ] do ssh -p $session_port $session_host true && break echo SSH server not ready, waiting..... sleep 5 count=$((count - 1)) done if [ $count -eq 0 ]; then echo SSH server did not respond, exiting exit 1 fi # Do not remove the container upon exit: it is now ready trap EXIT # Restore stdout/stderr exec 1>&3 2>&4 # Non-empty SSH_AGENT_CLEANUP means we have started ssh-agent in this # invocation, so make sure to share the relevant information with the # parent shell if [ "x${SSH_AGENT_CLEANUP}" != "x" ]; then cat <