def test_grub2_install(self, mock_guess_grub, mock_exec):
     mock_guess_grub.return_value = "/sbin/grub"
     expected_calls = [
         mock.call("chroot", "/target", "/sbin/grub", "/dev/foo", run_as_root=True, check_exit_code=[0]),
         mock.call("chroot", "/target", "/sbin/grub", "/dev/bar", run_as_root=True, check_exit_code=[0]),
     ]
     gu.grub2_install(["/dev/foo", "/dev/bar"], chroot="/target")
     self.assertEqual(mock_exec.call_args_list, expected_calls)
 def test_grub2_install(self, mock_guess_grub, mock_exec):
     mock_guess_grub.return_value = '/sbin/grub'
     expected_calls = [
         mock.call('chroot', '/target', '/sbin/grub', '/dev/foo',
                   run_as_root=True, check_exit_code=[0]),
         mock.call('chroot', '/target', '/sbin/grub', '/dev/bar',
                   run_as_root=True, check_exit_code=[0])
     ]
     gu.grub2_install(['/dev/foo', '/dev/bar'], chroot='/target')
     self.assertEqual(mock_exec.call_args_list, expected_calls)
Exemple #3
0
 def test_grub2_install(self, mock_guess_grub, mock_exec):
     mock_guess_grub.return_value = '/sbin/grub'
     expected_calls = [
         mock.call('chroot', '/target', '/sbin/grub', '/dev/foo',
                   run_as_root=True, check_exit_code=[0]),
         mock.call('chroot', '/target', '/sbin/grub', '/dev/bar',
                   run_as_root=True, check_exit_code=[0])
     ]
     gu.grub2_install(['/dev/foo', '/dev/bar'], chroot='/target')
     self.assertEqual(mock_exec.call_args_list, expected_calls)
Exemple #4
0
    def do_bootloader(self):
        LOG.debug('--- Installing bootloader (do_bootloader) ---')
        chroot = '/tmp/target'
        self.mount_target(chroot)

        mount2uuid = {}
        for fs in self.driver.partition_scheme.fss:
            mount2uuid[fs.mount] = utils.execute(
                'blkid',
                '-o',
                'value',
                '-s',
                'UUID',
                fs.device,
                check_exit_code=[0])[0].strip()

        grub = self.driver.grub

        grub.version = gu.guess_grub_version(chroot=chroot)
        boot_device = self.driver.partition_scheme.boot_device(grub.version)
        install_devices = [
            d.name for d in self.driver.partition_scheme.parteds
            if d.install_bootloader
        ]

        grub.append_kernel_params('root=UUID=%s ' % mount2uuid['/'])

        kernel = grub.kernel_name or \
            gu.guess_kernel(chroot=chroot, regexp=grub.kernel_regexp)
        initrd = grub.initrd_name or \
            gu.guess_initrd(chroot=chroot, regexp=grub.initrd_regexp)

        if grub.version == 1:
            gu.grub1_cfg(kernel=kernel,
                         initrd=initrd,
                         kernel_params=grub.kernel_params,
                         chroot=chroot)
            gu.grub1_install(install_devices, boot_device, chroot=chroot)
        else:
            # TODO(kozhukalov): implement which kernel to use by default
            # Currently only grub1_cfg accepts kernel and initrd parameters.
            gu.grub2_cfg(kernel_params=grub.kernel_params, chroot=chroot)
            gu.grub2_install(install_devices, chroot=chroot)

        # FIXME(agordeev) There's no convenient way to perfrom NIC remapping in
        #  Ubuntu, so injecting files prior the first boot should work
        with open(chroot + '/etc/udev/rules.d/70-persistent-net.rules',
                  'w') as f:
            f.write('# Generated by fuel-agent during provisioning: BEGIN\n')
            # pattern is aa:bb:cc:dd:ee:ff_eth0,aa:bb:cc:dd:ee:ff_eth1
            for mapping in self.driver.configdrive_scheme.\
                    common.udevrules.split(','):
                mac_addr, nic_name = mapping.split('_')
                f.write('SUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*", '
                        'ATTR{address}=="%s", ATTR{type}=="1", KERNEL=="eth*",'
                        ' NAME="%s"\n' % (mac_addr, nic_name))
            f.write('# Generated by fuel-agent during provisioning: END\n')
        # FIXME(agordeev): Disable net-generator that will add new etries to
        # 70-persistent-net.rules
        with open(
                chroot + '/etc/udev/rules.d/75-persistent-net-generator.rules',
                'w') as f:
            f.write('# Generated by fuel-agent during provisioning:\n'
                    '# DO NOT DELETE. It is needed to disable net-generator\n')

        # FIXME(kozhukalov): Prevent nailgun-agent from doing anything.
        # This ugly hack is to be used together with the command removing
        # this lock file not earlier than /etc/rc.local
        # The reason for this hack to appear is to prevent nailgun-agent from
        # changing mcollective config at the same time when cloud-init
        # does the same. Otherwise, we can end up with corrupted mcollective
        # config. For details see https://bugs.launchpad.net/fuel/+bug/1449186
        LOG.debug('Preventing nailgun-agent from doing '
                  'anything until it is unlocked')
        utils.makedirs_if_not_exists(os.path.join(chroot, 'etc/nailgun-agent'))
        with open(os.path.join(chroot, 'etc/nailgun-agent/nodiscover'), 'w'):
            pass

        with open(chroot + '/etc/fstab', 'wb') as f:
            for fs in self.driver.partition_scheme.fss:
                # TODO(kozhukalov): Think of improving the logic so as to
                # insert a meaningful fsck order value which is last zero
                # at fstab line. Currently we set it into 0 which means
                # a corresponding file system will never be checked. We assume
                # puppet or other configuration tool will care of it.
                f.write('UUID=%s %s %s defaults 0 0\n' %
                        (mount2uuid[fs.mount], fs.mount, fs.type))

        self.umount_target(chroot)
