Made some code and file cleanup.

This commit is contained in:
Martin Gracik 2009-06-09 16:10:01 +02:00
parent 1da93076b4
commit 032438ddbc
24 changed files with 367 additions and 335 deletions

View File

@ -1,81 +1,76 @@
# initrd template # initrd template
:makedir # create required directories
@initrd@/modules makedir @initrd@/modules
@initrd@/sbin makedir @initrd@/sbin
@initrd@/dev makedir @initrd@/dev
@initrd@/etc makedir @initrd@/etc
@initrd@/etc/udev/rules.d makedir @initrd@/etc/udev/rules.d
@initrd@/lib/udev/rules.d makedir @initrd@/lib/udev/rules.d
@initrd@/proc makedir @initrd@/proc
@initrd@/selinux makedir @initrd@/selinux
@initrd@/sys makedir @initrd@/sys
@initrd@/etc/terminfo/{a,b,d,l,s,v,x} makedir @initrd@/etc/terminfo/a
@initrd@/tmp makedir @initrd@/etc/terminfo/b
@initrd@/usr/libexec makedir @initrd@/etc/terminfo/d
@initrd@/usr/@libdir@/NetworkManager makedir @initrd@/etc/terminfo/l
@initrd@/usr/share/dbus-1/system-services makedir @initrd@/etc/terminfo/s
@initrd@/var/cache/hald makedir @initrd@/etc/terminfo/v
@initrd@/var/lib/dbus makedir @initrd@/etc/terminfo/x
@initrd@/var/lib/dhclient makedir @initrd@/tmp
@initrd@/var/lock/rpm makedir @initrd@/usr/libexec
@initrd@/var/run makedir @initrd@/usr/@libdir@/NetworkManager
@initrd@/var/run/dbus makedir @initrd@/usr/share/dbus-1/system-services
@initrd@/var/run/hald makedir @initrd@/var/cache/hald
@initrd@/var/run/NetworkManager makedir @initrd@/var/lib/dbus
@initrd@/etc/dbus-1/system.d makedir @initrd@/var/lib/dhclient
@initrd@/etc/modprobe.d makedir @initrd@/var/lock/rpm
@initrd@/etc/NetworkManager/dispatcher.d makedir @initrd@/var/run
@initrd@/@libdir@/dbus-1 makedir @initrd@/var/run/dbus
@initrd@/etc/sysconfig/network-scripts makedir @initrd@/var/run/hald
@initrd@/usr/share/PolicyKit/policy makedir @initrd@/var/run/NetworkManager
@initrd@/etc/PolicyKit makedir @initrd@/etc/dbus-1/system.d
@initrd@/var/lib/misc makedir @initrd@/etc/modprobe.d
@initrd@/etc/hal/fdi makedir @initrd@/etc/NetworkManager/dispatcher.d
@initrd@/usr/share/hal/fdi makedir @initrd@/@libdir@/dbus-1
@initrd@/usr/share/hwdata makedir @initrd@/etc/sysconfig/network-scripts
@initrd@/etc/rc.d/init.d makedir @initrd@/usr/share/PolicyKit/policy
@initrd@/usr/sbin makedir @initrd@/etc/PolicyKit
@initrd@/var/run/wpa_supplicant makedir @initrd@/var/lib/misc
makedir @initrd@/etc/hal/fdi
makedir @initrd@/usr/share/hal/fdi
makedir @initrd@/usr/share/hwdata
makedir @initrd@/etc/rc.d/init.d
makedir @initrd@/usr/sbin
makedir @initrd@/var/run/wpa_supplicant
:edit # set the buildarch
@initrd@/etc/arch text "@buildarch@" edit @initrd@/etc/arch text "@buildarch@"
# copy etc
copy @instroot@/etc/passwd to @initrd@/etc
copy @instroot@/etc/group to @initrd@/etc
copy @instroot@/etc/nsswitch.conf to @initrd@/etc
:copy # copy mount/umount
@instroot@/etc/passwd to @initrd@/etc copy @instroot@/bin/mount to @initrd@/sbin/mount
@instroot@/etc/group to @initrd@/etc copy @instroot@/bin/umount to @initrd@/sbin/umount
@instroot@/etc/nsswitch.conf to @initrd@/etc copy @instroot@/sbin/mount.nfs to @initrd@/sbin/mount.nfs
link @initrd@/sbin/umount.nfs to mount.nfs
# mount/umount # copy udev
:copy copy @instroot@/sbin/udevd to @initrd@/sbin
@instroot@/bin/mount to @initrd@/sbin/mount copy @instroot@/sbin/udevadm to @initrd@/sbin
@instroot@/bin/umount to @initrd@/sbin/umount link @initrd@/sbin/udevinfo to udevadm
@instroot@/usr/sbin/mount.nfs to @initrd@/sbin/mount.nfs link @initrd@/sbin/udevsettle to udevadm
:link
@initrd@/sbin/umount.nfs to @initrd@/sbin/mount.nfs
# udev # copy bash
:copy copy @instroot@/bin/bash to @initrd@/sbin/bash
@instroot@/sbin/udevd to @initrd@/sbin link @initrd@/sbin/sh to bash
@instroot@/sbin/udevadm to @initrd@/sbin copy @instroot@/sbin/consoletype to @initrd@/sbin/consoletype
:link copy @instroot@/usr/bin/logger to @initrd@/sbin/logger
@initrd@/sbin/udevinfo to @initrd@/sbin/udevadm
@initrd@/sbin/udevsettle to @initrd@/sbin/udevadm
# bash copy @instroot@/etc/rc.d/init.d/functions to @initrd@/etc/rc.d/init.d
:copy copy @instroot@/etc/sysconfig/network-scripts/network-functions* to @initrd@/etc/sysconfig/network-scripts
@instroot@/bin/bash to @initrd@/sbin/bash
:link
@initrd@/sbin/sh to @initrd@/sbin/bash
:copy
@instroot@/sbin/consoletype to @initrd@/sbin/consoletype
@instroot@/usr/bin/logger to @initrd@/sbin/logger
:copy
@instroot@/etc/rc.d/init.d/functions to @initrd@/etc/rc.d/init.d
@instroot@/etc/sysconfig/network-scripts/network-functions* @initrd@/etc/sysconfig/network-scripts
:link
@initrd@/etc/init.d to /etc/rc.d/init.d
link @initrd@/etc/init.d to /etc/rc.d/init.d

