[POWERPC][XEN] Merge with xen-unstable.hg.

Signed-off-by: Hollis Blanchard <hollisb@us.ibm.com>
This commit is contained in:
Hollis Blanchard committed 2007-02-06 15:03:52 -06:00
commit 4c03b0792e
949 files changed
+68821 -30599

No files matched your search

+1 -1
View File
@@ -8,7 +8,7 @@ all: build
build:
CC="$(CC)" CFLAGS="$(CFLAGS)" python setup.py build
if which $(MSGFMT) >/dev/null ; then \
for file in `cd xen/xm; find messages -name xen-xm.po`; do \
for file in `cd ./xen/xm; find messages -name xen-xm.po`; do \
dest=`echo "build/$$file" | \
sed -e 's#xen-xm.po#LC_MESSAGES/xen-xm.mo#'`; \
mkdir -p `dirname "$$dest"`; \
+180
View File
@@ -0,0 +1,180 @@
#!/usr/bin/python
vm_cfg = {
'name_label': 'API_HVM',
'user_version': 1,
'is_a_template': False,
'auto_power_on': False, # TODO
'memory_static_min': 64,
'memory_static_max': 128,
#'memory_dynamic_min': 64,
#'memory_dynamic_max': 128,
'VCPUs_policy': 'credit',
'VCPUs_params': {},
'VCPUs_number': 2,
'actions_after_shutdown': 'destroy',
'actions_after_reboot': 'restart',
'actions_after_crash': 'destroy',
'PV_bootloader': '',
'PV_bootloader_args': '',
'PV_kernel': '',
'PV_ramdisk': '',
'PV_args': '',
'HVM_boot': 'cda',
'platform_std_VGA': False,
'platform_serial': '',
'platform_localtime': False,
'platform_clock_offset': False,
'platform_enable_audio': False,
'PCI_bus': ''
}
local_vdi_cfg = {
'name_label': 'gentoo.hvm',
'name_description': '',
'location': 'file:/root/gentoo.amd64.hvm.img',
'virtual_size': 0,
'sector_size': 0,
'type': 'system',
'parent': '',
'SR_name': 'Local',
'sharable': False,
'read_only': False,
}
local_vbd_cfg = {
'VDI': '',
'VM': '',
'device': 'hda',
'mode': 'RW',
'type': 'disk',
'driver': 'ioemu',
}
vif_cfg = {
'name': 'API_VIF',
'type': 'ioemu',
'device': '',
'network': '',
'MAC': '',
'MTU': 1500,
}
console_cfg = {
'protocol': 'rfb',
'other_config': {'vncunused': 1, 'vncpasswd': 'testing'},
}
import sys
import time
sys.path.append('/usr/lib/python')
from xapi import connect, execute
def test_vm_create():
server, session = connect()
vm_uuid = None
local_vdi_uuid = None
local_vbd_uuid = None
vif_uuid = None
# List all VMs
vm_list = execute(server, 'VM.get_all', (session,))
vm_names = []
for vm_uuid in vm_list:
vm_record = execute(server, 'VM.get_record', (session, vm_uuid))
vm_names.append(vm_record['name_label'])
# Get default SR
local_sr_list = execute(server, 'SR.get_by_name_label',
(session, local_vdi_cfg['SR_name']))
local_sr_uuid = local_sr_list[0]
# Get default network
net_list = execute(server, 'network.get_all', (session,))
net_uuid = net_list[0]
try:
# Create a new VM
print 'Create VM'
vm_uuid = execute(server, 'VM.create', (session, vm_cfg))
print 'Create VDI'
# Create a new VDI (Local)
local_vdi_cfg['SR'] = local_sr_uuid
local_vdi_uuid = execute(server, 'VDI.create',
(session, local_vdi_cfg))
print 'Create VBD'
# Create a new VBD (Local)
local_vbd_cfg['VM'] = vm_uuid
local_vbd_cfg['VDI'] = local_vdi_uuid
local_vbd_uuid = execute(server, 'VBD.create',
(session, local_vbd_cfg))
print 'Craete VIF'
# Create a new VIF
vif_cfg['network'] = net_uuid
vif_cfg['VM'] = vm_uuid
vif_uuid = execute(server, 'VIF.create', (session, vif_cfg))
# Create a console
console_cfg['VM'] = vm_uuid
console_uuid = execute(server, 'console.create',
(session, console_cfg))
print console_uuid
# Start the VM
execute(server, 'VM.start', (session, vm_uuid, False))
time.sleep(30)
test_suspend = False
if test_suspend:
print 'Suspending VM..'
execute(server, 'VM.suspend', (session, vm_uuid))
print 'Suspended VM.'
time.sleep(5)
print 'Resuming VM ...'
execute(server, 'VM.resume', (session, vm_uuid, False))
print 'Resumed VM.'
# Wait for user to say we're good to shut it down
while True:
destroy = raw_input('destroy VM? ')
if destroy[0] in ('y', 'Y'):
break
finally:
# Clean up
if vif_uuid:
execute(server, 'VIF.destroy', (session, vif_uuid))
if local_vbd_uuid:
execute(server, 'VBD.destroy', (session, local_vbd_uuid))
if local_vdi_uuid:
execute(server, 'VDI.destroy', (session, local_vdi_uuid))
if vm_uuid:
try:
execute(server, 'VM.hard_shutdown', (session, vm_uuid))
time.sleep(2)
except:
pass
try:
execute(server, 'VM.destroy', (session, vm_uuid))
except:
pass
if __name__ == "__main__":
test_vm_create()
+214
View File
@@ -0,0 +1,214 @@
#!/usr/bin/python
vm_cfg = {
'name_label': 'APIVM',
'user_version': 1,
'is_a_template': False,
'auto_power_on': False, # TODO
'memory_static_min': 64,
'memory_static_max': 128,
#'memory_dynamic_min': 64,
#'memory_dynamic_max': 128,
'VCPUs_policy': 'credit',
'VCPUs_params': '',
'VCPUs_number': 2,
'actions_after_shutdown': 'destroy',
'actions_after_reboot': 'restart',
'actions_after_crash': 'destroy',
'PV_bootloader': '',
'PV_bootloader_args': '',
'PV_kernel': '/boot/vmlinuz-2.6.18-xenU',
'PV_ramdisk': '',
'PV_args': 'root=/dev/sda1 ro',
#'HVM_boot': '',
'platform_std_VGA': False,
'platform_serial': '',
'platform_localtime': False,
'platform_clock_offset': False,
'platform_enable_audio': False,
'PCI_bus': ''
}
vdi_cfg = {
'name_label': 'API_VDI',
'name_description': '',
'virtual_size': 100 * 1024,
'sector_size': 1024,
'type': 'system',
'parent': '',
'SR_name': 'QCoW',
'sharable': False,
'read_only': False,
}
vbd_cfg = {
'VDI': '',
'VM': '',
'device': 'sda2',
'mode': 'RW',
'type': 'disk',
'driver': 'paravirtualised',
}
local_vdi_cfg = {
'name_label': 'gentoo.amd64.img',
'name_description': '',
'location': 'file:/root/gentoo.amd64.img',
'virtual_size': 0,
'sector_size': 0,
'type': 'system',
'parent': '',
'SR_name': 'Local',
'sharable': False,
'read_only': False,
}
local_vbd_cfg = {
'VDI': '',
'VM': '',
'device': 'sda1',
'mode': 'RW',
'type': 'disk',
'driver': 'paravirtualised',
}
vif_cfg = {
'name': 'API_VIF',
'type': 'paravirtualised',
'device': '',
'network': '',
'MAC': '',
'MTU': 1500,
}
console_cfg = {
'protocol': 'rfb',
'other_config': {'vncunused': 1, 'vncpasswd': 'testing'},
}
import sys
import time
sys.path.append('/usr/lib/python')
from xapi import connect, execute
def test_vm_create():
server, session = connect()
vm_uuid = None
vdi_uuid = None
local_vdi_uuid = None
local_vbd_uuid = None
vbd_uuid = None
vif_uuid = None
# List all VMs
vm_list = execute(server, 'VM.get_all', (session,))
vm_names = []
for vm_uuid in vm_list:
vm_record = execute(server, 'VM.get_record', (session, vm_uuid))
vm_names.append(vm_record['name_label'])
# Get default SR
sr_list = execute(server, 'SR.get_by_name_label', (session,
vdi_cfg['SR_name']))
sr_uuid = sr_list[0]
local_sr_list = execute(server, 'SR.get_by_name_label',
(session, local_vdi_cfg['SR_name']))
local_sr_uuid = local_sr_list[0]
# Get default network
net_list = execute(server, 'network.get_all', (session,))
net_uuid = net_list[0]
try:
# Create a new VM
vm_uuid = execute(server, 'VM.create', (session, vm_cfg))
# Create a new VDI
vdi_cfg['SR'] = sr_uuid
vdi_uuid = execute(server, 'VDI.create', (session, vdi_cfg))
# Create a VDI backed VBD
vbd_cfg['VM'] = vm_uuid
vbd_cfg['VDI'] = vdi_uuid
vbd_uuid = execute(server, 'VBD.create', (session, vbd_cfg))
# Create a new VDI (Local)
local_vdi_cfg['SR'] = local_sr_uuid
local_vdi_uuid = execute(server, 'VDI.create',
(session, local_vdi_cfg))
# Create a new VBD (Local)
local_vbd_cfg['VM'] = vm_uuid
local_vbd_cfg['VDI'] = local_vdi_uuid
local_vbd_uuid = execute(server, 'VBD.create',
(session, local_vbd_cfg))
# Create a new VIF
vif_cfg['network'] = net_uuid
vif_cfg['VM'] = vm_uuid
vif_uuid = execute(server, 'VIF.create', (session, vif_cfg))
# Create a console
console_cfg['VM'] = vm_uuid
console_uuid = execute(server, 'console.create',
(session, console_cfg))
print console_uuid
# Start the VM
execute(server, 'VM.start', (session, vm_uuid, False))
time.sleep(30)
test_suspend = False
if test_suspend:
print 'Suspending VM..'
execute(server, 'VM.suspend', (session, vm_uuid))
print 'Suspended VM.'
time.sleep(5)
print 'Resuming VM ...'
execute(server, 'VM.resume', (session, vm_uuid, False))
print 'Resumed VM.'
finally:
# Wait for user to say we're good to shut it down
while True:
destroy = raw_input('destroy VM? ')
if destroy[0] in ('y', 'Y'):
break
# Clean up
if vif_uuid:
execute(server, 'VIF.destroy', (session, vif_uuid))
if local_vbd_uuid:
execute(server, 'VBD.destroy', (session, local_vbd_uuid))
if local_vdi_uuid:
execute(server, 'VDI.destroy', (session, local_vdi_uuid))
if vbd_uuid:
execute(server, 'VBD.destroy', (session, vbd_uuid))
if vdi_uuid:
execute(server, 'VDI.destroy', (session, vdi_uuid))
if vm_uuid:
try:
execute(server, 'VM.hard_shutdown', (session, vm_uuid))
time.sleep(2)
except:
pass
execute(server, 'VM.destroy', (session, vm_uuid))
if __name__ == "__main__":
test_vm_create()
+452 -133
View File
@@ -17,6 +17,9 @@
#============================================================================
import sys
import time
import re
import os
sys.path.append('/usr/lib/python')
from xen.util.xmlrpclib2 import ServerProxy
@@ -25,6 +28,10 @@ from pprint import pprint
from types import DictType
from getpass import getpass
# Get default values from the environment
SERVER_URI = os.environ.get('XAPI_SERVER_URI', 'http://localhost:9363/')
SERVER_USER = os.environ.get('XAPI_SERVER_USER', '')
SERVER_PASS = os.environ.get('XAPI_SERVER_PASS', '')
MB = 1024 * 1024
@@ -35,12 +42,15 @@ SR_LIST_FORMAT = '%(name_label)-18s %(uuid)-36s %(physical_size)-10s' \
'%(type)-10s'
VDI_LIST_FORMAT = '%(name_label)-18s %(uuid)-36s %(virtual_size)-8s '\
'%(sector_size)-8s'
VBD_LIST_FORMAT = '%(name_label)-18s %(uuid)-36s %(VDI)-8s '\
'%(image)-8s'
VBD_LIST_FORMAT = '%(device)-6s %(uuid)-36s %(VDI)-8s'
TASK_LIST_FORMAT = '%(name_label)-18s %(uuid)-36s %(status)-8s %(progress)-4s'
VIF_LIST_FORMAT = '%(name)-8s %(device)-7s %(uuid)-36s %(MAC)-10s'
CONSOLE_LIST_FORMAT = '%(uuid)-36s %(protocol)-8s %(location)-32s'
COMMANDS = {
'host-info': ('', 'Get Xen Host Info'),
'host-set-name': ('', 'Set host name'),
'pif-list': ('', 'List all PIFs'),
'sr-list': ('', 'List all SRs'),
'vbd-list': ('', 'List all VBDs'),
'vbd-create': ('<domname> <pycfg> [opts]',
@@ -48,7 +58,7 @@ COMMANDS = {
'vdi-create': ('<pycfg> [opts]', 'Create a VDI'),
'vdi-list' : ('', 'List all VDI'),
'vdi-rename': ('<vdi_uuid> <new_name>', 'Rename VDI'),
'vdi-delete': ('<vdi_uuid>', 'Delete VDI'),
'vdi-destroy': ('<vdi_uuid>', 'Delete VDI'),
'vif-create': ('<domname> <pycfg>', 'Create VIF attached to domname'),
'vtpm-create' : ('<domname> <pycfg>', 'Create VTPM attached to domname'),
@@ -60,9 +70,23 @@ COMMANDS = {
'vm-shutdown': ('<name> [opts]', 'Shutdown VM with name'),
'vm-start': ('<name>', 'Start VM with name'),
'vm-uuid': ('<name>', 'UUID of a domain by name.'),
'async-vm-start': ('<name>', 'Start VM asynchronously'),
}
OPTIONS = {
'sr-list': [(('-l', '--long'),
{'action':'store_true',
'help':'List all properties of SR'})
],
'vdi-list': [(('-l', '--long'),
{'action':'store_true',
'help':'List all properties of VDI'})
],
'vif-list': [(('-l', '--long'),
{'action':'store_true',
'help':'List all properties of VIF'})
],
'vm-list': [(('-l', '--long'),
{'action':'store_true',
'help':'List all properties of VMs'})
@@ -71,25 +95,28 @@ OPTIONS = {
'action': 'store_true'})],
'vdi-create': [(('--name-label',), {'help': 'Name for VDI'}),
(('--description',), {'help': 'Description for VDI'}),
(('--name-description',), {'help': 'Description for VDI'}),
(('--sector-size',), {'type': 'int',
'help': 'Sector size'}),
'help': 'Sector size',
'default': 0}),
(('--virtual-size',), {'type': 'int',
'default': 0,
'help': 'Size of VDI in sectors'}),
(('--type',), {'choices': ['system', 'user', 'ephemeral'],
'default': 'system',
'help': 'VDI type'}),
(('--sharable',), {'action': 'store_true',
'help': 'VDI sharable'}),
(('--read-only',), {'action': 'store_true',
'help': 'Read only'})],
'help': 'Read only'}),
(('--sr',), {})],
'vbd-create': [(('--VDI',), {'help': 'UUID of VDI to attach to.'}),
(('--mode',), {'choices': ['RO', 'RW'],
'help': 'device mount mode'}),
(('--driver',), {'choices':['paravirtualised', 'ioemu'],
'help': 'Driver for VBD'}),
(('--device',), {'help': 'Device name on guest domain'}),
(('--image',), {'help': 'Location of drive image.'})]
(('--device',), {'help': 'Device name on guest domain'})]
}
@@ -130,8 +157,13 @@ def parse_args(cmd_name, args, set_defaults = False):
values = defaults)
return opts, extraargs
def execute(fn, *args):
result = fn(*args)
def execute(server, fn, args, async = False):
if async:
func = eval('server.Async.%s' % fn)
else:
func = eval('server.%s' % fn)
result = func(*args)
if type(result) != DictType:
raise TypeError("Function returned object of type: %s" %
str(type(result)))
@@ -142,14 +174,23 @@ def execute(fn, *args):
_initialised = False
_server = None
_session = None
def _connect(*args):
def connect(*args):
global _server, _session, _initialised
if not _initialised:
_server = ServerProxy('httpu:///var/run/xend/xmlrpc.sock')
login = raw_input("Login: ")
password = getpass()
creds = (login, password)
_session = execute(_server.session.login_with_password, *creds)
# try without password or default credentials
try:
_server = ServerProxy(SERVER_URI)
_session = execute(_server.session, 'login_with_password',
(SERVER_USER, SERVER_PASS))
except:
login = raw_input("Login: ")
password = getpass()
creds = (login, password)
_server = ServerProxy(SERVER_URI)
_session = execute(_server.session, 'login_with_password',
creds)
_initialised = True
return (_server, _session)
@@ -162,14 +203,14 @@ def _read_python_cfg(filename):
return cfg
def resolve_vm(server, session, vm_name):
vm_uuid = execute(server.VM.get_by_name_label, session, vm_name)
vm_uuid = execute(server, 'VM.get_by_name_label', (session, vm_name))
if not vm_uuid:
return None
else:
return vm_uuid[0]
def resolve_vdi(server, session, vdi_name):
vdi_uuid = execute(server.VDI.get_by_name_label, session, vdi_name)
vdi_uuid = execute(server, 'VDI.get_by_name_label', (session, vdi_name))
if not vdi_uuid:
return None
else:
@@ -179,50 +220,58 @@ def resolve_vdi(server, session, vdi_name):
# Actual commands
#
def xapi_host_info(*args):
server, session = _connect()
hosts = execute(server.host.get_all, session)
def xapi_host_info(args, async = False):
server, session = connect()
hosts = execute(server, 'host.get_all', (session,))
for host in hosts: # there is only one, but ..
hostinfo = execute(server.host.get_record, session, host)
hostinfo = execute(server, 'host.get_record', (session, host))
print HOST_INFO_FORMAT % ('Name', hostinfo['name_label'])
print HOST_INFO_FORMAT % ('Version', hostinfo['software_version'])
print HOST_INFO_FORMAT % ('CPUs', len(hostinfo['host_CPUs']))
print HOST_INFO_FORMAT % ('VMs', len(hostinfo['resident_VMs']))
print HOST_INFO_FORMAT % ('UUID', host)
def xapi_host_set_name(*args):
for host_cpu_uuid in hostinfo['host_CPUs']:
host_cpu = execute(server, 'host_cpu.get_record',
(session, host_cpu_uuid))
print 'CPU %s Util: %.2f' % (host_cpu['number'],
float(host_cpu['utilisation']))
def xapi_host_set_name(args, async = False):
if len(args) < 1:
raise OptionError("No hostname specified")
server, session = _connect()
hosts = execute(server.host.get_all, session)
server, session = connect()
hosts = execute(server, 'host.get_all', (session,))
if len(hosts) > 0:
execute(server.host.set_name_label, session, hosts[0], args[0])
print 'Hostname: %s' % execute(server.host.get_name_label, session,
hosts[0])
execute(server, 'host.set_name_label', (session, hosts[0], args[0]))
print 'Hostname: %s' % execute(server, 'host.get_name_label',
(session, hosts[0]))
def xapi_vm_uuid(*args):
def xapi_vm_uuid(args, async = False):
if len(args) < 1:
raise OptionError("No domain name specified")
server, session = _connect()
server, session = connect()
vm_uuid = resolve_vm(server, session, args[0])
print vm_uuid
def xapi_vm_name(*args):
def xapi_vm_name(args, async = False):
if len(args) < 1:
raise OptionError("No UUID specified")
server, session = _connect()
vm_name = execute(server.VM.get_name_label, session, args[0])
server, session = connect()
vm_name = execute(server, 'VM.get_name_label', (session, args[0]))
print vm_name
def xapi_vm_list(*args):
def xapi_vm_list(args, async = False):
opts, args = parse_args('vm-list', args, set_defaults = True)
is_long = opts and opts.long
list_only = args
server, session = _connect()
vm_uuids = execute(server.VM.get_all, session)
server, session = connect()
vm_uuids = execute(server, 'VM.get_all', (session,))
if not is_long:
print VM_LIST_FORMAT % {'name_label':'Name',
'memory_actual':'Mem',
@@ -231,7 +280,12 @@ def xapi_vm_list(*args):
'uuid': 'UUID'}
for uuid in vm_uuids:
vm_info = execute(server.VM.get_record, session, uuid)
vm_info = execute(server, 'VM.get_record', (session, uuid))
# skip domain if we don't want
if list_only and vm_info['name_label'] not in list_only:
continue
if is_long:
vbds = vm_info['VBDs']
vifs = vm_info['VIFs']
@@ -240,13 +294,13 @@ def xapi_vm_list(*args):
vbd_infos = []
vtpm_infos = []
for vbd in vbds:
vbd_info = execute(server.VBD.get_record, session, vbd)
vbd_info = execute(server, 'VBD.get_record', (session, vbd))
vbd_infos.append(vbd_info)
for vif in vifs:
vif_info = execute(server.VIF.get_record, session, vif)
vif_info = execute(server, 'VIF.get_record', (session, vif))
vif_infos.append(vif_info)
for vtpm in vtpms:
vtpm_info = execute(server.VTPM.get_record, session, vtpm)
vtpm_info = execute(server, 'VTPM.get_record', (session, vtpm))
vtpm_infos.append(vtpm_info)
vm_info['VBDs'] = vbd_infos
vm_info['VIFs'] = vif_infos
@@ -255,7 +309,7 @@ def xapi_vm_list(*args):
else:
print VM_LIST_FORMAT % _stringify(vm_info)
def xapi_vm_create(*args):
def xapi_vm_create(args, async = False):
if len(args) < 1:
raise OptionError("Configuration file not specified")
@@ -263,49 +317,129 @@ def xapi_vm_create(*args):
cfg = _read_python_cfg(filename)
print 'Creating VM from %s ..' % filename
server, session = _connect()
uuid = execute(server.VM.create, session, cfg)
server, session = connect()
uuid = execute(server, 'VM.create', (session, cfg), async = async)
print 'Done. (%s)' % uuid
print uuid
def xapi_vm_destroy(*args):
def xapi_vm_destroy(args, async = False):
if len(args) < 1:
raise OptionError("No domain name specified.")
server, session = _connect()
server, session = connect()
vm_uuid = resolve_vm(server, session, args[0])
print 'Destroying VM %s (%s)' % (args[0], vm_uuid)
success = execute(server.VM.destroy, session, vm_uuid)
success = execute(server, 'VM.destroy', (session, vm_uuid), async = async)
print 'Done.'
def xapi_vm_start(*args):
def xapi_vm_start(args, async = False):
if len(args) < 1:
raise OptionError("No Domain name specified.")
server, session = _connect()
server, session = connect()
vm_uuid = resolve_vm(server, session, args[0])
print 'Starting VM %s (%s)' % (args[0], vm_uuid)
success = execute(server.VM.start, session, vm_uuid, False)
print 'Done.'
success = execute(server, 'VM.start', (session, vm_uuid, False), async = async)
if async:
print 'Task started: %s' % success
else:
print 'Done.'
def xapi_vm_shutdown(*args):
def xapi_vm_suspend(args, async = False):
if len(args) < 1:
raise OptionError("No Domain name specified.")
server, session = connect()
vm_uuid = resolve_vm(server, session, args[0])
print 'Suspending VM %s (%s)' % (args[0], vm_uuid)
success = execute(server, 'VM.suspend', (session, vm_uuid), async = async)
if async:
print 'Task started: %s' % success
else:
print 'Done.'
def xapi_vm_resume(args, async = False):
if len(args) < 1:
raise OptionError("No Domain name specified.")
server, session = connect()
vm_uuid = resolve_vm(server, session, args[0])
print 'Resuming VM %s (%s)' % (args[0], vm_uuid)
success = execute(server, 'VM.resume', (session, vm_uuid, False), async = async)
if async:
print 'Task started: %s' % success
else:
print 'Done.'
def xapi_vm_pause(args, async = False):
if len(args) < 1:
raise OptionError("No Domain name specified.")
server, session = connect()
vm_uuid = resolve_vm(server, session, args[0])
print 'Pausing VM %s (%s)' % (args[0], vm_uuid)
success = execute(server, 'VM.pause', (session, vm_uuid), async = async)
if async:
print 'Task started: %s' % success
else:
print 'Done.'
def xapi_vm_unpause(args, async = False):
if len(args) < 1:
raise OptionError("No Domain name specified.")
server, session = connect()
vm_uuid = resolve_vm(server, session, args[0])
print 'Pausing VM %s (%s)' % (args[0], vm_uuid)
success = execute(server, 'VM.unpause', (session, vm_uuid), async = async)
if async:
print 'Task started: %s' % success
else:
print 'Done.'
def xapi_task_list(args, async = False):
server, session = connect()
all_tasks = execute(server, 'task.get_all', (session,))
print TASK_LIST_FORMAT % {'name_label': 'Task Name',
'uuid': 'UUID',
'status': 'Status',
'progress': '%'}
for task_uuid in all_tasks:
task = execute(server, 'task.get_record', (session, task_uuid))
print TASK_LIST_FORMAT % task
def xapi_task_clear(args, async = False):
server, session = connect()
all_tasks = execute(server, 'task.get_all', (session,))
for task_uuid in all_tasks:
success = execute(server, 'task.destroy', (session, task_uuid))
print 'Destroyed Task %s' % task_uuid
def xapi_vm_shutdown(args, async = False):
opts, args = parse_args("vm-shutdown", args, set_defaults = True)
if len(args) < 1:
raise OptionError("No Domain name specified.")
server, session = _connect()
server, session = connect()
vm_uuid = resolve_vm(server, session, args[0])
if opts.force:
print 'Forcefully shutting down VM %s (%s)' % (args[0], vm_uuid)
success = execute(server.VM.hard_shutdown, session, vm_uuid)
success = execute(server, 'VM.hard_shutdown', (session, vm_uuid), async = async)
else:
print 'Shutting down VM %s (%s)' % (args[0], vm_uuid)
success = execute(server.VM.clean_shutdown, session, vm_uuid)
print 'Done.'
success = execute(server, 'VM.clean_shutdown', (session, vm_uuid), async = async)
def xapi_vbd_create(*args):
if async:
print 'Task started: %s' % success
else:
print 'Done.'
def xapi_vbd_create(args, async = False):
opts, args = parse_args('vbd-create', args)
if len(args) < 2:
@@ -323,13 +457,16 @@ def xapi_vbd_create(*args):
cfg[opt] = val
print 'Creating VBD ...',
server, session = _connect()
server, session = connect()
vm_uuid = resolve_vm(server, session, domname)
cfg['VM'] = vm_uuid
vbd_uuid = execute(server.VBD.create, session, cfg)
print 'Done. (%s)' % vbd_uuid
vbd_uuid = execute(server, 'VBD.create', (session, cfg), async = async)
if async:
print 'Task started: %s' % vbd_uuid
else:
print 'Done. (%s)' % vbd_uuid
def xapi_vif_create(*args):
def xapi_vif_create(args, async = False):
if len(args) < 2:
raise OptionError("Configuration file not specified")
@@ -338,54 +475,139 @@ def xapi_vif_create(*args):
cfg = _read_python_cfg(filename)
print 'Creating VIF from %s ..' % filename
server, session = _connect()
server, session = connect()
vm_uuid = resolve_vm(server, session, domname)
cfg['VM'] = vm_uuid
vif_uuid = execute(server.VIF.create, session, cfg)
print 'Done. (%s)' % vif_uuid
vif_uuid = execute(server, 'VIF.create', (session, cfg), async = async)
if async:
print 'Task started: %s' % vif_uuid
else:
print 'Done. (%s)' % vif_uuid
def xapi_vbd_list(*args):
server, session = _connect()
def xapi_vbd_list(args, async = False):
server, session = connect()
domname = args[0]
dom_uuid = resolve_vm(server, session, domname)
vbds = execute(server.VM.get_VBDs, session, dom_uuid)
vbds = execute(server, 'VM.get_VBDs', (session, dom_uuid))
print VBD_LIST_FORMAT % {'name_label': 'VDI Label',
print VBD_LIST_FORMAT % {'device': 'Device',
'uuid' : 'UUID',
'VDI': 'VDI',
'image': 'Image'}
'VDI': 'VDI'}
for vbd in vbds:
vbd_struct = execute(server.VBD.get_record, session, vbd)
vbd_struct = execute(server, 'VBD.get_record', (session, vbd))
print VBD_LIST_FORMAT % vbd_struct
def xapi_vbd_stats(args, async = False):
server, session = connect()
domname = args[0]
dom_uuid = resolve_vm(server, session, domname)
def xapi_vdi_list(*args):
server, session = _connect()
vdis = execute(server.VDI.get_all, session)
print VDI_LIST_FORMAT % {'name_label': 'VDI Label',
'uuid' : 'UUID',
'virtual_size': 'Sectors',
'sector_size': 'Sector Size'}
vbds = execute(server, 'VM.get_VBDs', (session, dom_uuid))
for vbd_uuid in vbds:
print execute(server, 'VBD.get_io_read_kbs', (session, vbd_uuid))
def xapi_vif_list(args, async = False):
server, session = connect()
opts, args = parse_args('vdi-list', args, set_defaults = True)
is_long = opts and opts.long
for vdi in vdis:
vdi_struct = execute(server.VDI.get_record, session, vdi)
print VDI_LIST_FORMAT % vdi_struct
domname = args[0]
dom_uuid = resolve_vm(server, session, domname)
vifs = execute(server, 'VM.get_VIFs', (session, dom_uuid))
def xapi_sr_list(*args):
server, session = _connect()
srs = execute(server.SR.get_all, session)
print SR_LIST_FORMAT % {'name_label': 'SR Label',
'uuid' : 'UUID',
'physical_size': 'Size',
'type': 'Type'}
for sr in srs:
sr_struct = execute(server.SR.get_record, session, sr)
sr_struct['physical_size'] = int(sr_struct['physical_size'])/MB
print SR_LIST_FORMAT % sr_struct
if not is_long:
print VIF_LIST_FORMAT % {'name': 'Name',
'device': 'Device',
'uuid' : 'UUID',
'MAC': 'MAC'}
for vif in vifs:
vif_struct = execute(server, 'VIF.get_record', (session, vif))
print VIF_LIST_FORMAT % vif_struct
else:
for vif in vifs:
vif_struct = execute(server, 'VIF.get_record', (session, vif))
pprint(vif_struct)
def xapi_vdi_create(*args):
def xapi_console_list(args, async = False):
server, session = connect()
opts, args = parse_args('vdi-list', args, set_defaults = True)
is_long = opts and opts.long
domname = args[0]
dom_uuid = resolve_vm(server, session, domname)
consoles = execute(server, 'VM.get_consoles', (session, dom_uuid))
if not is_long:
print CONSOLE_LIST_FORMAT % {'protocol': 'Protocol',
'location': 'Location',
'uuid': 'UUID'}
for console in consoles:
console_struct = execute(server, 'console.get_record',
(session, console))
print CONSOLE_LIST_FORMAT % console_struct
else:
for console in consoles:
console_struct = execute(server, 'console.get_record',
(session, console))
pprint(console_struct)
def xapi_vdi_list(args, async = False):
opts, args = parse_args('vdi-list', args, set_defaults = True)
is_long = opts and opts.long
server, session = connect()
vdis = execute(server, 'VDI.get_all', (session,))
if not is_long:
print VDI_LIST_FORMAT % {'name_label': 'VDI Label',
'uuid' : 'UUID',
'virtual_size': 'Sectors',
'sector_size': 'Sector Size'}
for vdi in vdis:
vdi_struct = execute(server, 'VDI.get_record', (session, vdi))
print VDI_LIST_FORMAT % vdi_struct
else:
for vdi in vdis:
vdi_struct = execute(server, 'VDI.get_record', (session, vdi))
pprint(vdi_struct)
def xapi_sr_list(args, async = False):
opts, args = parse_args('sr-list', args, set_defaults = True)
is_long = opts and opts.long
server, session = connect()
srs = execute(server, 'SR.get_all', (session,))
if not is_long:
print SR_LIST_FORMAT % {'name_label': 'SR Label',
'uuid' : 'UUID',
'physical_size': 'Size (MB)',
'type': 'Type'}
for sr in srs:
sr_struct = execute(server, 'SR.get_record', (session, sr))
sr_struct['physical_size'] = int(sr_struct['physical_size'])/MB
print SR_LIST_FORMAT % sr_struct
else:
for sr in srs:
sr_struct = execute(server, 'SR.get_record', (session, sr))
pprint(sr_struct)
def xapi_sr_rename(args, async = False):
server, session = connect()
sr = execute(server, 'SR.get_by_name_label', (session, args[0]))
execute(server, 'SR.set_name_label', (session, sr[0], args[1]))
def xapi_vdi_create(args, async = False):
opts, args = parse_args('vdi-create', args)
if len(args) > 0:
@@ -396,58 +618,106 @@ def xapi_vdi_create(*args):
for opt, val in opts:
cfg[opt] = val
server, session = _connect()
srs = execute(server.SR.get_all, session)
server, session = connect()
srs = []
if cfg.get('SR'):
srs = execute(server, 'SR.get_by_name_label', (session, cfg['SR']))
else:
srs = execute(server, 'SR.get_all', (session,))
sr = srs[0]
cfg['SR'] = sr
size = (cfg['virtual_size'] * cfg['sector_size'])/MB
print 'Creating VDI of size: %dMB ..' % size,
uuid = execute(server.VDI.create, session, cfg)
print 'Done. (%s)' % uuid
uuid = execute(server, 'VDI.create', (session, cfg), async = async)
if async:
print 'Task started: %s' % uuid
else:
print 'Done. (%s)' % uuid
def xapi_vdi_delete(*args):
server, session = _connect()
def xapi_vdi_destroy(args, async = False):
server, session = connect()
if len(args) < 1:
raise OptionError('Not enough arguments')
vdi_uuid = args[0]
print 'Deleting VDI %s' % vdi_uuid
result = execute(server.VDI.destroy, session, vdi_uuid)
print 'Done.'
result = execute(server, 'VDI.destroy', (session, vdi_uuid), async = async)
if async:
print 'Task started: %s' % result
else:
print 'Done.'
def xapi_vdi_rename(*args):
server, session = _connect()
def xapi_vdi_rename(args, async = False):
server, session = connect()
if len(args) < 2:
raise OptionError('Not enough arguments')
vdi_uuid = args[0]
vdi_uuid = execute(server, 'VDI.get_by_name_label', session, args[0])
vdi_name = args[1]
print 'Renaming VDI %s to %s' % (vdi_uuid, vdi_name)
result = execute(server.VDI.set_name_label, session, vdi_uuid, vdi_name)
print 'Done.'
print 'Renaming VDI %s to %s' % (vdi_uuid[0], vdi_name)
result = execute(server, 'VDI.set_name_label',
(session, vdi_uuid[0], vdi_name), async = async)
if async:
print 'Task started: %s' % result
else:
print 'Done.'
def xapi_vtpm_create(*args):
server, session = _connect()
def xapi_vtpm_create(args, async = False):
server, session = connect()
domname = args[0]
cfg = _read_python_cfg(args[1])
vm_uuid = resolve_vm(server, session, domname)
cfg['VM'] = vm_uuid
print "Creating vTPM with cfg = %s" % cfg
vtpm_uuid = execute(server.VTPM.create, session, cfg)
vtpm_uuid = execute(server, 'VTPM.create', (session, cfg))
print "Done. (%s)" % vtpm_uuid
vtpm_id = execute(server.VTPM.get_instance, session, vtpm_uuid)
print "Has instance number '%s'" % vtpm_id
vtpm_be = execute(server.VTPM.get_backend, session, vtpm_uuid)
print "Has backend in '%s'" % vtpm_be
driver = execute(server.VTPM.get_driver, session, vtpm_uuid)
print "Has driver type '%s'" % driver
vtpm_rec = execute(server.VTPM.get_record, session, vtpm_uuid)
print "Has vtpm record '%s'" % vtpm_rec
def xapi_pif_list(args, async = False):
server, session = connect()
pif_uuids = execute(server, 'PIF.get_all', (session,))
for pif_uuid in pif_uuids:
pif = execute(server, 'PIF.get_record', (session, pif_uuid))
print pif
def xapi_debug_wait(args, async = False):
secs = 10
if len(args) > 0:
secs = int(args[0])
server, session = connect()
task_uuid = execute(server, 'debug.wait', (session, secs), async=async)
print 'Task UUID: %s' % task_uuid
def xapi_vm_stat(args, async = False):
domname = args[0]
server, session = connect()
vm_uuid = resolve_vm(server, session, domname)
vif_uuids = execute(server, 'VM.get_VIFs', (session, vm_uuid))
vbd_uuids = execute(server, 'VM.get_VBDs', (session, vm_uuid))
vcpus_utils = execute(server, 'VM.get_VCPUs_utilisation',
(session, vm_uuid))
for vcpu_num in sorted(vcpus_utils.keys()):
print 'CPU %s : %5.2f%%' % (vcpu_num, vcpus_utils[vcpu_num] * 100)
for vif_uuid in vif_uuids:
vif = execute(server, 'VIF.get_record', (session, vif_uuid))
print '%(device)s: rx: %(io_read_kbs)10.2f tx: %(io_write_kbs)10.2f' \
% vif
for vbd_uuid in vbd_uuids:
vbd = execute(server, 'VBD.get_record', (session, vbd_uuid))
print '%(device)s: rd: %(io_read_kbs)10.2f wr: %(io_write_kbs)10.2f' \
% vbd
#
# Command Line Utils
#
@@ -465,12 +735,17 @@ class XenAPICmd(cmd.Cmd):
words = shlex.split(line)
if len(words) > 0:
cmd_name = words[0].replace('-', '_')
is_async = 'async' in cmd_name
if is_async:
cmd_name = re.sub('async_', '', cmd_name)
func_name = 'xapi_%s' % cmd_name
func = globals().get(func_name)
if func:
try:
args = tuple(words[1:])
func(*args)
func(args, async = is_async)
return True
except SystemExit:
return False
@@ -506,7 +781,7 @@ class XenAPICmd(cmd.Cmd):
return line
def shell():
server, session = _connect()
server, session = connect()
x = XenAPICmd(server, session)
x.cmdloop('Xen API Prompt. Type "help" for a list of functions')
@@ -517,22 +792,70 @@ def usage(command = None, print_usage = True):
print
print 'Subcommands:'
print
sorted_commands = sorted(COMMANDS.keys())
for command in sorted_commands:
args, description = COMMANDS[command]
print '%-16s %-40s' % (command, description)
for func in sorted(globals().keys()):
if func.startswith('xapi_'):
command = func[5:].replace('_', '-')
args, description = COMMANDS.get(command, ('', ''))
print '%-16s %-40s' % (command, description)
print
else:
parse_args(command, ['-h'])
def main(args):
# poor man's optparse that doesn't abort on unrecognised opts
if len(args) < 1 or args[0] in ('-h', '--help', 'help'):
options = {}
remaining = []
arg_n = 0
while args:
arg = args.pop(0)
if arg in ('--help', '-h'):
options['help'] = True
elif arg in ('--server', '-s') and args:
options['server'] = args.pop(0)
elif arg in ('--user', '-u') and args:
options['user'] = args.pop(0)
elif arg in ('--password', '-p') and args:
options['password'] = args.pop(0)
else:
remaining.append(arg)
# abort here if these conditions are true
if options.get('help') and not remaining:
usage()
sys.exit(1)
subcmd = args[0]
subcmd_func_name = 'xapi_' + subcmd.replace('-', '_')
if options.get('help') and remaining:
usage(remaining[0])
sys.exit(1)
if not remaining:
usage()
sys.exit(1)
if options.get('server'):
# it is ugly to use a global, but it is simple
global SERVER_URI
SERVER_URI = options['server']
if options.get('user'):
global SERVER_USER
SERVER_USER = options['user']
if options.get('password'):
global SERVER_PASS
SERVER_PASS = options['password']
subcmd = remaining[0].replace('-', '_')
is_async = 'async' in subcmd
if is_async:
subcmd = re.sub('async_', '', subcmd)
subcmd_func_name = 'xapi_' + subcmd
subcmd_func = globals().get(subcmd_func_name, None)
if subcmd == 'shell':
@@ -542,14 +865,10 @@ def main(args):
usage()
sys.exit(1)
if '-h' in args[1:] or '--help' in args[1:]:
usage(subcmd)
sys.exit(1)
try:
subcmd_func(*args[1:])
subcmd_func(remaining[1:], async = is_async)
except XenAPIError, e:
print 'Error: %s' % str(e.args[1])
print 'Error: %s' % str(e.args[0])
sys.exit(2)
except OptionError, e:
print 'Error: %s' % e
+12 -1
View File
@@ -30,6 +30,13 @@ xs = Extension("xs",
libraries = libraries,
sources = [ "xen/lowlevel/xs/xs.c" ])
scf = Extension("scf",
extra_compile_args = extra_compile_args,
include_dirs = include_dirs + [ "xen/lowlevel/scf" ],
library_dirs = library_dirs,
libraries = libraries,
sources = [ "xen/lowlevel/scf/scf.c" ])
acm = Extension("acm",
extra_compile_args = extra_compile_args,
include_dirs = include_dirs + [ "xen/lowlevel/acm" ],
@@ -37,6 +44,10 @@ acm = Extension("acm",
libraries = libraries,
sources = [ "xen/lowlevel/acm/acm.c" ])
modules = [ xc, xs, acm ]
if os.uname()[0] == 'SunOS':
modules.append(scf)
setup(name = 'xen',
version = '3.0',
description = 'Xen',
@@ -56,7 +67,7 @@ setup(name = 'xen',
'xen.xm.tests'
],
ext_package = "xen.lowlevel",
ext_modules = [ xc, xs, acm ]
ext_modules = modules
)
os.chdir('logging')
+156
View File
@@ -0,0 +1,156 @@
/*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
* Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#include <Python.h>
#include <libscf.h>
#include <stdio.h>
#define XEND_FMRI "svc:/system/xen/xend:default"
#define XEND_PG "config"
static PyObject *scf_exc;
static void *
scf_exception(const char *err, const char *value)
{
int scferr = scf_error();
const char *scfstrerr = scf_strerror(scferr);
PyObject *obj = Py_BuildValue("(isss)", scferr, err, scfstrerr, value);
PyErr_SetObject(scf_exc, obj);
return (NULL);
}
static PyObject *
pyscf_get_bool(PyObject *o, PyObject *args, PyObject *kwargs)
{
static char *kwlist[] = { "name", NULL };
scf_simple_prop_t *prop;
uint8_t *val;
char *name;
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s", kwlist, &name))
return (NULL);
prop = scf_simple_prop_get(NULL, XEND_FMRI, XEND_PG, name);
if (prop == NULL)
return (scf_exception("scf_simple_prop_get() failed", name));
if ((val = scf_simple_prop_next_boolean(prop)) == NULL)
return (scf_exception("scf_simple_prop_next_boolean() failed",
name));
if (*val) {
scf_simple_prop_free(prop);
Py_INCREF(Py_True);
return (Py_True);
}
scf_simple_prop_free(prop);
Py_INCREF(Py_False);
return (Py_False);
}
static PyObject *
pyscf_get_int(PyObject *o, PyObject *args, PyObject *kwargs)
{
static char *kwlist[] = { "name", NULL };
scf_simple_prop_t *prop;
PyObject *obj;
int64_t *val;
char *name;
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s", kwlist, &name))
return (NULL);
prop = scf_simple_prop_get(NULL, XEND_FMRI, XEND_PG, name);
if (prop == NULL)
return (scf_exception("scf_simple_prop_get() failed", name));
if ((val = scf_simple_prop_next_integer(prop)) == NULL)
return (scf_exception("scf_simple_prop_next_integer() failed",
name));
obj = PyInt_FromLong((long)*val);
scf_simple_prop_free(prop);
return (obj);
}
static PyObject *
pyscf_get_string(PyObject *o, PyObject *args, PyObject *kwargs)
{
static char *kwlist[] = { "name", NULL };
scf_simple_prop_t *prop;
PyObject *obj;
char *name;
char *str;
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s", kwlist, &name))
return (NULL);
prop = scf_simple_prop_get(NULL, XEND_FMRI, XEND_PG, name);
if (prop == NULL)
return (scf_exception("scf_simple_prop_get() failed", name));
if ((str = scf_simple_prop_next_astring(prop)) == NULL) {
scf_simple_prop_free(prop);
return (scf_exception("scf_simple_prop_next_astring() failed",
name));
}
obj = PyString_FromString(str);
scf_simple_prop_free(prop);
return (obj);
}
PyDoc_STRVAR(pyscf_get_bool__doc__,
"get_bool(name) - get the value of the named boolean property");
PyDoc_STRVAR(pyscf_get_int__doc__,
"get_int(name) - get the value of the named integer property");
PyDoc_STRVAR(pyscf_get_string__doc__,
"get_string(name) - get the value of the named string property");
static struct PyMethodDef pyscf_module_methods[] = {
{ "get_bool", (PyCFunction) pyscf_get_bool,
METH_VARARGS|METH_KEYWORDS, pyscf_get_bool__doc__ },
{ "get_int", (PyCFunction) pyscf_get_int,
METH_VARARGS|METH_KEYWORDS, pyscf_get_int__doc__ },
{ "get_string", (PyCFunction) pyscf_get_string,
METH_VARARGS|METH_KEYWORDS, pyscf_get_string__doc__ },
{ NULL, NULL, 0, NULL }
};
PyMODINIT_FUNC
initscf(void)
{
PyObject *m;
m = Py_InitModule("scf", pyscf_module_methods);
scf_exc = PyErr_NewException("scf.error", NULL, NULL);
Py_INCREF(scf_exc);
PyModule_AddObject(m, "error", scf_exc);
PyModule_AddIntConstant(m, "SCF_ERROR_NOT_FOUND", SCF_ERROR_NOT_FOUND);
}
+57
View File
@@ -160,6 +160,24 @@ static PyObject *pyxc_domain_destroy(XcObject *self, PyObject *args)
return dom_op(self, args, xc_domain_destroy);
}
static PyObject *pyxc_domain_shutdown(XcObject *self, PyObject *args)
{
uint32_t dom, reason;
if (!PyArg_ParseTuple(args, "ii", &dom, &reason))
return NULL;
if (xc_domain_shutdown(self->xc_handle, dom, reason) != 0)
return pyxc_error_to_exception();
Py_INCREF(zero);
return zero;
}
static PyObject *pyxc_domain_resume(XcObject *self, PyObject *args)
{
return dom_op(self, args, xc_domain_resume);
}
static PyObject *pyxc_vcpu_setaffinity(XcObject *self,
PyObject *args,
@@ -460,6 +478,24 @@ static PyObject *pyxc_evtchn_alloc_unbound(XcObject *self,
return PyInt_FromLong(port);
}
static PyObject *pyxc_evtchn_reset(XcObject *self,
PyObject *args,
PyObject *kwds)
{
uint32_t dom;
static char *kwd_list[] = { "dom", NULL };
if ( !PyArg_ParseTupleAndKeywords(args, kwds, "i", kwd_list, &dom) )
return NULL;
if ( xc_evtchn_reset(self->xc_handle, dom) < 0 )
return pyxc_error_to_exception();
Py_INCREF(zero);
return zero;
}
static PyObject *pyxc_physdev_pci_access_modify(XcObject *self,
PyObject *args,
PyObject *kwds)
@@ -1028,6 +1064,21 @@ static PyMethodDef pyxc_methods[] = {
" dom [int]: Identifier of domain to be destroyed.\n\n"
"Returns: [int] 0 on success; -1 on error.\n" },
{ "domain_resume",
(PyCFunction)pyxc_domain_resume,
METH_VARARGS, "\n"
"Resume execution of a suspended domain.\n"
" dom [int]: Identifier of domain to be resumed.\n\n"
"Returns: [int] 0 on success; -1 on error.\n" },
{ "domain_shutdown",
(PyCFunction)pyxc_domain_shutdown,
METH_VARARGS, "\n"
"Shutdown a domain.\n"
" dom [int, 0]: Domain identifier to use.\n"
" reason [int, 0]: Reason for shutdown.\n"
"Returns: [int] 0 on success; -1 on error.\n" },
{ "vcpu_setaffinity",
(PyCFunction)pyxc_vcpu_setaffinity,
METH_VARARGS | METH_KEYWORDS, "\n"
@@ -1168,6 +1219,12 @@ static PyMethodDef pyxc_methods[] = {
" remote_dom [int]: Remote domain to accept connections from.\n\n"
"Returns: [int] Unbound event-channel port.\n" },
{ "evtchn_reset",
(PyCFunction)pyxc_evtchn_reset,
METH_VARARGS | METH_KEYWORDS, "\n"
"Reset all connections.\n"
" dom [int]: Domain to reset.\n" },
{ "physdev_pci_access_modify",
(PyCFunction)pyxc_physdev_pci_access_modify,
METH_VARARGS | METH_KEYWORDS, "\n"
+28
View File
@@ -618,6 +618,33 @@ static PyObject *xspy_introduce_domain(XsHandle *self, PyObject *args)
return none(result);
}
#define xspy_resume_domain_doc "\n" \
"Tell xenstore to clear its shutdown flag for a domain.\n" \
"This ensures that a subsequent shutdown will fire the\n" \
"appropriate watches.\n" \
" dom [int]: domain id\n" \
"\n" \
"Returns None on success.\n" \
"Raises xen.lowlevel.xs.Error on error.\n"
static PyObject *xspy_resume_domain(XsHandle *self, PyObject *args)
{
uint32_t dom;
struct xs_handle *xh = xshandle(self);
bool result = 0;
if (!xh)
return NULL;
if (!PyArg_ParseTuple(args, "i", &dom))
return NULL;
Py_BEGIN_ALLOW_THREADS
result = xs_resume_domain(xh, dom);
Py_END_ALLOW_THREADS
return none(result);
}
#define xspy_release_domain_doc "\n" \
"Tell xenstore to release its channel to a domain.\n" \
@@ -789,6 +816,7 @@ static PyMethodDef xshandle_methods[] = {
XSPY_METH(transaction_start, METH_NOARGS),
XSPY_METH(transaction_end, METH_VARARGS | METH_KEYWORDS),
XSPY_METH(introduce_domain, METH_VARARGS),
XSPY_METH(resume_domain, METH_VARARGS),
XSPY_METH(release_domain, METH_VARARGS),
XSPY_METH(close, METH_NOARGS),
XSPY_METH(get_domain_path, METH_VARARGS),
+2 -2
View File
@@ -50,8 +50,7 @@ except ImportError:
def stringify(value):
if isinstance(value, float) or \
isinstance(value, long) or \
if isinstance(value, long) or \
(isinstance(value, int) and not isinstance(value, bool)):
return str(value)
elif isinstance(value, dict):
@@ -256,6 +255,7 @@ class UnixXMLRPCRequestHandler(XMLRPCRequestHandler):
class UnixXMLRPCServer(TCPXMLRPCServer):
address_family = socket.AF_UNIX
allow_address_reuse = True
def __init__(self, addr, allowed, xenapi, logRequests = 1):
mkdir.parents(os.path.dirname(addr), stat.S_IRWXU, True)
+12 -4
View File
@@ -294,8 +294,6 @@ class HttpServer:
backlog = 5
closed = False
def __init__(self, root, interface, port=8080):
self.root = root
self.interface = interface
@@ -303,6 +301,7 @@ class HttpServer:
# ready indicates when we are ready to begin accept connections
# it should be set after a successful bind
self.ready = False
self.closed = False
def run(self):
self.bind()
@@ -317,7 +316,6 @@ class HttpServer:
def stop(self):
self.close()
def bind(self):
self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
flags = fcntl.fcntl(self.socket.fileno(), fcntl.F_GETFD)
@@ -334,9 +332,16 @@ class HttpServer:
def close(self):
self.closed = True
self.ready = False
# shutdown socket explicitly to allow reuse
try:
self.socket.shutdown(2)
except socket.error:
pass
try:
self.socket.close()
except:
except socket.error:
pass
def getServerAddr(self):
@@ -345,6 +350,9 @@ class HttpServer:
def getResource(self, req):
return self.root.getRequestResource(req)
def shutdown(self):
self.close()
class UnixHttpServer(HttpServer):
+2 -2
View File
@@ -20,7 +20,7 @@
"""
import os
import XendRoot
import XendOptions
def network(op):
@@ -30,7 +30,7 @@ def network(op):
"""
if op not in ['start', 'stop']:
raise ValueError('Invalid operation: ' + op)
script = XendRoot.instance().get_network_script()
script = XendOptions.instance().get_network_script()
if script:
script.insert(1, op)
os.spawnv(os.P_WAIT, script[0], script)
File diff suppressed because it is too large. Load diff
+5 -24
View File
@@ -12,7 +12,7 @@
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#============================================================================
# Copyright (C) 2006 XenSource Ltd.
# Copyright (C) 2006-2007 XenSource Ltd.
#============================================================================
#
@@ -24,7 +24,7 @@ XEN_API_VM_POWER_STATE = [
'Paused',
'Running',
'Suspended',
'ShuttingDown',
'Halted',
'Unknown'
]
@@ -35,20 +35,6 @@ XEN_API_VM_POWER_STATE_SUSPENDED = 3
XEN_API_VM_POWER_STATE_SHUTTINGDOWN = 4
XEN_API_VM_POWER_STATE_UNKNOWN = 5
XEN_API_CPU_FEATURE = [
'FPU', 'VME', 'DE', 'PSE', 'TSC', 'MSR', 'PAE'
'MCE', 'CX8', 'APIC', 'SEP', 'MTRR', 'PGE', 'MCA',
'CMOV', 'PAT', 'PSE36', 'PN', 'CLFLSH', 'DTES',
'ACPI', 'MMX', 'FXCR', 'XMM', 'XMM2', 'SELFSNOOP',
'HT', 'ACC', 'IA64', 'SYSCALL', 'MP', 'NX', 'MMXEXT',
'LM', '3DNOWEXT', '3DNOW', 'RECOVERY', 'LONGRUN',
'LRTI', 'CXMMX', 'K6_MTRR', 'CYRIX_ARR', 'CENTAUR_MCR',
'K8', 'K7', 'P3', 'P4', 'CONSTANT_TSC', 'FXSAVE_LEAK',
'XMM3', 'MWAIT', 'DSCPL', 'EST', 'TM2', 'CID', 'CX16',
'XTPR', 'XSTORE', 'XSTORE_EN', 'XCRYPT', 'XCRYPT_EN',
'LAHF_LM', 'CMP_LEGACY'
]
XEN_API_ON_NORMAL_EXIT = [
'destroy',
'restart',
@@ -63,13 +49,8 @@ XEN_API_ON_CRASH_BEHAVIOUR = [
'rename_restart'
]
XEN_API_BOOT_TYPE = [
'bios',
'grub',
'kernel_external',
'kernel_internal'
]
XEN_API_VBD_MODE = ['RO', 'RW']
XEN_API_VDI_TYPE = ['system', 'user', 'ephemeral']
XEN_API_DRIVER_TYPE = ['ioemu', 'paravirtualised']
XEN_API_VBD_TYPE = ['CD', 'Disk']
XEN_API_TASK_STATUS_TYPE = ['pending', 'success', 'failure']
XEN_API_CONSOLE_PROTOCOL = ['vt100', 'rfb', 'rdp']
+4 -5
View File
@@ -21,11 +21,6 @@ from xen.xend import uuid
from xen.xend.XendError import *
from xen.xend.XendLogging import log
try:
import PAM
except ImportError:
log.warn("python-pam is required for XenAPI support.")
class XendAuthSessions:
"""Keeps track of Xen API Login Sessions using PAM.
@@ -80,7 +75,11 @@ class XendAuthSessions:
"""
pam_auth = None
try:
import PAM
pam_auth = PAM.pam()
except ImportError:
log.warn("python-pam is required for XenAPI support.")
return False
except NameError:
# if PAM doesn't exist, let's ignore it
return False
+97 -10
View File
@@ -12,7 +12,7 @@
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
import os, select, errno, stat
import os, select, errno, stat, signal
import random
import shlex
from xen.xend import sxp
@@ -21,12 +21,15 @@ from xen.util import mkdir
from XendLogging import log
from XendError import VmError
def bootloader(blexec, disk, quiet = False, blargs = '', kernel = '',
import pty, ptsname, termios, fcntl
def bootloader(blexec, disk, dom, quiet = False, blargs = '', kernel = '',
ramdisk = '', kernel_args = ''):
"""Run the boot loader executable on the given disk and return a
config image.
@param blexec Binary to use as the boot loader
@param disk Disk to run the boot loader on.
@param dom DomainInfo representing the domain being booted.
@param quiet Run in non-interactive mode, just booting the default.
@param blargs Arguments to pass to the bootloader."""
@@ -50,9 +53,41 @@ def bootloader(blexec, disk, quiet = False, blargs = '', kernel = '',
raise
break
child = os.fork()
# We need to present the bootloader's tty as a pty slave that xenconsole
# can access. Since the bootloader itself needs a pty slave,
# we end up with a connection like this:
#
# xenconsole -- (slave pty1 master) <-> (master pty2 slave) -- bootloader
#
# where we copy characters between the two master fds, as well as
# listening on the bootloader's fifo for the results.
# Termios runes for very raw access to the pty master fds.
attr = [ 0, 0, termios.CS8 | termios.CREAD | termios.CLOCAL,
0, 0, 0, [0] * 32 ]
(m1, s1) = pty.openpty()
termios.tcsetattr(m1, termios.TCSANOW, attr)
fcntl.fcntl(m1, fcntl.F_SETFL, os.O_NDELAY);
os.close(s1)
slavename = ptsname.ptsname(m1)
dom.storeDom("console/tty", slavename)
# Release the domain lock here, because we definitely don't want
# a stuck bootloader to deny service to other xend clients.
from xen.xend import XendDomain
domains = XendDomain.instance()
domains.domains_lock.release()
(child, m2) = pty.fork()
if (not child):
args = [ blexec ]
if kernel:
args.append("--kernel=%s" % kernel)
if ramdisk:
args.append("--ramdisk=%s" % ramdisk)
if kernel_args:
args.append("--args=%s" % kernel_args)
if quiet:
args.append("-q")
args.append("--output=%s" % fifo)
@@ -62,12 +97,19 @@ def bootloader(blexec, disk, quiet = False, blargs = '', kernel = '',
try:
log.debug("Launching bootloader as %s." % str(args))
os.execvp(args[0], args)
env = os.environ.copy()
env['TERM'] = 'vt100'
os.execvpe(args[0], args, env)
except OSError, e:
print e
pass
os._exit(1)
# record that this domain is bootloading
dom.bootloader_pid = child
termios.tcsetattr(m2, termios.TCSANOW, attr)
fcntl.fcntl(m2, fcntl.F_SETFL, os.O_NDELAY);
while True:
try:
r = os.open(fifo, os.O_RDONLY)
@@ -76,17 +118,53 @@ def bootloader(blexec, disk, quiet = False, blargs = '', kernel = '',
continue
break
ret = ""
inbuf=""; outbuf="";
while True:
select.select([r], [], [])
s = os.read(r, 1024)
ret = ret + s
if len(s) == 0:
break
sel = select.select([r, m1, m2], [m1, m2], [])
try:
if m1 in sel[0]:
s = os.read(m1, 1)
inbuf += s
if m2 in sel[1] and len(inbuf) != 0:
os.write(m2, inbuf[0])
inbuf = inbuf[1:]
except OSError, e:
if e.errno == errno.EIO:
pass
try:
if m2 in sel[0]:
s = os.read(m2, 1)
outbuf += s
if m1 in sel[1] and len(outbuf) != 0:
os.write(m1, outbuf[0])
outbuf = outbuf[1:]
except OSError, e:
if e.errno == errno.EIO:
pass
if r in sel[0]:
s = os.read(r, 1)
ret = ret + s
if len(s) == 0:
break
del inbuf
del outbuf
os.waitpid(child, 0)
os.close(r)
os.close(m2)
os.close(m1)
os.unlink(fifo)
# Re-acquire the lock to cover the changes we're about to make
# when we return to domain creation.
domains.domains_lock.acquire()
if dom.bootloader_pid is None:
msg = "Domain was died while the bootloader was running."
log.error(msg)
raise VmError, msg
dom.bootloader_pid = None
if len(ret) == 0:
msg = "Boot loader didn't return any data!"
log.error(msg)
@@ -97,3 +175,12 @@ def bootloader(blexec, disk, quiet = False, blargs = '', kernel = '',
pin.input_eof()
blcfg = pin.val
return blcfg
def bootloader_tidy(dom):
if hasattr(dom, "bootloader_pid") and dom.bootloader_pid is not None:
pid = dom.bootloader_pid
dom.bootloader_pid = None
os.kill(pid, signal.SIGKILL)
+101 -8
View File
@@ -22,11 +22,14 @@ from xen.xend.XendConfig import XendConfig
from xen.xend.XendConstants import *
SIGNATURE = "LinuxGuestRecord"
QEMU_SIGNATURE = "QemuDeviceModelRecord"
dm_batch = 512
XC_SAVE = "xc_save"
XC_RESTORE = "xc_restore"
sizeof_int = calcsize("i")
sizeof_unsigned_int = calcsize("I")
sizeof_unsigned_long = calcsize("L")
@@ -69,6 +72,11 @@ def save(fd, dominfo, network, live, dst):
"could not write guest state file: config len")
write_exact(fd, config, "could not write guest state file: config")
image_cfg = dominfo.info.get('image', {})
hvm = image_cfg.has_key('hvm')
if hvm:
log.info("save hvm domain")
# xc_save takes three customization parameters: maxit, max_f, and
# flags the last controls whether or not save is 'live', while the
# first two further customize behaviour when 'live' save is
@@ -76,7 +84,7 @@ def save(fd, dominfo, network, live, dst):
# libxenguest; see the comments and/or code in xc_linux_save() for
# more information.
cmd = [xen.util.auxbin.pathTo(XC_SAVE), str(fd),
str(dominfo.getDomid()), "0", "0", str(int(live)) ]
str(dominfo.getDomid()), "0", "0", str(int(live) | (int(hvm) << 2)) ]
log.debug("[xc_save]: %s", string.join(cmd))
def saveInputHandler(line, tochild):
@@ -90,13 +98,32 @@ def save(fd, dominfo, network, live, dst):
log.info("Domain %d suspended.", dominfo.getDomid())
dominfo.migrateDevices(network, dst, DEV_MIGRATE_STEP3,
domain_name)
#send signal to device model for save
if hvm:
log.info("release_devices for hvm domain")
dominfo._releaseDevices(True)
tochild.write("done\n")
tochild.flush()
log.debug('Written done')
forkHelper(cmd, fd, saveInputHandler, False)
# put qemu device model state
if hvm:
write_exact(fd, QEMU_SIGNATURE, "could not write qemu signature")
qemu_fd = os.open("/tmp/xen.qemu-dm.%d" % dominfo.getDomid(), os.O_RDONLY)
while True:
buf = os.read(qemu_fd, dm_batch)
if len(buf):
write_exact(fd, buf, "could not write device model state")
else:
break
os.close(qemu_fd)
os.remove("/tmp/xen.qemu-dm.%d" % dominfo.getDomid())
dominfo.destroyDomain()
dominfo.testDeviceComplete()
try:
dominfo.setName(domain_name)
except VmError:
@@ -109,11 +136,31 @@ def save(fd, dominfo, network, live, dst):
except Exception, exn:
log.exception("Save failed on domain %s (%s).", domain_name,
dominfo.getDomid())
dominfo._releaseDevices()
dominfo.testDeviceComplete()
dominfo.testvifsComplete()
log.debug("XendCheckpoint.save: devices released")
dominfo._resetChannels()
dominfo._removeDom('control/shutdown')
dominfo._removeDom('device-misc/vif/nextDeviceID')
dominfo._createChannels()
dominfo._introduceDomain()
dominfo._storeDomDetails()
dominfo._createDevices()
log.debug("XendCheckpoint.save: devices created")
dominfo.resumeDomain()
log.debug("XendCheckpoint.save: resumeDomain")
try:
dominfo.setName(domain_name)
except:
log.exception("Failed to reset the migrating domain's name")
raise Exception, exn
def restore(xd, fd, dominfo = None, paused = False):
@@ -147,19 +194,45 @@ def restore(xd, fd, dominfo = None, paused = False):
assert store_port
assert console_port
nr_pfns = (dominfo.getMemoryTarget() + 3) / 4
# if hvm, pass mem size to calculate the store_mfn
image_cfg = dominfo.info.get('image', {})
is_hvm = image_cfg.has_key('hvm')
if is_hvm:
hvm = dominfo.info['memory_static_min']
apic = dominfo.info['image']['hvm'].get('apic', 0)
pae = dominfo.info['image']['hvm'].get('pae', 0)
log.info("restore hvm domain %d, mem=%d, apic=%d, pae=%d",
dominfo.domid, hvm, apic, pae)
else:
hvm = 0
apic = 0
pae = 0
try:
l = read_exact(fd, sizeof_unsigned_long,
"not a valid guest state file: pfn count read")
nr_pfns = unpack("L", l)[0] # native sizeof long
if nr_pfns > 16*1024*1024: # XXX
max_pfn = unpack("L", l)[0] # native sizeof long
if max_pfn > 16*1024*1024: # XXX
raise XendError(
"not a valid guest state file: pfn count out of range")
balloon.free(xc.pages_to_kib(nr_pfns))
shadow = dominfo.info['shadow_memory']
log.debug("restore:shadow=0x%x, _static_max=0x%x, _static_min=0x%x, "
"nr_pfns=0x%x.", dominfo.info['shadow_memory'],
dominfo.info['memory_static_max'],
dominfo.info['memory_static_min'], nr_pfns)
balloon.free(xc.pages_to_kib(nr_pfns) + shadow * 1024)
shadow_cur = xc.shadow_mem_control(dominfo.getDomid(), shadow)
dominfo.info['shadow_memory'] = shadow_cur
cmd = map(str, [xen.util.auxbin.pathTo(XC_RESTORE),
fd, dominfo.getDomid(), nr_pfns,
store_port, console_port])
fd, dominfo.getDomid(), max_pfn,
store_port, console_port, hvm, pae, apic])
log.debug("[xc_restore]: %s", string.join(cmd))
handler = RestoreInputHandler()
@@ -169,10 +242,30 @@ def restore(xd, fd, dominfo = None, paused = False):
if handler.store_mfn is None or handler.console_mfn is None:
raise XendError('Could not read store/console MFN')
os.read(fd, 1) # Wait for source to close connection
dominfo.waitForDevices() # Wait for backends to set up
if not paused:
dominfo.unpause()
# get qemu state and create a tmp file for dm restore
if is_hvm:
qemu_signature = read_exact(fd, len(QEMU_SIGNATURE),
"invalid device model signature read")
if qemu_signature != QEMU_SIGNATURE:
raise XendError("not a valid device model state: found '%s'" %
qemu_signature)
qemu_fd = os.open("/tmp/xen.qemu-dm.%d" % dominfo.getDomid(),
os.O_WRONLY | os.O_CREAT | os.O_TRUNC)
while True:
buf = os.read(fd, dm_batch)
if len(buf):
write_exact(qemu_fd, buf,
"could not write dm state to tmp file")
else:
break
os.close(qemu_fd)
os.read(fd, 1) # Wait for source to close connection
dominfo.completeRestore(handler.store_mfn, handler.console_mfn)
+350 -114
View File
@@ -28,7 +28,7 @@ from xen.xend.PrettyPrint import prettyprintstring
from xen.xend.XendConstants import DOM_STATE_HALTED
log = logging.getLogger("xend.XendConfig")
log.setLevel(logging.WARN)
log.setLevel(logging.DEBUG)
"""
@@ -78,6 +78,25 @@ def scrub_password(data):
else:
return data
#
# CPU fields:
#
# vcpus_number -- the maximum number of vcpus that this domain may ever have.
# aka XendDomainInfo.getVCpuCount().
# vcpus -- the legacy configuration name for above.
# max_vcpu_id -- vcpus_number - 1. This is given to us by Xen.
#
# cpus -- the list of pCPUs available to each vCPU.
#
# vcpu_avail: a bitmap telling the guest domain whether it may use each of
# its VCPUs. This is translated to
# <dompath>/cpu/<id>/availability = {online,offline} for use
# by the guest domain.
# online_vpcus -- the number of VCPUs currently up, as reported by Xen. This
# is changed by changing vcpu_avail, and waiting for the
# domain to respond.
#
# Mapping from XendConfig configuration keys to the old
# legacy configuration keys that map directly.
@@ -106,8 +125,7 @@ XENAPI_HVM_CFG = {
'platform_std_vga': 'stdvga',
'platform_serial' : 'serial',
'platform_localtime': 'localtime',
'platform_enable_audio': 'soundhw',
'platform_keymap' : 'keymap',
'platform_keymap' : 'keymap'
}
# List of XendConfig configuration keys that have no direct equivalent
@@ -126,25 +144,21 @@ XENAPI_CFG_TYPES = {
'memory_dynamic_min': int,
'memory_dynamic_max': int,
'memory_actual': int,
'cpus': list,
'vcpus_policy': str,
'vcpus_params': str,
'vcpus_params': dict,
'vcpus_number': int,
'vcpus_features_required': list,
'vcpus_features_can_use': list,
'vcpus_features_force_on': list,
'vcpus_features_force_off': list,
'actions_after_shutdown': str,
'actions_after_reboot': str,
'actions_after_suspend': str,
'actions_after_crash': str,
'tpm_instance': int,
'tpm_backend': int,
'PV_bootloader': str,
'PV_kernel': str,
'PV_ramdisk': str,
'PV_args': str,
'PV_bootloader_args': str,
'HVM_boot': str,
'HVM_boot_policy': str,
'HVM_boot_params': dict,
'platform_std_vga': bool0,
'platform_serial': str,
'platform_localtime': bool0,
@@ -184,7 +198,7 @@ LEGACY_CFG_TYPES = {
'uuid': str,
'name': str,
'vcpus': int,
'vcpu_avail': int,
'vcpu_avail': long,
'memory': int,
'shadow_memory': int,
'maxmem': int,
@@ -231,7 +245,8 @@ LEGACY_IMAGE_CFG = [
('sdl', int),
('vncdisplay', int),
('vncunused', int),
('vncpasswd', str),
('vncpasswd', str),
('vnclisten', str),
]
LEGACY_IMAGE_HVM_CFG = [
@@ -248,17 +263,19 @@ LEGACY_IMAGE_HVM_DEVICES_CFG = [
('boot', str),
('fda', str),
('fdb', str),
('isa', str),
('isa', int),
('keymap', str),
('localtime', str),
('localtime', int),
('serial', str),
('stdvga', int),
('soundhw', str),
('usb', str),
('usb', int),
('usbdevice', str),
('vcpus', int),
]
LEGACY_DM = '/usr/lib/xen/bin/qemu-dm'
##
## Config Choices
##
@@ -326,7 +343,6 @@ class XendConfig(dict):
def _defaults(self):
defaults = {
'uuid': uuid.createString(),
'name_label': 'Domain-Unnamed',
'actions_after_shutdown': 'destroy',
'actions_after_reboot': 'restart',
@@ -338,7 +354,8 @@ class XendConfig(dict):
'PV_ramdisk': '',
'PV_args': '',
'PV_bootloader_args': '',
'HVM_boot': '',
'HVM_boot_policy': '',
'HVM_boot_params': {},
'memory_static_min': 0,
'memory_dynamic_min': 0,
'shadow_memory': 0,
@@ -354,16 +371,14 @@ class XendConfig(dict):
'cpu_weight': 256,
'cpu_cap': 0,
'vcpus_number': 1,
'online_vcpus': 1,
'max_vcpu_id': 0,
'vcpu_avail': 1,
'vcpus_params': {},
'console_refs': [],
'vif_refs': [],
'vbd_refs': [],
'vtpm_refs': [],
'other_config': {},
}
defaults['name_label'] = 'Domain-' + defaults['uuid']
return defaults
def _memory_sanity_check(self):
@@ -388,23 +403,31 @@ class XendConfig(dict):
event)
def _vcpus_sanity_check(self):
if self.get('vcpus_number') != None:
if 'vcpus_number' in self and 'vcpu_avail' not in self:
self['vcpu_avail'] = (1 << self['vcpus_number']) - 1
def _uuid_sanity_check(self):
"""Make sure UUID is in proper string format with hyphens."""
self['uuid'] = uuid.toString(uuid.fromString(self['uuid']))
if 'uuid' not in self or not self['uuid']:
self['uuid'] = uuid.createString()
else:
self['uuid'] = uuid.toString(uuid.fromString(self['uuid']))
def _name_sanity_check(self):
if 'name_label' not in self:
self['name_label'] = 'Domain-' + self['uuid']
def validate(self):
self._uuid_sanity_check()
self._name_sanity_check()
self._memory_sanity_check()
self._actions_sanity_check()
self._vcpus_sanity_check()
self._uuid_sanity_check()
def _dominfo_to_xapi(self, dominfo):
self['domid'] = dominfo['domid']
self['online_vcpus'] = dominfo['online_vcpus']
self['max_vcpu_id'] = dominfo['max_vcpu_id']
self['vcpus_number'] = dominfo['max_vcpu_id'] + 1
self['memory_dynamic_min'] = (dominfo['mem_kb'] + 1023)/1024
self['memory_dynamic_max'] = (dominfo['maxmem_kb'] + 1023)/1024
self['cpu_time'] = dominfo['cpu_time']/1e9
@@ -475,6 +498,12 @@ class XendConfig(dict):
log.warn("Unable to parse key %s: %s: %s" %
(key, str(val), e))
# Compatibility hack -- can go soon.
boot_order = sxp.child_value(sxp_cfg, 'HVM_boot')
if boot_order:
cfg['HVM_boot_policy'] = 'BIOS order'
cfg['HVM_boot_params'] = { 'order' : boot_order }
# Parsing the device SXP's. In most cases, the SXP looks
# like this:
#
@@ -508,8 +537,12 @@ class XendConfig(dict):
pci_devs = []
for pci_dev in sxp.children(config, 'dev'):
pci_dev_info = {}
for opt, val in pci_dev[1:]:
pci_dev_info[opt] = val
for opt_val in pci_dev[1:]:
try:
opt, val = opt_val
pci_dev_info[opt] = val
except TypeError:
pass
pci_devs.append(pci_dev_info)
cfg['devices'][pci_devs_uuid] = (dev_type,
@@ -551,7 +584,7 @@ class XendConfig(dict):
# "0-3,^1" -> [0,2,3]
# "0-3,^1,1" -> [0,1,2,3]
try:
if 'cpus' in cfg:
if 'cpus' in cfg and type(cfg['cpus']) != list:
cpus = []
for c in cfg['cpus'].split(','):
if c.find('-') != -1:
@@ -572,7 +605,6 @@ class XendConfig(dict):
if 'security' in cfg and isinstance(cfg['security'], str):
cfg['security'] = sxp.from_string(cfg['security'])
# TODO: get states
old_state = sxp.child_value(sxp_cfg, 'state')
if old_state:
for i in range(len(CONFIG_OLD_DOM_STATES)):
@@ -632,24 +664,35 @@ class XendConfig(dict):
self['memory_dynamic_max'] = self['memory_static_max']
self['memory_dynamic_min'] = self['memory_static_min']
# make sure max_vcpu_id is set correctly
self['max_vcpu_id'] = self['vcpus_number'] - 1
# set device references in the configuration
self['devices'] = cfg.get('devices', {})
self['console_refs'] = []
self['vif_refs'] = []
self['vbd_refs'] = []
self['vtpm_refs'] = []
for dev_uuid, (dev_type, dev_info) in self['devices'].items():
if dev_type == 'vif':
self['vif_refs'].append(dev_uuid)
elif dev_type in ('vbd','tap'):
self['vbd_refs'].append(dev_uuid)
elif dev_type in ('vtpm',):
self['vtpm_refs'].append(dev_uuid)
self['console_refs'] = cfg.get('console_refs', [])
self['vif_refs'] = cfg.get('vif_refs', [])
self['vbd_refs'] = cfg.get('vbd_refs', [])
self['vtpm_refs'] = cfg.get('vtpm_refs', [])
# coalesce hvm vnc frame buffer with vfb config
if self['image']['type'] == 'hvm' and self['image'].get('vnc', 0):
# add vfb device if it isn't there already
has_rfb = False
for console_uuid in self['console_refs']:
if self['devices'][console_uuid][1].get('protocol') == 'rfb':
has_rfb = True
break
if self['devices'][console_uuid][0] == 'vfb':
has_rfb = True
break
if not has_rfb:
dev_config = ['vfb']
# copy VNC related params from image config to vfb dev conf
for key in ['vncpasswd', 'vncunused', 'vncdisplay',
'vnclisten']:
if key in self['image']:
dev_config.append([key, self['image'][key]])
self.device_add('vfb', cfg_sxp = dev_config)
def _sxp_to_xapi_unsupported(self, sxp_cfg):
"""Read in an SXP configuration object and populate
@@ -692,6 +735,7 @@ class XendConfig(dict):
val = sxp.child_value(image_sxp, imgkey, None)
if val != None:
self[apikey] = val
self._hvm_boot_params_from_sxp(image_sxp)
# extract backend value
@@ -716,13 +760,11 @@ class XendConfig(dict):
_set_cfg_if_exists('on_xend_stop')
_set_cfg_if_exists('on_xend_start')
_set_cfg_if_exists('vcpu_avail')
_set_cfg_if_exists('max_vcpu_id') # needed for vcpuDomDetails
_set_cfg_if_exists('cpu_weight')
_set_cfg_if_exists('cpu_cap')
# Parse and store runtime configuration
_set_cfg_if_exists('start_time')
_set_cfg_if_exists('online_vcpus')
_set_cfg_if_exists('cpu_time')
_set_cfg_if_exists('shutdown_reason')
_set_cfg_if_exists('up_time')
@@ -738,13 +780,22 @@ class XendConfig(dict):
if 'image' in xapi_dict:
self['image'].update(xapi_dict['image'])
else:
hvm = self['HVM_boot'] != ''
hvm = self['HVM_boot_policy'] != ''
self['image']['type'] = hvm and 'hvm' or 'linux'
if hvm:
self['image']['hvm'] = {}
self['image']['hvm'] = {'devices': {}}
for xapi, cfgapi in XENAPI_HVM_CFG.items():
self['image']['hvm'][cfgapi] = self[xapi]
if xapi in self:
self['image']['hvm']['devices'][cfgapi] = self[xapi]
# currently unsupported options
self['image']['hvm']['device_model'] = LEGACY_DM
self['image']['vnc'] = 0
self['image']['hvm']['pae'] = 1
if self['platform_enable_audio']:
self['image']['hvm']['devices']['soundhw'] = 'sb16'
def _get_old_state_string(self):
"""Returns the old xm state string.
@@ -790,8 +841,6 @@ class XendConfig(dict):
else:
self[key] = val
self.validate()
def to_sxp(self, domain = None, ignore_devices = False, ignore = [],
legacy_only = True):
""" Get SXP representation of this config object.
@@ -815,9 +864,13 @@ class XendConfig(dict):
sxpr.append(['domid', domain.getDomid()])
if not legacy_only:
for name in XENAPI_CFG_TYPES.keys():
for name, typ in XENAPI_CFG_TYPES.items():
if name in self and self[name] not in (None, []):
sxpr.append([name, str(self[name])])
if typ == dict:
s = self[name].items()
else:
s = str(self[name])
sxpr.append([name, s])
for xenapi, legacy in XENAPI_CFG_TO_LEGACY_CFG.items():
if self.has_key(xenapi) and self[xenapi] not in (None, []):
@@ -855,14 +908,23 @@ class XendConfig(dict):
for cls in XendDevices.valid_devices():
found = False
# figure if there is a device that is running
if domain:
# figure if there is a dev controller is valid and running
if domain and domain.getDomid() != None:
try:
controller = domain.getDeviceController(cls)
configs = controller.configurations()
for config in configs:
if sxp.name(config) in ('vbd', 'tap'):
# The bootable flag is never written to the
# store as part of the device config.
dev_uuid = sxp.child_value(config, 'uuid')
dev_type, dev_cfg = self['devices'][dev_uuid]
is_bootable = dev_cfg.get('bootable', 0)
config.append(['bootable', int(is_bootable)])
sxpr.append(['device', config])
found = True
found = True
except:
log.exception("dumping sxp from device controllers")
pass
@@ -900,8 +962,7 @@ class XendConfig(dict):
if target == None:
target = self
if dev_type not in XendDevices.valid_devices() and \
dev_type not in XendDevices.pseudo_devices():
if dev_type not in XendDevices.valid_devices():
raise XendConfigError("XendConfig: %s not a valid device type" %
dev_type)
@@ -909,10 +970,10 @@ class XendConfig(dict):
raise XendConfigError("XendConfig: device_add requires some "
"config.")
if cfg_sxp:
log.debug("XendConfig.device_add: %s" % str(cfg_sxp))
if cfg_xenapi:
log.debug("XendConfig.device_add: %s" % str(cfg_xenapi))
#if cfg_sxp:
# log.debug("XendConfig.device_add: %s" % str(cfg_sxp))
#if cfg_xenapi:
# log.debug("XendConfig.device_add: %s" % str(cfg_xenapi))
if cfg_sxp:
if sxp.child0(cfg_sxp) == 'device':
@@ -923,20 +984,24 @@ class XendConfig(dict):
dev_type = sxp.name(config)
dev_info = {}
try:
for opt, val in config[1:]:
for opt_val in config[1:]:
try:
opt, val = opt_val
dev_info[opt] = val
except ValueError:
pass # SXP has no options for this device
except (TypeError, ValueError): # unpack error
pass
if dev_type == 'vbd':
dev_info['bootable'] = 0
if dev_info.get('dev', '').startswith('ioemu:'):
dev_info['driver'] = 'ioemu'
else:
dev_info['driver'] = 'paravirtualised'
# create uuid if it doesn't exist
dev_uuid = dev_info.get('uuid', uuid.createString())
dev_uuid = dev_info.get('uuid', None)
if not dev_uuid:
dev_uuid = uuid.createString()
dev_info['uuid'] = dev_uuid
# store dev references by uuid for certain device types
@@ -946,17 +1011,53 @@ class XendConfig(dict):
if param not in target:
target[param] = []
if dev_uuid not in target[param]:
if dev_type == 'vbd' and not target[param]:
# Compat hack -- this is the first disk, so mark it
# bootable.
dev_info['bootable'] = 1
target[param].append(dev_uuid)
elif dev_type in ('tap',):
elif dev_type == 'tap':
if 'vbd_refs' not in target:
target['vbd_refs'] = []
if dev_uuid not in target['vbd_refs']:
if not target['vbd_refs']:
# Compat hack -- this is the first disk, so mark it
# bootable.
dev_info['bootable'] = 1
target['vbd_refs'].append(dev_uuid)
elif dev_type == 'vfb':
# Populate other config with aux data that is associated
# with vfb
other_config = {}
for key in ['vncunused', 'vncdisplay', 'vnclisten',
'vncpasswd', 'type', 'display', 'xauthority',
'keymap']:
if key in dev_info:
other_config[key] = dev_info[key]
target['devices'][dev_uuid][1]['other_config'] = other_config
if 'console_refs' not in target:
target['console_refs'] = []
# Treat VFB devices as console devices so they are found
# through Xen API
if dev_uuid not in target['console_refs']:
target['console_refs'].append(dev_uuid)
elif dev_type == 'console':
if 'console_refs' not in target:
target['console_refs'] = []
if dev_uuid not in target['console_refs']:
target['console_refs'].append(dev_uuid)
return dev_uuid
if cfg_xenapi:
dev_info = {}
dev_info = {}
dev_uuid = ''
if dev_type == 'vif':
if cfg_xenapi.get('MAC'): # don't add if blank
dev_info['mac'] = cfg_xenapi.get('MAC')
@@ -967,22 +1068,28 @@ class XendConfig(dict):
# dev_info['vifname'] = cfg_xenapi.get('device')
if cfg_xenapi.get('type'):
dev_info['type'] = cfg_xenapi.get('type')
if cfg_xenapi.get('name'):
dev_info['name'] = cfg_xenapi.get('name')
dev_uuid = cfg_xenapi.get('uuid', uuid.createString())
dev_uuid = cfg_xenapi.get('uuid', None)
if not dev_uuid:
dev_uuid = uuid.createString()
dev_info['uuid'] = dev_uuid
self['devices'][dev_uuid] = (dev_type, dev_info)
self['vif_refs'].append(dev_uuid)
return dev_uuid
target['devices'][dev_uuid] = (dev_type, dev_info)
target['vif_refs'].append(dev_uuid)
elif dev_type in ('vbd', 'tap'):
if dev_type == 'vbd':
dev_info['uname'] = cfg_xenapi.get('image', '')
dev_info['dev'] = '%s:disk' % cfg_xenapi.get('device')
elif dev_type == 'tap':
dev_info['uname'] = 'tap:qcow:%s' % cfg_xenapi.get('image')
dev_info['dev'] = '%s:disk' % cfg_xenapi.get('device')
dev_info['type'] = cfg_xenapi.get('type', 'Disk')
if dev_info['type'] == 'CD':
old_vbd_type = 'cdrom'
else:
old_vbd_type = 'disk'
dev_info['driver'] = cfg_xenapi.get('driver')
dev_info['uname'] = cfg_xenapi.get('image', '')
dev_info['dev'] = '%s:%s' % (cfg_xenapi.get('device'),
old_vbd_type)
dev_info['bootable'] = int(cfg_xenapi.get('bootable', 0))
dev_info['driver'] = cfg_xenapi.get('driver', '')
dev_info['VDI'] = cfg_xenapi.get('VDI', '')
if cfg_xenapi.get('mode') == 'RW':
@@ -990,42 +1097,137 @@ class XendConfig(dict):
else:
dev_info['mode'] = 'r'
dev_uuid = cfg_xenapi.get('uuid', uuid.createString())
dev_uuid = cfg_xenapi.get('uuid', None)
if not dev_uuid:
dev_uuid = uuid.createString()
dev_info['uuid'] = dev_uuid
self['devices'][dev_uuid] = (dev_type, dev_info)
self['vbd_refs'].append(dev_uuid)
return dev_uuid
target['devices'][dev_uuid] = (dev_type, dev_info)
target['vbd_refs'].append(dev_uuid)
elif dev_type in ('vtpm'):
elif dev_type == 'vtpm':
if cfg_xenapi.get('type'):
dev_info['type'] = cfg_xenapi.get('type')
dev_uuid = cfg_xenapi.get('uuid', uuid.createString())
dev_uuid = cfg_xenapi.get('uuid', None)
if not dev_uuid:
dev_uuid = uuid.createString()
dev_info['uuid'] = dev_uuid
self['devices'][dev_uuid] = (dev_type, dev_info)
self['vtpm_refs'].append(dev_uuid)
return dev_uuid
target['devices'][dev_uuid] = (dev_type, dev_info)
target['vtpm_refs'].append(dev_uuid)
elif dev_type == 'console':
dev_uuid = cfg_xenapi.get('uuid', None)
if not dev_uuid:
dev_uuid = uuid.createString()
dev_info['uuid'] = dev_uuid
dev_info['protocol'] = cfg_xenapi.get('protocol', 'rfb')
dev_info['other_config'] = cfg_xenapi.get('other_config', {})
if dev_info['protocol'] == 'rfb':
# collapse other config into devinfo for things
# such as vncpasswd, vncunused, etc.
dev_info.update(cfg_xenapi.get('other_config', {}))
dev_info['type'] = 'vnc'
target['devices'][dev_uuid] = ('vfb', dev_info)
target['console_refs'].append(dev_uuid)
# Finally, if we are a pvfb, we need to make a vkbd
# as well that is not really exposed to Xen API
vkbd_uuid = uuid.createString()
target['devices'][vkbd_uuid] = ('vkbd', {})
elif dev_info['protocol'] == 'vt100':
# if someone tries to create a VT100 console
# via the Xen API, we'll have to ignore it
# because we create one automatically in
# XendDomainInfo._update_consoles
raise XendConfigError('Creating vt100 consoles via '
'Xen API is unsupported')
return dev_uuid
# no valid device to add
return ''
def device_update(self, dev_uuid, cfg_sxp):
def console_add(self, protocol, location, other_config = {}):
dev_uuid = uuid.createString()
if protocol == 'vt100':
dev_info = {
'uuid': dev_uuid,
'protocol': protocol,
'location': location,
'other_config': other_config,
}
if 'devices' not in self:
self['devices'] = {}
self['devices'][dev_uuid] = ('console', dev_info)
self['console_refs'].append(dev_uuid)
return dev_info
return {}
def console_update(self, console_uuid, key, value):
for dev_uuid, (dev_type, dev_info) in self['devices'].items():
if dev_uuid == console_uuid:
dev_info[key] = value
break
def console_get_all(self, protocol):
if protocol == 'vt100':
consoles = [dinfo for dtype, dinfo in self['devices'].values()
if dtype == 'console']
return [c for c in consoles if c.get('protocol') == protocol]
elif protocol == 'rfb':
vfbs = [dinfo for dtype, dinfo in self['devices'].values()
if dtype == 'vfb']
# move all non-console key values to other_config before
# returning console config
valid_keys = ['uuid', 'location']
for vfb in vfbs:
other_config = {}
for key, val in vfb.items():
if key not in valid_keys:
other_config[key] = vfb[key]
del vfb[key]
vfb['other_config'] = other_config
vfb['protocol'] = 'rfb'
return vfbs
else:
return []
def device_update(self, dev_uuid, cfg_sxp = [], cfg_xenapi = {}):
"""Update an existing device with the new configuration.
@rtype: boolean
@return: Returns True if succesfully found and updated a device conf
"""
if dev_uuid in self['devices']:
config = sxp.child0(cfg_sxp)
dev_type = sxp.name(config)
dev_info = {}
if dev_uuid in self['devices'] and cfg_sxp:
if sxp.child0(cfg_sxp) == 'device':
config = sxp.child0(cfg_sxp)
else:
config = cfg_sxp
try:
for opt, val in config[1:]:
self['devices'][opt] = val
except ValueError:
pass # SXP has no options for this device
dev_type, dev_info = self['devices'][dev_uuid]
for opt_val in config[1:]:
try:
opt, val = opt_val
dev_info[opt] = val
except (TypeError, ValueError):
pass # no value for this config option
self['devices'][dev_uuid] = (dev_type, dev_info)
return True
elif dev_uuid in self['devices'] and cfg_xenapi:
dev_type, dev_info = self['devices'][dev_uuid]
for key, val in cfg_xenapi.items():
dev_info[key] = val
self['devices'][dev_uuid] = (dev_type, dev_info)
return False
@@ -1045,11 +1247,24 @@ class XendConfig(dict):
"configuration dictionary.")
sxpr.append(dev_type)
config = [(opt, val) for opt, val in dev_info.items()]
if dev_type in ('console', 'vfb'):
config = [(opt, val) for opt, val in dev_info.items()
if opt != 'other_config']
else:
config = [(opt, val) for opt, val in dev_info.items()]
sxpr += config
return sxpr
def ordered_device_refs(self):
result = (self['console_refs'] +
self['vbd_refs'] +
self['vif_refs'] +
self['vtpm_refs'])
result.extend([u for u in self['devices'].keys() if u not in result])
return result
def all_devices_sxpr(self):
"""Returns the SXPR for all devices in the current configuration."""
sxprs = []
@@ -1058,7 +1273,9 @@ class XendConfig(dict):
if 'devices' not in self:
return sxprs
for dev_type, dev_info in self['devices'].values():
ordered_refs = self.ordered_device_refs()
for dev_uuid in ordered_refs:
dev_type, dev_info = self['devices'][dev_uuid]
if dev_type == 'pci': # special case for pci devices
sxpr = [['uuid', dev_info['uuid']]]
for pci_dev_info in dev_info['devs']:
@@ -1092,13 +1309,18 @@ class XendConfig(dict):
if 'hvm' in self['image']:
for arg, conv in LEGACY_IMAGE_HVM_CFG:
if self['image']['hvm'].get(arg):
image.append([arg, self['image']['hvm'][arg]])
image.append([arg, conv(self['image']['hvm'][arg])])
if 'hvm' in self['image'] and 'devices' in self['image']['hvm']:
for arg, conv in LEGACY_IMAGE_HVM_DEVICES_CFG:
if self['image']['hvm']['devices'].get(arg):
image.append([arg,
self['image']['hvm']['devices'][arg]])
val = self['image']['hvm']['devices'].get(arg)
if val != None:
try:
if conv: val = conv(val)
except (ValueError, TypeError):
if type(val) == bool: val = int(val)
image.append([arg, val])
return image
@@ -1107,15 +1329,17 @@ class XendConfig(dict):
# configuration
log.debug("update_with_image_sxp(%s)" % scrub_password(image_sxp))
# user-specified args must come last: previous releases did this and
# some domU kernels rely upon the ordering.
kernel_args = sxp.child_value(image_sxp, 'args', '')
# attempt to extract extra arguments from SXP config
arg_ip = sxp.child_value(image_sxp, 'ip')
if arg_ip and not re.search(r'ip=[^ ]+', kernel_args):
kernel_args += ' ip=%s' % arg_ip
kernel_args = 'ip=%s ' % arg_ip + kernel_args
arg_root = sxp.child_value(image_sxp, 'root')
if arg_root and not re.search(r'root=', kernel_args):
kernel_args += ' root=%s' % arg_root
kernel_args = 'root=%s ' % arg_root + kernel_args
if bootloader:
self['_temp_using_bootloader'] = '1'
@@ -1145,7 +1369,11 @@ class XendConfig(dict):
for arg, conv in LEGACY_IMAGE_HVM_DEVICES_CFG:
val = sxp.child_value(image_sxp, arg, None)
if val != None:
image_hvm_devices[arg] = conv(val)
try:
image_hvm_devices[arg] = conv(val)
except (ValueError, TypeError):
image_hvm_devices[arg] = val
if image_hvm or image_hvm_devices:
image['hvm'] = image_hvm
@@ -1157,12 +1385,20 @@ class XendConfig(dict):
val = sxp.child_value(image_sxp, imgkey, None)
if val != None:
type_conv = XENAPI_CFG_TYPES[apikey]
if callable(conv):
if callable(type_conv):
self[apikey] = type_conv(val)
else:
self[apikey] = val
self._hvm_boot_params_from_sxp(image_sxp)
def _hvm_boot_params_from_sxp(self, image_sxp):
boot = sxp.child_value(image_sxp, 'boot', None)
if boot is not None:
self['HVM_boot_policy'] = 'BIOS order'
self['HVM_boot_params'] = { 'order' : boot }
#
# debugging
#
+1
View File
@@ -80,6 +80,7 @@ ZOMBIE_PREFIX = 'Zombie-'
MINIMUM_RESTART_TIME = 20
RESTART_IN_PROGRESS = 'xend/restart_in_progress'
LAST_SHUTDOWN_REASON = 'xend/last_shutdown_reason'
#
# Device migration stages (eg. XendDomainInfo, XendCheckpoint, server.tpmif)
+3 -5
View File
@@ -21,6 +21,8 @@
from xen.xend.server import blkif, netif, tpmif, pciif, iopif, irqif, usbif, vfbif
from xen.xend.server.BlktapController import BlktapController
from xen.xend.server.ConsoleController import ConsoleController
class XendDevices:
""" An ugly halfway point between the module local device name
@@ -43,6 +45,7 @@ class XendDevices:
'tap': BlktapController,
'vfb': vfbif.VfbifController,
'vkbd': vfbif.VkbdifController,
'console': ConsoleController,
}
#@classmethod
@@ -50,11 +53,6 @@ class XendDevices:
return cls.controllers.keys()
valid_devices = classmethod(valid_devices)
#@classmethod
def pseudo_devices(cls):
return ['console']
pseudo_devices = classmethod(pseudo_devices)
#@classmethod
def make_controller(cls, name, domain):
"""Factory function to make device controllers per domain.
+32 -35
View File
@@ -32,7 +32,7 @@ import threading
import xen.lowlevel.xc
from xen.xend import XendRoot, XendCheckpoint, XendDomainInfo
from xen.xend import XendOptions, XendCheckpoint, XendDomainInfo, XendNode
from xen.xend.PrettyPrint import prettyprint
from xen.xend.XendConfig import XendConfig
from xen.xend.XendError import XendError, XendInvalidDomain, VmError
@@ -51,7 +51,7 @@ from xen.util import mkdir, security
from xen.xend import uuid
xc = xen.lowlevel.xc.xc()
xroot = XendRoot.instance()
xoptions = XendOptions.instance()
__all__ = [ "XendDomain" ]
@@ -115,7 +115,6 @@ class XendDomain:
dom0info['name'] = DOM0_NAME
dom0 = XendDomainInfo.recreate(dom0info, True)
self._add_domain(dom0)
except IndexError:
raise XendError('Unable to find Domain 0')
@@ -172,7 +171,6 @@ class XendDomain:
if dom['domid'] != DOM0_ID:
try:
new_dom = XendDomainInfo.recreate(dom, False)
self._add_domain(new_dom)
except Exception:
log.exception("Failed to create reference to running "
"domain id: %d" % dom['domid'])
@@ -214,7 +212,7 @@ class XendDomain:
@rtype: String
@return: Path.
"""
dom_path = xroot.get_xend_domains_path()
dom_path = xoptions.get_xend_domains_path()
if domuuid:
dom_path = os.path.join(dom_path, domuuid)
return dom_path
@@ -361,7 +359,7 @@ class XendDomain:
def _setDom0CPUCount(self):
"""Sets the number of VCPUs dom0 has. Retreived from the
Xend configuration, L{XendRoot}.
Xend configuration, L{XendOptions}.
@requires: Expects to be protected by domains_lock.
@rtype: None
@@ -369,7 +367,7 @@ class XendDomain:
dom0 = self.privilegedDomain()
# get max number of vcpus to use for dom0 from config
target = int(xroot.get_dom0_vcpus())
target = int(xoptions.get_dom0_vcpus())
log.debug("number of vcpus to use is %d", target)
# target == 0 means use all processors
@@ -377,7 +375,7 @@ class XendDomain:
dom0.setVCpuCount(target)
def _refresh(self):
def _refresh(self, refresh_shutdown = True):
"""Refresh the domain list. Needs to be called when
either xenstore has changed or when a method requires
up to date information (like uptime, cputime stats).
@@ -393,11 +391,10 @@ class XendDomain:
for dom in running:
domid = dom['domid']
if domid in self.domains:
self.domains[domid].update(dom)
self.domains[domid].update(dom, refresh_shutdown)
elif domid not in self.domains and dom['dying'] != 1:
try:
new_dom = XendDomainInfo.recreate(dom, False)
self._add_domain(new_dom)
except VmError:
log.exception("Unable to recreate domain")
try:
@@ -416,10 +413,10 @@ class XendDomain:
running_domids = [d['domid'] for d in running if d['dying'] != 1]
for domid, dom in self.domains.items():
if domid not in running_domids and domid != DOM0_ID:
self._remove_domain(dom, domid)
self.remove_domain(dom, domid)
def _add_domain(self, info):
def add_domain(self, info):
"""Add a domain to the list of running domains
@requires: Expects to be protected by the domains_lock.
@@ -434,7 +431,7 @@ class XendDomain:
if info.get_uuid() in self.managed_domains:
self._managed_domain_register(info)
def _remove_domain(self, info, domid = None):
def remove_domain(self, info, domid = None):
"""Remove the domain from the list of running domains
@requires: Expects to be protected by the domains_lock.
@@ -473,7 +470,6 @@ class XendDomain:
try:
security.refresh_ssidref(config)
dominfo = XendDomainInfo.restore(config)
self._add_domain(dominfo)
return dominfo
finally:
self.domains_lock.release()
@@ -495,7 +491,7 @@ class XendDomain:
"""
self.domains_lock.acquire()
try:
self._refresh()
self._refresh(refresh_shutdown = False)
dom = self.domain_lookup_nr(domid)
if not dom:
raise XendError("No domain named '%s'." % str(domid))
@@ -640,18 +636,18 @@ class XendDomain:
self.domains_lock.release()
def get_dev_property_by_uuid(self, klass, dev_uuid, field):
value = None
self.domains_lock.acquire()
try:
dom = self.get_vm_with_dev_uuid(klass, dev_uuid)
if not dom:
return None
value = dom.get_device_property(klass, dev_uuid, field)
return value
if dom:
value = dom.get_dev_property(klass, dev_uuid, field)
except ValueError, e:
pass
self.domains_lock.release()
return None
return value
def is_valid_vm(self, vm_ref):
return (self.get_vm_by_uuid(vm_ref) != None)
@@ -731,7 +727,7 @@ class XendDomain:
self.domains_lock.acquire()
try:
self._refresh()
self._refresh(refresh_shutdown = False)
# active domains
active_domains = self.domains.values()
@@ -848,7 +844,6 @@ class XendDomain:
os.open(chkpath, os.O_RDONLY),
dominfo,
paused = start_paused)
self._add_domain(dominfo)
os.unlink(chkpath)
except OSError, ex:
raise XendError("Failed to read stored checkpoint file")
@@ -873,10 +868,10 @@ class XendDomain:
self._refresh()
dominfo = XendDomainInfo.create(config)
self._add_domain(dominfo)
self.domain_sched_credit_set(dominfo.getDomid(),
dominfo.getWeight(),
dominfo.getCap())
if XendNode.instance().xenschedinfo() == 'credit':
self.domain_sched_credit_set(dominfo.getDomid(),
dominfo.getWeight(),
dominfo.getCap())
return dominfo
finally:
self.domains_lock.release()
@@ -893,10 +888,10 @@ class XendDomain:
self._refresh()
dominfo = XendDomainInfo.create_from_dict(config_dict)
self._add_domain(dominfo)
self.domain_sched_credit_set(dominfo.getDomid(),
dominfo.getWeight(),
dominfo.getCap())
if XendNode.instance().xenschedinfo() == 'credit':
self.domain_sched_credit_set(dominfo.getDomid(),
dominfo.getWeight(),
dominfo.getCap())
return dominfo
finally:
self.domains_lock.release()
@@ -950,7 +945,10 @@ class XendDomain:
POWER_STATE_NAMES[dominfo.state])
dominfo.start(is_managed = True)
self._add_domain(dominfo)
if XendNode.instance().xenschedinfo() == 'credit':
self.domain_sched_credit_set(dominfo.getDomid(),
dominfo.getWeight(),
dominfo.getCap())
finally:
self.domains_lock.release()
dominfo.waitForDevices()
@@ -983,7 +981,7 @@ class XendDomain:
(dominfo.getName(), dominfo.info.get('uuid')))
self._managed_domain_unregister(dominfo)
self._remove_domain(dominfo)
self.remove_domain(dominfo)
XendDevices.destroy_device_state(dominfo)
except Exception, ex:
raise XendError(str(ex))
@@ -1164,7 +1162,7 @@ class XendDomain:
dominfo.checkLiveMigrateMemory()
if port == 0:
port = xroot.get_xend_relocation_port()
port = xoptions.get_xend_relocation_port()
try:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect((dst, port))
@@ -1174,7 +1172,6 @@ class XendDomain:
sock.send("receive\n")
sock.recv(80)
XendCheckpoint.save(sock.fileno(), dominfo, True, live, dst)
dominfo.testDeviceComplete()
sock.close()
def domain_save(self, domid, dst):
+341 -158
View File
@@ -37,15 +37,16 @@ from xen.util import asserts
from xen.util.blkif import blkdev_uname_to_file
from xen.util import security
from xen.xend import balloon, sxp, uuid, image, arch
from xen.xend import XendRoot, XendNode, XendConfig
from xen.xend import balloon, sxp, uuid, image, arch, osdep
from xen.xend import XendOptions, XendNode, XendConfig
from xen.xend.XendConfig import scrub_password
from xen.xend.XendBootloader import bootloader
from xen.xend.XendBootloader import bootloader, bootloader_tidy
from xen.xend.XendError import XendError, VmError
from xen.xend.XendDevices import XendDevices
from xen.xend.XendTask import XendTask
from xen.xend.xenstore.xstransact import xstransact, complete
from xen.xend.xenstore.xsutil import GetDomainPath, IntroduceDomain
from xen.xend.xenstore.xsutil import GetDomainPath, IntroduceDomain, ResumeDomain
from xen.xend.xenstore.xswatch import xswatch
from xen.xend.XendConstants import *
from xen.xend.XendAPIConstants import *
@@ -54,31 +55,12 @@ MIGRATE_TIMEOUT = 30.0
BOOTLOADER_LOOPBACK_DEVICE = '/dev/xvdp'
xc = xen.lowlevel.xc.xc()
xroot = XendRoot.instance()
xoptions = XendOptions.instance()
log = logging.getLogger("xend.XendDomainInfo")
#log.setLevel(logging.TRACE)
#
# There are a number of CPU-related fields:
#
# vcpus: the number of virtual CPUs this domain is configured to use.
# vcpu_avail: a bitmap telling the guest domain whether it may use each of
# its VCPUs. This is translated to
# <dompath>/cpu/<id>/availability = {online,offline} for use
# by the guest domain.
# cpumap: a list of bitmaps, one for each VCPU, giving the physical
# CPUs that that VCPU may use.
# cpu: a configuration setting requesting that VCPU 0 is pinned to
# the specified physical CPU.
#
# vcpus and vcpu_avail settings persist with the VM (i.e. they are persistent
# across save, restore, migrate, and restart). The other settings are only
# specific to the domain, so are lost when the VM moves.
#
def create(config):
"""Creates and start a VM using the supplied configuration.
@@ -120,7 +102,6 @@ def create_from_dict(config_dict):
log.exception('Domain construction failed')
vm.destroy()
raise
return vm
def recreate(info, priv):
@@ -206,6 +187,11 @@ def recreate(info, priv):
vm._registerWatches()
vm.refreshShutdown(xeninfo)
# register the domain in the list
from xen.xend import XendDomain
XendDomain.instance().add_domain(vm)
return vm
@@ -402,12 +388,13 @@ class XendDomainInfo:
if self.state == DOM_STATE_HALTED:
try:
self._constructDomain()
self._initDomain()
self._storeVmDetails()
self._storeDomDetails()
self._registerWatches()
self.refreshShutdown()
XendTask.log_progress(0, 30, self._constructDomain)
XendTask.log_progress(31, 60, self._initDomain)
XendTask.log_progress(61, 70, self._storeVmDetails)
XendTask.log_progress(71, 80, self._storeDomDetails)
XendTask.log_progress(81, 90, self._registerWatches)
XendTask.log_progress(91, 100, self.refreshShutdown)
# save running configuration if XendDomains believe domain is
# persistent
@@ -439,7 +426,7 @@ class XendDomainInfo:
def shutdown(self, reason):
"""Shutdown a domain by signalling this via xenstored."""
log.debug('XendDomainInfo.shutdown')
log.debug('XendDomainInfo.shutdown(%s)', reason)
if self.state in (DOM_STATE_SHUTDOWN, DOM_STATE_HALTED,):
raise XendError('Domain cannot be shutdown')
@@ -451,6 +438,16 @@ class XendDomainInfo:
self._removeVm('xend/previous_restart_time')
self.storeDom("control/shutdown", reason)
## shutdown hypercall for hvm domain desides xenstore write
image_cfg = self.info.get('image', {})
hvm = image_cfg.has_key('hvm')
if hvm:
for code in DOMAIN_SHUTDOWN_REASONS.keys():
if DOMAIN_SHUTDOWN_REASONS[code] == reason:
break
xc.domain_shutdown(self.domid, code)
def pause(self):
"""Pause domain
@@ -496,7 +493,7 @@ class XendDomainInfo:
self._waitForDevice(dev_type, devid)
return self.getDeviceController(dev_type).sxpr(devid)
def device_configure(self, dev_config, devid = None):
def device_configure(self, dev_sxp, devid = None):
"""Configure an existing device.
@param dev_config: device configuration
@@ -506,19 +503,24 @@ class XendDomainInfo:
@return: Returns True if successfully updated device
@rtype: boolean
"""
deviceClass = sxp.name(dev_config)
# look up uuid of the device
dev_control = self.getDeviceController(deviceClass)
dev_sxpr = dev_control.sxpr(devid)
dev_uuid = sxp.child_value(sxpr, 'uuid')
if not dev_uuid:
return False
self.info.device_update(dev_uuid, dev_config)
dev_config_dict = self.info['devices'].get(dev_uuid)
if dev_config_dict:
dev_control.reconfigureDevice(devid, dev_config_dict[1])
# convert device sxp to a dict
dev_class = sxp.name(dev_sxp)
dev_config = {}
for opt_val in dev_sxp[1:]:
try:
dev_config[opt_val[0]] = opt_val[1]
except IndexError:
pass
# use DevController.reconfigureDevice to change device config
dev_control = self.getDeviceController(dev_class)
dev_uuid = dev_control.reconfigureDevice(devid, dev_config)
# update XendConfig with new device info
if dev_uuid:
self.info.device_update(dev_uuid, dev_sxp)
return True
def waitForDevices(self):
@@ -546,8 +548,6 @@ class XendDomainInfo:
return self.getDeviceController(deviceClass).destroyDevice(devid, force)
def getDeviceSxprs(self, deviceClass):
if self.state == DOM_STATE_RUNNING:
return self.getDeviceController(deviceClass).sxprs()
@@ -609,7 +609,7 @@ class XendDomainInfo:
['name', self.info['name_label']],
['vcpu_count', self.info['vcpus_number']]]
for i in range(0, self.info['max_vcpu_id']+1):
for i in range(0, self.info['vcpus_number']):
info = xc.vcpu_getinfo(self.domid, i)
sxpr.append(['vcpu',
@@ -682,6 +682,42 @@ class XendDomainInfo:
for device in devices:
self.info.device_add(device[0], cfg_sxp = device)
self._update_consoles()
def _update_consoles(self):
if self.domid == None or self.domid == 0:
return
# Update VT100 port if it exists
self.console_port = self.readDom('console/port')
if self.console_port is not None:
serial_consoles = self.info.console_get_all('vt100')
if not serial_consoles:
cfg = self.info.console_add('vt100', self.console_port)
self._createDevice('console', cfg)
else:
console_uuid = serial_consoles[0].get('uuid')
self.info.console_update(console_uuid, 'location',
self.console_port)
# Update VNC port if it exists and write to xenstore
vnc_port = self.readDom('console/vnc-port')
if vnc_port is not None:
for dev_uuid, (dev_type, dev_info) in self.info['devices'].items():
if dev_type == 'vfb':
old_location = dev_info.get('location')
listen_host = dev_info.get('vnclisten', 'localhost')
new_location = '%s:%s' % (listen_host, str(vnc_port))
if old_location == new_location:
break
dev_info['location'] = new_location
self.info.device_update(dev_uuid, cfg_xenapi = dev_info)
vfb_ctrl = self.getDeviceController('vfb')
vfb_ctrl.reconfigureDevice(0, dev_info)
break
#
# Function to update xenstore /vm/*
#
@@ -734,7 +770,7 @@ class XendDomainInfo:
'domid': str(self.domid),
'vm': self.vmpath,
'name': self.info['name_label'],
'console/limit': str(xroot.get_console_limit() * 1024),
'console/limit': str(xoptions.get_console_limit() * 1024),
'memory/target': str(self.info['memory_static_min'] * 1024)
}
@@ -893,8 +929,9 @@ class XendDomainInfo:
self._writeDom(self._vcpuDomDetails())
else:
self.info['vcpus_number'] = vcpus
self.info['online_vcpus'] = vcpus
xen.xend.XendDomain.instance().managed_config_save(self)
log.info("Set VCPU count on domain %s to %d", self.info['name_label'],
vcpus)
def getLabel(self):
return security.get_security_info(self.info, 'label')
@@ -914,7 +951,7 @@ class XendDomainInfo:
return self.info.get('cpu_cap', 0)
def getWeight(self):
return self.info['cpu_weight']
return self.info.get('cpu_weight', 256)
def setResume(self, state):
self._resume = state
@@ -969,9 +1006,15 @@ class XendDomainInfo:
log.warn('Domain has crashed: name=%s id=%d.',
self.info['name_label'], self.domid)
self._writeVm(LAST_SHUTDOWN_REASON, 'crash')
if xroot.get_enable_dump():
self.dumpCore()
if xoptions.get_enable_dump():
try:
self.dumpCore()
except XendError:
# This error has been logged -- there's nothing more
# we can do in this context.
pass
restart_reason = 'crash'
self._stateSet(DOM_STATE_HALTED)
@@ -988,6 +1031,7 @@ class XendDomainInfo:
log.info('Domain has shutdown: name=%s id=%d reason=%s.',
self.info['name_label'], self.domid, reason)
self._writeVm(LAST_SHUTDOWN_REASON, reason)
self._clearRestart()
@@ -1162,7 +1206,10 @@ class XendDomainInfo:
#
def dumpCore(self, corefile = None):
"""Create a core dump for this domain. Nothrow guarantee."""
"""Create a core dump for this domain.
@raise: XendError if core dumping failed.
"""
try:
if not corefile:
@@ -1205,16 +1252,26 @@ class XendDomainInfo:
@raise: VmError for invalid devices
"""
for (devclass, config) in self.info.get('devices', {}).values():
if devclass in XendDevices.valid_devices():
ordered_refs = self.info.ordered_device_refs()
for dev_uuid in ordered_refs:
devclass, config = self.info['devices'][dev_uuid]
if devclass in XendDevices.valid_devices():
log.info("createDevice: %s : %s" % (devclass, scrub_password(config)))
self._createDevice(devclass, config)
dev_uuid = config.get('uuid')
devid = self._createDevice(devclass, config)
# store devid in XendConfig for caching reasons
if dev_uuid in self.info['devices']:
self.info['devices'][dev_uuid][1]['devid'] = devid
if self.image:
self.image.createDeviceModel()
def _releaseDevices(self):
def _releaseDevices(self, suspend = False):
"""Release all domain's devices. Nothrow guarantee."""
if suspend and self.image:
self.image.destroy(suspend)
return
while True:
t = xstransact("%s/device" % self.dompath)
@@ -1328,6 +1385,9 @@ class XendDomainInfo:
# Set maximum number of vcpus in domain
xc.domain_max_vcpus(self.domid, int(self.info['vcpus_number']))
# register the domain in the list
from xen.xend import XendDomain
XendDomain.instance().add_domain(self)
def _introduceDomain(self):
assert self.domid is not None
@@ -1366,7 +1426,7 @@ class XendDomainInfo:
# this is done prior to memory allocation to aide in memory
# distribution for NUMA systems.
if self.info['cpus'] is not None and len(self.info['cpus']) > 0:
for v in range(0, self.info['max_vcpu_id']+1):
for v in range(0, self.info['vcpus_number']):
xc.vcpu_setaffinity(self.domid, v, self.info['cpus'])
# Use architecture- and image-specific calculations to determine
@@ -1380,6 +1440,7 @@ class XendDomainInfo:
self.info['shadow_memory'] * 1024,
self.info['memory_static_max'] * 1024)
log.debug("_initDomain:shadow_memory=0x%x, memory_static_max=0x%x, memory_static_min=0x%x.", self.info['shadow_memory'], self.info['memory_static_max'], self.info['memory_static_min'],)
# Round shadow up to a multiple of a MiB, as shadow_mem_control
# takes MiB and we must not round down and end up under-providing.
shadow = ((shadow + 1023) / 1024) * 1024
@@ -1425,6 +1486,7 @@ class XendDomainInfo:
try:
self.unwatchShutdown()
self._releaseDevices()
bootloader_tidy(self)
if self.image:
try:
@@ -1479,6 +1541,16 @@ class XendDomainInfo:
self.console_mfn = console_mfn
self._introduceDomain()
image_cfg = self.info.get('image', {})
hvm = image_cfg.has_key('hvm')
if hvm:
self.image = image.create(self,
self.info,
self.info['image'],
self.info['devices'])
if self.image:
self.image.createDeviceModel(True)
self.image.register_shutdown_watch()
self._storeDomDetails()
self._registerWatches()
self.refreshShutdown()
@@ -1515,9 +1587,22 @@ class XendDomainInfo:
except:
log.exception("XendDomainInfo.destroy: xc.domain_destroy failed.")
from xen.xend import XendDomain
XendDomain.instance().remove_domain(self)
self.cleanupDomain()
def resumeDomain(self):
log.debug("XendDomainInfo.resumeDomain(%s)", str(self.domid))
try:
if self.domid is not None:
xc.domain_resume(self.domid)
ResumeDomain(self.domid)
except:
log.exception("XendDomainInfo.resume: xc.domain_resume failed on domain %s." % (str(self.domid)))
#
# Channels for xenstore and console
#
@@ -1533,11 +1618,24 @@ class XendDomainInfo:
"""Create an event channel to the domain.
"""
try:
return xc.evtchn_alloc_unbound(domid=self.domid, remote_dom=0)
if self.domid != None:
return xc.evtchn_alloc_unbound(domid = self.domid,
remote_dom = 0)
except:
log.exception("Exception in alloc_unbound(%d)", self.domid)
log.exception("Exception in alloc_unbound(%s)", str(self.domid))
raise
def _resetChannels(self):
"""Reset all event channels in the domain.
"""
try:
if self.domid != None:
return xc.evtchn_reset(dom = self.domid)
except:
log.exception("Exception in evtcnh_reset(%s)", str(self.domid))
raise
#
# Bootloader configuration
#
@@ -1550,14 +1648,15 @@ class XendDomainInfo:
kernel = self.info['PV_kernel']
ramdisk = self.info['PV_ramdisk']
args = self.info['PV_args']
boot = self.info['HVM_boot']
boot = self.info['HVM_boot_policy']
if boot:
# HVM booting.
self.info['image']['type'] = 'hvm'
if not 'devices' in self.info['image']:
self.info['image']['devices'] = {}
self.info['image']['devices']['boot'] = boot
self.info['image']['devices']['boot'] = \
self.info['HVM_boot_params'].get('order', 'dc')
elif not blexec and kernel:
# Boot from dom0. Nothing left to do -- the kernel and ramdisk
# will be picked up by image.py.
@@ -1565,51 +1664,50 @@ class XendDomainInfo:
else:
# Boot using bootloader
if not blexec or blexec == 'pygrub':
blexec = '/usr/bin/pygrub'
blexec = osdep.pygrub_path
blcfg = None
for (devtype, devinfo) in self.info.all_devices_sxpr():
if not devtype or not devinfo or devtype not in ('vbd', 'tap'):
continue
disk = None
for param in devinfo:
if param[0] == 'uname':
disk = param[1]
break
disks = [x for x in self.info['vbd_refs']
if self.info['devices'][x][1]['bootable']]
if disk is None:
continue
fn = blkdev_uname_to_file(disk)
mounted = devtype == 'tap' and not os.stat(fn).st_rdev
if not disks:
msg = "Had a bootloader specified, but no disks are bootable"
log.error(msg)
raise VmError(msg)
devinfo = self.info['devices'][disks[0]]
devtype = devinfo[0]
disk = devinfo[1]['uname']
fn = blkdev_uname_to_file(disk)
mounted = devtype == 'tap' and not os.stat(fn).st_rdev
if mounted:
# This is a file, not a device. pygrub can cope with a
# file if it's raw, but if it's QCOW or other such formats
# used through blktap, then we need to mount it first.
log.info("Mounting %s on %s." %
(fn, BOOTLOADER_LOOPBACK_DEVICE))
vbd = {
'mode': 'RO',
'device': BOOTLOADER_LOOPBACK_DEVICE,
}
from xen.xend import XendDomain
dom0 = XendDomain.instance().privilegedDomain()
dom0._waitForDeviceUUID(dom0.create_vbd(vbd, fn))
fn = BOOTLOADER_LOOPBACK_DEVICE
try:
blcfg = bootloader(blexec, fn, self, False,
bootloader_args, kernel, ramdisk, args)
finally:
if mounted:
# This is a file, not a device. pygrub can cope with a
# file if it's raw, but if it's QCOW or other such formats
# used through blktap, then we need to mount it first.
log.info("Mounting %s on %s." %
log.info("Unmounting %s from %s." %
(fn, BOOTLOADER_LOOPBACK_DEVICE))
vbd = {
'mode': 'RO',
'device': BOOTLOADER_LOOPBACK_DEVICE,
}
from xen.xend import XendDomain
dom0 = XendDomain.instance().privilegedDomain()
dom0._waitForDeviceUUID(dom0.create_vbd_with_vdi(vbd, fn))
fn = BOOTLOADER_LOOPBACK_DEVICE
try:
blcfg = bootloader(blexec, fn, True,
bootloader_args, kernel, ramdisk, args)
finally:
if mounted:
log.info("Unmounting %s from %s." %
(fn, BOOTLOADER_LOOPBACK_DEVICE))
dom0.destroyDevice('tap', '/dev/xvdp')
break
dom0.destroyDevice('tap', '/dev/xvdp')
if blcfg is None:
msg = "Had a bootloader specified, but can't find disk"
@@ -1695,6 +1793,25 @@ class XendDomainInfo:
log.info("Dev still active but hit max loop timeout")
break
def testvifsComplete(self):
""" In case vifs are released and then created for the same
domain, we need to wait the device shut down.
"""
start = time.time()
while True:
test = 0
diff = time.time() - start
for i in self.getDeviceController('vif').deviceIDs():
test = 1
log.info("Dev %s still active, looping...", i)
time.sleep(0.1)
if test == 0:
break
if diff >= MIGRATE_TIMEOUT:
log.info("Dev still active but hit max loop timeout")
break
def _storeVmDetails(self):
to_store = {}
@@ -1811,7 +1928,8 @@ class XendDomainInfo:
# TODO: we should eventually get rid of old_dom_states
self.info.update_config(info)
self._update_consoles()
if refresh:
self.refreshShutdown(info)
@@ -1823,11 +1941,11 @@ class XendDomainInfo:
ignore_devices = ignore_store,
legacy_only = legacy_only)
if not ignore_store and self.dompath:
vnc_port = self.readDom('console/vnc-port')
if vnc_port is not None:
result.append(['device',
['console', ['vnc-port', str(vnc_port)]]])
#if not ignore_store and self.dompath:
# vnc_port = self.readDom('console/vnc-port')
# if vnc_port is not None:
# result.append(['device',
# ['console', ['vnc-port', str(vnc_port)]]])
return result
@@ -1859,7 +1977,11 @@ class XendDomainInfo:
else:
return 'unknown'
def get_vcpus_params(self):
return '' # TODO
if self.getDomid() is None:
return self.info['vcpus_params']
retval = xc.sched_credit_domain_get(self.getDomid())
return retval
def get_power_state(self):
return XEN_API_VM_POWER_STATE[self.state]
def get_platform_std_vga(self):
@@ -1875,11 +1997,9 @@ class XendDomainInfo:
def get_platform_keymap(self):
return self.info.get('platform_keymap', '')
def get_pci_bus(self):
return '' # TODO
return self.info.get('pci_bus', '')
def get_tools_version(self):
return {} # TODO
def get_other_config(self):
return {} # TODO
return self.info.get('tools_version', {})
def get_on_shutdown(self):
after_shutdown = self.info.get('action_after_shutdown')
@@ -1915,21 +2035,18 @@ class XendDomainInfo:
@rtype: dictionary
"""
dev_type_config = self.info['devices'].get(dev_uuid)
dev_type, dev_config = self.info['devices'].get(dev_uuid, (None, None))
# shortcut if the domain isn't started because
# the devcontrollers will have no better information
# than XendConfig.
if self.state in (XEN_API_VM_POWER_STATE_HALTED,):
if dev_type_config:
return copy.deepcopy(dev_type_config[1])
if dev_config:
return copy.deepcopy(dev_config)
return None
# instead of using dev_class, we use the dev_type
# that is from XendConfig.
# This will accomdate 'tap' as well as 'vbd'
dev_type = dev_type_config[0]
controller = self.getDeviceController(dev_type)
if not controller:
return None
@@ -1938,14 +2055,14 @@ class XendDomainInfo:
if not all_configs:
return None
dev_config = copy.deepcopy(dev_type_config[1])
updated_dev_config = copy.deepcopy(dev_config)
for _devid, _devcfg in all_configs.items():
if _devcfg.get('uuid') == dev_uuid:
dev_config.update(_devcfg)
dev_config['id'] = _devid
return dev_config
updated_dev_config.update(_devcfg)
updated_dev_config['id'] = _devid
return updated_dev_config
return dev_config
return updated_dev_config
def get_dev_xenapi_config(self, dev_class, dev_uuid):
config = self.get_dev_config_by_uuid(dev_class, dev_uuid)
@@ -1981,23 +2098,52 @@ class XendDomainInfo:
# handle that properly.
config['MTU'] = 1500 # TODO
config['io_read_kbs'] = 0.0
config['io_write_kbs'] = 0.0
if self.state not in (XEN_API_VM_POWER_STATE_HALTED,):
xennode = XendNode.instance()
rx_bps, tx_bps = xennode.get_vif_util(self.domid, devid)
config['io_read_kbs'] = rx_bps/1024
config['io_write_kbs'] = tx_bps/1024
else:
config['io_read_kbs'] = 0.0
config['io_write_kbs'] = 0.0
if dev_class == 'vbd':
if self.state not in (XEN_API_VM_POWER_STATE_HALTED,):
controller = self.getDeviceController(dev_class)
devid, _1, _2 = controller.getDeviceDetails(config)
xennode = XendNode.instance()
rd_blkps, wr_blkps = xennode.get_vbd_util(self.domid, devid)
config['io_read_kbs'] = rd_blkps
config['io_write_kbs'] = wr_blkps
else:
config['io_read_kbs'] = 0.0
config['io_write_kbs'] = 0.0
config['VDI'] = config.get('VDI', '')
config['device'] = config.get('dev', '')
if ':' in config['device']:
vbd_name, vbd_type = config['device'].split(':', 1)
config['device'] = vbd_name
if vbd_type == 'cdrom':
config['type'] = XEN_API_VBD_TYPE[0]
else:
config['type'] = XEN_API_VBD_TYPE[1]
config['driver'] = 'paravirtualised' # TODO
config['image'] = config.get('uname', '')
config['io_read_kbs'] = 0.0
config['io_write_kbs'] = 0.0
if config['mode'] == 'r':
if config.get('mode', 'r') == 'r':
config['mode'] = 'RO'
else:
config['mode'] = 'RW'
if dev_class == 'vtpm':
config['driver'] = 'paravirtualised' # TODO
if not config.has_key('type'):
config['type'] = 'paravirtualised' # TODO
if not config.has_key('backend'):
config['backend'] = "00000000-0000-0000-0000-000000000000"
return config
@@ -2008,15 +2154,16 @@ class XendDomainInfo:
except KeyError:
raise XendError('Invalid property for device: %s' % field)
def set_dev_property(self, dev_class, dev_uuid, field, value):
self.info['devices'][dev_uuid][1][field] = value
def get_vcpus_util(self):
# TODO: this returns the total accum cpu time, rather than util
# TODO: spec says that key is int, however, python does not allow
# non-string keys to dictionaries.
vcpu_util = {}
if 'max_vcpu_id' in self.info and self.domid != None:
for i in range(0, self.info['max_vcpu_id']+1):
info = xc.vcpu_getinfo(self.domid, i)
vcpu_util[str(i)] = info['cpu_time']/1000000000.0
xennode = XendNode.instance()
if 'vcpus_number' in self.info and self.domid != None:
for i in range(0, self.info['vcpus_number']):
util = xennode.get_vcpu_util(self.domid, i)
vcpu_util[str(i)] = util
return vcpu_util
@@ -2032,24 +2179,7 @@ class XendDomainInfo:
def get_vtpms(self):
return self.info.get('vtpm_refs', [])
def create_vbd(self, xenapi_vbd):
"""Create a VBD device from the passed struct in Xen API format.
@return: uuid of the device
@rtype: string
"""
dev_uuid = self.info.device_add('vbd', cfg_xenapi = xenapi_vbd)
if not dev_uuid:
raise XendError('Failed to create device')
if self.state == XEN_API_VM_POWER_STATE_RUNNING:
_, config = self.info['devices'][dev_uuid]
config['devid'] = self.getDeviceController('vbd').createDevice(config)
return dev_uuid
def create_vbd_with_vdi(self, xenapi_vbd, vdi_image_path):
def create_vbd(self, xenapi_vbd, vdi_image_path):
"""Create a VBD using a VDI from XendStorageRepository.
@param xenapi_vbd: vbd struct from the Xen API
@@ -2058,14 +2188,26 @@ class XendDomainInfo:
@return: uuid of the device
"""
xenapi_vbd['image'] = vdi_image_path
log.debug('create_vbd_with_vdi: %s' % xenapi_vbd)
dev_uuid = self.info.device_add('tap', cfg_xenapi = xenapi_vbd)
log.debug('create_vbd: %s' % xenapi_vbd)
dev_uuid = ''
if vdi_image_path.startswith('tap'):
dev_uuid = self.info.device_add('tap', cfg_xenapi = xenapi_vbd)
else:
dev_uuid = self.info.device_add('vbd', cfg_xenapi = xenapi_vbd)
if not dev_uuid:
raise XendError('Failed to create device')
if self.state == XEN_API_VM_POWER_STATE_RUNNING:
_, config = self.info['devices'][dev_uuid]
config['devid'] = self.getDeviceController('tap').createDevice(config)
dev_control = None
if vdi_image_path.startswith('tap'):
dev_control = self.getDeviceController('tap')
else:
dev_control = self.getDeviceController('vbd')
config['devid'] = dev_control.createDevice(config)
return dev_uuid
@@ -2103,6 +2245,47 @@ class XendDomainInfo:
return dev_uuid
def create_console(self, xenapi_console):
""" Create a console device from a Xen API struct.
@return: uuid of device
@rtype: string
"""
if self.state not in (DOM_STATE_HALTED,):
raise VmError("Can only add console to a halted domain.")
dev_uuid = self.info.device_add('console', cfg_xenapi = xenapi_console)
if not dev_uuid:
raise XendError('Failed to create device')
return dev_uuid
def destroy_device_by_uuid(self, dev_type, dev_uuid):
if dev_uuid not in self.info['devices']:
raise XendError('Device does not exist')
try:
if self.state == XEN_API_VM_POWER_STATE_RUNNING:
_, config = self.info['devices'][dev_uuid]
devid = config.get('devid')
if devid != None:
self.getDeviceController(dev_type).destroyDevice(devid, force = False)
else:
raise XendError('Unable to get devid for device: %s:%s' %
(dev_type, dev_uuid))
finally:
del self.info['devices'][dev_uuid]
self.info['%s_refs' % dev_type].remove(dev_uuid)
def destroy_vbd(self, dev_uuid):
self.destroy_device_by_uuid('vbd', dev_uuid)
def destroy_vif(self, dev_uuid):
self.destroy_device_by_uuid('vif', dev_uuid)
def destroy_vtpm(self, dev_uuid):
self.destroy_device_by_uuid('vtpm', dev_uuid)
def has_device(self, dev_class, dev_uuid):
return (dev_uuid in self.info['%s_refs' % dev_class.lower()])
+8
View File
@@ -43,6 +43,14 @@ class NetworkAlreadyConnected(XendError):
XendError.__init__(self, 'Network already connected')
self.pif_uuid = pif_uuid
class PIFIsPhysical(XendError):
def __init__(self):
XendError.__init__(self, 'PIF is physical')
class VLANTagInvalid(XendError):
def __init__(self):
XendError.__init__(self, 'VLAN tag invalid')
class VmError(XendError):
"""Vm construction error."""
pass
@@ -0,0 +1,94 @@
#!/usr/bin/python
#============================================================================
# This library is free software; you can redistribute it and/or
# modify it under the terms of version 2.1 of the GNU Lesser General Public
# License as published by the Free Software Foundation.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#============================================================================
# Copyright (C) 2007 XenSource Ltd.
#============================================================================
#
# A pseudo-StorageRepository to provide a representation for the images
# that can be specified by xm.
#
import commands
import logging
import os
import stat
import threading
import re
import sys
import struct
from xen.util import mkdir
from xen.xend import uuid
from xen.xend.XendError import XendError
from xen.xend.XendVDI import *
from xen.xend.XendTask import XendTask
from xen.xend.XendStorageRepository import XendStorageRepository
from xen.xend.XendStateStore import XendStateStore
from xen.xend.XendOptions import instance as xendoptions
MB = 1024 * 1024
log = logging.getLogger("xend.XendLocalStorageRepo")
class XendLocalStorageRepo(XendStorageRepository):
"""A backwards compatibility storage repository so that
traditional file:/dir/file.img and phy:/dev/hdxx images can
still be represented in terms of the Xen API.
"""
def __init__(self, sr_uuid, sr_type = 'local',
name_label = 'Local',
name_description = 'Traditional Local Storage Repo'):
"""
@ivar images: mapping of all the images.
@type images: dictionary by image uuid.
@ivar lock: lock to provide thread safety.
"""
XendStorageRepository.__init__(self, sr_uuid, sr_type,
name_label, name_description,
'/')
self.state = XendStateStore(xendoptions().get_xend_state_path()
+ '/local_sr')
stored_images = self.state.load_state('vdi')
if stored_images:
for image_uuid, image in stored_images.items():
self.images[image_uuid] = XendLocalVDI(image)
def create_vdi(self, vdi_struct):
""" Creates a fake VDI image for a traditional image string.
The image uri is stored in the attribute 'uri'
"""
vdi_struct['uuid'] = uuid.createString()
vdi_struct['SR'] = self.uuid
new_image = XendLocalVDI(vdi_struct)
self.images[new_image.uuid] = new_image
self.save_state()
return new_image.uuid
def save_state(self):
vdi_records = dict([(k, v.get_record(transient = False))
for k, v in self.images.items()])
self.state.save_state('vdi', vdi_records)
def destroy_vdi(self, vdi_uuid):
if vdi_uuid in self.images:
del self.images[vdi_uuid]
self.save_state()
+2 -2
View File
@@ -52,8 +52,8 @@ if 'TRACE' not in logging.__dict__:
for frame in frames:
filename = os.path.normcase(frame[1])
if filename != thisfile and filename != logging._srcfile:
major, minor, _, _, _ = sys.version_info
if major == 2 and minor >= 4:
major, minor, micro, _, _ = sys.version_info
if (major, minor, micro) >= (2, 4, 2):
return filename, frame[2], frame[3]
else:
return filename, frame[2]
+332
View File
@@ -0,0 +1,332 @@
#============================================================================
# This library is free software; you can redistribute it and/or
# modify it under the terms of version 2.1 of the GNU Lesser General Public
# License as published by the Free Software Foundation.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#============================================================================
# Copyright (C) 2007 XenSource Ltd.
#============================================================================
from xen.lowlevel.xc import xc
import time
import threading
import os
import re
"""Monitoring thread to keep track of Xend statistics. """
VBD_SYSFS_PATH = '/sys/devices/xen-backend/'
VBD_WR_PATH = VBD_SYSFS_PATH + '%s/statistics/wr_req'
VBD_RD_PATH = VBD_SYSFS_PATH + '%s/statistics/rd_req'
VBD_DOMAIN_RE = r'vbd-(?P<domid>\d+)-(?P<devid>\d+)$'
NET_PROCFS_PATH = '/proc/net/dev'
PROC_NET_DEV_RE = r'(?P<rx_bytes>\d+)\s+' \
r'(?P<rx_packets>\d+)\s+' \
r'(?P<rx_errs>\d+)\s+' \
r'(?P<rx_drop>\d+)\s+' \
r'(?P<rx_fifo>\d+)\s+' \
r'(?P<rx_frame>\d+)\s+' \
r'(?P<rx_compressed>\d+)\s+' \
r'(?P<rx_multicast>\d+)\s+' \
r'(?P<tx_bytes>\d+)\s+' \
r'(?P<tx_packets>\d+)\s+' \
r'(?P<tx_errs>\d+)\s+' \
r'(?P<tx_drop>\d+)\s+' \
r'(?P<tx_fifo>\d+)\s+' \
r'(?P<tx_collisions>\d+)\s+' \
r'(?P<tx_carrier>\d+)\s+' \
r'(?P<tx_compressed>\d+)\s*$'
VIF_DOMAIN_RE = re.compile(r'vif(?P<domid>\d+)\.(?P<iface>\d+):\s*' +
PROC_NET_DEV_RE)
PIF_RE = re.compile(r'^\s*(?P<iface>peth\d+):\s*' + PROC_NET_DEV_RE)
# The VBD transfer figures are in "requests" where we don't
# really know how many bytes per requests. For now we make
# up a number roughly could be.
VBD_ROUGH_BYTES_PER_REQUEST = 1024 * 8 * 4
# Interval to poll xc, sysfs and proc
POLL_INTERVAL = 2.0
class XendMonitor(threading.Thread):
"""Monitors VCPU, VBD, VIF and PIF statistics for Xen API.
Polls sysfs and procfs for statistics on VBDs and VIFs respectively.
@ivar domain_vcpus_util: Utilisation for VCPUs indexed by domain
@type domain_vcpus_util: {domid: {vcpuid: float, vcpuid: float}}
@ivar domain_vifs_util: Bytes per second for VIFs indexed by domain
@type domain_vifs_util: {domid: {vifid: (rx_bps, tx_bps)}}
@ivar domain_vbds_util: Blocks per second for VBDs index by domain.
@type domain_vbds_util: {domid: {vbdid: (rd_reqps, wr_reqps)}}
"""
def __init__(self):
threading.Thread.__init__(self)
self.setDaemon(True)
self.xc = xc()
self.lock = threading.Lock()
# tracks the last polled statistics
self._domain_vcpus = {}
self._domain_vifs = {}
self._domain_vbds = {}
self.pifs = {}
# instantaneous statistics
self._domain_vcpus_util = {}
self._domain_vifs_util = {}
self._domain_vbds_util = {}
self.pifs_util = {}
def get_domain_vcpus_util(self):
self.lock.acquire()
try:
return self._domain_vcpus_util
finally:
self.lock.release()
def get_domain_vbds_util(self):
self.lock.acquire()
try:
return self._domain_vbds_util
finally:
self.lock.release()
def get_domain_vifs_util(self):
self.lock.acquire()
try:
return self._domain_vifs_util
finally:
self.lock.release()
def get_pifs_util(self):
self.lock.acquire()
try:
return self.pifs_util
finally:
self.lock.release()
def _get_vif_stats(self):
stats = {}
if not os.path.exists(NET_PROCFS_PATH):
return stats
usage_at = time.time()
for line in open(NET_PROCFS_PATH):
is_vif = re.search(VIF_DOMAIN_RE, line.strip())
if not is_vif:
continue
domid = int(is_vif.group('domid'))
vifid = int(is_vif.group('iface'))
rx_bytes = int(is_vif.group('rx_bytes'))
tx_bytes = int(is_vif.group('tx_bytes'))
if not domid in stats:
stats[domid] = {}
stats[domid][vifid] = (usage_at, rx_bytes, tx_bytes)
return stats
def _get_pif_stats(self):
stats = {}
if not os.path.exists(NET_PROCFS_PATH):
return stats
usage_at = time.time()
for line in open(NET_PROCFS_PATH):
is_pif = re.search(PIF_RE, line.strip())
if not is_pif:
continue
pifname = is_pif.group('iface')
rx_bytes = int(is_pif.group('rx_bytes'))
tx_bytes = int(is_pif.group('tx_bytes'))
stats[pifname] = (usage_at, rx_bytes, tx_bytes)
return stats
def _get_vbd_stats(self):
stats = {}
if not os.path.exists(VBD_SYSFS_PATH):
return stats
for vbd_path in os.listdir(VBD_SYSFS_PATH):
is_vbd = re.search(VBD_DOMAIN_RE, vbd_path)
if not is_vbd:
continue
domid = int(is_vbd.group('domid'))
vbdid = int(is_vbd.group('devid'))
rd_stat_path = VBD_RD_PATH % vbd_path
wr_stat_path = VBD_WR_PATH % vbd_path
if not os.path.exists(rd_stat_path) or \
not os.path.exists(wr_stat_path):
continue
try:
usage_at = time.time()
rd_stat = int(open(rd_stat_path).readline().strip())
wr_stat = int(open(wr_stat_path).readline().strip())
rd_stat *= VBD_ROUGH_BYTES_PER_REQUEST
wr_stat *= VBD_ROUGH_BYTES_PER_REQUEST
if domid not in stats:
stats[domid] = {}
stats[domid][vbdid] = (usage_at, rd_stat, wr_stat)
except (IOError, ValueError):
continue
return stats
def _get_cpu_stats(self):
stats = {}
for domain in self.xc.domain_getinfo():
domid = domain['domid']
vcpu_count = domain['online_vcpus']
stats[domid] = {}
for i in range(vcpu_count):
vcpu_info = self.xc.vcpu_getinfo(domid, i)
usage = vcpu_info['cpu_time']
usage_at = time.time()
stats[domid][i] = (usage_at, usage)
return stats
def run(self):
# loop every second for stats
while True:
self.lock.acquire()
try:
active_domids = []
# Calculate utilisation for VCPUs
for domid, cputimes in self._get_cpu_stats().items():
active_domids.append(domid)
if domid not in self._domain_vcpus:
# if not initialised, save current stats
# and skip utilisation calculation
self._domain_vcpus[domid] = cputimes
self._domain_vcpus_util[domid] = {}
continue
for vcpu, (usage_at, usage) in cputimes.items():
if vcpu not in self._domain_vcpus[domid]:
continue
prv_usage_at, prv_usage = \
self._domain_vcpus[domid][vcpu]
interval_s = (usage_at - prv_usage_at) * 1000000000
if interval_s > 0:
util = (usage - prv_usage) / interval_s
self._domain_vcpus_util[domid][vcpu] = util
self._domain_vcpus[domid] = cputimes
# Calculate utilisation for VBDs
for domid, vbds in self._get_vbd_stats().items():
if domid not in self._domain_vbds:
self._domain_vbds[domid] = vbds
self._domain_vbds_util[domid] = {}
continue
for devid, (usage_at, rd, wr) in vbds.items():
if devid not in self._domain_vbds[domid]:
continue
prv_at, prv_rd, prv_wr = \
self._domain_vbds[domid][devid]
interval = usage_at - prv_at
rd_util = (rd - prv_rd)/interval
wr_util = (wr - prv_wr)/interval
self._domain_vbds_util[domid][devid] = \
(rd_util, wr_util)
self._domain_vbds[domid] = vbds
# Calculate utilisation for VIFs
for domid, vifs in self._get_vif_stats().items():
if domid not in self._domain_vifs:
self._domain_vifs[domid] = vifs
self._domain_vifs_util[domid] = {}
continue
for devid, (usage_at, rx, tx) in vifs.items():
if devid not in self._domain_vifs[domid]:
continue
prv_at, prv_rx, prv_tx = \
self._domain_vifs[domid][devid]
interval = usage_at - prv_at
rx_util = (rx - prv_rx)/interval
tx_util = (tx - prv_tx)/interval
# note these are flipped around because
# we are measuring the host interface,
# not the guest interface
self._domain_vifs_util[domid][devid] = \
(tx_util, rx_util)
self._domain_vifs[domid] = vifs
# Calculate utilisation for PIFs
for pifname, stats in self._get_pif_stats().items():
if pifname not in self.pifs:
self.pifs[pifname] = stats
continue
usage_at, rx, tx = stats
prv_at, prv_rx, prv_tx = self.pifs[pifname]
interval = usage_at - prv_at
rx_util = (rx - prv_rx)/interval
tx_util = (tx - prv_tx)/interval
self.pifs_util[pifname] = (rx_util, tx_util)
self.pifs[pifname] = stats
for domid in self._domain_vcpus_util.keys():
if domid not in active_domids:
del self._domain_vcpus_util[domid]
del self._domain_vcpus[domid]
for domid in self._domain_vifs_util.keys():
if domid not in active_domids:
del self._domain_vifs_util[domid]
del self._domain_vifs[domid]
for domid in self._domain_vbds_util.keys():
if domid not in active_domids:
del self._domain_vbds_util[domid]
del self._domain_vbds[domid]
finally:
self.lock.release()
# Sleep a while before next poll
time.sleep(POLL_INTERVAL)
+174 -35
View File
@@ -13,7 +13,7 @@
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#============================================================================
# Copyright (C) 2004, 2005 Mike Wray <mike.wray@hp.com>
# Copyright (c) 2006 Xensource Inc.
# Copyright (c) 2006, 2007 Xensource Inc.
#============================================================================
import os
@@ -23,13 +23,16 @@ import xen.lowlevel.xc
from xen.util import Brctl
from xen.xend import uuid
from xen.xend.XendError import XendError, NetworkAlreadyConnected
from xen.xend.XendRoot import instance as xendroot
from xen.xend.XendStorageRepository import XendStorageRepository
from xen.xend.XendError import *
from xen.xend.XendOptions import instance as xendoptions
from xen.xend.XendQCoWStorageRepo import XendQCoWStorageRepo
from xen.xend.XendLocalStorageRepo import XendLocalStorageRepo
from xen.xend.XendLogging import log
from xen.xend.XendPIF import *
from xen.xend.XendPIFMetrics import XendPIFMetrics
from xen.xend.XendNetwork import *
from xen.xend.XendStateStore import XendStateStore
from xen.xend.XendMonitor import XendMonitor
class XendNode:
"""XendNode - Represents a Domain 0 Host."""
@@ -37,15 +40,19 @@ class XendNode:
def __init__(self):
"""Initalises the state of all host specific objects such as
* Host
* Host_CPU
* host
* host_CPU
* host_metrics
* PIF
* Network
* PIF_metrics
* network
* Storage Repository
"""
self.xc = xen.lowlevel.xc.xc()
self.state_store = XendStateStore(xendroot().get_xend_state_path())
self.state_store = XendStateStore(xendoptions().get_xend_state_path())
self.monitor = XendMonitor()
self.monitor.start()
# load host state from XML file
saved_host = self.state_store.load_state('host')
@@ -54,12 +61,20 @@ class XendNode:
host = saved_host[self.uuid]
self.name = host.get('name_label', socket.gethostname())
self.desc = host.get('name_description', '')
self.host_metrics_uuid = host.get('metrics_uuid',
uuid.createString())
try:
self.other_config = eval(host['other_config'])
except:
self.other_config = {}
self.cpus = {}
else:
self.uuid = uuid.createString()
self.name = socket.gethostname()
self.desc = ''
self.other_config = {}
self.cpus = {}
self.host_metrics_uuid = uuid.createString()
# load CPU UUIDs
saved_cpus = self.state_store.load_state('cpu')
@@ -84,8 +99,10 @@ class XendNode:
self.cpus[cpu_uuid] = cpu_info
self.pifs = {}
self.pif_metrics = {}
self.networks = {}
self.srs = {}
# initialise networks
saved_networks = self.state_store.load_state('network')
if saved_networks:
@@ -103,11 +120,25 @@ class XendNode:
saved_pifs = self.state_store.load_state('pif')
if saved_pifs:
for pif_uuid, pif in saved_pifs.items():
if pif['network'] in self.networks:
if pif.get('network') in self.networks:
network = self.networks[pif['network']]
try:
self.PIF_create(pif['name'], pif['MTU'], pif['VLAN'],
pif['MAC'], network, False, pif_uuid)
if 'device' not in pif and 'name' in pif:
# Compatibility hack, can go pretty soon.
pif['device'] = pif['name']
if 'metrics' not in pif:
# Compatibility hack, can go pretty soon.
pif['metrics'] = uuid.createString()
try:
pif['VLAN'] = int(pif.get('VLAN', -1))
except (ValueError, TypeError):
pif['VLAN'] = -1
self._PIF_create(pif['device'], pif['MTU'],
pif['VLAN'],
pif['MAC'], network, False, pif_uuid,
pif['metrics'])
except NetworkAlreadyConnected, exn:
log.error('Cannot load saved PIF %s, as network %s ' +
'is already connected to PIF %s',
@@ -115,16 +146,26 @@ class XendNode:
else:
for name, mtu, mac in linux_get_phy_ifaces():
network = self.networks.values()[0]
self.PIF_create(name, mtu, '', mac, network, False)
self._PIF_create(name, mtu, -1, mac, network, False)
# initialise storage
saved_sr = self.state_store.load_state('sr')
if saved_sr and len(saved_sr) == 1:
sr_uuid = saved_sr.keys()[0]
self.sr = XendStorageRepository(sr_uuid)
else:
sr_uuid = uuid.createString()
self.sr = XendStorageRepository(sr_uuid)
saved_srs = self.state_store.load_state('sr')
if saved_srs:
for sr_uuid, sr_cfg in saved_srs.items():
if sr_cfg['type'] == 'qcow_file':
self.srs[sr_uuid] = XendQCoWStorageRepo(sr_uuid)
elif sr_cfg['type'] == 'local_image':
self.srs[sr_uuid] = XendLocalStorageRepo(sr_uuid)
# Create missing SRs if they don't exist
if not self.get_sr_by_type('local_image'):
image_sr_uuid = uuid.createString()
self.srs[image_sr_uuid] = XendLocalStorageRepo(image_sr_uuid)
if not self.get_sr_by_type('qcow_file'):
qcow_sr_uuid = uuid.createString()
self.srs[qcow_sr_uuid] = XendQCoWStorageRepo(qcow_sr_uuid)
def network_create(self, name_label, name_description,
@@ -146,16 +187,24 @@ class XendNode:
self.save_networks()
def PIF_create(self, name, mtu, vlan, mac, network, persist = True,
pif_uuid = None):
def _PIF_create(self, name, mtu, vlan, mac, network, persist = True,
pif_uuid = None, metrics_uuid = None):
for pif in self.pifs.values():
if pif.network == network:
raise NetworkAlreadyConnected(pif.uuid)
if pif_uuid is None:
pif_uuid = uuid.createString()
self.pifs[pif_uuid] = XendPIF(pif_uuid, name, mtu, vlan, mac, network,
self)
if metrics_uuid is None:
metrics_uuid = uuid.createString()
metrics = XendPIFMetrics(metrics_uuid)
pif = XendPIF(pif_uuid, metrics, name, mtu, vlan, mac, network, self)
metrics.set_PIF(pif)
self.pif_metrics[metrics_uuid] = metrics
self.pifs[pif_uuid] = pif
if persist:
self.save_PIFs()
self.refreshBridges()
@@ -163,12 +212,20 @@ class XendNode:
def PIF_create_VLAN(self, pif_uuid, network_uuid, vlan):
if vlan < 0 or vlan >= 4096:
raise VLANTagInvalid()
pif = self.pifs[pif_uuid]
network = self.networks[network_uuid]
return self.PIF_create(pif.name, pif.mtu, vlan, pif.mac, network)
return self._PIF_create(pif.device, pif.mtu, vlan, pif.mac, network)
def PIF_destroy(self, pif_uuid):
pif = self.pifs[pif_uuid]
if pif.vlan == -1:
raise PIFIsPhysical()
del self.pifs[pif_uuid]
self.save_PIFs()
@@ -176,17 +233,17 @@ class XendNode:
def save(self):
# save state
host_record = {self.uuid: {'name_label':self.name,
'name_description':self.desc}}
'name_description':self.desc,
'metrics_uuid': self.host_metrics_uuid,
'other_config': repr(self.other_config)}}
self.state_store.save_state('host',host_record)
self.state_store.save_state('cpu', self.cpus)
self.save_PIFs()
self.save_networks()
sr_record = {self.sr.uuid: self.sr.get_record()}
self.state_store.save_state('sr', sr_record)
self.save_SRs()
def save_PIFs(self):
pif_records = dict([(k, v.get_record(transient = False))
pif_records = dict([(k, v.get_record())
for k, v in self.pifs.items()])
self.state_store.save_state('pif', pif_records)
@@ -195,6 +252,11 @@ class XendNode:
for k, v in self.networks.items()])
self.state_store.save_state('network', net_records)
def save_SRs(self):
sr_records = dict([(k, v.get_record(transient = False))
for k, v in self.srs.items()])
self.state_store.save_state('sr', sr_records)
def shutdown(self):
return 0
@@ -203,7 +265,6 @@ class XendNode:
def notify(self, _):
return 0
#
# Ref validation
@@ -218,12 +279,50 @@ class XendNode:
def is_valid_network(self, network_ref):
return (network_ref in self.networks)
def is_valid_sr(self, sr_ref):
return (sr_ref in self.srs)
def is_valid_vdi(self, vdi_ref):
for sr in self.srs.values():
if sr.is_valid_vdi(vdi_ref):
return True
return False
#
# Storage Repo
# Storage Repositories
#
def get_sr(self):
return self.sr
def get_sr(self, sr_uuid):
return self.srs.get(sr_uuid)
def get_sr_by_type(self, sr_type):
return [sr.uuid for sr in self.srs.values() if sr.type == sr_type]
def get_sr_by_name(self, name):
return [sr.uuid for sr in self.srs.values() if sr.name_label == name]
def get_all_sr_uuid(self):
return self.srs.keys()
def get_vdi_by_uuid(self, vdi_uuid):
for sr in self.srs.values():
if sr.is_valid_vdi(vdi_uuid):
return sr.get_vdi_by_uuid(vdi_uuid)
return None
def get_vdi_by_name_label(self, name):
for sr in self.srs.values():
vdi = sr.get_vdi_by_name_label(name)
if vdi:
return vdi
return None
def get_sr_containing_vdi(self, vdi_uuid):
for sr in self.srs.values():
if sr.is_valid_vdi(vdi_uuid):
return sr
return None
#
# Host Functions
@@ -285,8 +384,16 @@ class XendNode:
raise XendError('Invalid CPU Reference')
def get_host_cpu_load(self, host_cpu_ref):
return 0.0
host_cpu = self.cpus.get(host_cpu_ref)
if not host_cpu:
return 0.0
vcpu = int(host_cpu['number'])
cpu_loads = self.monitor.get_domain_vcpus_util()
if 0 in cpu_loads and vcpu in cpu_loads[0]:
return cpu_loads[0][vcpu]
return 0.0
#
# Network Functions
@@ -365,14 +472,24 @@ class XendNode:
return [[k, info[k]] for k in ITEM_ORDER]
def xenschedinfo(self):
sched_id = self.xc.sched_id_get()
if sched_id == xen.lowlevel.xc.XEN_SCHEDULER_SEDF:
return 'sedf'
elif sched_id == xen.lowlevel.xc.XEN_SCHEDULER_CREDIT:
return 'credit'
else:
return 'unknown'
def xeninfo(self):
info = self.xc.xeninfo()
info['xen_scheduler'] = self.xenschedinfo()
ITEM_ORDER = ['xen_major',
'xen_minor',
'xen_extra',
'xen_caps',
'xen_scheduler',
'xen_pagesize',
'platform_params',
'xen_changeset',
@@ -387,6 +504,28 @@ class XendNode:
def xendinfo(self):
return [['xend_config_format', 3]]
#
# utilisation tracking
#
def get_vcpu_util(self, domid, vcpuid):
cpu_loads = self.monitor.get_domain_vcpus_util()
if domid in cpu_loads:
return cpu_loads[domid].get(vcpuid, 0.0)
return 0.0
def get_vif_util(self, domid, vifid):
vif_loads = self.monitor.get_domain_vifs_util()
if domid in vif_loads:
return vif_loads[domid].get(vifid, (0.0, 0.0))
return (0.0, 0.0)
def get_vbd_util(self, domid, vbdid):
vbd_loads = self.monitor.get_domain_vbds_util()
if domid in vbd_loads:
return vbd_loads[domid].get(vbdid, (0.0, 0.0))
return (0.0, 0.0)
# dictionary version of *info() functions to get rid of
# SXPisms.
def nodeinfo_dict(self):
@@ -20,7 +20,7 @@
Creates the servers and handles configuration.
Other classes get config variables by importing this module,
using instance() to get a XendRoot instance, and then
using instance() to get a XendOptions instance, and then
the config functions (e.g. get_xend_port()) to get
configured values.
"""
@@ -33,14 +33,11 @@ import sys
from xen.xend import sxp, osdep, XendLogging
from xen.xend.XendError import XendError
class XendRoot:
"""Root of the management classes."""
if os.uname()[0] == 'SunOS':
from xen.lowlevel import scf
"""Default path to the config file."""
config_default = "/etc/xen/xend-config.sxp"
"""Environment variable used to override config_default."""
config_var = "XEND_CONFIG"
class XendOptions:
"""Configuration options."""
"""Where network control scripts live."""
network_script_dir = osdep.scripts_dir
@@ -63,6 +60,10 @@ class XendRoot:
xend_tcp_xmlrpc_server_default = 'no'
xend_tcp_xmlrpc_server_address_default = 'localhost'
xend_tcp_xmlrpc_server_port_default = 8006
xend_unix_xmlrpc_server_default = 'yes'
"""Default interface address xend listens at. """
@@ -75,10 +76,10 @@ class XendRoot:
xend_relocation_address_default = ''
"""Default port xend serves HTTP at. """
xend_port_default = '8000'
xend_port_default = 8000
"""Default port xend serves relocation at. """
xend_relocation_port_default = '8002'
xend_relocation_port_default = 8002
xend_relocation_hosts_allow_default = ''
@@ -92,9 +93,9 @@ class XendRoot:
"""Default path the unix-domain server listens at."""
xend_unix_path_default = '/var/lib/xend/xend-socket'
dom0_min_mem_default = '0'
dom0_min_mem_default = 0
dom0_vcpus_default = '0'
dom0_vcpus_default = 0
vncpasswd_default = None
@@ -107,16 +108,20 @@ class XendRoot:
"""Default xend management state storage."""
xend_state_path_default = '/var/lib/xend/state'
components = {}
"""Default xend QCoW storage repository location."""
xend_storage_path_default = '/var/lib/xend/storage'
"""Default type of backend network interfaces"""
netback_type = osdep.netback_type
"""Default script to configure a backend network interface"""
vif_script = osdep.vif_script
def __init__(self):
self.config_path = None
self.config = None
self.configure()
def _logError(self, fmt, *args):
"""Logging function to log to stderr. We use this for XendRoot log
"""Logging function to log to stderr. We use this for XendOptions log
messages because they may be logged before the logger has been
configured. Other components can safely use the logger.
"""
@@ -125,11 +130,155 @@ class XendRoot:
def configure(self):
self.set_config()
XendLogging.init(self.get_config_value("logfile",
XendLogging.init(self.get_config_string("logfile",
self.logfile_default),
self.get_config_value("loglevel",
self.get_config_string("loglevel",
self.loglevel_default))
def set_config(self):
raise NotImplementedError()
def get_config_bool(self, name, val=None):
raise NotImplementedError()
def get_config_int(self, name, val=None):
raise NotImplementedError()
def get_config_string(self, name, val=None):
raise NotImplementedError()
def get_xen_api_server(self):
raise NotImplementedError()
def get_xend_http_server(self):
"""Get the flag indicating whether xend should run an http server.
"""
return self.get_config_bool("xend-http-server", self.xend_http_server_default)
def get_xend_tcp_xmlrpc_server(self):
return self.get_config_bool("xend-tcp-xmlrpc-server",
self.xend_tcp_xmlrpc_server_default)
def get_xend_tcp_xmlrpc_server_port(self):
return self.get_config_int("xend-tcp-xmlrpc-server-port",
self.xend_tcp_xmlrpc_server_port_default)
def get_xend_tcp_xmlrpc_server_address(self):
return self.get_config_string("xend-tcp-xmlrpc-server-address",
self.xend_tcp_xmlrpc_server_address_default)
def get_xend_unix_xmlrpc_server(self):
return self.get_config_bool("xend-unix-xmlrpc-server",
self.xend_unix_xmlrpc_server_default)
def get_xend_relocation_server(self):
"""Get the flag indicating whether xend should run a relocation server.
"""
return self.get_config_bool("xend-relocation-server",
self.xend_relocation_server_default)
def get_xend_port(self):
"""Get the port xend listens at for its HTTP interface.
"""
return self.get_config_int('xend-port', self.xend_port_default)
def get_xend_relocation_port(self):
"""Get the port xend listens at for connection to its relocation server.
"""
return self.get_config_int('xend-relocation-port',
self.xend_relocation_port_default)
def get_xend_relocation_hosts_allow(self):
return self.get_config_string("xend-relocation-hosts-allow",
self.xend_relocation_hosts_allow_default)
def get_xend_address(self):
"""Get the address xend listens at for its HTTP port.
This defaults to the empty string which allows all hosts to connect.
If this is set to 'localhost' only the localhost will be able to connect
to the HTTP port.
"""
return self.get_config_string('xend-address', self.xend_address_default)
def get_xend_relocation_address(self):
"""Get the address xend listens at for its relocation server port.
This defaults to the empty string which allows all hosts to connect.
If this is set to 'localhost' only the localhost will be able to connect
to the relocation port.
"""
return self.get_config_string('xend-relocation-address', self.xend_relocation_address_default)
def get_xend_unix_server(self):
"""Get the flag indicating whether xend should run a unix-domain server.
"""
return self.get_config_bool("xend-unix-server", self.xend_unix_server_default)
def get_xend_unix_path(self):
"""Get the path the xend unix-domain server listens at.
"""
return self.get_config_string("xend-unix-path", self.xend_unix_path_default)
def get_xend_domains_path(self):
""" Get the path for persistent domain configuration storage
"""
return self.get_config_string("xend-domains-path", self.xend_domains_path_default)
def get_xend_state_path(self):
""" Get the path for persistent domain configuration storage
"""
return self.get_config_string("xend-state-path", self.xend_state_path_default)
def get_xend_storage_path(self):
""" Get the path for persistent domain configuration storage
"""
return self.get_config_string("xend-storage-path", self.xend_storage_path_default)
def get_network_script(self):
"""@return the script used to alter the network configuration when
Xend starts and stops, or None if no such script is specified."""
s = self.get_config_string('network-script')
if s:
result = s.split(" ")
result[0] = os.path.join(self.network_script_dir, result[0])
return result
else:
return None
def get_external_migration_tool(self):
"""@return the name of the tool to handle virtual TPM migration."""
return self.get_config_string('external-migration-tool', self.external_migration_tool_default)
def get_enable_dump(self):
return self.get_config_bool('enable-dump', 'no')
def get_vif_script(self):
return self.get_config_string('vif-script', self.vif_script)
def get_dom0_min_mem(self):
return self.get_config_int('dom0-min-mem', self.dom0_min_mem_default)
def get_dom0_vcpus(self):
return self.get_config_int('dom0-cpus', self.dom0_vcpus_default)
def get_console_limit(self):
return self.get_config_int('console-limit', 1024)
def get_vnclisten_address(self):
return self.get_config_string('vnc-listen', self.xend_vnc_listen_default)
def get_vncpasswd_default(self):
return self.get_config_string('vncpasswd',
self.vncpasswd_default)
class XendOptionsFile(XendOptions):
"""Default path to the config file."""
config_default = "/etc/xen/xend-config.sxp"
"""Environment variable used to override config_default."""
config_var = "XEND_CONFIG"
def set_config(self):
"""If the config file exists, read it. If not, ignore it.
@@ -158,19 +307,6 @@ class XendRoot:
self.config_path)
self.config = ['xend-config']
def get_config(self, name=None):
"""Get the configuration element with the given name, or
the whole configuration if no name is given.
@param name: element name (optional)
@return: config or none
"""
if name is None:
val = self.config
else:
val = sxp.child(self.config, name)
return val
def get_config_value(self, name, val=None):
"""Get the value of an atomic configuration element.
@@ -195,128 +331,63 @@ class XendRoot:
except Exception:
raise XendError("invalid xend config %s: expected int: %s" % (name, v))
def get_config_string(self, name, val=None):
return self.get_config_value(name, val)
def get_xen_api_server(self):
"""Get the Xen-API server configuration.
"""
return self.get_config_value('xen-api-server',
self.xen_api_server_default)
def get_xend_http_server(self):
"""Get the flag indicating whether xend should run an http server.
"""
return self.get_config_bool("xend-http-server", self.xend_http_server_default)
if os.uname()[0] == 'SunOS':
class XendOptionsSMF(XendOptions):
def get_xend_tcp_xmlrpc_server(self):
return self.get_config_bool("xend-tcp-xmlrpc-server",
self.xend_tcp_xmlrpc_server_default)
def set_config(self):
pass
def get_xend_unix_xmlrpc_server(self):
return self.get_config_bool("xend-unix-xmlrpc-server",
self.xend_unix_xmlrpc_server_default)
def get_config_bool(self, name, val=None):
try:
return scf.get_bool(name)
except scf.error, e:
if e[0] == scf.SCF_ERROR_NOT_FOUND:
return val
else:
raise XendError("option %s: %s:%s" % (name, e[1], e[2]))
def get_xend_relocation_server(self):
"""Get the flag indicating whether xend should run a relocation server.
"""
return self.get_config_bool("xend-relocation-server",
self.xend_relocation_server_default)
def get_config_int(self, name, val=None):
try:
return scf.get_int(name)
except scf.error, e:
if e[0] == scf.SCF_ERROR_NOT_FOUND:
return val
else:
raise XendError("option %s: %s:%s" % (name, e[1], e[2]))
def get_xend_port(self):
"""Get the port xend listens at for its HTTP interface.
"""
return self.get_config_int('xend-port', self.xend_port_default)
def get_config_string(self, name, val=None):
try:
return scf.get_string(name)
except scf.error, e:
if e[0] == scf.SCF_ERROR_NOT_FOUND:
return val
else:
raise XendError("option %s: %s:%s" % (name, e[1], e[2]))
def get_xend_relocation_port(self):
"""Get the port xend listens at for connection to its relocation server.
"""
return self.get_config_int('xend-relocation-port',
self.xend_relocation_port_default)
def get_xend_relocation_hosts_allow(self):
return self.get_config_value("xend-relocation-hosts-allow",
self.xend_relocation_hosts_allow_default)
def get_xend_address(self):
"""Get the address xend listens at for its HTTP port.
This defaults to the empty string which allows all hosts to connect.
If this is set to 'localhost' only the localhost will be able to connect
to the HTTP port.
"""
return self.get_config_value('xend-address', self.xend_address_default)
def get_xend_relocation_address(self):
"""Get the address xend listens at for its relocation server port.
This defaults to the empty string which allows all hosts to connect.
If this is set to 'localhost' only the localhost will be able to connect
to the relocation port.
"""
return self.get_config_value('xend-relocation-address', self.xend_relocation_address_default)
def get_xend_unix_server(self):
"""Get the flag indicating whether xend should run a unix-domain server.
"""
return self.get_config_bool("xend-unix-server", self.xend_unix_server_default)
def get_xend_unix_path(self):
"""Get the path the xend unix-domain server listens at.
"""
return self.get_config_value("xend-unix-path", self.xend_unix_path_default)
def get_xend_domains_path(self):
""" Get the path for persistent domain configuration storage
"""
return self.get_config_value("xend-domains-path", self.xend_domains_path_default)
def get_xend_state_path(self):
""" Get the path for persistent domain configuration storage
"""
return self.get_config_value("xend-state-path", self.xend_state_path_default)
def get_network_script(self):
"""@return the script used to alter the network configuration when
Xend starts and stops, or None if no such script is specified."""
s = self.get_config_value('network-script')
if s:
result = s.split(" ")
result[0] = os.path.join(self.network_script_dir, result[0])
return result
else:
return None
def get_external_migration_tool(self):
"""@return the name of the tool to handle virtual TPM migration."""
return self.get_config_value('external-migration-tool', self.external_migration_tool_default)
def get_enable_dump(self):
return self.get_config_bool('enable-dump', 'no')
def get_vif_script(self):
return self.get_config_value('vif-script', 'vif-bridge')
def get_dom0_min_mem(self):
return self.get_config_int('dom0-min-mem', self.dom0_min_mem_default)
def get_dom0_vcpus(self):
return self.get_config_int('dom0-cpus', self.dom0_vcpus_default)
def get_console_limit(self):
return self.get_config_int('console-limit', 1024)
def get_vnclisten_address(self):
return self.get_config_value('vnc-listen', self.xend_vnc_listen_default)
def get_vncpasswd_default(self):
return self.get_config_value('vncpasswd',
self.vncpasswd_default)
def get_xen_api_server(self):
# When the new server is a supported configuration, we should
# expand this.
return [["unix"]]
def instance():
"""Get an instance of XendRoot.
"""Get an instance of XendOptions.
Use this instead of the constructor.
"""
global inst
try:
inst
except:
inst = XendRoot()
if os.uname()[0] == 'SunOS':
inst = XendOptionsSMF()
else:
inst = XendOptionsFile()
return inst
+23 -29
View File
@@ -90,18 +90,20 @@ def linux_set_mtu(iface, mtu):
class XendPIF:
"""Representation of a Physical Network Interface."""
def __init__(self, uuid, name, mtu, vlan, mac, network, host):
def __init__(self, uuid, metrics, device, mtu, vlan, mac, network,
host):
self.uuid = uuid
self.name = name
self.metrics = metrics
self.device = device
self.mac = mac
self.mtu = mtu
self.vlan = vlan
self.network = network
self.host = host
def set_name(self, new_name):
self.name = new_name
def set_device(self, new_device):
self.device = new_device
def set_mac(self, new_mac):
success = linux_set_mac(new_mac)
if success:
@@ -114,24 +116,15 @@ class XendPIF:
self.mtu = new_mtu
return success
def get_io_read_kbs(self):
return 0.0
def get_io_write_kbs(self):
return 0.0
def get_record(self, transient = True):
result = {'name': self.name,
'MAC': self.mac,
'MTU': self.mtu,
'VLAN': self.vlan,
'host': self.host.uuid,
'network': self.network.uuid}
if transient:
result['io_read_kbs'] = self.get_io_read_kbs()
result['io_write_kbs'] = self.get_io_write_kbs()
return result
def get_record(self):
return {'uuid': self.uuid,
'device': self.device,
'MAC': self.mac,
'MTU': self.mtu,
'VLAN': self.vlan,
'host': self.host.uuid,
'network': self.network.uuid,
'metrics': self.metrics.uuid}
def refresh(self, bridges):
ifname = self.interface_name()
@@ -141,13 +134,14 @@ class XendPIF:
# there's nothing we can do -- this should have been set up with
# the network script. Otherwise, we can use vconfig to derive
# a subinterface.
if not self.vlan:
if self.vlan == -1:
return
rc, _ = _cmd('vconfig add %s %s', self.name, self.vlan)
rc, _ = _cmd('vconfig add %s %d', self.device, self.vlan)
if rc != 0:
log.error('Could not refresh %s', ifname)
log.error('Could not refresh VLAN for interface %s', ifname)
return
log.info('Created network interface %s', ifname)
for brname, nics in bridges.items():
@@ -173,10 +167,10 @@ class XendPIF:
def interface_name(self):
if self.vlan:
return '%s.%s' % (self.name, self.vlan)
if self.vlan != -1:
return '%s.%d' % (self.device, self.vlan)
else:
return self.name
return self.device
def _cmd(cmd, *args):
+47
View File
@@ -0,0 +1,47 @@
#============================================================================
# This library is free software; you can redistribute it and/or
# modify it under the terms of version 2.1 of the GNU Lesser General Public
# License as published by the Free Software Foundation.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#============================================================================
# Copyright (c) 2006-2007 Xensource Inc.
#============================================================================
class XendPIFMetrics:
"""PIF Metrics."""
def __init__(self, uuid):
self.uuid = uuid
def set_PIF(self, pif):
self.pif = pif
def get_io_read_kbs(self):
return self._get_stat(0)
def get_io_write_kbs(self):
return self._get_stat(1)
def _get_stat(self, n):
from xen.xend.XendNode import instance as xennode
pifname = self.pif.device
pifs_util = xennode().monitor.get_pifs_util()
if pifname in pifs_util:
return pifs_util[pifname][n]
return 0.0
def get_record(self):
return {'uuid' : self.uuid,
'PIF' : self.pif.uuid,
'io_read_kbs' : self.get_io_read_kbs(),
'io_write_kbs' : self.get_io_write_kbs()
}
+3 -3
View File
@@ -24,7 +24,7 @@ import types
from encode import *
from xen.xend import sxp
from xen.xend import XendRoot
from xen.xend import XendOptions
DEBUG = 0
@@ -34,7 +34,7 @@ HTTP_ACCEPTED = 202
HTTP_NO_CONTENT = 204
xroot = XendRoot.instance()
xoptions = XendOptions.instance()
class XendError(RuntimeError):
@@ -218,7 +218,7 @@ class UnixXendClientProtocol(HttpXendClientProtocol):
def __init__(self, path=None):
if path is None:
path = xroot.get_xend_unix_path()
path = xoptions.get_xend_unix_path()
self.path = path
def makeConnection(self, _):
@@ -0,0 +1,366 @@
#!/usr/bin/python
#============================================================================
# This library is free software; you can redistribute it and/or
# modify it under the terms of version 2.1 of the GNU Lesser General Public
# License as published by the Free Software Foundation.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#============================================================================
# Copyright (C) 2006,2007 XenSource Ltd.
#============================================================================
#
# The default QCOW Xen API Storage Repository
#
import commands
import logging
import os
import stat
import threading
import re
import sys
import struct
from xen.util import mkdir
from xen.xend import uuid
from xen.xend.XendError import XendError
from xen.xend.XendVDI import *
from xen.xend.XendTask import XendTask
from xen.xend.XendStorageRepository import XendStorageRepository
from xen.xend.XendOptions import instance as xendoptions
XEND_STORAGE_NO_MAXIMUM = sys.maxint
XEND_STORAGE_QCOW_FILENAME = "%s.qcow"
XEND_STORAGE_VDICFG_FILENAME = "%s.vdi.xml"
QCOW_CREATE_COMMAND = "/usr/sbin/qcow-create -r %d %s"
MB = 1024 * 1024
log = logging.getLogger("xend.XendQCowStorageRepo")
def qcow_virtual_size(qcow_file):
"""Read the first 32 bytes of the QCoW header to determine its size.
See: http://www.gnome.org/~markmc/qcow-image-format.html.
"""
try:
qcow_header = open(qcow_file, 'rb').read(32)
parts = struct.unpack('>IIQIIQ', qcow_header)
return parts[-1]
except IOError:
return -1
class XendQCoWStorageRepo(XendStorageRepository):
"""A simple file backed QCOW Storage Repository.
This class exposes the interface to create VDI's via the
Xen API. The backend is a file-backed QCOW format that is stored
in XEND_STORAGE_DIR or any that is specified in the constructor.
The actual images are created in the format <uuid>.img and <uuid>.qcow.
"""
def __init__(self, sr_uuid,
sr_type = "qcow_file",
name_label = "QCoW",
name_description = "Xend QCoW Storage Repository",
location = xendoptions().get_xend_storage_path(),
storage_max = XEND_STORAGE_NO_MAXIMUM):
"""
@keyword storage_max: Maximum disk space to use in bytes.
@type storage_max: int
@ivar storage_free: storage space free for this repository
@ivar images: mapping of all the images.
@type images: dictionary by image uuid.
@ivar lock: lock to provide thread safety.
"""
XendStorageRepository.__init__(self, sr_uuid, sr_type, name_label,
name_description, location,
storage_max)
self.storage_free = 0
self._refresh()
def get_record(self, transient = True):
retval = {'uuid': self.uuid,
'name_label': self.name_label,
'name_description': self.name_description,
'virtual_allocation': self.virtual_allocation,
'physical_utilisation': self.physical_utilisation,
'physical_size': self.physical_size,
'type': self.type,
'location': self.location,
'VDIs': self.images.keys()}
if self.physical_size == XEND_STORAGE_NO_MAXIMUM:
stfs = os.statvfs(self.location)
retval['physical_size'] = stfs.f_blocks * stfs.f_frsize
return retval
def _refresh(self):
"""Internal function that refreshes the state of the disk and
updates the list of images available.
"""
self.lock.acquire()
try:
mkdir.parents(self.location, stat.S_IRWXU)
# scan the directory and populate self.images
virtual_alloc = 0
physical_used = 0
seen_images = []
for filename in os.listdir(self.location):
if filename[-5:] == XEND_STORAGE_QCOW_FILENAME[-5:]:
image_uuid = filename[:-5]
seen_images.append(image_uuid)
qcow_file = XEND_STORAGE_QCOW_FILENAME % image_uuid
cfg_file = XEND_STORAGE_VDICFG_FILENAME % image_uuid
qcow_path = os.path.join(self.location, qcow_file)
cfg_path = os.path.join(self.location, cfg_file)
phys_size = os.stat(qcow_path).st_size
virt_size = qcow_virtual_size(qcow_path)
# add this image if we haven't seen it before
if image_uuid not in self.images:
vdi = XendQCoWVDI(image_uuid, self.uuid,
qcow_path, cfg_path,
virt_size, phys_size)
if cfg_path and os.path.exists(cfg_path):
try:
vdi.load_config(cfg_path)
except:
log.error('Corrupt VDI configuration file %s' %
cfg_path)
self.images[image_uuid] = vdi
physical_used += phys_size
virtual_alloc += virt_size
# remove images that aren't valid
for image_uuid in self.images.keys():
if image_uuid not in seen_images:
try:
os.unlink(self.images[image_uuid].qcow_path)
except OSError:
pass
del self.images[image_uuid]
self.virtual_allocation = virtual_alloc
self.physical_utilisation = physical_used
# update free storage if we have to track that
if self.physical_size == XEND_STORAGE_NO_MAXIMUM:
self.storage_free = self._get_free_space()
else:
self.storage_free = self.physical_size - self.virtual_allocation
finally:
self.lock.release()
def _get_free_space(self):
"""Returns the amount of free space in bytes available in the storage
partition. Note that this may not be used if the storage repository
is initialised with a maximum size in storage_max.
@rtype: int
"""
stfs = os.statvfs(self.location)
return stfs.f_bavail * stfs.f_frsize
def _has_space_available_for(self, size_bytes):
"""Returns whether there is enough space for an image in the
partition which the storage_dir resides on.
@rtype: bool
"""
if self.physical_size != XEND_STORAGE_NO_MAXIMUM:
return self.storage_free > size_bytes
bytes_free = self._get_free_space()
if size_bytes < bytes_free:
return True
return False
def _create_image_files(self, desired_size_bytes):
"""Create an image and return its assigned UUID.
@param desired_size_bytes: Desired image size in bytes
@type desired_size_bytes: int
@rtype: string
@return: uuid
@raises XendError: If an error occurs.
"""
self.lock.acquire()
try:
if not self._has_space_available_for(desired_size_bytes):
raise XendError("Not enough space")
image_uuid = uuid.createString()
qcow_path = os.path.join(self.location,
XEND_STORAGE_QCOW_FILENAME % image_uuid)
if qcow_path and os.path.exists(qcow_path):
raise XendError("Image with same UUID alreaady exists:" %
image_uuid)
cmd = QCOW_CREATE_COMMAND % (desired_size_bytes/MB, qcow_path)
rc, output = commands.getstatusoutput(cmd)
if rc != 0:
# cleanup the image file
os.unlink(qcow_path)
raise XendError("Failed to create QCOW Image: %s" % output)
self._refresh()
return image_uuid
finally:
self.lock.release()
def destroy_vdi(self, image_uuid):
"""Destroy an image that is managed by this storage repository.
@param image_uuid: Image UUID
@type image_uuid: String
@rtype: String
"""
self.lock.acquire()
try:
if image_uuid in self.images:
# TODO: check if it is being used?
qcow_path = self.images[image_uuid].qcow_path
cfg_path = self.images[image_uuid].cfg_path
try:
os.unlink(qcow_path)
if cfg_path and os.path.exists(cfg_path):
os.unlink(cfg_path)
except OSError:
log.exception("Failed to destroy image")
del self.images[image_uuid]
return True
finally:
self.lock.release()
return False
def list_images(self):
""" List all the available images by UUID.
@rtype: list of strings.
@return: list of UUIDs
"""
self.lock.acquire()
try:
return self.images.keys()
finally:
self.lock.release()
def free_space_bytes(self):
"""Returns the amount of available space in KB.
@rtype: int
"""
self.lock.acquire()
try:
return self.storage_free
finally:
self.lock.release()
def total_space_bytes(self):
"""Returns the total usable space of the storage repo in KB.
@rtype: int
"""
self.lock.acquire()
try:
if self.physical_size == XEND_STORAGE_NO_MAXIMUM:
stfs = os.statvfs(self.location)
return stfs.f_blocks * stfs.f_frsize
else:
return self.physical_size
finally:
self.lock.release()
def used_space_bytes(self):
"""Returns the total amount of space used by this storage repository.
@rtype: int
"""
self.lock.acquire()
try:
return self.physical_utilisation
finally:
self.lock.release()
def virtual_allocation(self):
"""Returns the total virtual space allocated within the storage repo.
@rtype: int
"""
self.lock.acquire()
try:
return self.virtual_allocation
finally:
self.lock.release()
def create_vdi(self, vdi_struct):
image_uuid = None
try:
sector_count = int(vdi_struct.get('virtual_size', 0))
sector_size = int(vdi_struct.get('sector_size', 1024))
size_bytes = (sector_count * sector_size)
image_uuid = self._create_image_files(size_bytes)
image = self.images[image_uuid]
image_cfg = {
'sector_size': sector_size,
'virtual_size': sector_count,
'type': vdi_struct.get('type', 'system'),
'name_label': vdi_struct.get('name_label', ''),
'name_description': vdi_struct.get('name_description', ''),
'sharable': bool(vdi_struct.get('sharable', False)),
'read_only': bool(vdi_struct.get('read_only', False)),
}
# load in configuration from vdi_struct
image.load_config_dict(image_cfg)
# save configuration to file
cfg_filename = XEND_STORAGE_VDICFG_FILENAME % image_uuid
cfg_path = os.path.join(self.location, cfg_filename)
image.save_config(cfg_path)
except Exception, e:
# cleanup before raising exception
if image_uuid:
self.destroy_vdi(image_uuid)
raise
return image_uuid
# remove everything below this line!! for testing only
if __name__ == "__main__":
xsr = XendStorageRepository()
print 'Free Space: %d MB' % (xsr.free_space_bytes()/MB)
print "Create Image:",
print xsr._create_image_files(10 * MB)
print 'Delete all images:'
for image_uuid in xsr.list_images():
print image_uuid,
xsr._destroy_image_files(image_uuid)
print
+1 -1
View File
@@ -107,7 +107,7 @@ class XendStateStore:
if child.nodeType != Node.ELEMENT_NODE:
continue # skip non element nodes
uuid = child.getAttribute('uuid')
uuid = child.getAttribute('uuid').encode('utf8')
cls_dict = {}
for val_elem in child.childNodes:
if val_elem.nodeType != Node.ELEMENT_NODE:
+31 -320
View File
@@ -13,65 +13,28 @@
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#============================================================================
# Copyright (C) 2006 XenSource Ltd.
# Copyright (C) 2006, 2007 XenSource Ltd.
#============================================================================
#
# The default QCOW Xen API Storage Repository
# Abstract class for XendStorageRepositories
#
import commands
import logging
import os
import stat
import threading
import re
import sys
import struct
from xen.util import mkdir
from xen.xend import uuid
from xen.xend.XendError import XendError
from xen.xend.XendVDI import *
XEND_STORAGE_NO_MAXIMUM = sys.maxint
XEND_STORAGE_DIR = "/var/lib/xend/storage/"
XEND_STORAGE_QCOW_FILENAME = "%s.qcow"
XEND_STORAGE_VDICFG_FILENAME = "%s.vdi.xml"
QCOW_CREATE_COMMAND = "/usr/sbin/qcow-create -r %d %s"
MB = 1024 * 1024
log = logging.getLogger("xend.XendStorageRepository")
def qcow_virtual_size(qcow_file):
"""Read the first 32 bytes of the QCoW header to determine its size.
See: http://www.gnome.org/~markmc/qcow-image-format.html.
"""
try:
qcow_header = open(qcow_file, 'rb').read(32)
parts = struct.unpack('>IIQIIQ', qcow_header)
return parts[-1]
except IOError:
return -1
class XendStorageRepository:
"""A simple file backed QCOW Storage Repository.
""" Base class for Storage Repos. """
This class exposes the interface to create VDI's via the
Xen API. The backend is a file-backed QCOW format that is stored
in XEND_STORAGE_DIR or any that is specified in the constructor.
The actual images are created in the format <uuid>.img and <uuid>.qcow.
"""
def __init__(self, uuid,
sr_type = "qcow_file",
name_label = "Local",
name_description = "Xend Storage Repository",
location = XEND_STORAGE_DIR,
sr_type = "unknown",
name_label = 'Unknown',
name_description = 'Not Implemented',
location = '',
storage_max = XEND_STORAGE_NO_MAXIMUM):
"""
@keyword storage_max: Maximum disk space to use in bytes.
@@ -91,303 +54,51 @@ class XendStorageRepository:
self.name_description = name_description
self.images = {}
self.storage_max = storage_max
self.storage_free = 0
self.storage_used = 0
self.storage_alloc = 0
self.physical_size = storage_max
self.physical_utilisation = 0
self.virtual_allocation = 0
self.lock = threading.RLock()
self._refresh()
def get_record(self):
def get_record(self, transient = True):
retval = {'uuid': self.uuid,
'name_label': self.name_label,
'name_description': self.name_description,
'virtual_allocation': self.storage_alloc,
'physical_utilisation': self.storage_used,
'physical_size': self.storage_max,
'virtual_allocation': self.virtual_allocation,
'physical_utilisation': self.physical_utilisation,
'physical_size': self.physical_size,
'type': self.type,
'location': self.location,
'VDIs': self.images.keys()}
if self.storage_max == XEND_STORAGE_NO_MAXIMUM:
stfs = os.statvfs(self.location)
retval['physical_size'] = stfs.f_blocks * stfs.f_frsize
return retval
def _refresh(self):
"""Internal function that refreshes the state of the disk and
updates the list of images available.
"""
self.lock.acquire()
try:
mkdir.parents(self.location, stat.S_IRWXU)
# scan the directory and populate self.images
virtual_alloc = 0
physical_used = 0
seen_images = []
for filename in os.listdir(self.location):
if filename[-5:] == XEND_STORAGE_QCOW_FILENAME[-5:]:
image_uuid = filename[:-5]
seen_images.append(image_uuid)
qcow_file = XEND_STORAGE_QCOW_FILENAME % image_uuid
cfg_file = XEND_STORAGE_VDICFG_FILENAME % image_uuid
qcow_path = os.path.join(self.location, qcow_file)
cfg_path = os.path.join(self.location, cfg_file)
phys_size = os.stat(qcow_path).st_size
virt_size = qcow_virtual_size(qcow_path)
# add this image if we haven't seen it before
if image_uuid not in self.images:
vdi = XendQCOWVDI(image_uuid, self.uuid,
qcow_path, cfg_path,
virt_size, phys_size)
if cfg_path and os.path.exists(cfg_path):
try:
vdi.load_config(cfg_path)
except:
log.error('Corrupt VDI configuration file %s' %
cfg_path)
self.images[image_uuid] = vdi
physical_used += phys_size
virtual_alloc += virt_size
# remove images that aren't valid
for image_uuid in self.images.keys():
if image_uuid not in seen_images:
try:
os.unlink(self.images[image_uuid].qcow_path)
except OSError:
pass
del self.images[image_uuid]
self.storage_alloc = virtual_alloc
self.storage_used = physical_used
# update free storage if we have to track that
if self.storage_max == XEND_STORAGE_NO_MAXIMUM:
self.storage_free = self._get_free_space()
else:
self.storage_free = self.storage_max - self.storage_alloc
finally:
self.lock.release()
def _get_free_space(self):
"""Returns the amount of free space in bytes available in the storage
partition. Note that this may not be used if the storage repository
is initialised with a maximum size in storage_max.
@rtype: int
"""
stfs = os.statvfs(self.location)
return stfs.f_bavail * stfs.f_frsize
def _has_space_available_for(self, size_bytes):
"""Returns whether there is enough space for an image in the
partition which the storage_dir resides on.
@rtype: bool
"""
if self.storage_max != XEND_STORAGE_NO_MAXIMUM:
return self.storage_free > size_bytes
bytes_free = self._get_free_space()
if size_bytes < bytes_free:
return True
return False
def _create_image_files(self, desired_size_bytes):
"""Create an image and return its assigned UUID.
@param desired_size_bytes: Desired image size in bytes
@type desired_size_bytes: int
@rtype: string
@return: uuid
@raises XendError: If an error occurs.
"""
self.lock.acquire()
try:
if not self._has_space_available_for(desired_size_bytes):
raise XendError("Not enough space")
image_uuid = uuid.createString()
qcow_path = os.path.join(self.location,
XEND_STORAGE_QCOW_FILENAME % image_uuid)
if qcow_path and os.path.exists(qcow_path):
raise XendError("Image with same UUID alreaady exists:" %
image_uuid)
cmd = QCOW_CREATE_COMMAND % (desired_size_bytes/MB, qcow_path)
rc, output = commands.getstatusoutput(cmd)
if rc != 0:
# cleanup the image file
os.unlink(qcow_path)
raise XendError("Failed to create QCOW Image: %s" % output)
self._refresh()
return image_uuid
finally:
self.lock.release()
def destroy_image(self, image_uuid):
"""Destroy an image that is managed by this storage repository.
@param image_uuid: Image UUID
@type image_uuid: String
@rtype: String
"""
self.lock.acquire()
try:
if image_uuid in self.images:
# TODO: check if it is being used?
qcow_path = self.images[image_uuid].qcow_path
cfg_path = self.images[image_uuid].cfg_path
try:
os.unlink(qcow_path)
if cfg_path and os.path.exists(cfg_path):
os.unlink(cfg_path)
except OSError:
log.exception("Failed to destroy image")
del self.images[image_uuid]
return True
finally:
self.lock.release()
return False
def list_images(self):
""" List all the available images by UUID.
@rtype: list of strings.
@return: list of UUIDs
"""
self.lock.acquire()
try:
return self.images.keys()
finally:
self.lock.release()
def free_space_bytes(self):
"""Returns the amount of available space in KB.
@rtype: int
"""
self.lock.acquire()
try:
return self.storage_free
finally:
self.lock.release()
def total_space_bytes(self):
"""Returns the total usable space of the storage repo in KB.
@rtype: int
"""
self.lock.acquire()
try:
if self.storage_max == XEND_STORAGE_NO_MAXIMUM:
stfs = os.statvfs(self.location)
return stfs.f_blocks * stfs.f_frsize
else:
return self.storage_max
finally:
self.lock.release()
def used_space_bytes(self):
"""Returns the total amount of space used by this storage repository.
@rtype: int
"""
self.lock.acquire()
try:
return self.storage_used
finally:
self.lock.release()
def virtual_allocation(self):
"""Returns the total virtual space allocated within the storage repo.
@rtype: int
"""
self.lock.acquire()
try:
return self.storage_alloc
finally:
self.lock.release()
def is_valid_vdi(self, vdi_uuid):
return (vdi_uuid in self.images)
def create_image(self, vdi_struct):
image_uuid = None
try:
sector_count = int(vdi_struct.get('virtual_size', 0))
sector_size = int(vdi_struct.get('sector_size', 1024))
size_bytes = (sector_count * sector_size)
image_uuid = self._create_image_files(size_bytes)
image = self.images[image_uuid]
image_cfg = {
'sector_size': sector_size,
'virtual_size': sector_count,
'type': vdi_struct.get('type', 'system'),
'name_label': vdi_struct.get('name_label', ''),
'name_description': vdi_struct.get('name_description', ''),
'sharable': bool(vdi_struct.get('sharable', False)),
'read_only': bool(vdi_struct.get('read_only', False)),
}
# load in configuration from vdi_struct
image.load_config_dict(image_cfg)
# save configuration to file
cfg_filename = XEND_STORAGE_VDICFG_FILENAME % image_uuid
cfg_path = os.path.join(self.location, cfg_filename)
image.save_config(cfg_path)
except Exception, e:
# cleanup before raising exception
if image_uuid:
self.destroy_image(image_uuid)
raise
return image_uuid
def xen_api_get_by_name_label(self, label):
def get_vdi_by_uuid(self, image_uuid):
self.lock.acquire()
try:
for image_uuid, val in self.images.items():
if val.name_label == label:
return self.images.get(image_uuid)
finally:
self.lock.release()
def get_vdi_by_name_label(self, label):
self.lock.acquire()
try:
for image_uuid, image in self.images.items():
if image.name_label == label:
return image_uuid
return None
finally:
self.lock.release()
def xen_api_get_by_uuid(self, image_uuid):
self.lock.acquire()
try:
return self.images.get(image_uuid)
finally:
self.lock.release()
def get_vdis(self):
return self.images.keys()
# remove everything below this line!!
if __name__ == "__main__":
xsr = XendStorageRepository()
print 'Free Space: %d MB' % (xsr.free_space_bytes()/MB)
print "Create Image:",
print xsr._create_image_files(10 * MB)
print 'Delete all images:'
for image_uuid in xsr.list_images():
print image_uuid,
xsr._destroy_image_files(image_uuid)
def create_vdi(self, vdi_struct):
raise NotImplementedError()
print
def destroy_vdi(self, vdi_struct):
raise NotImplementedError()
+228
View File
@@ -0,0 +1,228 @@
#===========================================================================
# This library is free software; you can redistribute it and/or
# modify it under the terms of version 2.1 of the GNU Lesser General Public
# License as published by the Free Software Foundation.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#============================================================================
# Copyright (C) 2007 XenSource Ltd
#============================================================================
from xen.xend.XendAPIConstants import XEN_API_TASK_STATUS_TYPE
from xen.xend.XendLogging import log
import thread
import threading
class XendTask(threading.Thread):
"""Represents a Asynchronous Task used by Xen API.
Basically proxies the callable object in a thread and returns the
results via self.{type,result,error_code,error_info}.
@cvar task_progress: Thread local storage for progress tracking.
It is a dict indexed by thread_id. Note that the
thread_id may be reused when the previous
thread with the thread_id ends.
@cvar task_progress_lock: lock on thread access to task_progress
"""
# progress stack:
# thread_id : [(start_task, end_task),
# (start_sub_task, end_sub_task)..]
# example : (0, 100), (50, 100) (50, 100) ...
# That would mean that the task is 75% complete.
# as it is 50% of the last 50% of the task.
task_progress = {}
task_progress_lock = threading.Lock()
def __init__(self, uuid, func, args, func_name, return_type, label, desc,
session):
"""
@param uuid: UUID of the task
@type uuid: string
@param func: Method to call (from XendAPI)
@type func: callable object
@param args: arguments to pass to function
@type args: list or tuple
@param label: name label of the task.
@type label: string
@param desc: name description of the task.
@type desc: string
@param func_name: function name, eg ('VM.start')
@type desc: string
"""
threading.Thread.__init__(self)
self.status_lock = threading.Lock()
self.status = XEN_API_TASK_STATUS_TYPE[0]
self.progress = 0
self.type = return_type
self.uuid = uuid
self.result = None
self.error_code = ''
self.error_info = []
self.name_label = label or func.__name__
self.name_description = desc
self.thread_id = 0
self.func_name = func_name
self.func = func
self.args = args
self.session = session
def set_status(self, new_status):
self.status_lock.acquire()
try:
self.status = new_status
finally:
self.status_lock.release()
def get_status(self):
self.status_lock.acquire()
try:
return self.status
finally:
self.status_lock.release()
def run(self):
"""Runs the method and stores the result for later access.
Is invoked by threading.Thread.start().
"""
self.thread_id = thread.get_ident()
self.task_progress_lock.acquire()
try:
self.task_progress[self.thread_id] = {}
self.progress = 0
finally:
self.task_progress_lock.release()
try:
result = self.func(*self.args)
if result['Status'] == 'Success':
self.result = result['Value']
self.set_status(XEN_API_TASK_STATUS_TYPE[1])
else:
self.error_code = result['ErrorDescription'][0]
self.error_info = result['ErrorDescription'][1:]
self.set_status(XEN_API_TASK_STATUS_TYPE[2])
except Exception, e:
log.exception('Error running Async Task')
self.error_code = 'INTERNAL ERROR'
self.error_info = [str(e)]
self.set_status(XEN_API_TASK_STATUS_TYPE[2])
self.task_progress_lock.acquire()
try:
del self.task_progress[self.thread_id]
self.progress = 100
finally:
self.task_progress_lock.release()
def get_record(self):
"""Returns a Xen API compatible record."""
return {
'uuid': self.uuid,
'name_label': self.name_label,
'name_description': self.name_description,
'status': self.status,
'progress': self.get_progress(),
'type': self.type,
'result': self.result,
'error_code': self.error_code,
'error_info': self.error_info,
'allowed_operations': {},
'session': self.session,
}
def get_progress(self):
""" Checks the thread local progress storage. """
if self.status != XEN_API_TASK_STATUS_TYPE[0]:
return 100
self.task_progress_lock.acquire()
try:
# Pop each progress range in the stack and map it on to
# the next progress range until we find out cumulative
# progress based on the (start, end) range of each level
start = 0
prog_stack = self.task_progress.get(self.thread_id, [])[:]
if len(prog_stack) > 0:
start, stop = prog_stack.pop()
while prog_stack:
new_start, new_stop = prog_stack.pop()
start = new_start + ((new_stop - new_start)/100.0 * start)
# only update progress if it increases, this will prevent
# progress from going backwards when tasks are popped off
# the stack
if start > self.progress:
self.progress = int(start)
finally:
self.task_progress_lock.release()
return self.progress
def log_progress(cls, progress_min, progress_max,
func, *args, **kwds):
""" Callable function wrapper that logs the progress of the
function to thread local storage for task progress calculation.
This is a class method so other parts of Xend will update
the task progress by calling:
XendTask.push_progress(progress_min, progress_max,
func, *args, **kwds)
The results of the progress is stored in thread local storage
and the result of the func(*args, **kwds) is returned back
to the caller.
"""
thread_id = thread.get_ident()
retval = None
# Log the start of the method
cls.task_progress_lock.acquire()
try:
if type(cls.task_progress.get(thread_id)) != list:
cls.task_progress[thread_id] = []
cls.task_progress[thread_id].append((progress_min,
progress_max))
finally:
cls.task_progress_lock.release()
# Execute the method
retval = func(*args, **kwds)
# Log the end of the method by popping the progress range
# off the stack.
cls.task_progress_lock.acquire()
try:
cls.task_progress[thread_id].pop()
finally:
cls.task_progress_lock.release()
return retval
log_progress = classmethod(log_progress)
+110
View File
@@ -0,0 +1,110 @@
#===========================================================================
# This library is free software; you can redistribute it and/or
# modify it under the terms of version 2.1 of the GNU Lesser General Public
# License as published by the Free Software Foundation.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#============================================================================
# Copyright (C) 2007 XenSource Ltd
#============================================================================
"""
Task Manager for Xen API asynchronous tasks.
Stores all tasks in a simple dictionary in module's own local storage to
avoid the 'instance()' methods.
Tasks are indexed by UUID.
"""
from xen.xend.XendTask import XendTask
from xen.xend import uuid
import threading
tasks = {}
tasks_lock = threading.Lock()
def create_task(func, args, func_name, return_type, label, session):
"""Creates a new Task and registers it with the XendTaskManager.
@param func: callable object XMLRPC method
@type func: callable object
@param args: tuple or list of arguments
@type args: tuple or list
@param func_name: XMLRPC method name, so we can estimate the progress
@type func_name: string
@return: Task UUID
@rtype: string.
"""
task_uuid = uuid.createString()
try:
tasks_lock.acquire()
task = XendTask(task_uuid, func, args, func_name, return_type, label,
'', session)
tasks[task_uuid] = task
finally:
tasks_lock.release()
task.start()
return task_uuid
def destroy_task(task_uuid):
"""Destroys a task.
@param task_uuid: Task UUID
@type task_uuid: string.
"""
try:
tasks_lock.acquire()
if task_uuid in tasks:
del tasks[task_uuid]
finally:
tasks_lock.release()
def get_all_tasks():
""" Returns all the UUID of tracked tasks, completed or pending.
@returns: list of UUIDs
@rtype: list of strings
"""
try:
tasks_lock.acquire()
return tasks.keys()
finally:
tasks_lock.release()
def get_task(task_uuid):
""" Retrieves a task by UUID.
@rtype: XendTask or None
@return: Task denoted by UUID.
"""
try:
tasks_lock.acquire()
return tasks.get(task_uuid)
finally:
tasks_lock.release()
def get_tasks_by_name(task_name):
""" Retrieves a task by UUID.
@rtype: XendTask or None
@return: Task denoted by UUID.
"""
try:
tasks_lock.acquire()
return [t.uuid for t in tasks if t.name_label == name]
finally:
tasks_lock.release()
+32 -10
View File
@@ -57,8 +57,6 @@ class XendVDI(AutoSaveObject):
'sector_size',
'virtual_size',
'physical_utilisation',
'parent',
'children',
'sharable',
'read_only']
@@ -72,11 +70,10 @@ class XendVDI(AutoSaveObject):
self.sector_size = 1024
self.virtual_size = 0
self.physical_utilisation = 0
self.parent = None
self.children = []
self.sharable = False
self.read_only = False
self.type = "system"
self.location = ''
def load_config_dict(self, cfg):
"""Loads configuration into the object from a dict.
@@ -141,23 +138,24 @@ class XendVDI(AutoSaveObject):
return True
def get_record(self):
def get_record(self, transient = True):
return {'uuid': self.uuid,
'name_label': self.name_label,
'name_description': self.name_description,
'virtual_size': self.virtual_size,
'physical_utilisation': self.physical_utilisation,
'sector_size': self.sector_size,
'parent': None,
'children': [],
'sharable': False,
'readonly': False,
'SR': self.sr.get_uuid(),
'SR': self.sr_uuid,
'location': self.get_location(),
'VBDs': []}
def get_location(self):
raise NotImplementedError()
class XendQCOWVDI(XendVDI):
class XendQCoWVDI(XendVDI):
def __init__(self, uuid, sr_uuid, qcow_path, cfg_path, vsize, psize):
XendVDI.__init__(self, uuid, sr_uuid)
self.auto_save = False
@@ -167,4 +165,28 @@ class XendQCOWVDI(XendVDI):
self.virtual_size = vsize
self.sector_size = 512
self.auto_save = True
self.location = 'tap:qcow:%s' % self.qcow_path
def get_location(self):
return self.location
class XendLocalVDI(XendVDI):
def __init__(self, vdi_struct):
vdi_uuid = vdi_struct['uuid']
sr_uuid = vdi_struct['SR']
XendVDI.__init__(self, vdi_uuid, sr_uuid)
self.auto_save = False
self.cfg_path = None
self.name_label = vdi_struct.get('name_label','')
self.name_description = vdi_struct.get('name_description', '')
self.physical_utilisation = 0
self.virtual_size = 0
self.sector_size = 0
self.type = vdi_struct.get('type', '')
self.sharable = vdi_struct.get('sharable', False)
self.read_only = vdi_struct.get('read_only', False)
self.location = vdi_struct.get('location', 'file:/dev/null')
def get_location(self):
return self.location
+3 -3
View File
@@ -22,7 +22,7 @@ import time
import xen.lowlevel.xc
import XendDomain
import XendRoot
import XendOptions
from XendLogging import log
from XendError import VmError
@@ -107,11 +107,11 @@ def free(need_mem):
# usage, so we recheck the required alloc each time around the loop, but
# track the last used value so that we don't trigger too many watches.
xroot = XendRoot.instance()
xoptions = XendOptions.instance()
xc = xen.lowlevel.xc.xc()
try:
dom0_min_mem = xroot.get_dom0_min_mem() * 1024
dom0_min_mem = xoptions.get_dom0_min_mem() * 1024
retries = 0
sleep_time = SLEEP_TIME_GROWTH
+93 -66
View File
@@ -26,6 +26,7 @@ import xen.lowlevel.xc
from xen.xend.XendConstants import REVERSE_DOMAIN_SHUTDOWN_REASONS
from xen.xend.XendError import VmError, XendError
from xen.xend.XendLogging import log
from xen.xend.XendOptions import instance as xenopts
from xen.xend.server.netif import randomMAC
from xen.xend.xenstore.xswatch import xswatch
from xen.xend import arch
@@ -172,7 +173,7 @@ class ImageHandler:
"""Build the domain. Define in subclass."""
raise NotImplementedError()
def createDeviceModel(self):
def createDeviceModel(self, restore = False):
"""Create device model for the domain (define in subclass if needed)."""
pass
@@ -277,7 +278,7 @@ class HVMImageHandler(ImageHandler):
raise VmError("HVM guest support is unavailable: is VT/AMD-V "
"supported by your CPU and enabled in your BIOS?")
self.dmargs = self.parseDeviceModelArgs(imageConfig, deviceConfig)
self.dmargs = self.parseDeviceModelArgs(vmConfig)
self.device_model = imageConfig['hvm'].get('device_model')
if not self.device_model:
raise VmError("hvm: missing device model")
@@ -292,8 +293,6 @@ class HVMImageHandler(ImageHandler):
self.pid = None
self.dmargs += self.configVNC(imageConfig)
self.pae = imageConfig['hvm'].get('pae', 0)
self.apic = imageConfig['hvm'].get('apic', 0)
self.acpi = imageConfig['hvm']['devices'].get('acpi', 0)
@@ -327,13 +326,14 @@ class HVMImageHandler(ImageHandler):
# Return a list of cmd line args to the device models based on the
# xm config file
def parseDeviceModelArgs(self, imageConfig, deviceConfig):
def parseDeviceModelArgs(self, vmConfig):
dmargs = [ 'boot', 'fda', 'fdb', 'soundhw',
'localtime', 'serial', 'stdvga', 'isa', 'vcpus',
'localtime', 'serial', 'stdvga', 'isa',
'acpi', 'usb', 'usbdevice', 'keymap' ]
ret = []
hvmDeviceConfig = imageConfig['hvm']['devices']
hvmDeviceConfig = vmConfig['image']['hvm']['devices']
ret = ['-vcpus', str(self.vm.getVCpuCount())]
for a in dmargs:
v = hvmDeviceConfig.get(a)
@@ -343,8 +343,11 @@ class HVMImageHandler(ImageHandler):
# Handle booleans gracefully
if a in ['localtime', 'std-vga', 'isa', 'usb', 'acpi']:
if v != None: v = int(v)
if v: ret.append("-%s" % a)
try:
if v != None: v = int(v)
if v: ret.append("-%s" % a)
except (ValueError, TypeError):
pass # if we can't convert it to a sane type, ignore it
else:
if v:
ret.append("-%s" % a)
@@ -361,76 +364,91 @@ class HVMImageHandler(ImageHandler):
ret = ret + ["-domain-name", str(self.vm.info['name_label'])]
nics = 0
for devuuid, (devtype, devinfo) in deviceConfig.items():
if devtype == 'vbd':
uname = devinfo.get('uname')
if uname is not None and 'file:' in uname:
(_, vbdparam) = string.split(uname, ':', 1)
if not os.path.isfile(vbdparam):
raise VmError('Disk image does not exist: %s' %
vbdparam)
if devtype == 'vif':
dtype = devinfo.get('type', 'ioemu')
if dtype != 'ioemu':
continue
nics += 1
mac = devinfo.get('mac')
if mac == None:
mac = randomMAC()
bridge = devinfo.get('bridge', 'xenbr0')
model = devinfo.get('model', 'rtl8139')
ret.append("-net")
ret.append("nic,vlan=%d,macaddr=%s,model=%s" %
(nics, mac, model))
ret.append("-net")
ret.append("tap,vlan=%d,bridge=%s" % (nics, bridge))
return ret
for devuuid in vmConfig['vbd_refs']:
devinfo = vmConfig['devices'][devuuid][1]
uname = devinfo.get('uname')
if uname is not None and 'file:' in uname:
(_, vbdparam) = string.split(uname, ':', 1)
if not os.path.isfile(vbdparam):
raise VmError('Disk image does not exist: %s' %
vbdparam)
def configVNC(self, imageConfig):
# Handle graphics library related options
vnc = imageConfig.get('vnc')
sdl = imageConfig.get('sdl')
ret = []
nographic = imageConfig.get('nographic')
for devuuid in vmConfig['vif_refs']:
devinfo = vmConfig['devices'][devuuid][1]
dtype = devinfo.get('type', 'ioemu')
if dtype != 'ioemu':
continue
nics += 1
mac = devinfo.get('mac')
if mac is None:
mac = randomMAC()
bridge = devinfo.get('bridge', 'xenbr0')
model = devinfo.get('model', 'rtl8139')
ret.append("-net")
ret.append("nic,vlan=%d,macaddr=%s,model=%s" %
(nics, mac, model))
ret.append("-net")
ret.append("tap,vlan=%d,bridge=%s" % (nics, bridge))
# get password from VM config (if password omitted, None)
vncpasswd_vmconfig = imageConfig.get('vncpasswd')
if nographic:
#
# Find RFB console device, and if it exists, make QEMU enable
# the VNC console.
#
if vmConfig['image'].get('nographic'):
# skip vnc init if nographic is set
ret.append('-nographic')
return ret
if vnc:
vncdisplay = imageConfig.get('vncdisplay',
int(self.vm.getDomid()))
vncunused = imageConfig.get('vncunused')
vnc_config = {}
has_vnc = int(vmConfig['image'].get('vnc', 0)) != 0
has_sdl = int(vmConfig['image'].get('sdl', 0)) != 0
for dev_uuid in vmConfig['console_refs']:
dev_type, dev_info = vmConfig['devices'][dev_uuid]
if dev_type == 'vfb':
vnc_config = dev_info.get('other_config', {})
has_vnc = True
break
if vncunused:
ret += ['-vncunused']
if has_vnc:
if not vnc_config:
for key in ('vncunused', 'vnclisten', 'vncdisplay',
'vncpasswd'):
if key in vmConfig['image']:
vnc_config[key] = vmConfig['image'][key]
if not vnc_config.get('vncunused', 0) and \
vnc_config.get('vncdisplay', 0):
ret.append('-vnc')
ret.append(str(vncdisplay))
else:
ret += ['-vnc', '%d' % vncdisplay]
ret.append('-vncunused')
vnclisten = imageConfig.get('vnclisten')
vnclisten = vnc_config.get('vnclisten',
xenopts().get_vnclisten_address())
ret.append('-vnclisten')
ret.append(str(vnclisten))
if not(vnclisten):
vnclisten = (xen.xend.XendRoot.instance().
get_vnclisten_address())
if vnclisten:
ret += ['-vnclisten', vnclisten]
# Store vncpassword in xenstore
vncpasswd = vnc_config.get('vncpasswd')
if not vncpasswd:
vncpasswd = xenopts().get_vncpasswd_default()
vncpasswd = vncpasswd_vmconfig
if vncpasswd is None:
vncpasswd = (xen.xend.XendRoot.instance().
get_vncpasswd_default())
if vncpasswd is None:
raise VmError('vncpasswd is not set up in ' +
'VMconfig and xend-config.')
raise VmError('vncpasswd is not setup in vmconfig or '
'xend-config.sxp')
if vncpasswd != '':
self.vm.storeVm("vncpasswd", vncpasswd)
self.vm.storeVm('vncpasswd', vncpasswd)
elif has_sdl:
# SDL is default in QEMU.
pass
else:
ret.append('-nographic')
return ret
def createDeviceModel(self):
def createDeviceModel(self, restore = False):
if self.pid:
return
# Execute device model.
@@ -439,6 +457,8 @@ class HVMImageHandler(ImageHandler):
args = args + ([ "-d", "%d" % self.vm.getDomid(),
"-m", "%s" % (self.getRequiredInitialReservation() / 1024)])
args = args + self.dmargs
if restore:
args = args + ([ "-loadvm", "/tmp/xen.qemu-dm.%d" % self.vm.getDomid() ])
env = dict(os.environ)
if self.display:
env['DISPLAY'] = self.display
@@ -457,12 +477,16 @@ class HVMImageHandler(ImageHandler):
self.register_reboot_feature_watch()
self.pid = self.vm.gatherDom(('image/device-model-pid', int))
def destroy(self):
def destroy(self, suspend = False):
self.unregister_shutdown_watch()
self.unregister_reboot_feature_watch();
if self.pid:
try:
os.kill(self.pid, signal.SIGKILL)
sig = signal.SIGKILL
if suspend:
log.info("use sigusr1 to signal qemu %d", self.pid)
sig = signal.SIGUSR1
os.kill(self.pid, sig)
except OSError, exn:
log.exception(exn)
try:
@@ -551,6 +575,9 @@ class IA64_HVM_ImageHandler(HVMImageHandler):
extra_pages = 1024 + 3
return mem_kb + extra_pages * page_kb
def getRequiredInitialReservation(self):
return self.vm.getMemoryTarget()
def getRequiredShadowMemory(self, shadow_mem_kb, maxmem_kb):
# Explicit shadow memory is not a concept
return 0
+15
View File
@@ -29,8 +29,23 @@ _xend_autorestart = {
"SunOS": False,
}
_pygrub_path = {
"SunOS": "/usr/lib/xen/bin/pygrub"
}
_netback_type = {
"SunOS": "SUNW_mac"
}
_vif_script = {
"SunOS": "vif-vnic"
}
def _get(var, default=None):
return var.get(os.uname()[0], default)
scripts_dir = _get(_scripts_dir, "/etc/xen/scripts")
xend_autorestart = _get(_xend_autorestart)
pygrub_path = _get(_pygrub_path, "/usr/bin/pygrub")
netback_type = _get(_netback_type, "netfront")
vif_script = _get(_vif_script, "vif-bridge")
@@ -0,0 +1,35 @@
from xen.xend.server.DevController import DevController
from xen.xend.XendLogging import log
from xen.xend.XendError import VmError
class ConsoleController(DevController):
"""A dummy controller for us to represent serial and vnc
console devices with persistent UUIDs.
"""
valid_cfg = ['location', 'uuid', 'protocol']
def __init__(self, vm):
DevController.__init__(self, vm)
self.hotplug = False
def getDeviceDetails(self, config):
back = dict([(k, config[k]) for k in self.valid_cfg if k in config])
return (self.allocateDeviceID(), back, {})
def getDeviceConfiguration(self, devid):
result = DevController.getDeviceConfiguration(self, devid)
devinfo = self.readBackend(devid, *self.valid_cfg)
config = dict(zip(self.valid_cfg, devinfo))
config = dict([(key, val) for key, val in config.items()
if val != None])
return config
def migrate(self, deviceConfig, network, dst, step, domName):
return 0
def destroyDevice(self, devid, force):
DevController.destroyDevice(self, devid, True)
@@ -19,7 +19,7 @@
from threading import Event
import types
from xen.xend import sxp, XendRoot
from xen.xend import sxp, XendOptions
from xen.xend.XendError import VmError
from xen.xend.XendLogging import log
@@ -50,7 +50,7 @@ xenbusState = {
'Closed' : 6,
}
xroot = XendRoot.instance()
xoptions = XendOptions.instance()
xenbusState.update(dict(zip(xenbusState.values(), xenbusState.keys())))
@@ -75,7 +75,7 @@ class DevController:
def __init__(self, vm):
self.vm = vm
self.hotplug = True
def createDevice(self, config):
"""Trigger the creation of a device with the given configuration.
@@ -151,6 +151,9 @@ class DevController:
def waitForDevice(self, devid):
log.debug("Waiting for %s.", devid)
if not self.hotplug:
return
status = self.waitForBackend(devid)
@@ -324,7 +327,7 @@ class DevController:
Make sure that the migration has finished and only
then return from the call.
"""
tool = xroot.get_external_migration_tool()
tool = xoptions.get_external_migration_tool()
if tool:
log.info("Calling external migration tool for step %d" % step)
fd = os.popen("%s -type %s -step %d -host %s -domname %s" %
@@ -341,7 +344,7 @@ class DevController:
""" Recover from device migration. The given step was the
last one that was successfully executed.
"""
tool = xroot.get_external_migration_tool()
tool = xoptions.get_external_migration_tool()
if tool:
log.info("Calling external migration tool")
fd = os.popen("%s -type %s -step %d -host %s -domname %s -recover" %
+1 -1
View File
@@ -203,7 +203,7 @@ class Daemon:
if not osdep.xend_autorestart:
self.run(os.fdopen(w, 'w'))
break
os._exit(0)
pid = self.fork_pid()
if pid:
+1 -1
View File
@@ -25,7 +25,7 @@ class SrvRoot(SrvDir):
"""Server sub-components. Each entry is (name, class), where
'name' is the entry name and 'class' is the name of its class.
"""
#todo Get this list from the XendRoot config.
#todo Get this list from the XendOptions config.
subdirs = [
('node', 'SrvNode' ),
('domain', 'SrvDomainDir' ),
+28 -40
View File
@@ -48,7 +48,7 @@ from threading import Thread
from xen.web.httpserver import HttpServer, UnixHttpServer
from xen.xend import XendNode, XendRoot, XendAPI
from xen.xend import XendNode, XendOptions, XendAPI
from xen.xend import Vifctl
from xen.xend.XendLogging import log
from xen.xend.XendClient import XEN_API_SOCKET
@@ -57,7 +57,7 @@ from xen.web.SrvDir import SrvDir
from SrvRoot import SrvRoot
from XMLRPCServer import XMLRPCServer
xroot = XendRoot.instance()
xoptions = XendOptions.instance()
class XendServers:
@@ -65,6 +65,7 @@ class XendServers:
def __init__(self, root):
self.servers = []
self.root = root
self.running = False
self.cleaningUp = False
self.reloadingConfig = False
@@ -79,6 +80,7 @@ class XendServers:
server.shutdown()
except:
pass
self.running = False
def reloadConfig(self, signum = 0, frame = None):
log.debug("SrvServer.reloadConfig()")
@@ -107,13 +109,12 @@ class XendServers:
if server.ready:
continue
thread = Thread(target=server.run, name=server.__class__.__name__)
if isinstance(server, HttpServer):
thread.setDaemon(True)
thread = Thread(target=server.run,
name=server.__class__.__name__)
thread.setDaemon(True)
thread.start()
threads.append(thread)
# check for when all threads have initialized themselves and then
# close the status pipe
@@ -143,47 +144,32 @@ class XendServers:
status.close()
status = None
# Interruptible Thread.join - Python Bug #1167930
# Replaces: for t in threads: t.join()
# Reason: The above will cause python signal handlers to be
# blocked so we're not able to catch SIGTERM in any
# way for cleanup
runningThreads = threads
while len(runningThreads) > 0:
try:
for t in threads:
t.join(1.0)
runningThreads = [t for t in threads
if t.isAlive() and not t.isDaemon()]
if self.cleaningUp and len(runningThreads) > 0:
log.debug("Waiting for %s." %
[x.getName() for x in runningThreads])
except:
pass
# loop to keep main thread alive until it receives a SIGTERM
self.running = True
while self.running:
time.sleep(100000000)
if self.reloadingConfig:
log.info("Restarting all XML-RPC and Xen-API servers...")
self.cleaningUp = False
self.reloadingConfig = False
xroot.set_config()
new_servers = [x for x in self.servers
if isinstance(x, HttpServer)]
self.servers = new_servers
xoptions.set_config()
self.servers = []
_loadConfig(self, self.root, True)
else:
break
def _loadConfig(servers, root, reload):
if not reload and xroot.get_xend_http_server():
if xoptions.get_xend_http_server():
servers.add(HttpServer(root,
xroot.get_xend_address(),
xroot.get_xend_port()))
if not reload and xroot.get_xend_unix_server():
path = xroot.get_xend_unix_path()
xoptions.get_xend_address(),
xoptions.get_xend_port()))
if xoptions.get_xend_unix_server():
path = xoptions.get_xend_unix_path()
log.info('unix path=' + path)
servers.add(UnixHttpServer(root, path))
api_cfg = xroot.get_xen_api_server()
api_cfg = xoptions.get_xen_api_server()
if api_cfg:
try:
addrs = [(str(x[0]).split(':'),
@@ -213,15 +199,17 @@ def _loadConfig(servers, root, reload):
servers.add(XMLRPCServer(auth, True, True, addr,
int(port),
hosts_allowed = allowed))
except ValueError, exn:
log.error('Xen-API server configuration %s is invalid.', api_cfg)
except TypeError, exn:
except (ValueError, TypeError), exn:
log.exception('Xen API Server init failed')
log.error('Xen-API server configuration %s is invalid.', api_cfg)
if xroot.get_xend_tcp_xmlrpc_server():
servers.add(XMLRPCServer(XendAPI.AUTH_PAM, False, True))
if xoptions.get_xend_tcp_xmlrpc_server():
addr = xoptions.get_xend_tcp_xmlrpc_server_address()
port = xoptions.get_xend_tcp_xmlrpc_server_port()
servers.add(XMLRPCServer(XendAPI.AUTH_PAM, False, use_tcp = True,
host = addr, port = port))
if xroot.get_xend_unix_xmlrpc_server():
if xoptions.get_xend_unix_xmlrpc_server():
servers.add(XMLRPCServer(XendAPI.AUTH_PAM, False))
+24 -11
View File
@@ -34,7 +34,7 @@ from xen.xend.XendError import XendInvalidDomain
def fixup_sxpr(sexpr):
ret = []
for k in sexpr:
if type(k) in (types.ListType, types.TupleType):
if type(k) in (list, tuple):
if len(k) != 2 or k[0] != 'vcpu_avail':
ret.append(fixup_sxpr(k))
else:
@@ -139,6 +139,8 @@ class XMLRPCServer:
meth = getattr(self.xenapi, meth_name)
if callable(meth) and hasattr(meth, 'api'):
self.server.register_function(meth, getattr(meth, 'api'))
self.server.register_instance(XendAPI.XendAPIAsyncProxy(self.xenapi))
# Legacy deprecated xm xmlrpc api
# --------------------------------------------------------------------
@@ -179,21 +181,32 @@ class XMLRPCServer:
# Custom runloop so we can cleanup when exiting.
# -----------------------------------------------------------------
try:
self.server.socket.settimeout(1.0)
while self.running:
self.server.handle_request()
finally:
self.cleanup()
self.shutdown()
def cleanup(self):
log.debug("XMLRPCServer.cleanup()")
try:
self.server.socket.close()
except Exception, exn:
log.exception(exn)
pass
log.debug('XMLRPCServer.cleanup()')
if hasattr(self, 'server'):
try:
# This is here to make sure the socket is actually
# cleaned up when close() is called. Otherwise
# SO_REUSEADDR doesn't take effect. To replicate,
# try 'xend reload' and look for EADDRINUSE.
#
# May be caued by us calling close() outside of
# the listen()ing thread.
self.server.socket.shutdown(2)
except socket.error, e:
pass # ignore any socket errors
try:
self.server.socket.close()
except socket.error, e:
pass
def shutdown(self):
self.running = False
self.ready = False
if self.ready:
self.ready = False
self.cleanup()
+1
View File
@@ -101,6 +101,7 @@ class BlkifController(DevController):
self.writeBackend(devid,
'type', new_back['type'],
'params', new_back['params'])
return new_back.get('uuid')
else:
raise VmError('Refusing to reconfigure device %s:%d to %s' %
(self.deviceClass, devid, config))
+19 -10
View File
@@ -24,10 +24,10 @@ import os
import random
import re
from xen.xend import XendRoot
from xen.xend import XendOptions
from xen.xend.server.DevController import DevController
xroot = XendRoot.instance()
xoptions = XendOptions.instance()
def randomMAC():
"""Generate a random MAC address.
@@ -138,8 +138,8 @@ class NetifController(DevController):
def getDeviceDetails(self, config):
"""@see DevController.getDeviceDetails"""
script = os.path.join(xroot.network_script_dir,
config.get('script', xroot.get_vif_script()))
script = os.path.join(xoptions.network_script_dir,
config.get('script', xoptions.get_vif_script()))
typ = config.get('type')
bridge = config.get('bridge')
mac = config.get('mac')
@@ -147,19 +147,23 @@ class NetifController(DevController):
rate = config.get('rate')
uuid = config.get('uuid')
ipaddr = config.get('ip')
model = config.get('model')
devid = self.allocateDeviceID()
if not typ:
typ = xoptions.netback_type
if not mac:
mac = randomMAC()
back = { 'script' : script,
'mac' : mac,
'handle' : "%i" % devid }
'handle' : "%i" % devid,
'type' : typ }
if typ == 'ioemu':
front = {}
back['type'] = 'ioemu'
else:
front = { 'handle' : "%i" % devid,
'mac' : mac }
@@ -173,6 +177,8 @@ class NetifController(DevController):
back['rate'] = parseRate(rate)
if uuid:
back['uuid'] = uuid
if model:
back['model'] = model
return (devid, back, front)
@@ -182,11 +188,12 @@ class NetifController(DevController):
result = DevController.getDeviceConfiguration(self, devid)
devinfo = self.readBackend(devid, 'script', 'ip', 'bridge',
'mac', 'type', 'vifname', 'rate', 'uuid')
(script, ip, bridge, mac, typ, vifname, rate, uuid) = devinfo
'mac', 'type', 'vifname', 'rate',
'uuid', 'model')
(script, ip, bridge, mac, typ, vifname, rate, uuid, model) = devinfo
if script:
network_script_dir = xroot.network_script_dir + os.sep
network_script_dir = xoptions.network_script_dir + os.sep
result['script'] = script.replace(network_script_dir, "")
if ip:
result['ip'] = ip
@@ -202,6 +209,8 @@ class NetifController(DevController):
result['rate'] = formatRate(rate)
if uuid:
result['uuid'] = uuid
if model:
result['model'] = model
return result
+7 -7
View File
@@ -24,7 +24,7 @@ from xen.web import protocol, tcp, unix
from xen.xend import sxp
from xen.xend import XendDomain
from xen.xend import XendRoot
from xen.xend import XendOptions
from xen.xend.XendError import XendError
from xen.xend.XendLogging import log
@@ -114,15 +114,15 @@ class RelocationProtocol(protocol.Protocol):
def listenRelocation():
xroot = XendRoot.instance()
if xroot.get_xend_unix_server():
xoptions = XendOptions.instance()
if xoptions.get_xend_unix_server():
path = '/var/lib/xend/relocation-socket'
unix.UnixListener(path, RelocationProtocol)
if xroot.get_xend_relocation_server():
port = xroot.get_xend_relocation_port()
interface = xroot.get_xend_relocation_address()
if xoptions.get_xend_relocation_server():
port = xoptions.get_xend_relocation_port()
interface = xoptions.get_xend_relocation_address()
hosts_allow = xroot.get_xend_relocation_hosts_allow()
hosts_allow = xoptions.get_xend_relocation_hosts_allow()
if hosts_allow == '':
hosts_allow = None
else:
@@ -2,9 +2,9 @@ import os
import re
import unittest
import xen.xend.XendRoot
import xen.xend.XendOptions
xen.xend.XendRoot.XendRoot.config_default = '/dev/null'
xen.xend.XendOptions.XendOptions.config_default = '/dev/null'
from xen.xend.server import netif
@@ -13,7 +13,7 @@ FAKE_DOMID = 42
FAKE_DEVID = 63
xroot = xen.xend.XendRoot.instance()
xoptions = xen.xend.XendOptions.instance()
class test_controllers(unittest.TestCase):
@@ -36,8 +36,8 @@ class test_controllers(unittest.TestCase):
self.assertEqual(backdets['handle'], str(FAKE_DEVID))
self.assertEqual(backdets['script'],
os.path.join(xroot.network_script_dir,
xroot.get_vif_script()))
os.path.join(xoptions.network_script_dir,
xoptions.get_vif_script()))
self.assertValidMac(backdets['mac'], expectedMac)
self.assertEqual(frontdets['handle'], str(FAKE_DEVID))
+4 -4
View File
@@ -20,7 +20,7 @@
"""Support for virtual TPM interfaces."""
from xen.xend import XendRoot
from xen.xend import XendOptions
from xen.xend.XendLogging import log
from xen.xend.XendError import XendError
from xen.xend.XendConstants import DEV_MIGRATE_TEST, VTPM_DELETE_SCRIPT
@@ -29,7 +29,7 @@ from xen.xend.server.DevController import DevController
import os
import re
xroot = XendRoot.instance()
xoptions = XendOptions.instance()
def destroy_vtpmstate(name):
if os.path.exists(VTPM_DELETE_SCRIPT):
@@ -88,7 +88,7 @@ class TPMifController(DevController):
def migrate(self, deviceConfig, network, dst, step, domName):
"""@see DevContoller.migrate"""
if network:
tool = xroot.get_external_migration_tool()
tool = xoptions.get_external_migration_tool()
if tool != '':
log.info("Request to network-migrate device to %s. step=%d.",
dst, step)
@@ -116,7 +116,7 @@ class TPMifController(DevController):
def recover_migrate(self, deviceConfig, network, dst, step, domName):
"""@see DevContoller.recover_migrate"""
if network:
tool = xroot.get_external_migration_tool()
tool = xoptions.get_external_migration_tool()
if tool != '':
log.info("Request to recover network-migrated device. last good step=%d.",
step)
+71 -6
View File
@@ -14,7 +14,8 @@ def spawn_detached(path, args, env):
os.waitpid(p, 0)
CONFIG_ENTRIES = ['type', 'vncdisplay', 'vnclisten', 'vncpasswd', 'vncunused',
'display', 'xauthority']
'display', 'xauthority', 'keymap',
'uuid', 'location', 'protocol']
class VfbifController(DevController):
"""Virtual frame buffer controller. Handles all vfb devices for a domain.
@@ -27,10 +28,11 @@ class VfbifController(DevController):
def getDeviceDetails(self, config):
"""@see DevController.getDeviceDetails"""
back = dict([(k, config[k]) for k in CONFIG_ENTRIES
back = dict([(k, str(config[k])) for k in CONFIG_ENTRIES
if config.has_key(k)])
return (0, back, {})
devid = 0
return (devid, back, {})
def getDeviceConfiguration(self, devid):
@@ -44,6 +46,10 @@ class VfbifController(DevController):
def createDevice(self, config):
DevController.createDevice(self, config)
if self.vm.info.get('HVM_boot_policy'):
# is HVM, so qemu-dm will handle the vfb.
return
std_args = [ "--domid", "%d" % self.vm.getDomid(),
"--title", self.vm.getName() ]
t = config.get("type", None)
@@ -52,7 +58,7 @@ class VfbifController(DevController):
if config.has_key("vncpasswd"):
passwd = config["vncpasswd"]
else:
passwd = xen.xend.XendRoot.instance().get_vncpasswd_default()
passwd = xen.xend.XendOptions.instance().get_vncpasswd_default()
if passwd:
self.vm.storeVm("vncpasswd", passwd)
log.debug("Stored a VNC password for vfb access")
@@ -64,10 +70,12 @@ class VfbifController(DevController):
if config.has_key("vncunused"):
args += ["--unused"]
elif config.has_key("vncdisplay"):
args += ["--vncport", "%d" % (5900 + config["vncdisplay"])]
args += ["--vncport", "%d" % (5900 + int(config["vncdisplay"]))]
vnclisten = config.get("vnclisten",
xen.xend.XendRoot.instance().get_vnclisten_address())
xen.xend.XendOptions.instance().get_vnclisten_address())
args += [ "--listen", vnclisten ]
if config.has_key("keymap"):
args += ["-k", "%s" % config["keymap"]]
spawn_detached(args[0], args + std_args, os.environ)
elif t == "sdl":
args = [xen.util.auxbin.pathTo("xen-sdlfb")]
@@ -80,6 +88,42 @@ class VfbifController(DevController):
else:
raise VmError('Unknown vfb type %s (%s)' % (t, repr(config)))
def waitForDevice(self, devid):
if self.vm.info.get('HVM_boot_policy'):
log.debug('skip waiting for HVM vfb')
# is a qemu-dm managed device, don't wait for hotplug for these.
return
DevController.waitForDevice(self, devid)
def reconfigureDevice(self, _, config):
""" Only allow appending location information of vnc port into
xenstore."""
if 'location' in config:
(devid, back, front) = self.getDeviceDetails(config)
self.writeBackend(devid, 'location', config['location'])
return back.get('uuid')
raise VmError('Refusing to reconfigure device vfb:%d' % devid)
def destroyDevice(self, devid, force):
if self.vm.info.get('HVM_boot_policy'):
# remove the backend xenstore entries for HVM guests no matter
# what
DevController.destroyDevice(self, devid, True)
else:
DevController.destroyDevice(self, devid, force)
def migrate(self, deviceConfig, network, dst, step, domName):
if self.vm.info.get('HVM_boot_policy'):
return 0
return DevController.migrate(self, deviceConfig, network, dst, step,
domName)
class VkbdifController(DevController):
"""Virtual keyboard controller. Handles all vkbd devices for a domain.
"""
@@ -90,3 +134,24 @@ class VkbdifController(DevController):
back = {}
front = {}
return (devid, back, front)
def waitForDevice(self, config):
if self.vm.info.get('HVM_boot_policy'):
# is a qemu-dm managed device, don't wait for hotplug for these.
return
DevController.waitForDevice(self, config)
def destroyDevice(self, devid, force):
if self.vm.info.get('HVM_boot_policy'):
# remove the backend xenstore entries for HVM guests no matter
# what
DevController.destroyDevice(self, devid, True)
else:
DevController.destroyDevice(self, devid, force)
def migrate(self, deviceConfig, network, dst, step, domName):
if self.vm.info.get('HVM_boot_policy'):
return 0
return DevController.migrate(self, deviceConfig, network, dst, step,
domName)
@@ -0,0 +1,42 @@
import unittest
import xen.xend.XendConfig as XendConfig
class test_XendConfig(unittest.TestCase):
def testParseFromSXP(self):
cfg = XendConfig.XendConfig(
sxp_obj = (
['vm',
['bootloader_args', '-q --default_args="root=/dev/sda1 ro" --extra_args="quiet" /images/VM1.sda'],
['bootloader', '/usr/bin/pygrub'],
['device', ['vif', ['mac', '00:16:3E:4C:D1:00'], ['script', 'vif-bridge'], ['bridge', 'xenbr0']]],
['device', ['vif', ['mac', '00:16:3E:48:56:26'], ['script', 'vif-bridge'], ['bridge', 'vbridge0']]],
['device', ['vbd', ['uname', 'phy:/images/VM1.sda'], ['dev', 'sda'], ['mode', 'w']]],
['device', ['vbd', ['uname', 'phy:/images/VM1.sdb'], ['dev', 'sdb'], ['mode', 'w']]],
['memory', '256'], ['name', 'VM1'], ['on_crash', 'restart'],
['uuid', '10927a76-fe27-49b2-8f57-2970b7bbed6c'], ['vcpus', '1']
]))
self.assertEqual(cfg['uuid'], '10927a76-fe27-49b2-8f57-2970b7bbed6c')
self.assertEqual(cfg['name_label'], 'VM1')
self.assertEqual(cfg['memory_static_max'], 256)
ordered_refs = cfg.ordered_device_refs()
self.assertEqual(cfg['devices'][ordered_refs[0]][0], 'vbd')
self.assertEqual(cfg['devices'][ordered_refs[1]][0], 'vbd')
self.assertEqual(cfg['devices'][ordered_refs[2]][0], 'vif')
self.assertEqual(cfg['devices'][ordered_refs[3]][0], 'vif')
self.assertEqual(cfg['devices'][ordered_refs[0]][1]['uname'],
'phy:/images/VM1.sda')
self.assertEqual(cfg['devices'][ordered_refs[1]][1]['uname'],
'phy:/images/VM1.sdb')
self.assertEqual(cfg['devices'][ordered_refs[2]][1]['mac'],
'00:16:3E:4C:D1:00')
self.assertEqual(cfg['devices'][ordered_refs[3]][1]['mac'],
'00:16:3E:48:56:26')
def test_suite():
return unittest.makeSuite(test_XendConfig)
+3
View File
@@ -24,3 +24,6 @@ def IntroduceDomain(domid, page, port):
def GetDomainPath(domid):
return xshandle().get_domain_path(domid)
def ResumeDomain(domid):
return xshandle().resume_domain(domid)
+42 -27
View File
@@ -24,10 +24,12 @@ import os.path
import sys
import socket
import re
import time
import xmlrpclib
from xen.xend import sxp
from xen.xend import PrettyPrint
from xen.xend import osdep
import xen.xend.XendClient
from xen.xend.XendBootloader import bootloader
from xen.util import blkif
@@ -189,6 +191,10 @@ gopts.var('vcpus', val='VCPUS',
fn=set_int, default=1,
use="# of Virtual CPUS in domain.")
gopts.var('vcpu_avail', val='VCPUS',
fn=set_long, default=None,
use="Bitmask for virtual CPUs to make available immediately.")
gopts.var('cpu_cap', val='CAP',
fn=set_int, default=None,
use="""Set the maximum amount of cpu.
@@ -291,7 +297,8 @@ gopts.var('vfb', val="type={vnc,sdl},vncunused=1,vncdisplay=N,vnclisten=ADDR,dis
For type=vnc, connect an external vncviewer. The server will listen
on ADDR (default 127.0.0.1) on port N+5900. N defaults to the
domain id. If vncunused=1, the server will try to find an arbitrary
unused port above 5900.
unused port above 5900. vncpasswd overrides the XenD configured
default password.
For type=sdl, a viewer will be started automatically using the
given DISPLAY and XAUTHORITY, which default to the current user's
ones.""")
@@ -300,7 +307,7 @@ gopts.var('vif', val="type=TYPE,mac=MAC,bridge=BRIDGE,ip=IPADDR,script=SCRIPT,ba
fn=append_value, default=[],
use="""Add a network interface with the given MAC address and bridge.
The vif is configured by calling the given configuration script.
If type is not specified, default is netfront not ioemu device.
If type is not specified, default is netfront.
If mac is not specified a random MAC address is used.
If not specified then the network backend chooses it's own MAC address.
If bridge is not specified the first bridge found is used.
@@ -587,6 +594,9 @@ def configure_vfbs(config_devs, vals):
'xauthority', 'type', 'vncpasswd' ]:
err("configuration option %s unknown to vfbs" % k)
config.append([k,v])
if not d.has_key("keymap"):
if vals.keymap:
config.append(['keymap',vals.keymap])
if not d.has_key("display") and os.environ.has_key("DISPLAY"):
config.append(["display", os.environ['DISPLAY']])
if not d.has_key("xauthority"):
@@ -703,23 +713,6 @@ def configure_hvm(config_image, vals):
config_image.append([a, vals.__dict__[a]])
config_image.append(['vncpasswd', vals.vncpasswd])
def run_bootloader(vals, config_image):
if not os.access(vals.bootloader, os.F_OK):
err("Bootloader '%s' does not exist" % vals.bootloader)
if not os.access(vals.bootloader, os.X_OK):
err("Bootloader '%s' isn't executable" % vals.bootloader)
if len(vals.disk) < 1:
err("No disks configured and boot loader requested")
(uname, dev, mode, backend) = vals.disk[0]
file = blkif.blkdev_uname_to_file(uname)
if vals.bootentry:
warn("The bootentry option is deprecated. Use bootargs and pass "
"--entry= directly.")
vals.bootargs = "--entry=%s" %(vals.bootentry,)
return bootloader(vals.bootloader, file, not vals.console_autoconnect,
vals.bootargs, config_image)
def make_config(vals):
"""Create the domain configuration.
@@ -735,7 +728,7 @@ def make_config(vals):
map(add_conf, ['name', 'memory', 'maxmem', 'shadow_memory',
'restart', 'on_poweroff',
'on_reboot', 'on_crash', 'vcpus', 'features',
'on_reboot', 'on_crash', 'vcpus', 'vcpu_avail', 'features',
'on_xend_start', 'on_xend_stop'])
if vals.uuid is not None:
@@ -759,10 +752,14 @@ def make_config(vals):
config_image = configure_image(vals)
if vals.bootloader:
config_image = run_bootloader(vals, config_image)
if vals.bootloader == "pygrub":
vals.bootloader = osdep.pygrub_path
config.append(['bootloader', vals.bootloader])
if vals.bootargs:
config.append(['bootloader_args', vals.bootargs])
else:
config.append(['bootloader_args', '-q'])
config.append(['image', config_image])
config_devs = []
@@ -823,7 +820,7 @@ def preprocess_ioports(vals):
if len(d) == 1:
d.append(d[0])
# Components are in hex: add hex specifier.
hexd = map(lambda v: '0x'+v, d)
hexd = ['0x' + x for x in d]
ioports.append(hexd)
vals.ioports = ioports
@@ -990,8 +987,6 @@ def preprocess_vnc(vals):
vals.extra = vnc + ' ' + vals.extra
def preprocess(vals):
if not vals.kernel and not vals.bootloader:
err("No kernel specified")
preprocess_disk(vals)
preprocess_pci(vals)
preprocess_ioports(vals)
@@ -1176,6 +1171,7 @@ def config_security_check(config, verbose):
try:
domain_label = security.ssidref2label(security.NULL_SSIDREF)
except:
import traceback
traceback.print_exc(limit=1)
return 0
domain_policy = 'NULL'
@@ -1251,9 +1247,28 @@ def main(argv):
if not create_security_check(config):
raise security.ACMError('Security Configuration prevents domain from starting')
else:
dom = make_domain(opts, config)
if opts.vals.console_autoconnect:
console.execConsole(dom)
cpid = os.fork()
if cpid != 0:
for i in range(10):
# Catch failure of the create process
time.sleep(1)
(p, rv) = os.waitpid(cpid, os.WNOHANG)
if os.WIFEXITED(rv):
if os.WEXITSTATUS(rv) != 0:
sys.exit(os.WEXITSTATUS(rv))
try:
# Acquire the console of the created dom
name = sxp.child_value(config, 'name', -1)
dom = server.xend.domain(name)
domid = int(sxp.child_value(dom, 'domid', '-1'))
console.execConsole(domid)
except:
pass
print("Could not start console\n");
sys.exit(0)
dom = make_domain(opts, config)
if __name__ == '__main__':
main(sys.argv)
+55 -17
View File
@@ -130,7 +130,7 @@ SUBCOMMAND_HELP = {
'log' : ('', 'Print Xend log'),
'rename' : ('<Domain> <NewDomainName>', 'Rename a domain.'),
'sched-sedf' : ('<Domain> [options]', 'Get/set EDF parameters.'),
'sched-credit': ('-d <Domain> [-w[=WEIGHT]|-c[=CAP]]',
'sched-credit': ('[-d <Domain> [-w[=WEIGHT]|-c[=CAP]]]',
'Get/set credit scheduler parameters.'),
'sysrq' : ('<Domain> <letter>', 'Send a sysrq to a domain.'),
'vcpu-list' : ('[<Domain>]',
@@ -693,16 +693,28 @@ def parse_doms_info(info):
up_time = time.time() - start_time
return {
'domid' : get_info('domid', str, ''),
'name' : get_info('name', str, '??'),
'domid' : get_info('domid', str, ''),
'name' : get_info('name', str, '??'),
'mem' : get_info('memory_dynamic_min', int, 0),
'vcpus' : get_info('online_vcpus', int, 0),
'state' : get_info('state', str, ''),
'cpu_time' : get_info('cpu_time', float, 0),
'state' : get_info('state', str, ''),
'cpu_time' : get_info('cpu_time', float, 0.0),
# VCPUs is the number online when the VM is up, or the number
# configured otherwise.
'vcpus' : get_info('online_vcpus', int,
get_info('vcpus', int, 0)),
'up_time' : up_time,
'seclabel' : security.get_security_printlabel(info),
}
def check_sched_type(sched):
current = 'unknown'
for x in server.xend.node.info()[1:]:
if len(x) > 1 and x[0] == 'xen_scheduler':
current = x[1]
break
if sched != current:
err("Xen is running with the %s scheduler" % current)
sys.exit(1)
def parse_sedf_info(info):
def get_info(n, t, d):
@@ -717,6 +729,10 @@ def parse_sedf_info(info):
'weight' : get_info('weight', int, -1),
}
def domid_match(domid, info):
return domid is None or domid == info['name'] or \
domid == str(info['domid'])
def xm_brief_list(doms):
print '%-40s %3s %5s %5s %10s %9s' % \
('Name', 'ID', 'Mem', 'VCPUs', 'State', 'Time(s)')
@@ -1091,9 +1107,7 @@ def xm_sched_sedf(args):
print( ("%(name)-32s %(domid)3d %(period)9.1f %(slice)9.1f" +
" %(latency)7.1f %(extratime)6d %(weight)6d") % info)
def domid_match(domid, info):
return domid is None or domid == info['name'] or \
domid == str(info['domid'])
check_sched_type('sedf')
# we want to just display current info if no parameters are passed
if len(args) == 0:
@@ -1130,6 +1144,9 @@ def xm_sched_sedf(args):
doms = filter(lambda x : domid_match(domid, x),
[parse_doms_info(dom)
for dom in getDomains(None, 'running')])
if domid is not None and doms == []:
err("Domain '%s' does not exist." % domid)
usage('sched-sedf')
# print header if we aren't setting any parameters
if len(opts.keys()) == 0:
@@ -1167,6 +1184,8 @@ def xm_sched_sedf(args):
def xm_sched_credit(args):
"""Get/Set options for Credit Scheduler."""
check_sched_type('credit')
try:
opts, params = getopt.getopt(args, "d:w:c:",
["domain=", "weight=", "cap="])
@@ -1174,27 +1193,46 @@ def xm_sched_credit(args):
err(opterr)
usage('sched-credit')
domain = None
domid = None
weight = None
cap = None
for o, a in opts:
if o == "-d":
domain = a
domid = a
elif o == "-w":
weight = int(a)
elif o == "-c":
cap = int(a);
if domain is None:
# place holder for system-wide scheduler parameters
err("No domain given.")
usage('sched-credit')
doms = filter(lambda x : domid_match(domid, x),
[parse_doms_info(dom)
for dom in getDomains(None, 'running')])
if weight is None and cap is None:
print server.xend.domain.sched_credit_get(domain)
if domid is not None and doms == []:
err("Domain '%s' does not exist." % domid)
usage('sched-credit')
# print header if we aren't setting any parameters
print '%-33s %-2s %-6s %-4s' % ('Name','ID','Weight','Cap')
for d in doms:
try:
info = server.xend.domain.sched_credit_get(d['domid'])
except xmlrpclib.Fault:
# domain does not support sched-credit?
info = {'weight': -1, 'cap': -1}
info['name'] = d['name']
info['domid'] = int(d['domid'])
print( ("%(name)-32s %(domid)3d %(weight)6d %(cap)4d") % info)
else:
result = server.xend.domain.sched_credit_set(domain, weight, cap)
if domid is None:
# place holder for system-wide scheduler parameters
err("No domain given.")
usage('sched-credit')
result = server.xend.domain.sched_credit_set(domid, weight, cap)
if result != 0:
err(str(result))
+29 -2
View File
@@ -12,14 +12,14 @@
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
# ============================================================================
# Copyright (c) 2006 XenSource Inc.
# Copyright (c) 2006-2007 XenSource Inc.
# ============================================================================
#
#
msgid ""
msgstr ""
"Project-Id-Version: Xen-xm 3.0\n"
"PO-Revision-Date: 2006-12-28 15:43+0000\n"
"PO-Revision-Date: 2007-01-31 12:34+0000\n"
"Last-Translator: Ewan Mellor <ewan@xensource.com>\n"
"Language-Team: xen-devel <xen-devel@lists.xensource.com>\n"
"MIME-Version: 1.0\n"
@@ -41,15 +41,30 @@ msgstr "The method %(1)s takes %(2)s argument(s) (%(3)s given)."
msgid "SESSION_AUTHENTICATION_FAILED"
msgstr "Permission denied."
msgid "VALUE_NOT_SUPPORTED"
msgstr "Value \"%(2)s\" for %(1)s is not supported by this server. The server said \"%(3)s\"."
msgid "HOST_CPU_HANDLE_INVALID"
msgstr "The host_cpu handle %(1)s is invalid."
msgid "HOST_HANDLE_INVALID"
msgstr "The host handle %(1)s is invalid."
msgid "HOST_METRICS_HANDLE_INVALID"
msgstr "The host_metrics handle %(1)s is invalid."
msgid "PIF_HANDLE_INVALID"
msgstr "The PIF handle %(1)s is invalid."
msgid "PIF_METRICS_HANDLE_INVALID"
msgstr "The PIF_METRICS handle %(1)s is invalid."
msgid "SR_HANDLE_INVALID"
msgstr "The SR handle %(1)s is invalid."
msgid "TASK_HANDLE_INVALID"
msgstr "The task handle %(1)s is invalid."
msgid "VBD_HANDLE_INVALID"
msgstr "The VBD handle %(1)s is invalid."
@@ -62,11 +77,23 @@ msgstr "The VIF handle %(1)s is invalid."
msgid "VM_HANDLE_INVALID"
msgstr "The VM handle %(1)s is invalid."
msgid "VM_METRICS_HANDLE_INVALID"
msgstr "The VM_metrics handle %(1)s is invalid."
msgid "VTPM_HANDLE_INVALID"
msgstr "The VTPM handle %(1)s is invalid."
msgid "OPERATION_NOT_ALLOWED"
msgstr "You attempted an operation that was not allowed."
msgid "NETWORK_ALREADY_CONNECTED"
msgstr "The network you specified already has a PIF attached to it, and so another one may not be attached."
msgid "PIF_IS_PHYSICAL"
msgstr "The PIF %(1)s corresponds to a physical interface, and so may not be destroyed."
msgid "VLAN_TAG_INVALID"
msgstr "The VLAN tag you gave (%(1)s) is invalid -- it must be between 0 and 4095."
msgid "VM_BAD_POWER_STATE"
msgstr "The VM must be %(2)s to perform the requested operation (it is currently %(3)s)."
+1
View File
@@ -52,6 +52,7 @@ def help():
def main(argv):
opts = gopts
opts.reset()
args = opts.parse(argv)
if len(args) != 2:
+10 -10
View File
@@ -250,7 +250,8 @@ class OptVar(Opt):
class OptVals:
"""Class to hold option values.
"""
pass
def __init__(self):
self.quiet = False
class Opts:
"""Container for options.
@@ -276,7 +277,6 @@ class Opts:
self.argv = []
# Option values.
self.vals = OptVals()
self.vals.quiet = 0
# Variables for default scripts.
self.vars = {}
# Option to use for bare words.
@@ -559,14 +559,6 @@ def set_bool(opt, k, v):
else:
opt.opts.err('Invalid value:' +v)
def set_u32(opt, k, v):
"""Set an option to an u32 value."""
try:
v = u32(v)
except:
opt.opts.err('Invalid value: ' + str(v))
opt.set(v)
def set_value(opt, k, v):
"""Set an option to a value."""
opt.set(v)
@@ -579,6 +571,14 @@ def set_int(opt, k, v):
opt.opts.err('Invalid value: ' + str(v))
opt.set(v)
def set_long(opt, k, v):
"""Set an option to a long integer value."""
try:
v = long(v)
except:
opt.opts.err('Invalid value: ' + str(v))
opt.set(v)
def set_float(opt, k, v):
"""Set an option to a float value."""
try:
+1
View File
@@ -118,6 +118,7 @@ def main_dom(opts, args):
def main(argv):
opts = gopts
opts.reset()
args = opts.parse(argv)
if opts.vals.help:
return
+2 -2
View File
@@ -3,9 +3,9 @@ import os.path
import tempfile
import unittest
import xen.xend.XendRoot
import xen.xend.XendOptions
xen.xend.XendRoot.XendRoot.config_default = '/dev/null'
xen.xend.XendOptions.XendOptions.config_default = '/dev/null'
import xen.xm.create
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.