2008-09-12 00:21:12 +00:00
|
|
|
#
|
|
|
|
# pylorax
|
|
|
|
# Install image and tree support data generation tool -- Python module.
|
|
|
|
#
|
2009-04-22 13:01:28 +00:00
|
|
|
# Copyright (C) 2008, 2009 Red Hat, Inc.
|
2008-09-12 00:21:12 +00:00
|
|
|
#
|
|
|
|
# This program is free software; you can redistribute it and/or modify
|
|
|
|
# it under the terms of the GNU General Public License as published by
|
|
|
|
# the Free Software Foundation; either version 2 of the License, or
|
|
|
|
# (at your option) any later version.
|
|
|
|
#
|
|
|
|
# This program is distributed in the hope that it will be useful,
|
|
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
# GNU General Public License for more details.
|
|
|
|
#
|
|
|
|
# You should have received a copy of the GNU General Public License
|
|
|
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
#
|
|
|
|
# Author(s): David Cantrell <dcantrell@redhat.com>
|
2009-04-22 13:01:28 +00:00
|
|
|
# Martin Gracik <mgracik@redhat.com>
|
2008-09-12 00:21:12 +00:00
|
|
|
#
|
|
|
|
|
2009-04-22 13:01:28 +00:00
|
|
|
import sys
|
2008-09-13 02:04:02 +00:00
|
|
|
import os
|
|
|
|
import shutil
|
|
|
|
import tempfile
|
2009-04-22 13:01:28 +00:00
|
|
|
import time
|
|
|
|
import ConfigParser
|
2008-09-13 02:04:02 +00:00
|
|
|
|
2008-10-05 04:44:28 +00:00
|
|
|
import yum
|
|
|
|
import rpmUtils
|
|
|
|
|
2009-04-22 13:01:28 +00:00
|
|
|
import instroot
|
|
|
|
import images
|
2008-10-05 04:44:28 +00:00
|
|
|
|
2008-09-13 00:34:15 +00:00
|
|
|
|
2008-10-10 03:04:13 +00:00
|
|
|
class Lorax:
|
2009-04-22 13:01:28 +00:00
|
|
|
def __init__(self, repos, options):
|
|
|
|
self.repos = repos
|
|
|
|
|
|
|
|
# required
|
|
|
|
self.product = options.product
|
|
|
|
self.version = options.version
|
|
|
|
self.release = options.release
|
|
|
|
self.output = options.output
|
|
|
|
|
|
|
|
# optional
|
|
|
|
self.debug = options.debug
|
|
|
|
self.variant = options.variant
|
|
|
|
self.bugurl = options.bugurl
|
|
|
|
self.updates = options.updates
|
|
|
|
self.mirrorlist = options.mirrorlist
|
|
|
|
self.confdir = options.confdir
|
|
|
|
self.cleanup = options.cleanup
|
|
|
|
|
2008-10-10 07:44:06 +00:00
|
|
|
self.conf = {}
|
2009-04-22 13:01:28 +00:00
|
|
|
if not self.confdir:
|
|
|
|
self.confdir = '/etc/lorax'
|
|
|
|
self.conf['confdir'] = self.confdir
|
2008-10-10 07:44:06 +00:00
|
|
|
self.conf['datadir'] = '/usr/share/lorax'
|
2009-04-22 13:01:28 +00:00
|
|
|
self.conf['tmpdir'] = tempfile.gettempdir()
|
2008-09-13 00:34:15 +00:00
|
|
|
|
2008-10-10 03:04:13 +00:00
|
|
|
def run(self):
|
|
|
|
"""run()
|
2008-09-12 00:21:12 +00:00
|
|
|
|
2008-10-10 03:04:13 +00:00
|
|
|
Generate install images.
|
|
|
|
"""
|
2008-09-13 02:04:02 +00:00
|
|
|
|
2009-04-22 13:01:28 +00:00
|
|
|
print('Collecting repos...')
|
|
|
|
self.repo, self.extrarepos = self.__collectRepos()
|
2008-10-10 07:51:45 +00:00
|
|
|
|
2009-04-22 13:01:28 +00:00
|
|
|
if not self.repo:
|
|
|
|
sys.stderr.write('No valid repository.\n')
|
|
|
|
sys.exit(1)
|
2008-10-10 08:11:13 +00:00
|
|
|
|
2009-04-22 13:01:28 +00:00
|
|
|
print('Initializing directories...')
|
2008-10-10 07:54:29 +00:00
|
|
|
self.buildinstdir, self.treedir, self.cachedir = self.__initializeDirs()
|
2009-04-22 13:01:28 +00:00
|
|
|
|
|
|
|
print('Writing yum configuration...')
|
2008-10-10 07:54:29 +00:00
|
|
|
self.yumconf = self.__writeYumConf()
|
2008-10-10 07:51:45 +00:00
|
|
|
|
2009-04-22 13:01:28 +00:00
|
|
|
print('Getting the build architecture...')
|
|
|
|
self.buildarch = self.__getBuildArch()
|
2008-09-13 02:04:02 +00:00
|
|
|
|
2009-04-22 13:01:28 +00:00
|
|
|
print('Creating install root tree...')
|
|
|
|
self.makeInstRoot()
|
2008-09-13 02:04:02 +00:00
|
|
|
|
2009-04-22 13:01:28 +00:00
|
|
|
print('Writing .treeinfo...')
|
|
|
|
self.__writeTreeInfo()
|
2008-09-13 02:04:02 +00:00
|
|
|
|
2009-04-22 13:01:28 +00:00
|
|
|
print('Writing .discinfo...')
|
|
|
|
self.__writeDiscInfo()
|
2008-09-13 02:04:02 +00:00
|
|
|
|
2009-04-22 13:01:28 +00:00
|
|
|
print('Creating images...')
|
|
|
|
self.makeImages()
|
|
|
|
|
|
|
|
if self.cleanup:
|
|
|
|
print('Cleaning up...')
|
|
|
|
self.cleanUp()
|
|
|
|
|
|
|
|
def __collectRepos(self):
|
|
|
|
"""_collectRepos()
|
|
|
|
|
|
|
|
Get the main repo (the first one) and then build a list of all remaining
|
|
|
|
repos in the list. Sanitize each repo URL for proper yum syntax.
|
2008-10-10 03:04:13 +00:00
|
|
|
"""
|
2008-09-13 02:04:02 +00:00
|
|
|
|
2009-04-22 13:01:28 +00:00
|
|
|
repolist = []
|
|
|
|
for repospec in self.repos:
|
|
|
|
if repospec.startswith('/'):
|
|
|
|
repo = 'file://%s' % (repospec,)
|
|
|
|
print('Adding local repo:\n %s' % (repo,))
|
|
|
|
repolist.append(repo)
|
|
|
|
elif repospec.startswith('http://') or repospec.startswith('ftp://'):
|
|
|
|
print('Adding remote repo:\n %s' % (repospec,))
|
|
|
|
repolist.append(repospec)
|
2008-09-13 02:04:02 +00:00
|
|
|
|
2009-04-22 13:01:28 +00:00
|
|
|
if not repolist:
|
|
|
|
return None, []
|
|
|
|
else:
|
|
|
|
return repolist[0], repolist[1:]
|
2008-09-13 02:04:02 +00:00
|
|
|
|
2009-04-22 13:01:28 +00:00
|
|
|
def __initializeDirs(self):
|
|
|
|
"""_initializeDirs()
|
2008-09-13 02:04:02 +00:00
|
|
|
|
2009-04-22 13:01:28 +00:00
|
|
|
Create directories used for image generation.
|
|
|
|
"""
|
|
|
|
|
|
|
|
if not os.path.isdir(self.output):
|
|
|
|
os.makedirs(self.output, mode=0755)
|
|
|
|
|
|
|
|
self.conf['tmpdir'] = tempfile.mkdtemp('XXXXXX', 'lorax.tmp.', self.conf['tmpdir'])
|
|
|
|
buildinstdir = tempfile.mkdtemp('XXXXXX', 'buildinstall.tree.', self.conf['tmpdir'])
|
|
|
|
treedir = tempfile.mkdtemp('XXXXXX', 'treedir.', self.conf['tmpdir'])
|
|
|
|
cachedir = tempfile.mkdtemp('XXXXXX', 'yumcache.', self.conf['tmpdir'])
|
|
|
|
|
|
|
|
print('Working directories:')
|
|
|
|
print(' tmpdir = %s' % (self.conf['tmpdir'],))
|
|
|
|
print(' buildinstdir = %s' % (buildinstdir,))
|
|
|
|
print(' treedir = %s' % (treedir,))
|
|
|
|
print(' cachedir = %s' % (cachedir,))
|
2008-09-13 02:04:02 +00:00
|
|
|
|
2009-04-22 13:01:28 +00:00
|
|
|
return buildinstdir, treedir, cachedir
|
|
|
|
|
|
|
|
def __writeYumConf(self):
|
|
|
|
"""_writeYumConf()
|
|
|
|
|
|
|
|
Generate a temporary yum.conf file for image generation. Returns the path
|
|
|
|
to the temporary yum.conf file on success, None of failure.
|
2008-10-10 03:04:13 +00:00
|
|
|
"""
|
2008-09-13 02:04:02 +00:00
|
|
|
|
2009-04-22 13:01:28 +00:00
|
|
|
(fd, yumconf) = tempfile.mkstemp(prefix='yum.conf', dir=self.conf['tmpdir'])
|
|
|
|
f = os.fdopen(fd, 'w')
|
2008-09-13 02:04:02 +00:00
|
|
|
|
2009-04-22 13:01:28 +00:00
|
|
|
f.write('[main]\n')
|
|
|
|
f.write('cachedir=%s\n' % (self.cachedir,))
|
|
|
|
f.write('keepcache=0\n')
|
|
|
|
f.write('gpgcheck=0\n')
|
|
|
|
f.write('plugins=0\n')
|
|
|
|
f.write('reposdir=\n')
|
|
|
|
f.write('tsflags=nodocs\n\n')
|
|
|
|
|
|
|
|
f.write('[loraxrepo]\n')
|
|
|
|
f.write('name=lorax repo\n')
|
|
|
|
f.write('baseurl=%s\n' % (self.repo,))
|
|
|
|
f.write('enabled=1\n\n')
|
|
|
|
|
|
|
|
for n, extra in enumerate(self.extrarepos, start=1):
|
|
|
|
f.write('[lorax-extrarepo-%d]\n' % (n,))
|
|
|
|
f.write('name=lorax extra repo %d\n' % (n,))
|
|
|
|
f.write('baseurl=%s\n' % (extra,))
|
|
|
|
f.write('enabled=1\n')
|
|
|
|
|
|
|
|
for n, mirror in enumerate(self.mirrorlist, start=1):
|
|
|
|
f.write('[lorax-mirrorlistrepo-%d]\n' % (n,))
|
|
|
|
f.write('name=lorax mirrorlist repo %d\n' % (n,))
|
|
|
|
f.write('mirrorlist=%s\n' % (mirror,))
|
|
|
|
f.write('enabled=1\n')
|
2008-10-06 01:08:38 +00:00
|
|
|
|
2009-04-22 13:01:28 +00:00
|
|
|
f.close()
|
|
|
|
print('Wrote lorax yum configuration to %s' % (yumconf,))
|
|
|
|
|
|
|
|
return yumconf
|
|
|
|
|
|
|
|
def __getBuildArch(self):
|
|
|
|
"""_getBuildArch()
|
2008-09-13 02:04:02 +00:00
|
|
|
|
2008-10-10 03:04:13 +00:00
|
|
|
Query the configured yum repositories to determine our build architecture,
|
|
|
|
which is the architecture of the anaconda package in the repositories.
|
2008-09-13 02:04:02 +00:00
|
|
|
|
2008-10-10 03:04:13 +00:00
|
|
|
This function is based on a subset of what repoquery(1) does.
|
|
|
|
"""
|
2008-09-13 02:04:02 +00:00
|
|
|
|
2008-10-10 03:04:13 +00:00
|
|
|
uname_arch = os.uname()[4]
|
2008-09-13 02:04:02 +00:00
|
|
|
|
2009-04-22 13:01:28 +00:00
|
|
|
if not self.yumconf or not os.path.isfile(self.yumconf):
|
|
|
|
sys.stderr.write('ERROR: yum.conf does not exist, defaulting to %s\n' % (uname_arch,))
|
2008-10-10 03:04:13 +00:00
|
|
|
return uname_arch
|
2008-09-13 02:04:02 +00:00
|
|
|
|
2008-10-10 03:04:13 +00:00
|
|
|
repoq = yum.YumBase()
|
2009-04-22 13:01:28 +00:00
|
|
|
repoq.doConfigSetup(self.yumconf)
|
2008-09-13 02:04:02 +00:00
|
|
|
|
2008-10-10 03:04:13 +00:00
|
|
|
try:
|
|
|
|
repoq.doRepoSetup()
|
2009-04-22 13:01:28 +00:00
|
|
|
except yum.Errors.RepoError:
|
|
|
|
sys.stderr.write('ERROR: cannot query yum repo, defaulting to %s\n' % (uname_arch,))
|
2008-10-10 03:04:13 +00:00
|
|
|
return uname_arch
|
2008-09-13 02:04:02 +00:00
|
|
|
|
2008-10-10 03:04:13 +00:00
|
|
|
repoq.doSackSetup(rpmUtils.arch.getArchList())
|
|
|
|
repoq.doTsSetup()
|
2008-09-13 02:04:02 +00:00
|
|
|
|
2008-10-10 03:04:13 +00:00
|
|
|
ret_arch = None
|
|
|
|
for pkg in repoq.pkgSack.simplePkgList():
|
|
|
|
(n, a, e, v, r) = pkg
|
|
|
|
if n == 'anaconda':
|
|
|
|
ret_arch = a
|
|
|
|
break
|
2008-09-13 02:04:02 +00:00
|
|
|
|
2009-04-22 13:01:28 +00:00
|
|
|
if not ret_arch:
|
2008-10-10 03:04:13 +00:00
|
|
|
ret_arch = uname_arch
|
2008-10-06 01:08:38 +00:00
|
|
|
|
2008-10-10 03:04:13 +00:00
|
|
|
return ret_arch
|
2008-10-04 01:46:01 +00:00
|
|
|
|
2009-04-22 13:01:28 +00:00
|
|
|
def __writeTreeInfo(self, discnum=1, totaldiscs=1, packagedir=''):
|
|
|
|
outfile = os.path.join(self.output, '.treeinfo')
|
|
|
|
|
|
|
|
data = { 'timestamp': time.time(),
|
|
|
|
'family': self.product,
|
|
|
|
'version': self.version,
|
|
|
|
'arch': self.buildarch,
|
|
|
|
'variant': self.variant,
|
|
|
|
'discnum': str(discnum),
|
|
|
|
'totaldiscs': str(totaldiscs),
|
|
|
|
'packagedir': packagedir }
|
|
|
|
|
|
|
|
c = ConfigParser.ConfigParser()
|
|
|
|
|
|
|
|
section = 'general'
|
|
|
|
c.add_section(section)
|
|
|
|
for key, value in data.items():
|
|
|
|
c.set(section, key, value)
|
2008-10-06 01:08:38 +00:00
|
|
|
|
2009-04-22 13:01:28 +00:00
|
|
|
try:
|
|
|
|
f = open(outfile, 'w')
|
|
|
|
except IOError:
|
|
|
|
return False
|
|
|
|
else:
|
|
|
|
c.write(f)
|
|
|
|
f.close()
|
|
|
|
return True
|
|
|
|
|
|
|
|
def __writeDiscInfo(self, discnum=0):
|
|
|
|
outfile = os.path.join(self.output, '.discinfo')
|
2008-10-04 01:46:01 +00:00
|
|
|
|
2009-04-22 13:01:28 +00:00
|
|
|
try:
|
|
|
|
f = open(outfile, 'w')
|
|
|
|
except IOError:
|
|
|
|
return False
|
|
|
|
else:
|
|
|
|
f.write('%f\n' % (time.time(),))
|
|
|
|
f.write('%s\n' % (self.release,))
|
|
|
|
f.write('%s\n' % (self.buildarch,))
|
|
|
|
f.write('%d\n' % (discnum,))
|
|
|
|
f.close()
|
|
|
|
return True
|
|
|
|
|
|
|
|
def makeInstRoot(self):
|
|
|
|
root = instroot.InstRoot(conf=self.conf,
|
|
|
|
yumconf=self.yumconf,
|
|
|
|
arch=self.buildarch,
|
|
|
|
treedir=self.treedir,
|
|
|
|
updates=self.updates)
|
|
|
|
root.run()
|
2008-09-13 02:04:02 +00:00
|
|
|
|
2009-04-22 13:01:28 +00:00
|
|
|
# TODO
|
|
|
|
def makeImages(self):
|
|
|
|
pass
|
2008-09-13 02:04:02 +00:00
|
|
|
|
2009-04-22 13:01:28 +00:00
|
|
|
def cleanUp(self, trash=[]):
|
|
|
|
"""cleanup([trash])
|
2008-09-13 02:04:02 +00:00
|
|
|
|
2009-04-22 13:01:28 +00:00
|
|
|
Given a list of things to remove, cleanUp() will remove them if it can.
|
|
|
|
Never fails, just tries to remove things and returns regardless of
|
|
|
|
failures removing things.
|
2008-10-10 03:04:13 +00:00
|
|
|
"""
|
2008-10-05 06:59:46 +00:00
|
|
|
|
2009-04-22 13:01:28 +00:00
|
|
|
for item in trash:
|
|
|
|
if os.path.isdir(item):
|
|
|
|
shutil.rmtree(item, ignore_errors=True)
|
|
|
|
else:
|
|
|
|
os.unlink(item)
|
2008-10-10 03:04:13 +00:00
|
|
|
|
2009-04-22 13:01:28 +00:00
|
|
|
if os.path.isdir(self.conf['tmpdir']):
|
|
|
|
shutil.rmtree(self.conf['tmpdir'], ignore_errors=True)
|
2008-10-10 03:04:13 +00:00
|
|
|
|