Updates docs for SR1 with final revision
[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 string xor function
84 #
85 function  xor()
86 {
87       local res=(`echo "$1" | sed "s/../0x& /g"`)
88       shift 1
89       while [[ "$1" ]]; do
90             local one=(`echo "$1" | sed "s/../0x& /g"`)
91             local count1=${#res[@]}
92             if [ $count1 -lt ${#one[@]} ]
93             then
94                   count1=${#one[@]}
95             fi
96             for (( i = 0; i < $count1; i++ ))
97             do
98                   res[$i]=$((${one[$i]:-0} ^ ${res[$i]:-0}))
99             done
100             shift 1
101       done
102        printf "%02x" "${res[@]}"
103 }
104 #
105 # END of string xor function
106 ############################################################################
107
108 ############################################################################
109 # BEGIN of variables to customize
110 #
111 BUILD_BASE=$(readlink -e ../build/)
112 RESULT_DIR="${BUILD_BASE}/release"
113 BUILD_SPEC="${BUILD_BASE}/config.mk"
114 CACHE_DIR="cache"
115 LOCAL_CACHE_ARCH_NAME="fuel-cache"
116
117 REMOTE_ACCESS_METHD=curl
118 INCLUDE_DIR=../include
119 #
120 # END of variables to customize
121 ############################################################################
122
123 ############################################################################
124 # BEGIN of script assigned variables
125 #
126 SCRIPT_DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
127 LOCK_FILE="${SCRIPT_DIR}/.build.lck"
128 CACHE_TMP="${SCRIPT_DIR}/tmp"
129 TEST_SUCCEED=0
130 TEST_FAIL=0
131 UNIT_TEST=0
132 UPDATE_CACHE=0
133 POPULATE_CACHE=0
134 RECURSIVE=0
135 DETACH=0
136 DEBUG=0
137 INTEGRATION_TEST=0
138 FULL_INTEGRATION_TEST=0
139 INTERACTIVE=0
140 BUILD_CACHE_URI=
141 BUILD_SPEC=
142 BUILD_DIR=
143 BUILD_LOG=
144 BUILD_VERSION=
145 MAKE_ARGS=
146 FUEL_GIT_SRC="$(make -f ../build/config.mk get-fuel-repo | cut -d " " -f1)"
147 FUEL_GIT_BRANCH="$(make -f ../build/config.mk get-fuel-repo | cut -d " " -f2)"
148 CACHE_MD5=$(md5sum ../build/cache.mk | cut -f1 -d " ")
149 CONFIG_MD5=$(md5sum ../build/config.mk | cut -f1 -d " ")
150 FUEL_COMMIT_ID=$(git ls-remote $FUEL_GIT_SRC -t $FUEL_GIT_BRANCH | cut -d $'\t' -f1)
151 REMOTE_CACHE_ARCH_HASH_TMP="$(xor $CACHE_MD5 $CONFIG_MD5)"
152 REMOTE_CACHE_ARCH_HASH="$(xor $REMOTE_CACHE_ARCH_HASH_TMP $FUEL_COMMIT_ID)"
153 REMOTE_CACHE_ARCH_NAME="fuel_cache-$REMOTE_CACHE_ARCH_HASH"
154 #
155 # END of script assigned variables
156 ############################################################################
157
158 ############################################################################
159 # BEGIN of include pragmas
160 #
161 source ${INCLUDE_DIR}/build.sh.debug
162 #
163 # END of include
164 ############################################################################
165
166 ############################################################################
167 # BEGIN of main
168 #
169 while getopts "s:c:v:f:l:r:RtTh" OPTION
170 do
171     case $OPTION in
172         h)
173             usage
174             rc=0
175             exit $rc
176             ;;
177
178         s)
179             BUILD_SPEC=${OPTARG}
180             ;;
181
182         c)
183             BUILD_CACHE_URI=${OPTARG}
184             ;;
185
186         l)
187             BUILD_LOG=${OPTARG}
188             ;;
189
190         v)
191             BUILD_VERSION=${OPTARG}
192             ;;
193
194         f)
195             BUILD_FLAGS=${OPTARG}
196             ;;
197
198         r)  REMOTE_ACCESS_METHD=${OPTARG}
199             ;;
200
201         R)
202             RECURSIVE=1
203             ;;
204
205         t)
206             INTEGRATION_TEST=1
207             ;;
208
209         T)
210             INTEGRATION_TEST=1
211             FULL_INTEGRATION_TEST=1
212             ;;
213
214         *)
215             echo "${OPTION} is not a valid argument"
216             rc=100
217             exit $rc
218             ;;
219     esac
220 done
221
222 if [ -z $BUILD_DIR ]; then
223     BUILD_DIR=$(echo $@ | cut -d ' ' -f ${OPTIND})
224 fi
225
226 for ((i=0; i<${#BUILD_FLAGS};i++)); do
227     case ${BUILD_FLAGS:$i:1} in
228         s)
229             rc=0
230             exit $rc
231             ;;
232
233         f)
234             rc=1
235             exit $rc
236             ;;
237
238         t)
239             UNIT_TEST=1
240             ;;
241
242         i)
243             INTERACTIVE=1
244             ;;
245
246         P)
247             POPULATE_CACHE=1
248             ;;
249
250         d)
251             DETACH=1
252             echo "Detach is not yet supported - exiting ...."
253             rc=100
254             exit $rc
255             ;;
256
257         D)
258             DEBUG=1
259             ;;
260
261         *)
262             echo "${BUILD_FLAGS:$i:1} is not a valid build flag - exiting ...."
263             rc=100
264             exit $rc
265             ;;
266     esac
267 done
268
269 if [ ${INTEGRATION_TEST} -eq 1 ]; then
270     integration-test
271     rc=0
272     exit $rc
273 fi
274
275 if [ ! -f ${BUILD_SPEC} ]; then
276     echo "spec file does not exist: $BUILD_SPEC - exiting ...."
277     rc=100
278     exit $rc
279 fi
280
281 if [ -z ${BUILD_DIR} ]; then
282     echo "Missing build directory - exiting ...."
283     rc=100
284     exit $rc
285 fi
286
287 if [ ! -z ${BUILD_LOG} ]; then
288     if [[ ${RECURSIVE} -ne 1 ]]; then
289         set +e
290         eval $0 -R $@ > ${BUILD_LOG} 2>&1
291         rc=$?
292         set -e
293         if [ $rc -ne 0]; then
294             exit $rc
295         fi
296     fi
297 fi
298
299 if [ ${TEST_SUCCEED} -eq 1 ]; then
300     sleep 1
301     rc=0
302     exit $rc
303 fi
304
305 if [ ${TEST_FAIL} -eq 1 ]; then
306     sleep 1
307     rc=1
308     exit $rc
309 fi
310
311 if [ -e ${LOCK_FILE} ]; then
312     echo "A build job is already running, exiting....."
313     rc=101
314     exit $rc
315 fi
316
317 echo $$ > ${LOCK_FILE}
318
319 if [ ! -z ${BUILD_CACHE_URI} ]; then
320     if [ ${POPULATE_CACHE} -ne 1 ]; then
321         rm -rf ${CACHE_TMP}/cache
322         mkdir -p ${CACHE_TMP}/cache
323         echo "Downloading cache archive ${BUILD_CACHE_URI}/${REMOTE_CACHE_ARCH_NAME} ..."
324         set +e
325         ${REMOTE_ACCESS_METHD} -o ${CACHE_TMP}/cache/${LOCAL_CACHE_ARCH_NAME}.tgz ${BUILD_CACHE_URI}/${REMOTE_CACHE_ARCH_NAME}.tgz
326         rc=$?
327         set -e
328         if [ $rc -ne 0 ]; then
329             echo "Remote cache does not exist, or is not accessible - a new cache will be built ..."
330             POPULATE_CACHE=1
331         else
332             echo "Unpacking cache archive ..."
333             set +e
334             tar -C ${CACHE_TMP}/cache -xvf ${CACHE_TMP}/cache/${LOCAL_CACHE_ARCH_NAME}.tgz
335             rc=$?
336             set -e
337             if [ $rc -ne 0 ]; then
338                 echo "WARNING: The cache seems to be corrupt or has trailing garbage, will try to use brute force"
339                 echo "Info about the cache below:"
340                 set +e
341                 file ${CACHE_TMP}/cache/${LOCAL_CACHE_ARCH_NAME}.tgz
342                 tar -C ${CACHE_TMP}/cache -tvf ${CACHE_TMP}/cache/${LOCAL_CACHE_ARCH_NAME}.tgz
343                 set -e
344                 echo "Current time is: `date`"
345                 set +e
346                 pushd ${CACHE_TMP}/cache
347                 gunzip -dcq ${CACHE_TMP}/cache/${LOCAL_CACHE_ARCH_NAME}.tgz | tar -xvf -
348                 rc=$?
349                 set -e
350                 popd
351                 if [ $rc -ne 0 ]; then
352                     echo "ERROR: Not able to resolve the cache corruption"
353                     POPULATE_CACHE=1
354                 else
355                     echo "The chache corruption was resolved"
356                     cp ${CACHE_TMP}/cache/cache/.versions ${BUILD_BASE}/.
357                     set +e
358                     make -C ${BUILD_BASE} validate-cache;
359                     rc=$?
360                     set -e
361                     if [ $rc -ne 0 ]; then
362                         echo "Cache invalid - a new cache will be built "
363                         POPULATE_CACHE=1
364                     else
365                         echo "Cache is up to date and will be used"
366                         cp -rf ${CACHE_TMP}/cache/cache/. ${BUILD_BASE}
367                     fi
368                 fi
369             else
370                 echo "Cache archive is intact"
371                 cp ${CACHE_TMP}/cache/cache/.versions ${BUILD_BASE}/.
372                 set +e
373                 make -C ${BUILD_BASE} validate-cache;
374                 rc=$?
375                 set -e
376
377                 if [ $rc -ne 0 ]; then
378                     echo "Cache invalid - a new cache will be built "
379                     POPULATE_CACHE=1
380                 else
381                     echo "Cache is up to date and will be used"
382                     cp -rf ${CACHE_TMP}/cache/cache/. ${BUILD_BASE}
383                 fi
384             fi
385             rm -rf ${CACHE_TMP}/cache
386         fi
387     fi
388 fi
389
390 if [ ${POPULATE_CACHE} -eq 1 ]; then
391     if [ ${DEBUG} -eq 0 ]; then
392         set +e
393         cd ${BUILD_BASE} && make clean
394         rc=$?
395         set -e
396         if [ $rc -ne 0 ]; then
397             echo "Build - make clean failed, exiting ..."
398             rc=100
399             exit $rc
400         fi
401     fi
402 fi
403
404 if [ ! -z ${BUILD_VERSION} ]; then
405     MAKE_ARGS+="REVSTATE=${BUILD_VERSION} "
406 fi
407
408 if [ ${UNIT_TEST} -eq 1 ]; then
409     MAKE_ARGS+="UNIT_TEST=TRUE "
410 else
411     MAKE_ARGS+="UNIT_TEST=FALSE "
412 fi
413
414 if [ ${INTERACTIVE} -eq 1 ]; then
415     MAKE_ARGS+="INTERACTIVE=TRUE "
416 else
417     MAKE_ARGS+="INTERACTIVE=FALSE "
418 fi
419
420 MAKE_ARGS+=all
421
422 if [ ${DEBUG} -eq 0 ]; then
423     set +e
424     cd ${BUILD_BASE} && make ${MAKE_ARGS}
425     rc=$?
426     set -e
427     if [ $rc -gt 0 ]; then
428         echo "Build: make all failed, exiting ..."
429         rc=200
430         exit $rc
431     fi
432 else
433     debug_make
434 fi
435 set +e
436 make -C ${BUILD_BASE} prepare-cache
437 rc=$?
438 set -e
439
440 if [ $rc -gt 0 ]; then
441     echo "Build: make prepare-cache failed - exiting ..."
442     rc=100
443     exit $rc
444 fi
445 echo "Copying built OPNFV .iso file to target directory ${BUILD_DIR} ..."
446 rm -rf ${BUILD_DIR}
447 mkdir -p ${BUILD_DIR}
448 cp ${BUILD_BASE}/.versions ${BUILD_DIR}
449 cp ${RESULT_DIR}/*.iso* ${BUILD_DIR}
450
451 if [ $POPULATE_CACHE -eq 1 ]; then
452     if [ ! -z ${BUILD_CACHE_URI} ]; then
453         echo "Building cache ..."
454         tar --dereference -C ${BUILD_BASE} -caf ${BUILD_BASE}/${LOCAL_CACHE_ARCH_NAME}.tgz ${CACHE_DIR}
455         set +e
456         tar -C ${CACHE_TMP}/cache -tvf ${BUILD_BASE}/${LOCAL_CACHE_ARCH_NAME}.tgz
457         rc=$?
458         set -e
459         if [ $rc -ne 0 ]; then
460             echo "WARNING the cache archive generated seems to be corrupt, or containing trailing garbage"
461         else
462             echo "The Cache archive build is intact"
463         fi
464         echo "Uploading cache ${BUILD_CACHE_URI}/${REMOTE_CACHE_ARCH_NAME}"
465         ${REMOTE_ACCESS_METHD} -T ${BUILD_BASE}/${LOCAL_CACHE_ARCH_NAME}.tgz ${BUILD_CACHE_URI}/${REMOTE_CACHE_ARCH_NAME}.tgz
466         rm ${BUILD_BASE}/${LOCAL_CACHE_ARCH_NAME}.tgz
467     fi
468 fi
469 echo "Success!!!"
470 exit 0
471 #
472 # END of main
473 ############################################################################