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)

View file

@ -1,11 +1,4 @@
#
# CORE
# Copyright (c)2011-2012 the Boeing Company.
# See the LICENSE file included in this distribution.
#
# author: Jeff Ahrenholz <jeffrey.m.ahrenholz@boeing.com>
#
'''
"""
xenconfig.py: Implementation of the XenConfigManager class for managing
configurable items for XenNodes.
@ -17,72 +10,93 @@ Node type config: XenConfigManager.configs[0] = (type='mytype', values)
All nodes of this type have this config.
Node-specific config: XenConfigManager.configs[nodenumber] = (type, values)
The node having this specific number has this config.
'''
"""
import sys, os, threading, subprocess, time, string
import ConfigParser
from xml.dom.minidom import parseString, Document
from core.constants import *
import os
import string
from core import constants
from core.api import coreapi
from core.conf import ConfigurableManager, Configurable
from core.conf import Configurable
from core.conf import ConfigurableManager
from core.enumerations import ConfigDataTypes
from core.enumerations import ConfigFlags
from core.enumerations import ConfigTlvs
from core.enumerations import RegisterTlvs
from core.misc import log
logger = log.get_logger(__name__)
class XenConfigManager(ConfigurableManager):
''' Xen controller object. Lives in a Session instance and is used for
building Xen profiles.
'''
_name = "xen"
_type = coreapi.CORE_TLV_REG_EMULSRV
"""
Xen controller object. Lives in a Session instance and is used for
building Xen profiles.
"""
name = "xen"
config_type = RegisterTlvs.EMULATION_SERVER.value
def __init__(self, session):
ConfigurableManager.__init__(self, session)
self.verbose = self.session.getcfgitembool('verbose', False)
self.default_config = XenDefaultConfig(session, objid=None)
"""
Creates a XenConfigManager instance.
:param core.session.Session session: session this manager is tied to
:return: nothing
"""
ConfigurableManager.__init__(self)
self.default_config = XenDefaultConfig(session, object_id=None)
self.loadconfigfile()
def setconfig(self, nodenum, conftype, values):
''' add configuration values for a node to a dictionary; values are
usually received from a Configuration Message, and may refer to a
node for which no object exists yet
'''
if nodenum is None:
nodenum = 0 # used for storing the global default config
"""
add configuration values for a node to a dictionary; values are
usually received from a Configuration Message, and may refer to a
node for which no object exists yet
"""
if nodenum is None:
nodenum = 0 # used for storing the global default config
return ConfigurableManager.setconfig(self, nodenum, conftype, values)
def getconfig(self, nodenum, conftype, defaultvalues):
''' get configuration values for a node; if the values don't exist in
our dictionary then return the default values supplied; if conftype
is None then we return a match on any conftype.
'''
if nodenum is None:
nodenum = 0 # used for storing the global default config
return ConfigurableManager.getconfig(self, nodenum, conftype,
defaultvalues)
"""
get configuration values for a node; if the values don't exist in
our dictionary then return the default values supplied; if conftype
is None then we return a match on any conftype.
"""
if nodenum is None:
nodenum = 0 # used for storing the global default config
return ConfigurableManager.getconfig(self, nodenum, conftype, defaultvalues)
def clearconfig(self, nodenum):
''' remove configuration values for a node
'''
"""
remove configuration values for a node
"""
ConfigurableManager.clearconfig(self, nodenum)
if 0 in self.configs:
self.configs.pop(0)
def configure(self, session, msg):
''' Handle configuration messages for global Xen config.
'''
return self.default_config.configure(self, msg)
def configure(self, session, config_data):
"""
Handle configuration messages for global Xen config.
:param core.conf.ConfigData config_data: configuration data for carrying out a configuration
"""
return self.default_config.configure(self, config_data)
def loadconfigfile(self, filename=None):
''' Load defaults from the /etc/core/xen.conf file into dict object.
'''
"""
Load defaults from the /etc/core/xen.conf file into dict object.
"""
if filename is None:
filename = os.path.join(CORE_CONF_DIR, 'xen.conf')
filename = os.path.join(constants.CORE_CONF_DIR, 'xen.conf')
cfg = ConfigParser.SafeConfigParser()
if filename not in cfg.read(filename):
self.session.warn("unable to read Xen config file: %s" % filename)
logger.warn("unable to read Xen config file: %s" % filename)
return
section = "xen"
if not cfg.has_section(section):
self.session.warn("%s is missing a xen section!" % filename)
logger.warn("%s is missing a xen section!" % filename)
return
self.configfile = dict(cfg.items(section))
# populate default config items from config file entries
@ -92,13 +106,14 @@ class XenConfigManager(ConfigurableManager):
if names[i] in self.configfile:
vals[i] = self.configfile[names[i]]
# this sets XenConfigManager.configs[0] = (type='xen', vals)
self.setconfig(None, self.default_config._name, vals)
self.setconfig(None, self.default_config.name, vals)
def getconfigitem(self, name, model=None, node=None, value=None):
''' Get a config item of the given name, first looking for node-specific
configuration, then model specific, and finally global defaults.
If a value is supplied, it will override any stored config.
'''
"""
Get a config item of the given name, first looking for node-specific
configuration, then model specific, and finally global defaults.
If a value is supplied, it will override any stored config.
"""
if value is not None:
return value
n = None
@ -111,8 +126,8 @@ class XenConfigManager(ConfigurableManager):
defaultvalues=None)
if v is None:
# get item from default config for the machine type
(t, v) = self.getconfig(nodenum=None,
conftype=self.default_config._name,
(t, v) = self.getconfig(nodenum=None,
conftype=self.default_config.name,
defaultvalues=None)
confignames = self.default_config.getnames()
@ -124,142 +139,136 @@ class XenConfigManager(ConfigurableManager):
if name in self.configfile:
return self.configfile[name]
else:
#self.warn("missing config item '%s'" % name)
# logger.warn("missing config item '%s'" % name)
return None
class XenConfig(Configurable):
''' Manage Xen configuration profiles.
'''
@classmethod
def configure(cls, xen, msg):
''' Handle configuration messages for setting up a model.
Similar to Configurable.configure(), but considers opaque data
for indicating node types.
'''
reply = None
nodenum = msg.gettlv(coreapi.CORE_TLV_CONF_NODE)
objname = msg.gettlv(coreapi.CORE_TLV_CONF_OBJ)
conftype = msg.gettlv(coreapi.CORE_TLV_CONF_TYPE)
opaque = msg.gettlv(coreapi.CORE_TLV_CONF_OPAQUE)
"""
Manage Xen configuration profiles.
"""
nodetype = objname
@classmethod
def configure(cls, xen, config_data):
"""
Handle configuration messages for setting up a model.
Similar to Configurable.configure(), but considers opaque data
for indicating node types.
:param xen: xen instance to configure
:param core.conf.ConfigData config_data: configuration data for carrying out a configuration
"""
reply = None
node_id = config_data.node
object_name = config_data.object
config_type = config_data.type
opaque = config_data.opaque
values_str = config_data.data_values
nodetype = object_name
if opaque is not None:
opaque_items = opaque.split(':')
if len(opaque_items) != 2:
xen.warn("xen config: invalid opaque data in conf message")
logger.warn("xen config: invalid opaque data in conf message")
return None
nodetype = opaque_items[1]
if xen.verbose:
xen.info("received configure message for %s" % nodetype)
if conftype == coreapi.CONF_TYPE_FLAGS_REQUEST:
if xen.verbose:
xen.info("replying to configure request for %s " % nodetype)
logger.info("received configure message for %s", nodetype)
if config_type == ConfigFlags.REQUEST.value:
logger.info("replying to configure request for %s " % nodetype)
# when object name is "all", the reply to this request may be None
# if this node has not been configured for this model; otherwise we
# reply with the defaults for this model
if objname == "all":
typeflags = coreapi.CONF_TYPE_FLAGS_UPDATE
if object_name == "all":
typeflags = ConfigFlags.UPDATE.value
else:
typeflags = coreapi.CONF_TYPE_FLAGS_NONE
values = xen.getconfig(nodenum, nodetype, defaultvalues=None)[1]
typeflags = ConfigFlags.NONE.value
values = xen.getconfig(node_id, nodetype, defaultvalues=None)[1]
if values is None:
# get defaults from default "xen" config which includes
# settings from both cls._confdefaultvalues and xen.conf
# settings from both cls._confdefaultvalues and xen.conf
defaults = cls.getdefaultvalues()
values = xen.getconfig(nodenum, cls._name, defaults)[1]
values = xen.getconfig(node_id, cls.name, defaults)[1]
if values is None:
return None
# reply with config options
if nodenum is None:
nodenum = 0
reply = cls.toconfmsg(0, nodenum, typeflags, nodetype, values)
elif conftype == coreapi.CONF_TYPE_FLAGS_RESET:
if objname == "all":
xen.clearconfig(nodenum)
#elif conftype == coreapi.CONF_TYPE_FLAGS_UPDATE:
if node_id is None:
node_id = 0
reply = cls.config_data(0, node_id, typeflags, nodetype, values)
elif config_type == ConfigFlags.RESET.value:
if object_name == "all":
xen.clearconfig(node_id)
# elif conftype == coreapi.CONF_TYPE_FLAGS_UPDATE:
else:
# store the configuration values for later use, when the XenNode
# object has been created
if objname is None:
xen.info("no configuration object for node %s" % nodenum)
if object_name is None:
logger.info("no configuration object for node %s" % node_id)
return None
values_str = msg.gettlv(coreapi.CORE_TLV_CONF_VALUES)
if values_str is None:
# use default or preconfigured values
defaults = cls.getdefaultvalues()
values = xen.getconfig(nodenum, cls._name, defaults)[1]
values = xen.getconfig(node_id, cls.name, defaults)[1]
else:
# use new values supplied from the conf message
values = values_str.split('|')
xen.setconfig(nodenum, nodetype, values)
xen.setconfig(node_id, nodetype, values)
return reply
@classmethod
def toconfmsg(cls, flags, nodenum, typeflags, nodetype, values):
''' Convert this class to a Config API message. Some TLVs are defined
by the class, but node number, conf type flags, and values must
be passed in.
'''
def config_data(cls, flags, node_id, type_flags, nodetype, values):
"""
Convert this class to a Config API message. Some TLVs are defined
by the class, but node number, conf type flags, and values must
be passed in.
"""
values_str = string.join(values, '|')
tlvdata = ""
tlvdata += coreapi.CoreConfTlv.pack(coreapi.CORE_TLV_CONF_NODE, nodenum)
tlvdata += coreapi.CoreConfTlv.pack(coreapi.CORE_TLV_CONF_OBJ,
cls._name)
tlvdata += coreapi.CoreConfTlv.pack(coreapi.CORE_TLV_CONF_TYPE,
typeflags)
datatypes = tuple( map(lambda x: x[1], cls._confmatrix) )
tlvdata += coreapi.CoreConfTlv.pack(coreapi.CORE_TLV_CONF_DATA_TYPES,
datatypes)
tlvdata += coreapi.CoreConfTlv.pack(coreapi.CORE_TLV_CONF_VALUES,
values_str)
captions = reduce( lambda a,b: a + '|' + b, \
map(lambda x: x[4], cls._confmatrix))
tlvdata += coreapi.CoreConfTlv.pack(coreapi.CORE_TLV_CONF_CAPTIONS,
captions)
possiblevals = reduce( lambda a,b: a + '|' + b, \
map(lambda x: x[3], cls._confmatrix))
tlvdata += coreapi.CoreConfTlv.pack(
coreapi.CORE_TLV_CONF_POSSIBLE_VALUES, possiblevals)
if cls._bitmap is not None:
tlvdata += coreapi.CoreConfTlv.pack(coreapi.CORE_TLV_CONF_BITMAP,
cls._bitmap)
if cls._confgroups is not None:
tlvdata += coreapi.CoreConfTlv.pack(coreapi.CORE_TLV_CONF_GROUPS,
cls._confgroups)
opaque = "%s:%s" % (cls._name, nodetype)
tlvdata += coreapi.CoreConfTlv.pack(coreapi.CORE_TLV_CONF_OPAQUE,
opaque)
tlvdata += coreapi.CoreConfigTlv.pack(ConfigTlvs.NODE.value, node_id)
tlvdata += coreapi.CoreConfigTlv.pack(ConfigTlvs.OBJECT.value, cls.name)
tlvdata += coreapi.CoreConfigTlv.pack(ConfigTlvs.TYPE.value, type_flags)
datatypes = tuple(map(lambda x: x[1], cls.config_matrix))
tlvdata += coreapi.CoreConfigTlv.pack(ConfigTlvs.DATA_TYPES.value, datatypes)
tlvdata += coreapi.CoreConfigTlv.pack(ConfigTlvs.VALUES.value, values_str)
captions = reduce(lambda a, b: a + '|' + b, map(lambda x: x[4], cls.config_matrix))
tlvdata += coreapi.CoreConfigTlv.pack(ConfigTlvs.CAPTIONS, captions)
possiblevals = reduce(lambda a, b: a + '|' + b, map(lambda x: x[3], cls.config_matrix))
tlvdata += coreapi.CoreConfigTlv.pack(ConfigTlvs.POSSIBLE_VALUES.value, possiblevals)
if cls.bitmap is not None:
tlvdata += coreapi.CoreConfigTlv.pack(ConfigTlvs.BITMAP.value, cls.bitmap)
if cls.config_groups is not None:
tlvdata += coreapi.CoreConfigTlv.pack(ConfigTlvs.GROUPS.value, cls.config_groups)
opaque = "%s:%s" % (cls.name, nodetype)
tlvdata += coreapi.CoreConfigTlv.pack(ConfigTlvs.OPAQUE.value, opaque)
msg = coreapi.CoreConfMessage.pack(flags, tlvdata)
return msg
class XenDefaultConfig(XenConfig):
''' Global default Xen configuration options.
'''
_name = "xen"
"""
Global default Xen configuration options.
"""
name = "xen"
# Configuration items:
# ('name', 'type', 'default', 'possible-value-list', 'caption')
_confmatrix = [
('ram_size', coreapi.CONF_DATA_TYPE_STRING, '256', '',
config_matrix = [
('ram_size', ConfigDataTypes.STRING.value, '256', '',
'ram size (MB)'),
('disk_size', coreapi.CONF_DATA_TYPE_STRING, '256M', '',
('disk_size', ConfigDataTypes.STRING.value, '256M', '',
'disk size (use K/M/G suffix)'),
('iso_file', coreapi.CONF_DATA_TYPE_STRING, '', '',
('iso_file', ConfigDataTypes.STRING.value, '', '',
'iso file'),
('mount_path', coreapi.CONF_DATA_TYPE_STRING, '', '',
('mount_path', ConfigDataTypes.STRING.value, '', '',
'mount path'),
('etc_path', coreapi.CONF_DATA_TYPE_STRING, '', '',
('etc_path', ConfigDataTypes.STRING.value, '', '',
'etc path'),
('persist_tar_iso', coreapi.CONF_DATA_TYPE_STRING, '', '',
('persist_tar_iso', ConfigDataTypes.STRING.value, '', '',
'iso persist tar file'),
('persist_tar', coreapi.CONF_DATA_TYPE_STRING, '', '',
('persist_tar', ConfigDataTypes.STRING.value, '', '',
'persist tar file'),
('root_password', coreapi.CONF_DATA_TYPE_STRING, 'password', '',
('root_password', ConfigDataTypes.STRING.value, 'password', '',
'root password'),
]
_confgroups = "domU properties:1-%d" % len(_confmatrix)
]
config_groups = "domU properties:1-%d" % len(config_matrix)