aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
Diffstat (limited to 'tools')
-rw-r--r--tools/xenmgr/lib/EventTypes.py2
-rw-r--r--tools/xenmgr/lib/XendClient.py4
-rw-r--r--tools/xenmgr/lib/XendDomain.py91
-rw-r--r--tools/xenmgr/lib/XendDomainInfo.py789
-rw-r--r--tools/xenmgr/lib/server/SrvConsoleServer.py30
-rw-r--r--tools/xenmgr/lib/server/SrvDomain.py6
-rwxr-xr-xtools/xenmgr/lib/server/blkif.py118
-rwxr-xr-xtools/xenmgr/lib/server/controller.py29
-rw-r--r--tools/xenmgr/lib/server/messages.py3
-rwxr-xr-xtools/xenmgr/lib/server/netif.py59
-rw-r--r--tools/xenmgr/lib/xm/create.py180
-rw-r--r--tools/xenmgr/lib/xm/main.py424
-rw-r--r--tools/xenmgr/lib/xm/opts.py213
-rw-r--r--tools/xenmgr/lib/xm/shutdown.py3
14 files changed, 1257 insertions, 694 deletions
diff --git a/tools/xenmgr/lib/EventTypes.py b/tools/xenmgr/lib/EventTypes.py
index c8d5e62aa7..6350baa5dd 100644
--- a/tools/xenmgr/lib/EventTypes.py
+++ b/tools/xenmgr/lib/EventTypes.py
@@ -8,7 +8,7 @@
## xend.domain.unpause: dom
## xend.domain.pause: dom
## xend.domain.shutdown: dom
-## xend.domain.halt: dom
+## xend.domain.destroy: dom
## xend.domain.migrate.begin: dom, to
## Begin tells: src host, src domain uri, dst host. Dst id known?
diff --git a/tools/xenmgr/lib/XendClient.py b/tools/xenmgr/lib/XendClient.py
index fb4a5b4421..664835a155 100644
--- a/tools/xenmgr/lib/XendClient.py
+++ b/tools/xenmgr/lib/XendClient.py
@@ -199,9 +199,9 @@ class Xend:
return xend_call(self.domainurl(id),
{'op' : 'shutdown'})
- def xend_domain_halt(self, id):
+ def xend_domain_destroy(self, id):
return xend_call(self.domainurl(id),
- {'op' : 'halt'})
+ {'op' : 'destroy'})
def xend_domain_save(self, id, filename):
return xend_call(self.domainurl(id),
diff --git a/tools/xenmgr/lib/XendDomain.py b/tools/xenmgr/lib/XendDomain.py
index f236a43d80..106af33b61 100644
--- a/tools/xenmgr/lib/XendDomain.py
+++ b/tools/xenmgr/lib/XendDomain.py
@@ -6,6 +6,8 @@
"""
import sys
+from twisted.internet import defer
+
import Xc; xc = Xc.new()
import xenctl.ip
@@ -59,21 +61,26 @@ class XendDomain:
for d in domlist:
domid = str(d['dom'])
doms[domid] = d
+ dlist = []
for config in self.domain_db.values():
domid = str(sxp.child_value(config, 'id'))
print "dom=", domid, "config=", config
if domid in doms:
print "dom=", domid, "new"
- self._new_domain(config)
+ deferred = self._new_domain(config, doms[domid])
+ dlist.append(deferred)
else:
print "dom=", domid, "del"
self._delete_domain(domid)
- print "doms:"
- for d in self.domain.values(): print 'dom', d
- print "refresh..."
- self.refresh()
- print "doms:"
- for d in self.domain.values(): print 'dom', d
+ deferred = defer.DeferredList(dlist, fireOnOneErrback=1)
+ def cbok(val):
+ print "doms:"
+ for d in self.domain.values(): print 'dom', d
+ print "refresh..."
+ self.refresh()
+ print "doms:"
+ for d in self.domain.values(): print 'dom', d
+ deferred.addCallback(cbok)
def sync(self):
"""Sync domain db to disk.
@@ -90,31 +97,36 @@ class XendDomain:
def close(self):
pass
- def _new_domain(self, info):
+ def _new_domain(self, savedinfo, info):
"""Create a domain entry from saved info.
"""
- console = None
- kernel = None
- id = sxp.child_value(info, 'id')
- dom = int(id)
- name = sxp.child_value(info, 'name')
- memory = int(sxp.child_value(info, 'memory'))
- consoleinfo = sxp.child(info, 'console')
- if consoleinfo:
- consoleid = sxp.child_value(consoleinfo, 'id')
- console = self.xconsole.console_get(consoleid)
- if dom and console is None:
- # Try to connect a console.
- console = self.xconsole.console_create(dom)
- config = sxp.child(info, 'config')
- if config:
- image = sxp.child(info, 'image')
- if image:
- image = sxp.child0(image)
- kernel = sxp.child_value(image, 'kernel')
- dominfo = XendDomainInfo.XendDomainInfo(
- config, dom, name, memory, kernel, console)
- self.domain[id] = dominfo
+## console = None
+## kernel = None
+## id = sxp.child_value(info, 'id')
+## dom = int(id)
+## name = sxp.child_value(info, 'name')
+## memory = int(sxp.child_value(info, 'memory'))
+## consoleinfo = sxp.child(info, 'console')
+## if consoleinfo:
+## consoleid = sxp.child_value(consoleinfo, 'id')
+## console = self.xconsole.console_get(consoleid)
+## if dom and console is None:
+## # Try to connect a console.
+## console = self.xconsole.console_create(dom)
+## config = sxp.child(info, 'config')
+## if config:
+## image = sxp.child(info, 'image')
+## if image:
+## image = sxp.child0(image)
+## kernel = sxp.child_value(image, 'kernel')
+## dominfo = XendDomainInfo.XendDomainInfo(
+## config, dom, name, memory, kernel, console)
+ config = sxp.child_value(savedinfo, 'config')
+ deferred = XendDomainInfo.vm_recreate(config, info)
+ def fn(dominfo):
+ self.domain[dominfo.id] = dominfo
+ deferred.addCallback(fn)
+ return deferred
def _add_domain(self, id, info, notify=1):
self.domain[id] = info
@@ -143,10 +155,13 @@ class XendDomain:
doms[id] = d
if id not in self.domain:
config = None
- image = None
- newinfo = XendDomainInfo.XendDomainInfo(
- config, d['dom'], d['name'], d['mem_kb']/1024, image=image, info=d)
- self._add_domain(newinfo.id, newinfo)
+ #image = None
+ #newinfo = XendDomainInfo.XendDomainInfo(
+ # config, d['dom'], d['name'], d['mem_kb']/1024, image=image, info=d)
+ deferred = XendDomainInfo.vm_recreate(config, d)
+ def fn(dominfo):
+ self._add_domain(dominfo.id, dominfo)
+ deferred.addCallback(fn)
# Remove entries for domains that no longer exist.
for d in self.domain.values():
dominfo = doms.get(d.id)
@@ -217,13 +232,13 @@ class XendDomain:
self.refresh()
return val
- def domain_halt(self, id):
+ def domain_destroy(self, id):
"""Terminate domain immediately.
"""
dom = int(id)
if dom <= 0:
return 0
- eserver.inject('xend.domain.halt', id)
+ eserver.inject('xend.domain.destroy', id)
val = xc.domain_destroy(dom=dom)
self.refresh()
return val
@@ -235,14 +250,14 @@ class XendDomain:
pass
def domain_save(self, id, dst, progress=0):
- """Save domain state to file, halt domain.
+ """Save domain state to file, destroy domain.
"""
dom = int(id)
self.domain_pause(id)
eserver.inject('xend.domain.save', id)
rc = xc.linux_save(dom=dom, state_file=dst, progress=progress)
if rc == 0:
- self.domain_halt(id)
+ self.domain_destroy(id)
return rc
def domain_restore(self, src, config, progress=0):
diff --git a/tools/xenmgr/lib/XendDomainInfo.py b/tools/xenmgr/lib/XendDomainInfo.py
index 3828fcf2ec..0dfd1a71ee 100644
--- a/tools/xenmgr/lib/XendDomainInfo.py
+++ b/tools/xenmgr/lib/XendDomainInfo.py
@@ -60,160 +60,6 @@ class VmError(ValueError):
return self.value
-class XendDomainInfo:
- """Virtual machine object."""
-
- def __init__(self, config, dom, name, memory, image=None, console=None, info=None):
- """Construct a virtual machine object.
-
- config configuration
- dom domain id
- name name
- memory memory size (in MB)
- image image object
- """
- #todo: add info: runtime, state, ...
- self.config = config
- self.id = str(dom)
- self.dom = dom
- self.name = name
- self.memory = memory
- self.image = image
- self.console = console
- self.devices = {}
- self.configs = []
- self.info = info
- self.ipaddrs = []
- self.block_controller = 0
- self.net_controller = 0
-
- #todo: state: running, suspended
- self.state = 'running'
- #todo: set to migrate info if migrating
- self.migrate = None
-
- def update(self, info):
- """Update with info from xc.domain_getinfo().
- """
- self.info = info
-
- def __str__(self):
- s = "domain"
- s += " id=" + self.id
- s += " name=" + self.name
- s += " memory=" + str(self.memory)
- if self.console:
- s += " console=" + self.console.id
- if self.image:
- s += " image=" + self.image
- s += ""
- return s
-
- __repr__ = __str__
-
- def sxpr(self):
- sxpr = ['domain',
- ['id', self.id],
- ['name', self.name],
- ['memory', self.memory] ]
- if self.info:
- run = (self.info['running'] and 'R') or 'r'
- block = (self.info['blocked'] and 'B') or 'b'
- stop = (self.info['paused'] and 'P') or 'p'
- susp = (self.info['shutdown'] and 'S') or 's'
- crash = (self.info['crashed'] and 'C') or 'c'
- state = run + block + stop + susp + crash
- sxpr.append(['state', state])
- if self.info['shutdown']:
- reasons = ["poweroff", "reboot", "suspend"]
- reason = reasons[self.info['shutdown_reason']]
- sxpr.append(['shutdown_reason', reason])
- sxpr.append(['cpu', self.info['cpu']])
- sxpr.append(['cpu_time', self.info['cpu_time']/1e9])
- if self.console:
- sxpr.append(self.console.sxpr())
- if self.config:
- sxpr.append(['config', self.config])
- return sxpr
-
- def add_device(self, type, dev):
- """Add a device to a virtual machine.
-
- dev device to add
- """
- dl = self.devices.get(type, [])
- dl.append(dev)
- self.devices[type] = dl
-
- def get_devices(self, type):
- val = self.devices.get(type, [])
- print 'get_devices', type; sxp.show(val); print
- return val
-
- def get_device_by_id(self, type, id):
- """Get the device with the given id.
-
- id device id
-
- returns device or None
- """
- return sxp.child_with_id(self.get_devices(type), id)
-
- def get_device_by_index(self, type, idx):
- """Get the device with the given index.
-
- idx device index
-
- returns device or None
- """
- dl = self.get_devices(type)
- if 0 <= idx < len(dl):
- return dl[idx]
- else:
- return None
-
- def add_config(self, val):
- """Add configuration data to a virtual machine.
-
- val data to add
- """
- self.configs.append(val)
-
- def destroy(self):
- if self.dom <= 0:
- return 0
- return xc.domain_destroy(dom=self.dom)
-
- def died(self):
- print 'died>', self.dom
- self.release_vifs()
-
- def release_vifs(self):
- print 'release_vifs>', self.dom
- vifs = self.get_devices('vif')
- for v in vifs:
- vif = sxp.child_value(v, 'vif')
- bridge = sxp.child_value(v, 'bridge')
- XendBridge.vif_bridge_rem(self.dom, vif, bridge)
-
- def show(self):
- """Print virtual machine info.
- """
- print "[VM dom=%d name=%s memory=%d" % (self.dom, self.name, self.memory)
- print "image:"
- sxp.show(self.image)
- print
- for dl in self.devices:
- for dev in dl:
- print "device:"
- sxp.show(dev)
- print
- for val in self.configs:
- print "config:"
- sxp.show(val)
- print
- print "]"
-
def blkdev_name_to_number(name):
"""Take the given textual block-device name (e.g., '/dev/sda1',
'hda') and return the device number used by the OS. """
@@ -264,7 +110,7 @@ def lookup_raw_partn(partition):
return None
-def lookup_disk_uname( uname ):
+def lookup_disk_uname(uname):
"""Lookup a list of segments for a physical device.
uname [string]: name of the device in the format \'phy:dev\' for a physical device
returns [list of dicts]: list of extents that make up the named device
@@ -277,7 +123,7 @@ def lookup_disk_uname( uname ):
segments = None
return segments
-def make_disk(dom, uname, dev, mode):
+def make_disk(dom, uname, dev, mode, recreate=0):
"""Create a virtual disk device for a domain.
@returns Deferred
@@ -289,21 +135,21 @@ def make_disk(dom, uname, dev, mode):
raise VmError("vbd: Multi-segment vdisk: uname=%s" % uname)
segment = segments[0]
vdev = blkdev_name_to_number(dev)
- ctrl = xend.blkif_create(dom)
+ ctrl = xend.blkif_create(dom, recreate=recreate)
def fn(ctrl):
- return xend.blkif_dev_create(dom, vdev, mode, segment)
+ return xend.blkif_dev_create(dom, vdev, mode, segment, recreate=recreate)
ctrl.addCallback(fn)
return ctrl
-def make_vif(dom, vif, vmac):
+def make_vif(dom, vif, vmac, recreate=0):
"""Create a virtual network device for a domain.
@returns Deferred
"""
- xend.netif_create(dom)
- d = xend.netif_dev_create(dom, vif, vmac)
+ xend.netif_create(dom, recreate=recreate)
+ d = xend.netif_dev_create(dom, vif, vmac, recreate=recreate)
return d
def vif_up(iplist):
@@ -338,49 +184,6 @@ def vif_up(iplist):
finally:
if not nlb: set_ip_nonlocal_bind(0)
-def xen_domain_create(config, ostype, name, memory, kernel, ramdisk, cmdline, vifs_n):
- """Create a domain. Builds the image but does not configure it.
-
- config configuration
- ostype OS type
- name domain name
- memory domain memory (MB)
- kernel kernel image
- ramdisk kernel ramdisk
- cmdline kernel commandline
- vifs_n number of network interfaces
- returns vm
- """
- flags = 0
- 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)
-
- cpu = int(sxp.child_value(config, 'cpu', '-1'))
- print 'xen_domain_create> create ', memory, name, cpu
- dom = xc.domain_create(mem_kb= memory * 1024, name= name, cpu= cpu)
- if dom <= 0:
- raise VmError('Creating domain failed: name=%s memory=%d kernel=%s'
- % (name, memory, kernel))
- console = xendConsole.console_create(dom)
- buildfn = getattr(xc, '%s_build' % ostype)
-
- print 'xen_domain_create> build ', ostype, dom, kernel, cmdline, ramdisk
- if len(cmdline) >= 256:
- print 'Warning: kernel cmdline too long'
- err = buildfn(dom = dom,
- image = kernel,
- control_evtchn = console.port2,
- cmdline = cmdline,
- ramdisk = ramdisk,
- flags = flags)
- if err != 0:
- raise VmError('Building domain failed: type=%s dom=%d err=%d'
- % (ostype, dom, err))
- vm = XendDomainInfo(config, dom, name, memory, kernel, console)
- return vm
-
config_handlers = {}
def add_config_handler(name, h):
@@ -450,34 +253,27 @@ def vm_create(config):
returns Deferred
raises VmError for invalid configuration
"""
- # todo - add support for scheduling params?
print 'vm_create>'
- vm = None
- try:
- name = sxp.child_value(config, 'name')
- memory = int(sxp.child_value(config, 'memory', '128'))
- image = sxp.child_value(config, 'image')
-
- image_name = sxp.name(image)
- image_handler = get_image_handler(image_name)
- if image_handler is None:
- raise VmError('unknown image type: ' + image_name)
- vm = image_handler(config, name, memory, image)
- deferred = vm_configure(vm, config)
- except StandardError, ex:
- # Catch errors, cleanup and re-raise.
- if vm:
- vm.destroy()
- raise
- def cbok(x):
- print 'vm_create> cbok', x
- return x
- deferred.addCallback(cbok)
- print 'vm_create<'
- return deferred
+ vm = XendDomainInfo()
+ return vm.construct(config)
+
+def vm_recreate(config, info):
+ """Create the VM object for an existing domain.
+ """
+ vm = XendDomainInfo()
+ vm.recreate = 1
+ vm.setdom(info['dom'])
+ vm.name = info['name']
+ vm.memory = info['mem_kb']/1024
+ if config:
+ d = vm.construct(config)
+ else:
+ d = defer.Deferred()
+ d.callback(vm)
+ return d
def vm_restore(src, config, progress=0):
- """Restore a VM.
+ """Restore a VM from a disk image.
src saved state to restore
config configuration
@@ -485,11 +281,14 @@ def vm_restore(src, config, progress=0):
returns deferred
raises VmError for invalid configuration
"""
+ vm = XendDomainInfo()
+ vm.config = config
ostype = "linux" #todo set from config
restorefn = getattr(xc, "%s_restore" % ostype)
dom = restorefn(state_file=src, progress=progress)
- if dom < 0: return dom
- deferred = dom_configure(dom, config)
+ if dom < 0:
+ raise VMError('restore failed')
+ deferred = vm.dom_configure(dom)
def vifs_cb(val, vm):
vif_up(vm.ipaddrs)
deferred.addCallback(vifs_cb, vm)
@@ -501,115 +300,25 @@ def dom_get(dom):
return domlist[0]
return None
-def dom_configure(dom, config):
- """Configure a domain.
-
- dom domain id
- config configuration
- returns deferred
- """
- d = dom_get(dom)
- if not d:
- raise VMError("Domain not found: %d" % dom)
- try:
- name = d['name']
- memory = d['memory']/1024
- image = None
- vm = VM(config, dom, name, memory, image)
- deferred = vm_configure(vm, config)
- except StandardError, ex:
- if vm:
- vm.destroy()
- raise
- return deferred
def append_deferred(dlist, v):
if isinstance(v, defer.Deferred):
dlist.append(v)
-def vm_create_devices(vm, config):
- """Create the devices for a vm.
-
- vm virtual machine
- config configuration
-
- returns Deferred
- raises VmError for invalid devices
- """
- print '>vm_create_devices'
- dlist = []
- devices = sxp.children(config, 'device')
- index = {}
- for d in devices:
- dev = sxp.child0(d)
- if dev is None:
- raise VmError('invalid device')
- dev_name = sxp.name(dev)
- dev_index = index.get(dev_name, 0)
- dev_handler = get_device_handler(dev_name)
- if dev_handler is None:
- raise VmError('unknown device type: ' + dev_name)
- v = dev_handler(vm, dev, dev_index)
- append_deferred(dlist, v)
- index[dev_name] = dev_index + 1
- deferred = defer.DeferredList(dlist, fireOnOneErrback=1)
- print '<vm_create_devices'
- return deferred
-
-def config_controllers(vm, config):
- for c in sxp.children(config, 'controller'):
- name = sxp.name(c)
- if name == 'block':
- vm.block_controller = 1
- xend.blkif_set_control_domain(vm.dom)
- elif name == 'net':
- vm.net_controller = 1
- xend.netif_set_control_domain(vm.dom)
- else:
- raise VmError('invalid controller type:' + str(name))
-
-def vm_configure(vm, config):
- """Configure a vm.
-
- vm virtual machine
- config configuration
-
- returns Deferred - calls callback with vm
- """
- config_controllers(vm, config)
- if vm.block_controller:
- d = defer.Deferred()
- d.callback(1)
- else:
- d = xend.blkif_create(vm.dom)
- d.addCallback(_vm_configure1, vm, config)
- return d
-
-def _vm_configure1(val, vm, config):
- d = vm_create_devices(vm, config)
+def _vm_configure1(val, vm):
+ d = vm.create_devices()
print '_vm_configure1> made devices...'
def cbok(x):
print '_vm_configure1> cbok', x
return x
d.addCallback(cbok)
- d.addCallback(_vm_configure2, vm, config)
+ d.addCallback(_vm_configure2, vm)
print '_vm_configure1<'
return d
-def _vm_configure2(val, vm, config):
+def _vm_configure2(val, vm):
print '>callback _vm_configure2...'
- dlist = []
- index = {}
- for field in sxp.children(config):
- field_name = sxp.name(field)
- field_index = index.get(field_name, 0)
- field_handler = get_config_handler(field_name)
- # Ignore unknown fields. Warn?
- if field_handler:
- v = field_handler(vm, config, field, field_index)
- append_deferred(dlist, v)
- index[field_name] = field_index + 1
- d = defer.DeferredList(dlist, fireOnOneErrback=1)
+ d = vm.configure_fields()
def cbok(results):
print '_vm_configure2> cbok', results
return vm
@@ -622,22 +331,369 @@ def _vm_configure2(val, vm, config):
print '<_vm_configure2'
return d
-def config_devices(config, name):
- """Get a list of the 'device' nodes of a given type from a config.
+class XendDomainInfo:
+ """Virtual machine object."""
- config configuration
- name device type
- return list of device configs
- """
- devices = []
- for d in sxp.children(config, 'device'):
- dev = sxp.child0(d)
- if dev is None: continue
- if name == sxp.name(dev):
- devices.append(dev)
- return devices
+ def __init__(self):
+ self.recreate = 0
+ self.config = None
+ self.id = None
+ self.dom = None
+ self.name = None
+ self.memory = None
+ self.image = None
+ self.ramdisk = None
+ self.cmdline = None
+ self.console = None
+ self.devices = {}
+ self.configs = []
+ self.info = None
+ self.ipaddrs = []
+ self.blkif_backend = 0
+ self.netif_backend = 0
+ #todo: state: running, suspended
+ self.state = 'running'
+ #todo: set to migrate info if migrating
+ self.migrate = None
+
+ def setdom(self, dom):
+ self.dom = int(dom)
+ self.id = str(dom)
-def vm_image_linux(config, name, memory, image):
+ def update(self, info):
+ """Update with info from xc.domain_getinfo().
+ """
+ self.info = info
+
+ def __str__(self):
+ s = "domain"
+ s += " id=" + self.id
+ s += " name=" + self.name
+ s += " memory=" + str(self.memory)
+ if self.console:
+ s += " console=" + self.console.id
+ if self.image:
+ s += " image=" + self.image
+ s += ""
+ return s
+
+ __repr__ = __str__
+
+ def sxpr(self):
+ sxpr = ['domain',
+ ['id', self.id],
+ ['name', self.name],
+ ['memory', self.memory] ]
+ if self.info:
+ run = (self.info['running'] and 'r') or '-'
+ block = (self.info['blocked'] and 'b') or '-'
+ stop = (self.info['paused'] and 'p') or '-'
+ susp = (self.info['shutdown'] and 's') or '-'
+ crash = (self.info['crashed'] and 'c') or '-'
+ state = run + block + stop + susp + crash
+ sxpr.append(['state', state])
+ if self.info['shutdown']:
+ reasons = ["poweroff", "reboot", "suspend"]
+ reason = reasons[self.info['shutdown_reason']]
+ sxpr.append(['shutdown_reason', reason])
+ sxpr.append(['cpu', self.info['cpu']])
+ sxpr.append(['cpu_time', self.info['cpu_time']/1e9])
+ if self.console:
+ sxpr.append(self.console.sxpr())
+ if self.config:
+ sxpr.append(['config', self.config])
+ return sxpr
+
+ def construct(self, config):
+ # todo - add support for scheduling params?
+ self.config = config
+ try:
+ self.name = sxp.child_value(config, 'name')
+ self.memory = int(sxp.child_value(config, 'memory', '128'))
+ self.configure_backends()
+ image = sxp.child_value(config, 'image')
+ image_name = sxp.name(image)
+ image_handler = get_image_handler(image_name)
+ if image_handler is None:
+ raise VmError('unknown image type: ' + image_name)
+ image_handler(self, image)
+ deferred = self.configure()
+ 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
+
+ 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
+ """
+ devices = []
+ for d in sxp.children(self.config, 'device'):
+ dev = sxp.child0(d)
+ if dev is None: continue
+ if name == sxp.name(dev):
+ devices.append(dev)
+ return devices
+
+ def add_device(self, type, dev):
+ """Add a device to a virtual machine.
+
+ dev device to add
+ """
+ dl = self.devices.get(type, [])
+ dl.append(dev)
+ self.devices[type] = dl
+
+ def get_devices(self, type):
+ 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
+ """
+ dl = self.get_devices(type)
+ for d in dl:
+ if d.getprop('id') == id:
+ return d
+ return None
+
+ def get_device_by_index(self, type, idx):
+ """Get the device with the given index.
+
+ idx device index
+
+ returns device or None
+ """
+ dl = self.get_devices(type)
+ if 0 <= idx < len(dl):
+ return dl[idx]
+ else:
+ return None
+
+ def add_config(self, val):
+ """Add configuration data to a virtual machine.
+
+ val data to add
+ """
+ self.configs.append(val)
+
+ def destroy(self):
+ if self.dom <= 0:
+ return 0
+ return xc.domain_destroy(dom=self.dom)
+
+ def died(self):
+ print 'died>', self.dom
+ self.release_devices()
+
+ def release_devices(self):
+ print 'release_devices>', self.dom
+ self.release_vifs()
+ self.release_vbds()
+ self.devices = {}
+
+ def release_vifs(self):
+ print 'release_vifs>', self.dom
+ if self.dom is None: return
+ ctrl = xend.netif_get(self.dom)
+ if ctrl:
+ ctrl.destroy()
+
+ def release_vbds(self):
+ print 'release_vbds>', self.dom
+ if self.dom is None: return
+ ctrl = xend.blkif_get(self.dom)
+ if ctrl:
+ ctrl.destroy()
+
+ def show(self):
+ """Print virtual machine info.
+ """
+ print "[VM dom=%d name=%s memory=%d" % (self.dom, self.name, self.memory)
+ print "image:"
+ sxp.show(self.image)
+ print
+ for dl in self.devices:
+ for dev in dl:
+ print "device:"
+ sxp.show(dev)
+ print
+ for val in self.configs:
+ print "config:"
+ sxp.show(val)
+ print
+ print "]"
+
+ def init_domain(self):
+ """Initialize the domain memory.
+ """
+ if self.recreate: return
+ memory = self.memory
+ name = self.name
+ cpu = int(sxp.child_value(self.config, 'cpu', '-1'))
+ print 'init_domain>', memory, name, cpu
+ dom = xc.domain_create(mem_kb= memory * 1024, name= name, cpu= cpu)
+ if dom <= 0:
+ raise VmError('Creating domain failed: name=%s memory=%d'
+ % (name, memory))
+ self.setdom(dom)
+
+ def build_domain(self, ostype, kernel, ramdisk, cmdline, vifs_n):
+ """Build the domain boot image.
+ """
+ if self.recreate: return
+ if len(cmdline) >= 256:
+ print 'Warning: kernel cmdline too long'
+ dom = self.dom
+ buildfn = getattr(xc, '%s_build' % ostype)
+ print 'build_domain>', ostype, dom, kernel, cmdline, ramdisk
+ flags = 0
+ if self.netif_backend: flags |= SIF_NET_BE_DOMAIN
+ if self.blkif_backend: flags |= SIF_BLK_BE_DOMAIN
+ err = buildfn(dom = dom,
+ image = kernel,
+ control_evtchn = self.console.port2,
+ cmdline = cmdline,
+ ramdisk = ramdisk,
+ flags = flags)
+ if err != 0:
+ raise VmError('Building domain failed: type=%s dom=%d err=%d'
+ % (ostype, dom, err))
+
+ 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
+ """
+ print 'create_domain>', ostype, kernel
+ if not self.recreate:
+ 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)
+ print 'create-domain> init_domain...'
+ self.init_domain()
+ print 'create_domain>', 'dom=', self.dom
+ self.console = xendConsole.console_create(self.dom)
+ self.build_domain(ostype, kernel, ramdisk, cmdline, vifs_n)
+ self.image = kernel
+ self.ramdisk = ramdisk
+ self.cmdline = cmdline
+
+ def create_devices(self):
+ """Create the devices for a vm.
+
+ returns Deferred
+ raises VmError for invalid devices
+ """
+ print '>create_devices'
+ dlist = []
+ devices = sxp.children(self.config, 'device')
+ index = {}
+ for d in devices:
+ dev = sxp.child0(d)
+ if dev is None:
+ raise VmError('invalid device')
+ dev_name = sxp.name(dev)
+ dev_index = index.get(dev_name, 0)
+ dev_handler = get_device_handler(dev_name)
+ if dev_handler is None:
+ raise VmError('unknown device type: ' + dev_name)
+ v = dev_handler(self, dev, dev_index)
+ append_deferred(dlist, v)
+ index[dev_name] = dev_index + 1
+ deferred = defer.DeferredList(dlist, fireOnOneErrback=1)
+ print '<create_devices'
+ return deferred
+
+ def configure_backends(self):
+ """Set configuration flags if the vm is a backend for netif of blkif.
+ """
+ for c in sxp.children(self.config, 'backend'):
+ name = sxp.name(c)
+ if name == 'blkif':
+ self.blkif_backend = 1
+ elif name == 'netif':
+ self.netif_backend = 1
+ else:
+ raise VmError('invalid backend type:' + str(name))
+
+ def create_backends(self):
+ """Setup the netif and blkif backends.
+ """
+ if self.blkif_backend:
+ xend.blkif_set_control_domain(self.dom, recreate=self.recreate)
+ if self.netif_backend:
+ xend.netif_set_control_domain(self.dom, recreate=self.recreate)
+
+ def configure(self):
+ """Configure a vm.
+
+ vm virtual machine
+ config configuration
+
+ returns Deferred - calls callback with vm
+ """
+ if self.blkif_backend:
+ d = defer.Deferred()
+ d.callback(1)
+ 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.
+
+ dom domain id
+ returns deferred
+ """
+ d = dom_get(dom)
+ if not d:
+ raise VMError("Domain not found: %d" % dom)
+ try:
+ self.setdom(dom)
+ self.name = d['name']
+ self.memory = d['memory']/1024
+ deferred = self.configure()
+ except StandardError, ex:
+ self.destroy()
+ raise
+ return deferred
+
+ def configure_fields(self):
+ dlist = []
+ index = {}
+ for field in sxp.children(self.config):
+ field_name = sxp.name(field)
+ field_index = index.get(field_name, 0)
+ field_handler = get_config_handler(field_name)
+ # Ignore unknown fields. Warn?
+ if field_handler:
+ v = field_handler(self, self.config, field, field_index)
+ append_deferred(dlist, v)
+ index[field_name] = field_index + 1
+ d = defer.DeferredList(dlist, fireOnOneErrback=1)
+ return d
+
+
+def vm_image_linux(vm, image):
"""Create a VM for a linux image.
name vm name
@@ -658,12 +714,11 @@ def vm_image_linux(config, name, memory, image):
if args:
cmdline += " " + args
ramdisk = sxp.child_value(image, "ramdisk", '')
- vifs = config_devices(config, "vif")
- vm = xen_domain_create(config, "linux", name, memory, kernel,
- ramdisk, cmdline, len(vifs))
+ vifs = vm.config_devices("vif")
+ vm.create_domain("linux", kernel, ramdisk, cmdline, len(vifs))
return vm
-def vm_image_netbsd(config, name, memory, image):
+def vm_image_netbsd(vm, image):
"""Create a VM for a bsd image.
name vm name
@@ -685,9 +740,8 @@ def vm_image_netbsd(config, name, memory, image):
if args:
cmdline += " " + args
ramdisk = sxp.child_value(image, "ramdisk")
- vifs = config_devices(config, "vif")
- vm = xen_domain_create(config, "netbsd", name, memory, kernel,
- ramdisk, cmdline, len(vifs))
+ vifs = vm.config_devices("vif")
+ vm.create_domain("netbsd", kernel, ramdisk, cmdline, len(vifs))
return vm
@@ -698,18 +752,18 @@ def vm_dev_vif(vm, val, index):
val vif config
index vif index
"""
- if vm.net_controller:
- raise VmError('vif: vif in control domain')
+ if vm.netif_backend:
+ raise VmError('vif: vif in netif backend domain')
vif = index #todo
vmac = sxp.child_value(val, "mac")
- defer = make_vif(vm.dom, vif, vmac)
+ defer = make_vif(vm.dom, vif, vmac, vm.recreate)
def fn(id):
+ dev = xend.netif_dev(vm.dom, vif)
+ devid = sxp.attribute(val, 'id')
+ if devid:
+ dev.setprop('id', devid)
bridge = sxp.child_value(val, "bridge")
- bridge = XendBridge.vif_bridge_add(vm.dom, vif, bridge)
- dev = ['vif', ['vif', vif], ['bridge', bridge] ]
- netdev = xend.netif_dev(vm.dom, vif)
- if netdev and netdev.mac:
- dev += [ 'mac', netdev.mac ]
+ dev.bridge_add(bridge)
vm.add_device('vif', dev)
print 'vm_dev_vif> created', dev
return id
@@ -723,8 +777,9 @@ def vm_dev_vbd(vm, val, index):
val vbd config
index vbd index
"""
- if vm.block_controller:
- raise VmError('vbd: vbd in control domain')
+ 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')
@@ -732,9 +787,10 @@ def vm_dev_vbd(vm, val, index):
if not dev:
raise VMError('vbd: Missing dev')
mode = sxp.child_value(val, 'mode', 'r')
- defer = make_disk(vm.dom, uname, dev, mode)
+ defer = make_disk(vm.dom, uname, dev, mode, vm.recreate)
def fn(vbd):
- vm.add_device('vbd', val)
+ dev = xend.blkif_dev(vm.dom, vdev)
+ vm.add_device('vbd', dev)
return vbd
defer.addCallback(fn)
return defer
@@ -765,7 +821,8 @@ def vm_dev_pci(vm, val, index):
func = parse_pci(func)
except:
raise VMError('pci: invalid parameter')
- rc = xc.physdev_pci_access_modify(dom=vm.dom, bus=bus, dev=dev, func=func, enable=1)
+ 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' %
@@ -833,13 +890,11 @@ def vm_field_vnet(vm, config, val, index):
if id is None:
raise VmError('vnet: missing vif id')
dev = vm.get_device_by_id('vif', id)
- if not sxp.elementp(dev, 'vif'):
- raise VmError('vnet: invalid vif id %s' % 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]])
+ #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]])
# Register image handlers for linux and bsd.
add_image_handler('linux', vm_image_linux)
diff --git a/tools/xenmgr/lib/server/SrvConsoleServer.py b/tools/xenmgr/lib/server/SrvConsoleServer.py
index 7179a0d1d4..94b7c8e6c8 100644
--- a/tools/xenmgr/lib/server/SrvConsoleServer.py
+++ b/tools/xenmgr/lib/server/SrvConsoleServer.py
@@ -584,28 +584,31 @@ class Daemon:
reactor.diconnectAll()
sys.exit(0)
- def blkif_set_control_domain(self, dom):
+ def blkif_set_control_domain(self, dom, recreate=0):
"""Set the block device backend control domain.
"""
- return self.blkifCF.setControlDomain(dom)
+ return self.blkifCF.setControlDomain(dom, recreate=recreate)
def blkif_get_control_domain(self, dom):
"""Get the block device backend control domain.
"""
return self.blkifCF.getControlDomain()
- def blkif_create(self, dom):
+ def blkif_create(self, dom, recreate=0):
"""Create a block device interface controller.
Returns Deferred
"""
- d = self.blkifCF.createInstance(dom)
+ d = self.blkifCF.createInstance(dom, recreate=recreate)
return d
+ def blkif_get(self, dom):
+ return self.blkifCF.getInstanceByDom(dom)
+
def blkif_dev(self, dom, vdev):
return self.blkifCF.getDomainDevice(dom, vdev)
- def blkif_dev_create(self, dom, vdev, mode, segment):
+ def blkif_dev_create(self, dom, vdev, mode, segment, recreate=0):
"""Create a block device.
Returns Deferred
@@ -614,26 +617,29 @@ class Daemon:
if not ctrl:
raise ValueError('No blkif controller: %d' % dom)
print 'blkif_dev_create>', dom, vdev, mode, segment
- d = ctrl.attach_device(vdev, mode, segment)
+ d = ctrl.attachDevice(vdev, mode, segment, recreate=recreate)
return d
- def netif_set_control_domain(self, dom):
+ def netif_set_control_domain(self, dom, recreate=0):
"""Set the network interface backend control domain.
"""
- return self.netifCF.setControlDomain(dom)
+ return self.netifCF.setControlDomain(dom, recreate=recreate)
def netif_get_control_domain(self, dom):
"""Get the network interface backend control domain.
"""
return self.netifCF.getControlDomain()
- def netif_create(self, dom):
+ def netif_create(self, dom, recreate=0):
"""Create a network interface controller.
"""
- return self.netifCF.createInstance(dom)
+ return self.netifCF.createInstance(dom, recreate=recreate)
+
+ def netif_get(self, dom):
+ return self.netifCF.getInstanceByDom(dom)
- def netif_dev_create(self, dom, vif, vmac):
+ def netif_dev_create(self, dom, vif, vmac, recreate=0):
"""Create a network device.
todo
@@ -641,7 +647,7 @@ class Daemon:
ctrl = self.netifCF.getInstanceByDom(dom)
if not ctrl:
raise ValueError('No netif controller: %d' % dom)
- d = ctrl.attach_device(vif, vmac)
+ d = ctrl.attachDevice(vif, vmac, recreate=recreate)
return d
def netif_dev(self, dom, vif):
diff --git a/tools/xenmgr/lib/server/SrvDomain.py b/tools/xenmgr/lib/server/SrvDomain.py
index 5034869e63..d8287e05ea 100644
--- a/tools/xenmgr/lib/server/SrvDomain.py
+++ b/tools/xenmgr/lib/server/SrvDomain.py
@@ -32,8 +32,8 @@ class SrvDomain(SrvDir):
req.setHeader("Location", "%s/.." % req.prePathURL())
return val
- def op_halt(self, op, req):
- val = self.xd.domain_halt(self.dom.id)
+ def op_destroy(self, op, req):
+ val = self.xd.domain_destroy(self.dom.id)
req.setHeader("Location", "%s/.." % req.prePathURL())
return val
@@ -196,7 +196,7 @@ class SrvDomain(SrvDir):
req.write('<input type="submit" name="op" value="unpause">')
req.write('<input type="submit" name="op" value="pause">')
req.write('<input type="submit" name="op" value="shutdown">')
- req.write('<input type="submit" name="op" value="halt">')
+ req.write('<input type="submit" name="op" value="destroy">')
req.write('<br><input type="submit" name="op" value="migrate">')
req.write('To: <input type="text" name="destination">')
req.write('</form>')
diff --git a/tools/xenmgr/lib/server/blkif.py b/tools/xenmgr/lib/server/blkif.py
index 8da827baa9..92706316b1 100755
--- a/tools/xenmgr/lib/server/blkif.py
+++ b/tools/xenmgr/lib/server/blkif.py
@@ -1,3 +1,5 @@
+from twisted.internet import defer
+
import channel
import controller
from messages import *
@@ -22,7 +24,7 @@ class BlkifControllerFactory(controller.ControllerFactory):
self.attached = 1
self.registerChannel()
- def createInstance(self, dom):
+ def createInstance(self, dom, recreate=0):
d = self.addDeferred()
blkif = self.getInstanceByDom(dom)
if blkif:
@@ -30,7 +32,10 @@ class BlkifControllerFactory(controller.ControllerFactory):
else:
blkif = BlkifController(self, dom)
self.addInstance(blkif)
- blkif.send_be_create()
+ if recreate:
+ self.callDeferred(blkif)
+ else:
+ blkif.send_be_create()
return d
def getDomainDevices(self, dom):
@@ -41,10 +46,11 @@ class BlkifControllerFactory(controller.ControllerFactory):
blkif = self.getInstanceByDom(dom)
return (blkif and blkif.getDevice(vdev)) or None
- def setControlDomain(self, dom):
+ def setControlDomain(self, dom, recreate=0):
if self.dom == dom: return
self.deregisterChannel()
- self.attached = 0
+ if not recreate:
+ self.attached = 0
self.dom = dom
self.registerChannel()
#
@@ -55,6 +61,28 @@ class BlkifControllerFactory(controller.ControllerFactory):
def getControlDomain(self):
return self.dom
+ def reattachDevice(self, dom, vdev):
+ blkif = self.getInstanceByDom(dom)
+ if blkif:
+ blkif.reattachDevice(vdev)
+ self.attached = self.devicesAttached()
+ if self.attached:
+ self.reattached()
+
+ def devicesAttached(self):
+ """Check if all devices are attached.
+ """
+ attached = 1
+ for blkif in self.getInstances():
+ if not blkif.attached:
+ attached = 0
+ break
+ return attached
+
+ def reattached(self):
+ for blkif in self.getInstances():
+ blkif.reattached()
+
def recv_be_create(self, msg, req):
#print 'recv_be_create>'
val = unpackMsg('blkif_be_create_t', msg)
@@ -86,29 +114,7 @@ class BlkifControllerFactory(controller.ControllerFactory):
if self.attached:
self.callDeferred(0)
else:
- self.reattach_device(val['domid'], val['vdevice'])
-
- def reattach_device(self, dom, vdev):
- blkif = self.getInstanceByDom(dom)
- if blkif:
- blkif.reattach_device(vdev)
- self.attached = self.devices_attached()
- if self.attached:
- self.reattached()
-
- def devices_attached(self):
- """Check if all devices are attached.
- """
- attached = 1
- for blkif in self.getInstances():
- if not blkif.attached:
- attached = 0
- break
- return attached
-
- def reattached(self):
- for blkif in self.getInstances():
- blkif.reattached()
+ self.reattachDevice(val['domid'], val['vdevice'])
def recv_be_driver_status_changed(self, msg, req):
val = unpackMsg('blkif_be_driver_status_changed_t', msg)
@@ -117,11 +123,12 @@ class BlkifControllerFactory(controller.ControllerFactory):
for blkif in self.getInstances():
blkif.detach()
-class BlkDev:
+class BlkDev(controller.Dev):
"""Info record for a block device.
"""
- def __init__(self, vdev, mode, segment):
+ def __init__(self, ctrl, vdev, mode, segment):
+ controller.Dev.__init__(self, ctrl)
self.vdev = vdev
self.mode = mode
self.device = segment['device']
@@ -131,6 +138,14 @@ class BlkDev:
def readonly(self):
return 'w' not in self.mode
+
+ def sxpr(self):
+ print 'BlkDev>sxpr>', vars(self)
+ val = ['blkif', ['vdev', self.vdev], ['mode', self.mode] ]
+ return val
+
+ def destroy(self):
+ self.controller.send_be_vbd_destroy(self.vdev)
class BlkifController(controller.Controller):
"""Block device interface controller. Handles all block devices
@@ -154,21 +169,43 @@ class BlkifController(controller.Controller):
self.registerChannel()
#print 'BlkifController<', 'dom=', self.dom, 'idx=', self.idx
+ def lostChannel(self):
+ print 'BlkifController>lostChannel>', 'dom=', self.dom
+ #self.destroyDevices()
+ controller.Controller.lostChannel(self)
+
def getDevices(self):
return self.devices.values()
def getDevice(self, vdev):
return self.devices.get(vdev)
- def attach_device(self, vdev, mode, segment):
+ def addDevice(self, vdev, mode, segment):
+ if vdev in self.devices: return None
+ dev = BlkDev(self, vdev, mode, segment)
+ self.devices[vdev] = dev
+ return dev
+
+ def attachDevice(self, vdev, mode, segment, recreate=0):
"""Attach a device to the specified interface.
"""
#print 'BlkifController>attach_device>', self.dom, vdev, mode, segment
- if vdev in self.devices: return -1
- dev = BlkDev(vdev, mode, segment)
- self.devices[vdev] = dev
- self.send_be_vbd_create(vdev)
- return self.factory.addDeferred()
+ dev = self.addDevice(vdev, mode, segment)
+ if not dev: return -1
+ if recreate:
+ d = defer.Deferred()
+ d.callback(self)
+ else:
+ self.send_be_vbd_create(vdev)
+ d = self.factory.addDeferred()
+ return d
+
+ def destroy(self):
+ self.destroyDevices()
+
+ def destroyDevices(self):
+ for dev in self.getDevices():
+ dev.destroy()
def detach(self):
"""Detach all devices, when the back-end control domain has changed.
@@ -178,7 +215,7 @@ class BlkifController(controller.Controller):
dev.attached = 0
self.send_be_vbd_create(vdev)
- def reattach_device(self, vdev):
+ def reattachDevice(self, vdev):
"""Reattach a device, when the back-end control domain has changed.
"""
dev = self.devices[vdev]
@@ -254,4 +291,13 @@ class BlkifController(controller.Controller):
'extent.sector_start' : dev.start_sector,
'extent.sector_length' : dev.nr_sectors })
self.factory.writeRequest(msg)
+
+ def send_be_vbd_destroy(self, vdev):
+ dev = self.devices[vdev]
+ msg = packMsg('blkif_be_vbd_destroy_t',
+ { 'domid' : self.dom,
+ 'blkif_handle' : 0,
+ 'vdevice' : dev.vdev })
+ del self.devices[vdev]
+ self.factory.writeRequest(msg)
diff --git a/tools/xenmgr/lib/server/controller.py b/tools/xenmgr/lib/server/controller.py
index 791e987511..cb543fa57c 100755
--- a/tools/xenmgr/lib/server/controller.py
+++ b/tools/xenmgr/lib/server/controller.py
@@ -95,7 +95,7 @@ class ControllerFactory(CtrlMsgRcvr):
if instance.idx in self.instances:
del self.instances[instance.idx]
- def createInstance(self, dom):
+ def createInstance(self, dom, recreate=0):
raise NotImplementedError()
def instanceClosed(self, instance):
@@ -136,3 +136,30 @@ class Controller(CtrlMsgRcvr):
def lostChannel(self):
self.factory.instanceClosed(self)
+
+class Dev:
+
+ def __init__(self, controller):
+ self.controller = controller
+ self.props = {}
+
+ def setprop(self, k, v):
+ self.props[k] = v
+
+ def getprop(self, k, v=None):
+ return self.props.get(k, v)
+
+ def hasprop(self, k):
+ return k in self.props
+
+ def delprop(self, k):
+ if k in self.props:
+ del self.props[k]
+
+ #def __repr__(self):
+ # return str(self.sxpr())
+
+ def sxpr(self):
+ raise NotImplementedError()
+
+
diff --git a/tools/xenmgr/lib/server/messages.py b/tools/xenmgr/lib/server/messages.py
index 78bc24526f..0313670279 100644
--- a/tools/xenmgr/lib/server/messages.py
+++ b/tools/xenmgr/lib/server/messages.py
@@ -76,6 +76,9 @@ blkif_formats = {
'blkif_be_vbd_grow_t':
(CMSG_BLKIF_BE, CMSG_BLKIF_BE_VBD_GROW),
+ 'blkif_be_vbd_destroy_t':
+ (CMSG_BLKIF_BE, CMSG_BLKIF_BE_VBD_DESTROY),
+
'blkif_fe_interface_status_changed_t':
(CMSG_BLKIF_FE, CMSG_BLKIF_FE_INTERFACE_STATUS_CHANGED),
diff --git a/tools/xenmgr/lib/server/netif.py b/tools/xenmgr/lib/server/netif.py
index f3da86ba82..d2a6a53860 100755
--- a/tools/xenmgr/lib/server/netif.py
+++ b/tools/xenmgr/lib/server/netif.py
@@ -1,5 +1,9 @@
import random
+from twisted.internet import defer
+
+from xenmgr import XendBridge
+
import channel
import controller
from messages import *
@@ -22,7 +26,7 @@ class NetifControllerFactory(controller.ControllerFactory):
self.attached = 1
self.registerChannel()
- def createInstance(self, dom):
+ def createInstance(self, dom, recreate=0):
"""Create or find the network interface controller for a domain.
"""
#print 'netif>createInstance> dom=', dom
@@ -40,12 +44,13 @@ class NetifControllerFactory(controller.ControllerFactory):
netif = self.getInstanceByDom(dom)
return (netif and netif.getDevice(vif)) or None
- def setControlDomain(self, dom):
+ def setControlDomain(self, dom, recreate=0):
"""Set the 'back-end' device driver domain.
"""
if self.dom == dom: return
self.deregisterChannel()
- self.attached = 0
+ if not recreate:
+ self.attached = 0
self.dom = dom
self.registerChannel()
#
@@ -98,20 +103,38 @@ class NetifControllerFactory(controller.ControllerFactory):
## print "Done notifying guests"
## recovery = False
-class NetDev:
+class NetDev(controller.Dev):
"""Info record for a network device.
"""
- def __init__(self, vif, mac):
+ def __init__(self, ctrl, vif, mac):
+ controller.Dev.__init__(self, ctrl)
self.vif = vif
self.mac = mac
self.evtchn = None
+ self.bridge = None
def sxpr(self):
vif = str(self.vif)
mac = ':'.join(map(lambda x: "%x" % x, self.mac))
- return ['netif', ['vif', vif], ['mac', mac]]
-
+ val = ['netif', ['vif', vif], ['mac', mac]]
+ if self.bridge:
+ val += ['bridge', self.bridge]
+ return val
+
+ def bridge_add(self, bridge):
+ self.bridge = XendBridge.vif_bridge_add(self.controller.dom, self.vif, bridge)
+
+ def bridge_rem(self):
+ if not self.bridge: return
+ XendBridge.vif_bridge_rem(self.controller.dom, self.vif, self.bridge)
+ self.bridge = None
+
+ def destroy(self):
+ self.bridge_rem()
+ self.controller.send_be_destroy(self.vif)
+
+
class NetifController(controller.Controller):
"""Network interface controller. Handles all network devices for a domain.
"""
@@ -150,8 +173,7 @@ class NetifController(controller.Controller):
def lostChannel(self):
print 'NetifController>lostChannel>', 'dom=', self.dom
- #for vif in self.devices:
- # self.send_be_destroy(vif)
+ #self.destroyDevices()
controller.Controller.lostChannel(self)
def getDevices(self):
@@ -167,11 +189,18 @@ class NetifController(controller.Controller):
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(vif, mac)
+ dev = NetDev(self, vif, mac)
self.devices[vif] = dev
return dev
- def attach_device(self, vif, vmac):
+ def destroy(self):
+ self.destroyDevices()
+
+ def destroyDevices(self):
+ for dev in self.getDevices():
+ dev.destroy()
+
+ def attachDevice(self, vif, vmac, recreate=0):
"""Attach a network device.
If vmac is None a random mac address is assigned.
@@ -179,8 +208,12 @@ class NetifController(controller.Controller):
@param vmac mac address (string)
"""
self.addDevice(vif, vmac)
- d = self.factory.addDeferred()
- self.send_be_create(vif)
+ if recreate:
+ d = defer.Deferred()
+ d.callback(self)
+ else:
+ d = self.factory.addDeferred()
+ self.send_be_create(vif)
return d
def reattach_devices(self):
diff --git a/tools/xenmgr/lib/xm/create.py b/tools/xenmgr/lib/xm/create.py
index 29b4c7b6dc..e3ccad20b7 100644
--- a/tools/xenmgr/lib/xm/create.py
+++ b/tools/xenmgr/lib/xm/create.py
@@ -1,3 +1,6 @@
+# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
+"""Domain creation.
+"""
import string
import sys
@@ -13,7 +16,7 @@ Create a domain.
""")
gopts.opt('help', short='h',
- fn=set_value, default=0,
+ fn=set_true, default=0,
use="Print this help.")
gopts.opt('quiet', short='q',
@@ -36,21 +39,19 @@ gopts.opt('load', short='L', val='FILE',
fn=set_value, default=None,
use='Domain saved state to load.')
-def set_var(opt, k, v):
- opt.set(v)
- for d in string.split(v, ';' ):
- (k, v) = string.split(d, '=')
- opt.opts.setvar(k, v)
-
gopts.opt('define', short='D', val='VAR=VAL',
fn=set_var, default=None,
- use="""Set variables before loading defaults, e.g. '-D vmid=3;ip=1.2.3.4'
- to set vmid and ip.""")
+ 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.")
+
gopts.opt('console', short='c',
fn=set_true, default=0,
use="Connect to console after domain is created.")
@@ -71,34 +72,48 @@ gopts.opt('memory', short='m', val='MEMORY',
fn=set_value, default=128,
use="Domain memory in MB.")
+gopts.opt('blkif',
+ fn=set_true, default=0,
+ use="Make the domain a block device backend.")
+
+gopts.opt('netif',
+ fn=set_true, default=0,
+ use="Make the domain a network interface backend.")
+
gopts.opt('disk', short='d', 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 is r,
- read-write if mode is 'w'.""")
+ is exported to the domain as VDEV. The disk is read-only if MODE
+ is 'r', read-write if MODE is 'w'.
+ The option may be repeated to add more than one disk.
+ """)
gopts.opt('pci', val='BUS,DEV,FUNC',
fn=append_value, default=[],
- use="""Add a PCI device to a domain, using given params (in hex).""")
+ 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",
fn=append_value, default=[],
use="Add an IP address to the domain.")
-gopts.opt('mac', short='M', val="MAC",
+gopts.opt('vif', val="mac=MAC,bridge=BRIDGE",
fn=append_value, default=[],
- use="""Add a network interface with the given mac address to the domain.
- More than one interface may be specified. Interfaces with unspecified MAC addresses
- are allocated a random address.""")
+ use="""Add a network interface with the given MAC address and bridge.
+ If mac is not specified a random MAC address is used.
+ If bridge is not specified the default bridge is used.
+ This option may be repeated to add more than one vif.
+ Specifying vifs will increase the number of interfaces as needed.
+ """)
-gopts.opt('nics', val="N",
+gopts.opt('nics', val="NUM",
fn=set_int, default=1,
- use="Set the number of network interfaces.")
-
-gopts.opt('vnet', val='VNET',
- fn=append_value, default=[],
- use="""Define the vnets for the network interfaces.
- More than one vnet may be given, they are used in order.
+ use="""Set the number of network interfaces.
+ Use the vif option to define interface parameters, otherwise
+ defaults are used. Specifying vifs will increase the
+ number of interfaces as needed.
""")
gopts.opt('root', short='R', val='DEVICE',
@@ -116,15 +131,15 @@ gopts.opt('ip', short='I', val='IPADDR',
gopts.opt('gateway', val="IPADDR",
fn=set_value, default='',
- use="Set kernel IP gateway.")
+ use="Set the kernel IP gateway.")
gopts.opt('netmask', val="MASK",
fn=set_value, default = '',
- use="Set kernel IP netmask.")
+ use="Set the kernel IP netmask.")
gopts.opt('hostname', val="NAME",
fn=set_value, default='',
- use="Set kernel IP hostname.")
+ use="Set the kernel IP hostname.")
gopts.opt('interface', val="INTF",
fn=set_value, default="eth0",
@@ -132,7 +147,7 @@ gopts.opt('interface', val="INTF",
gopts.opt('dhcp', val="off|dhcp",
fn=set_value, default='off',
- use="Set kernel dhcp option.")
+ use="Set the kernel dhcp option.")
gopts.opt('nfs_server', val="IPADDR",
fn=set_value, default=None,
@@ -143,19 +158,16 @@ gopts.opt('nfs_root', val="PATH",
use="Set the path of the root NFS directory.")
def strip(pre, s):
+ """Strip prefix 'pre' if present.
+ """
if s.startswith(pre):
return s[len(pre):]
else:
return s
-def make_config(opts):
-
- config = ['config',
- ['name', opts.name ],
- ['memory', opts.memory ] ]
- if opts.cpu:
- config.append(['cpu', opts.cpu])
-
+def configure_image(config, opts):
+ """Create the image config.
+ """
config_image = [ opts.builder ]
config_image.append([ 'kernel', os.path.abspath(opts.kernel) ])
if opts.ramdisk:
@@ -169,8 +181,10 @@ def make_config(opts):
if opts.extra:
config_image.append(['args', opts.extra])
config.append(['image', config_image ])
-
- config_devs = []
+
+def configure_disks(config_devs, opts):
+ """Create the config for disks (virtual block devices).
+ """
for (uname, dev, mode) in opts.disk:
config_vbd = ['vbd',
['uname', uname],
@@ -178,18 +192,34 @@ def make_config(opts):
['mode', mode ] ]
config_devs.append(['device', config_vbd])
+def configure_pci(config_devs, opts):
+ """Create the config for pci devices.
+ """
for (bus, dev, func) in opts.pci:
config_pci = ['pci', ['bus', bus], ['dev', dev], ['func', func]]
config_devs.append(['device', config_pci])
- for idx in range(0, opts.nics):
- config_vif = ['vif', ['@', ['id', 'vif%d' % idx]]]
- if idx < len(opts.mac):
- config_vif.append(['mac', opts.mac[idx]])
+def configure_vifs(config_devs, opts):
+ """Create the config for virtual network interfaces.
+ """
+ vifs = opts.vif
+ vifs_n = max(opts.nics, len(vifs))
+
+ for idx in range(0, vifs_n):
+ if idx < len(vifs):
+ d = vifs[idx]
+ mac = d.get('mac')
+ bridge = d.get('bridge')
+ else:
+ mac = None
+ bridge = None
+ config_vif = ['vif']
+ if mac:
+ config_vif.append(['mac', mac])
+ if bridge:
+ config_vif.append(['bridge', bridge])
config_devs.append(['device', config_vif])
- config += config_devs
-
## if vfr_ipaddr:
## config_vfr = ['vfr']
## idx = 0 # No way of saying which IP is for which vif?
@@ -197,15 +227,27 @@ def make_config(opts):
## config_vfr.append(['vif', ['id', idx], ['ip', ip]])
## config.append(config_vfr)
- if opts.vnet:
- config_vnet = ['vnet']
- idx = 0
- for vnet in opts.vnet:
- config_vif = ['vif', ['id', 'vif%d' % idx], ['vnet', vnet]]
- config_vnet.append(config_vif)
- idx += 1
- config.append(config_vnet)
-
+
+def make_config(opts):
+ """Create the domain configuration.
+ """
+
+ config = ['vm',
+ ['name', opts.name ],
+ ['memory', opts.memory ] ]
+ if opts.cpu:
+ config.append(['cpu', opts.cpu])
+ if opts.blkif:
+ config.append(['backend', ['blkif']])
+ if opts.netif:
+ config.append(['backend', ['netif']])
+
+ configure_image(config, opts)
+ config_devs = []
+ configure_disks(config_devs, opts)
+ configure_pci(config_devs, opts)
+ configure_vifs(config_devs, opts)
+ config += config_devs
return config
def preprocess_disk(opts):
@@ -213,7 +255,6 @@ def preprocess_disk(opts):
disk = []
for v in opts.disk:
d = v.split(',')
- print 'disk', v, d
if len(d) != 3:
opts.err('Invalid disk specifier: ' + v)
disk.append(d)
@@ -231,6 +272,22 @@ def preprocess_pci(opts):
pci.append(hexd)
opts.pci = pci
+def preprocess_vifs(opts):
+ if not opts.vif: return
+ vifs = []
+ for vif in opts.vif:
+ d = {}
+ a = vif.split(',')
+ for b in a:
+ (k, v) = b.strip().split('=')
+ k = k.strip()
+ v = v.strip()
+ if k not in ['mac', 'bridge']:
+ opts.err('Invalid vif specifier: ' + vif)
+ d[k] = v
+ vifs.append(d)
+ opts.vif = vifs
+
def preprocess_ip(opts):
setip = (opts.hostname or opts.netmask
or opts.gateway or opts.dhcp or opts.interface)
@@ -259,6 +316,7 @@ def preprocess(opts):
opts.err("No kernel specified")
preprocess_disk(opts)
preprocess_pci(opts)
+ preprocess_vifs(opts)
preprocess_ip(opts)
preprocess_nfs(opts)
@@ -266,8 +324,8 @@ def make_domain(opts, config):
"""Create, build and start a domain.
Returns: [int] the ID of the new domain.
"""
- if opts.load:
- filename = os.path.abspath(opts.load)
+ if opts.vals.load:
+ filename = os.path.abspath(opts.vals.load)
dominfo = server.xend_domain_restore(filename, config)
else:
dominfo = server.xend_domain_create(config)
@@ -280,7 +338,7 @@ def make_domain(opts, config):
console_port = None
if server.xend_domain_unpause(dom) < 0:
- server.xend_domain_halt(dom)
+ server.xend_domain_destroy(dom)
opts.err("Failed to start domain %d" % dom)
opts.info("Started domain %d, console on port %d"
% (dom, console_port))
@@ -289,16 +347,16 @@ def make_domain(opts, config):
def main(argv):
opts = gopts
args = opts.parse(argv)
- if opts.help:
+ if opts.vals.help:
opts.usage()
return
- if opts.config:
+ if opts.vals.config:
pass
else:
opts.load_defaults()
- preprocess(opts)
- config = make_config(opts)
- if opts.dryrun:
+ preprocess(opts.vals)
+ config = make_config(opts.vals)
+ if opts.vals.dryrun:
PrettyPrint.prettyprint(config)
else:
make_domain(opts, config)
diff --git a/tools/xenmgr/lib/xm/main.py b/tools/xenmgr/lib/xm/main.py
index f124d63518..86f606fd83 100644
--- a/tools/xenmgr/lib/xm/main.py
+++ b/tools/xenmgr/lib/xm/main.py
@@ -10,27 +10,72 @@ from xenmgr import sxp
from xenmgr.XendClient import server
from xenmgr.xm import create, shutdown
+class Prog:
+ """Base class for sub-programs.
+ """
+
+ """Program group it belongs to"""
+ group = 'all'
+ """Program name."""
+ name = '??'
+ """Short program info."""
+ info = ''
+
+ def __init__(self, xm):
+ self.xm = xm
+
+ def err(self, msg):
+ self.xm.err(msg)
+
+ def help(self, args):
+ self.shortHelp(args)
+
+ def shortHelp(self, args):
+ print "%-14s %s" % (self.name, self.info)
+
+ def main(self, args):
+ """Program main entry point.
+ """
+ pass
+
+
+class ProgUnknown(Prog):
+
+ name = 'unknown'
+ info = ''
+
+ def help(self, args):
+ self.xm.err("Unknown command: %s\nTry '%s help' for more information."
+ % (args[0], self.xm.name))
+
+ main = help
+
class Xm:
+ """Main application.
+ """
def __init__(self):
- self.prog = 'xm'
- pass
+ self.name = 'xm'
+ self.unknown = ProgUnknown(self)
+ self.progs = {}
def err(self, msg):
print >>sys.stderr, "Error:", msg
sys.exit(1)
def main(self, args):
- """Main entry point. Dispatches to the xm_ methods.
+ """Main entry point. Dispatches to the progs.
"""
- self.prog = args[0]
+ self.name = args[0]
if len(args) < 2:
self.err("Missing command\nTry '%s help' for more information."
- % self.prog)
- prog = 'xm_' + args[1]
+ % self.name)
help = self.helparg(args)
- fn = getattr(self, prog, self.unknown)
- fn(help, args[1:])
+ p = self.getprog(args[1], self.unknown)
+ if help:
+ p.help(args[1:])
+ else:
+ p.main(args[1:])
def helparg(self, args):
for a in args:
@@ -38,39 +83,87 @@ class Xm:
return 1
return 0
- def unknown(self, help, args):
- if help and len(args) == 1:
- self.xm_help(help, args)
- else:
- self.err("Unknown command: %s\nTry '%s help' for more information."
- % (args[0], self.prog))
+ def prog(self, pklass):
+ """Add a sub-program.
+
+ pklass program class (Prog subclass)
+ """
+ p = pklass(self)
+ self.progs[p.name] = p
+ return p
+
+ def getprog(self, name, val=None):
+ """Get a sub-program.
+ """
+ return self.progs.get(name, val)
- def help(self, meth, args):
- """Print help on an xm_ method.
- Uses the method documentation string if there is one.
+ def proglist(self):
+ """Get a list of sub-programs, ordered by group.
"""
- name = meth[3:]
- f = getattr(self, meth)
- print "%-14s %s" % (name, f.__doc__ or '')
-
- def xm_help(self, help, args):
- """Print help."""
- for k in dir(self):
- if not k.startswith('xm_'): continue
- self.help(k, args)
- print "\nTry '%s CMD -h' for help on CMD" % self.prog
-
- def xm_create(self, help, args):
- """Create a domain."""
+ groups = {}
+ for p in self.progs.values():
+ l = groups.get(p.group, [])
+ l.append(p)
+ groups[p.group] = l
+ kl = groups.keys()
+ kl.sort()
+ pl = []
+ for k in kl:
+ l = groups[k]
+ l.sort()
+ pl += l
+ return pl
+
+# Create the application object, then add the sub-program classes.
+xm = Xm()
+
+class ProgHelp(Prog):
+
+ name = "help"
+ info = "Print help."
+
+ def help(self, args):
+ if len(args) == 2:
+ name = args[1]
+ p = self.xm.getprog(name)
+ if p:
+ p.help(args)
+ else:
+ print '%s: Unknown command: %s' % (self.name, name)
+ else:
+ for p in self.xm.proglist():
+ p.shortHelp(args)
+ print "\nTry '%s help CMD' for help on CMD" % self.xm.name
+
+ main = help
+
+xm.prog(ProgHelp)
+
+class ProgCreate(Prog):
+
+ group = 'domain'
+ name = "create"
+ info = """Create a domain."""
+
+ def help(self, args):
+ create.main([args[0], '-h'])
+
+ def main(self, args):
create.main(args)
- def xm_save(self, help, args):
- """Save domain state (and config) to file."""
- if help:
- print args[0], "DOM FILE [CONFIG]"
- print """\nSave domain with id DOM to FILE.
- Optionally save config to CONFIG."""
- return
+xm.prog(ProgCreate)
+
+class ProgSave(Prog):
+ group = 'domain'
+ name = "save"
+ info = """Save domain state (and config) to file."""
+
+ def help(self, args):
+ print args[0], "DOM FILE [CONFIG]"
+ print """\nSave domain with id DOM to FILE.
+ Optionally save config to CONFIG."""
+
+ def main(self, args):
if len(args) < 3: self.err("%s: Missing arguments" % args[0])
dom = args[1]
savefile = os.path.abspath(args[2])
@@ -83,23 +176,45 @@ class Xm:
PrettyPrint.prettyprint(config, out=out)
out.close()
server.xend_domain_save(dom, savefile)
-
- def xm_restore(self, help, args):
- """Create a domain from a saved state."""
- if help:
- print args[0], "FILE CONFIG"
- print "\nRestore a domain from FILE using configuration CONFIG."
- return
+
+xm.prog(ProgSave)
+
+class ProgRestore(Prog):
+ group = 'domain'
+ name = "restore"
+ info = """Create a domain from a saved state."""
+
+ def help(self, args):
+ print args[0], "FILE CONFIG"
+ print "\nRestore a domain from FILE using configuration CONFIG."
+
+ def main(self, help, args):
if len(args) < 3: self.err("%s: Missing arguments" % args[0])
savefile = os.path.abspath(args[1])
configfile = os.path.abspath(args[2])
info = server.xend_domain_restore(savefile, configfile)
PrettyPrint.prettyprint(info)
- def xm_domains(self, help, args):
- """List domains."""
- if help: self.help('xm_' + args[0], args); return
- doms = server.xend_domains()
+xm.prog(ProgRestore)
+
+class ProgList(Prog):
+ group = 'domain'
+ name = "list"
+ info = """List info about domains."""
+
+ def help(self, args):
+ if help:
+ print args[0], '[DOM...]'
+ print """\nGet information about domains.
+ Either all domains or the domains given."""
+ return
+
+ def main(self, args):
+ n = len(args)
+ if n == 1:
+ doms = server.xend_domains()
+ else:
+ doms = map(int, args[1:])
doms.sort()
print 'Dom Name Mem(MB) CPU State Time(s)'
for dom in doms:
@@ -113,111 +228,167 @@ class Xm:
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)
- def xm_domain(self, help, args):
- """Get information about a domain."""
- if help:
- print args[0], 'DOM'
- print '\nGet information about domain DOM.'
- return
- if len(args) < 2: self.err("%s: Missing domain" % args[0])
- dom = args[1]
- info = server.xend_domain(dom)
- PrettyPrint.prettyprint(info)
- print
+xm.prog(ProgList)
- def xm_halt(self, help, args):
- """Terminate a domain immediately."""
- if help:
- print args[0], 'DOM'
- print '\nTerminate domain DOM immediately.'
- return
+class ProgDestroy(Prog):
+ group = 'domain'
+ name = "destroy"
+ info = """Terminate a domain immediately."""
+
+ def help(self, args):
+ print args[0], 'DOM'
+ print '\nTerminate domain DOM immediately.'
+
+ def main(self, args):
if len(args) < 2: self.err("%s: Missing domain" % args[0])
dom = args[1]
- server.xend_domain_halt(dom)
+ server.xend_domain_destroy(dom)
+
+xm.prog(ProgDestroy)
+
+class ProgShutdown(Prog):
+ group = 'domain'
+ name = "shutdown"
+ info = """Shutdown a domain."""
- def xm_shutdown(self, help, args):
- """Shutdown a domain."""
+ def help(self, args):
+ print args[0], 'DOM'
+ print '\nSignal domain DOM to shutdown.'
+
+ def main(self, args):
shutdown.main(args)
- def xm_pause(self, help, args):
- """Pause execution of a domain."""
- if help:
- print args[0], 'DOM'
- print '\nPause execution of domain DOM.'
- return
+xm.prog(ProgShutdown)
+
+class ProgPause(Prog):
+ group = 'domain'
+ name = "pause"
+ info = """Pause execution of a domain."""
+
+ def help(self, args):
+ print args[0], 'DOM'
+ print '\nPause execution of domain DOM.'
+
+ def main(self, args):
if len(args) < 2: self.err("%s: Missing domain" % args[0])
dom = args[1]
server.xend_domain_pause(dom)
- def xm_unpause(self, help, args):
- """Unpause a paused domain."""
- if help:
- print args[0], 'DOM'
- print '\nUnpause execution of domain DOM.'
- return
+xm.prog(ProgPause)
+
+class ProgUnpause(Prog):
+ group = 'domain'
+ name = "unpause"
+ info = """Unpause a paused domain."""
+
+ def help(self, args):
+ print args[0], 'DOM'
+ print '\nUnpause execution of domain DOM.'
+
+ def main(self, args):
if len(args) < 2: self.err("%s: Missing domain" % args[0])
dom = args[1]
server.xend_domain_unpause(dom)
- def xm_pincpu(self, help, args):
- """Pin a domain to a cpu. """
- if help:
- print args[0],'DOM CPU'
- print '\nPin domain DOM to cpu CPU.'
- return
+xm.prog(ProgUnpause)
+
+class ProgPincpu(Prog):
+ group = 'domain'
+ name = "pincpu"
+ info = """Pin a domain to a cpu. """
+
+ def help(self, args):
+ print args[0],'DOM CPU'
+ print '\nPin domain DOM to cpu CPU.'
+
+ def main(self, args):
if len(args) != 3: self.err("%s: Invalid argument(s)" % args[0])
v = map(int, args[1:3])
server.xend_domain_pincpu(*v)
- def xm_bvt(self, help, args):
- """Set BVT scheduler parameters."""
- if help:
- print args[0], "DOM MCUADV WARP WARPL WARPU"
- print '\nSet Borrowed Virtual Time scheduler parameters.'
- return
+xm.prog(ProgPincpu)
+
+class ProgBvt(Prog):
+ group = 'scheduler'
+ name = "bvt"
+ info = """Set BVT scheduler parameters."""
+
+ def help(self, args):
+ print args[0], "DOM MCUADV WARP WARPL WARPU"
+ print '\nSet Borrowed Virtual Time scheduler parameters.'
+
+ def main(self, args):
if len(args) != 6: self.err("%s: Invalid argument(s)" % args[0])
v = map(int, args[1:6])
server.xend_domain_cpu_bvt_set(*v)
- def xm_bvtslice(self, help, args):
- """Set the BVT scheduler slice."""
- if help:
- print args[0], 'SLICE'
- print '\nSet Borrowed Virtual Time scheduler slice.'
- return
+xm.prog(ProgBvt)
+
+class ProgBvtslice(Prog):
+ group = 'scheduler'
+ name = "bvtslice"
+ info = """Set the BVT scheduler slice."""
+
+ def help(self, args):
+ print args[0], 'SLICE'
+ print '\nSet Borrowed Virtual Time scheduler slice.'
+
+ def main(self, args):
if len(args) < 2: self.err('%s: Missing slice' % args[0])
server.xend_node_cpu_bvt_slice_set(slice)
- def xm_atropos(self, help, args):
- """Set atropos parameters."""
- if help:
- print args[0], "DOM PERIOD SLICE LATENCY XTRATIME"
- print "\nSet atropos parameters."
- return
+xm.prog(ProgBvtslice)
+
+class ProgAtropos(Prog):
+ group = 'scheduler'
+ name= "atropos"
+ info = """Set atropos parameters."""
+
+ def help(self, args):
+ print args[0], "DOM PERIOD SLICE LATENCY XTRATIME"
+ print "\nSet atropos parameters."
+
+ def main(self, args):
if len(args) != 5: self.err("%s: Invalid argument(s)" % args[0])
v = map(int, args[1:5])
server.xend_domain_cpu_atropos_set(*v)
- def xm_rrobin(self, help, args):
- """Set round robin slice."""
- if help:
- print args[0], "SLICE"
- print "\nSet round robin scheduler slice."
- return
+xm.prog(ProgAtropos)
+
+class ProgRrobin(Prog):
+ group = 'scheduler'
+ name = "rrobin"
+ info = """Set round robin slice."""
+
+ def help(self, args):
+ print args[0], "SLICE"
+ print "\nSet round robin scheduler slice."
+
+ def main(self, args):
if len(args) != 2: self.err("%s: Invalid argument(s)" % args[0])
rrslice = int(args[1])
server.xend_node_rrobin_set(rrslice)
- def xm_info(self, help, args):
- """Get information about the xen host."""
- if help: self.help('xm_' + args[0], args); return
+xm.prog(ProgRrobin)
+
+class ProgInfo(Prog):
+ group = 'host'
+ name = "info"
+ info = """Get information about the xen host."""
+
+ def main(self, args):
info = server.xend_node()
for x in info[1:]:
print "%-23s:" % x[0], x[1]
- def xm_consoles(self, help, args):
- """Get information about domain consoles."""
- if help: self.help('xm_' + args[0], args); return
+xm.prog(ProgInfo)
+
+class ProgConsoles(Prog):
+ group = 'console'
+ name = "consoles"
+ info = """Get information about domain consoles."""
+
+ def main(self, args):
l = server.xend_consoles()
print "Dom Port Id"
for x in l:
@@ -228,12 +399,18 @@ class Xm:
d['id'] = sxp.child_value(info, 'id', '?')
print "%(dom)3s %(port)4s %(id)3s" % d
- def xm_console(self, help, args):
- """Open a console to a domain."""
- if help:
- print "console DOM"
- print "\nOpen a console to domain DOM."
- return
+xm.prog(ProgConsoles)
+
+class ProgConsole(Prog):
+ group = 'console'
+ name = "console"
+ info = """Open a console to a domain."""
+
+ def help(self, args):
+ print "console DOM"
+ print "\nOpen a console to domain DOM."
+
+ def main(self, args):
if len(args) < 2: self.err("%s: Missing domain" % args[0])
dom = args[1]
info = server.xend_domain(dom)
@@ -244,6 +421,7 @@ class Xm:
from xenctl import console_client
console_client.connect("localhost", int(port))
+xm.prog(ProgConsole)
+
def main(args):
- xm = Xm()
xm.main(args)
diff --git a/tools/xenmgr/lib/xm/opts.py b/tools/xenmgr/lib/xm/opts.py
index 426a6d24d1..b2cb2c7463 100644
--- a/tools/xenmgr/lib/xm/opts.py
+++ b/tools/xenmgr/lib/xm/opts.py
@@ -1,3 +1,6 @@
+# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
+"""Object-oriented command-line option support.
+"""
from getopt import getopt
import os
import os.path
@@ -5,8 +8,22 @@ import sys
import types
class Opt:
+ """An individual option.
+ """
def __init__(self, opts, name, short=None, long=None,
val=None, fn=None, use=None, default=None):
+ """Create an option.
+
+ opts parent options object
+ name name of the field it controls
+ short short (1-char) command line switch (optional)
+ long long command-line switch. Defaults to option name.
+ 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
+ """
self.opts = opts
self.name = name
self.short = short
@@ -24,18 +41,34 @@ class Opt:
self.fn = fn
self.specified_opt = None
self.specified_val = None
+ self.value = None
self.set(default)
+ def __repr__(self):
+ return self.name + '=' + str(self.specified_val)
+
+ __str__ = __repr__
+
def set(self, value):
- setattr(self.opts, self.name, value)
+ """Set the option value.
+ """
+ self.opts.setopt(self.name, value)
def get(self):
- return getattr(self.opts, self.name)
+ """Get the option value.
+ """
+ return self.opts.getopt(self.name)
def append(self, value):
- self.set(self.get().append(value))
+ """Append a value to the option value.
+ """
+ v = self.get() or []
+ v.append(value)
+ self.set(v)
def short_opt(self):
+ """Short option spec.
+ """
if self.short:
if self.val:
return self.short + ':'
@@ -45,6 +78,8 @@ class Opt:
return None
def long_opt(self):
+ """Long option spec.
+ """
if self.long:
if self.val:
return self.long + '='
@@ -68,6 +103,12 @@ class Opt:
print '\tDefault', self.default or 'None'
def specify(self, k, v):
+ """Specify the option. Called when the option is set
+ from the command line.
+
+ k option switch used
+ v optional value given (if any)
+ """
if k in self.optkeys:
if self.val is None and v:
self.opts.err("Option '%s' does not take a value" % k)
@@ -80,52 +121,113 @@ class Opt:
return 0
def specified(self):
+ """Test whether the option has been specified: set
+ from the command line.
+ """
return self.specified_opt
+class OptVals:
+ """Class to hold option values.
+ """
+ pass
+
class Opts:
+ """Container for options.
+ """
def __init__(self, use=None):
- self._usage = use
- self._options = []
- self._options_map = {}
- self._argv = []
- self._vals = {}
- self._globals = {}
- self._locals = {}
- self.quiet = 0
+ """Options constructor.
+
+ use usage string
+ """
+ self.use = use
+ # List of options.
+ self.options = []
+ # Options indexed by name.
+ self.options_map = {}
+ # Command-line arguments.
+ self.argv = []
+ # Option values.
+ self.vals = OptVals()
+ self.vals.quiet = 0
+ # Variables for default scripts.
+ self.vars = {}
+
+ def __repr__(self):
+ return '\n'.join(map(str, self.options))
+
+ __str__ = __repr__
def opt(self, name, **args):
+ """Add an option.
+
+ name option name
+ **args keyword params for option constructor
+ """
x = Opt(self, name, **args)
- self._options.append(x)
- self._options_map[name] = x
+ self.options.append(x)
+ self.options_map[name] = x
return x
+ def setvar(self, var, val):
+ """Set a default script variable.
+ """
+ self.vars[var] = val
+
+ def getvar(self, var):
+ """Get a default script variable.
+ """
+ return self.vars.get(var)
+
+ def option(self, name):
+ """Get an option (object).
+ """
+ return self.options_map.get(name)
+
+ def setopt(self, name, val):
+ """Set an option value.
+ An option can also be set using 'opts.vals.name = val'.
+ """
+ setattr(self.vals, name, val)
+
def getopt(self, name):
- return self._options_map.get(name)
+ """Get an option value.
+ An option value can also be got using 'opts.vals.name'.
+ """
+ getattr(self.vals, name)
def specified(self, name):
- opt = self.getopt(name)
+ """Test if an option has been specified.
+ """
+ opt = self.option(name)
return opt and opt.specified()
- def setvar(self, name, val):
- self._globals[name] = val
-
def err(self, msg):
+ """Print an error to stderr and exit.
+ """
print >>sys.stderr, "Error:", msg
sys.exit(1)
def info(self, msg):
- if self.quiet: return
+ """Print a message to stdout (unless quiet is set).
+ """
+ if self.vals.quiet: return
print msg
def warn(self, msg):
+ """Print a warning to stdout.
+ """
print >>sys.stderr, "Warning:", msg
def parse(self, argv):
- self._argv = argv
+ """Parse arguments argv using the options.
+
+ return remaining arguments
+ """
+ self.argv = argv
(vals, args) = getopt(argv[1:], self.short_opts(), self.long_opts())
- self._args = args
+ self.args = args
for (k, v) in vals:
- for opt in self._options:
+ for opt in self.options:
if opt.specify(k, v): break
else:
print >>sys.stderr, "Error: Unknown option:", k
@@ -133,63 +235,92 @@ class Opts:
return args
def short_opts(self):
+ """Get short options specifier for getopt.
+ """
l = []
- for x in self._options:
+ for x in self.options:
y = x.short_opt()
if not y: continue
l.append(y)
return ''.join(l)
def long_opts(self):
+ """Get long options specifier for getopt.
+ """
l = []
- for x in self._options:
+ for x in self.options:
y = x.long_opt()
if not y: continue
l.append(y)
- return ''.join(l)
+ return l
def usage(self):
- print 'Usage: ', self._argv[0], self._usage or 'OPTIONS'
- for opt in self._options:
+ print 'Usage: ', self.argv[0], self.use or 'OPTIONS'
+ for opt in self.options:
opt.show()
def load_defaults(self):
- for x in [ '' ] + self.path.split(':'):
+ """Load a defaults script. Assumes these options set:
+ 'path' search path
+ 'default' script name
+ """
+ for x in [ '' ] + self.vals.path.split(':'):
if x:
- p = os.path.join(x, self.defaults)
+ p = os.path.join(x, self.vals.defaults)
else:
- p = self.defaults
+ p = self.vals.defaults
if os.path.exists(p):
self.load(p)
break
else:
self.err("Cannot open defaults file %s" % self.defaults)
- def load(self, defaults):
- self._globals['sys'] = sys
- self._globals['config_file'] = defaults
- execfile(defaults, self._globals, self._locals)
+ def load(self, defaults, help=0):
+ """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.
+ """
+ # Create global and lobal dicts for the file.
+ # Initialize locals to the vars.
+ # Use exec to do the standard imports and
+ # define variables we are passing to the script.
+ globals = {}
+ locals = {}
+ locals.update(self.vars)
+ cmd = '\n'.join(["import sys",
+ "import os",
+ "import os.path",
+ "xm_file = '%s'" % defaults,
+ "xm_help = %d" % help ])
+ exec cmd in globals, locals
+ execfile(defaults, globals, locals)
+ if help: return
+ # Extract the values set by the script and set the corresponding
+ # options, if not set on the command line.
vtypes = [ types.StringType,
types.ListType,
types.IntType,
types.FloatType
]
- for (k, v) in self._locals.items():
+ for (k, v) in locals.items():
if self.specified(k): continue
if not(type(v) in vtypes): continue
- print 'SET ', k, v
- setattr(self, k, v)
+ self.setopt(k, v)
def set_true(opt, k, v):
+ """Set an option true."""
opt.set(1)
def set_false(opt, k, v):
+ """Set an option false."""
opt.set(0)
def set_value(opt, k, v):
+ """Set an option to a valoue."""
opt.set(v)
def set_int(opt, k, v):
+ """Set an option to an integer value."""
try:
v = int(v)
except:
@@ -197,4 +328,12 @@ def set_int(opt, k, v):
opt.set(v)
def append_value(opt, k, v):
+ """Append a value to a list option."""
opt.append(v)
+
+def set_var(opt, k, v):
+ """Set a default script variable.
+ """
+ (var, val) = v.strip().split('=')
+ opt.opts.setvar(var.strip(), val.strip())
+
diff --git a/tools/xenmgr/lib/xm/shutdown.py b/tools/xenmgr/lib/xm/shutdown.py
index 0108a8df0f..90fff21f6a 100644
--- a/tools/xenmgr/lib/xm/shutdown.py
+++ b/tools/xenmgr/lib/xm/shutdown.py
@@ -1,3 +1,6 @@
+# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
+"""Domain shutdown.
+"""
import string
import sys
import time