mirror of
https://github.com/xen-project/xen.git
synced 2026-10-29 10:40:03 +01:00
bitkeeper revision 1.1159.170.110 (42527636gInunc40rkIVZVCuDC-_OQ)
Merge
This commit is contained in:
commit
2208888f15
444 files changed
+40955
-6684
No files matched your search
+12
-3
@@ -1,9 +1,18 @@
|
||||
|
||||
all:
|
||||
python setup.py build
|
||||
XEN_ROOT = ../..
|
||||
include $(XEN_ROOT)/tools/Rules.mk
|
||||
|
||||
all: build
|
||||
build:
|
||||
CFLAGS="$(CFLAGS)" python setup.py build
|
||||
|
||||
ifndef XEN_PYTHON_NATIVE_INSTALL
|
||||
install: all
|
||||
python setup.py install --home="$(prefix)/usr"
|
||||
CFLAGS="$(CFLAGS)" python setup.py install --home="$(DESTDIR)/usr"
|
||||
else
|
||||
install: all
|
||||
CFLAGS="$(CFLAGS)" python setup.py install --root="$(DESTDIR)"
|
||||
endif
|
||||
|
||||
clean:
|
||||
rm -rf build *.pyc *.pyo *.o *.a *~
|
||||
@@ -259,6 +259,7 @@ static PyTypeObject xu_notifier_type = {
|
||||
*/
|
||||
|
||||
#define TYPE(_x,_y) (((_x)<<8)|(_y))
|
||||
|
||||
#define P2C(_struct, _field, _ctype) \
|
||||
do { \
|
||||
PyObject *obj; \
|
||||
@@ -279,6 +280,29 @@ static PyTypeObject xu_notifier_type = {
|
||||
} \
|
||||
xum->msg.length = sizeof(_struct); \
|
||||
} while ( 0 )
|
||||
|
||||
/** Set a char[] field in a struct from a Python string.
|
||||
* Can't do this in P2C because of the typing.
|
||||
*/
|
||||
#define P2CSTRING(_struct, _field) \
|
||||
do { \
|
||||
PyObject *obj; \
|
||||
if ( (obj = PyDict_GetItemString(payload, #_field)) != NULL ) \
|
||||
{ \
|
||||
if ( PyString_Check(obj) ) \
|
||||
{ \
|
||||
_struct * _cobj = (_struct *)&xum->msg.msg[0]; \
|
||||
int _field_n = sizeof(_cobj->_field); \
|
||||
memset(_cobj->_field, 0, _field_n); \
|
||||
strncpy(_cobj->_field, \
|
||||
PyString_AsString(obj), \
|
||||
_field_n - 1); \
|
||||
dict_items_parsed++; \
|
||||
} \
|
||||
} \
|
||||
xum->msg.length = sizeof(_struct); \
|
||||
} while ( 0 )
|
||||
|
||||
#define C2P(_struct, _field, _pytype, _ctype) \
|
||||
do { \
|
||||
PyObject *obj = Py ## _pytype ## _From ## _ctype \
|
||||
@@ -647,6 +671,9 @@ static PyObject *xu_message_new(PyObject *self, PyObject *args)
|
||||
P2C(mem_request_t, target, u32);
|
||||
P2C(mem_request_t, status, u32);
|
||||
break;
|
||||
case TYPE(CMSG_SHUTDOWN, CMSG_SHUTDOWN_SYSRQ):
|
||||
P2C(shutdown_sysrq_t, key, char);
|
||||
break;
|
||||
}
|
||||
|
||||
if ( dict_items_parsed != PyDict_Size(payload) )
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
SV_PORT = 8080
|
||||
SV_ROOT = "/var/xen/sv/"
|
||||
PID_FILE = "/var/xen/sv.pid"
|
||||
SV_ROOT = "/var/lib/xen/sv/"
|
||||
PID_FILE = "/var/run/xen-sv.pid"
|
||||
@@ -78,6 +78,8 @@ class Args:
|
||||
val = str(v)
|
||||
elif type == 'sxpr':
|
||||
val = self.sxpr(v)
|
||||
elif type == 'bool':
|
||||
val = self.bool(v)
|
||||
else:
|
||||
raise ArgError('invalid type:' + str(type))
|
||||
return val
|
||||
@@ -86,6 +88,9 @@ class Args:
|
||||
except StandardError, ex:
|
||||
raise ArgError(str(ex))
|
||||
|
||||
def bool(self, v):
|
||||
return (v.lower() in ['on', 'yes', '1', 'true'])
|
||||
|
||||
def sxpr(self, v):
|
||||
if isinstance(v, types.ListType):
|
||||
val = v
|
||||
|
||||
@@ -37,6 +37,20 @@ def network(op, script=None, bridge=None, antispoof=None):
|
||||
args = ' '.join(args)
|
||||
os.system(script + ' ' + args)
|
||||
|
||||
def set_vif_name(vif_old, vif_new):
|
||||
if vif_old == vif_new:
|
||||
vif = vif_new
|
||||
return vif
|
||||
if os.system("ip link show %s" % vif_old) == 0:
|
||||
os.system("ip link set %s down" % vif_old)
|
||||
os.system("ip link set %s name %s" % (vif_old, vif_new))
|
||||
os.system("ip link set %s up" % vif_new)
|
||||
if os.system("ip link show %s" % vif_new) == 0:
|
||||
vif = vif_new
|
||||
else:
|
||||
vif = vif_old
|
||||
return vif
|
||||
|
||||
def vifctl(op, vif=None, script=None, domain=None, mac=None, bridge=None, ipaddr=[]):
|
||||
"""Call a vif control script.
|
||||
Xend calls this when bringing vifs up or down.
|
||||
|
||||
@@ -449,9 +449,9 @@ class XendDomainInfo:
|
||||
|
||||
self.init_domain()
|
||||
self.configure_console()
|
||||
self.configure_backends()
|
||||
self.construct_image()
|
||||
self.configure_restart()
|
||||
self.configure_backends()
|
||||
deferred = self.configure()
|
||||
def cberr(err):
|
||||
self.destroy()
|
||||
@@ -1227,6 +1227,7 @@ add_config_handler('memory', vm_field_ignore)
|
||||
add_config_handler('cpu', vm_field_ignore)
|
||||
add_config_handler('cpu_weight', vm_field_ignore)
|
||||
add_config_handler('console', vm_field_ignore)
|
||||
add_config_handler('restart', vm_field_ignore)
|
||||
add_config_handler('image', vm_field_ignore)
|
||||
add_config_handler('device', vm_field_ignore)
|
||||
add_config_handler('backend', vm_field_ignore)
|
||||
|
||||
@@ -6,12 +6,14 @@ import errno
|
||||
import sys
|
||||
import socket
|
||||
import time
|
||||
import types
|
||||
|
||||
from twisted.internet import reactor
|
||||
from twisted.internet import defer
|
||||
#defer.Deferred.debug = 1
|
||||
from twisted.internet.protocol import Protocol
|
||||
from twisted.internet.protocol import ClientFactory
|
||||
from twisted.python.failure import Failure
|
||||
|
||||
import sxp
|
||||
import XendDB
|
||||
@@ -45,11 +47,9 @@ class Xfrd(Protocol):
|
||||
sxp.show(req, out=self.transport)
|
||||
|
||||
def loseConnection(self):
|
||||
print 'Xfrd>loseConnection>'
|
||||
self.transport.loseConnection()
|
||||
|
||||
def connectionLost(self, reason):
|
||||
print 'Xfrd>connectionLost>', reason
|
||||
self.xinfo.connectionLost(reason)
|
||||
|
||||
def dataReceived(self, data):
|
||||
@@ -70,17 +70,15 @@ class XfrdClientFactory(ClientFactory):
|
||||
self.xinfo = xinfo
|
||||
|
||||
def startedConnecting(self, connector):
|
||||
print 'Started to connect', 'self=', self, 'connector=', connector
|
||||
pass
|
||||
|
||||
def buildProtocol(self, addr):
|
||||
print 'buildProtocol>', addr
|
||||
return Xfrd(self.xinfo)
|
||||
|
||||
def clientConnectionLost(self, connector, reason):
|
||||
print 'clientConnectionLost>', 'connector=', connector, 'reason=', reason
|
||||
pass
|
||||
|
||||
def clientConnectionFailed(self, connector, reason):
|
||||
print 'clientConnectionFailed>', 'connector=', connector, 'reason=', reason
|
||||
self.xinfo.error(reason)
|
||||
|
||||
class XfrdInfo:
|
||||
@@ -90,7 +88,7 @@ class XfrdInfo:
|
||||
|
||||
"""Suspend timeout (seconds).
|
||||
We set a timeout because suspending a domain can hang."""
|
||||
timeout = 30
|
||||
timeout = 10
|
||||
|
||||
def __init__(self):
|
||||
from xen.xend import XendDomain
|
||||
@@ -98,6 +96,9 @@ class XfrdInfo:
|
||||
self.deferred = defer.Deferred()
|
||||
self.suspended = {}
|
||||
self.paused = {}
|
||||
self.state = 'init'
|
||||
# List of errors encountered.
|
||||
self.errors = []
|
||||
|
||||
def vmconfig(self):
|
||||
dominfo = self.xd.domain_get(self.src_dom)
|
||||
@@ -107,12 +108,38 @@ class XfrdInfo:
|
||||
val = None
|
||||
return val
|
||||
|
||||
def add_error(self, err):
|
||||
"""Add an error to the error list.
|
||||
Returns the error added (which may have been unwrapped if it
|
||||
was a Twisted Failure).
|
||||
"""
|
||||
while isinstance(err, Failure):
|
||||
err = err.value
|
||||
if err not in self.errors:
|
||||
self.errors.append(err)
|
||||
return err
|
||||
|
||||
def error_summary(self, msg=None):
|
||||
"""Get a XendError summarising the errors (if any).
|
||||
"""
|
||||
if msg is None:
|
||||
msg = "errors"
|
||||
if self.errors:
|
||||
errmsg = msg + ': ' + ', '.join(map(str, self.errors))
|
||||
else:
|
||||
errmsg = msg
|
||||
return XendError(errmsg)
|
||||
|
||||
def get_errors(self):
|
||||
"""Get the list of errors.
|
||||
"""
|
||||
return self.errors
|
||||
|
||||
def error(self, err):
|
||||
print 'Error>', err
|
||||
self.state = 'error'
|
||||
self.add_error(err)
|
||||
if not self.deferred.called:
|
||||
print 'Error> calling errback'
|
||||
self.deferred.errback(err)
|
||||
self.deferred.errback(self.error_summary())
|
||||
|
||||
def dispatch(self, xfrd, val):
|
||||
|
||||
@@ -139,28 +166,23 @@ class XfrdInfo:
|
||||
cbok(val)
|
||||
|
||||
def unknown(self, xfrd, val):
|
||||
print 'unknown>', val
|
||||
xfrd.loseConnection()
|
||||
return None
|
||||
|
||||
def xfr_err(self, xfrd, val):
|
||||
# If we get an error with non-zero code the operation failed.
|
||||
# An error with code zero indicates hello success.
|
||||
print 'xfr_err>', val
|
||||
v = sxp.child0(val)
|
||||
print 'xfr_err>', type(v), v
|
||||
err = int(sxp.child0(val))
|
||||
if not err: return
|
||||
self.error(err);
|
||||
self.error("transfer daemon (xfrd) error: " + str(err))
|
||||
xfrd.loseConnection()
|
||||
return None
|
||||
|
||||
def xfr_progress(self, xfrd, val):
|
||||
print 'xfr_progress>', val
|
||||
return None
|
||||
|
||||
def xfr_vm_destroy(self, xfrd, val):
|
||||
print 'xfr_vm_destroy>', val
|
||||
try:
|
||||
vmid = sxp.child0(val)
|
||||
val = self.xd.domain_destroy(vmid)
|
||||
@@ -168,28 +190,32 @@ class XfrdInfo:
|
||||
del self.paused[vmid]
|
||||
if vmid in self.suspended:
|
||||
del self.suspended[vmid]
|
||||
except:
|
||||
except StandardError, err:
|
||||
self.add_error("vm_destroy failed")
|
||||
self.add_error(err)
|
||||
val = errno.EINVAL
|
||||
return ['xfr.err', val]
|
||||
|
||||
def xfr_vm_pause(self, xfrd, val):
|
||||
print 'xfr_vm_pause>', val
|
||||
try:
|
||||
vmid = sxp.child0(val)
|
||||
val = self.xd.domain_pause(vmid)
|
||||
self.paused[vmid] = 1
|
||||
except:
|
||||
except StandardError, err:
|
||||
self.add_error("vm_pause failed")
|
||||
self.add_error(err)
|
||||
val = errno.EINVAL
|
||||
return ['xfr.err', val]
|
||||
|
||||
def xfr_vm_unpause(self, xfrd, val):
|
||||
print 'xfr_vm_unpause>', val
|
||||
try:
|
||||
vmid = sxp.child0(val)
|
||||
val = self.xd.domain_unpause(vmid)
|
||||
if vmid in self.paused:
|
||||
del self.paused[vmid]
|
||||
except:
|
||||
except StandardError, err:
|
||||
self.add_error("vm_unpause failed")
|
||||
self.add_error(err)
|
||||
val = errno.EINVAL
|
||||
return ['xfr.err', val]
|
||||
|
||||
@@ -199,7 +225,6 @@ class XfrdInfo:
|
||||
Suspending can hang, so we set a timeout and fail if it
|
||||
takes too long.
|
||||
"""
|
||||
print 'xfr_vm_suspend>', val
|
||||
try:
|
||||
vmid = sxp.child0(val)
|
||||
d = defer.Deferred()
|
||||
@@ -208,15 +233,15 @@ class XfrdInfo:
|
||||
# the domain died. Set a timeout and error handler so the subscriptions
|
||||
# will be cleaned up if suspending hangs or there is an error.
|
||||
def onSuspended(e, v):
|
||||
print 'xfr_vm_suspend>onSuspended>', e, v
|
||||
if v[1] != vmid: return
|
||||
subscribe(on=0)
|
||||
d.callback(v)
|
||||
if not d.called:
|
||||
d.callback(v)
|
||||
|
||||
def onDied(e, v):
|
||||
print 'xfr_vm_suspend>onDied>', e, v
|
||||
if v[1] != vmid: return
|
||||
d.errback(XendError('Domain died'))
|
||||
if not d.called:
|
||||
d.errback(XendError('Domain %s died while suspending' % vmid))
|
||||
|
||||
def subscribe(on=1):
|
||||
if on:
|
||||
@@ -227,24 +252,25 @@ class XfrdInfo:
|
||||
action('xend.domain.died', onDied)
|
||||
|
||||
def cberr(err):
|
||||
print 'xfr_vm_suspend>cberr>', err
|
||||
subscribe(on=0)
|
||||
self.add_error("suspend failed")
|
||||
self.add_error(err)
|
||||
return err
|
||||
|
||||
d.addErrback(cberr)
|
||||
d.setTimeout(self.timeout)
|
||||
subscribe()
|
||||
val = self.xd.domain_shutdown(vmid, reason='suspend')
|
||||
self.suspended[vmid] = 1
|
||||
d.addErrback(cberr)
|
||||
d.setTimeout(self.timeout)
|
||||
return d
|
||||
except Exception, err:
|
||||
print 'xfr_vm_suspend> Exception', err
|
||||
self.add_error("suspend failed")
|
||||
self.add_error(err)
|
||||
traceback.print_exc()
|
||||
val = errno.EINVAL
|
||||
return ['xfr.err', val]
|
||||
|
||||
def connectionLost(self, reason=None):
|
||||
print 'XfrdInfo>connectionLost>', reason
|
||||
for vmid in self.suspended:
|
||||
try:
|
||||
self.xd.domain_destroy(vmid)
|
||||
@@ -279,7 +305,7 @@ class XendMigrateInfo(XfrdInfo):
|
||||
['id', self.xid ],
|
||||
['state', self.state ],
|
||||
['live', self.live ],
|
||||
['resource', self.resource] ]
|
||||
['resource', self.resource ] ]
|
||||
sxpr_src = ['src', ['host', self.src_host], ['domain', self.src_dom] ]
|
||||
sxpr.append(sxpr_src)
|
||||
sxpr_dst = ['dst', ['host', self.dst_host] ]
|
||||
@@ -291,12 +317,12 @@ class XendMigrateInfo(XfrdInfo):
|
||||
def request(self, xfrd):
|
||||
vmconfig = self.vmconfig()
|
||||
if not vmconfig:
|
||||
self.error(XendError("vm config not found"))
|
||||
xfrd.loseConnection()
|
||||
return
|
||||
log.info('Migrate BEGIN: ' + str(self.sxpr()))
|
||||
log.info('Migrate BEGIN: %s' % str(self.sxpr()))
|
||||
eserver.inject('xend.domain.migrate',
|
||||
[ self.dominfo.name, self.dominfo.id,
|
||||
"begin", self.sxpr() ])
|
||||
[ self.dominfo.name, self.dominfo.id, "begin", self.sxpr() ])
|
||||
xfrd.request(['xfr.migrate',
|
||||
self.src_dom,
|
||||
vmconfig,
|
||||
@@ -305,19 +331,6 @@ class XendMigrateInfo(XfrdInfo):
|
||||
self.live,
|
||||
self.resource ])
|
||||
|
||||
## def xfr_vm_suspend(self, xfrd, val):
|
||||
## def cbok(val):
|
||||
## # Special case for localhost: destroy devices early.
|
||||
## if self.dst_host in ["localhost", "127.0.0.1"]:
|
||||
## self.dominfo.restart_cancel()
|
||||
## self.dominfo.cleanup()
|
||||
## self.dominfo.destroy_console()
|
||||
## return val
|
||||
|
||||
## d = XfrdInfo.xfr_vm_suspend(self, xfrd, val)
|
||||
## d.addCallback(cbok)
|
||||
## return d
|
||||
|
||||
def xfr_migrate_ok(self, xfrd, val):
|
||||
dom = int(sxp.child0(val))
|
||||
self.state = 'ok'
|
||||
@@ -327,17 +340,15 @@ class XendMigrateInfo(XfrdInfo):
|
||||
self.deferred.callback(self)
|
||||
|
||||
def connectionLost(self, reason=None):
|
||||
print 'XfrdMigrateInfo>connectionLost>', reason
|
||||
XfrdInfo.connectionLost(self, reason)
|
||||
if self.state =='ok':
|
||||
log.info('Migrate OK: ' + str(self.sxpr()))
|
||||
else:
|
||||
self.state = 'error'
|
||||
self.error(XendError("migrate failed"))
|
||||
self.error("migrate failed")
|
||||
log.info('Migrate ERROR: ' + str(self.sxpr()))
|
||||
eserver.inject('xend.domain.migrate',
|
||||
[ self.dominfo.name, self.dominfo.id,
|
||||
self.state, self.sxpr() ])
|
||||
[ self.dominfo.name, self.dominfo.id, self.state, self.sxpr() ])
|
||||
|
||||
class XendSaveInfo(XfrdInfo):
|
||||
"""Representation of a save in-progress and its interaction with xfrd.
|
||||
@@ -361,16 +372,15 @@ class XendSaveInfo(XfrdInfo):
|
||||
return sxpr
|
||||
|
||||
def request(self, xfrd):
|
||||
print '***request>', self.vmconfig()
|
||||
vmconfig = self.vmconfig()
|
||||
if not vmconfig:
|
||||
self.error(XendError("vm config not found"))
|
||||
xfrd.loseConnection()
|
||||
return
|
||||
print '***request> begin'
|
||||
log.info('Save BEGIN: ' + str(self.sxpr()))
|
||||
eserver.inject('xend.domain.save',
|
||||
[self.dominfo.name, self.dominfo.id,
|
||||
"begin", self.sxpr()])
|
||||
[ self.dominfo.name, self.dominfo.id,
|
||||
"begin", self.sxpr() ])
|
||||
xfrd.request(['xfr.save', self.src_dom, vmconfig, self.file ])
|
||||
|
||||
def xfr_save_ok(self, xfrd, val):
|
||||
@@ -380,13 +390,12 @@ class XendSaveInfo(XfrdInfo):
|
||||
self.deferred.callback(self)
|
||||
|
||||
def connectionLost(self, reason=None):
|
||||
print 'XfrdSaveInfo>connectionLost>', reason
|
||||
XfrdInfo.connectionLost(self, reason)
|
||||
if self.state =='ok':
|
||||
log.info('Save OK: ' + str(self.sxpr()))
|
||||
else:
|
||||
self.state = 'error'
|
||||
self.error(XendError("save failed"))
|
||||
self.error("save failed")
|
||||
log.info('Save ERROR: ' + str(self.sxpr()))
|
||||
eserver.inject('xend.domain.save',
|
||||
[ self.dominfo.name, self.dominfo.id,
|
||||
@@ -409,8 +418,9 @@ class XendRestoreInfo(XfrdInfo):
|
||||
return sxpr
|
||||
|
||||
def request(self, xfrd):
|
||||
print '***request>', self.file
|
||||
log.info('restore BEGIN: ' + str(self.sxpr()))
|
||||
eserver.inject('xend.restore', [ 'begin', self.sxpr()])
|
||||
|
||||
xfrd.request(['xfr.restore', self.file ])
|
||||
|
||||
def xfr_restore_ok(self, xfrd, val):
|
||||
@@ -419,8 +429,17 @@ class XendRestoreInfo(XfrdInfo):
|
||||
self.state = 'ok'
|
||||
if not self.deferred.called:
|
||||
self.deferred.callback(dominfo)
|
||||
|
||||
|
||||
def connectionLost(self, reason=None):
|
||||
XfrdInfo.connectionLost(self, reason)
|
||||
if self.state =='ok':
|
||||
log.info('Restore OK: ' + self.file)
|
||||
else:
|
||||
self.state = 'error'
|
||||
self.error("restore failed")
|
||||
log.info('Restore ERROR: ' + str(self.sxpr()))
|
||||
eserver.inject('xend.restore', [ self.state, self.sxpr()])
|
||||
|
||||
class XendMigrate:
|
||||
"""External api for interaction with xfrd for migrate and save.
|
||||
Singleton.
|
||||
@@ -445,7 +464,6 @@ class XendMigrate:
|
||||
self.db.saveall("", self.session_db)
|
||||
|
||||
def sync_session(self, xid):
|
||||
print 'sync_session>', type(xid), xid, self.session_db[xid]
|
||||
self.db.save(xid, self.session_db[xid])
|
||||
|
||||
def close(self):
|
||||
@@ -458,7 +476,6 @@ class XendMigrate:
|
||||
self.sync_session(xid)
|
||||
|
||||
def _delete_session(self, xid):
|
||||
print '***_delete_session>', xid
|
||||
if xid in self.session:
|
||||
del self.session[xid]
|
||||
if xid in self.session_db:
|
||||
@@ -482,16 +499,23 @@ class XendMigrate:
|
||||
@param info: session
|
||||
@return: deferred
|
||||
"""
|
||||
def cbremove(val):
|
||||
print '***cbremove>', val
|
||||
dfr = defer.Deferred()
|
||||
def cbok(val):
|
||||
self._delete_session(info.xid)
|
||||
if not dfr.called:
|
||||
dfr.callback(val)
|
||||
return val
|
||||
def cberr(err):
|
||||
self._delete_session(info.xid)
|
||||
if not dfr.called:
|
||||
dfr.errback(err)
|
||||
return err
|
||||
self._add_session(info)
|
||||
info.deferred.addCallback(cbremove)
|
||||
info.deferred.addErrback(cbremove)
|
||||
info.deferred.addCallback(cbok)
|
||||
info.deferred.addErrback(cberr)
|
||||
xcf = XfrdClientFactory(info)
|
||||
reactor.connectTCP('localhost', XFRD_PORT, xcf)
|
||||
return info.deferred
|
||||
return dfr
|
||||
|
||||
def migrate_begin(self, dominfo, host, port=XFRD_PORT, live=0, resource=0):
|
||||
"""Begin to migrate a domain to another host.
|
||||
|
||||
@@ -2,6 +2,11 @@
|
||||
|
||||
"""Xend root class.
|
||||
Creates the event server and handles configuration.
|
||||
|
||||
Other classes get config variables by importing this module,
|
||||
using instance() to get a XendRoot instance, and then
|
||||
the config functions (e.g. get_xend_port()) to get
|
||||
configured values.
|
||||
"""
|
||||
|
||||
import os
|
||||
@@ -20,7 +25,7 @@ class XendRoot:
|
||||
"""Root of the management classes."""
|
||||
|
||||
"""Default path to the root of the database."""
|
||||
dbroot_default = "/var/xen/xend-db"
|
||||
dbroot_default = "/var/lib/xen/xend-db"
|
||||
|
||||
"""Default path to the config file."""
|
||||
config_default = "/etc/xen/xend-config.sxp"
|
||||
@@ -34,17 +39,33 @@ class XendRoot:
|
||||
"""Where block control scripts live."""
|
||||
block_script_dir = "/etc/xen/scripts"
|
||||
|
||||
"""Default path to the log file. """
|
||||
logfile_default = "/var/log/xend.log"
|
||||
|
||||
loglevel_default = 'DEBUG'
|
||||
|
||||
"""Default interface address xend listens at. """
|
||||
xend_address_default = ''
|
||||
|
||||
"""Default port xend serves HTTP at. """
|
||||
xend_port_default = '8000'
|
||||
|
||||
"""Default port xend serves events at. """
|
||||
xend_event_port_default = '8001'
|
||||
|
||||
"""Default inteface address xend listens at for consoles."""
|
||||
console_address_default = ''
|
||||
|
||||
"""Default port xend serves consoles at. """
|
||||
console_port_base_default = '9600'
|
||||
|
||||
components = {}
|
||||
|
||||
def __init__(self):
|
||||
self.dbroot = None
|
||||
self.config_path = None
|
||||
self.config = None
|
||||
self.logger = None
|
||||
self.logging = None
|
||||
self.configure()
|
||||
eserver.subscribe('xend.*', self.event_handler)
|
||||
#eserver.subscribe('xend.domain.created', self.event_handler)
|
||||
@@ -73,9 +94,9 @@ class XendRoot:
|
||||
|
||||
def _format(self, msg, args):
|
||||
if args:
|
||||
return str(msg)
|
||||
else:
|
||||
return str(msg) % args
|
||||
else:
|
||||
return str(msg)
|
||||
|
||||
def _log(self, mode, fmt, args):
|
||||
"""Logging function that uses the logger if it exists, otherwise
|
||||
@@ -90,7 +111,7 @@ class XendRoot:
|
||||
if log:
|
||||
getattr(log, mode)(fmt, *args)
|
||||
else:
|
||||
print >>stderr, "xend", "[%s]" % level, self._format(msg, args)
|
||||
print >>sys.stderr, "xend", "[%s]" % level, self._format(fmt, args)
|
||||
|
||||
def logDebug(self, fmt, *args):
|
||||
"""Log a debug message.
|
||||
@@ -132,7 +153,6 @@ class XendRoot:
|
||||
self.configure_logger()
|
||||
self.dbroot = self.get_config_value("dbroot", self.dbroot_default)
|
||||
|
||||
|
||||
def configure_logger(self):
|
||||
logfile = self.get_config_value("logfile", self.logfile_default)
|
||||
loglevel = self.get_config_value("loglevel", self.loglevel_default)
|
||||
@@ -146,7 +166,7 @@ class XendRoot:
|
||||
def get_logger(self):
|
||||
"""Get the logger.
|
||||
"""
|
||||
return self.logging.getLogger()
|
||||
return self.logging and self.logging.getLogger()
|
||||
|
||||
def get_dbroot(self):
|
||||
"""Get the path to the database root.
|
||||
@@ -160,14 +180,20 @@ class XendRoot:
|
||||
"""
|
||||
self.config_path = os.getenv(self.config_var, self.config_default)
|
||||
if os.path.exists(self.config_path):
|
||||
fin = file(self.config_path, 'rb')
|
||||
#self.logInfo('Reading config file %s', self.config_path)
|
||||
try:
|
||||
config = sxp.parse(fin)
|
||||
fin = file(self.config_path, 'rb')
|
||||
try:
|
||||
config = sxp.parse(fin)
|
||||
finally:
|
||||
fin.close()
|
||||
config.insert(0, 'xend-config')
|
||||
self.config = config
|
||||
finally:
|
||||
fin.close()
|
||||
except Exception, ex:
|
||||
self.logError('Reading config file %s: %s', self.config_path, str(ex))
|
||||
raise
|
||||
else:
|
||||
self.logError('Config file does not exist: %s', self.config_path)
|
||||
self.config = ['xend-config']
|
||||
|
||||
def get_config(self, name=None):
|
||||
@@ -193,10 +219,35 @@ class XendRoot:
|
||||
return sxp.child_value(self.config, name, val=val)
|
||||
|
||||
def get_xend_port(self):
|
||||
return int(self.get_config_value('xend-port', '8000'))
|
||||
"""Get the port xend listens at for its HTTP interface.
|
||||
"""
|
||||
return int(self.get_config_value('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 int(self.get_config_value('xend-event-port', self.xend_event_port_default))
|
||||
|
||||
def get_xend_address(self):
|
||||
return self.get_config_value('xend-address', '')
|
||||
"""Get the address xend listens at for its HTTP and event ports.
|
||||
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.
|
||||
"""
|
||||
return self.get_config_value('xend-address', self.xend_address_default)
|
||||
|
||||
def get_console_address(self):
|
||||
"""Get the address xend listens at for its console ports.
|
||||
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 console ports.
|
||||
"""
|
||||
return self.get_config_value('console-address', self.console_address_default)
|
||||
|
||||
def get_console_port_base(self):
|
||||
"""Get the base port number used to generate console ports for domains.
|
||||
"""
|
||||
return int(self.get_config_value('console-port-base', self.console_port_base_default))
|
||||
|
||||
def get_block_script(self, type):
|
||||
return self.get_config_value('block-%s' % type, '')
|
||||
|
||||
@@ -106,7 +106,8 @@ class SrvBase(resource.Resource):
|
||||
try:
|
||||
val = op_method(op, req)
|
||||
except Exception, err:
|
||||
return self._perform_err(err, op, req)
|
||||
self._perform_err(err, op, req)
|
||||
return ''
|
||||
|
||||
if isinstance(val, defer.Deferred):
|
||||
val.addCallback(self._perform_cb, op, req, dfr=1)
|
||||
|
||||
@@ -15,6 +15,7 @@ import pwd
|
||||
import re
|
||||
import StringIO
|
||||
import traceback
|
||||
import time
|
||||
|
||||
from twisted.internet import pollreactor
|
||||
pollreactor.install()
|
||||
@@ -484,10 +485,12 @@ class Daemon:
|
||||
# XXX KAF: Why doesn't this capture output from C extensions that
|
||||
# fprintf(stdout) or fprintf(stderr) ??
|
||||
os.open('/var/log/xend-debug.log', os.O_WRONLY|os.O_CREAT)
|
||||
os.dup(1)
|
||||
else:
|
||||
os.open('/dev/null', os.O_RDWR)
|
||||
os.dup(0)
|
||||
os.dup(1)
|
||||
os.open('/var/log/xend-debug.log', os.O_WRONLY|os.O_CREAT)
|
||||
|
||||
|
||||
def start(self, trace=0):
|
||||
"""Attempts to start the daemons.
|
||||
@@ -514,8 +517,8 @@ class Daemon:
|
||||
self.install_child_reaper()
|
||||
|
||||
if self.fork_pid(XEND_PID_FILE):
|
||||
#Parent
|
||||
pass
|
||||
#Parent. Sleep to give child time to start.
|
||||
time.sleep(1)
|
||||
else:
|
||||
# Child
|
||||
self.tracing(trace)
|
||||
@@ -593,10 +596,10 @@ class Daemon:
|
||||
def set_user(self):
|
||||
# Set the UID.
|
||||
try:
|
||||
os.setuid(pwd.getpwnam(USER)[2])
|
||||
os.setuid(pwd.getpwnam(XEND_USER)[2])
|
||||
return 0
|
||||
except KeyError, error:
|
||||
print "Error: no such user '%s'" % USER
|
||||
print "Error: no such user '%s'" % XEND_USER
|
||||
return 1
|
||||
|
||||
def stop(self):
|
||||
@@ -606,7 +609,7 @@ class Daemon:
|
||||
xroot = XendRoot.instance()
|
||||
log.info("Xend Daemon started")
|
||||
self.createFactories()
|
||||
self.listenEvent()
|
||||
self.listenEvent(xroot)
|
||||
self.listenNotifier()
|
||||
self.listenVirq()
|
||||
SrvServer.create(bridge=1)
|
||||
@@ -619,9 +622,11 @@ class Daemon:
|
||||
self.netifCF = netif.NetifControllerFactory()
|
||||
self.consoleCF = console.ConsoleControllerFactory()
|
||||
|
||||
def listenEvent(self):
|
||||
def listenEvent(self, xroot):
|
||||
protocol = EventFactory(self)
|
||||
return reactor.listenTCP(EVENT_PORT, protocol)
|
||||
port = xroot.get_xend_event_port()
|
||||
interface = xroot.get_xend_address()
|
||||
return reactor.listenTCP(port, protocol, interface=interface)
|
||||
|
||||
def listenNotifier(self):
|
||||
protocol = NotifierProtocol(self.channelF)
|
||||
|
||||
@@ -88,7 +88,7 @@ class SrvDir(SrvBase):
|
||||
req.write('</body></html>')
|
||||
return ''
|
||||
except Exception, ex:
|
||||
self._perform_err(ex, req)
|
||||
self._perform_err(ex, "GET", req)
|
||||
|
||||
def ls(self, req, use_sxp=0):
|
||||
url = req.prePathURL()
|
||||
|
||||
@@ -29,13 +29,8 @@ class SrvDomain(SrvDir):
|
||||
[['dom', 'int'],
|
||||
['config', 'sxpr']])
|
||||
deferred = fn(req.args, {'dom': self.dom.dom})
|
||||
deferred.addErrback(self._op_configure_err, req)
|
||||
return deferred
|
||||
|
||||
def _op_configure_err(self, err, req):
|
||||
req.setResponseCode(http.BAD_REQUEST, "Error: "+ str(err))
|
||||
return str(err)
|
||||
|
||||
def op_unpause(self, op, req):
|
||||
val = self.xd.domain_unpause(self.dom.name)
|
||||
return val
|
||||
@@ -68,16 +63,11 @@ class SrvDomain(SrvDir):
|
||||
['file', 'str']])
|
||||
deferred = fn(req.args, {'dom': self.dom.id})
|
||||
deferred.addCallback(self._op_save_cb, req)
|
||||
deferred.addErrback(self._op_save_err, req)
|
||||
return deferred
|
||||
|
||||
def _op_save_cb(self, val, req):
|
||||
return 0
|
||||
|
||||
def _op_save_err(self, err, req):
|
||||
req.setResponseCode(http.BAD_REQUEST, "Error: "+ str(err))
|
||||
return str(err)
|
||||
|
||||
def op_migrate(self, op, req):
|
||||
fn = FormFn(self.xd.domain_migrate,
|
||||
[['dom', 'str'],
|
||||
@@ -85,9 +75,7 @@ class SrvDomain(SrvDir):
|
||||
['live', 'int'],
|
||||
['resource', 'int']])
|
||||
deferred = fn(req.args, {'dom': self.dom.id})
|
||||
print 'op_migrate>', deferred
|
||||
deferred.addCallback(self._op_migrate_cb, req)
|
||||
deferred.addErrback(self._op_migrate_err, req)
|
||||
return deferred
|
||||
|
||||
def _op_migrate_cb(self, info, req):
|
||||
@@ -101,11 +89,6 @@ class SrvDomain(SrvDir):
|
||||
print '_op_migrate_cb> url=', url
|
||||
return url
|
||||
|
||||
def _op_migrate_err(self, err, req):
|
||||
print '_op_migrate_err>', err, req
|
||||
req.setResponseCode(http.BAD_REQUEST, "Error: "+ str(err))
|
||||
return str(err)
|
||||
|
||||
def op_pincpu(self, op, req):
|
||||
fn = FormFn(self.xd.domain_pincpu,
|
||||
[['dom', 'str'],
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/python2
|
||||
#!/usr/bin/python
|
||||
# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
|
||||
|
||||
"""Example xend HTTP and console server.
|
||||
|
||||
@@ -66,8 +66,11 @@ def blkdev_name_to_number(name):
|
||||
if re.match( '/dev/sd[a-p]([0-9]|1[0-5])', n):
|
||||
return 8 * 256 + 16 * (ord(n[7:8]) - ord('a')) + int(n[8:])
|
||||
|
||||
if re.match( '/dev/hd[a-p]([0-9]|[1-5][0-9]|6[0-3])', n):
|
||||
return 3 * 256 + 16 * (ord(n[7:8]) - ord('a')) + int(n[8:])
|
||||
if re.match( '/dev/hd[a-t]([1-9]|[1-5][0-9]|6[0-3])?', n):
|
||||
ide_majors = [ 3, 22, 33, 34, 56, 57, 88, 89, 90, 91 ]
|
||||
major = ide_majors[(ord(n[7:8]) - ord('a')) / 2]
|
||||
minor = ((ord(n[7:8]) - ord('a')) % 2) * 64 + int(n[8:] or 0)
|
||||
return major * 256 + minor
|
||||
|
||||
# see if this is a hex device number
|
||||
if re.match( '^(0x)?[0-9a-fA-F]+$', name ):
|
||||
@@ -178,6 +181,8 @@ class BlkifBackendInterface(controller.BackendInterface):
|
||||
self.close()
|
||||
d = defer.Deferred()
|
||||
d.addCallback(cb_destroy)
|
||||
if self.evtchn:
|
||||
channel.eventChannelClose(self.evtchn)
|
||||
self.send_be_disconnect(response=d)
|
||||
|
||||
def send_be_disconnect(self, response=None):
|
||||
|
||||
@@ -11,7 +11,31 @@ VIRQ_CONSOLE = 3 # (DOM0) bytes received on emergency console.
|
||||
VIRQ_DOM_EXC = 4 # (DOM0) Exceptional event for some domain.
|
||||
|
||||
def eventChannel(dom1, dom2):
|
||||
return xc.evtchn_bind_interdomain(dom1=dom1, dom2=dom2)
|
||||
"""Create an event channel between domains.
|
||||
The returned dict contains dom1, dom2, port1 and port2 on success.
|
||||
|
||||
@return dict (empty on error)
|
||||
"""
|
||||
evtchn = xc.evtchn_bind_interdomain(dom1=dom1, dom2=dom2)
|
||||
if evtchn:
|
||||
evtchn['dom1'] = dom1
|
||||
evtchn['dom2'] = dom2
|
||||
return evtchn
|
||||
|
||||
def eventChannelClose(evtchn):
|
||||
"""Close an event channel that was opened by eventChannel().
|
||||
"""
|
||||
def evtchn_close(dom, port):
|
||||
if (dom is None) or (port is None): return
|
||||
try:
|
||||
xc.evtchn_close(dom=dom, port=port)
|
||||
except Exception, ex:
|
||||
pass
|
||||
|
||||
if not evtchn: return
|
||||
evtchn_close(evtchn.get('dom1'), evtchn.get('port1'))
|
||||
evtchn_close(evtchn.get('dom2'), evtchn.get('port2'))
|
||||
|
||||
|
||||
class ChannelFactory:
|
||||
"""Factory for creating channels.
|
||||
|
||||
@@ -11,6 +11,8 @@ from xen.xend.XendError import XendError
|
||||
from xen.xend import EventServer
|
||||
eserver = EventServer.instance()
|
||||
from xen.xend.XendLogging import log
|
||||
from xen.xend import XendRoot
|
||||
xroot = XendRoot.instance()
|
||||
|
||||
import controller
|
||||
from messages import *
|
||||
@@ -82,7 +84,7 @@ class ConsoleControllerFactory(controller.ControllerFactory):
|
||||
|
||||
def createController(self, dom, console_port=None):
|
||||
if console_port is None:
|
||||
console_port = CONSOLE_PORT_BASE + dom
|
||||
console_port = xroot.get_console_port_base() + dom
|
||||
for c in self.getControllers():
|
||||
if c.console_port == console_port:
|
||||
raise XendError('console port in use: ' + str(console_port))
|
||||
@@ -191,7 +193,8 @@ class ConsoleController(controller.Controller):
|
||||
pass
|
||||
else:
|
||||
f = ConsoleFactory(self, self.idx)
|
||||
self.listener = reactor.listenTCP(self.console_port, f)
|
||||
interface = xroot.get_console_address()
|
||||
self.listener = reactor.listenTCP(self.console_port, f, interface=interface)
|
||||
|
||||
def connect(self, addr, conn):
|
||||
"""Connect a TCP connection to the console.
|
||||
|
||||
@@ -130,7 +130,13 @@ class NetDev(controller.SplitDev):
|
||||
self.bridge = None
|
||||
self.script = None
|
||||
self.ipaddr = []
|
||||
self.vifname = None
|
||||
|
||||
self.vifname = sxp.child_value(config, 'vifname')
|
||||
if self.vifname is None:
|
||||
self.vifname = self.default_vifname()
|
||||
if len(self.vifname) > 15:
|
||||
raise XendError('invalid vifname: too long: ' + self.vifname)
|
||||
mac = self._get_config_mac(config)
|
||||
if mac is None:
|
||||
raise XendError("invalid mac")
|
||||
@@ -140,7 +146,8 @@ class NetDev(controller.SplitDev):
|
||||
self.ipaddr = self._get_config_ipaddr(config) or []
|
||||
|
||||
try:
|
||||
self.backendDomain = int(sxp.child_value(config, 'backend', '0'))
|
||||
xd = get_component('xen.xend.XendDomain')
|
||||
self.backendDomain = int(xd.domain_lookup(sxp.child_value(config, 'backend', '0')).id)
|
||||
except:
|
||||
raise XendError('invalid backend domain')
|
||||
|
||||
@@ -161,7 +168,8 @@ class NetDev(controller.SplitDev):
|
||||
bridge = sxp.child_value(config, 'bridge')
|
||||
script = sxp.child_value(config, 'script')
|
||||
ipaddr = self._get_config_ipaddr(config)
|
||||
backendDomain = sxp.child_value(config, 'backend', '0')
|
||||
xd = get_component('xen.xend.XendDomain')
|
||||
backendDomain = str(xd.domain_lookup(sxp.child_value(config, 'backend', '0')).id)
|
||||
if (mac is not None) and (mac != self.mac):
|
||||
raise XendError("cannot change mac")
|
||||
if (backendDomain is not None) and (backendDomain != str(self.backendDomain)):
|
||||
@@ -187,7 +195,9 @@ class NetDev(controller.SplitDev):
|
||||
val = ['vif',
|
||||
['idx', self.idx],
|
||||
['vif', vif],
|
||||
['mac', mac]]
|
||||
['mac', mac],
|
||||
['vifname', self.vifname],
|
||||
]
|
||||
if self.bridge:
|
||||
val.append(['bridge', self.bridge])
|
||||
if self.script:
|
||||
@@ -205,8 +215,11 @@ class NetDev(controller.SplitDev):
|
||||
def get_vifname(self):
|
||||
"""Get the virtual interface device name.
|
||||
"""
|
||||
return "vif%d.%d" % (self.controller.dom, self.vif)
|
||||
return self.vifname
|
||||
|
||||
def default_vifname(self):
|
||||
return "vif%d.%d" % (self.controller.dom, self.vif)
|
||||
|
||||
def get_mac(self):
|
||||
"""Get the MAC address as a string.
|
||||
"""
|
||||
@@ -238,6 +251,8 @@ class NetDev(controller.SplitDev):
|
||||
@param op: operation name (up, down)
|
||||
@param vmname: vmname
|
||||
"""
|
||||
if op == 'up':
|
||||
Vifctl.set_vif_name(self.default_vifname(), self.vifname)
|
||||
Vifctl.vifctl(op, **self.vifctl_params(vmname=vmname))
|
||||
vnet = XendVnet.instance().vnet_of_bridge(self.bridge)
|
||||
if vnet:
|
||||
@@ -265,7 +280,9 @@ class NetDev(controller.SplitDev):
|
||||
msg = packMsg('netif_be_create_t',
|
||||
{ 'domid' : self.controller.dom,
|
||||
'netif_handle' : self.vif,
|
||||
'mac' : self.mac })
|
||||
'mac' : self.mac,
|
||||
#'vifname' : self.vifname
|
||||
})
|
||||
self.getBackendInterface().writeRequest(msg, response=d)
|
||||
return d
|
||||
|
||||
@@ -286,6 +303,8 @@ class NetDev(controller.SplitDev):
|
||||
if change:
|
||||
self.reportStatus()
|
||||
log.debug("Destroying vif domain=%d vif=%d", self.controller.dom, self.vif)
|
||||
if self.evtchn:
|
||||
channel.eventChannelClose(self.evtchn)
|
||||
self.vifctl('down')
|
||||
d = self.send_be_disconnect()
|
||||
d.addCallback(cb_destroy)
|
||||
|
||||
@@ -3,9 +3,5 @@ XEND_PID_FILE = '/var/run/xend.pid'
|
||||
XFRD_PID_FILE = '/var/run/xfrd.pid'
|
||||
XEND_TRACE_FILE = '/var/log/xend.trace'
|
||||
|
||||
USER = 'root'
|
||||
|
||||
EVENT_PORT = 8001
|
||||
|
||||
CONSOLE_PORT_BASE = 9600
|
||||
XEND_USER = 'root'
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/python2
|
||||
#!/usr/bin/python
|
||||
# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
|
||||
"""
|
||||
Input-driven parsing for s-expression (sxp) format.
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
import random
|
||||
import string
|
||||
import sys
|
||||
import socket
|
||||
|
||||
from xen.xend import sxp
|
||||
from xen.xend import PrettyPrint
|
||||
@@ -81,6 +82,14 @@ gopts.opt('console_autoconnect', short='c',
|
||||
fn=set_true, default=0,
|
||||
use="Connect to the console after the domain is created.")
|
||||
|
||||
gopts.var('vnc', val='no|yes',
|
||||
fn=set_bool, default=None,
|
||||
use="""Spawn a vncviewer listening for a vnc server in the domain.
|
||||
The address of the vncviewer is passed to the domain on the kernel command
|
||||
line using 'VNC_SERVER=<host>:<port>'. The port used by vnc is 5500 + DISPLAY.
|
||||
A display value with a free port is chosen if possible.
|
||||
""")
|
||||
|
||||
gopts.var('name', val='NAME',
|
||||
fn=set_value, default=None,
|
||||
use="Domain name. Must be unique.")
|
||||
@@ -151,7 +160,7 @@ gopts.var('ipaddr', val="IPADDR",
|
||||
fn=append_value, default=[],
|
||||
use="Add an IP address to the domain.")
|
||||
|
||||
gopts.var('vif', val="mac=MAC,bridge=BRIDGE,script=SCRIPT,backend=DOM",
|
||||
gopts.var('vif', val="mac=MAC,bridge=BRIDGE,script=SCRIPT,backend=DOM,vifname=NAME",
|
||||
fn=append_value, default=[],
|
||||
use="""Add a network interface with the given MAC address and bridge.
|
||||
The vif is configured by calling the given configuration script.
|
||||
@@ -159,6 +168,8 @@ gopts.var('vif', val="mac=MAC,bridge=BRIDGE,script=SCRIPT,backend=DOM",
|
||||
If bridge is not specified the default bridge 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
|
||||
where D is the domain id and N is the interface id.
|
||||
This option may be repeated to add more than one vif.
|
||||
Specifying vifs will increase the number of interfaces as needed.""")
|
||||
|
||||
@@ -289,14 +300,18 @@ def configure_vifs(config_devs, vals):
|
||||
script = d.get('script')
|
||||
backend = d.get('backend')
|
||||
ip = d.get('ip')
|
||||
vifname = d.get('vifname')
|
||||
else:
|
||||
mac = randomMAC()
|
||||
bridge = None
|
||||
script = None
|
||||
backend = None
|
||||
ip = None
|
||||
vifname = None
|
||||
config_vif = ['vif']
|
||||
config_vif.append(['mac', mac])
|
||||
if vifname:
|
||||
config_vif.append(['vifname', vifname])
|
||||
if bridge:
|
||||
config_vif.append(['bridge', bridge])
|
||||
if script:
|
||||
@@ -383,7 +398,7 @@ def preprocess_vifs(opts, vals):
|
||||
(k, v) = b.strip().split('=', 1)
|
||||
k = k.strip()
|
||||
v = v.strip()
|
||||
if k not in ['mac', 'bridge', 'script', 'backend', 'ip']:
|
||||
if k not in ['mac', 'bridge', 'script', 'backend', 'ip', 'vifname']:
|
||||
opts.err('Invalid vif specifier: ' + vif)
|
||||
d[k] = v
|
||||
vifs.append(d)
|
||||
@@ -409,6 +424,58 @@ def preprocess_nfs(opts, vals):
|
||||
opts.err('Must set nfs root and nfs server')
|
||||
nfs = 'nfsroot=' + vals.nfs_server + ':' + vals.nfs_root
|
||||
vals.extra = nfs + ' ' + vals.extra
|
||||
|
||||
|
||||
def get_host_addr():
|
||||
host = socket.gethostname()
|
||||
addr = socket.gethostbyname(host)
|
||||
return addr
|
||||
|
||||
VNC_BASE_PORT = 5500
|
||||
|
||||
def choose_vnc_display():
|
||||
"""Try to choose a free vnc display.
|
||||
"""
|
||||
def netstat_local_ports():
|
||||
"""Run netstat to get a list of the local ports in use.
|
||||
"""
|
||||
l = os.popen("netstat -nat").readlines()
|
||||
r = []
|
||||
# Skip 2 lines of header.
|
||||
for x in l[2:]:
|
||||
# Local port is field 3.
|
||||
y = x.split()[3]
|
||||
# Field is addr:port, split off the port.
|
||||
y = y.split(':')[1]
|
||||
r.append(int(y))
|
||||
return r
|
||||
|
||||
ports = netstat_local_ports()
|
||||
for d in range(1, 100):
|
||||
port = VNC_BASE_PORT + d
|
||||
if port in ports: continue
|
||||
return d
|
||||
return None
|
||||
|
||||
def spawn_vnc(display):
|
||||
os.system("vncviewer -listen %d &" % display)
|
||||
return VNC_BASE_PORT + display
|
||||
|
||||
def preprocess_vnc(opts, 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: return
|
||||
vnc_display = choose_vnc_display()
|
||||
if not vnc_display:
|
||||
opts.warn("No free vnc display")
|
||||
return
|
||||
print 'VNC=', vnc_display
|
||||
vnc_port = spawn_vnc(vnc_display)
|
||||
if vnc_port > 0:
|
||||
vnc_host = get_host_addr()
|
||||
vnc = 'VNC_VIEWER=%s:%d' % (vnc_host, vnc_port)
|
||||
vals.extra = vnc + ' ' + vals.extra
|
||||
|
||||
def preprocess(opts, vals):
|
||||
if not vals.kernel:
|
||||
@@ -418,6 +485,7 @@ def preprocess(opts, vals):
|
||||
preprocess_vifs(opts, vals)
|
||||
preprocess_ip(opts, vals)
|
||||
preprocess_nfs(opts, vals)
|
||||
preprocess_vnc(opts, vals)
|
||||
|
||||
def make_domain(opts, config):
|
||||
"""Create, build and start a domain.
|
||||
|
||||