librpc/rpc: add dcerpc_binding_handle_call_params*
[metze/samba/wip.git] / bootstrap / config.py
1 #!/usr/bin/env python3
2
3 # Copyright (C) Catalyst.Net Ltd 2019
4 #
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.
9 #
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.
14 #
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/>.
17
18 """
19 Manage dependencies and bootstrap environments for Samba.
20
21 Config file for packages and templates.
22
23 Author: Joe Guo <joeg@catalyst.net.nz>
24 """
25 import os
26 from os.path import abspath, dirname, join
27 HERE = abspath(dirname(__file__))
28 # output dir for rendered files
29 OUT = join(HERE, 'generated-dists')
30
31
32 # pkgs with same name in all packaging systems
33 COMMON = [
34     'acl',
35     'attr',
36     'autoconf',
37     'binutils',
38     'bison',
39     'curl',
40     'flex',
41     'gcc',
42     'gdb',
43     'git',
44     'gzip',
45     'hostname',
46     'htop',
47     'lcov',
48     'make',
49     'patch',
50     'perl',
51     'psmisc',  # for pstree in test
52     'rng-tools',
53     'rsync',
54     'sed',
55     'sudo',  # docker images has no sudo by default
56     'tar',
57     'tree',
58 ]
59
60
61 # define pkgs for all packaging systems in parallel
62 # make it easier to find missing ones
63 # use latest ubuntu and fedora as defaults
64 # deb, rpm, ...
65 PKGS = [
66     # NAME1-dev, NAME2-devel
67     ('lmdb-utils', 'lmdb'),
68     ('mingw-w64', 'mingw64-gcc'),
69     ('nettle-dev', 'nettle-devel'),
70     ('zlib1g-dev', 'zlib-devel'),
71     ('libbsd-dev', 'libbsd-devel'),
72     ('libaio-dev', 'libaio-devel'),
73     ('libarchive-dev', 'libarchive-devel'),
74     ('libblkid-dev', 'libblkid-devel'),
75     ('libcap-dev', 'libcap-devel'),
76     ('libacl1-dev', 'libacl-devel'),
77     ('libattr1-dev', 'libattr-devel'),
78
79     # libNAME1-dev, NAME2-devel
80     ('libpopt-dev', 'popt-devel'),
81     ('libreadline-dev', 'readline-devel'),
82     ('libjansson-dev', 'jansson-devel'),
83     ('liblmdb-dev', 'lmdb-devel'),
84     ('libncurses5-dev', 'ncurses-devel'),
85     # NOTE: Debian 7+ or Ubuntu 16.04+
86     ('libsystemd-dev', 'systemd-devel'),
87     ('libkrb5-dev', 'krb5-devel'),
88     ('libldap2-dev', 'openldap-devel'),
89     ('libcups2-dev', 'cups-devel'),
90     ('libpam0g-dev', 'pam-devel'),
91     ('libgpgme11-dev', 'gpgme-devel'),
92     # NOTE: Debian 8+ and Ubuntu 14.04+
93     ('libgnutls28-dev', 'gnutls-devel'),
94     ('libtasn1-bin', 'libtasn1-tools'),
95     ('libtasn1-dev', 'libtasn1-devel'),
96     ('', 'quota-devel'),
97     ('uuid-dev', 'libuuid-devel'),
98     ('libjs-jquery', ''),
99     ('libavahi-common-dev', 'avahi-devel'),
100     ('libdbus-1-dev', 'dbus-devel'),
101     ('libpcap-dev', 'libpcap-devel'),
102     ('libunwind-dev', 'libunwind-devel'),  # for back trace
103     ('libglib2.0-dev', 'glib2-devel'),
104     ('libicu-dev', 'libicu-devel'),
105
106     # NAME1, NAME2
107     # for debian, locales provide locale support with language packs
108     # ubuntu split language packs to language-pack-xx
109     # for centos, glibc-common provide locale support with language packs
110     # fedora split language packs  to glibc-langpack-xx
111     ('locales', 'glibc-common'),  # required for locale
112     ('language-pack-en', 'glibc-langpack-en'),  # we need en_US.UTF-8
113     ('bind9utils', 'bind-utils'),
114     ('dnsutils', ''),
115     ('xsltproc', 'libxslt'),
116     ('krb5-user', ''),
117     ('krb5-config', ''),
118     ('krb5-kdc', 'krb5-server'),
119     ('apt-utils', 'yum-utils'),
120     ('pkg-config', 'pkgconfig'),
121     ('procps', 'procps-ng'),  # required for the free cmd in tests
122     ('lsb-release', 'lsb-release'),  # we need lsb_relase to show info
123     ('', 'rpcgen'),  # required for test
124     # refer: https://fedoraproject.org/wiki/Changes/SunRPCRemoval
125     ('', 'libtirpc-devel'),  # for <rpc/rpc.h> header on fedora
126     ('', 'libnsl2-devel'),  # for <rpcsvc/yp_prot.h> header on fedora
127     ('', 'rpcsvc-proto-devel'), # for <rpcsvc/rquota.h> header
128     ('mawk', 'gawk'),
129
130     # python
131     ('python-dev', 'python-devel'),
132     ('python-dbg', ''),
133     ('python-iso8601', ''),
134     ('python-gpg', 'python2-gpg'),  # defaults to ubuntu/fedora latest
135     ('python-crypto', 'python-crypto'),
136     ('python-markdown', 'python-markdown'),
137     ('python-dnspython', 'python-dns'),
138     ('python-pexpect', ''),  # for wintest only
139
140     ('python3', 'python3'),
141     ('python3-dev', 'python3-devel'),
142     ('python3-dbg', ''),
143     ('python3-iso8601', ''),
144     ('python3-gpg', 'python3-gpg'),  # defaults to ubuntu/fedora latest
145     ('python3-crypto', 'python3-crypto'),
146     ('python3-markdown', 'python3-markdown'),
147     ('python3-matplotlib', ''),
148     ('python3-dnspython', 'python3-dns'),
149     ('python3-pexpect', ''),  # for wintest only
150
151     ('', 'libsemanage-python'),
152     ('', 'policycoreutils-python'),
153
154     # perl
155     ('libparse-yapp-perl', 'perl-Parse-Yapp'),
156     ('libjson-perl', 'perl-JSON-Parse'),
157     ('perl-modules', ''),
158     ('', 'perl-Archive-Tar'),
159     ('', 'perl-ExtUtils-MakeMaker'),
160     ('', 'perl-Test-Base'),
161     ('', 'perl-generators'),
162     ('', 'perl-interpreter'),
163
164     # fs
165     ('xfslibs-dev', 'xfsprogs-devel'), # for xfs quota support
166     ('', 'glusterfs-api-devel'),
167     ('glusterfs-common', 'glusterfs-devel'),
168     ('libcephfs-dev', 'libcephfs-devel'),
169
170     # misc
171     # @ means group for rpm, use fedora as rpm default
172     ('build-essential', '@development-tools'),
173     ('debhelper', ''),
174     # rpm has no pkg for docbook-xml
175     ('docbook-xml', 'docbook-dtds'),
176     ('docbook-xsl', 'docbook-style-xsl'),
177     ('', 'keyutils-libs-devel'),
178     ('', 'which'),
179 ]
180
181
182 DEB_PKGS = COMMON + [pkg for pkg, _ in PKGS if pkg]
183 RPM_PKGS = COMMON + [pkg for _, pkg in PKGS if pkg]
184
185 GENERATED_MARKER = r"""
186 #
187 # This file is generated by 'bootstrap/template.py --render'
188 # See also bootstrap/config.py
189 #
190 """
191
192
193 APT_BOOTSTRAP = r"""
194 #!/bin/bash
195 {GENERATED_MARKER}
196 set -xueo pipefail
197
198 export DEBIAN_FRONTEND=noninteractive
199 apt-get -y update
200
201 apt-get -y install \
202     {pkgs}
203
204 apt-get -y autoremove
205 apt-get -y autoclean
206 apt-get -y clean
207 """
208
209
210 YUM_BOOTSTRAP = r"""
211 #!/bin/bash
212 {GENERATED_MARKER}
213 set -xueo pipefail
214
215 yum update -y
216 yum install -y epel-release
217 yum update -y
218
219 yum install -y \
220     {pkgs}
221
222 yum clean all
223
224 if [ ! -f /usr/bin/python3 ]; then
225     ln -sf /usr/bin/python3.6 /usr/bin/python3
226 fi
227 """
228
229
230 DNF_BOOTSTRAP = r"""
231 #!/bin/bash
232 {GENERATED_MARKER}
233 set -xueo pipefail
234
235 dnf update -y
236
237 dnf install -y \
238     --setopt=install_weak_deps=False \
239     {pkgs}
240
241 dnf clean all
242 """
243
244 ZYPPER_BOOTSTRAP = r"""
245 #!/bin/bash
246 {GENERATED_MARKER}
247 set -xueo pipefail
248
249 zypper --non-interactive refresh
250 zypper --non-interactive update
251 zypper --non-interactive install \
252     --no-recommends \
253     system-user-nobody \
254     {pkgs}
255
256 zypper --non-interactive clean
257
258 if [ -f /usr/lib/mit/bin/krb5-config ]; then
259     ln -sf /usr/lib/mit/bin/krb5-config /usr/bin/krb5-config
260 fi
261 """
262
263 # A generic shell script to setup locale
264 LOCALE_SETUP = r"""
265 #!/bin/bash
266 {GENERATED_MARKER}
267 set -xueo pipefail
268
269 # refer to /usr/share/i18n/locales
270 INPUTFILE=en_US
271 # refer to /usr/share/i18n/charmaps
272 CHARMAP=UTF-8
273 # locale to generate in /usr/lib/locale
274 # glibc/localedef will normalize UTF-8 to utf8, follow the naming style
275 LOCALE=$INPUTFILE.utf8
276
277 # if locale is already correct, exit
278 ( locale | grep LC_ALL | grep -i $LOCALE ) && exit 0
279
280 # if locale not available, generate locale into /usr/lib/locale
281 if ! ( locale --all-locales | grep -i $LOCALE )
282 then
283     # no-archive means create its own dir
284     localedef --inputfile $INPUTFILE --charmap $CHARMAP --no-archive $LOCALE
285 fi
286
287 # update locale conf and global env file
288 # set both LC_ALL and LANG for safe
289
290 # update conf for Debian family
291 FILE=/etc/default/locale
292 if [ -f $FILE ]
293 then
294     echo LC_ALL="$LOCALE" > $FILE
295     echo LANG="$LOCALE" >> $FILE
296 fi
297
298 # update conf for RedHat family
299 FILE=/etc/locale.conf
300 if [ -f $FILE ]
301 then
302     # LC_ALL is not valid in this file, set LANG only
303     echo LANG="$LOCALE" > $FILE
304 fi
305
306 # update global env file
307 FILE=/etc/environment
308 if [ -f $FILE ]
309 then
310     # append LC_ALL if not exist
311     grep LC_ALL $FILE || echo LC_ALL="$LOCALE" >> $FILE
312     # append LANG if not exist
313     grep LANG $FILE || echo LANG="$LOCALE" >> $FILE
314 fi
315 """
316
317
318 DOCKERFILE = r"""
319 {GENERATED_MARKER}
320 FROM {docker_image}
321
322 # pass in with --build-arg while build
323 ARG SHA1SUM
324 RUN [ -n $SHA1SUM ] && echo $SHA1SUM > /sha1sum.txt
325
326 ADD *.sh /tmp/
327 # need root permission, do it before USER samba
328 RUN /tmp/bootstrap.sh && /tmp/locale.sh
329
330 # if ld.gold exists, force link it to ld
331 RUN set -x; LD=$(which ld); LD_GOLD=$(which ld.gold); test -x $LD_GOLD && ln -sf $LD_GOLD $LD && test -x $LD && echo "$LD is now $LD_GOLD"
332
333 # make test can not work with root, so we have to create a new user
334 RUN useradd -m -U -s /bin/bash samba && \
335     mkdir -p /etc/sudoers.d && \
336     echo "samba ALL=(ALL) NOPASSWD:ALL" > /etc/sudoers.d/samba
337
338 USER samba
339 WORKDIR /home/samba
340 # samba tests rely on this
341 ENV USER=samba LC_ALL=en_US.utf8 LANG=en_US.utf8
342 """
343
344 # Vagrantfile snippet for each dist
345 VAGRANTFILE_SNIPPET = r"""
346     config.vm.define "{name}" do |v|
347         v.vm.box = "{vagrant_box}"
348         v.vm.hostname = "{name}"
349         v.vm.provision :shell, path: "{name}/bootstrap.sh"
350         v.vm.provision :shell, path: "{name}/locale.sh"
351     end
352 """
353
354 # global Vagrantfile with snippets for all dists
355 VAGRANTFILE_GLOBAL = r"""
356 {GENERATED_MARKER}
357
358 Vagrant.configure("2") do |config|
359     config.ssh.insert_key = false
360
361 {vagrantfile_snippets}
362
363 end
364 """
365
366
367 DEB_DISTS = {
368     'debian7': {
369         'docker_image': 'debian:7',
370         'vagrant_box': 'debian/wheezy64',
371         'replace': {
372             'libgnutls28-dev': 'libgnutls-dev',
373             'libsystemd-dev': '',  # not available, remove
374             'lmdb-utils': '',  # not available, remove
375             'liblmdb-dev': '',  # not available, remove
376             'python-gpg': 'python-gpgme',
377             'python3-gpg': '',  # no python3 gpg pkg available, remove
378             'language-pack-en': '',   # included in locales
379         }
380     },
381     'debian8': {
382         'docker_image': 'debian:8',
383         'vagrant_box': 'debian/jessie64',
384         'replace': {
385             'python-gpg': 'python-gpgme',
386             'python3-gpg': 'python3-gpgme',
387             'language-pack-en': '',   # included in locales
388         }
389     },
390     'debian9': {
391         'docker_image': 'debian:9',
392         'vagrant_box': 'debian/stretch64',
393         'replace': {
394             'language-pack-en': '',   # included in locales
395         }
396     },
397     'ubuntu1404': {
398         'docker_image': 'ubuntu:14.04',
399         'vagrant_box': 'ubuntu/trusty64',
400         'replace': {
401             'libsystemd-dev': '',  # remove
402             'libgnutls28-dev': 'libgnutls-dev',
403             'python-gpg': 'python-gpgme',
404             'python3-gpg': 'python3-gpgme',
405             'lmdb-utils': 'lmdb-utils/trusty-backports',
406             'liblmdb-dev': 'liblmdb-dev/trusty-backports',
407             'libunwind-dev': 'libunwind8-dev',
408             'glusterfs-common': '',
409             'libcephfs-dev': '',
410         }
411     },
412     'ubuntu1604': {
413         'docker_image': 'ubuntu:16.04',
414         'vagrant_box': 'ubuntu/xenial64',
415         'replace': {
416             'python-gpg': 'python-gpgme',
417             'python3-gpg': 'python3-gpgme',
418             'glusterfs-common': '',
419             'libcephfs-dev': '',
420         }
421     },
422     'ubuntu1804': {
423         'docker_image': 'ubuntu:18.04',
424         'vagrant_box': 'ubuntu/bionic64',
425     },
426 }
427
428
429 RPM_DISTS = {
430     'centos6': {
431         'docker_image': 'centos:6',
432         'vagrant_box': 'centos/6',
433         'bootstrap': YUM_BOOTSTRAP,
434         'replace': {
435             'lsb-release': 'redhat-lsb',
436             'python3': 'python36',
437             'python3-devel': 'python36-devel',
438             'python2-gpg': 'pygpgme',
439             'python3-gpg': '',  # no python3-gpg yet
440             '@development-tools': '"@Development Tools"',  # add quotes
441             'glibc-langpack-en': '',  # included in glibc-common
442             'glibc-locale-source': '',  # included in glibc-common
443             'procps-ng': 'procps',  # centos6 still use old name
444             # update perl core modules on centos
445             # fix: Can't locate Archive/Tar.pm in @INC
446             'perl': 'perl-core',
447             'rpcsvc-proto-devel': '',
448             'glusterfs-api-devel': '',
449             'glusterfs-devel': '',
450             'libcephfs-devel': '',
451         }
452     },
453     'centos7': {
454         'docker_image': 'centos:7',
455         'vagrant_box': 'centos/7',
456         'bootstrap': YUM_BOOTSTRAP,
457         'replace': {
458             'lsb-release': 'redhat-lsb',
459             'python3': 'python36',
460             'python3-crypto': 'python36-crypto',
461             'python3-devel': 'python36-devel',
462             'python3-dns': 'python36-dns',
463             'python3-gpg': 'python36-gpg',
464             'python3-iso8601' : 'python36-iso8601',
465             'python3-markdown': 'python36-markdown',
466             # although python36-devel is available
467             # after epel-release installed
468             # however, all other python3 pkgs are still python36-ish
469             'python2-gpg': 'pygpgme',
470             'python3-gpg': '',  # no python3-gpg yet
471             '@development-tools': '"@Development Tools"',  # add quotes
472             'glibc-langpack-en': '',  # included in glibc-common
473             'glibc-locale-source': '',  # included in glibc-common
474             # update perl core modules on centos
475             # fix: Can't locate Archive/Tar.pm in @INC
476             'perl': 'perl-core',
477             'rpcsvc-proto-devel': '',
478             'glusterfs-api-devel': '',
479             'glusterfs-devel': '',
480             'libcephfs-devel': '',
481         }
482     },
483     'fedora28': {
484         'docker_image': 'fedora:28',
485         'vagrant_box': 'fedora/28-cloud-base',
486         'bootstrap': DNF_BOOTSTRAP,
487         'replace': {
488             'lsb-release': 'redhat-lsb',
489         }
490     },
491     'fedora29': {
492         'docker_image': 'fedora:29',
493         'vagrant_box': 'fedora/29-cloud-base',
494         'bootstrap': DNF_BOOTSTRAP,
495         'replace': {
496             'lsb-release': 'redhat-lsb',
497         }
498     },
499     'opensuse150': {
500         'docker_image': 'opensuse/leap:15.0',
501         'vagrant_box': 'opensuse/openSUSE-15.0-x86_64',
502         'bootstrap': ZYPPER_BOOTSTRAP,
503         'replace': {
504             '@development-tools': '',
505             'dbus-devel': 'dbus-1-devel',
506             'docbook-style-xsl': 'docbook-xsl-stylesheets',
507             'glibc-common': 'glibc-locale',
508             'glibc-locale-source': 'glibc-i18ndata',
509             'glibc-langpack-en': '',
510             'jansson-devel': 'libjansson-devel',
511             'keyutils-libs-devel': 'keyutils-devel',
512             'krb5-workstation': 'krb5-client',
513             'libnsl2-devel': 'libnsl-devel',
514             'libsemanage-python': 'python2-semanage',
515             'nettle-devel': 'libnettle-devel',
516             'openldap-devel': 'openldap2-devel',
517             'perl-Archive-Tar': 'perl-Archive-Tar-Wrapper',
518             'perl-JSON-Parse': 'perl-JSON-XS',
519             'perl-generators': '',
520             'perl-interpreter': '',
521             'procps-ng': 'procps',
522             'python-dns': 'python2-dnspython',
523             'python3-crypto': 'python3-pycrypto',
524             'python3-dns': 'python3-dnspython',
525             'python3-markdown': 'python3-Markdown',
526             'quota-devel': '',
527             'glusterfs-api-devel': '',
528             'libtasn1-tools': '', # asn1Parser is part of libtasn1
529             'mingw64-gcc': '', # doesn't exist
530         }
531     }
532 }
533
534
535 DEB_FAMILY = {
536     'name': 'deb',
537     'pkgs': DEB_PKGS,
538     'bootstrap': APT_BOOTSTRAP,  # family default
539     'dists': DEB_DISTS,
540 }
541
542
543 RPM_FAMILY = {
544     'name': 'rpm',
545     'pkgs': RPM_PKGS,
546     'bootstrap': YUM_BOOTSTRAP,  # family default
547     'dists': RPM_DISTS,
548 }
549
550
551 YML_HEADER = r"""
552 ---
553 packages:
554 """
555
556
557 def expand_family_dists(family):
558     dists = {}
559     for name, config in family['dists'].items():
560         config = config.copy()
561         config['name'] = name
562         config['home'] = join(OUT, name)
563         config['family'] = family['name']
564         config['GENERATED_MARKER'] = GENERATED_MARKER
565
566         # replace dist specific pkgs
567         replace = config.get('replace', {})
568         pkgs = []
569         for pkg in family['pkgs']:
570             pkg = replace.get(pkg, pkg)  # replace if exists or get self
571             if pkg:
572                 pkgs.append(pkg)
573         pkgs.sort()
574
575         lines = ['  - {}'.format(pkg) for pkg in pkgs]
576         config['packages.yml'] = YML_HEADER.lstrip() + os.linesep.join(lines)
577
578         sep = ' \\' + os.linesep + '    '
579         config['pkgs'] = sep.join(pkgs)
580
581         # get dist bootstrap template or fall back to family default
582         bootstrap_template = config.get('bootstrap', family['bootstrap'])
583         config['bootstrap.sh'] = bootstrap_template.format(**config).strip()
584         config['locale.sh'] = LOCALE_SETUP.format(**config).strip()
585
586         config['Dockerfile'] = DOCKERFILE.format(**config).strip()
587         # keep the indent, no strip
588         config['vagrantfile_snippet'] = VAGRANTFILE_SNIPPET.format(**config)
589
590         dists[name] = config
591     return dists
592
593
594 # expanded config for dists
595 DEB_DISTS_EXP = expand_family_dists(DEB_FAMILY)
596 RPM_DISTS_EXP = expand_family_dists(RPM_FAMILY)
597
598 # assemble all together
599 DISTS = {}
600 DISTS.update(DEB_DISTS_EXP)
601 DISTS.update(RPM_DISTS_EXP)
602
603
604 def render_vagrantfile(dists):
605     """
606     Render all snippets for each dist into global Vagrantfile.
607
608     Vagrant supports multiple vms in one Vagrantfile.
609     This make it easier to manage the fleet, e.g:
610
611     start all: vagrant up
612     start one: vagrant up ubuntu1804
613
614     All other commands apply to above syntax, e.g.: status, destroy, provision
615     """
616     # sort dists by name and put all vagrantfile snippets together
617     snippets = [
618         dists[dist]['vagrantfile_snippet']
619         for dist in sorted(dists.keys())]
620
621     return VAGRANTFILE_GLOBAL.format(
622             vagrantfile_snippets=''.join(snippets),
623             GENERATED_MARKER=GENERATED_MARKER
624             )
625
626
627 VAGRANTFILE = render_vagrantfile(DISTS)
628
629
630 # data we need to expose
631 __all__ = ['DISTS', 'VAGRANTFILE', 'OUT']