10
share/images/README Normal file
View File

@ -0,0 +1,10 @@
This directory contains image files that can be used to create media
capable of starting the @PRODUCT@ installation process.
The boot.iso file is an ISO 9660 image of a bootable CD-ROM. It is useful
in cases where the CD-ROM installation method is not desired, but the
CD-ROM's boot speed would be an advantage.
To use this image file, burn the file onto CD-R (or CD-RW) media as you
normally would.

View File

@ -0,0 +1,7 @@
The files in this directory are useful for booting a machine via PXE.
The following files are available:
vmlinuz - the kernel used for the installer
initrd.img - an initrd with support for all install methods and
drivers supported for installation of @PRODUCT@

View File

@ -7,14 +7,14 @@ import tempfile
import time import time
import ConfigParser import ConfigParser
import re import re
from errors import LoraxError
from config import Container from config import Container
import utils.rpmutil as rpmutil from utils.rpmutils import Yum
from utils.fileutils import rm
import images import images
from exceptions import LoraxError
class Config(Container): class Config(Container):
def __init__(self): def __init__(self):
@ -52,50 +52,52 @@ class Lorax(object):
# check if we have all required options # check if we have all required options
if not self.conf.repos: if not self.conf.repos:
raise LoraxError, 'missing repos' raise LoraxError, "missing required parameter 'repos'"
if not self.conf.outdir: if not self.conf.outdir:
raise LoraxError, 'missing outdir' raise LoraxError, "missing required parameter 'outdir'"
if not self.conf.product: if not self.conf.product:
raise LoraxError, 'missing product' raise LoraxError, "missing required parameter 'product'"
if not self.conf.version: if not self.conf.version:
raise LoraxError, 'missing version' raise LoraxError, "missing required parameter 'version'"
if not self.conf.release: if not self.conf.release:
raise LoraxError, 'missing release' raise LoraxError, "missing required parameter 'release'"
self.yum = None self.yum = None
def run(self): def run(self):
print('Collecting repos...') bold = ('\033[1m', '\033[0m')
print('%sCollecting repos%s' % bold)
self.collectRepos() self.collectRepos()
# check if we have at least one valid repository # check if we have at least one valid repository
if not self.conf.repo: if not self.conf.repo:
sys.stderr.write('ERROR: no valid repository\n') sys.stderr.write('ERROR: No valid repository\n')
sys.exit(1) sys.exit(1)
print('Initializing directories...') print('%sInitializing directories%s' % bold)
self.initDirs() self.initDirs()
print('Initializing yum...') print('%sInitializing yum%s' % bold)
self.initYum() self.initYum()
print('Setting build architecture...') print('%sSetting build architecture%s' % bold)
self.setBuildArch() self.setBuildArch()
print('Writing .treeinfo...') print('%sWriting .treeinfo%s' % bold)
self.writeTreeInfo() self.writeTreeInfo()
print('Writing .discinfo...') print('%sWriting .discinfo%s' % bold)
self.writeDiscInfo() self.writeDiscInfo()
print('Preparing the install tree...') print('%sPreparing the install tree%s' % bold)
self.prepareInstRoot() self.prepareInstRoot()
print('Creating the images...') print('%sCreating the images%s' % bold)
self.makeImages() self.makeImages()
if self.conf.cleanup: if self.conf.cleanup:
print('Cleaning up...') print('%sCleaning up%s' % bold)
self.cleanUp() self.cleanUp()
def collectRepos(self): def collectRepos(self):
@ -128,7 +130,7 @@ class Lorax(object):
os.makedirs(treedir) os.makedirs(treedir)
cachedir = os.path.join(self.conf.tempdir, 'yumcache') cachedir = os.path.join(self.conf.tempdir, 'yumcache')
os.makedirs(cachedir) os.makedirs(cachedir)
initrddir = os.path.join(self.conf.tempdir, 'initrd') initrddir = os.path.join(self.conf.tempdir, 'initrddir')
os.makedirs(initrddir) os.makedirs(initrddir)
print('Working directories:') print('Working directories:')
@ -145,8 +147,8 @@ class Lorax(object):
try: try:
f = open(yumconf, 'w') f = open(yumconf, 'w')
except IOError: except IOError as why:
sys.stderr.write('ERROR: Unable to write yum.conf file\n') sys.stderr.write('ERROR: Unable to write yum.conf file: %s\n' % why)
sys.exit(1) sys.exit(1)
else: else:
f.write('[main]\n') f.write('[main]\n')
@ -179,10 +181,11 @@ class Lorax(object):
self.conf.addAttr('yumconf') self.conf.addAttr('yumconf')
self.conf.set(yumconf=yumconf) self.conf.set(yumconf=yumconf)
self.yum = rpmutil.Yum(yumconf=self.conf.yumconf, installroot=self.conf.treedir) # create the Yum object
self.yum = Yum(yumconf=self.conf.yumconf, installroot=self.conf.treedir)
# remove not needed options # remove not needed attributes
self.conf.delAttr(['repo', 'extrarepos', 'mirrorlist']) self.conf.delAttr(['repo', 'extrarepos', 'mirrorlist', 'cachedir'])
def setBuildArch(self): def setBuildArch(self):
unamearch = os.uname()[4] unamearch = os.uname()[4]
@ -190,10 +193,11 @@ class Lorax(object):
self.conf.addAttr('buildarch') self.conf.addAttr('buildarch')
self.conf.set(buildarch=unamearch) self.conf.set(buildarch=unamearch)
anaconda = self.yum.find('anaconda') installed, available = self.yum.find('anaconda')
try: try:
self.conf.set(buildarch=anaconda[0].arch) self.conf.set(buildarch=available[0].arch)
except: except:
# FIXME specify what exceptions can we get here
pass pass
# set the libdir # set the libdir
@ -206,7 +210,7 @@ class Lorax(object):
def writeTreeInfo(self, discnum=1, totaldiscs=1, packagedir=''): def writeTreeInfo(self, discnum=1, totaldiscs=1, packagedir=''):
outfile = os.path.join(self.conf.outdir, '.treeinfo') outfile = os.path.join(self.conf.outdir, '.treeinfo')
# don't print anything instead of None if variant is not specified # don't print anything instead of None, if variant is not specified
variant = '' variant = ''
if self.conf.variant: if self.conf.variant:
variant = self.conf.variant variant = self.conf.variant
@ -232,7 +236,8 @@ class Lorax(object):
c.set(section, 'kernel', 'images/pxeboot/vmlinuz') c.set(section, 'kernel', 'images/pxeboot/vmlinuz')
c.set(section, 'initrd', 'images/pxeboot/initrd.img') c.set(section, 'initrd', 'images/pxeboot/initrd.img')
# XXX actually create the boot iso somewhere, and set up this attribute # XXX actually create the boot iso somewhere before calling writeTreeInfo(),
# and set up this attribute properly
self.conf.addAttr('bootiso') self.conf.addAttr('bootiso')
if self.conf.bootiso: if self.conf.bootiso:
@ -263,7 +268,7 @@ class Lorax(object):
return True return True
def prepareInstRoot(self): def prepareInstRoot(self):
# XXX why do we need this? # XXX do we need this?
os.symlink(os.path.join(os.path.sep, 'tmp'), os.symlink(os.path.join(os.path.sep, 'tmp'),
os.path.join(self.conf.treedir, 'var', 'lib', 'xkb')) os.path.join(self.conf.treedir, 'var', 'lib', 'xkb'))
@ -271,19 +276,11 @@ class Lorax(object):
i = images.Images(self.conf, self.yum) i = images.Images(self.conf, self.yum)
i.run() i.run()
# XXX figure out where to put this
#def copyUpdates(self):
# if self.conf.updates and os.path.isdir(self.conf.updates):
# cp(os.path.join(self.conf.updates, '*'), self.conf.treedir)
# self.conf.delAttr('updates')
def cleanUp(self, trash=[]): def cleanUp(self, trash=[]):
for item in trash: for item in trash:
if os.path.isdir(item): if os.path.exists(item):
shutil.rmtree(item, ignore_errors=True) rm(item)
else:
os.unlink(item)
# remove the whole lorax tempdir # remove the whole lorax tempdir
if os.path.isdir(self.conf.tempdir): if os.path.isdir(self.conf.tempdir):
shutil.rmtree(self.conf.tempdir, ignore_errors=True) rm(self.conf.tempdir)

