Пример #1
0
def install_packages_uml(conn, suite, profile, target):
    traits = get_traits(conn, profile)
    tp = TraitParent(conn, suite)
    pp = TraitPackage(conn, suite)
    packages = ' '.join([p.package for p in pp.all_packages(traits, tp)])
    os.system('chroot %s apt-get update' % target)
    os.system('chroot %s apt-get -y install %s' % (target, packages))
Пример #2
0
    def __init__(self, conn, suite, target):
        # target should already be a path object
        self.target = path(target)
        self.trait = None

        # setup relation objects
        self.traitpackage = TraitPackage(conn, suite)
        self.traittemplate = TraitTemplate(conn, suite)
        self.traitscripts = TraitScript(conn, suite)

        # setup empty variable containers
        self.profiledata = {}
        self.machine_data = {}
        self.familydata = {}

        # It's odd, but running the same
        # code for setting debconf selections
        # returns a 1 on the preseed process, yet
        # returns a 0 when it's done during
        # the templates process.
        # -- I found the problem, debconf reports
        #    an error if the question doesn't exist
        #    yet.
        # This attribute helps keep track of the
        # problem, and will run the debconf
        # selections during the templates
        # process, if the value is True.
        # I don't really like this, but it seems
        # to work for now, so I'm going to leave
        # it as is, and come up with a better
        # solution later.
        self.debconf_problem = False
Пример #3
0
def install_packages_uml(conn, suite, profile, target):
    traits = get_traits(conn, profile)
    tp = TraitParent(conn, suite)
    pp = TraitPackage(conn, suite)
    packages = ' '.join([p.package for p in pp.all_packages(traits, tp)])
    os.system('chroot %s apt-get update' % target)
    os.system('chroot %s apt-get -y install %s' % (target, packages))
Пример #4
0
    def __init__(self, conn, suite, target):
        # target should already be a path object
        self.target = path(target)
        self.trait = None

        # setup relation objects
        self.traitpackage = TraitPackage(conn, suite)
        self.traittemplate = TraitTemplate(conn, suite)
        self.traitscripts = TraitScript(conn, suite)

        # setup empty variable containers
        self.profiledata = {}
        self.mtypedata = {}
        self.familydata = {}
Пример #5
0
    def __init__(self, conn, suite, target):
        # target should already be a path object
        self.target = path(target)
        self.trait = None

        # setup relation objects
        self.traitpackage = TraitPackage(conn, suite)
        self.traittemplate = TraitTemplate(conn, suite)
        self.traitscripts = TraitScript(conn, suite)

        # setup empty variable containers
        self.profiledata = {}
        self.machine_data = {}
        self.familydata = {}

        # It's odd, but running the same
        # code for setting debconf selections
        # returns a 1 on the preseed process, yet
        # returns a 0 when it's done during
        # the templates process.
        # -- I found the problem, debconf reports
        #    an error if the question doesn't exist
        #    yet.
        # This attribute helps keep track of the
        # problem, and will run the debconf
        # selections during the templates
        # process, if the value is True.
        # I don't really like this, but it seems
        # to work for now, so I'm going to leave
        # it as is, and come up with a better
        # solution later.
        self.debconf_problem = False
Пример #6
0
    def __init__(self, conn, suite):
        Installer.__init__(self, conn)
        self.traitpackage = TraitPackage(conn, suite)
        self.traittemplate = TraitTemplate(conn, suite)
        self.traitscripts = TraitScript(conn, suite)
        self.profiledata = {}
        self.mtypedata = {}
        self.familydata = {}
        self.trait_processes = DEFAULT_PROCESSES
        if self.defenv.has_option('installer', 'trait_processes'):
            self.trait_processes = self.defenv.get_list(
                'trait_processes', 'installer')

        self._process_map = {
            'pre': self._process_pre,
            'remove': self._process_remove,
            'install': self._process_install,
            'templates': self._process_templates,
            'config': self._process_config,
            'chroot': self._process_chroot,
            'reconfig': self._process_reconfig,
            'post': self._process_post
        }
Пример #7
0
    def __init__(self, conn, suite, target):
        # target should already be a path object
        self.target = path(target)
        self.trait = None
        
        # setup relation objects
        self.traitpackage = TraitPackage(conn, suite)
        self.traittemplate = TraitTemplate(conn, suite)
        self.traitscripts = TraitScript(conn, suite)

        # setup empty variable containers
        self.profiledata = {}
        self.mtypedata = {}
        self.familydata = {}
Пример #8
0
 def __init__(self, conn, suite):
     Installer.__init__(self, conn)
     self.traitpackage = TraitPackage(conn, suite)
     self.traittemplate = TraitTemplate(conn, suite)
     self.traitscripts = TraitScript(conn, suite)
     self.profiledata = {}
     self.mtypedata = {}
     self.familydata = {}
     self.trait_processes = DEFAULT_PROCESSES
     if self.defenv.has_option('installer', 'trait_processes'):
         self.trait_processes = self.defenv.get_list('trait_processes', 'installer')
         
     self._process_map = {
         'pre' : self._process_pre,
         'remove' : self._process_remove,
         'install' : self._process_install,
         'templates' : self._process_templates,
         'config' : self._process_config,
         'chroot' : self._process_chroot,
         'reconfig' : self._process_reconfig,
         'post' : self._process_post
         }
