Example #1
0
class ChrootInstaller(BaseInstaller):
    # we may need more __init__ args later
    def __init__(self, conn):
        BaseInstaller.__init__(self, conn)
        self._bootstrapped = False
        self._install_finished = False

        self._processes = [
            'ready_target', 'bootstrap', 'mount_target_proc',
            'mount_target_sys', 'make_device_entries', 'mount_target_devpts',
            'apt_sources_installer', 'ready_base_for_install', 'pre_install',
            'install', 'post_install', 'apt_sources_final',
            'umount_target_sys', 'umount_target_proc'
        ]
        # pre_install is unmapped
        # post_install is unmapped
        self._process_map = dict(
            ready_target=self.create_target_directory,
            bootstrap=self.bootstrap_target,
            mount_target_proc=self.mount_target_proc,
            mount_target_sys=self.mount_target_sys,
            make_device_entries=self.make_device_entries,
            mount_target_devpts=self.mount_target_devpts,
            apt_sources_installer=self.apt_sources_installer,
            ready_base_for_install=self.ready_base_for_install,
            install=self.install,
            apt_sources_final=self.apt_sources_final,
            umount_target_sys=self.umount_target_sys,
            umount_target_proc=self.umount_target_proc)
        # this is only used in the machine installer
        self.mtypedata = {}

    # the default script for the chroot installer is None
    def make_script(self, procname):
        return None

    def set_logfile(self, logfile):
        BaseInstaller.set_logfile(self, logfile)
        self.log.info('-' * 30)
        msg = '%s initialized' % self.__class__.__name__
        self.log.info(msg)
        self.log.info('-' * 30)

    @requires_target_set
    def set_profile(self, profile):
        self.installer = ProfileInstaller(self)
        self.installer.mtypedata.update(self.mtypedata)
        self.installer.set_profile(profile)
        self.set_suite(self.installer.suite)

    @requires_target_exists
    def _bootstrap_with_tarball(self, suite):
        suite_path = path(self.defenv.get('installer', 'suite_storage'))
        filename = '%s.tar.gz' % suite
        basefile = suite_path / filename
        taropts = '-xzf'
        if not basefile.exists():
            filename = '%s.tar' % suite
            basefile = suite_path / filename
            taropts = '-xf'
        cmd = 'tar -C %s %s %s' % (self.target, taropts, basefile)
        # if cmd returns nonzero, runlog will raise an error
        runlog(cmd)
        # we need to do certain things here that debootstrap
        # does for us, like copy /etc/resolv.conf
        self._bootstrapped = True

    @requires_target_exists
    def _bootstrap_with_debootstrap(self, suite):
        mirror = self.defenv.get('installer', 'http_mirror')
        cmd = debootstrap(suite, self.target, mirror)
        # if cmd returns nonzero, runlog will raise an error
        runlog(cmd)
        self._bootstrapped = True

    @requires_suite_set
    def bootstrap_target(self):
        if not self.target.exists():
            self.target.mkdir()
        if not self.target.isdir():
            raise InstallTargetError, "%s is not a directory" % self.target
        if self.defenv.getboolean('installer', 'bootstrap_target'):
            self.log.info('bootstrapping with debootstrap')
            self._bootstrap_with_debootstrap(self.base_suite)
        else:
            self.log.info('bootstrapping with premade tarball')
            self._bootstrap_with_tarball(self.base_suite)
        # here we add the apt keys that are needed
        aptkeys = AptKeyHandler(self.conn)
        keys = self.defenv.get_list('archive_keys', 'installer')
        for key in keys:
            row = aptkeys.get_row(key)
            filename = self.target / ('%s.key' % key)
            if filename.exists():
                raise RuntimeError, "%s already exists" % filename
            keyfile = file(filename, 'w')
            keyfile.write(row.data)
            keyfile.close()
            #self.chroot('apt-key add %s.key' % key)
            self.chroot(['apt-key', 'add', '%s.key' % key])
            os.remove(filename)
            if filename.exists():
                raise RuntimeError, "%s wasn't deleted" % filename
            self.log.info('added key %s (%s) to apt' % (key, row.keyid))

    @requires_bootstrap
    def make_device_entries(self):
        self.log.info('nothing done for make_device_entries yet')

    @requires_bootstrap
    def apt_sources_installer(self):
        make_sources_list(self.conn, self.target, self.suite)

    @requires_install_complete
    def apt_sources_final(self):
        sourceslist = self.target / 'etc/apt/sources.list'
        sourceslist_installer = path('%s.installer' % sourceslist)
        os.rename(sourceslist, sourceslist_installer)
        make_official_sources_list(self.conn, self.target, self.suite)

    # this is probably not useful anymore
    # it still has a purpose in the machine installer -
    #  it sets up the mdadm.conf file with the raid devices it creates
    #  if it creates any.
    @requires_bootstrap
    def ready_base_for_install(self):
        # update the package lists
        #self.chroot('apt-get -y update')
        self.chroot(['apt-get', '-y', 'update'])

    # common method for mounting /proc and /sys
    # here fs is either 'proc' or 'sys' or 'devpts'
    def _mount_target_virtfs(self, fs):
        fstype = dict(proc='proc', sys='sysfs', devpts='devpts')
        target = self.target / fs
        if fs == 'devpts':
            target = self.target / 'dev' / 'pts'
        if not target.isdir():
            target.mkdir()
        #cmd = 'mount -t %s none %s' % (fstype[fs], target)
        cmd = ['mount', '-t', fstype[fs], 'none', str(target)]
        runlog(cmd)

    def _umount_target_virtfs(self, fs):
        # work around binfmt-support /proc locking
        # found this idea while messing around in live-helper
        target = self.target / fs
        if fs == 'proc':
            binfmt_misc = self.target / 'proc/sys/fs/binfmt_misc'
            status = binfmt_misc / 'status'
            if status.exists():
                self.log.info('Unmounting /proc/sys/fs/binfmt_misc in chroot')
                #cmd = 'umount %s' % binfmt
                cmd = ['umount', str(binfmt_misc)]
                runlog(cmd)
        if fs == 'devpts':
            target = self.target / 'dev' / 'pts'
        #cmd = 'umount %s' % target
        cmd = ['umount', str(target)]
        runlog(cmd)

    def _target_proc_mounted(self):
        testfile = self.target / 'proc/version'
        return testfile.isfile()

    def _target_sys_mounted(self):
        testdir = self.target / 'sys/kernel'
        return testdir.isdir()

    @requires_bootstrap
    def mount_target_proc(self):
        self._mount_target_virtfs('proc')

    @requires_bootstrap
    def mount_target_sys(self):
        self._mount_target_virtfs('sys')

    def mount_target_devpts(self):
        self._mount_target_virtfs('devpts')

    @requires_target_proc_mounted
    def umount_target_proc(self):
        self._umount_target_virtfs('proc')

    @requires_target_sys_mounted
    def umount_target_sys(self):
        self._umount_target_virtfs('sys')

    def umount_target_devpts(self):
        self._umount_target_virtfs('devpts')

    @requires_target_proc_mounted
    @requires_target_sys_mounted
    @requires_installer_set
    def install(self):
        self.installer.run_all_processes()
        self._install_finished = True

    def log_all_processes_finished(self):
        self.log.info('-' * 30)
        self.log.info('%s processes finished' % self.__class__.__name__)
        self.log.info('-' * 30)

    def save_logfile_in_target(self):
        install_log = self.target / 'root/paella/install.log'
        self.mainlog.filename.copyfile(install_log)
