another line of interest in the summary
[build.git] / vbuild-nightly.sh
1 #!/bin/bash
2 REVISION=$(echo '$Revision$' | sed -e 's,\$,,g' -e 's,^\w*:\s,,' )
3
4 COMMANDPATH=$0
5 COMMAND=$(basename $0)
6
7 # default values, tunable with command-line options
8 DEFAULT_FCDISTRO=f7
9 DEFAULT_PLDISTRO=planetlab
10 DEFAULT_PERSONALITY=linux32
11 DEFAULT_BASE="@DATE@--@PLDISTRO@-@FCDISTRO@-@PERSONALITY@"
12 DEFAULT_SVNPATH="http://svn.planet-lab.org/svn/build/trunk"
13
14 # NOTE: do not think we want to put email addresses into scripts
15 # that can be harvested by spambots. --mef
16 DEFAULT_MAILTO="onelab-build@one-lab.org"
17
18 # web publishing results
19 DEFAULT_WEBPATH="/build/@PLDISTRO@/"
20
21 # for the test part
22 TESTBUILDURL="http://build.one-lab.org/"
23 TESTBOX=onelab-test.inria.fr
24 TESTBOXSSH=root@onelab-test.inria.fr
25 TESTSVNPATH="http://svn.planet-lab.org/svn/tests/trunk/system/"
26 TESTSCRIPT=TestMain.py
27 ####################
28 # assuming vserver runs in UTC
29 DATE=$(date +'%Y.%m.%d')
30
31 # temporary - wrap a quick summary of suspicious stuff
32 # this is to focus on installation that go wrong
33 # use with care, a *lot* of other things can go bad as well
34 function summary () {
35     from=$1; shift
36     echo "******************** BEG SUMMARY" 
37     python - $from <<EOF
38 # read a full log and tries to extract the interesting stuff
39
40 import sys,re
41 m_show_line=re.compile(".* BEG (RPM|VSERVER).*|.*'boot'.*|\* .*|.*is not installed.*")
42 m_installing_any=re.compile('\r  (Installing:[^\]]*]) ')
43 m_installing_err=re.compile('\r  (Installing:[^\]]*])(..+)')
44 m_installing_end=re.compile('Installed:.*')
45 m_installing_doc=re.compile(".*such file or directory for /usr/share/info.*")
46
47 def scan_log (filename):
48
49     try:
50         if filename=="-":
51             filename="stdin"
52             f=sys.stdin
53         else:
54             f=open(filename)
55         echo=False
56         for line in f.xreadlines():
57             if m_show_line.match(line):
58                 print line,
59             elif m_installing_err.match(line):
60                 (installing,error)=m_installing_err.match(line).groups()
61                 print installing
62                 print error
63                 echo=True
64             elif m_installing_end.match(line):
65                 echo=False
66             elif m_installing_any.match(line):
67                 if echo: 
68                     installing=m_installing_any.match(line).group(1)
69                     print installing
70                 echo=False
71             else:
72                 if echo: print line,
73         f.close()
74     except:
75         print 'Failed to analyze',filename
76
77 for arg in sys.argv[1:]:
78     scan_log(arg)
79 EOF
80     echo "******************** END SUMMARY" 
81 }
82
83
84 # Notify recipient of failure or success, manage various stamps 
85 function failure() {
86     set -x
87     WEBLOG=${WEBPATH}/${BASE}.log.txt
88     cp $LOG ${WEBLOG}
89     summary $LOG >> ${WEBLOG}
90     (echo -n "============================== $COMMAND: failure at " ; date ; tail -c 20k $WEBLOG) > ${WEBLOG}.ko
91     if [ -n "$MAILTO" ] ; then
92         tail -c 20k ${WEBPATH}/${BASE}.log.txt | mail -s "Failures for build ${BASE}" $MAILTO
93     fi
94     exit 1
95 }
96
97 function success () {
98     set -x
99     WEBLOG=${WEBPATH}/${BASE}.log.txt
100     cp $LOG ${WEBLOG}
101     summary $LOG >> ${WEBLOG}
102     touch ${WEBLOG}.ok
103     if [ -n "$MAILTO" ] ; then
104         (echo "$PLDISTRO ($BASE) build for $FCDISTRO completed on $(date)" ) | mail -s "Successfull build for ${BASE}" $MAILTO
105     fi
106     exit 0
107 }
108
109 # run in the vserver - do not manage success/failure, will be done from the root ctx
110 function build () {
111     set -x
112     set -e
113
114     echo -n "============================== Starting $COMMAND:build on "
115     date
116
117     cd /build
118   # if TAGSRELEASE specified : update PLDISTROTAGS with this tag
119     if [ -n "$TAGSRELEASE" ] ; then
120         svn up -r $TAGSRELEASE $PLDISTROTAGS
121     fi
122
123     show_env
124     
125     echo "Running make IN $(pwd)"
126     # stage1
127     make -C /build "${MAKEOPTS[@]}" PLDISTROTAGS=${PLDISTROTAGS} PLDISTRO=${PLDISTRO} "${MAKEVARS[@]}" stage1=true 
128     # versions
129     make -C /build "${MAKEOPTS[@]}" PLDISTROTAGS=${PLDISTROTAGS} PLDISTRO=${PLDISTRO} "${MAKEVARS[@]}" NIGHTLY_BASE=${BASE} versions
130     # actual stuff
131     make -C /build "${MAKEOPTS[@]}" PLDISTROTAGS=${PLDISTROTAGS} PLDISTRO=${PLDISTRO} "${MAKEVARS[@]}" $MAKETARGETS
132
133 }
134
135 # this was formerly run in the myplc-devel chroot but now is run in the root context,
136 # this is so that the .ssh config gets done manually, and once and for all
137 function runtest () {
138     set -x
139     set -e
140     trap failure ERR INT
141
142     echo -n "============================== Starting $COMMAND:runtest on $(date)"
143
144     ### the URL to the myplc package
145     rpm=$( (cd /vservers/$BASE/build/RPMS/i386 ; ls myplc-[0-9]*.rpm) )
146     if [ ${#rpm[@]} != 1 ] ; then
147         echo "$COMMAND: Cannot locate rpm for testing"
148         failure
149         exit 1
150     fi
151     url=${TESTBUILDURL}${PLDISTRO}/${BASE}/RPMS/i386/${rpm}
152
153     # compute test directory name on test box
154     testdir=test-${BASE}
155     # clean it
156     ssh ${TESTBOXSSH} rm -rf ${testdir}
157     # check it out
158     ssh ${TESTBOXSSH} svn co ${TESTSVNPATH} ${testdir}
159     # invoke test on testbox - pass url and build url - so the tests can use myplc-init-vserver.sh
160     ssh 2>&1 ${TESTBOXSSH} python -u ${testdir}/${TESTSCRIPT} --build ${SVNPATH} --url ${url} 
161     # still missing - need to populate /var/www/html/install-rpms on the myplc
162         
163     if [ "$?" != 0 ] ; then
164         failure
165     fi
166     
167     echo -n "============================== End $COMMAND:runtest on $(date)"
168 }
169
170 function show_env () {
171     set +x
172     echo FCDISTRO=$FCDISTRO
173     echo PLDISTRO=$PLDISTRO
174     echo BASE=$BASE
175     echo SVNPATH=$SVNPATH
176     echo MAKEVARS="${MAKEVARS[@]}"
177     echo MAKEOPTS="${MAKEOPTS[@]}"
178     echo PLDISTROTAGS="$PLDISTROTAGS"
179     echo TAGSRELEASE="$TAGSRELEASE"
180     echo -n "(might be unexpanded)"
181     echo WEBPATH="$WEBPATH"
182     if [ -d /vservers ] ; then
183         echo PLDISTROTAGS="$PLDISTROTAGS"
184     else
185         echo "XXXXXXXXXXXXXXXXXXXX Contents of tags definition file /build/$PLDISTROTAGS"
186         cat /build/$PLDISTROTAGS
187         echo "XXXXXXXXXXXXXXXXXXXX end tags definition"
188     fi
189     set -x
190 }
191
192 function usage () {
193     echo "Usage: $COMMAND [option] make-targets"
194     echo "This is $REVISION"
195     echo "Supported options"
196     echo " -n dry-run : -n passed to make - vserver gets created though - no mail sent"
197     echo " -f fcdistro - defaults to $DEFAULT_FCDISTRO"
198     echo " -d pldistro - defaults to $DEFAULT_PLDISTRO"
199     echo " -p personality - defaults to $DEFAULT_PERSONALITY"
200     echo " -b base - defaults to $DEFAULT_BASE"
201     echo "    @NAME@ replaced as appropriate"
202     echo " -t pldistrotags - defaults to \${PLDISTRO}-tags.mk"
203     echo " -r tagsrelease - a release number that refers to PLDISTROTAGS - defaults to HEAD"
204     echo " -s svnpath - where to fetch the build module"
205     echo " -o : overwrite - re-run in base directory, do not create vserver"
206     echo " -m mailto"
207     echo " -a makevar=value - space in values are not supported"
208     echo " -w webpath - defaults to $DEFAULT_WEBPATH"
209     echo " -B : run build only"
210     echo " -T : run test only"
211     echo " -v : be verbose"
212     echo " -7 : uses weekday-@FCDISTRO@ as base"
213     exit 1
214 }
215
216 function main () {
217
218     set -e
219
220     # preserve arguments for passing them again later
221     declare -a argv
222     for arg in "$@"; do argv=(${argv[@]} "$arg") ; done
223     
224     # parse arguments
225     MAKEVARS=()
226     MAKEOPTS=()
227     DO_BUILD=true
228     DO_TEST=true
229     while getopts "nf:d:b:p:t:r:s:om:a:w:BTvh7" opt ; do
230         case $opt in
231             n) DRY_RUN="true" ; MAKEOPTS=(${MAKEOPTS[@]} -n) ;;
232             f) FCDISTRO=$OPTARG ;;
233             d) PLDISTRO=$OPTARG ;;
234             p) PERSONALITY=$OPTARG ;;
235             b) BASE=$OPTARG ;;
236             t) PLDISTROTAGS=$OPTARG ;;
237             r) TAGSRELEASE=$OPTARG ;;
238             s) SVNPATH=$OPTARG ;;
239             o) OVERWRITEMODE=true ;;
240             m) MAILTO=$OPTARG ;;
241             a) MAKEVARS=(${MAKEVARS[@]} "$OPTARG") ;;
242             w) WEBPATH=$OPTARG ;;
243             B) DO_TEST= ;;
244             T) DO_BUILD= ; OVERWRITEMODE=true ;;
245             v) set -x ;;
246             7) BASE="$(date +%a|tr A-Z a-z)-@FCDISTRO@" ;;
247             h|*) usage ;;
248         esac
249     done
250         
251     shift $(($OPTIND - 1))
252     MAKETARGETS="$@"
253     
254     # set defaults
255     [ -z "$FCDISTRO" ] && FCDISTRO=$DEFAULT_FCDISTRO
256     [ -z "$PLDISTRO" ] && PLDISTRO=$DEFAULT_PLDISTRO
257     [ -z "$PERSONALITY" ] && PERSONALITY=$DEFAULT_PERSONALITY
258     [ -z "$PLDISTROTAGS" ] && PLDISTROTAGS="${PLDISTRO}-tags.mk"
259     [ -z "$BASE" ] && BASE="$DEFAULT_BASE"
260     [ -z "$WEBPATH" ] && WEBPATH="$DEFAULT_WEBPATH"
261     [ -z "$SVNPATH" ] && SVNPATH="$DEFAULT_SVNPATH"
262
263     # NOTE: suggest that by default no email is sent and that the user
264     # should explicitly invoke this script with the -m arg to pass in
265     # the appropriate email address. --mef
266     if [ "$PLDISTRO" = "onelab" ] ; then
267         [ -z "$MAILTO" ] && MAILTO="$DEFAULT_MAILTO"
268     fi
269     [ -n "$DRY_RUN" ] && MAILTO=""
270         
271     ### set BASE from DISTRO, if unspecified
272     sedargs="-e s,@DATE@,${DATE},g -e s,@FCDISTRO@,${FCDISTRO},g -e s,@PLDISTRO@,${PLDISTRO},g -e s,@PERSONALITY@,${PERSONALITY},g"
273     BASE=$(echo ${BASE} | sed $sedargs)
274     WEBPATH=$(echo ${WEBPATH} | sed $sedargs)
275
276     if [ ! -d /vservers ] ; then
277         # in the vserver
278         echo "==================== Within vserver BEG $(date)"
279         build
280         echo "==================== Within vserver END $(date)"
281
282     else
283         trap failure ERR INT
284         # we run in the root context : 
285         # (*) create or check for the vserver to use
286         # (*) copy this command in the vserver
287         # (*) invoke it
288         
289         if [ -n "$OVERWRITEMODE" ] ; then
290             ### Re-use a vserver (finish an unfinished build..)
291             if [ ! -d /vservers/${BASE} ] ; then
292                 echo $COMMAND : cannot find vserver $BASE
293                 exit 1
294             fi
295             # manage LOG - beware it might be a symlink so nuke it first
296             LOG=/vservers/${BASE}.log.txt
297             rm -f $LOG
298             exec > $LOG 2>&1
299             set -x
300             echo "XXXXXXXXXX $COMMAND: using existing vserver $BASE" $(date)
301             show_env
302             # update build
303             vserver ${BASE} exec svn update /build
304         else
305             # create vserver: check it does not exist yet
306             i=
307             while [ -d /vservers/${BASE}${i} ] ; do
308                 # we name subsequent builds <base>-n<i> so the logs and builds get sorted properly
309                 [ -z ${i} ] && BASE=${BASE}-n
310                 i=$((${i}+1))
311                 if [ $i -gt 100 ] ; then
312                     echo "$COMMAND: Failed to create build vserver /vservers/${BASE}${i}"
313                     exit 1
314                 fi
315             done
316             BASE=${BASE}${i}
317             # need update
318             # manage LOG - beware it might be a symlink so nuke it first
319             LOG=/vservers/${BASE}.log.txt
320             rm -f $LOG
321             exec > $LOG 2>&1 
322             set -x
323             echo "XXXXXXXXXX $COMMAND: creating vserver $BASE" $(date)
324             show_env
325
326             ### extract the whole build - much simpler
327             tmpdir=/tmp/$COMMAND-$$
328             svn export $SVNPATH $tmpdir
329             # Create vserver
330             cd $tmpdir
331             ./vbuild-init-vserver.sh -f ${FCDISTRO} -d ${PLDISTRO} -p ${PERSONALITY} ${BASE}
332             # cleanup
333             cd -
334             rm -rf $tmpdir
335             # Extract build again - in the vserver
336             vserver ${BASE} exec svn checkout ${SVNPATH} /build
337         fi
338         echo "XXXXXXXXXX $COMMAND: preparation of vserver $BASE done" $(date)
339
340         # The log inside the vserver contains everything
341         LOG2=/vservers/${BASE}/log.txt
342         (echo "==================== BEG VSERVER Transcript of vserver creation" ; \
343          cat $LOG ; \
344          echo "==================== END VSERVER Transcript of vserver creation" ; \
345          echo "xxxxxxxxxx Messing with logs, symlinking $LOG2 to $LOG" ) >> $LOG2
346         ### not too nice : nuke the former log, symlink it to the new one
347         rm $LOG; ln -s $LOG2 $LOG
348         LOG=$LOG2
349         # redirect log again
350         exec >> $LOG 2>&1 
351
352         if [ -n "$DO_BUILD" ] ; then 
353
354             cp $COMMANDPATH /vservers/${BASE}/build/
355
356             # invoke this command in the vserver for building (-T)
357             vserver ${BASE} exec chmod +x /build/$COMMAND
358             vserver ${BASE} exec /build/$COMMAND "${argv[@]}" -b "${BASE}"
359         fi
360
361         # publish to the web so runtest can find them
362         rm -rf $WEBPATH/$BASE ; mkdir -p $WEBPATH/$BASE/{RPMS,SRPMS}
363         rsync --archive --delete --verbose /vservers/$BASE/build/RPMS/ $WEBPATH/$BASE/RPMS/
364         rsync --archive --delete --verbose /vservers/$BASE/build/SRPMS/ $WEBPATH/$BASE/SRPMS/
365         
366         if [ -n "$DO_TEST" ] ; then 
367             runtest
368         fi
369
370         success 
371         
372     fi
373
374 }  
375
376 ##########
377 main "$@"