Пример #9
0
class TraitInstallerHelper(object):
    def __init__(self, conn, suite, target):
        # target should already be a path object
        self.target = path(target)
        self.trait = None
        
        # setup relation objects
        self.traitpackage = TraitPackage(conn, suite)
        self.traittemplate = TraitTemplate(conn, suite)
        self.traitscripts = TraitScript(conn, suite)

        # setup empty variable containers
        self.profiledata = {}
        self.machine_data = {}
        self.familydata = {}

        # It's odd, but running the same
        # code for setting debconf selections
        # returns a 1 on the preseed process, yet
        # returns a 0 when it's done during
        # the templates process.
        # -- I found the problem, debconf reports
        #    an error if the question doesn't exist
        #    yet.
        # This attribute helps keep track of the
        # problem, and will run the debconf
        # selections during the templates
        # process, if the value is True.
        # I don't really like this, but it seems
        # to work for now, so I'm going to leave
        # it as is, and come up with a better
        # solution later.
        self.debconf_problem = False

    def set_trait(self, trait):
        self.traitpackage.set_trait(trait)
        self.traittemplate.set_trait(trait)
        self.traitscripts.set_trait(trait)
        self.trait = trait
        self.packages = self.traitpackage.packages()
        self.templates = self.traittemplate.templates()
        os.environ['PAELLA_TRAIT'] = trait
        #self.log.info('trait set to %s' % trait)

    # helper to run commands in a chroot on the target
    def chroot(self, command, failure_suppressed=False):
        # we need to remove this if/else when we're sure
        # we don't need it anymore
        if type(command) is list:
            cmd = ['chroot', str(self.target)] + command
        else:
            cmd = 'chroot %s %s' % (self.target, command)
        return runlog(cmd, failure_suppressed=failure_suppressed)
        
    def remove_packages(self, packages):
        if packages:
            #packages_arg = ' '.join(packages)
            #command = 'apt-get -y remove %s' % packages_arg
            command = ['apt-get', '-y', 'remove'] + packages
            self.chroot(command)
        else:
            self.log.info('No packages to remove')
        
    def install_packages(self, packages, unauthenticated=False):
        if packages:
            #packages_arg = ' '.join(packages)
            opts = []
            if unauthenticated:
                opts.append('--allow-unauthenticated')
            #command = 'apt-get -y %s install %s' % (opts, packages_arg)
            command = ['apt-get', '-y'] + opts + ['install'] + packages
            stmt = 'install command for trait %s is:  %s' % (self.trait, ' '.join(command))
            self.log.info(stmt)
            self.chroot(command)
        else:
            self.log.info('No packages to install')
            
    def remove_cached_debs(self):
        archives = self.target / 'var/cache/apt/archives'
        partial = archives / 'partial'
        debs = archives.listdir('*.deb')
        pdebs = partial.listdir('*.deb')
        if pdebs:
            self.log.warn("we found some partial debs, and this shouldn't happen")
            raise RuntimeError , "partial debs found"
        all_debs = debs + pdebs
        for deb in all_debs:
            deb.remove()
            if deb.exists():
                raise RemoveDebsError, 'Failed to remove %s' % deb
            
    # order of updates is important here
    def _update_templatedata(self):
        self.traittemplate.template.update(self.familydata)
        self.traittemplate.template.update(self.profiledata)
        self.traittemplate.template.update(self.machine_data)

        
    def _make_template_common(self, template, tmpl):
        sub = self.traittemplate.template.sub()
        if tmpl != sub:
            self.log.info('template %s subbed' % (template.template))
        return sub

    def make_template(self, template):
        self.traittemplate.set_template(template.template)
        tmpl = self.traittemplate.template.template
        if tmpl.startswith('##cheetah'):
            self.log.info("%s is a cheetah template" % template.template)
        self._update_templatedata()
        return self._make_template_common(template, tmpl)
        

    def make_template_with_data(self, template, data):
        self.traittemplate.set_template(template.template)
        tmpl = self.traittemplate.template.template
        self.traittemplate.template.update(data)
        return self._make_template_common(template, tmpl)

    # the template argument is a template row
    # in retrospect the template column should've  been 'filename'
    def install_template(self, template, text):
        tname = template.template
        target_filename = self.target / tname
        self.log.info('target template %s' % target_filename)
        makepaths(target_filename.dirname())
        if target_filename.isfile():
            backup_filename = self.target / path('root/paella') / tname
            if not backup_filename.isfile():
                makepaths(backup_filename.dirname())
                target_filename.copy(backup_filename)
                self.log.info('template %s backed up' % tname)
            else:
                msg = 'overwriting previously installed template %s' % tname
                self.log.info(msg)
        else:
            self.log.info('installing NEW template %s' % tname)
        target_filename.write_bytes(text)

        mode = template.mode
        # a simple attempt to insure mode is a valid octal string
        # this is one of the very rare places eval is used
        # there are a few strings with 8's and 9's that will pass
        # the if statement, but the eval will raise SyntaxError then.
        # If the mode is unusable the install will fail at this point.
        if mode[0] == '0' and len(mode) <= 7 and mode.isdigit():
            mode = eval(mode)
            target_filename.chmod(mode)
        else:
            raise InstallError, 'bad mode %s, please use octal prefixed by 0' % mode
        
        own = ':'.join([template.owner, template.grp_owner])
        #command = 'chown %s %s' % (own, path('/') / template.template)
        template_path = path('/') / template.template
        command = ['chown', own, str(template_path)]
        # This command is run in a chroot to make the correct uid, gid
        self.chroot(command)

    def _check_debconf_destroyed(self, config_path):
        if isfile(config_path):
            self.log.warn('%s is not supposed to be there' % config_path)
            raise InstallDebconfError, '%s is not supposed to be there' % config_path


    def set_debconf_selections(self, template):
        trait = self.trait
        self.log.info('Setting debconf selections for trait %s' % trait)
        self.traittemplate.set_template(template.template)
        tmpl = self.traittemplate.template.template
        self._update_templatedata()
        sub = self.traittemplate.template.sub()
        if tmpl == sub:
            msg = "static debconf selections, no substitutions for trait %s" % trait
        else:
            msg = "debconf selections contain substitutions for trait %s" % trait
        self.log.info(msg)
        config_path = self.target / 'root/paella_debconf'
        self._check_debconf_destroyed(config_path)
        config_path.write_text(sub + '\n')
        cmd = ['chroot', self.target,
               'debconf-set-selections', '-v', '/root/paella_debconf']
        try:
            retval = runlog(cmd)
        except RunLogError:
            self.log.info('there was a problem with debconf-set-selections')
            self.log.info('command was %s' % ' '.join(cmd))
            # make sure that we raise an error if this is not the
            # first run of debconf-set-selections
            if self.debconf_problem:
                msg = "We already had a problem with set_debconf_selections"
                raise RuntimeError , msg
            self.debconf_problem = True
        # we're going to keep these files
        # instead of rm'ing them, until I feel
        # better about this code.  Besides, the
        # format of the files has to be just so
        # or debconf has problems, so this is a
        # good way to figure out what happened.
        if False:
            os.remove(config_path)
            self._check_debconf_destroyed(config_path)
        os.rename(config_path, '%s-%s' % (config_path, trait))
        
    def reconfigure_debconf(self, packages):
        self.log.info('running reconfigure')
        os.environ['DEBIAN_FRONTEND'] = 'noninteractive'
        for package in packages:
            self.log.info('RECONFIGURING %s' % package)
            #self.chroot('dpkg-reconfigure -plow %s' % package)
            self.chroot(['dpkg-reconfigure', '-plow', package])
        
    def make_script(self, procname):
        script = self.traitscripts.get(procname)
        if script is not None:
            # special handling for the chroot script to ensure
            # it's run in the target chroot
            if procname == 'chroot':
                tmpscript = make_script(procname, script, self.target, execpath=True)
                #return 'chroot %s %s' % (self.target, tmpscript)
                return ['chroot', str(self.target), tmpscript]
            else:
                return make_script(procname, script, self.target, execpath=False)
        else:
            return None
Пример #10
0
def get_profile_packages(conn, suite, profile):
    traits = get_traits(conn, profile)
    tp = TraitParent(conn, suite)
    pp = TraitPackage(conn, suite)
    packages = [p.package for p in pp.all_packages(traits, tp)]
    return packages
Пример #11
0
class TraitInstallerHelper(object):
    def __init__(self, conn, suite, target):
        # target should already be a path object
        self.target = path(target)
        self.trait = None
        
        # setup relation objects
        self.traitpackage = TraitPackage(conn, suite)
        self.traittemplate = TraitTemplate(conn, suite)
        self.traitscripts = TraitScript(conn, suite)

        # setup empty variable containers
        self.profiledata = {}
        self.mtypedata = {}
        self.familydata = {}

    def remove_packages(self, packages):
        packages_arg = ' '.join(packages)
        command = 'apt-get -y remove %s' % packages_arg

    def install_packages(self, packages, unauthenticated=False):
        packages_arg = ' '.join(packages)
        opts = ''
        if unauthenticated:
            opts = '--allow-unauthenticated'
        command = 'apt-get -y %s install %s' % (opts, packages_arg)

    def set_trait(self, trait):
        self.traitpackage.set_trait(trait)
        self.traittemplate.set_trait(trait)
        self.traitscripts.set_trait(trait)
        self.trait = trait
        self.packages = self.traitpackage.packages()
        self.templates = self.traittemplate.templates()
        os.environ['PAELLA_TRAIT'] = trait
        #self.log.info('trait set to %s' % trait)
        
    # the template argument is a template row
    # in retrospect the template column should've  been 'filename'
    def install_template(self, template, text):
        target_filename = self.target / template.template
        makepaths(target_filename.dirname())
        if target_filename.isfile():
            backup_filename = self.target / path('root/paella') / template.template
            if not backup_filename.isfile():
                makepaths(backup_filename.dirname())
                target_filename.copy(backup_filename)
        target_filename.write_bytes(text)

        mode = template.mode
        # a simple attempt to insure mode is a valid octal string
        # this is one of the very rare places eval is used
        # there are a few strings with 8's and 9's that will pass
        # the if statement, but the eval will raise SyntaxError then.
        # If the mode is unusable the install will fail at this point.
        if mode[0] == '0' and len(mode) <= 7 and mode.isdigit():
            mode = eval(mode)
            target_filename.chmod(mode)
        else:
            raise InstallError, 'bad mode %s, please use octal prefixed by 0' % mode
        
        own = ':'.join([template.owner, template.grp_owner])
        # This command is run in a chroot to make the correct uid, gid
        os.system(self.command('chown', "%s '%s'" %(own, join('/', template.template))))
