]>
Commit | Line | Data |
---|---|---|
11fdf7f2 | 1 | #!/usr/bin/env bash |
7c673cae FG |
2 | # |
3 | # Copyright (C) 2014, 2015 Red Hat <contact@redhat.com> | |
4 | # | |
5 | # Author: Loic Dachary <loic@dachary.org> | |
6 | # | |
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) | |
10 | # any later version. | |
11 | # | |
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. | |
16 | # | |
17 | function get_image_name() { | |
18 | local os_type=$1 | |
19 | local os_version=$2 | |
20 | ||
21 | echo ceph-$os_type-$os_version-$USER | |
22 | } | |
23 | ||
24 | function setup_container() { | |
25 | local os_type=$1 | |
26 | local os_version=$2 | |
f67539c2 TL |
27 | local dockercmd=$3 |
28 | local opts="$4" | |
29 | ||
30 | # rm not valid here | |
31 | opts=${opts//' --rm'}; | |
7c673cae FG |
32 | |
33 | local image=$(get_image_name $os_type $os_version) | |
34 | local build=true | |
f67539c2 TL |
35 | if $dockercmd images $image | grep --quiet "^$image " ; then |
36 | eval touch --date=$($dockercmd inspect $image | jq '.[0].Created') $image | |
7c673cae FG |
37 | found=$(find -L test/$os_type-$os_version/* -newer $image) |
38 | rm $image | |
39 | if test -n "$found" ; then | |
f67539c2 | 40 | $dockercmd rmi $image |
7c673cae FG |
41 | else |
42 | build=false | |
43 | fi | |
44 | fi | |
45 | if $build ; then | |
46 | # | |
47 | # In the dockerfile, | |
48 | # replace environment variables %%FOO%% with their content | |
49 | # | |
50 | rm -fr dockerfile | |
51 | cp --dereference --recursive test/$os_type-$os_version dockerfile | |
52 | os_version=$os_version user_id=$(id -u) \ | |
53 | perl -p -e 's/%%(\w+)%%/$ENV{$1}/g' \ | |
54 | dockerfile/Dockerfile.in > dockerfile/Dockerfile | |
f67539c2 | 55 | $dockercmd $opts build --tag=$image dockerfile |
7c673cae FG |
56 | rm -fr dockerfile |
57 | fi | |
58 | } | |
59 | ||
60 | function get_upstream() { | |
61 | git rev-parse --show-toplevel | |
62 | } | |
63 | ||
64 | function get_downstream() { | |
65 | local os_type=$1 | |
66 | local os_version=$2 | |
67 | ||
68 | local image=$(get_image_name $os_type $os_version) | |
69 | local upstream=$(get_upstream) | |
70 | local dir=$(dirname $upstream) | |
71 | echo "$dir/$image" | |
72 | } | |
73 | ||
74 | function setup_downstream() { | |
75 | local os_type=$1 | |
76 | local os_version=$2 | |
77 | local ref=$3 | |
78 | ||
79 | local image=$(get_image_name $os_type $os_version) | |
80 | local upstream=$(get_upstream) | |
81 | local dir=$(dirname $upstream) | |
82 | local downstream=$(get_downstream $os_type $os_version) | |
83 | ||
84 | ( | |
85 | cd $dir | |
86 | if ! test -d $downstream ; then | |
87 | # Inspired by https://github.com/git/git/blob/master/contrib/workdir/git-new-workdir | |
88 | mkdir -p $downstream/.git || return 1 | |
89 | for x in config refs logs/refs objects info hooks packed-refs remotes rr-cache | |
90 | do | |
91 | case $x in | |
92 | */*) | |
93 | mkdir -p "$downstream/.git/$x" | |
94 | ;; | |
95 | esac | |
96 | ln -s "$upstream/.git/$x" "$downstream/.git/$x" | |
7c673cae | 97 | done |
11fdf7f2 | 98 | cp "$upstream/.git/HEAD" "$downstream/.git/HEAD" |
7c673cae FG |
99 | fi |
100 | cd $downstream | |
101 | git reset --hard $ref || return 1 | |
102 | git submodule sync --recursive || return 1 | |
103 | git submodule update --force --init --recursive || return 1 | |
104 | ) | |
105 | } | |
106 | ||
107 | function run_in_docker() { | |
108 | local os_type=$1 | |
109 | shift | |
110 | local os_version=$1 | |
111 | shift | |
112 | local ref=$1 | |
113 | shift | |
f67539c2 TL |
114 | local dockercmd=$1 |
115 | shift | |
7c673cae FG |
116 | local opts="$1" |
117 | shift | |
118 | local script=$1 | |
119 | ||
120 | setup_downstream $os_type $os_version $ref || return 1 | |
f67539c2 | 121 | setup_container $os_type $os_version $dockercmd "$opts" || return 1 |
7c673cae FG |
122 | local downstream=$(get_downstream $os_type $os_version) |
123 | local image=$(get_image_name $os_type $os_version) | |
124 | local upstream=$(get_upstream) | |
125 | local ccache | |
126 | mkdir -p $HOME/.ccache | |
127 | ccache="--volume $HOME/.ccache:$HOME/.ccache" | |
128 | user="--user $USER" | |
f67539c2 | 129 | local cmd="$dockercmd run $opts --name $image --privileged $ccache" |
7c673cae FG |
130 | cmd+=" --volume $downstream:$downstream" |
131 | cmd+=" --volume $upstream:$upstream" | |
f67539c2 TL |
132 | if test "$dockercmd" = "podman" ; then |
133 | cmd+=" --userns=keep-id" | |
134 | fi | |
7c673cae FG |
135 | local status=0 |
136 | if test "$script" = "SHELL" ; then | |
f67539c2 | 137 | echo Running: $cmd --tty --interactive --workdir $downstream $user $image bash |
7c673cae FG |
138 | $cmd --tty --interactive --workdir $downstream $user $image bash |
139 | else | |
f67539c2 | 140 | echo Running: $cmd --workdir $downstream $user $image "$@" |
7c673cae FG |
141 | if ! $cmd --workdir $downstream $user $image "$@" ; then |
142 | status=1 | |
143 | fi | |
144 | fi | |
145 | return $status | |
146 | } | |
147 | ||
148 | function remove_all() { | |
149 | local os_type=$1 | |
150 | local os_version=$2 | |
f67539c2 | 151 | local dockercmd=$3 |
7c673cae FG |
152 | local image=$(get_image_name $os_type $os_version) |
153 | ||
f67539c2 TL |
154 | $dockercmd rm $image |
155 | $dockercmd rmi $image | |
7c673cae FG |
156 | } |
157 | ||
158 | function usage() { | |
159 | cat <<EOF | |
f67539c2 TL |
160 | Run commands within Ceph sources, in a container. Use podman if available, |
161 | docker if not. | |
7c673cae FG |
162 | $0 [options] command args ... |
163 | ||
164 | [-h|--help] display usage | |
165 | [--verbose] trace all shell lines | |
166 | ||
167 | [--os-type type] docker image repository (centos, ubuntu, etc.) | |
168 | (defaults to ubuntu) | |
11fdf7f2 TL |
169 | [--os-version version] docker image tag (7 for centos, 16.04 for ubuntu, etc.) |
170 | (defaults to 16.04) | |
7c673cae FG |
171 | [--ref gitref] git reset --hard gitref before running the command |
172 | (defaults to git rev-parse HEAD) | |
173 | [--all types+versions] list of docker image repositories and tags | |
174 | ||
175 | [--shell] run an interactive shell in the container | |
176 | [--remove-all] remove the container and the image for the specified types+versions | |
f67539c2 | 177 | [--no-rm] don't remove the container when finished |
7c673cae | 178 | |
f67539c2 | 179 | [--opts options] run the container with 'options' |
7c673cae FG |
180 | |
181 | docker-test.sh must be run from a Ceph clone and it will run the | |
182 | command in a container, using a copy of the clone so that long running | |
183 | commands such as make check are not disturbed while development | |
184 | continues. Here is a sample use case including an interactive session | |
185 | and running a unit test: | |
186 | ||
187 | $ lsb_release -d | |
11fdf7f2 | 188 | Description: Ubuntu Xenial Xerus (development branch) |
7c673cae FG |
189 | $ test/docker-test.sh --os-type centos --os-version 7 --shell |
190 | HEAD is now at 1caee81 autotools: add --enable-docker | |
191 | bash-4.2$ pwd | |
192 | /srv/ceph/ceph-centos-7 | |
193 | bash-4.2$ lsb_release -d | |
194 | Description: CentOS Linux release 7.0.1406 (Core) | |
195 | bash-4.2$ | |
196 | $ time test/docker-test.sh --os-type centos --os-version 7 unittest_str_map | |
197 | HEAD is now at 1caee81 autotools: add --enable-docker | |
198 | Running main() from gtest_main.cc | |
199 | [==========] Running 2 tests from 1 test case. | |
200 | [----------] Global test environment set-up. | |
201 | [----------] 2 tests from str_map | |
202 | [ RUN ] str_map.json | |
203 | [ OK ] str_map.json (1 ms) | |
204 | [ RUN ] str_map.plaintext | |
205 | [ OK ] str_map.plaintext (0 ms) | |
206 | [----------] 2 tests from str_map (1 ms total) | |
207 | ||
208 | [----------] Global test environment tear-down | |
209 | [==========] 2 tests from 1 test case ran. (1 ms total) | |
210 | [ PASSED ] 2 tests. | |
211 | ||
212 | real 0m3.759s | |
213 | user 0m0.074s | |
214 | sys 0m0.051s | |
215 | ||
216 | The --all argument is a bash associative array literal listing the | |
217 | operating system version for each operating system type. For instance | |
218 | ||
11fdf7f2 | 219 | docker-test.sh --all '([ubuntu]="16.04 17.04" [centos]="7")' |
7c673cae FG |
220 | |
221 | is strictly equivalent to | |
222 | ||
11fdf7f2 TL |
223 | docker-test.sh --os-type ubuntu --os-version 16.04 |
224 | docker-test.sh --os-type ubuntu --os-version 17.04 | |
7c673cae FG |
225 | docker-test.sh --os-type centos --os-version 7 |
226 | ||
227 | The --os-type and --os-version must be exactly as displayed by docker images: | |
228 | ||
229 | $ docker images | |
230 | REPOSITORY TAG IMAGE ID ... | |
231 | centos 7 87e5b6b3ccc1 ... | |
11fdf7f2 | 232 | ubuntu 16.04 6b4e8a7373fe ... |
7c673cae FG |
233 | |
234 | The --os-type value can be any string in the REPOSITORY column, the --os-version | |
235 | can be any string in the TAG column. | |
236 | ||
237 | The --shell and --remove actions are mutually exclusive. | |
238 | ||
239 | Run make check in centos 7 | |
240 | docker-test.sh --os-type centos --os-version 7 -- make check | |
241 | ||
242 | Run make check on a giant | |
243 | docker-test.sh --ref giant -- make check | |
244 | ||
245 | Run an interactive shell and set resolv.conf to use 172.17.42.1 | |
246 | docker-test.sh --opts --dns=172.17.42.1 --shell | |
247 | ||
11fdf7f2 TL |
248 | Run make check on centos 7, ubuntu 16.04 and ubuntu 17.04 |
249 | docker-test.sh --all '([ubuntu]="16.04 17.04" [centos]="7")' -- make check | |
7c673cae FG |
250 | EOF |
251 | } | |
252 | ||
253 | function main_docker() { | |
f67539c2 TL |
254 | local dockercmd="docker" |
255 | if type podman > /dev/null; then | |
256 | dockercmd="podman" | |
257 | fi | |
258 | ||
259 | if ! $dockercmd ps > /dev/null 2>&1 ; then | |
7c673cae FG |
260 | echo "docker not available: $0" |
261 | return 0 | |
262 | fi | |
263 | ||
264 | local temp | |
f67539c2 | 265 | temp=$(getopt -o scht:v:o:a:r: --long remove-all,verbose,shell,no-rm,help,os-type:,os-version:,opts:,all:,ref: -n $0 -- "$@") || return 1 |
7c673cae FG |
266 | |
267 | eval set -- "$temp" | |
268 | ||
269 | local os_type=ubuntu | |
11fdf7f2 | 270 | local os_version=16.04 |
7c673cae FG |
271 | local all |
272 | local remove=false | |
273 | local shell=false | |
274 | local opts | |
275 | local ref=$(git rev-parse HEAD) | |
f67539c2 | 276 | local no-rm=false |
7c673cae FG |
277 | |
278 | while true ; do | |
279 | case "$1" in | |
280 | --remove-all) | |
281 | remove=true | |
282 | shift | |
283 | ;; | |
284 | --verbose) | |
285 | set -xe | |
286 | PS4='${BASH_SOURCE[0]}:$LINENO: ${FUNCNAME[0]}: ' | |
287 | shift | |
288 | ;; | |
289 | -s|--shell) | |
290 | shell=true | |
291 | shift | |
292 | ;; | |
293 | -h|--help) | |
294 | usage | |
295 | return 0 | |
296 | ;; | |
297 | -t|--os-type) | |
298 | os_type=$2 | |
299 | shift 2 | |
300 | ;; | |
301 | -v|--os-version) | |
302 | os_version=$2 | |
303 | shift 2 | |
304 | ;; | |
305 | -o|--opts) | |
306 | opts="$2" | |
307 | shift 2 | |
308 | ;; | |
309 | -a|--all) | |
310 | all="$2" | |
311 | shift 2 | |
312 | ;; | |
313 | -r|--ref) | |
314 | ref="$2" | |
315 | shift 2 | |
316 | ;; | |
f67539c2 TL |
317 | --no-rm) |
318 | no-rm=true | |
319 | shift | |
320 | ;; | |
7c673cae FG |
321 | --) |
322 | shift | |
323 | break | |
324 | ;; | |
325 | *) | |
326 | echo "unexpected argument $1" | |
327 | return 1 | |
328 | ;; | |
329 | esac | |
330 | done | |
331 | ||
332 | if test -z "$all" ; then | |
333 | all="([$os_type]=\"$os_version\")" | |
334 | fi | |
335 | ||
336 | declare -A os_type2versions | |
337 | eval os_type2versions="$all" | |
338 | ||
f67539c2 TL |
339 | if ! $no-rm ; then |
340 | opts+=" --rm" | |
341 | fi | |
342 | ||
7c673cae FG |
343 | for os_type in ${!os_type2versions[@]} ; do |
344 | for os_version in ${os_type2versions[$os_type]} ; do | |
345 | if $remove ; then | |
f67539c2 | 346 | remove_all $os_type $os_version $dockercmd || return 1 |
7c673cae | 347 | elif $shell ; then |
f67539c2 | 348 | run_in_docker $os_type $os_version $ref $dockercmd "$opts" SHELL || return 1 |
7c673cae | 349 | else |
f67539c2 | 350 | run_in_docker $os_type $os_version $ref $dockercmd "$opts" "$@" || return 1 |
7c673cae FG |
351 | fi |
352 | done | |
353 | done | |
354 | } |