Fix to solve issues around cache archives having trailing garbage
[genesis.git] / fuel / ci / build.sh
1 #!/bin/bash
2 set -e
3 ##############################################################################
4 # Copyright (c) 2015 Ericsson AB and others.
5 # stefan.k.berg@ericsson.com
6 # jonas.bjurel@ericsson.com
7 # All rights reserved. This program and the accompanying materials
8 # are made available under the terms of the Apache License, Version 2.0
9 # which accompanies this distribution, and is available at
10 # http://www.apache.org/licenses/LICENSE-2.0
11 ##############################################################################
12
13 trap 'echo "Exiting ..."; \
14 if [ -f ${LOCK_FILE} ]; then \
15    if [ $(cat ${LOCK_FILE}) -eq $$ ]; then \
16       rm -f ${LOCK_FILE}; \
17    fi; \
18 fi;' EXIT
19
20 ############################################################################
21 # BEGIN of usage description
22 #
23 usage ()
24 {
25 cat << EOF
26 $0 Builds the Fuel@OPNFV stack
27
28 usage: $0 [-s spec-file] [-c cache-URI] [-l log-file] [-f Flags] build-directory
29
30 OPTIONS:
31   -s spec-file ($BUILD_SPEC), define the build-spec file, default ../build/config.mk
32   -c cache base URI ($BUILD_CACHE_URI), specifies the base URI to a build cache to be used/updated - the name is automatically generated from the md5sum of the spec-file, http://, ftp://, file://[absolute path] suported.
33
34   -l log-file ($BUILD_LOG), specifies the output log-file (stdout and stderr), if not specified logs are output to console as normal
35   -v version tag to be applied to the build result
36   -r alternative remote access method script/program. curl is default.
37   -t run small build-script unit test.
38   -T run large build-script unit test.
39   -f build flags ($BUILD_FLAGS):
40      o s: Do nothing, succeed
41      o f: Do nothing, fail
42      o t: run build unit tests
43      o i: run interactive (-t flag to docker run)
44      o P: Populate a new local cache and push it to the (-c cache-URI) cache artifactory if -c option is present, currently file://, http:// and ftp:// are supported
45      o d: Detatch - NOT YET SUPPORTED
46
47   build-directory ($BUILD_DIR), specifies the directory for the output artifacts (.iso file).
48
49   -h help, prints this help text
50
51 Description:
52 build.sh builds opnfv .iso artifact.
53 To reduce build time it uses build cache on a local or remote location. The cache is rebuilt and uploaded if either of the below conditions are met:
54 1) The P(opulate) flag is set and the -c cache-base-URI is provided, if -c is not provided the cache will stay local.
55 2) If the cache is invalidated by one of the following conditions:
56    - The config spec md5sum does not compare to the md5sum for the spec which the cache was built.
57    - The git Commit-Id on the remote repos/HEAD defined in the spec file does not correspont with the Commit-Id for what the cache was built with.
58 3) A valid cache does not exist on the specified -c cache-base-URI.
59
60 The cache URI object name is fuel_cache-"md5sum(spec file)"
61
62 Logging by default to console, but can be directed elsewhere with the -l option in which case both stdout and stderr is redirected to that destination.
63
64 Built in unit testing of components is enabled by adding the t(est) flag.
65
66 Return codes:
67  - 0 Success!
68  - 1-99 Unspecified build error
69  - 100-199 Build system internal error (not build it self)
70    o 101 Build system instance busy
71  - 200 Build failure
72
73 Examples:
74 build -c http://opnfv.org/artifactory/fuel/cache -d ~/jenkins/genesis/fuel/ci/output -f ti
75 NOTE: At current the build scope is set to the git root of the repository, -d destination locations outside that scope will not work
76 EOF
77 }
78 #
79 # END of usage description
80 ############################################################################
81
82 ############################################################################
83 # BEGIN of variables to customize
84 #
85 BUILD_BASE=$(readlink -e ../build/)
86 RESULT_DIR="${BUILD_BASE}/release"
87 BUILD_SPEC="${BUILD_BASE}/config.mk"
88 CACHE_DIR="cache"
89 LOCAL_CACHE_ARCH_NAME="fuel-cache"
90 REMOTE_CACHE_ARCH_NAME="fuel_cache-$(md5sum ${BUILD_SPEC}| cut -f1 -d " ")"
91 REMOTE_ACCESS_METHD=curl
92 INCLUDE_DIR=../include
93 #
94 # END of variables to customize
95 ############################################################################
96
97 ############################################################################
98 # BEGIN of script assigned variables
99 #
100 SCRIPT_DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
101 LOCK_FILE="${SCRIPT_DIR}/.build.lck"
102 CACHE_TMP="${SCRIPT_DIR}/tmp"
103 TEST_SUCCEED=0
104 TEST_FAIL=0
105 UNIT_TEST=0
106 UPDATE_CACHE=0
107 POPULATE_CACHE=0
108 RECURSIVE=0
109 DETACH=0
110 DEBUG=0
111 INTEGRATION_TEST=0
112 FULL_INTEGRATION_TEST=0
113 INTERACTIVE=0
114 BUILD_CACHE_URI=
115 BUILD_SPEC=
116 BUILD_DIR=
117 BUILD_LOG=
118 BUILD_VERSION=
119 MAKE_ARGS=
120 #
121 # END of script assigned variables
122 ############################################################################
123
124 ############################################################################
125 # BEGIN of include pragmas
126 #
127 source ${INCLUDE_DIR}/build.sh.debug
128 #
129 # END of include
130 ############################################################################
131
132 ############################################################################
133 # BEGIN of main
134 #
135 while getopts "s:c:v:f:l:r:RtTh" OPTION
136 do
137     case $OPTION in
138         h)
139             usage
140             rc=0
141             exit $rc
142             ;;
143
144         s)
145             BUILD_SPEC=${OPTARG}
146             ;;
147
148         c)
149             BUILD_CACHE_URI=${OPTARG}
150             ;;
151
152         l)
153             BUILD_LOG=${OPTARG}
154             ;;
155
156         v)
157             BUILD_VERSION=${OPTARG}
158             ;;
159
160         f)
161             BUILD_FLAGS=${OPTARG}
162             ;;
163
164         r)  REMOTE_ACCESS_METHD=${OPTARG}
165             ;;
166
167         R)
168             RECURSIVE=1
169             ;;
170
171         t)
172             INTEGRATION_TEST=1
173             ;;
174
175         T)
176             INTEGRATION_TEST=1
177             FULL_INTEGRATION_TEST=1
178             ;;
179
180         *)
181             echo "${OPTION} is not a valid argument"
182             rc=100
183             exit $rc
184             ;;
185     esac
186 done
187
188 if [ -z $BUILD_DIR ]; then
189     BUILD_DIR=$(echo $@ | cut -d ' ' -f ${OPTIND})
190 fi
191
192 for ((i=0; i<${#BUILD_FLAGS};i++)); do
193     case ${BUILD_FLAGS:$i:1} in
194         s)
195             rc=0
196             exit $rc
197             ;;
198
199         f)
200             rc=1
201             exit $rc
202             ;;
203
204         t)
205             UNIT_TEST=1
206             ;;
207
208         i)
209             INTERACTIVE=1
210             ;;
211
212         P)
213             POPULATE_CACHE=1
214             ;;
215
216         d)
217             DETACH=1
218             echo "Detach is not yet supported - exiting ...."
219             rc=100
220             exit $rc
221             ;;
222
223         D)
224             DEBUG=1
225             ;;
226
227         *)
228             echo "${BUILD_FLAGS:$i:1} is not a valid build flag - exiting ...."
229             rc=100
230             exit $rc
231             ;;
232     esac
233 done
234
235 if [ ${INTEGRATION_TEST} -eq 1 ]; then
236     integration-test
237     rc=0
238     exit $rc
239 fi
240
241 if [ ! -f ${BUILD_SPEC} ]; then
242     echo "spec file does not exist: $BUILD_SPEC - exiting ...."
243     rc=100
244     exit $rc
245 fi
246
247 if [ -z ${BUILD_DIR} ]; then
248     echo "Missing build directory - exiting ...."
249     rc=100
250     exit $rc
251 fi
252
253 if [ ! -z ${BUILD_LOG} ]; then
254     if [[ ${RECURSIVE} -ne 1 ]]; then
255         set +e
256         eval $0 -R $@ > ${BUILD_LOG} 2>&1
257         rc=$?
258         set -e
259         if [ $rc -ne 0]; then
260             exit $rc
261         fi
262     fi
263 fi
264
265 if [ ${TEST_SUCCEED} -eq 1 ]; then
266     sleep 1
267     rc=0
268     exit $rc
269 fi
270
271 if [ ${TEST_FAIL} -eq 1 ]; then
272     sleep 1
273     rc=1
274     exit $rc
275 fi
276
277 if [ -e ${LOCK_FILE} ]; then
278     echo "A build job is already running, exiting....."
279     rc=101
280     exit $rc
281 fi
282
283 echo $$ > ${LOCK_FILE}
284
285 if [ ! -z ${BUILD_CACHE_URI} ]; then
286     if [ ${POPULATE_CACHE} -ne 1 ]; then
287         rm -rf ${CACHE_TMP}/cache
288         mkdir -p ${CACHE_TMP}/cache
289         echo "Downloading cache archive ${BUILD_CACHE_URI}/${REMOTE_CACHE_ARCH_NAME} ..."
290         set +e
291         ${REMOTE_ACCESS_METHD} -o ${CACHE_TMP}/cache/${LOCAL_CACHE_ARCH_NAME}.tgz ${BUILD_CACHE_URI}/${REMOTE_CACHE_ARCH_NAME}.tgz
292         rc=$?
293         set -e
294         if [ $rc -ne 0 ]; then
295             echo "Remote cache does not exist, or is not accessible - a new cache will be built ..."
296             POPULATE_CACHE=1
297         else
298             echo "Unpacking cache archive ..."
299             set +e
300             tar -C ${CACHE_TMP}/cache -xvf ${CACHE_TMP}/cache/${LOCAL_CACHE_ARCH_NAME}.tgz
301             rc=$?
302             set -e
303             if [ $rc -ne 0 ]; then
304                 echo "WARNING: The cache seems to be corrupt or has trailing garbage, will try to use brute force"
305                 echo "Info about the cache below:"
306                 set +e
307                 file ${CACHE_TMP}/cache/${LOCAL_CACHE_ARCH_NAME}.tgz
308                 tar -C ${CACHE_TMP}/cache -tvf ${CACHE_TMP}/cache/${LOCAL_CACHE_ARCH_NAME}.tgz
309                 set -e
310                 echo "Current time is: `date`"
311                 set +e
312                 pushd ${CACHE_TMP}/cache
313                 gunzip -dcq ${CACHE_TMP}/cache/${LOCAL_CACHE_ARCH_NAME}.tgz | tar -xvf -
314                 rc=$?
315                 set -e
316                 popd
317                 if [ $rc -ne 0 ]; then
318                     echo "ERROR: Not able to resolve the cache corruption"
319                     POPULATE_CACHE=1
320                 else
321                     echo "The chache corruption was resolved"
322                     cp ${CACHE_TMP}/cache/cache/.versions ${BUILD_BASE}/.
323                     set +e
324                     make -C ${BUILD_BASE} validate-cache;
325                     rc=$?
326                     set -e
327                     if [ $rc -ne 0 ]; then
328                         echo "Cache invalid - a new cache will be built "
329                         POPULATE_CACHE=1
330                     else
331                         echo "Cache is up to date and will be used"
332                         cp -rf ${CACHE_TMP}/cache/cache/. ${BUILD_BASE}
333                     fi
334                 fi
335             else
336                 echo "Cache archive is intact"
337                 cp ${CACHE_TMP}/cache/cache/.versions ${BUILD_BASE}/.
338                 set +e
339                 make -C ${BUILD_BASE} validate-cache;
340                 rc=$?
341                 set -e
342
343                 if [ $rc -ne 0 ]; then
344                     echo "Cache invalid - a new cache will be built "
345                     POPULATE_CACHE=1
346                 else
347                     echo "Cache is up to date and will be used"
348                     cp -rf ${CACHE_TMP}/cache/cache/. ${BUILD_BASE}
349                 fi
350             fi
351             rm -rf ${CACHE_TMP}/cache
352         fi
353     fi
354 fi
355
356 if [ ${POPULATE_CACHE} -eq 1 ]; then
357     if [ ${DEBUG} -eq 0 ]; then
358         set +e
359         cd ${BUILD_BASE} && make clean
360         rc=$?
361         set -e
362         if [ $rc -ne 0 ]; then
363             echo "Build - make clean failed, exiting ..."
364             rc=100
365             exit $rc
366         fi
367     fi
368 fi
369
370 if [ ! -z ${BUILD_VERSION} ]; then
371     MAKE_ARGS+="REVSTATE=${BUILD_VERSION} "
372 fi
373
374 if [ ${UNIT_TEST} -eq 1 ]; then
375     MAKE_ARGS+="UNIT_TEST=TRUE "
376 else
377     MAKE_ARGS+="UNIT_TEST=FALSE "
378 fi
379
380 if [ ${INTERACTIVE} -eq 1 ]; then
381     MAKE_ARGS+="INTERACTIVE=TRUE "
382 else
383     MAKE_ARGS+="INTERACTIVE=FALSE "
384 fi
385
386 MAKE_ARGS+=all
387
388 if [ ${DEBUG} -eq 0 ]; then
389     set +e
390     cd ${BUILD_BASE} && make ${MAKE_ARGS}
391     rc=$?
392     set -e
393     if [ $rc -gt 0 ]; then
394         echo "Build: make all failed, exiting ..."
395         rc=200
396         exit $rc
397     fi
398 else
399     debug_make
400 fi
401 set +e
402 make -C ${BUILD_BASE} prepare-cache
403 rc=$?
404 set -e
405
406 if [ $rc -gt 0 ]; then
407     echo "Build: make prepare-cache failed - exiting ..."
408     rc=100
409     exit $rc
410 fi
411 echo "Copying built OPNFV .iso file to target directory ${BUILD_DIR} ..."
412 rm -rf ${BUILD_DIR}
413 mkdir -p ${BUILD_DIR}
414 cp ${BUILD_BASE}/.versions ${BUILD_DIR}
415 cp ${RESULT_DIR}/*.iso* ${BUILD_DIR}
416
417 if [ $POPULATE_CACHE -eq 1 ]; then
418     if [ ! -z ${BUILD_CACHE_URI} ]; then
419         echo "Building cache ..."
420         tar --dereference -C ${BUILD_BASE} -caf ${BUILD_BASE}/${LOCAL_CACHE_ARCH_NAME}.tgz ${CACHE_DIR}
421         set +e
422         tar -C ${CACHE_TMP}/cache -tvf ${BUILD_BASE}/${LOCAL_CACHE_ARCH_NAME}.tgz
423         rc=$?
424         set -e
425         if [ $rc -ne 0 ]; then
426             echo "WARNING the cache archive generated seems to be corrupt, or containing trailing garbage"
427         else
428             echo "The Cache archive build is intact"
429         fi
430         echo "Uploading cache ${BUILD_CACHE_URI}/${REMOTE_CACHE_ARCH_NAME}"
431         ${REMOTE_ACCESS_METHD} -T ${BUILD_BASE}/${LOCAL_CACHE_ARCH_NAME}.tgz ${BUILD_CACHE_URI}/${REMOTE_CACHE_ARCH_NAME}.tgz
432         rm ${BUILD_BASE}/${LOCAL_CACHE_ARCH_NAME}.tgz
433     fi
434 fi
435 echo "Success!!!"
436 exit 0
437 #
438 # END of main
439 ############################################################################