Пример #12
0
class TraitInstallerHelper(object):
    def __init__(self, conn, suite, target):
        # target should already be a path object
        self.target = path(target)
        self.trait = None
        
        # setup relation objects
        self.traitpackage = TraitPackage(conn, suite)
        self.traittemplate = TraitTemplate(conn, suite)
        self.traitscripts = TraitScript(conn, suite)

        # setup empty variable containers
        self.profiledata = {}
        self.mtypedata = {}
        self.familydata = {}

    def set_trait(self, trait):
        self.traitpackage.set_trait(trait)
        self.traittemplate.set_trait(trait)
        self.traitscripts.set_trait(trait)
        self.trait = trait
        self.packages = self.traitpackage.packages()
        self.templates = self.traittemplate.templates()
        os.environ['PAELLA_TRAIT'] = trait
        #self.log.info('trait set to %s' % trait)

    # helper to run commands in a chroot on the target
    def chroot(self, command, failure_suppressed=False):
        # we need to remove this if/else when we're sure
        # we don't need it anymore
        if type(command) is list:
            cmd = ['chroot', str(self.target)] + command
        else:
            cmd = 'chroot %s %s' % (self.target, command)
        return runlog(cmd, failure_suppressed=failure_suppressed)
        
    def remove_packages(self, packages):
        if packages:
            #packages_arg = ' '.join(packages)
            #command = 'apt-get -y remove %s' % packages_arg
            command = ['apt-get', '-y', 'remove'] + packages
            self.chroot(command)
        else:
            self.log.info('No packages to remove')
        
    def install_packages(self, packages, unauthenticated=False):
        if packages:
            #packages_arg = ' '.join(packages)
            opts = []
            if unauthenticated:
                opts.append('--allow-unauthenticated')
            #command = 'apt-get -y %s install %s' % (opts, packages_arg)
            command = ['apt-get', '-y'] + opts + ['install'] + packages
            stmt = 'install command for trait %s is:  %s' % (self.trait, ' '.join(command))
            self.log.info(stmt)
            self.chroot(command)
        else:
            self.log.info('No packages to install')
            
    def remove_cached_debs(self):
        archives = self.target / 'var/cache/apt/archives'
        partial = archives / 'partial'
        debs = archives.listdir('*.deb')
        pdebs = partial.listdir('*.deb')
        all_debs = debs + pdebs
        for deb in all_debs:
            deb.remove()
            if deb.exists():
                raise RemoveDebsError, 'Failed to remove %s' % deb
            
    # order of updates is important here
    def _update_templatedata(self):
        self.traittemplate.template.update(self.familydata)
        self.traittemplate.template.update(self.mtypedata)
        self.traittemplate.template.update(self.profiledata)
        
    def _make_template_common(self, template, tmpl):
        sub = self.traittemplate.template.sub()
        if tmpl != sub:
            self.log.info('template %s subbed' % (template.template))
        return sub

    def make_template(self, template):
        self.traittemplate.set_template(template.template)
        tmpl = self.traittemplate.template.template
        self._update_templatedata()
        return self._make_template_common(template, tmpl)
        

    def make_template_with_data(self, template, data):
        self.traittemplate.set_template(template.template)
        tmpl = self.traittemplate.template.template
        self.traittemplate.template.update(data)
        return self._make_template_common(template, tmpl)

    # the template argument is a template row
    # in retrospect the template column should've  been 'filename'
    def install_template(self, template, text):
        tname = template.template
        target_filename = self.target / tname
        self.log.info('target template %s' % target_filename)
        makepaths(target_filename.dirname())
        if target_filename.isfile():
            backup_filename = self.target / path('root/paella') / tname
            if not backup_filename.isfile():
                makepaths(backup_filename.dirname())
                target_filename.copy(backup_filename)
                self.log.info('template %s backed up' % tname)
            else:
                msg = 'overwriting previously installed template %s' % tname
                self.log.info(msg)
        else:
            self.log.info('installing NEW template %s' % tname)
        target_filename.write_bytes(text)

        mode = template.mode
        # a simple attempt to insure mode is a valid octal string
        # this is one of the very rare places eval is used
        # there are a few strings with 8's and 9's that will pass
        # the if statement, but the eval will raise SyntaxError then.
        # If the mode is unusable the install will fail at this point.
        if mode[0] == '0' and len(mode) <= 7 and mode.isdigit():
            mode = eval(mode)
            target_filename.chmod(mode)
        else:
            raise InstallError, 'bad mode %s, please use octal prefixed by 0' % mode
        
        own = ':'.join([template.owner, template.grp_owner])
        #command = 'chown %s %s' % (own, path('/') / template.template)
        template_path = path('/') / template.template
        command = ['chown', own, str(template_path)]
        # This command is run in a chroot to make the correct uid, gid
        self.chroot(command)

    def _check_debconf_destroyed(self, config_path):
        if isfile(config_path):
            self.log.warn('%s is not supposed to be there' % config_path)
            raise InstallDebconfError, '%s is not supposed to be there' % config_path

    # here template is the template row
    def install_debconf_template(self, template):
        trait = self.trait
        self.log.info('Installing debconf for %s' % trait)
        self.traittemplate.set_template(template.template)
        tmpl = self.traittemplate.template.template
        self._update_templatedata()
        sub = self.traittemplate.template.sub()
        if tmpl == sub:
            msg = 'static debconf, no substitutions for trait %s' % trait
            self.log.info(msg)
        else:
            self.log.info('templated debconf for trait %s' % trait)
        config_path = self.target / 'tmp/paella_debconf'
        self._check_debconf_destroyed(config_path)
        config_path.write_bytes(sub + '\n')
        target_path = self.target / 'var/cache/debconf/config.dat'
        self.log.info('debconf config is %s %s' % (config_path, target_path))
        copy_configdb(config_path, target_path)
        os.remove(config_path)
        self._check_debconf_destroyed(config_path)

    def set_debconf_selections(self, template):
        trait = self.trait
        self.log.info('Setting debconf selections for trait %s' % trait)
        self.traittemplate.set_template(template.template)
        tmpl = self.traittemplate.template.template
        self._update_templatedata()
        sub = self.traittemplate.template.sub()
        if tmpl == sub:
            msg = "static debconf selections, no substitutions for trait %s" % trait
        else:
            msg = "debconf selections contain substitutions for trait %s" % trait
        self.log.info(msg)
        config_path = self.target / 'tmp/paella_debconf'
        self._check_debconf_destroyed(config_path)
        config_path.write_bytes(sub + '\n')
        cmd = ['chroot', self.target, 'debconf-set-selections', '/tmp/paella_debconf']
        retval = subprocess.call(cmd)
        if retval:
            raise RuntimeError, "there was a problem with debconf-set-selections"
        os.remove(config_path)
        self._check_debconf_destroyed(config_path)
        
        
    def reconfigure_debconf(self, packages):
        self.log.info('running reconfigure')
        os.environ['DEBIAN_FRONTEND'] = 'noninteractive'
        for package in packages:
            self.log.info('RECONFIGURING %s' % package)
            self.chroot('dpkg-reconfigure -plow %s' % package)
        
        
    def make_script(self, procname):
        script = self.traitscripts.get(procname)
        if script is not None:
            # special handling for the chroot script to ensure
            # it's run in the target chroot
            if procname == 'chroot':
                tmpscript = make_script(procname, script, self.target, execpath=True)
                return 'chroot %s %s' % (self.target, tmpscript)
            else:
                return make_script(procname, script, self.target, execpath=False)
        else:
            return None
