aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorcl349@firebug.cl.cam.ac.uk <cl349@firebug.cl.cam.ac.uk>2005-06-07 13:38:16 +0000
committercl349@firebug.cl.cam.ac.uk <cl349@firebug.cl.cam.ac.uk>2005-06-07 13:38:16 +0000
commit7fef17356935ab96fded686d7fca4b4d30800d8c (patch)
treec2ffbcfc3c1004bfc85460db19b7e4fd07a997c5
parent3a834bf16537de45babbcec5200c7168349bb8f4 (diff)
downloadxen-7fef17356935ab96fded686d7fca4b4d30800d8c.tar.gz
xen-7fef17356935ab96fded686d7fca4b4d30800d8c.tar.bz2
xen-7fef17356935ab96fded686d7fca4b4d30800d8c.zip
bitkeeper revision 1.1662.1.18 (42a5a348BpHwgoiWQI1wI9LMej7F3w)
setup.py: Add xen.xend.xenstore. xsresource.py, xsobj.py, xsnode.py, __init__.py: new file Signed-off-by: Mike Wray <mike.wray@hp.com> Signed-off-by: Christian Limpach <Christian.Limpach@cl.cam.ac.uk>
-rw-r--r--.rootkeys4
-rw-r--r--tools/python/setup.py1
-rw-r--r--tools/python/xen/xend/xenstore/__init__.py2
-rw-r--r--tools/python/xen/xend/xenstore/xsnode.py382
-rw-r--r--tools/python/xen/xend/xenstore/xsobj.py519
-rw-r--r--tools/python/xen/xend/xenstore/xsresource.py136
6 files changed, 1044 insertions, 0 deletions
diff --git a/.rootkeys b/.rootkeys
index 7aceab3599..ae7543d74c 100644
--- a/.rootkeys
+++ b/.rootkeys
@@ -878,6 +878,10 @@
41ee5e8dq9NtihbL4nWKjuSLOhXPUg tools/python/xen/xend/server/usbif.py
40c9c469LNxLVizOUpOjEaTKKCm8Aw tools/python/xen/xend/sxp.py
42a48d152jkT7ykQT_LWKnS-ojV_ZA tools/python/xen/xend/uuid.py
+42a5a2c0ik9zrQvwjTUKDVVEQmvO2Q tools/python/xen/xend/xenstore/__init__.py
+42a5a2c04xNCYAUXD0b9IDf4XekXRg tools/python/xen/xend/xenstore/xsnode.py
+42a5a2c0-aP98db2PJIDxQJfTEMZ-A tools/python/xen/xend/xenstore/xsobj.py
+42a5a2c0gxfQiAH_oVTShNPeG0LG2Q tools/python/xen/xend/xenstore/xsresource.py
40d05079aFRp6NQdo5wIh5Ly31c0cg tools/python/xen/xm/__init__.py
40cf2937gKQcATgXKGtNeWb1PDH5nA tools/python/xen/xm/create.py
40f552eariuUSB9TWqCPnDLz5zvxMw tools/python/xen/xm/destroy.py
diff --git a/tools/python/setup.py b/tools/python/setup.py
index 5902d4151f..fabe80bd8b 100644
--- a/tools/python/setup.py
+++ b/tools/python/setup.py
@@ -48,6 +48,7 @@ setup(name = 'xen',
'xen.util',
'xen.xend',
'xen.xend.server',
+ 'xen.xend.xenstore',
'xen.xm',
'xen.web',
],
diff --git a/tools/python/xen/xend/xenstore/__init__.py b/tools/python/xen/xend/xenstore/__init__.py
new file mode 100644
index 0000000000..6772d2ceca
--- /dev/null
+++ b/tools/python/xen/xend/xenstore/__init__.py
@@ -0,0 +1,2 @@
+from xsnode import *
+from xsobj import *
diff --git a/tools/python/xen/xend/xenstore/xsnode.py b/tools/python/xen/xend/xenstore/xsnode.py
new file mode 100644
index 0000000000..ae770219ab
--- /dev/null
+++ b/tools/python/xen/xend/xenstore/xsnode.py
@@ -0,0 +1,382 @@
+import errno
+import os
+import os.path
+import select
+import sys
+import time
+
+from xen.lowlevel import xs
+from xen.xend import sxp
+from xen.xend.PrettyPrint import prettyprint
+
+SELECT_TIMEOUT = 2.0
+
+def getEventPath(event):
+ return os.path.join("/_event", event)
+
+def getEventIdPath(event):
+ return os.path.join(eventPath(event), "@eid")
+
+class Subscription:
+
+ def __init__(self, event, fn, id):
+ self.event = event
+ self.watcher = None
+ self.fn = fn
+ self.id = id
+
+ def watch(self, watcher):
+ self.watcher = watcher
+ watcher.addSubs(self)
+
+ def unwatch(self):
+ watcher = self.watcher
+ if watcher:
+ self.watcher = None
+ watcher.delSubs(self)
+
+ def notify(self, event):
+ try:
+ self.fn(event, id)
+ except SystemExitException:
+ raise
+ except:
+ pass
+
+class Watcher:
+
+ def __init__(self, store, event):
+ self.path = getEventPath(event)
+ self.eidPath = getEventIdPath(event)
+ store.mkdirs(self.path)
+ if not store.exists(self.eidPath):
+ store.writeInt(self.eidPath, 0)
+ self.xs = None
+ self.subs = []
+
+ def __getattr__(self, k, v):
+ if k == "fileno":
+ if self.xs:
+ return self.xs.fileno
+ else:
+ return -1
+ else:
+ return self.__dict__.get(k, v)
+
+ def addSubs(self, subs):
+ self.subs.append(subs)
+ self.watch()
+
+ def delSubs(self, subs):
+ self.subs.remove(subs)
+ if len(self.subs) == 0:
+ self.unwatch()
+
+ def getEvent(self):
+ return self.event
+
+ def watch(self):
+ if self.xs: return
+ self.xs = xs.open()
+ self.xs.watch(path)
+
+ def unwatch(self):
+ if self.xs:
+ self.xs.unwatch(self.path)
+ self.xs.close()
+ self.xs = None
+
+ def watching(self):
+ return self.xs is not None
+
+ def getNotification(self):
+ p = self.xs.read_watch()
+ self.xs.acknowledge_watch()
+ eid = self.xs.readInt(self.eidPath)
+ return p
+
+ def notify(self, subs):
+ p = self.getNotification()
+ for s in subs:
+ s.notify(p)
+
+class XenStore:
+
+ def __init__(self):
+ self.xs = None
+ #self.xs = xs.open()
+ self.subscription = {}
+ self.subscription_id = 0
+ self.events = {}
+ self.write("/", "")
+
+ def getxs(self):
+ if self.xs is None:
+ ex = None
+ for i in range(0,20):
+ try:
+ self.xs = xs.open()
+ ex = None
+ break
+ except Exception, ex:
+ print >>stderr, "Exception connecting to xsdaemon:", ex
+ print >>stderr, "Trying again..."
+ time.sleep(1)
+ else:
+ raise ex
+
+ #todo would like to reconnect if xs conn closes (e.g. daemon restart).
+ return self.xs
+
+ def dump(self, path="/", out=sys.stdout):
+ print 'dump>', path
+ val = ['node']
+ val.append(['path', path])
+## perms = ['perms']
+## for p in self.getPerms(path):
+## l = ['perm']
+## l.append('dom', p.get['dom'])
+## for k in ['read', 'write', 'create', 'owner']:
+## v = p.get(k)
+## l.append([k, v])
+## perms.append(l)
+## val.append(perms)
+ data = self.read(path)
+ if data:
+ val.append(['data', data])
+ children = ['children']
+ for x in self.lsPaths(path):
+ print 'dump>', 'child=', x
+ children.append(self.dump(x))
+ if len(children) > 1:
+ val.append(children)
+ prettyprint(val, out=out)
+ return val
+
+ def getPerms(self, path):
+ return self.getxs().get_permissions(path)
+
+ def ls(self, path="/"):
+ return self.getxs().ls(path)
+
+ def lsPaths(self, path="/"):
+ return [ os.path.join(path, x) for x in self.ls(path) ]
+
+ def lsr(self, path="/", list=None):
+ if list is None:
+ list = []
+ list.append(path)
+ for x in self.lsPaths(path):
+ list.append(x)
+ self.lsr(x, list=list)
+ return list
+
+ def rm(self, path):
+ try:
+ #for x in self.lsPaths():
+ # self.getxs().rm(x)
+ self.getxs().rm(path)
+ except:
+ pass
+
+ def exists(self, path):
+ try:
+ self.getxs().ls(path)
+ return True
+ except RuntimeError, ex:
+ if ex.args[0] == errno.ENOENT:
+ return False
+ else:
+ raise
+
+ def mkdirs(self, path):
+ if self.exists(path):
+ return
+ elts = path.split("/")
+ p = "/"
+ for x in elts:
+ if x == "": continue
+ p = os.path.join(p, x)
+ if not self.exists(p):
+ self.getxs().write(p, "", create=True)
+
+ def read(self, path):
+ try:
+ return self.getxs().read(path)
+ except RuntimeError, ex:
+ if ex.args[0] == errno.EISDIR:
+ return None
+ else:
+ raise
+
+ def create(self, path, excl=False):
+ self.write(path, "", create=True, excl=excl)
+
+ def write(self, path, data, create=True, excl=False):
+ self.mkdirs(path)
+ self.getxs().write(path, data, create=create, excl=excl)
+
+ def begin(self, path):
+ self.getxs().begin_transaction(path)
+
+ def commit(self, abandon=False):
+ self.getxs().end_transaction(abort=abandon)
+
+ def subscribe(self, event, fn):
+ watcher = self.watchEvent(event)
+ self.subscription_id += 1
+ subs = Subscription(event, fn, self.subscription_id)
+ self.subscription[subs.id] = subs
+ subs.watch(watcher)
+ return subs.id
+
+ def unsubscribe(self, sid):
+ s = self.subscription.get(sid)
+ if not s: return
+ del self.subscription[s.id]
+ s.unwatch()
+ unwatchEvent(s.event)
+
+ def sendEvent(self, event, data):
+ eventPath = getEventPath(event)
+ eidPath = getEventIdPath(event)
+ try:
+ self.begin(eventPath)
+ self.mkdirs(eventPath)
+ if self.exists(eidPath):
+ eid = self.readInt(eidPath)
+ eid += 1
+ else:
+ eid = 1
+ self.writeInt(eidPath, eid)
+ self.write(os.path.join(eventPath, str(eid)), data)
+ finally:
+ self.commit()
+
+ def watchEvent(self, event):
+ if event in self.events:
+ return
+ watcher = Watcher(event)
+ self.watchers[watcher.getEvent()] = watcher
+ self.watchStart()
+ return watcher
+
+ def unwatchEvent(self, event):
+ watcher = self.watchers.get(event)
+ if not watcher:
+ return
+ if not watcher.watching():
+ del self.watchers[event]
+
+ def watchStart(self):
+ if self.watchThread: return
+
+ def watchMain(self):
+ try:
+ while True:
+ if self.watchThread is None: return
+ if not self.events:
+ return
+ rd = self.watchers.values()
+ try:
+ (rd, wr, er) = select.select(rd, [], [], SELECT_TIMEOUT)
+ for watcher in rd:
+ watcher.notify()
+ except socket.error, ex:
+ if ex.args[0] in (EAGAIN, EINTR):
+ pass
+ else:
+ raise
+ finally:
+ self.watchThread = None
+
+ def introduceDomain(self, dom, page, evtchn, path):
+ self.getxs().introduce_domain(dom, page, evtchn.port1, path)
+
+ def releaseDomain(self, dom):
+ self.getxs().release_domain(dom)
+
+def getXenStore():
+ global xenstore
+ try:
+ return xenstore
+ except:
+ xenstore = XenStore()
+ return xenstore
+
+class XenNode:
+
+ def __init__(self, path="/", create=True):
+ self.store = getXenStore()
+ self.path = path
+ if not self.store.exists(path):
+ if create:
+ self.store.create(path)
+ else:
+ raise ValueError("path does not exist: '%s'" % path)
+
+ def relPath(self, path=""):
+ if not path:
+ return self.path
+ if path and path.startswith("/"):
+ path = path[1:]
+ return os.path.join(self.path, path)
+
+ def delete(self, path=""):
+ self.store.rm(self.relPath(path))
+
+ def exists(self, path=""):
+ return self.store.exists(self.relPath(path))
+
+ def getNode(self, path="", create=True):
+ if path == "":
+ return self
+ else:
+ return XenNode(self.relPath(path=path), create=create)
+
+ getChild = getNode
+
+ def getData(self, path=""):
+ path = self.relPath(path)
+ try:
+ return self.store.read(path)
+ except:
+ return None
+
+ def setData(self, data, path=""):
+ path = self.relPath(path)
+ #print 'XenNode>setData>', 'path=', path, 'data=', data
+ return self.store.write(path, data)
+
+ def getLock(self):
+ return None
+
+ def lock(self, lockid):
+ return None
+
+ def unlock(self, lockid):
+ return None
+
+ def deleteChild(self, name):
+ self.delete(name)
+
+ def deleteChildren(self):
+ for name in self.ls():
+ self.deleteChild(name)
+
+ def getChildren(self):
+ return [ self.getNode(name) for name in self.ls() ]
+
+ def ls(self):
+ return self.store.ls(self.path)
+
+ def introduceDomain(self, dom, page, evtchn, path):
+ self.store.introduceDomain(dom, page, evtchn, path)
+
+ def releaseDomain(self, dom):
+ self.store.releaseDomain(dom)
+
+ def __repr__(self):
+ return "<XenNode %s>" % self.path
+
+
diff --git a/tools/python/xen/xend/xenstore/xsobj.py b/tools/python/xen/xend/xenstore/xsobj.py
new file mode 100644
index 0000000000..62e18d07d9
--- /dev/null
+++ b/tools/python/xen/xend/xenstore/xsobj.py
@@ -0,0 +1,519 @@
+import string
+import types
+
+from xen.xend import sxp
+from xsnode import XenNode
+from xen.util.mac import macToString, macFromString
+
+VALID_KEY_CHARS = string.ascii_letters + string.digits + "_-@"
+
+def hasAttr(obj, attr):
+ if isinstance(obj, dict):
+ return obj.contains(attr)
+ else:
+ return hasattr(obj, attr)
+
+def getAttr(obj, attr):
+ if isinstance(obj, dict):
+ return dict.get(attr)
+ else:
+ return getattr(obj, attr, None)
+
+def setAttr(obj, attr, val):
+ if isinstance(obj, dict):
+ dict[attr] = val
+ else:
+ setattr(obj, attr, val)
+
+class DBConverter:
+ """Conversion of values to and from strings in xenstore.
+ """
+
+ converters = {}
+
+ def checkType(cls, ty):
+ if ty is None or ty in cls.converters:
+ return
+ raise ValueError("invalid converter type: '%s'" % ty)
+
+ checkType = classmethod(checkType)
+
+ def getConverter(cls, ty=None):
+ if ty is None:
+ ty = "str"
+ conv = cls.converters.get(ty)
+ if not conv:
+ raise ValueError("no converter for type: '%s'" % ty)
+ return conv
+
+ getConverter = classmethod(getConverter)
+
+ def convertToDB(cls, val, ty=None):
+ return cls.getConverter(ty).toDB(val)
+
+ convertToDB = classmethod(convertToDB)
+
+ def convertFromDB(cls, val, ty=None):
+ return cls.getConverter(ty).fromDB(val)
+
+ convertFromDB = classmethod(convertFromDB)
+
+ # Must define in subclass.
+ name = None
+
+ def __init__(self):
+ self.register()
+
+ def register(self):
+ if not self.name:
+ raise ValueError("invalid converter name: '%s'" % self.name)
+ self.converters[self.name] = self
+
+ def toDB(self, val):
+ raise NotImplementedError()
+
+ def fromDB(self, val):
+ raise NotImplementedError()
+
+class StrConverter(DBConverter):
+
+ name = "str"
+
+ def toDB(self, val):
+ # Convert True/False to 1/0, otherwise they convert to
+ # 'True' and 'False' rather than '1' and '0', even though
+ # isinstance(True/False, int) is true.
+ if isinstance(val, bool):
+ val = int(val)
+ return str(val)
+
+ def fromDB(self, data):
+ return data
+
+StrConverter()
+
+class BoolConverter(DBConverter):
+
+ name = "bool"
+
+ def toDB(self, val):
+ return str(int(bool(val)))
+
+ def fromDB(self, data):
+ return bool(int(data))
+
+BoolConverter()
+
+class SxprConverter(DBConverter):
+
+ name = "sxpr"
+
+ def toDB(self, val):
+ return sxp.to_string(val)
+
+ def fromDB(self, data):
+ return sxp.from_string(data)
+
+SxprConverter()
+
+class IntConverter(DBConverter):
+
+ name = "int"
+
+ def toDB(self, val):
+ return str(int(val))
+
+ def fromDB(self, data):
+ return int(data)
+
+IntConverter()
+
+class FloatConverter(DBConverter):
+
+ name = "float"
+
+ def toDB(self, val):
+ return str(float(val))
+
+ def fromDB(self, data):
+ return float(data)
+
+FloatConverter()
+
+class LongConverter(DBConverter):
+
+ name = "long"
+
+ def toDB(self, val):
+ return str(long(val))
+
+ def fromDB(self, data):
+ return long(data)
+
+LongConverter()
+
+class MacConverter(DBConverter):
+
+ name = "mac"
+
+ def toDB(self, val):
+ return macToString(val)
+
+ def fromDB(self, data):
+ return macFromString(data)
+
+MacConverter()
+
+class DBVar:
+
+ def __init__(self, var, ty=None, path=None):
+ DBConverter.checkType(ty)
+ if path is None:
+ path = var
+ self.var = var
+ self.ty = ty
+ self.path = path
+ varpath = filter(bool, self.var.split())
+ self.attrpath = varpath[:-1]
+ self.attr = varpath[-1]
+
+ def exportToDB(self, db, obj):
+ self.setDB(db, self.getObj(obj))
+
+ def importFromDB(self, db, obj):
+ self.setObj(obj, self.getDB(db))
+
+ def getObj(self, obj):
+ o = obj
+ for x in self.attrpath:
+ o = getAttr(o, x)
+ if o is None:
+ return None
+ return getAttr(o, self.attr)
+
+ def setObj(self, obj, val):
+ o = obj
+ for x in self.attrpath:
+ o = getAttr(o, x)
+ # Don't set obj attr if val is None.
+ if val is None and hasAttr(o, self.attr):
+ return
+ setAttr(o, self.attr, val)
+
+ def getDB(self, db):
+ data = getattr(db, self.path)
+ return DBConverter.convertFromDB(data, ty=self.ty)
+
+ def setDB(self, db, val):
+ # Don't set in db if val is None.
+ #print 'DBVar>setDB>', self.path, 'val=', val
+ if val is None:
+ return
+ data = DBConverter.convertToDB(val, ty=self.ty)
+ #print 'DBVar>setDB>', self.path, 'data=', data
+ setattr(db, self.path, data)
+
+
+class DBMap(dict):
+ """A persistent map. Extends dict with persistence.
+ Set and get values using the usual map syntax:
+
+ m[k], m.get(k)
+ m[k] = v
+
+ Also supports being treated as an object with attributes.
+ When 'k' is a legal identifier you may also use
+
+ m.k, getattr(m, k)
+ m.k = v, setattr(m, k)
+ k in m, hasattr(m, k)
+
+ When setting you can pass in a normal value, for example
+
+ m.x = 3
+
+ Getting works too:
+
+ m.x ==> 3
+
+ while m['x'] will return the map for x.
+
+ m['x'].getData() ==> 3
+
+ To get values from subdirs use get() to get the subdir first:
+
+ get(m, 'foo').x
+ m['foo'].x
+
+ instead of m.foo.x, because m.foo will return the data for field foo,
+ not the directory.
+
+ You can assign values into a subdir by passing a map:
+
+ m.foo = {'x': 1, 'y':2 }
+
+ You can also use paths as keys:
+
+ m['foo/x'] = 1
+
+ sets field x in subdir foo.
+
+ """
+
+ __db__ = None
+ __data__ = None
+ __perms__ = None
+ __parent__ = None
+ __name__ = ""
+
+ __transaction__ = False
+
+ # True if value set since saved (or never saved).
+ __dirty__ = True
+
+ def __init__(self, parent=None, name="", db=None):
+ if parent is None:
+ self.__name__ = name
+ else:
+ if not isinstance(parent, DBMap):
+ raise ValueError("invalid parent")
+ self.__parent__ = parent
+ self.__name__ = name
+ db = self.__parent__.getChildDB(name)
+ self.setDB(db)
+
+ def getName(self):
+ return self.__name__
+
+ def getPath(self):
+ return self.__db__ and self.__db__.relPath()
+
+ def introduceDomain(self, dom, page, evtchn, path=None):
+ db = self.__db__
+ if path is None:
+ path = db.relPath()
+ print 'DBMap>introduceDomain>', dom, page, evtchn, path
+ try:
+ db.introduceDomain(dom, page, evtchn, path)
+ except Exception, ex:
+ import traceback
+ traceback.print_exc()
+ print 'DBMap>introduceDomain>', ex
+ pass # todo: don't ignore
+
+ def releaseDomain(self, dom):
+ db = self.__db__
+ print 'DBMap>releaseDomain>', dom
+ try:
+ db.releaseDomain(dom)
+ except Exception, ex:
+ import traceback
+ traceback.print_exc()
+ print 'DBMap>releaseDomain>', ex
+ pass # todo: don't ignore
+
+ def transactionBegin(self):
+ # Begin a transaction.
+ pass
+
+ def transactionCommit(self):
+ # Commit writes to db.
+ pass
+
+ def transactionFail(self):
+ # Fail a transaction.
+ # We have changed values, what do we do?
+ pass
+
+ def watch(self, fn):
+ pass
+
+ def unwatch(self, watch):
+ pass
+
+ def checkName(self, k):
+ if k == "":
+ raise ValueError("invalid key, empty string")
+ for c in k:
+ if c in VALID_KEY_CHARS: continue
+ raise ValueError("invalid key char '%s'" % c)
+
+ def _setData(self, v):
+ #print 'DBMap>_setData>', self.getPath(), 'data=', v
+ if v != self.__data__:
+ self.__dirty__ = True
+ self.__data__ = v
+
+ def setData(self, v):
+ if isinstance(v, dict):
+ for (key, val) in v.items():
+ self[key] = val
+ else:
+ self._setData(v)
+
+ def getData(self):
+ return self.__data__
+
+ def _set(self, k, v):
+ dict.__setitem__(self, k, v)
+
+ def _get(self, k):
+ try:
+ return dict.__getitem__(self, k)
+ except:
+ return None
+
+ def _del(self, k, v):
+ try:
+ dict.__delitem__(self, k)
+ except:
+ pass
+
+ def _contains(self, k):
+ return dict.__contains__(self, k)
+
+ def __setitem__(self, k, v, save=False):
+ node = self.addChild(k)
+ node.setData(v)
+ if save:
+ node.saveDB()
+
+ def __getitem__(self, k):
+ if self._contains(k):
+ v = self._get(k)
+ else:
+ v = self.readChildDB(k)
+ self._set(k, v)
+ return v
+
+ def __delitem__(self, k):
+ self._del(k)
+ self.deleteChildDB(k)
+
+ def __repr__(self):
+ if len(self):
+ return dict.__repr__(self)
+ else:
+ return repr(self.__data__)
+
+ def __setattr__(self, k, v):
+ if k.startswith("__"):
+ object.__setattr__(self, k, v)
+ else:
+ self.__setitem__(k, v, save=True)
+ return v
+
+ def __getattr__(self, k):
+ if k.startswith("__"):
+ v = object.__getattr__(self, k)
+ else:
+ try:
+ v = self.__getitem__(k).getData()
+ except LookupError, ex:
+ raise AttributeError(ex.args)
+ return v
+
+ def __delattr__(self, k):
+ return self.__delitem__(k)
+
+ def delete(self):
+ dict.clear(self)
+ self.__data__ = None
+ if self.__db__:
+ self.__db__.delete()
+
+ def clear(self):
+ dict.clear(self)
+ if self.__db__:
+ self.__db__.deleteChildren()
+
+ def getChild(self, k):
+ return self._get(k)
+
+ def getChildDB(self, k):
+ self.checkName(k)
+ return self.__db__ and self.__db__.getChild(k)
+
+ def deleteChildDB(self, k):
+ if self.__db__:
+ self.__db__.deleteChild(k)
+
+ def _addChild(self, k):
+ kid = self._get(k)
+ if kid is None:
+ kid = DBMap(parent=self, name=k, db=self.getChildDB(k))
+ self._set(k, kid)
+ return kid
+
+ def addChild(self, path):
+ l = path.split("/")
+ n = self
+ for x in l:
+ if x == "": continue
+ n = n._addChild(x)
+ return n
+
+ def setDB(self, db):
+ if (db is not None) and not isinstance(db, XenNode):
+ raise ValueError("invalid db")
+ self.__db__ = db
+ for (k, v) in self.items():
+ if v is None: continue
+ if isinstance(v, DBMap):
+ v._setDB(self.addChild(k), restore)
+
+ def readDB(self):
+ if self.__db__ is None:
+ return
+ self.__data__ = self.__db__.getData()
+ for k in self.__db__.ls():
+ n = self.addChild(k)
+ n.readDB()
+ self.__dirty__ = False
+
+ def readChildDB(self, k):
+ if self.__db__ and (k in self.__db__.ls()):
+ n = self.addChild(k)
+ n.readDB()
+ raise LookupError("invalid key '%s'" % k)
+
+ def saveDB(self, sync=False, save=False):
+ """Save unsaved data to db.
+ If save or sync is true, saves whether dirty or not.
+ If sync is true, removes db entries not in the map.
+ """
+
+ if self.__db__ is None:
+ #print 'DBMap>saveDB>',self.getPath(), 'no db'
+ return
+ # Write data.
+ #print 'DBMap>saveDB>', self.getPath(), 'dirty=', self.__dirty__, 'data=', self.__data__
+ if ((self.__data__ is not None)
+ and (sync or save or self.__dirty__)):
+ self.__db__.setData(self.__data__)
+ self.__dirty__ = False
+ else:
+ #print 'DBMap>saveDB>', self.getPath(), 'not written'
+ pass
+ # Write children.
+ for (name, node) in self.items():
+ if not isinstance(node, DBMap): continue
+ node.saveDB(sync=sync, save=save)
+ # Remove db nodes not in children.
+ if sync:
+ for name in self.__db__.ls():
+ if name not in self:
+ self.__db__.delete(name)
+
+ def importFromDB(self, obj, fields):
+ """Set fields in obj from db fields.
+ """
+ for f in fields:
+ f.importFromDB(self, obj)
+
+ def exportToDB(self, obj, fields, save=False, sync=False):
+ """Set fields in db from obj fields.
+ """
+ for f in fields:
+ f.exportToDB(self, obj)
+ self.saveDB(save=save, sync=sync)
diff --git a/tools/python/xen/xend/xenstore/xsresource.py b/tools/python/xen/xend/xenstore/xsresource.py
new file mode 100644
index 0000000000..37011bdea3
--- /dev/null
+++ b/tools/python/xen/xend/xenstore/xsresource.py
@@ -0,0 +1,136 @@
+#============================================================================
+# Copyright (C) 2005 Mike Wray <mike.wray@hp.com>
+#============================================================================
+# HTTP interface onto xenstore (read-only).
+# Mainly intended for testing.
+
+import os
+import os.path
+
+from xen.web.httpserver import HttpServer, UnixHttpServer
+from xen.web.SrvBase import SrvBase
+from xen.web.SrvDir import SrvDir
+from xen.xend.Args import FormFn
+from xen.xend.xenstore import XenNode
+
+def pathurl(req):
+ url = req.prePathURL()
+ if not url.endswith('/'):
+ url += '/'
+ return url
+
+def writelist(req, l):
+ req.write('(')
+ for k in l:
+ req.write(' ' + k)
+ req.write(')')
+
+def lsData(dbnode, req, url):
+ v = dbnode.getData()
+ if v is None:
+ req.write('<p>No data')
+ else:
+ req.write('<p>Data: <pre>')
+ req.write(str(v))
+ req.write('</pre>')
+ v = dbnode.getLock()
+ if v is None:
+ req.write("<p>Unlocked")
+ else:
+ req.write("<p>Lock = %s" % v)
+
+def lsChildren(dbnode, req, url):
+ l = dbnode.ls()
+ if l:
+ req.write('<p>Children: <ul>')
+ for key in l:
+ child = dbnode.getChild(key)
+ data = child.getData()
+ if data is None: data = ""
+ req.write('<li><a href="%(url)s%(key)s">%(key)s</a> %(data)s</li>'
+ % { "url": url, "key": key, "data": data })
+ req.write('</ul>')
+ else:
+ req.write('<p>No children')
+
+
+class DBDataResource(SrvBase):
+ """Resource for the node data.
+ """
+
+ def __init__(self, dbnode):
+ SrvBase.__init__(self)
+ self.dbnode = dbnode
+
+ def render_GET(self, req):
+ req.write('<html><head></head><body>')
+ self.print_path(req)
+ req.write("<pre>")
+ req.write(self.getData() or self.getNoData())
+ req.write("</pre>")
+ req.write('</body></html>')
+
+ def getContentType(self):
+ # Use content-type from metadata.
+ return "text/plain"
+
+ def getData(self):
+ v = self.dbnode.getData()
+ if v is None: return v
+ return str(v)
+
+ def getNoData(self):
+ return ""
+
+class DBNodeResource(SrvDir):
+ """Resource for a DB node.
+ """
+
+ def __init__(self, dbnode):
+ SrvDir.__init__(self)
+ self.dbnode = dbnode
+
+ def get(self, x):
+ val = None
+ if x == "__data__":
+ val = DBDataResource(self.dbnode)
+ else:
+ if self.dbnode.exists(x):
+ child = self.dbnode.getChild(x, create=False)
+ else:
+ child = None
+ if child is not None:
+ val = DBNodeResource(child)
+ return val
+
+ def render_POST(self, req):
+ return self.perform(req)
+
+ def ls(self, req, use_sxp=0):
+ if use_sxp:
+ writelist(req, self.dbnode.getChildren())
+ else:
+ url = pathurl(req)
+ req.write("<fieldset>")
+ lsData(self.dbnode, req, url)
+ lsChildren(self.dbnode, req, url)
+ req.write("</fieldset>")
+
+ def form(self, req):
+ url = req.prePathURL()
+ pass
+
+class DBRootResource(DBNodeResource):
+ """Resource for the root of a DB.
+ """
+
+ def __init__(self):
+ DBNodeResource.__init__(self, XenNode())
+
+def main(argv):
+ root = SrvDir()
+ root.putChild('xenstore', DBRootResource())
+ interface = ''
+ port = 8003
+ server = HttpServer(root=root, interface=interface, port=port)
+ server.run()