diff --git a/packages/base/all/initrds/loader-initrd-files/src/bin/swiget b/packages/base/all/initrds/loader-initrd-files/src/bin/swiget index 34615678..333674a9 100755 --- a/packages/base/all/initrds/loader-initrd-files/src/bin/swiget +++ b/packages/base/all/initrds/loader-initrd-files/src/bin/swiget @@ -284,7 +284,7 @@ class Runner(onl.install.InstallUtils.SubprocessMixin): l = [x for x in os.listdir(d) if x.endswith('.swi')] l = [os.path.join(d, x) for x in l] l.sort(key=swiSortKey) - return l[-1] + return l[-1] if l else None pm = ProcMountsParser() parts = [x for x in pm.mounts if x.device == dev] @@ -294,6 +294,9 @@ class Runner(onl.install.InstallUtils.SubprocessMixin): self.log.info("found 'latest' swi %s", dst) else: dst = os.path.join(parts[0].dir, src) + if dst is None: + self.log.error("missing SWI") + return None if not os.path.exists(dst): self.log.error("missing SWI: %s", dst) return None diff --git a/packages/base/all/vendor-config-onl/src/bin/loader-shell b/packages/base/all/vendor-config-onl/src/bin/loader-shell index e006aef4..9e758889 100755 --- a/packages/base/all/vendor-config-onl/src/bin/loader-shell +++ b/packages/base/all/vendor-config-onl/src/bin/loader-shell @@ -1,6 +1,6 @@ #!/usr/bin/python -"""Run native ONIE tools +"""Run native (on-disk) loader tools """ import onl.install.ShellApp diff --git a/packages/base/all/vendor-config-onl/src/bin/upgrade-shell b/packages/base/all/vendor-config-onl/src/bin/upgrade-shell new file mode 100755 index 00000000..7e488d28 --- /dev/null +++ b/packages/base/all/vendor-config-onl/src/bin/upgrade-shell @@ -0,0 +1,7 @@ +#!/usr/bin/python + +"""Run the upgrade image +""" + +import onl.install.ShellApp +onl.install.ShellApp.Upgrader.main() diff --git a/packages/base/all/vendor-config-onl/src/boot.d/62.upgrade-system b/packages/base/all/vendor-config-onl/src/boot.d/62.upgrade-system new file mode 100755 index 00000000..4fb8aadb --- /dev/null +++ b/packages/base/all/vendor-config-onl/src/boot.d/62.upgrade-system @@ -0,0 +1 @@ +/sbin/onl-upgrade-system diff --git a/packages/base/all/vendor-config-onl/src/boot.d/62.upgrade-loader b/packages/base/all/vendor-config-onl/src/boot.d/63.upgrade-loader similarity index 100% rename from packages/base/all/vendor-config-onl/src/boot.d/62.upgrade-loader rename to packages/base/all/vendor-config-onl/src/boot.d/63.upgrade-loader diff --git a/packages/base/all/vendor-config-onl/src/boot.d/63.upgrade-swi b/packages/base/all/vendor-config-onl/src/boot.d/64.upgrade-swi similarity index 100% rename from packages/base/all/vendor-config-onl/src/boot.d/63.upgrade-swi rename to packages/base/all/vendor-config-onl/src/boot.d/64.upgrade-swi diff --git a/packages/base/all/vendor-config-onl/src/etc/onl/sysconfig/00-defaults.yml b/packages/base/all/vendor-config-onl/src/etc/onl/sysconfig/00-defaults.yml index 5ec6effc..a9519949 100644 --- a/packages/base/all/vendor-config-onl/src/etc/onl/sysconfig/00-defaults.yml +++ b/packages/base/all/vendor-config-onl/src/etc/onl/sysconfig/00-defaults.yml @@ -22,6 +22,9 @@ upgrade: package: dir: /lib/platform-config/current/onl/upgrade/onie + system: + auto: advisory + firmware: auto: advisory package: diff --git a/packages/base/all/vendor-config-onl/src/lib/install/lib.sh b/packages/base/all/vendor-config-onl/src/lib/install/lib.sh index 388ab892..74dd273f 100644 --- a/packages/base/all/vendor-config-onl/src/lib/install/lib.sh +++ b/packages/base/all/vendor-config-onl/src/lib/install/lib.sh @@ -62,17 +62,26 @@ installer_mkchroot() { local rootdir rootdir=$1 + local hasDevTmpfs + if grep -q devtmpfs /proc/filesystems; then + hasDevTmpfs=1 + fi + # special handling for /dev, which usually already has nested mounts installer_say "Setting up /dev" rm -fr "${rootdir}/dev"/* - for dev in /dev/*; do - if test -d "$dev"; then - mkdir "${rootdir}${dev}" - else - cp -a "$dev" "${rootdir}${dev}" - fi - done - mkdir -p "${rootdir}/dev/pts" + if test "$hasDevTmpfs"; then + : + else + for dev in /dev/*; do + if test -d "$dev"; then + mkdir "${rootdir}${dev}" + else + cp -a "$dev" "${rootdir}${dev}" + fi + done + mkdir -p "${rootdir}/dev/pts" + fi installer_say "Setting up /run" rm -fr "${rootdir}/run"/* @@ -99,6 +108,10 @@ installer_mkchroot() { installer_say "Setting up mounts" mount -t proc proc "${rootdir}/proc" mount -t sysfs sysfs "${rootdir}/sys" + if test "$hasDevTmpfs"; then + mount -t devtmpfs devtmpfs "${rootdir}/dev" + mkdir -p ${rootdir}/dev/pts + fi mount -t devpts devpts "${rootdir}/dev/pts" if test ${TMPDIR+set}; then diff --git a/packages/base/all/vendor-config-onl/src/python/onl/install/App.py b/packages/base/all/vendor-config-onl/src/python/onl/install/App.py index fec1128e..5ab00ed7 100644 --- a/packages/base/all/vendor-config-onl/src/python/onl/install/App.py +++ b/packages/base/all/vendor-config-onl/src/python/onl/install/App.py @@ -17,9 +17,32 @@ import time from InstallUtils import InitrdContext from InstallUtils import SubprocessMixin from InstallUtils import ProcMountsParser +from ShellApp import Onie import ConfUtils, BaseInstall -class App(SubprocessMixin): +class OnieHelper(Onie): + """Unpack the initrd, but keep it around.""" + + UMOUNT = False + # leave self.onieDir mounted + + ictx = None + + def _runInitrdShell(self, initrd): + with InitrdContext(initrd, log=self.log) as self.ictx: + self.initrdDir = self.ictx.dir + self.ictx.detach() + + def shutdown(self): + + self.ictx.attach() + self.ictx.shutdown() + + if self.dctx is not None: + self.dctx.attach() + self.dctx.shutdown() + +class App(SubprocessMixin, object): def __init__(self, url=None, debug=False, force=False, @@ -43,6 +66,8 @@ class App(SubprocessMixin): self.nextUpdate = None + self.onieHelper = None + def run(self): if self.url is not None: @@ -123,27 +148,27 @@ class App(SubprocessMixin): self.log.info("please reboot this system now.") return 0 - def runLocal(self): + def runLocalOrChroot(self): - self.log.info("getting installer configuration") - if os.path.exists(ConfUtils.MachineConf.PATH): - self.machineConf = ConfUtils.MachineConf() - else: - self.log.warn("missing /etc/machine.conf from ONIE runtime") - self.machineConf = ConfUtils.MachineConf(path='/dev/null') - self.installerConf = ConfUtils.InstallerConf() + if self.machineConf is None: + self.log.error("missing machine.conf") + return 1 + if self.installerConf is None: + self.log.error("missing installer.conf") + return 1 ##self.log.info("using native GRUB") ##self.grubEnv = ConfUtils.GrubEnv(log=self.log.getChild("grub")) - pat = "/mnt/onie-boot/onie/initrd.img*" - l = glob.glob(pat) - if l: - initrd = l[0] - self.log.info("using native ONIE initrd+chroot GRUB (%s)", initrd) - initrdDir = InitrdContext.mkChroot(initrd, log=self.log) - self.grubEnv = ConfUtils.ChrootGrubEnv(initrdDir, - bootDir="/mnt/onie-boot", + self.onieHelper = OnieHelper(log=self.log) + code = self.onieHelper.run() + if code: + self.log.warn("cannot find ONIE initrd") + + if self.onieHelper.onieDir is not None: + self.log.info("using native ONIE initrd+chroot GRUB (%s)", self.onieHelper.onieDir) + self.grubEnv = ConfUtils.ChrootGrubEnv(self.onieHelper.initrdDir, + bootDir=self.onieHelper.onieDir, path="/grub/grubenv", log=self.log.getChild("grub")) # direct access using ONIE initrd as a chroot @@ -216,6 +241,19 @@ class App(SubprocessMixin): self.log.info("Install finished.") return 0 + def runLocal(self): + + self.log.info("getting installer configuration") + if os.path.exists(ConfUtils.MachineConf.PATH): + self.machineConf = ConfUtils.MachineConf() + else: + self.log.warn("missing /etc/machine.conf from ONIE runtime") + self.machineConf = ConfUtils.MachineConf(path='/dev/null') + + self.installerConf = ConfUtils.InstallerConf() + + return self.runLocalOrChroot() + def findPlatform(self): plat = arch = None @@ -302,6 +340,10 @@ class App(SubprocessMixin): if installer is not None: installer.shutdown() + h, self.onieHelper = self.onieHelper, None + if h is not None: + h.shutdown() + def post_mortem(self): self.log.info("re-attaching to tty") fdno = os.open("/dev/console", os.O_RDWR) diff --git a/packages/base/all/vendor-config-onl/src/python/onl/install/BaseInstall.py b/packages/base/all/vendor-config-onl/src/python/onl/install/BaseInstall.py index 8459d3af..196d6b52 100644 --- a/packages/base/all/vendor-config-onl/src/python/onl/install/BaseInstall.py +++ b/packages/base/all/vendor-config-onl/src/python/onl/install/BaseInstall.py @@ -394,7 +394,7 @@ class Base: for m in pm.mounts: if m.device.startswith(self.device): if not self.force: - self.log.error("mount %s on %s will be erased by install", + self.log.error("mount %s on %s will be erased by install (try --force)", m.dir, m.device) return 1 else: @@ -704,9 +704,6 @@ class UbootInstaller(SubprocessMixin, Base): self.device = self.im.getDevice() - code = self.assertUnmounted() - if code: return code - self.rawLoaderDevice = None # set to a partition device for raw loader install, # default to None for FS-based install @@ -825,6 +822,9 @@ class UbootInstaller(SubprocessMixin, Base): self.log.error("not a block device: %s", self.device) return 1 + code = self.assertUnmounted() + if code: return code + code = self.maybeCreateLabel() if code: return code diff --git a/packages/base/all/vendor-config-onl/src/python/onl/install/ConfUtils.py b/packages/base/all/vendor-config-onl/src/python/onl/install/ConfUtils.py index b81fd347..4f2a831c 100644 --- a/packages/base/all/vendor-config-onl/src/python/onl/install/ConfUtils.py +++ b/packages/base/all/vendor-config-onl/src/python/onl/install/ConfUtils.py @@ -7,6 +7,7 @@ import os import logging import subprocess from InstallUtils import SubprocessMixin, ChrootSubprocessMixin, MountContext +from cStringIO import StringIO class ConfBase: @@ -45,6 +46,14 @@ class ConfBase: def __setattr__(self, attr, val): self.__dict__['_data'][attr] = val + def dumps(self): + """Generate a serialized representation.""" + buf = StringIO() + data = self.__dict__.get('_data', {}) + for key, val in data.iteritems(): + buf.write("%s=\"%s\"\n" % (key, val,)) + return buf.getvalue() + class ConfFileBase(ConfBase): PATH = None diff --git a/packages/base/all/vendor-config-onl/src/python/onl/install/InstallUtils.py b/packages/base/all/vendor-config-onl/src/python/onl/install/InstallUtils.py index 830abf00..a071d3b2 100644 --- a/packages/base/all/vendor-config-onl/src/python/onl/install/InstallUtils.py +++ b/packages/base/all/vendor-config-onl/src/python/onl/install/InstallUtils.py @@ -179,6 +179,25 @@ class SubprocessMixin: # don't believe it self.check_call(cmd, vmode=self.V1) + def cpR(self, srcRoot, dstRoot): + srcRoot = os.path.abspath(srcRoot) + dstRoot = os.path.abspath(dstRoot) + dstRoot = os.path.join(dstRoot, os.path.split(srcRoot)[1]) + for r, dl, fl in os.walk(srcRoot): + + for de in dl: + src = os.path.join(r, de) + subdir = src[len(srcRoot)+1:] + dst = os.path.join(dstRoot, subdir) + if not os.path.exists(dst): + self.makedirs(dst) + + for fe in fl: + src = os.path.join(r, fe) + subdir = src[len(srcRoot)+1:] + dst = os.path.join(dstRoot, subdir) + self.copy2(src, dst) + class TempdirContext(SubprocessMixin): def __init__(self, prefix=None, suffix=None, chroot=None, log=None): @@ -739,27 +758,28 @@ class InitrdContext(SubprocessMixin): else: self.unlink(dst) - for e in os.listdir("/dev"): - src = os.path.join("/dev", e) - dst = os.path.join(dev2, e) - if os.path.islink(src): - self.symlink(os.readlink(src), dst) - elif os.path.isdir(src): - self.mkdir(dst) - elif os.path.isfile(src): - self.copy2(src, dst) - else: - st = os.stat(src) - if stat.S_ISBLK(st.st_mode): - maj, min = os.major(st.st_rdev), os.minor(st.st_rdev) - self.log.debug("+ mknod %s b %d %d", dst, maj, min) - os.mknod(dst, st.st_mode, st.st_rdev) - elif stat.S_ISCHR(st.st_mode): - maj, min = os.major(st.st_rdev), os.minor(st.st_rdev) - self.log.debug("+ mknod %s c %d %d", dst, maj, min) - os.mknod(dst, st.st_mode, st.st_rdev) + if not self._hasDevTmpfs: + for e in os.listdir("/dev"): + src = os.path.join("/dev", e) + dst = os.path.join(dev2, e) + if os.path.islink(src): + self.symlink(os.readlink(src), dst) + elif os.path.isdir(src): + self.mkdir(dst) + elif os.path.isfile(src): + self.copy2(src, dst) else: - self.log.debug("skipping device %s", src) + st = os.stat(src) + if stat.S_ISBLK(st.st_mode): + maj, min = os.major(st.st_rdev), os.minor(st.st_rdev) + self.log.debug("+ mknod %s b %d %d", dst, maj, min) + os.mknod(dst, st.st_mode, st.st_rdev) + elif stat.S_ISCHR(st.st_mode): + maj, min = os.major(st.st_rdev), os.minor(st.st_rdev) + self.log.debug("+ mknod %s c %d %d", dst, maj, min) + os.mknod(dst, st.st_mode, st.st_rdev) + else: + self.log.debug("skipping device %s", src) dst = os.path.join(self.dir, "dev/pts") if not os.path.exists(dst): @@ -772,6 +792,11 @@ class InitrdContext(SubprocessMixin): def __enter__(self): + with open("/proc/filesystems") as fd: + buf = fd.read() + if "devtmpfs" in buf: + self._hasDevTmpfs = True + if self.initrd is not None: self.log.debug("extracting initrd %s", self.initrd) @@ -792,6 +817,16 @@ class InitrdContext(SubprocessMixin): cmd = ('mount', '-t', 'sysfs', 'sysfs', dst,) self.check_call(cmd, vmode=self.V1) + # maybe mount devtmpfs + if self._hasDevTmpfs: + dst = os.path.join(self.dir, "dev") + cmd = ('mount', '-t', 'devtmpfs', 'devtmpfs', dst,) + self.check_call(cmd, vmode=self.V1) + + dst = os.path.join(self.dir, "dev/pts") + if not os.path.exists(dst): + self.mkdir(dst) + dst = os.path.join(self.dir, "dev/pts") cmd = ('mount', '-t', 'devpts', 'devpts', dst,) self.check_call(cmd, vmode=self.V1) @@ -830,6 +865,10 @@ class InitrdContext(SubprocessMixin): self.__initrd, self.initrd = self.initrd, None self.__dir, self.dir = self.dir, None + def attach(self): + self.initrd = self.__initrd + self.dir = self.__dir + @classmethod def mkChroot(cls, initrd, log=None): with cls(initrd=initrd, log=log) as ctx: diff --git a/packages/base/all/vendor-config-onl/src/python/onl/install/ShellApp.py b/packages/base/all/vendor-config-onl/src/python/onl/install/ShellApp.py index 0d85d7f3..711c6d78 100644 --- a/packages/base/all/vendor-config-onl/src/python/onl/install/ShellApp.py +++ b/packages/base/all/vendor-config-onl/src/python/onl/install/ShellApp.py @@ -16,8 +16,9 @@ from InstallUtils import BlkidParser from InstallUtils import FitInitrdContext import onl.platform.current +from onl.sysconfig import sysconfig -class AppBase(SubprocessMixin): +class AppBase(SubprocessMixin, object): @property def PROG(self): @@ -106,6 +107,8 @@ class OnieBootContext: self.pm = ProcMountsParser() self.blkid = BlkidParser(log=self.log.getChild("blkid")) self.mtd = ProcMtdParser(log=self.log.getChild("mtd")) + self.dctx = None + self.onieDir = None def _g(d): pat = os.path.join(d, "onie/initrd.img*") @@ -123,19 +126,19 @@ class OnieBootContext: 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) + 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" % onieDir) + 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.ictx.detach() return self + # else, try to mount the directory containing the initrd with MountContext(dev, log=self.log) as self.mctx: - initrd = _g(ctx.dir) + initrd = _g(self.dctx.dir) if initrd is None: raise ValueError("cannot find ONIE initrd on %s" % dev) self.log.debug("found ONIE initrd at %s", initrd) @@ -156,6 +159,7 @@ class OnieBootContext: 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 @@ -202,6 +206,7 @@ class Onie(AppBase): return self._runInitrdShell(ctx.initrd) class Loader(AppBase): + """Application shell that uses the (installed) loader runtime.""" PROG = "loader-shell" @@ -318,6 +323,49 @@ class Loader(AppBase): self.log.error("invalid platform-config") return 1 +class Upgrader(AppBase): + """Application shell that uses on-disk upgrade loader runtime.""" + + PROG = "upgrade-shell" + + def runGrub(self): + + d = sysconfig.upgrade.loader.package.dir + for b in sysconfig.upgrade.loader.package.grub: + p = os.path.join(d, b) + if os.path.exists(p): + self.log.debug("found upgrade initrd at %s", p) + return self._runInitrdShell(p) + + self.log.error("cannot find upgrade initrd") + return 1 + + def runUboot(self): + + d = sysconfig.upgrade.loader.package.dir + for b in sysconfig.upgrade.loader.package.fit: + p = os.path.join(d, b) + if os.path.exists(p): + self.log.debug("found upgrade FIT image %s", p) + return self._runFitShell(p) + + self.log.error("cannot find FIT image") + return 1 + + def run(self): + + self.platform = onl.platform.current.OnlPlatform() + self.pc = self.platform.platform_config + + 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 + main = Onie.main if __name__ == "__main__": diff --git a/packages/base/all/vendor-config-onl/src/python/onl/install/SystemInstall.py b/packages/base/all/vendor-config-onl/src/python/onl/install/SystemInstall.py new file mode 100644 index 00000000..b3339550 --- /dev/null +++ b/packages/base/all/vendor-config-onl/src/python/onl/install/SystemInstall.py @@ -0,0 +1,267 @@ +"""App.py + +Application code for onl-install. +""" + +import logging +import os, sys +import json +import tempfile +import zipfile +import shutil +import argparse +import fnmatch +import subprocess + +from onl.install.InstallUtils import InitrdContext +from onl.install.InstallUtils import ProcMountsParser +from onl.install.ConfUtils import MachineConf, InstallerConf +from onl.install.ShellApp import Onie, Upgrader +from onl.install.InstallUtils import SubprocessMixin +import onl.install.App + +from onl.sysconfig import sysconfig + +from onl.mounts import OnlMountContextReadWrite + +class UpgradeHelper(Upgrader): + + def __init__(self, callback=None, log=None): + super(UpgradeHelper, self).__init__(log=log) + self.callback = callback + + def _runInitrdShell(self, p): + if self.callback is not None: + self.callback(self, p) + +class App(SubprocessMixin): + + def __init__(self, force=False, log=None): + + if log is not None: + self.log = log + else: + self.log = logging.getLogger(self.__class__.__name__) + + self.force = force + + self.onieHelper = None + + def _runInitrd(self, helper, path): + with InitrdContext(initrd=path, log=self.log) as ctx: + + tdir = os.path.join(ctx.dir, "tmp") + abs_idir = tempfile.mkdtemp(dir=tdir, + prefix="installer-", suffix=".d") + chroot_idir = abs_idir[len(ctx.dir):] + + self.onieHelper = onl.install.App.OnieHelper(log=self.log) + code = self.onieHelper.run() + if code: + self.log.error("cannot find/unpack ONIE initrd") + return code + self.log.info("onie directory is %s", self.onieHelper.onieDir) + self.log.info("initrd directory is %s", self.onieHelper.initrdDir) + + src = os.path.join(self.onieHelper.initrdDir, "etc/machine.conf") + dst = os.path.join(ctx.dir, "etc/machine.conf") + self.log.debug("+ /bin/cp %s %s", src, dst) + shutil.copy2(src, dst) + + h, self.onieHelper = self.onieHelper, None + if h is not None: + h.shutdown() + + src = "/etc/fw_env.config" + if os.path.exists(src): + dst = os.path.join(ctx.dir, "etc/fw_env.config") + self.log.debug("+ /bin/cp %s %s", src, dst) + shutil.copy2(src, dst) + + srcRoot = "/etc/onl" + dstRoot = os.path.join(ctx.dir, "etc") + self.cpR(srcRoot, dstRoot) + + # constitute an /etc/onl/installer.conf in place + installerConf = InstallerConf(path="/dev/null") + + with open("/etc/onl/loader/versions.json") as fd: + data = json.load(fd) + installerConf.onl_version = data['VERSION_ID'] + + installerConf.installer_dir = chroot_idir + + abs_postinst = tempfile.mktemp(dir=abs_idir, + prefix="postinst-", suffix=".sh") + chroot_postinst = abs_postinst[len(ctx.dir):] + installerConf.installer_postinst = chroot_postinst + + # make an empty(ish) zip file (local path in installer_dir) for collateral + zipPath = tempfile.mktemp(dir=abs_idir, + prefix="install-", suffix=".zip") + with zipfile.ZipFile(zipPath, "w") as zf: + pass + installerConf.installer_zip = os.path.split(zipPath)[1] + + # finalize the local installer.conf + dst = os.path.join(ctx.dir, "etc/onl/installer.conf") + with open(dst, "w") as fd: + fd.write(installerConf.dumps()) + + # populate installer_dir with the contents of the loader upgrade + # See also Loader_Upgrade_x86_64.do_upgrade + # Here the initrd filename is as per the installer.zip; + # it is renamed on install to the grub directory + sdir = sysconfig.upgrade.loader.package.dir + + # get kernels for grub installs: + pats = ["kernel-*",] + for f in os.listdir(sdir): + for pat in pats: + if fnmatch.fnmatch(f, pat): + src = os.path.join(sdir, f) + dst = os.path.join(abs_idir, f) + self.log.debug("+ /bin/cp %s %s", src, dst) + shutil.copy2(src, dst) + try: + l = sysconfig.upgrade.loader.package.grub + except AttributeError: + l = [] + for f in l: + src = os.path.join(sdir, f) + if os.path.exists(src): + dst = os.path.join(abs_idir, f) + self.log.debug("+ /bin/cp %s %s", src, dst) + shutil.copy2(src, dst) + + # get FIT files from powerpc installs: + try: + l = sysconfig.upgrade.loader.package.fit + except AttributeError: + l = [] + for f in l: + src = os.path.join(sdir, f) + if os.path.exists(src): + dst = os.path.join(abs_idir, f) + self.log.debug("+ /bin/cp %s %s", src, dst) + shutil.copy2(src, dst) + + with OnlMountContextReadWrite('ONL-BOOT', logger=self.log) as octx: + src = os.path.join(octx.directory, "boot-config") + dst = os.path.join(abs_idir, "boot-config") + self.log.debug("+ /bin/cp %s %s", src, dst) + shutil.copy2(src, dst) + + # chroot to the onl-install script + ##cmd = ('chroot', ctx.dir, + ## '/bin/sh', '-i') + if self.log.level < logging.INFO: + cmd = ('chroot', ctx.dir, "/usr/bin/onl-install", "--verbose", "--force",) + else: + cmd = ('chroot', ctx.dir, "/usr/bin/onl-install", "--force",) + try: + self.check_call(cmd) + except subprocess.CalledProcessError, what: + pass + + def run(self): + """XXX roth -- migrate this to onl.install.App.App + + XXX roth -- assume TMPDIR=/tmp. + """ + + pm = ProcMountsParser() + + # resize /tmp to be large enough for the initrd, see tmpfs + # nonsense in installer.sh.in + tflags = None + tdev = os.stat('/tmp').st_dev + pdir = None + for m in pm.mounts: + if m.fsType in ('ramfs', 'tmpfs',): + dev = os.stat(m.dir).st_dev + if dev == tdev: + self.log.info("found tmpfs/ramfs %s (%s)", dev, m.flags) + pdir = m.dir + tflags = m.flags + + # XXX glean this from install.sh.in (installer_tmpfs_kmin) + if pdir is None: + self.check_call(('mount', + '-o', 'size=1048576k', + '-t', 'tmpfs', + 'tmpfs', '/tmp',)) + else: + self.check_call(('mount', + '-o', 'remount,size=1048576k', + pdir,)) + + for m in pm.mounts: + if m.dir.startswith('/mnt/onl'): + if not self.force: + self.log.error("directory %s is still mounted (try --force)", m.dir) + return 1 + self.log.warn("unmounting %s (--force)", m.dir) + self.check_call(('umount', m.dir,)) + + upgrader = UpgradeHelper(callback=self._runInitrd, log=self.log) + try: + code = upgrader.run() + except: + self.log.exception("upgrader failed") + code = 1 + upgrader.shutdown() + return code + + def shutdown(self): + + h, self.onieHelper = self.onieHelper, None + if h is not None: + h.shutdown() + + @classmethod + def main(cls): + + logging.basicConfig() + logger = logging.getLogger("onl-install") + logger.setLevel(logging.DEBUG) + + # send to ONIE log + hnd = logging.FileHandler("/dev/console") + logger.addHandler(hnd) + logger.propagate = False + + onie_verbose = 'onie_verbose' in os.environ + installer_debug = 'installer_debug' in os.environ + + ap = argparse.ArgumentParser() + ap.add_argument('-v', '--verbose', action='store_true', + default=onie_verbose, + help="Enable verbose logging") + ap.add_argument('-D', '--debug', action='store_true', + default=installer_debug, + help="Enable python debugging") + ap.add_argument('-F', '--force', action='store_true', + help="Unmount filesystems before install") + ops = ap.parse_args() + + if ops.verbose: + logger.setLevel(logging.DEBUG) + + app = cls(force=ops.force, + log=logger) + try: + code = app.run() + except: + logger.exception("runner failed") + code = 1 + if ops.debug: + app.post_mortem() + + app.shutdown() + sys.exit(code) + +main = App.main + +if __name__ == "__main__": + main() diff --git a/packages/base/all/vendor-config-onl/src/python/onl/upgrade/system.py b/packages/base/all/vendor-config-onl/src/python/onl/upgrade/system.py new file mode 100644 index 00000000..9bcbf3cd --- /dev/null +++ b/packages/base/all/vendor-config-onl/src/python/onl/upgrade/system.py @@ -0,0 +1,78 @@ +#!/usr/bin/python +############################################################ +# +# ONL System Upgrade +# +############################################################ +import os +import sys +import fnmatch +from onl.upgrade import ubase +from onl.sysconfig import sysconfig +from onl.mounts import OnlMountManager, OnlMountContextReadOnly, OnlMountContextReadWrite + +from onl.install.SystemInstall import App + +class SystemUpgrade(ubase.BaseUpgrade): + name="system" + Name="System" + title="System Compatibility Version Check" + atype="A Compatible System" + + current_version_key="Current System Compatibility Version" + next_version_key="Next System Compatibility Version" + + def auto_upgrade_default(self): + return sysconfig.upgrade.system.auto + + def init_versions(self): + + # + # Current loader version file. + # If this file doesn't exist then in-place upgrade is not supported. + # + ETC_LOADER_VERSIONS_JSON = sysconfig.upgrade.loader.versions + + # Upgrade Loader Version file. + NEXT_LOADER_VERSIONS_JSON = os.path.join(sysconfig.upgrade.loader.package.dir, "manifest.json") + + VKEY = "SYSTEM_COMPATIBILITY_VERSION" + + self.current_version = self.load_json(ETC_LOADER_VERSIONS_JSON, VKEY, None) + + self.next_version = self.load_json(NEXT_LOADER_VERSIONS_JSON, + "version", {}).get(VKEY, None) + + def prepare_upgrade(self): + pass + + def summarize(self): + self.logger.info("Current System Compatibility Version: %s", + self.current_version) + self.logger.info(" Next System Compatibility Version: %s", + self.next_version) + self.logger.info("") + + + def upgrade_notes(self): + return """ + * One or more reboots will be required to complete this upgrade. +""" + + def do_upgrade(self, forced=False): + app = App(force=True, log=self.logger) + try: + code = app.run() + except: + self.logger.exception("upgrade failed") + code = 1 + app.shutdown() + if code: + self.abort("System upgrade failed.") + else: + self.logger.info("Upgrade succeeded, rebooting") + self.reboot() + +if __name__ == '__main__': + klass = SystemUpgrade + klass().main() diff --git a/packages/base/all/vendor-config-onl/src/sbin/onl-install-system b/packages/base/all/vendor-config-onl/src/sbin/onl-install-system new file mode 100755 index 00000000..9ae0fea3 --- /dev/null +++ b/packages/base/all/vendor-config-onl/src/sbin/onl-install-system @@ -0,0 +1,7 @@ +#!/usr/bin/python + +"""Re-install ONL using the ONL installer infrastructure. +""" + +import onl.install.SystemInstall +onl.install.SystemInstall.main() diff --git a/packages/base/all/vendor-config-onl/src/sbin/onl-upgrade-system b/packages/base/all/vendor-config-onl/src/sbin/onl-upgrade-system new file mode 100755 index 00000000..efc4bdc7 --- /dev/null +++ b/packages/base/all/vendor-config-onl/src/sbin/onl-upgrade-system @@ -0,0 +1,3 @@ +#!/usr/bin/python +from onl.upgrade.system import SystemUpgrade +SystemUpgrade().main() diff --git a/tools/onlpm.py b/tools/onlpm.py index 68e301e6..3ce1cb32 100755 --- a/tools/onlpm.py +++ b/tools/onlpm.py @@ -1098,7 +1098,6 @@ if __name__ == '__main__': ap.add_argument("--repo-package-dir", default=os.environ.get('ONLPM_OPTION_REPO_PACKAGE_DIR', 'packages')) ap.add_argument("--packagedirs", nargs='+', metavar='PACKAGEDIR') ap.add_argument("--subdir", default=os.getcwd()) - ap.add_argument("--extract", metavar='PACKAGE') ap.add_argument("--extract-dir", nargs=2, metavar=('PACKAGE', 'DIR'), action='append') ap.add_argument("--force", action='store_true') ap.add_argument("--list", action='store_true');