Пример #13
0
class TraitInstaller(Installer):
    def __init__(self, conn, suite):
        Installer.__init__(self, conn)
        self.traitpackage = TraitPackage(conn, suite)
        self.traittemplate = TraitTemplate(conn, suite)
        self.traitscripts = TraitScript(conn, suite)
        self.profiledata = {}
        self.mtypedata = {}
        self.familydata = {}
        self.trait_processes = DEFAULT_PROCESSES
        if self.defenv.has_option('installer', 'trait_processes'):
            self.trait_processes = self.defenv.get_list('trait_processes', 'installer')
            
        self._process_map = {
            'pre' : self._process_pre,
            'remove' : self._process_remove,
            'install' : self._process_install,
            'templates' : self._process_templates,
            'config' : self._process_config,
            'chroot' : self._process_chroot,
            'reconfig' : self._process_reconfig,
            'post' : self._process_post
            }
        
    def set_trait(self, trait):
        self.traitpackage.set_trait(trait)
        self.traittemplate.set_trait(trait)
        self.traitscripts.set_trait(trait)
        self._current_trait_ = trait
        self.packages = self.traitpackage.packages()
        self.templates = self.traittemplate.templates()
        os.environ['PAELLA_TRAIT'] = trait
        self.log.info('trait set to %s' % self._current_trait_)

    def _info(self):
        return self._current_trait_, self.packages, self.templates
    
    def _process_pre(self):
        self.process_prepost_script('pre', self._current_trait_)

    def _process_remove(self):
        trait, packages, templates = self._info()
        self.process_packages(trait, 'remove', packages)

    def _process_install(self):
        trait, packages, templates = self._info()
        self.process_packages(trait, 'install', packages, templates)

    def _process_config(self):
        trait, packages, templates = self._info()
        script = self._make_script('config')
        if script is None:
            self.log.info('there is no config script for trait %s' % trait)
        else:
            self.process_hooked_action(script, 'config', trait)

    def _process_generic_script(self, action):
        trait, packages, templates = self._info()
        script = self._make_script(action)
        if script is None:
            self.log.info('there is no %s script for trait %s' % (action, trait))
        else:
            self.process_hooked_action(script, action, trait)
        
    def _process_templates(self):
        trait, packages, templates = self._info()
        script = self._make_script('templates')
        if script is None:
            if len(templates):
                self.install_templates(templates)
        else:
            self.process_hooked_action(script, 'templates', trait)
        
    def _process_chroot(self):
        trait, packages, templates = self._info()
        script = self._make_script('chroot', execpath=True)
        if script is not None:
            self.log.info('chroot exists for trait %s' % trait)
            self.run('chroot-script', script)
            if script[0] == '/':
                script = script[1:]
            os.remove(join(self.target, script))
        
    def _process_reconfig(self):
        trait, packages, templates = self._info()
        script = self._make_script('reconfig')
        if script is None:
            self.reconfigure_debconf(packages)
        else:
            self.process_hooked_action(script, 'reconfig', trait)
        
    def _process_post(self):
        self.process_prepost_script('post', self._current_trait_)

    def process(self):
        trait, packages, templates = self._info()
        self.log.info('processing trait:  %s' % trait)
        if 'PAELLA_TARGET' not in os.environ.keys():
            self.log.warn('PAELLA_TARGET not set.')
            os.environ['PAELLA_TARGET'] = self.target
        machine = None
        curenv = {}
        if 'PAELLA_MACHINE' in os.environ.keys():
            machine = os.environ['PAELLA_MACHINE']
            curenv = CurrentEnvironment(self.conn, machine)
        if machine is not None:
            self.log.info('processing trait %s on machine %s' % (trait, machine))
        curenv['current_trait'] = trait
        for proc in self.trait_processes:
            self.log.info('processing %s for trait %s' % (proc, trait))
            curenv['current_trait_process'] = proc
            if proc in self._process_map.keys():
                self._process_map[proc]()
            else:
                self._process_generic_script(proc)
            self.log.info('%s has been processed for trait %s' % (proc, trait))
            
    
    def run(self, name, command, args='', proc=False, chroot=True,
            keeprunning=False):
        tname = 'trait-%s-%s' % (self._current_trait_, name)
        self.log.info('running %s' % tname)
        runvalue = Installer.run(self, tname, command, args=args, proc=proc,
                                 chroot=chroot)
        return runvalue

    def runscript(self, script, name, info, chroot=False):
        self.log.info(info['start'])
        trait = self._current_trait_
        self.log.info('running script %s for trait %s' % (script, trait))
        runvalue = self.run(name, script, chroot=chroot)
        os.remove(script)
        self.log.info(info['done'])

    # prepost is either 'pre' or 'post'
    def process_prepost_script(self, prepost, trait):
        script = self._make_script(prepost)
        runvalue = 0
        if script is not None:
            info = dict(start='%s script started' % prepost,
                        done='%s script done' % prepost)
            runvalue = self.runscript(script, '%s-script' % prepost, info)
        else:
            self.log.info('no %s script for trait %s' % (prepost, trait))
        if runvalue:
            raise InstallError, 'Error in running %s script for %s' % (prepost, trait)

    def process_hooked_action(self, script, action, trait):
        self.log.info('%s has been hooked for trait %s' % (action, trait))
        info = dict(start='%s script started' % action,
                    done='%s script done' % action)
        runvalue = self.runscript(script, '%s-script' % action, info)
        if runvalue:
            InstallError, 'hooked action %s failed on trait %s' % (action, trait)
        
    def process_packages(self, trait, action, packages, templates=[]):
        script = self._make_script(action)
        if script is None:
            affected = [p for p in packages if p.action == action]
            length = len(affected)
            if length:
                ing = INGDICT[action]
                stmt = '%s %d packages for trait %s' % (ing, length, trait)
                self.log.info(stmt)
                if action == 'remove':
                    self.remove(affected)
                elif action == 'install':
                    self.install(affected, templates)
                else:
                    raise InstallError, '%s not implemented in process_packages'
        else:
            self.process_hooked_action(script, action, trait)
        
    def remove(self, packages):
        packages = ' '.join([p.package for p in packages])
        command, args = 'apt-get -y remove', packages
        runvalue = self.run('remove', command, args=args, proc=True)
        if runvalue:
            self.log.warn('Problem removing packages %s' % ', '.join(packages))
            
                
    def install(self, packages, templates):
        trait = self._current_trait_
        package_args = ' '.join([p.package for p in packages])
        #opts = '--force-yes'
        opts = ''
        if self.defenv.getboolean('installer', 'allow_unauthenticated_packages'):
            opts = '--allow-unauthenticated'
        cmd = 'apt-get -y %s install %s' % (opts, package_args)
        stmt = 'install command for %s is %s' % (trait, cmd)
        self.log.info(stmt)
        runvalue = self.run('install', cmd, proc=False, keeprunning=False)
        if runvalue:
            self.log.warn('PROBLEM installing %s' % trait)
            self.log.warn('packages --> %s' % package_args)
            raise InstallError, 'problem installing packages'
        if not self.defenv.getboolean('installer', 'keep_installed_packages'):
            runvalue = remove_debs(self.target)
            if runvalue:
                self.log.warn('PROBLEM removing downloaded debs')
                raise InstallError, 'problem removing downloaded debs'
        else:
            self.log.info('keeping packages for %s' % trait)
            
                
    def install_templates(self, templates):
        trait = self._current_trait_
        num = len(templates)
        stmt = 'in install_templates, there are %d templates for trait %s' % (num, trait)
        self.log.info(stmt)
        for t in templates:
            if t.template == 'var/cache/debconf/config.dat':
                self.log.info('Installing Debconf template ...')
                self.install_debconf_template(t)
            else:
                self.make_template(t)
            
    def configure(self, packages, templates):
        trait = self._current_trait_
        stmt = 'in configure, there are %d templates for trait %s' % (len(templates), trait)
        self.log.info(stmt)
        for p in packages:
            for t in [t for t in templates if t.package == p.package]:
                if t.template == 'var/cache/debconf/config.dat':
                    self.log.info('Installing Debconf template ...')
                    self.install_debconf_template(t)
                else:
                    self.make_template(t)
            
    def _make_script(self, name, execpath=False):
        script = self.traitscripts.get(name)
        if script is not None:
            stmt = '%s script exists for trait %s' % (name, self._current_trait_)
            self.log.info(stmt)
            return make_script(name, script, self.target, execpath=execpath)
        else:
            return None
        
    def make_template(self, template):
        self.traittemplate.set_template(template.template)
        tmpl = self.traittemplate.template.template
        self._update_templatedata()
        self._make_template_common(template, tmpl)
        

    def make_template_with_data(self, template, data):
        self.traittemplate.set_template(template.template)
        tmpl = self.traittemplate.template.template
        self.traittemplate.template.update(data)
        self._make_template_common(template, tmpl)

    def _install_template(self, template, text):
        target_filename = os.path.join(self.target, template.template)
        self.log.info('target template %s' % target_filename)
        backup_filename = os.path.join(self.target,
                                       self.paelladir, 'original_files', template.template)
        for p in target_filename, backup_filename:
            makepaths(os.path.dirname(p))
        if os.path.isfile(target_filename):
            if not os.path.isfile(backup_filename):
                cmd = 'mv %s %s' % (target_filename, os.path.dirname(backup_filename))
                os.system(cmd)
                self.log.info('template %s backed up' % template.template)
            else:
                self.log.info('overwriting previously installed template %s' % template.template)
        else:
            self.log.info('installing new template %s' % template.template)
        newfile = file(target_filename, 'w')
        newfile.write(text)
        newfile.close()
        
        # Set Ownership and Permissions

        mode = template.mode

        # a simple attempt to insure mode is a valid octal string
        # this is one of the very rare places eval is used
        # there are a few strings with 8's and 9's that will pass
        # the if statement, but the eval will raise SyntaxError then.
        # If the mode is unusable the install will fail at this point.
        if mode[0] == '0' and len(mode) <= 7 and mode.isdigit():
            mode = eval(mode)
            os.chmod(target_filename, mode)
        else:
            raise InstallError, 'bad mode %s, please use octal prefixed by 0' % mode
        
        own = ':'.join([template.owner, template.grp_owner])
        command = 'chown %s %s' % (own, path('/') / template.template)
        chroot = 'chroot %s %s' % (self.target, command)
        # This command is run in a chroot to make the correct uid, gid
        subprocess.call(chroot, shell=True)
        
        
    def _make_template_common(self, template, tmpl):
        sub = self.traittemplate.template.sub()
        if tmpl != sub:
            self.log.info('template %s subbed' % (template.template))
        self._install_template(template, sub)
        

    # order of updates is important here
    def _update_templatedata(self):
        self.traittemplate.template.update(self.familydata)
        self.traittemplate.template.update(self.mtypedata)
        self.traittemplate.template.update(self.profiledata)
        
    def install_debconf_template(self, template):
        trait = self._current_trait_
        self.log.info('Installing debconf for %s' % trait)
        self.traittemplate.set_template(template.template)
        tmpl = self.traittemplate.template.template
        self._update_templatedata()
        sub = self.traittemplate.template.sub()
        if tmpl == sub:
            self.log.info('static debconf, no substitutions')
            self.log.info('for trait %s ' % trait)
        else:
            self.log.info('templated debconf for trait %s' % trait)
        config_path = join(self.target, 'tmp/paella_debconf')
        if isfile(config_path):
            self.log.warn('%s is not supposed to be there' % config_path)
            raise RuntimeError, '%s is not supposed to be there' % config_path
        debconf = file(config_path, 'w')
        debconf.write(sub + '\n')
        debconf.close()
        target_path = join(self.target, 'var/cache/debconf/config.dat')
        self.log.info('debconf config is %s %s' % (config_path, target_path))
        copy_configdb(config_path, target_path)
        os.remove(config_path)

    def set_template_path(self, path):
        self.traittemplate.template.set_path(path)

    def reconfigure_debconf(self, packages):
        self.log.info('running reconfigure')
        reconfig = [p.package for p in packages if p.action == 'reconfig']
        os.environ['DEBIAN_FRONTEND'] = 'noninteractive'
        for package in reconfig:
            self.log.info('RECONFIGURING %s' % package)
            os.system(self.command('dpkg-reconfigure -plow %s' % package))