Example #2
0
class ChrootInstaller(BaseChrootInstaller):
    # we may need more __init__ args later
    def __init__(self, conn):
        BaseChrootInstaller.__init__(self, conn)
        self._bootstrapped = False
        self._install_finished = False
        
        self._processes = [
            'ready_target',
            'bootstrap',
            'mount_target_proc',
            'mount_target_sys',
            'make_device_entries',
            'mount_target_devpts',
            'apt_sources_installer',
            'ready_base_for_install',
            'pre_install',
            'install',
            'post_install',
            'apt_sources_final',
            'umount_target_sys',
            'umount_target_proc',
            'umount_target_devpts'
            ]
        # pre_install is unmapped
        # post_install is unmapped
        self._process_map = dict(ready_target=self.create_target_directory,
                                 bootstrap=self.bootstrap_target,
                                 mount_target_proc=self.mount_target_proc,
                                 mount_target_sys=self.mount_target_sys,
                                 make_device_entries=self.make_device_entries,
                                 mount_target_devpts=self.mount_target_devpts,
                                 apt_sources_installer=self.apt_sources_installer,
                                 ready_base_for_install=self.ready_base_for_install,
                                 install=self.install,
                                 apt_sources_final=self.apt_sources_final,
                                 umount_target_sys=self.umount_target_sys,
                                 umount_target_proc=self.umount_target_proc,
                                 umount_target_devpts=self.umount_target_devpts
                                 )
        # this is only used in the machine installer
        self.machine_data = {}
    
    # the default script for the chroot installer is None
    def make_script(self, procname):
        return None

    def set_logfile(self, logfile):
        BaseInstaller.set_logger(self, filename=logfile)
        self.log.info('-'*30)
        msg = '%s initialized' % self.__class__.__name__
        self.log.info(msg)
        self.log.info('-'*30)
        
    def set_profile(self, profile):
        self.check_target_set()
        self.installer = ProfileInstaller(self)
        if os.environ.has_key('DEBUG'):
            self.log.info("ChrootInstaller.machine_data: %s" % self.machine_data)
        self.installer.machine_data.update(self.machine_data)
        if os.environ.has_key('DEBUG'):
            self.log.info("ProfileInstaller.machine_data: %s" % self.installer.machine_data)
        self.installer.set_profile(profile)
        self.set_suite(self.installer.suite)
    
    
    def _bootstrap_with_tarball(self, suite):
        self.check_target_exists()
        suite_path = path(self.defenv.get('installer', 'suite_storage'))
        arch = get_architecture()
        filename = '%s-%s.tar.gz' % (suite, arch)
        basefile = suite_path / filename
        taropts = '-xzf'
        # we normally expect a tar.gz
        # but we'll check for a plain tar also
        if not basefile.exists():
            filename = '%s-%s.tar' % (suite, arch)
            basefile = suite_path / filename
            taropts = '-xf'
        if not basefile.exists():
            # We don't really want to ruin an install
            # by not having a tarball, so we log a warning
            # and proceed with a debootstrap.
            msg = "base tarball not found, reverting to debootstrap"
            self.log.warn(msg)
            self._bootstrap_with_debootstrap(suite)
        else:
            #cmd = 'tar -C %s %s %s' % (self.target, taropts, basefile)
            cmd = ['tar', '-C', str(self.target), taropts, str(basefile)]
            # if cmd returns nonzero, runlog will raise an error
            runlog(cmd)
            # we need to do certain things after extraction
            # that debootstrap does for us,
            # like copy /etc/resolv.conf to the target.
            # these things should be done in the
            # ready_base_for_install process
            
            # this is now done in post_process
            #self._bootstrapped = True
            
    def _bootstrap_with_debootstrap(self, suite):
        self.check_target_exists()
        mirror = self.defenv.get('installer', 'http_mirror')
        # debug stuff
        cmd = debootstrap(suite, self.target, mirror)
        # if cmd returns nonzero, runlog will raise an error
        runlog(cmd)
        # this is now done in post_process
        #self._bootstrapped = True

    def bootstrap_target(self):
        self.check_suite_set()
        if not self.target.exists():
            self.target.mkdir()
        if not self.target.isdir():
            raise InstallTargetError, "%s is not a directory" % self.target
        if self.defenv.getboolean('installer', 'bootstrap_target'):
            self.log.info('bootstrapping with debootstrap')
            self._bootstrap_with_debootstrap(self.base_suite)
        else:
            self.log.info('bootstrapping with premade tarball')
            self._bootstrap_with_tarball(self.base_suite)
        # here we add the apt keys that are needed
        # we should probably split this part off into
        # another process.  This step needs to be done
        # before the ready_base_for_install process, or
        # at least at the beginning of that process.
        aptkeys = AptKeyHandler(self.conn)
        keys = self.defenv.get_list('archive_keys', 'installer')
        for key in keys:
            try:
                row = aptkeys.get_row(key)
            except NoAptKeyError:
                msg = "There's no apt key named %s in the database" % key
                self.log.error(msg)
                raise UnsatisfiedRequirementsError , msg
            filename = self.target / ('%s.key' % key)
            if filename.exists():
                msg = "%s already exists" % filename
                self.log.error(msg)
                raise RuntimeError , msg
            keyfile = file(filename, 'w')
            keyfile.write(row.data)
            keyfile.close()
            self.chroot(['apt-key', 'add', '%s.key' % key])
            os.remove(filename)
            if filename.exists():
                msg = "%s wasn't deleted" % filename
                self.log.error(msg)
                raise RuntimeError , msg
            self.log.info('added key %s (%s) to apt' % (key, row.keyid))
        
    def make_device_entries(self):
        self.check_bootstrap()
        self.log.info('nothing done for make_device_entries yet')
        
    def apt_sources_installer(self):
        self.check_bootstrap()
        make_sources_list(self.conn, self.target, self.suite)
        
    def apt_sources_final(self):
        self.check_install_complete()
        sourceslist = self.target / 'etc/apt/sources.list'
        sourceslist_installer = path('%s.installer' % sourceslist)
        os.rename(sourceslist, sourceslist_installer)
        make_official_sources_list(self.conn, self.target, self.suite)

    
    def ready_base_for_install(self):
        """This gets the base that was either
        debootstrapped or extracted ready
        to install packages.  Since the
        install hasn't happened yet, replacing
        files like /etc/resolv.conf and the
        package lists shouldn't affect anything.
        the apt_sources_installer process is called
        right before this one, so there should be
        an appropriate sources.list to update packages
        with.
        """
        self.check_bootstrap()
        # 'copy' /etc/resolv.conf to target
        resolvconf = file('/etc/resolv.conf').read()
        target_resolvconf = self.target / 'etc/resolv.conf'
        target_resolvconf.write_text(resolvconf)
        # update the package lists
        self.chroot(['apt-get', '-y', 'update'])
        
        
    # common method for mounting /proc and /sys
    # here fs is either 'proc' or 'sys' or 'devpts'
    def _mount_target_virtfs(self, fs):
        fstype = dict(proc='proc', sys='sysfs', devpts='devpts')
        target = self.target / fs
        if fs == 'devpts':
            target = self.target / 'dev' / 'pts'
        if not target.isdir():
            self.log.info('creating %s' % target)
            target.mkdir()
        #cmd = 'mount -t %s none %s' % (fstype[fs], target)
        cmd = ['mount', '-t', fstype[fs], 'none', str(target)]
        runlog(cmd)
        
        
    def _umount_target_virtfs(self, fs):
        self.log.info('running umount for %s' % fs)
        # work around binfmt-support /proc locking
        # found this idea while messing around in live-helper
        target = self.target / fs
        if fs == 'proc':
            binfmt_misc = self.target / 'proc/sys/fs/binfmt_misc'
            status = binfmt_misc / 'status'
            if status.exists():
                self.log.info('Unmounting /proc/sys/fs/binfmt_misc in chroot')
                #cmd = 'umount %s' % binfmt
                cmd = ['umount', str(binfmt_misc)]
                runlog(cmd)
            # hack to stop mdadm on target
            mdstat = self.target / 'proc/mdstat'
            if mdstat.isfile():
                mdadm_initscript = self.target / 'etc/init.d/mdadm'
                if mdadm_initscript.isfile():
                    self.log.info("Stopping mdadm from running on target.")
                    cmd = ['chroot', self.target, '/etc/init.d/mdadm', 'stop']
                    runlog(cmd)
        if fs == 'devpts':
            target = self.target / 'dev' / 'pts'
        #cmd = 'umount %s' % target
        cmd = ['umount', str(target)]
        runlog(cmd)
        
    def _target_proc_mounted(self):
        testfile = self.target / 'proc/version'
        return testfile.isfile()

    def _target_sys_mounted(self):
        testdir = self.target / 'sys/kernel'
        return testdir.isdir()
    
    def mount_target_proc(self):
        self.check_bootstrap()
        self._mount_target_virtfs('proc')

    def mount_target_sys(self):
        self.check_bootstrap()
        self._mount_target_virtfs('sys')

    def mount_target_devpts(self):
        self.check_bootstrap()
        self._mount_target_virtfs('devpts')
        
    def umount_target_proc(self):
        self.check_target_proc_mounted()
        self._umount_target_virtfs('proc')

    def umount_target_sys(self):
        self.check_target_sys_mounted()
        self._umount_target_virtfs('sys')

    def umount_target_devpts(self):
        self._umount_target_virtfs('devpts')
        
    def install(self):
        self.check_target_proc_mounted()
        self.check_target_sys_mounted()
        self.check_installer_set()
        self.installer.run_all_processes()
        # this is now done in post_process
        #self._install_finished = True

    def log_all_processes_finished(self):
        self.log.info('-'*30)
        self.log.info('%s processes finished' % self.__class__.__name__)
        self.log.info('-'*30)

    def save_logfile_in_target(self):
        install_log = self.target / 'root/paella/install.log'
        self.mainlog.filename.copyfile(install_log)

    # if scripts are hooked into certain processes, we
    # need to mark those processes as being completed
    # in order for other processes to be run.
    def post_process(self, procname):
        name = self.__class__.__name__
        self.log.info('%s(%s) post_process' % (name, procname))
        if procname == 'bootstrap':
            self.log.info('%s marking %s finished' % (name, procname))
            self._bootstrapped = True
        elif procname == 'install':
            self.log.info('%s marking %s finished' % (name, procname))
            self._install_finished = True
