Ejemplo n.º 1
0
    def extractMediaTemplate(self, topdir):
        tmpRoot = tempfile.mkdtemp(dir=constants.tmpDir)
        try:
            client = self.getConaryClient(\
                tmpRoot, getArchFlavor(self.baseFlavor).freeze())

            log.info("extracting ad-hoc content from " \
                  "media-template=%s" % client.cfg.installLabelPath[0].asString())
            uJob = self._getUpdateJob(client, "media-template")
            if uJob:
                client.applyUpdate(uJob, callback = self.callback)
                log.info("success: copying media template data to unified tree")

                # copy content into unified tree root. add recurse and no-deref
                # flags to command. following symlinks is really bad in this case.
                oldTemplateDir = os.path.join(tmpRoot,
                                              'usr', 'lib', 'media-template')
                if os.path.exists(oldTemplateDir):
                    call('cp', '-R', '--no-dereference', oldTemplateDir, topdir)
                for tDir in ('all', 'disc1'):
                    srcDir = os.path.join(tmpRoot, tDir)
                    destDir = os.path.join(topdir, 'media-template2')
                    if os.path.exists(srcDir):
                        util.mkdirChain(destDir)
                        call('cp', '-R', '--no-dereference', srcDir, destDir)
            else:
                log.info("media-template not found on repository")
        finally:
            util.rmtree(tmpRoot, ignore_errors = True)
Ejemplo n.º 2
0
    def extractPublicKeys(self, keyDir, topdir, csdir):
        self.status('Extracting Public Keys')
        homeDir = tempfile.mkdtemp(dir = constants.tmpDir)
        tmpRoot = tempfile.mkdtemp(dir = constants.tmpDir)
        try:
            client = self.getConaryClient( \
                tmpRoot, getArchFlavor(self.baseFlavor).freeze())

            fingerprints = {}
            fpTrovespecs = {}
            for filename in [x for x in os.listdir(csdir) if x.endswith('.ccs')]:
                cs = changeset.ChangeSetFromFile(os.path.join(csdir, filename))
                troves = [trove.Trove(x) for x in cs.iterNewTroveList()]
                for trv in troves:
                    label = trv.version.v.trailingLabel()
                    for sig in trv.troveInfo.sigs.digitalSigs.iter():
                        tspecList = fpTrovespecs.get(sig[0], set())
                        tspecList.add('%s=%s[%s]' % (trv.getName(),
                                                 str(trv.getVersion()),
                                                 str(trv.getFlavor())))
                        fpTrovespecs[sig[0]] = tspecList
                        if fingerprints.has_key(label):
                            if sig[0] not in fingerprints[label]:
                                fingerprints[label].append(sig[0])
                        else:
                            fingerprints.update({label:[sig[0]]})

            missingKeys = []
            for label, fingerprints in fingerprints.items():
                for fp in fingerprints:
                    try:
                        key = client.repos.getAsciiOpenPGPKey(label, fp)
                        fd, fname = tempfile.mkstemp(dir = constants.tmpDir)
                        os.close(fd)
                        fd = open(fname, 'w')
                        fd.write(key)
                        fd.close()
                        call('gpg', '--home', homeDir,
                             '--trust-model', 'always',
                             '--import', fname)
                        os.unlink(fname)
                    except openpgpfile.KeyNotFound:
                        missingKeys.append(fp)

            if missingKeys:
                errorMessage = 'The following troves do not have keys in ' \
                    'their associated repositories:\n'
                for fingerprint in missingKeys:
                    errorMessage += '%s requires %s\n' %  \
                        (', '.join(fpTrovespecs[fingerprint]), fingerprint)
                raise RuntimeError(errorMessage)
            call('gpg', '--home', homeDir, '--export',
                 '--no-auto-check-trustdb', '-o',
                 os.path.join(topdir, 'public_keys.gpg'))
        finally:
            util.rmtree(homeDir, ignore_errors = True)
            util.rmtree(tmpRoot, ignore_errors = True)