Exemple #5
0
    def do_bootloader(self):
        LOG.debug('--- Installing bootloader (do_bootloader) ---')
        chroot = '/tmp/target'
        self.mount_target(chroot)

        mount2uuid = {}
        for fs in self.driver.partition_scheme.fss:
            mount2uuid[fs.mount] = utils.execute(
                'blkid', '-o', 'value', '-s', 'UUID', fs.device,
                check_exit_code=[0])[0].strip()

        if '/' not in mount2uuid:
            raise errors.WrongPartitionSchemeError(
                'Error: device with / mountpoint has not been found')

        grub = self.driver.grub

        guessed_version = gu.guess_grub_version(chroot=chroot)
        if guessed_version != grub.version:
            grub.version = guessed_version
            LOG.warning('Grub version differs from which the operating system '
                        'should have by default. Found version in image: '
                        '{0}'.format(guessed_version))
        boot_device = self.driver.partition_scheme.boot_device(grub.version)
        install_devices = [d.name for d in self.driver.partition_scheme.parteds
                           if d.install_bootloader]

        grub.append_kernel_params('root=UUID=%s ' % mount2uuid['/'])

        kernel = grub.kernel_name or \
            gu.guess_kernel(chroot=chroot, regexp=grub.kernel_regexp)
        initrd = grub.initrd_name or \
            gu.guess_initrd(chroot=chroot, regexp=grub.initrd_regexp)

        if grub.version == 1:
            gu.grub1_cfg(kernel=kernel, initrd=initrd,
                         kernel_params=grub.kernel_params, chroot=chroot,
                         grub_timeout=CONF.grub_timeout)
            gu.grub1_install(install_devices, boot_device, chroot=chroot)
        else:
            # TODO(kozhukalov): implement which kernel to use by default
            # Currently only grub1_cfg accepts kernel and initrd parameters.
            gu.grub2_cfg(kernel_params=grub.kernel_params, chroot=chroot,
                         grub_timeout=CONF.grub_timeout)
            gu.grub2_install(install_devices, chroot=chroot)

        if CONF.fix_udev_net_rules:
            # FIXME(agordeev) There's no convenient way to perfrom NIC
            # remapping in Ubuntu, so injecting files prior the first boot
            # should work
            with open(chroot + '/etc/udev/rules.d/70-persistent-net.rules',
                      'wt', encoding='utf-8') as f:
                f.write(u'# Generated by fuel-agent during provisioning: '
                        u'BEGIN\n')
                # pattern is aa:bb:cc:dd:ee:ff_eth0,aa:bb:cc:dd:ee:ff_eth1
                for mapping in self.driver.configdrive_scheme.\
                        common.udevrules.split(','):
                    mac_addr, nic_name = mapping.split('_')
                    f.write(u'SUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*", '
                            u'ATTR{address}=="%s", ATTR{type}=="1", '
                            u'KERNEL=="eth*", NAME="%s"\n' % (mac_addr,
                                                              nic_name))
                f.write(
                    u'# Generated by fuel-agent during provisioning: END\n')
            # FIXME(agordeev): Disable net-generator that will add new etries
            # to 70-persistent-net.rules
            with open(chroot +
                      '/etc/udev/rules.d/75-persistent-net-generator.rules',
                      'wt', encoding='utf-8') as f:
                f.write(u'# Generated by fuel-agent during provisioning:\n'
                        u'# DO NOT DELETE. It is needed to disable '
                        u'net-generator\n')

        # FIXME(kozhukalov): Prevent nailgun-agent from doing anything.
        # This ugly hack is to be used together with the command removing
        # this lock file not earlier than /etc/rc.local
        # The reason for this hack to appear is to prevent nailgun-agent from
        # changing mcollective config at the same time when cloud-init
        # does the same. Otherwise, we can end up with corrupted mcollective
        # config. For details see https://bugs.launchpad.net/fuel/+bug/1449186
        LOG.debug('Preventing nailgun-agent from doing '
                  'anything until it is unlocked')
        utils.makedirs_if_not_exists(os.path.join(chroot, 'etc/nailgun-agent'))
        with open(os.path.join(chroot, 'etc/nailgun-agent/nodiscover'), 'w'):
            pass

        # FIXME(kozhukalov): When we have just os-root fs image and don't have
        # os-var-log fs image while / and /var/log are supposed to be
        # separate file systems and os-var-log is mounted into
        # non-empty directory on the / file system, those files in /var/log
        # directory become unavailable.
        # The thing is that among those file there is /var/log/upstart
        # where upstart daemon writes its logs. We have specific upstart job
        # which is to flush open files once all file systems are mounted.
        # This job needs upstart directory to be available on os-var-log
        # file system.
        # This is just a temporary fix and correct fix will be available soon
        # via updates.
        utils.execute('mkdir', '-p', chroot + '/var/log/upstart')

        with open(chroot + '/etc/fstab', 'wt', encoding='utf-8') as f:
            for fs in self.driver.partition_scheme.fss:
                # TODO(kozhukalov): Think of improving the logic so as to
                # insert a meaningful fsck order value which is last zero
                # at fstab line. Currently we set it into 0 which means
                # a corresponding file system will never be checked. We assume
                # puppet or other configuration tool will care of it.
                if fs.mount == '/':
                    f.write('UUID=%s %s %s defaults,errors=panic 0 0\n' %
                            (mount2uuid[fs.mount], fs.mount, fs.type))
                else:
                    f.write('UUID=%s %s %s defaults 0 0\n' %
                            (mount2uuid[fs.mount], fs.mount, fs.type))

        self.umount_target(chroot)
