merged cleanup branch with master

This commit is contained in:
Rod A Santiago 2017-06-19 18:09:28 -07:00
parent 0a91fe7a3e
commit 55a6e2dcef
81 changed files with 11596 additions and 15021 deletions

View file

@ -1,51 +1,43 @@
#
# CORE
# Copyright (c)2011-2012 the Boeing Company.
# See the LICENSE file included in this distribution.
#
'''
xen.py: implementation of the XenNode and XenVEth classes that support
"""
xen.py: implementation of the XenNode and XenVEth classes that support
generating Xen domUs based on an ISO image and persistent configuration area
'''
"""
from core.netns.vnet import *
import base64
import os
import shutil
import string
import subprocess
import sys
import threading
import crypt
from core import constants
from core.coreobj import PyCoreNetIf
from core.coreobj import PyCoreNode
from core.enumerations import NodeTypes
from core.misc import log
from core.misc import nodeutils
from core.misc import utils
from core.netns.vnode import LxcNode
from core.coreobj import PyCoreObj, PyCoreNode, PyCoreNetIf
from core.misc.ipaddr import *
from core.misc.utils import *
from core.constants import *
from core.api import coreapi
from core.netns.vif import TunTap
from core.emane.nodes import EmaneNode
logger = log.get_logger(__name__)
try:
import parted
except ImportError, e:
#print "Failed to load parted Python module required by Xen support."
#print "Error was:", e
raise ImportError
except ImportError:
logger.error("failed to import parted for xen nodes")
import base64
import crypt
import subprocess
try:
import fsimage
except ImportError, e:
except ImportError:
# fix for fsimage under Ubuntu
sys.path.append("/usr/lib/xen-default/lib/python")
try:
import fsimage
except ImportError, e:
#print "Failed to load fsimage Python module required by Xen support."
#print "Error was:", e
raise ImportError
import os
import time
import shutil
import string
except ImportError:
logger.error("failed to import fsimage for xen nodes")
# XXX move these out to config file
AWK_PATH = "/bin/awk"
@ -60,11 +52,12 @@ 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):
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)
PyCoreNetIf.__init__(self, node=node, name=name, mtu=mtu)
self.localname = localname
self.up = False
self.hwaddr = hwaddr
@ -76,8 +69,8 @@ class XenVEth(PyCoreNetIf):
'vifname=%s' % self.localname, 'script=vif-core']
if self.hwaddr is not None:
cmd.append('mac=%s' % self.hwaddr)
check_call(cmd)
check_call([IP_BIN, "link", "set", self.localname, "up"])
subprocess.check_call(cmd)
subprocess.check_call([constants.IP_BIN, "link", "set", self.localname, "up"])
self.up = True
def shutdown(self):
@ -87,28 +80,28 @@ class XenVEth(PyCoreNetIf):
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,
# check_call([XM_PATH, 'network-detach', self.node.vmname,
# self.hwaddr])
self.up = False
class XenNode(PyCoreNode):
apitype = coreapi.CORE_NODE_XEN
apitype = NodeTypes.XEN.value
FilesToIgnore = frozenset([
#'ipforward.sh',
# 'ipforward.sh',
'quaggaboot.sh',
])
FilesRedirection = {
'ipforward.sh' : '/core-tmp/ipforward.sh',
'ipforward.sh': '/core-tmp/ipforward.sh',
}
CmdsToIgnore = frozenset([
#'sh ipforward.sh',
#'sh quaggaboot.sh zebra',
#'sh quaggaboot.sh ospfd',
#'sh quaggaboot.sh ospf6d',
# 'sh ipforward.sh',
# 'sh quaggaboot.sh zebra',
# 'sh quaggaboot.sh ospfd',
# 'sh quaggaboot.sh ospf6d',
'killall zebra',
'killall ospfd',
'killall ospf6d',
@ -116,43 +109,39 @@ class XenNode(PyCoreNode):
])
def RedirCmd_ipforward(self):
sysctlFile = 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=sysctlFile)
sysctlFile = 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=sysctlFile)
p1.wait()
sysctlFile.close()
def RedirCmd_zebra(self):
check_call([SED_PATH, '-i', '-e', 's/^zebra=no/zebra=yes/',
os.path.join(self.mountdir, self.etcdir, 'quagga/daemons')])
subprocess.check_call([SED_PATH, '-i', '-e', 's/^zebra=no/zebra=yes/',
os.path.join(self.mountdir, self.etcdir, 'quagga/daemons')])
def RedirCmd_ospfd(self):
check_call([SED_PATH, '-i', '-e', 's/^ospfd=no/ospfd=yes/',
os.path.join(self.mountdir, self.etcdir, 'quagga/daemons')])
subprocess.check_call([SED_PATH, '-i', '-e', 's/^ospfd=no/ospfd=yes/',
os.path.join(self.mountdir, self.etcdir, 'quagga/daemons')])
def RedirCmd_ospf6d(self):
check_call([SED_PATH, '-i', '-e',
's/^ospf6d=no/ospf6d=yes/',
os.path.join(self.mountdir, self.etcdir, 'quagga/daemons')])
subprocess.check_call([SED_PATH, '-i', '-e',
's/^ospf6d=no/ospf6d=yes/',
os.path.join(self.mountdir, self.etcdir, 'quagga/daemons')])
CmdsRedirection = {
'sh ipforward.sh' : RedirCmd_ipforward,
'sh quaggaboot.sh zebra' : RedirCmd_zebra,
'sh quaggaboot.sh ospfd' : RedirCmd_ospfd,
'sh quaggaboot.sh ospf6d' : RedirCmd_ospf6d,
'sh ipforward.sh': RedirCmd_ipforward,
'sh quaggaboot.sh zebra': RedirCmd_zebra,
'sh quaggaboot.sh ospfd': RedirCmd_ospfd,
'sh quaggaboot.sh ospf6d': RedirCmd_ospf6d,
}
# CoreNode: no __init__, take from LxcNode & SimpleLxcNode
def __init__(self, session, objid = None, name = None,
nodedir = None, bootsh = "boot.sh", verbose = False,
start = True, model = None,
vgname = None, ramsize = None, disksize = None,
isofile = None):
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,
verbose = verbose)
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
@ -180,36 +169,35 @@ class XenNode(PyCoreNode):
# TODO: remove this temporary hack
self.FilesRedirection['/usr/local/etc/quagga/Quagga.conf'] = \
os.path.join(self.getconfigitem('mount_path'), self.etcdir,
'quagga/Quagga.conf')
'quagga/Quagga.conf')
# LxcNode initialization
# self.makenodedir()
if self.nodedir is None:
self.nodedir = \
os.path.join(session.sessiondir, self.name + ".conf")
self.nodedir = os.path.join(session.sessiondir, 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"
raise Exception("Xen PVM node requires a temporary nodedir")
self.tmpnodedir = False
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)
"""
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):
self.warn("XEN PVM startup() called: preparing disk for %s" % self.name)
logger.warn("XEN PVM startup() called: preparing disk for %s" % self.name)
self.lock.acquire()
try:
if self.up:
@ -217,10 +205,10 @@ class XenNode(PyCoreNode):
self.createlogicalvolume()
self.createpartitions()
persistdev = self.createfilesystems()
check_call([MOUNT_BIN, '-t', 'ext4', persistdev, self.mountdir])
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.setrootpassword(pw=self.getconfigitem('root_password'))
self.sethostname(old='UBASE', new=self.name)
self.setupssh(keypath=self.getconfigitem('ssh_key_path'))
self.createvm()
@ -230,11 +218,11 @@ class XenNode(PyCoreNode):
# from class LxcNode (also SimpleLxcNode)
def boot(self):
self.warn("XEN PVM boot() called")
logger.warn("XEN PVM boot() called")
self.lock.acquire()
if not self.up:
raise Exception, "Can't boot VM without initialized disk"
raise Exception("Can't boot VM without initialized disk")
if self.booted:
self.lock.release()
@ -246,18 +234,17 @@ class XenNode(PyCoreNode):
self.untarpersistent(tarname=tarname, iso=False)
try:
check_call([UMOUNT_BIN, self.mountdir])
subprocess.check_call([constants.UMOUNT_BIN, self.mountdir])
self.unmount_all(self.mountdir)
check_call([UDEVADM_PATH, 'settle'])
check_call([KPARTX_PATH, '-d', self.lvpath])
subprocess.check_call([UDEVADM_PATH, 'settle'])
subprocess.check_call([KPARTX_PATH, '-d', self.lvpath])
#time.sleep(5)
#time.sleep(1)
# time.sleep(5)
# time.sleep(1)
# unpause VM
if self.verbose:
self.warn("XEN PVM boot() unpause domU %s" % self.vmname)
mutecheck_call([XM_PATH, 'unpause', self.vmname])
logger.warn("XEN PVM boot() unpause domU %s" % self.vmname)
utils.mutecheck_call([XM_PATH, 'unpause', self.vmname])
self.booted = True
finally:
@ -265,10 +252,10 @@ class XenNode(PyCoreNode):
def validate(self):
self.session.services.validatenodeservices(self)
# from class LxcNode (also SimpleLxcNode)
def shutdown(self):
self.warn("XEN PVM shutdown() called")
logger.warn("XEN PVM shutdown() called")
if not self.up:
return
self.lock.acquire()
@ -281,27 +268,25 @@ class XenNode(PyCoreNode):
try:
# RJE XXX what to do here
if self.booted:
mutecheck_call([XM_PATH, 'destroy', self.vmname])
utils.mutecheck_call([XM_PATH, 'destroy', self.vmname])
self.booted = False
except OSError:
pass
except subprocess.CalledProcessError:
except (OSError, subprocess.CalledProcessError):
# ignore this error too, the VM may have exited already
pass
logger.exception("error during shutdown")
# discard LVM volume
lvmRemoveCount = 0
while os.path.exists(self.lvpath):
try:
check_call([UDEVADM_PATH, 'settle'])
mutecall([LVCHANGE_PATH, '-an', self.lvpath])
subprocess.check_call([UDEVADM_PATH, 'settle'])
utils.mutecall([LVCHANGE_PATH, '-an', self.lvpath])
lvmRemoveCount += 1
mutecall([LVREMOVE_PATH, '-f', self.lvpath])
utils.mutecall([LVREMOVE_PATH, '-f', self.lvpath])
except OSError:
pass
if (lvmRemoveCount > 1):
self.warn("XEN PVM shutdown() required %d lvremove " \
"executions." % lvmRemoveCount)
logger.exception("error during shutdown")
if lvmRemoveCount > 1:
logger.warn("XEN PVM shutdown() required %d lvremove executions." % lvmRemoveCount)
self._netif.clear()
del self.session
@ -313,117 +298,124 @@ class XenNode(PyCoreNode):
self.lock.release()
def createlogicalvolume(self):
''' Create a logical volume for this Xen domU. Called from startup().
'''
"""
Create a logical volume for this Xen domU. Called from startup().
"""
if os.path.exists(self.lvpath):
raise Exception, "LVM volume already exists"
mutecheck_call([LVCREATE_PATH, '--size', self.disksize,
'--name', self.lvname, self.vgname])
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.
'''
"""
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);
persist_size = int(0.75 * constraint.maxSize)
self.createpartition(device=dev, disk=disk, start=1,
end=(persist_size - 1) , type="ext4")
end=persist_size - 1, type="ext4")
self.createpartition(device=dev, disk=disk, start=persist_size,
end=(constraint.maxSize - 1) , type="linux-swap(v1)")
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.
'''
"""
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)
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.
'''
"""
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()
check_call([KPARTX_PATH, '-a', self.lvpath])
mutecheck_call([MKFSEXT4_PATH, '-L', 'persist', persistdev])
mutecheck_call([MKSWAP_PATH, '-f', '-L', 'swap', swapdev])
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.
'''
tarname = tarname.replace('%h', self.name) # filename may use hostname
"""
Unpack a persistent template tar file to the mounted mount dir.
Uses fsimage library to read from an ISO file.
"""
tarname = tarname.replace('%h', self.name) # filename may use hostname
if iso:
try:
fs = fsimage.open(self.isofile, 0)
except IOError, e:
self.warn("Failed to open ISO file: %s (%s)" % (self.isofile,e))
except IOError:
logger.exception("Failed to open ISO file: %s", self.isofile)
return
try:
tardata = fs.open_file(tarname).read();
except IOError, e:
self.warn("Failed to open tar file: %s (%s)" % (tarname, e))
tardata = fs.open_file(tarname).read()
except IOError:
logger.exception("Failed to open tar file: %s", tarname)
return
finally:
del fs;
del fs
else:
try:
f = open(tarname)
tardata = f.read()
f.close()
except IOError, e:
self.warn("Failed to open tar file: %s (%s)" % (tarname, e))
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)
'-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)))
check_call([SED_PATH, '-i', '-e',
'/^root:/s_^root:\([^:]*\):_root:' + saltedpw + ':_',
os.path.join(self.mountdir, self.etcdir, 'shadow')])
"""
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.
'''
check_call([SED_PATH, '-i', '-e', 's/%s/%s/' % (old, new),
os.path.join(self.mountdir, self.etcdir, 'hostname')])
check_call([SED_PATH, '-i', '-e', 's/%s/%s/' % (old, new),
os.path.join(self.mountdir, self.etcdir, 'hosts')])
"""
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.
'''
"""
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')
check_call([SED_PATH, '-i', '-e',
's/PermitRootLogin no/PermitRootLogin yes/', sshdcfg])
subprocess.check_call([SED_PATH, '-i', '-e',
's/PermitRootLogin no/PermitRootLogin yes/', sshdcfg])
sshdir = os.path.join(self.getconfigitem('mount_path'), self.etcdir,
'ssh')
sshdir = sshdir.replace('/','\\/') # backslash slashes for use in sed
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'):
sshdir = sshdir.replace('/', '\\/') # backslash slashes for use in sed
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)
@ -431,10 +423,11 @@ class XenNode(PyCoreNode):
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.
'''
"""
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')
@ -445,110 +438,109 @@ class XenNode(PyCoreNode):
for action in ('poweroff', 'reboot', 'suspend', 'crash', 'halt'):
args.append('on_%s=destroy' % action)
args.append('extra=' + self.getconfigitem('xm_create_extra'))
mutecheck_call(args)
utils.mutecheck_call(args)
# from class LxcNode
def privatedir(self, path):
#self.warn("XEN PVM privatedir() called")
# self.warn("XEN PVM privatedir() called")
# Do nothing, Xen PVM nodes are fully private
pass
# from class LxcNode
def opennodefile(self, filename, mode = "w"):
self.warn("XEN PVM opennodefile() called")
raise Exception, "Can't open VM file with opennodefile()"
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"):
def openpausednodefile(self, filename, mode="w"):
dirname, basename = os.path.split(filename)
if not basename:
raise ValueError, "no basename for filename: " + filename
if dirname and dirname[0] == "/":
dirname = dirname[1:]
#dirname = dirname.replace("/", ".")
# dirname = dirname.replace("/", ".")
dirname = os.path.join(self.nodedir, dirname)
if not os.path.isdir(dirname):
os.makedirs(dirname, mode = 0755)
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):
def nodefile(self, filename, contents, mode=0644):
if filename in self.FilesToIgnore:
#self.warn("XEN PVM nodefile(filename=%s) ignored" % [filename])
# self.warn("XEN PVM nodefile(filename=%s) ignored" % [filename])
return
if filename in self.FilesRedirection:
redirFilename = self.FilesRedirection[filename]
self.warn("XEN PVM nodefile(filename=%s) redirected to %s" % (filename, redirFilename))
logger.warn("XEN PVM nodefile(filename=%s) redirected to %s" % (filename, redirFilename))
filename = redirFilename
self.warn("XEN PVM nodefile(filename=%s) called" % [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"
return
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"
return
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()
self.info("created nodefile: '%s'; mode: 0%o" % (f.name, mode))
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
return False # XXX
def cmd(self, args, wait = True):
def cmd(self, args, wait=True):
cmdAsString = string.join(args, ' ')
if cmdAsString in self.CmdsToIgnore:
#self.warn("XEN PVM cmd(args=[%s]) called and ignored" % cmdAsString)
# self.warn("XEN PVM cmd(args=[%s]) called and ignored" % cmdAsString)
return 0
if cmdAsString in self.CmdsRedirection:
self.CmdsRedirection[cmdAsString](self)
return 0
self.warn("XEN PVM cmd(args=[%s]) called, but not yet implemented" % cmdAsString)
return 0
logger("XEN PVM cmd(args=[%s]) called, but not yet implemented" % cmdAsString)
return 0
def cmdresult(self, args):
cmdAsString = string.join(args, ' ')
if cmdAsString in self.CmdsToIgnore:
#self.warn("XEN PVM cmd(args=[%s]) called and ignored" % cmdAsString)
return (0, "")
self.warn("XEN PVM cmdresult(args=[%s]) called, but not yet implemented" % cmdAsString)
return (0, "")
# 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" % cmdAsString)
return 0, ""
def popen(self, args):
cmdAsString = string.join(args, ' ')
self.warn("XEN PVM popen(args=[%s]) called, but not yet implemented" % cmdAsString)
logger.warn("XEN PVM popen(args=[%s]) called, but not yet implemented" % cmdAsString)
return
def icmd(self, args):
cmdAsString = string.join(args, ' ')
self.warn("XEN PVM icmd(args=[%s]) called, but not yet implemented" % cmdAsString)
logger.warn("XEN PVM icmd(args=[%s]) called, but not yet implemented" % cmdAsString)
return
def term(self, sh = "/bin/sh"):
self.warn("XEN PVM term() called, but not yet implemented")
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.
'''
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 == True:
@ -560,33 +552,22 @@ class XenNode(PyCoreNode):
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
# 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"):
self.warn("XEN PVM shcmd(args=[%s]) called, but not yet implemented" % cmdstr)
def shcmd(self, cmdstr, sh="/bin/sh"):
logger("XEN PVM shcmd(args=[%s]) called, but not yet implemented" % cmdstr)
return
# from class SimpleLxcNode
def info(self, msg):
if self.verbose:
print "%s: %s" % (self.name, msg)
sys.stdout.flush()
# from class SimpleLxcNode
def warn(self, msg):
print >> sys.stderr, "%s: %s" % (self.name, msg)
sys.stderr.flush()
def mount(self, source, target):
self.warn("XEN PVM Nodes can't bind-mount filesystems")
logger.warn("XEN PVM Nodes can't bind-mount filesystems")
def umount(self, target):
self.warn("XEN PVM Nodes can't bind-mount filesystems")
logger.warn("XEN PVM Nodes can't bind-mount filesystems")
def newifindex(self):
self.lock.acquire()
@ -606,16 +587,16 @@ class XenNode(PyCoreNode):
return -1
def addnetif(self, netif, ifindex):
self.warn("XEN PVM addnetif() called")
logger.warn("XEN PVM addnetif() called")
PyCoreNode.addnetif(self, netif, ifindex)
def delnetif(self, ifindex):
self.warn("XEN PVM delnetif() called")
logger.warn("XEN PVM delnetif() called")
PyCoreNode.delnetif(self, ifindex)
def newveth(self, ifindex = None, ifname = None, net = None, hwaddr = None):
self.warn("XEN PVM newveth(ifindex=%s, ifname=%s) called" %
(ifindex, ifname))
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:
@ -623,12 +604,12 @@ class XenNode(PyCoreNode):
ifindex = self.newifindex()
if ifname is None:
ifname = "eth%d" % ifindex
sessionid = self.session.shortsessionid()
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 = ifclass(node=self, name=name, localname=localname,
mtu=1500, net=net, hwaddr=hwaddr)
veth.name = ifname
try:
@ -641,14 +622,14 @@ class XenNode(PyCoreNode):
finally:
self.lock.release()
def newtuntap(self, ifindex = None, ifname = None, net = None):
self.warn("XEN PVM newtuntap() called but not implemented")
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),
# self.cmd([IP_BIN, "link", "set", "dev", self.ifname(ifindex),
# "address", str(addr)])
def addaddr(self, ifindex, addr):
@ -662,49 +643,49 @@ class XenNode(PyCoreNode):
try:
self._netif[ifindex].deladdr(addr)
except ValueError:
self.warn("trying to delete unknown address: %s" % addr)
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)
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)
" ".join(self.valid_deladdrtype)
for a in addr[t]:
self.deladdr(ifindex, a)
# update cached information
self.getaddr(self.ifname(ifindex), rescan = True)
self.getaddr(self.ifname(ifindex), rescan=True)
# Xen PVM relies on boot process to bring up links
#def ifup(self, ifindex):
# 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):
self.warn("XEN PVM newnetif(ifindex=%s, ifname=%s) called" %
(ifindex, ifname))
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"
return
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"
return
raise Exception("Can't access add veth as VM is already running")
try:
if isinstance(net, EmaneNode):
raise Exception, "Xen PVM doesn't yet support Emane nets"
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)
@ -719,8 +700,8 @@ class XenNode(PyCoreNode):
# netif.addaddr(addr)
# return ifindex
else:
ifindex = self.newveth(ifindex = ifindex, ifname = ifname,
net = net, hwaddr = hwaddr)
ifindex = self.newveth(ifindex=ifindex, ifname=ifname,
net=net, hwaddr=hwaddr)
if net is not None:
self.attachnet(ifindex, net)
@ -728,24 +709,27 @@ class XenNode(PyCoreNode):
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))
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.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 maketuple(addrlist):
for addr in utils.maketuple(addrlist):
self.addaddr(ifindex, addr)
#self.ifup(ifindex)
# self.ifup(ifindex)
return ifindex
finally:
self.lock.release()
def connectnode(self, ifname, othernode, otherifname):
self.warn("XEN PVM connectnode() called")
logger.warn("XEN PVM connectnode() called")
# tmplen = 8
# tmp1 = "tmp." + "".join([random.choice(string.ascii_lowercase)
@ -768,21 +752,19 @@ class XenNode(PyCoreNode):
self.lock.acquire()
if not self.up:
self.lock.release()
raise Exception, "Can't access VM file as VM disk isn't ready"
return
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"
return
raise Exception("Can't access VM file as VM is already running")
if filename in self.FilesToIgnore:
#self.warn("XEN PVM addfile(filename=%s) ignored" % [filename])
# self.warn("XEN PVM addfile(filename=%s) ignored" % [filename])
return
if filename in self.FilesRedirection:
redirFilename = self.FilesRedirection[filename]
self.warn("XEN PVM addfile(filename=%s) redirected to %s" % (filename, redirFilename))
logger.warn("XEN PVM addfile(filename=%s) redirected to %s" % (filename, redirFilename))
filename = redirFilename
try:
@ -794,24 +776,24 @@ class XenNode(PyCoreNode):
fout.write(contents)
os.chmod(fout.name, mode)
fout.close()
self.info("created nodefile: '%s'; mode: 0%o" % (fout.name, mode))
logger.info("created nodefile: '%s'; mode: 0%o" % (fout.name, mode))
finally:
self.lock.release()
self.warn("XEN PVM addfile(filename=%s) called" % [filename])
logger.warn("XEN PVM addfile(filename=%s) called" % [filename])
#shcmd = "mkdir -p $(dirname '%s') && mv '%s' '%s' && sync" % \
# shcmd = "mkdir -p $(dirname '%s') && mv '%s' '%s' && sync" % \
# (filename, srcname, filename)
#self.shcmd(shcmd)
# 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.
'''
"""
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.objs():
for o in self.session.objects.itervalues():
if not isinstance(o, LxcNode):
continue
o.umount(path)