Ejemplo n.º 3
0
    def prepareTemplates(self, topdir, templateDir):
        self.status("Preparing ISO template")
        _linkRecurse(templateDir, topdir)
        productDir = os.path.join(topdir, self.productDir)

        # replace isolinux.bin with a real copy, since it's modified
        call('cp', '--remove-destination', '-a',
            templateDir + '/isolinux/isolinux.bin', topdir + '/isolinux/isolinux.bin')
        if os.path.exists(os.path.join(templateDir, 'isolinux')):
            for msgFile in [x for x in os.listdir(os.path.join(templateDir, 'isolinux')) if x.endswith('.msg')]:
                call('cp', '--remove-destination', '-a',
                     os.path.join(templateDir, 'isolinux', msgFile),
                     os.path.join(topdir, 'isolinux', msgFile))

        csdir = os.path.join(topdir, self.productDir, 'changesets')
        util.mkdirChain(csdir)
        return csdir
Ejemplo n.º 4
0
    def convertSplash(self, topdir, tmpPath):
        # convert syslinux-splash.png to splash.lss, if exists
        if os.path.exists(tmpPath + '/pixmaps/syslinux-splash.png'):
            log.info("found syslinux-splash.png, converting to splash.lss")

            splash = file(tmpPath + '/pixmaps/splash.lss', 'w')
            palette = [] # '#000000=0', '#cdcfd5=7', '#c90000=2', '#ffffff=15', '#5b6c93=9']
            pngtopnm = subprocess.Popen(['pngtopnm', tmpPath + '/pixmaps/syslinux-splash.png'], stdout = subprocess.PIPE)
            ppmtolss16 = subprocess.Popen(['ppmtolss16'] + palette, stdin = pngtopnm.stdout, stdout = splash)
            ppmtolss16.communicate()

        # copy the splash.lss files to the appropriate place
        if os.path.exists(tmpPath + '/pixmaps/splash.lss'):
            log.info("found splash.lss; moving to isolinux directory")
            splashTarget = os.path.join(topdir, 'isolinux')
            call('cp', '--remove-destination', tmpPath + '/pixmaps/splash.lss', splashTarget)
            # FIXME: regenerate boot.iso here

        # Locate splash for isolinux vesamenu background.
        for name in ('vesamenu-splash.jpg', 'vesamenu-splash.png'):
            sourcePath = os.path.join(tmpPath, 'pixmaps', name)
            if os.path.exists(sourcePath):
                ext = name.split('.')[-1]
                name = 'splash.%s' % ext
                util.copyfile(sourcePath,
                        os.path.join(topdir, 'isolinux', name))

                # Rewrite isolinux.cfg to point to the background image.
                isolinux = os.path.join(topdir, 'isolinux', 'isolinux.cfg')
                lines = open(isolinux).readlines()
                for n, line in enumerate(lines):
                    if line.startswith('menu background '):
                        lines[n] = 'menu background %s\n' % name
                open(isolinux, 'w').write(''.join(lines))

                break
