Have xenstored initialise its connections, meaning that xend can be out of

that loop completely -- the xc_init_store, initDomainStore calls can all go.

Have xenstored understand where the local domain information goes.  Xend no
longer has to generate a path and pass it to xenstored through
xs_introduce_domain -- we just allow xenstored to generate the path, and then
call GetDomainPath later.  There is still some work required to tidy this up.

Change the uuid module to generate uuids as lists of bytes, not in the
stringified form.  Added a unit test for that module.

Change the semantics of Xend restart, relying on these changes to the
xenstored semantics and earlier changes to add an opaque handle to the
hypervisor's domain-specific data block.  The semantics are now clearer, as
Xend can validate whether the details in the store match the current live
domain.

Added a usage statement to xenstored.

Some of this code is by Steven Hand.

Signed-off-by: Ewan Mellor <ewan@xensource.com>
This commit is contained in:
emellor@leeni.uk.xensource.com committed 2005-10-17 16:22:05 +01:00
1 parent dcd2f1cf1f
commit 706fcdf4de
17 files changed
+312 -247

No files matched your search

-24
View File
@@ -862,23 +862,6 @@ static PyObject *pyxc_domain_memory_increase_reservation(PyObject *self,
return zero;
}
static PyObject *pyxc_init_store(PyObject *self, PyObject *args,
PyObject *kwds)
{
XcObject *xc = (XcObject *)self;
int remote_port;
static char *kwd_list[] = { "remote_port", NULL };
if ( !PyArg_ParseTupleAndKeywords(args, kwds, "i", kwd_list,
&remote_port) )
return NULL;
return PyInt_FromLong(xc_init_store(xc->xc_handle, remote_port));
}
static PyMethodDef pyxc_methods[] = {
{ "handle",
(PyCFunction)pyxc_handle,
@@ -1158,13 +1141,6 @@ static PyMethodDef pyxc_methods[] = {
" mem_kb [long]: .\n"
"Returns: [int] 0 on success; -1 on error.\n" },
{ "init_store",
(PyCFunction)pyxc_init_store,
METH_VARARGS | METH_KEYWORDS, "\n"
"Initialize the store event channel and return the store page mfn.\n"
" remote_port [int]: store event channel port number.\n"
"Returns: [int] mfn on success; <0 on error.\n" },
{ NULL, NULL, 0, NULL }
};
+4 -6
View File
@@ -686,7 +686,6 @@ static PyObject *xspy_transaction_end(PyObject *self, PyObject *args,
" dom [int] : domain id\n" \
" page [long] : address of domain's xenstore page\n" \
" port [int] : port the domain is using for xenstore\n" \
" path [string]: path to the domain's data in xenstore\n" \
"\n" \
"Returns None on success.\n" \
"Raises RuntimeError on error.\n" \
@@ -695,12 +694,11 @@ static PyObject *xspy_transaction_end(PyObject *self, PyObject *args,
static PyObject *xspy_introduce_domain(PyObject *self, PyObject *args,
PyObject *kwds)
{
static char *kwd_spec[] = { "dom", "page", "port", "path", NULL };
static char *arg_spec = "iiis|";
static char *kwd_spec[] = { "dom", "page", "port", NULL };
static char *arg_spec = "iii";
domid_t dom = 0;
unsigned long page = 0;
unsigned int port = 0;
char *path = NULL;
struct xs_handle *xh = xshandle(self);
PyObject *val = NULL;
@@ -709,10 +707,10 @@ static PyObject *xspy_introduce_domain(PyObject *self, PyObject *args,
if (!xh)
goto exit;
if (!PyArg_ParseTupleAndKeywords(args, kwds, arg_spec, kwd_spec,
&dom, &page, &port, &path))
&dom, &page, &port))
goto exit;
Py_BEGIN_ALLOW_THREADS
xsval = xs_introduce_domain(xh, dom, page, port, path);
xsval = xs_introduce_domain(xh, dom, page, port);
Py_END_ALLOW_THREADS
if (!xsval) {
PyErr_SetFromErrno(PyExc_RuntimeError);
+4 -5
View File
@@ -143,15 +143,13 @@ def restore(xd, fd):
if m:
store_mfn = int(m.group(2))
dominfo.setStoreRef(store_mfn)
log.debug("IntroduceDomain %d %d %d %s",
log.debug("IntroduceDomain %d %d %d",
dominfo.getDomid(),
store_mfn,
dominfo.store_channel,
dominfo.getDomainPath())
dominfo.store_channel)
IntroduceDomain(dominfo.getDomid(),
store_mfn,
dominfo.store_channel,
dominfo.getDomainPath())
dominfo.store_channel)
else:
m = re.match(r"^(console-mfn) (\d+)$", line)
if m:
@@ -171,6 +169,7 @@ def forkHelper(cmd, fd, inputHandler, closeToChild):
if closeToChild:
child.tochild.close()
lasterr = "error unknown"
try:
fds = [child.fromchild.fileno(),
child.childerr.fileno()]
+21 -18
View File
@@ -21,8 +21,10 @@
Nothing here is persistent (across reboots).
Needs to be persistent for one uptime.
"""
import os
import logging
import os
import sys
import threading
import xen.lowlevel.xc
@@ -62,8 +64,11 @@ class XendDomain:
self.domains_lock.acquire()
try:
self.refresh(True)
self._add_domain(
XendDomainInfo.recreate(self.xen_domains()[PRIV_DOMAIN],
True))
self.dom0_setup()
self.refresh(True)
finally:
self.domains_lock.release()
@@ -178,25 +183,23 @@ class XendDomain:
'Cannot recreate information for dying domain %d.'
' Xend will ignore this domain from now on.',
doms[d]['dom'])
elif d == PRIV_DOMAIN:
log.fatal(
"No record of privileged domain %d! Terminating.", d)
sys.exit(1)
else:
try:
dominfo = XendDomainInfo.recreate(doms[d])
self._add_domain(dominfo)
self._add_domain(
XendDomainInfo.recreate(doms[d], False))
except:
if d == PRIV_DOMAIN:
log.exception(
"Failed to recreate information for domain "
"%d. Doing nothing except crossing my "
"fingers.", d)
else:
log.exception(
"Failed to recreate information for domain "
"%d. Destroying it in the hope of "
"recovery.", d)
try:
xc.domain_destroy(dom = d)
except:
log.exception('Destruction of %d failed.', d)
log.exception(
"Failed to recreate information for domain "
"%d. Destroying it in the hope of "
"recovery.", d)
try:
xc.domain_destroy(dom = d)
except:
log.exception('Destruction of %d failed.', d)
## public:
+54 -56
View File
@@ -28,7 +28,6 @@ import logging
import string
import time
import threading
import errno
import xen.lowlevel.xc
from xen.util import asserts
@@ -42,7 +41,7 @@ from xen.xend.XendBootloader import bootloader
from xen.xend.XendError import XendError, VmError
from xen.xend.XendRoot import get_component
from uuid import getUuid
import uuid
from xen.xend.xenstore.xstransact import xstransact
from xen.xend.xenstore.xsutil import GetDomainPath, IntroduceDomain
@@ -153,7 +152,7 @@ def create(config):
log.debug("XendDomainInfo.create(%s)", config)
vm = XendDomainInfo(getUuid(), parseConfig(config))
vm = XendDomainInfo(uuid.create(), parseConfig(config))
try:
vm.construct()
vm.initDomain()
@@ -169,7 +168,7 @@ def create(config):
raise
def recreate(xeninfo):
def recreate(xeninfo, 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,
and asking us to recreate them causes problems."""
@@ -179,39 +178,52 @@ def recreate(xeninfo):
assert not xeninfo['dying']
domid = xeninfo['dom']
dompath = GetDomainPath(domid)
if not dompath:
raise XendError(
'No domain path in store for existing domain %d' % domid)
try:
dompath = GetDomainPath(domid)
if not dompath:
raise XendError(
'No domain path in store for existing domain %d' % domid)
vmpath = xstransact.Read(dompath, "vm")
if not vmpath:
raise XendError(
'No vm path in store for existing domain %d' % domid)
uuid = xstransact.Read(vmpath, "uuid")
if not uuid:
uuid1_str = xstransact.Read(vmpath, "uuid")
if not uuid1_str:
raise XendError(
'No vm/uuid path in store for existing domain %d' % domid)
log.info("Recreating domain %d, UUID %s.", domid, uuid)
uuid1 = uuid.fromString(uuid1_str)
vm = XendDomainInfo(uuid, xeninfo, domid, True)
uuid2 = xeninfo['handle']
if uuid1 != uuid2:
raise XendError(
'Uuid in store does not match uuid for existing domain %d: '
'%s != %s' % (domid, uuid1_str, uuid.toString(uuid2)))
log.info("Recreating domain %d, UUID %s.", domid, uuid1_str)
vm = XendDomainInfo(uuid2, xeninfo, domid, dompath, True)
except Exception, exn:
log.warn(str(exn))
uuid = getUuid()
if priv:
new_uuid = [0 for i in range(0, 16)]
else:
new_uuid = uuid.create()
log.info("Recreating domain %d with new UUID %s.", domid, uuid)
log.info("Recreating domain %d with new UUID %s.", domid,
uuid.toString(new_uuid))
vm = XendDomainInfo(uuid, xeninfo, domid, True)
vm = XendDomainInfo(new_uuid, xeninfo, domid, dompath, True)
vm.removeDom()
vm.storeVmDetails()
vm.storeDomDetails()
vm.create_channel()
if domid == 0:
vm.initStoreConnection()
if domid != 0:
# Setup store and console channels
vm.create_channels()
vm.refreshShutdown(xeninfo)
return vm
@@ -225,12 +237,12 @@ def restore(config):
log.debug("XendDomainInfo.restore(%s)", config)
uuid = sxp.child_value(config, 'uuid')
vm = XendDomainInfo(uuid, parseConfig(config))
vm = XendDomainInfo(uuid.fromString(sxp.child_value(config, 'uuid')),
parseConfig(config))
try:
vm.construct()
vm.configure()
vm.create_channel()
vm.create_channels()
vm.storeVmDetails()
vm.storeDomDetails()
vm.refreshShutdown()
@@ -355,9 +367,10 @@ class XendDomainInfo:
MINIMUM_RESTART_TIME = 20
def __init__(self, uuid, info, domid = None, augment = False):
def __init__(self, uuidbytes, info, domid = None, dompath = None,
augment = False):
self.uuid = uuid
self.uuidbytes = uuidbytes
self.info = info
if domid is not None:
@@ -367,11 +380,8 @@ class XendDomainInfo:
else:
self.domid = None
self.vmpath = VMROOT + uuid
if self.domid is None:
self.dompath = None
else:
self.dompath = DOMROOT + str(self.domid)
self.vmpath = VMROOT + uuid.toString(uuidbytes)
self.dompath = dompath
if augment:
self.augmentInfo()
@@ -440,6 +450,9 @@ class XendDomainInfo:
defaultInfo('cpu', lambda: None)
defaultInfo('cpu_weight', lambda: 1.0)
defaultInfo('vcpus', lambda: 1)
self.info['vcpus'] = int(self.info['vcpus'])
defaultInfo('vcpu_avail', lambda: (1 << self.info['vcpus']) - 1)
defaultInfo('bootloader', lambda: None)
defaultInfo('backend', lambda: [])
@@ -576,7 +589,7 @@ class XendDomainInfo:
def storeVmDetails(self):
to_store = {
'uuid': self.uuid,
'uuid': uuid.toString(self.uuidbytes),
# XXX
'memory/target': str(self.info['memory_KiB'])
@@ -651,9 +664,6 @@ class XendDomainInfo:
def getDomainPath(self):
return self.dompath
def getUuid(self):
return self.uuid
def getVCpuCount(self):
return self.info['vcpus']
@@ -921,7 +931,7 @@ class XendDomainInfo:
def sxpr(self):
sxpr = ['domain',
['domid', self.domid],
['uuid', self.uuid],
['uuid', uuid.toString(self.uuidbytes)],
['memory', self.info['memory_KiB'] / 1024]]
for e in ROUNDTRIPPING_CONFIG_ENTRIES:
@@ -1038,7 +1048,8 @@ class XendDomainInfo:
self.domid,
self.info['ssidref'])
self.domid = xc.domain_create(dom = 0, ssidref = self.info['ssidref'])
self.domid = xc.domain_create(dom = 0, ssidref = self.info['ssidref'],
handle = self.uuidbytes)
if self.domid < 0:
raise VmError('Creating domain failed: name=%s' %
@@ -1089,10 +1100,9 @@ class XendDomainInfo:
def construct_image(self):
"""Construct the boot image for the domain.
"""
self.create_channel()
self.create_channels()
self.image.createImage()
IntroduceDomain(self.domid, self.store_mfn,
self.store_channel, self.dompath)
IntroduceDomain(self.domid, self.store_mfn, self.store_channel)
## public:
@@ -1199,7 +1209,7 @@ class XendDomainInfo:
self.storeDom(path, port)
return port
def create_channel(self):
def create_channels(self):
"""Create the channels to the domain.
"""
self.store_channel = self.eventChannel("store/port")
@@ -1312,13 +1322,15 @@ class XendDomainInfo:
"""
new_name = self.generateUniqueName()
new_uuid = getUuid()
new_uuid = uuid.create()
new_uuid_str = uuid.toString(new_uuid)
log.info("Renaming dead domain %s (%d, %s) to %s (%s).",
self.info['name'], self.domid, self.uuid, new_name, new_uuid)
self.info['name'], self.domid, uuid.toString(self.uuidbytes),
new_name, new_uuid_str)
self.release_devices()
self.info['name'] = new_name
self.uuid = new_uuid
self.vmpath = VMROOT + new_uuid
self.uuidbytes = new_uuid
self.vmpath = VMROOT + new_uuid_str
self.storeVmDetails()
self.preserve()
@@ -1384,20 +1396,6 @@ class XendDomainInfo:
self.storeDom("control/sysrq", '%c' % key)
def initStoreConnection(self):
ref = xc.init_store(self.store_channel)
if ref and ref >= 0:
self.setStoreRef(ref)
try:
IntroduceDomain(self.domid, ref, self.store_channel,
self.dompath)
except RuntimeError, ex:
if ex.args[0] == errno.EISCONN:
pass
else:
raise
def infoIsSet(self, name):
return name in self.info and self.info[name] is not None
+12 -8
View File
@@ -36,23 +36,27 @@ def getUuidUuidgen(random = True):
cmd += " -r"
else:
cmd += " -t"
return commands.getoutput(cmd)
return fromString(commands.getoutput(cmd))
def getUuidRandom():
"""Generate a random UUID."""
bytes = [ random.randint(0, 255) for i in range(0, 16) ]
# Encode the variant.
bytes[6] = (bytes[6] & 0x0f) | 0x40
bytes[8] = (bytes[8] & 0x3f) | 0x80
f = "%02x"
return ( "-".join([f*4, f*2, f*2, f*2, f*6]) % tuple(bytes) )
return [ random.randint(0, 255) for i in range(0, 16) ]
#uuidFactory = getUuidUuidgen
uuidFactory = getUuidRandom
def getUuid():
def create():
return uuidFactory()
def toString(u):
f = "%02x"
return ( "-".join([f*4, f*2, f*2, f*2, f*6]) % tuple(u) )
def fromString(s):
s = s.replace('-', '')
return [ int(s[i : i + 2], 16) for i in range(0, 32, 2) ]
+2 -2
View File
@@ -19,8 +19,8 @@ def xshandle():
xs_lock.release()
return xs_handle
def IntroduceDomain(domid, page, port, path):
return xshandle().introduce_domain(domid, page, port, path)
def IntroduceDomain(domid, page, port):
return xshandle().introduce_domain(domid, page, port)
def GetDomainPath(domid):
return xshandle().get_domain_path(domid)
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.