3 # Copyright (C) 2014, 2015 Red Hat <contact@redhat.com>
5 # Author: Loic Dachary <loic@dachary.org>
7 # This program is free software; you can redistribute it and/or modify
8 # it under the terms of the GNU Library Public License as published by
9 # the Free Software Foundation; either version 2, or (at your option)
12 # This program is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 # GNU Library Public License for more details.
17 function get_image_name() {
21 echo ceph-$os_type-$os_version-$USER
24 function setup_container() {
29 local image=$(get_image_name $os_type $os_version)
31 if docker images $image | grep --quiet "^$image " ; then
32 eval touch --date=$(docker inspect $image | jq '.[0].Created') $image
33 found=$(find -L test/$os_type-$os_version/* -newer $image)
35 if test -n "$found" ; then
44 # replace environment variables %%FOO%% with their content
47 cp --dereference --recursive test/$os_type-$os_version dockerfile
48 os_version=$os_version user_id=$(id -u) \
49 perl -p -e 's/%%(\w+)%%/$ENV{$1}/g' \
50 dockerfile/Dockerfile.in > dockerfile/Dockerfile
51 docker $opts build --tag=$image dockerfile
56 function get_upstream() {
57 git rev-parse --show-toplevel
60 function get_downstream() {
64 local image=$(get_image_name $os_type $os_version)
65 local upstream=$(get_upstream)
66 local dir=$(dirname $upstream)
70 function setup_downstream() {
75 local image=$(get_image_name $os_type $os_version)
76 local upstream=$(get_upstream)
77 local dir=$(dirname $upstream)
78 local downstream=$(get_downstream $os_type $os_version)
82 if ! test -d $downstream ; then
83 # Inspired by https://github.com/git/git/blob/master/contrib/workdir/git-new-workdir
84 mkdir -p $downstream/.git || return 1
85 for x in config refs logs/refs objects info hooks packed-refs remotes rr-cache
89 mkdir -p "$downstream/.git/$x"
92 ln -s "$upstream/.git/$x" "$downstream/.git/$x"
93 cp "$upstream/.git/HEAD" "$downstream/.git/HEAD"
97 git reset --hard $ref || return 1
98 git submodule sync --recursive || return 1
99 git submodule update --force --init --recursive || return 1
103 function run_in_docker() {
114 setup_downstream $os_type $os_version $ref || return 1
115 setup_container $os_type $os_version "$opts" || return 1
116 local downstream=$(get_downstream $os_type $os_version)
117 local image=$(get_image_name $os_type $os_version)
118 local upstream=$(get_upstream)
120 mkdir -p $HOME/.ccache
121 ccache="--volume $HOME/.ccache:$HOME/.ccache"
123 local cmd="docker run $opts --rm --name $image --privileged $ccache"
124 cmd+=" --volume $downstream:$downstream"
125 cmd+=" --volume $upstream:$upstream"
127 if test "$script" = "SHELL" ; then
128 $cmd --tty --interactive --workdir $downstream $user $image bash
130 if ! $cmd --workdir $downstream $user $image "$@" ; then
137 function remove_all() {
140 local image=$(get_image_name $os_type $os_version)
148 Run commands within Ceph sources, in a docker container
149 $0 [options] command args ...
151 [-h|--help] display usage
152 [--verbose] trace all shell lines
154 [--os-type type] docker image repository (centos, ubuntu, etc.)
156 [--os-version version] docker image tag (7 for centos, 12.04 for ubuntu, etc.)
158 [--ref gitref] git reset --hard gitref before running the command
159 (defaults to git rev-parse HEAD)
160 [--all types+versions] list of docker image repositories and tags
162 [--shell] run an interactive shell in the container
163 [--remove-all] remove the container and the image for the specified types+versions
165 [--opts options] run the contain with 'options'
167 docker-test.sh must be run from a Ceph clone and it will run the
168 command in a container, using a copy of the clone so that long running
169 commands such as make check are not disturbed while development
170 continues. Here is a sample use case including an interactive session
171 and running a unit test:
174 Description: Ubuntu Trusty Tahr (development branch)
175 $ test/docker-test.sh --os-type centos --os-version 7 --shell
176 HEAD is now at 1caee81 autotools: add --enable-docker
178 /srv/ceph/ceph-centos-7
179 bash-4.2$ lsb_release -d
180 Description: CentOS Linux release 7.0.1406 (Core)
182 $ time test/docker-test.sh --os-type centos --os-version 7 unittest_str_map
183 HEAD is now at 1caee81 autotools: add --enable-docker
184 Running main() from gtest_main.cc
185 [==========] Running 2 tests from 1 test case.
186 [----------] Global test environment set-up.
187 [----------] 2 tests from str_map
189 [ OK ] str_map.json (1 ms)
190 [ RUN ] str_map.plaintext
191 [ OK ] str_map.plaintext (0 ms)
192 [----------] 2 tests from str_map (1 ms total)
194 [----------] Global test environment tear-down
195 [==========] 2 tests from 1 test case ran. (1 ms total)
202 The --all argument is a bash associative array literal listing the
203 operating system version for each operating system type. For instance
205 docker-test.sh --all '([ubuntu]="12.04 14.04" [centos]="6 7")'
207 is strictly equivalent to
209 docker-test.sh --os-type ubuntu --os-version 12.04
210 docker-test.sh --os-type ubuntu --os-version 14.04
211 docker-test.sh --os-type centos --os-version 6
212 docker-test.sh --os-type centos --os-version 7
214 The --os-type and --os-version must be exactly as displayed by docker images:
217 REPOSITORY TAG IMAGE ID ...
218 centos 7 87e5b6b3ccc1 ...
219 ubuntu 14.04 6b4e8a7373fe ...
221 The --os-type value can be any string in the REPOSITORY column, the --os-version
222 can be any string in the TAG column.
224 The --shell and --remove actions are mutually exclusive.
226 Run make check in centos 7
227 docker-test.sh --os-type centos --os-version 7 -- make check
229 Run make check on a giant
230 docker-test.sh --ref giant -- make check
232 Run an interactive shell and set resolv.conf to use 172.17.42.1
233 docker-test.sh --opts --dns=172.17.42.1 --shell
235 Run make check on centos 6, centos 7, ubuntu 12.04 and ubuntu 14.04
236 docker-test.sh --all '([ubuntu]="12.04 14.04" [centos]="6 7")' -- make check
240 function main_docker() {
241 if ! docker ps > /dev/null 2>&1 ; then
242 echo "docker not available: $0"
247 temp=$(getopt -o scht:v:o:a:r: --long remove-all,verbose,shell,help,os-type:,os-version:,opts:,all:,ref: -n $0 -- "$@") || return 1
252 local os_version=14.04
257 local ref=$(git rev-parse HEAD)
267 PS4='${BASH_SOURCE[0]}:$LINENO: ${FUNCNAME[0]}: '
303 echo "unexpected argument $1"
309 if test -z "$all" ; then
310 all="([$os_type]=\"$os_version\")"
313 declare -A os_type2versions
314 eval os_type2versions="$all"
316 for os_type in ${!os_type2versions[@]} ; do
317 for os_version in ${os_type2versions[$os_type]} ; do
319 remove_all $os_type $os_version || return 1
321 run_in_docker $os_type $os_version $ref "$opts" SHELL || return 1
323 run_in_docker $os_type $os_version $ref "$opts" "$@" || return 1