def upgradeBootLoader(self): """Upgrade the boot loader settings.""" self.blkidParts = BlkidParser(log=self.log.getChild("blkid")) code = self.installGrubCfg() if code: return code return 0
def upgradeBootLoader(self): """Upgrade the boot loader settings as part of a loader upgrade.""" self.blkidParts = BlkidParser(log=self.log.getChild("blkid")) # XXX boot-config (and saved boot-config) should be unchanged during loader upgrade code = self.installUbootEnv() if code: return code return 0
def run(self): self.platform = onl.platform.current.OnlPlatform() self.pc = self.platform.platform_config self.pm = ProcMountsParser() self.blkid = BlkidParser(log=self.log.getChild("blkid")) if 'grub' in self.pc: return self.runGrub() if 'flat_image_tree' in self.pc: return self.runUboot() self.log.error("invalid platform-config") return 1
def umountAny(self, device=None, label=None): p = ProcMountsParser() if label is not None: b = BlkidParser(log=self.log) for e in b.parts: if label == e.label: device = e.device break for m in p.mounts: if device is not None and device in m.device: try: self.check_call(('umount', m.device,), vmode=self.V1) except CalledProcessError, what: self.log.warn("cannot umount %s: %s", m.device, str(what))
def upgradeBootLoader(self): """Upgrade the boot loader settings.""" self.blkidParts = BlkidParser(log=self.log.getChild("blkid")) code = self.findGpt() if code: return code if self.isUEFI: code = self.findEsp() if code: return code self.im.grubEnv.__dict__['espPart'] = self.espDevice else: self.im.grubEnv.__dict__['espPart'] = None code = self.installGrubCfg() if code: return code return 0
def findGpt(self): self.blkidParts = BlkidParser(log=self.log.getChild("blkid")) deviceOrLabel = self.im.platformConf['grub']['device'] if deviceOrLabel.startswith('/dev'): tgtDevice, tgtLabel = deviceOrLabel, None else: tgtDevice, tgtLabel = None, deviceOrLabel # enumerate labeled partitions to try to identify # the boot device for part in self.blkidParts: dev, partno = part.splitDev() if tgtLabel is not None and tgtLabel == part.label: if not len(partno): self.log.error("cannot use whole disk") return 1 if self.device is None: self.device = dev else: self.log.error("found multiple devices: %s, %s", dev, self.device) return 1 elif tgtDevice is not None and tgtDevice == dev: if not len(partno): self.log.error("cannot use whole disk") return 1 if self.device is None: self.device = dev else: self.log.error("found multiple devices: %s, %s", dev, self.device) return 1 if self.device is None: self.log.error("cannot find an install device") return 1 if not self.isUEFI: code = self.assertUnmounted() if code: return code # optionally back up a config partition # if it's on the boot device for part in self.blkidParts: dev, partno = part.splitDev() if dev == self.device and part.label == 'ONL-CONFIG': self.backupConfig(part.device) self.partedDevice = parted.getDevice(self.device) self.partedDisk = parted.newDisk(self.partedDevice) # enumerate the partitions that will stay and go minpart = -1 for part in self.partedDisk.partitions: if part.getFlag(parted.PARTITION_HIDDEN): minpart = max(minpart, part.number+1) continue # else, the partition should exist blkidParts = [x for x in self.blkidParts if x.device == part.path] if not blkidParts: self.log.warn("cannot identify partition %s", part) continue blkidPart = blkidParts[0] if not blkidPart.isOnieReserved(): continue # else, check the GPT label for reserved-ness if (part.name and ('GRUB' in part.name or 'ONIE-BOOT' in part.name or 'DIAG' in part.name)): minpart = max(minpart, part.number+1) if minpart < 0: self.log.error("cannot find an install partition") return 1 self.minpart = minpart return 0
def partitionParted(self): """Build partitions according to the partition spec. XXX roth -- hopefully the GPT labels specified here work correctly (that is, are ignored) on an msdos label """ constraint = self.partedDevice.optimalAlignedConstraint # default partition layout constraint devices = {} def _u2s(sz, u): """Convert to units of logical sectors.""" bsz = sz * u bsz = bsz + self.partedDevice.sectorSize - 1 return bsz / self.partedDevice.sectorSize def _align(spos): """Align this sector number.""" sz = self.partedDevice.sectorSize psz = self.partedDevice.physicalSectorSize if type(psz) != int: return spos if psz <= sz: return spos if (psz % sz) != 0: return spos if psz > 1048576: return spos stride = psz / sz off = spos % stride off = stride - off off = off % stride spos += off return spos UNITS = { 'GiB' : 1024 * 1024 * 1024, 'G' : 1000 * 1000 * 1000, 'MiB' : 1024 * 1024, 'M' : 1000 * 1000, 'KiB' : 1024, 'K' : 1000, } for part in self.im.platformConf['installer']: label, partData = list(part.items())[0] if type(partData) == dict: sz, fmt = partData['='], partData.get('format', 'ext4') else: sz, fmt = partData, 'ext4' cnt = None nextBlock = self.nextBlock or 1 minpart = self.minpart or 1 for ul, ub in UNITS.items(): if sz.endswith(ul): cnt = _u2s(int(sz[:-len(ul)], 10), ub) break if sz == '100%': cnt = self.partedDevice.getLength() - nextBlock if cnt is None: self.log.error("invalid size (no units) for %s: %s", part, sz) return 1 start = _align(nextBlock) end = start + cnt - 1 if end <= self.partedDevice.getLength(): self.log.info("Allocating %d sectors for %s", cnt, label) else: self.log.warn("%s: start sector %d, end sector %d, max %d", label, start, end, self.partedDevice.getLength()) self.log.error("invalid partition %s [%s] (too big)", label, sz) return 1 geom = parted.Geometry(device=self.partedDevice, start=start, length=end-start+1) fs = parted.FileSystem(type=fmt, geometry=geom) part = parted.Partition(disk=self.partedDisk, type=parted.PARTITION_NORMAL, fs=fs, geometry=geom) if self.partedDisk.type == 'gpt': part.getPedPartition().set_name(label) self.partedDisk.addPartition(part, constraint=constraint) self.partedDisk.commit() self.check_call(('partprobe', self.device,)) if fmt == 'raw': self.log.info("Leaving %s (%s) unformatted (raw)", part.path, label) else: self.log.info("Formatting %s (%s) as %s", part.path, label, fmt) if fmt == 'msdos': self.mkdosfs(part.path, label=label) elif fmt == 'ext4': self.mke4fs(part.path, label=label, huge_file=False) elif fmt == 'ext2': self.mke2fs(part.path, label=label) else: self.mkfs(part.path, fstype=fmt) self.nextBlock, self.minpart = end+1, minpart+1 devices[label] = part.path if label == 'ONL-CONFIG' and self.configArchive is not None: self.restoreConfig(part.path) self.blkidParts = BlkidParser(log=self.log.getChild("blkid")) # re-read the partitions return 0
def run(self): self.pm = ProcMountsParser() self.blkid = BlkidParser(log=self.log.getChild("blkid")) self.mtd = ProcMtdParser(log=self.log.getChild("mtd")) def _g(d): pat = os.path.join(d, "onie/initrd.img*") l = glob.glob(pat) if l: return l[0] return None # try to find a mounted, labeled partition try: dev = self.blkid['ONIE-BOOT'].device except IndexError: dev = None if dev is not None: self.log.debug("found ONIE boot device %s", dev) parts = [p for p in self.pm.mounts if p.device == dev] if parts: onieDir = parts[0] self.log.debug("found ONIE boot mounted at %s", onieDir) initrd = _g(onieDir) if initrd is None: self.log.warn("cannot find ONIE initrd on %s", onieDir) else: self.log.debug("found ONIE initrd at %s", initrd) return _runInitrdShell(initrd) with MountContext(dev, log=self.log) as ctx: initrd = _g(ctx.dir) if initrd is None: self.log.warn("cannot find ONIE initrd on %s", dev) else: self.log.debug("found ONIE initrd at %s", initrd) return self._runInitrdShell(initrd) self.log.warn("cannot find an ONIE initrd") return 1 # try to find onie initrd on a mounted fs (GRUB); # for ONIE images this is usually /mnt/onie-boot for part in self.pm.mounts: if not part.device.startswith('/dev/'): continue initrd = _g(part.dir) if initrd is None: self.log.debug("cannot find ONIE initrd on %s (%s)", part.device, part.dir) else: self.log.debug("found ONIE initrd at %s", initrd) return self._runInitrdShell(initrd) # grovel through MTD devices (u-boot) parts = [p for p in self.mtd.parts if p.label == "onie"] if parts: part = parts[0] self.log.debug("found ONIE MTD device %s", part.charDevice or part.blockDevice) return self._runFitShell(part.blockDevice) elif self.mtd.mounts: self.log.error("cannot find ONIE MTD device") return 1 self.log.error("cannot find ONIE initrd") return 1
def __enter__(self): self.pm = ProcMountsParser() self.blkid = BlkidParser(log=self.log.getChild("blkid")) self.mtd = ProcMtdParser(log=self.log.getChild("mtd")) def _g(d): pat = os.path.join(d, "onie/initrd.img*") l = glob.glob(pat) if l: return l[0] return None # try to find a mounted, labeled partition try: dev = self.blkid['ONIE-BOOT'].device except IndexError: dev = None if dev is not None: self.log.debug("found ONIE boot device %s", dev) parts = [p for p in self.pm.mounts if p.device == dev] if parts: self.log.debug("found ONIE boot mounted at %s", parts[0].dir) initrd = _g(parts[0].dir) if initrd is None: raise ValueError("cannot find ONIE initrd on %s" % parts[0].dir) self.log.debug("found ONIE initrd at %s", initrd) with InitrdContext(initrd=initrd, log=self.log) as self.ictx: self.initrd = initrd self.initrdDir = self.ictx.dir self.ictx.detach() return self # else, try to mount the directory containing the initrd with MountContext(dev, log=self.log) as self.dctx: initrd = _g(self.dctx.dir) if initrd is None: raise ValueError("cannot find ONIE initrd on %s" % dev) self.onieDir = self.dctx.dir self.dctx.detach() self.log.debug("found ONIE initrd at %s", initrd) with InitrdContext(initrd=initrd, log=self.log) as self.ictx: self.initrd = initrd self.initrdDir = self.ictx.dir self.ictx.detach() return self raise ValueError("cannot find an ONIE initrd") # try to find onie initrd on a mounted fs (GRUB); # for ONIE images this is usually /mnt/onie-boot for part in self.pm.mounts: if not part.device.startswith('/dev/'): continue initrd = _g(part.dir) if initrd is None: self.log.debug("cannot find ONIE initrd on %s (%s)", part.device, part.dir) else: self.onieDir = part.dir self.log.debug("found ONIE initrd at %s", initrd) with InitrdContext(initrd=initrd, log=self.log) as self.ictx: self.initrd = initrd self.initrdDir = self.ictx.dir self.ictx.detach() return self # grovel through MTD devices (u-boot) parts = [p for p in self.mtd.parts if p.label == "onie"] if parts: part = parts[0] self.log.debug("found ONIE MTD device %s", part.charDevice or part.blockDevice) with UbootInitrdContext(part.blockDevice, log=self.log) as self.fctx: with InitrdContext(initrd=self.fctx.initrd, log=self.log) as self.ictx: self.initrd = self.fctx.initrd self.fctx.detach() self.initrdDir = self.ictx.dir self.ictx.detach() return self if self.mtd.mounts: raise ValueError("cannot find ONIE MTD device") raise ValueError("cannot find ONIE initrd")
def installUboot(self): if self.device is None: self.log.error("missing block device YAML config") return 1 st = os.stat(self.device) if not stat.S_ISBLK(st[stat.ST_MODE]): self.log.error("not a block device: %s", self.device) return 1 # get a handle to the installer zip p = os.path.join(self.im.installerConf.installer_dir, self.im.installerConf.installer_zip) self.zf = zipfile.ZipFile(p) code = self.loadPlugins() if code: return code code = self.runPlugins(Plugin.PLUGIN_PREINSTALL) if code: return code code = self.assertUnmounted() if code: return code if "mtdblock" in self.device: code = self.ubifsinit() if code: return code code = self.ubi_getinfo() if code: return code code = self.ubi_installSwi() if code: return code code = self.ubi_installLoader() if code: return code code = self.ubi_installBootConfig() if code: return code code = self.ubi_installOnlConfig() if code: return code code = self.runPlugins(Plugin.PLUGIN_POSTINSTALL) if code: return code code = self.installUbootEnv() return code code = self.maybeCreateLabel() if code: return code self.log.info("Installing to %s", self.device) self.log.info("found %s partitions (bsz %s, lbsz %s)", self.partedDisk.type, self.partedDevice.sectorSize, self.partedDevice.physicalSectorSize) if self.partedDisk.type != 'msdos': self.log.error("not an MSDOS partition table") return 1 if self.partedDevice.sectorSize != 512: self.log.warn("invalid logical block size, expected 512") if self.partedDevice.physicalSectorSize != 512: self.log.warn("invalid physical block size, expected 512") self.log.info("found a disk with %d blocks", self.partedDevice.getLength()) self.blkidParts = BlkidParser(log=self.log.getChild("blkid")) code = self.findMsdos() if code: return code code = self.deletePartitions() if code: return code self.log.info("next usable block is %s", self.nextBlock) code = self.partitionParted() if code: return code # compute the path to the raw loader partition, # if indicated by the configuration self.rawLoaderDevice = None for item in self.im.platformConf['installer']: partIdx, partData = list(item.items())[0] label, part = list(partData.items())[0] if label == 'ONL-BOOT' and part['format'] == 'raw': self.rawLoaderDevice = self.device + str(partIdx + 1) break code = self.installSwi() if code: return code code = self.installLoader() if code: return code if self.rawLoaderDevice is None: code = self.installBootConfig() if code: return code else: self.log.info( "ONL-BOOT is a raw partition (%s), skipping boot-config", self.rawLoaderDevice) code = self.installOnlConfig() if code: return code self.log.info("syncing block devices") self.check_call(('sync', )) # XXX roth probably not needed code = self.installUbootEnv() if code: return code code = self.runPlugins(Plugin.PLUGIN_POSTINSTALL) if code: return code return 0