Пример #14
0
class TraitInstallerHelper(object):
    def __init__(self, conn, suite, target):
        # target should already be a path object
        self.target = path(target)
        self.trait = None

        # setup relation objects
        self.traitpackage = TraitPackage(conn, suite)
        self.traittemplate = TraitTemplate(conn, suite)
        self.traitscripts = TraitScript(conn, suite)

        # setup empty variable containers
        self.profiledata = {}
        self.mtypedata = {}
        self.familydata = {}

    def remove_packages(self, packages):
        packages_arg = ' '.join(packages)
        command = 'apt-get -y remove %s' % packages_arg

    def install_packages(self, packages, unauthenticated=False):
        packages_arg = ' '.join(packages)
        opts = ''
        if unauthenticated:
            opts = '--allow-unauthenticated'
        command = 'apt-get -y %s install %s' % (opts, packages_arg)

    def set_trait(self, trait):
        self.traitpackage.set_trait(trait)
        self.traittemplate.set_trait(trait)
        self.traitscripts.set_trait(trait)
        self.trait = trait
        self.packages = self.traitpackage.packages()
        self.templates = self.traittemplate.templates()
        os.environ['PAELLA_TRAIT'] = trait
        #self.log.info('trait set to %s' % trait)

    # the template argument is a template row
    # in retrospect the template column should've  been 'filename'
    def install_template(self, template, text):
        target_filename = self.target / template.template
        makepaths(target_filename.dirname())
        if target_filename.isfile():
            backup_filename = self.target / path(
                'root/paella') / template.template
            if not backup_filename.isfile():
                makepaths(backup_filename.dirname())
                target_filename.copy(backup_filename)
        target_filename.write_bytes(text)

        mode = template.mode
        # a simple attempt to insure mode is a valid octal string
        # this is one of the very rare places eval is used
        # there are a few strings with 8's and 9's that will pass
        # the if statement, but the eval will raise SyntaxError then.
        # If the mode is unusable the install will fail at this point.
        if mode[0] == '0' and len(mode) <= 7 and mode.isdigit():
            mode = eval(mode)
            target_filename.chmod(mode)
        else:
            raise InstallError, 'bad mode %s, please use octal prefixed by 0' % mode

        own = ':'.join([template.owner, template.grp_owner])
        # This command is run in a chroot to make the correct uid, gid
        os.system(
            self.command('chown',
                         "%s '%s'" % (own, join('/', template.template))))
Пример #15
0
class TraitInstallerHelper(object):
    def __init__(self, conn, suite, target):
        # target should already be a path object
        self.target = path(target)
        self.trait = None

        # setup relation objects
        self.traitpackage = TraitPackage(conn, suite)
        self.traittemplate = TraitTemplate(conn, suite)
        self.traitscripts = TraitScript(conn, suite)

        # setup empty variable containers
        self.profiledata = {}
        self.machine_data = {}
        self.familydata = {}

        # It's odd, but running the same
        # code for setting debconf selections
        # returns a 1 on the preseed process, yet
        # returns a 0 when it's done during
        # the templates process.
        # -- I found the problem, debconf reports
        #    an error if the question doesn't exist
        #    yet.
        # This attribute helps keep track of the
        # problem, and will run the debconf
        # selections during the templates
        # process, if the value is True.
        # I don't really like this, but it seems
        # to work for now, so I'm going to leave
        # it as is, and come up with a better
        # solution later.
        self.debconf_problem = False

    def set_trait(self, trait):
        self.traitpackage.set_trait(trait)
        self.traittemplate.set_trait(trait)
        self.traitscripts.set_trait(trait)
        self.trait = trait
        self.packages = self.traitpackage.packages()
        self.templates = self.traittemplate.templates()
        os.environ["PAELLA_TRAIT"] = trait
        # self.log.info('trait set to %s' % trait)

    # helper to run commands in a chroot on the target
    def chroot(self, command, failure_suppressed=False):
        # we need to remove this if/else when we're sure
        # we don't need it anymore
        if type(command) is list:
            cmd = ["chroot", str(self.target)] + command
        else:
            cmd = "chroot %s %s" % (self.target, command)
        return runlog(cmd, failure_suppressed=failure_suppressed)

    def remove_packages(self, packages):
        if packages:
            # packages_arg = ' '.join(packages)
            # command = 'apt-get -y remove %s' % packages_arg
            command = ["apt-get", "-y", "remove"] + packages
            self.chroot(command)
        else:
            self.log.info("No packages to remove")

    def install_packages(self, packages, unauthenticated=False):
        if packages:
            command = install_packages_command(
                packages, self.defenv, action="install", loginfo=self.log.info, trait=self.trait
            )
            self.chroot(command)
        else:
            self.log.info("No packages to install")

    def install_packagesOrig(self, packages, unauthenticated=False):
        if packages:
            apt_cmd = "apt-get"
            apt_opts = ""
            if self.defenv.has_option("installer", "apt_command"):
                apt_cmd = self.defenv.get("installer", "apt_command")
            if self.defenv.has_option("installer", "apt_command_opts"):
                apt_opts = self.defenv.get("installer", "apt_command_opts")
            # packages_arg = ' '.join(packages)
            self.log.info("apt command is %s" % apt_cmd)
            opts = apt_opts.split()
            unauthenticated_optdict = {"apt-get": "--allow-unauthenticated", "aptitude": "--allow-untrusted"}
            if unauthenticated and unauthenticated_optdict[apt_cmd] not in opts:
                opts.append(unauthenticated_optdict[apt_cmd])
            if "--assume-yes" not in opts:
                opts.append("--assume-yes")
            if apt_cmd == "aptitude":
                if "--add-user-tag" not in opts:
                    usertag = "paella-trait-%s" % self.trait
                    opts += ["--add-user-tag", usertag]
            full_command = [apt_cmd] + opts + ["install"] + packages
            # command = 'apt-get -y %s install %s' % (opts, packages_arg)
            # command = ['apt-get', '-y'] + opts + ['install'] + packages
            stmt = "install command for trait %s is:  %s" % (self.trait, " ".join(full_command))
            self.log.info(stmt)
            self.chroot(full_command)
        else:
            self.log.info("No packages to install")

    def remove_cached_debs(self):
        archives = self.target / "var/cache/apt/archives"
        partial = archives / "partial"
        debs = archives.listdir("*.deb")
        pdebs = partial.listdir("*.deb")
        if pdebs:
            self.log.error("we found some partial debs, and this shouldn't happen")
            raise RuntimeError, "partial debs found"
        all_debs = debs + pdebs
        for deb in all_debs:
            deb.remove()
            if deb.exists():
                msg = "Failed to remove %s" % deb
                self.log.error(msg)
                raise RemoveDebsError, msg

    # order of updates is important here
    def _update_templatedata(self):
        self.traittemplate.template.update(self.familydata)
        self.traittemplate.template.update(self.profiledata)
        self.traittemplate.template.update(self.machine_data)

    def _make_template_common(self, template, tmpl):
        sub = self.traittemplate.template.sub()
        if tmpl != sub:
            self.log.info("template %s subbed" % (template.template))
        return sub

    def make_template(self, template):
        self.traittemplate.set_template(template.template)
        tmpl = self.traittemplate.template.template
        if tmpl.startswith("##cheetah"):
            self.log.info("%s is a cheetah template" % template.template)
        self._update_templatedata()
        return self._make_template_common(template, tmpl)

    def make_template_with_data(self, template, data):
        self.traittemplate.set_template(template.template)
        tmpl = self.traittemplate.template.template
        self.traittemplate.template.update(data)
        return self._make_template_common(template, tmpl)

    # the template argument is a template row
    # in retrospect the template column should've  been 'filename'
    def install_template(self, template, text):
        tname = template.template
        target_filename = self.target / tname
        self.log.info("target template %s" % target_filename)
        makepaths(target_filename.dirname())
        if target_filename.isfile():
            backup_filename = self.target / path("root/paella") / tname
            if not backup_filename.isfile():
                makepaths(backup_filename.dirname())
                target_filename.copy(backup_filename)
                self.log.info("template %s backed up" % tname)
            else:
                msg = "overwriting previously installed template %s" % tname
                self.log.info(msg)
        else:
            self.log.info("installing NEW template %s" % tname)
        target_filename.write_bytes(text)

        mode = template.mode
        # a simple attempt to insure mode is a valid octal string
        # this is one of the very rare places eval is used
        # there are a few strings with 8's and 9's that will pass
        # the if statement, but the eval will raise SyntaxError then.
        # If the mode is unusable the install will fail at this point.
        if mode[0] == "0" and len(mode) <= 7 and mode.isdigit():
            mode = eval(mode)
            target_filename.chmod(mode)
        else:
            msg = "bad mode %s, please use octal prefixed by 0" % mode
            self.log.error(msg)
            raise InstallError, msg

        own = ":".join([template.owner, template.grp_owner])
        # command = 'chown %s %s' % (own, path('/') / template.template)
        template_path = path("/") / template.template
        command = ["chown", own, str(template_path)]
        # This command is run in a chroot to make the correct uid, gid
        self.chroot(command)

    def _check_debconf_destroyed(self, config_path):
        if isfile(config_path):
            self.log.error("%s is not supposed to be there" % config_path)
            raise InstallDebconfError, "%s is not supposed to be there" % config_path

    def set_debconf_selections(self, template):
        trait = self.trait
        self.log.info("Setting debconf selections for trait %s" % trait)
        self.traittemplate.set_template(template.template)
        tmpl = self.traittemplate.template.template
        self._update_templatedata()
        sub = self.traittemplate.template.sub()
        if tmpl == sub:
            msg = "static debconf selections, no substitutions for trait %s" % trait
        else:
            msg = "debconf selections contain substitutions for trait %s" % trait
        self.log.info(msg)
        config_path = self.target / "root/paella_debconf"
        self._check_debconf_destroyed(config_path)
        config_path.write_text(sub + "\n")
        cmd = ["chroot", self.target, "debconf-set-selections", "-v", "/root/paella_debconf"]
        try:
            retval = runlog(cmd)
        except RunLogError:
            self.log.info("there was a problem with debconf-set-selections")
            self.log.info("command was %s" % " ".join(cmd))
            # make sure that we raise an error if this is not the
            # first run of debconf-set-selections
            if self.debconf_problem:
                msg = "We already had a problem with set_debconf_selections"
                self.log.error(msg)
                raise RuntimeError, msg
            self.debconf_problem = True
        # we're going to keep these files
        # instead of rm'ing them, until I feel
        # better about this code.  Besides, the
        # format of the files has to be just so
        # or debconf has problems, so this is a
        # good way to figure out what happened.
        if False:
            os.remove(config_path)
            self._check_debconf_destroyed(config_path)
        os.rename(config_path, "%s-%s" % (config_path, trait))

    def reconfigure_debconf(self, packages):
        self.log.info("running reconfigure")
        os.environ["DEBIAN_FRONTEND"] = "noninteractive"
        for package in packages:
            self.log.info("RECONFIGURING %s" % package)
            # self.chroot('dpkg-reconfigure -plow %s' % package)
            self.chroot(["dpkg-reconfigure", "-plow", package])

    def make_script(self, procname):
        script = self.traitscripts.get(procname)
        if script is not None:
            # special handling for the chroot script to ensure
            # it's run in the target chroot
            if procname == "chroot":
                tmpscript = make_script(procname, script, self.target, execpath=True)
                # return 'chroot %s %s' % (self.target, tmpscript)
                return ["chroot", str(self.target), tmpscript]
            else:
                return make_script(procname, script, self.target, execpath=False)
        else:
            return None