Ejemplo n.º 5
0
    def buildIsos(self, topdir):
        outputDir = os.path.join(constants.finishedDir, self.UUID)
        self.outputDir = outputDir
        util.mkdirChain(outputDir)
        # add the group writeable bit
        os.chmod(outputDir, os.stat(outputDir)[0] & 0777 | 0020)

        isoList = []

        if self.basefilename:
            isoNameTemplate = self.basefilename + '-'
        else:
            isoNameTemplate = "%s-%s-%s-" % \
                (self.jobData['project']['hostname'],
                 upstream(self.baseVersion),
                 self.arch)
        sourceDir = os.path.normpath(topdir + "/../")

        for d in sorted(os.listdir(sourceDir)):
            if not d.startswith('disc'):
                continue

            discNum = d.split("disc")[-1]
            discNumStr = "Disc %d" % int(discNum)
            truncatedName = self.jobData['name'][:31-len(discNumStr)]
            volumeId = "%s %s" % (truncatedName, discNumStr)
            outputIsoName = isoNameTemplate + d + ".iso"
            if os.access(os.path.join(sourceDir, d, "isolinux/isolinux.bin"), os.R_OK):
                os.chdir(os.path.join(sourceDir, d))
                call("mkisofs", "-o", outputDir + "/" + outputIsoName,
                                "-b", "isolinux/isolinux.bin",
                                "-c", "isolinux/boot.cat",
                                "-no-emul-boot",
                                "-boot-load-size", "4",
                                "-boot-info-table", "-R", "-J",
                                "-V", volumeId,
                                "-T", ".")
            else:
                os.chdir(os.path.join(sourceDir, d))
                call("mkisofs", "-o", outputDir + "/" + outputIsoName,
                     "-R", "-J", "-V", volumeId, "-T", ".")

            # mkisofs will happily ignore out of space conditions and produce a
            # truncated ISO file, so assume that if there's less than 1MB of
            # free space afterwards that it failed.
            fst = os.statvfs(outputDir)
            if fst.f_bsize * fst.f_bfree < 1000000:
                raise RuntimeError(
                        "Not enough scratch space while running mkisofs")

            isoList.append((outputIsoName, "%s Disc %s" % (self.jobData['project']['name'], discNum)))

        isoList = [ (os.path.join(outputDir, iso[0]), iso[1]) for iso in isoList ]
        # this for loop re-identifies any iso greater than 700MB as a DVD
        for index, (iso, name) in zip(range(len(isoList)), isoList[:]):
            szPipe = os.popen('isosize %s' % iso, 'r')
            isoSize = int(szPipe.read())
            szPipe.close()
            if isoSize > 734003200: # 700 MB in bytes
                newIso = iso.replace('disc', 'dvd')
                newName = name.replace('Disc', 'DVD')
                os.rename(iso, newIso)
                isoList[index] = (newIso, newName)

        for iso, name in isoList:
            if not os.access(iso, os.R_OK):
                raise RuntimeError, "ISO generation failed"
            else:
                cmd = [constants.implantIsoMd5]
                if not self.showMediaCheck:
                    cmd.append('--supported-iso')
                cmd.append(iso)
                call(*cmd)

        # add the netboot images
        for f in ('boot.iso', 'diskboot.img'):
            inF = os.path.join(topdir, 'images', f)
            outF = os.path.join(outputDir, f)
            if os.path.exists(inF):
                gencslist._linkOrCopyFile(inF, outF)
                isoList += ( (outF, f), )
        return isoList
