2 # run tests on all Samba subprojects and push to a git tree on success
3 # Copyright Andrew Tridgell 2010
4 # released under GNU GPL v3 or later
6 from __future__
import print_function
7 from subprocess
import call
, check_call
, check_output
, Popen
, PIPE
, CalledProcessError
13 from optparse
import OptionParser
16 from email
.mime
.text
import MIMEText
17 from email
.mime
.base
import MIMEBase
18 from email
.mime
.application
import MIMEApplication
19 from email
.mime
.multipart
import MIMEMultipart
20 from distutils
.sysconfig
import get_python_lib
24 from waflib
.Build
import CACHE_SUFFIX
26 sys
.path
.insert(0, "./third_party/waf")
27 from waflib
.Build
import CACHE_SUFFIX
30 os
.environ
["PYTHONUNBUFFERED"] = "1"
32 # This speeds up testing remarkably.
33 os
.environ
['TDB_NO_FSYNC'] = '1'
37 '''get to the top of the git repo'''
40 if os
.path
.exists(os
.path
.join(p
, ".git")):
42 p
= os
.path
.abspath(os
.path
.join(p
, '..'))
46 gitroot
= find_git_root()
48 raise Exception("Failed to find git root")
51 def_testbase
= os
.getenv("AUTOBUILD_TESTBASE", "/memdisk/%s" % os
.getenv('USER'))
53 parser
= OptionParser()
54 parser
.add_option("--tail", help="show output while running", default
=False, action
="store_true")
55 parser
.add_option("--keeplogs", help="keep logs", default
=False, action
="store_true")
56 parser
.add_option("--nocleanup", help="don't remove test tree", default
=False, action
="store_true")
57 parser
.add_option("--testbase", help="base directory to run tests in (default %s)" % def_testbase
,
59 parser
.add_option("--passcmd", help="command to run on success", default
=None)
60 parser
.add_option("--verbose", help="show all commands as they are run",
61 default
=False, action
="store_true")
62 parser
.add_option("--rebase", help="rebase on the given tree before testing",
63 default
=None, type='str')
64 parser
.add_option("--pushto", help="push to a git url on success",
65 default
=None, type='str')
66 parser
.add_option("--mark", help="add a Tested-By signoff before pushing",
67 default
=False, action
="store_true")
68 parser
.add_option("--fix-whitespace", help="fix whitespace on rebase",
69 default
=False, action
="store_true")
70 parser
.add_option("--retry", help="automatically retry if master changes",
71 default
=False, action
="store_true")
72 parser
.add_option("--email", help="send email to the given address on failure",
73 type='str', default
=None)
74 parser
.add_option("--email-from", help="send email from the given address",
75 type='str', default
="autobuild@samba.org")
76 parser
.add_option("--email-server", help="send email via the given server",
77 type='str', default
='localhost')
78 parser
.add_option("--always-email", help="always send email, even on success",
80 parser
.add_option("--daemon", help="daemonize after initial setup",
82 parser
.add_option("--branch", help="the branch to work on (default=master)",
83 default
="master", type='str')
84 parser
.add_option("--log-base", help="location where the logs can be found (default=cwd)",
85 default
=gitroot
, type='str')
86 parser
.add_option("--attach-logs", help="Attach logs to mails sent on success/failure?",
87 default
=False, action
="store_true")
88 parser
.add_option("--restrict-tests", help="run as make test with this TESTS= regex",
90 parser
.add_option("--enable-coverage", dest
='enable_coverage',
91 action
="store_const", const
='--enable-coverage', default
='',
92 help="Add --enable-coverage option while configure")
94 (options
, args
) = parser
.parse_args()
97 if options
.rebase
is None:
98 raise Exception('You can only use --retry if you also rebase')
100 testbase
= "%s/b%u" % (options
.testbase
, os
.getpid())
101 test_master
= "%s/master" % testbase
102 test_prefix
= "%s/prefix" % testbase
103 test_tmpdir
= "%s/tmp" % testbase
104 os
.environ
['TMPDIR'] = test_tmpdir
106 if options
.enable_coverage
:
107 LCOV_CMD
= "cd ${TEST_SOURCE_DIR} && lcov --capture --directory . --output-file ${LOG_BASE}/${NAME}.info --rc 'geninfo_adjust_src_path=${TEST_SOURCE_DIR}/'"
109 LCOV_CMD
= 'echo "lcov skipped since no --enable-coverage specified"'
112 # If we are only running specific test,
113 # do not sleep randomly to wait for it to start
114 def random_sleep(low
, high
):
117 def random_sleep(low
, high
):
118 return 'sleep {}'.format(random
.randint(low
, high
))
126 "talloc": "lib/talloc",
127 "replace": "lib/replace",
128 "tevent": "lib/tevent",
130 "docs-xml": "docs-xml"
133 ctdb_configure_params
= " --enable-developer ${PREFIX}"
134 samba_configure_params
= " ${ENABLE_COVERAGE} ${PREFIX} --with-profiling-data"
136 samba_libs_envvars
= "PYTHONPATH=${PYTHON_PREFIX}:$PYTHONPATH"
137 samba_libs_envvars
+= " PKG_CONFIG_PATH=$PKG_CONFIG_PATH:${PREFIX_DIR}/lib/pkgconfig"
138 samba_libs_envvars
+= " ADDITIONAL_CFLAGS='-Wmissing-prototypes'"
139 samba_libs_configure_base
= samba_libs_envvars
+ " ./configure --abi-check ${ENABLE_COVERAGE} --enable-debug -C ${PREFIX}"
140 samba_libs_configure_libs
= samba_libs_configure_base
+ " --bundled-libraries=cmocka,popt,NONE"
141 samba_libs_configure_bundled_libs
= " --bundled-libraries=!talloc,!pytalloc-util,!tdb,!pytdb,!ldb,!pyldb,!pyldb-util,!tevent,!pytevent,!popt"
142 samba_libs_configure_samba
= samba_libs_configure_base
+ samba_libs_configure_bundled_libs
145 def format_option(name
, value
=None):
146 """Format option as str list."""
147 if value
is None: # boolean option
149 if not isinstance(value
, list): # single value option
152 return ['{}={}'.format(name
, item
) for item
in value
]
163 test_options
= format_option('--include-env', include_envs
)
165 test_options
= format_option('--exclude-env', exclude_envs
)
167 # join envs options to original test options
168 TESTS
= (TESTS
+ ' ' + ' '.join(test_options
)).strip()
172 # Allow getting a full CI with
173 # git push -o ci.variable='AUTOBUILD_FAIL_IMMEDIATELY=0'
175 FAIL_IMMEDIATELY
= os
.getenv("AUTOBUILD_FAIL_IMMEDIATELY", "1")
177 if int(FAIL_IMMEDIATELY
):
178 _options
.append('FAIL_IMMEDIATELY=1')
180 _options
.append("TESTS='{}'".format(TESTS
))
182 return ' '.join([cmd
] + _options
)
185 # When updating this list, also update .gitlab-ci.yml to add the job
186 # and to make it a dependency of 'page' for the coverage report.
190 ("random-sleep", random_sleep(300, 900)),
191 ("configure", "./configure " + ctdb_configure_params
),
192 ("make", "make all"),
193 ("install", "make install"),
194 ("test", "make autotest"),
195 ("check-clean-tree", "../script/clean-source-tree.sh"),
196 ("clean", "make clean"),
200 ("random-sleep", random_sleep(300, 900)),
201 ("autoconf", "autoconf"),
202 ("configure", "./configure"),
203 ("make", "make html htmlman"),
204 ("clean", "make clean"),
207 # We have 'test' before 'install' because, 'test' should work without 'install (runs all the other envs)'
209 ("random-sleep", random_sleep(300, 900)),
210 ("configure", "./configure.developer --with-selftest-prefix=./bin/ab" + samba_configure_params
),
212 ("test", make_test(exclude_envs
=[
225 "ad_dc_default_smb1",
233 "ad_member_idmap_rid",
234 "ad_member_idmap_ad",
241 "fileserver_smb1_done",
255 "ad_dc_default_smb1",
256 "ad_dc_default_smb1_done",
260 "clusteredmember_smb1",
262 ("test-slow-none", make_test(cmd
='make test', TESTS
="--include=selftest/slow-none", include_envs
=["none"])),
264 ("install", "make install"),
265 ("check-clean-tree", "script/clean-source-tree.sh"),
266 ("clean", "make clean"),
269 # We have 'test' before 'install' because, 'test' should work without 'install (runs all the other envs)'
271 ("random-sleep", random_sleep(300, 900)),
272 ("configure", "./configure.developer --with-selftest-prefix=./bin/ab --with-system-mitkrb5 --with-experimental-mit-ad-dc" + samba_configure_params
),
274 ("test", make_test(exclude_envs
=[
287 "ad_dc_default_smb1",
288 "ad_dc_default_smb1_done",
296 "ad_member_idmap_rid",
297 "ad_member_idmap_ad",
304 "fileserver_smb1_done",
318 "ad_dc_default_smb1",
319 "ad_dc_default_smb1_done",
323 "clusteredmember_smb1",
326 ("install", "make install"),
327 ("check-clean-tree", "script/clean-source-tree.sh"),
328 ("clean", "make clean"),
332 ("random-sleep", random_sleep(300, 900)),
333 ("configure", "./configure.developer --without-ad-dc --without-ldap --without-ads --without-json --with-selftest-prefix=./bin/ab" + samba_configure_params
),
335 ("test", make_test(include_envs
=[
344 ("install", "make install"),
345 ("check-clean-tree", "script/clean-source-tree.sh"),
346 ("clean", "make clean"),
349 "samba-fileserver": [
350 ("random-sleep", random_sleep(300, 900)),
351 ("configure", "./configure.developer --without-ad-dc --with-system-heimdalkrb5 --with-selftest-prefix=./bin/ab" + samba_configure_params
),
353 ("test", make_test(include_envs
=[
356 "fileserver_smb1_done",
358 "ktest", # ktest is also tested in samba and samba-mitkrb5
359 # but is tested here against a system Heimdal
362 ("check-clean-tree", "script/clean-source-tree.sh"),
366 ("random-sleep", random_sleep(300, 900)),
367 ("configure", "./configure.developer --with-selftest-prefix=./bin/ab" + samba_configure_params
),
369 ("test", make_test(include_envs
=[
371 "ad_member_idmap_rid",
372 "ad_member_idmap_ad",
376 ("check-clean-tree", "script/clean-source-tree.sh"),
380 ("random-sleep", random_sleep(1, 1)),
381 ("configure", "./configure.developer --with-selftest-prefix=./bin/ab" + samba_configure_params
),
383 ("test", make_test(include_envs
=[
391 ("check-clean-tree", "script/clean-source-tree.sh"),
395 ("random-sleep", random_sleep(1, 1)),
396 ("configure", "./configure.developer --with-selftest-prefix=./bin/ab" + samba_configure_params
),
398 ("test", make_test(include_envs
=[
404 ("check-clean-tree", "script/clean-source-tree.sh"),
408 ("random-sleep", random_sleep(1, 1)),
409 ("configure", "./configure.developer --with-selftest-prefix=./bin/ab" + samba_configure_params
),
411 ("test", make_test(include_envs
=[
418 ("check-clean-tree", "script/clean-source-tree.sh"),
422 ("random-sleep", random_sleep(1, 1)),
423 ("configure", "./configure.developer --with-selftest-prefix=./bin/ab" + samba_configure_params
),
425 ("test", make_test(include_envs
=[
432 ("check-clean-tree", "script/clean-source-tree.sh"),
436 ("random-sleep", random_sleep(1, 1)),
437 ("configure", "./configure.developer --with-selftest-prefix=./bin/ab" + samba_configure_params
),
439 ("test", make_test(include_envs
=[
440 "ad_dc_default", "ad_dc_default_smb1", "ad_dc_default_smb1_done"])),
442 ("check-clean-tree", "script/clean-source-tree.sh"),
446 ("random-sleep", random_sleep(1, 1)),
447 ("configure", "./configure.developer --with-selftest-prefix=./bin/ab" + samba_configure_params
),
449 ("test", make_test(include_envs
=["ad_dc_slowtests"])),
451 ("check-clean-tree", "script/clean-source-tree.sh"),
454 "samba-schemaupgrade": [
455 ("random-sleep", random_sleep(1, 1)),
456 ("configure", "./configure.developer --with-selftest-prefix=./bin/ab" + samba_configure_params
),
458 ("test", make_test(include_envs
=["schema_dc", "schema_pair_dc"])),
460 ("check-clean-tree", "script/clean-source-tree.sh"),
463 # We split out the ad_dc_ntvfs tests (which are long) so other test do not wait
464 # This is currently the longest task, so we don't randomly delay it.
465 "samba-ad-dc-ntvfs": [
466 ("random-sleep", random_sleep(1, 1)),
467 ("configure", "./configure.developer --with-selftest-prefix=./bin/ab" + samba_configure_params
),
469 ("test", make_test(include_envs
=["ad_dc_ntvfs"])),
471 ("check-clean-tree", "script/clean-source-tree.sh"),
474 # Test fips compliance
476 ("random-sleep", random_sleep(100, 500)),
477 ("configure", "./configure.developer --with-selftest-prefix=./bin/ab --with-system-mitkrb5 --with-experimental-mit-ad-dc" + samba_configure_params
),
479 ("test", make_test(include_envs
=["ad_dc_fips", "ad_member_fips"])),
481 ("check-clean-tree", "script/clean-source-tree.sh"),
484 # run the backup/restore testenvs separately as they're fairly standalone
485 # (and CI seems to max out at ~8 different DCs running at once)
486 "samba-ad-dc-backup": [
487 ("random-sleep", random_sleep(300, 900)),
488 ("configure", "./configure.developer --with-selftest-prefix=./bin/ab" + samba_configure_params
),
490 ("test", make_test(include_envs
=[
499 ("check-clean-tree", "script/clean-source-tree.sh"),
503 ("random-sleep", random_sleep(1, 1)),
504 ("configure", "./configure.developer --with-selftest-prefix=./bin/ab --with-system-mitkrb5 --with-experimental-mit-ad-dc" + samba_configure_params
),
506 ("test", make_test(include_envs
=[
508 "ad_member_idmap_rid",
509 "ad_member_idmap_ad",
513 ("check-clean-tree", "script/clean-source-tree.sh"),
516 "samba-ad-dc-1-mitkrb5": [
517 ("random-sleep", random_sleep(1, 1)),
518 ("configure", "./configure.developer --with-selftest-prefix=./bin/ab --with-system-mitkrb5 --with-experimental-mit-ad-dc" + samba_configure_params
),
520 ("test", make_test(include_envs
=[
528 ("check-clean-tree", "script/clean-source-tree.sh"),
531 "samba-ad-dc-4-mitkrb5": [
532 ("random-sleep", random_sleep(1, 1)),
533 ("configure", "./configure.developer --with-selftest-prefix=./bin/ab --with-system-mitkrb5 --with-experimental-mit-ad-dc" + samba_configure_params
),
535 ("test", make_test(include_envs
=[
542 ("check-clean-tree", "script/clean-source-tree.sh"),
546 ("configure", "./configure.developer --with-selftest-prefix=./bin/ab --abi-check-disable" + samba_configure_params
),
548 ("test", make_test(TESTS
="${TESTS}")),
552 # Test cross-compile infrastructure
554 ("random-sleep", random_sleep(900, 1500)),
555 ("configure-native", "./configure.developer --with-selftest-prefix=./bin/ab" + samba_configure_params
),
556 ("configure-cross-execute", "./configure.developer --out ./bin-xe --cross-compile --cross-execute=script/identity_cc.sh" \
557 " --cross-answers=./bin-xe/cross-answers.txt --with-selftest-prefix=./bin-xe/ab" + samba_configure_params
),
558 ("verify-cross-execute-output", "grep '^Checking value of NSIG' ./bin-xe/cross-answers.txt"),
559 ("configure-cross-answers", "./configure.developer --out ./bin-xa --cross-compile" \
560 " --cross-answers=./bin-xe/cross-answers.txt --with-selftest-prefix=./bin-xa/ab" + samba_configure_params
),
561 ("compare-results", "script/compare_cc_results.py "
562 "./bin/c4che/default{} "
563 "./bin-xe/c4che/default{} "
564 "./bin-xa/c4che/default{}".format(*([CACHE_SUFFIX
]*3))),
565 ("modify-cross-answers", "sed -i.bak -e 's/^\\(Checking value of NSIG:\\) .*/\\1 \"1234\"/' ./bin-xe/cross-answers.txt"),
566 ("configure-cross-answers-modified", "./configure.developer --out ./bin-xa2 --cross-compile" \
567 " --cross-answers=./bin-xe/cross-answers.txt --with-selftest-prefix=./bin-xa2/ab" + samba_configure_params
),
568 ("verify-cross-answers", "test $(sed -n -e 's/VALUEOF_NSIG = \\(.*\\)/\\1/p' ./bin-xa2/c4che/default{})" \
569 " = \"'1234'\"".format(CACHE_SUFFIX
)),
570 ("invalidate-cross-answers", "sed -i.bak -e '/^Checking value of NSIG/d' ./bin-xe/cross-answers.txt"),
571 ("configure-cross-answers-fail", "./configure.developer --out ./bin-xa3 --cross-compile" \
572 " --cross-answers=./bin-xe/cross-answers.txt --with-selftest-prefix=./bin-xa3/ab" + samba_configure_params
+ \
576 # test build with -O3 -- catches extra warnings and bugs, tests the ad_dc environments
578 ("random-sleep", random_sleep(300, 900)),
579 ("configure", "ADDITIONAL_CFLAGS='-O3 -Wp,-D_FORTIFY_SOURCE=2' ./configure.developer --with-selftest-prefix=./bin/ab --abi-check-disable" + samba_configure_params
),
581 ("test", make_test(cmd
='make test', TESTS
="--exclude=selftest/slow-none", include_envs
=["none"])),
582 ("quicktest", make_test(cmd
='make quicktest', include_envs
=["ad_dc", "ad_dc_smb1", "ad_dc_smb1_done"])),
584 ("install", "make install"),
585 ("check-clean-tree", "script/clean-source-tree.sh"),
586 ("clean", "make clean"),
590 ("random-sleep", random_sleep(900, 1500)),
592 # make sure we have tdb around:
593 ("tdb-configure", "cd lib/tdb && PYTHONPATH=${PYTHON_PREFIX}:$PYTHONPATH PKG_CONFIG_PATH=$PKG_CONFIG_PATH:${PREFIX_DIR}/lib/pkgconfig ./configure --bundled-libraries=NONE --abi-check --enable-debug -C ${PREFIX}"),
594 ("tdb-make", "cd lib/tdb && make"),
595 ("tdb-install", "cd lib/tdb && make install"),
597 # build samba with cluster support (also building ctdb):
599 "PYTHONPATH=${PYTHON_PREFIX}:$PYTHONPATH "
600 "PKG_CONFIG_PATH=${PREFIX_DIR}/lib/pkgconfig:${PKG_CONFIG_PATH} "
601 "./configure.developer ${PREFIX} "
602 "--with-selftest-prefix=./bin/ab "
603 "--with-cluster-support "
605 "--bundled-libraries=!tdb"),
606 ("samba-make", "make"),
607 ("samba-check", "./bin/smbd -b | grep CLUSTER_SUPPORT"),
608 ("samba-install", "make install"),
609 ("ctdb-check", "test -e ${PREFIX_DIR}/sbin/ctdbd"),
612 make_test(cmd
='make test',
613 include_envs
=["clusteredmember_smb1"])
617 ("check-clean-tree", "script/clean-source-tree.sh"),
618 ("clean", "make clean"),
619 ("ctdb-clean", "cd ./ctdb && make clean"),
623 ("random-sleep", random_sleep(300, 900)),
624 ("talloc-configure", "cd lib/talloc && " + samba_libs_configure_libs
),
625 ("talloc-make", "cd lib/talloc && make"),
626 ("talloc-install", "cd lib/talloc && make install"),
628 ("tdb-configure", "cd lib/tdb && " + samba_libs_configure_libs
),
629 ("tdb-make", "cd lib/tdb && make"),
630 ("tdb-install", "cd lib/tdb && make install"),
632 ("tevent-configure", "cd lib/tevent && " + samba_libs_configure_libs
),
633 ("tevent-make", "cd lib/tevent && make"),
634 ("tevent-install", "cd lib/tevent && make install"),
636 ("ldb-configure", "cd lib/ldb && " + samba_libs_configure_libs
),
637 ("ldb-make", "cd lib/ldb && make"),
638 ("ldb-install", "cd lib/ldb && make install"),
640 ("nondevel-configure", "./configure ${PREFIX}"),
641 ("nondevel-make", "make -j"),
642 ("nondevel-check", "./bin/smbd -b | grep WITH_NTVFS_FILESERVER && exit 1; exit 0"),
643 ("nondevel-install", "make install"),
644 ("nondevel-dist", "make dist"),
646 # retry with all modules shared
647 ("allshared-distclean", "make distclean"),
648 ("allshared-configure", samba_libs_configure_samba
+ " --with-shared-modules=ALL"),
649 ("allshared-make", "make -j"),
653 ("random-sleep", random_sleep(1, 1)),
654 # build with all modules static
655 ("allstatic-configure", "./configure.developer " + samba_configure_params
+ " --with-static-modules=ALL"),
656 ("allstatic-make", "make -j"),
657 ("allstatic-test", make_test(TESTS
="samba3.smb2.create.*nt4_dc")),
660 # retry without any required modules
661 ("none-distclean", "make distclean"),
662 ("none-configure", "./configure.developer " + samba_configure_params
+ " --with-static-modules=!FORCED,!DEFAULT --with-shared-modules=!FORCED,!DEFAULT"),
663 ("none-make", "make -j"),
665 # retry with nonshared smbd and smbtorture
666 ("nonshared-distclean", "make distclean"),
667 ("nonshared-configure", "./configure.developer " + samba_configure_params
+ " --bundled-libraries=ALL --with-static-modules=ALL --nonshared-binary=smbtorture,smbd/smbd"),
668 ("nonshared-make", "make -j")
672 # build the fuzzers (static) via the oss-fuzz script
673 ("fuzzers-mkdir-prefix", "mkdir -p ${PREFIX_DIR}"),
674 ("fuzzers-build", "OUT=${PREFIX_DIR} LIB_FUZZING_ENGINE= SANITIZER=address CXX= CFLAGS= ./lib/fuzzing/oss-fuzz/build_samba.sh --enable-afl"),
675 ("fuzzers-check", "./lib/fuzzing/oss-fuzz/check_build.sh ${PREFIX_DIR}")
678 # Test Samba without python still builds. When this test fails
679 # due to more use of Python, the expectations is that the newly
680 # failing part of the code should be disabled when
681 # --disable-python is set (rather than major work being done to
682 # support this environment). The target here is for vendors
683 # shipping a minimal smbd.
685 ("random-sleep", random_sleep(300, 900)),
686 ("configure", "./configure.developer ${ENABLE_COVERAGE} ${PREFIX} --with-profiling-data --disable-python --without-ad-dc"),
688 ("install", "make install"),
689 ("find-python", "script/find_python.sh ${PREFIX}"),
690 ("test", "make test-nopython"),
692 ("check-clean-tree", "script/clean-source-tree.sh"),
693 ("clean", "make clean"),
695 ("talloc-configure", "cd lib/talloc && " + samba_libs_configure_base
+ " --bundled-libraries=cmocka,NONE --disable-python"),
696 ("talloc-make", "cd lib/talloc && make"),
697 ("talloc-install", "cd lib/talloc && make install"),
699 ("tdb-configure", "cd lib/tdb && " + samba_libs_configure_base
+ " --bundled-libraries=cmocka,NONE --disable-python"),
700 ("tdb-make", "cd lib/tdb && make"),
701 ("tdb-install", "cd lib/tdb && make install"),
703 ("tevent-configure", "cd lib/tevent && " + samba_libs_configure_base
+ " --bundled-libraries=cmocka,NONE --disable-python"),
704 ("tevent-make", "cd lib/tevent && make"),
705 ("tevent-install", "cd lib/tevent && make install"),
707 ("ldb-configure", "cd lib/ldb && " + samba_libs_configure_base
+ " --bundled-libraries=cmocka,NONE --disable-python"),
708 ("ldb-make", "cd lib/ldb && make"),
709 ("ldb-install", "cd lib/ldb && make install"),
711 # retry against installed library packages
712 ("libs-configure", samba_libs_configure_base
+ samba_libs_configure_bundled_libs
+ " --disable-python --without-ad-dc"),
713 ("libs-make", "make -j"),
714 ("libs-install", "make install"),
715 ("libs-check-clean-tree", "script/clean-source-tree.sh"),
716 ("libs-clean", "make clean"),
719 # check we can do the same thing using python2
720 "samba-nopython-py2": [
721 ("random-sleep", random_sleep(300, 900)),
722 ("configure", "PYTHON=python2 ./configure.developer ${ENABLE_COVERAGE} ${PREFIX} --with-profiling-data --disable-python --without-ad-dc"),
723 ("make", "PYTHON=python2 make -j"),
724 ("install", "PYTHON=python2 make install"),
725 ("find-python", "script/find_python.sh ${PREFIX}"),
726 ("test", "make test-nopython"),
728 ("check-clean-tree", "script/clean-source-tree.sh"),
729 ("clean", "PYTHON=python2 make clean"),
731 ("talloc-configure", "cd lib/talloc && PYTHON=python2 " + samba_libs_configure_base
+ " --bundled-libraries=cmocka,NONE --disable-python"),
732 ("talloc-make", "cd lib/talloc && PYTHON=python2 make"),
733 ("talloc-install", "cd lib/talloc && PYTHON=python2 make install"),
735 ("tdb-configure", "cd lib/tdb && PYTHON=python2 " + samba_libs_configure_base
+ " --bundled-libraries=cmocka,NONE --disable-python"),
736 ("tdb-make", "cd lib/tdb && PYTHON=python2 make"),
737 ("tdb-install", "cd lib/tdb && PYTHON=python2 make install"),
739 ("tevent-configure", "cd lib/tevent && PYTHON=python2 " + samba_libs_configure_base
+ " --bundled-libraries=cmocka,NONE --disable-python"),
740 ("tevent-make", "cd lib/tevent && PYTHON=python2 make"),
741 ("tevent-install", "cd lib/tevent && PYTHON=python2 make install"),
743 ("ldb-configure", "cd lib/ldb && PYTHON=python2 " + samba_libs_configure_base
+ " --bundled-libraries=cmocka,NONE --disable-python"),
744 ("ldb-make", "cd lib/ldb && PYTHON=python2 make"),
745 ("ldb-install", "cd lib/ldb && PYTHON=python2 make install"),
747 # retry against installed library packages
748 ("libs-configure", "PYTHON=python2 " + samba_libs_configure_base
+ samba_libs_configure_bundled_libs
+ " --disable-python --without-ad-dc"),
749 ("libs-make", "PYTHON=python2 make -j"),
750 ("libs-install", "PYTHON=python2 make install"),
751 ("libs-check-clean-tree", "script/clean-source-tree.sh"),
752 ("libs-clean", "PYTHON=python2 make clean"),
756 ("random-sleep", random_sleep(60, 600)),
757 ("configure", "./configure ${ENABLE_COVERAGE} --enable-developer -C ${PREFIX}"),
759 ("install", "make install"),
760 ("test", "make test"),
762 ("clean", "make clean"),
763 ("configure-no-lmdb", "./configure ${ENABLE_COVERAGE} --enable-developer --without-ldb-lmdb -C ${PREFIX}"),
764 ("make-no-lmdb", "make"),
765 ("test-no-lmdb", "make test"),
766 ("lcov-no-lmdb", LCOV_CMD
),
767 ("install-no-lmdb", "make install"),
768 ("check-clean-tree", "../../script/clean-source-tree.sh"),
769 ("distcheck", "make distcheck"),
770 ("clean", "make clean"),
774 ("random-sleep", random_sleep(60, 600)),
775 ("configure", "./configure ${ENABLE_COVERAGE} --enable-developer -C ${PREFIX}"),
777 ("install", "make install"),
778 ("test", "make test"),
780 ("check-clean-tree", "../../script/clean-source-tree.sh"),
781 ("distcheck", "make distcheck"),
782 ("clean", "make clean"),
786 ("random-sleep", random_sleep(60, 600)),
787 ("configure", "./configure ${ENABLE_COVERAGE} --enable-developer -C ${PREFIX}"),
789 ("install", "make install"),
790 ("test", "make test"),
792 ("check-clean-tree", "../../script/clean-source-tree.sh"),
793 ("distcheck", "make distcheck"),
794 ("clean", "make clean"),
798 ("random-sleep", random_sleep(60, 600)),
799 ("configure", "./configure ${ENABLE_COVERAGE} --enable-developer -C ${PREFIX}"),
801 ("install", "make install"),
802 ("test", "make test"),
804 ("check-clean-tree", "../../script/clean-source-tree.sh"),
805 ("distcheck", "make distcheck"),
806 ("clean", "make clean"),
810 ("random-sleep", random_sleep(60, 600)),
811 ("configure", "./configure ${ENABLE_COVERAGE} --enable-developer -C ${PREFIX}"),
813 ("install", "make install"),
814 ("test", "make test"),
816 ("check-clean-tree", "../../script/clean-source-tree.sh"),
817 ("distcheck", "make distcheck"),
818 ("clean", "make clean"),
822 ("random-sleep", random_sleep(60, 600)),
823 ("configure", "perl Makefile.PL PREFIX=${PREFIX_DIR}"),
824 ("touch", "touch *.yp"),
826 ("test", "make test"),
827 ("install", "make install"),
828 ("checkout-yapp-generated", "git checkout lib/Parse/Pidl/IDL.pm lib/Parse/Pidl/Expr.pm"),
829 ("check-clean-tree", "../script/clean-source-tree.sh"),
830 ("clean", "make clean"),
833 # these are useful for debugging autobuild
834 'pass': [("pass", 'echo passing && /bin/true')],
835 'fail': [("fail", 'echo failing && /bin/false')],
838 defaulttasks
= list(tasks
.keys())
840 defaulttasks
.remove("pass")
841 defaulttasks
.remove("fail")
842 defaulttasks
.remove("samba-test-only")
843 defaulttasks
.remove("samba-fuzz")
844 defaulttasks
.remove("samba-fips")
845 if os
.environ
.get("AUTOBUILD_SKIP_SAMBA_O3", "0") == "1":
846 defaulttasks
.remove("samba-o3")
855 def run_cmd(cmd
, dir=".", show
=None, output
=False, checkfail
=True):
857 show
= options
.verbose
859 do_print("Running: '%s' in '%s'" % (cmd
, dir))
861 out
= check_output([cmd
], shell
=True, cwd
=dir)
862 return out
.decode(encoding
='utf-8', errors
='backslashreplace')
864 return check_call(cmd
, shell
=True, cwd
=dir)
866 return call(cmd
, shell
=True, cwd
=dir)
868 def rmdir_force(dirname
, re_raise
=True):
870 run_cmd("test -d %s && chmod -R +w %s; rm -rf %s" % (
871 dirname
, dirname
, dirname
), output
=True, show
=True)
872 except CalledProcessError
as e
:
873 do_print("Failed: '%s'" % (str(e
)))
874 run_cmd("tree %s" % dirname
, output
=True, show
=True)
880 class builder(object):
881 '''handle build of one directory'''
883 def __init__(self
, name
, sequence
, cp
=True):
885 self
.dir = builddirs
.get(name
, '.')
886 self
.tag
= self
.name
.replace('/', '_')
887 self
.sequence
= sequence
889 self
.stdout_path
= "%s/%s.stdout" % (gitroot
, self
.tag
)
890 self
.stderr_path
= "%s/%s.stderr" % (gitroot
, self
.tag
)
892 do_print("stdout for %s in %s" % (self
.name
, self
.stdout_path
))
893 do_print("stderr for %s in %s" % (self
.name
, self
.stderr_path
))
894 run_cmd("rm -f %s %s" % (self
.stdout_path
, self
.stderr_path
))
895 self
.stdout
= open(self
.stdout_path
, 'w')
896 self
.stderr
= open(self
.stderr_path
, 'w')
897 self
.stdin
= open("/dev/null", 'r')
898 self
.test_source_dir
= "%s/%s" % (testbase
, self
.tag
)
899 self
.cwd
= "%s/%s" % (self
.test_source_dir
, self
.dir)
900 self
.prefix
= "%s/%s" % (test_prefix
, self
.tag
)
901 rmdir_force(self
.test_source_dir
)
902 rmdir_force(self
.prefix
)
904 run_cmd("cp -R -a -l %s %s" % (test_master
, self
.test_source_dir
), dir=test_master
, show
=True)
906 run_cmd("git clone --recursive --shared %s %s" % (test_master
, self
.test_source_dir
), dir=test_master
, show
=True)
909 def start_next(self
):
910 if self
.next
== len(self
.sequence
):
911 if not options
.nocleanup
:
912 rmdir_force(self
.test_source_dir
)
913 rmdir_force(self
.prefix
)
914 do_print('%s: Completed OK' % self
.name
)
917 (self
.stage
, self
.cmd
) = self
.sequence
[self
.next
]
918 self
.cmd
= self
.cmd
.replace("${PYTHON_PREFIX}", get_python_lib(plat_specific
=1, standard_lib
=0, prefix
=self
.prefix
))
919 self
.cmd
= self
.cmd
.replace("${PREFIX}", "--prefix=%s" % self
.prefix
)
920 self
.cmd
= self
.cmd
.replace("${PREFIX_DIR}", "%s" % self
.prefix
)
921 self
.cmd
= self
.cmd
.replace("${TESTS}", options
.restrict_tests
)
922 self
.cmd
= self
.cmd
.replace("${TEST_SOURCE_DIR}", self
.test_source_dir
)
923 self
.cmd
= self
.cmd
.replace("${LOG_BASE}", options
.log_base
)
924 self
.cmd
= self
.cmd
.replace("${NAME}", self
.name
)
925 self
.cmd
= self
.cmd
.replace("${ENABLE_COVERAGE}", options
.enable_coverage
)
926 do_print('%s: [%s] Running %s in %r' % (self
.name
, self
.stage
, self
.cmd
, self
.cwd
))
927 self
.proc
= Popen(self
.cmd
, shell
=True,
928 close_fds
=True, cwd
=self
.cwd
,
929 stdout
=self
.stdout
, stderr
=self
.stderr
, stdin
=self
.stdin
)
933 class buildlist(object):
934 '''handle build of multiple directories'''
936 def __init__(self
, tasknames
, rebase_url
, rebase_branch
="master"):
937 self
.tail_proc
= None
940 if options
.restrict_tests
:
941 tasknames
= ["samba-test-only"]
943 tasknames
= defaulttasks
945 self
.tlist
= [builder(n
, tasks
[n
], cp
=(n
!= "pidl")) for n
in tasknames
]
948 rebase_remote
= "rebaseon"
949 retry_task
= [("retry",
951 git remote add -t %s %s %s
955 git describe %s/%s > old_remote_branch.desc
957 git describe %s/%s > remote_branch.desc
958 diff old_remote_branch.desc remote_branch.desc
961 rebase_branch
, rebase_remote
, rebase_url
,
963 rebase_remote
, rebase_branch
,
965 rebase_remote
, rebase_branch
968 self
.retry
= builder('retry', retry_task
, cp
=False)
969 self
.need_retry
= False
972 if self
.tail_proc
is not None:
973 self
.tail_proc
.terminate()
974 self
.tail_proc
.wait()
975 self
.tail_proc
= None
976 if self
.retry
is not None:
977 self
.retry
.proc
.terminate()
978 self
.retry
.proc
.wait()
981 if b
.proc
is not None:
982 run_cmd("killbysubdir %s > /dev/null 2>&1" % b
.test_source_dir
, checkfail
=False)
994 b
.status
= b
.proc
.poll()
1000 ret
= self
.retry
.proc
.poll()
1002 self
.need_retry
= True
1012 if options
.retry
and self
.need_retry
:
1014 do_print("retry needed")
1015 return (0, None, None, None, "retry")
1018 if os
.WIFSIGNALED(b
.status
) or os
.WEXITSTATUS(b
.status
) != 0:
1020 return (b
.status
, b
.name
, b
.stage
, b
.tag
, "%s: [%s] failed '%s' with status %d" % (b
.name
, b
.stage
, b
.cmd
, b
.status
))
1023 return (0, None, None, None, "All OK")
1025 def write_system_info(self
, filename
):
1026 with
open(filename
, 'w') as f
:
1027 for cmd
in ['uname -a',
1031 'cat /proc/cpuinfo',
1034 'df -m %s' % testbase
]:
1036 out
= run_cmd(cmd
, output
=True, checkfail
=False)
1037 except CalledProcessError
as e
:
1038 out
= "<failed: %s>" % str(e
)
1039 print('### %s' % cmd
, file=f
)
1043 def tarlogs(self
, fname
):
1044 with tarfile
.open(fname
, "w:gz") as tar
:
1045 for b
in self
.tlist
:
1046 tar
.add(b
.stdout_path
, arcname
="%s.stdout" % b
.tag
)
1047 tar
.add(b
.stderr_path
, arcname
="%s.stderr" % b
.tag
)
1048 if os
.path
.exists("autobuild.log"):
1049 tar
.add("autobuild.log")
1050 filename
= 'system-info.txt'
1051 self
.write_system_info(filename
)
1054 def remove_logs(self
):
1055 for b
in self
.tlist
:
1056 os
.unlink(b
.stdout_path
)
1057 os
.unlink(b
.stderr_path
)
1059 def start_tail(self
):
1060 cmd
= ["tail", "-f"]
1061 for b
in self
.tlist
:
1062 cmd
.append(b
.stdout_path
)
1063 cmd
.append(b
.stderr_path
)
1064 self
.tail_proc
= Popen(cmd
, close_fds
=True)
1067 def cleanup(do_raise
=False):
1068 if options
.nocleanup
:
1070 run_cmd("stat %s || true" % test_tmpdir
, show
=True)
1071 run_cmd("stat %s" % testbase
, show
=True)
1072 do_print("Cleaning up %r" % cleanup_list
)
1073 for d
in cleanup_list
:
1074 ok
= rmdir_force(d
, re_raise
=False)
1077 if os
.path
.isdir(d
):
1078 do_print("Killing, waiting and retry")
1079 run_cmd("killbysubdir %s > /dev/null 2>&1" % d
, checkfail
=False)
1081 do_print("Waiting and retry")
1083 rmdir_force(d
, re_raise
=do_raise
)
1086 def daemonize(logfile
):
1088 if pid
== 0: # Parent
1091 if pid
!= 0: # Actual daemon
1096 import resource
# Resource usage information.
1097 maxfd
= resource
.getrlimit(resource
.RLIMIT_NOFILE
)[1]
1098 if maxfd
== resource
.RLIM_INFINITY
:
1099 maxfd
= 1024 # Rough guess at maximum number of open file descriptors.
1100 for fd
in range(0, maxfd
):
1105 os
.open(logfile
, os
.O_RDWR | os
.O_CREAT
)
1110 def write_pidfile(fname
):
1111 '''write a pid file, cleanup on exit'''
1112 with
open(fname
, mode
='w') as f
:
1113 f
.write("%u\n" % os
.getpid())
1116 def rebase_tree(rebase_url
, rebase_branch
="master"):
1117 rebase_remote
= "rebaseon"
1118 do_print("Rebasing on %s" % rebase_url
)
1119 run_cmd("git describe HEAD", show
=True, dir=test_master
)
1120 run_cmd("git remote add -t %s %s %s" %
1121 (rebase_branch
, rebase_remote
, rebase_url
),
1122 show
=True, dir=test_master
)
1123 run_cmd("git fetch %s" % rebase_remote
, show
=True, dir=test_master
)
1124 if options
.fix_whitespace
:
1125 run_cmd("git rebase --force-rebase --whitespace=fix %s/%s" %
1126 (rebase_remote
, rebase_branch
),
1127 show
=True, dir=test_master
)
1129 run_cmd("git rebase --force-rebase %s/%s" %
1130 (rebase_remote
, rebase_branch
),
1131 show
=True, dir=test_master
)
1132 diff
= run_cmd("git --no-pager diff HEAD %s/%s" %
1133 (rebase_remote
, rebase_branch
),
1134 dir=test_master
, output
=True)
1136 do_print("No differences between HEAD and %s/%s - exiting" %
1137 (rebase_remote
, rebase_branch
))
1139 run_cmd("git describe %s/%s" %
1140 (rebase_remote
, rebase_branch
),
1141 show
=True, dir=test_master
)
1142 run_cmd("git describe HEAD", show
=True, dir=test_master
)
1143 run_cmd("git --no-pager diff --stat HEAD %s/%s" %
1144 (rebase_remote
, rebase_branch
),
1145 show
=True, dir=test_master
)
1148 def push_to(push_url
, push_branch
="master"):
1149 push_remote
= "pushto"
1150 do_print("Pushing to %s" % push_url
)
1152 run_cmd("git config --replace-all core.editor script/commit_mark.sh", dir=test_master
)
1153 run_cmd("git commit --amend -c HEAD", dir=test_master
)
1154 # the notes method doesn't work yet, as metze hasn't allowed refs/notes/* in master
1155 # run_cmd("EDITOR=script/commit_mark.sh git notes edit HEAD", dir=test_master)
1156 run_cmd("git remote add -t %s %s %s" %
1157 (push_branch
, push_remote
, push_url
),
1158 show
=True, dir=test_master
)
1159 run_cmd("git push %s +HEAD:%s" %
1160 (push_remote
, push_branch
),
1161 show
=True, dir=test_master
)
1164 def send_email(subject
, text
, log_tar
):
1165 if options
.email
is None:
1166 do_print("not sending email because the recipient is not set")
1167 do_print("the text content would have been:\n\nSubject: %s\n\n%s" %
1170 outer
= MIMEMultipart()
1171 outer
['Subject'] = subject
1172 outer
['To'] = options
.email
1173 outer
['From'] = options
.email_from
1174 outer
['Date'] = email
.utils
.formatdate(localtime
=True)
1175 outer
.preamble
= 'Autobuild mails are now in MIME because we optionally attach the logs.\n'
1176 outer
.attach(MIMEText(text
, 'plain'))
1177 if options
.attach_logs
:
1178 with
open(log_tar
, 'rb') as fp
:
1179 msg
= MIMEApplication(fp
.read(), 'gzip', email
.encoders
.encode_base64
)
1180 # Set the filename parameter
1181 msg
.add_header('Content-Disposition', 'attachment', filename
=os
.path
.basename(log_tar
))
1183 content
= outer
.as_string()
1184 s
= smtplib
.SMTP(options
.email_server
)
1185 email_user
= os
.getenv('SMTP_USERNAME')
1186 email_password
= os
.getenv('SMTP_PASSWORD')
1187 if email_user
is not None:
1189 s
.login(email_user
, email_password
)
1191 s
.sendmail(options
.email_from
, [options
.email
], content
)
1196 def email_failure(status
, failed_task
, failed_stage
, failed_tag
, errstr
,
1197 elapsed_time
, log_base
=None, add_log_tail
=True):
1198 '''send an email to options.email about the failure'''
1199 elapsed_minutes
= elapsed_time
/ 60.0
1200 if log_base
is None:
1205 Your autobuild on %s failed after %.1f minutes
1206 when trying to test %s with the following error:
1210 the autobuild has been abandoned. Please fix the error and resubmit.
1212 A summary of the autobuild process is here:
1215 ''' % (platform
.node(), elapsed_minutes
, failed_task
, errstr
, log_base
)
1217 if options
.restrict_tests
:
1219 The build was restricted to tests matching %s\n""" % options
.restrict_tests
1221 if failed_task
!= 'rebase':
1223 You can see logs of the failed task here:
1228 or you can get full logs of all tasks in this job here:
1232 The top commit for the tree that was built was:
1236 ''' % (log_base
, failed_tag
, log_base
, failed_tag
, log_base
, top_commit_msg
)
1239 f
= open("%s/%s.stdout" % (gitroot
, failed_tag
), 'r')
1240 lines
= f
.readlines()
1241 log_tail
= "".join(lines
[-50:])
1242 num_lines
= len(lines
)
1244 # Also include stderr (compile failures) if < 50 lines of stdout
1245 f
= open("%s/%s.stderr" % (gitroot
, failed_tag
), 'r')
1246 log_tail
+= "".join(f
.readlines()[-(50 - num_lines
):])
1249 The last 50 lines of log messages:
1255 logs
= os
.path
.join(gitroot
, 'logs.tar.gz')
1256 send_email('autobuild[%s] failure on %s for task %s during %s'
1257 % (options
.branch
, platform
.node(), failed_task
, failed_stage
),
1261 def email_success(elapsed_time
, log_base
=None):
1262 '''send an email to options.email about a successful build'''
1263 if log_base
is None:
1268 Your autobuild on %s has succeeded after %.1f minutes.
1270 ''' % (platform
.node(), elapsed_time
/ 60.)
1272 if options
.restrict_tests
:
1274 The build was restricted to tests matching %s\n""" % options
.restrict_tests
1276 if options
.keeplogs
:
1279 you can get full logs of all tasks in this job here:
1286 The top commit for the tree that was built was:
1289 ''' % top_commit_msg
1291 logs
= os
.path
.join(gitroot
, 'logs.tar.gz')
1292 send_email('autobuild[%s] success on %s' % (options
.branch
, platform
.node()),
1296 # get the top commit message, for emails
1297 top_commit_msg
= run_cmd("git log -1", dir=gitroot
, output
=True)
1300 os
.makedirs(testbase
)
1301 except Exception as reason
:
1302 raise Exception("Unable to create %s : %s" % (testbase
, reason
))
1303 cleanup_list
.append(testbase
)
1306 logfile
= os
.path
.join(testbase
, "log")
1307 do_print("Forking into the background, writing progress to %s" % logfile
)
1310 write_pidfile(gitroot
+ "/autobuild.pid")
1312 start_time
= time
.time()
1316 run_cmd("rm -rf %s" % test_tmpdir
, show
=True)
1317 os
.makedirs(test_tmpdir
)
1318 # The waf uninstall code removes empty directories all the way
1319 # up the tree. Creating a file in test_tmpdir stops it from
1321 run_cmd("touch %s" % os
.path
.join(test_tmpdir
,
1322 ".directory-is-not-empty"), show
=True)
1323 run_cmd("stat %s" % test_tmpdir
, show
=True)
1324 run_cmd("stat %s" % testbase
, show
=True)
1325 run_cmd("git clone --recursive --shared %s %s" % (gitroot
, test_master
), show
=True, dir=gitroot
)
1331 if options
.rebase
is not None:
1332 rebase_tree(options
.rebase
, rebase_branch
=options
.branch
)
1334 cleanup_list
.append(gitroot
+ "/autobuild.pid")
1336 elapsed_time
= time
.time() - start_time
1337 email_failure(-1, 'rebase', 'rebase', 'rebase',
1338 'rebase on %s failed' % options
.branch
,
1339 elapsed_time
, log_base
=options
.log_base
)
1343 blist
= buildlist(args
, options
.rebase
, rebase_branch
=options
.branch
)
1346 (status
, failed_task
, failed_stage
, failed_tag
, errstr
) = blist
.run()
1347 if status
!= 0 or errstr
!= "retry":
1349 cleanup(do_raise
=True)
1354 cleanup_list
.append(gitroot
+ "/autobuild.pid")
1360 do_print("waiting for tail to flush")
1363 elapsed_time
= time
.time() - start_time
1365 if options
.passcmd
is not None:
1366 do_print("Running passcmd: %s" % options
.passcmd
)
1367 run_cmd(options
.passcmd
, dir=test_master
)
1368 if options
.pushto
is not None:
1369 push_to(options
.pushto
, push_branch
=options
.branch
)
1370 if options
.keeplogs
or options
.attach_logs
:
1371 blist
.tarlogs("logs.tar.gz")
1372 do_print("Logs in logs.tar.gz")
1373 if options
.always_email
:
1374 email_success(elapsed_time
, log_base
=options
.log_base
)
1380 # something failed, gather a tar of the logs
1381 blist
.tarlogs("logs.tar.gz")
1383 if options
.email
is not None:
1384 email_failure(status
, failed_task
, failed_stage
, failed_tag
, errstr
,
1385 elapsed_time
, log_base
=options
.log_base
)
1387 elapsed_minutes
= elapsed_time
/ 60.0
1390 ####################################################################
1394 Your autobuild[%s] on %s failed after %.1f minutes
1395 when trying to test %s with the following error:
1399 the autobuild has been abandoned. Please fix the error and resubmit.
1401 ####################################################################
1403 ''' % (options
.branch
, platform
.node(), elapsed_minutes
, failed_task
, errstr
))
1407 do_print("Logs in logs.tar.gz")