bitkeeper revision 1.1045 (40ec1aa7Tw6ojoQiO9Pu3Cz1YCaofA)

Merge boulderdash.cl.cam.ac.uk:/auto/groups/xeno/BK/xeno.bk
into boulderdash.cl.cam.ac.uk:/auto/anfs/scratch/boulderdash/gm281/xeno-clone/xeno.bk
This commit is contained in:
gm281@boulderdash.cl.cam.ac.uk committed 2004-07-07 15:45:43 +00:00
commit ab0d0fa800
128 files changed
+5811 -3725

No files matched your search

+42 -11
View File
@@ -3,7 +3,7 @@ import re
import socket
import struct
def readlines(fd):
def _readlines(fd):
"""Version of readlines safe against EINTR.
"""
import errno
@@ -21,7 +21,7 @@ def readlines(fd):
lines.append(line)
return lines
def readline(fd):
def _readline(fd):
"""Version of readline safe against EINTR.
"""
while 1:
@@ -42,11 +42,14 @@ as it may have been moved onto the bridge.
NBE_BRIDGE = 'nbe-br'
def get_current_ipaddr(dev='eth0'):
"""Return a string containing the primary IP address for the given
network interface (default 'eth0').
"""Get the primary IP address for the given network interface.
dev network interface (default eth0)
returns interface address as a string
"""
fd = os.popen( '/sbin/ifconfig ' + dev + ' 2>/dev/null' )
lines = readlines(fd)
lines = _readlines(fd)
for line in lines:
m = re.search( '^\s+inet addr:([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+).*',
line )
@@ -57,11 +60,14 @@ def get_current_ipaddr(dev='eth0'):
return None
def get_current_ipmask(dev='eth0'):
"""Return a string containing the primary IP netmask for the given
network interface (default 'eth0').
"""Get the primary IP netmask for a network interface.
dev network interface (default eth0)
returns interface netmask as a string
"""
fd = os.popen( '/sbin/ifconfig ' + dev + ' 2>/dev/null' )
lines = readlines(fd)
lines = _readlines(fd)
for line in lines:
m = re.search( '^.+Mask:([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+).*',
line )
@@ -72,11 +78,14 @@ def get_current_ipmask(dev='eth0'):
return None
def get_current_ipgw(dev='eth0'):
"""Return a string containing the IP gateway for the given
network interface (default 'eth0').
"""Get the IP gateway for a network interface.
dev network interface (default eth0)
returns gateway address as a string
"""
fd = os.popen( '/sbin/route -n' )
lines = readlines(fd)
lines = _readlines(fd)
for line in lines:
m = re.search( '^\S+\s+([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)' +
'\s+\S+\s+\S*G.*' + dev + '.*', line )
@@ -88,24 +97,46 @@ def get_current_ipgw(dev='eth0'):
def inet_aton(addr):
"""Convert an IP addr in IPv4 dot notation into an int.
addr IP address as a string
returns integer
"""
b = socket.inet_aton(addr)
return struct.unpack('!I', b)[0]
def inet_ntoa(n):
"""Convert an int into an IP addr in IPv4 dot notation.
n IP address
returns string
"""
b = struct.pack('!I', n)
return socket.inet_ntoa(b)
def add_offset_to_ip(addr, offset):
"""Add a numerical offset to an IP addr in IPv4 dot notation.
addr IP address
offset offset to add
returns new address
"""
n = inet_aton(addr)
n += offset
return inet_ntoa(n)
def check_subnet( ip, network, netmask ):
"""Check if an IP address is in the subnet defined by
a network address and mask'.
ip IP adress
network network address
netmask network mask
returns 1 if it is in the subnet, 0 if not
"""
n_ip = inet_aton(ip)
n_net = inet_aton(network)
n_mask = inet_aton(netmask)
+1
View File
@@ -1,3 +1,4 @@
import types
import sxp
class ArgError(StandardError):
+33 -2
View File
@@ -1,6 +1,11 @@
# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
"""Client API for the HTTP interface on xend.
Callable as a script - see main().
This API is the 'control-plane' for xend.
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 sys
import httplib
@@ -27,6 +32,8 @@ class Foo(httplib.HTTPResponse):
def sxprio(sxpr):
"""Convert an sxpr to a string.
"""
io = StringIO()
sxp.show(sxpr, out=io)
print >> io
@@ -80,6 +87,12 @@ def eventurl(location, root, id=''):
return urljoin(location, root, 'event/', id)
def xend_request(url, method, data=None):
"""Make a request to xend.
url xend request url
method http method: POST or GET
data request argument data (dict)
"""
urlinfo = urlparse.urlparse(url)
(uproto, ulocation, upath, uparam, uquery, ufrag) = urlinfo
if DEBUG: print url, urlinfo
@@ -122,20 +135,37 @@ def xend_request(url, method, data=None):
return val
def xend_get(url, args=None):
"""Make a xend request using GET.
Requests using GET are 'safe' and may be repeated without
nasty side-effects.
"""
return xend_request(url, "GET", args)
def xend_call(url, data):
"""Make xend request using POST.
Requests using POST potentially cause side-effects and should
not be repeated unless it really is wanted to do the side
effect again.
"""
return xend_request(url, "POST", data)
class Xend:
"""Default location of the xend server."""
SRV_DEFAULT = "localhost:8000"
"""Default path to the xend root on the server."""
ROOT_DEFAULT = "/xend/"
def __init__(self, srv=None, root=None):
self.bind(srv, root)
def bind(self, srv=None, root=None):
"""Bind to a given server.
srv server location (host:port)
root server xend root path
"""
if srv is None: srv = self.SRV_DEFAULT
if root is None: root = self.ROOT_DEFAULT
if not root.endswith('/'): root += '/'
@@ -200,9 +230,10 @@ class Xend:
return xend_call(self.domainurl(id),
{'op' : 'pause'})
def xend_domain_shutdown(self, id):
def xend_domain_shutdown(self, id, reason):
return xend_call(self.domainurl(id),
{'op' : 'shutdown'})
{'op' : 'shutdown',
'reason' : reason })
def xend_domain_destroy(self, id):
return xend_call(self.domainurl(id),
+132 -10
View File
@@ -5,8 +5,11 @@
Needs to be persistent for one uptime.
"""
import sys
import traceback
from twisted.internet import defer
defer.Deferred.debug = 1
from twisted.internet import reactor
import xen.lowlevel.xc; xc = xen.lowlevel.xc.new()
@@ -28,10 +31,19 @@ __all__ = [ "XendDomain" ]
class XendDomain:
"""Index of all domains. Singleton.
"""
"""Path to domain database."""
dbpath = "domain"
"""Table of domain info indexed by domain id."""
domain = {}
"""Table of configs for domain restart, indexed by domain id."""
restarts = {}
"""Table of delayed calls."""
schedule = {}
def __init__(self):
self.xconsole = XendConsole.instance()
# Table of domain info indexed by domain id.
@@ -49,6 +61,53 @@ class XendDomain:
print 'XendDomain> virq', val
self.reap()
def schedule_later(self, _delay, _name, _fn, *args):
"""Schedule a function to be called later (if not already scheduled).
_delay delay in seconds
_name schedule name
_fn function
args arguments
"""
if self.schedule.get(_name): return
self.schedule[_name] = reactor.callLater(_delay, _fn, *args)
def schedule_cancel(self, name):
"""Cancel a scheduled function call.
name schedule name to cancel
"""
callid = self.schedule.get(name)
if not callid:
return
if callid.active():
callid.cancel()
del self.schedule[name]
def reap_schedule(self, delay=0):
"""Schedule reap to be called later.
delay delay in seconds
"""
self.schedule_later(delay, 'reap', self.reap)
def reap_cancel(self):
"""Cancel any scheduled reap.
"""
self.schedule_cancel('reap')
def refresh_schedule(self, delay=0):
"""Schedule refresh to be called later.
delay delay in seconds
"""
self.schedule_later(delay, 'refresh', self.refresh)
def refresh_cancel(self):
"""Cancel any scheduled refresh.
"""
self.schedule_cancel('refresh')
def rm_all(self):
"""Remove all domain info. Used after reboot.
"""
@@ -145,6 +204,7 @@ class XendDomain:
"""Look for domains that have crashed or stopped.
Tidy them up.
"""
self.reap_cancel()
print 'XendDomain>reap>'
domlist = xc.domain_getinfo()
casualties = []
@@ -158,12 +218,14 @@ class XendDomain:
for d in casualties:
id = str(d['dom'])
print 'XendDomain>reap> died id=', id, d
self.domain_destroy(id, refresh=0)
self.final_domain_destroy(id)
print 'XendDomain>reap<'
def refresh(self):
"""Refresh domain list from Xen.
"""
self.refresh_cancel()
print 'XendDomain>refresh>'
domlist = xc.domain_getinfo()
# Index the domlist by id.
# Add entries for any domains we don't know about.
@@ -184,7 +246,7 @@ class XendDomain:
d.update(dominfo)
else:
self._delete_domain(d.id)
self.reap()
self.reap_schedule(1)
def refresh_domain(self, id):
"""Refresh information for a single domain.
@@ -267,21 +329,70 @@ class XendDomain:
"""Shutdown domain (nicely).
id domain id
reason shutdown type: poweroff, reboot, halt
reason shutdown type: poweroff, reboot, suspend, halt
"""
dom = int(id)
if dom <= 0:
return 0
self.domain_restart_schedule(id, reason)
eserver.inject('xend.domain.shutdown', [id, reason])
if reason == 'halt':
reason = 'poweroff'
val = xend.domain_shutdown(dom, reason)
self.refresh()
self.refresh_schedule()
return val
def domain_destroy(self, id, refresh=1):
"""Terminate domain immediately.
def domain_restart_schedule(self, id, reason):
"""Schedule a restart for a domain if it needs one.
id domain id
reason shutdown reason
"""
if id in self.restarts:
# Don't schedule if already there.
return
restart = 0
if reason in ['poweroff', 'reboot']:
dominfo = self.domain.get(id)
if dominfo and (dominfo.autorestart or reason == 'reboot'):
restart = 1
# Clear autorestart flag to avoid multiple restarts.
dominfo.autorestart = 0
if restart:
self.restarts[id] = dominfo.config
def domain_restart_cancel(self, id):
"""Cancel any restart scheduled for a domain.
id domain id
"""
dominfo = self.domain.get(id)
if dominfo:
dominfo.autorestart = 0
if id in self.restarts:
del self.restarts[id]
def domain_restarts(self):
"""Execute any scheduled domain restarts for domains that have gone.
"""
for id in self.restarts.keys():
if id in self.domain:
# Don't execute restart for domains still running.
continue
config = self.restarts[id]
# Remove it from the restarts.
del self.restarts[id]
try:
self.domain_create(config)
except:
print >>sys.stderr, "XendDomain> Exception restarting domain"
traceback.print_exc(sys.stderr)
def final_domain_destroy(self, id):
"""Final destruction of a domain..
id domain id
refresh send a domain destroy event if true
"""
dom = int(id)
if dom <= 0:
@@ -292,15 +403,26 @@ class XendDomain:
val = dominfo.destroy()
else:
val = xc.domain_destroy(dom=dom)
if refresh: self.refresh()
return val
def domain_destroy(self, id):
"""Terminate domain immediately.
Camcels any restart for the domain.
id domain id
"""
self.domain_restart_cancel(id)
val = self.final_domain_destroy(id)
self.refresh_schedule()
return val
def domain_migrate(self, id, dst):
"""Start domain migration.
id domain id
"""
# Need a cancel too?
# Don't forget to cancel restart for it.
pass
def domain_save(self, id, dst, progress=0):
+39 -17
View File
@@ -9,11 +9,13 @@ Author: Mike Wray <mike.wray@hpl.hp.com>
"""
import string
import types
import re
import sys
import os
from twisted.internet import defer
defer.Deferred.debug = 1
import xen.lowlevel.xc; xc = xen.lowlevel.xc.new()
import xen.util.ip
@@ -78,8 +80,13 @@ def lookup_raw_partn(partition):
if not re.match( '/dev/', partition ):
partition = '/dev/' + partition
drive = re.split( '[0-9]', partition )[0]
"""Try and match non-standard scsi raid arraysa
"""
if re.match( '/dev/cciss/c[0-9]+d[0-9]+p[0-9]+', partition ):
drive = re.split( 'p[0-9]+', partition )[0]
else:
drive = re.split( '[0-9]', partition )[0]
if drive == partition:
fd = os.popen( '/sbin/sfdisk -s ' + drive + ' 2>/dev/null' )
@@ -283,7 +290,7 @@ def vm_restore(src, progress=0):
d = restorefn(state_file=src, progress=progress)
dom = int(d['dom'])
if dom < 0:
raise VMError('restore failed')
raise VmError('restore failed')
vmconfig = sxp.from_string(d['vmconfig'])
vm.config = sxp.child_value(vmconfig, 'config')
deferred = vm.dom_configure(dom)
@@ -356,6 +363,8 @@ class XendDomainInfo:
self.state = self.STATE_OK
#todo: set to migrate info if migrating
self.migrate = None
#Whether to auto-restart
self.autorestart = 0
def setdom(self, dom):
self.dom = int(dom)
@@ -412,6 +421,8 @@ class XendDomainInfo:
try:
self.name = sxp.child_value(config, 'name')
self.memory = int(sxp.child_value(config, 'memory', '128'))
if sxp.child(config, 'autorestart', None):
self.autorestart = 1
self.configure_backends()
image = sxp.child_value(config, 'image')
image_name = sxp.name(image)
@@ -420,14 +431,18 @@ class XendDomainInfo:
raise VmError('unknown image type: ' + image_name)
image_handler(self, image)
deferred = self.configure()
def cbok(x):
print 'vm_create> 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.
self.destroy()
raise
def cbok(x):
print 'vm_create> cbok', x
return x
deferred.addCallback(cbok)
print 'vm_create<'
return deferred
@@ -503,6 +518,9 @@ class XendDomainInfo:
devices have been released.
"""
if self.dom is None: return 0
chan = xend.getDomChannel(self.dom)
if chan:
chan.close()
return xc.domain_destroy(dom=self.dom)
def cleanup(self):
@@ -611,7 +629,7 @@ class XendDomainInfo:
if not os.path.isfile(kernel):
raise VmError('Kernel image does not exist: %s' % kernel)
if ramdisk and not os.path.isfile(ramdisk):
raise VMError('Kernel ramdisk does not exist: %s' % ramdisk)
raise VmError('Kernel ramdisk does not exist: %s' % ramdisk)
print 'create-domain> init_domain...'
self.init_domain()
print 'create_domain>', 'dom=', self.dom
@@ -691,12 +709,16 @@ class XendDomainInfo:
"""
d = dom_get(dom)
if not d:
raise VMError("Domain not found: %d" % dom)
raise VmError("Domain not found: %d" % dom)
try:
self.setdom(dom)
self.name = d['name']
self.memory = d['memory']/1024
deferred = self.configure()
def cberr(err):
self.destroy()
return err
deferred.addErrback(cberr)
except StandardError, ex:
self.destroy()
raise
@@ -807,10 +829,10 @@ def vm_dev_vbd(vm, val, index):
vdev = index
uname = sxp.child_value(val, 'uname')
if not uname:
raise VMError('vbd: Missing uname')
raise VmError('vbd: Missing uname')
dev = sxp.child_value(val, 'dev')
if not dev:
raise VMError('vbd: Missing dev')
raise VmError('vbd: Missing dev')
mode = sxp.child_value(val, 'mode', 'r')
defer = make_disk(vm.dom, uname, dev, mode, vm.recreate)
def fn(vbd):
@@ -821,7 +843,7 @@ def vm_dev_vbd(vm, val, index):
return defer
def parse_pci(val):
if isinstance(val, StringType):
if isinstance(val, types.StringType):
radix = 10
if val.startswith('0x') or val.startswith('0X'):
radix = 16
@@ -833,24 +855,24 @@ def parse_pci(val):
def vm_dev_pci(vm, val, index):
bus = sxp.child_value(val, 'bus')
if not bus:
raise VMError('pci: Missing bus')
raise VmError('pci: Missing bus')
dev = sxp.child_value(val, 'dev')
if not dev:
raise VMError('pci: Missing dev')
raise VmError('pci: Missing dev')
func = sxp.child_value(val, 'func')
if not func:
raise VMError('pci: Missing func')
raise VmError('pci: Missing func')
try:
bus = parse_pci(bus)
dev = parse_pci(dev)
func = parse_pci(func)
except:
raise VMError('pci: invalid parameter')
raise VmError('pci: invalid parameter')
rc = xc.physdev_pci_access_modify(dom=vm.dom, bus=bus, dev=dev,
func=func, enable=1)
if rc < 0:
#todo non-fatal
raise VMError('pci: Failed to configure device: bus=%s dev=%s func=%s' %
raise VmError('pci: Failed to configure device: bus=%s dev=%s func=%s' %
(bus, dev, func))
return rc
+132 -8
View File
@@ -2,22 +2,125 @@
import sys
import socket
import time
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
import sxp
import XendDB
import EventServer; eserver = EventServer.instance()
from xen.xend.packing import SxpPacker, SxpUnpacker
from xen.xend import XendDomain
xd = XendDomain.instance()
XFRD_PORT = 8002
XFR_PROTO_MAJOR = 1
XFR_PROTO_MINOR = 0
class Migrate(Protocol):
def __init__(self, minfo):
self.packer = None
self.unpacker = None
self.minfo = minfo
def connectionMade(self):
self.packer = SxpPacker(self.transport)
self.unpacker = SxpPacker()
# Send hello.
self.packer.pack(['xfr.hello', XFR_PROTO_MAJOR, XFR_PROTO_MINOR])
# Send migrate.
vmconfig = self.minfo.vmconfig()
if not vmconfig:
self.loseConnection()
return
self.packer.pack(['xfr.migrate',
self.minfo.src_dom,
vmconfig,
self.minfo.dst_host,
self.minfo.dst_port])
def connectionLost(self, reason):
self.minfo.closed(reason)
def dataReceived(self, data):
try:
self.unpacker.reset(data)
val = self.unpacker.unpack()
print 'dataReceived>', 'val=', val
op = val[0]
op.replace('.', '_')
if op.startwith('xfr_'):
fn = getattr(self, op, self.unknown)
else:
fn = self.unknown
fn(val)
except Exception, ex:
print 'dataReceived>', ex
pass
def unknown(self, val):
print 'unknown>', val
def xfr_progress(self, val):
print 'xfr_progress>', val
def xfr_error(self, val):
# If we get an error with non-zero code the migrate failed.
# An error with code zero indicates hello success.
err = int(val[1])
if not err: return
self.minfo.error(err);
self.loseConnection()
def xfr_ok(self, val):
# An ok indicates migrate completed successfully, and contains
# the new domain id on the remote system.
dom = int(val[1])
self.minfo.ok(dom)
self.loseConnection()
class MigrateClientFactory(ClientFactory):
def __init__(self, minfo):
ClientFactory.__init__(self)
self.minfo = minfo
def startedConnecting(self, connector):
print 'Started to connect', 'self=', self, 'connector=', connector
def buildProtocol(self, addr):
print 'buildProtocol>', addr
return Migrate(self.minfo)
def clientConnectionLost(self, connector, reason):
print 'clientConnectionLost>', 'connector=', connector, 'reason=', reason
def clientConnectionFailed(self, connector, reason):
print 'clientConnectionFailed>', 'connector=', connector, 'reason=', reason
class XendMigrateInfo:
# states: begin, active, failed, succeeded?
def __init__(self, id, dom, dst):
def __init__(self, id, dom, host, port):
self.id = id
self.state = 'begin'
self.src_host = socket.gethostname()
self.src_dom = dom
self.dst_host = dst
self.dst_port = port
self.dst_dom = None
self.start = 0
self.deferred = defer.Deferred()
def set_state(self, state):
self.state = state
@@ -29,12 +132,33 @@ class XendMigrateInfo:
sxpr = ['migrate', ['id', self.id], ['state', self.state] ]
sxpr_src = ['src', ['host', self.src_host], ['domain', self.src_dom] ]
sxpr.append(sxpr_src)
sxpr_dst = ['dst', ['host', self.dst] ]
sxpr_dst = ['dst', ['host', self.dst_host] ]
if self.dst_dom:
sxpr_dst.append(['domain', self.dst_dom])
sxpr.append(sxpr_dst)
return sxpr
def vmconfig(self):
dominfo = xd.domain_get(self.dom)
if dominfo:
val = return sxp.to_string(dominfo)
else:
val = None
return None
def error(self, err):
self.state = 'error'
def ok(self, dom):
self.state = 'ok'
self.dst_dom = dom
def close(self):
if self.state =='ok':
eserver.inject('xend.migrate.ok', self.sxpr())
else:
self.state = 'error'
eserver.inject('xend.migrate.error', self.sxpr())
class XendMigrate:
# Represents migration in progress.
@@ -84,15 +208,15 @@ class XendMigrate:
def migrate_get(self, id):
return self.migrate.get(id)
def migrate_begin(self, dom, dst):
def migrate_begin(self, dom, host):
# Check dom for existence, not migrating already.
# Create migrate info, tell xend to migrate it?
# - or fork migrate command ourselves?
# Subscribe to migrate notifications (for updating).
id = self.nextid()
info = XenMigrateInfo(id, dom, dst)
info = XenMigrateInfo(id, dom, host, XFRD_PORT)
self._add_migrate(id, info)
return id
mcf = MigrateClientFactory(info)
reactor.connectTCP('localhost', XFRD_PORT, mcf)
return info.deferred
def instance():
global inst
+329
View File
@@ -0,0 +1,329 @@
# XDR-style packer/unpacker for sxpr.
#
# string -> [STRING] [len:u16] <len bytes>
# atom -> [ATOM] [len:u16] <len bytes>
# int -> [UINT] [value]
# list -> [LIST] {1 elt}* 0
# null -> [NULL]
# none -> [NONE]
# bool -> [BOOL] { 0:u8 | 1:u8 }
#
# types packed as u16.
#
# So (a b c) -> [LIST] 1 a 1 b 1 c 0
# () -> [LIST] 0
import struct
try:
from cStringIO import StringIO as _StringIO
except ImportError:
from StringIO import StringIO as _StringIO
import types
class Error(Exception):
def __init__(self, msg):
self.msg = msg
def __repr__(self):
return repr(self.msg)
def __str__(self):
return str(self.msg)
class ConversionError(Error):
pass
BOOL_SIZE = 1
BOOL_FMT = '>B'
BYTE_SIZE = 1
BYTE_FMT = '>b'
UBYTE_FMT = '>B'
SHORT_SIZE = 2
SHORT_FMT = '>h'
USHORT_FMT = '>H'
INT_SIZE = 4
INT_FMT = '>l'
UINT_FMT = '>L'
NONE_CODE = 0
NULL_CODE = 1
INT_CODE = 2
STRING_CODE = 3
ATOM_CODE = 4
BOOL_CODE = 5
LIST_CODE = 10
class Packer:
def __init__(self, io=None):
self.reset(io=io)
def reset(self, io=None):
if io is None:
io = _StringIO()
self.io = io
def get_buffer(self):
return self.io.getvalue()
def get_io(self):
return self.io
def struct_pack(self, fmt, x):
try:
self.io.write(struct.pack(fmt, x))
except struct.error, msg:
raise ConversionError, msg
def pack_none(self):
pass
def pack_bool(self, x):
# { '1' | '0' }
print 'bool>', x
if x:
self.io.write('\1')
else:
self.io.write('\0')
def pack_byte(self, x):
self.struct_pack(BYTE_FMT, x & 0xff)
def pack_char(self, x):
print 'char>', x
self.io.write(x)
def pack_ubyte(self, x):
print 'ubyte>', x
self.struct_pack(UBYTE_FMT, x & 0xff)
def pack_ushort(self, x):
print 'ushort>', x
self.struct_pack(USHORT_FMT, x & 0xffff)
def pack_short(self, x):
print 'short>', x
self.struct_pack(SHORT_FMT, x & 0xffff)
def pack_uint(self, x):
print 'uint>', x
self.struct_pack(UINT_FMT, x)
def pack_int(self, x):
print 'int>', x
self.struct_pack(INT_FMT, x)
def pack_uhyper(self, x):
print 'uhyper>', x
self.pack_uint(x>>32 & 0xffffffffL)
self.pack_uint(x & 0xffffffffL)
pack_hyper = pack_uhyper
def pack_fstring(self, n, x):
print 'fstring>', x
self.io.write(x)
pack_fopaque = pack_fstring
def pack_string(self, x):
print 'string>', x
n = len(x)
self.pack_ushort(n)
self.pack_fstring(n, x)
pack_opaque = pack_string
pack_bytes = pack_string
def pack_list(self, x, pack_item):
print 'list>', x
# { '1' <item> }* '0'
for item in x:
self.pack_bool(1)
pack_item(item)
self.pack_bool(0)
def pack_farray(self, x, pack_item):
# <item>*
# Can pass n and check length - but is it worth it?
print 'farray>', list
for item in x:
pack_item(item)
def pack_array(self, x, pack_item):
# n <item>*n
print 'array>', x
self.pack_uint(len(x))
self.pack_farray(x, pack_item)
class Unpacker:
def __init__(self, data):
self.reset(data)
def reset(self, data):
if isinstance(data, types.StringType):
data = _StringIO(data)
self.io = data
def get_bytes(self, n):
if n < 0:
raise ConversionError('negative byte count')
data = self.io.read(n)
return data
def struct_unpack(self, fmt, n):
data = self.get_bytes(n)
try:
return struct.unpack(fmt, data)[0]
except struct.error, msg:
raise ConversionError, msg
def unpack_none(self):
return None
def unpack_bool(self):
return self.struct_unpack(BOOL_FMT, BOOL_SIZE)
def unpack_char(self):
return self.get_bytes(1)[0]
def unpack_byte(self):
return self.struct_unpack(BYTE_FMT, BYTE_SIZE)
def unpack_ubyte(self):
return self.struct_unpack(UBYTE_FMT, BYTE_SIZE)
def unpack_ushort(self):
return self.struct_unpack(USHORT_FMT, SHORT_SIZE)
def unpack_short(self):
return self.struct_unpack(SHORT_FMT, SHORT_SIZE)
def unpack_uint(self):
x = self.struct_unpack(UINT_FMT, UINT_SIZE)
try:
return int(x)
except OverflowError:
return x
def unpack_int(self):
return self.struct_unpack(INT_FMT, INT_SIZE)
def unpack_uhyper(self):
hi = self.unpack_uint()
lo = self.unpack_uint()
return long(hi)<<32 | lo
def unpack_hyper(self):
x = self.unpack_uhyper()
if x >= 0x8000000000000000L:
x = x - 0x10000000000000000L
return x
def unpack_fstring(self, n):
return self.get_bytes(n)
unpack_fopaque = unpack_fstring
def unpack_string(self):
n = self.unpack_ushort()
return self.unpack_fstring(n)
unpack_opaque = unpack_string
unpack_bytes = unpack_string
def unpack_list(self, unpack_item):
list = []
while self.unpack_bool():
list.append(unpack_item())
return list
def unpack_farray(self, n, unpack_item):
list = []
for i in range(n):
list.append(unpack_item())
return list
def unpack_array(self, unpack_item):
n = self.unpack_ushort()
return self.unpack_farray(n, unpack_item)
class SxpPacker(Packer):
pack_code = Packer.pack_ushort
def pack(self, x):
if isinstance(x, types.NoneType):
self.pack_code(NONE_CODE)
self.pack_none()
elif isinstance(x, types.IntType):
self.pack_code(INT_CODE)
self.pack_int(x)
elif isinstance(x, types.StringType):
self.pack_code(STRING_CODE)
self.pack_string(x)
elif isinstance(x, types.ListType):
self.pack_code(LIST_CODE)
self.pack_list(x, self.pack)
else:
raise Error('invalid type ' + str(type(x)))
class SxpUnpacker(Unpacker):
unpack_code = Unpacker.unpack_ushort
def unpack(self):
code = self.unpack_code()
if code == NONE_CODE:
val = self.unpack_none()
elif code == INT_CODE:
val = self.unpack_int()
elif code == BOOL_CODE:
val = self.unpack_bool()
elif code == STRING_CODE:
val = self.unpack_string()
elif code == ATOM_CODE:
val = self.unpack_string()
elif code == LIST_CODE:
val = self.unpack_list(self.unpack)
else:
raise Error('invalid code ' + str(code))
return val
def main():
d = "['vfarm', ['@', ['name', 'vfarm1']], ['memory', 1024], ['image', 'splinux'], ['args', 'root=/dev/nfs ip=dhcp'], [ 1, -1, 1000000]]"
print"> len=", len(d), "d=", d
obj = ['vfarm', ['@', ['name', 'vfarm1']],
['memory', 1024],
['image', 'splinux'],
['args', 'root=/dev/nfs ip=dhcp'],
[ 1, -1, 1000000] ]
print "> obj=", obj
pack = SxpPacker()
pack.pack(obj)
data = pack.get_buffer()
print "> len=", len(data), "data=", data
unpack = SxpUnpacker(data)
obj_unpack = unpack.unpack()
print "> obj=", obj_unpack
#obj = [100,101,102, 999.00234, { 'a': 1, 'b': 2 } ]
#pack.reset()
#pack.pack_item(obj)
#data = pack.get_buffer()
#print "> obj=", obj
#print "> len=", len(data), "data=", data
#unpack.reset(data)
#obj_unpack = unpack.unpack_item()
#print "> obj=", obj_unpack
if __name__ == "__main__":
main()
+1
View File
@@ -8,6 +8,7 @@ import types
import StringIO
from twisted.internet import defer
defer.Deferred.debug = 1
from twisted.internet import reactor
from twisted.web import error
from twisted.web import resource
+55 -11
View File
@@ -14,6 +14,7 @@ import socket
import pwd
import re
import StringIO
import traceback
from twisted.internet import pollreactor
pollreactor.install()
@@ -22,6 +23,7 @@ from twisted.internet import reactor
from twisted.internet import protocol
from twisted.internet import abstract
from twisted.internet import defer
defer.Deferred.debug = 1
from xen.lowlevel import xu
@@ -392,6 +394,12 @@ class EventProtocol(protocol.Protocol):
eserver.inject(sxp.name(event), event)
return ['ok']
def op_traceon(self, name, v):
self.daemon.tracing(1)
def op_traceoff(self, name, v):
self.daemon.tracing(0)
class EventFactory(protocol.Factory):
"""Asynchronous handler for the event server socket.
@@ -424,6 +432,7 @@ class Daemon:
"""
def __init__(self):
self.shutdown = 0
self.traceon = 0
def daemon_pids(self):
pids = []
@@ -482,7 +491,7 @@ class Daemon:
while code > 0:
code = os.waitpid(-1, os.WNOHANG)
def start(self,trace=0):
def start(self, trace=0):
if self.cleanup(kill=False):
return 1
@@ -506,7 +515,21 @@ class Daemon:
# Child
logfile = self.open_logfile()
self.redirect_output(logfile)
if trace:
self.tracing(trace)
self.run()
return 0
def tracing(self, traceon):
"""Turn tracing on or off.
traceon tracing flag
"""
if traceon == self.traceon:
return
self.traceon = traceon
if traceon:
self.tracefile = open('/var/log/xend.trace', 'w+', 1)
self.traceindent = 0
sys.settrace(self.trace)
@@ -514,26 +537,35 @@ class Daemon:
threading.settrace(self.trace) # Only in Python >= 2.3
except:
pass
self.run()
return 0
def print_trace(self,str):
def print_trace(self, str):
for i in range(self.traceindent):
self.tracefile.write(" ")
ch = " "
if (i % 5):
ch = ' '
else:
ch = '|'
self.tracefile.write(ch)
self.tracefile.write(str)
def trace(self, frame, event, arg):
if not self.traceon:
print >>self.tracefile
print >>self.tracefile, '-' * 20, 'TRACE OFF', '-' * 20
self.tracefile.close()
self.tracefile = None
return None
if event == 'call':
code = frame.f_code
filename = code.co_filename
m = re.search('.*xenmgr/(.*)', code.co_filename)
m = re.search('.*xend/(.*)', filename)
if not m:
return None
modulename = m.group(1)
if re.search('sxp.py', modulename):
return None
self.traceindent += 1
self.print_trace("++++ %s:%s\n"
self.print_trace("> %s:%s\n"
% (modulename, code.co_name))
elif event == 'line':
filename = frame.f_code.co_filename
@@ -543,15 +575,18 @@ class Daemon:
elif event == 'return':
code = frame.f_code
filename = code.co_filename
m = re.search('.*xenmgr/(.*)', code.co_filename)
m = re.search('.*xend/(.*)', filename)
if not m:
return None
modulename = m.group(1)
self.print_trace("---- %s:%s\n"
self.print_trace("< %s:%s\n"
% (modulename, code.co_name))
self.traceindent -= 1
elif event == 'exception':
pass
self.print_trace("! Exception:\n")
(ex, val, tb) = arg
traceback.print_exception(ex, val, tb, 10, self.tracefile)
#del tb
return self.trace
def open_logfile(self):
@@ -629,6 +664,15 @@ class Daemon:
reactor.diconnectAll()
sys.exit(0)
def getDomChannel(self, dom):
"""Get the channel to a domain.
dom domain
returns channel (or None)
"""
return self.channelF.getDomChannel(dom)
def blkif_set_control_domain(self, dom, recreate=0):
"""Set the block device backend control domain.
"""
+5 -1
View File
@@ -27,7 +27,11 @@ class SrvDomain(SrvDir):
return val
def op_shutdown(self, op, req):
val = self.xd.domain_shutdown(self.dom.id)
#val = self.xd.domain_shutdown(self.dom.id)
fn = FormFn(self.xd.domain_shutdown,
[['dom', 'int'],
['reason', 'str']])
val = fn(req.args, {'dom': self.dom.id})
req.setResponseCode(202)
req.setHeader("Location", "%s/.." % req.prePathURL())
return val
+25 -7
View File
@@ -1,5 +1,6 @@
# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
import traceback
from StringIO import StringIO
from twisted.protocols import http
@@ -24,6 +25,7 @@ class SrvDomainDir(SrvDir):
val = None
try:
dom = self.xd.domain_get(x)
if not dom: raise KeyError('No such domain')
val = SrvDomain(dom)
except KeyError, ex:
print 'SrvDomainDir>', ex
@@ -38,6 +40,9 @@ class SrvDomainDir(SrvDir):
return v
def op_create(self, op, req):
"""Create a domain.
Expects the domain config in request parameter 'config' in SXP format.
"""
ok = 0
try:
configstring = req.args.get('config')[0]
@@ -48,7 +53,8 @@ class SrvDomainDir(SrvDir):
config = pin.get_val()
ok = 1
except Exception, ex:
print 'op_create>', ex
print 'op_create> Exception in config', ex
traceback.print_exc()
if not ok:
req.setResponseCode(http.BAD_REQUEST, "Invalid configuration")
return "Invalid configuration"
@@ -57,19 +63,20 @@ class SrvDomainDir(SrvDir):
"Invalid configuration")
try:
deferred = self.xd.domain_create(config)
deferred.addCallback(self._cb_op_create, configstring, req)
deferred.addCallback(self._op_create_cb, configstring, req)
deferred.addErrback(self._op_create_err, req)
return deferred
except Exception, ex:
raise
#return ['err', str(ex) ]
#req.setResponseCode(http.BAD_REQUEST, "Error creating domain")
#return str(ex)
print 'op_create> Exception creating domain:'
traceback.print_exc()
req.setResponseCode(http.BAD_REQUEST, "Error creating domain")
return str(ex)
#return error.ErrorPage(http.BAD_REQUEST,
# "Error creating domain",
# str(ex))
def _cb_op_create(self, dominfo, configstring, req):
def _op_create_cb(self, dominfo, configstring, req):
"""Callback to handle deferred domain creation.
"""
dom = dominfo.id
@@ -89,7 +96,16 @@ class SrvDomainDir(SrvDir):
out.close()
return val
def _op_create_err(self, err, req):
"""Callback to handle errors in deferred domain creation.
"""
print 'op_create> Deferred Exception creating domain:', err
req.setResponseCode(http.BAD_REQUEST, "Error creating domain")
return str(err)
def op_restore(self, op, req):
"""Restore a domain from file.
"""
fn = FormFn(self.xd.domain_restore,
[['file', 'str']])
val = fn(req.args)
@@ -131,6 +147,8 @@ class SrvDomainDir(SrvDir):
req.write('</ul>')
def form(self, req):
"""Generate the form(s) for domain dir operations.
"""
req.write('<form method="post" action="%s" enctype="multipart/form-data">'
% req.prePathURL())
req.write('<button type="submit" name="op" value="create">Create Domain</button>')
+93 -61
View File
@@ -1,4 +1,7 @@
# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
from twisted.internet import defer
defer.Deferred.debug = 1
from xen.xend import sxp
from xen.xend import PrettyPrint
@@ -18,53 +21,78 @@ class BlkifControllerFactory(controller.ControllerFactory):
self.majorTypes = [ CMSG_BLKIF_BE ]
self.subTypes = {
CMSG_BLKIF_BE_CREATE : self.recv_be_create,
CMSG_BLKIF_BE_CONNECT : self.recv_be_connect,
CMSG_BLKIF_BE_VBD_CREATE : self.recv_be_vbd_create,
CMSG_BLKIF_BE_VBD_GROW : self.recv_be_vbd_grow,
CMSG_BLKIF_BE_DRIVER_STATUS_CHANGED: self.recv_be_driver_status_changed,
}
self.attached = 1
self.registerChannel()
def createInstance(self, dom, recreate=0):
d = self.addDeferred()
"""Create a block device controller for a domain.
dom domain
recreate if true it's a recreate (after xend restart)
"""
d = defer.Deferred()
blkif = self.getInstanceByDom(dom)
if blkif:
self.callDeferred(blkif)
d.callback(blkif)
else:
blkif = BlkifController(self, dom)
self.addInstance(blkif)
if recreate:
self.callDeferred(blkif)
d.callback(blkif)
else:
blkif.send_be_create()
d1 = defer.Deferred()
d1.addCallback(self.respond_be_create, d)
d1.addErrback(d.errback)
blkif.send_be_create(response=d1)
return d
def getDomainDevices(self, dom):
"""Get the block devices for a domain.
dom domain
returns devices
"""
blkif = self.getInstanceByDom(dom)
return (blkif and blkif.getDevices()) or []
def getDomainDevice(self, dom, vdev):
"""Get a block device from a domain.
dom domain
vdev device index
returns device
"""
blkif = self.getInstanceByDom(dom)
return (blkif and blkif.getDevice(vdev)) or None
def setControlDomain(self, dom, recreate=0):
"""Set the back-end block device controller domain.
dom domain
recreate if true it's a recreate (after xend restart)
"""
if self.dom == dom: return
self.deregisterChannel()
if not recreate:
self.attached = 0
self.dom = dom
self.registerChannel()
#
#if xend.blkif.be_port:
# xend.blkif.recovery = True
#xend.blkif.be_port = xend.main.port_from_dom(dom)
def getControlDomain(self):
"""Get the back-end block device controller domain.
"""
return self.dom
def reattachDevice(self, dom, vdev):
"""Reattach a device (on changing control domain).
dom domain
vdev device index
"""
blkif = self.getInstanceByDom(dom)
if blkif:
blkif.reattachDevice(vdev)
@@ -83,17 +111,20 @@ class BlkifControllerFactory(controller.ControllerFactory):
return attached
def reattached(self):
"""Notify all block interface we have been reattached
(after changing control domain).
"""
for blkif in self.getInstances():
blkif.reattached()
def recv_be_create(self, msg, req):
#print 'recv_be_create>'
def respond_be_create(self, msg, d):
print 'respond_be_create>'
val = unpackMsg('blkif_be_create_t', msg)
blkif = self.getInstanceByDom(val['domid'])
self.callDeferred(blkif)
d.callback(blkif)
def recv_be_connect(self, msg, req):
#print 'recv_be_create>'
def respond_be_connect(self, msg):
print 'respond_be_connect>', self
val = unpackMsg('blkif_be_connect_t', msg)
blkif = self.getInstanceByDom(val['domid'])
if blkif:
@@ -101,25 +132,30 @@ class BlkifControllerFactory(controller.ControllerFactory):
else:
pass
def recv_be_vbd_create(self, msg, req):
#print 'recv_be_vbd_create>'
def respond_be_vbd_create(self, msg, d):
print 'recv_be_vbd_create>', self
val = unpackMsg('blkif_be_vbd_create_t', msg)
blkif = self.getInstanceByDom(val['domid'])
if blkif:
blkif.send_be_vbd_grow(val['vdevice'])
d1 = defer.Deferred()
d1.addCallback(self.respond_be_vbd_grow, d)
if d: d1.addErrback(d.errback)
blkif.send_be_vbd_grow(val['vdevice'], response=d1)
else:
pass
def recv_be_vbd_grow(self, msg, req):
#print 'recv_be_vbd_grow>'
def respond_be_vbd_grow(self, msg, d):
print 'recv_be_vbd_grow>', self
val = unpackMsg('blkif_be_vbd_grow_t', msg)
# Check status?
if self.attached:
self.callDeferred(0)
if d:
d.callback(0)
else:
self.reattachDevice(val['domid'], val['vdevice'])
def recv_be_driver_status_changed(self, msg, req):
print 'recv_be_driver_status_changed>', self, req
val = unpackMsg('blkif_be_driver_status_changed_t', msg)
status = val['status']
if status == BLKIF_DRIVER_STATUS_UP and not self.attached:
@@ -147,7 +183,6 @@ class BlkDev(controller.Dev):
return val
def destroy(self):
print 'BlkDev>destroy>', self.vdev
PrettyPrint.prettyprint(self.sxpr())
self.controller.send_be_vbd_destroy(self.vdev)
@@ -157,7 +192,6 @@ class BlkifController(controller.Controller):
"""
def __init__(self, factory, dom):
#print 'BlkifController> dom=', dom
controller.Controller.__init__(self, factory, dom)
self.devices = {}
@@ -172,7 +206,6 @@ class BlkifController(controller.Controller):
self.attached = 1
self.evtchn = None
self.registerChannel()
#print 'BlkifController<', 'dom=', self.dom, 'idx=', self.idx
def sxpr(self):
val = ['blkif', ['dom', self.dom]]
@@ -182,11 +215,6 @@ class BlkifController(controller.Controller):
self.evtchn['port2']])
return val
def lostChannel(self):
print 'BlkifController>lostChannel>', 'dom=', self.dom
#self.destroyDevices()
controller.Controller.lostChannel(self)
def getDevices(self):
return self.devices.values()
@@ -201,26 +229,32 @@ class BlkifController(controller.Controller):
def attachDevice(self, vdev, mode, segment, recreate=0):
"""Attach a device to the specified interface.
vdev device index
mode read/write mode
segment segment
recreate if true it's being recreated (after xend restart)
returns deferred
"""
#print 'BlkifController>attach_device>', self.dom, vdev, mode, segment
dev = self.addDevice(vdev, mode, segment)
if not dev: return -1
d = defer.Deferred()
if recreate:
d = defer.Deferred()
d.callback(self)
else:
self.send_be_vbd_create(vdev)
d = self.factory.addDeferred()
d1 = defer.Deferred()
d1.addCallback(self.factory.respond_be_vbd_create, d)
d1.addErrback(d.errback)
self.send_be_vbd_create(vdev, response=d1)
return d
def destroy(self):
print 'BlkifController>destroy> dom=', self.dom
def cb_destroy(val):
self.send_be_destroy()
d = self.factory.addDeferred()
d = defer.Deferred()
d.addCallback(cb_destroy)
self.send_be_disconnect()
#self.destroyDevices()
self.send_be_disconnect(response=d)
def destroyDevices(self):
for dev in self.getDevices():
@@ -232,7 +266,9 @@ class BlkifController(controller.Controller):
self.attached = 0
for dev in self.devices.values():
dev.attached = 0
self.send_be_vbd_create(vdev)
d1 = defer.Deferred()
d1.addCallback(self.factory.respond_be_vbd_create, None)
self.send_be_vbd_create(vdev, response=d1)
def reattachDevice(self, vdev):
"""Reattach a device, when the back-end control domain has changed.
@@ -273,51 +309,47 @@ class BlkifController(controller.Controller):
'blkif_handle' : val['handle'],
'evtchn' : self.evtchn['port1'],
'shmem_frame' : val['shmem_frame'] })
self.factory.writeRequest(msg)
pass
d = defer.Deferred()
d.addCallback(self.factory.respond_be_connect)
self.factory.writeRequest(msg, response=d)
#def recv_fe_interface_status_changed(self, msg, req):
# (hnd, status, chan) = unpackMsg('blkif_fe_interface_status_changed_t', msg)
# print 'recv_fe_interface_status_changed>', hnd, status, chan
# pass
def send_fe_interface_status_changed(self):
def send_fe_interface_status_changed(self, response=None):
msg = packMsg('blkif_fe_interface_status_changed_t',
{ 'handle' : 0,
'status' : BLKIF_INTERFACE_STATUS_CONNECTED,
'evtchn' : self.evtchn['port2'] })
self.writeRequest(msg)
self.writeRequest(msg, response=response)
def send_be_create(self):
def send_be_create(self, response=None):
msg = packMsg('blkif_be_create_t',
{ 'domid' : self.dom,
'blkif_handle' : 0 })
self.factory.writeRequest(msg)
self.factory.writeRequest(msg, response=response)
def send_be_disconnect(self):
def send_be_disconnect(self, response=None):
print '>BlkifController>send_be_disconnect>', 'dom=', self.dom
msg = packMsg('blkif_be_disconnect_t',
{ 'domid' : self.dom,
'blkif_handle' : 0 })
self.factory.writeRequest(msg)
self.factory.writeRequest(msg, response=response)
def send_be_destroy(self):
def send_be_destroy(self, response=None):
print '>BlkifController>send_be_destroy>', 'dom=', self.dom
msg = packMsg('blkif_be_destroy_t',
{ 'domid' : self.dom,
'blkif_handle' : 0 })
self.factory.writeRequest(msg)
self.factory.writeRequest(msg, response=response)
def send_be_vbd_create(self, vdev):
def send_be_vbd_create(self, vdev, response=None):
dev = self.devices[vdev]
msg = packMsg('blkif_be_vbd_create_t',
{ 'domid' : self.dom,
'blkif_handle' : 0,
'vdevice' : dev.vdev,
'readonly' : dev.readonly() })
self.factory.writeRequest(msg)
self.factory.writeRequest(msg, response=response)
def send_be_vbd_grow(self, vdev):
def send_be_vbd_grow(self, vdev, response=None):
dev = self.devices[vdev]
msg = packMsg('blkif_be_vbd_grow_t',
{ 'domid' : self.dom,
@@ -326,9 +358,9 @@ class BlkifController(controller.Controller):
'extent.device' : dev.device,
'extent.sector_start' : dev.start_sector,
'extent.sector_length' : dev.nr_sectors })
self.factory.writeRequest(msg)
self.factory.writeRequest(msg, response=response)
def send_be_vbd_destroy(self, vdev):
def send_be_vbd_destroy(self, vdev, response=None):
print '>BlkifController>send_be_vbd_destroy>', 'dom=', self.dom, 'vdev=', vdev
PrettyPrint.prettyprint(self.sxpr())
dev = self.devices[vdev]
@@ -337,5 +369,5 @@ class BlkifController(controller.Controller):
'blkif_handle' : 0,
'vdevice' : dev.vdev })
del self.devices[vdev]
self.factory.writeRequest(msg)
self.factory.writeRequest(msg, response=response)
+46 -19
View File
@@ -1,3 +1,5 @@
# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
import xen.lowlevel.xc; xc = xen.lowlevel.xc.new()
from xen.lowlevel import xu
from messages import msgTypeName
@@ -24,14 +26,11 @@ class ChannelFactory:
self.notifier = xu.notifier()
def addChannel(self, channel):
"""Add a channel.
"""Add a channel. Registers with the notifier.
"""
idx = channel.idx
self.channels[idx] = channel
self.notifier.bind(idx)
# Try to wake it up
#self.notifier.unmask(idx)
#channel.notify()
def getChannel(self, idx):
"""Get the channel with the given index (if any).
@@ -40,6 +39,7 @@ class ChannelFactory:
def delChannel(self, idx):
"""Remove the channel with the given index (if any).
Deregisters with the notifier.
"""
if idx in self.channels:
del self.channels[idx]
@@ -48,15 +48,31 @@ class ChannelFactory:
def domChannel(self, dom):
"""Get the channel for the given domain.
Construct if necessary.
dom domain
returns channel
"""
chan = self.getDomChannel(dom)
if not chan:
chan = Channel(self, dom)
self.addChannel(chan)
return chan
def getDomChannel(self, dom):
"""Get the channel for the given domain.
dom domain
returns channel (or None)
"""
dom = int(dom)
for chan in self.channels.values():
if not isinstance(chan, Channel): continue
if chan.dom == dom:
return chan
chan = Channel(self, dom)
self.addChannel(chan)
return chan
return None
def virqChannel(self, virq):
"""Get the channel for the given virq.
@@ -109,12 +125,11 @@ class BaseChannel:
def notificationReceived(self):
"""Called when a notification is received.
Closes the channel on error, otherwise calls
handleNotification(type), which should be defined
Calls handleNotification(), which should be defined
in a subclass.
"""
if not self.closed:
self.handleNotification(type)
if self.closed: return
self.handleNotification()
def close(self):
"""Close the channel. Calls channelClosed() on the factory.
@@ -122,7 +137,7 @@ class BaseChannel:
"""
self.factory.channelClosed(self)
def handleNotification(self, type):
def handleNotification(self):
"""Handle notification.
Define in subclass.
"""
@@ -159,9 +174,9 @@ class VirqChannel(BaseChannel):
"""Close the channel. Calls lostChannel(self) on all its clients and
channelClosed() on the factory.
"""
for c in self.clients:
for c in self.clients[:]:
c.lostChannel(self)
del self.clients
self.clients = []
BaseChannel.close(self)
def registerClient(self, client):
@@ -172,7 +187,7 @@ class VirqChannel(BaseChannel):
"""
self.clients.append(client)
def handleNotification(self, type):
def handleNotification(self):
for c in self.clients:
c.virqReceived(self.virq)
@@ -208,23 +223,27 @@ class Channel(BaseChannel):
def getLocalPort(self):
"""Get the local port.
"""
if self.closed: return -1
return self.port.local_port
def getRemotePort(self):
"""Get the remote port.
"""
if self.closed: return -1
return self.port.remote_port
def close(self):
"""Close the channel. Calls lostChannel() on all its devices and
channelClosed() on the factory.
"""
if self.closed: return
self.closed = 1
for d in self.devs:
for d in self.devs[:]:
d.lostChannel()
self.factory.channelClosed(self)
self.devs = []
self.devs_by_type = {}
self.port.disconnect()
def registerDevice(self, types, dev):
"""Register a device controller.
@@ -265,10 +284,15 @@ class Channel(BaseChannel):
def __repr__(self):
return ('<Channel dom=%d ports=%d:%d>'
% (self.dom,
self.port.local_port,
self.port.remote_port))
self.getLocalPort(),
self.getRemotePort()))
def handleNotification(self, type):
def handleNotification(self):
"""Process outstanding messages in repsonse to notification on the port.
"""
if self.closed:
print 'handleNotification> Notification on closed channel', self
return
work = 0
work += self.handleRequests()
work += self.handleResponses()
@@ -277,6 +301,9 @@ class Channel(BaseChannel):
self.notify()
def notify(self):
"""Notify the other end of the port that messages have been processed.
"""
if self.closed: return
self.port.notify()
def handleRequests(self):
+57 -38
View File
@@ -1,3 +1,4 @@
# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
from twisted.internet import reactor
from twisted.internet import protocol
@@ -12,11 +13,6 @@ import controller
from messages import *
from params import *
"""Telnet binary option."""
TRANSMIT_BINARY = '0'
WILL = chr(251)
IAC = chr(255)
class ConsoleProtocol(protocol.Protocol):
"""Asynchronous handler for a console TCP socket.
"""
@@ -36,19 +32,12 @@ class ConsoleProtocol(protocol.Protocol):
self.loseConnection()
return
else:
# KAF: A nice quiet successful connect. Don't bother with telnet
# control sequence -- telnet is not the appropriate protocol here.
# KAF: A nice quiet successful connect.
#self.transport.write("Connected to console %d on domain %d\n"
# % (self.idx, self.controller.dom))
#self.setTelnetTransmitBinary()
eserver.inject('xend.console.connect',
[self.idx, self.addr[0], self.addr[1]])
def setTelnetTransmitBinary(self):
"""Send the sequence to set the telnet TRANSMIT-BINARY option.
"""
self.write(IAC + WILL + TRANSMIT_BINARY)
def dataReceived(self, data):
if self.controller.handleInput(self, data):
self.loseConnection()
@@ -104,11 +93,15 @@ class ConsoleController(controller.Controller):
output and the connected TCP sockets to post console input.
"""
STATUS_NEW = 'new'
STATUS_CLOSED = 'closed'
STATUS_CONNECTED = 'connected'
STATUS_LISTENING = 'listening'
def __init__(self, factory, dom, console_port):
#print 'ConsoleController> dom=', dom, type(dom)
controller.Controller.__init__(self, factory, dom)
self.majorTypes = [ CMSG_CONSOLE ]
self.status = "new"
self.status = self.STATUS_NEW
self.addr = None
self.conn = None
self.rbuf = xu.buffer()
@@ -118,7 +111,6 @@ class ConsoleController(controller.Controller):
self.registerChannel()
self.listener = None
self.listen()
#print 'ConsoleController<', 'dom=', self.dom, 'idx=', self.idx
def sxpr(self):
val =['console',
@@ -136,29 +128,31 @@ class ConsoleController(controller.Controller):
return not (self.closed() or self.rbuf.empty())
def closed(self):
return self.status == 'closed'
return self.status == self.STATUS_CLOSED
def connected(self):
return self.status == 'connected'
return self.status == self.STATUS_CONNECTED
def close(self):
try:
#print 'ConsoleController> close dom=', self.dom
self.status = "closed"
if self.conn:
self.conn.loseConnection()
self.listener.stopListening()
self.deregisterChannel()
self.lostChannel()
except Exception, ex:
print 'ConsoleController>close>', ex
raise
"""Close the console controller.
"""
self.lostChannel()
def lostChannel(self):
"""The channel to the domain has been lost.
Cleanup: disconnect TCP connections and listeners, notify the controller.
"""
self.status = self.STATUS_CLOSED
if self.conn:
self.conn.loseConnection()
self.listener.stopListening()
controller.Controller.lostChannel(self)
def listen(self):
"""Listen for TCP connections to the console port..
"""
if self.closed(): return
self.status = "listening"
self.status = self.STATUS_LISTENING
if self.listener:
#self.listener.startListening()
pass
@@ -167,15 +161,25 @@ class ConsoleController(controller.Controller):
self.listener = reactor.listenTCP(self.console_port, f)
def connect(self, addr, conn):
"""Connect a TCP connection to the console.
Fails if closed or already connected.
addr peer address
conn connection
returns 0 if ok, negative otherwise
"""
if self.closed(): return -1
if self.connected(): return -1
self.addr = addr
self.conn = conn
self.status = "connected"
self.status = self.STATUS_CONNECTED
self.handleOutput()
return 0
def disconnect(self):
"""Disconnect the TCP connection to the console.
"""
if self.conn:
self.conn.loseConnection()
self.addr = None
@@ -183,15 +187,29 @@ class ConsoleController(controller.Controller):
self.listen()
def requestReceived(self, msg, type, subtype):
#print '***Console', self.dom, msg.get_payload()
"""Receive console data from the console channel.
msg console message
type major message type
subtype minor message typ
"""
self.rbuf.write(msg.get_payload())
self.handleOutput()
def responseReceived(self, msg, type, subtype):
"""Handle a response to a request written to the console channel.
Just ignore it because the return values are not interesting.
msg console message
type major message type
subtype minor message typ
"""
pass
def produceRequests(self):
# Send as much pending console data as there is room for.
"""Write pending console data to the console channel.
Writes as much to the channel as it can.
"""
work = 0
while not self.wbuf.empty() and self.channel.writeReady():
msg = xu.message(CMSG_CONSOLE, 0, 0)
@@ -201,7 +219,12 @@ class ConsoleController(controller.Controller):
def handleInput(self, conn, data):
"""Handle some external input aimed at the console.
Called from a TCP connection (conn).
Called from a TCP connection (conn). Ignores the input
if the calling connection (conn) is not the one connected
to the console (self.conn).
conn connection
data input data
"""
if self.closed(): return -1
if conn != self.conn: return 0
@@ -215,18 +238,14 @@ class ConsoleController(controller.Controller):
Sends it to the connected console (if any).
"""
if self.closed():
#print 'Console>handleOutput> closed'
return -1
if not self.conn:
#print 'Console>handleOutput> not connected'
return 0
while not self.rbuf.empty():
try:
#print 'Console>handleOutput> writing...'
bytes = self.conn.write(self.rbuf.peek())
if bytes > 0:
self.rbuf.discard(bytes)
except socket.error, error:
pass
#print 'Console>handleOutput<'
return 0
+163 -34
View File
@@ -1,10 +1,50 @@
# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
from twisted.internet import defer
defer.Deferred.debug = 1
import channel
from messages import msgTypeName
DEBUG=0
class OutOfOrderError(RuntimeError):
"""Error reported when a response arrives out of order.
"""
pass
class Responder:
"""Handler for a response to a message.
"""
def __init__(self, mid, deferred):
"""Create a responder.
mid message id of response to handle
deferred deferred object holding the callbacks
"""
self.mid = mid
self.deferred = deferred
def responseReceived(self, msg):
if self.deferred.called: return
self.deferred.callback(msg)
def error(self, err):
if self.deferred.called: return
self.deferred.errback(err)
class CtrlMsgRcvr:
"""Abstract class for things that deal with a control interface to a domain.
Instance variables:
dom : the domain we are a control interface for
majorTypes: list of major message types we are interested in
subTypes : mapping of message subtypes to methods
channel : channel to the domain
idx : channel index
"""
@@ -15,50 +55,140 @@ class CtrlMsgRcvr:
self.dom = None
self.channel = None
self.idx = None
self.responders = []
# Timeout (in seconds) for deferreds.
self.timeout = 10
def setTimeout(self, timeout):
self.timeout = timeout
def requestReceived(self, msg, type, subtype):
"""Dispatch a request to handlers.
msg message
type major message type
subtype minor message type
"""
msgid = msg.get_header()['id']
if DEBUG:
print 'requestReceived>', self, msgid, msgTypeName(type, subtype)
method = self.subTypes.get(subtype)
if method:
method(msg, 1)
else:
elif DEBUG:
print ('requestReceived> No handler: Message type %s %d:%d'
% (msgTypeName(type, subtype), type, subtype)), self
def responseReceived(self, msg, type, subtype):
"""Dispatch a response to handlers.
msg message
type major message type
subtype minor message type
"""
msgid = msg.get_header()['id']
if DEBUG:
print 'responseReceived>', self, msgid, msgTypeName(type, subtype)
if self.callResponders(msg):
return
method = self.subTypes.get(subtype)
if method:
method(msg, 0)
else:
elif DEBUG:
print ('responseReceived> No handler: Message type %s %d:%d'
% (msgTypeName(type, subtype), type, subtype)), self
def addResponder(self, mid, deferred):
"""Add a responder for a message id.
The deferred is called with callback(msg) when a response
with the given message id arrives. Responses are expected
to arrive in order of message id. When a response arrives,
waiting responders for messages with lower id have errback
called with an OutOfOrder error.
mid message id of response expected
deferred a Deferred to handle the response
returns Responder
"""
if self.timeout > 0:
deferred.setTimeout(self.timeout)
resp = Responder(mid, deferred)
self.responders.append(resp)
return resp
def callResponders(self, msg):
"""Call any waiting responders for a response message.
msg response message
returns 1 if there was a responder for the message, 0 otherwise
"""
hdr = msg.get_header()
mid = hdr['id']
handled = 0
while self.responders:
resp = self.responders[0]
if resp.mid > mid:
break
self.responders.pop()
if resp.mid < mid:
print 'handleResponse> Out of order:', resp.mid, mid
resp.error(OutOfOrderError())
else:
handled = 1
resp.responseReceived(msg)
break
return handled
def lostChannel(self):
"""Called when the channel to the domain is lost.
"""
pass
def registerChannel(self):
#print 'CtrlMsgRcvr>registerChannel>', self
"""Register interest in our major message types with the
channel to our domain.
"""
self.channel = self.channelFactory.domChannel(self.dom)
self.idx = self.channel.getIndex()
if self.majorTypes:
self.channel.registerDevice(self.majorTypes, self)
def deregisterChannel(self):
#print 'CtrlMsgRcvr>deregisterChannel>', self
"""Deregister interest in our major message types with the
channel to our domain.
"""
if self.channel:
self.channel.deregisterDevice(self)
del self.channel
def produceRequests(self):
"""Produce any queued requests.
return number produced
"""
return 0
def writeRequest(self, msg):
def writeRequest(self, msg, response=None):
"""Write a request to the channel.
msg message
response Deferred to handle the response (optional)
"""
if self.channel:
if DEBUG: print 'CtrlMsgRcvr>writeRequest>', self, msg
if response:
self.addResponder(msg.get_header()['id'], response)
self.channel.writeRequest(msg)
else:
print 'CtrlMsgRcvr>writeRequest>', 'no channel!', self
def writeResponse(self, msg):
"""Write a response to the channel.
"""
if self.channel:
if DEBUG: print 'CtrlMsgRcvr>writeResponse>', self, msg
self.channel.writeResponse(msg)
else:
print 'CtrlMsgRcvr>writeResponse>', 'no channel!', self
@@ -66,6 +196,12 @@ class CtrlMsgRcvr:
class ControllerFactory(CtrlMsgRcvr):
"""Abstract class for factories creating controllers.
Maintains a table of instances.
Instance variables:
instances : mapping of index to controller instance
dlist : list of deferreds
dom : domain
"""
def __init__(self):
@@ -73,55 +209,46 @@ class ControllerFactory(CtrlMsgRcvr):
self.instances = {}
self.dlist = []
self.dom = 0
# Timeout (in seconds) for deferreds.
self.timeout = 10
def addInstance(self, instance):
"""Add a controller instance (under its index).
"""
self.instances[instance.idx] = instance
def getInstance(self, idx):
"""Get a controller instance from its index.
"""
return self.instances.get(idx)
def getInstances(self):
"""Get a list of all controller instances.
"""
return self.instances.values()
def getInstanceByDom(self, dom):
"""Get the controller instance for the given domain.
"""
for inst in self.instances.values():
if inst.dom == dom:
return inst
return None
def delInstance(self, instance):
#print 'ControllerFactory>delInstance>', instance.idx
"""Delete an instance from the table.
"""
if instance.idx in self.instances:
#print 'ControllerFactory>delInstance> remove', instance.idx
del self.instances[instance.idx]
def createInstance(self, dom, recreate=0):
"""Create an instance. Define in a subclass.
"""
raise NotImplementedError()
def instanceClosed(self, instance):
#print 'ControllerFactory>instanceClosed>', instance.idx, instance
"""Callback called when an instance is closed (usually by the instance).
"""
self.delInstance(instance)
def addDeferred(self):
d = defer.Deferred()
if self.timeout > 0:
# The deferred will error if not called before timeout.
d.setTimeout(self.timeout)
self.dlist.append(d)
return d
def callDeferred(self, *args):
if self.dlist:
d = self.dlist.pop(0)
d.callback(*args)
def errDeferred(self, *args):
if self.dlist:
d = self.dlist.pop(0)
d.errback(*args)
class Controller(CtrlMsgRcvr):
"""Abstract class for a device controller attached to a domain.
"""
@@ -134,15 +261,20 @@ class Controller(CtrlMsgRcvr):
self.idx = None
def close(self):
self.deregisterChannel()
"""Close the controller.
"""
self.lostChannel()
def lostChannel(self):
#print 'Controller>lostChannel>', self, self.factory
"""The controller channel has been lost.
"""
self.deregisterChannel()
self.factory.instanceClosed(self)
class Dev:
"""Abstract class for a device attached to a device controller.
"""
def __init__(self, controller):
self.controller = controller
self.props = {}
@@ -160,9 +292,6 @@ class Dev:
if k in self.props:
del self.props[k]
#def __repr__(self):
# return str(self.sxpr())
def sxpr(self):
raise NotImplementedError()
-269
View File
@@ -1,269 +0,0 @@
import struct
class Struct:
maxDepth = 10
base = ['x', 'B', 'H', 'I', 'L', 'Q', 'c', 'h', 'i', 'l', 'q', ]
sizes = {'B': 1,
'H': 2,
'I': 4,
'L': 4,
'Q': 8,
'c': 1,
'h': 2,
'i': 4,
'l': 4,
'q': 8,
'x': 1,
}
formats = {
'int8' : 'B',
'int16' : 'H',
'int32' : 'I',
'int64' : 'Q',
'u8' : 'B',
'u16' : 'H',
'u32' : 'I',
'u64' : 'Q'
}
def typedef(self, name, val):
self.formats[name] = val
def struct(self, name, *f):
self.typedef(name, StructInfo(self, f))
def getType(self, name):
return self.formats[name]
def format(self, ty):
d = 0
f = ty
while d < self.maxDepth:
d += 1
f = self.formats[f]
if isinstance(f, StructInfo):
return f.format()
if f in self.base:
return f
return -1
def alignedformat(self, ty):
fmt = self.format(ty)
#print 'alignedformat> %s |%s|' %(ty, fmt)
afmt = self.align(fmt)
#print 'alignedformat< %s |%s| |%s|' % (ty, fmt, afmt)
return afmt
def align(self, fmt):
n1 = 0
afmt = ''
for a in fmt:
n2 = self.getSize(a)
m = n1 % n2
if m:
d = (n2 - m)
afmt += 'x' * d
n1 += d
afmt += a
n1 += n2
return afmt
def fmtsize(self, fmt):
s = 0
for f in fmt:
s += self.getSize(f)
return s
def getSize(self, f):
return self.sizes[f]
def pack(self, ty, data):
return self.getType(ty).pack(data)
def unpack(self, ty, data):
return self.getType(ty).unpack(data)
def show(self):
l = self.formats.keys()
l.sort()
for v in l:
print "%-35s %-10s %s" % (v, self.format(v), self.alignedformat(v))
class StructInfo:
def __init__(self, s, f):
self.fmt = None
self.structs = s
self.fields = f
def alignedformat(self):
if self.afmt: return self.afmt
self.afmt = self.structs.align(self.format())
return self.afmt
def format(self):
if self.fmt: return self.fmt
fmt = ""
for (ty, name) in self.fields:
fmt += self.formatString(ty)
self.fmt = fmt
return fmt
def formatString(self, ty):
if ty in self.fields:
ty = self.fields[ty]
return self.structs.format(ty)
def pack(self, *args):
return struct.pack(self.alignedformat(), *args)
def unpack(self, data):
return struct.unpack(self.alignedformat(), data)
types = Struct()
types.typedef('short' , 'h')
types.typedef('int' , 'i')
types.typedef('long' , 'l')
types.typedef('unsigned short', 'H')
types.typedef('unsigned int' , 'I')
types.typedef('unsigned long' , 'L')
types.typedef('domid_t' , 'u64')
types.typedef('blkif_vdev_t' , 'u16')
types.typedef('blkif_pdev_t' , 'u16')
types.typedef('blkif_sector_t', 'u64')
types.struct('u8[6]',
('u8', 'a1'),
('u8', 'a2'),
('u8', 'a3'),
('u8', 'a4'),
('u8', 'a5'),
('u8', 'a6'))
types.struct('blkif_fe_interface_status_changed_t',
('unsigned int', 'handle'),
('unsigned int', 'status'),
('unsigned int', 'evtchn'))
types.struct('blkif_fe_driver_status_changed_t',
('unsigned int', 'status'),
('unsigned int', 'nr_interfaces'))
types.struct('blkif_fe_interface_connect_t',
('unsigned int' , 'handle'),
('unsigned long', 'shmem_frame'))
types.struct('blkif_fe_interface_disconnect_t',
('unsigned int', 'handle'))
types.struct('blkif_extent_t',
('blkif_pdev_t' , 'device'),
('blkif_sector_t', 'sector_start'),
('blkif_sector_t', 'sector_length'))
types.struct('blkif_be_create_t',
('domid_t' , 'domid'),
('unsigned int', 'blkif_handle'),
('unsigned int', 'status'))
types.struct('blkif_be_destroy_t',
('domid_t' , 'domid'),
('unsigned int', 'blkif_handle'),
('unsigned int', 'status'))
types.struct('blkif_be_connect_t',
('domid_t' , 'domid'),
('unsigned int' , 'blkif_handle'),
('unsigned int' , 'evtchn'),
('unsigned long', 'shmem_frame'),
('unsigned int' , 'status'))
types.struct('blkif_be_disconnect_t',
('domid_t' , 'domid'),
('unsigned int', 'blkif_handle'),
('unsigned int', 'status'))
types.struct('blkif_be_vbd_create_t',
('domid_t' , 'domid'), #Q
('unsigned int', 'blkif_handle'), #I
('blkif_vdev_t', 'vdevice'), #H
('int' , 'readonly'), #i
('unsigned int', 'status')) #I
types.struct('blkif_be_vbd_destroy_t',
('domid_t' , 'domid'),
('unsigned int', 'blkif_handle'),
('blkif_vdev_t', 'vdevice'),
('unsigned int', 'status'))
types.struct('blkif_be_vbd_grow_t',
('domid_t' , 'domid'), #Q
('unsigned int' , 'blkif_handle'), #I
('blkif_vdev_t' , 'vdevice'), #H
('blkif_extent_t', 'extent'), #HQQ
('unsigned int' , 'status')) #I
types.struct('blkif_be_vbd_shrink_t',
('domid_t' , 'domid'),
('unsigned int', 'blkif_handle'),
('blkif_vdev_t', 'vdevice'),
('unsigned int', 'status'))
types.struct('blkif_be_driver_status_changed_t',
('unsigned int', 'status'),
('unsigned int', 'nr_interfaces'))
types.struct('netif_fe_interface_status_changed_t',
('unsigned int', 'handle'),
('unsigned int', 'status'),
('unsigned int', 'evtchn'),
('u8[6]', 'mac'))
types.struct('netif_fe_driver_status_changed_t',
('unsigned int', 'status'),
('unsigned int', 'nr_interfaces'))
types.struct('netif_fe_interface_connect_t',
('unsigned int', 'handle'),
('unsigned long', 'tx_shmem_frame'),
('unsigned long', 'rx_shmem_frame'))
types.struct('netif_fe_interface_disconnect_t',
('unsigned int', 'handle'))
types.struct('netif_be_create_t',
('domid_t' , 'domid'),
('unsigned int', 'netif_handle'),
('u8[6]' , 'mac'),
('unsigned int', 'status'))
types.struct('netif_be_destroy_t',
('domid_t' , 'domid'),
('unsigned int', 'netif_handle'),
('unsigned int', 'status'))
types.struct('netif_be_connect_t',
('domid_t' , 'domid'),
('unsigned int' , 'netif_handle'),
('unsigned int' , 'evtchn'),
('unsigned long', 'tx_shmem_frame'),
('unsigned long', 'rx_shmem_frame'),
('unsigned int' , 'status'))
types.struct('netif_be_disconnect_t',
('domid_t' , 'domid'),
('unsigned int', 'netif_handle'),
('unsigned int', 'status'))
types.struct('netif_be_driver_status_changed_t',
('unsigned int', 'status'),
('unsigned int', 'nr_interfaces'))
if 1 or __name__ == "__main__":
types.show()
+21
View File
@@ -1,3 +1,5 @@
# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
import channel
import controller
from messages import *
@@ -7,11 +9,23 @@ class DomainControllerFactory(controller.ControllerFactory):
"""
def createInstance(self, dom):
"""Create a domain controller.
dom domain
returns domain controller
"""
d = DomainController(self, dom)
self.addInstance(d)
return d
def getInstanceByDom(self, dom):
"""Get a domain controller for a domain, creating if necessary.
dom domain
returns domain controller
"""
for inst in self.instances.values():
if inst.dom == dom:
return inst
@@ -21,8 +35,11 @@ class DomainControllerFactory(controller.ControllerFactory):
class DomainController(controller.Controller):
"""Generic controller for a domain.
Used for domain shutdown.
"""
"""Map shutdown reasons to the message type to use.
"""
reasons = {'poweroff' : 'shutdown_poweroff_t',
'reboot' : 'shutdown_reboot_t',
'suspend' : 'shutdown_suspend_t' }
@@ -34,6 +51,10 @@ class DomainController(controller.Controller):
print 'DomainController>', self, self.channel, self.idx
def shutdown(self, reason):
"""Shutdown a domain.
reason shutdown reason
"""
msgtype = self.reasons.get(reason)
if not msgtype:
raise ValueError('invalid reason:' + reason)
+38 -3
View File
@@ -148,6 +148,9 @@ netif_formats = {
msg_formats.update(netif_formats)
#============================================================================
# Domain shutdown message types.
#============================================================================
CMSG_SHUTDOWN = 6
CMSG_SHUTDOWN_POWEROFF = 0
@@ -176,8 +179,23 @@ msg_formats.update(shutdown_formats)
class Msg:
pass
_next_msgid = 0
def nextid():
global _next_msgid
return ++_next_msgid
def packMsg(ty, params):
if DEBUG: print '>packMsg', ty, params
"""Pack a message.
Any 'mac' parameter is passed in as an int[6] array and converted.
ty message type name
params message parameter dict
returns xu message
"""
msgid = nextid()
if DEBUG: print '>packMsg', msgid, ty, params
(major, minor) = msg_formats[ty]
args = {}
for (k, v) in params.items():
@@ -189,11 +207,19 @@ def packMsg(ty, params):
if DEBUG:
for (k, v) in args.items():
print 'packMsg>', k, v, type(v)
msgid = 0
msg = xu.message(major, minor, msgid, args)
return msg
def unpackMsg(ty, msg):
"""Unpack a message.
Any mac addresses in the message are converted to int[6] array
in the return dict.
ty message type
msg xu message
returns parameter dict
"""
args = msg.get_payload()
mac = [0, 0, 0, 0, 0, 0]
macs = []
@@ -208,10 +234,19 @@ def unpackMsg(ty, msg):
args['mac'] = mac
for k in macs:
del args[k]
if DEBUG: print '<unpackMsg', ty, args
if DEBUG:
msgid = msg.get_header()['id']
print '<unpackMsg', msgid, ty, args
return args
def msgTypeName(ty, subty):
"""Convert a message type, subtype pair (ints) to a message type name (string).
ty integer message type
subty integer message subtype
returns message type name (or None)
"""
for (name, info) in msg_formats.items():
if info[0] == ty and info[1] == subty:
return name
+94 -64
View File
@@ -1,6 +1,9 @@
# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
import random
from twisted.internet import defer
defer.Deferred.debug = 1
from xen.xend import sxp
from xen.xend import PrettyPrint
@@ -21,8 +24,8 @@ class NetifControllerFactory(controller.ControllerFactory):
self.majorTypes = [ CMSG_NETIF_BE ]
self.subTypes = {
CMSG_NETIF_BE_CREATE : self.recv_be_create,
CMSG_NETIF_BE_CONNECT: self.recv_be_connect,
#CMSG_NETIF_BE_CREATE : self.recv_be_create,
#CMSG_NETIF_BE_CONNECT: self.recv_be_connect,
CMSG_NETIF_BE_DRIVER_STATUS_CHANGED: self.recv_be_driver_status_changed,
}
self.attached = 1
@@ -30,8 +33,12 @@ class NetifControllerFactory(controller.ControllerFactory):
def createInstance(self, dom, recreate=0):
"""Create or find the network interface controller for a domain.
dom domain
recreate if true this is a recreate (xend restarted)
returns netif controller
"""
#print 'netif>createInstance> dom=', dom
netif = self.getInstanceByDom(dom)
if netif is None:
netif = NetifController(self, dom)
@@ -39,15 +46,31 @@ class NetifControllerFactory(controller.ControllerFactory):
return netif
def getDomainDevices(self, dom):
"""Get the network device controllers for a domain.
dom domain
returns netif controller
"""
netif = self.getInstanceByDom(dom)
return (netif and netif.getDevices()) or []
def getDomainDevice(self, dom, vif):
"""Get a virtual network interface device for a domain.
dom domain
vif virtual interface index
returns NetDev
"""
netif = self.getInstanceByDom(dom)
return (netif and netif.getDevice(vif)) or None
def setControlDomain(self, dom, recreate=0):
"""Set the 'back-end' device driver domain.
dom domain
recreate if true this is a recreate (xend restarted)
"""
if self.dom == dom: return
self.deregisterChannel()
@@ -55,19 +78,13 @@ class NetifControllerFactory(controller.ControllerFactory):
self.attached = 0
self.dom = dom
self.registerChannel()
#
#if xend.netif.be_port.remote_dom != 0:
# xend.netif.recovery = True
# xend.netif.be_port = xend.main.port_from_dom(dom)
#
def getControlDomain(self):
"""Get the domain id of the back-end control domain.
"""
return self.dom
def recv_be_create(self, msg, req):
self.callDeferred(0)
def recv_be_connect(self, msg, req):
def respond_be_connect(self, msg):
val = unpackMsg('netif_be_connect_t', msg)
dom = val['domid']
vif = val['netif_handle']
@@ -75,7 +92,7 @@ class NetifControllerFactory(controller.ControllerFactory):
if netif:
netif.send_interface_connected(vif)
else:
print "recv_be_connect> unknown vif=", vif
print "respond_be_connect> unknown vif=", vif
pass
def recv_be_driver_status_changed(self, msg, req):
@@ -88,23 +105,6 @@ class NetifControllerFactory(controller.ControllerFactory):
netif.reattach_devices()
self.attached = 1
## pl = msg.get_payload()
## status = pl['status']
## if status == NETIF_DRIVER_STATUS_UP:
## if xend.netif.recovery:
## print "New netif backend now UP, notifying guests:"
## for netif_key in interface.list.keys():
## netif = interface.list[netif_key]
## netif.create()
## print " Notifying %d" % netif.dom
## msg = xu.message(
## CMSG_NETIF_FE,
## CMSG_NETIF_FE_INTERFACE_STATUS_CHANGED, 0,
## { 'handle' : 0, 'status' : 1 })
## netif.ctrlif_tx_req(xend.main.port_from_dom(netif.dom),msg)
## print "Done notifying guests"
## recovery = False
class NetDev(controller.Dev):
"""Info record for a network device.
"""
@@ -130,9 +130,13 @@ class NetDev(controller.Dev):
return val
def get_vifname(self):
"""Get the virtual interface device name.
"""
return "vif%d.%d" % (self.controller.dom, self.vif)
def get_mac(self):
"""Get the MAC address as a string.
"""
return ':'.join(map(lambda x: "%x" % x, self.mac))
def vifctl_params(self):
@@ -141,23 +145,31 @@ class NetDev(controller.Dev):
'ipaddr': self.ipaddr }
def up(self, bridge=None, ipaddr=[]):
"""Bring the device up.
bridge ethernet bridge to connect to
ipaddr list of ipaddrs to filter using iptables
"""
self.bridge = bridge
self.ipaddr = ipaddr
Vifctl.up(self.get_vifname(), **self.vifctl_params())
def down(self):
"""Bring the device down.
"""
Vifctl.down(self.get_vifname(), **self.vifctl_params())
def destroy(self):
"""Destroy the device's resources and disconnect from the back-end
device controller.
"""
def cb_destroy(val):
self.controller.send_be_destroy(self.vif)
print 'NetDev>destroy>', 'vif=', self.vif
PrettyPrint.prettyprint(self.sxpr())
self.down()
d = self.controller.factory.addDeferred()
#d = self.controller.factory.addDeferred()
d = defer.Deferred()
d.addCallback(cb_destroy)
self.controller.send_be_disconnect(self.vif)
#self.controller.send_be_destroy(self.vif)
self.controller.send_be_disconnect(self.vif, response=d)
class NetifController(controller.Controller):
@@ -165,7 +177,6 @@ class NetifController(controller.Controller):
"""
def __init__(self, factory, dom):
#print 'NetifController> dom=', dom
controller.Controller.__init__(self, factory, dom)
self.devices = {}
@@ -178,21 +189,23 @@ class NetifController(controller.Controller):
self.recv_fe_interface_connect,
}
self.registerChannel()
#print 'NetifController<', 'dom=', self.dom, 'idx=', self.idx
def sxpr(self):
val = ['netif', ['dom', self.dom]]
return val
def randomMAC(self):
# VIFs get a random MAC address with a "special" vendor id.
#
# NB. The vendor is currently an "obsolete" one that used to belong
# to DEC (AA-00-00). Using it is probably a bit rude :-)
#
# NB2. The first bit of the first random octet is set to zero for
# all dynamic MAC addresses. This may allow us to manually specify
# MAC addresses for some VIFs with no fear of clashes.
"""Generate a random MAC address.
Uses OUI (Organizationally Unique Identifier) AA:00:00, an
unassigned one that used to belong to DEC. The OUI list is
available at 'standards.ieee.org'.
The remaining 3 fields are random, with the first bit of the first
random field set 0.
returns array of 6 ints
"""
mac = [ 0xaa, 0x00, 0x00,
random.randint(0x00, 0x7f),
random.randint(0x00, 0xff),
@@ -200,29 +213,46 @@ class NetifController(controller.Controller):
return mac
def lostChannel(self):
print 'NetifController>lostChannel>', 'dom=', self.dom
#self.destroyDevices()
"""Method called when the channel has been lost.
"""
controller.Controller.lostChannel(self)
def getDevices(self):
"""Get a list of the devices.
"""
return self.devices.values()
def getDevice(self, vif):
"""Get a device.
vif device index
returns device (or None)
"""
return self.devices.get(vif)
def addDevice(self, vif, vmac):
"""Add a network interface. If vmac is None a random MAC is
assigned. If specified, vmac must be a string of the form
XX:XX:XX:XX:XX where X is hex digit.
vif device index
vmac device MAC
returns device
"""
if vmac is None:
mac = self.randomMAC()
else:
mac = [ int(x, 16) for x in vmac.split(':') ]
if len(mac) != 6: raise ValueError("invalid mac")
#print "attach_device>", "vif=", vif, "mac=", mac
dev = NetDev(self, vif, mac)
self.devices[vif] = dev
return dev
def destroy(self):
print 'NetifController>destroy>', 'dom=', self.dom
"""Destroy the controller and all devices.
"""
self.destroyDevices()
def destroyDevices(self):
@@ -237,20 +267,19 @@ class NetifController(controller.Controller):
@param vmac mac address (string)
"""
self.addDevice(vif, vmac)
d = defer.Deferred()
if recreate:
d = defer.Deferred()
d.callback(self)
else:
d = self.factory.addDeferred()
self.send_be_create(vif)
self.send_be_create(vif, response=d)
return d
def reattach_devices(self):
"""Reattach all devices when the back-end control domain has changed.
"""
d = self.factory.addDeferred()
#d = self.factory.addDeferred()
self.send_be_create(vif)
self.attach_fe_devices(0)
self.attach_fe_devices()
def attach_fe_devices(self):
for dev in self.devices.values():
@@ -279,38 +308,39 @@ class NetifController(controller.Controller):
'evtchn' : dev.evtchn['port1'],
'tx_shmem_frame' : val['tx_shmem_frame'],
'rx_shmem_frame' : val['rx_shmem_frame'] })
self.factory.writeRequest(msg)
d = defer.Deferred()
d.addCallback(self.factory.respond_be_connect)
self.factory.writeRequest(msg, response=d)
def send_interface_connected(self, vif):
def send_interface_connected(self, vif, response=None):
dev = self.devices[vif]
msg = packMsg('netif_fe_interface_status_changed_t',
{ 'handle' : dev.vif,
'status' : NETIF_INTERFACE_STATUS_CONNECTED,
'evtchn' : dev.evtchn['port2'],
'mac' : dev.mac })
self.writeRequest(msg)
self.writeRequest(msg, response=response)
def send_be_create(self, vif):
def send_be_create(self, vif, response=None):
dev = self.devices[vif]
msg = packMsg('netif_be_create_t',
{ 'domid' : self.dom,
'netif_handle' : dev.vif,
'mac' : dev.mac })
self.factory.writeRequest(msg)
self.factory.writeRequest(msg, response=response)
def send_be_disconnect(self, vif):
def send_be_disconnect(self, vif, response=None):
dev = self.devices[vif]
msg = packMsg('netif_be_disconnect_t',
{ 'domid' : self.dom,
'netif_handle' : dev.vif })
self.factory.writeRequest(msg)
self.factory.writeRequest(msg, response=response)
def send_be_destroy(self, vif):
print 'NetifController>send_be_destroy>', 'dom=', self.dom, 'vif=', vif
def send_be_destroy(self, vif, response=None):
PrettyPrint.prettyprint(self.sxpr())
dev = self.devices[vif]
del self.devices[vif]
msg = packMsg('netif_be_destroy_t',
{ 'domid' : self.dom,
'netif_handle' : vif })
self.factory.writeRequest(msg)
self.factory.writeRequest(msg, response=response)
+73 -37
View File
@@ -1,4 +1,5 @@
# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
"""Domain creation.
"""
import string
@@ -12,15 +13,25 @@ from xen.util import console_client
from xen.xm.opts import *
gopts = Opts(use="""[options]
gopts = Opts(use="""[options] [vars]
Create a domain.
Domain creation parameters can be set by command-line switches, from
a python configuration script or an SXP config file. See documentation
for --defaults, --config. Configuration variables can be set using
VAR=VAL on the command line. For example vmid=3 sets vmid to 3.
""")
gopts.opt('help', short='h',
fn=set_true, default=0,
use="Print this help.")
gopts.opt('help_config',
fn=set_true, default=0,
use="Print help for configuration file.")
gopts.opt('quiet', short='q',
fn=set_true, default=0,
use="Quiet.")
@@ -31,58 +42,73 @@ gopts.opt('path', val='PATH',
gopts.opt('defaults', short='f', val='FILE',
fn=set_value, default='xmdefaults',
use="Use the given default script.")
use="""Use the given Python defaults script.
The defaults script is loaded after arguments have been processed.
Each command-line option sets a configuration variable named after
its long option name, and these variables are placed in the
environment of the script before it is loaded.
Variables for options that may be repeated have list values.
Other variables can be set using VAR=VAL on the command line.
After the script is loaded, option values that were not set on the
command line are replaced by the values set in the script.
""")
gopts.opt('config', short='F', val='FILE',
fn=set_value, default=None,
use='Domain configuration to use (SXP).')
use="""Domain configuration to use (SXP).
SXP is the underlying configuration format used by Xen.
SXP configs can be hand-written or generated from Python defaults
scripts, using the -n (dryrun) option to print the config.
""")
gopts.opt('load', short='L', val='FILE',
fn=set_value, default=None,
use='Domain saved state to load.')
gopts.opt('define', short='D', val='VAR=VAL',
fn=set_var, default=None,
use="""Set a variable before loading defaults, e.g. '-D vmid=3'
to set vmid. May be repeated to set more thanone variable.""")
gopts.opt('dryrun', short='n',
fn=set_true, default=0,
use="Dry run - print the config but don't create the domain.")
gopts.opt('name', short='N', val='NAME',
fn=set_value, default=None,
use="Domain name.")
use="""Dry run - print the config but don't create the domain.
The defaults file is loaded and the SXP configuration is created and printed.
""")
gopts.opt('console_autoconnect', short='c',
fn=set_true, default=0,
use="Connect to console after domain is created.")
gopts.opt('kernel', short='k', val='FILE',
gopts.var('name', val='NAME',
fn=set_value, default=None,
use="Domain name.")
gopts.var('kernel', val='FILE',
fn=set_value, default=None,
use="Path to kernel image.")
gopts.opt('ramdisk', short='r', val='FILE',
gopts.var('ramdisk', val='FILE',
fn=set_value, default='',
use="Path to ramdisk.")
gopts.opt('builder', short='b', val='FUNCTION',
gopts.var('builder', val='FUNCTION',
fn=set_value, default='linux',
use="Function to use to build the domain.")
gopts.opt('memory', short='m', val='MEMORY',
gopts.var('memory', val='MEMORY',
fn=set_value, default=128,
use="Domain memory in MB.")
gopts.opt('blkif',
fn=set_true, default=0,
gopts.var('autorestart', val='no|yes',
fn=set_bool, default=0,
use="Whether to restart the domain on exit.")
gopts.var('blkif', val='no|yes',
fn=set_bool, default=0,
use="Make the domain a block device backend.")
gopts.opt('netif',
fn=set_true, default=0,
gopts.var('netif', val='no|yes',
fn=set_bool, default=0,
use="Make the domain a network interface backend.")
gopts.opt('disk', short='d', val='phy:DEV,VDEV,MODE',
gopts.var('disk', val='phy:DEV,VDEV,MODE',
fn=append_value, default=[],
use="""Add a disk device to a domain. The physical device is DEV,
which is exported to the domain as VDEV. The disk is read-only if MODE
@@ -90,18 +116,18 @@ gopts.opt('disk', short='d', val='phy:DEV,VDEV,MODE',
The option may be repeated to add more than one disk.
""")
gopts.opt('pci', val='BUS,DEV,FUNC',
gopts.var('pci', val='BUS,DEV,FUNC',
fn=append_value, default=[],
use="""Add a PCI device to a domain, using given params (in hex).
For example '-pci c0,02,1a'.
The option may be repeated to add more than one pci device.
""")
gopts.opt('ipaddr', short='i', val="IPADDR",
gopts.var('ipaddr', val="IPADDR",
fn=append_value, default=[],
use="Add an IP address to the domain.")
gopts.opt('vif', val="mac=MAC,bridge=BRIDGE",
gopts.var('vif', val="mac=MAC,bridge=BRIDGE",
fn=append_value, default=[],
use="""Add a network interface with the given MAC address and bridge.
If mac is not specified a random MAC address is used.
@@ -110,7 +136,7 @@ gopts.opt('vif', val="mac=MAC,bridge=BRIDGE",
Specifying vifs will increase the number of interfaces as needed.
""")
gopts.opt('nics', val="NUM",
gopts.var('nics', val="NUM",
fn=set_int, default=1,
use="""Set the number of network interfaces.
Use the vif option to define interface parameters, otherwise
@@ -118,44 +144,44 @@ gopts.opt('nics', val="NUM",
number of interfaces as needed.
""")
gopts.opt('root', short='R', val='DEVICE',
gopts.var('root', val='DEVICE',
fn=set_value, default='',
use="""Set the root= parameter on the kernel command line.
Use a device, e.g. /dev/sda1, or /dev/nfs for NFS root.""")
gopts.opt('extra', short='E', val="ARGS",
gopts.var('extra', val="ARGS",
fn=set_value, default='',
use="Set extra arguments to append to the kernel command line.")
gopts.opt('ip', short='I', val='IPADDR',
gopts.var('ip', val='IPADDR',
fn=set_value, default='',
use="Set the kernel IP interface address.")
gopts.opt('gateway', val="IPADDR",
gopts.var('gateway', val="IPADDR",
fn=set_value, default='',
use="Set the kernel IP gateway.")
gopts.opt('netmask', val="MASK",
gopts.var('netmask', val="MASK",
fn=set_value, default = '',
use="Set the kernel IP netmask.")
gopts.opt('hostname', val="NAME",
gopts.var('hostname', val="NAME",
fn=set_value, default='',
use="Set the kernel IP hostname.")
gopts.opt('interface', val="INTF",
gopts.var('interface', val="INTF",
fn=set_value, default="eth0",
use="Set the kernel IP interface name.")
gopts.opt('dhcp', val="off|dhcp",
gopts.var('dhcp', val="off|dhcp",
fn=set_value, default='off',
use="Set the kernel dhcp option.")
gopts.opt('nfs_server', val="IPADDR",
gopts.var('nfs_server', val="IPADDR",
fn=set_value, default=None,
use="Set the address of the NFS server for NFS root.")
gopts.opt('nfs_root', val="PATH",
gopts.var('nfs_root', val="PATH",
fn=set_value, default=None,
use="Set the path of the root NFS directory.")
@@ -244,6 +270,8 @@ def make_config(opts):
config.append(['backend', ['blkif']])
if opts.netif:
config.append(['backend', ['netif']])
if opts.autorestart:
config.append(['autorestart'])
configure_image(config, opts)
config_devs = []
@@ -282,7 +310,7 @@ def preprocess_vifs(opts):
d = {}
a = vif.split(',')
for b in a:
(k, v) = b.strip().split('=')
(k, v) = b.strip().split('=', 1)
k = k.strip()
v = v.strip()
if k not in ['mac', 'bridge']:
@@ -352,7 +380,15 @@ def main(argv):
args = opts.parse(argv)
if opts.vals.help:
opts.usage()
if opts.vals.help or opts.vals.help_config:
opts.load_defaults(help=1)
if opts.vals.help or opts.vals.help_config:
return
# Process remaining args as config variables.
for arg in args:
if '=' in arg:
(var, val) = arg.strip().split('=', 1)
gopts.setvar(var.strip(), val.strip())
if opts.vals.config:
pass
else:
+82
View File
@@ -0,0 +1,82 @@
# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
"""Variable definition and help support for Python defaults files.
"""
import sys
class Vars:
"""A set of configuration variables.
"""
def __init__(self, name, help, env):
"""Create a variable set.
name name of the defaults file
help help flag
env local environment
"""
self.name = name
self.help = help
self.env = env
self.vars = []
def var(self, name, use=None, check=None):
"""Define a configuration variable.
If provided, the check function will be called as check(var, val)
where var is the variable name and val is its value (string).
It should return a new value for the variable, or raise ValueError if
the value is not acceptable.
name variable name
use variable usage string
check variable check function
"""
self.vars.append(Var(name, use, check))
def check(self):
"""Execute the variable checks or print help, depending on the value
of the help flag passed to the constructor.
"""
if self.help:
self.doHelp()
else:
for v in self.vars:
v.doCheck(self.env)
def doHelp(self, out=sys.stderr):
"""Print help for the variables.
"""
if self.vars:
print >>out, "\nConfiguration variables for %s:\n" % self.name
for v in self.vars:
v.doHelp(out)
print >>out
class Var:
"""A single variable.
"""
def __init__(self, name, use, check):
"""Create a variable.
name variable name
use variable use string
check variable value check function
"""
self.name = name
self.use = use or ''
self.check = check
def doCheck(self, env):
"""Execute the check and set the variable to the new value.
"""
if not self.check: return
env[self.name] = self.check(self.name, env.get(self.name))
def doHelp(self, out):
"""Print help for the variable.
"""
print >>out, "%-12s" % self.name, self.use
+25
View File
@@ -5,10 +5,12 @@ import os
import os.path
import sys
from getopt import getopt
import socket
from xen.xend import PrettyPrint
from xen.xend import sxp
from xen.xend.XendClient import server
from xen.xend.XendClient import main as xend_client_main
from xen.xm import create, shutdown
class Prog:
@@ -65,6 +67,13 @@ class Xm:
sys.exit(1)
def main(self, args):
try:
self.main_call(args)
except socket.error, ex:
print >>sys.stderr, ex
self.err("Error connecting to xend, is xend running?")
def main_call(self, args):
"""Main entry point. Dispatches to the progs.
"""
self.name = args[0]
@@ -478,5 +487,21 @@ class ProgConsole(Prog):
xm.prog(ProgConsole)
class ProgCall(Prog):
name = "call"
info = "Call xend api functions."
def help (self, args):
print "call fn argss..."
print """
Call a xend HTTP API function. The leading 'xend_' on the function
can be omitted. See xen.xend.XendClient for the API functions.
"""
def main(self, args):
xend_client_main(args)
xm.prog(ProgCall)
def main(args):
xm.main(args)
+92 -13
View File
@@ -126,6 +126,42 @@ class Opt:
"""
return self.specified_opt
class OptVar(Opt):
"""An individual option variable.
"""
def __init__(self, opts, name,
val=None, fn=None, use=None, default=None):
"""Create an option.
opts parent options object
name name of the field it controls
val string used to print option args in help.
If val is not specified the option has no arg.
fn function to call when the option is specified.
use usage (help) string
default default value if not specified on command-line
"""
if val is None:
val = name.upper()
Opt.__init__(self, opts, name, val=val, fn=fn, use=use, default=default)
self.optkeys = []
self.optkeys.append(self.long)
def short_opt(self):
return None
def long_opt(self):
return None
def show(self):
print '%s=%s' %(self.optkeys[0], self.val)
print
if self.use:
print '\t',
print self.use
if self.val:
print '\tDefault', self.default or 'None'
class OptVals:
"""Class to hold option values.
"""
@@ -134,6 +170,13 @@ class OptVals:
class Opts:
"""Container for options.
"""
imports = ["import sys",
"import os",
"import os.path",
"from xen.util.ip import *",
]
def __init__(self, use=None):
"""Options constructor.
@@ -168,6 +211,12 @@ class Opts:
self.options_map[name] = x
return x
def var(self, name, **args):
x = OptVar(self, name, **args)
self.options.append(x)
self.options_map[name] = x
return x
def setvar(self, var, val):
"""Set a default script variable.
"""
@@ -232,7 +281,18 @@ class Opts:
else:
print >>sys.stderr, "Error: Unknown option:", k
self.usage()
return args
xargs = []
for arg in args:
isvar = 0
if '=' in arg:
(k, v) = arg.split('=', 1)
for opt in self.options:
if opt.specify(k, v):
isvar = 1
break
if not isvar:
xargs.append(arg)
return xargs
def short_opts(self):
"""Get short options specifier for getopt.
@@ -257,9 +317,10 @@ class Opts:
def usage(self):
print 'Usage: ', self.argv[0], self.use or 'OPTIONS'
for opt in self.options:
print
opt.show()
def load_defaults(self):
def load_defaults(self, help=0):
"""Load a defaults script. Assumes these options set:
'path' search path
'default' script name
@@ -270,12 +331,12 @@ class Opts:
else:
p = self.vals.defaults
if os.path.exists(p):
self.load(p)
self.load(p, help)
break
else:
self.err("Cannot open defaults file %s" % self.vals.defaults)
def load(self, defaults, help=0):
def load(self, defaults, help):
"""Load a defaults file. Local variables in the file
are used to set options with the same names.
Variables are not used to set options that are already specified.
@@ -287,15 +348,22 @@ class Opts:
globals = {}
locals = {}
locals.update(self.vars)
cmd = '\n'.join(["import sys",
"import os",
"import os.path",
"import xen.util.ip",
"xm_file = '%s'" % defaults,
"xm_help = %d" % help ])
cmd = '\n'.join(self.imports +
[ "from xen.xm.help import Vars",
"xm_file = '%s'" % defaults,
"xm_help = %d" % help,
"xm_vars = Vars(xm_file, xm_help, locals())"
])
exec cmd in globals, locals
execfile(defaults, globals, locals)
if help: return
try:
execfile(defaults, globals, locals)
except:
if not help: raise
if help:
print 'The following imports are done automatically:'
for x in self.imports:
print x
return
# Extract the values set by the script and set the corresponding
# options, if not set on the command line.
vtypes = [ types.StringType,
@@ -316,6 +384,17 @@ def set_false(opt, k, v):
"""Set an option false."""
opt.set(0)
def set_bool(opt, k, v):
"""Set a boolean option.
"""
if v in ['yes']:
opt.set(1)
elif v in ['no']:
opt.set(0)
else:
opt.opts.err('Invalid value:' +v)
def set_value(opt, k, v):
"""Set an option to a valoue."""
opt.set(v)
@@ -335,6 +414,6 @@ def append_value(opt, k, v):
def set_var(opt, k, v):
"""Set a default script variable.
"""
(var, val) = v.strip().split('=')
(var, val) = v.strip().split('=', 1)
opt.opts.setvar(var.strip(), val.strip())
+29 -6
View File
@@ -1,4 +1,5 @@
# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
"""Domain shutdown.
"""
import string
@@ -10,7 +11,8 @@ from xen.xm.opts import *
gopts = Opts(use="""[options] [DOM]
Shutdown one or more domains gracefully.""")
Shutdown one or more domains gracefully.
""")
gopts.opt('help', short='h',
fn=set_true, default=0,
@@ -24,18 +26,22 @@ gopts.opt('wait', short='w',
fn=set_true, default=0,
use='Wait for shutdown to complete.')
gopts.opt('norestart', short='n',
gopts.opt('halt', short='H',
fn=set_true, default=0,
use='Prevent domain restart.')
use='Shutdown without reboot.')
def shutdown(opts, doms, wait):
gopts.opt('reboot', short='R',
fn=set_true, default=0,
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)
for d in doms:
server.xend_domain_shutdown(d)
server.xend_domain_shutdown(d, mode)
if wait:
while doms:
alive = domains()
@@ -49,6 +55,21 @@ def shutdown(opts, doms, wait):
time.sleep(1)
opts.info("All domains terminated")
def shutdown_mode(opts):
mode = 'poweroff'
if opts.vals.wait:
mode = 'halt'
if opts.vals.reboot:
opts.err("Can't specify wait and reboot")
else:
if opts.vals.halt and opts.vals.reboot:
opts.err("Can't specify halt and reboot")
if opts.vals.halt:
mode = 'halt'
elif opts.vals.reboot:
mode = 'reboot'
return mode
def main_all(opts, args):
shutdown(opts, None, opts.vals.wait)
@@ -59,7 +80,9 @@ def main_dom(opts, args):
domid = int(dom)
except:
opts.err('Invalid domain: ' + dom)
shutdown(opts, [ domid ], opts.vals.wait)
mode = shutdown_mode(opts)
shutdown(opts, [ domid ], mode, opts.vals.wait)
def main(argv):
opts = gopts
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.