bootstrap: Add Fedora 31
[metze/samba-autobuild/.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     ('python3', 'python3'),
131     ('python3-dev', 'python3-devel'),
132     ('python3-dbg', ''),
133     ('python3-iso8601', ''),
134     ('python3-gpg', 'python3-gpg'),  # defaults to ubuntu/fedora latest
135     ('python3-crypto', 'python3-crypto'),
136     ('python3-markdown', 'python3-markdown'),
137     ('python3-matplotlib', ''),
138     ('python3-dnspython', 'python3-dns'),
139     ('python3-pexpect', ''),  # for wintest only
140
141     ('', 'libsemanage-python'),
142     ('', 'policycoreutils-python'),
143
144     # perl
145     ('libparse-yapp-perl', 'perl-Parse-Yapp'),
146     ('libjson-perl', 'perl-JSON-Parse'),
147     ('perl-modules', ''),
148     ('', 'perl-Archive-Tar'),
149     ('', 'perl-ExtUtils-MakeMaker'),
150     ('', 'perl-Test-Base'),
151     ('', 'perl-generators'),
152     ('', 'perl-interpreter'),
153
154     # fs
155     ('xfslibs-dev', 'xfsprogs-devel'), # for xfs quota support
156     ('', 'glusterfs-api-devel'),
157     ('glusterfs-common', 'glusterfs-devel'),
158     ('libcephfs-dev', 'libcephfs-devel'),
159
160     # misc
161     # @ means group for rpm, use fedora as rpm default
162     ('build-essential', '@development-tools'),
163     ('debhelper', ''),
164     # rpm has no pkg for docbook-xml
165     ('docbook-xml', 'docbook-dtds'),
166     ('docbook-xsl', 'docbook-style-xsl'),
167     ('', 'keyutils-libs-devel'),
168     ('', 'which'),
169 ]
170
171
172 DEB_PKGS = COMMON + [pkg for pkg, _ in PKGS if pkg]
173 RPM_PKGS = COMMON + [pkg for _, pkg in PKGS if pkg]
174
175 GENERATED_MARKER = r"""
176 #
177 # This file is generated by 'bootstrap/template.py --render'
178 # See also bootstrap/config.py
179 #
180 """
181
182
183 APT_BOOTSTRAP = r"""
184 #!/bin/bash
185 {GENERATED_MARKER}
186 set -xueo pipefail
187
188 export DEBIAN_FRONTEND=noninteractive
189 apt-get -y update
190
191 apt-get -y install \
192     {pkgs}
193
194 apt-get -y autoremove
195 apt-get -y autoclean
196 apt-get -y clean
197 """
198
199
200 YUM_BOOTSTRAP = r"""
201 #!/bin/bash
202 {GENERATED_MARKER}
203 set -xueo pipefail
204
205 yum update -y
206 yum install -y epel-release
207 yum install -y yum-plugin-copr
208 yum copr enable -y sergiomb/SambaAD
209 yum update -y
210
211 yum install -y \
212     {pkgs}
213
214 yum clean all
215
216 if [ ! -f /usr/bin/python3 ]; then
217     ln -sf /usr/bin/python3.6 /usr/bin/python3
218 fi
219 """
220
221 CENTOS8_YUM_BOOTSTRAP = r"""
222 #!/bin/bash
223 {GENERATED_MARKER}
224 set -xueo pipefail
225
226 yum update -y
227 yum install -y dnf-plugins-core
228 yum install -y epel-release
229 yum config-manager --set-enabled PowerTools -y
230 yum update -y
231
232 yum install -y \
233     --setopt=install_weak_deps=False \
234     {pkgs}
235
236 yum clean all
237 """
238
239 DNF_BOOTSTRAP = r"""
240 #!/bin/bash
241 {GENERATED_MARKER}
242 set -xueo pipefail
243
244 dnf update -y
245
246 dnf install -y \
247     --setopt=install_weak_deps=False \
248     {pkgs}
249
250 dnf clean all
251 """
252
253 ZYPPER_BOOTSTRAP = r"""
254 #!/bin/bash
255 {GENERATED_MARKER}
256 set -xueo pipefail
257
258 zypper --non-interactive refresh
259 zypper --non-interactive update
260 zypper --non-interactive install \
261     --no-recommends \
262     system-user-nobody \
263     {pkgs}
264
265 zypper --non-interactive clean
266
267 if [ -f /usr/lib/mit/bin/krb5-config ]; then
268     ln -sf /usr/lib/mit/bin/krb5-config /usr/bin/krb5-config
269 fi
270 """
271
272 # A generic shell script to setup locale
273 LOCALE_SETUP = r"""
274 #!/bin/bash
275 {GENERATED_MARKER}
276 set -xueo pipefail
277
278 # refer to /usr/share/i18n/locales
279 INPUTFILE=en_US
280 # refer to /usr/share/i18n/charmaps
281 CHARMAP=UTF-8
282 # locale to generate in /usr/lib/locale
283 # glibc/localedef will normalize UTF-8 to utf8, follow the naming style
284 LOCALE=$INPUTFILE.utf8
285
286 # if locale is already correct, exit
287 ( locale | grep LC_ALL | grep -i $LOCALE ) && exit 0
288
289 # if locale not available, generate locale into /usr/lib/locale
290 if ! ( locale --all-locales | grep -i $LOCALE )
291 then
292     # no-archive means create its own dir
293     localedef --inputfile $INPUTFILE --charmap $CHARMAP --no-archive $LOCALE
294 fi
295
296 # update locale conf and global env file
297 # set both LC_ALL and LANG for safe
298
299 # update conf for Debian family
300 FILE=/etc/default/locale
301 if [ -f $FILE ]
302 then
303     echo LC_ALL="$LOCALE" > $FILE
304     echo LANG="$LOCALE" >> $FILE
305 fi
306
307 # update conf for RedHat family
308 FILE=/etc/locale.conf
309 if [ -f $FILE ]
310 then
311     # LC_ALL is not valid in this file, set LANG only
312     echo LANG="$LOCALE" > $FILE
313 fi
314
315 # update global env file
316 FILE=/etc/environment
317 if [ -f $FILE ]
318 then
319     # append LC_ALL if not exist
320     grep LC_ALL $FILE || echo LC_ALL="$LOCALE" >> $FILE
321     # append LANG if not exist
322     grep LANG $FILE || echo LANG="$LOCALE" >> $FILE
323 fi
324 """
325
326
327 DOCKERFILE = r"""
328 {GENERATED_MARKER}
329 FROM {docker_image}
330
331 # pass in with --build-arg while build
332 ARG SHA1SUM
333 RUN [ -n $SHA1SUM ] && echo $SHA1SUM > /sha1sum.txt
334
335 ADD *.sh /tmp/
336 # need root permission, do it before USER samba
337 RUN /tmp/bootstrap.sh && /tmp/locale.sh
338
339 # if ld.gold exists, force link it to ld
340 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"
341
342 # make test can not work with root, so we have to create a new user
343 RUN useradd -m -U -s /bin/bash samba && \
344     mkdir -p /etc/sudoers.d && \
345     echo "samba ALL=(ALL) NOPASSWD:ALL" > /etc/sudoers.d/samba
346
347 USER samba
348 WORKDIR /home/samba
349 # samba tests rely on this
350 ENV USER=samba LC_ALL=en_US.utf8 LANG=en_US.utf8
351 """
352
353 # Vagrantfile snippet for each dist
354 VAGRANTFILE_SNIPPET = r"""
355     config.vm.define "{name}" do |v|
356         v.vm.box = "{vagrant_box}"
357         v.vm.hostname = "{name}"
358         v.vm.provision :shell, path: "{name}/bootstrap.sh"
359         v.vm.provision :shell, path: "{name}/locale.sh"
360     end
361 """
362
363 # global Vagrantfile with snippets for all dists
364 VAGRANTFILE_GLOBAL = r"""
365 {GENERATED_MARKER}
366
367 Vagrant.configure("2") do |config|
368     config.ssh.insert_key = false
369
370 {vagrantfile_snippets}
371
372 end
373 """
374
375
376 DEB_DISTS = {
377     'debian7': {
378         'docker_image': 'debian:7',
379         'vagrant_box': 'debian/wheezy64',
380         'replace': {
381             'libgnutls28-dev': 'libgnutls-dev',
382             'libsystemd-dev': '',  # not available, remove
383             'lmdb-utils': '',  # not available, remove
384             'liblmdb-dev': '',  # not available, remove
385             'python-gpg': 'python-gpgme',
386             'python3-gpg': '',  # no python3 gpg pkg available, remove
387             'language-pack-en': '',   # included in locales
388         }
389     },
390     'debian8': {
391         'docker_image': 'debian:8',
392         'vagrant_box': 'debian/jessie64',
393         'replace': {
394             'python-gpg': 'python-gpgme',
395             'python3-gpg': 'python3-gpgme',
396             'language-pack-en': '',   # included in locales
397         }
398     },
399     'debian9': {
400         'docker_image': 'debian:9',
401         'vagrant_box': 'debian/stretch64',
402         'replace': {
403             'language-pack-en': '',   # included in locales
404         }
405     },
406     'ubuntu1404': {
407         'docker_image': 'ubuntu:14.04',
408         'vagrant_box': 'ubuntu/trusty64',
409         'replace': {
410             'libsystemd-dev': '',  # remove
411             'libgnutls28-dev': 'libgnutls-dev',
412             'python-gpg': 'python-gpgme',
413             'python3-gpg': 'python3-gpgme',
414             'lmdb-utils': 'lmdb-utils/trusty-backports',
415             'liblmdb-dev': 'liblmdb-dev/trusty-backports',
416             'libunwind-dev': 'libunwind8-dev',
417             'glusterfs-common': '',
418             'libcephfs-dev': '',
419         }
420     },
421     'ubuntu1604': {
422         'docker_image': 'ubuntu:16.04',
423         'vagrant_box': 'ubuntu/xenial64',
424         'replace': {
425             'python-gpg': 'python-gpgme',
426             'python3-gpg': 'python3-gpgme',
427             'glusterfs-common': '',
428             'libcephfs-dev': '',
429         }
430     },
431     'ubuntu1804': {
432         'docker_image': 'ubuntu:18.04',
433         'vagrant_box': 'ubuntu/bionic64',
434     },
435 }
436
437
438 RPM_DISTS = {
439     'centos6': {
440         'docker_image': 'centos:6',
441         'vagrant_box': 'centos/6',
442         'bootstrap': YUM_BOOTSTRAP,
443         'replace': {
444             'lsb-release': 'redhat-lsb',
445             'python3': 'python36',
446             'python3-devel': 'python36-devel',
447             'python2-gpg': 'pygpgme',
448             'python3-gpg': '',  # no python3-gpg yet
449             '@development-tools': '"@Development Tools"',  # add quotes
450             'glibc-langpack-en': '',  # included in glibc-common
451             'glibc-locale-source': '',  # included in glibc-common
452             'procps-ng': 'procps',  # centos6 still use old name
453             # update perl core modules on centos
454             # fix: Can't locate Archive/Tar.pm in @INC
455             'perl': 'perl-core',
456             'rpcsvc-proto-devel': '',
457             'glusterfs-api-devel': '',
458             'glusterfs-devel': '',
459             'libcephfs-devel': '',
460         }
461     },
462     'centos7': {
463         'docker_image': 'centos:7',
464         'vagrant_box': 'centos/7',
465         'bootstrap': YUM_BOOTSTRAP,
466         'replace': {
467             'lsb-release': 'redhat-lsb',
468             'python3': 'python36',
469             'python3-crypto': 'python36-crypto',
470             'python3-devel': 'python36-devel',
471             'python3-dns': 'python36-dns',
472             'python3-gpg': 'python36-gpg',
473             'python3-iso8601' : 'python36-iso8601',
474             'python3-markdown': 'python36-markdown',
475             # although python36-devel is available
476             # after epel-release installed
477             # however, all other python3 pkgs are still python36-ish
478             'python2-gpg': 'pygpgme',
479             'python3-gpg': '',  # no python3-gpg yet
480             '@development-tools': '"@Development Tools"',  # add quotes
481             'glibc-langpack-en': '',  # included in glibc-common
482             'glibc-locale-source': '',  # included in glibc-common
483             # update perl core modules on centos
484             # fix: Can't locate Archive/Tar.pm in @INC
485             'perl': 'perl-core',
486             'rpcsvc-proto-devel': '',
487             'glusterfs-api-devel': '',
488             'glusterfs-devel': '',
489             'libcephfs-devel': '',
490             'gnutls-devel': 'compat-gnutls34-devel',
491         }
492     },
493     'centos8': {
494         'docker_image': 'centos:8',
495         'vagrant_box': 'centos/8',
496         'bootstrap': CENTOS8_YUM_BOOTSTRAP,
497         'replace': {
498             'lsb-release': 'redhat-lsb',
499             '@development-tools': '"@Development Tools"',  # add quotes
500             'libsemanage-python': 'python3-libsemanage',
501             'lcov': '', # does not exist
502             'perl-JSON-Parse': '', # does not exist?
503             'perl-Test-Base': 'perl-Test-Simple',
504             'policycoreutils-python': 'python3-policycoreutils',
505             'python3-crypto': '',
506             'quota-devel': '', # FIXME: Add me back, once available!
507         }
508     },
509     'fedora29': {
510         'docker_image': 'fedora:29',
511         'vagrant_box': 'fedora/29-cloud-base',
512         'bootstrap': DNF_BOOTSTRAP,
513         'replace': {
514             'lsb-release': 'redhat-lsb',
515         }
516     },
517     'fedora30': {
518         'docker_image': 'fedora:30',
519         'vagrant_box': 'fedora/30-cloud-base',
520         'bootstrap': DNF_BOOTSTRAP,
521         'replace': {
522             'lsb-release': 'redhat-lsb',
523         }
524     },
525     'fedora31': {
526         'docker_image': 'fedora:31',
527         'vagrant_box': 'fedora/31-cloud-base',
528         'bootstrap': DNF_BOOTSTRAP,
529         'replace': {
530             'lsb-release': 'redhat-lsb',
531             'libsemanage-python': 'python3-libsemanage',
532             'policycoreutils-python': 'python3-policycoreutils',
533         }
534     },
535     'opensuse150': {
536         'docker_image': 'opensuse/leap:15.0',
537         'vagrant_box': 'opensuse/openSUSE-15.0-x86_64',
538         'bootstrap': ZYPPER_BOOTSTRAP,
539         'replace': {
540             '@development-tools': '',
541             'dbus-devel': 'dbus-1-devel',
542             'docbook-style-xsl': 'docbook-xsl-stylesheets',
543             'glibc-common': 'glibc-locale',
544             'glibc-locale-source': 'glibc-i18ndata',
545             'glibc-langpack-en': '',
546             'jansson-devel': 'libjansson-devel',
547             'keyutils-libs-devel': 'keyutils-devel',
548             'krb5-workstation': 'krb5-client',
549             'libnsl2-devel': 'libnsl-devel',
550             'libsemanage-python': 'python2-semanage',
551             'nettle-devel': 'libnettle-devel',
552             'openldap-devel': 'openldap2-devel',
553             'perl-Archive-Tar': 'perl-Archive-Tar-Wrapper',
554             'perl-JSON-Parse': 'perl-JSON-XS',
555             'perl-generators': '',
556             'perl-interpreter': '',
557             'procps-ng': 'procps',
558             'python-dns': 'python2-dnspython',
559             'python3-crypto': 'python3-pycrypto',
560             'python3-dns': 'python3-dnspython',
561             'python3-markdown': 'python3-Markdown',
562             'quota-devel': '',
563             'glusterfs-api-devel': '',
564             'libtasn1-tools': '', # asn1Parser is part of libtasn1
565             'mingw64-gcc': '', # doesn't exist
566         }
567     },
568     'opensuse151': {
569         'docker_image': 'opensuse/leap:15.1',
570         'vagrant_box': 'opensuse/openSUSE-15.1-x86_64',
571         'bootstrap': ZYPPER_BOOTSTRAP,
572         'replace': {
573             '@development-tools': '',
574             'dbus-devel': 'dbus-1-devel',
575             'docbook-style-xsl': 'docbook-xsl-stylesheets',
576             'glibc-common': 'glibc-locale',
577             'glibc-locale-source': 'glibc-i18ndata',
578             'glibc-langpack-en': '',
579             'jansson-devel': 'libjansson-devel',
580             'keyutils-libs-devel': 'keyutils-devel',
581             'krb5-workstation': 'krb5-client',
582             'libnsl2-devel': 'libnsl-devel',
583             'libsemanage-python': 'python2-semanage',
584             'nettle-devel': 'libnettle-devel',
585             'openldap-devel': 'openldap2-devel',
586             'perl-Archive-Tar': 'perl-Archive-Tar-Wrapper',
587             'perl-JSON-Parse': 'perl-JSON-XS',
588             'perl-generators': '',
589             'perl-interpreter': '',
590             'procps-ng': 'procps',
591             'python-dns': 'python2-dnspython',
592             'python3-crypto': 'python3-pycrypto',
593             'python3-dns': 'python3-dnspython',
594             'python3-markdown': 'python3-Markdown',
595             'quota-devel': '',
596             'glusterfs-api-devel': '',
597             'libtasn1-tools': '', # asn1Parser is part of libtasn1
598             'mingw64-gcc': '', # doesn't exist
599         }
600     }
601 }
602
603
604 DEB_FAMILY = {
605     'name': 'deb',
606     'pkgs': DEB_PKGS,
607     'bootstrap': APT_BOOTSTRAP,  # family default
608     'dists': DEB_DISTS,
609 }
610
611
612 RPM_FAMILY = {
613     'name': 'rpm',
614     'pkgs': RPM_PKGS,
615     'bootstrap': YUM_BOOTSTRAP,  # family default
616     'dists': RPM_DISTS,
617 }
618
619
620 YML_HEADER = r"""
621 ---
622 packages:
623 """
624
625
626 def expand_family_dists(family):
627     dists = {}
628     for name, config in family['dists'].items():
629         config = config.copy()
630         config['name'] = name
631         config['home'] = join(OUT, name)
632         config['family'] = family['name']
633         config['GENERATED_MARKER'] = GENERATED_MARKER
634
635         # replace dist specific pkgs
636         replace = config.get('replace', {})
637         pkgs = []
638         for pkg in family['pkgs']:
639             pkg = replace.get(pkg, pkg)  # replace if exists or get self
640             if pkg:
641                 pkgs.append(pkg)
642         pkgs.sort()
643
644         lines = ['  - {}'.format(pkg) for pkg in pkgs]
645         config['packages.yml'] = YML_HEADER.lstrip() + os.linesep.join(lines)
646
647         sep = ' \\' + os.linesep + '    '
648         config['pkgs'] = sep.join(pkgs)
649
650         # get dist bootstrap template or fall back to family default
651         bootstrap_template = config.get('bootstrap', family['bootstrap'])
652         config['bootstrap.sh'] = bootstrap_template.format(**config).strip()
653         config['locale.sh'] = LOCALE_SETUP.format(**config).strip()
654
655         config['Dockerfile'] = DOCKERFILE.format(**config).strip()
656         # keep the indent, no strip
657         config['vagrantfile_snippet'] = VAGRANTFILE_SNIPPET.format(**config)
658
659         dists[name] = config
660     return dists
661
662
663 # expanded config for dists
664 DEB_DISTS_EXP = expand_family_dists(DEB_FAMILY)
665 RPM_DISTS_EXP = expand_family_dists(RPM_FAMILY)
666
667 # assemble all together
668 DISTS = {}
669 DISTS.update(DEB_DISTS_EXP)
670 DISTS.update(RPM_DISTS_EXP)
671
672
673 def render_vagrantfile(dists):
674     """
675     Render all snippets for each dist into global Vagrantfile.
676
677     Vagrant supports multiple vms in one Vagrantfile.
678     This make it easier to manage the fleet, e.g:
679
680     start all: vagrant up
681     start one: vagrant up ubuntu1804
682
683     All other commands apply to above syntax, e.g.: status, destroy, provision
684     """
685     # sort dists by name and put all vagrantfile snippets together
686     snippets = [
687         dists[dist]['vagrantfile_snippet']
688         for dist in sorted(dists.keys())]
689
690     return VAGRANTFILE_GLOBAL.format(
691             vagrantfile_snippets=''.join(snippets),
692             GENERATED_MARKER=GENERATED_MARKER
693             )
694
695
696 VAGRANTFILE = render_vagrantfile(DISTS)
697
698
699 # data we need to expose
700 __all__ = ['DISTS', 'VAGRANTFILE', 'OUT']