mirror of
https://github.com/Telecominfraproject/OpenNetworkLinux.git
synced 2025-12-25 17:27:01 +00:00
Factor out the SWI retrieval and directory mounting
This commit is contained in:
244
packages/base/all/initrds/loader-initrd-files/src/bin/swiget
Executable file
244
packages/base/all/initrds/loader-initrd-files/src/bin/swiget
Executable file
@@ -0,0 +1,244 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
"""swiget
|
||||
|
||||
Retrieve/resolve a SWI file to the local filesystem path.
|
||||
"""
|
||||
|
||||
import sys, os
|
||||
import time
|
||||
import urllib
|
||||
import subprocess
|
||||
import shutil
|
||||
import logging
|
||||
import tempfile
|
||||
|
||||
import onl.install.InstallUtils
|
||||
MountContext = onl.install.InstallUtils.MountContext
|
||||
BlkidParser = onl.install.InstallUtils.BlkidParser
|
||||
ProcMountsParser = onl.install.InstallUtils.ProcMountsParser
|
||||
|
||||
import onl.mounts
|
||||
OnlMountManager = onl.mounts.OnlMountManager
|
||||
|
||||
import onl.network
|
||||
HostInfo = onl.network.HostInfo
|
||||
|
||||
class Runner(onl.install.InstallUtils.SubprocessMixin):
|
||||
|
||||
def __init__(self, log):
|
||||
self.log = log
|
||||
|
||||
self.nextUpdate = None
|
||||
|
||||
def reporthook(self, blocks, bsz, sz):
|
||||
if time.time() < self.nextUpdate: return
|
||||
self.nextUpdate = time.time() + 0.25
|
||||
if sz:
|
||||
pct = blocks * bsz * 100 / sz
|
||||
sys.stderr.write("downloaded %d%% ...\r" % pct)
|
||||
else:
|
||||
icon = "|/-\\"[blocks % 4]
|
||||
sys.stderr.write("downloading ... %s\r" % icon)
|
||||
|
||||
def get(self, SWI):
|
||||
|
||||
# XXX lots of fixups required here for proper IPv6 support
|
||||
if SWI.startswith('http://') or SWI.startswith('ftp://'):
|
||||
self.log.info("retrieving %s via HTTP/FTP", SWI)
|
||||
dst = tempfile.mktemp(prefix="swiget-", suffix=".swi")
|
||||
if os.isatty(sys.stdout.fileno()):
|
||||
dst, headers = urllib.urlretrieve(SWI, dst, self.reporthook)
|
||||
else:
|
||||
dst, headers = urllib.urlretrieve(SWI, dst)
|
||||
sys.stderr.write("\n")
|
||||
return dst
|
||||
|
||||
if SWI.startswith('scp://') or SWI.startswith('ssh://'):
|
||||
buf = SWI[6:]
|
||||
h, sep, r = buf.partition('/')
|
||||
if not sep:
|
||||
self.log.error("invalid SWI %s", SWI)
|
||||
return None
|
||||
hinfo = HostInfo.fromString(h)
|
||||
rcmd = "cat /%s" % r
|
||||
cmd = ['dbclient', '-y', hinfo.host, rcmd,]
|
||||
if hinfo.port is not None:
|
||||
cmd[2:2] = ['-p', str(hinfo.port),]
|
||||
if hinfo.user is not None:
|
||||
cmd[2:2] = ['-l', hinfo.user,]
|
||||
env = {}
|
||||
env.update(os.environ)
|
||||
if hinfo.password is not None:
|
||||
env['DROPBEAR_PASSWORD'] = hinfo.password
|
||||
dst = tempfile.mktemp(prefix="swiget-", suffix=".swi")
|
||||
with open(dst, "w") as fd:
|
||||
self.check_call(cmd, stdout=fd, env=env)
|
||||
return dst
|
||||
|
||||
if SWI.startswith('tftp://'):
|
||||
buf = SWI[7:]
|
||||
h, sep, r = buf.partition('/')
|
||||
if not sep:
|
||||
self.log.error("invalid SWI %s", SWI)
|
||||
return None
|
||||
hinfo = HostInfo.fromString(h)
|
||||
port = hinfo.port or 69
|
||||
dst = tempfile.mktemp(prefix="swiget-", suffix=".swi")
|
||||
cmd = ('tftp', '-g', '-r', r, '-l', dst, hinfo.host, str(hinfo.port),)
|
||||
self.check_call(cmd)
|
||||
return dst
|
||||
|
||||
if SWI.startswith('nfs://'):
|
||||
buf = SWI[6:]
|
||||
h, sep, r = buf.partition('/')
|
||||
if not sep:
|
||||
self.log.error("invalid SWI %s", SWI)
|
||||
return None
|
||||
hinfo = HostInfo.fromString(h)
|
||||
|
||||
if '/' in r:
|
||||
root, base = os.path.split(r)
|
||||
else:
|
||||
root, base = '/', r
|
||||
src = "%s:/%s" % (hinfo.bhost, root,)
|
||||
mpt = self.mkdtemp(prefix="swiget-nfs-", suffix=".d")
|
||||
cmd = ['mount', '-t', 'nfs', src, mpt,]
|
||||
if hinfo.port is not None:
|
||||
cmd[3:3] = ['-o', "ro,nolock,port=%s" % hinfo.port,]
|
||||
else:
|
||||
cmd[3:3] = ['-o', 'ro,nolock',]
|
||||
self.check_call(cmd)
|
||||
|
||||
dst = tempfile.mktemp(prefix="swiget-", suffix=".swi")
|
||||
try:
|
||||
src = "%s/%s" % (mpt, base,)
|
||||
self.copy2(src, dst)
|
||||
except:
|
||||
if os.path.exists(dst):
|
||||
self.unlink(dst)
|
||||
raise
|
||||
finally:
|
||||
self.check_call(('umount', mpt,))
|
||||
self.rmdir(mpt)
|
||||
|
||||
return dst
|
||||
|
||||
blkid = BlkidParser(log=self.log)
|
||||
|
||||
if ':' in SWI:
|
||||
devspec, sep, r = SWI.partition(':')
|
||||
|
||||
p = "/dev/%s" % devspec
|
||||
if os.path.exists(p):
|
||||
return self.blockdevCopy(p, r)
|
||||
|
||||
try:
|
||||
part = blkid[devspec]
|
||||
except IndexError:
|
||||
part = None
|
||||
if part is not None:
|
||||
return self.blockdevCopy(part.device, r)
|
||||
|
||||
mm = OnlMountManager("/etc/mtab.yml", self.log)
|
||||
label = mpt = None
|
||||
for k, v in mm.mdata['mounts'].items():
|
||||
if v['dir'].endswith('/' + devspec):
|
||||
label = k
|
||||
mpt = v['dir']
|
||||
break
|
||||
if label is not None:
|
||||
try:
|
||||
part = blkid[label]
|
||||
except IndexError:
|
||||
part = None
|
||||
if part is not None:
|
||||
return self.blockdevCopy(part.device, r, dir=mpt)
|
||||
|
||||
self.log.error("cannot find device specifier for %s", SWI)
|
||||
return None
|
||||
|
||||
# local file
|
||||
if SWI.startswith('/') and os.path.exists(SWI):
|
||||
return SWI
|
||||
|
||||
# possibly unmounted dirctory
|
||||
if SWI.startswith('/') and not os.path.exists(SWI):
|
||||
mm = OnlMountManager("/etc/mtab.yml", self.log)
|
||||
label = mpt = path = None
|
||||
for k, v in mm.mdata['mounts'].items():
|
||||
if SWI.startswith(v['dir'] + '/'):
|
||||
label = k
|
||||
mpt = v['dir']
|
||||
path = SWI[len(mpt)+1:]
|
||||
break
|
||||
if label is not None:
|
||||
try:
|
||||
part = blkid[label]
|
||||
except IndexError:
|
||||
part = None
|
||||
if part is not None:
|
||||
return self.blockdevCopy(part.device, path, dir=mpt)
|
||||
|
||||
self.log.error("invalid SWI %s", SWI)
|
||||
return None
|
||||
|
||||
def blockdevCopy(self, dev, src, dir=None):
|
||||
|
||||
def latest(d):
|
||||
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=os.path.getmtime)
|
||||
return l[-1]
|
||||
|
||||
pm = ProcMountsParser()
|
||||
parts = [x for x in pm.mounts if x.device == dev]
|
||||
if parts:
|
||||
if src == ':latest':
|
||||
dst = latest(parts[0].dir)
|
||||
self.log.info("found 'latest' swi %s", dst)
|
||||
else:
|
||||
dst = os.path.join(parts[0].dir, src)
|
||||
if not os.path.exists(dst):
|
||||
self.log.error("missing SWI: %s", dst)
|
||||
return None
|
||||
return dst
|
||||
|
||||
with MountContext(device=dev, log=self.log) as ctx:
|
||||
if src == ':latest':
|
||||
dst = latest(ctx.dir)
|
||||
self.log.info("found 'latest' swi %s", dst)
|
||||
else:
|
||||
dst = os.path.join(ctx.dir, src)
|
||||
if not os.path.exists(dst):
|
||||
self.log.error("missing SWI: %s:%s", dev, src)
|
||||
return None
|
||||
|
||||
# move to its proper location as per mtab
|
||||
# XXX perms may not be right here
|
||||
if dir is not None:
|
||||
self.check_call(('mount', '--move', ctx.dir, dir,))
|
||||
ctx.mounted = False
|
||||
return os.path.join(dir, src)
|
||||
|
||||
ctx.mounted = False
|
||||
ctx.hostDir = None
|
||||
return dst
|
||||
|
||||
@classmethod
|
||||
def main(cls):
|
||||
SWI = sys.argv[1]
|
||||
logging.basicConfig()
|
||||
logger = logging.getLogger("swiget")
|
||||
logger.setLevel(logging.DEBUG)
|
||||
r = cls(logger)
|
||||
dst = r.get(SWI)
|
||||
if dst is None:
|
||||
sys.exit(1)
|
||||
sys.stdout.write(dst + "\n")
|
||||
sys.exit(0)
|
||||
|
||||
main = Runner.main
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
184
packages/base/all/initrds/loader-initrd-files/src/bin/swimount
Executable file
184
packages/base/all/initrds/loader-initrd-files/src/bin/swimount
Executable file
@@ -0,0 +1,184 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
"""swimount
|
||||
|
||||
Mount a directory specified in $SWI.
|
||||
"""
|
||||
|
||||
import os, sys
|
||||
import shutil
|
||||
import logging
|
||||
|
||||
import onl.install.InstallUtils
|
||||
BlkidParser = onl.install.InstallUtils.BlkidParser
|
||||
|
||||
import onl.mounts
|
||||
MountContext = onl.install.InstallUtils.MountContext
|
||||
OnlMountManager = onl.mounts.OnlMountManager
|
||||
ProcMountsParser = onl.install.InstallUtils.ProcMountsParser
|
||||
|
||||
import onl.network
|
||||
HostInfo = onl.network.HostInfo
|
||||
|
||||
class Runner(onl.install.InstallUtils.SubprocessMixin):
|
||||
|
||||
def __init__(self, log):
|
||||
self.log = log
|
||||
|
||||
self.blkid = BlkidParser(log=self.log)
|
||||
|
||||
def mount(self, SWI):
|
||||
|
||||
if SWI.startswith('nfs://'):
|
||||
buf = SWI[6:]
|
||||
buf = buf.rstrip('/')
|
||||
h, sep, r = buf.partition('/')
|
||||
if not sep:
|
||||
self.log.error("invalid SWI %s", SWI)
|
||||
return None
|
||||
hinfo = HostInfo.fromString(h)
|
||||
|
||||
if not r:
|
||||
r = '/'
|
||||
else:
|
||||
r = '/' + r
|
||||
src = "%s:%s" % (hinfo.bhost, r,)
|
||||
mpt = self.mkdtemp(prefix="swimount-nfs-", suffix=".d")
|
||||
cmd = ['mount', '-t', 'nfs', src, mpt,]
|
||||
if hinfo.port is not None:
|
||||
cmd[3:3] = ['-o', "nolock,port=%s" % hinfo.port,]
|
||||
else:
|
||||
cmd[3:3] = ['-o', 'nolock',]
|
||||
self.check_call(cmd)
|
||||
|
||||
return mpt
|
||||
|
||||
# local path specifier
|
||||
if not SWI.startswith('dir:'):
|
||||
self.log.error("invalid SWI %s", SWI)
|
||||
return None
|
||||
SWI = SWI[4:]
|
||||
|
||||
if ':' in SWI:
|
||||
devspec, sep, r = SWI.partition(':')
|
||||
return self.devspecMount(devspec, r)
|
||||
|
||||
if not SWI.startswith('/'):
|
||||
return self.devspecMount(SWI, '/')
|
||||
|
||||
if not os.path.isdir(SWI):
|
||||
self.log.error("invalid SWI %s (not a directory)", SWI)
|
||||
return None
|
||||
|
||||
# local directory, but actually mounted
|
||||
if os.stat('/').st_dev != os.stat(SWI).st_dev:
|
||||
return SWI
|
||||
|
||||
# possibly unmounted dirctory
|
||||
mm = OnlMountManager("/etc/mtab.yml", self.log)
|
||||
label = mpt = path = None
|
||||
for k, v in mm.mdata['mounts'].items():
|
||||
if SWI == v['dir']:
|
||||
label = k
|
||||
mpt = v['dir']
|
||||
path = '/'
|
||||
break
|
||||
if SWI.startswith(v['dir'] + '/'):
|
||||
label = k
|
||||
mpt = v['dir']
|
||||
path = SWI[len(mpt)+1:]
|
||||
break
|
||||
if label is not None:
|
||||
try:
|
||||
part = self.blkid[label]
|
||||
except IndexError:
|
||||
part = None
|
||||
if part is not None:
|
||||
return self.blockdevMount(part.device, path, dir=mpt)
|
||||
|
||||
self.log.error("invalid SWI %s", SWI)
|
||||
return None
|
||||
|
||||
def devspecMount(self, devspec, path):
|
||||
"""Find using a device specifier."""
|
||||
|
||||
p = "/dev/%s" % devspec
|
||||
if os.path.exists(p):
|
||||
return self.blockdevMount(p, r)
|
||||
|
||||
try:
|
||||
part = self.blkid[devspec]
|
||||
except IndexError:
|
||||
part = None
|
||||
if part is not None:
|
||||
return self.blockdevMount(part.device, r)
|
||||
|
||||
mm = OnlMountManager("/etc/mtab.yml", self.log)
|
||||
label = mpt = None
|
||||
for k, v in mm.mdata['mounts'].items():
|
||||
if v['dir'].endswith('/' + devspec):
|
||||
label = k
|
||||
mpt = v['dir']
|
||||
break
|
||||
if label is not None:
|
||||
try:
|
||||
part = self.blkid[label]
|
||||
except IndexError:
|
||||
part = None
|
||||
if part is not None:
|
||||
return self.blockdevMount(part.device, path, dir=mpt)
|
||||
|
||||
self.log.error("cannot find device specifier for %s", SWI)
|
||||
return None
|
||||
|
||||
def blockdevMount(self, dev, src, dir=None):
|
||||
|
||||
pm = ProcMountsParser()
|
||||
parts = [x for x in pm.mounts if x.device == dev]
|
||||
if parts:
|
||||
dst = parts[0].dir
|
||||
if src and src != '/': dst = os.path.join(dst, src)
|
||||
if not os.path.exists(dst):
|
||||
self.log.error("missing SWI: %s", dst)
|
||||
return None
|
||||
self.check_call(('mount', '-o', 'rw,remount', dst,))
|
||||
return dst
|
||||
|
||||
with MountContext(device=dev, log=self.log) as ctx:
|
||||
dst = ctx.dir
|
||||
if src and src != '/': dst = os.path.join(dst, src)
|
||||
if not os.path.exists(dst):
|
||||
self.log.error("missing SWI: %s:%s", dev, src)
|
||||
return None
|
||||
|
||||
# move to its proper location as per mtab
|
||||
# XXX perms may not be right here
|
||||
if dir is not None:
|
||||
self.check_call(('mount', '-o', 'rw,remount', ctx.dir,))
|
||||
self.check_call(('mount', '--move', ctx.dir, dir,))
|
||||
ctx.mounted = False
|
||||
dst = dir
|
||||
if src and src != '/': dst = os.path.join(dst, src)
|
||||
return dst
|
||||
|
||||
ctx.mounted = False
|
||||
ctx.hostDir = None
|
||||
return dst
|
||||
|
||||
@classmethod
|
||||
def main(cls):
|
||||
SWI = sys.argv[1]
|
||||
logging.basicConfig()
|
||||
logger = logging.getLogger("swimount")
|
||||
logger.setLevel(logging.DEBUG)
|
||||
r = cls(logger)
|
||||
dst = r.mount(SWI)
|
||||
if dst is None:
|
||||
sys.exit(1)
|
||||
sys.stdout.write(dst + "\n")
|
||||
sys.exit(0)
|
||||
|
||||
main = Runner.main
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user