View File

@ -1,14 +1,10 @@
# pylorax/actions/__init__.py # pylorax/actions/__init__.py
import logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger('pylorax.actions')
import sys import sys
import os import os
def getActions(): def getActions(verbose=False):
actions = {} actions = {}
root, actions_dir = os.path.split(os.path.dirname(__file__)) root, actions_dir = os.path.split(os.path.dirname(__file__))
@ -21,17 +17,20 @@ def getActions():
modules.add(os.path.join(actions_dir, basename).replace('/', '.')) modules.add(os.path.join(actions_dir, basename).replace('/', '.'))
for module in modules: for module in modules:
logger.debug('loading actions from module %s' % module) if verbose:
print("Loading actions from module '%s'" % module)
imported = __import__(module, globals(), locals(), [module], -1) imported = __import__(module, globals(), locals(), [module], -1)
try: try:
commands = getattr(imported, 'COMMANDS') commands = getattr(imported, 'COMMANDS')
except AttributeError: except AttributeError:
logger.debug('no actions found') if verbose:
print("No actions found")
continue continue
else: else:
for command, classname in commands.items(): for command, classname in commands.items():
logger.debug('loaded: %s' % classname) if verbose:
print("Loaded: %s" % classname)
actions[command] = getattr(imported, classname) actions[command] = getattr(imported, classname)
sys.path.pop(0) sys.path.pop(0)