Пример #16
0
class TraitInstaller(Installer):
    def __init__(self, conn, suite):
        Installer.__init__(self, conn)
        self.traitpackage = TraitPackage(conn, suite)
        self.traittemplate = TraitTemplate(conn, suite)
        self.traitscripts = TraitScript(conn, suite)
        self.profiledata = {}
        self.mtypedata = {}
        self.familydata = {}
        self.trait_processes = DEFAULT_PROCESSES
        if self.defenv.has_option('installer', 'trait_processes'):
            self.trait_processes = self.defenv.get_list(
                'trait_processes', 'installer')

        self._process_map = {
            'pre': self._process_pre,
            'remove': self._process_remove,
            'install': self._process_install,
            'templates': self._process_templates,
            'config': self._process_config,
            'chroot': self._process_chroot,
            'reconfig': self._process_reconfig,
            'post': self._process_post
        }

    def set_trait(self, trait):
        self.traitpackage.set_trait(trait)
        self.traittemplate.set_trait(trait)
        self.traitscripts.set_trait(trait)
        self._current_trait_ = trait
        self.packages = self.traitpackage.packages()
        self.templates = self.traittemplate.templates()
        os.environ['PAELLA_TRAIT'] = trait
        self.log.info('trait set to %s' % self._current_trait_)

    def _info(self):
        return self._current_trait_, self.packages, self.templates

    def _process_pre(self):
        self.process_prepost_script('pre', self._current_trait_)

    def _process_remove(self):
        trait, packages, templates = self._info()
        self.process_packages(trait, 'remove', packages)

    def _process_install(self):
        trait, packages, templates = self._info()
        self.process_packages(trait, 'install', packages, templates)

    def _process_config(self):
        trait, packages, templates = self._info()
        script = self._make_script('config')
        if script is None:
            self.log.info('there is no config script for trait %s' % trait)
        else:
            self.process_hooked_action(script, 'config', trait)

    def _process_generic_script(self, action):
        trait, packages, templates = self._info()
        script = self._make_script(action)
        if script is None:
            self.log.info('there is no %s script for trait %s' %
                          (action, trait))
        else:
            self.process_hooked_action(script, action, trait)

    def _process_templates(self):
        trait, packages, templates = self._info()
        script = self._make_script('templates')
        if script is None:
            if len(templates):
                self.install_templates(templates)
        else:
            self.process_hooked_action(script, 'templates', trait)

    def _process_chroot(self):
        trait, packages, templates = self._info()
        script = self._make_script('chroot', execpath=True)
        if script is not None:
            self.log.info('chroot exists for trait %s' % trait)
            self.run('chroot-script', script)
            if script[0] == '/':
                script = script[1:]
            os.remove(join(self.target, script))

    def _process_reconfig(self):
        trait, packages, templates = self._info()
        script = self._make_script('reconfig')
        if script is None:
            self.reconfigure_debconf(packages)
        else:
            self.process_hooked_action(script, 'reconfig', trait)

    def _process_post(self):
        self.process_prepost_script('post', self._current_trait_)

    def process(self):
        trait, packages, templates = self._info()
        self.log.info('processing trait:  %s' % trait)
        if 'PAELLA_TARGET' not in os.environ.keys():
            self.log.warn('PAELLA_TARGET not set.')
            os.environ['PAELLA_TARGET'] = self.target
        machine = None
        curenv = {}
        if 'PAELLA_MACHINE' in os.environ.keys():
            machine = os.environ['PAELLA_MACHINE']
            curenv = CurrentEnvironment(self.conn, machine)
        if machine is not None:
            self.log.info('processing trait %s on machine %s' %
                          (trait, machine))
        curenv['current_trait'] = trait
        for proc in self.trait_processes:
            self.log.info('processing %s for trait %s' % (proc, trait))
            curenv['current_trait_process'] = proc
            if proc in self._process_map.keys():
                self._process_map[proc]()
            else:
                self._process_generic_script(proc)
            self.log.info('%s has been processed for trait %s' % (proc, trait))

    def run(self,
            name,
            command,
            args='',
            proc=False,
            chroot=True,
            keeprunning=False):
        tname = 'trait-%s-%s' % (self._current_trait_, name)
        self.log.info('running %s' % tname)
        runvalue = Installer.run(self,
                                 tname,
                                 command,
                                 args=args,
                                 proc=proc,
                                 chroot=chroot)
        return runvalue

    def runscript(self, script, name, info, chroot=False):
        self.log.info(info['start'])
        trait = self._current_trait_
        self.log.info('running script %s for trait %s' % (script, trait))
        runvalue = self.run(name, script, chroot=chroot)
        os.remove(script)
        self.log.info(info['done'])

    # prepost is either 'pre' or 'post'
    def process_prepost_script(self, prepost, trait):
        script = self._make_script(prepost)
        runvalue = 0
        if script is not None:
            info = dict(start='%s script started' % prepost,
                        done='%s script done' % prepost)
            runvalue = self.runscript(script, '%s-script' % prepost, info)
        else:
            self.log.info('no %s script for trait %s' % (prepost, trait))
        if runvalue:
            raise InstallError, 'Error in running %s script for %s' % (prepost,
                                                                       trait)

    def process_hooked_action(self, script, action, trait):
        self.log.info('%s has been hooked for trait %s' % (action, trait))
        info = dict(start='%s script started' % action,
                    done='%s script done' % action)
        runvalue = self.runscript(script, '%s-script' % action, info)
        if runvalue:
            InstallError, 'hooked action %s failed on trait %s' % (action,
                                                                   trait)

    def process_packages(self, trait, action, packages, templates=[]):
        script = self._make_script(action)
        if script is None:
            affected = [p for p in packages if p.action == action]
            length = len(affected)
            if length:
                ing = INGDICT[action]
                stmt = '%s %d packages for trait %s' % (ing, length, trait)
                self.log.info(stmt)
                if action == 'remove':
                    self.remove(affected)
                elif action == 'install':
                    self.install(affected, templates)
                else:
                    raise InstallError, '%s not implemented in process_packages'
        else:
            self.process_hooked_action(script, action, trait)

    def remove(self, packages):
        packages = ' '.join([p.package for p in packages])
        command, args = 'apt-get -y remove', packages
        runvalue = self.run('remove', command, args=args, proc=True)
        if runvalue:
            self.log.warn('Problem removing packages %s' % ', '.join(packages))

    def install(self, packages, templates):
        trait = self._current_trait_
        package_args = ' '.join([p.package for p in packages])
        #opts = '--force-yes'
        opts = ''
        if self.defenv.getboolean('installer',
                                  'allow_unauthenticated_packages'):
            opts = '--allow-unauthenticated'
        cmd = 'apt-get -y %s install %s' % (opts, package_args)
        stmt = 'install command for %s is %s' % (trait, cmd)
        self.log.info(stmt)
        runvalue = self.run('install', cmd, proc=False, keeprunning=False)
        if runvalue:
            self.log.warn('PROBLEM installing %s' % trait)
            self.log.warn('packages --> %s' % package_args)
            raise InstallError, 'problem installing packages'
        if not self.defenv.getboolean('installer', 'keep_installed_packages'):
            runvalue = remove_debs(self.target)
            if runvalue:
                self.log.warn('PROBLEM removing downloaded debs')
                raise InstallError, 'problem removing downloaded debs'
        else:
            self.log.info('keeping packages for %s' % trait)

    def install_templates(self, templates):
        trait = self._current_trait_
        num = len(templates)
        stmt = 'in install_templates, there are %d templates for trait %s' % (
            num, trait)
        self.log.info(stmt)
        for t in templates:
            if t.template == 'var/cache/debconf/config.dat':
                self.log.info('Installing Debconf template ...')
                self.install_debconf_template(t)
            else:
                self.make_template(t)

    def configure(self, packages, templates):
        trait = self._current_trait_
        stmt = 'in configure, there are %d templates for trait %s' % (
            len(templates), trait)
        self.log.info(stmt)
        for p in packages:
            for t in [t for t in templates if t.package == p.package]:
                if t.template == 'var/cache/debconf/config.dat':
                    self.log.info('Installing Debconf template ...')
                    self.install_debconf_template(t)
                else:
                    self.make_template(t)

    def _make_script(self, name, execpath=False):
        script = self.traitscripts.get(name)
        if script is not None:
            stmt = '%s script exists for trait %s' % (name,
                                                      self._current_trait_)
            self.log.info(stmt)
            return make_script(name, script, self.target, execpath=execpath)
        else:
            return None

    def make_template(self, template):
        self.traittemplate.set_template(template.template)
        tmpl = self.traittemplate.template.template
        self._update_templatedata()
        self._make_template_common(template, tmpl)

    def make_template_with_data(self, template, data):
        self.traittemplate.set_template(template.template)
        tmpl = self.traittemplate.template.template
        self.traittemplate.template.update(data)
        self._make_template_common(template, tmpl)

    def _install_template(self, template, text):
        target_filename = os.path.join(self.target, template.template)
        self.log.info('target template %s' % target_filename)
        backup_filename = os.path.join(self.target, self.paelladir,
                                       'original_files', template.template)
        for p in target_filename, backup_filename:
            makepaths(os.path.dirname(p))
        if os.path.isfile(target_filename):
            if not os.path.isfile(backup_filename):
                cmd = 'mv %s %s' % (target_filename,
                                    os.path.dirname(backup_filename))
                os.system(cmd)
                self.log.info('template %s backed up' % template.template)
            else:
                self.log.info('overwriting previously installed template %s' %
                              template.template)
        else:
            self.log.info('installing new template %s' % template.template)
        newfile = file(target_filename, 'w')
        newfile.write(text)
        newfile.close()

        # Set Ownership and Permissions

        mode = template.mode

        # a simple attempt to insure mode is a valid octal string
        # this is one of the very rare places eval is used
        # there are a few strings with 8's and 9's that will pass
        # the if statement, but the eval will raise SyntaxError then.
        # If the mode is unusable the install will fail at this point.
        if mode[0] == '0' and len(mode) <= 7 and mode.isdigit():
            mode = eval(mode)
            os.chmod(target_filename, mode)
        else:
            raise InstallError, 'bad mode %s, please use octal prefixed by 0' % mode

        own = ':'.join([template.owner, template.grp_owner])
        command = 'chown %s %s' % (own, path('/') / template.template)
        chroot = 'chroot %s %s' % (self.target, command)
        # This command is run in a chroot to make the correct uid, gid
        subprocess.call(chroot, shell=True)

    def _make_template_common(self, template, tmpl):
        sub = self.traittemplate.template.sub()
        if tmpl != sub:
            self.log.info('template %s subbed' % (template.template))
        self._install_template(template, sub)

    # order of updates is important here
    def _update_templatedata(self):
        self.traittemplate.template.update(self.familydata)
        self.traittemplate.template.update(self.mtypedata)
        self.traittemplate.template.update(self.profiledata)

    def install_debconf_template(self, template):
        trait = self._current_trait_
        self.log.info('Installing debconf for %s' % trait)
        self.traittemplate.set_template(template.template)
        tmpl = self.traittemplate.template.template
        self._update_templatedata()
        sub = self.traittemplate.template.sub()
        if tmpl == sub:
            self.log.info('static debconf, no substitutions')
            self.log.info('for trait %s ' % trait)
        else:
            self.log.info('templated debconf for trait %s' % trait)
        config_path = join(self.target, 'tmp/paella_debconf')
        if isfile(config_path):
            self.log.warn('%s is not supposed to be there' % config_path)
            raise RuntimeError, '%s is not supposed to be there' % config_path
        debconf = file(config_path, 'w')
        debconf.write(sub + '\n')
        debconf.close()
        target_path = join(self.target, 'var/cache/debconf/config.dat')
        self.log.info('debconf config is %s %s' % (config_path, target_path))
        copy_configdb(config_path, target_path)
        os.remove(config_path)

    def set_template_path(self, path):
        self.traittemplate.template.set_path(path)

    def reconfigure_debconf(self, packages):
        self.log.info('running reconfigure')
        reconfig = [p.package for p in packages if p.action == 'reconfig']
        os.environ['DEBIAN_FRONTEND'] = 'noninteractive'
        for package in reconfig:
            self.log.info('RECONFIGURING %s' % package)
            os.system(self.command('dpkg-reconfigure -plow %s' % package))