Exemple #6
0
    def do_bootloader(self):
        LOG.debug('--- Installing bootloader (do_bootloader) ---')
        chroot = '/tmp/target'
        self.mount_target(chroot)

        mount2uuid = {}
        for fs in self.driver.partition_scheme.fss:
            mount2uuid[fs.mount] = utils.execute(
                'blkid', '-o', 'value', '-s', 'UUID', fs.device,
                check_exit_code=[0])[0].strip()

        grub = self.driver.grub

        grub.version = gu.guess_grub_version(chroot=chroot)
        boot_device = self.driver.partition_scheme.boot_device(grub.version)
        install_devices = [d.name for d in self.driver.partition_scheme.parteds
                           if d.install_bootloader]

        grub.append_kernel_params('root=UUID=%s ' % mount2uuid['/'])

        kernel = grub.kernel_name or \
            gu.guess_kernel(chroot=chroot, regexp=grub.kernel_regexp)
        initrd = grub.initrd_name or \
            gu.guess_initrd(chroot=chroot, regexp=grub.initrd_regexp)

        if grub.version == 1:
            gu.grub1_cfg(kernel=kernel, initrd=initrd,
                         kernel_params=grub.kernel_params, chroot=chroot)
            gu.grub1_install(install_devices, boot_device, chroot=chroot)
        else:
            # TODO(kozhukalov): implement which kernel to use by default
            # Currently only grub1_cfg accepts kernel and initrd parameters.
            gu.grub2_cfg(kernel_params=grub.kernel_params, chroot=chroot)
            gu.grub2_install(install_devices, chroot=chroot)

        # FIXME(agordeev) There's no convenient way to perfrom NIC remapping in
        #  Ubuntu, so injecting files prior the first boot should work
        with open(chroot + '/etc/udev/rules.d/70-persistent-net.rules',
                  'w') as f:
            f.write('# Generated by fuel-agent during provisioning: BEGIN\n')
            # pattern is aa:bb:cc:dd:ee:ff_eth0,aa:bb:cc:dd:ee:ff_eth1
            for mapping in self.driver.configdrive_scheme.\
                    common.udevrules.split(','):
                mac_addr, nic_name = mapping.split('_')
                f.write('SUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*", '
                        'ATTR{address}=="%s", ATTR{type}=="1", KERNEL=="eth*",'
                        ' NAME="%s"\n' % (mac_addr, nic_name))
            f.write('# Generated by fuel-agent during provisioning: END\n')
        # FIXME(agordeev): Disable net-generator that will add new etries to
        # 70-persistent-net.rules
        with open(chroot +
                  '/etc/udev/rules.d/75-persistent-net-generator.rules',
                  'w') as f:
            f.write('# Generated by fuel-agent during provisioning:\n'
                    '# DO NOT DELETE. It is needed to disable net-generator\n')

        # FIXME(kozhukalov): Prevent nailgun-agent from doing anything.
        # This ugly hack is to be used together with the command removing
        # this lock file not earlier than /etc/rc.local
        # The reason for this hack to appear is to prevent nailgun-agent from
        # changing mcollective config at the same time when cloud-init
        # does the same. Otherwise, we can end up with corrupted mcollective
        # config. For details see https://bugs.launchpad.net/fuel/+bug/1449186
        LOG.debug('Preventing nailgun-agent from doing '
                  'anything until it is unlocked')
        utils.makedirs_if_not_exists(os.path.join(chroot, 'etc/nailgun-agent'))
        with open(os.path.join(chroot, 'etc/nailgun-agent/nodiscover'), 'w'):
            pass

        with open(chroot + '/etc/fstab', 'wb') as f:
            for fs in self.driver.partition_scheme.fss:
                # TODO(kozhukalov): Think of improving the logic so as to
                # insert a meaningful fsck order value which is last zero
                # at fstab line. Currently we set it into 0 which means
                # a corresponding file system will never be checked. We assume
                # puppet or other configuration tool will care of it.
                f.write('UUID=%s %s %s defaults 0 0\n' %
                        (mount2uuid[fs.mount], fs.mount, fs.type))

        self.umount_target(chroot)