View File

@ -65,14 +65,13 @@ class LoraxAction(object):
"""Returns a pattern that needs to be installed, prior to calling the execute method.""" """Returns a pattern that needs to be installed, prior to calling the execute method."""
return None return None
@property
def getDeps(self): def getDeps(self):
# FIXME hmmm, how can i do this more generic? # FIXME hmmm, how can i do this more generic?
return None return None
# +-----------------+ ##### builtin actions
# | builtin actions |
# +-----------------+
class Copy(LoraxAction): class Copy(LoraxAction):
@ -85,10 +84,6 @@ class Copy(LoraxAction):
self._attrs['mode'] = kwargs.get('mode') self._attrs['mode'] = kwargs.get('mode')
def execute(self, verbose=False): def execute(self, verbose=False):
dst_dir = os.path.dirname(self.dst)
if not os.path.isdir(dst_dir):
os.makedirs(dst_dir)
cp(src=self.src, dst=self.dst, mode=self.mode, verbose=verbose) cp(src=self.src, dst=self.dst, mode=self.mode, verbose=verbose)
self._attrs['success'] = True self._attrs['success'] = True
@ -129,7 +124,7 @@ class Link(LoraxAction):
self._attrs['target'] = kwargs.get('target') self._attrs['target'] = kwargs.get('target')
def execute(self, verbose=False): def execute(self, verbose=False):
os.symlink(self.name, self.target) os.symlink(self.target, self.name)
self._attrs['success'] = True self._attrs['success'] = True
@property @property
@ -230,7 +225,10 @@ class MakeDir(LoraxAction):
def execute(self, verbose=False): def execute(self, verbose=False):
if not os.path.isdir(self.dir): if not os.path.isdir(self.dir):
os.makedirs(path=self.dir, mode=self.mode) if self.mode:
os.makedirs(self.dir, mode=int(self.mode))
else:
os.makedirs(self.dir)
self._attrs['success'] = True self._attrs['success'] = True
@property @property

View File

@ -1,21 +0,0 @@
# pylorax/base.py
import commands
def seq(arg):
if type(arg) not in (type([]), type(())):
return [arg]
else:
return arg
def getConsoleSize():
err, output = commands.getstatusoutput('stty size')
if not err:
height, width = output.split()
else:
# set defaults
height, width = 24, 80
return int(height), int(width)

View File