Пример #17
0
class TraitInstallerHelper(object):
    def __init__(self, conn, suite, target):
        # target should already be a path object
        self.target = path(target)
        self.trait = None

        # setup relation objects
        self.traitpackage = TraitPackage(conn, suite)
        self.traittemplate = TraitTemplate(conn, suite)
        self.traitscripts = TraitScript(conn, suite)

        # setup empty variable containers
        self.profiledata = {}
        self.machine_data = {}
        self.familydata = {}

        # It's odd, but running the same
        # code for setting debconf selections
        # returns a 1 on the preseed process, yet
        # returns a 0 when it's done during
        # the templates process.
        # -- I found the problem, debconf reports
        #    an error if the question doesn't exist
        #    yet.
        # This attribute helps keep track of the
        # problem, and will run the debconf
        # selections during the templates
        # process, if the value is True.
        # I don't really like this, but it seems
        # to work for now, so I'm going to leave
        # it as is, and come up with a better
        # solution later.
        self.debconf_problem = False

    def set_trait(self, trait):
        self.traitpackage.set_trait(trait)
        self.traittemplate.set_trait(trait)
        self.traitscripts.set_trait(trait)
        self.trait = trait
        self.packages = self.traitpackage.packages()
        self.templates = self.traittemplate.templates()
        os.environ['PAELLA_TRAIT'] = trait
        #self.log.info('trait set to %s' % trait)

    # helper to run commands in a chroot on the target
    def chroot(self, command, failure_suppressed=False):
        # we need to remove this if/else when we're sure
        # we don't need it anymore
        if type(command) is list:
            cmd = ['chroot', str(self.target)] + command
        else:
            cmd = 'chroot %s %s' % (self.target, command)
        return runlog(cmd, failure_suppressed=failure_suppressed)

    def remove_packages(self, packages):
        if packages:
            #packages_arg = ' '.join(packages)
            #command = 'apt-get -y remove %s' % packages_arg
            command = ['apt-get', '-y', 'remove'] + packages
            self.chroot(command)
        else:
            self.log.info('No packages to remove')

    def install_packages(self, packages, unauthenticated=False):
        if packages:
            command = install_packages_command(packages,
                                               self.defenv,
                                               action='install',
                                               loginfo=self.log.info,
                                               trait=self.trait)
            self.chroot(command)
        else:
            self.log.info('No packages to install')

    def install_packagesOrig(self, packages, unauthenticated=False):
        if packages:
            apt_cmd = 'apt-get'
            apt_opts = ''
            if self.defenv.has_option('installer', 'apt_command'):
                apt_cmd = self.defenv.get('installer', 'apt_command')
            if self.defenv.has_option('installer', 'apt_command_opts'):
                apt_opts = self.defenv.get('installer', 'apt_command_opts')
            #packages_arg = ' '.join(packages)
            self.log.info('apt command is %s' % apt_cmd)
            opts = apt_opts.split()
            unauthenticated_optdict = {
                'apt-get': '--allow-unauthenticated',
                'aptitude': '--allow-untrusted'
            }
            if unauthenticated and unauthenticated_optdict[apt_cmd] not in opts:
                opts.append(unauthenticated_optdict[apt_cmd])
            if '--assume-yes' not in opts:
                opts.append('--assume-yes')
            if apt_cmd == 'aptitude':
                if '--add-user-tag' not in opts:
                    usertag = 'paella-trait-%s' % self.trait
                    opts += ['--add-user-tag', usertag]
            full_command = [apt_cmd] + opts + ['install'] + packages
            #command = 'apt-get -y %s install %s' % (opts, packages_arg)
            #command = ['apt-get', '-y'] + opts + ['install'] + packages
            stmt = 'install command for trait %s is:  %s' % (
                self.trait, ' '.join(full_command))
            self.log.info(stmt)
            self.chroot(full_command)
        else:
            self.log.info('No packages to install')

    def remove_cached_debs(self):
        archives = self.target / 'var/cache/apt/archives'
        partial = archives / 'partial'
        debs = archives.listdir('*.deb')
        pdebs = partial.listdir('*.deb')
        if pdebs:
            self.log.error(
                "we found some partial debs, and this shouldn't happen")
            raise RuntimeError, "partial debs found"
        all_debs = debs + pdebs
        for deb in all_debs:
            deb.remove()
            if deb.exists():
                msg = 'Failed to remove %s' % deb
                self.log.error(msg)
                raise RemoveDebsError, msg

    # order of updates is important here
    def _update_templatedata(self):
        self.traittemplate.template.update(self.familydata)
        self.traittemplate.template.update(self.profiledata)
        self.traittemplate.template.update(self.machine_data)

    def _make_template_common(self, template, tmpl):
        sub = self.traittemplate.template.sub()
        if tmpl != sub:
            self.log.info('template %s subbed' % (template.template))
        return sub

    def make_template(self, template):
        self.traittemplate.set_template(template.template)
        tmpl = self.traittemplate.template.template
        if tmpl.startswith('##cheetah'):
            self.log.info("%s is a cheetah template" % template.template)
        self._update_templatedata()
        return self._make_template_common(template, tmpl)

    def make_template_with_data(self, template, data):
        self.traittemplate.set_template(template.template)
        tmpl = self.traittemplate.template.template
        self.traittemplate.template.update(data)
        return self._make_template_common(template, tmpl)

    # the template argument is a template row
    # in retrospect the template column should've  been 'filename'
    def install_template(self, template, text):
        tname = template.template
        target_filename = self.target / tname
        self.log.info('target template %s' % target_filename)
        makepaths(target_filename.dirname())
        if target_filename.isfile():
            backup_filename = self.target / path('root/paella') / tname
            if not backup_filename.isfile():
                makepaths(backup_filename.dirname())
                target_filename.copy(backup_filename)
                self.log.info('template %s backed up' % tname)
            else:
                msg = 'overwriting previously installed template %s' % tname
                self.log.info(msg)
        else:
            self.log.info('installing NEW template %s' % tname)
        target_filename.write_bytes(text)

        mode = template.mode
        # a simple attempt to insure mode is a valid octal string
        # this is one of the very rare places eval is used
        # there are a few strings with 8's and 9's that will pass
        # the if statement, but the eval will raise SyntaxError then.
        # If the mode is unusable the install will fail at this point.
        if mode[0] == '0' and len(mode) <= 7 and mode.isdigit():
            mode = eval(mode)
            target_filename.chmod(mode)
        else:
            msg = 'bad mode %s, please use octal prefixed by 0' % mode
            self.log.error(msg)
            raise InstallError, msg

        own = ':'.join([template.owner, template.grp_owner])
        #command = 'chown %s %s' % (own, path('/') / template.template)
        template_path = path('/') / template.template
        command = ['chown', own, str(template_path)]
        # This command is run in a chroot to make the correct uid, gid
        self.chroot(command)

    def _check_debconf_destroyed(self, config_path):
        if isfile(config_path):
            self.log.error('%s is not supposed to be there' % config_path)
            raise InstallDebconfError, '%s is not supposed to be there' % config_path

    def set_debconf_selections(self, template):
        trait = self.trait
        self.log.info('Setting debconf selections for trait %s' % trait)
        self.traittemplate.set_template(template.template)
        tmpl = self.traittemplate.template.template
        self._update_templatedata()
        sub = self.traittemplate.template.sub()
        if tmpl == sub:
            msg = "static debconf selections, no substitutions for trait %s" % trait
        else:
            msg = "debconf selections contain substitutions for trait %s" % trait
        self.log.info(msg)
        config_path = self.target / 'root/paella_debconf'
        self._check_debconf_destroyed(config_path)
        config_path.write_text(sub + '\n')
        cmd = [
            'chroot', self.target, 'debconf-set-selections', '-v',
            '/root/paella_debconf'
        ]
        try:
            retval = runlog(cmd)
        except RunLogError:
            self.log.info('there was a problem with debconf-set-selections')
            self.log.info('command was %s' % ' '.join(cmd))
            # make sure that we raise an error if this is not the
            # first run of debconf-set-selections
            if self.debconf_problem:
                msg = "We already had a problem with set_debconf_selections"
                self.log.error(msg)
                raise RuntimeError, msg
            self.debconf_problem = True
        # we're going to keep these files
        # instead of rm'ing them, until I feel
        # better about this code.  Besides, the
        # format of the files has to be just so
        # or debconf has problems, so this is a
        # good way to figure out what happened.
        if False:
            os.remove(config_path)
            self._check_debconf_destroyed(config_path)
        os.rename(config_path, '%s-%s' % (config_path, trait))

    def reconfigure_debconf(self, packages):
        self.log.info('running reconfigure')
        os.environ['DEBIAN_FRONTEND'] = 'noninteractive'
        for package in packages:
            self.log.info('RECONFIGURING %s' % package)
            #self.chroot('dpkg-reconfigure -plow %s' % package)
            self.chroot(['dpkg-reconfigure', '-plow', package])

    def make_script(self, procname):
        script = self.traitscripts.get(procname)
        if script is not None:
            # special handling for the chroot script to ensure
            # it's run in the target chroot
            if procname == 'chroot':
                tmpscript = make_script(procname,
                                        script,
                                        self.target,
                                        execpath=True)
                #return 'chroot %s %s' % (self.target, tmpscript)
                return ['chroot', str(self.target), tmpscript]
            else:
                return make_script(procname,
                                   script,
                                   self.target,
                                   execpath=False)
        else:
            return None
Пример #18
0
def get_profile_packages(conn, suite, profile):
    traits = get_traits(conn, profile)
    tp = TraitParent(conn, suite)
    pp = TraitPackage(conn, suite)
    packages = [p.package for p in pp.all_packages(traits, tp)]
    return packages