X-Git-Url: https://git.siccegge.de//index.cgi?p=forks%2Fvmdebootstrap.git;a=blobdiff_plain;f=vmdebootstrap;h=c9764ae67c44fffe66cdff7b42d23fe4acbca7a6;hp=c10d63348338f959823ecc32e4ef2be64b37e06a;hb=HEAD;hpb=0a48e950071e16d3df1dd140c1f667adfe33847d diff --git a/vmdebootstrap b/vmdebootstrap index c10d633..c9764ae 100755 --- a/vmdebootstrap +++ b/vmdebootstrap @@ -20,6 +20,7 @@ import cliapp import crypt import logging import os +import glob import re import sys import shutil @@ -30,7 +31,7 @@ import time from distro_info import DebianDistroInfo, UbuntuDistroInfo -__version__ = '0.10' +__version__ = '0.11' # pylint: disable=invalid-name,line-too-long,missing-docstring,too-many-branches @@ -482,7 +483,11 @@ class VmDebootstrap(cliapp.Application): # pylint: disable=too-many-public-meth def setup_kpartx(self): bootindex = None swapindex = None - out = self.runcmd(['kpartx', '-avs', self.settings['image']]) + if 'freebsd' in os.sys.platform: + out = self.runcmd(['mdconfig', '-a', '-t', 'vnode', '-f', + self.settings['image']]) + else: + out = self.runcmd(['kpartx', '-avs', self.settings['image']]) if self.settings['bootsize'] and self.settings['swap'] > 0: bootindex = 0 rootindex = 1 @@ -510,19 +515,22 @@ class VmDebootstrap(cliapp.Application): # pylint: disable=too-many-public-meth parts = 1 boot = None swap = None - devices = [line.split()[2] - for line in out.splitlines() - if line.startswith('add map ')] + if 'freebsd' in os.sys.platform: + devices = glob.glob("/dev/%ss*" % out.strip()) + else: + devices = ['/dev/mapper/%s' % line.split()[2] + for line in out.splitlines() + if line.startswith('add map ')] if len(devices) != parts: msg = 'Surprising number of partitions - check output of losetup -a' logging.debug("%s", self.runcmd(['losetup', '-a'])) logging.debug("%s: devices=%s parts=%s", msg, devices, parts) raise cliapp.AppException(msg) - root = '/dev/mapper/%s' % devices[rootindex] + root = devices[rootindex] if self.settings['bootsize'] or self.settings['use-uefi']: - boot = '/dev/mapper/%s' % devices[bootindex] + boot = devices[bootindex] if self.settings['swap'] > 0: - swap = '/dev/mapper/%s' % devices[swapindex] + swap = devices[swapindex] return root, boot, swap def _efi_packages(self): @@ -692,24 +700,33 @@ class VmDebootstrap(cliapp.Application): # pylint: disable=too-many-public-meth def create_fstab(self, rootdir, rootdev, roottype, bootdev, boottype): # pylint: disable=too-many-arguments def fsuuid(device): - out = self.runcmd(['blkid', '-c', '/dev/null', '-o', 'value', - '-s', 'UUID', device]) - return out.splitlines()[0].strip() + if 'freebsd' in os.sys.platform: + out = self.runcmd(['grub-probe', '-d', device, '-t', 'fs_uuid']) + return "/dev/ufsid/%s" % out.strip() + else: + out = self.runcmd(['blkid', '-c', '/dev/null', '-o', 'value', + '-s', 'UUID', device]) + return "UUID=%s" % out.splitlines()[0].strip() if rootdev: - rootdevstr = 'UUID=%s' % fsuuid(rootdev) + rootdevstr = fsuuid(rootdev) else: rootdevstr = '/dev/sda1' if bootdev and not self.settings['use-uefi']: - bootdevstr = 'UUID=%s' % fsuuid(bootdev) + bootdevstr = fsuuid(bootdev) else: bootdevstr = None fstab = os.path.join(rootdir, 'etc', 'fstab') with open(fstab, 'w') as f: - f.write('proc /proc proc defaults 0 0\n') - f.write('%s / %s errors=remount-ro 0 1\n' % (rootdevstr, roottype)) + if 'freebsd' in os.sys.platform: + f.write('proc /proc linprocfs rw 0 0\n') + f.write('sys /sys linsysfs rw 0 0\n') + f.write('fdesc /dev/fd fdescfs rw 0 0\n') + else: + f.write('proc /proc proc defaults 0 0\n') + f.write('%s / %s rw 0 1\n' % (rootdevstr, roottype)) if bootdevstr: f.write('%s /boot %s errors=remount-ro 0 2\n' % (bootdevstr, boottype)) if self.settings['swap'] > 0: @@ -784,20 +801,34 @@ class VmDebootstrap(cliapp.Application): # pylint: disable=too-many-public-meth else: logging.debug('not removing non-existent %s', pathname) + def mask_udev_predictable_rules(self, rootdir): + """ + This can be reset later but to get networking working immediately + on boot, the interface we're going to use must be known without + reference to the eventual machine. + http://www.freedesktop.org/wiki/Software/systemd/PredictableNetworkInterfaceNames/ + """ + self.message('Disabling systemd predictable interface names') + udev_path = os.path.join( + 'etc', 'udev', 'rules.d', '80-net-setup-link.rules') + self.runcmd(['chroot', rootdir, 'ln', '-s', '/dev/null', udev_path]) + def setup_networking(self, rootdir): self.message('Setting up networking') + ifc_file = os.path.join(rootdir, 'etc', 'network', 'interfaces') + ifc_d = os.path.join(rootdir, 'etc', 'network', 'interfaces.d') - # unconditionally write for wheezy (which became oldstable on 04/25/2015) + # unconditionally write for wheezy (which became oldstable 2015.04.25) if self.was_oldstable(datetime.date(2015, 4, 26)): - with open(os.path.join(rootdir, 'etc', 'network', 'interfaces'), 'w') as netfile: + with open(ifc_file, 'w') as netfile: netfile.write('source /etc/network/interfaces.d/*\n') - os.mkdir(os.path.join(rootdir, 'etc', 'network', 'interfaces.d')) - - elif not os.path.exists(os.path.join(rootdir, 'etc', 'network', 'interfaces')): - iface_path = os.path.join(rootdir, 'etc', 'network', 'interfaces') - with open(iface_path, 'w') as netfile: + elif not os.path.exists(ifc_file): + with open(ifc_file, 'a') as netfile: netfile.write('source-directory /etc/network/interfaces.d\n') - ethpath = os.path.join(rootdir, 'etc', 'network', 'interfaces.d', 'setup') + + if not os.path.exists(ifc_d): + os.mkdir(ifc_d) + ethpath = os.path.join(ifc_d, 'setup') with open(ethpath, 'w') as eth: eth.write('auto lo\n') eth.write('iface lo inet loopback\n') @@ -806,6 +837,8 @@ class VmDebootstrap(cliapp.Application): # pylint: disable=too-many-public-meth eth.write('\n') eth.write('auto eth0\n') eth.write('iface eth0 inet dhcp\n') + # force predictable interface names + self.mask_udev_predictable_rules(rootdir) def append_serial_console(self, rootdir): if self.settings['serial-console']: @@ -830,12 +863,20 @@ class VmDebootstrap(cliapp.Application): # pylint: disable=too-many-public-meth cfg.write("%s\n" % command) def _mount_wrapper(self, rootdir): - self.runcmd(['mount', '/dev', '-t', 'devfs', '-obind', - '%s' % os.path.join(rootdir, 'dev')]) - self.runcmd(['mount', '/proc', '-t', 'proc', '-obind', - '%s' % os.path.join(rootdir, 'proc')]) - self.runcmd(['mount', '/sys', '-t', 'sysfs', '-obind', - '%s' % os.path.join(rootdir, 'sys')]) + if 'freebsd' in os.sys.platform: + self.runcmd(['mount', 'dev', '-t', 'devfs', + '%s' % os.path.join(rootdir, 'dev')]) + self.runcmd(['mount', 'proc', '-t', 'linprocfs', + '%s' % os.path.join(rootdir, 'proc')]) + self.runcmd(['mount', 'sys', '-t', 'linsysfs', + '%s' % os.path.join(rootdir, 'sys')]) + else: + self.runcmd(['mount', '/dev', '-t', 'devfs', '-obind', + '%s' % os.path.join(rootdir, 'dev')]) + self.runcmd(['mount', '/proc', '-t', 'proc', '-obind', + '%s' % os.path.join(rootdir, 'proc')]) + self.runcmd(['mount', '/sys', '-t', 'sysfs', '-obind', + '%s' % os.path.join(rootdir, 'sys')]) def _umount_wrapper(self, rootdir): self.runcmd(['umount', os.path.join(rootdir, 'sys')]) @@ -1004,7 +1045,13 @@ append initrd=%(initrd)s root=UUID=%(uuid)s ro %(kserial)s time.sleep(5) self.runcmd(['umount', mount_point], ignore_fail=False) - self.runcmd(['kpartx', '-d', self.settings['image']], ignore_fail=True) + if 'freebsd' in os.sys.platform: + out = self.runcmd(['mdconfig', '-l', '-f', self.settings['image']]) + for devid in out.split(): + self.runcmd(['mdconfig', '-d', '-u', devid], + ignore_fail=True) + else: + self.runcmd(['kpartx', '-d', self.settings['image']], ignore_fail=True) for dirname in self.remove_dirs: shutil.rmtree(dirname) @@ -1024,14 +1071,12 @@ append initrd=%(initrd)s root=UUID=%(uuid)s ro %(kserial)s logging.debug( "%s usage: %s", self.settings['image'], self.runcmd(['du', self.settings['image']])) - with open('/dev/tty', 'w') as tty: - try: + try: + with open('/dev/tty', 'w') as tty: cliapp.runcmd([script, rootdir, self.settings['image']], stdout=tty, stderr=tty) - except IOError: - subprocess.call([script, rootdir, self.settings['image']]) - logging.debug( - "%s usage: %s", self.settings['image'], - self.runcmd(['du', self.settings['image']])) + except IOError: + logging.debug('tty unavailable, trying in headless mode.') + subprocess.call([script, rootdir, self.settings['image']]) def create_tarball(self, rootdir): # Create a tarball of the disk's contents