@ -2,10 +2,9 @@
import sys import sys
import re import re
from errors import TemplateError
from base import seq from utils.rpmutils import seq
from exceptions import TemplateError
class Container(object): class Container(object):
@ -24,16 +23,17 @@ class Container(object):
def __getitem__(self, attr): def __getitem__(self, attr):
self.__checkInternal(attr) self.__checkInternal(attr)
if attr not in self.__dict__: if attr not in self.__dict__:
raise AttributeError, "'Container' object has no attribute '%s'" % attr raise AttributeError, "'Container' object has no attribute '%s'" % attr
return self.__dict__[attr] return self.__dict__[attr]
def __setattr__(self, attr, value): def __setattr__(self, attr, value):
raise AttributeError, 'you cannot do that, use addAttr() and set() instead' raise AttributeError, "you can't do that, use addAttr() and/or set()"
def __delattr__(self, attr): def __delattr__(self, attr):
raise AttributeError, 'you cannot do that, use delAttr() instead' raise AttributeError, "you can't do that, use delAttr()"
def addAttr(self, attrs): def addAttr(self, attrs):
for attr in filter(lambda attr: attr not in self.__dict__, seq(attrs)): for attr in filter(lambda attr: attr not in self.__dict__, seq(attrs)):
@ -70,62 +70,54 @@ class Container(object):
def __checkInternal(self, attr): def __checkInternal(self, attr):
if attr.startswith('__'): if attr.startswith('__'):
raise AttributeError, 'do not mess with internal stuff' raise AttributeError, "do not mess with internal objects"
class Template(object): class Template(object):
def __init__(self): def __init__(self):
self._actions = [] self._actions = []
def parse(self, filename, supported_actions, vars): def parse(self, filename, supported_actions, variables):
try: try:
f = open(filename, 'r') f = open(filename, 'r')
except IOError: except IOError as why:
sys.stdout.write('ERROR: Unable to open the template file\n') sys.stderr.write("ERROR: Unable to open template file '%s': %s\n" % (filename, why))
return False return False
else: else:
lines = f.readlines() lines = f.readlines()
f.close() f.close()
# check vars # check template variables
for lineno, line in enumerate(lines, start=1): for lineno, line in enumerate(lines, start=1):
for var in re.findall(r'@.*?@', line) for var in filter(lambda var: var not in variables, re.findall(r'@(.*?)@', line)):
if var not in vars: raise TemplateError, "unknown variable '%s' on line %d" % (var, lineno)
raise TemplateError, 'unknown variable "%s" on line %d' % (var, lineno)
active_action = '' # parse the template
in_action = False
for lineno, line in enumerate(lines, start=1): for lineno, line in enumerate(lines, start=1):
line = line.strip() line = line.strip()
if not line or line.startswith('#'): line, sep, comment = line.partition('#')
if not line:
continue continue
for var, value in vars.items(): # expand variables
line = re.sub(r'(.*)%s(.*)' % var, '\g<1>%s\g<2>' % value, line) for var, value in variables.items():
line = re.sub(r'@%s@' % var, value, line)
if in_action and not line.startswith(':'): # get the command
# create the action object command, line = line.split(None, 1)
regex = supported_actions[active_action].REGEX if command not in supported_actions:
m = re.match(regex, line) raise TemplateError, "unknown command '%s' on line %d" % (command, lineno)
if m:
new_action = supported_actions[active_action](**m.groupdict())
self._actions.append(new_action)
else:
# didn't match the regex
raise TemplateError, 'invalid action format "%s" on line %d' % (line, lineno)
if in_action and line.startswith(':'): # create the action object
in_action = False regex = supported_actions[command].REGEX
m = re.match(regex, line)
if not in_action and line.startswith(':'): if m:
active_action = line[1:] new_action = supported_actions[command](**m.groupdict())
self._actions.append(new_action)
if active_action not in supported_actions: else:
raise TemplateError, 'unknown action "%s" on line %d' % (active_action, lineno) # didn't match the regex
else: raise TemplateError, "invalid command format '%s' on line %d" % (line, lineno)
in_action = True
continue
return True return True

View File

@ -1,4 +1,4 @@
# pylorax/exceptions.py # pylorax/errors.py
class LoraxError(Exception): class LoraxError(Exception):
pass pass

View File

