merge with xen-unstable.hg

This commit is contained in:
awilliam@xenbuild2.aw committed 2007-01-10 08:40:47 -07:00
commit a77c31c882
341 files changed
+14414 -6261

No files matched your search

+16 -2
View File
@@ -7,16 +7,30 @@ all: build
.PHONY: 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 \
dest=`echo "build/$$file" | \
sed -e 's#xen-xm.po#LC_MESSAGES/xen-xm.mo#'`; \
mkdir -p `dirname "$$dest"`; \
$(MSGFMT) -c -o "$$dest" "xen/xm/$$file"; \
done; \
fi
.PHONY: install
ifndef XEN_PYTHON_NATIVE_INSTALL
install: all
install: install-messages
CC="$(CC)" CFLAGS="$(CFLAGS)" python setup.py install --home="$(DESTDIR)/usr" --prefix="" --force
else
install: all
install: install-messages
CC="$(CC)" CFLAGS="$(CFLAGS)" python setup.py install --root="$(DESTDIR)" --force
endif
install-messages: all
if which $(MSGFMT) >/dev/null ; then \
mkdir -p "$(DESTDIR)/usr/share/locale"; \
cp -R build/messages/* "$(DESTDIR)/usr/share/locale/"; \
fi
.PHONY: test
test:
export LD_LIBRARY_PATH=$$(readlink -f ../libxc):$$(readlink -f ../xenstore); python test.py -b -u
+70 -25
View File
@@ -41,6 +41,7 @@ VBD_LIST_FORMAT = '%(name_label)-18s %(uuid)-36s %(VDI)-8s '\
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]',
@@ -63,6 +64,15 @@ COMMANDS = {
}
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'})
],
'vm-list': [(('-l', '--long'),
{'action':'store_true',
'help':'List all properties of VMs'})
@@ -145,7 +155,7 @@ _session = None
def _connect(*args):
global _server, _session, _initialised
if not _initialised:
_server = ServerProxy('httpu:///var/run/xend/xmlrpc.sock')
_server = ServerProxy('httpu:///var/run/xend/xen-api.sock')
login = raw_input("Login: ")
password = getpass()
creds = (login, password)
@@ -361,29 +371,53 @@ def xapi_vbd_list(*args):
print VBD_LIST_FORMAT % vbd_struct
def xapi_vdi_list(*args):
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)
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
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):
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)
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 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):
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):
opts, args = parse_args('vdi-create', args)
@@ -421,10 +455,11 @@ def xapi_vdi_rename(*args):
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 'Renaming VDI %s to %s' % (vdi_uuid[0], vdi_name)
result = execute(server.VDI.set_name_label, session, vdi_uuid[0], vdi_name)
print 'Done.'
@@ -448,6 +483,14 @@ def xapi_vtpm_create(*args):
print "Has vtpm record '%s'" % vtpm_rec
def xapi_pif_list(*args):
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
#
# Command Line Utils
#
@@ -517,10 +560,12 @@ 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'])
@@ -549,7 +594,7 @@ def main(args):
try:
subcmd_func(*args[1:])
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
+16 -13
View File
@@ -35,6 +35,8 @@
fprintf(stderr, "ERROR: " _m " (%d = %s)\n" , ## _a , \
errno, strerror(errno))
static PyObject *acm_error_obj;
/* generic shared function */
void * __getssid(int domid, uint32_t *buflen)
{
@@ -80,28 +82,26 @@ static PyObject *policy(PyObject * self, PyObject * args)
{
/* out */
char *policyreference;
PyObject *ret = NULL;
PyObject *ret;
void *ssid_buffer;
uint32_t buf_len;
if (!PyArg_ParseTuple(args, "", NULL)) {
goto out1;
return NULL;
}
ssid_buffer = __getssid(0, &buf_len);
if (ssid_buffer == NULL) {
goto out1;
} else if (buf_len < sizeof(struct acm_ssid_buffer)) {
goto out2;
} else {
if (ssid_buffer == NULL || buf_len < sizeof(struct acm_ssid_buffer)) {
free(ssid_buffer);
return PyErr_SetFromErrno(acm_error_obj);
}
else {
struct acm_ssid_buffer *ssid = (struct acm_ssid_buffer *)ssid_buffer;
policyreference = (char *)(ssid_buffer + ssid->policy_reference_offset
+ sizeof (struct acm_policy_reference_buffer));
ret = Py_BuildValue("s", policyreference);
free(ssid_buffer);
return ret;
}
ret = Py_BuildValue("s", policyreference);
out2:
free(ssid_buffer);
out1:
return ret;
}
@@ -213,5 +213,8 @@ static PyMethodDef acmMethods[] = {
/* inits */
PyMODINIT_FUNC initacm(void)
{
Py_InitModule("acm", acmMethods);
PyObject *m = Py_InitModule("acm", acmMethods);
acm_error_obj = PyErr_NewException("acm.Error", PyExc_RuntimeError, NULL);
Py_INCREF(acm_error_obj);
PyModule_AddObject(m, "Error", acm_error_obj);
}
+25
View File
@@ -28,6 +28,31 @@ def cmd(p, s):
if not opts.dryrun:
os.system(c)
bridgeRE = re.compile(r'([^\t]*)\t*[^\t]*\t*[^\t]*\t*([^\t]*)')
def get_state():
fin = os.popen(CMD_BRCTL + ' show', 'r')
try:
bridges = {}
brlist = None
brname = None
first = True
for line in fin:
if first:
first = False
elif line[0] == '\t':
brlist.append(line.strip())
else:
if brname:
bridges[brname] = brlist
m = bridgeRE.match(line)
brname = m.group(1)
brlist = [m.group(2).strip()]
if brname:
bridges[brname] = brlist
return bridges
finally:
fin.close()
def vif_bridge_add(params):
"""Add the network interface for vif on dom to a bridge.
"""
+7 -5
View File
@@ -115,7 +115,7 @@ def get_security_info(info, field):
if isinstance(info, dict):
security = info['security']
elif isinstance(info, list):
security = sxp.child_value(info, 'security', )
security = sxp.child_value(info, 'security')
if not security:
if field == 'ssidref':
#return default ssid
@@ -357,7 +357,7 @@ def refresh_ssidref(config):
if isinstance(config, dict):
security = config['security']
elif isinstance(config, list):
security = sxp.child_value(config, 'security',)
security = sxp.child_value(config, 'security')
else:
err("Instance type of config parameter not supported.")
if not security:
@@ -637,11 +637,11 @@ def res_security_check(resource, domain_label):
"""
rtnval = 1
#build canonical resource name
resource = unify_resname(resource)
# if security is on, ask the hypervisor for a decision
if on():
#build canonical resource name
resource = unify_resname(resource)
(label, ssidref, policy) = get_res_security_details(resource)
domac = ['access_control']
domac.append(['policy', active_policy])
@@ -660,6 +660,8 @@ def res_security_check(resource, domain_label):
# security is off, make sure resource isn't labeled
else:
# Note, we can't canonicalise the resource here, because people using
# xm without ACM are free to use relative paths.
(label, policy) = get_res_label(resource)
if policy != 'NULL':
raise ACMError("Security is off, but '"+resource+"' is labeled")
+34 -12
View File
@@ -20,6 +20,7 @@
An enhanced XML-RPC client/server interface for Python.
"""
import re
import string
import fcntl
from types import *
@@ -49,13 +50,15 @@ except ImportError:
def stringify(value):
if isinstance(value, IntType) and not isinstance(value, BooleanType):
if isinstance(value, float) or \
isinstance(value, long) or \
(isinstance(value, int) and not isinstance(value, bool)):
return str(value)
elif isinstance(value, DictType):
elif isinstance(value, dict):
for k, v in value.items():
value[k] = stringify(v)
return value
elif isinstance(value, (TupleType, ListType)):
elif isinstance(value, (tuple, list)):
return [stringify(v) for v in value]
else:
return value
@@ -163,8 +166,10 @@ class ServerProxy(xmlrpclib.ServerProxy):
class TCPXMLRPCServer(SocketServer.ThreadingMixIn, SimpleXMLRPCServer):
allow_reuse_address = True
def __init__(self, addr, allowed, requestHandler=None,
def __init__(self, addr, allowed, xenapi, requestHandler=None,
logRequests = 1):
self.xenapi = xenapi
if requestHandler is None:
requestHandler = XMLRPCRequestHandler
SimpleXMLRPCServer.__init__(self, addr,
@@ -182,7 +187,7 @@ class TCPXMLRPCServer(SocketServer.ThreadingMixIn, SimpleXMLRPCServer):
flags |= fcntl.FD_CLOEXEC
fcntl.fcntl(client.fileno(), fcntl.F_SETFD, flags)
return (client, addr)
def _marshaled_dispatch(self, data, dispatch_method = None):
params, method = xmlrpclib.loads(data)
if False:
@@ -214,13 +219,30 @@ class TCPXMLRPCServer(SocketServer.ThreadingMixIn, SimpleXMLRPCServer):
except xmlrpclib.Fault, fault:
response = xmlrpclib.dumps(fault)
except Exception, exn:
import xen.xend.XendClient
log.exception(exn)
response = xmlrpclib.dumps(
xmlrpclib.Fault(xen.xend.XendClient.ERROR_INTERNAL, str(exn)))
if self.xenapi:
if _is_not_supported(exn):
errdesc = ['MESSAGE_METHOD_UNKNOWN', method]
else:
log.exception('Internal error handling %s', method)
errdesc = ['INTERNAL_ERROR', str(exn)]
response = xmlrpclib.dumps(
({ "Status": "Failure",
"ErrorDescription": errdesc },),
methodresponse = 1)
else:
log.exception('Internal error handling %s', method)
import xen.xend.XendClient
response = xmlrpclib.dumps(
xmlrpclib.Fault(xen.xend.XendClient.ERROR_INTERNAL, str(exn)))
return response
notSupportedRE = re.compile(r'method "(.*)" is not supported')
def _is_not_supported(exn):
m = notSupportedRE.search(exn[0])
return m is not None
# This is a XML-RPC server that sits on a Unix domain socket.
# It implements proper support for allow_reuse_address by
# unlink()'ing an existing socket.
@@ -235,10 +257,10 @@ class UnixXMLRPCRequestHandler(XMLRPCRequestHandler):
class UnixXMLRPCServer(TCPXMLRPCServer):
address_family = socket.AF_UNIX
def __init__(self, addr, allowed, logRequests = 1):
def __init__(self, addr, allowed, xenapi, logRequests = 1):
mkdir.parents(os.path.dirname(addr), stat.S_IRWXU, True)
if self.allow_reuse_address and os.path.exists(addr):
os.unlink(addr)
TCPXMLRPCServer.__init__(self, addr, allowed,
TCPXMLRPCServer.__init__(self, addr, allowed, xenapi,
UnixXMLRPCRequestHandler, logRequests)
File diff suppressed because it is too large. Load diff
+2 -1
View File
@@ -41,7 +41,7 @@ XEN_API_CPU_FEATURE = [
'CMOV', 'PAT', 'PSE36', 'PN', 'CLFLSH', 'DTES',
'ACPI', 'MMX', 'FXCR', 'XMM', 'XMM2', 'SELFSNOOP',
'HT', 'ACC', 'IA64', 'SYSCALL', 'MP', 'NX', 'MMXEXT',
'LM', '3DNOWEXT', '3DNOW', 'RECOVERY', 'LONGRUN',
'LM', 'THREEDNOWEXT', 'THREEDNOW', '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',
@@ -73,3 +73,4 @@ XEN_API_BOOT_TYPE = [
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']
-13
View File
@@ -130,16 +130,3 @@ def instance():
inst = XendAuthSessions()
inst.init()
return inst
# Handy Authentication Decorators
# -------------------------------
def session_required(func):
def check_session(self, session, *args, **kwargs):
if instance().is_session_valid(session):
return func(self, session, *args, **kwargs)
else:
return {'Status': 'Failure',
'ErrorDescription': XEND_ERROR_SESSION_INVALID}
return check_session
+6
View File
@@ -53,6 +53,12 @@ def bootloader(blexec, disk, quiet = False, blargs = '', kernel = '',
child = os.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)
+57 -33
View File
@@ -93,6 +93,8 @@ XENAPI_CFG_TO_LEGACY_CFG = {
'actions_after_reboot': 'on_reboot',
'actions_after_crash': 'on_crash',
'platform_localtime': 'localtime',
'PV_bootloader': 'bootloader',
'PV_bootloader_args': 'bootloader_args',
}
LEGACY_CFG_TO_XENAPI_CFG = reverse_dict(XENAPI_CFG_TO_LEGACY_CFG)
@@ -139,7 +141,7 @@ XENAPI_CFG_TYPES = {
'tpm_backend': int,
'PV_bootloader': str,
'PV_kernel': str,
'PV_initrd': str,
'PV_ramdisk': str,
'PV_args': str,
'PV_bootloader_args': str,
'HVM_boot': str,
@@ -297,7 +299,7 @@ class XendConfig(dict):
self._sxp_to_xapi_unsupported(sxp_obj)
elif xapi:
self.update_with_xenapi_config(xapi)
self._add_xapi_unsupported()
self._add_xapi_unsupported(xapi)
elif dominfo:
# output from xc.domain_getinfo
self._dominfo_to_xapi(dominfo)
@@ -506,8 +508,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,
@@ -570,7 +576,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)):
@@ -715,6 +720,8 @@ class XendConfig(dict):
_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')
@@ -724,19 +731,22 @@ class XendConfig(dict):
_set_cfg_if_exists('up_time')
_set_cfg_if_exists('status') # TODO, deprecated
def _add_xapi_unsupported(self):
def _add_xapi_unsupported(self, xapi_dict):
"""Updates the configuration object with entries that are not
officially supported by the Xen API but is required for
the rest of Xend to function.
"""
# populate image
hvm = self['HVM_boot'] != ''
self['image']['type'] = hvm and 'hvm' or 'linux'
if hvm:
self['image']['hvm'] = {}
for xapi, cfgapi in XENAPI_HVM_CFG.items():
self['image']['hvm'][cfgapi] = self[xapi]
if 'image' in xapi_dict:
self['image'].update(xapi_dict['image'])
else:
hvm = self['HVM_boot'] != ''
self['image']['type'] = hvm and 'hvm' or 'linux'
if hvm:
self['image']['hvm'] = {}
for xapi, cfgapi in XENAPI_HVM_CFG.items():
self['image']['hvm'][cfgapi] = self[xapi]
def _get_old_state_string(self):
@@ -848,14 +858,15 @@ 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:
sxpr.append(['device', config])
found = True
found = True
except:
log.exception("dumping sxp from device controllers")
pass
@@ -916,11 +927,12 @@ 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':
if dev_info.get('dev', '').startswith('ioemu:'):
@@ -989,7 +1001,7 @@ class XendConfig(dict):
self['vbd_refs'].append(dev_uuid)
return dev_uuid
elif dev_type in ('vtpm'):
elif dev_type == 'vtpm':
if cfg_xenapi.get('type'):
dev_info['type'] = cfg_xenapi.get('type')
@@ -1012,11 +1024,12 @@ class XendConfig(dict):
dev_type = sxp.name(config)
dev_info = {}
try:
for opt, val in config[1:]:
self['devices'][opt] = val
except ValueError:
pass # SXP has no options for this device
for opt_val in config[1:]:
try:
opt, val = opt_val
self['devices'][dev_uuid][opt] = val
except (TypeError, ValueError):
pass # no value for this config option
return True
@@ -1095,23 +1108,34 @@ class XendConfig(dict):
return image
def update_with_image_sxp(self, image_sxp):
def update_with_image_sxp(self, image_sxp, bootloader = False):
# Convert Legacy "image" config to Xen API PV_*
# configuration
log.debug("update_with_image_sxp(%s)" % scrub_password(image_sxp))
self['PV_kernel'] = sxp.child_value(image_sxp, 'kernel','')
self['PV_ramdisk'] = sxp.child_value(image_sxp, 'ramdisk','')
kernel_args = sxp.child_value(image_sxp, 'args', '')
kernel_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
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
self['PV_args'] = kernel_args
kernel_args += 'root=%s ' % arg_root
# 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', '')
if bootloader:
self['_temp_using_bootloader'] = '1'
self['_temp_kernel'] = sxp.child_value(image_sxp, 'kernel','')
self['_temp_ramdisk'] = sxp.child_value(image_sxp, 'ramdisk','')
self['_temp_args'] = kernel_args
else:
self['PV_kernel'] = sxp.child_value(image_sxp, 'kernel','')
self['PV_ramdisk'] = sxp.child_value(image_sxp, 'ramdisk','')
self['PV_args'] = kernel_args
# Store image SXP in python dictionary format
image = {}
+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)
+44 -7
View File
@@ -36,6 +36,7 @@ from xen.xend import XendRoot, XendCheckpoint, XendDomainInfo
from xen.xend.PrettyPrint import prettyprint
from xen.xend.XendConfig import XendConfig
from xen.xend.XendError import XendError, XendInvalidDomain, VmError
from xen.xend.XendError import VMBadState
from xen.xend.XendLogging import log
from xen.xend.XendAPIConstants import XEN_API_VM_POWER_STATE
from xen.xend.XendConstants import XS_VMROOT
@@ -376,7 +377,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).
@@ -392,7 +393,7 @@ 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)
@@ -494,7 +495,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))
@@ -604,6 +605,16 @@ class XendDomain:
finally:
self.domains_lock.release()
def get_all_vms(self):
self.domains_lock.acquire()
try:
result = self.domains.values()
result += [x for x in self.managed_domains.values() if
x not in result]
return result
finally:
self.domains_lock.release()
def get_vm_by_uuid(self, vm_uuid):
self.domains_lock.acquire()
try:
@@ -720,7 +731,7 @@ class XendDomain:
self.domains_lock.acquire()
try:
self._refresh()
self._refresh(refresh_shutdown = False)
# active domains
active_domains = self.domains.values()
@@ -782,7 +793,9 @@ class XendDomain:
raise XendError("Cannot save privileged domain %s" % domname)
if dominfo.state != DOM_STATE_RUNNING:
raise XendError("Cannot suspend domain that is not running.")
raise VMBadState("Domain is not running",
POWER_STATE_NAMES[DOM_STATE_RUNNING],
POWER_STATE_NAMES[dominfo.state])
dom_uuid = dominfo.get_uuid()
@@ -869,6 +882,26 @@ class XendDomain:
self.domains_lock.release()
def domain_create_from_dict(self, config_dict):
"""Create a domain from a configuration dictionary.
@param config_dict: configuration
@rtype: XendDomainInfo
"""
self.domains_lock.acquire()
try:
self._refresh()
dominfo = XendDomainInfo.create_from_dict(config_dict)
self._add_domain(dominfo)
self.domain_sched_credit_set(dominfo.getDomid(),
dominfo.getWeight(),
dominfo.getCap())
return dominfo
finally:
self.domains_lock.release()
def domain_new(self, config):
"""Create a domain from a configuration but do not start it.
@@ -912,7 +945,9 @@ class XendDomain:
raise XendInvalidDomain(str(domid))
if dominfo.state != DOM_STATE_HALTED:
raise XendError("Domain is already running")
raise VMBadState("Domain is already running",
POWER_STATE_NAMES[DOM_STATE_HALTED],
POWER_STATE_NAMES[dominfo.state])
dominfo.start(is_managed = True)
self._add_domain(dominfo)
@@ -940,7 +975,9 @@ class XendDomain:
raise XendInvalidDomain(str(domid))
if dominfo.state != DOM_STATE_HALTED:
raise XendError("Domain is still running")
raise VMBadState("Domain is still running",
POWER_STATE_NAMES[DOM_STATE_HALTED],
POWER_STATE_NAMES[dominfo.state])
log.info("Domain %s (%s) deleted." %
(dominfo.getName(), dominfo.info.get('uuid')))
+60 -24
View File
@@ -37,7 +37,7 @@ 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 balloon, sxp, uuid, image, arch, osdep
from xen.xend import XendRoot, XendNode, XendConfig
from xen.xend.XendConfig import scrub_password
@@ -81,13 +81,12 @@ log = logging.getLogger("xend.XendDomainInfo")
def create(config):
"""Creates and start a VM using the supplied configuration.
(called from XMLRPCServer directly)
@param config: A configuration object involving lists of tuples.
@type config: list of lists, eg ['vm', ['image', 'xen.gz']]
@rtype: XendDomainInfo
@return: A up and running XendDomainInfo instance
@return: An up and running XendDomainInfo instance
@raise VmError: Invalid configuration or failure to start.
"""
@@ -102,6 +101,28 @@ def create(config):
return vm
def create_from_dict(config_dict):
"""Creates and start a VM using the supplied configuration.
@param config_dict: An configuration dictionary.
@rtype: XendDomainInfo
@return: An up and running XendDomainInfo instance
@raise VmError: Invalid configuration or failure to start.
"""
log.debug("XendDomainInfo.create_from_dict(%s)",
scrub_password(config_dict))
vm = XendDomainInfo(XendConfig.XendConfig(xapi = config_dict))
try:
vm.start()
except:
log.exception('Domain construction failed')
vm.destroy()
raise
return vm
def recreate(info, priv):
"""Create the VM object for an existing domain. The domain must not
be dying, as the paths in the store should already have been removed,
@@ -418,7 +439,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')
@@ -490,7 +511,7 @@ class XendDomainInfo:
# look up uuid of the device
dev_control = self.getDeviceController(deviceClass)
dev_sxpr = dev_control.sxpr(devid)
dev_uuid = sxp.child_value(sxpr, 'uuid')
dev_uuid = sxp.child_value(dev_sxpr, 'uuid')
if not dev_uuid:
return False
@@ -893,7 +914,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
@@ -948,9 +969,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()
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)
@@ -967,6 +994,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()
@@ -1051,12 +1079,6 @@ class XendDomainInfo:
"""
from xen.xend import XendDomain
config = self.sxpr()
if self._infoIsSet('cpus') and len(self.info['cpus']) != 0:
config.append(['cpus', reduce(lambda x, y: str(x) + "," + str(y),
self.info['cpus'])])
if self._readVm(RESTART_IN_PROGRESS):
log.error('Xend failed during restart of domain %s. '
'Refusing to restart to avoid loops.',
@@ -1097,7 +1119,8 @@ class XendDomainInfo:
new_dom = None
try:
new_dom = XendDomain.instance().domain_create(config)
new_dom = XendDomain.instance().domain_create_from_dict(
self.info)
new_dom.unpause()
rst_cnt = self._readVm('xend/restart_count')
rst_cnt = int(rst_cnt) + 1
@@ -1146,7 +1169,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:
@@ -1539,6 +1565,8 @@ class XendDomainInfo:
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
elif not blexec and kernel:
# Boot from dom0. Nothing left to do -- the kernel and ramdisk
@@ -1547,7 +1575,7 @@ 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():
@@ -1598,7 +1626,7 @@ class XendDomainInfo:
log.error(msg)
raise VmError(msg)
self.info.update_with_image_sxp(blcfg)
self.info.update_with_image_sxp(blcfg, True)
#
@@ -1831,8 +1859,7 @@ class XendDomainInfo:
return self.info.get('memory_dynamic_max', 0)
def get_memory_dynamic_min(self):
return self.info.get('memory_dynamic_min', 0)
def get_vcpus_policy(self):
sched_id = xc.sched_id_get()
if sched_id == xen.lowlevel.xc.XEN_SCHEDULER_SEDF:
@@ -1847,8 +1874,6 @@ class XendDomainInfo:
return XEN_API_VM_POWER_STATE[self.state]
def get_platform_std_vga(self):
return self.info.get('platform_std_vga', False)
def get_platform_keymap(self):
return ''
def get_platform_serial(self):
return self.info.get('platform_serial', '')
def get_platform_localtime(self):
@@ -1952,8 +1977,19 @@ class XendDomainInfo:
config['device'] = 'eth%d' % devid
else:
config['device'] = ''
config['network'] = '' # Invalid for Xend
if not config.has_key('network'):
try:
config['network'] = \
XendNode.instance().bridge_to_network(
config.get('bridge')).uuid
except Exception:
log.exception('bridge_to_network')
# Ignore this for now -- it may happen if the device
# has been specified using the legacy methods, but at
# some point we're going to have to figure out how to
# handle that properly.
config['MTU'] = 1500 # TODO
config['io_read_kbs'] = 0.0
config['io_write_kbs'] = 0.0
@@ -1965,7 +2001,7 @@ class XendDomainInfo:
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'
+11
View File
@@ -32,6 +32,17 @@ class XendError(Fault):
def __str__(self):
return self.value
class VMBadState(XendError):
def __init__(self, value, expected, actual):
XendError.__init__(self, value)
self.expected = expected
self.actual = actual
class NetworkAlreadyConnected(XendError):
def __init__(self, pif_uuid):
XendError.__init__(self, 'Network already connected')
self.pif_uuid = pif_uuid
class VmError(XendError):
"""Vm construction error."""
pass
+22 -1
View File
@@ -16,7 +16,10 @@
# Copyright (C) 2005, 2006 XenSource Ltd.
#============================================================================
import inspect
import os
import os.path
import sys
import stat
import tempfile
import types
@@ -38,6 +41,24 @@ if 'TRACE' not in logging.__dict__:
self.log(logging.TRACE, *args, **kwargs)
logging.Logger.trace = trace
def findCaller(self):
"""
Override logging.Logger.findCaller so that the above trace function
does not appear as the source of log messages. The signature of this
function changed between Python 2.3 and 2.4.
"""
frames = inspect.stack()
thisfile = os.path.normcase(frames[0][1])
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:
return filename, frame[2], frame[3]
else:
return filename, frame[2]
logging.Logger.findCaller = findCaller
log = logging.getLogger("xend")
@@ -46,7 +67,7 @@ MAX_BYTES = 1 << 20 # 1MB
BACKUP_COUNT = 5
STDERR_FORMAT = "[%(name)s] %(levelname)s (%(module)s:%(lineno)d) %(message)s"
LOGFILE_FORMAT = "[%(asctime)s %(name)s %(process)d] %(levelname)s (%(module)s:%(lineno)d) %(message)s"
LOGFILE_FORMAT = "[%(asctime)s %(process)d] %(levelname)s (%(module)s:%(lineno)d) %(message)s"
DATE_FORMAT = "%Y-%m-%d %H:%M:%S"
+112
View File
@@ -0,0 +1,112 @@
#============================================================================
# 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 Xensource Inc.
#============================================================================
import os
import commands
import re
import struct
import socket
import XendDomain
import XendNode
from XendLogging import log
IP_ROUTE_RE = r'^default via ([\d\.]+) dev (\w+)'
def linux_get_default_network():
"""Returns the network details of the host."""
ip_cmd = '/sbin/ip route'
rc, output = commands.getstatusoutput(ip_cmd)
default_route = None
default_dev = None
default_netmask = None
if rc == 0:
# find default route/device
for line in output.split('\n'):
is_default = re.search(IP_ROUTE_RE, line)
if is_default:
default_route = is_default.group(1)
default_dev = is_default.group(2)
# find network address and network mask
if default_dev:
dev_re = r'^([\d\.]+)/(\d+) dev %s' % default_dev
for line in output.split('\n'):
is_dev = re.search(dev_re, line)
if is_dev:
# convert integer netmask to string representation
netmask = 0xffffffff ^ (2**(32-int(is_dev.group(2))) - 1)
packed = struct.pack('!I', netmask)
default_netmask = socket.inet_ntoa(packed)
return (default_route, default_netmask)
class XendNetwork:
def __init__(self, uuid, name, description, gateway, netmask):
self.uuid = uuid
self.name_label = name
self.name_description = description
self.default_gateway = gateway
self.default_netmask = netmask
def set_name_label(self, new_name):
self.name_label = new_name
XendNode.instance().save_networks()
def set_name_description(self, new_desc):
self.name_description = new_desc
XendNode.instance().save_networks()
def set_default_gateway(self, new_gateway):
if re.search('^\d+\.\d+\.\d+\.\d+$', new_gateway):
self.default_gateway = new_gateway
XendNode.instance().save_networks()
def set_default_netmask(self, new_netmask):
if re.search('^\d+\.\d+\.\d+\.\d+$', new_netmask):
self.default_netmask = new_netmask
XendNode.instance().save_networks()
def get_VIF_UUIDs(self):
result = []
vms = XendDomain.instance().get_all_vms()
for vm in vms:
vifs = vm.get_vifs()
for vif in vifs:
vif_cfg = vm.get_dev_xenapi_config('vif', vif)
if vif_cfg.get('network') == self.uuid:
result.append(vif)
return result
def get_PIF_UUIDs(self):
return [x.uuid for x in XendNode.instance().pifs.values()
if x.network == self]
def get_record(self, transient = True):
result = {
'uuid': self.uuid,
'name_label': self.name_label,
'name_description': self.name_description,
'default_gateway': self.default_gateway,
'default_netmask': self.default_netmask,
}
if transient:
result['VIFs'] = self.get_VIF_UUIDs()
result['PIFs'] = self.get_PIF_UUIDs()
return result
+214 -20
View File
@@ -19,34 +19,181 @@
import os
import socket
import xen.lowlevel.xc
from xen.util import Brctl
from xen.xend import uuid
from xen.xend.XendError import XendError
from xen.xend.XendError import XendError, NetworkAlreadyConnected
from xen.xend.XendRoot import instance as xendroot
from xen.xend.XendStorageRepository import XendStorageRepository
from xen.xend.XendLogging import log
from xen.xend.XendPIF import *
from xen.xend.XendNetwork import *
from xen.xend.XendStateStore import XendStateStore
class XendNode:
"""XendNode - Represents a Domain 0 Host."""
def __init__(self):
self.xc = xen.lowlevel.xc.xc()
self.uuid = uuid.createString()
self.cpus = {}
self.name = socket.gethostname()
self.desc = ""
self.sr = XendStorageRepository()
"""Initalises the state of all host specific objects such as
* Host
* Host_CPU
* PIF
* Network
* Storage Repository
"""
self.xc = xen.lowlevel.xc.xc()
self.state_store = XendStateStore(xendroot().get_xend_state_path())
# load host state from XML file
saved_host = self.state_store.load_state('host')
if saved_host and len(saved_host.keys()) == 1:
self.uuid = saved_host.keys()[0]
host = saved_host[self.uuid]
self.name = host.get('name_label', socket.gethostname())
self.desc = host.get('name_description', '')
self.cpus = {}
else:
self.uuid = uuid.createString()
self.name = socket.gethostname()
self.desc = ''
self.cpus = {}
# load CPU UUIDs
saved_cpus = self.state_store.load_state('cpu')
for cpu_uuid, cpu in saved_cpus.items():
self.cpus[cpu_uuid] = cpu
# verify we have enough cpus here
physinfo = self.physinfo_dict()
cpu_count = physinfo['nr_cpus']
cpu_features = physinfo['hw_caps']
for i in range(cpu_count):
# construct uuid by appending extra bit on the host.
# since CPUs belong to a host.
cpu_uuid = self.uuid + '-%04d' % i
cpu_info = {'uuid': cpu_uuid,
'host': self.uuid,
'number': i,
'features': cpu_features}
self.cpus[cpu_uuid] = cpu_info
# If the number of CPUs don't match, we should just reinitialise
# the CPU UUIDs.
if cpu_count != len(self.cpus):
self.cpus = {}
for i in range(cpu_count):
cpu_uuid = uuid.createString()
cpu_info = {'uuid': cpu_uuid,
'host': self.uuid,
'number': i,
'features': cpu_features}
self.cpus[cpu_uuid] = cpu_info
self.pifs = {}
self.networks = {}
# initialise networks
saved_networks = self.state_store.load_state('network')
if saved_networks:
for net_uuid, network in saved_networks.items():
self.network_create(network.get('name_label'),
network.get('name_description', ''),
network.get('default_gateway', ''),
network.get('default_netmask', ''),
False, net_uuid)
else:
gateway, netmask = linux_get_default_network()
self.network_create('net0', '', gateway, netmask, False)
# initialise PIFs
saved_pifs = self.state_store.load_state('pif')
if saved_pifs:
for pif_uuid, pif in saved_pifs.items():
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)
except NetworkAlreadyConnected, exn:
log.error('Cannot load saved PIF %s, as network %s ' +
'is already connected to PIF %s',
pif_uuid, pif['network'], exn.pif_uuid)
else:
for name, mtu, mac in linux_get_phy_ifaces():
network = self.networks.values()[0]
self.PIF_create(name, mtu, '', 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)
def network_create(self, name_label, name_description,
default_gateway, default_netmask, persist = True,
net_uuid = None):
if net_uuid is None:
net_uuid = uuid.createString()
self.networks[net_uuid] = XendNetwork(net_uuid, name_label,
name_description,
default_gateway,
default_netmask)
if persist:
self.save_networks()
return net_uuid
def network_destroy(self, net_uuid):
del self.networks[net_uuid]
self.save_networks()
def PIF_create(self, name, mtu, vlan, mac, network, persist = True,
pif_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 persist:
self.save_PIFs()
self.refreshBridges()
return pif_uuid
def PIF_create_VLAN(self, pif_uuid, network_uuid, vlan):
pif = self.pifs[pif_uuid]
network = self.networks[network_uuid]
return self.PIF_create(pif.name, pif.mtu, vlan, pif.mac, network)
def PIF_destroy(self, pif_uuid):
del self.pifs[pif_uuid]
self.save_PIFs()
def save(self):
# save state
host_record = {self.uuid: {'name_label':self.name,
'name_description':self.desc}}
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)
def save_PIFs(self):
pif_records = dict([(k, v.get_record(transient = False))
for k, v in self.pifs.items()])
self.state_store.save_state('pif', pif_records)
def save_networks(self):
net_records = dict([(k, v.get_record(transient = False))
for k, v in self.networks.items()])
self.state_store.save_state('network', net_records)
def shutdown(self):
return 0
@@ -56,7 +203,8 @@ class XendNode:
def notify(self, _):
return 0
#
# Ref validation
#
@@ -67,6 +215,9 @@ class XendNode:
def is_valid_cpu(self, cpu_ref):
return (cpu_ref in self.cpus)
def is_valid_network(self, network_ref):
return (network_ref in self.networks)
#
# Storage Repo
#
@@ -100,6 +251,9 @@ class XendNode:
def set_description(self, new_desc):
self.desc = new_desc
def get_uuid(self):
return self.uuid
#
# Host CPU Functions
#
@@ -133,7 +287,42 @@ class XendNode:
def get_host_cpu_load(self, host_cpu_ref):
return 0.0
#
# Network Functions
#
def get_network_refs(self):
return self.networks.keys()
def get_network(self, network_ref):
return self.networks[network_ref]
def bridge_to_network(self, bridge):
"""
Determine which network a particular bridge is attached to.
@param bridge The name of the bridge. If empty, the default bridge
will be used instead (the first one in the list returned by brctl
show); this is the behaviour of the vif-bridge script.
@return The XendNetwork instance to which this bridge is attached.
@raise Exception if the interface is not connected to a network.
"""
if not bridge:
rc, bridge = commands.getstatusoutput(
'brctl show | cut -d "\n" -f 2 | cut -f 1')
if rc != 0 or not bridge:
raise Exception(
'Could not find default bridge, and none was specified')
bridges = Brctl.get_state()
if bridge not in bridges:
raise Exception('Bridge %s is not up' % bridge)
for pif in self.pifs.values():
if pif.interface_name() in bridges[bridge]:
return pif.network
raise Exception('Bridge %s is not connected to a network' % bridge)
#
# Getting host information.
@@ -210,7 +399,12 @@ class XendNode:
return dict(self.physinfo())
def info_dict(self):
return dict(self.info())
def refreshBridges(self):
for pif in self.pifs.values():
pif.refresh(Brctl.get_state())
def instance():
global inst
@@ -218,5 +412,5 @@ def instance():
inst
except:
inst = XendNode()
inst.save()
return inst
+198
View File
@@ -0,0 +1,198 @@
#============================================================================
# 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 Xensource Inc.
#============================================================================
import commands
import logging
import os
import re
log = logging.getLogger("xend.XendPIF")
log.setLevel(logging.TRACE)
MAC_RE = re.compile(':'.join(['[0-9a-f]{2}'] * 6))
IP_IFACE_RE = re.compile(r'^\d+: (\w+):.*mtu (\d+) .* link/\w+ ([0-9a-f:]+)')
def linux_phy_to_virt(pif_name):
return 'eth' + re.sub(r'^[a-z]+', '', pif_name)
def linux_get_phy_ifaces():
"""Returns a list of physical interfaces.
Identifies PIFs as those that have a interface name starting with 'p'
and have the fake 'fe:ff:ff:ff:ff:ff' MAC address.
See /etc/xen/scripts/network-bridge for how the devices are renamed.
@rtype: array of 3-element tuple (name, mtu, mac)
"""
ip_cmd = 'ip -o link show'
rc, output = commands.getstatusoutput(ip_cmd)
ifaces = {}
phy_ifaces = []
if rc == 0:
# parse all interfaces into (name, mtu, mac)
for line in output.split('\n'):
has_if = re.search(IP_IFACE_RE, line)
if has_if:
ifaces[has_if.group(1)] = has_if.groups()
# resolve pifs' mac addresses
for name, mtu, mac in ifaces.values():
if name[0] == 'p' and mac == 'fe:ff:ff:ff:ff:ff':
bridged_ifname = linux_phy_to_virt(name)
bridged_if = ifaces.get(bridged_ifname)
if bridged_if:
bridged_mac = bridged_if[2]
phy_ifaces.append((name, int(mtu), bridged_mac))
return phy_ifaces
def linux_set_mac(iface, mac):
if not re.search(MAC_RE, mac):
return False
ip_mac_cmd = 'ip link set %s addr %s' % \
(linux_phy_to_virt(iface), mac)
rc, output = commands.getstatusoutput(ip_mac_cmd)
if rc == 0:
return True
return False
def linux_set_mtu(iface, mtu):
try:
ip_mtu_cmd = 'ip link set %s mtu %d' % \
(linux_phy_to_virt(iface), int(mtu))
rc, output = commands.getstatusoutput(ip_mtu_cmd)
if rc == 0:
return True
return False
except ValueError:
return False
class XendPIF:
"""Representation of a Physical Network Interface."""
def __init__(self, uuid, name, mtu, vlan, mac, network, host):
self.uuid = uuid
self.name = name
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_mac(self, new_mac):
success = linux_set_mac(new_mac)
if success:
self.mac = new_mac
return success
def set_mtu(self, new_mtu):
success = linux_set_mtu(new_mtu)
if success:
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 refresh(self, bridges):
ifname = self.interface_name()
rc, _ = _cmd('ip link show %s', ifname)
if rc != 0:
# Interface does not exist. If it's a physical interface, then
# 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:
return
rc, _ = _cmd('vconfig add %s %s', self.name, self.vlan)
if rc != 0:
log.error('Could not refresh %s', ifname)
return
log.info('Created network interface %s', ifname)
for brname, nics in bridges.items():
if ifname in nics:
log.debug('%s is already attached to %s', ifname, brname)
return
# The interface is not attached to a bridge. Create one, and attach
# the interface to it.
brname = _new_bridge_name(bridges)
rc, _ = _cmd('brctl addbr %s', brname)
if rc != 0:
log.error('Could not create bridge %s for interface %s', brname,
ifname)
return
log.info('Created network bridge %s', brname)
rc, _ = _cmd('brctl addif %s %s', brname, ifname)
if rc != 0:
log.error('Could not add %s to %s', ifname, brname)
return
log.info('Added network interface %s to bridge %s', ifname, brname)
def interface_name(self):
if self.vlan:
return '%s.%s' % (self.name, self.vlan)
else:
return self.name
def _cmd(cmd, *args):
if len(args) > 0:
cmd = cmd % args
rc, output = commands.getstatusoutput(cmd)
if rc != 0:
log.debug('%s failed with code %d' % (cmd, rc))
log.trace('%s: %s' % (cmd, output))
return rc, output
def _new_bridge_name(bridges):
n = 0
while True:
brname = 'xenbr%d' % n
if brname not in bridges:
return brname
n += 1
+8
View File
@@ -104,6 +104,9 @@ class XendRoot:
"""Default session storage path."""
xend_domains_path_default = '/var/lib/xend/domains'
"""Default xend management state storage."""
xend_state_path_default = '/var/lib/xend/state'
components = {}
def __init__(self):
@@ -263,6 +266,11 @@ class XendRoot:
"""
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."""
+210
View File
@@ -0,0 +1,210 @@
#============================================================================
# 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) 2004, 2005 Mike Wray <mike.wray@hp.com>
# Copyright (c) 2006 Xensource Inc.
#============================================================================
import os
from xen.xend import uuid
from xen.xend.XendLogging import log
from xml.dom import minidom
from xml.dom import Node
class XendStateStore:
"""Manages persistent storage of Xend's internal state, mainly
relating to API objects.
It stores objects atomically in the file system as flat XML files
categorised by their 'class'.
For example:
/var/lib/xend/state/cpu.xml will contain the host cpu state
/var/lib/xend/state/sr.xml will contain the storage repository state.
For the application, it will load the state via this class:
load_state('cpu') will return a marshalled dictionary object
containing the cpu state.
save_state('cpu', dict) will save the state contained in the dictionary
object about the 'cpu'.
The state is stored where each top level element has a UUID in its
attributes. eg:
host['49c01812-3c28-1ad4-a59d-2a3f81b13ec2'] = {
'name': 'norwich',
'desc': 'Test Xen Host',
'cpu': {'6fc2d1ed-7eb0-4c9d-8006-3657d5483ae0': <obj>,
'669df3b8-62be-4e61-800b-bbe8ee63a760': <obj>}
}
will turn into:
<hosts>
<host uuid='49c01812-3c28-1ad4-a59d-2a3f81b13ec2'>
<name type='string'>norwich</name>
<description type='string'>Test Xen Host</description>
<cpu uuid='6fc2d1ed-7eb0-4c9d-8006-3657d5483ae0' />
<cpu uuid='669df3b8-62be-4e61-800b-bbe8ee63a760' />
</host>
</hosts>
Note that it only dumps one level, so the references to CPU are
stored in a separate file.
"""
def __init__(self, base = "/var/lib/xend/state"):
self.base = base
if not os.path.exists(self.base):
os.makedirs(self.base)
def _xml_file(self, cls):
"""Return the absolute filename of the XML state storage file.
@param cls: name of the class.
@type cls: string
@rtype: string
@return absolute filename of XML file to write/read from.
"""
return os.path.join(self.base, '%s.xml' % cls)
def load_state(self, cls):
"""Load the saved state of a class from persistent XML storage.
References loaded from the XML will just point to an empty
dictionary which the caller will need to replace manually.
@param cls: name of the class to load.
@type cls: string
@rtype: dict
"""
xml_path = self._xml_file(cls)
if not os.path.exists(xml_path):
return {}
dom = minidom.parse(xml_path)
root = dom.documentElement
state = {}
for child in root.childNodes:
if child.nodeType != Node.ELEMENT_NODE:
continue # skip non element nodes
uuid = child.getAttribute('uuid')
cls_dict = {}
for val_elem in child.childNodes:
if val_elem.nodeType != Node.ELEMENT_NODE:
continue # skip non element nodes
val_name = val_elem.tagName
val_type = val_elem.getAttribute('type').encode('utf8')
val_uuid = val_elem.getAttribute('uuid').encode('utf8')
val_elem.normalize()
val_text = ''
if val_elem.firstChild:
val_text = val_elem.firstChild.nodeValue.strip()
if val_type == '' and val_uuid != '':
# this is a reference
if val_name not in cls_dict:
cls_dict[val_name] = {}
cls_dict[val_name][val_uuid] = None
elif val_type == 'string':
cls_dict[val_name] = val_text.encode('utf8')
elif val_type == 'float':
cls_dict[val_name] = float(val_text)
elif val_type == 'int':
cls_dict[val_name] = int(val_text)
elif val_type == 'bool':
cls_dict[val_name] = bool(int(val_text))
state[uuid] = cls_dict
return state
def save_state(self, cls, state):
"""Save a Xen API record struct into an XML persistent storage
for future loading when Xend restarts.
If we encounter a dictionary or a list, we only store the
keys because they are going to be UUID references to another
object.
@param cls: Class name (singular) of the record
@type cls: string
@param state: a Xen API struct of the state of the class.
@type state: dict
@rtype: None
"""
xml_path = self._xml_file(cls)
doc = minidom.getDOMImplementation().createDocument(None,
cls + 's',
None)
root = doc.documentElement
# Marshall a dictionary into our custom XML file format.
for uuid, info in state.items():
node = doc.createElement(cls)
root.appendChild(node)
node.setAttribute('uuid', uuid)
for key, val in info.items():
store_val = val
store_type = None
# deal with basic types
if type(val) in (str, unicode):
store_val = val
store_type = 'string'
elif type(val) == int:
store_val = str(val)
store_type = 'int'
elif type(val) == float:
store_val = str(val)
store_type = 'float'
elif type(val) == bool:
store_val = str(int(val))
store_type = 'bool'
if store_type != None:
val_node = doc.createElement(key)
val_node.setAttribute('type', store_type)
node.appendChild(val_node)
# attach the value
val_text = doc.createTextNode(store_val)
val_node.appendChild(val_text)
continue
# deal with dicts and lists
if type(val) == dict:
for val_uuid in val.keys():
val_node = doc.createElement(key)
val_node.setAttribute('uuid', val_uuid)
node.appendChild(val_node)
elif type(val) in (list, tuple):
for val_uuid in val:
val_node = doc.createElement(key)
val_node.setAttribute('uuid', val_uuid)
node.appendChild(val_node)
open(xml_path, 'w').write(doc.toprettyxml())
+104 -70
View File
@@ -24,25 +24,38 @@ 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_MAX_IGNORE = -1
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 -p %d %s"
QCOW_CREATE_COMMAND = "/usr/sbin/qcow-create -r %d %s"
MB = 1024 * 1024
log = logging.getLogger("xend.XendStorageRepository")
class DeviceInvalidError(Exception):
pass
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.
@@ -54,11 +67,13 @@ class XendStorageRepository:
The actual images are created in the format <uuid>.img and <uuid>.qcow.
"""
def __init__(self, storage_dir = XEND_STORAGE_DIR,
storage_max = XEND_STORAGE_MAX_IGNORE):
def __init__(self, uuid,
sr_type = "qcow_file",
name_label = "Local",
name_description = "Xend Storage Repository",
location = XEND_STORAGE_DIR,
storage_max = XEND_STORAGE_NO_MAXIMUM):
"""
@keyword storage_dir: Where the images will be stored.
@type storage_dir: string
@keyword storage_max: Maximum disk space to use in bytes.
@type storage_max: int
@@ -67,71 +82,82 @@ class XendStorageRepository:
@type images: dictionary by image uuid.
@ivar lock: lock to provide thread safety.
"""
self.storage_dir = storage_dir
self.storage_max = storage_max
self.storage_free = 0
self.images = {}
# XenAPI Parameters
self.uuid = self._sr_uuid()
self.type = "qcow-file"
self.location = self.storage_dir
self.name_label = "Local"
self.name_description = "Xend Storage Repository"
self.uuid = uuid
self.type = sr_type
self.location = location
self.name_label = name_label
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.lock = threading.RLock()
self._refresh()
self._refresh()
def _sr_uuid(self):
uuid_file = os.path.join(XEND_STORAGE_DIR, 'uuid')
try:
if uuid_file and os.path.exists(uuid_file):
return open(uuid_file, 'r').read().strip()
else:
new_uuid = uuid.createString()
open(uuid_file, 'w').write(new_uuid + '\n')
return new_uuid
except IOError:
log.exception("Failed to determine SR UUID")
return uuid.createString()
def get_record(self):
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,
'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(XEND_STORAGE_DIR, stat.S_IRWXU)
mkdir.parents(self.location, stat.S_IRWXU)
# scan the directory and populate self.images
total_used = 0
virtual_alloc = 0
physical_used = 0
seen_images = []
for filename in os.listdir(XEND_STORAGE_DIR):
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:
qcow_file = XEND_STORAGE_QCOW_FILENAME % image_uuid
cfg_file = XEND_STORAGE_VDICFG_FILENAME % image_uuid
qcow_path = os.path.join(XEND_STORAGE_DIR, qcow_file)
cfg_path = os.path.join(XEND_STORAGE_DIR, cfg_file)
qcow_size = os.stat(qcow_path).st_size
# TODO: no way to stat virtual size of qcow
vdi = XendQCOWVDI(image_uuid, self.uuid,
qcow_path, cfg_path,
qcow_size, qcow_size)
virt_size, phys_size)
if cfg_path and os.path.exists(cfg_path):
vdi.load_config(cfg_path)
try:
vdi.load_config(cfg_path)
except:
log.error('Corrupt VDI configuration file %s' %
cfg_path)
self.images[image_uuid] = vdi
total_used += qcow_size
physical_used += phys_size
virtual_alloc += virt_size
# remove images that aren't valid
for image_uuid in self.images.keys():
@@ -142,11 +168,14 @@ class XendStorageRepository:
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_MAX_IGNORE:
self.storage_free = self.storage_max - total_used
else:
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()
@@ -158,7 +187,7 @@ class XendStorageRepository:
@rtype: int
"""
stfs = os.statvfs(self.storage_dir)
stfs = os.statvfs(self.location)
return stfs.f_bavail * stfs.f_frsize
def _has_space_available_for(self, size_bytes):
@@ -167,22 +196,19 @@ class XendStorageRepository:
@rtype: bool
"""
if self.storage_max != -1:
return self.storage_free
if self.storage_max != XEND_STORAGE_NO_MAXIMUM:
return self.storage_free > size_bytes
bytes_free = self._get_free_space()
try:
if size_bytes < bytes_free:
return True
except DeviceInvalidError:
pass
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_kb: Desired image size in KB.
@type desired_size_kb: int
@param desired_size_bytes: Desired image size in bytes
@type desired_size_bytes: int
@rtype: string
@return: uuid
@@ -194,7 +220,7 @@ class XendStorageRepository:
raise XendError("Not enough space")
image_uuid = uuid.createString()
qcow_path = os.path.join(XEND_STORAGE_DIR,
qcow_path = os.path.join(self.location,
XEND_STORAGE_QCOW_FILENAME % image_uuid)
if qcow_path and os.path.exists(qcow_path):
@@ -268,10 +294,11 @@ class XendStorageRepository:
"""
self.lock.acquire()
try:
if self.storage_max != XEND_STORAGE_MAX_IGNORE:
return self.storage_max
if self.storage_max == XEND_STORAGE_NO_MAXIMUM:
stfs = os.statvfs(self.location)
return stfs.f_blocks * stfs.f_frsize
else:
return self.free_space_bytes() + self.used_space_bytes()
return self.storage_max
finally:
self.lock.release()
@@ -281,10 +308,17 @@ class XendStorageRepository:
"""
self.lock.acquire()
try:
total_used = 0
for val in self.images.values():
total_used += val.physical_utilisation
return total_used
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()
@@ -315,7 +349,7 @@ class XendStorageRepository:
# save configuration to file
cfg_filename = XEND_STORAGE_VDICFG_FILENAME % image_uuid
cfg_path = os.path.join(XEND_STORAGE_DIR, cfg_filename)
cfg_path = os.path.join(self.location, cfg_filename)
image.save_config(cfg_path)
except Exception, e:
@@ -327,10 +361,10 @@ class XendStorageRepository:
return image_uuid
def xen_api_get_by_label(self, label):
def xen_api_get_by_name_label(self, label):
self.lock.acquire()
try:
for image_uuid, val in self.images.values():
for image_uuid, val in self.images.items():
if val.name_label == label:
return image_uuid
return None
+15
View File
@@ -141,6 +141,21 @@ class XendVDI(AutoSaveObject):
return True
def get_record(self):
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(),
'VBDs': []}
class XendQCOWVDI(XendVDI):
def __init__(self, uuid, sr_uuid, qcow_path, cfg_path, vsize, psize):
+13 -5
View File
@@ -68,7 +68,7 @@ class ImageHandler:
def __init__(self, vm, vmConfig, imageConfig, deviceConfig):
self.vm = vm
self.bootloader = None
self.bootloader = False
self.kernel = None
self.ramdisk = None
self.cmdline = None
@@ -77,10 +77,15 @@ class ImageHandler:
def configure(self, vmConfig, imageConfig, _):
"""Config actions common to all unix-like domains."""
self.bootloader = vmConfig['PV_bootloader']
self.kernel = vmConfig['PV_kernel']
self.cmdline = vmConfig['PV_args']
self.ramdisk = vmConfig['PV_ramdisk']
if '_temp_using_bootloader' in vmConfig:
self.bootloader = True
self.kernel = vmConfig['_temp_kernel']
self.cmdline = vmConfig['_temp_args']
self.ramdisk = vmConfig['_temp_ramdisk']
else:
self.kernel = vmConfig['PV_kernel']
self.cmdline = vmConfig['PV_args']
self.ramdisk = vmConfig['PV_ramdisk']
self.vm.storeVm(("image/ostype", self.ostype),
("image/kernel", self.kernel),
("image/cmdline", self.cmdline),
@@ -312,6 +317,9 @@ class HVMImageHandler(ImageHandler):
def configure(self, vmConfig, imageConfig, deviceConfig):
ImageHandler.configure(self, vmConfig, imageConfig, deviceConfig)
if not self.kernel:
self.kernel = '/usr/lib/xen/boot/hvmloader'
info = xc.xeninfo()
if 'hvm' not in info['xen_caps']:
raise VmError("HVM guest support is unavailable: is VT/AMD-V "
+5
View File
@@ -29,8 +29,13 @@ _xend_autorestart = {
"SunOS": False,
}
_pygrub_path = {
"SunOS": "/usr/lib/xen/bin/pygrub"
}
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")
+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:
+10 -6
View File
@@ -48,7 +48,7 @@ from threading import Thread
from xen.web.httpserver import HttpServer, UnixHttpServer
from xen.xend import XendRoot, XendAPI
from xen.xend import XendNode, XendRoot, XendAPI
from xen.xend import Vifctl
from xen.xend.XendLogging import log
from xen.xend.XendClient import XEN_API_SOCKET
@@ -100,6 +100,8 @@ class XendServers:
signal.signal(signal.SIGHUP, self.reloadConfig)
while True:
XendNode.instance().refreshBridges()
threads = []
for server in self.servers:
if server.ready:
@@ -198,16 +200,18 @@ def _loadConfig(servers, root, reload):
if len(addrport) == 1:
if addrport[0] == 'unix':
servers.add(XMLRPCServer(auth,
servers.add(XMLRPCServer(auth, True,
path = XEN_API_SOCKET,
hosts_allowed = allowed))
else:
servers.add(
XMLRPCServer(auth, True, '', int(addrport[0]),
XMLRPCServer(auth, True, True, '',
int(addrport[0]),
hosts_allowed = allowed))
else:
addr, port = addrport
servers.add(XMLRPCServer(auth, True, addr, int(port),
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)
@@ -215,10 +219,10 @@ def _loadConfig(servers, root, reload):
log.error('Xen-API server configuration %s is invalid.', api_cfg)
if xroot.get_xend_tcp_xmlrpc_server():
servers.add(XMLRPCServer(XendAPI.AUTH_PAM, True))
servers.add(XMLRPCServer(XendAPI.AUTH_PAM, False, True))
if xroot.get_xend_unix_xmlrpc_server():
servers.add(XMLRPCServer(XendAPI.AUTH_PAM))
servers.add(XMLRPCServer(XendAPI.AUTH_PAM, False))
def create():
+9 -6
View File
@@ -89,8 +89,8 @@ methods = ['device_create', 'device_configure',
exclude = ['domain_create', 'domain_restore']
class XMLRPCServer:
def __init__(self, auth, use_tcp=False, host = "localhost", port = 8006,
path = XML_RPC_SOCKET, hosts_allowed = None):
def __init__(self, auth, use_xenapi, use_tcp=False, host = "localhost",
port = 8006, path = XML_RPC_SOCKET, hosts_allowed = None):
self.use_tcp = use_tcp
self.port = port
self.host = host
@@ -100,7 +100,7 @@ class XMLRPCServer:
self.ready = False
self.running = True
self.auth = auth
self.xenapi = XendAPI.XendAPI(auth)
self.xenapi = use_xenapi and XendAPI.XendAPI(auth) or None
def run(self):
authmsg = (self.auth == XendAPI.AUTH_NONE and
@@ -115,11 +115,13 @@ class XMLRPCServer:
self.port, authmsg)
self.server = TCPXMLRPCServer((self.host, self.port),
self.hosts_allowed,
self.xenapi is not None,
logRequests = False)
else:
log.info("Opening Unix domain socket XML-RPC server on %s%s",
self.path, authmsg)
self.server = UnixXMLRPCServer(self.path, self.hosts_allowed,
self.xenapi is not None,
logRequests = False)
except socket.error, exn:
log.error('Cannot start server: %s!', exn.args[1])
@@ -133,9 +135,10 @@ class XMLRPCServer:
# and has the 'api' attribute.
for meth_name in dir(self.xenapi):
meth = getattr(self.xenapi, meth_name)
if meth_name[0] != '_' and callable(meth) and hasattr(meth, 'api'):
self.server.register_function(meth, getattr(meth, 'api'))
if meth_name[0] != '_':
meth = getattr(self.xenapi, meth_name)
if callable(meth) and hasattr(meth, 'api'):
self.server.register_function(meth, getattr(meth, 'api'))
# Legacy deprecated xm xmlrpc api
# --------------------------------------------------------------------
+6 -2
View File
@@ -150,16 +150,20 @@ class NetifController(DevController):
devid = self.allocateDeviceID()
# The default type is 'netfront'.
if not typ:
typ = 'netfront'
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 }
+1 -1
View File
@@ -64,7 +64,7 @@ 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())
args += [ "--listen", vnclisten ]
+67 -8
View File
@@ -44,17 +44,45 @@
# OF THIS SOFTWARE.
# --------------------------------------------------------------------
import gettext
import xmlrpclib
import xen.util.xmlrpclib2
translation = gettext.translation('xen-xm', fallback = True)
class Failure(Exception):
def __init__(self, details):
self.details = details
try:
# If this failure is MESSAGE_PARAMETER_COUNT_MISMATCH, then we
# correct the return values here, to account for the fact that we
# transparently add the session handle as the first argument.
if details[0] == 'MESSAGE_PARAMETER_COUNT_MISMATCH':
details[2] = str(int(details[2]) - 1)
details[3] = str(int(details[3]) - 1)
self.details = details
except Exception, exn:
self.details = ['INTERNAL_ERROR', 'Client-side: ' + str(exn)]
def __str__(self):
return "Xen-API failure: %s" % str(self.details)
try:
return translation.ugettext(self.details[0]) % self._details_map()
except TypeError, exn:
return "Message database broken: %s.\nXen-API failure: %s" % \
(exn, str(self.details))
except Exception, exn:
import sys
print >>sys.stderr, exn
return "Xen-API failure: %s" % str(self.details)
def _details_map(self):
return dict([(str(i), self.details[i])
for i in range(len(self.details))])
_RECONNECT_AND_RETRY = (lambda _ : ())
class Session(xen.util.xmlrpclib2.ServerProxy):
@@ -80,6 +108,8 @@ class Session(xen.util.xmlrpclib2.ServerProxy):
encoding, verbose,
allow_none)
self._session = None
self.last_login_method = None
self.last_login_params = None
def xenapi_request(self, methodname, params):
@@ -87,13 +117,31 @@ class Session(xen.util.xmlrpclib2.ServerProxy):
self._login(methodname, params)
return None
else:
full_params = (self._session,) + params
return _parse_result(getattr(self, methodname)(*full_params))
retry_count = 0
while retry_count < 3:
full_params = (self._session,) + params
result = _parse_result(getattr(self, methodname)(*full_params))
if result == _RECONNECT_AND_RETRY:
retry_count += 1
if self.last_login_method:
self._login(self.last_login_method,
self.last_login_params)
else:
raise xmlrpclib.Fault(401, 'You must log in')
else:
return result
raise xmlrpclib.Fault(
500, 'Tried 3 times to get a valid session, but failed')
def _login(self, method, params):
self._session = _parse_result(
getattr(self, 'session.%s' % method)(*params))
result = _parse_result(getattr(self, 'session.%s' % method)(*params))
if result == _RECONNECT_AND_RETRY:
raise xmlrpclib.Fault(
500, 'Received SESSION_INVALID when logging in')
self._session = result
self.last_login_method = method
self.last_login_params = params
def __getattr__(self, name):
@@ -106,7 +154,7 @@ class Session(xen.util.xmlrpclib2.ServerProxy):
def _parse_result(result):
if 'Status' not in result:
if type(result) != dict or 'Status' not in result:
raise xmlrpclib.Fault(500, 'Missing Status in response from server')
if result['Status'] == 'Success':
if 'Value' in result:
@@ -116,7 +164,10 @@ def _parse_result(result):
'Missing Value in response from server')
else:
if 'ErrorDescription' in result:
raise Failure(result['ErrorDescription'])
if result['ErrorDescription'][0] == 'SESSION_INVALID':
return _RECONNECT_AND_RETRY
else:
raise Failure(result['ErrorDescription'])
else:
raise xmlrpclib.Fault(
500, 'Missing ErrorDescription in response from server')
@@ -127,10 +178,18 @@ class _Dispatcher:
def __init__(self, send, name):
self.__send = send
self.__name = name
def __repr__(self):
if self.__name:
return '<XenAPI._Dispatcher for %s>' % self.__name
else:
return '<XenAPI._Dispatcher>'
def __getattr__(self, name):
if self.__name is None:
return _Dispatcher(self.__send, name)
else:
return _Dispatcher(self.__send, "%s.%s" % (self.__name, name))
def __call__(self, *args):
return self.__send(self.__name, args)
+16 -6
View File
@@ -28,6 +28,7 @@ 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
@@ -300,7 +301,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.
@@ -718,8 +719,11 @@ def run_bootloader(vals, config_image):
"--entry= directly.")
vals.bootargs = "--entry=%s" %(vals.bootentry,)
kernel = sxp.child_value(config_image, 'kernel')
ramdisk = sxp.child_value(config_image, 'ramdisk')
args = sxp.child_value(config_image, 'args')
return bootloader(vals.bootloader, file, not vals.console_autoconnect,
vals.bootargs, config_image)
vals.bootargs, kernel, ramdisk, args)
def make_config(vals):
"""Create the domain configuration.
@@ -759,7 +763,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
# if a kernel is specified, we're using the bootloader
# non-interactively, and need to let xend run it so we preserve the
# real kernel choice.
if not vals.kernel:
config_image = run_bootloader(vals, config_image)
config.append(['bootloader', vals.bootloader])
if vals.bootargs:
config.append(['bootloader_args', vals.bootargs])
@@ -823,7 +834,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 +1001,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 +1185,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'
+32 -15
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>]',
@@ -717,6 +717,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,10 +1095,6 @@ 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'])
# we want to just display current info if no parameters are passed
if len(args) == 0:
domid = None
@@ -1174,27 +1174,43 @@ 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)
# 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))
@@ -1244,7 +1260,7 @@ def xm_console(args):
if quiet:
sys.exit(1)
else:
raise Exception("Domain is not started")
raise xmlrpclib.Fault(0, "Domain '%s' is not started" % dom)
console.execConsole(domid)
@@ -1780,7 +1796,8 @@ def _run_cmd(cmd, cmd_name, args):
except SystemExit, code:
return code == 0, code
except XenAPI.Failure, exn:
err(str(exn))
for line in [''] + wrap(str(exn), 80) + ['']:
print >>sys.stderr, line
except xmlrpclib.Fault, ex:
if ex.faultCode == XendClient.ERROR_INVALID_DOMAIN:
err("Domain '%s' does not exist." % ex.faultString)
+72
View File
@@ -0,0 +1,72 @@
# ============================================================================
# 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 XenSource Inc.
# ============================================================================
#
#
msgid ""
msgstr ""
"Project-Id-Version: Xen-xm 3.0\n"
"PO-Revision-Date: 2006-12-28 15:43+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"
"Content-Type: text/plain; charset=ASCII\n"
"Content-Transfer-Encoding: 8bit\n"
msgid "INTERNAL_ERROR"
msgstr "Internal error: %(1)s."
msgid "MAP_DUPLICATE_KEY"
msgstr "This map already contains %(1)s -> %(2)s."
msgid "MESSAGE_METHOD_UNKNOWN"
msgstr "The method %(1)s is unsupported."
msgid "MESSAGE_PARAMETER_COUNT_MISMATCH"
msgstr "The method %(1)s takes %(2)s argument(s) (%(3)s given)."
msgid "SESSION_AUTHENTICATION_FAILED"
msgstr "Permission denied."
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 "SR_HANDLE_INVALID"
msgstr "The SR handle %(1)s is invalid."
msgid "VBD_HANDLE_INVALID"
msgstr "The VBD handle %(1)s is invalid."
msgid "VDI_HANDLE_INVALID"
msgstr "The VDI handle %(1)s is invalid."
msgid "VIF_HANDLE_INVALID"
msgstr "The VIF handle %(1)s is invalid."
msgid "VM_HANDLE_INVALID"
msgstr "The VM handle %(1)s is invalid."
msgid "VTPM_HANDLE_INVALID"
msgstr "The VTPM handle %(1)s is invalid."
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 "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:
-8
View File
@@ -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)
+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
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.