Exemple #7
0
    def do_bootloader(self):
        LOG.debug('--- Installing bootloader (do_bootloader) ---')
        chroot = '/tmp/target'
        self.mount_target(chroot)

        mount2uuid = {}
        for fs in self.driver.partition_scheme.fss:
            mount2uuid[fs.mount] = utils.execute(
                'blkid', '-c', '/dev/null', '-o', 'value',
                '-s', 'UUID', fs.device,
                check_exit_code=[0])[0].strip()

        if '/' not in mount2uuid:
            raise errors.WrongPartitionSchemeError(
                'Error: device with / mountpoint has not been found')

        # NOTE(sslypushenko) Due to possible races between LVM and multipath,
        # we need to adjust LVM devices filter.
        # This code is required only for Ubuntu 14.04, because in trusty,
        # LVM filters, does not recognize partions on multipath devices
        # out of the box. It is fixed in latest LVM versions
        multipath_devs = [parted.name
                          for parted in self.driver.partition_scheme.parteds
                          if hw.is_multipath_device(parted.name)]
        # If there are no multipath devices on the node, we should not do
        # anything to prevent regression.
        if multipath_devs:
            # We need to explicitly whitelist each non-mutlipath device
            lvm_filter = []
            for parted in self.driver.partition_scheme.parteds:
                device = parted.name
                if device in multipath_devs:
                    continue
                # We use devlinks from /dev/disk/by-id instead of /dev/sd*,
                # because the first one are persistent.
                devlinks_by_id = [
                    link for link in hw.udevreport(device).get('DEVLINKS', [])
                    if link.startswith('/dev/disk/by-id/')]
                for link in devlinks_by_id:
                    lvm_filter.append(
                        'a|^{}(p)?(-part)?[0-9]*|'.format(link))

            # Multipath devices should be whitelisted. All other devlinks
            # should be blacklisted, to prevent LVM from grubbing underlying
            # multipath devices.
            lvm_filter.extend(CONF.lvm_filter_for_mpath)
            # Setting devices/preferred_names also helps LVM to find devices by
            # the proper devlinks
            bu.override_lvm_config(
                chroot,
                {'devices': {
                    'scan': CONF.mpath_lvm_scan_dirs,
                    'global_filter': lvm_filter,
                    'preferred_names': CONF.mpath_lvm_preferred_names}},
                lvm_conf_path=CONF.lvm_conf_path,
                update_initramfs=True)

        grub = self.driver.grub

        guessed_version = gu.guess_grub_version(chroot=chroot)
        if guessed_version != grub.version:
            grub.version = guessed_version
            LOG.warning('Grub version differs from which the operating system '
                        'should have by default. Found version in image: '
                        '{0}'.format(guessed_version))
        boot_device = self.driver.partition_scheme.boot_device(grub.version)
        install_devices = [d.name for d in self.driver.partition_scheme.parteds
                           if d.install_bootloader]

        grub.append_kernel_params('root=UUID=%s ' % mount2uuid['/'])

        kernel = grub.kernel_name or gu.guess_kernel(chroot=chroot,
                                                     regexp=grub.kernel_regexp)

        initrd = grub.initrd_name or gu.guess_initrd(chroot=chroot,
                                                     regexp=grub.initrd_regexp)

        if grub.version == 1:
            gu.grub1_cfg(kernel=kernel, initrd=initrd,
                         kernel_params=grub.kernel_params, chroot=chroot,
                         grub_timeout=CONF.grub_timeout)
            gu.grub1_install(install_devices, boot_device, chroot=chroot)
        else:
            # TODO(kozhukalov): implement which kernel to use by default
            # Currently only grub1_cfg accepts kernel and initrd parameters.
            gu.grub2_cfg(kernel_params=grub.kernel_params, chroot=chroot,
                         grub_timeout=CONF.grub_timeout)
            gu.grub2_install(install_devices, chroot=chroot)

        if CONF.fix_udev_net_rules:
            # FIXME(agordeev) There's no convenient way to perfrom NIC
            # remapping in Ubuntu, so injecting files prior the first boot
            # should work
            with open(chroot + '/etc/udev/rules.d/70-persistent-net.rules',
                      'wt', encoding='utf-8') as f:
                f.write(u'# Generated by fuel-agent during provisioning: '
                        u'BEGIN\n')
                # pattern is aa:bb:cc:dd:ee:ff_eth0,aa:bb:cc:dd:ee:ff_eth1
                for mapping in self.driver.configdrive_scheme. \
                        common.udevrules.split(','):
                    mac_addr, nic_name = mapping.split('_')
                    f.write(u'SUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*", '
                            u'ATTR{address}=="%s", ATTR{type}=="1", '
                            u'KERNEL=="eth*", NAME="%s"\n' % (mac_addr,
                                                              nic_name))
                f.write(
                    u'# Generated by fuel-agent during provisioning: END\n')
            # FIXME(agordeev): Disable net-generator that will add new etries
            # to 70-persistent-net.rules
            with open(chroot + '/etc/udev/rules.d/'
                               '75-persistent-net-generator.rules', 'wt',
                      encoding='utf-8') as f:
                f.write(u'# Generated by fuel-agent during provisioning:\n'
                        u'# DO NOT DELETE. It is needed to disable '
                        u'net-generator\n')

        # FIXME(kozhukalov): Prevent nailgun-agent from doing anything.
        # This ugly hack is to be used together with the command removing
        # this lock file not earlier than /etc/rc.local
        # The reason for this hack to appear is to prevent nailgun-agent from
        # changing mcollective config at the same time when cloud-init
        # does the same. Otherwise, we can end up with corrupted mcollective
        # config. For details see https://bugs.launchpad.net/fuel/+bug/1449186
        LOG.debug('Preventing nailgun-agent from doing '
                  'anything until it is unlocked')
        utils.makedirs_if_not_exists(os.path.join(chroot, 'etc/nailgun-agent'))
        with open(os.path.join(chroot, 'etc/nailgun-agent/nodiscover'), 'w'):
            pass

        # FIXME(kozhukalov): When we have just os-root fs image and don't have
        # os-var-log fs image while / and /var/log are supposed to be
        # separate file systems and os-var-log is mounted into
        # non-empty directory on the / file system, those files in /var/log
        # directory become unavailable.
        # The thing is that among those file there is /var/log/upstart
        # where upstart daemon writes its logs. We have specific upstart job
        # which is to flush open files once all file systems are mounted.
        # This job needs upstart directory to be available on os-var-log
        # file system.
        # This is just a temporary fix and correct fix will be available soon
        # via updates.
        utils.execute('mkdir', '-p', chroot + '/var/log/upstart')

        with open(chroot + '/etc/fstab', 'wt', encoding='utf-8') as f:
            for fs in self.driver.partition_scheme.fss:
                # TODO(kozhukalov): Think of improving the logic so as to
                # insert a meaningful fsck order value which is last zero
                # at fstab line. Currently we set it into 0 which means
                # a corresponding file system will never be checked. We assume
                # puppet or other configuration tool will care of it.
                if fs.mount == '/':
                    f.write(u'UUID=%s %s %s defaults,errors=panic 0 0\n' %
                            (mount2uuid[fs.mount], fs.mount, fs.type))
                else:
                    f.write(u'UUID=%s %s %s defaults 0 0\n' %
                            (mount2uuid[fs.mount], fs.mount, fs.type))

        self.umount_target(chroot)
