def setup(self): util.mkdirChain(util.joinPaths(self.image_root, 'boot', 'grub')) # path to grub stage1/stage2 files in rPL/rLS util.copytree( util.joinPaths(self.image_root, 'usr', 'share', 'grub', '*', '*'), util.joinPaths(self.image_root, 'boot', 'grub')) # path to grub files in SLES if is_SUSE(self.image_root): util.copytree( util.joinPaths(self.image_root, 'usr', 'lib', 'grub', '*'), util.joinPaths(self.image_root, 'boot', 'grub')) if is_UBUNTU(self.image_root): # path to grub files in x86 Ubuntu util.copytree( util.joinPaths(self.image_root, 'usr', 'lib', 'grub', 'i386-pc', '*'), util.joinPaths(self.image_root, 'boot', 'grub')) # path to grub files in x86_64 Ubuntu util.copytree( util.joinPaths(self.image_root, 'usr', 'lib', 'grub', 'x86_64-pc', '*'), util.joinPaths(self.image_root, 'boot', 'grub')) util.mkdirChain(util.joinPaths(self.image_root, 'etc')) # Create a stub grub.conf self.writeConf() # Create the appropriate links if self._get_grub_conf() != 'menu.lst': os.symlink('grub.conf', util.joinPaths( self.image_root, 'boot', 'grub', 'menu.lst')) os.symlink('../boot/grub/grub.conf', util.joinPaths(self.image_root, 'etc', 'grub.conf')) if is_SUSE(self.image_root): self._suse_grub_stub()
def addScsiModules(self): # FIXME: this part of the code needs a rewrite, because any # bootable image type / distro combination may need different # drivers to be specified here. It's not a simple True/False. # Also, 'Raw HD Image' means QEMU/KVM to me, but someone else # might be using it with another environment. filePath = self.filePath("etc/modprobe.conf") if self.jobData["buildType"] == buildtypes.AMI: moduleList = ["xenblk"] else: moduleList = ["mptbase", "mptspi"] if is_SUSE(self.root): filePath = filePath + ".local" if self.jobData["buildType"] == buildtypes.RAW_HD_IMAGE: self.scsiModules = True moduleList = ["piix"] if not self.scsiModules: return if not os.path.exists(filePath): log.warning("%s not found while adding scsi modules" % os.path.basename(filePath)) util.mkdirChain(os.path.split(filePath)[0]) f = open(filePath, "a") if os.stat(filePath)[6]: f.write("\n") for idx in range(0, len(moduleList)): f.write("alias scsi_hostadapter%s %s\n" % (idx and idx or "", moduleList[idx])) f.close()
def _suse_sysconfig_bootloader(self): # write /etc/sysconfig/bootloader for SUSE systems contents = ( 'CYCLE_DETECTION="no"\n' 'CYCLE_NEXT_ENTRY="1"\n' 'LOADER_LOCATION=""\n' 'LOADER_TYPE="grub"\n' ) if is_SUSE(self.image_root, version=11): consoleArgs = '' if (self.jobData['buildType'] == buildtypes.validBuildTypes['XEN_OVA']): consoleArgs = ' console=ttyS0 xencons=ttyS' contents += ( 'DEFAULT_APPEND="root=LABEL=%s showopts%s"\n' 'FAILSAFE_APPEND="root=LABEL=%s%s"\n' % (self.root_label, consoleArgs, self.root_label, consoleArgs)) self.createFile('etc/sysconfig/bootloader', contents)
def add_kernels(self): bootDirFiles = os.listdir(util.joinPaths(self.image_root, 'boot')) kernels = sorted(x[8:] for x in bootDirFiles if x.startswith('vmlinuz-2.6')) initrds = sorted([x for x in bootDirFiles if re.match('init(rd|ramfs)-.*.img', x)]) if initrds: # initrds are called initramfs on e.g. RHEL 6, stay consistent. rdPrefix = initrds[0].split('-')[0] else: rdPrefix = 'initrd' kernels.reverse() if kernels: log.info("Manually populating grub.conf with installed kernels") if is_SUSE(self.image_root): self._mkinitrd_suse(kernels) else: self.writeConf(kernels) irg = rh_initrd.RedhatGenerator(self.image_root) irg.generate([ (kver, '/boot/%s-%s.img' % (rdPrefix, kver)) for kver in kernels]) else: log.error("No kernels found; this image will not be bootable.")
def postTagScripts(self): # misc. stuff that needs to run after tag handlers have finished dhcp = self.filePath("etc/sysconfig/network/dhcp") if os.path.isfile(dhcp): # tell SUSE to set the hostname via DHCP cmd = r"""/bin/sed -e 's/DHCLIENT_SET_HOSTNAME=.*/DHCLIENT_SET_HOSTNAME="yes"/g' -i %s""" % dhcp logCall(cmd) logCall("rm -rf %s/var/lib/conarydb/rollbacks/*" % self.root) # set up shadow passwords/md5 passwords authConfigCmd = "chroot %s %%s --kickstart --enablemd5 --enableshadow" " --disablecache" % self.root if self.fileExists("/usr/sbin/authconfig"): logCall(authConfigCmd % "/usr/sbin/authconfig") elif self.fileExists("/usr/bin/authconfig"): logCall(authConfigCmd % "/usr/bin/authconfig") elif self.fileExists("/usr/sbin/pwconv"): logCall("chroot %s /usr/sbin/pwconv" % self.root) # allow empty password to log in for virtual appliance fn = self.filePath("etc/pam.d/common-auth") if os.path.exists(fn): f = open(fn) lines = [] for line in f: line = line.strip() if "pam_unix2.so" in line and "nullok" not in line: line += " nullok" lines.append(line) lines.append("") f = open(fn, "w") f.write("\n".join(lines)) f.close() # Unlock the root account by blanking its password, unless a valid # password is already set. if self.fileExists("usr/sbin/usermod") and not hasRootPassword(self.root): log.info("Blanking root password.") logCall("chroot %s /usr/sbin/usermod -p '' root" % self.root, ignoreErrors=True) else: log.info("Not changing root password.") # Set up selinux autorelabel if appropriate selinux = self.filePath("etc/selinux/config") if os.path.exists(selinux): selinuxLines = [x.strip() for x in file(selinux).readlines()] if not "SELINUX=disabled" in selinuxLines: self.createFile(".autorelabel") # write an appropriate SLES inittab for XenServer # and update /etc/securetty so that logins work. if is_SUSE(self.root): if self.jobData["buildType"] == buildtypes.XEN_OVA: cmd = r"/bin/sed -e 's/^#cons:/cons:/' -e 's/^\([1-6]\):/#\1:/' -i %s" % self.filePath("/etc/inittab") logCall(cmd) cmd = r"echo -e 'console\nxvc0' >> %s" % self.filePath("/etc/securetty") logCall(cmd) elif self.jobData["buildType"] == buildtypes.AMI: cmd = r"/bin/sed -i 's/^#\(l4\)/\1/g' %s" % self.filePath("/etc/inittab") logCall(cmd) # This returns a non-zero exit code try: if is_SUSE(self.root, version=10): cmd = r"chroot %s /sbin/chkconfig --levels 2345 network on" % self.root else: cmd = r"chroot %s /sbin/chkconfig -s network 2345" % self.root logCall(cmd) except: pass # RedHat needs a config to tell it it's okay to upgrade the kernel if is_RH(self.root) and not self.fileExists("etc/sysconfig/kernel"): self.createFile("etc/sysconfig/kernel", "UPDATEDEFAULT=yes\n" "DEFAULTKERNEL=kernel\n") # Finish installation of bootloader if not self.fileExists("boot/boot"): # So /boot/blah in grub conf still works if /boot is separate os.symlink(".", self.filePath("boot/boot")) self.bootloader.install()
def preTagScripts(self): fakeRoot = self.root # create a swap file if self.swapSize: swapFile = util.joinPaths(fakeRoot, self.swapPath) util.mkdirChain(os.path.dirname(swapFile)) # sparse files cannot work for swap space logCall("dd if=/dev/zero of=%s bs=4096 count=%d" % (swapFile, self.swapSize / 4096)) logCall("/sbin/mkswap %s" % swapFile) os.chmod(swapFile, 0600) # Copy a skeleton config tree. # Exclude things that are not being installed. exceptFiles = [] # GPM (mouse daemon for virtual terminals) if not os.path.isfile(os.path.join(fakeRoot, "usr", "sbin", "gpm")): exceptFiles.append(os.path.join(os.path.sep, "etc", "sysconfig", "mouse")) # X windows start_x = False for svc in ("xdm", "gdm", "kdm"): if not os.path.isfile(os.path.join(fakeRoot, "etc", "init.d", svc)): continue # make sure the binary exists too for path in (("usr", "X11R6", "bin"), ("usr", "bin")): if os.path.isfile(os.path.join(*(fakeRoot,) + path + (svc,))): start_x = True if not start_x: exceptFiles.append(os.path.join(os.path.sep, "etc", "X11.*")) # use the appropriate skeleton files depending on the OS base if is_SUSE(fakeRoot): skelDir = os.path.join(constants.skelDir, "sle") elif is_UBUNTU(fakeRoot): skelDir = os.path.join(constants.skelDir, "ubuntu") else: skelDir = os.path.join(constants.skelDir, "rpl") copytree(skelDir, fakeRoot, exceptFiles) self.writeConaryRc(os.path.join(fakeRoot, "etc", "conaryrc"), self.cc) self.writeSystemModel(os.path.join(fakeRoot, "etc", "conary", "system-model")) # If X is available, use runlevel 5 by default, for graphical login if start_x: inittab = os.path.join(fakeRoot, "etc", "inittab") if os.path.isfile(inittab): cmd = r"/bin/sed -e 's/^\(id\):[0-6]:\(initdefault:\)$/\1:5:\2/' -i %s" % inittab logCall(cmd) else: log.warning("inittab does not appear to be present") # copy timezone data into /etc/localtime if os.path.exists(os.path.join(fakeRoot, "usr", "share", "zoneinfo", "UTC")): copyfile( os.path.join(fakeRoot, "usr", "share", "zoneinfo", "UTC"), os.path.join(fakeRoot, "etc", "localtime") ) # Write the /etc/sysconfig/appliance-name for distro-release initscript. # Only overwrite if the file is non existent or empty. (RBL-3104) appliancePath = os.path.join(fakeRoot, "etc", "sysconfig") if not os.path.exists(appliancePath): util.mkdirChain(appliancePath) appNameFile = os.path.join(appliancePath, "appliance-name") if not os.path.exists(appNameFile) or not os.path.getsize(appNameFile): f = open(appNameFile, "w") name = self.jobData["project"]["name"] if isinstance(name, unicode): name = name.encode("utf8") f.write(name + "\n") f.close() # Disable selinux by default selinux = "etc/selinux/config" if self.fileExists(selinux): contents = self.readFile(selinux) contents = contents.replace( "SELINUX=enforcing\n", "# NOTE: This is overridden by rBuilder. To prevent this, " "change it back using a group post-install script.\n" "SELINUX=disabled\n", ) self.createFile(selinux, contents) if is_SUSE(self.root): # SUSE needs /dev/fd for mkinitrd (RBL-5689) os.symlink("/proc/self/fd", self.filePath("dev/fd")) elif is_SUSE(self.root, version=11): self.createFile("etc/sysconfig/mkinitrd", 'OPTIONS="-A"\n') # Configure the bootloader (but don't install it yet). self.bootloader.setup() self.addScsiModules() self.writeDeviceMaps()
def _mkinitrd_suse(self, kernels): # Extend mkinitrd config with modules for VM targets kconf = self.filePath('etc/sysconfig/kernel') out = open(kconf + '.tmp', 'w') for line in open(kconf): if line[:15] == 'INITRD_MODULES=': modules = set(shlex.split(line[15:])[0].split()) # Fix for SUP-3634 -- EC2 images not booting # ec2 images do not need extra modules specifically sd_ # TODO -- revisit after all kernels are updated if self.jobData['buildType'] == buildtypes.AMI and is_SUSE(self.image_root, version=11): modules.add('xenblk') else: modules.add('piix') modules.add('megaraid') modules.add('mptscsih') modules.add('mptspi') modules.add('sd_mod') if is_SUSE(self.image_root, version=11): modules.add('pata_oldpiix') modules.add('pata_mpiix') modules.add('ata_piix') modules.add('virtio_net') modules.add('virtio_blk') modules.add('virtio_pci') out.write('INITRD_MODULES="%s"' % (' '.join(modules))) else: out.write(line) out.close() os.rename(kconf + '.tmp', kconf) # Order kernels so the desired one is added last and thus the default. kernels.sort() kernels_xen = [x for x in kernels if x.endswith('-xen')] kernels_not_xen = [x for x in kernels if not x.endswith('-xen')] if self.force_domU: kernels = kernels_not_xen + kernels_xen else: kernels = kernels_xen + kernels_not_xen log.info("Rebuilding initrd(s)") kpaths = ['vmlinuz-' + x for x in kernels] ipaths = ['initrd-' + x for x in kernels] mkinitrdCmd = ['/usr/sbin/chroot', self.image_root, '/sbin/mkinitrd', '-k', ' '.join(kpaths), '-i', ' '.join(ipaths), ] # More SLES 11 magic: make a temporary device node # for the root fs device, and remove it after mkinitrd runs. if is_SUSE(self.image_root, version=11): if self.jobData['buildType'] == buildtypes.APPLIANCE_ISO: tmpRootDev = os.path.join(self.image_root, 'dev', 'root') mkinitrdCmd.extend([ '-d', '/dev/root' ]) else: # Patch for card 2258 # Need to make sure we use the correct loop device for mkinitrd proc_mount = '/proc/mounts' loop = os.path.join('dev', 'root') if os.path.exists(proc_mount): mounts = open(proc_mount).readlines() loops = sorted([ x.split() for x in mounts if x.startswith('/dev/loop') ]) if loops: for l in loops: if l[1] == self.image_root: loop = l[0][1:] tmpRootDev = os.path.join(self.image_root, loop) mkinitrdCmd.extend([ '-d', loop ]) os.mknod(tmpRootDev, 0600 | stat.S_IFBLK, os.stat(self.image_root).st_dev) logCall(mkinitrdCmd) if is_SUSE(self.image_root, version=11): os.unlink(tmpRootDev) # Build grub config log.info("Adding kernel entries") self.createFile('boot/grub/menu.lst', contents="""\ # GRUB configuration generated by rBuilder timeout 8 ##YaST - generic_mbr ##YaST - activate """) self.createFile('boot/grub/device.map', '(hd0) /dev/sda\n') self._suse_sysconfig_bootloader() self._suse_grub_stub() # for SLES 11 os.environ['PBL_SKIP_BOOT_TEST'] = '1' for kver, kpath, ipath in zip(kernels, kpaths, ipaths): flavor = kpath.split('-')[-1] if flavor == 'xen' and self.force_domU: flavor = 'default' logCall(['/usr/sbin/chroot', self.image_root, '/usr/lib/bootloader/bootloader_entry', 'add', flavor, kver, kpath, ipath])
def install(self): cfgfile = self._get_grub_conf() grub_conf = util.joinPaths(self.image_root, 'boot/grub', cfgfile) # TODO: clean up the various paths by which mkinitrd gets run, this # workflow doesn't necessarily make sense. mkinitrdWasRun = False # RPM-based images will not populate grub.conf, so do it here. for line in open(grub_conf): line = line.split() if len(line) < 2 or 'vmlinuz-' not in line[1]: continue kver = os.path.basename(line[1])[8:] if kver != 'template': break else: # No non-template kernel entry was found, so populate it by hand. self.add_kernels() mkinitrdWasRun = True # Now that grubby has had a chance to add the new kernel, # remove the template entry added in setup() if os.path.exists(util.joinPaths(self.image_root, 'sbin', 'grubby')): logCall('chroot %s /sbin/grubby ' '--remove-kernel=/boot/vmlinuz-template' % self.image_root, ignoreErrors=True) # If bootman is present, configure it for grub and run it if os.path.exists(util.joinPaths(self.image_root, 'sbin', 'bootman')): bootman_config = open(util.joinPaths(self.image_root, 'etc', 'bootman.conf'), 'w') print >> bootman_config, 'BOOTLOADER=grub' bootman_config.close() bootloader.writeBootmanConfigs(self) logCall('chroot "%s" /sbin/bootman' % self.image_root) irg = rh_initrd.RedhatGenerator(self.image_root) irg.generateFromBootman() mkinitrdWasRun = True elif not mkinitrdWasRun and not is_SUSE(self.image_root): irg = rh_initrd.RedhatGenerator(self.image_root) irg.generateFromGrub(cfgfile) mkinitrdWasRun = True # Workaround for RPL-2423 if os.path.exists(grub_conf): contents = open(grub_conf).read() contents = re.compile('^default .*', re.M ).sub('default 0', contents) open(grub_conf, 'w').write(contents) if cfgfile == 'menu.lst' and os.path.exists(grub_conf): # workaround for bootloader management tools in SUSE writing # menu.lst wrong f = open(grub_conf) newLines = [] rootdev_re = re.compile('root=/dev/.*? ') grubroot_re = re.compile('root \(.*\)') doubleboot_re = re.compile('/boot/boot') kernel_re = re.compile('^\s+kernel') for line in f: line = rootdev_re.sub('root=LABEL=%s ' % self.root_label, line) if (self.jobData['buildType'] == buildtypes.validBuildTypes['AMI']): line = grubroot_re.sub('root (hd0)', line) else: line = grubroot_re.sub('root (hd0,0)', line) line = doubleboot_re.sub('/boot', line) if (kernel_re.match(line) and (self.jobData['buildType'] == buildtypes.validBuildTypes['XEN_OVA'])): line = line.replace('\n', ' console=ttyS0 xencons=ttyS\n') newLines.append(line) contents = ''.join(newLines) f = open(grub_conf, 'w') f.write(contents) f.close()
def writeConf(self, kernels=()): if os.path.exists(util.joinPaths(self.image_root, 'etc', 'issue')): f = open(util.joinPaths(self.image_root, 'etc', 'issue')) name = f.readline().strip() if not name: name = self.jobData['project']['name'] f.close() else: name = self.jobData['project']['name'] bootDirFiles = os.listdir(util.joinPaths(self.image_root, 'boot')) xen = bool([x for x in bootDirFiles if re.match('vmlinuz-.*xen.*', x)]) dom0 = bool([x for x in bootDirFiles if re.match('xen.gz-.*', x)]) initrds = sorted([x for x in bootDirFiles if re.match('init(rd|ramfs)-.*.img', x)]) hasInitrd = bool(initrds) # RH-alikes ship a combo dom0/domU kernel so we have to use the image # flavor to determine whether to use the dom0 bootloader configuration. if self.force_domU: dom0 = False clock = "" if self.jobData['buildType'] == buildtypes.VMWARE_IMAGE: if self.arch == 'x86': clock = "clock=pit" elif self.arch == 'x86_64': clock = "notsc" if self.jobData['buildType'] == buildtypes.AMI: ami = True else: ami = False if initrds: # initrds are called initramfs on e.g. RHEL 6, stay consistent. rdPrefix = initrds[0].split('-')[0] else: rdPrefix = 'initrd' grubConfMacros = None grubConfMacroPath = util.joinPaths(self.image_root, 'etc', 'sysconfig', 'grubconfmacros') if os.path.exists(grubConfMacroPath): grubConfMacros = loadMacros([grubConfMacroPath, ]) conf = getGrubConf(name, hasInitrd, xen, dom0, clock, includeTemplate=not is_SUSE(self.image_root, version=11), kversions=kernels, ami=ami, rdPrefix=rdPrefix, root_label=self.root_label, grubConfMacros=grubConfMacros, ) cfgfile = self._get_grub_conf() if cfgfile == 'menu.lst' and is_SUSE(self.image_root): self._suse_sysconfig_bootloader() f = open(util.joinPaths(self.image_root, 'boot', 'grub', cfgfile), 'w') f.write(conf) f.close() os.chmod(util.joinPaths(self.image_root, 'boot', 'grub', cfgfile), 0600)
def _get_grub_conf(self): if is_SUSE(self.image_root) or is_UBUNTU(self.image_root): return 'menu.lst' return 'grub.conf'