+ bootindex = None
+ swapindex = None
+ 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
+ swapindex = 2
+ parts = 3
+ elif self.settings['use-uefi']:
+ bootindex = 0
+ rootindex = 1
+ parts = 2
+ elif self.settings['use-uefi'] and self.settings['swap'] > 0:
+ bootindex = 0
+ rootindex = 1
+ swapindex = 2
+ parts = 3
+ elif self.settings['bootsize']:
+ bootindex = 0
+ rootindex = 1
+ parts = 2
+ elif self.settings['swap'] > 0:
+ rootindex = 0
+ swapindex = 1
+ parts = 2
+ else:
+ rootindex = 0
+ parts = 1
+ boot = None
+ swap = None
+ 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 = devices[rootindex]
+ if self.settings['bootsize'] or self.settings['use-uefi']:
+ boot = devices[bootindex]
+ if self.settings['swap'] > 0:
+ swap = devices[swapindex]
+ return root, boot, swap
+
+ def _efi_packages(self):
+ packages = []
+ pkg = self.efi_arch_table[self.settings['arch']]['package']
+ self.message("Adding %s" % pkg)
+ packages.append(pkg)
+ extra = self.efi_arch_table[self.settings['arch']]['extra']
+ if extra and isinstance(extra, str):
+ bin_pkg = self.efi_arch_table[str(extra)]['bin_package']
+ self.message("Adding support for %s using %s" % (extra, bin_pkg))
+ packages.append(bin_pkg)
+ return packages
+
+ def _copy_efi_binary(self, efi_removable, efi_install):
+ logging.debug("using bootdir=%s", self.bootdir)
+ logging.debug("moving %s to %s", efi_removable, efi_install)
+ if efi_removable.startswith('/'):
+ efi_removable = efi_removable[1:]
+ if efi_install.startswith('/'):
+ efi_install = efi_install[1:]
+ efi_output = os.path.join(self.bootdir, efi_removable)
+ efi_input = os.path.join(self.bootdir, efi_install)
+ if not os.path.exists(efi_input):
+ logging.warning("%s does not exist (%s)", efi_input, efi_install)
+ raise cliapp.AppException("Missing %s" % efi_install)
+ if not os.path.exists(os.path.dirname(efi_output)):
+ os.makedirs(os.path.dirname(efi_output))
+ logging.debug(
+ 'Moving UEFI support: %s -> %s', efi_input, efi_output)
+ if os.path.exists(efi_output):
+ os.unlink(efi_output)
+ os.rename(efi_input, efi_output)
+
+ def configure_efi(self):
+ """
+ Copy the bootloader file from the package into the location
+ so needs to be after grub and kernel already installed.
+ """
+ self.message('Configuring EFI')
+ efi_removable = str(self.efi_arch_table[self.settings['arch']]['removable'])
+ efi_install = str(self.efi_arch_table[self.settings['arch']]['install'])
+ self.message('Installing UEFI support binary')
+ self._copy_efi_binary(efi_removable, efi_install)
+
+ def configure_extra_efi(self):
+ extra = str(self.efi_arch_table[self.settings['arch']]['extra'])
+ if extra:
+ efi_removable = str(self.efi_arch_table[extra]['removable'])
+ efi_install = str(self.efi_arch_table[extra]['install'])
+ self.message('Copying UEFI support binary for %s' % extra)
+ self._copy_efi_binary(efi_removable, efi_install)
+
+ def mkfs(self, device, fstype):
+ self.message('Creating filesystem %s' % fstype)
+ self.runcmd(['mkfs', '-t', fstype, device])
+
+ def suite_to_codename(self, distro):
+ suite = self.debian_info.codename(distro, datetime.date.today())
+ if not suite:
+ return distro
+ return suite
+
+ def was_oldstable(self, limit):
+ suite = self.suite_to_codename(self.settings['distribution'])
+ # this check is only for debian
+ if not self.debian_info.valid(suite):
+ return False
+ return suite == self.debian_info.old(limit)
+
+ def was_stable(self, limit):
+ suite = self.suite_to_codename(self.settings['distribution'])
+ # this check is only for debian
+ if not self.debian_info.valid(suite):
+ return False
+ return suite == self.debian_info.stable(limit)
+
+ def debootstrap(self, rootdir): # pylint: disable=too-many-statements
+ msg = "(%s)" % self.settings['variant'] if self.settings['variant'] else ''
+ self.message(
+ 'Debootstrapping %s [%s] %s' % (
+ self.settings['distribution'], self.settings['arch'], msg))
+
+ include = self.settings['package']
+
+ if not self.settings['foreign'] and not self.settings['no-acpid']:
+ include.append('acpid')
+
+ if self.settings['grub']:
+ if self.settings['use-uefi']:
+ include.extend(self._efi_packages())
+ else:
+ include.append('grub-pc')
+
+ if not self.settings['no-kernel']:
+ if self.settings['kernel-package']:
+ kernel_image = self.settings['kernel-package']
+ else:
+ if self.settings['arch'] == 'i386':
+ # wheezy (which became oldstable on 04/25/2015) used '486'
+ if self.was_oldstable(datetime.date(2015, 4, 26)):
+ kernel_arch = '486'
+ else:
+ kernel_arch = '586'
+ elif self.settings['arch'] == 'armhf':
+ kernel_arch = 'armmp'
+ else:
+ kernel_arch = self.settings['arch']
+ kernel_image = 'linux-image-%s' % kernel_arch
+ include.append(kernel_image)
+
+ if self.settings['sudo'] and 'sudo' not in include:
+ include.append('sudo')
+
+ args = ['debootstrap', '--arch=%s' % self.settings['arch']]
+
+ if self.settings['package']:
+ args.append(
+ '--include=%s' % ','.join(include))
+ if self.settings['foreign']:
+ args.append('--foreign')
+ if self.settings['debootstrapopts']:
+ for opt in self.settings['debootstrapopts']:
+ for part in opt.split(' '):
+ args.append('--%s' % part)
+ elif self.settings['variant']:
+ args.append('--variant')
+ args.append(self.settings['variant'])
+ args += [self.settings['distribution'],
+ rootdir, self.settings['mirror']]
+ logging.debug(" ".join(args))
+ self.runcmd(args)
+ if self.settings['foreign']:
+ # set a noninteractive debconf environment for secondstage
+ env = {
+ "DEBIAN_FRONTEND": "noninteractive",
+ "DEBCONF_NONINTERACTIVE_SEEN": "true",
+ "LC_ALL": "C"
+ }
+ # add the mapping to the complete environment.
+ env.update(os.environ)
+ # First copy the binfmt handler over
+ self.message('Setting up binfmt handler')
+ shutil.copy(self.settings['foreign'], '%s/usr/bin/' % rootdir)
+ # Next, run the package install scripts etc.
+ self.message('Running debootstrap second stage')
+ self.runcmd(['chroot', rootdir,
+ '/debootstrap/debootstrap', '--second-stage'],
+ env=env)
+
+ def set_hostname(self, rootdir):
+ hostname = self.settings['hostname']
+ with open(os.path.join(rootdir, 'etc', 'hostname'), 'w') as f:
+ f.write('%s\n' % hostname)
+
+ etc_hosts = os.path.join(rootdir, 'etc', 'hosts')
+ try:
+ with open(etc_hosts, 'r') as f:
+ data = f.read()
+ with open(etc_hosts, 'w') as f:
+ for line in data.splitlines():
+ if line.startswith('127.0.0.1'):
+ line += ' %s' % hostname
+ f.write('%s\n' % line)
+ except IOError:
+ pass
+
+ def create_fstab(self, rootdir, rootdev, roottype, bootdev, boottype): # pylint: disable=too-many-arguments
+ def fsuuid(device):
+ 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 = fsuuid(rootdev)