@ -2,10 +2,86 @@
import sys import sys
import os import os
import commands
import re
from utils.fileutil import cp, mv, rm, touch, replace import actions
import actions.base
from config import Template
import initrd from utils.fileutils import cp, mv, rm, touch, edit, replace
from utils.ldd import LDD
class InitRD(object):
def __init__(self, config, yum):
self.conf = config
self.yum = yum
# get supported actions
supported_actions = actions.getActions()
initrd_templates = []
initrd_templates.append(os.path.join(self.conf.confdir, 'templates', 'initrd'))
initrd_templates.append(os.path.join(self.conf.confdir, 'templates', self.conf.buildarch,
'initrd'))
vars = { 'instroot': self.conf.treedir,
'initrd': self.conf.initrddir,
'libdir': self.conf.libdir,
'buildarch': self.conf.buildarch,
'confdir' : self.conf.confdir,
'datadir': self.conf.datadir }
self.template = Template()
for filename in initrd_templates:
if os.path.isfile(filename):
self.template.parse(filename, supported_actions, vars)
self._actions = []
def getPackages(self):
packages = []
for action in filter(lambda action: action.install, self.template.actions):
m = re.match(r'%s(.*)' % self.conf.treedir, action.install)
if m:
packages.append(m.group(1))
return packages
def getDeps(self):
ldd = LDD(libroot=os.path.join(self.conf.treedir, self.conf.libdir))
for action in filter(lambda action: hasattr(action, 'getDeps'), self.template.actions):
ldd.getDeps(action.getDeps)
# resolve symlinks
ldd.getLinks()
# add dependencies to actions
for dep in ldd.deps:
kwargs = {}
kwargs['src'] = dep
kwargs['dst'] = re.sub(r'%s(?P<file>.*)' % self.conf.treedir,
'%s\g<file>' % self.conf.initrddir,
dep)
new_action = actions.base.Copy(**kwargs)
self._actions.append(new_action)
def processActions(self):
# create the initrd temporary directory if it does not exist
if not os.path.isdir(self.conf.initrddir):
os.makedirs(self.conf.initrddir)
for action in self.template.actions + self._actions:
action.execute()
def create(self, dst):
err, output = commands.getstatusoutput('find %s | cpio --quiet -c -o | gzip -9 > %s' %
(self.conf.initrddir, dst))
def cleanUp(self):
rm(self.conf.initrddir)
class Images(object): class Images(object):
@ -13,6 +89,8 @@ class Images(object):
self.conf = config self.conf = config
self.yum = yum self.yum = yum
self.initrd = InitRD(self.conf, self.yum)
# XXX don't see this used anywhere... maybe in some other script, have to check... # XXX don't see this used anywhere... maybe in some other script, have to check...
#syslinux = os.path.join(self.conf.treedir, 'usr', 'lib', 'syslinux', 'syslinux-nomtools') #syslinux = os.path.join(self.conf.treedir, 'usr', 'lib', 'syslinux', 'syslinux-nomtools')
#if not os.path.isfile(syslinux): #if not os.path.isfile(syslinux):
@ -23,45 +101,95 @@ class Images(object):
# sys.exit(1) # sys.exit(1)
def run(self): def run(self):
self.prepareBootTree() bold = ('\033[1m', '\033[0m')
def prepareBootTree(self): print('%sInstalling needed packages%s' % bold)
i = initrd.InitRD(self.conf, self.yum) self.installPackages()
pkgs = i.getPkgs()
# install needed packages print('%sCopying updates%s' % bold)
self.copyUpdates()
print('%sInitializing output directory%s' % bold)
self.initOutputDirs()
print('%sPopulating the isolinux directory%s' % bold)
self.populateIsolinuxDir()
# XXX a lot of other stuff needs to be done here
pass
print('%sDONE%s' % bold)
def installPackages(self):
# required packages
self.yum.addPackages(['anaconda', 'anaconda-runtime', 'kernel', 'syslinux']) self.yum.addPackages(['anaconda', 'anaconda-runtime', 'kernel', 'syslinux'])
self.yum.addPackages(pkgs)
# optional packages from confdir
packages_files = []
packages_files.append(os.path.join(self.conf.confdir, 'packages', 'packages'))
packages_files.append(os.path.join(self.conf.confdir, 'packages', self.conf.buildarch,
'packages'))
packages = set()
for pfile in packages_files:
if os.path.isfile(pfile):
f = open(pfile, 'r')
for line in f.readlines():
line = line.strip()
if not line or line.startswith('#'):
continue
if line.startswith('-'):
packages.discard(line[1:])
else:
packages.add(line)
f.close()
self.yum.addPackages(list(packages))
# packages required for initrd image
packages = self.initrd.getPackages()
self.yum.addPackages(packages)
# install all packages
self.yum.install() self.yum.install()
def copyUpdates(self):
if self.conf.updates and os.path.isdir(self.conf.updates):
cp(os.path.join(self.conf.updates, '*'), self.conf.treedir)
self.conf.delAttr('updates')
def initOutputDirs(self):
# create the destination directories # create the destination directories
self.imgdir = os.path.join(self.conf.outdir, 'images') self.imgdir = os.path.join(self.conf.outdir, 'images')
if os.path.exists(self.imgdir): if os.path.exists(self.imgdir):
rm(self.imgdir) rm(self.imgdir)
self.pxedir = os.path.join(self.imgdir, 'pxeboot')
os.makedirs(self.imgdir) os.makedirs(self.imgdir)
self.pxedir = os.path.join(self.imgdir, 'pxeboot')
os.makedirs(self.pxedir) os.makedirs(self.pxedir)
# write the images/README # write the images/README
f = open(os.path.join(self.imgdir, 'README'), 'w') src = os.path.join(self.conf.datadir, 'images', 'README')
f.write('This directory contains image files that can be used to create media\n' dst = os.path.join(self.imgdir, 'README')
'capable of starting the %s installation process.\n\n' % self.conf.product) cp(src, dst)
f.write('The boot.iso file is an ISO 9660 image of a bootable CD-ROM. It is useful\n' replace(dst, r'@PRODUCT@', self.conf.product)
'in cases where the CD-ROM installation method is not desired, but the\n'
'CD-ROM\'s boot speed would be an advantage.\n\n')
f.write('To use this image file, burn the file onto CD-R (or CD-RW) media as you\n'
'normally would.\n')
f.close()
# write the images/pxeboot/README # write the images/pxeboot/README
f = open(os.path.join(self.pxedir, 'README'), 'w') src = os.path.join(self.conf.datadir, 'images', 'pxeboot', 'README')
f.write('The files in this directory are useful for booting a machine via PXE.\n\n') dst = os.path.join(self.pxedir, 'README')
f.write('The following files are available:\n') cp(src, dst)
f.write('vmlinuz - the kernel used for the installer\n') replace(dst, r'@PRODUCT@', self.conf.product)
f.write('initrd.img - an initrd with support for all install methods and\n')
f.write(' drivers supported for installation of %s\n' % self.conf.product)
f.close()
# create the isolinux directory
self.isodir = os.path.join(self.conf.outdir, 'isolinux')
if os.path.exists(self.isodir):
rm(self.isodir)
os.makedirs(self.isodir)
def populateIsolinuxDir(self):
# set up some dir variables for further use # set up some dir variables for further use
anacondadir = os.path.join(self.conf.treedir, 'usr', 'lib', 'anaconda-runtime') anacondadir = os.path.join(self.conf.treedir, 'usr', 'lib', 'anaconda-runtime')
bootdiskdir = os.path.join(anacondadir, 'boot') bootdiskdir = os.path.join(anacondadir, 'boot')
@ -69,13 +197,7 @@ class Images(object):
isolinuxbin = os.path.join(syslinuxdir, 'isolinux.bin') isolinuxbin = os.path.join(syslinuxdir, 'isolinux.bin')
if os.path.isfile(isolinuxbin): if os.path.isfile(isolinuxbin):
print('Creating the isolinux directory...') # copy the isolinux.bin
self.isodir = os.path.join(self.conf.outdir, 'isolinux')
if os.path.exists(self.isodir):
rm(self.isodir)
os.makedirs(self.isodir)
# copy the isolinux.bin to isolinux dir
cp(isolinuxbin, self.isodir) cp(isolinuxbin, self.isodir)
# copy the syslinux.cfg to isolinux/isolinux.cfg # copy the syslinux.cfg to isolinux/isolinux.cfg
@ -86,20 +208,22 @@ class Images(object):
replace(isolinuxcfg, r'@PRODUCT@', self.conf.product) replace(isolinuxcfg, r'@PRODUCT@', self.conf.product)
replace(isolinuxcfg, r'@VERSION@', self.conf.version) replace(isolinuxcfg, r'@VERSION@', self.conf.version)
# copy the grub.conf to isolinux dir # copy the grub.conf
cp(os.path.join(bootdiskdir, 'grub.conf'), self.isodir) cp(os.path.join(bootdiskdir, 'grub.conf'), self.isodir)
# create the initrd in isolinux dir # XXX do we want this here?
i.getDeps() # create the initrd.img
i.processActions() print('Creating the initrd.img')
i.create(os.path.join(self.isodir, 'initrd.img')) self.initrd.getDeps()
i.cleanUp() self.initrd.processActions()
self.initrd.create(os.path.join(self.isodir, 'initrd.img'))
#self.initrd.cleanUp()
# copy the vmlinuz to isolinux dir # copy the vmlinuz
vmlinuz = os.path.join(self.conf.treedir, 'boot', 'vmlinuz-*') vmlinuz = os.path.join(self.conf.treedir, 'boot', 'vmlinuz-*')
cp(vmlinuz, os.path.join(self.isodir, 'vmlinuz')) cp(vmlinuz, os.path.join(self.isodir, 'vmlinuz'))
# copy the splash files to isolinux dir # copy the splash files
vesasplash = os.path.join(anacondadir, 'syslinux-vesa-splash.jpg') vesasplash = os.path.join(anacondadir, 'syslinux-vesa-splash.jpg')
if os.path.isfile(vesasplash): if os.path.isfile(vesasplash):
cp(vesasplash, os.path.join(self.isodir, 'splash.jpg')) cp(vesasplash, os.path.join(self.isodir, 'splash.jpg'))
@ -111,29 +235,27 @@ class Images(object):
splashtools = os.path.join(anacondadir, 'splashtools.sh') splashtools = os.path.join(anacondadir, 'splashtools.sh')
splashlss = os.path.join(bootdiskdir, 'splash.lss') splashlss = os.path.join(bootdiskdir, 'splash.lss')
if os.path.isfile(splashtools): if os.path.isfile(splashtools):
os.system('%s %s %s' % (splashtools, cmd = '%s %s %s' % (splashtools,
os.path.join(bootdiskdir, 'syslinux-splash.jpg'), os.path.join(bootdiskdir, 'syslinux-splash.jpg'),
splashlss)) splashlss)
os.system(cmd)
if os.path.isfile(splashlss): if os.path.isfile(splashlss):
cp(splashlss, self.isodir) cp(splashlss, self.isodir)
# copy the .msg files to isolinux dir # copy the .msg files
for file in os.listdir(bootdiskdir): for file in os.listdir(bootdiskdir):
if file.endswith('.msg'): if file.endswith('.msg'):
cp(os.path.join(bootdiskdir, file), self.isodir) cp(os.path.join(bootdiskdir, file), self.isodir)
replace(os.path.join(self.isodir, file), r'@VERSION@', self.conf.version) replace(os.path.join(self.isodir, file), r'@VERSION@', self.conf.version)
# if present, copy the memtest to isolinux dir # if present, copy the memtest
# XXX search for it in bootdiskdir or treedir/install/boot ?
#cp(os.path.join(bootdiskdir, 'memtest*'), os.path.join(self.isodir, 'memtest'))
cp(os.path.join(self.conf.treedir, 'boot', 'memtest*'), cp(os.path.join(self.conf.treedir, 'boot', 'memtest*'),
os.path.join(self.isodir, 'memtest')) os.path.join(self.isodir, 'memtest'))
if os.path.isfile(os.path.join(self.isodir, 'memtest')): if os.path.isfile(os.path.join(self.isodir, 'memtest')):
f = open(isolinuxcfg, 'a') text = "label memtest86\n"
f.write('label memtest86\n') text = text + " menu label ^Memory test\n"
f.write(' menu label ^Memory test\n') text = text + " kernel memtest\n"
f.write(' kernel memtest\n') text = text + " append -\n"
f.write(' append -\n') edit(isolinuxcfg, text, append=True)
f.close()
else: else:
print('No isolinux binary found, skipping isolinux creation') sys.stderr.write('No isolinux binary found, skipping isolinux creation\n')