Ejemplo n.º 6
0
    def writeProductImage(self, topdir, arch):
        """write the product.img cramfs"""
        baseDir = os.path.join(topdir, self.productDir, 'base')
        tmpPath = tempfile.mkdtemp(dir=constants.tmpDir)
        self.writeBuildStamp(tmpPath)

        # RHEL 6 anaconda looks for product.img in a different location than
        # rPL 1 or rPL 2. To aid in detection, the path to product.img is
        # stashed in .treeinfo.
        treeInfo = os.path.join(topdir, '.treeinfo')
        productPath = os.path.join(baseDir, "product.img")
        stage2 = None
        if os.path.exists(treeInfo):
            try:
                parser = ConfigParser.SafeConfigParser()
                parser.read(treeInfo)
                # Look for an images-ARCH section, which may include a
                # path to product.img
                for section in parser.sections():
                    if not section.startswith('images-'):
                        continue
                    if parser.has_option(section, 'product.img'):
                        productPath = os.path.normpath(os.path.join(topdir,
                            parser.get(section, 'product.img')))
                # There may also be a pointer to the stage2
                if parser.has_option('stage2', 'mainimage'):
                    stage2 = parser.get('stage2', 'mainimage')
            except:
                log.exception("Failed to parse .treeinfo; "
                        "using default paths.")
        log.info("Target path for product.img is %s", productPath)

        # extract anaconda-images from repository, if exists
        tmpRoot = tempfile.mkdtemp(dir=constants.tmpDir)
        util.mkdirChain(os.path.join(tmpRoot, 'usr', 'share', 'anaconda',
                                     'pixmaps'))
        cclient = self.getConaryClient(tmpRoot, arch)
        cclient.setUpdateCallback(self.callback)

        log.info("generating anaconda artwork.")
        autoGenPath = tempfile.mkdtemp(dir=constants.tmpDir)
        ai = AnacondaImages( \
            self.jobData['name'],
            indir = constants.anacondaImagesPath,
            outdir = autoGenPath,
            fontfile = '/usr/share/fonts/bitstream-vera/Vera.ttf')
        ai.processImages()

        uJob = None
        log.info("checking for artwork from anaconda-custom=%s" % cclient.cfg.installLabelPath[0].asString())
        uJob = self._getUpdateJob(cclient, "anaconda-custom")
        if uJob:
            log.info("custom artwork found. applying on top of generated artwork")
            cclient.applyUpdate(uJob, callback = self.callback,
                                replaceFiles = True)
            log.info("success.")

        # if syslinux-splash.png does not exist in the anaconda-custom trove, change the
        # syslinux messages to fit our autogenerated palette.
        if not os.path.exists(os.path.join(tmpRoot, 'usr', 'share', 'anaconda', 'pixmaps', 'syslinux-splash.png')) and \
            os.path.isdir(os.path.join(topdir, 'isolinux')):
            # do this here because we know we don't have custom artwork.
            # modify isolinux message colors to match default splash palette.
            for msgFile in [x for x in os.listdir( \
                os.path.join(topdir, 'isolinux')) if x.endswith('.msg')]:

                call('sed', '-i', 's/07/0a/g;s/02/0e/g',
                     os.path.join(topdir, 'isolinux', msgFile))

        # copy autogenerated pixmaps into cramfs root
        util.mkdirChain(os.path.join(tmpPath, 'pixmaps'))
        tmpTar = tempfile.mktemp(dir = constants.tmpDir, suffix = '.tar')
        call('tar', 'cf', tmpTar, '-C', autoGenPath, '.')
        call('tar', 'xf', tmpTar, '-C', os.path.join(tmpPath, 'pixmaps'))
        os.unlink(tmpTar)

        if uJob:
            # copy pixmaps and scripts into cramfs root
            tmpTar = tempfile.mktemp(dir = constants.tmpDir, suffix = '.tar')
            call('tar', 'cf', tmpTar, '-C',
                 os.path.join(tmpRoot, 'usr', 'share', 'anaconda'), '.')
            call('tar', 'xf', tmpTar, '-C', tmpPath)
            os.unlink(tmpTar)

        self.convertSplash(topdir, tmpPath)
        self.changeIsolinuxMenuTitle(topdir)
        self.writeConaryRc(os.path.join(tmpPath, 'conaryrc'), cclient)

        # extract constants.py from the stage2.img template and override the BETANAG flag
        # this would be better if constants.py could load a secondary constants.py
        for path in (stage2, 'images/stage2.img', 'rPath/base/stage2.img'):
            if not path:
                # stage2 is None if .treeinfo was not found
                continue
            fullpath = os.path.join(topdir, path)
            if not os.path.exists(fullpath):
                continue
            betaNag = int(self.getBuildData('betaNag'))
            log.info('Copying constants.py from %s and setting beta nag to %s',
                    path, betaNag)

            stage2Path = tempfile.mkdtemp(dir=constants.tmpDir)
            logCall(['/bin/mount', '-o', 'loop,ro', fullpath, stage2Path])
            out = open(tmpPath + '/constants.py', 'w')
            for line in open(os.path.join(stage2Path
                    + '/usr/lib/anaconda/constants.py')):
                if line.startswith('BETANAG ='):
                    line = 'BETANAG = %d\n' % betaNag
                out.write(line)
            out.close()
            logCall(['/bin/umount', '-d', stage2Path])
            os.rmdir(stage2Path)
            break
        else:
            log.info('Could not find stage2.img; not changing beta nag')

        # create cramfs
        logCall(['/sbin/mkfs.cramfs', tmpPath, productPath])

        # clean up
        util.rmtree(tmpPath, ignore_errors = True)
        util.rmtree(tmpRoot, ignore_errors = True)
        util.rmtree(autoGenPath, ignore_errors = True)