Example #3
0
class ChrootInstaller(BaseInstaller):
    # we may need more __init__ args later
    def __init__(self, conn):
        BaseInstaller.__init__(self, conn)
        self._bootstrapped = False
        self._install_finished = False
        
        self._processes = [
            'ready_target',
            'bootstrap',
            'mount_target_proc',
            'mount_target_sys',
            'make_device_entries',
            'mount_target_devpts',
            'apt_sources_installer',
            'ready_base_for_install',
            'pre_install',
            'install',
            'post_install',
            'apt_sources_final',
            'umount_target_sys',
            'umount_target_proc'
            ]
        # pre_install is unmapped
        # post_install is unmapped
        self._process_map = dict(ready_target=self.create_target_directory,
                                 bootstrap=self.bootstrap_target,
                                 mount_target_proc=self.mount_target_proc,
                                 mount_target_sys=self.mount_target_sys,
                                 make_device_entries=self.make_device_entries,
                                 mount_target_devpts=self.mount_target_devpts,
                                 apt_sources_installer=self.apt_sources_installer,
                                 ready_base_for_install=self.ready_base_for_install,
                                 install=self.install,
                                 apt_sources_final=self.apt_sources_final,
                                 umount_target_sys=self.umount_target_sys,
                                 umount_target_proc=self.umount_target_proc
                                 )
        # this is only used in the machine installer
        self.mtypedata = {}
    
    # the default script for the chroot installer is None
    def make_script(self, procname):
        return None

    def set_logfile(self, logfile):
        BaseInstaller.set_logfile(self, logfile)
        self.log.info('-'*30)
        msg = '%s initialized' % self.__class__.__name__
        self.log.info(msg)
        self.log.info('-'*30)
        
    @requires_target_set
    def set_profile(self, profile):
        self.installer = ProfileInstaller(self)
        self.installer.mtypedata.update(self.mtypedata)
        self.installer.set_profile(profile)
        self.set_suite(self.installer.suite)
    
    
    @requires_target_exists
    def _bootstrap_with_tarball(self, suite):
        suite_path = path(self.defenv.get('installer', 'suite_storage'))
        filename = '%s.tar.gz' % suite
        basefile = suite_path / filename
        taropts = '-xzf'
        if not basefile.exists():
            filename = '%s.tar' % suite
            basefile = suite_path / filename
            taropts = '-xf'
        cmd = 'tar -C %s %s %s' % (self.target, taropts, basefile)
        # if cmd returns nonzero, runlog will raise an error
        runlog(cmd)
        # we need to do certain things here that debootstrap
        # does for us, like copy /etc/resolv.conf
        self._bootstrapped = True
            
    @requires_target_exists
    def _bootstrap_with_debootstrap(self, suite):
        mirror = self.defenv.get('installer', 'http_mirror')
        cmd = debootstrap(suite, self.target, mirror)
        # if cmd returns nonzero, runlog will raise an error
        runlog(cmd)
        self._bootstrapped = True

    @requires_suite_set
    def bootstrap_target(self):
        if not self.target.exists():
            self.target.mkdir()
        if not self.target.isdir():
            raise InstallTargetError, "%s is not a directory" % self.target
        if self.defenv.getboolean('installer', 'bootstrap_target'):
            self.log.info('bootstrapping with debootstrap')
            self._bootstrap_with_debootstrap(self.base_suite)
        else:
            self.log.info('bootstrapping with premade tarball')
            self._bootstrap_with_tarball(self.base_suite)
        # here we add the apt keys that are needed
        aptkeys = AptKeyHandler(self.conn)
        keys = self.defenv.get_list('archive_keys', 'installer')
        for key in keys:
            row = aptkeys.get_row(key)
            filename = self.target / ('%s.key' % key)
            if filename.exists():
                raise RuntimeError, "%s already exists" % filename
            keyfile = file(filename, 'w')
            keyfile.write(row.data)
            keyfile.close()
            #self.chroot('apt-key add %s.key' % key)
            self.chroot(['apt-key', 'add', '%s.key' % key])
            os.remove(filename)
            if filename.exists():
                raise RuntimeError, "%s wasn't deleted" % filename
            self.log.info('added key %s (%s) to apt' % (key, row.keyid))
        
    @requires_bootstrap
    def make_device_entries(self):
        self.log.info('nothing done for make_device_entries yet')
        
    @requires_bootstrap
    def apt_sources_installer(self):
        make_sources_list(self.conn, self.target, self.suite)
        
    @requires_install_complete
    def apt_sources_final(self):
        sourceslist = self.target / 'etc/apt/sources.list'
        sourceslist_installer = path('%s.installer' % sourceslist)
        os.rename(sourceslist, sourceslist_installer)
        make_official_sources_list(self.conn, self.target, self.suite)

    # this is probably not useful anymore
    # it still has a purpose in the machine installer -
    #  it sets up the mdadm.conf file with the raid devices it creates
    #  if it creates any.
    @requires_bootstrap
    def ready_base_for_install(self):
        # update the package lists
        #self.chroot('apt-get -y update')
        self.chroot(['apt-get', '-y', 'update'])
        
        
    # common method for mounting /proc and /sys
    # here fs is either 'proc' or 'sys' or 'devpts'
    def _mount_target_virtfs(self, fs):
        fstype = dict(proc='proc', sys='sysfs', devpts='devpts')
        target = self.target / fs
        if fs == 'devpts':
            target = self.target / 'dev' / 'pts'
        if not target.isdir():
            target.mkdir()
        #cmd = 'mount -t %s none %s' % (fstype[fs], target)
        cmd = ['mount', '-t', fstype[fs], 'none', str(target)]
        runlog(cmd)
        
        
    def _umount_target_virtfs(self, fs):
        # work around binfmt-support /proc locking
        # found this idea while messing around in live-helper
        target = self.target / fs
        if fs == 'proc':
            binfmt_misc = self.target / 'proc/sys/fs/binfmt_misc'
            status = binfmt_misc / 'status'
            if status.exists():
                self.log.info('Unmounting /proc/sys/fs/binfmt_misc in chroot')
                #cmd = 'umount %s' % binfmt
                cmd = ['umount', str(binfmt_misc)]
                runlog(cmd)
        if fs == 'devpts':
            target = self.target / 'dev' / 'pts'
        #cmd = 'umount %s' % target
        cmd = ['umount', str(target)]
        runlog(cmd)
        
    def _target_proc_mounted(self):
        testfile = self.target / 'proc/version'
        return testfile.isfile()

    def _target_sys_mounted(self):
        testdir = self.target / 'sys/kernel'
        return testdir.isdir()
    
    @requires_bootstrap
    def mount_target_proc(self):
        self._mount_target_virtfs('proc')

    @requires_bootstrap
    def mount_target_sys(self):
        self._mount_target_virtfs('sys')

    def mount_target_devpts(self):
        self._mount_target_virtfs('devpts')
        
    @requires_target_proc_mounted
    def umount_target_proc(self):
        self._umount_target_virtfs('proc')

    @requires_target_sys_mounted
    def umount_target_sys(self):
        self._umount_target_virtfs('sys')

    def umount_target_devpts(self):
        self._umount_target_virtfs('devpts')
        
    @requires_target_proc_mounted
    @requires_target_sys_mounted
    @requires_installer_set
    def install(self):
        self.installer.run_all_processes()
        self._install_finished = True

    def log_all_processes_finished(self):
        self.log.info('-'*30)
        self.log.info('%s processes finished' % self.__class__.__name__)
        self.log.info('-'*30)

    def save_logfile_in_target(self):
        install_log = self.target / 'root/paella/install.log'
        self.mainlog.filename.copyfile(install_log)