mirror of
https://github.com/xen-project/xen.git
synced 2026-10-29 02:30:03 +01:00
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>
This commit is contained in:
1 parent
3a834bf165
commit
7fef173569
6 files changed
+1044
No files matched your search
@@ -48,6 +48,7 @@ setup(name = 'xen',
|
||||
'xen.util',
|
||||
'xen.xend',
|
||||
'xen.xend.server',
|
||||
'xen.xend.xenstore',
|
||||
'xen.xm',
|
||||
'xen.web',
|
||||
],
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
from xsnode import *
|
||||
from xsobj import *
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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)
|
||||
@@ -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()
|
||||