*** FIRST VERSION OF CI BUILD SCRIPT ***
[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 usage ()
21 {
22 cat << EOF
23 $0 Builds the Fuel@OPNFV stack
24
25 usage: $0 [-s spec-file] [-c cache-URI] [-l log-file] [-f Flags] build-directory
26
27 OPTIONS:
28   -s spec-file ($BUILD_SPEC), define the build-spec file, default ../build/config.mk
29   -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.
30
31   -l log-file ($BUILD_LOG), specifies the output log-file (stdout and stderr), if not specified logs are output to console as normal
32   -v version tag to be applied to the build result
33   -r alternative remote access method script/program. curl is default.
34   -f build flags ($BUILD_FLAGS):
35      o s: Do nothing, succeed
36      o f: Do nothing, fail
37      o t: run build unit tests
38      o i: run interactive (-t flag to docker run)
39      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
40      o d: Detatch - NOT YET SUPPORTED
41
42   build-directory ($BUILD_DIR), specifies the directory for the output artifacts (.iso file).
43
44   -h help, prints this help text
45
46 Description:
47 build.sh builds opnfv .iso artifact.
48 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:
49 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.
50 2) If the cache is invalidated by one of the following conditions:
51    - The config spec md5sum does not compare to the md5sum for the spec which the cache was built.
52    - 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.
53 3) A valid cache does not exist on the specified -c cache-base-URI.
54
55 The cache URI object name is fuel_cache-"md5sum(spec file)"
56
57 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.
58
59 Built in unit testing of components is enabled by adding the t(est) flag.
60
61 Return codes:
62  - 0 Success!
63  - 1-99 Unspecified build error
64  - 100-199 Build system internal error (not build it self)
65    o 101 Build system instance busy
66  - 200 Build failure
67
68 Examples:
69 build -c http://opnfv.org/artifactory/fuel/cache -d ~/jenkins/genesis/fuel/ci/output -f ti
70 NOTE: At current the build scope is set to the git root of the repository, -d destination locations outside that scope will not work
71 EOF
72 }
73
74
75
76 debug_make () {
77     make -C ${BUILD_BASE} clean
78     echo "This is a fake debug fuel .iso image" > ${BUILD_BASE}/fuel-6.0.1.iso
79     echo "This is a fake debug versions file" > ${BUILD_BASE}/.versions
80     rm -rf ${BUILD_BASE}/release
81     mkdir ${BUILD_BASE}/release
82     echo "This is a fake debug OPNFV .iso image"  > ${BUILD_BASE}/release/fake-debug.iso
83     echo "This is a fake debug OPNFV .iso.txt message"  > ${BUILD_BASE}/release/fake-debug.iso.txt
84     echo "This a fake debug odl build history" > ${BUILD_BASE}/opendaylight/.odl-build-history
85     echo "This a fake debug odl build log" > ${BUILD_BASE}/opendaylight/.odl-build.log
86 }
87
88 cache_check () {
89     if [ ! -f ${BUILD_BASE}/fuel-6.0.1.iso ] || \
90        [ ! -f ${BUILD_BASE}/.versions ] || \
91        [ ! -f ${BUILD_BASE}/opendaylight/.odl-build-history ]; \
92        [ ! -f ${BUILD_BASE}/opendaylight/.odl-build.log ]; then
93         echo "Cache not present in the build system"
94         echo "TEST FAILED"
95         exit $rc
96     fi
97 }
98
99 integration-test () {
100
101 ##### Always succeed integration test ####
102     make -C ${BUILD_BASE} clean
103     echo "TEST - $0 - ALWAYS SUCCEED"
104     set +e
105     $0 -f s tmp/output
106     rc=$?
107     set -e
108     if [ $rc -ne 0 ]; then
109         echo "TEST FAILED"
110         rc=150
111         exit $rc
112     fi
113
114 ##### Always fail integration test ####
115     make -C ${BUILD_BASE} clean
116     echo "TEST - $0 - ALWAYS FAIL"
117     set +e
118     $0 -f f tmp/output
119     rc=$?
120     set -e
121     if [ $rc -eq 0 ]; then
122         echo "TEST FAILED"
123         rc=151
124         exit $rc
125     fi
126
127 ##### Populate cache integration test ####
128     make -C ${BUILD_BASE} clean
129     echo "TEST - $0 - POPULATE CACHE"
130     rm -rf tmp
131     mkdir tmp
132     mkdir tmp/cache
133     set +e
134     $0 -c ${BUILD_CACHE_URI} -f PD tmp/output
135     rc=$?
136     set -e
137     if [ $rc -ne 0 ]; then
138         echo "TEST FAILED"
139         rc=152
140         exit $rc
141     fi
142
143     if [ ! -f  tmp/output/fake-debug.iso ] || [ ! -f  tmp/output/fake-debug.iso ]; then
144         echo "TEST FAILED"
145         rc=153
146         exit $rc
147     fi
148     rc=154
149     cache_check
150
151 ##### Build uinge cache integration test ####
152     make -C ${BUILD_BASE} clean
153     echo "TEST - $0 - BUILD USING CACHE"
154     set +e
155     $0 -c ${BUILD_CACHE_URI} -f D tmp/output
156     rc=$?
157     set -e
158     if [ $rc -ne 0 ]; then
159         echo "TEST FAILED"
160         rc=155
161         exit $rc
162     fi
163
164     if [ ! -f  tmp/output/fake-debug.iso ] || [ ! -f  tmp/output/fake-debug.iso ]; then
165         echo "TEST FAILED"
166         rc=156
167         exit $rc
168     fi
169     rc=157
170     cache_check
171
172 #### Repopulate cache because cache non existant ####
173     make -C ${BUILD_BASE} clean
174     echo "TEST - $0 - BUILD USING CACHE"
175     rm -rf tmp/cache/*
176     set +e
177     $0 -c ${BUILD_CACHE_URI} -f D tmp/output
178     rc=$?
179     set -e
180     if [ $rc -ne 0 ]; then
181         echo "TEST FAILED"
182         rc=158
183         exit $rc
184     fi
185
186     if [ ! -f  tmp/output/fake-debug.iso ] || [ ! -f  tmp/output/fake-debug.iso ]; then
187         echo "TEST FAILED"
188         rc=160
189         exit $rc
190     fi
191     rc=161
192     cache_check
193
194 # Repopulate cache because cach is ivalidated
195 #TBD
196 rm -rf tmp
197 echo "All tests passed!"
198 rc=0
199 exit $rc
200 }
201
202 #DEFAULT VALUES
203 BUILD_BASE=$(readlink -e ../build/)
204 RESULT_DIR="${BUILD_BASE}/release"
205 BUILD_SPEC="${BUILD_BASE}/config.mk"
206 CACHE_DIR="cache"
207 LOCAL_CACHE_ARCH_NAME="fuel-cache"
208 REMOTE_CACHE_ARCH_NAME="fuel_cache-$(md5sum ${BUILD_SPEC}| cut -f1 -d " ")"
209 REMOTE_ACCESS_METHD=curl
210
211 #SCRIPT ASSIGNED VARIABLES
212 SCRIPT_DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
213 LOCK_FILE="${SCRIPT_DIR}/.build.lck"
214 TEST_SUCCEED=0
215 TEST_FAIL=0
216 UNIT_TEST=0
217 UPDATE_CACHE=0
218 POPULATE_CACHE=0
219 RECURSIV=0
220 DETACH=0
221 DEBUG=0
222 INTEGRATION_TEST=0
223 INTERACTIVE=0
224 BUILD_CACHE_URI=
225 BUILD_SPEC=
226 BUILD_DIR=
227 BUILD_LOG=
228 BUILD_VERSION=
229 MAKE_ARGS=
230
231 while getopts "s:c:v:f:l:r:RTh" OPTION
232 do
233     case $OPTION in
234         h)
235             usage
236             rc=0
237             exit $rc
238             ;;
239
240         s)
241             BUILD_SPEC=${OPTARG}
242             ;;
243
244         c)
245             BUILD_CACHE_URI=${OPTARG}
246             ;;
247
248         l)
249             BUILD_LOG=${OPTARG}
250             ;;
251
252         v)
253             BUILD_VERSION=${OPTARG}
254             ;;
255
256         f)
257             BUILD_FLAGS=${OPTARG}
258             ;;
259
260         r)  REMOTE_ACCESS_METHD=${OPTARG}
261             ;;
262
263         R)
264             RECURSIVE=1
265             ;;
266
267         T)
268             INTEGRATION_TEST=1
269             ;;
270
271         *)
272             echo "${OPTION} is not a valid argument"
273             rc=100
274             exit $rc
275             ;;
276     esac
277 done
278
279 if [ -z $BUILD_DIR ]; then
280     BUILD_DIR=$(echo $@ | cut -d ' ' -f ${OPTIND})
281 fi
282
283 for ((i=0; i<${#BUILD_FLAGS};i++)); do
284     case ${BUILD_FLAGS:$i:1} in
285         s)
286             rc=0
287             exit $rc
288             ;;
289
290         f)
291             rc=1
292             exit $rc
293             ;;
294
295         t)
296             UNIT_TEST=1
297             ;;
298
299         i)
300             INTERACTIVE=1
301             ;;
302
303         P)
304             POPULATE_CACHE=1
305             ;;
306
307         d)
308             DETACH=1
309             echo "Detach is not yet supported - exiting ...."
310             rc=100
311             exit $rc
312             ;;
313
314         D)
315             DEBUG=1
316             ;;
317
318         *)
319             echo "${BUILD_FLAGS:$i:1} is not a valid build flag"
320             rc=100
321             exit $rc
322             ;;
323     esac
324 done
325
326 if [ ${INTEGRATION_TEST} -eq 1 ]; then
327     integration-test
328     rc=0
329     exit $rc
330 fi
331
332 if [ ! -f ${BUILD_SPEC} ]; then
333     echo "spec file does not exist: $BUILD_SPEC"
334     rc=100
335     exit $rc
336 fi
337
338 if [ -z ${BUILD_DIR} ]; then
339     echo "Missing build directory"
340     rc=100
341     exit $rc
342 fi
343
344 if [ ! -z ${BUILD_LOG} ]; then
345     if [[ ${RECURSIVE} -ne 1 ]]; then
346         set +e
347         eval $0 -R $@ > ${BUILD_LOG} 2>&1
348         rc=$?
349         set -e
350         if [ $rc -ne 0]; then
351             exit $rc
352         fi
353     fi
354 fi
355
356 if [ ${TEST_SUCCEED} -eq 1 ]; then
357     sleep 1
358     rc=0
359     exit $rc
360 fi
361
362 if [ ${TEST_FAIL} -eq 1 ]; then
363     sleep 1
364     rc=1
365     exit $rc
366 fi
367
368 if [ -e ${LOCK_FILE} ]; then
369     echo "A build job is already running, exiting....."
370     rc=101
371     exit $rc
372 fi
373
374 echo $$ > ${LOCK_FILE}
375
376 if [ ! -z ${BUILD_CACHE_URI} ]; then
377     if [ ${POPULATE_CACHE} -ne 1 ]; then
378         rm -rf /tmp/cache
379         mkdir /tmp/cache
380         echo "Downloading cach file ${BUILD_CACHE_URI}/${REMOTE_CACHE_ARCH_NAME} ..."
381         set +e
382         ${REMOTE_ACCESS_METHD} -o /tmp/cache/${LOCAL_CACHE_ARCH_NAME}.tgz ${BUILD_CACHE_URI}/${REMOTE_CACHE_ARCH_NAME}
383         rc=$?
384         set -e
385         if [ $rc -ne 0 ]; then
386                 echo "Remote cache does not exist, or is not accessible - a new cache will be built ..."
387                 POPULATE_CACHE=1
388         else
389             echo "Unpacking cache file ..."
390             tar -C /tmp/cache -xvf /tmp/cache/${LOCAL_CACHE_ARCH_NAME}.tgz
391             cp /tmp/cache/cache/.versions ${BUILD_BASE}/.
392             echo "Validating cache content ..."
393             set +e
394             make -C ${BUILD_BASE} validate-cache;
395             rc=$?
396             if [ $rc -ne 0 ]; then
397                 echo "Cache invalid - a new cache will be built "
398                 POPULATE_CACHE=1
399             else
400                 cp -rf /tmp/cache/cache/. ${BUILD_BASE}
401             fi
402             rm -rf /tmp/cache
403         fi
404     fi
405 fi
406
407 if [ ${POPULATE_CACHE} -eq 1 ]; then
408     if [ ${DEBUG} -eq 0 ]; then
409         set +e
410         cd ${BUILD_BASE} && make clean
411         rc=$?
412         set -e
413         if [ $rc -ne 0 ]; then
414             echo "Build - make clean failed, exiting ..."
415             rc=100
416             exit $rc
417         fi
418     fi
419 fi
420
421 if [ ! -z ${BUILD_VERSION} ]; then
422     MAKE_ARGS+="REVSTATE=${BUILD_VERSION} "
423 fi
424
425 if [ ${UNIT_TEST} -eq 1 ]; then
426     MAKE_ARGS+="UNIT_TEST=TRUE "
427 else
428     MAKE_ARGS+="UNIT_TEST=FALSE "
429 fi
430
431 if [ ${INTERACTIVE} -eq 1 ]; then
432     MAKE_ARGS+="INTERACTIVE=TRUE "
433 else
434     MAKE_ARGS+="INTERACTIVE=FALSE "
435 fi
436
437 MAKE_ARGS+=all
438
439 if [ ${DEBUG} -eq 0 ]; then
440     set +e
441     cd ${BUILD_BASE} && make ${MAKE_ARGS}
442     rc=$?
443     set -e
444     if [ $rc -gt 0 ]; then
445         echo "Build: make all failed, exiting ..."
446         rc=200
447         exit $rc
448     fi
449 else
450 debug_make
451 fi
452 set +e
453 make -C ${BUILD_BASE} prepare-cache
454 rc=$?
455 set -e
456
457 if [ $rc -gt 0 ]; then
458     echo "Build: make prepare-cache failed, exiting ..."
459     rc=100
460     exit $rc
461 fi
462 echo "Copying built OPNFV .iso file to target directory ${BUILD_DIR} ..."
463 rm -rf ${BUILD_DIR}
464 mkdir ${BUILD_DIR}
465 cp ${BUILD_BASE}/.versions ${BUILD_DIR}
466 cp ${RESULT_DIR}/*.iso* ${BUILD_DIR}
467
468 if [ $POPULATE_CACHE -eq 1 ]; then
469     if [ ! -z ${BUILD_CACHE_URI} ]; then
470         echo "Building cache ..."
471         tar --dereference -C ${BUILD_BASE} -caf ${BUILD_BASE}/${LOCAL_CACHE_ARCH_NAME}.tgz ${CACHE_DIR}
472         echo "Uploading cache ${BUILD_CACHE_URI}/${REMOTE_CACHE_ARCH_NAME}"
473         ${REMOTE_ACCESS_METHD} -T ${BUILD_BASE}/${LOCAL_CACHE_ARCH_NAME}.tgz ${BUILD_CACHE_URI}/${REMOTE_CACHE_ARCH_NAME}
474         rm ${BUILD_BASE}/${LOCAL_CACHE_ARCH_NAME}.tgz
475     fi
476 fi
477 echo "Success!!!"
478 exit 0