Exemple #8
0
    def do_bootloader(self):
        LOG.debug('--- Installing bootloader (do_bootloader) ---')
        chroot = '/tmp/target'
        self.mount_target(chroot)

        mount2uuid = {}
        for fs in self.driver.partition_scheme.fss:
            mount2uuid[fs.mount] = utils.execute(
                'blkid',
                '-o',
                'value',
                '-s',
                'UUID',
                fs.device,
                check_exit_code=[0])[0].strip()

        if '/' not in mount2uuid:
            raise errors.WrongPartitionSchemeError(
                'Error: device with / mountpoint has not been found')

        grub = self.driver.grub

        guessed_version = gu.guess_grub_version(chroot=chroot)
        if guessed_version != grub.version:
            grub.version = guessed_version
            LOG.warning('Grub version differs from which the operating system '
                        'should have by default. Found version in image: '
                        '{0}'.format(guessed_version))
        boot_device = self.driver.partition_scheme.boot_device(grub.version)
        install_devices = [
            d.name for d in self.driver.partition_scheme.parteds
            if d.install_bootloader
        ]

        grub.append_kernel_params('root=UUID=%s ' % mount2uuid['/'])

        kernel = grub.kernel_name or \
            gu.guess_kernel(chroot=chroot, regexp=grub.kernel_regexp)
        initrd = grub.initrd_name or \
            gu.guess_initrd(chroot=chroot, regexp=grub.initrd_regexp)

        if grub.version == 1:
            gu.grub1_cfg(kernel=kernel,
                         initrd=initrd,
                         kernel_params=grub.kernel_params,
                         chroot=chroot,
                         grub_timeout=CONF.grub_timeout)
            gu.grub1_install(install_devices, boot_device, chroot=chroot)
        else:
            # TODO(kozhukalov): implement which kernel to use by default
            # Currently only grub1_cfg accepts kernel and initrd parameters.
            gu.grub2_cfg(kernel_params=grub.kernel_params,
                         chroot=chroot,
                         grub_timeout=CONF.grub_timeout)
            gu.grub2_install(install_devices, chroot=chroot)

        if CONF.fix_udev_net_rules:
            # FIXME(agordeev) There's no convenient way to perfrom NIC
            # remapping in Ubuntu, so injecting files prior the first boot
            # should work
            with open(chroot + '/etc/udev/rules.d/70-persistent-net.rules',
                      'wt',
                      encoding='utf-8') as f:
                f.write(u'# Generated by fuel-agent during provisioning: '
                        u'BEGIN\n')
                # pattern is aa:bb:cc:dd:ee:ff_eth0,aa:bb:cc:dd:ee:ff_eth1
                for mapping in self.driver.configdrive_scheme.\
                        common.udevrules.split(','):
                    mac_addr, nic_name = mapping.split('_')
                    f.write(u'SUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*", '
                            u'ATTR{address}=="%s", ATTR{type}=="1", '
                            u'KERNEL=="eth*", NAME="%s"\n' %
                            (mac_addr, nic_name))
                f.write(
                    u'# Generated by fuel-agent during provisioning: END\n')
            # FIXME(agordeev): Disable net-generator that will add new etries
            # to 70-persistent-net.rules
            with open(chroot +
                      '/etc/udev/rules.d/75-persistent-net-generator.rules',
                      'wt',
                      encoding='utf-8') as f:
                f.write(u'# Generated by fuel-agent during provisioning:\n'
                        u'# DO NOT DELETE. It is needed to disable '
                        u'net-generator\n')

        # FIXME(kozhukalov): Prevent nailgun-agent from doing anything.
        # This ugly hack is to be used together with the command removing
        # this lock file not earlier than /etc/rc.local
        # The reason for this hack to appear is to prevent nailgun-agent from
        # changing mcollective config at the same time when cloud-init
        # does the same. Otherwise, we can end up with corrupted mcollective
        # config. For details see https://bugs.launchpad.net/fuel/+bug/1449186
        LOG.debug('Preventing nailgun-agent from doing '
                  'anything until it is unlocked')
        utils.makedirs_if_not_exists(os.path.join(chroot, 'etc/nailgun-agent'))
        with open(os.path.join(chroot, 'etc/nailgun-agent/nodiscover'), 'w'):
            pass

        # FIXME(kozhukalov): When we have just os-root fs image and don't have
        # os-var-log fs image while / and /var/log are supposed to be
        # separate file systems and os-var-log is mounted into
        # non-empty directory on the / file system, those files in /var/log
        # directory become unavailable.
        # The thing is that among those file there is /var/log/upstart
        # where upstart daemon writes its logs. We have specific upstart job
        # which is to flush open files once all file systems are mounted.
        # This job needs upstart directory to be available on os-var-log
        # file system.
        # This is just a temporary fix and correct fix will be available soon
        # via updates.
        utils.execute('mkdir', '-p', chroot + '/var/log/upstart')

        with open(chroot + '/etc/fstab', 'wt', encoding='utf-8') as f:
            for fs in self.driver.partition_scheme.fss:
                # TODO(kozhukalov): Think of improving the logic so as to
                # insert a meaningful fsck order value which is last zero
                # at fstab line. Currently we set it into 0 which means
                # a corresponding file system will never be checked. We assume
                # puppet or other configuration tool will care of it.
                if fs.mount == '/':
                    f.write(u'UUID=%s %s %s defaults,errors=panic 0 0\n' %
                            (mount2uuid[fs.mount], fs.mount, fs.type))
                else:
                    f.write(u'UUID=%s %s %s defaults 0 0\n' %
                            (mount2uuid[fs.mount], fs.mount, fs.type))

        self.umount_target(chroot)