bitkeeper revision 1.1108.33.13 (410a4f615sv1r0U6d481Qr5KYOtvpQ)

Merge ssh://xenbk@gandalf.hpl.hp.com//var/bk/xeno-unstable.bk
into labyrinth.cl.cam.ac.uk:/auto/anfs/scratch/labyrinth/iap10/xeno-clone/xeno.bk
This commit is contained in:
iap10@labyrinth.cl.cam.ac.uk committed 2004-07-30 13:38:41 +00:00
commit 83bf229e04
22 files changed
+974 -510

No files matched your search

+54 -50
View File
@@ -9,6 +9,7 @@ The 'data-plane' is done separately. For example, consoles
are accessed via sockets on xend, but the list of consoles
is accessible via this API.
"""
import os
import sys
import httplib
import types
@@ -130,7 +131,6 @@ class XendRequest:
class XendClientProtocol:
"""Abstract class for xend clients.
"""
def xendRequest(self, url, method, args=None):
"""Make a request to xend.
Implement in a subclass.
@@ -176,6 +176,9 @@ class XendClientProtocol:
"""Handle the data returned in response to the request.
"""
if data is None: return None
type = self.getHeader('Content-Type')
if type != sxp.mime_type:
return data
try:
pin = sxp.Parser()
pin.input(data);
@@ -194,11 +197,22 @@ class XendClientProtocol:
"""
raise err
def getHeader(self, key):
"""Get a header from the response.
Case is ignored in the key.
@param key: header key
@return: header
"""
raise NotImplementedError()
class SynchXendClientProtocol(XendClientProtocol):
"""A synchronous xend client. This will make a request, wait for
the reply and return the result.
"""
resp = None
def xendRequest(self, url, method, args=None):
"""Make a request to xend.
@@ -211,6 +225,7 @@ class SynchXendClientProtocol(XendClientProtocol):
if DEBUG: conn.set_debuglevel(1)
conn.request(method, url.fullpath(), self.request.data, self.request.headers)
resp = conn.getresponse()
self.resp = resp
val = self.handleStatus(resp.version, resp.status, resp.reason)
if val is None:
data = None
@@ -220,6 +235,10 @@ class SynchXendClientProtocol(XendClientProtocol):
val = self.handleResponse(data)
return val
def getHeader(self, key):
return self.resp.getheader(key)
class AsynchXendClient(http.HTTPClient):
"""A subclass of twisted's HTTPClient to deal with a connection to xend.
Makes the request when connected, and delegates handling responses etc.
@@ -245,6 +264,9 @@ class AsynchXendClient(http.HTTPClient):
def handleStatus(self, version, status, message):
return self.protocol.handleStatus(version, status, message)
def handleHeader(self, key, val):
return self.protocol.handleHeader(key, val)
def handleResponse(self, data):
return self.protocol.handleResponse(data)
@@ -257,47 +279,7 @@ class AsynchXendClientProtocol(XendClientProtocol):
"""
def __init__(self):
self.err = None
def xendRequest(self, url, method, args=None):
"""Make a request to xend. The returned deferred is called when
the result is available.
@param url: xend request url
@param method: http method: POST or GET
@param args: request arguments (dict)
@return: deferred
"""
request = XendRequest(url, method, args)
self.deferred = Deferred()
clientCreator = ClientCreator(reactor, AsynchXendClient, self, request)
clientCreator.connectTCP(url.host, url.port)
return self.deferred
def callErrback(self, err):
if not self.deferred.called:
self.err = err
self.deferred.errback(err)
return err
def callCallback(self, val):
if not self.deferred.called:
self.deferred.callback(val)
return val
def handleException(self, err):
return self.callErrback(err)
def handleResponse(self, data):
if self.err: return self.err
val = XendClientProtocol.handleResponse(self, data)
if isinstance(val, Exception):
self.callErrback(val)
else:
self.callCallback(val)
return val
def __init__(self):
self.err = None
self.headers = {}
def xendRequest(self, url, method, args=None):
"""Make a request to xend. The returned deferred is called when
@@ -328,6 +310,12 @@ class AsynchXendClientProtocol(XendClientProtocol):
def handleException(self, err):
return self.callErrback(err)
def handleHeader(self, key, val):
self.headers[key.lower()] = val
def getHeader(self, key):
return self.headers.get(key.lower())
def handleResponse(self, data):
if self.err: return self.err
val = XendClientProtocol.handleResponse(self, data)
@@ -344,9 +332,15 @@ class Xend:
"""Default location of the xend server."""
SRV_DEFAULT = "localhost:8000"
"""Environment variable to set the location of xend."""
SRV_VAR = "XEND"
"""Default path to the xend root on the server."""
ROOT_DEFAULT = "/xend/"
"""Environment variable to set the xend root path."""
ROOT_VAR = "XEND_ROOT"
def __init__(self, client=None, srv=None, root=None):
"""Create a xend client interface.
If the client protocol is not specified, the default
@@ -361,14 +355,24 @@ class Xend:
self.client = client
self.bind(srv, root)
def default_server(self):
"""Get the default location of the xend server.
"""
return os.getenv(self.SRV_VAR, self.SRV_DEFAULT)
def default_root(self):
"""Get the default root path on the xend server.
"""
return os.getenv(self.ROOT_VAR, self.ROOT_DEFAULT)
def bind(self, srv=None, root=None):
"""Bind to a given server.
@param srv: server location (host:port)
@param root: xend root path on the server
"""
if srv is None: srv = self.SRV_DEFAULT
if root is None: root = self.ROOT_DEFAULT
if srv is None: srv = self.default_server()
if root is None: root = self.default_root()
if not root.endswith('/'): root += '/'
(host, port) = srv.split(':', 1)
self.url = URL(host=host, port=port, path=root)
@@ -397,9 +401,6 @@ class Xend:
def eventurl(self, id=''):
return self.url.relative('event/' + str(id))
def dmesgurl(self, id=''):
return self.url.relative('node/dmesg/' + str(id))
def xend(self):
return self.xendGet(self.url)
@@ -408,14 +409,17 @@ class Xend:
def xend_node_shutdown(self):
return self.xendPost(self.nodeurl(),
{'op' : 'shutdown'})
{'op' : 'shutdown'})
def xend_node_restart(self):
return self.xendPost(self.nodeurl(),
{'op' : 'reboot'})
{'op' : 'reboot'})
def xend_node_dmesg(self):
return self.xendGet(self.dmesgurl())
return self.xendGet(self.nodeurl('dmesg'))
def xend_node_log(self):
return self.xendGet(self.nodeurl('log'))
def xend_node_cpu_rrobin_slice_set(self, slice):
return self.xendPost(self.nodeurl(),
+2 -2
View File
@@ -1,4 +1,4 @@
# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
"""Get dmesg output for this node.
"""
@@ -11,7 +11,7 @@ class XendDmesg:
self.xc = xen.lowlevel.xc.new()
def info(self):
return [ self.xc.readconsolering() ]
return self.xc.readconsolering()
def instance():
+195 -135
View File
@@ -39,15 +39,23 @@ class XendDomain:
dbpath = "domain"
"""Table of domain info indexed by domain id."""
domain = {}
domain_by_id = {}
domain_by_name = {}
"""Table of domains to restart, indexed by domain id."""
restarts = {}
restarts_by_id = {}
restarts_by_name = {}
"""Table of delayed calls."""
schedule = {}
def __init__(self):
# Hack alert. Python does not support mutual imports, but XendDomainInfo
# needs access to the XendDomain instance to look up domains. Attempting
# to import XendDomain from XendDomainInfo causes unbounded recursion.
# So we stuff the XendDomain instance (self) into XendDomainInfo's
# namespace as 'xd'.
XendDomainInfo.xd = self
# Table of domain info indexed by domain id.
self.db = XendDB.XendDB(self.dbpath)
self.domain_db = self.db.fetchall("")
@@ -173,7 +181,8 @@ class XendDomain:
@return: deferred
"""
def cbok(dominfo):
self.domain[dominfo.id] = dominfo
self.domain_by_id[dominfo.id] = dominfo
self.domain_by_name[dominfo.name] = dominfo
if dominfo.restart_pending():
self.domain_restart_add(dominfo)
@@ -181,17 +190,17 @@ class XendDomain:
deferred.addCallback(cbok)
return deferred
def _add_domain(self, id, info, notify=1):
def _add_domain(self, info, notify=1):
"""Add a domain entry to the tables.
@param id: domain id
@param info: domain info object
@param notify: send a domain created event if true
"""
self.domain[id] = info
self.domain_db[id] = info.sxpr()
self.sync_domain(id)
if notify: eserver.inject('xend.domain.created', id)
self.domain_by_id[info.id] = info
self.domain_db[info.id] = info.sxpr()
self.domain_by_name[info.name] = info
self.sync_domain(info.id)
if notify: eserver.inject('xend.domain.created', info.name)
def _delete_domain(self, id, notify=1):
"""Remove a domain from the tables.
@@ -199,9 +208,12 @@ class XendDomain:
@param id: domain id
@param notify: send a domain died event if true
"""
if id in self.domain:
if notify: eserver.inject('xend.domain.died', id)
del self.domain[id]
if id in self.domain_by_id:
info = self.domain_by_id[id]
if notify: eserver.inject('xend.domain.died', info.name)
if info.name in self.domain_by_name:
del self.domain_by_name[info.name]
del self.domain_by_id[id]
if id in self.domain_db:
del self.domain_db[id]
self.db.delete(id)
@@ -229,7 +241,7 @@ class XendDomain:
if reason in ['poweroff', 'reboot']:
self.domain_restart_schedule(id, reason)
self.final_domain_destroy(id)
if len(self.restarts):
if self.domain_restarts_exist():
self.domain_restarts_schedule()
def refresh(self):
@@ -243,14 +255,14 @@ class XendDomain:
for d in domlist:
id = str(d['dom'])
doms[id] = d
if id not in self.domain:
if id not in self.domain_by_id:
savedinfo = None
deferred = XendDomainInfo.vm_recreate(savedinfo, d)
def cbok(dominfo):
self._add_domain(dominfo.id, dominfo)
self._add_domain(dominfo)
deferred.addCallback(cbok)
# Remove entries for domains that no longer exist.
for d in self.domain.values():
for d in self.domain_by_id.values():
info = doms.get(d.id)
if info:
d.update(info)
@@ -263,7 +275,7 @@ class XendDomain:
@param id: domain id
"""
dominfo = self.domain.get(id)
dominfo = self.domain_by_id.get(id)
if dominfo:
self.domain_db[id] = dominfo.sxpr()
self.sync_domain(id)
@@ -283,17 +295,25 @@ class XendDomain:
raise
pass
else:
d = self.domain.get(id)
d = self.domain_by_id.get(id)
if d:
d.update(dominfo[0])
def domain_ls(self):
"""Get list of domain ids.
"""Get list of domain names.
@return: domain ids
@return: domain names
"""
self.refresh()
return self.domain.keys()
return self.domain_by_name.keys()
def domain_ls_ids(self):
"""Get list of domain ids.
@return: domain names
"""
self.refresh()
return self.domain_by_id.keys()
def domains(self):
"""Get list of domain objects.
@@ -301,7 +321,7 @@ class XendDomain:
@return: domain objects
"""
self.refresh()
return self.domain.values()
return self.domain_by_id.values()
def domain_create(self, config):
"""Create a domain from a configuration.
@@ -310,7 +330,7 @@ class XendDomain:
@return: deferred
"""
def cbok(dominfo):
self._add_domain(dominfo.id, dominfo)
self._add_domain(dominfo)
return dominfo
deferred = XendDomainInfo.vm_create(config)
deferred.addCallback(cbok)
@@ -323,7 +343,7 @@ class XendDomain:
@return: deferred
"""
def cbok(dominfo):
self._add_domain(dominfo.id, dominfo)
self._add_domain(dominfo)
return dominfo
log.info("Restarting domain: id=%s name=%s", dominfo.id, dominfo.name)
deferred = dominfo.restart()
@@ -338,15 +358,14 @@ class XendDomain:
@param config: configuration
@return: deferred
"""
log.debug('domain_configure> id=%s config=%s', id, str(config))
dom = int(id)
dominfo = self.domain_get(dom)
dominfo = self.domain_get(id)
if not dominfo:
raise XendError("Invalid domain: " + str(id))
log.debug('domain_configure> id=%s config=%s', id, str(config))
if dominfo.config:
raise XendError("Domain already configured: " + str(id))
raise XendError("Domain already configured: " + dominfo.name)
def cbok(dominfo):
self._add_domain(dominfo.id, dominfo)
self._add_domain(dominfo)
return dominfo
deferred = dominfo.construct(config)
deferred.addCallback(cbok)
@@ -361,7 +380,7 @@ class XendDomain:
"""
def cbok(dominfo):
self._add_domain(dominfo.id, dominfo)
self._add_domain(dominfo)
return dominfo
deferred = XendDomainInfo.vm_restore(src, progress=progress)
deferred.addCallback(cbok)
@@ -375,25 +394,45 @@ class XendDomain:
"""
id = str(id)
self.refresh_domain(id)
return self.domain.get(id)
return self.domain_by_id.get(id)
def domain_lookup(self, name):
name = str(name)
dominfo = self.domain_by_name.get(name) or self.domain_by_id.get(name)
if dominfo:
return dominfo
raise XendError('invalid domain:' + name)
def domain_exists(self, name):
name = str(name)
if self.domain_by_name.get(name) or self.domain_by_id.get(name):
return 1
else:
return 0
def domain_unpause(self, id):
"""Unpause domain execution.
@param id: domain id
"""
dom = int(id)
eserver.inject('xend.domain.unpause', id)
return xc.domain_unpause(dom=dom)
dominfo = self.domain_lookup(id)
eserver.inject('xend.domain.unpause', dominfo.name)
try:
return xc.domain_unpause(dom=dominfo.dom)
except Exception, ex:
raise XendError(str(ex))
def domain_pause(self, id):
"""Pause domain execution.
@param id: domain id
"""
dom = int(id)
eserver.inject('xend.domain.pause', id)
return xc.domain_pause(dom=dom)
dominfo = self.domain_lookup(id)
eserver.inject('xend.domain.pause', dominfo.name)
try:
return xc.domain_pause(dom=dominfo.dom)
except Exception, ex:
raise XendError(str(ex))
def domain_shutdown(self, id, reason='poweroff'):
"""Shutdown domain (nicely).
@@ -406,18 +445,15 @@ class XendDomain:
@param id: domain id
@param reason: shutdown type: poweroff, reboot, suspend, halt
"""
dom = int(id)
id = str(id)
if dom <= 0:
return 0
dominfo = self.domain_lookup(id)
if reason == 'halt':
self.domain_restart_cancel(id)
self.domain_restart_cancel(dominfo.id)
else:
self.domain_restart_schedule(id, reason, force=1)
eserver.inject('xend.domain.shutdown', [id, reason])
self.domain_restart_schedule(dominfo.id, reason, force=1)
eserver.inject('xend.domain.shutdown', [dominfo.name, reason])
if reason == 'halt':
reason = 'poweroff'
val = xend.domain_shutdown(dom, reason)
val = xend.domain_shutdown(dominfo.id, reason)
self.refresh_schedule()
return val
@@ -428,10 +464,10 @@ class XendDomain:
@param reason: shutdown reason
"""
log.debug('domain_restart_schedule> %s %s %d', id, reason, force)
dominfo = self.domain.get(id)
dominfo = self.domain_lookup(id)
if not dominfo:
return
if id in self.restarts:
if dominfo.id in self.restarts_by_id:
return
restart = (force and reason == 'reboot') or dominfo.restart_needed(reason)
if restart:
@@ -439,8 +475,9 @@ class XendDomain:
self.domain_restart_add(dominfo)
def domain_restart_add(self, dominfo):
self.restarts[dominfo.id] = dominfo
log.info('Scheduling restart for domain: id=%s name=%s', dominfo.id, dominfo.name)
self.restarts_by_name[dominfo.name] = dominfo
self.restarts_by_id[dominfo.id] = dominfo
log.info('Scheduling restart for domain: name=%s id=%s', dominfo.name, dominfo.id)
self.domain_restarts_schedule()
def domain_restart_cancel(self, id):
@@ -448,53 +485,57 @@ class XendDomain:
@param id: domain id
"""
dominfo = self.restarts.get(id)
dominfo = self.restarts_by_id.get(id) or self.restarts_by_name.get(id)
if dominfo:
log.info('Cancelling restart for domain: id=%s name=%s', dominfo.id, dominfo.name)
log.info('Cancelling restart for domain: name=%s id=%s', dominfo.name, dominfo.id)
dominfo.restart_cancel()
del self.restarts[id]
del self.restarts_by_id[dominfo.id]
del self.restarts_by_name[dominfo.name]
def domain_restarts(self):
"""Execute any scheduled domain restarts for domains that have gone.
"""
self.domain_restarts_cancel()
for id in self.restarts.keys():
if id in self.domain:
for dominfo in self.restarts_by_id.values():
if dominfo.id in self.domain_by_id:
# Don't execute restart for domains still running.
continue
dominfo = self.restarts[id]
# Remove it from the restarts.
del self.restarts[id]
del self.restarts_by_id[dominfo.id]
del self.restarts_by_name[dominfo.name]
try:
def cbok(dominfo):
log.info('Restarted domain id=%s as %s', id, dominfo.id)
log.info('Restarted domain name=%s id=%s', dominfo.name, dominfo.id)
self.domain_unpause(dominfo.id)
def cberr(err):
log.exception("Delayed exception restarting domain: id=%s", id)
log.exception("Delayed exception restarting domain: name=%s id=%s",
dominfo.name, dominfo.id)
deferred = self.domain_restart(dominfo)
deferred.addCallback(cbok)
deferred.addErrback(cberr)
except:
log.exception("Exception restarting domain: id=%s", id)
if len(self.restarts):
log.exception("Exception restarting domain: name=%s id=%s",
dominfo.name, dominfo.id)
if self.domain_restarts_exist():
# Run again later if any restarts remain.
self.refresh_schedule(delay=5)
def domain_restarts_exist(self):
return len(self.restarts_by_id)
def final_domain_destroy(self, id):
"""Final destruction of a domain..
@param id: domain id
"""
dom = int(id)
if dom <= 0:
return 0
log.info('Destroying domain: id=%s', str(id))
eserver.inject('xend.domain.destroy', id)
dominfo = self.domain.get(id)
dominfo = self.domain_lookup(id)
log.info('Destroying domain: name=%s', dominfo.name)
eserver.inject('xend.domain.destroy', dominfo.name)
if dominfo:
val = dominfo.destroy()
else:
val = xc.domain_destroy(dom=dom)
#todo
val = xc.domain_destroy(dom=dominfo.dom)
return val
def domain_destroy(self, id, reason='halt'):
@@ -504,7 +545,6 @@ class XendDomain:
@param id: domain id
"""
id = str(id)
if reason == 'halt':
self.domain_restart_cancel(id)
elif reason == 'reboot':
@@ -522,9 +562,9 @@ class XendDomain:
# Need a cancel too?
# Don't forget to cancel restart for it.
print 'domain_migrate>', id, dst
dom = int(id)
dominfo = self.domain_lookup(id)
xmigrate = XendMigrate.instance()
val = xmigrate.migrate_begin(dom, dst)
val = xmigrate.migrate_begin(dominfo.id, dst)
print 'domain_migrate<', val
return val
@@ -536,9 +576,9 @@ class XendDomain:
@param progress: output progress if true
@return: deferred
"""
dom = int(id)
dominfo = self.domain_lookup(id)
xmigrate = XendMigrate.instance()
return xmigrate.save_begin(dom, dst)
return xmigrate.save_begin(dominfo.id, dst)
def domain_pincpu(self, dom, cpu):
"""Pin a domain to a cpu.
@@ -546,156 +586,176 @@ class XendDomain:
@param dom: domain
@param cpu: cpu number
"""
dom = int(dom)
return xc.domain_pincpu(dom, cpu)
dominfo = self.domain_lookup(id)
try:
return xc.domain_pincpu(itn(dominfo.id), cpu)
except Exception, ex:
raise XendError(str(ex))
def domain_cpu_bvt_set(self, dom, mcuadv, warp, warpl, warpu):
def domain_cpu_bvt_set(self, id, mcuadv, warp, warpl, warpu):
"""Set BVT (Borrowed Virtual Time) scheduler parameters for a domain.
"""
dom = int(dom)
return xc.bvtsched_domain_set(dom=dom, mcuadv=mcuadv,
warp=warp, warpl=warpl, warpu=warpu)
dominfo = self.domain_lookup(id)
try:
return xc.bvtsched_domain_set(dom=dominfo.dom, mcuadv=mcuadv,
warp=warp, warpl=warpl, warpu=warpu)
except Exception, ex:
raise XendError(str(ex))
def domain_cpu_bvt_get(self, dom):
def domain_cpu_bvt_get(self, id):
"""Get BVT (Borrowed Virtual Time) scheduler parameters for a domain.
"""
dom = int(dom)
return xc.bvtsched_domain_get(dom)
dominfo = self.domain_lookup(id)
try:
return xc.bvtsched_domain_get(dominfo.dom)
except Exception, ex:
raise XendError(str(ex))
def domain_cpu_fbvt_set(self, dom, mcuadv, warp, warpl, warpu):
def domain_cpu_fbvt_set(self, id, mcuadv, warp, warpl, warpu):
"""Set FBVT (Fair Borrowed Virtual Time) scheduler parameters for a domain.
"""
dom = int(dom)
return xc.fbvtsched_domain_set(dom=dom, mcuadv=mcuadv,
warp=warp, warpl=warpl, warpu=warpu)
dominfo = self.domain_lookup(id)
try:
return xc.fbvtsched_domain_set(dom=dominfo.dom, mcuadv=mcuadv,
warp=warp, warpl=warpl, warpu=warpu)
except Exception, ex:
raise XendError(str(ex))
def domain_cpu_fbvt_get(self, dom):
def domain_cpu_fbvt_get(self, id):
"""Get FBVT (Fair Borrowed Virtual Time) scheduler parameters for a domain.
"""
dom = int(dom)
return xc.fbvtsched_domain_get(dom)
dominfo = self.domain_lookup(id)
try:
return xc.fbvtsched_domain_get(dominfo.dom)
except Exception, ex:
raise XendError(str(ex))
def domain_cpu_atropos_set(self, dom, period, slice, latency, xtratime):
def domain_cpu_atropos_set(self, id, period, slice, latency, xtratime):
"""Set Atropos scheduler parameters for a domain.
"""
dom = int(dom)
return xc.atropos_domain_set(dom, period, slice, latency, xtratime)
dominfo = self.domain_lookup(id)
try:
return xc.atropos_domain_set(dominfo.dom, period, slice, latency, xtratime)
except Exception, ex:
raise XendError(str(ex))
def domain_cpu_atropos_get(self, dom):
def domain_cpu_atropos_get(self, id):
"""Get Atropos scheduler parameters for a domain.
"""
dom = int(dom)
return xc.atropos_domain_get(dom)
dominfo = self.domain_lookup(id)
try:
return xc.atropos_domain_get(dominfo.dom)
except Exception, ex:
raise XendError(str(ex))
def domain_device_create(self, dom, devconfig):
def domain_device_create(self, id, devconfig):
"""Create a new device for a domain.
@param dom: domain id
@param id: domain id
@param devconfig: device configuration
@return: deferred
"""
dom = int(dom)
dominfo = self.domain_get(dom)
if not dominfo:
raise XendError("invalid domain:" + str(dom))
dominfo = self.domain_lookup(id)
self.refresh_schedule()
val = dominfo.device_create(devconfig)
self.update_domain(dominfo.id)
return val
def domain_device_destroy(self, dom, type, idx):
def domain_device_destroy(self, id, type, idx):
"""Destroy a device.
@param dom: domain id
@param id: domain id
@param type: device type
@param idx: device index
"""
dom = int(dom)
dominfo = self.domain_get(dom)
if not dominfo:
raise XendError("invalid domain:" + str(dom))
dominfo = self.domain_lookup(id)
self.refresh_schedule()
val = dominfo.device_destroy(type, idx)
self.update_domain(dominfo.id)
return val
def domain_devtype_ls(self, dom, type):
def domain_devtype_ls(self, id, type):
"""Get list of device indexes for a domain.
@param dom: domain
@param id: domain
@param type: device type
@return: device indexes
"""
dominfo = self.domain_get(dom)
if not dominfo: return None
dominfo = self.domain_lookup(id)
devs = dominfo.get_devices(type)
return range(0, len(devs))
#return range(0, len(devs))
return devs
def domain_devtype_get(self, dom, type, idx):
def domain_devtype_get(self, id, type, idx):
"""Get a device from a domain.
@param dom: domain
@param id: domain
@param type: device type
@param idx: device index
@return: device object (or None)
"""
dominfo = self.domain_get(dom)
if not dominfo: return None
dominfo = self.domain_lookup(id)
return dominfo.get_device_by_index(type, idx)
def domain_vif_ls(self, dom):
def domain_vif_ls(self, id):
"""Get list of virtual network interface (vif) indexes for a domain.
@param dom: domain
@param id: domain
@return: vif indexes
"""
return self.domain_devtype_ls(dom, 'vif')
return self.domain_devtype_ls(id, 'vif')
def domain_vif_get(self, dom, vif):
def domain_vif_get(self, id, vif):
"""Get a virtual network interface (vif) from a domain.
@param dom: domain
@param id: domain
@param vif: vif index
@return: vif device object (or None)
"""
return self.domain_devtype_get(dom, 'vif', vif)
return self.domain_devtype_get(id, 'vif', vif)
def domain_vbd_ls(self, dom):
def domain_vbd_ls(self, id):
"""Get list of virtual block device (vbd) indexes for a domain.
@param dom: domain
@param id: domain
@return: vbd indexes
"""
return self.domain_devtype_ls(dom, 'vbd')
return self.domain_devtype_ls(id, 'vbd')
def domain_vbd_get(self, dom, vbd):
def domain_vbd_get(self, id, vbd):
"""Get a virtual block device (vbd) from a domain.
@param dom: domain
@param id: domain
@param vbd: vbd index
@return: vbd device (or None)
"""
return self.domain_devtype_get(dom, 'vbd', vbd)
return self.domain_devtype_get(id, 'vbd', vbd)
def domain_shadow_control(self, dom, op):
def domain_shadow_control(self, id, op):
"""Shadow page control.
@param dom: domain
@param id: domain
@param op: operation
"""
dom = int(dom)
return xc.shadow_control(dom, op)
dominfo = self.domain_lookup(id)
try:
return xc.shadow_control(dominfo.dom, op)
except Exception, ex:
raise XendError(str(ex))
def domain_maxmem_set(self, dom, mem):
def domain_maxmem_set(self, id, mem):
"""Set the memory limit for a domain.
@param dom: domain
@param mem: memory limit (in MB)
@return: 0 on success, -1 on error
"""
dom = int(dom)
dominfo = self.domain_lookup(id)
maxmem = int(mem) * 1024
return xc.domain_setmaxmem(dom, maxmem_kb = maxmem)
try:
return xc.domain_setmaxmem(dominfo.dom, maxmem_kb = maxmem)
except Exception, ex:
raise XendError(str(ex))
def instance():
+177 -147
View File
@@ -193,8 +193,8 @@ config_handlers = {}
def add_config_handler(name, h):
"""Add a handler for a config field.
name field name
h handler: fn(vm, config, field, index)
@param name: field name
@param h: handler: fn(vm, config, field, index)
"""
config_handlers[name] = h
@@ -212,16 +212,15 @@ image_handlers = {}
def add_image_handler(name, h):
"""Add a handler for an image type
name image type
h handler: fn(config, name, memory, image)
@param name: image type
@param h: handler: fn(config, name, memory, image)
"""
image_handlers[name] = h
def get_image_handler(name):
"""Get the handler for an image type.
name image type
returns handler or None
@param name: image type
@return: handler or None
"""
return image_handlers.get(name)
@@ -233,17 +232,16 @@ device_handlers = {}
def add_device_handler(name, h):
"""Add a handler for a device type.
name device type
h handler: fn(vm, dev)
@param name: device type
@param h: handler: fn(vm, dev)
"""
device_handlers[name] = h
def get_device_handler(name):
"""Get the handler for a device type.
name device type
returns handler or None
@param name : device type
@return; handler or None
"""
return device_handlers.get(name)
@@ -252,10 +250,9 @@ def vm_create(config):
If a vm has been partially created and there is an error it
is destroyed.
config configuration
returns Deferred
raises VmError for invalid configuration
@param config configuration
@return: Deferred
@raise: VmError for invalid configuration
"""
vm = XendDomainInfo()
return vm.construct(config)
@@ -314,21 +311,27 @@ def vm_restore(src, progress=0):
return deferred
def dom_get(dom):
"""Get info from xen for an existing domain.
@param dom: domain id
@return: info or None
"""
domlist = xc.domain_getinfo(dom=dom)
if domlist and dom == domlist[0]['dom']:
return domlist[0]
return None
def append_deferred(dlist, v):
"""Append a value to a deferred list if it is a deferred.
@param dlist: list of deferreds
@param v: value to add
"""
if isinstance(v, defer.Deferred):
dlist.append(v)
def _vm_configure1(val, vm):
d = vm.create_devices()
def cbok(x):
return x
d.addCallback(cbok)
d.addCallback(_vm_configure2, vm)
return d
@@ -348,7 +351,7 @@ class XendDomainInfo:
"""Minimum time between domain restarts in seconds.
"""
MINIMUM_RESTART_TIME = 10
MINIMUM_RESTART_TIME = 20
def __init__(self):
self.recreate = 0
@@ -363,6 +366,7 @@ class XendDomainInfo:
self.cmdline = None
self.console = None
self.devices = {}
self.device_index = {}
self.configs = []
self.info = None
self.ipaddrs = []
@@ -378,9 +382,13 @@ class XendDomainInfo:
self.console_port = None
def setdom(self, dom):
"""Set the domain id.
@param dom: domain id
"""
self.dom = int(dom)
self.id = str(dom)
def update(self, info):
"""Update with info from xc.domain_getinfo().
"""
@@ -437,13 +445,39 @@ class XendDomainInfo:
sxpr.append(['config', self.config])
return sxpr
def check_name(self, name):
"""Check if a vm name is valid. Valid names start with a non-digit
and contain alphabetic characters, digits, or characters in '_-.'.
The same name cannot be used for more than one vm at the same time.
@param name: name
@raise: VMerror if invalid
"""
if name is None or name == '':
raise VmError('missing vm name')
if name[0] in string.digits:
raise VmError('invalid vm name')
for c in name:
if c in string.digits: continue
if c in '_-.': continue
if c in string.ascii_letters: continue
raise VmError('invalid vm name')
# See comment in XendDomain constructor about 'xd'.
if xd.domain_exists(name):
raise VmError('vm name clash: ' + name)
def construct(self, config):
"""Construct the vm instance from its configuration.
@param config: configuration
@return: deferred
@raise: VmError on error
"""
# todo - add support for scheduling params?
self.config = config
try:
self.name = sxp.child_value(config, 'name')
if self.name is None:
raise VmError('missing domain name')
self.check_name(self.name)
self.memory = int(sxp.child_value(config, 'memory'))
if self.memory is None:
raise VmError('missing memory size')
@@ -462,12 +496,9 @@ class XendDomainInfo:
raise VmError('unknown image type: ' + image_name)
image_handler(self, image)
deferred = self.configure()
def cbok(x):
return x
def cberr(err):
self.destroy()
return err
deferred.addCallback(cbok)
deferred.addErrback(cberr)
except StandardError, ex:
# Catch errors, cleanup and re-raise.
@@ -478,8 +509,10 @@ class XendDomainInfo:
def config_devices(self, name):
"""Get a list of the 'device' nodes of a given type from the config.
name device type
return list of device configs
@param name: device type
@type name: string
@return: device configs
@rtype: list
"""
devices = []
for d in sxp.children(self.config, 'device'):
@@ -490,31 +523,57 @@ class XendDomainInfo:
return devices
def config_device(self, type, idx):
"""Get a device config from the device nodes of a given type
from the config.
@param type: device type
@type type: string
@param idx: index
@type idx: int
@return config or None
"""
devs = self.config_devices(type)
if 0 <= idx < len(devs):
return devs[idx]
else:
return None
def next_device_index(self, type):
"""Get the next index for a given device type.
@param type: device type
@type type: string
@return device index
@rtype: int
"""
idx = self.device_index.get(type, 0)
self.device_index[type] = idx + 1
return idx
def add_device(self, type, dev):
"""Add a device to a virtual machine.
dev device to add
@param type: device type
@param dev: device to add
"""
dl = self.devices.get(type, [])
dl.append(dev)
self.devices[type] = dl
def get_devices(self, type):
"""Get a list of the devices of a given type.
@param type: device type
@return: devices
"""
val = self.devices.get(type, [])
return val
def get_device_by_id(self, type, id):
"""Get the device with the given id.
id device id
returns device or None
@param id: device id
@return: device or None
"""
dl = self.get_devices(type)
for d in dl:
@@ -525,20 +584,20 @@ class XendDomainInfo:
def get_device_by_index(self, type, idx):
"""Get the device with the given index.
idx device index
returns device or None
@param idx: device index
@return: device or None
"""
idx = str(idx)
dl = self.get_devices(type)
if 0 <= idx < len(dl):
return dl[idx]
else:
return None
for d in dl:
if d.getidx() == idx:
return d
return None
def add_config(self, val):
"""Add configuration data to a virtual machine.
val data to add
@param val: data to add
"""
self.configs.append(val)
@@ -563,7 +622,10 @@ class XendDomainInfo:
if chan:
log.debug("Closing channel to domain %d", self.dom)
chan.close()
return xc.domain_destroy(dom=self.dom)
try:
return xc.domain_destroy(dom=self.dom)
except Exception, err:
log.exception("Domain destroy failed: ", self.name)
def cleanup(self):
"""Cleanup vm resources: release devices.
@@ -661,11 +723,11 @@ class XendDomainInfo:
def create_domain(self, ostype, kernel, ramdisk, cmdline, vifs_n):
"""Create a domain. Builds the image but does not configure it.
ostype OS type
kernel kernel image
ramdisk kernel ramdisk
cmdline kernel commandline
vifs_n number of network interfaces
@param ostype: OS type
@param kernel: kernel image
@param ramdisk: kernel ramdisk
@param cmdline: kernel commandline
@param vifs_n: number of network interfaces
"""
if not self.recreate:
if not os.path.isfile(kernel):
@@ -685,8 +747,8 @@ class XendDomainInfo:
def create_devices(self):
"""Create the devices for a vm.
returns Deferred
raises VmError for invalid devices
@return: Deferred
@raise: VmError for invalid devices
"""
dlist = []
devices = sxp.children(self.config, 'device')
@@ -730,16 +792,17 @@ class XendDomainInfo:
"""
dev = self.get_device_by_index(type, idx)
if not dev:
raise VmError('invalid device: %s %d' % (type, idx))
raise VmError('invalid device: %s %s' % (type, idx))
devs = self.devices.get(type)
if 0 <= idx < len(devs):
del devs[idx]
dev_config = self.config_device(type, idx)
index = devs.index(dev)
dev_config = self.config_device(type, index)
if dev_config:
self.config.remove(['device', dev_config])
dev.destroy()
def configure_console(self):
"""Configure the vm console port.
"""
x = sxp.child_value(self.config, 'console')
if x:
try:
@@ -749,12 +812,20 @@ class XendDomainInfo:
self.console_port = port
def configure_restart(self):
"""Configure the vm restart mode.
"""
r = sxp.child_value(self.config, 'restart', RESTART_ONREBOOT)
if r not in restart_modes:
raise VmError('invalid restart mode: ' + str(r))
self.restart_mode = r;
def restart_needed(self, reason):
"""Determine if the vm needs to be restarted when shutdown
for the given reason.
@param reason: shutdown reason
@return 1 if needs restaert, 0 otherwise
"""
if self.restart_mode == RESTART_NEVER:
return 0
if self.restart_mode == RESTART_ALWAYS:
@@ -764,12 +835,18 @@ class XendDomainInfo:
return 0
def restart_cancel(self):
"""Cancel a vm restart.
"""
self.restart_state = None
def restarting(self):
"""Put the vm into restart mode.
"""
self.restart_state = STATE_RESTART_PENDING
def restart_pending(self):
"""Test if the vm has a pending restart.
"""
return self.restart_state == STATE_RESTART_PENDING
def restart_check(self):
@@ -781,7 +858,8 @@ class XendDomainInfo:
if self.restart_time is not None:
tdelta = tnow - self.restart_time
if tdelta < self.MINIMUM_RESTART_TIME:
msg = 'VM %d restarting too fast' % self.dom
self.restart_cancel()
msg = 'VM %s restarting too fast' % self.name
log.error(msg)
raise VmError(msg)
self.restart_time = tnow
@@ -830,17 +908,17 @@ class XendDomainInfo:
"""
if self.blkif_backend:
d = defer.Deferred()
d.callback(1)
d.callback(self)
else:
d = xend.blkif_create(self.dom, recreate=self.recreate)
d.addCallback(_vm_configure1, self)
return d
def dom_configure(self, dom):
"""Configure a domain.
"""Configure a vm for an existing domain.
dom domain id
returns deferred
@param dom: domain id
@return: deferred
"""
d = dom_get(dom)
if not d:
@@ -860,6 +938,8 @@ class XendDomainInfo:
return deferred
def configure_fields(self):
"""Process the vm configuration fields using the registered handlers.
"""
dlist = []
index = {}
for field in sxp.children(self.config):
@@ -880,11 +960,10 @@ class XendDomainInfo:
def vm_image_linux(vm, image):
"""Create a VM for a linux image.
name vm name
memory vm memory
image image config
returns vm
@param name: vm name
@param memory: vm memory
@param image: image config
@return: vm
"""
kernel = sxp.child_value(image, "kernel")
cmdline = ""
@@ -905,11 +984,10 @@ def vm_image_linux(vm, image):
def vm_image_netbsd(vm, image):
"""Create a VM for a bsd image.
name vm name
memory vm memory
image image config
returns vm
@param name: vm name
@param memory: vm memory
@param image: image config
@return: vm
"""
#todo: Same as for linux. Is that right? If so can unify them.
kernel = sxp.child_value(image, "kernel")
@@ -932,13 +1010,14 @@ def vm_image_netbsd(vm, image):
def vm_dev_vif(vm, val, index):
"""Create a virtual network interface (vif).
vm virtual machine
val vif config
index vif index
@param vm: virtual machine
@param val: vif config
@param index: vif index
@return: deferred
"""
if vm.netif_backend:
raise VmError('vif: vif in netif backend domain')
vif = index #todo
vif = vm.next_device_index('vif')
vmac = sxp.child_value(val, "mac")
xend.netif_create(vm.dom, recreate=vm.recreate)
log.debug("Creating vif dom=%d vif=%d mac=%s", vm.dom, vif, str(vmac))
@@ -954,13 +1033,13 @@ def vm_dev_vif(vm, val, index):
def vm_dev_vbd(vm, val, index):
"""Create a virtual block device (vbd).
vm virtual machine
val vbd config
index vbd index
@param vm: virtual machine
@param val: vbd config
@param index: vbd index
@return: deferred
"""
if vm.blkif_backend:
raise VmError('vbd: vbd in blkif backend domain')
vdev = index
uname = sxp.child_value(val, 'uname')
if not uname:
raise VmError('vbd: Missing uname')
@@ -971,13 +1050,16 @@ def vm_dev_vbd(vm, val, index):
log.debug("Creating vbd dom=%d uname=%s dev=%s", vm.dom, uname, dev)
defer = make_disk(vm.dom, uname, dev, mode, vm.recreate)
def fn(vbd):
dev = xend.blkif_dev(vm.dom, vdev)
vm.add_device('vbd', dev)
vbd.dev = dev
vbd.uname = uname
vm.add_device('vbd', vbd)
return vbd
defer.addCallback(fn)
return defer
def parse_pci(val):
"""Parse a pci field.
"""
if isinstance(val, types.StringType):
radix = 10
if val.startswith('0x') or val.startswith('0X'):
@@ -988,6 +1070,13 @@ def parse_pci(val):
return v
def vm_dev_pci(vm, val, index):
"""Add a pci device.
@param vm: virtual machine
@param val: device configuration
@param index: device index
@return: 0 on success
"""
bus = sxp.child_value(val, 'bus')
if not bus:
raise VmError('pci: Missing bus')
@@ -1013,78 +1102,21 @@ def vm_dev_pci(vm, val, index):
return rc
def vm_field_vfr(vm, config, val, index):
"""Handle a vfr field in a config.
vm virtual machine
config vm config
val vfr field
"""
# Get the rules and add them.
# (vfr (vif (id foo) (ip x.x.x.x)) ... )
list = sxp.children(val, 'vif')
ipaddrs = []
for v in list:
id = sxp.child_value(v, 'id')
if id is None:
raise VmError('vfr: missing vif id')
id = int(id)
dev = vm.get_device_by_index('vif', id)
if not dev:
raise VmError('vfr: invalid vif id %d' % id)
vif = sxp.child_value(dev, 'vif')
ip = sxp.child_value(v, 'ip')
if not ip:
raise VmError('vfr: missing ip address')
ipaddrs.append(ip);
# todo: Configure the ipaddrs.
vm.ipaddrs = ipaddrs
def vnet_bridge(vnet, vmac, dom, idx):
"""Add the device for the vif to the bridge for its vnet.
"""
vif = "vif%d.%d" % (dom, idx)
try:
cmd = "(vif.conn (vif %s) (vnet %s) (vmac %s))" % (vif, vnet, vmac)
log.debug("vnet_bridge> %s", cmd)
out = file("/proc/vnet/policy", "wb")
out.write(cmd)
err = out.close()
log.debug("vnet_bridge> err=%d", err)
except IOError, ex:
log.exception("vnet_bridge>")
def vm_field_vnet(vm, config, val, index):
"""Handle a vnet field in a config.
vm virtual machine
config vm config
val vnet field
index index
"""
# Get the vif children. For each vif look up the vif device
# with the given id and configure its vnet.
# (vnet (vif (id foo) (vnet 2) (mac x:x:x:x:x:x)) ... )
vif_vnets = sxp.children(val, 'vif')
for v in vif_vnets:
id = sxp.child_value(v, 'id')
if id is None:
raise VmError('vnet: missing vif id')
dev = vm.get_device_by_id('vif', id)
#vnet = sxp.child_value(v, 'vnet', 1)
#mac = sxp.child_value(dev, 'mac')
#vif = sxp.child_value(dev, 'vif')
#vnet_bridge(vnet, mac, vm.dom, 0)
#vm.add_config([ 'vif.vnet', ['id', id], ['vnet', vnet], ['mac', mac]])
def vm_field_ignore(vm, config, val, index):
"""Dummy config field handler used for fields with built-in handling.
@param vm: virtual machine
@param config: vm config
@param val: vfr field
@param index: field index
"""
pass
# Register image handlers for linux and bsd.
# Register image handlers.
add_image_handler('linux', vm_image_linux)
add_image_handler('netbsd', vm_image_netbsd)
# Register device handlers for vifs and vbds.
# Register device handlers.
add_device_handler('vif', vm_dev_vif)
add_device_handler('vbd', vm_dev_vbd)
add_device_handler('pci', vm_dev_pci)
@@ -1098,6 +1130,4 @@ add_config_handler('image', vm_field_ignore)
add_config_handler('device', vm_field_ignore)
add_config_handler('backend', vm_field_ignore)
# Register config handlers for vfr and vnet.
add_config_handler('vfr', vm_field_vfr)
add_config_handler('vnet', vm_field_vnet)
# Register other config handlers.
+4
View File
@@ -44,6 +44,7 @@ class XendLogging:
mode='a',
maxBytes=self.maxBytes,
backupCount=self.backupCount)
self.logfilename = filename
self.logfile.setFormatter(Formatter(self.logFileFormat, self.dateFormat))
log = self.getLogger()
log.addHandler(self.logfile)
@@ -51,6 +52,9 @@ class XendLogging:
def getLogFile(self):
return self.logfile
def getLogFilename(self):
return self.logfilename
def initLogStderr(self):
self.logstderr = StreamHandler()
self.logstderr.setFormatter(Formatter(self.logStderrFormat, self.dateFormat))
+7 -5
View File
@@ -1,10 +1,12 @@
# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
import os
from SrvDir import SrvDir
from xen.xend import sxp
from xen.xend import XendDmesg
from SrvDir import SrvDir
class SrvDmesg(SrvDir):
"""Xen Dmesg output.
"""
@@ -16,13 +18,13 @@ class SrvDmesg(SrvDir):
def render_GET(self, req):
try:
if self.use_sxp(req):
req.setHeader("Content-Type", sxp.mime_type)
sxp.show(['dmesg'] + self.info(), out=req)
req.setHeader("Content-Type", "text/plain")
req.write(self.info())
else:
req.write('<html><head></head><body>')
req.write('<pre>')
self.print_path(req)
req.write(self.info()[0])
req.write('<pre>')
req.write(self.info())
req.write('</pre></body></html>')
return ''
except Exception, ex:
+47 -61
View File
@@ -22,9 +22,9 @@ class SrvDomain(SrvDir):
def op_configure(self, op, req):
fn = FormFn(self.xd.domain_configure,
[['dom', 'int'],
[['dom', 'str'],
['config', 'sxpr']])
deferred = fn(req.args, {'dom': self.dom.id})
deferred = fn(req.args, {'dom': self.dom.name})
deferred.addErrback(self._op_configure_err, req)
return deferred
@@ -33,35 +33,35 @@ class SrvDomain(SrvDir):
return str(err)
def op_unpause(self, op, req):
val = self.xd.domain_unpause(self.dom.id)
val = self.xd.domain_unpause(self.dom.name)
return val
def op_pause(self, op, req):
val = self.xd.domain_pause(self.dom.id)
val = self.xd.domain_pause(self.dom.name)
return val
def op_shutdown(self, op, req):
fn = FormFn(self.xd.domain_shutdown,
[['dom', 'int'],
[['dom', 'str'],
['reason', 'str']])
val = fn(req.args, {'dom': self.dom.id})
val = fn(req.args, {'dom': self.dom.name})
req.setResponseCode(http.ACCEPTED)
req.setHeader("Location", "%s/.." % req.prePathURL())
return val
def op_destroy(self, op, req):
fn = FormFn(self.xd.domain_destroy,
[['dom', 'int'],
[['dom', 'str'],
['reason', 'str']])
val = fn(req.args, {'dom': self.dom.id})
val = fn(req.args, {'dom': self.dom.name})
req.setHeader("Location", "%s/.." % req.prePathURL())
return val
def op_save(self, op, req):
fn = FormFn(self.xd.domain_save,
[['dom', 'int'],
[['dom', 'str'],
['file', 'str']])
deferred = fn(req.args, {'dom': self.dom.id})
deferred = fn(req.args, {'dom': self.dom.name})
deferred.addCallback(self._op_save_cb, req)
deferred.addErrback(self._op_save_err, req)
return deferred
@@ -75,9 +75,9 @@ class SrvDomain(SrvDir):
def op_migrate(self, op, req):
fn = FormFn(self.xd.domain_migrate,
[['dom', 'int'],
[['dom', 'str'],
['destination', 'str']])
deferred = fn(req.args, {'dom': self.dom.id})
deferred = fn(req.args, {'dom': self.dom.name})
print 'op_migrate>', deferred
deferred.addCallback(self._op_migrate_cb, req)
deferred.addErrback(self._op_migrate_err, req)
@@ -99,99 +99,85 @@ class SrvDomain(SrvDir):
req.setResponseCode(http.BAD_REQUEST, "Error: "+ str(err))
return str(err)
def op_device_create(self, op, req):
fn = FormFn(self.xd.domain_device_create,
[['dom', 'int'],
['config', 'sxpr']])
d = fn(req.args, {'dom': self.dom.id})
return d
def op_device_destroy(self, op, req):
fn = FormFn(self.xd.domain_device_destroy,
[['dom', 'int'],
['type', 'str'],
['index', 'int']])
val = fn(req.args, {'dom': self.dom.id})
return val
def op_pincpu(self, op, req):
fn = FormFn(self.xd.domain_pincpu,
[['dom', 'int'],
[['dom', 'str'],
['cpu', 'int']])
val = fn(req.args, {'dom': self.dom.id})
val = fn(req.args, {'dom': self.dom.name})
return val
def op_cpu_bvt_set(self, op, req):
fn = FormFn(self.xd.domain_cpu_bvt_set,
[['dom', 'int'],
[['dom', 'str'],
['mcuadv', 'int'],
['warp', 'int'],
['warpl', 'int'],
['warpu', 'int']])
val = fn(req.args, {'dom': self.dom.id})
val = fn(req.args, {'dom': self.dom.name})
return val
def op_cpu_fbvt_set(self, op, req):
fn = FormFn(self.xd.domain_cpu_fbvt_set,
[['dom', 'int'],
[['dom', 'str'],
['mcuadv', 'int'],
['warp', 'int'],
['warpl', 'int'],
['warpu', 'int']])
val = fn(req.args, {'dom': self.dom.id})
val = fn(req.args, {'dom': self.dom.name})
return val
def op_cpu_atropos_set(self, op, req):
fn = FormFn(self.xd.domain_cpu_atropos_set,
[['dom', 'int'],
[['dom', 'str'],
['period', 'int'],
['slice', 'int'],
['latency', 'int'],
['xtratime', 'int']])
val = fn(req.args, {'dom': self.dom.id})
val = fn(req.args, {'dom': self.dom.name})
return val
def op_maxmem_set(self, op, req):
fn = FormFn(self.xd.domain_maxmem_set,
[['dom', 'int'],
[['dom', 'str'],
['memory', 'int']])
val = fn(req.args, {'dom': self.dom.id})
val = fn(req.args, {'dom': self.dom.name})
return val
def op_device_create(self, op, req):
fn = FormFn(self.xd.domain_device_create,
[['dom', 'str'],
['config', 'sxpr']])
d = fn(req.args, {'dom': self.dom.name})
return d
def op_device_destroy(self, op, req):
fn = FormFn(self.xd.domain_device_destroy,
[['dom', 'str'],
['type', 'str'],
['idx', 'str']])
val = fn(req.args, {'dom': self.dom.name})
return val
def op_vifs(self, op, req):
return self.xd.domain_vif_ls(self.dom.id)
devs = self.xd.domain_vif_ls(self.dom.name)
return [ dev.sxpr() for dev in devs ]
def op_vif(self, op, req):
fn = FormFn(self.xd.domain_vif_get,
[['dom', 'int'],
['vif', 'int']])
val = fn(req.args, {'dom': self.dom.id})
[['dom', 'str'],
['vif', 'str']])
val = fn(req.args, {'dom': self.dom.name})
return val
def op_vbds(self, op, req):
return self.xd.domain_vbd_ls(self.dom.id)
devs = self.xd.domain_vbd_ls(self.dom.name)
return [ dev.sxpr() for dev in devs ]
def op_vbd(self, op, req):
fn = FormFn(self.xd.domain_vbd_get,
[['dom', 'int'],
['vbd', 'int']])
val = fn(req.args, {'dom': self.dom.id})
return val
def op_vbd_add(self, op, req):
fn = FormFn(self.xd.domain_vbd_add,
[['dom', 'int'],
['uname', 'str'],
['dev', 'str'],
['mode', 'str']])
val = fn(req.args, {'dom': self.dom.id})
return val
def op_vbd_remove(self, op, req):
fn = FormFn(self.xd.domain_vbd_remove,
[['dom', 'int'],
['dev', 'str']])
val = fn(req.args, {'dom': self.dom.id})
[['dom', 'str'],
['vbd', 'str']])
val = fn(req.args, {'dom': self.dom.name})
return val
def render_POST(self, req):
+6 -6
View File
@@ -24,7 +24,7 @@ class SrvDomainDir(SrvDir):
def domain(self, x):
val = None
dom = self.xd.domain_get(x)
dom = self.xd.domain_lookup(x)
if not dom:
raise XendError('No such domain ' + str(x))
val = SrvDomain(dom)
@@ -74,7 +74,7 @@ class SrvDomainDir(SrvDir):
def _op_create_cb(self, dominfo, configstring, req):
"""Callback to handle deferred domain creation.
"""
dom = dominfo.id
dom = dominfo.name
domurl = "%s/%s" % (req.prePathURL(), dom)
req.setResponseCode(http.CREATED, "created")
req.setHeader("Location", domurl)
@@ -112,7 +112,7 @@ class SrvDomainDir(SrvDir):
return deferred
def _op_restore_cb(self, dominfo, req):
dom = dominfo.id
dom = dominfo.name
domurl = "%s/%s" % (req.prePathURL(), dom)
req.setResponseCode(http.CREATED)
req.setHeader("Location", domurl)
@@ -159,12 +159,12 @@ class SrvDomainDir(SrvDir):
sxp.show(domains, out=req)
else:
domains = self.xd.domains()
domains.sort(lambda x, y: cmp(x.id, y.id))
domains.sort(lambda x, y: cmp(x.name, y.name))
req.write('<ul>')
for d in domains:
req.write('<li><a href="%s%s"> Domain %s</a>'
% (url, d.id, d.id))
req.write('name=%s' % d.name)
% (url, d.name, d.name))
req.write('id=%s' % d.id)
req.write('memory=%d'% d.memory)
req.write('</li>')
req.write('</ul>')
+4 -1
View File
@@ -1,6 +1,7 @@
# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
import os
from SrvDir import SrvDir
from xen.xend import sxp
from xen.xend import XendNode
@@ -14,6 +15,7 @@ class SrvNode(SrvDir):
SrvDir.__init__(self)
self.xn = XendNode.instance()
self.add('dmesg', 'SrvDmesg')
self.add('log', 'SrvXendLog')
def op_shutdown(self, op, req):
val = self.xn.shutdown()
@@ -58,7 +60,8 @@ class SrvNode(SrvDir):
req.write('<ul>')
for d in self.info():
req.write('<li> %10s: %s' % (d[0], str(d[1])))
req.write('<li><a href="' + url + 'dmesg">Xen dmesg output</a>')
req.write('<li><a href="%sdmesg">Xen dmesg output</a>' % url)
req.write('<li><a href="%slog>Xend log</a>' % url)
req.write('</ul>')
req.write('</body></html>')
return ''
@@ -0,0 +1,24 @@
# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
from twisted.web import static
from xen.xend import XendRoot
from SrvDir import SrvDir
class SrvXendLog(SrvDir):
"""Xend log.
"""
def __init__(self):
SrvDir.__init__(self)
logging = XendRoot.instance().get_logging()
self.logfile = static.File(logging.getLogFilename(), defaultType="text/plain")
self.logfile.type = "text/plain"
self.logfile.encoding = None
def render_GET(self, req):
try:
return self.logfile.render(req)
except Exception, ex:
self._perform_err(ex, req)
+24 -9
View File
@@ -160,13 +160,15 @@ class BlkifControllerFactory(controller.ControllerFactory):
else:
pass
def respond_be_vbd_create(self, msg, d):
def respond_be_vbd_create(self, msg, dev, d):
"""Response handler for a be_vbd_create message.
Tries to grow the vbd, and passes the deferred I{d} on for
the grow to call.
@param msg: message
@type msg: xu message
@param dev: device
@type dev: BlkDev
@param d: deferred to call
@type d: Deferred
"""
@@ -174,17 +176,19 @@ class BlkifControllerFactory(controller.ControllerFactory):
blkif = self.getInstanceByDom(val['domid'])
if blkif:
d1 = defer.Deferred()
d1.addCallback(self.respond_be_vbd_grow, d)
d1.addCallback(self.respond_be_vbd_grow, dev, d)
if d: d1.addErrback(d.errback)
blkif.send_be_vbd_grow(val['vdevice'], response=d1)
else:
pass
def respond_be_vbd_grow(self, msg, d):
def respond_be_vbd_grow(self, msg, dev, d):
"""Response handler for a be_vbd_grow message.
@param msg: message
@type msg: xu message
@param dev: device
@type dev: BlkDev
@param d: deferred to call
@type d: Deferred or None
"""
@@ -192,7 +196,7 @@ class BlkifControllerFactory(controller.ControllerFactory):
# Check status?
if self.attached:
if d:
d.callback(0)
d.callback(dev)
else:
self.reattachDevice(val['domid'], val['vdevice'])
@@ -215,7 +219,9 @@ class BlkDev(controller.Dev):
"""
def __init__(self, ctrl, vdev, mode, segment):
controller.Dev.__init__(self, ctrl)
controller.Dev.__init__(self, segment['device'], ctrl)
self.dev = None
self.uname = None
self.vdev = vdev
self.mode = mode
self.device = segment['device']
@@ -227,7 +233,15 @@ class BlkDev(controller.Dev):
return 'w' not in self.mode
def sxpr(self):
val = ['blkdev', ['vdev', self.vdev], ['mode', self.mode] ]
val = ['blkdev',
['idx', self.idx],
['vdev', self.vdev],
['device', self.device],
['mode', self.mode]]
if self.dev:
val.append(['dev', self.dev])
if self.uname:
val.append(['uname', self.uname])
return val
def destroy(self):
@@ -288,6 +302,7 @@ class BlkifController(controller.Controller):
def attachDevice(self, vdev, mode, segment, recreate=0):
"""Attach a device to the specified interface.
On success the returned deferred will be called with the device.
@param vdev: device index
@type vdev: int
@@ -304,10 +319,10 @@ class BlkifController(controller.Controller):
if not dev: return -1
d = defer.Deferred()
if recreate:
d.callback(self)
d.callback(dev)
else:
d1 = defer.Deferred()
d1.addCallback(self.factory.respond_be_vbd_create, d)
d1.addCallback(self.factory.respond_be_vbd_create, dev, d)
d1.addErrback(d.errback)
self.send_be_vbd_create(vdev, response=d1)
return d
@@ -331,7 +346,7 @@ class BlkifController(controller.Controller):
for dev in self.devices.values():
dev.attached = 0
d1 = defer.Deferred()
d1.addCallback(self.factory.respond_be_vbd_create, None)
d1.addCallback(self.factory.respond_be_vbd_create, None, None)
self.send_be_vbd_create(vdev, response=d1)
def reattachDevice(self, vdev):
+5 -1
View File
@@ -327,10 +327,14 @@ class Dev:
"""Abstract class for a device attached to a device controller.
"""
def __init__(self, controller):
def __init__(self, idx, controller):
self.idx = str(idx)
self.controller = controller
self.props = {}
def getidx(self):
return self.idx
def setprop(self, k, v):
self.props[k] = v
+7 -4
View File
@@ -112,7 +112,7 @@ class NetDev(controller.Dev):
"""
def __init__(self, ctrl, vif, config):
controller.Dev.__init__(self, ctrl)
controller.Dev.__init__(self, vif, ctrl)
self.vif = vif
self.evtchn = None
self.configure(config)
@@ -122,7 +122,7 @@ class NetDev(controller.Dev):
self.mac = None
self.bridge = None
self.script = None
self.ipaddr = None
self.ipaddr = []
vmac = sxp.child_value(config, 'mac')
if not vmac: raise XendError("invalid mac")
@@ -140,7 +140,10 @@ class NetDev(controller.Dev):
def sxpr(self):
vif = str(self.vif)
mac = self.get_mac()
val = ['vif', ['idx', vif], ['mac', mac]]
val = ['vif',
['idx', self.idx],
['vif', vif],
['mac', mac]]
if self.bridge:
val.append(['bridge', self.bridge])
if self.script:
@@ -161,7 +164,7 @@ class NetDev(controller.Dev):
def get_mac(self):
"""Get the MAC address as a string.
"""
return ':'.join(map(lambda x: "%x" % x, self.mac))
return ':'.join(map(lambda x: "%02x" % x, self.mac))
def vifctl_params(self, vmname=None):
dom = self.controller.dom
+2 -1
View File
@@ -366,10 +366,11 @@ def show(sxpr, out=sys.stdout):
show(x, out)
i += 1
out.write(k_list_close)
elif isinstance(sxpr, (types.IntType, types.FloatType)):
out.write(str(sxpr))
elif isinstance(sxpr, types.StringType) and atomp(sxpr):
out.write(sxpr)
else:
#out.write("'" + str(sxpr) + "'")
out.write(repr(str(sxpr)))
def show_xml(sxpr, out=sys.stdout):
+3 -3
View File
@@ -402,7 +402,7 @@ def make_domain(opts, config):
except XendError, ex:
opts.err(str(ex))
dom = int(sxp.child_value(dominfo, 'id'))
dom = sxp.child_value(dominfo, 'name')
console_info = sxp.child(dominfo, 'console')
if console_info:
console_port = int(sxp.child_value(console_info, 'console_port'))
@@ -411,8 +411,8 @@ def make_domain(opts, config):
if server.xend_domain_unpause(dom) < 0:
server.xend_domain_destroy(dom)
opts.err("Failed to unpause domain %d" % dom)
opts.info("Started domain %d, console on port %d"
opts.err("Failed to unpause domain %s" % dom)
opts.info("Started domain %s, console on port %d"
% (dom, console_port))
return (dom, console_port)
+1 -5
View File
@@ -27,14 +27,10 @@ def main(argv):
return
if len(args) < 1: opts.err('Missing domain')
dom = args[0]
try:
domid = int(dom)
except:
opts.err('Invalid domain: ' + dom)
if opts.vals.reboot:
mode = 'reboot'
else:
mode = 'halt'
server.xend_domain_destroy(domid, mode)
server.xend_domain_destroy(dom, mode)
+237 -27
View File
@@ -13,6 +13,39 @@ from xen.xend.XendClient import XendError, server
from xen.xend.XendClient import main as xend_client_main
from xen.xm import create, destroy, shutdown
class Group:
name = ""
info = ""
def __init__(self, xm):
self.xm = xm
self.progs = {}
def addprog(self, prog):
self.progs[prog.name] = prog
def getprog(self, name):
return self.progs.get(name)
def proglist(self):
kl = self.progs.keys()
kl.sort()
return [ self.getprog(k) for k in kl ]
def help(self, args):
if self.info:
print
print self.info
print
else:
print
def shortHelp(self, args):
self.help(args)
for p in self.proglist():
p.shortHelp(args)
class Prog:
"""Base class for sub-programs.
"""
@@ -61,6 +94,7 @@ class Xm:
self.name = 'xm'
self.unknown = ProgUnknown(self)
self.progs = {}
self.groups = {}
def err(self, msg):
print >>sys.stderr, "Error:", msg
@@ -101,6 +135,7 @@ class Xm:
"""
p = pklass(self)
self.progs[p.name] = p
self.getgroup(p.group).addprog(p)
return p
def getprog(self, name, val=None):
@@ -123,26 +158,71 @@ class Xm:
return self.progs.get(match, val)
def proglist(self):
"""Get a list of sub-programs, ordered by group.
"""
groups = {}
for p in self.progs.values():
l = groups.get(p.group, [])
l.append(p)
groups[p.group] = l
kl = groups.keys()
def group(self, klass):
g = klass(self)
self.groups[g.name] = g
return g
def getgroup(self, name):
return self.groups[name]
def grouplist(self):
kl = self.groups.keys()
kl.sort()
pl = []
for k in kl:
l = groups[k]
l.sort()
pl += l
return pl
return [ self.getgroup(k) for k in kl ]
# Create the application object, then add the sub-program classes.
xm = Xm()
class GroupAll(Group):
name = "all"
info = ""
xm.group(GroupAll)
class GroupDomain(Group):
name = "domain"
info = "Commands on domains:"
xm.group(GroupDomain)
class GroupScheduler(Group):
name = "scheduler"
info = "Comands controlling scheduling:"
xm.group(GroupScheduler)
class GroupHost(Group):
name = "host"
info = "Commands related to the xen host (node):"
xm.group(GroupHost)
class GroupConsole(Group):
name = "console"
info = "Commands related to consoles:"
xm.group(GroupConsole)
class GroupVbd(Group):
name = "vbd"
info = "Commands related to virtual block devices:"
xm.group(GroupVbd)
class GroupVif(Group):
name = "vif"
info = "Commands related to virtual network interfaces:"
xm.group(GroupVif)
class ProgHelp(Prog):
name = "help"
@@ -157,8 +237,8 @@ class ProgHelp(Prog):
else:
print '%s: Unknown command: %s' % (self.name, name)
else:
for p in self.xm.proglist():
p.shortHelp(args)
for g in self.xm.grouplist():
g.shortHelp(args)
print "\nTry '%s help CMD' for help on CMD" % self.xm.name
main = help
@@ -220,7 +300,7 @@ xm.prog(ProgRestore)
class ProgList(Prog):
group = 'domain'
name = "list"
info = """List info about domains."""
info = """List information about domains."""
short_options = 'l'
long_options = ['long']
@@ -246,10 +326,10 @@ class ProgList(Prog):
use_long = 1
if n == 0:
doms = map(int, server.xend_domains())
doms = server.xend_domains()
doms.sort()
else:
doms = map(int, params)
doms = params
if use_long:
self.long_list(doms)
@@ -257,22 +337,27 @@ class ProgList(Prog):
self.brief_list(doms)
def brief_list(self, doms):
print 'Dom Name Mem(MB) CPU State Time(s)'
print 'Name Id Mem(MB) CPU State Time(s) Console'
for dom in doms:
info = server.xend_domain(dom)
d = {}
d['dom'] = int(dom)
d['dom'] = int(sxp.child_value(info, 'id', '-1'))
d['name'] = sxp.child_value(info, 'name', '??')
d['mem'] = int(sxp.child_value(info, 'memory', '0'))
d['cpu'] = int(sxp.child_value(info, 'cpu', '0'))
d['state'] = sxp.child_value(info, 'state', '??')
d['cpu_time'] = float(sxp.child_value(info, 'cpu_time', '0'))
print ("%(dom)-4d %(name)-16s %(mem)7d %(cpu)3d %(state)5s %(cpu_time)7.1f" % d)
console = sxp.child(info, 'console')
if console:
d['port'] = sxp.child_value(console, 'console_port')
else:
d['port'] = ''
print ("%(name)-16s %(dom)3d %(mem)7d %(cpu)3d %(state)5s %(cpu_time)7.1f %(port)4s"
% d)
def long_list(self, doms):
for dom in doms:
info = server.xend_domain(dom)
print '\nDomain %d' % dom
PrettyPrint.prettyprint(info)
xm.prog(ProgList)
@@ -367,6 +452,40 @@ class ProgMaxmem(Prog):
xm.prog(ProgMaxmem)
class ProgDomid(Prog):
group = 'domain'
name = 'domid'
info = 'Convert a domain name to a domain id.'
def help(self, args):
print args[0], "DOM"
print '\nGet the domain id for the domain with name DOM.'
def main (self, args):
if len(args) != 2: self.err("%s: Invalid argument(s)" % args[0])
name = args[1]
dom = server.xend_domain(name)
print sxp.child_value(dom, 'id')
xm.prog(ProgDomid)
class ProgDomname(Prog):
group = 'domain'
name = 'domname'
info = 'Convert a domain id to a domain name.'
def help(self, args):
print args[0], "DOM"
print '\nGet the name for the domain with id DOM.'
def main (self, args):
if len(args) != 2: self.err("%s: Invalid argument(s)" % args[0])
name = args[1]
dom = server.xend_domain(name)
print sxp.child_value(dom, 'name')
xm.prog(ProgDomname)
class ProgBvt(Prog):
group = 'scheduler'
name = "bvt"
@@ -507,7 +626,7 @@ class ProgConsole(Prog):
info = """Open a console to a domain."""
def help(self, args):
print "console DOM"
print args[0], "DOM"
print "\nOpen a console to domain DOM."
def main(self, args):
@@ -528,7 +647,7 @@ class ProgCall(Prog):
info = "Call xend api functions."
def help (self, args):
print "call fn argss..."
print args[0], "function args..."
print """
Call a xend HTTP API function. The leading 'xend_' on the function
can be omitted. See xen.xend.XendClient for the API functions.
@@ -545,9 +664,100 @@ class ProgDmesg(Prog):
info = """Print Xen boot output."""
def main(self, args):
print server.xend_node_dmesg()[1]
print server.xend_node_dmesg()
xm.prog(ProgDmesg)
class ProgLog(Prog):
group = 'host'
name = "log"
info = """Print the xend log."""
def main(self, args):
print server.xend_node_log()
xm.prog(ProgLog)
class ProgVifList(Prog):
group = 'vif'
name = 'vif-list'
info = """List virtual network interfaces for a domain."""
def help(self, args):
print args[0], "DOM"
print "\nList virtual network interfaces for domain DOM"
def main(self, args):
if len(args) != 2: self.err("%s: Invalid argument(s)" % args[0])
dom = args[1]
for x in server.xend_domain_vifs(dom):
sxp.show(x)
print
xm.prog(ProgVifList)
class ProgVbdList(Prog):
group = 'vbd'
name = 'vbd-list'
info = """List virtual block devices for a domain."""
def help(self, args):
print args[0], "DOM"
print "\nList virtual block devices for domain DOM"
def main(self, args):
if len(args) != 2: self.err("%s: Invalid argument(s)" % args[0])
dom = args[1]
for x in server.xend_domain_vbds(dom):
sxp.show(x)
print
xm.prog(ProgVbdList)
class ProgVbdCreate(Prog):
group = 'vbd'
name = 'vbd-create'
info = """Create a new virtual block device for a domain"""
def help(self, args):
print args[0], "DOM UNAME DEV MODE"
print """
Create a virtual block device for a domain.
UNAME - device to export, e.g. phys:hda2
DEV - device name in the domain, e.g. xda1
MODE - access mode: r for read, w for read-write
"""
def main(self, args):
if len(args) != 5: self.err("%s: Invalid argument(s)" % args[0])
dom = args[1]
vbd = ['vbd',
['uname', args[2]],
['dev', args[3]],
['mode', args[4]]]
server.xend_domain_device_create(dom, vbd)
xm.prog(ProgVbdCreate)
class ProgVbdDestroy(Prog):
group = 'vbd'
name = 'vbd-destroy'
info = """Destroy a domain's virtual block device"""
def help(self, args):
print args[0], "DOM DEV"
print """
Destroy vbd DEV attached to domain DOM. Detaches the device
from the domain, but does not destroy the device contents."""
def main(self, args):
if len(args!=3): self.err("%s: Invalid argument(s)" % args[0])
dom = args[1]
dev = args[2]
sever.xend_domain_device_destroy(dom, "vbd", dev)
xm.prog(ProgVbdDestroy)
def main(args):
xm.main(args)
+9 -13
View File
@@ -9,6 +9,9 @@ import time
from xen.xend.XendClient import server
from xen.xm.opts import *
DOM0_NAME = 'Domain-0'
DOM0_ID = '0'
gopts = Opts(use="""[options] [DOM]
Shutdown one or more domains gracefully.
@@ -35,11 +38,10 @@ gopts.opt('reboot', short='R',
use='Shutdown and reboot.')
def shutdown(opts, doms, mode, wait):
def domains():
return [ int(a) for a in server.xend_domains() ]
if doms == None: doms = domains()
if 0 in doms:
doms.remove(0)
if doms == None: doms = server.xend_domains()
for x in [DOM0_NAME, DOM0_ID]:
if x in doms:
doms.remove(x)
for d in doms:
server.xend_domain_shutdown(d, mode)
if wait:
@@ -50,7 +52,7 @@ def shutdown(opts, doms, mode, wait):
if d in alive: continue
dead.append(d)
for d in dead:
opts.info("Domain %d terminated" % d)
opts.info("Domain %s terminated" % d)
doms.remove(d)
time.sleep(1)
opts.info("All domains terminated")
@@ -76,13 +78,8 @@ def main_all(opts, args):
def main_dom(opts, args):
if len(args) < 1: opts.err('Missing domain')
dom = args[0]
try:
domid = int(dom)
except:
opts.err('Invalid domain: ' + dom)
mode = shutdown_mode(opts)
shutdown(opts, [ domid ], mode, opts.vals.wait)
shutdown(opts, [ dom ], mode, opts.vals.wait)
def main(argv):
opts = gopts
@@ -90,7 +87,6 @@ def main(argv):
if opts.vals.help:
opts.usage()
return
print 'shutdown.main>', len(args), args
if opts.vals.all:
main_all(opts, args)
else:
Reference in new issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.