View File

@ -1,84 +0,0 @@
# pylorax/initrd.py
import os
import re
import actions
from config import Template
from utils.libutil import LDD
from utils.fileutil import rm
class InitRD(object):
def __init__(self, config, yum):
self.conf = config
self.yum = yum
if not os.path.isdir(self.conf.initrddir):
os.makedirs(self.conf.initrddir)
# get supported actions
supported_actions = actions.getActions()
initrd_templates = []
initrd_templates.append(os.path.join(self.conf.confdir, 'templates', 'initrd'))
initrd_templates.append(os.path.join(self.conf.confdir, 'templates', self.conf.buildarch,
'initrd'))
vars = { '@instroot@': self.conf.treedir,
'@initrd@': self.conf.initrddir,
'@libdir@': self.conf.libdir,
'@buildarch@': self.conf.buildarch,
'@confdir@' : self.conf.confdir,
'@datadir@': self.conf.datadir }
self.template = Template()
for file in initrd_templates:
if os.path.isfile(file):
self.template.parse(file, supported_actions, vars)
self.actions = []
def getPkgs(self):
# get needed packages
pkgs = []
for action in filter(lambda action: hasattr(action, 'install'), self.template.actions):
m = re.match(r'%s(.*)' % self.conf.treedir, action.install)
if m:
pkgs.append(m.group(1))
return pkgs
def getDeps(self):
# get needed dependencies
ldd = LDD(libroot=os.path.join(self.conf.treedir, self.conf.libdir))
for action in filter(lambda action: hasattr(action, 'getDeps'), self.template.actions):
file = action.getDeps()
ldd.getDeps(file)
# resolve symlinks
ldd.getLinks()
# add dependencies to actions
for dep in ldd.deps:
kwargs = {}
kwargs['src'] = dep
kwargs['dst'] = re.sub(r'%s(?P<file>.*)' % self.conf.treedir,
'%s\g<file>' % self.conf.initrddir,
dep)
new_action = actions.fileactions.Copy(**kwargs)
self.actions.append(new_action)
def processActions(self):
for action in self.template.actions:
action.execute()
for action in self.actions:
action.execute()
def create(self, dst):
os.system('find %s | cpio --quiet -c -o | gzip -9 > %s' % (self.conf.initrddir, dst))
def cleanUp(self):
rm(self.conf.initrddir)

