From 6f1a21e4c2dde6436886e9c3c3f9305d5bc6d13a Mon Sep 17 00:00:00 2001 From: Colin Walters Date: Wed, 19 Mar 2014 10:56:24 -0400 Subject: [PATCH] Split ROOT_PATH usage into getTargetPhysicalRoot()/getSysroot() This mirrors the change to Anaconda, in order to enable OSTree support. For OSTree, the location of the OS checkout (and e.g. /etc/fstab) is really in /ostree/deploy/$osname/deploy/$revision/etc/fstab. In order to properly support OSTree, Blivet will need to gain an understanding of the separation between the physical system / and the target root. This patch will be used in Anaconda, which will call setSysroot() attribute after the root being installed is laid out. After that, when we call write(), the fstab data will be correctly written into the target root. Related: rhbz#1113535 Port of rpmostreepayload patches from master commit 5b39c90ae582a8fb008c3633954a33b58394802c --- blivet/__init__.py | 102 +++++++++++++++++++++++++++++++++------------- blivet/devicelibs/dasd.py | 4 +- blivet/fcoe.py | 8 ++-- blivet/iscsi.py | 14 +++---- blivet/util.py | 4 +- blivet/zfcp.py | 8 ++-- 6 files changed, 92 insertions(+), 48 deletions(-) diff --git a/blivet/__init__.py b/blivet/__init__.py index 85b67da..6b127d7 100644 --- a/blivet/__init__.py +++ b/blivet/__init__.py @@ -30,7 +30,10 @@ __version__ = '0.18.34' ## enable_installer_mode is called. ## isys = None +iutil = None ROOT_PATH = '/' +_storageRoot = ROOT_PATH +_sysroot = ROOT_PATH shortProductName = 'blivet' productName = 'blivet' bootLoaderError = Exception @@ -99,7 +102,10 @@ log = logging.getLogger("blivet") def enable_installer_mode(): global isys + global iutil global ROOT_PATH + global _storageRoot + global _sysroot global shortProductName global productName global get_bootloader @@ -108,6 +114,7 @@ def enable_installer_mode(): global ERROR_RAISE from pyanaconda import isys + from pyanaconda import iutil from pyanaconda.constants import ROOT_PATH from pyanaconda.constants import shortProductName from pyanaconda.constants import productName @@ -116,11 +123,48 @@ def enable_installer_mode(): from pyanaconda.errors import errorHandler from pyanaconda.errors import ERROR_RAISE + if hasattr(iutil, 'getTargetPhysicalRoot'): + # Introduced in newer Anaconda + _storageRoot = iutil.getTargetPhysicalRoot() + _sysroot = iutil.getSysroot() + else: + _storageRoot = _sysroot = ROOT_PATH + from pyanaconda.anaconda_log import program_log_lock util.program_log_lock = program_log_lock flags.installer_mode = True +def getSysroot(): + """Returns the path to the target OS installation. + + For traditional installations, this is the same as the physical + storage root. + """ + return _sysroot + +def getTargetPhysicalRoot(): + """Returns the path to the "physical" storage root. + + This may be distinct from the sysroot, which could be a + chroot-type subdirectory of the physical root. This is used for + example by all OSTree-based installations. + """ + return _storageRoot + +def setSysroot(storageRoot, sysroot=None): + """Change the OS root path. + :param storageRoot: The root of physical storage + :param sysroot: An optional chroot subdirectory of storageRoot + + Change the + """ + global _storageRoot + global _sysroot + _storageRoot = _sysroot = storageRoot + if sysroot is not None: + _sysroot = sysroot + def storageInitialize(storage, ksdata, protected): """ Perform installer-specific storage initialization. """ from pyanaconda.flags import flags as anaconda_flags @@ -202,7 +246,7 @@ def writeEscrowPackets(storage): backupPassphrase = generateBackupPassphrase() try: - escrowDir = ROOT_PATH + "/root" + escrowDir = _sysroot + "/root" log.debug("escrow: writing escrow packets to %s", escrowDir) util.makedirs(escrowDir) for device in escrowDevices: @@ -1665,22 +1709,22 @@ class Blivet(object): return list(pkgs) def write(self): - if not os.path.isdir("%s/etc" % ROOT_PATH): - os.mkdir("%s/etc" % ROOT_PATH) + if not os.path.isdir("%s/etc" % _sysroot): + os.mkdir("%s/etc" % _sysroot) self.fsset.write() self.makeMtab() - self.iscsi.write(ROOT_PATH, self) - self.fcoe.write(ROOT_PATH) - self.zfcp.write(ROOT_PATH) - write_dasd_conf(self.dasd, ROOT_PATH) + self.iscsi.write(_sysroot, self) + self.fcoe.write(_sysroot) + self.zfcp.write(_sysroot) + write_dasd_conf(self.dasd, _sysroot) def turnOnSwap(self, upgrading=None): - self.fsset.turnOnSwap(rootPath=ROOT_PATH, + self.fsset.turnOnSwap(rootPath=_sysroot, upgrading=upgrading) def mountFilesystems(self, raiseErrors=None, readOnly=None, skipRoot=False): - self.fsset.mountFilesystems(rootPath=ROOT_PATH, + self.fsset.mountFilesystems(rootPath=_sysroot, raiseErrors=raiseErrors, readOnly=readOnly, skipRoot=skipRoot) @@ -1797,7 +1841,7 @@ class Blivet(object): def makeMtab(self): path = "/etc/mtab" target = "/proc/self/mounts" - path = os.path.normpath("%s/%s" % (ROOT_PATH, path)) + path = os.path.normpath("%s/%s" % (_sysroot, path)) if os.path.islink(path): # return early if the mtab symlink is already how we like it @@ -2130,7 +2174,7 @@ def mountExistingSystem(fsset, rootDevice, allowDirty=None, dirtyCB=None, readOnly=None): """ Mount filesystems specified in rootDevice's /etc/fstab file. """ - rootPath = ROOT_PATH + rootPath = _sysroot if dirtyCB is None: dirtyCB = lambda l: False @@ -2172,7 +2216,7 @@ def mountExistingSystem(fsset, rootDevice, if dirtyDevs and (not allowDirty or dirtyCB(dirtyDevs)): raise DirtyFSError("\n".join(dirtyDevs)) - fsset.mountFilesystems(rootPath=ROOT_PATH, readOnly=readOnly, skipRoot=True) + fsset.mountFilesystems(rootPath=_sysroot, readOnly=readOnly, skipRoot=True) class BlkidTab(object): @@ -2529,7 +2573,7 @@ class FSSet(object): loop mounts? """ if not chroot or not os.path.isdir(chroot): - chroot = ROOT_PATH + chroot = _sysroot path = "%s/etc/fstab" % chroot if not os.access(path, os.R_OK): @@ -2703,10 +2747,10 @@ class FSSet(object): self.active = False def createSwapFile(self, device, size): - """ Create and activate a swap file under ROOT_PATH. """ + """ Create and activate a swap file under storage root. """ filename = "/SWAP" count = 0 - basedir = os.path.normpath("%s/%s" % (ROOT_PATH, + basedir = os.path.normpath("%s/%s" % (getTargetPhysicalRoot(), device.format.mountpoint)) while os.path.exists("%s/%s" % (basedir, filename)) or \ self.devicetree.getDeviceByName(filename): @@ -2727,10 +2771,10 @@ class FSSet(object): def mkDevRoot(self): root = self.rootDevice - dev = "%s/%s" % (ROOT_PATH, root.path) - if not os.path.exists("%s/dev/root" %(ROOT_PATH,)) and os.path.exists(dev): + dev = "%s/%s" % (_sysroot, root.path) + if not os.path.exists("%s/dev/root" %(_sysroot,)) and os.path.exists(dev): rdev = os.stat(dev).st_rdev - os.mknod("%s/dev/root" % (ROOT_PATH,), stat.S_IFBLK | 0600, rdev) + os.mknod("%s/dev/root" % (_sysroot,), stat.S_IFBLK | 0600, rdev) @property def swapDevices(self): @@ -2742,7 +2786,7 @@ class FSSet(object): @property def rootDevice(self): - for path in ["/", ROOT_PATH]: + for path in ["/", getTargetPhysicalRoot()]: for device in self.devices: try: mountpoint = device.format.mountpoint @@ -2755,19 +2799,19 @@ class FSSet(object): def write(self): """ write out all config files based on the set of filesystems """ # /etc/fstab - fstab_path = os.path.normpath("%s/etc/fstab" % ROOT_PATH) + fstab_path = os.path.normpath("%s/etc/fstab" % _sysroot) fstab = self.fstab() open(fstab_path, "w").write(fstab) # /etc/crypttab - crypttab_path = os.path.normpath("%s/etc/crypttab" % ROOT_PATH) + crypttab_path = os.path.normpath("%s/etc/crypttab" % _sysroot) crypttab = self.crypttab() origmask = os.umask(0077) open(crypttab_path, "w").write(crypttab) os.umask(origmask) # /etc/mdadm.conf - mdadm_path = os.path.normpath("%s/etc/mdadm.conf" % ROOT_PATH) + mdadm_path = os.path.normpath("%s/etc/mdadm.conf" % _sysroot) mdadm_conf = self.mdadmConf() if mdadm_conf: open(mdadm_path, "w").write(mdadm_conf) @@ -2900,11 +2944,11 @@ def getReleaseString(): relVer = None try: - relArch = util.capture_output(["arch"], root=ROOT_PATH).strip() + relArch = util.capture_output(["arch"], root=_sysroot).strip() except: relArch = None - filename = "%s/etc/redhat-release" % ROOT_PATH + filename = "%s/etc/redhat-release" % getSysroot() if os.access(filename, os.R_OK): with open(filename) as f: try: @@ -2923,8 +2967,8 @@ def getReleaseString(): return (relArch, relName, relVer) def findExistingInstallations(devicetree): - if not os.path.exists(ROOT_PATH): - util.makedirs(ROOT_PATH) + if not os.path.exists(getTargetPhysicalRoot()): + util.makedirs(getTargetPhysicalRoot()) roots = [] for device in devicetree.leaves: @@ -2940,7 +2984,7 @@ def findExistingInstallations(devicetree): options = device.format.options + ",ro" try: - device.format.mount(options=options, mountpoint=ROOT_PATH) + device.format.mount(options=options, mountpoint=getSysroot()) except Exception as e: log.warning("mount of %s as %s failed: %s" % (device.name, device.format.type, @@ -2948,7 +2992,7 @@ def findExistingInstallations(devicetree): device.teardown() continue - if not os.access(ROOT_PATH + "/etc/fstab", os.R_OK): + if not os.access(getSysroot() + "/etc/fstab", os.R_OK): device.teardown(recursive=True) continue @@ -3000,7 +3044,7 @@ class Root(object): def parseFSTab(devicetree, chroot=None): """ parse /etc/fstab and return a tuple of a mount dict and swap list """ if not chroot or not os.path.isdir(chroot): - chroot = ROOT_PATH + chroot = _sysroot mounts = {} swaps = [] diff --git a/blivet/devicelibs/dasd.py b/blivet/devicelibs/dasd.py index 7eb2551..5beb11d 100644 --- a/blivet/devicelibs/dasd.py +++ b/blivet/devicelibs/dasd.py @@ -110,14 +110,14 @@ def dasd_needs_format(dasd): return False -def write_dasd_conf(disks, ROOT_PATH): +def write_dasd_conf(disks, root): """ Write /etc/dasd.conf to target system for all DASD devices configured during installation. """ if not (arch.isS390() or disks): return - with open(os.path.realpath(ROOT_PATH + "/etc/dasd.conf"), "w") as f: + with open(os.path.realpath(root + "/etc/dasd.conf"), "w") as f: for dasd in sorted(disks, key=lambda d: d.name): fields = [dasd.busid] + dasd.getOpts() f.write("%s\n" % " ".join(fields),) diff --git a/blivet/fcoe.py b/blivet/fcoe.py index 42d7550..71ffbcb 100644 --- a/blivet/fcoe.py +++ b/blivet/fcoe.py @@ -149,15 +149,15 @@ class fcoe(object): return error_msg - def write(self, ROOT_PATH): + def write(self, root): if not self.nics: return - if not os.path.isdir(ROOT_PATH + "/etc/fcoe"): - os.makedirs(ROOT_PATH + "/etc/fcoe", 0755) + if not os.path.isdir(root + "/etc/fcoe"): + os.makedirs(root + "/etc/fcoe", 0755) for nic, dcb, auto_vlan in self.nics: - fd = os.open(ROOT_PATH + "/etc/fcoe/cfg-" + nic, + fd = os.open(root + "/etc/fcoe/cfg-" + nic, os.O_RDWR | os.O_CREAT) os.write(fd, '# Created by anaconda\n') os.write(fd, '# Enable/Disable FCoE service at the Ethernet port\n') diff --git a/blivet/iscsi.py b/blivet/iscsi.py index fceb881..eb640cd 100644 --- a/blivet/iscsi.py +++ b/blivet/iscsi.py @@ -360,7 +360,7 @@ class iscsi(object): self.stabilize() - def write(self, ROOT_PATH, storage): + def write(self, root, storage): if not self.initiatorSet: return @@ -377,17 +377,17 @@ class iscsi(object): if autostart: node.setParameter("node.startup", "automatic") - if not os.path.isdir(ROOT_PATH + "/etc/iscsi"): - os.makedirs(ROOT_PATH + "/etc/iscsi", 0755) - fd = os.open(ROOT_PATH + INITIATOR_FILE, os.O_RDWR | os.O_CREAT) + if not os.path.isdir(root + "/etc/iscsi"): + os.makedirs(root + "/etc/iscsi", 0755) + fd = os.open(root + INITIATOR_FILE, os.O_RDWR | os.O_CREAT) os.write(fd, "InitiatorName=%s\n" %(self.initiator)) os.close(fd) # copy "db" files. *sigh* - if os.path.isdir(ROOT_PATH + "/var/lib/iscsi"): - shutil.rmtree(ROOT_PATH + "/var/lib/iscsi") + if os.path.isdir(root + "/var/lib/iscsi"): + shutil.rmtree(root + "/var/lib/iscsi") if os.path.isdir("/var/lib/iscsi"): - shutil.copytree("/var/lib/iscsi", ROOT_PATH + "/var/lib/iscsi", + shutil.copytree("/var/lib/iscsi", root + "/var/lib/iscsi", symlinks=True) def getNode(self, name, address, port, iface): diff --git a/blivet/util.py b/blivet/util.py index d43b252..505acc6 100644 --- a/blivet/util.py +++ b/blivet/util.py @@ -277,13 +277,13 @@ def makedirs(path): def copy_to_system(source): # do the import now because enable_installer_mode() has finally been called. - from . import ROOT_PATH + from . import getSysroot if not os.access(source, os.R_OK): log.info("copy_to_system: source '%s' does not exist." % source) return False - target = ROOT_PATH + source + target = getSysroot() + source target_dir = os.path.dirname(target) log.debug("copy_to_system: '%s' -> '%s'." % (source, target)) if not os.path.isdir(target_dir): diff --git a/blivet/zfcp.py b/blivet/zfcp.py index cf8ec40..565c201 100644 --- a/blivet/zfcp.py +++ b/blivet/zfcp.py @@ -409,15 +409,15 @@ class ZFCP: except ValueError as e: log.warn(str(e)) - def write(self, ROOT_PATH): + def write(self, root): if len(self.fcpdevs) == 0: return - f = open(ROOT_PATH + zfcpconf, "w") + f = open(root + zfcpconf, "w") for d in self.fcpdevs: f.write("%s\n" %(d,)) f.close() - - f = open(ROOT_PATH + "/etc/modprobe.conf", "a") + + f = open(root + "/etc/modprobe.conf", "a") f.write("alias scsi_hostadapter zfcp\n") f.close() -- 1.9.3