core-extra/daemon/core/xen/xen.py

788 lines
30 KiB
Python

"""
xen.py: implementation of the XenNode and XenVEth classes that support
generating Xen domUs based on an ISO image and persistent configuration area
"""
import base64
import os
import shutil
import string
import subprocess
import sys
import threading
import crypt
from core import constants
from core import logger
from core.coreobj import PyCoreNetIf
from core.coreobj import PyCoreNode
from core.enumerations import NodeTypes
from core.misc import nodeutils
from core.misc import utils
from core.netns.vnode import LxcNode
try:
import parted
except ImportError:
logger.error("failed to import parted for xen nodes")
try:
import fsimage
except ImportError:
# fix for fsimage under Ubuntu
sys.path.append("/usr/lib/xen-default/lib/python")
try:
import fsimage
except ImportError:
logger.error("failed to import fsimage for xen nodes")
# XXX move these out to config file
AWK_PATH = "/bin/awk"
KPARTX_PATH = "/sbin/kpartx"
LVCREATE_PATH = "/sbin/lvcreate"
LVREMOVE_PATH = "/sbin/lvremove"
LVCHANGE_PATH = "/sbin/lvchange"
MKFSEXT4_PATH = "/sbin/mkfs.ext4"
MKSWAP_PATH = "/sbin/mkswap"
TAR_PATH = "/bin/tar"
SED_PATH = "/bin/sed"
XM_PATH = "/usr/sbin/xm"
UDEVADM_PATH = "/sbin/udevadm"
class XenVEth(PyCoreNetIf):
def __init__(self, node, name, localname, mtu=1500, net=None, start=True, hwaddr=None):
# note that net arg is ignored
PyCoreNetIf.__init__(self, node=node, name=name, mtu=mtu)
self.localname = localname
self.up = False
self.hwaddr = hwaddr
if start:
self.startup()
def startup(self):
cmd = [XM_PATH, "network-attach", self.node.vmname, "vifname=%s" % self.localname, "script=vif-core"]
if self.hwaddr is not None:
cmd.append("mac=%s" % self.hwaddr)
subprocess.check_call(cmd)
subprocess.check_call([constants.IP_BIN, "link", "set", self.localname, "up"])
self.up = True
def shutdown(self):
if not self.up:
return
if self.localname:
if self.hwaddr is not None:
pass
# this should be doable, but some argument isn"t a string
# check_call([XM_PATH, "network-detach", self.node.vmname,
# self.hwaddr])
self.up = False
class XenNode(PyCoreNode):
apitype = NodeTypes.XEN.value
files_to_ignore = frozenset([
# "ipforward.sh",
"quaggaboot.sh",
])
files_redirection = {
"ipforward.sh": "/core-tmp/ipforward.sh",
}
cmds_to_ignore = frozenset([
# "sh ipforward.sh",
# "sh quaggaboot.sh zebra",
# "sh quaggaboot.sh ospfd",
# "sh quaggaboot.sh ospf6d",
"killall zebra",
"killall ospfd",
"killall ospf6d",
"pidof zebra", "pidof ospfd", "pidof ospf6d",
])
def redir_cmd_ipforward(self):
sysctl_file = open(os.path.join(self.mountdir, self.etcdir, "sysctl.conf"), "a")
p1 = subprocess.Popen([AWK_PATH, "/^\/sbin\/sysctl -w/ {print $NF}",
os.path.join(self.nodedir, "core-tmp/ipforward.sh")], stdout=sysctl_file)
p1.wait()
sysctl_file.close()
def redir_cmd_zebra(self):
subprocess.check_call([SED_PATH, "-i", "-e", "s/^zebra=no/zebra=yes/",
os.path.join(self.mountdir, self.etcdir, "quagga/daemons")])
def redir_cmd_ospfd(self):
subprocess.check_call([SED_PATH, "-i", "-e", "s/^ospfd=no/ospfd=yes/",
os.path.join(self.mountdir, self.etcdir, "quagga/daemons")])
def redir_cmd_ospf6d(self):
subprocess.check_call([SED_PATH, "-i", "-e", "s/^ospf6d=no/ospf6d=yes/",
os.path.join(self.mountdir, self.etcdir, "quagga/daemons")])
cmds_redirection = {
"sh ipforward.sh": redir_cmd_ipforward,
"sh quaggaboot.sh zebra": redir_cmd_zebra,
"sh quaggaboot.sh ospfd": redir_cmd_ospfd,
"sh quaggaboot.sh ospf6d": redir_cmd_ospf6d,
}
# CoreNode: no __init__, take from LxcNode & SimpleLxcNode
def __init__(self, session, objid=None, name=None,
nodedir=None, bootsh="boot.sh", start=True, model=None,
vgname=None, ramsize=None, disksize=None,
isofile=None):
# SimpleLxcNode initialization
PyCoreNode.__init__(self, session=session, objid=objid, name=name)
self.nodedir = nodedir
self.model = model
# indicates startup() has been invoked and disk has been initialized
self.up = False
# indicates boot() has been invoked and domU is running
self.booted = False
self.ifindex = 0
self.lock = threading.RLock()
self._netif = {}
# domU name
self.vmname = "c" + str(session.session_id) + "-" + name
# LVM volume group name
self.vgname = self.getconfigitem("vg_name", vgname)
# LVM logical volume name
self.lvname = self.vmname + "-"
# LVM logical volume device path name
self.lvpath = os.path.join("/dev", self.vgname, self.lvname)
self.disksize = self.getconfigitem("disk_size", disksize)
self.ramsize = int(self.getconfigitem("ram_size", ramsize))
self.isofile = self.getconfigitem("iso_file", isofile)
# temporary mount point for paused VM persistent filesystem
self.mountdir = None
self.etcdir = self.getconfigitem("etc_path")
# TODO: remove this temporary hack
self.files_redirection["/usr/local/etc/quagga/Quagga.conf"] = os.path.join(
self.getconfigitem("mount_path"), self.etcdir, "quagga/Quagga.conf")
# LxcNode initialization
# self.makenodedir()
if self.nodedir is None:
self.nodedir = os.path.join(session.session_dir, self.name + ".conf")
self.mountdir = self.nodedir + self.getconfigitem("mount_path")
if not os.path.isdir(self.mountdir):
os.makedirs(self.mountdir)
self.tmpnodedir = True
else:
raise Exception("Xen PVM node requires a temporary nodedir")
self.bootsh = bootsh
if start:
self.startup()
def getconfigitem(self, name, default=None):
"""
Configuration items come from the xen.conf file and/or input from
the GUI, and are stored in the session using the XenConfigManager
object. self.model is used to identify particular profiles
associated with a node type in the GUI.
"""
return self.session.xen.getconfigitem(name=name, model=self.model, node=self, value=default)
# from class LxcNode (also SimpleLxcNode)
def startup(self):
logger.warn("XEN PVM startup() called: preparing disk for %s", self.name)
self.lock.acquire()
try:
if self.up:
raise Exception("already up")
self.createlogicalvolume()
self.createpartitions()
persistdev = self.createfilesystems()
subprocess.check_call([constants.MOUNT_BIN, "-t", "ext4", persistdev, self.mountdir])
self.untarpersistent(tarname=self.getconfigitem("persist_tar_iso"),
iso=True)
self.setrootpassword(pw=self.getconfigitem("root_password"))
self.sethostname(old="UBASE", new=self.name)
self.setupssh(keypath=self.getconfigitem("ssh_key_path"))
self.createvm()
self.up = True
finally:
self.lock.release()
# from class LxcNode (also SimpleLxcNode)
def boot(self):
logger.warn("XEN PVM boot() called")
self.lock.acquire()
if not self.up:
raise Exception("Can't boot VM without initialized disk")
if self.booted:
self.lock.release()
return
self.session.services.bootnodeservices(self)
tarname = self.getconfigitem("persist_tar")
if tarname:
self.untarpersistent(tarname=tarname, iso=False)
try:
subprocess.check_call([constants.UMOUNT_BIN, self.mountdir])
self.unmount_all(self.mountdir)
subprocess.check_call([UDEVADM_PATH, "settle"])
subprocess.check_call([KPARTX_PATH, "-d", self.lvpath])
# time.sleep(5)
# time.sleep(1)
# unpause VM
logger.warn("XEN PVM boot() unpause domU %s", self.vmname)
utils.mutecheck_call([XM_PATH, "unpause", self.vmname])
self.booted = True
finally:
self.lock.release()
def validate(self):
self.session.services.validatenodeservices(self)
# from class LxcNode (also SimpleLxcNode)
def shutdown(self):
logger.warn("XEN PVM shutdown() called")
if not self.up:
return
self.lock.acquire()
try:
if self.up:
# sketch from SimpleLxcNode
for netif in self.netifs():
netif.shutdown()
try:
# RJE XXX what to do here
if self.booted:
utils.mutecheck_call([XM_PATH, "destroy", self.vmname])
self.booted = False
except (OSError, subprocess.CalledProcessError):
# ignore this error too, the VM may have exited already
logger.exception("error during shutdown")
# discard LVM volume
lvm_remove_count = 0
while os.path.exists(self.lvpath):
try:
subprocess.check_call([UDEVADM_PATH, "settle"])
utils.mutecall([LVCHANGE_PATH, "-an", self.lvpath])
lvm_remove_count += 1
utils.mutecall([LVREMOVE_PATH, "-f", self.lvpath])
except OSError:
logger.exception("error during shutdown")
if lvm_remove_count > 1:
logger.warn("XEN PVM shutdown() required %d lvremove executions.", lvm_remove_count)
self._netif.clear()
del self.session
self.up = False
finally:
self.rmnodedir()
self.lock.release()
def createlogicalvolume(self):
"""
Create a logical volume for this Xen domU. Called from startup().
"""
if os.path.exists(self.lvpath):
raise Exception, "LVM volume already exists"
utils.mutecheck_call([LVCREATE_PATH, "--size", self.disksize,
"--name", self.lvname, self.vgname])
def createpartitions(self):
"""
Partition the LVM volume into persistent and swap partitions
using the parted module.
"""
dev = parted.Device(path=self.lvpath)
dev.removeFromCache()
disk = parted.freshDisk(dev, "msdos")
constraint = parted.Constraint(device=dev)
persist_size = int(0.75 * constraint.maxSize)
self.createpartition(device=dev, disk=disk, start=1,
end=persist_size - 1, type="ext4")
self.createpartition(device=dev, disk=disk, start=persist_size,
end=constraint.maxSize - 1, type="linux-swap(v1)")
disk.commit()
def createpartition(self, device, disk, start, end, type):
"""
Create a single partition of the specified type and size and add
it to the disk object, using the parted module.
"""
geo = parted.Geometry(device=device, start=start, end=end)
fs = parted.FileSystem(type=type, geometry=geo)
part = parted.Partition(disk=disk, fs=fs, type=parted.PARTITION_NORMAL, geometry=geo)
constraint = parted.Constraint(exactGeom=geo)
disk.addPartition(partition=part, constraint=constraint)
def createfilesystems(self):
"""
Make an ext4 filesystem and swap space. Return the device name for
the persistent partition so we can mount it.
"""
output = subprocess.Popen([KPARTX_PATH, "-l", self.lvpath],
stdout=subprocess.PIPE).communicate()[0]
lines = output.splitlines()
persistdev = "/dev/mapper/" + lines[0].strip().split(" ")[0].strip()
swapdev = "/dev/mapper/" + lines[1].strip().split(" ")[0].strip()
subprocess.check_call([KPARTX_PATH, "-a", self.lvpath])
utils.mutecheck_call([MKFSEXT4_PATH, "-L", "persist", persistdev])
utils.mutecheck_call([MKSWAP_PATH, "-f", "-L", "swap", swapdev])
return persistdev
def untarpersistent(self, tarname, iso):
"""
Unpack a persistent template tar file to the mounted mount dir.
Uses fsimage library to read from an ISO file.
"""
# filename may use hostname
tarname = tarname.replace("%h", self.name)
if iso:
try:
fs = fsimage.open(self.isofile, 0)
except IOError:
logger.exception("Failed to open ISO file: %s", self.isofile)
return
try:
tardata = fs.open_file(tarname).read()
except IOError:
logger.exception("Failed to open tar file: %s", tarname)
return
finally:
del fs
else:
try:
f = open(tarname)
tardata = f.read()
f.close()
except IOError:
logger.exception("Failed to open tar file: %s", tarname)
return
p = subprocess.Popen([TAR_PATH, "-C", self.mountdir, "--numeric-owner",
"-xf", "-"], stdin=subprocess.PIPE)
p.communicate(input=tardata)
p.wait()
def setrootpassword(self, pw):
"""
Set the root password by updating the shadow password file that
is on the filesystem mounted in the temporary area.
"""
saltedpw = crypt.crypt(pw, "$6$" + base64.b64encode(os.urandom(12)))
subprocess.check_call([SED_PATH, "-i", "-e",
"/^root:/s_^root:\([^:]*\):_root:" + saltedpw + ":_",
os.path.join(self.mountdir, self.etcdir, "shadow")])
def sethostname(self, old, new):
"""
Set the hostname by updating the hostname and hosts files that
reside on the filesystem mounted in the temporary area.
"""
subprocess.check_call([SED_PATH, "-i", "-e", "s/%s/%s/" % (old, new),
os.path.join(self.mountdir, self.etcdir, "hostname")])
subprocess.check_call([SED_PATH, "-i", "-e", "s/%s/%s/" % (old, new),
os.path.join(self.mountdir, self.etcdir, "hosts")])
def setupssh(self, keypath):
"""
Configure SSH access by installing host keys and a system-wide
authorized_keys file.
"""
sshdcfg = os.path.join(self.mountdir, self.etcdir, "ssh/sshd_config")
subprocess.check_call([SED_PATH, "-i", "-e", "s/PermitRootLogin no/PermitRootLogin yes/", sshdcfg])
sshdir = os.path.join(self.getconfigitem("mount_path"), self.etcdir, "ssh")
# backslash slashes for use in sed
sshdir = sshdir.replace("/", "\\/")
subprocess.check_call([SED_PATH, "-i", "-e",
"s/#AuthorizedKeysFile %h\/.ssh\/authorized_keys/" + \
"AuthorizedKeysFile " + sshdir + "\/authorized_keys/",
sshdcfg])
for f in "ssh_host_rsa_key", "ssh_host_rsa_key.pub", "authorized_keys":
src = os.path.join(keypath, f)
dst = os.path.join(self.mountdir, self.etcdir, "ssh", f)
shutil.copy(src, dst)
if f[-3:] != "pub":
os.chmod(dst, 0600)
def createvm(self):
"""
Instantiate a *paused* domU VM
Instantiate it now, so we can add network interfaces,
pause it so we can have the filesystem open for configuration.
"""
args = [XM_PATH, "create", os.devnull, "--paused"]
args.extend(["name=" + self.vmname, "memory=" + str(self.ramsize)])
args.append("disk=tap:aio:" + self.isofile + ",hda,r")
args.append("disk=phy:" + self.lvpath + ",hdb,w")
args.append("bootloader=pygrub")
bootargs = "--kernel=/isolinux/vmlinuz --ramdisk=/isolinux/initrd"
args.append("bootargs=" + bootargs)
for action in ("poweroff", "reboot", "suspend", "crash", "halt"):
args.append("on_%s=destroy" % action)
args.append("extra=" + self.getconfigitem("xm_create_extra"))
utils.mutecheck_call(args)
# from class LxcNode
def privatedir(self, path):
# self.warn("XEN PVM privatedir() called")
# Do nothing, Xen PVM nodes are fully private
pass
# from class LxcNode
def opennodefile(self, filename, mode="w"):
logger.warn("XEN PVM opennodefile() called")
raise Exception("Can't open VM file with opennodefile()")
# from class LxcNode
# open a file on a paused Xen node
def openpausednodefile(self, filename, mode="w"):
dirname, basename = os.path.split(filename)
if not basename:
raise ValueError("no basename for filename: %s" % filename)
if dirname and dirname[0] == "/":
dirname = dirname[1:]
# dirname = dirname.replace("/", ".")
dirname = os.path.join(self.nodedir, dirname)
if not os.path.isdir(dirname):
os.makedirs(dirname, mode=0755)
hostfilename = os.path.join(dirname, basename)
return open(hostfilename, mode)
# from class LxcNode
def nodefile(self, filename, contents, mode=0644):
if filename in self.files_to_ignore:
# self.warn("XEN PVM nodefile(filename=%s) ignored" % [filename])
return
if filename in self.files_redirection:
redirection_filename = self.files_redirection[filename]
logger.warn("XEN PVM nodefile(filename=%s) redirected to %s", filename, redirection_filename)
filename = redirection_filename
logger.warn("XEN PVM nodefile(filename=%s) called", filename)
self.lock.acquire()
if not self.up:
self.lock.release()
raise Exception("Can't access VM file as VM disk isn't ready")
if self.booted:
self.lock.release()
raise Exception("Can't access VM file as VM is already running")
try:
f = self.openpausednodefile(filename, "w")
f.write(contents)
os.chmod(f.name, mode)
f.close()
logger.info("created nodefile: %s; mode: 0%o", f.name, mode)
finally:
self.lock.release()
# from class SimpleLxcNode
def alive(self):
# is VM running?
return False # XXX
def cmd(self, args, wait=True):
cmd_string = string.join(args, " ")
if cmd_string in self.cmds_to_ignore:
# self.warn("XEN PVM cmd(args=[%s]) called and ignored" % cmdAsString)
return 0
if cmd_string in self.cmds_redirection:
self.cmds_redirection[cmd_string](self)
return 0
logger("XEN PVM cmd(args=[%s]) called, but not yet implemented", cmd_string)
return 0
def cmdresult(self, args):
cmd_string = string.join(args, " ")
if cmd_string in self.cmds_to_ignore:
# self.warn("XEN PVM cmd(args=[%s]) called and ignored" % cmdAsString)
return 0, ""
logger.warn("XEN PVM cmdresult(args=[%s]) called, but not yet implemented", cmd_string)
return 0, ""
def popen(self, args):
cmd_string = string.join(args, " ")
logger.warn("XEN PVM popen(args=[%s]) called, but not yet implemented", cmd_string)
return
def icmd(self, args):
cmd_string = string.join(args, " ")
logger.warn("XEN PVM icmd(args=[%s]) called, but not yet implemented", cmd_string)
return
def term(self, sh="/bin/sh"):
logger.warn("XEN PVM term() called, but not yet implemented")
return
def termcmdstring(self, sh="/bin/sh"):
"""
We may add "sudo" to the command string because the GUI runs as a
normal user. Use SSH if control interface is available, otherwise
use Xen console with a keymapping for easy login.
"""
controlifc = None
for ifc in self.netifs():
if hasattr(ifc, "control") and ifc.control is True:
controlifc = ifc
break
cmd = "xterm "
# use SSH if control interface is available
if controlifc:
controlip = controlifc.addrlist[0].split("/")[0]
cmd += "-e ssh root@%s" % controlip
return cmd
# otherwise use "xm console"
# pw = self.getconfigitem("root_password")
# cmd += "-xrm "XTerm*VT100.translations: #override <Key>F1: "
# cmd += "string(\"root\\n\") \\n <Key>F2: string(\"%s\\n\")" " % pw
cmd += "-e sudo %s console %s" % (XM_PATH, self.vmname)
return cmd
def shcmd(self, cmdstr, sh="/bin/sh"):
logger("XEN PVM shcmd(args=[%s]) called, but not yet implemented", cmdstr)
return
def mount(self, source, target):
logger.warn("XEN PVM Nodes can't bind-mount filesystems")
def umount(self, target):
logger.warn("XEN PVM Nodes can't bind-mount filesystems")
def newifindex(self):
self.lock.acquire()
try:
while self.ifindex in self._netif:
self.ifindex += 1
ifindex = self.ifindex
self.ifindex += 1
return ifindex
finally:
self.lock.release()
def getifindex(self, netif):
for ifindex in self._netif:
if self._netif[ifindex] is netif:
return ifindex
return -1
def addnetif(self, netif, ifindex):
logger.warn("XEN PVM addnetif() called")
PyCoreNode.addnetif(self, netif, ifindex)
def delnetif(self, ifindex):
logger.warn("XEN PVM delnetif() called")
PyCoreNode.delnetif(self, ifindex)
def newveth(self, ifindex=None, ifname=None, net=None, hwaddr=None):
logger.warn("XEN PVM newveth(ifindex=%s, ifname=%s) called", ifindex, ifname)
self.lock.acquire()
try:
if ifindex is None:
ifindex = self.newifindex()
if ifname is None:
ifname = "eth%d" % ifindex
sessionid = self.session.short_session_id()
name = "n%s.%s.%s" % (self.objid, ifindex, sessionid)
localname = "n%s.%s.%s" % (self.objid, ifname, sessionid)
ifclass = XenVEth
veth = ifclass(node=self, name=name, localname=localname,
mtu=1500, net=net, hwaddr=hwaddr)
veth.name = ifname
try:
self.addnetif(veth, ifindex)
except:
veth.shutdown()
del veth
raise
return ifindex
finally:
self.lock.release()
def newtuntap(self, ifindex=None, ifname=None, net=None):
logger.warn("XEN PVM newtuntap() called but not implemented")
def sethwaddr(self, ifindex, addr):
self._netif[ifindex].sethwaddr(addr)
if self.up:
pass
# self.cmd([IP_BIN, "link", "set", "dev", self.ifname(ifindex),
# "address", str(addr)])
def addaddr(self, ifindex, addr):
if self.up:
pass
# self.cmd([IP_BIN, "addr", "add", str(addr),
# "dev", self.ifname(ifindex)])
self._netif[ifindex].addaddr(addr)
def deladdr(self, ifindex, addr):
try:
self._netif[ifindex].deladdr(addr)
except ValueError:
logger.exception("trying to delete unknown address: %s", addr)
if self.up:
pass
# self.cmd([IP_BIN, "addr", "del", str(addr),
# "dev", self.ifname(ifindex)])
valid_deladdrtype = ("inet", "inet6", "inet6link")
def delalladdr(self, ifindex, addrtypes=valid_deladdrtype):
addr = self.getaddr(self.ifname(ifindex), rescan=True)
for t in addrtypes:
if t not in self.valid_deladdrtype:
raise ValueError("addr type must be in: " + " ".join(self.valid_deladdrtype))
for a in addr[t]:
self.deladdr(ifindex, a)
# update cached information
self.getaddr(self.ifname(ifindex), rescan=True)
# Xen PVM relies on boot process to bring up links
# def ifup(self, ifindex):
# if self.up:
# self.cmd([IP_BIN, "link", "set", self.ifname(ifindex), "up"])
def newnetif(self, net=None, addrlist=[], hwaddr=None, ifindex=None, ifname=None):
logger.warn("XEN PVM newnetif(ifindex=%s, ifname=%s) called", ifindex, ifname)
self.lock.acquire()
if not self.up:
self.lock.release()
raise Exception("Can't access add veth as VM disk isn't ready")
if self.booted:
self.lock.release()
raise Exception("Can't access add veth as VM is already running")
try:
if nodeutils.is_node(net, NodeTypes.EMANE):
raise Exception("Xen PVM doesn't yet support Emane nets")
# ifindex = self.newtuntap(ifindex = ifindex, ifname = ifname,
# net = net)
# # TUN/TAP is not ready for addressing yet; the device may
# # take some time to appear, and installing it into a
# # namespace after it has been bound removes addressing;
# # save addresses with the interface now
# self.attachnet(ifindex, net)
# netif = self.netif(ifindex)
# netif.sethwaddr(hwaddr)
# for addr in maketuple(addrlist):
# netif.addaddr(addr)
# return ifindex
else:
ifindex = self.newveth(ifindex=ifindex, ifname=ifname,
net=net, hwaddr=hwaddr)
if net is not None:
self.attachnet(ifindex, net)
rulefile = os.path.join(self.getconfigitem("mount_path"),
self.etcdir,
"udev/rules.d/70-persistent-net.rules")
f = self.openpausednodefile(rulefile, "a")
f.write(
"\n# Xen PVM virtual interface #%s %s with MAC address %s\n" % (ifindex, self.ifname(ifindex), hwaddr))
# Using MAC address as we"re now loading PVM net driver "early"
# OLD: Would like to use MAC address, but udev isn"t working with paravirtualized NICs. Perhaps the "set hw address" isn"t triggering a rescan.
f.write(
'SUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*", ATTR{address}=="%s", KERNEL=="eth*", NAME="%s"\n' % (
hwaddr, self.ifname(ifindex)))
# f.write("SUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*", DEVPATH=="/devices/vif-%s/?*", KERNEL=="eth*", NAME="%s"\n" % (ifindex, self.ifname(ifindex)))
f.close()
if hwaddr:
self.sethwaddr(ifindex, hwaddr)
for addr in utils.maketuple(addrlist):
self.addaddr(ifindex, addr)
# self.ifup(ifindex)
return ifindex
finally:
self.lock.release()
def connectnode(self, ifname, othernode, otherifname):
logger.warn("XEN PVM connectnode() called")
# tmplen = 8
# tmp1 = "tmp." + "".join([random.choice(string.ascii_lowercase)
# for x in xrange(tmplen)])
# tmp2 = "tmp." + "".join([random.choice(string.ascii_lowercase)
# for x in xrange(tmplen)])
# check_call([IP_BIN, "link", "add", "name", tmp1,
# "type", "veth", "peer", "name", tmp2])
#
# check_call([IP_BIN, "link", "set", tmp1, "netns", str(self.pid)])
# self.cmd([IP_BIN, "link", "set", tmp1, "name", ifname])
# self.addnetif(PyCoreNetIf(self, ifname), self.newifindex())
#
# check_call([IP_BIN, "link", "set", tmp2, "netns", str(othernode.pid)])
# othernode.cmd([IP_BIN, "link", "set", tmp2, "name", otherifname])
# othernode.addnetif(PyCoreNetIf(othernode, otherifname),
# othernode.newifindex())
def addfile(self, srcname, filename, mode=0644):
self.lock.acquire()
if not self.up:
self.lock.release()
raise Exception("Can't access VM file as VM disk isn't ready")
if self.booted:
self.lock.release()
raise Exception("Can't access VM file as VM is already running")
if filename in self.files_to_ignore:
# self.warn("XEN PVM addfile(filename=%s) ignored" % [filename])
return
if filename in self.files_redirection:
redirection_filename = self.files_redirection[filename]
logger.warn("XEN PVM addfile(filename=%s) redirected to %s", filename, redirection_filename)
filename = redirection_filename
try:
fin = open(srcname, "r")
contents = fin.read()
fin.close()
fout = self.openpausednodefile(filename, "w")
fout.write(contents)
os.chmod(fout.name, mode)
fout.close()
logger.info("created nodefile: %s; mode: 0%o", fout.name, mode)
finally:
self.lock.release()
logger.warn("XEN PVM addfile(filename=%s) called", filename)
# shcmd = "mkdir -p $(dirname "%s") && mv "%s" "%s" && sync" % \
# (filename, srcname, filename)
# self.shcmd(shcmd)
def unmount_all(self, path):
"""
Namespaces inherit the host mounts, so we need to ensure that all
namespaces have unmounted our temporary mount area so that the
kpartx command will succeed.
"""
# Session.bootnodes() already has self.session._objslock
for o in self.session.objects.itervalues():
if not isinstance(o, LxcNode):
continue
o.umount(path)