smbd: move notify_fname() out of rmdir_internals() up to close_directory()
[samba4-gss.git] / bootstrap / config.py
blob8b2672f9dddb7d49cf7eda31aefa90fa2de3b3bf
1 #!/usr/bin/env python3
3 # Copyright (C) Catalyst.Net Ltd 2019
5 # This program is free software; you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License as published by
7 # the Free Software Foundation; either version 3 of the License, or
8 # (at your option) any later version.
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
15 # You should have received a copy of the GNU General Public License
16 # along with this program. If not, see <http://www.gnu.org/licenses/>.
18 """
19 Manage dependencies and bootstrap environments for Samba.
21 Config file for packages and templates.
23 Update the lists in this file to require new packages in the
24 container images used in GitLab CI
26 Author: Joe Guo <joeg@catalyst.net.nz>
27 """
28 import os
29 from os.path import abspath, dirname, join
30 HERE = abspath(dirname(__file__))
31 # output dir for rendered files
32 OUT = join(HERE, 'generated-dists')
35 # pkgs with same name in all packaging systems
36 COMMON = [
37 'acl',
38 'attr',
39 'autoconf',
40 'binutils',
41 'bison',
42 'ccache',
43 'curl',
44 'chrpath',
45 'codespell',
46 'flex',
47 'gcc',
48 'gdb',
49 'git',
50 'gzip',
51 'hostname',
52 'htop',
53 'jq',
54 'lcov',
55 'make',
56 'patch',
57 'perl',
58 'psmisc', # for pstree in test
59 'rng-tools',
60 'rsync',
61 'sed',
62 'shfmt',
63 'sudo', # docker images has no sudo by default
64 'tar',
65 'tree',
66 'wget',
67 'cargo',
71 # define pkgs for all packaging systems in parallel
72 # make it easier to find missing ones
73 # use latest ubuntu and fedora as defaults
74 # deb, rpm, ...
75 PKGS = [
76 # NAME1-dev, NAME2-devel
77 ('lmdb-utils', 'lmdb'),
78 ('mingw-w64', 'mingw64-gcc'),
79 ('zlib1g-dev', 'zlib-devel'),
80 ('libbsd-dev', 'libbsd-devel'),
81 ('liburing-dev', 'liburing-devel'),
82 ('libarchive-dev', 'libarchive-devel'),
83 ('libblkid-dev', 'libblkid-devel'),
84 ('libcap-dev', 'libcap-devel'),
85 ('libacl1-dev', 'libacl-devel'),
86 ('libattr1-dev', 'libattr-devel'),
87 ('libutf8proc-dev', 'utf8proc-devel'),
88 ('libssl-dev', 'openssl-devel'),
89 ('libclang-dev', 'clang-devel'),
91 # libNAME1-dev, NAME2-devel
92 ('libpopt-dev', 'popt-devel'),
93 ('libreadline-dev', 'readline-devel'),
94 ('libjansson-dev', 'jansson-devel'),
95 ('liblmdb-dev', 'lmdb-devel'),
96 ('libncurses5-dev', 'ncurses-devel'),
97 # NOTE: Debian 7+ or Ubuntu 16.04+
98 ('libsystemd-dev', 'systemd-devel'),
99 ('libkrb5-dev', 'krb5-devel'),
100 ('libldap2-dev', 'openldap-devel'),
101 ('libcups2-dev', 'cups-devel'),
102 ('libpam0g-dev', 'pam-devel'),
103 ('libgpgme11-dev', 'gpgme-devel'),
104 # NOTE: Debian 8+ and Ubuntu 14.04+
105 ('libgnutls28-dev', 'gnutls-devel'),
106 ('gnutls-bin', 'gnutls-utils'),
107 ('libtasn1-bin', 'libtasn1-tools'),
108 ('libtasn1-dev', 'libtasn1-devel'),
109 ('', 'quota-devel'),
110 ('uuid-dev', 'libuuid-devel'),
111 ('libjs-jquery', ''),
112 ('libavahi-common-dev', 'avahi-devel'),
113 ('libdbus-1-dev', 'dbus-devel'),
114 ('libpcap-dev', 'libpcap-devel'),
115 ('libunwind-dev', 'libunwind-devel'), # for back trace
116 ('libglib2.0-dev', 'glib2-devel'),
117 ('libicu-dev', 'libicu-devel'),
118 ('heimdal-multidev', ''),
120 # NAME1, NAME2
121 # for debian, locales provide locale support with language packs
122 # ubuntu split language packs to language-pack-xx
123 # for centos, glibc-common provide locale support with language packs
124 # fedora split language packs to glibc-langpack-xx
125 ('locales', 'glibc-common'), # required for locale
126 ('language-pack-en', 'glibc-langpack-en'), # we need en_US.UTF-8
127 ('bind9utils', 'bind-utils'),
128 ('dnsutils', ''),
129 ('xsltproc', 'libxslt'),
130 ('krb5-user', 'krb5-workstation'),
131 ('krb5-config', ''),
132 ('krb5-kdc', 'krb5-server'),
133 ('apt-utils', 'yum-utils'),
134 ('pkg-config', 'pkgconfig'),
135 ('procps', 'procps-ng'), # required for the free cmd in tests
136 ('lsb-release', 'lsb-release'), # we need lsb_release to show info
137 ('', 'rpcgen'), # required for test
138 # refer: https://fedoraproject.org/wiki/Changes/SunRPCRemoval
139 ('', 'libtirpc-devel'), # for <rpc/rpc.h> header on fedora
140 ('', 'rpcsvc-proto-devel'), # for <rpcsvc/rquota.h> header
141 ('mawk', 'gawk'),
142 ('', 'mold'),
143 ('shellcheck', 'ShellCheck'),
144 ('', 'crypto-policies-scripts'),
146 ('python3', 'python3'),
147 ('python3-cryptography', 'python3-cryptography'), # for krb5 tests
148 ('python3-dev', 'python3-devel'),
149 ('python3-dbg', ''),
150 ('python3-iso8601', 'python3-iso8601'),
151 ('python3-gpg', 'python3-gpg'), # defaults to ubuntu/fedora latest
152 ('python3-markdown', 'python3-markdown'),
153 ('python3-dnspython', 'python3-dns'),
154 ('python3-pexpect', ''), # for wintest only
155 ('python3-pyasn1', 'python3-pyasn1'), # for krb5 tests
156 ('python3-setproctitle', 'python3-setproctitle'),
157 ('python3-requests', 'python3-requests'), # for cert auto enroll
159 ('', 'python3-libsemanage'),
160 ('', 'python3-policycoreutils'),
162 # perl
163 ('libparse-yapp-perl', 'perl-Parse-Yapp'),
164 ('perl-modules', ''),
165 ('', 'perl-FindBin'),
166 ('', 'perl-Archive-Tar'),
167 ('', 'perl-ExtUtils-MakeMaker'),
168 ('', 'perl-Test-Base'),
169 ('', 'perl-generators'),
170 ('', 'perl-interpreter'),
172 # fs
173 ('xfslibs-dev', 'xfsprogs-devel'), # for xfs quota support
174 ('', 'glusterfs-api-devel'),
175 ('glusterfs-common', 'glusterfs-devel'),
176 ('libcephfs-dev', 'libcephfs-devel'),
178 # spotlight
179 ('libtracker-sparql-2.0-dev', 'tracker-devel'),
181 # misc
182 # @ means group for rpm, use fedora as rpm default
183 ('build-essential', '@development-tools'),
184 ('debhelper', ''),
185 # rpm has no pkg for docbook-xml
186 ('docbook-xml', 'docbook-dtds'),
187 ('docbook-xsl', 'docbook-style-xsl'),
188 ('libkeyutils-dev', 'keyutils-libs-devel'),
189 ('', 'which'),
190 ('xz-utils', 'xz')
194 DEB_PKGS = COMMON + [pkg for pkg, _ in PKGS if pkg]
195 RPM_PKGS = COMMON + [pkg for _, pkg in PKGS if pkg]
197 GENERATED_MARKER = r"""
199 # This file is generated by 'bootstrap/template.py --render'
200 # See also bootstrap/config.py
205 APT_BOOTSTRAP = r"""
206 #!/bin/bash
207 {GENERATED_MARKER}
208 set -xueo pipefail
210 export DEBIAN_FRONTEND=noninteractive
211 apt-get -y update
213 apt-get -y install \
214 {pkgs}
216 apt-get -y autoremove
217 apt-get -y autoclean
218 apt-get -y clean
222 YUM_BOOTSTRAP = r"""
223 #!/bin/bash
224 {GENERATED_MARKER}
225 set -xueo pipefail
227 yum update -y
228 yum install -y epel-release
229 yum install -y yum-plugin-copr
230 yum copr enable -y sergiomb/SambaAD
231 yum update -y
233 yum install -y \
234 {pkgs}
236 yum clean all
238 if [ ! -f /usr/bin/python3 ]; then
239 ln -sf /usr/bin/python3.6 /usr/bin/python3
243 ROCKY8_DNF_BOOTSTRAP = r"""
244 #!/bin/bash
245 {GENERATED_MARKER}
246 set -xueo pipefail
248 yum update -y
249 yum install -y dnf-plugins-core
250 yum install -y epel-release
251 yum install -y centos-release-ceph-pacific
253 sed -i 's/mirrorlist/#mirrorlist/g' /etc/yum.repos.d/CentOS-Ceph-*
254 sed -i 's|#baseurl=http://mirror.centos.org|baseurl=http://vault.centos.org|g' /etc/yum.repos.d/CentOS-Ceph-*
255 sed -i 's/$contentdir/centos/g' /etc/yum.repos.d/CentOS-Ceph-*
257 yum -v repolist all
258 yum config-manager --set-enabled powertools -y
260 yum update -y
262 yum install -y \
263 --setopt=install_weak_deps=False \
264 --setopt=centos-ceph-pacific.module_hotfixes=true \
265 {pkgs}
267 yum clean all
270 CENTOS9S_DNF_BOOTSTRAP = r"""
271 #!/bin/bash
272 {GENERATED_MARKER}
273 set -xueo pipefail
275 dnf update -y
276 dnf install -y dnf-plugins-core
277 dnf install -y epel-release
278 dnf install -y centos-release-gluster9
280 dnf -v repolist all
281 dnf config-manager --set-enabled crb -y
283 dnf update -y
285 dnf install -y \
286 --setopt=install_weak_deps=False \
287 {pkgs}
289 dnf clean all
292 DNF_BOOTSTRAP = r"""
293 #!/bin/bash
294 {GENERATED_MARKER}
295 set -xueo pipefail
297 dnf update -y
299 dnf install -y \
300 --setopt=install_weak_deps=False \
301 {pkgs}
303 dnf clean all
305 update-crypto-policies --set DEFAULT:AD-SUPPORT
308 DNF_BOOTSTRAP_MIT = r"""
309 #!/bin/bash
310 {GENERATED_MARKER}
311 set -xueo pipefail
313 dnf update -y
314 dnf install -y dnf-plugins-core
315 dnf copr -y enable abbra/krb5-test
316 dnf update -y
318 dnf install -y \
319 --setopt=install_weak_deps=False \
320 {pkgs}
322 dnf clean all
325 ZYPPER_BOOTSTRAP = r"""
326 #!/bin/bash
327 {GENERATED_MARKER}
328 set -xueo pipefail
330 zypper --non-interactive refresh
331 zypper --non-interactive update
332 zypper --non-interactive install \
333 --no-recommends \
334 system-user-nobody \
335 {pkgs}
337 zypper --non-interactive clean
339 if [ -f /usr/lib/mit/bin/krb5-config ]; then
340 ln -sf /usr/lib/mit/bin/krb5-config /usr/bin/krb5-config
344 # A generic shell script to setup locale
345 LOCALE_SETUP = r"""
346 #!/bin/bash
347 {GENERATED_MARKER}
348 set -xueo pipefail
350 # refer to /usr/share/i18n/locales
351 INPUTFILE=en_US
352 # refer to /usr/share/i18n/charmaps
353 CHARMAP=UTF-8
354 # locale to generate in /usr/lib/locale
355 # glibc/localedef will normalize UTF-8 to utf8, follow the naming style
356 LOCALE=$INPUTFILE.utf8
358 # if locale is already correct, exit
359 ( locale | grep LC_ALL | grep -i $LOCALE ) && exit 0
361 # if locale not available, generate locale into /usr/lib/locale
362 if ! ( locale --all-locales | grep -i $LOCALE )
363 then
364 # no-archive means create its own dir
365 localedef --inputfile $INPUTFILE --charmap $CHARMAP --no-archive $LOCALE
368 # update locale conf and global env file
369 # set both LC_ALL and LANG for safe
371 # update conf for Debian family
372 FILE=/etc/default/locale
373 if [ -f $FILE ]
374 then
375 echo LC_ALL="$LOCALE" > $FILE
376 echo LANG="$LOCALE" >> $FILE
379 # update conf for RedHat family
380 FILE=/etc/locale.conf
381 if [ -f $FILE ]
382 then
383 # LC_ALL is not valid in this file, set LANG only
384 echo LANG="$LOCALE" > $FILE
387 # update global env file
388 FILE=/etc/environment
389 if [ -f $FILE ]
390 then
391 # append LC_ALL if not exist
392 grep LC_ALL $FILE || echo LC_ALL="$LOCALE" >> $FILE
393 # append LANG if not exist
394 grep LANG $FILE || echo LANG="$LOCALE" >> $FILE
399 DOCKERFILE = r"""
400 {GENERATED_MARKER}
401 FROM {docker_image}
403 # pass in with --build-arg while build
404 ARG SHA1SUM
405 RUN [ -n $SHA1SUM ] && echo $SHA1SUM > /sha1sum.txt
407 ADD *.sh /tmp/
408 # need root permission, do it before USER samba
409 RUN /tmp/bootstrap.sh && /tmp/locale.sh
411 # if ld.gold exists, force link it to ld
412 RUN set -x; ! LD_GOLD=$(which ld.gold) || {{ LD=$(which ld) && ln -sf $LD_GOLD $LD && test -x $LD && echo "$LD is now $LD_GOLD"; }}
413 # if ld.mold exists, force link it to ld (prefer mold over gold! ;-)
414 RUN set -x; ! LD_MOLD=$(which ld.mold) || {{ LD=$(which ld) && ln -sf $LD_MOLD $LD && test -x $LD && echo "$LD is now $LD_MOLD"; }}
416 # make test can not work with root, so we have to create a new user
417 RUN useradd -m -U -s /bin/bash samba && \
418 mkdir -p /etc/sudoers.d && \
419 echo "samba ALL=(ALL) NOPASSWD:ALL" > /etc/sudoers.d/samba
421 USER samba
422 WORKDIR /home/samba
423 # samba tests rely on this
424 ENV USER=samba LC_ALL=en_US.utf8 LANG=en_US.utf8 LANGUAGE=en_US
427 # Vagrantfile snippet for each dist
428 VAGRANTFILE_SNIPPET = r"""
429 config.vm.define "{name}" do |v|
430 v.vm.box = "{vagrant_box}"
431 v.vm.hostname = "{name}"
432 v.vm.provision :shell, path: "{name}/bootstrap.sh"
433 v.vm.provision :shell, path: "{name}/locale.sh"
437 # global Vagrantfile with snippets for all dists
438 VAGRANTFILE_GLOBAL = r"""
439 {GENERATED_MARKER}
441 Vagrant.configure("2") do |config|
442 config.ssh.insert_key = false
444 {vagrantfile_snippets}
449 DEB_DISTS = {
450 'debian11': {
451 'docker_image': 'debian:11',
452 'vagrant_box': 'debian/bullseye64',
453 'replace': {
454 'language-pack-en': '', # included in locales
455 'shfmt': '',
456 'cargo': '', # included cargo is broken
459 'debian11-32bit': {
460 'docker_image': 'registry-1.docker.io/i386/debian:11',
461 'vagrant_box': 'debian/bullseye32',
462 'replace': {
463 'language-pack-en': '', # included in locales
464 'shfmt': '',
465 'cargo': '', # included cargo is broken
468 'debian12': {
469 'docker_image': 'debian:12',
470 'vagrant_box': 'debian/bookworm64',
471 'replace': {
472 'language-pack-en': '', # included in locales
473 'libtracker-sparql-2.0-dev': '', # only tracker 3.x is available
474 'cargo': '', # included cargo is broken
477 'debian12-32bit': {
478 'docker_image': 'registry-1.docker.io/i386/debian:12',
479 'vagrant_box': 'debian/bookworm32',
480 'replace': {
481 'language-pack-en': '', # included in locales
482 'libtracker-sparql-2.0-dev': '', # only tracker 3.x is available
483 'cargo': '', # included cargo is broken
486 'ubuntu1804': {
487 'docker_image': 'ubuntu:18.04',
488 'vagrant_box': 'ubuntu/bionic64',
489 'replace': {
490 'liburing-dev': '', # not available
491 'shfmt': '',
494 'ubuntu1804-32bit': {
495 'docker_image': 'registry-1.docker.io/i386/ubuntu:18.04',
496 'vagrant_box': 'ubuntu/bionic32',
497 'replace': {
498 'liburing-dev': '', # not available
499 'shfmt': '',
502 'ubuntu2004': {
503 'docker_image': 'ubuntu:20.04',
504 'vagrant_box': 'ubuntu/focal64',
505 'replace': {
506 'liburing-dev': '', # not available
507 'shfmt': '',
510 'ubuntu2204': {
511 'docker_image': 'ubuntu:22.04',
512 'vagrant_box': 'ubuntu/jammy64',
513 'replace': {
514 'libtracker-sparql-2.0-dev': '', # only tracker 3.x is available
520 RPM_DISTS = {
521 'rocky8': {
522 'docker_image': 'docker.io/library/rockylinux:8',
523 'vagrant_box': 'rocky/8',
524 'bootstrap': ROCKY8_DNF_BOOTSTRAP,
525 'replace': {
526 'lsb-release': 'redhat-lsb',
527 '@development-tools': '"@Development Tools"', # add quotes
528 'lcov': '', # does not exist
529 'perl-JSON-Parse': '', # does not exist?
530 'perl-Test-Base': 'perl-Test-Simple',
531 'perl-FindBin': '',
532 'liburing-devel': '', # not available yet, Add me back, once available!
533 'mold': '',
534 'ShellCheck': '',
535 'shfmt': '',
536 'codespell': '',
539 'centos9s': {
540 'docker_image': 'quay.io/centos/centos:stream9',
541 'vagrant_box': 'centos/stream9',
542 'bootstrap': CENTOS9S_DNF_BOOTSTRAP,
543 'replace': {
544 'lsb-release': 'lsb_release',
545 '@development-tools': '"@Development Tools"', # add quotes
546 'lcov': '', # does not exist
547 'perl-JSON-Parse': '', # does not exist?
548 'perl-Test-Base': 'perl-Test-Simple',
549 'perl-FindBin': '',
550 'mold': '',
551 'ShellCheck': '',
552 'shfmt': '',
553 'codespell': '',
554 'libcephfs-devel': '', # not available anymore
555 'curl': '', # Use installed curl-minimal
558 'fedora40': {
559 'docker_image': 'quay.io/fedora/fedora:40',
560 'vagrant_box': 'fedora/40-cloud-base',
561 'bootstrap': DNF_BOOTSTRAP,
562 'replace': {
563 'lsb-release': 'redhat-lsb',
564 'perl-FindBin': '',
565 'python3-iso8601': 'python3-dateutil',
566 'libtracker-sparql-2.0-dev': '', # only tracker 3.x is available
569 'opensuse155': {
570 'docker_image': 'opensuse/leap:15.5',
571 'vagrant_box': 'opensuse/openSUSE-15.5-x86_64',
572 'bootstrap': ZYPPER_BOOTSTRAP,
573 'replace': {
574 '@development-tools': '',
575 'dbus-devel': 'dbus-1-devel',
576 'docbook-style-xsl': 'docbook-xsl-stylesheets',
577 'glibc-common': 'glibc-locale',
578 'glibc-locale-source': 'glibc-i18ndata',
579 'glibc-langpack-en': '',
580 'jansson-devel': 'libjansson-devel',
581 'keyutils-libs-devel': 'keyutils-devel',
582 'krb5-workstation': 'krb5-client',
583 'python3-libsemanage': 'python3-semanage',
584 'openldap-devel': 'openldap2-devel',
585 'perl-Archive-Tar': 'perl-Archive-Tar-Wrapper',
586 'perl-JSON-Parse': 'perl-JSON-XS',
587 'perl-generators': '',
588 'perl-interpreter': '',
589 'perl-FindBin': '',
590 'procps-ng': 'procps',
591 'python3-iso8601': 'python3-python-dateutil',
592 'python3-dns': 'python3-dnspython',
593 'python3-markdown': 'python3-Markdown',
594 'quota-devel': '',
595 'glusterfs-api-devel': '',
596 'gnutls-utils': 'gnutls',
597 'libtasn1-tools': '', # asn1Parser is part of libtasn1
598 'mold': '',
599 'shfmt': '',
600 'yum-utils': '',
606 DEB_FAMILY = {
607 'name': 'deb',
608 'pkgs': DEB_PKGS,
609 'bootstrap': APT_BOOTSTRAP, # family default
610 'dists': DEB_DISTS,
614 RPM_FAMILY = {
615 'name': 'rpm',
616 'pkgs': RPM_PKGS,
617 'bootstrap': YUM_BOOTSTRAP, # family default
618 'dists': RPM_DISTS,
622 YML_HEADER = r"""
624 packages:
628 def expand_family_dists(family):
629 dists = {}
630 for name, config in family['dists'].items():
631 config = config.copy()
632 config['name'] = name
633 config['home'] = join(OUT, name)
634 config['family'] = family['name']
635 config['GENERATED_MARKER'] = GENERATED_MARKER
637 # replace dist specific pkgs
638 replace = config.get('replace', {})
639 pkgs = []
640 for pkg in family['pkgs']:
641 pkg = replace.get(pkg, pkg) # replace if exists or get self
642 if pkg:
643 pkgs.append(pkg)
644 pkgs.sort()
646 lines = [' - {}'.format(pkg) for pkg in pkgs]
647 config['packages.yml'] = YML_HEADER.lstrip() + os.linesep.join(lines)
649 sep = ' \\' + os.linesep + ' '
650 config['pkgs'] = sep.join(pkgs)
652 # get dist bootstrap template or fall back to family default
653 bootstrap_template = config.get('bootstrap', family['bootstrap'])
654 config['bootstrap.sh'] = bootstrap_template.format(**config).strip()
655 config['locale.sh'] = LOCALE_SETUP.format(**config).strip()
657 config['Dockerfile'] = DOCKERFILE.format(**config).strip()
658 # keep the indent, no strip
659 config['vagrantfile_snippet'] = VAGRANTFILE_SNIPPET.format(**config)
661 dists[name] = config
662 return dists
665 # expanded config for dists
666 DEB_DISTS_EXP = expand_family_dists(DEB_FAMILY)
667 RPM_DISTS_EXP = expand_family_dists(RPM_FAMILY)
669 # assemble all together
670 DISTS = {}
671 DISTS.update(DEB_DISTS_EXP)
672 DISTS.update(RPM_DISTS_EXP)
675 def render_vagrantfile(dists):
677 Render all snippets for each dist into global Vagrantfile.
679 Vagrant supports multiple vms in one Vagrantfile.
680 This make it easier to manage the fleet, e.g:
682 start all: vagrant up
683 start one: vagrant up ubuntu1804
685 All other commands apply to above syntax, e.g.: status, destroy, provision
687 # sort dists by name and put all vagrantfile snippets together
688 snippets = [
689 dists[dist]['vagrantfile_snippet']
690 for dist in sorted(dists.keys())]
692 return VAGRANTFILE_GLOBAL.format(
693 vagrantfile_snippets=''.join(snippets),
694 GENERATED_MARKER=GENERATED_MARKER
698 VAGRANTFILE = render_vagrantfile(DISTS)
701 # data we need to expose
702 __all__ = ['DISTS', 'VAGRANTFILE', 'OUT']