mirror of
https://github.com/xen-project/xen.git
synced 2026-10-29 18:50:05 +01:00
Merge latest xen-unstable into xen-ia64-unstable
This commit is contained in:
commit
c179fd9015
391 files changed
+48089
-2085
No files matched your search
@@ -44,7 +44,8 @@ setup(name = 'xen',
|
||||
'xen.web',
|
||||
'xen.sv',
|
||||
|
||||
'xen.xend.tests'
|
||||
'xen.xend.tests',
|
||||
'xen.xm.tests'
|
||||
],
|
||||
ext_package = "xen.lowlevel",
|
||||
ext_modules = [ xc, xs ]
|
||||
|
||||
@@ -438,19 +438,20 @@ static PyObject *pyxc_vmx_build(PyObject *self,
|
||||
char *image;
|
||||
int control_evtchn, store_evtchn;
|
||||
int vcpus = 1;
|
||||
int lapic = 0;
|
||||
int memsize;
|
||||
unsigned long store_mfn = 0;
|
||||
|
||||
static char *kwd_list[] = { "dom", "control_evtchn", "store_evtchn",
|
||||
"memsize", "image", "vcpus", NULL };
|
||||
"memsize", "image", "lapic", "vcpus", NULL };
|
||||
|
||||
if ( !PyArg_ParseTupleAndKeywords(args, kwds, "iiiisi", kwd_list,
|
||||
if ( !PyArg_ParseTupleAndKeywords(args, kwds, "iiiisii", kwd_list,
|
||||
&dom, &control_evtchn, &store_evtchn,
|
||||
&memsize, &image, &vcpus) )
|
||||
&memsize, &image, &lapic, &vcpus) )
|
||||
return NULL;
|
||||
|
||||
if ( xc_vmx_build(xc->xc_handle, dom, memsize, image, control_evtchn,
|
||||
vcpus, store_evtchn, &store_mfn) != 0 )
|
||||
lapic, vcpus, store_evtchn, &store_mfn) != 0 )
|
||||
return PyErr_SetFromErrno(xc_error);
|
||||
|
||||
return Py_BuildValue("{s:i}", "store_mfn", store_mfn);
|
||||
@@ -857,6 +858,29 @@ static PyObject *pyxc_domain_memory_increase_reservation(PyObject *self,
|
||||
return zero;
|
||||
}
|
||||
|
||||
static PyObject *pyxc_domain_ioport_permission(PyObject *self,
|
||||
PyObject *args,
|
||||
PyObject *kwds)
|
||||
{
|
||||
XcObject *xc = (XcObject *)self;
|
||||
uint32_t dom;
|
||||
int first_port, nr_ports, allow_access, ret;
|
||||
|
||||
static char *kwd_list[] = { "dom", "first_port", "nr_ports", "allow_access", NULL };
|
||||
|
||||
if ( !PyArg_ParseTupleAndKeywords(args, kwds, "iiii", kwd_list,
|
||||
&dom, &first_port, &nr_ports, &allow_access) )
|
||||
return NULL;
|
||||
|
||||
ret = xc_domain_ioport_permission(
|
||||
xc->xc_handle, dom, first_port, nr_ports, allow_access);
|
||||
if ( ret != 0 )
|
||||
return PyErr_SetFromErrno(xc_error);
|
||||
|
||||
Py_INCREF(zero);
|
||||
return zero;
|
||||
}
|
||||
|
||||
static PyMethodDef pyxc_methods[] = {
|
||||
{ "handle",
|
||||
(PyCFunction)pyxc_handle,
|
||||
@@ -1126,6 +1150,16 @@ static PyMethodDef pyxc_methods[] = {
|
||||
" mem_kb [long]: .\n"
|
||||
"Returns: [int] 0 on success; -1 on error.\n" },
|
||||
|
||||
{ "domain_ioport_permission",
|
||||
(PyCFunction)pyxc_domain_ioport_permission,
|
||||
METH_VARARGS | METH_KEYWORDS, "\n"
|
||||
"Allow a domain access to a range of IO ports\n"
|
||||
" dom [int]: Identifier of domain to be allowed access.\n"
|
||||
" first_port [int]: First IO port\n"
|
||||
" nr_ports [int]: Number of IO ports\n"
|
||||
" allow_access [int]: Non-zero means enable access; else disable access\n\n"
|
||||
"Returns: [int] 0 on success; -1 on error.\n" },
|
||||
|
||||
{ NULL, NULL, 0, NULL }
|
||||
};
|
||||
|
||||
|
||||
@@ -695,7 +695,7 @@ static PyObject *xspy_introduce_domain(PyObject *self, PyObject *args,
|
||||
PyObject *kwds)
|
||||
{
|
||||
static char *kwd_spec[] = { "dom", "page", "port", NULL };
|
||||
static char *arg_spec = "iii";
|
||||
static char *arg_spec = "ili";
|
||||
domid_t dom = 0;
|
||||
unsigned long page = 0;
|
||||
unsigned int port = 0;
|
||||
|
||||
@@ -380,9 +380,6 @@ class SocketConnector:
|
||||
self.state = "disconnected"
|
||||
self.transport = None
|
||||
|
||||
def getDestination(self):
|
||||
raise NotImplementedError()
|
||||
|
||||
def connectTransport(self):
|
||||
raise NotImplementedError()
|
||||
|
||||
|
||||
@@ -85,9 +85,6 @@ class TCPConnector(SocketConnector):
|
||||
raise IOError("unknown service: " + ex)
|
||||
return port
|
||||
|
||||
def getDestination(self):
|
||||
return (self.host, self.port)
|
||||
|
||||
def connectTransport(self):
|
||||
self.transport = TCPClientConnection(
|
||||
self.host, self.port, self.bindAddress, self)
|
||||
@@ -98,9 +95,6 @@ def listenTCP(port, factory, interface='', backlog=None):
|
||||
l.startListening()
|
||||
return l
|
||||
|
||||
def SetCloExec(SocketListener):
|
||||
SocketListener.SetCloExec()
|
||||
|
||||
def connectTCP(host, port, factory, timeout=None, bindAddress=None):
|
||||
c = TCPConnector(host, port, factory, timeout=timeout, bindAddress=bindAddress)
|
||||
c.connect()
|
||||
|
||||
@@ -67,9 +67,6 @@ class UnixConnector(SocketConnector):
|
||||
self.addr = path
|
||||
self.timeout = timeout
|
||||
|
||||
def getDestination(self):
|
||||
return self.addr
|
||||
|
||||
def connectTransport(self):
|
||||
self.transport = UnixClientConnection(self.addr, self)
|
||||
self.transport.connect(self.timeout)
|
||||
|
||||
@@ -32,4 +32,5 @@ def network(op):
|
||||
raise ValueError('Invalid operation: ' + op)
|
||||
script = XendRoot.instance().get_network_script()
|
||||
if script:
|
||||
os.spawnl(os.P_WAIT, script, script, op)
|
||||
script.insert(1, op)
|
||||
os.spawnv(os.P_WAIT, script[0], script)
|
||||
@@ -7,9 +7,9 @@
|
||||
|
||||
import os
|
||||
import re
|
||||
import select
|
||||
import string
|
||||
import sxp
|
||||
import threading
|
||||
from struct import pack, unpack, calcsize
|
||||
|
||||
from xen.util.xpopen import xPopen3
|
||||
@@ -81,6 +81,7 @@ def save(fd, dominfo, live):
|
||||
log.info("Domain %d suspended.", dominfo.getDomid())
|
||||
tochild.write("done\n")
|
||||
tochild.flush()
|
||||
log.debug('Written done')
|
||||
|
||||
forkHelper(cmd, fd, saveInputHandler, False)
|
||||
|
||||
@@ -176,43 +177,42 @@ def forkHelper(cmd, fd, inputHandler, closeToChild):
|
||||
if closeToChild:
|
||||
child.tochild.close()
|
||||
|
||||
lasterr = "error unknown"
|
||||
thread = threading.Thread(target = slurp, args = (child.childerr,))
|
||||
thread.start()
|
||||
|
||||
try:
|
||||
fds = [child.fromchild.fileno(),
|
||||
child.childerr.fileno()]
|
||||
p = select.poll()
|
||||
map(p.register, fds)
|
||||
while len(fds) > 0:
|
||||
r = p.poll()
|
||||
for (fd, event) in r:
|
||||
if event & select.POLLIN:
|
||||
if fd == child.childerr.fileno():
|
||||
lasterr = child.childerr.readline().rstrip()
|
||||
log.error('%s', lasterr)
|
||||
else:
|
||||
l = child.fromchild.readline().rstrip()
|
||||
while l:
|
||||
log.debug('%s', l)
|
||||
inputHandler(l, child.tochild)
|
||||
try:
|
||||
l = child.fromchild.readline().rstrip()
|
||||
except:
|
||||
l = None
|
||||
try:
|
||||
while 1:
|
||||
line = child.fromchild.readline()
|
||||
if line == "":
|
||||
break
|
||||
else:
|
||||
line = line.rstrip()
|
||||
log.debug('%s', line)
|
||||
inputHandler(line, child.tochild)
|
||||
|
||||
if event & select.POLLERR:
|
||||
raise XendError('Error reading from child process for %s',
|
||||
cmd)
|
||||
thread.join()
|
||||
|
||||
if event & select.POLLHUP:
|
||||
fds.remove(fd)
|
||||
p.unregister(fd)
|
||||
except IOError, exn:
|
||||
raise XendError('Error reading from child process for %s: %s' %
|
||||
(cmd, exn))
|
||||
finally:
|
||||
child.fromchild.close()
|
||||
child.childerr.close()
|
||||
if not closeToChild:
|
||||
child.tochild.close()
|
||||
|
||||
if child.wait() >> 8 == 127:
|
||||
lasterr = "popen failed"
|
||||
if child.wait() != 0:
|
||||
raise XendError("%s failed: %s" % (string.join(cmd), lasterr))
|
||||
status = child.wait()
|
||||
if status >> 8 == 127:
|
||||
raise XendError("%s failed: popen failed" % string.join(cmd))
|
||||
elif status != 0:
|
||||
raise XendError("%s failed" % string.join(cmd))
|
||||
|
||||
|
||||
def slurp(file):
|
||||
while 1:
|
||||
line = file.readline()
|
||||
if line == "":
|
||||
break
|
||||
else:
|
||||
log.error('%s', line)
|
||||
@@ -492,6 +492,40 @@ class XendDomain:
|
||||
except Exception, ex:
|
||||
raise XendError(str(ex))
|
||||
|
||||
def domain_ioport_range_enable(self, domid, first, last):
|
||||
"""Enable access to a range of IO ports for a domain
|
||||
|
||||
@param first: first IO port
|
||||
@param last: last IO port
|
||||
@return: 0 on success, -1 on error
|
||||
"""
|
||||
dominfo = self.domain_lookup(domid)
|
||||
nr_ports = last - first + 1
|
||||
try:
|
||||
return xc.domain_ioport_permission(dominfo.getDomid(),
|
||||
first_port = first,
|
||||
nr_ports = nr_ports,
|
||||
allow_access = 1)
|
||||
except Exception, ex:
|
||||
raise XendError(str(ex))
|
||||
|
||||
def domain_ioport_range_disable(self, domid, first, last):
|
||||
"""Disable access to a range of IO ports for a domain
|
||||
|
||||
@param first: first IO port
|
||||
@param last: last IO port
|
||||
@return: 0 on success, -1 on error
|
||||
"""
|
||||
dominfo = self.domain_lookup(domid)
|
||||
nr_ports = last - first + 1
|
||||
try:
|
||||
return xc.domain_ioport_permission(dominfo.getDomid(),
|
||||
first_port = first,
|
||||
nr_ports = nr_ports,
|
||||
allow_access = 0)
|
||||
except Exception, ex:
|
||||
raise XendError(str(ex))
|
||||
|
||||
|
||||
def instance():
|
||||
"""Singleton constructor. Use this instead of the class constructor.
|
||||
|
||||
@@ -336,7 +336,7 @@ def dom_get(dom):
|
||||
return domlist[0]
|
||||
except Exception, err:
|
||||
# ignore missing domain
|
||||
log.debug("domain_getinfo(%d) failed, ignoring: %s", dom, str(err))
|
||||
log.trace("domain_getinfo(%d) failed, ignoring: %s", dom, str(err))
|
||||
return None
|
||||
|
||||
|
||||
@@ -569,6 +569,8 @@ class XendDomainInfo:
|
||||
self.storeDomDetails()
|
||||
self.refreshShutdown()
|
||||
|
||||
log.debug("XendDomainInfo.completeRestore done")
|
||||
|
||||
|
||||
def storeVmDetails(self):
|
||||
to_store = {
|
||||
@@ -595,6 +597,7 @@ class XendDomainInfo:
|
||||
to_store = {
|
||||
'domid': str(self.domid),
|
||||
'vm': self.vmpath,
|
||||
'name': self.info['name'],
|
||||
'console/limit': str(xroot.get_console_limit() * 1024),
|
||||
'memory/target': str(self.info['memory_KiB'])
|
||||
}
|
||||
@@ -1065,8 +1068,11 @@ class XendDomainInfo:
|
||||
assert self.domid is not None
|
||||
assert self.store_mfn is not None
|
||||
assert self.store_port is not None
|
||||
|
||||
IntroduceDomain(self.domid, self.store_mfn, self.store_port)
|
||||
|
||||
try:
|
||||
IntroduceDomain(self.domid, self.store_mfn, self.store_port)
|
||||
except RuntimeError, exn:
|
||||
raise XendError(str(exn))
|
||||
|
||||
|
||||
def initDomain(self):
|
||||
@@ -1274,7 +1280,6 @@ class XendDomainInfo:
|
||||
|
||||
now = time.time()
|
||||
rst = self.readVm('xend/previous_restart_time')
|
||||
log.error(rst)
|
||||
if rst:
|
||||
rst = float(rst)
|
||||
timeout = now - rst
|
||||
@@ -1283,8 +1288,8 @@ class XendDomainInfo:
|
||||
'VM %s restarting too fast (%f seconds since the last '
|
||||
'restart). Refusing to restart to avoid loops.',
|
||||
self.info['name'], timeout)
|
||||
self.destroy()
|
||||
return
|
||||
self.destroy()
|
||||
return
|
||||
|
||||
self.writeVm('xend/previous_restart_time', str(now))
|
||||
|
||||
@@ -1305,7 +1310,11 @@ class XendDomainInfo:
|
||||
except:
|
||||
log.exception('Failed to restart domain %d.', self.domid)
|
||||
finally:
|
||||
self.removeVm('xend/restart_in_progress')
|
||||
# new_dom's VM will be the same as this domain's VM, except where
|
||||
# the rename flag has instructed us to call preserveForRestart.
|
||||
# In that case, it is important that we use new_dom.removeVm, not
|
||||
# self.removeVm.
|
||||
new_dom.removeVm('xend/restart_in_progress')
|
||||
|
||||
# self.configure_bootloader()
|
||||
# self.exportToDB()
|
||||
@@ -1396,9 +1405,10 @@ def addControllerClass(device_class, cls):
|
||||
controllerClasses[device_class] = cls
|
||||
|
||||
|
||||
from xen.xend.server import blkif, netif, tpmif, pciif, usbif
|
||||
from xen.xend.server import blkif, netif, tpmif, pciif, iopif, usbif
|
||||
addControllerClass('vbd', blkif.BlkifController)
|
||||
addControllerClass('vif', netif.NetifController)
|
||||
addControllerClass('vtpm', tpmif.TPMifController)
|
||||
addControllerClass('pci', pciif.PciController)
|
||||
addControllerClass('ioports', iopif.IOPortsController)
|
||||
addControllerClass('usb', usbif.UsbifController)
|
||||
@@ -17,7 +17,7 @@
|
||||
#============================================================================
|
||||
|
||||
"""Xend root class.
|
||||
Creates the event server and handles configuration.
|
||||
Creates the servers and handles configuration.
|
||||
|
||||
Other classes get config variables by importing this module,
|
||||
using instance() to get a XendRoot instance, and then
|
||||
@@ -72,9 +72,6 @@ class XendRoot:
|
||||
"""Default port xend serves HTTP at. """
|
||||
xend_port_default = '8000'
|
||||
|
||||
"""Default port xend serves events at. """
|
||||
xend_event_port_default = '8001'
|
||||
|
||||
"""Default port xend serves relocation at. """
|
||||
xend_relocation_port_default = '8002'
|
||||
|
||||
@@ -114,7 +111,7 @@ class XendRoot:
|
||||
"""
|
||||
return self.components.get(name)
|
||||
|
||||
def _logError(self, fmt, args):
|
||||
def _logError(self, fmt, *args):
|
||||
"""Logging function to log to stderr. We use this for XendRoot log
|
||||
messages because they may be logged before the logger has been
|
||||
configured. Other components can safely use the logger.
|
||||
@@ -144,7 +141,10 @@ class XendRoot:
|
||||
config = sxp.parse(fin)
|
||||
finally:
|
||||
fin.close()
|
||||
config.insert(0, 'xend-config')
|
||||
if config is None:
|
||||
config = ['xend-config']
|
||||
else:
|
||||
config.insert(0, 'xend-config')
|
||||
self.config = config
|
||||
except Exception, ex:
|
||||
self._logError('Reading config file %s: %s',
|
||||
@@ -207,21 +207,16 @@ class XendRoot:
|
||||
"""
|
||||
return self.get_config_int('xend-port', self.xend_port_default)
|
||||
|
||||
def get_xend_event_port(self):
|
||||
"""Get the port xend listens at for connection to its event server.
|
||||
"""
|
||||
return self.get_config_int('xend-event-port', self.xend_event_port_default)
|
||||
|
||||
def get_xend_relocation_port(self):
|
||||
"""Get the port xend listens at for connection to its relocation server.
|
||||
"""
|
||||
return self.get_config_int('xend-relocation-port', self.xend_relocation_port_default)
|
||||
|
||||
def get_xend_address(self):
|
||||
"""Get the address xend listens at for its HTTP and event ports.
|
||||
"""Get the address xend listens at for its HTTP port.
|
||||
This defaults to the empty string which allows all hosts to connect.
|
||||
If this is set to 'localhost' only the localhost will be able to connect
|
||||
to the HTTP and event ports.
|
||||
to the HTTP port.
|
||||
"""
|
||||
return self.get_config_value('xend-address', self.xend_address_default)
|
||||
|
||||
@@ -229,7 +224,7 @@ class XendRoot:
|
||||
"""Get the address xend listens at for its relocation server port.
|
||||
This defaults to the empty string which allows all hosts to connect.
|
||||
If this is set to 'localhost' only the localhost will be able to connect
|
||||
to the HTTP and event ports.
|
||||
to the relocation port.
|
||||
"""
|
||||
return self.get_config_value('xend-relocation-address', self.xend_relocation_address_default)
|
||||
|
||||
@@ -250,7 +245,9 @@ class XendRoot:
|
||||
s = self.get_config_value('network-script')
|
||||
|
||||
if s:
|
||||
return os.path.join(self.network_script_dir, s)
|
||||
result = s.split(" ")
|
||||
result[0] = os.path.join(self.network_script_dir, result[0])
|
||||
return result
|
||||
else:
|
||||
return None
|
||||
|
||||
@@ -258,9 +255,6 @@ class XendRoot:
|
||||
def get_enable_dump(self):
|
||||
return self.get_config_bool('enable-dump', 'no')
|
||||
|
||||
def get_vif_bridge(self):
|
||||
return self.get_config_value('vif-bridge', 'xenbr0')
|
||||
|
||||
def get_vif_script(self):
|
||||
return self.get_config_value('vif-script', 'vif-bridge')
|
||||
|
||||
|
||||
@@ -203,6 +203,10 @@ class VmxImageHandler(ImageHandler):
|
||||
|
||||
self.dmargs += self.configVNC(imageConfig)
|
||||
|
||||
self.lapic = 0
|
||||
lapic = sxp.child_value(imageConfig, 'lapic')
|
||||
if not lapic is None:
|
||||
self.lapic = int(lapic)
|
||||
|
||||
def buildDomain(self):
|
||||
# Create an event channel
|
||||
@@ -217,6 +221,7 @@ class VmxImageHandler(ImageHandler):
|
||||
log.debug("control_evtchn = %d", self.device_channel)
|
||||
log.debug("store_evtchn = %d", store_evtchn)
|
||||
log.debug("memsize = %d", self.vm.getMemoryTarget() / 1024)
|
||||
log.debug("lapic = %d", self.lapic)
|
||||
log.debug("vcpus = %d", self.vm.getVCpuCount())
|
||||
|
||||
return xc.vmx_build(dom = self.vm.getDomid(),
|
||||
@@ -224,6 +229,7 @@ class VmxImageHandler(ImageHandler):
|
||||
control_evtchn = self.device_channel,
|
||||
store_evtchn = store_evtchn,
|
||||
memsize = self.vm.getMemoryTarget() / 1024,
|
||||
lapic = self.lapic,
|
||||
vcpus = self.vm.getVCpuCount())
|
||||
|
||||
|
||||
|
||||
@@ -16,12 +16,18 @@
|
||||
# Copyright (C) 2005 XenSource Ltd
|
||||
#============================================================================
|
||||
|
||||
from threading import Event
|
||||
|
||||
from xen.xend import sxp
|
||||
from xen.xend.XendError import VmError
|
||||
from xen.xend.XendLogging import log
|
||||
from xen.xend.xenstore.xstransact import xstransact
|
||||
|
||||
from xen.xend.xenstore.xstransact import xstransact
|
||||
from xen.xend.xenstore.xswatch import xswatch
|
||||
|
||||
DEVICE_CREATE_TIMEOUT = 120
|
||||
HOTPLUG_STATUS_NODE = "hotplug-status"
|
||||
HOTPLUG_STATUS_ERROR = "error"
|
||||
|
||||
class DevController:
|
||||
"""Abstract base class for a device controller. Device controllers create
|
||||
@@ -51,9 +57,23 @@ class DevController:
|
||||
@return The ID for the newly created device.
|
||||
"""
|
||||
(devid, back, front) = self.getDeviceDetails(config)
|
||||
if devid is None:
|
||||
return 0
|
||||
|
||||
self.writeDetails(config, devid, back, front)
|
||||
|
||||
status, fn_ret = self.waitForBackend(devid)
|
||||
if status:
|
||||
self.destroyDevice(devid)
|
||||
raise VmError( ("Device %s (%s) could not be connected. "
|
||||
"Hotplug scripts not working")
|
||||
% (devid, self.deviceClass))
|
||||
|
||||
elif fn_ret == HOTPLUG_STATUS_ERROR:
|
||||
self.destroyDevice(devid)
|
||||
raise VmError( ("Device %s (%s) could not be connected. "
|
||||
"Backend device not found!")
|
||||
% (devid, self.deviceClass))
|
||||
return devid
|
||||
|
||||
|
||||
@@ -69,11 +89,19 @@ class DevController:
|
||||
def destroyDevice(self, devid):
|
||||
"""Destroy the specified device.
|
||||
|
||||
The implementation here simply deletes the appropriate paths from
|
||||
the store. This may be overridden by subclasses who need to perform
|
||||
other tasks on destruction.
|
||||
@param devid The device ID, or something device-specific from which
|
||||
the device ID can be determined (such as a guest-side device name).
|
||||
|
||||
The implementation here simply deletes the appropriate paths from the
|
||||
store. This may be overridden by subclasses who need to perform other
|
||||
tasks on destruction. Further, the implementation here can only
|
||||
accept integer device IDs, or values that can be converted to
|
||||
integers. Subclasses may accept other values and convert them to
|
||||
integers before passing them here.
|
||||
"""
|
||||
|
||||
devid = int(devid)
|
||||
|
||||
frontpath = self.frontendPath(devid)
|
||||
backpath = xstransact.Read(frontpath, "backend")
|
||||
|
||||
@@ -234,6 +262,29 @@ class DevController:
|
||||
xstransact.Write(frontpath, frontDetails)
|
||||
xstransact.Write(backpath, backDetails)
|
||||
|
||||
def waitForBackend(self,devid):
|
||||
ev = Event()
|
||||
|
||||
def hotplugStatus():
|
||||
status = self.readBackend(devid, HOTPLUG_STATUS_NODE)
|
||||
if status is not None:
|
||||
watch.xs.unwatch(backpath, watch)
|
||||
hotplugStatus.value = status
|
||||
ev.set()
|
||||
|
||||
hotplugStatus.value = None
|
||||
frontpath = self.frontendPath(devid)
|
||||
backpath = xstransact.Read(frontpath, "backend")
|
||||
|
||||
watch = xswatch(backpath, hotplugStatus)
|
||||
|
||||
ev.wait(DEVICE_CREATE_TIMEOUT)
|
||||
if ev.isSet():
|
||||
return (0, hotplugStatus.value)
|
||||
else:
|
||||
return (-1, hotplugStatus.value)
|
||||
|
||||
|
||||
|
||||
def backendPath(self, backdom, devid):
|
||||
"""@param backdom [XendDomainInfo] The backend domain info."""
|
||||
|
||||
@@ -19,7 +19,6 @@ import xen.lowlevel.xc
|
||||
from xen.xend.server import SrvServer
|
||||
from xen.xend.XendLogging import log
|
||||
|
||||
import event
|
||||
import relocate
|
||||
from params import *
|
||||
|
||||
@@ -262,10 +261,7 @@ class Daemon:
|
||||
return 1
|
||||
|
||||
def stop(self):
|
||||
result = self.cleanup_xend(True)
|
||||
from xen.xend import Vifctl
|
||||
Vifctl.network("stop")
|
||||
return result
|
||||
return self.cleanup_xend(True)
|
||||
|
||||
def run(self, status):
|
||||
try:
|
||||
@@ -276,7 +272,6 @@ class Daemon:
|
||||
log.info("Xend changeset: %s.", xinfo['xen_changeset'])
|
||||
del xc
|
||||
|
||||
event.listenEvent(self)
|
||||
relocate.listenRelocation()
|
||||
servers = SrvServer.create()
|
||||
self.daemonize()
|
||||
|
||||
@@ -25,7 +25,6 @@ from xen.xend import XendDomain
|
||||
from xen.xend.XendDomainInfo import XendDomainInfo
|
||||
from xen.xend.Args import FormFn
|
||||
from xen.xend.XendError import XendError
|
||||
from xen.xend.XendLogging import log
|
||||
|
||||
from xen.web.SrvDir import SrvDir
|
||||
from SrvDomain import SrvDomain
|
||||
@@ -52,7 +51,7 @@ class SrvDomainDir(SrvDir):
|
||||
else:
|
||||
return self.domain(x)
|
||||
|
||||
def op_create(self, op, req):
|
||||
def op_create(self, _, req):
|
||||
"""Create a domain.
|
||||
Expects the domain config in request parameter 'config' in SXP format.
|
||||
"""
|
||||
@@ -66,12 +65,12 @@ class SrvDomainDir(SrvDir):
|
||||
pin.input_eof()
|
||||
config = pin.get_val()
|
||||
ok = 1
|
||||
except sxp.ParseError, ex:
|
||||
errmsg = 'Invalid configuration ' + str(ex)
|
||||
except Exception, ex:
|
||||
print 'op_create> Exception in config', ex
|
||||
traceback.print_exc()
|
||||
errmsg = 'Configuration error ' + str(ex)
|
||||
except sxp.ParseError, ex:
|
||||
errmsg = 'Invalid configuration ' + str(ex)
|
||||
if not ok:
|
||||
raise XendError(errmsg)
|
||||
try:
|
||||
@@ -108,7 +107,7 @@ class SrvDomainDir(SrvDir):
|
||||
"""
|
||||
return req.threadRequest(self.do_restore, op, req)
|
||||
|
||||
def do_restore(self, op, req):
|
||||
def do_restore(self, _, req):
|
||||
fn = FormFn(self.xd.domain_restore,
|
||||
[['file', 'str']])
|
||||
dominfo = fn(req.args)
|
||||
|
||||
@@ -43,7 +43,7 @@ class BlkifController(DevController):
|
||||
|
||||
dev = sxp.child_value(config, 'dev')
|
||||
if re.match('^ioemu:', dev):
|
||||
return (0,{},{})
|
||||
return (None,{},{})
|
||||
|
||||
devid = blkif.blkdev_name_to_number(dev)
|
||||
|
||||
|
||||
@@ -1,195 +0,0 @@
|
||||
#============================================================================
|
||||
# This library is free software; you can redistribute it and/or
|
||||
# modify it under the terms of version 2.1 of the GNU Lesser General Public
|
||||
# License as published by the Free Software Foundation.
|
||||
#
|
||||
# This library is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
# Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public
|
||||
# License along with this library; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#============================================================================
|
||||
# Copyright (C) 2004, 2005 Mike Wray <mike.wray@hp.com>
|
||||
# Copyright (C) 2005 XenSource Ltd
|
||||
#============================================================================
|
||||
|
||||
import sys
|
||||
import StringIO
|
||||
|
||||
from xen.web import protocol, tcp, unix
|
||||
|
||||
from xen.xend import scheduler
|
||||
from xen.xend import sxp
|
||||
from xen.xend import PrettyPrint
|
||||
from xen.xend.XendError import XendError
|
||||
from xen.xend import XendLogging
|
||||
from xen.xend import XendRoot
|
||||
|
||||
|
||||
xroot = XendRoot.instance()
|
||||
|
||||
|
||||
DEBUG = 0
|
||||
|
||||
class EventProtocol(protocol.Protocol):
|
||||
"""Asynchronous handler for a connected event socket.
|
||||
"""
|
||||
|
||||
def __init__(self, daemon):
|
||||
#protocol.Protocol.__init__(self)
|
||||
self.daemon = daemon
|
||||
# Event queue.
|
||||
self.queue = []
|
||||
self.parser = sxp.Parser()
|
||||
self.pretty = 1
|
||||
|
||||
def dataReceived(self, data):
|
||||
try:
|
||||
self.parser.input(data)
|
||||
while(self.parser.ready()):
|
||||
val = self.parser.get_val()
|
||||
res = self.dispatch(val)
|
||||
self.send_result(res)
|
||||
if self.parser.at_eof():
|
||||
self.loseConnection()
|
||||
except SystemExit:
|
||||
raise
|
||||
except:
|
||||
self.send_error()
|
||||
|
||||
def loseConnection(self):
|
||||
if self.transport:
|
||||
self.transport.loseConnection()
|
||||
if self.connected:
|
||||
scheduler.now(self.connectionLost)
|
||||
|
||||
def connectionLost(self, reason=None):
|
||||
pass
|
||||
|
||||
def send_reply(self, sxpr):
|
||||
io = StringIO.StringIO()
|
||||
if self.pretty:
|
||||
PrettyPrint.prettyprint(sxpr, out=io)
|
||||
else:
|
||||
sxp.show(sxpr, out=io)
|
||||
print >> io
|
||||
io.seek(0)
|
||||
if self.transport:
|
||||
return self.transport.write(io.getvalue())
|
||||
else:
|
||||
return 0
|
||||
|
||||
def send_result(self, res):
|
||||
if res is None:
|
||||
resp = ['ok']
|
||||
else:
|
||||
resp = ['ok', res]
|
||||
return self.send_reply(resp)
|
||||
|
||||
def send_error(self):
|
||||
(extype, exval) = sys.exc_info()[:2]
|
||||
return self.send_reply(['err',
|
||||
['type', str(extype)],
|
||||
['value', str(exval)]])
|
||||
|
||||
def send_event(self, val):
|
||||
return self.send_reply(['event', val[0], val[1]])
|
||||
|
||||
def queue_event(self, name, v):
|
||||
# Despite the name we don't queue the event here.
|
||||
# We send it because the transport will queue it.
|
||||
self.send_event([name, v])
|
||||
|
||||
def opname(self, name):
|
||||
return 'op_' + name.replace('.', '_')
|
||||
|
||||
def operror(self, name, req):
|
||||
raise XendError('Invalid operation: ' +name)
|
||||
|
||||
def dispatch(self, req):
|
||||
op_name = sxp.name(req)
|
||||
op_method_name = self.opname(op_name)
|
||||
op_method = getattr(self, op_method_name, self.operror)
|
||||
return op_method(op_name, req)
|
||||
|
||||
def op_help(self, _1, _2):
|
||||
def nameop(x):
|
||||
if x.startswith('op_'):
|
||||
return x[3:].replace('_', '.')
|
||||
else:
|
||||
return x
|
||||
|
||||
l = [ nameop(k) for k in dir(self) if k.startswith('op_') ]
|
||||
return l
|
||||
|
||||
def op_quit(self, _1, _2):
|
||||
self.loseConnection()
|
||||
|
||||
def op_exit(self, _1, _2):
|
||||
sys.exit(0)
|
||||
|
||||
def op_pretty(self, _1, _2):
|
||||
self.pretty = 1
|
||||
|
||||
def op_info(self, _1, _2):
|
||||
val = ['info']
|
||||
#val += self.daemon.blkifs()
|
||||
#val += self.daemon.netifs()
|
||||
#val += self.daemon.usbifs()
|
||||
return val
|
||||
|
||||
def op_trace(self, _, v):
|
||||
mode = (v[1] == 'on')
|
||||
self.daemon.tracing(mode)
|
||||
|
||||
def op_log_stderr(self, _, v):
|
||||
mode = v[1]
|
||||
if mode == 'on':
|
||||
XendLogging.addLogStderr()
|
||||
else:
|
||||
XendLogging.removeLogStderr()
|
||||
|
||||
def op_domain_ls(self, _1, _2):
|
||||
xd = xroot.get_component("xen.xend.XendDomain")
|
||||
return xd.list_names()
|
||||
|
||||
def op_domain_configure(self, _, v):
|
||||
domid = sxp.child_value(v, "dom")
|
||||
config = sxp.child_value(v, "config")
|
||||
if domid is None:
|
||||
raise XendError("missing domain id")
|
||||
if config is None:
|
||||
raise XendError("missing domain config")
|
||||
xd = xroot.get_component("xen.xend.XendDomain")
|
||||
xd.domain_configure(domid, config)
|
||||
|
||||
def op_domain_unpause(self, _, v):
|
||||
domid = sxp.child_value(v, "dom")
|
||||
if domid is None:
|
||||
raise XendError("missing domain id")
|
||||
xd = xroot.get_component("xen.xend.XendDomain")
|
||||
xd.domain_unpause(domid)
|
||||
|
||||
class EventFactory(protocol.ServerFactory):
|
||||
"""Asynchronous handler for the event server socket.
|
||||
"""
|
||||
|
||||
def __init__(self, daemon):
|
||||
protocol.ServerFactory.__init__(self)
|
||||
self.daemon = daemon
|
||||
|
||||
def buildProtocol(self, _):
|
||||
return EventProtocol(self.daemon)
|
||||
|
||||
def listenEvent(daemon):
|
||||
factory = EventFactory(daemon)
|
||||
if xroot.get_xend_unix_server():
|
||||
path = '/var/lib/xend/event-socket'
|
||||
unix.listenUNIX(path, factory)
|
||||
if xroot.get_xend_http_server():
|
||||
port = xroot.get_xend_event_port()
|
||||
interface = xroot.get_xend_address()
|
||||
tcp.listenTCP(port, factory, interface=interface)
|
||||
@@ -0,0 +1,86 @@
|
||||
#============================================================================
|
||||
# This library is free software; you can redistribute it and/or
|
||||
# modify it under the terms of version 2.1 of the GNU Lesser General Public
|
||||
# License as published by the Free Software Foundation.
|
||||
#
|
||||
# This library is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
# Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public
|
||||
# License along with this library; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#============================================================================
|
||||
# Copyright (C) 2004, 2005 Mike Wray <mike.wray@hp.com>
|
||||
# Copyright (C) 2005 XenSource Ltd
|
||||
# Copyright (C) 2005 Jody Belka
|
||||
#============================================================================
|
||||
|
||||
|
||||
import types
|
||||
|
||||
import xen.lowlevel.xc;
|
||||
|
||||
from xen.xend import sxp
|
||||
from xen.xend.XendError import VmError
|
||||
|
||||
from xen.xend.server.DevController import DevController
|
||||
|
||||
|
||||
xc = xen.lowlevel.xc.new()
|
||||
|
||||
|
||||
def parse_ioport(val):
|
||||
"""Parse an i/o port field.
|
||||
"""
|
||||
if isinstance(val, types.StringType):
|
||||
radix = 10
|
||||
if val.startswith('0x') or val.startswith('0X'):
|
||||
radix = 16
|
||||
v = int(val, radix)
|
||||
else:
|
||||
v = val
|
||||
return v
|
||||
|
||||
|
||||
class IOPortsController(DevController):
|
||||
|
||||
def __init__(self, vm):
|
||||
DevController.__init__(self, vm)
|
||||
|
||||
|
||||
def getDeviceDetails(self, config):
|
||||
"""@see DevController.getDeviceDetails"""
|
||||
|
||||
def get_param(field):
|
||||
try:
|
||||
val = sxp.child_value(config, field)
|
||||
|
||||
if not val:
|
||||
raise VmError('ioports: Missing %s config setting' % field)
|
||||
|
||||
return parse_ioport(val)
|
||||
except:
|
||||
raise VmError('ioports: Invalid config setting %s: %s' %
|
||||
(field, val))
|
||||
|
||||
io_from = get_param('from')
|
||||
io_to = get_param('to')
|
||||
|
||||
if io_to < io_from or io_to >= 65536:
|
||||
raise VmError('ioports: Invalid i/o range: %s - %s' %
|
||||
(io_from, io_to))
|
||||
|
||||
rc = xc.domain_ioport_permission(dom = self.getDomid(),
|
||||
first_port = io_from,
|
||||
nr_ports = io_to - io_from + 1,
|
||||
allow_access = True)
|
||||
|
||||
if rc < 0:
|
||||
#todo non-fatal
|
||||
raise VmError(
|
||||
'ioports: Failed to configure legacy i/o range: %s - %s' %
|
||||
(io_from, io_to))
|
||||
|
||||
return (dev, {}, {})
|
||||
@@ -21,6 +21,7 @@
|
||||
"""
|
||||
|
||||
import os
|
||||
import random
|
||||
|
||||
from xen.xend import sxp
|
||||
from xen.xend import XendRoot
|
||||
@@ -31,6 +32,25 @@ from xen.xend.server.DevController import DevController
|
||||
xroot = XendRoot.instance()
|
||||
|
||||
|
||||
def randomMAC():
|
||||
"""Generate a random MAC address.
|
||||
|
||||
Uses OUI (Organizationally Unique Identifier) AA:00:00, an
|
||||
unassigned one that used to belong to DEC. The OUI list is
|
||||
available at 'standards.ieee.org'.
|
||||
|
||||
The remaining 3 fields are random, with the first bit of the first
|
||||
random field set 0.
|
||||
|
||||
@return: MAC address string
|
||||
"""
|
||||
mac = [ 0xaa, 0x00, 0x00,
|
||||
random.randint(0x00, 0x7f),
|
||||
random.randint(0x00, 0xff),
|
||||
random.randint(0x00, 0xff) ]
|
||||
return ':'.join(map(lambda x: "%02x" % x, mac))
|
||||
|
||||
|
||||
class NetifController(DevController):
|
||||
"""Network interface controller. Handles all network devices for a domain.
|
||||
"""
|
||||
@@ -51,22 +71,25 @@ class NetifController(DevController):
|
||||
script = os.path.join(xroot.network_script_dir,
|
||||
sxp.child_value(config, 'script',
|
||||
xroot.get_vif_script()))
|
||||
bridge = sxp.child_value(config, 'bridge',
|
||||
xroot.get_vif_bridge())
|
||||
mac = sxp.child_value(config, 'mac')
|
||||
bridge = sxp.child_value(config, 'bridge')
|
||||
mac = sxp.child_value(config, 'mac')
|
||||
ipaddr = _get_config_ipaddr(config)
|
||||
|
||||
devid = self.allocateDeviceID()
|
||||
|
||||
if not mac:
|
||||
mac = randomMAC()
|
||||
|
||||
back = { 'script' : script,
|
||||
'mac' : mac,
|
||||
'bridge' : bridge,
|
||||
'mac' : mac,
|
||||
'handle' : "%i" % devid }
|
||||
if ipaddr:
|
||||
back['ip'] = ' '.join(ipaddr)
|
||||
if bridge:
|
||||
back['bridge'] = bridge
|
||||
|
||||
front = { 'handle' : "%i" % devid,
|
||||
'mac' : mac }
|
||||
'mac' : mac }
|
||||
|
||||
return (devid, back, front)
|
||||
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
@@ -5,15 +5,14 @@
|
||||
# Public License. See the file "COPYING" in the main directory of
|
||||
# this archive for more details.
|
||||
|
||||
import errno
|
||||
import threading
|
||||
from xen.lowlevel import xs
|
||||
from xen.xend.xenstore.xsutil import xshandle
|
||||
|
||||
|
||||
class xstransact:
|
||||
|
||||
def __init__(self, path):
|
||||
assert path is not None
|
||||
|
||||
self.in_transaction = False # Set this temporarily -- if this
|
||||
# constructor fails, then we need to
|
||||
# protect __del__.
|
||||
|
||||
+139
-104
@@ -19,7 +19,6 @@
|
||||
|
||||
"""Domain creation.
|
||||
"""
|
||||
import random
|
||||
import os
|
||||
import os.path
|
||||
import string
|
||||
@@ -34,7 +33,6 @@ from xen.xend import sxp
|
||||
from xen.xend import PrettyPrint
|
||||
from xen.xend.XendClient import server, XendError
|
||||
from xen.xend.XendBootloader import bootloader
|
||||
from xen.xend import XendRoot; xroot = XendRoot.instance()
|
||||
from xen.util import blkif
|
||||
|
||||
from xen.xm.opts import *
|
||||
@@ -158,6 +156,10 @@ gopts.var('cpu', val='CPU',
|
||||
fn=set_int, default=None,
|
||||
use="CPU to run the domain on.")
|
||||
|
||||
gopts.var('lapic', val='LAPIC',
|
||||
fn=set_int, default=0,
|
||||
use="Disable or enable local APIC of VMX domain.")
|
||||
|
||||
gopts.var('vcpus', val='VCPUS',
|
||||
fn=set_int, default=1,
|
||||
use="# of Virtual CPUS in domain.")
|
||||
@@ -238,6 +240,12 @@ gopts.var('pci', val='BUS,DEV,FUNC',
|
||||
For example '-pci c0,02,1a'.
|
||||
The option may be repeated to add more than one pci device.""")
|
||||
|
||||
gopts.var('ioports', val='FROM[-TO]',
|
||||
fn=append_value, default=[],
|
||||
use="""Add a legacy I/O range to a domain, using given params (in hex).
|
||||
For example '-ioports 02f8-02ff'.
|
||||
The option may be repeated to add more than one i/o range.""")
|
||||
|
||||
gopts.var('usb', val='PATH',
|
||||
fn=append_value, default=[],
|
||||
use="""Add a physical USB port to a domain, as specified by the path
|
||||
@@ -254,7 +262,7 @@ gopts.var('vif', val="mac=MAC,be_mac=MAC,bridge=BRIDGE,script=SCRIPT,backend=DOM
|
||||
If mac is not specified a random MAC address is used.
|
||||
The MAC address of the backend interface can be selected with be_mac.
|
||||
If not specified then the network backend chooses it's own MAC address.
|
||||
If bridge is not specified the default bridge is used.
|
||||
If bridge is not specified the first bridge found is used.
|
||||
If script is not specified the default script is used.
|
||||
If backend is not specified the default backend driver domain is used.
|
||||
If vifname is not specified the backend virtual interface will have name vifD.N
|
||||
@@ -316,10 +324,6 @@ gopts.var('nfs_root', val="PATH",
|
||||
fn=set_value, default=None,
|
||||
use="Set the path of the root NFS directory.")
|
||||
|
||||
gopts.var('memmap', val='FILE',
|
||||
fn=set_value, default='',
|
||||
use="Path to memap SXP file.")
|
||||
|
||||
gopts.var('device_model', val='FILE',
|
||||
fn=set_value, default='',
|
||||
use="Path to device model program.")
|
||||
@@ -377,9 +381,23 @@ gopts.var('sdl', val='',
|
||||
use="""Should the device model use SDL?""")
|
||||
|
||||
gopts.var('display', val='DISPLAY',
|
||||
fn=set_value, default='localhost:0',
|
||||
fn=set_value, default=None,
|
||||
use="X11 display to use")
|
||||
|
||||
|
||||
def err(msg):
|
||||
"""Print an error to stderr and exit.
|
||||
"""
|
||||
print >>sys.stderr, "Error:", msg
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def warn(msg):
|
||||
"""Print a warning to stdout.
|
||||
"""
|
||||
print >>sys.stderr, "Warning:", msg
|
||||
|
||||
|
||||
def strip(pre, s):
|
||||
"""Strip prefix 'pre' if present.
|
||||
"""
|
||||
@@ -388,7 +406,7 @@ def strip(pre, s):
|
||||
else:
|
||||
return s
|
||||
|
||||
def configure_image(opts, vals):
|
||||
def configure_image(vals):
|
||||
"""Create the image config.
|
||||
"""
|
||||
config_image = [ vals.builder ]
|
||||
@@ -407,7 +425,7 @@ def configure_image(opts, vals):
|
||||
config_image.append(['vcpus', vals.vcpus])
|
||||
return config_image
|
||||
|
||||
def configure_disks(opts, config_devs, vals):
|
||||
def configure_disks(config_devs, vals):
|
||||
"""Create the config for disks (virtual block devices).
|
||||
"""
|
||||
for (uname, dev, mode, backend) in vals.disk:
|
||||
@@ -419,19 +437,26 @@ def configure_disks(opts, config_devs, vals):
|
||||
config_vbd.append(['backend', backend])
|
||||
config_devs.append(['device', config_vbd])
|
||||
|
||||
def configure_pci(opts, config_devs, vals):
|
||||
def configure_pci(config_devs, vals):
|
||||
"""Create the config for pci devices.
|
||||
"""
|
||||
for (bus, dev, func) in vals.pci:
|
||||
config_pci = ['pci', ['bus', bus], ['dev', dev], ['func', func]]
|
||||
config_devs.append(['device', config_pci])
|
||||
|
||||
def configure_usb(opts, config_devs, vals):
|
||||
def configure_ioports(config_devs, vals):
|
||||
"""Create the config for legacy i/o ranges.
|
||||
"""
|
||||
for (io_from, io_to) in vals.ioports:
|
||||
config_ioports = ['ioports', ['from', io_from], ['to', io_to]]
|
||||
config_devs.append(['device', config_ioports])
|
||||
|
||||
def configure_usb(config_devs, vals):
|
||||
for path in vals.usb:
|
||||
config_usb = ['usb', ['path', path]]
|
||||
config_devs.append(['device', config_usb])
|
||||
|
||||
def configure_vtpm(opts, config_devs, vals):
|
||||
def configure_vtpm(config_devs, vals):
|
||||
"""Create the config for virtual TPM interfaces.
|
||||
"""
|
||||
vtpm = vals.vtpm
|
||||
@@ -445,9 +470,9 @@ def configure_vtpm(opts, config_devs, vals):
|
||||
else:
|
||||
try:
|
||||
if int(instance) == 0:
|
||||
opts.err('VM config error: vTPM instance must not be 0.')
|
||||
err('VM config error: vTPM instance must not be 0.')
|
||||
except ValueError:
|
||||
opts.err('Vm config error: could not parse instance number.')
|
||||
err('Vm config error: could not parse instance number.')
|
||||
backend = d.get('backend')
|
||||
config_vtpm = ['vtpm']
|
||||
if instance:
|
||||
@@ -456,7 +481,7 @@ def configure_vtpm(opts, config_devs, vals):
|
||||
config_vtpm.append(['backend', backend])
|
||||
config_devs.append(['device', config_vtpm])
|
||||
|
||||
def configure_tpmif(opts, config_devs, vals):
|
||||
def configure_tpmif(config_devs, vals):
|
||||
"""Create the config for virtual TPM interfaces.
|
||||
"""
|
||||
tpmif = vals.tpmif
|
||||
@@ -471,25 +496,7 @@ def configure_tpmif(opts, config_devs, vals):
|
||||
config_devs.append(['device', config_tpmif])
|
||||
|
||||
|
||||
def randomMAC():
|
||||
"""Generate a random MAC address.
|
||||
|
||||
Uses OUI (Organizationally Unique Identifier) AA:00:00, an
|
||||
unassigned one that used to belong to DEC. The OUI list is
|
||||
available at 'standards.ieee.org'.
|
||||
|
||||
The remaining 3 fields are random, with the first bit of the first
|
||||
random field set 0.
|
||||
|
||||
@return: MAC address string
|
||||
"""
|
||||
mac = [ 0xaa, 0x00, 0x00,
|
||||
random.randint(0x00, 0x7f),
|
||||
random.randint(0x00, 0xff),
|
||||
random.randint(0x00, 0xff) ]
|
||||
return ':'.join(map(lambda x: "%02x" % x, mac))
|
||||
|
||||
def configure_vifs(opts, config_devs, vals):
|
||||
def configure_vifs(config_devs, vals):
|
||||
"""Create the config for virtual network interfaces.
|
||||
"""
|
||||
vifs = vals.vif
|
||||
@@ -499,8 +506,6 @@ def configure_vifs(opts, config_devs, vals):
|
||||
if idx < len(vifs):
|
||||
d = vifs[idx]
|
||||
mac = d.get('mac')
|
||||
if not mac:
|
||||
mac = randomMAC()
|
||||
be_mac = d.get('be_mac')
|
||||
bridge = d.get('bridge')
|
||||
script = d.get('script')
|
||||
@@ -508,7 +513,7 @@ def configure_vifs(opts, config_devs, vals):
|
||||
ip = d.get('ip')
|
||||
vifname = d.get('vifname')
|
||||
else:
|
||||
mac = randomMAC()
|
||||
mac = None
|
||||
be_mac = None
|
||||
bridge = None
|
||||
script = None
|
||||
@@ -516,7 +521,8 @@ def configure_vifs(opts, config_devs, vals):
|
||||
ip = None
|
||||
vifname = None
|
||||
config_vif = ['vif']
|
||||
config_vif.append(['mac', mac])
|
||||
if mac:
|
||||
config_vif.append(['mac', mac])
|
||||
if vifname:
|
||||
config_vif.append(['vifname', vifname])
|
||||
if be_mac:
|
||||
@@ -531,7 +537,7 @@ def configure_vifs(opts, config_devs, vals):
|
||||
config_vif.append(['ip', ip])
|
||||
config_devs.append(['device', config_vif])
|
||||
|
||||
def configure_vfr(opts, config, vals):
|
||||
def configure_vfr(config, vals):
|
||||
if not vals.ipaddr: return
|
||||
config_vfr = ['vfr']
|
||||
idx = 0 # No way of saying which IP is for which vif?
|
||||
@@ -539,37 +545,42 @@ def configure_vfr(opts, config, vals):
|
||||
config_vfr.append(['vif', ['id', idx], ['ip', ip]])
|
||||
config.append(config_vfr)
|
||||
|
||||
def configure_vmx(opts, config_image, vals):
|
||||
def configure_vmx(config_image, vals):
|
||||
"""Create the config for VMX devices.
|
||||
"""
|
||||
args = [ 'memmap', 'device_model', 'vcpus', 'cdrom',
|
||||
'boot', 'fda', 'fdb', 'localtime', 'serial', 'macaddr', 'stdvga',
|
||||
'isa', 'nographic', 'vnc', 'vncviewer', 'sdl', 'display', 'ne2000']
|
||||
args = [ 'device_model', 'vcpus', 'cdrom', 'boot', 'fda', 'fdb',
|
||||
'localtime', 'serial', 'macaddr', 'stdvga', 'isa', 'nographic',
|
||||
'vnc', 'vncviewer', 'sdl', 'display', 'ne2000', 'lapic']
|
||||
for a in args:
|
||||
if (vals.__dict__[a]):
|
||||
config_image.append([a, vals.__dict__[a]])
|
||||
|
||||
def run_bootloader(opts, vals):
|
||||
def run_bootloader(vals):
|
||||
if not os.access(vals.bootloader, os.X_OK):
|
||||
opts.err("Bootloader isn't executable")
|
||||
err("Bootloader isn't executable")
|
||||
if len(vals.disk) < 1:
|
||||
opts.err("No disks configured and boot loader requested")
|
||||
err("No disks configured and boot loader requested")
|
||||
(uname, dev, mode, backend) = vals.disk[0]
|
||||
file = blkif.blkdev_uname_to_file(uname)
|
||||
|
||||
return bootloader(vals.bootloader, file, not vals.console_autoconnect,
|
||||
vals.vcpus, vals.blentry)
|
||||
|
||||
def make_config(opts, vals):
|
||||
def make_config(vals):
|
||||
"""Create the domain configuration.
|
||||
"""
|
||||
|
||||
config = ['vm',
|
||||
['name', vals.name ],
|
||||
['memory', vals.memory ],
|
||||
['ssidref', vals.ssidref ]]
|
||||
if vals.maxmem:
|
||||
config.append(['maxmem', vals.maxmem])
|
||||
config = ['vm']
|
||||
|
||||
def add_conf(n):
|
||||
if hasattr(vals, n):
|
||||
v = getattr(vals, n)
|
||||
if v:
|
||||
config.append([n, v])
|
||||
|
||||
map(add_conf, ['name', 'memory', 'ssidref', 'maxmem', 'restart',
|
||||
'on_poweroff', 'on_reboot', 'on_crash'])
|
||||
|
||||
if vals.cpu is not None:
|
||||
config.append(['cpu', vals.cpu])
|
||||
if vals.cpu_weight is not None:
|
||||
@@ -580,34 +591,27 @@ def make_config(opts, vals):
|
||||
config.append(['backend', ['netif']])
|
||||
if vals.tpmif:
|
||||
config.append(['backend', ['tpmif']])
|
||||
if vals.restart:
|
||||
config.append(['restart', vals.restart])
|
||||
if vals.on_poweroff:
|
||||
config.append(['on_poweroff', vals.on_poweroff])
|
||||
if vals.on_reboot:
|
||||
config.append(['on_reboot', vals.on_reboot])
|
||||
if vals.on_crash:
|
||||
config.append(['on_crash', vals.on_crash])
|
||||
|
||||
if vals.bootloader:
|
||||
config.append(['bootloader', vals.bootloader])
|
||||
config_image = run_bootloader(opts, vals)
|
||||
config_image = run_bootloader(vals)
|
||||
else:
|
||||
config_image = configure_image(opts, vals)
|
||||
configure_vmx(opts, config_image, vals)
|
||||
config.append(['image', config_image ])
|
||||
config_image = configure_image(vals)
|
||||
configure_vmx(config_image, vals)
|
||||
config.append(['image', config_image])
|
||||
|
||||
config_devs = []
|
||||
configure_disks(opts, config_devs, vals)
|
||||
configure_pci(opts, config_devs, vals)
|
||||
configure_vifs(opts, config_devs, vals)
|
||||
configure_usb(opts, config_devs, vals)
|
||||
configure_vtpm(opts, config_devs, vals)
|
||||
configure_disks(config_devs, vals)
|
||||
configure_pci(config_devs, vals)
|
||||
configure_ioports(config_devs, vals)
|
||||
configure_vifs(config_devs, vals)
|
||||
configure_usb(config_devs, vals)
|
||||
configure_vtpm(config_devs, vals)
|
||||
config += config_devs
|
||||
|
||||
return config
|
||||
|
||||
def preprocess_disk(opts, vals):
|
||||
def preprocess_disk(vals):
|
||||
if not vals.disk: return
|
||||
disk = []
|
||||
for v in vals.disk:
|
||||
@@ -618,23 +622,37 @@ def preprocess_disk(opts, vals):
|
||||
elif n == 4:
|
||||
pass
|
||||
else:
|
||||
opts.err('Invalid disk specifier: ' + v)
|
||||
err('Invalid disk specifier: ' + v)
|
||||
disk.append(d)
|
||||
vals.disk = disk
|
||||
|
||||
def preprocess_pci(opts, vals):
|
||||
def preprocess_pci(vals):
|
||||
if not vals.pci: return
|
||||
pci = []
|
||||
for v in vals.pci:
|
||||
d = v.split(',')
|
||||
if len(d) != 3:
|
||||
opts.err('Invalid pci specifier: ' + v)
|
||||
err('Invalid pci specifier: ' + v)
|
||||
# Components are in hex: add hex specifier.
|
||||
hexd = map(lambda v: '0x'+v, d)
|
||||
pci.append(hexd)
|
||||
vals.pci = pci
|
||||
|
||||
def preprocess_vifs(opts, vals):
|
||||
def preprocess_ioports(vals):
|
||||
if not vals.ioports: return
|
||||
ioports = []
|
||||
for v in vals.ioports:
|
||||
d = v.split('-')
|
||||
if len(d) < 1 or len(d) > 2:
|
||||
err('Invalid i/o port range specifier: ' + v)
|
||||
if len(d) == 1:
|
||||
d.append(d[0])
|
||||
# Components are in hex: add hex specifier.
|
||||
hexd = map(lambda v: '0x'+v, d)
|
||||
ioports.append(hexd)
|
||||
vals.ioports = ioports
|
||||
|
||||
def preprocess_vifs(vals):
|
||||
if not vals.vif: return
|
||||
vifs = []
|
||||
for vif in vals.vif:
|
||||
@@ -645,12 +663,12 @@ def preprocess_vifs(opts, vals):
|
||||
k = k.strip()
|
||||
v = v.strip()
|
||||
if k not in ['mac', 'be_mac', 'bridge', 'script', 'backend', 'ip', 'vifname']:
|
||||
opts.err('Invalid vif specifier: ' + vif)
|
||||
err('Invalid vif specifier: ' + vif)
|
||||
d[k] = v
|
||||
vifs.append(d)
|
||||
vals.vif = vifs
|
||||
|
||||
def preprocess_vtpm(opts, vals):
|
||||
def preprocess_vtpm(vals):
|
||||
if not vals.vtpm: return
|
||||
vtpms = []
|
||||
for vtpm in vals.vtpm:
|
||||
@@ -661,12 +679,12 @@ def preprocess_vtpm(opts, vals):
|
||||
k = k.strip()
|
||||
v = v.strip()
|
||||
if k not in ['backend', 'instance']:
|
||||
opts.err('Invalid vtpm specifier: ' + vtpm)
|
||||
err('Invalid vtpm specifier: ' + vtpm)
|
||||
d[k] = v
|
||||
vtpms.append(d)
|
||||
vals.vtpm = vtpms
|
||||
|
||||
def preprocess_tpmif(opts, vals):
|
||||
def preprocess_tpmif(vals):
|
||||
if not vals.tpmif: return
|
||||
tpmifs = []
|
||||
for tpmif in vals.tpmif:
|
||||
@@ -677,12 +695,12 @@ def preprocess_tpmif(opts, vals):
|
||||
k = k.strip()
|
||||
v = v.strip()
|
||||
if k not in ['frontend']:
|
||||
opts.err('Invalid tpmif specifier: ' + vtpm)
|
||||
err('Invalid tpmif specifier: ' + vtpm)
|
||||
d[k] = v
|
||||
tpmifs.append(d)
|
||||
vals.tpmif = tpmifs
|
||||
|
||||
def preprocess_ip(opts, vals):
|
||||
def preprocess_ip(vals):
|
||||
if vals.ip or vals.dhcp != 'off':
|
||||
dummy_nfs_server = '1.2.3.4'
|
||||
ip = (vals.ip
|
||||
@@ -696,10 +714,10 @@ def preprocess_ip(opts, vals):
|
||||
ip = ''
|
||||
vals.cmdline_ip = ip
|
||||
|
||||
def preprocess_nfs(opts, vals):
|
||||
def preprocess_nfs(vals):
|
||||
if not vals.nfs_root: return
|
||||
if not vals.nfs_server:
|
||||
opts.err('Must set nfs root and nfs server')
|
||||
err('Must set nfs root and nfs server')
|
||||
nfs = 'nfsroot=' + vals.nfs_server + ':' + vals.nfs_root
|
||||
vals.extra = nfs + ' ' + vals.extra
|
||||
|
||||
@@ -745,14 +763,14 @@ def spawn_vnc(display):
|
||||
|
||||
return VNC_BASE_PORT + display
|
||||
|
||||
def preprocess_vnc(opts, vals):
|
||||
def preprocess_vnc(vals):
|
||||
"""If vnc was specified, spawn a vncviewer in listen mode
|
||||
and pass its address to the domain on the kernel command line.
|
||||
"""
|
||||
if not (vals.vnc and vals.vncviewer) or vals.dryrun: return
|
||||
vnc_display = choose_vnc_display()
|
||||
if not vnc_display:
|
||||
opts.warn("No free vnc display")
|
||||
warn("No free vnc display")
|
||||
return
|
||||
print 'VNC=', vnc_display
|
||||
vnc_port = spawn_vnc(vnc_display)
|
||||
@@ -761,17 +779,18 @@ def preprocess_vnc(opts, vals):
|
||||
vnc = 'VNC_VIEWER=%s:%d' % (vnc_host, vnc_port)
|
||||
vals.extra = vnc + ' ' + vals.extra
|
||||
|
||||
def preprocess(opts, vals):
|
||||
def preprocess(vals):
|
||||
if not vals.kernel:
|
||||
opts.err("No kernel specified")
|
||||
preprocess_disk(opts, vals)
|
||||
preprocess_pci(opts, vals)
|
||||
preprocess_vifs(opts, vals)
|
||||
preprocess_ip(opts, vals)
|
||||
preprocess_nfs(opts, vals)
|
||||
preprocess_vnc(opts, vals)
|
||||
preprocess_vtpm(opts, vals)
|
||||
preprocess_tpmif(opts, vals)
|
||||
err("No kernel specified")
|
||||
preprocess_disk(vals)
|
||||
preprocess_pci(vals)
|
||||
preprocess_ioports(vals)
|
||||
preprocess_vifs(vals)
|
||||
preprocess_ip(vals)
|
||||
preprocess_nfs(vals)
|
||||
preprocess_vnc(vals)
|
||||
preprocess_vtpm(vals)
|
||||
preprocess_tpmif(vals)
|
||||
|
||||
def make_domain(opts, config):
|
||||
"""Create, build and start a domain.
|
||||
@@ -792,14 +811,14 @@ def make_domain(opts, config):
|
||||
import signal
|
||||
if vncpid:
|
||||
os.kill(vncpid, signal.SIGKILL)
|
||||
opts.err(str(ex))
|
||||
err(str(ex))
|
||||
|
||||
dom = sxp.child_value(dominfo, 'name')
|
||||
|
||||
if not opts.vals.paused:
|
||||
if server.xend_domain_unpause(dom) < 0:
|
||||
server.xend_domain_destroy(dom)
|
||||
opts.err("Failed to unpause domain %s" % dom)
|
||||
err("Failed to unpause domain %s" % dom)
|
||||
opts.info("Started domain %s" % (dom))
|
||||
return int(sxp.child_value(dominfo, 'domid'))
|
||||
|
||||
@@ -853,8 +872,8 @@ def balloon_out(dom0_min_mem, opts):
|
||||
del xc
|
||||
return ret
|
||||
|
||||
def main(argv):
|
||||
random.seed()
|
||||
|
||||
def parseCommandLine(argv):
|
||||
opts = gopts
|
||||
args = opts.parse(argv)
|
||||
if opts.vals.help:
|
||||
@@ -862,25 +881,41 @@ def main(argv):
|
||||
if opts.vals.help or opts.vals.help_config:
|
||||
opts.load_defconfig(help=1)
|
||||
if opts.vals.help or opts.vals.help_config:
|
||||
return
|
||||
return (None, None)
|
||||
|
||||
if not opts.vals.display:
|
||||
opts.vals.display = os.getenv("DISPLAY")
|
||||
|
||||
# Process remaining args as config variables.
|
||||
for arg in args:
|
||||
if '=' in arg:
|
||||
(var, val) = arg.strip().split('=', 1)
|
||||
gopts.setvar(var.strip(), val.strip())
|
||||
opts.vals.display = os.getenv("DISPLAY")
|
||||
if opts.vals.config:
|
||||
config = opts.vals.config
|
||||
else:
|
||||
opts.load_defconfig()
|
||||
preprocess(opts, opts.vals)
|
||||
preprocess(opts.vals)
|
||||
if not opts.getopt('name') and opts.getopt('defconfig'):
|
||||
opts.setopt('name', os.path.basename(opts.getopt('defconfig')))
|
||||
config = make_config(opts, opts.vals)
|
||||
config = make_config(opts.vals)
|
||||
|
||||
return (opts, config)
|
||||
|
||||
|
||||
def main(argv):
|
||||
(opts, config) = parseCommandLine(argv)
|
||||
|
||||
if not opts:
|
||||
return
|
||||
|
||||
if opts.vals.dryrun:
|
||||
PrettyPrint.prettyprint(config)
|
||||
else:
|
||||
from xen.xend import XendRoot
|
||||
|
||||
xroot = XendRoot.instance()
|
||||
|
||||
dom0_min_mem = xroot.get_dom0_min_mem()
|
||||
if dom0_min_mem != 0:
|
||||
if balloon_out(dom0_min_mem, opts):
|
||||
|
||||
@@ -61,6 +61,8 @@ xm common subcommands:
|
||||
top monitor system and domains in real-time
|
||||
unpause <DomId> unpause a paused domain
|
||||
|
||||
<DomName> can be substituted for <DomId> in xm subcommands.
|
||||
|
||||
For a complete list of subcommands run 'xm help --long'
|
||||
For more help on xm see the xm(1) man page
|
||||
For more help on xm create, see the xmdomain.cfg(5) man page"""
|
||||
@@ -110,6 +112,12 @@ xm full list of subcommands:
|
||||
where <DevId> may either be the device ID
|
||||
or the device name as mounted in the guest.
|
||||
block-list <DomId> List virtual block devices for a domain
|
||||
|
||||
network-attach <DomID> [script=<script>] [ip=<ip>] [mac=<mac>]
|
||||
[bridge=<bridge>] [backend=<backDomID>]
|
||||
Create a new virtual network device
|
||||
network-detach <DomId> <DevId> Destroy a domain's virtual network
|
||||
device, where <DevId> is the device ID.
|
||||
network-limit <DomId> <Vif> <Credit> <Period>
|
||||
Limit the transmission rate of a virtual network interface
|
||||
network-list <DomId> List virtual network interfaces for a domain
|
||||
@@ -119,6 +127,8 @@ xm full list of subcommands:
|
||||
vnet-create <config> create a vnet from a config file
|
||||
vnet-delete <vnetid> delete a vnet
|
||||
|
||||
<DomName> can be substituted for <DomId> in xm subcommands.
|
||||
|
||||
For a short list of subcommands run 'xm help'
|
||||
For more help on xm see the xm(1) man page
|
||||
For more help on xm create, see the xmdomain.cfg(5) man page"""
|
||||
@@ -450,10 +460,14 @@ def xm_mem_set(args):
|
||||
server.xend_domain_mem_target_set(dom, mem_target)
|
||||
|
||||
def xm_set_vcpus(args):
|
||||
arg_check(args, 2, "set-vcpus")
|
||||
|
||||
from xen.xend.XendClient import server
|
||||
server.xend_domain_set_vcpus(args[0], int(args[1]))
|
||||
|
||||
def xm_domid(args):
|
||||
arg_check(args, 1, "domid")
|
||||
|
||||
name = args[0]
|
||||
|
||||
from xen.xend.XendClient import server
|
||||
@@ -461,6 +475,8 @@ def xm_domid(args):
|
||||
print sxp.child_value(dom, 'domid')
|
||||
|
||||
def xm_domname(args):
|
||||
arg_check(args, 1, "domname")
|
||||
|
||||
name = args[0]
|
||||
|
||||
from xen.xend.XendClient import server
|
||||
@@ -584,14 +600,39 @@ def xm_block_attach(args):
|
||||
from xen.xend.XendClient import server
|
||||
server.xend_domain_device_create(dom, vbd)
|
||||
|
||||
def xm_block_detach(args):
|
||||
arg_check(args,2,"block-detach")
|
||||
|
||||
def xm_network_attach(args):
|
||||
n = len(args)
|
||||
if n == 0:
|
||||
usage("network-attach")
|
||||
|
||||
dom = args[0]
|
||||
vif = ['vif']
|
||||
|
||||
for a in args[1:]:
|
||||
vif.append(a.split("="))
|
||||
|
||||
from xen.xend.XendClient import server
|
||||
server.xend_domain_device_create(dom, vif)
|
||||
|
||||
|
||||
def detach(args, command, deviceClass):
|
||||
arg_check(args, 2, command)
|
||||
|
||||
dom = args[0]
|
||||
dev = args[1]
|
||||
|
||||
from xen.xend.XendClient import server
|
||||
server.xend_domain_device_destroy(dom, 'vbd', dev)
|
||||
server.xend_domain_device_destroy(dom, deviceClass, dev)
|
||||
|
||||
|
||||
def xm_block_detach(args):
|
||||
detach(args, 'block-detach', 'vbd')
|
||||
|
||||
|
||||
def xm_network_detach(args):
|
||||
detach(args, 'network-detach', 'vif')
|
||||
|
||||
|
||||
def xm_vnet_list(args):
|
||||
from xen.xend.XendClient import server
|
||||
@@ -625,6 +666,10 @@ def xm_vnet_list(args):
|
||||
def xm_vnet_create(args):
|
||||
arg_check(args, 1, "vnet-create")
|
||||
conf = args[0]
|
||||
if not os.access(conf, os.R_OK):
|
||||
print "File not found: %s" % conf
|
||||
sys.exit(1)
|
||||
|
||||
from xen.xend.XendClient import server
|
||||
server.xend_vnet_create(conf)
|
||||
|
||||
@@ -669,6 +714,8 @@ commands = {
|
||||
"block-detach": xm_block_detach,
|
||||
"block-list": xm_block_list,
|
||||
# network
|
||||
"network-attach": xm_network_attach,
|
||||
"network-detach": xm_network_detach,
|
||||
"network-limit": xm_network_limit,
|
||||
"network-list": xm_network_list,
|
||||
# vnet
|
||||
@@ -754,7 +801,10 @@ def main(argv=sys.argv):
|
||||
else:
|
||||
err("Error connecting to xend: %s. Is xend running?" % ex[1])
|
||||
sys.exit(1)
|
||||
except IOError:
|
||||
except KeyboardInterrupt:
|
||||
print "Interrupted."
|
||||
sys.exit(1)
|
||||
except IOError, ex:
|
||||
if os.geteuid() != 0:
|
||||
err("Most commands need root access. Please try again as root.")
|
||||
else:
|
||||
|
||||
@@ -0,0 +1,96 @@
|
||||
import os
|
||||
import os.path
|
||||
import tempfile
|
||||
import unittest
|
||||
|
||||
import xen.xend.XendRoot
|
||||
|
||||
xen.xend.XendRoot.XendRoot.config_default = '/dev/null'
|
||||
|
||||
import xen.xm.create
|
||||
|
||||
|
||||
class test_create(unittest.TestCase):
|
||||
|
||||
def assertEqualModuloNulls_(self, a, b):
|
||||
for k, v in a.iteritems():
|
||||
if v:
|
||||
self.failUnless(k in b, '%s not in b' % k)
|
||||
self.assertEqual(v, b[k])
|
||||
else:
|
||||
self.assert_(k not in b or not b[k], '%s in b' % k)
|
||||
|
||||
|
||||
def assertEqualModuloNulls(self, a, b):
|
||||
self.assertEqualModuloNulls_(a, b)
|
||||
self.assertEqualModuloNulls_(b, a)
|
||||
|
||||
|
||||
def t(self, args, expected):
|
||||
self.assertEqualModuloNulls(
|
||||
xen.xm.create.parseCommandLine(args.split(' '))[0].vals.__dict__,
|
||||
expected)
|
||||
|
||||
|
||||
def testCommandLine(self):
|
||||
(fd, fname) = tempfile.mkstemp()
|
||||
try:
|
||||
self.t('-f %s kernel=/mykernel display=fakedisplay '
|
||||
'macaddr=ab:cd:ef:ed nics=0' % fname,
|
||||
{ 'name' : os.path.basename(fname),
|
||||
'xm_file' : fname,
|
||||
'defconfig' : fname,
|
||||
'kernel' : '/mykernel',
|
||||
'display' : 'fakedisplay',
|
||||
'macaddr' : 'ab:cd:ef:ed',
|
||||
'memory' : 128,
|
||||
'vcpus' : 1,
|
||||
'boot' : 'c',
|
||||
'dhcp' : 'off',
|
||||
'interface' : 'eth0',
|
||||
'path' : '.:/etc/xen',
|
||||
'builder' : 'linux',
|
||||
})
|
||||
finally:
|
||||
os.close(fd)
|
||||
|
||||
|
||||
def testConfigFileAndCommandLine(self):
|
||||
(fd, fname) = tempfile.mkstemp()
|
||||
os.write(fd,
|
||||
'''
|
||||
name = "testname"
|
||||
memory = 256
|
||||
ssidref = 1
|
||||
kernel = "/mykernel"
|
||||
maxmem = 1024
|
||||
cpu = 2
|
||||
cpu_weight = 0.75
|
||||
''')
|
||||
try:
|
||||
self.t('-f %s display=fakedisplay macaddr=ab:cd:ef:ed nics=0' %
|
||||
fname,
|
||||
{ 'name' : 'testname',
|
||||
'xm_file' : fname,
|
||||
'defconfig' : fname,
|
||||
'kernel' : '/mykernel',
|
||||
'display' : 'fakedisplay',
|
||||
'macaddr' : 'ab:cd:ef:ed',
|
||||
'memory' : 256,
|
||||
'maxmem' : 1024,
|
||||
'cpu' : 2,
|
||||
'ssidref' : 1,
|
||||
'cpu_weight' : 0.75,
|
||||
'vcpus' : 1,
|
||||
'boot' : 'c',
|
||||
'dhcp' : 'off',
|
||||
'interface' : 'eth0',
|
||||
'path' : '.:/etc/xen',
|
||||
'builder' : 'linux',
|
||||
})
|
||||
finally:
|
||||
os.close(fd)
|
||||
|
||||
|
||||
def test_suite():
|
||||
return unittest.makeSuite(test_create)
|
||||