#!/usr/bin/env python # $Id: gen-nodeinstaller-patchfiles 707 2008-02-07 04:25:05Z mblack $ # # Copyright (C) 2007 Platform Computing Inc # # This program is free software; you can redistribute it and/or modify # it under the terms of version 2 of the GNU General Public License as # published by the Free Software Foundation. # # 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, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA # # # This script will create the nodeinstaller patchfiles tarball for the Kusu Boot Media # import os import subprocess import sys import tempfile import shutil import optparse import atexit import string # This is the list of components found in src/kits/base/packages that are # required to build the kusu installer runtime KUSU_RUNTIME = ['kusu-autoinstall', 'kusu-boot', 'kusu-buildkit', 'python-cheetah', 'kusu-core', 'kusu-createrepo', 'kusu-driverpatch', 'kusu-hardware', 'kusu-installer', 'python-IPy', 'kusu-kitops', 'kusu-md5crypt', 'kusu-networktool', 'kusu-nodeinstaller', 'primitive', 'kusu-path', 'python-sqlite2', 'kusu-repoman', 'python-sqlalchemy', 'kusu-ui', 'kusu-util'] CURRENT_PKGS = [] def cleanup(tdir): """Housekeeping routines""" if os.path.exists(tdir): shutil.rmtree(tdir) def getKusuTrunk(): """Returns the SVN trunk for Kusu/Emerald""" script = sys.argv[0] bindir = os.path.dirname(script) trunk = os.path.normpath(bindir + '/..') return trunk def getRPM(arg, dirname, names): """Returns the binary RPM""" li = [] if '.svn' in names: names.remove('.svn') for pkg in KUSU_RUNTIME: li.extend([name for name in names if name.startswith(pkg) and name.endswith('.rpm')]) if li: for l in li: CURRENT_PKGS.append(os.path.abspath(os.path.join(dirname,l))) def getAnacondaScript(distro, version): """Returns the 'faux' anaconda script from the SVN sources.""" trunk = getKusuTrunk() distspath = 'src/dists/%(distro)s/%(version)s/nodeinstaller' % {'distro':distro, 'version':version} anacondaScript = os.path.abspath(os.path.join(trunk, os.path.join(distspath,'updates.img/anaconda'))) return anacondaScript def getKSTemplate(distro, version): """Returns the ks.cfg.tmpl from the SVN sources.""" trunk = getKusuTrunk() distspath = 'src/dists/%(distro)s/%(version)s/nodeinstaller' % {'distro':distro, 'version':version} kscfgtmpl = os.path.abspath(os.path.join(trunk, os.path.join(distspath,'ks.cfg.tmpl'))) return kscfgtmpl def generateUpdatesImg(updatesdir, updatesimgpath): """ Generate the updates.img file. updatesdir points to the directory containing the contents that should be included in the updates.img file. """ packExt2FS(updatesdir, updatesimgpath, 20000) def packExt2FS(dirname, rootimgpath, size=5000): """Packs the directory dir into an ext2fs rootimgpath. The size of the image can be passed as well. """ if not os.path.exists(dirname): raise OSError if os.getuid() <> 0: raise OSError, "Operation requires root access!" # nuke existing rootimgpath if existing if os.path.exists(rootimgpath): os.remove(rootimgpath) rootimgpath = os.path.abspath(rootimgpath) # create scratchdir scratchdir = tempfile.mkdtemp('emerald-') tmprootdir = tempfile.mkdtemp(dir=scratchdir) # create a block device, format it, mount it cwd = scratchdir ddP = subprocess.Popen("dd of=%s if=/dev/zero bs=1024 count=%s >/dev/null 2>&1" % (rootimgpath,size),shell=True,cwd=scratchdir) ddP.communicate() mke2fsP = subprocess.Popen("mke2fs -F %s >/dev/null 2>&1" % rootimgpath,shell=True,cwd=scratchdir) mke2fsP.communicate() mountP = subprocess.Popen("mount -o loop %s %s" % (rootimgpath,tmprootdir),shell=True,cwd=scratchdir) mountP.communicate() # copy the contents over to the newly made ext2fs filesystem cmd = '(find . | cpio -mpdu %s) >/dev/null 2>&1' cpioP = subprocess.Popen(cmd % tmprootdir,shell=True,cwd=dirname,stdout=subprocess.PIPE) cpioP.wait() # housecleaning umountP = subprocess.Popen("umount %s" % tmprootdir,shell=True,cwd=scratchdir) umountP.communicate() if os.path.exists(tmprootdir): shutil.rmtree(tmprootdir) if os.path.exists(scratchdir): shutil.rmtree(scratchdir) if __name__ == '__main__': parser = optparse.OptionParser() parser.add_option('-d', '--dir', dest='nidir', help="Specify path of the nodeinstaller directory to generate.") options, args = parser.parse_args() if not options.nidir: print 'Please specify the name of nodeinstaller directory to generate!' sys.exit(-1) #tarball = os.path.abspath(options.tarball) nidir = os.path.abspath(options.nidir) # ensure the directory is safe if nidir in ['/'+d for d in os.listdir('/') if not os.path.isfile(d)]: print '%s is not a safe directory. Please specify another path!' % options.nidir sys.exit(-1) # get the base kit RPMS directory basekitRPMSdir = os.path.join(getKusuTrunk(),'src/kits/base/RPMS') os.path.walk(basekitRPMSdir,getRPM,None) # take out kusu-nodeinstaller-patchfiles nipkg = [p for p in CURRENT_PKGS if os.path.basename(p).startswith('kusu-nodeinstaller-patchfiles')] for p in nipkg: CURRENT_PKGS.remove(p) if len(CURRENT_PKGS) <> len(KUSU_RUNTIME): #print 'There are missing packages from the Base kit. Please rebuild the Base kit!' tmplst = KUSU_RUNTIME[:] NEW_CURRENT_PKGS = [] for i in CURRENT_PKGS: n = string.join(string.split(os.path.basename(i), '-')[:-2], '-') if n in tmplst: NEW_CURRENT_PKGS.append(i) tmplst.remove(n) CURRENT_PKGS = NEW_CURRENT_PKGS[:] if len(tmplst) > 0: print 'There are missing packages from the Base kit. Please rebuild the Base kit!' print 'Missing packages:' for i in tmplst: print ' %s' % i sys.exit(-1) print 'Generating nodeinstaller patchfiles for rhel, fedora and centos' rhel5AnacondaScript = getAnacondaScript('rhel','5') rhel5kscfgTemplate = getKSTemplate('rhel','5') centos5AnacondaScript = getAnacondaScript('centos','5') centos5kscfgTemplate = getKSTemplate('centos','5') fedora6AnacondaScript = getAnacondaScript('fedora','6') fedora6kscfgTemplate = getKSTemplate('fedora','6') # get the nodeinstaller patchfiles directory tardir = tempfile.mkdtemp(prefix='emerald-') atexit.register(cleanup,tardir) niPatchfilesDir = tardir # create the necessary patchfiles subdirectories # RHEL 5 rhel5PatchfilesDir = os.path.join(niPatchfilesDir,'nodeinstaller/rhel/5') os.makedirs(rhel5PatchfilesDir) os.mkdir(os.path.join(rhel5PatchfilesDir,'i386')) shutil.copy(rhel5kscfgTemplate,os.path.join(rhel5PatchfilesDir,'i386')) os.mkdir(os.path.join(rhel5PatchfilesDir,'x86_64')) shutil.copy(rhel5kscfgTemplate,os.path.join(rhel5PatchfilesDir,'x86_64')) # create a temp holding directory tdir = tempfile.mkdtemp(prefix='emerald-') atexit.register(cleanup,tdir) # get a handle to /dev/null for redirecting stderr err = open('/dev/null','w') for pkg in CURRENT_PKGS: rpm2cpioP = subprocess.Popen('rpm2cpio %s' % pkg, shell=True, cwd=tdir, stdout=subprocess.PIPE, stderr=err) cpioP = subprocess.Popen('cpio -id', shell=True, cwd=tdir,stdin=rpm2cpioP.stdout,stdout=subprocess.PIPE, stderr=err) cpioP.wait() # fix the missing __init__.py initpy = os.path.join(tdir,'opt/kusu/lib/python/kusu/__init__.py') f = open(initpy,'w') f.close() # copy the 'faux' anaconda script for each distro shutil.copy(rhel5AnacondaScript, tdir) os.chmod(os.path.join(tdir,'anaconda'),0755) updatesimg = os.path.join(rhel5PatchfilesDir,'i386/updates.img') generateUpdatesImg(tdir,updatesimg) # also copy this for the x86_64 version shutil.copy(updatesimg, os.path.join(rhel5PatchfilesDir,'x86_64/updates.img')) # remove temp holding directory shutil.rmtree(tdir,ignore_errors=True) err.close() # CENTOS 5 centos5PatchfilesDir = os.path.join(niPatchfilesDir,'nodeinstaller/centos/5') os.makedirs(centos5PatchfilesDir) os.mkdir(os.path.join(centos5PatchfilesDir,'i386')) shutil.copy(centos5kscfgTemplate,os.path.join(centos5PatchfilesDir,'i386')) os.mkdir(os.path.join(centos5PatchfilesDir,'x86_64')) shutil.copy(centos5kscfgTemplate,os.path.join(centos5PatchfilesDir,'x86_64')) # create a temp holding directory tdir = tempfile.mkdtemp(prefix='emerald-') atexit.register(cleanup,tdir) # get a handle to /dev/null for redirecting stderr err = open('/dev/null','w') for pkg in CURRENT_PKGS: rpm2cpioP = subprocess.Popen('rpm2cpio %s' % pkg, shell=True, cwd=tdir, stdout=subprocess.PIPE, stderr=err) cpioP = subprocess.Popen('cpio -id', shell=True, cwd=tdir,stdin=rpm2cpioP.stdout,stdout=subprocess.PIPE, stderr=err) cpioP.wait() # fix the missing __init__.py initpy = os.path.join(tdir,'opt/kusu/lib/python/kusu/__init__.py') f = open(initpy,'w') f.close() # copy the 'faux' anaconda script for each distro shutil.copy(centos5AnacondaScript, tdir) os.chmod(os.path.join(tdir,'anaconda'),0755) updatesimg = os.path.join(centos5PatchfilesDir,'i386/updates.img') generateUpdatesImg(tdir,updatesimg) # also copy this for the x86_64 version shutil.copy(updatesimg, os.path.join(centos5PatchfilesDir,'x86_64/updates.img')) # remove temp holding directory shutil.rmtree(tdir,ignore_errors=True) err.close() # FEDORA CORE 6 fedora6PatchfilesDir = os.path.join(niPatchfilesDir,'nodeinstaller/fedora/6') os.makedirs(fedora6PatchfilesDir) os.mkdir(os.path.join(fedora6PatchfilesDir,'i386')) shutil.copy(fedora6kscfgTemplate,os.path.join(fedora6PatchfilesDir,'i386')) os.mkdir(os.path.join(fedora6PatchfilesDir,'x86_64')) shutil.copy(fedora6kscfgTemplate,os.path.join(fedora6PatchfilesDir,'x86_64')) # create a temp holding directory tdir = tempfile.mkdtemp(prefix='emerald-') atexit.register(cleanup,tdir) # get a handle to /dev/null for redirecting stderr err = open('/dev/null','w') for pkg in CURRENT_PKGS: rpm2cpioP = subprocess.Popen('rpm2cpio %s' % pkg, shell=True, cwd=tdir, stdout=subprocess.PIPE, stderr=err) cpioP = subprocess.Popen('cpio -id', shell=True, cwd=tdir,stdin=rpm2cpioP.stdout,stdout=subprocess.PIPE, stderr=err) cpioP.wait() # fix the missing __init__.py initpy = os.path.join(tdir,'opt/kusu/lib/python/kusu/__init__.py') f = open(initpy,'w') f.close() # copy the 'faux' anaconda script for each distro shutil.copy(fedora6AnacondaScript, tdir) os.chmod(os.path.join(tdir,'anaconda'),0755) updatesimg = os.path.join(fedora6PatchfilesDir,'i386/updates.img') generateUpdatesImg(tdir,updatesimg) # also copy this for the x86_64 version shutil.copy(updatesimg, os.path.join(fedora6PatchfilesDir,'x86_64/updates.img')) # remove temp holding directory shutil.rmtree(tdir,ignore_errors=True) err.close() # remove existing nidir if any if os.path.exists(nidir): shutil.rmtree(nidir) os.mkdir(nidir) err = open('/dev/null','w') cmd = 'find . | cpio -mpdu %s' % nidir cpioP = subprocess.Popen(cmd,shell=True,cwd=tardir,stdout=subprocess.PIPE,stderr=err) cpioP.wait() err.close() print 'Generate nodeinstaller patchfile in', nidir sys.exit(0)