View File

@ -1,4 +1,4 @@
# pylorax/utils/rpmutil.py # pylorax/utils/rpmutils.py
import sys import sys
import os import os
@ -6,6 +6,7 @@ import stat
import yum import yum
import urlgrabber import urlgrabber
import shutil import shutil
import commands
import yum.callbacks import yum.callbacks
import yum.rpmtrans import yum.rpmtrans
@ -13,7 +14,23 @@ import yum.rpmtrans
from rpmUtils.miscutils import rpm2cpio from rpmUtils.miscutils import rpm2cpio
from cpioarchive import CpioArchive from cpioarchive import CpioArchive
from pylorax.base import seq, getConsoleSize
def seq(arg):
if type(arg) not in (type([]), type(())):
return [arg]
else:
return arg
def getConsoleSize():
err, output = commands.getstatusoutput('stty size')
if not err:
height, width = output.split()
else:
# set defaults
height, width = 24, 80
return int(height), int(width)
class Callback(yum.rpmtrans.SimpleCliCallBack): class Callback(yum.rpmtrans.SimpleCliCallBack):
@ -74,7 +91,7 @@ class Yum(object):
def download(self, packages): def download(self, packages):
for package in seq(packages): for package in seq(packages):
print('Downloading package %s...' % package) print('Downloading package %s' % package)
fn = urlgrabber.urlgrab(package.remote_url) fn = urlgrabber.urlgrab(package.remote_url)
shutil.copy(fn, self.installroot) shutil.copy(fn, self.installroot)
@ -82,7 +99,7 @@ class Yum(object):
def addPackages(self, patterns): def addPackages(self, patterns):
for pattern in seq(patterns): for pattern in seq(patterns):
print('Adding package matching %s...' % pattern) print('Adding package matching %s' % pattern)
try: try:
self.yb.install(name=pattern) self.yb.install(name=pattern)
except yum.Errors.InstallError: except yum.Errors.InstallError:
@ -103,7 +120,7 @@ class Yum(object):
self.yb.close() self.yb.close()
def extract_rpm(rpmfile, destdir): def extractRPM(rpmfile, destdir):
if not os.path.isdir(destdir): if not os.path.isdir(destdir):
os.makedirs(destdir) os.makedirs(destdir)
@ -125,7 +142,7 @@ def extract_rpm(rpmfile, destdir):
if not os.path.isdir(path): if not os.path.isdir(path):
os.makedirs(path) os.makedirs(path)
else: else:
print('Extracting %s...' % entry.name) print('Extracting %s' % entry.name)
dir = os.path.dirname(path) dir = os.path.dirname(path)
if not os.path.isdir(dir): if not os.path.isdir(dir):
os.makedirs(dir) os.makedirs(dir)