ia64/xen-unstable

changeset 5360:22daf37c41c8

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>
author cl349@firebug.cl.cam.ac.uk
date Tue Jun 07 13:38:16 2005 +0000 (2005-06-07)
parents fd8e5378d8ac
children c6c987d8999c
files .rootkeys tools/python/setup.py tools/python/xen/xend/xenstore/__init__.py tools/python/xen/xend/xenstore/xsnode.py tools/python/xen/xend/xenstore/xsobj.py tools/python/xen/xend/xenstore/xsresource.py
line diff
     1.1 --- a/.rootkeys	Tue Jun 07 13:21:38 2005 +0000
     1.2 +++ b/.rootkeys	Tue Jun 07 13:38:16 2005 +0000
     1.3 @@ -878,6 +878,10 @@ 4294a1bf8rMUcddot-B2-pOxORimOg tools/pyt
     1.4  41ee5e8dq9NtihbL4nWKjuSLOhXPUg tools/python/xen/xend/server/usbif.py
     1.5  40c9c469LNxLVizOUpOjEaTKKCm8Aw tools/python/xen/xend/sxp.py
     1.6  42a48d152jkT7ykQT_LWKnS-ojV_ZA tools/python/xen/xend/uuid.py
     1.7 +42a5a2c0ik9zrQvwjTUKDVVEQmvO2Q tools/python/xen/xend/xenstore/__init__.py
     1.8 +42a5a2c04xNCYAUXD0b9IDf4XekXRg tools/python/xen/xend/xenstore/xsnode.py
     1.9 +42a5a2c0-aP98db2PJIDxQJfTEMZ-A tools/python/xen/xend/xenstore/xsobj.py
    1.10 +42a5a2c0gxfQiAH_oVTShNPeG0LG2Q tools/python/xen/xend/xenstore/xsresource.py
    1.11  40d05079aFRp6NQdo5wIh5Ly31c0cg tools/python/xen/xm/__init__.py
    1.12  40cf2937gKQcATgXKGtNeWb1PDH5nA tools/python/xen/xm/create.py
    1.13  40f552eariuUSB9TWqCPnDLz5zvxMw tools/python/xen/xm/destroy.py
     2.1 --- a/tools/python/setup.py	Tue Jun 07 13:21:38 2005 +0000
     2.2 +++ b/tools/python/setup.py	Tue Jun 07 13:38:16 2005 +0000
     2.3 @@ -48,6 +48,7 @@ setup(name            = 'xen',
     2.4                           'xen.util',
     2.5                           'xen.xend',
     2.6                           'xen.xend.server',
     2.7 +                         'xen.xend.xenstore',
     2.8                           'xen.xm',
     2.9                           'xen.web',
    2.10                           ],
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/tools/python/xen/xend/xenstore/__init__.py	Tue Jun 07 13:38:16 2005 +0000
     3.3 @@ -0,0 +1,2 @@
     3.4 +from xsnode import *
     3.5 +from xsobj import *
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/tools/python/xen/xend/xenstore/xsnode.py	Tue Jun 07 13:38:16 2005 +0000
     4.3 @@ -0,0 +1,382 @@
     4.4 +import errno
     4.5 +import os
     4.6 +import os.path
     4.7 +import select
     4.8 +import sys
     4.9 +import time
    4.10 +
    4.11 +from xen.lowlevel import xs
    4.12 +from xen.xend import sxp
    4.13 +from xen.xend.PrettyPrint import prettyprint
    4.14 +
    4.15 +SELECT_TIMEOUT = 2.0
    4.16 +
    4.17 +def getEventPath(event):
    4.18 +    return os.path.join("/_event", event)
    4.19 +
    4.20 +def getEventIdPath(event):
    4.21 +    return os.path.join(eventPath(event), "@eid")
    4.22 +
    4.23 +class Subscription:
    4.24 +
    4.25 +    def __init__(self, event, fn, id):
    4.26 +        self.event = event
    4.27 +        self.watcher = None
    4.28 +        self.fn = fn
    4.29 +        self.id = id
    4.30 +
    4.31 +    def watch(self, watcher):
    4.32 +        self.watcher = watcher
    4.33 +        watcher.addSubs(self)
    4.34 +
    4.35 +    def unwatch(self):
    4.36 +        watcher = self.watcher
    4.37 +        if watcher:
    4.38 +            self.watcher = None
    4.39 +            watcher.delSubs(self)
    4.40 +
    4.41 +    def notify(self, event):
    4.42 +        try:
    4.43 +            self.fn(event, id)
    4.44 +        except SystemExitException:
    4.45 +            raise
    4.46 +        except:
    4.47 +            pass
    4.48 +
    4.49 +class Watcher:
    4.50 +
    4.51 +    def __init__(self, store, event):
    4.52 +        self.path = getEventPath(event)
    4.53 +        self.eidPath = getEventIdPath(event)
    4.54 +        store.mkdirs(self.path)
    4.55 +        if not store.exists(self.eidPath):
    4.56 +            store.writeInt(self.eidPath, 0)
    4.57 +        self.xs = None
    4.58 +        self.subs = []
    4.59 +
    4.60 +    def __getattr__(self, k, v):
    4.61 +        if k == "fileno":
    4.62 +            if self.xs:
    4.63 +                return self.xs.fileno
    4.64 +            else:
    4.65 +                return -1
    4.66 +        else:
    4.67 +            return self.__dict__.get(k, v)
    4.68 +
    4.69 +    def addSubs(self, subs):
    4.70 +        self.subs.append(subs)
    4.71 +        self.watch()
    4.72 +
    4.73 +    def delSubs(self, subs):
    4.74 +        self.subs.remove(subs)
    4.75 +        if len(self.subs) == 0:
    4.76 +            self.unwatch()
    4.77 +
    4.78 +    def getEvent(self):
    4.79 +        return self.event
    4.80 +
    4.81 +    def watch(self):
    4.82 +        if self.xs: return
    4.83 +        self.xs = xs.open()
    4.84 +        self.xs.watch(path)
    4.85 +
    4.86 +    def unwatch(self):
    4.87 +        if self.xs:
    4.88 +            self.xs.unwatch(self.path)
    4.89 +            self.xs.close()
    4.90 +            self.xs = None
    4.91 +            
    4.92 +    def watching(self):
    4.93 +        return self.xs is not None
    4.94 +
    4.95 +    def getNotification(self):
    4.96 +        p = self.xs.read_watch()
    4.97 +        self.xs.acknowledge_watch()
    4.98 +        eid = self.xs.readInt(self.eidPath)
    4.99 +        return p
   4.100 +
   4.101 +    def notify(self, subs):
   4.102 +        p = self.getNotification()
   4.103 +        for s in subs:
   4.104 +            s.notify(p)
   4.105 +            
   4.106 +class XenStore:
   4.107 +
   4.108 +    def __init__(self):
   4.109 +        self.xs = None
   4.110 +        #self.xs = xs.open()
   4.111 +        self.subscription = {}
   4.112 +        self.subscription_id = 0
   4.113 +        self.events = {}
   4.114 +        self.write("/", "")
   4.115 +
   4.116 +    def getxs(self):
   4.117 +        if self.xs is None:
   4.118 +            ex = None
   4.119 +            for i in range(0,20):
   4.120 +                try:
   4.121 +                    self.xs = xs.open()
   4.122 +                    ex = None
   4.123 +                    break
   4.124 +                except Exception, ex:
   4.125 +                    print >>stderr, "Exception connecting to xsdaemon:", ex
   4.126 +                    print >>stderr, "Trying again..."
   4.127 +                    time.sleep(1)
   4.128 +            else:
   4.129 +                raise ex
   4.130 +            
   4.131 +        #todo would like to reconnect if xs conn closes (e.g. daemon restart).
   4.132 +        return self.xs
   4.133 +
   4.134 +    def dump(self, path="/", out=sys.stdout):
   4.135 +        print 'dump>', path
   4.136 +        val = ['node']
   4.137 +        val.append(['path',  path])
   4.138 +##         perms = ['perms']
   4.139 +##         for p in self.getPerms(path):
   4.140 +##             l = ['perm']
   4.141 +##             l.append('dom', p.get['dom'])
   4.142 +##             for k in ['read', 'write', 'create', 'owner']:
   4.143 +##                 v = p.get(k)
   4.144 +##                 l.append([k, v])
   4.145 +##             perms.append(l)
   4.146 +##         val.append(perms)
   4.147 +        data = self.read(path)
   4.148 +        if data:
   4.149 +            val.append(['data',  data])
   4.150 +        children = ['children']
   4.151 +        for x in self.lsPaths(path):
   4.152 +            print 'dump>', 'child=', x
   4.153 +            children.append(self.dump(x))
   4.154 +        if len(children) > 1:
   4.155 +            val.append(children)
   4.156 +        prettyprint(val, out=out)
   4.157 +        return val
   4.158 +
   4.159 +    def getPerms(self, path):
   4.160 +        return self.getxs().get_permissions(path)
   4.161 +
   4.162 +    def ls(self, path="/"):
   4.163 +        return self.getxs().ls(path)
   4.164 +
   4.165 +    def lsPaths(self, path="/"):
   4.166 +        return [ os.path.join(path, x) for x in self.ls(path) ]
   4.167 +
   4.168 +    def lsr(self, path="/", list=None):
   4.169 +        if list is None:
   4.170 +            list = []
   4.171 +        list.append(path)
   4.172 +        for x in self.lsPaths(path):
   4.173 +            list.append(x)
   4.174 +            self.lsr(x, list=list)
   4.175 +        return list
   4.176 +
   4.177 +    def rm(self, path):
   4.178 +        try:
   4.179 +            #for x in self.lsPaths():
   4.180 +            #    self.getxs().rm(x)
   4.181 +            self.getxs().rm(path)
   4.182 +        except:
   4.183 +            pass
   4.184 +
   4.185 +    def exists(self, path):
   4.186 +        try:
   4.187 +            self.getxs().ls(path)
   4.188 +            return True
   4.189 +        except RuntimeError, ex:
   4.190 +            if ex.args[0] == errno.ENOENT:
   4.191 +                return False
   4.192 +            else:
   4.193 +                raise
   4.194 +
   4.195 +    def mkdirs(self, path):
   4.196 +        if self.exists(path):
   4.197 +            return
   4.198 +        elts = path.split("/")
   4.199 +        p = "/"
   4.200 +        for x in elts:
   4.201 +            if x == "": continue
   4.202 +            p = os.path.join(p, x)
   4.203 +            if not self.exists(p):
   4.204 +                self.getxs().write(p, "", create=True)
   4.205 +
   4.206 +    def read(self, path):
   4.207 +        try:
   4.208 +            return self.getxs().read(path)
   4.209 +        except RuntimeError, ex:
   4.210 +            if ex.args[0] == errno.EISDIR:
   4.211 +                return None
   4.212 +            else:
   4.213 +                raise
   4.214 +
   4.215 +    def create(self, path, excl=False):
   4.216 +        self.write(path, "", create=True, excl=excl)
   4.217 +
   4.218 +    def write(self, path, data, create=True, excl=False):
   4.219 +        self.mkdirs(path)
   4.220 +        self.getxs().write(path, data, create=create, excl=excl)
   4.221 +
   4.222 +    def begin(self, path):
   4.223 +        self.getxs().begin_transaction(path)
   4.224 +
   4.225 +    def commit(self, abandon=False):
   4.226 +        self.getxs().end_transaction(abort=abandon)
   4.227 +
   4.228 +    def subscribe(self, event, fn):
   4.229 +        watcher = self.watchEvent(event)
   4.230 +        self.subscription_id += 1
   4.231 +        subs = Subscription(event, fn, self.subscription_id)
   4.232 +        self.subscription[subs.id] = subs
   4.233 +        subs.watch(watcher)
   4.234 +        return subs.id
   4.235 +
   4.236 +    def unsubscribe(self, sid):
   4.237 +        s = self.subscription.get(sid)
   4.238 +        if not s: return
   4.239 +        del self.subscription[s.id]
   4.240 +        s.unwatch()
   4.241 +        unwatchEvent(s.event)
   4.242 +
   4.243 +    def sendEvent(self, event, data):
   4.244 +        eventPath = getEventPath(event)
   4.245 +        eidPath = getEventIdPath(event)
   4.246 +        try:
   4.247 +            self.begin(eventPath)
   4.248 +            self.mkdirs(eventPath)
   4.249 +            if self.exists(eidPath):
   4.250 +                eid = self.readInt(eidPath)
   4.251 +                eid += 1
   4.252 +            else:
   4.253 +                eid = 1
   4.254 +            self.writeInt(eidPath, eid)
   4.255 +            self.write(os.path.join(eventPath, str(eid)), data)
   4.256 +        finally:
   4.257 +            self.commit()
   4.258 +
   4.259 +    def watchEvent(self, event):
   4.260 +        if event in  self.events:
   4.261 +            return
   4.262 +        watcher = Watcher(event)
   4.263 +        self.watchers[watcher.getEvent()] = watcher
   4.264 +        self.watchStart()
   4.265 +        return watcher
   4.266 +
   4.267 +    def unwatchEvent(self, event):
   4.268 +        watcher = self.watchers.get(event)
   4.269 +        if not watcher:
   4.270 +            return
   4.271 +        if not watcher.watching():
   4.272 +            del self.watchers[event]
   4.273 +
   4.274 +    def watchStart(self):
   4.275 +        if self.watchThread: return
   4.276 +
   4.277 +    def watchMain(self):
   4.278 +        try:
   4.279 +            while True:
   4.280 +                if self.watchThread is None: return
   4.281 +                if not self.events:
   4.282 +                    return
   4.283 +                rd = self.watchers.values()
   4.284 +                try:
   4.285 +                    (rd, wr, er) = select.select(rd, [], [], SELECT_TIMEOUT)
   4.286 +                    for watcher in rd:
   4.287 +                        watcher.notify()
   4.288 +                except socket.error, ex:
   4.289 +                    if ex.args[0] in (EAGAIN, EINTR):
   4.290 +                        pass
   4.291 +                    else:
   4.292 +                        raise
   4.293 +        finally:
   4.294 +            self.watchThread = None
   4.295 +
   4.296 +    def introduceDomain(self, dom, page, evtchn, path):
   4.297 +        self.getxs().introduce_domain(dom, page, evtchn.port1, path)
   4.298 +
   4.299 +    def releaseDomain(self, dom):
   4.300 +        self.getxs().release_domain(dom)
   4.301 +
   4.302 +def getXenStore():
   4.303 +    global xenstore
   4.304 +    try:
   4.305 +        return xenstore
   4.306 +    except:
   4.307 +        xenstore = XenStore()
   4.308 +        return xenstore
   4.309 +
   4.310 +class XenNode:
   4.311 +
   4.312 +    def __init__(self, path="/", create=True):
   4.313 +        self.store = getXenStore()
   4.314 +        self.path = path
   4.315 +        if not self.store.exists(path):
   4.316 +            if create:
   4.317 +                self.store.create(path)
   4.318 +            else:
   4.319 +                raise ValueError("path does not exist: '%s'" % path)
   4.320 +
   4.321 +    def relPath(self, path=""):
   4.322 +        if not path:
   4.323 +            return self.path
   4.324 +        if path and path.startswith("/"):
   4.325 +            path = path[1:]
   4.326 +        return os.path.join(self.path, path)
   4.327 +
   4.328 +    def delete(self, path=""):
   4.329 +        self.store.rm(self.relPath(path))
   4.330 +
   4.331 +    def exists(self, path=""):
   4.332 +        return self.store.exists(self.relPath(path))
   4.333 +
   4.334 +    def getNode(self, path="", create=True):
   4.335 +        if path == "":
   4.336 +            return self
   4.337 +        else:
   4.338 +            return XenNode(self.relPath(path=path), create=create)
   4.339 +
   4.340 +    getChild = getNode
   4.341 +
   4.342 +    def getData(self, path=""):
   4.343 +        path = self.relPath(path)
   4.344 +        try:
   4.345 +            return self.store.read(path)
   4.346 +        except:
   4.347 +            return None
   4.348 +
   4.349 +    def setData(self, data, path=""):
   4.350 +        path = self.relPath(path)
   4.351 +        #print 'XenNode>setData>', 'path=', path, 'data=', data
   4.352 +        return self.store.write(path, data)
   4.353 +
   4.354 +    def getLock(self):
   4.355 +        return None
   4.356 +
   4.357 +    def lock(self, lockid):
   4.358 +        return None
   4.359 +
   4.360 +    def unlock(self, lockid):
   4.361 +        return None
   4.362 +
   4.363 +    def deleteChild(self, name):
   4.364 +        self.delete(name)
   4.365 +
   4.366 +    def deleteChildren(self):
   4.367 +        for name in self.ls():
   4.368 +            self.deleteChild(name)
   4.369 +
   4.370 +    def getChildren(self):
   4.371 +        return [ self.getNode(name) for name in self.ls() ]
   4.372 +
   4.373 +    def ls(self):
   4.374 +        return self.store.ls(self.path)
   4.375 +
   4.376 +    def introduceDomain(self, dom, page, evtchn, path):
   4.377 +        self.store.introduceDomain(dom, page, evtchn, path)
   4.378 +        
   4.379 +    def releaseDomain(self, dom):
   4.380 +        self.store.releaseDomain(dom)
   4.381 +
   4.382 +    def __repr__(self):
   4.383 +        return "<XenNode %s>" % self.path
   4.384 +
   4.385 +
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/tools/python/xen/xend/xenstore/xsobj.py	Tue Jun 07 13:38:16 2005 +0000
     5.3 @@ -0,0 +1,519 @@
     5.4 +import string
     5.5 +import types
     5.6 +
     5.7 +from xen.xend import sxp
     5.8 +from xsnode import XenNode
     5.9 +from xen.util.mac import macToString, macFromString
    5.10 +
    5.11 +VALID_KEY_CHARS = string.ascii_letters + string.digits + "_-@"
    5.12 +
    5.13 +def hasAttr(obj, attr):
    5.14 +    if isinstance(obj, dict):
    5.15 +        return obj.contains(attr)
    5.16 +    else:
    5.17 +        return hasattr(obj, attr)
    5.18 +
    5.19 +def getAttr(obj, attr):
    5.20 +    if isinstance(obj, dict):
    5.21 +        return dict.get(attr)
    5.22 +    else:
    5.23 +        return getattr(obj, attr, None)
    5.24 +
    5.25 +def setAttr(obj, attr, val):
    5.26 +    if isinstance(obj, dict):
    5.27 +        dict[attr] = val
    5.28 +    else:
    5.29 +        setattr(obj, attr, val)
    5.30 +
    5.31 +class DBConverter:
    5.32 +    """Conversion of values to and from strings in xenstore.
    5.33 +    """
    5.34 +
    5.35 +    converters = {}
    5.36 +
    5.37 +    def checkType(cls, ty):
    5.38 +        if ty is None or ty in cls.converters:
    5.39 +            return
    5.40 +        raise ValueError("invalid converter type: '%s'" % ty)
    5.41 +
    5.42 +    checkType = classmethod(checkType)
    5.43 +    
    5.44 +    def getConverter(cls, ty=None):
    5.45 +        if ty is None:
    5.46 +            ty = "str"
    5.47 +        conv = cls.converters.get(ty)
    5.48 +        if not conv:
    5.49 +            raise ValueError("no converter for type: '%s'" % ty)
    5.50 +        return conv
    5.51 +
    5.52 +    getConverter = classmethod(getConverter)
    5.53 +
    5.54 +    def convertToDB(cls, val, ty=None):
    5.55 +        return cls.getConverter(ty).toDB(val)
    5.56 +
    5.57 +    convertToDB = classmethod(convertToDB)
    5.58 +
    5.59 +    def convertFromDB(cls, val, ty=None):
    5.60 +        return cls.getConverter(ty).fromDB(val)
    5.61 +
    5.62 +    convertFromDB = classmethod(convertFromDB)
    5.63 +
    5.64 +    # Must define in subclass.
    5.65 +    name = None
    5.66 +
    5.67 +    def __init__(self):
    5.68 +        self.register()
    5.69 +    
    5.70 +    def register(self):
    5.71 +        if not self.name:
    5.72 +            raise ValueError("invalid converter name: '%s'" % self.name)
    5.73 +        self.converters[self.name] = self
    5.74 +
    5.75 +    def toDB(self, val):
    5.76 +        raise NotImplementedError()
    5.77 +
    5.78 +    def fromDB(self, val):
    5.79 +        raise NotImplementedError()
    5.80 +
    5.81 +class StrConverter(DBConverter):
    5.82 +
    5.83 +    name = "str"
    5.84 +    
    5.85 +    def toDB(self, val):
    5.86 +        # Convert True/False to 1/0, otherwise they convert to
    5.87 +        # 'True' and 'False' rather than '1' and '0', even though
    5.88 +        # isinstance(True/False, int) is true.
    5.89 +        if isinstance(val, bool):
    5.90 +            val = int(val)
    5.91 +        return str(val)
    5.92 +
    5.93 +    def fromDB(self, data):
    5.94 +        return data
    5.95 +
    5.96 +StrConverter()
    5.97 +    
    5.98 +class BoolConverter(DBConverter):
    5.99 +
   5.100 +    name = "bool"
   5.101 +
   5.102 +    def toDB(self, val):
   5.103 +        return str(int(bool(val)))
   5.104 +
   5.105 +    def fromDB(self, data):
   5.106 +        return bool(int(data))
   5.107 +
   5.108 +BoolConverter()
   5.109 +
   5.110 +class SxprConverter(DBConverter):
   5.111 +
   5.112 +    name = "sxpr"
   5.113 +    
   5.114 +    def toDB(self, val):
   5.115 +        return sxp.to_string(val)
   5.116 +
   5.117 +    def fromDB(self, data):
   5.118 +        return sxp.from_string(data)
   5.119 +    
   5.120 +SxprConverter()
   5.121 +
   5.122 +class IntConverter(DBConverter):
   5.123 +
   5.124 +    name = "int"
   5.125 +    
   5.126 +    def toDB(self, val):
   5.127 +        return str(int(val))
   5.128 +
   5.129 +    def fromDB(self, data):
   5.130 +        return int(data)
   5.131 +    
   5.132 +IntConverter()
   5.133 +    
   5.134 +class FloatConverter(DBConverter):
   5.135 +
   5.136 +    name = "float"
   5.137 +    
   5.138 +    def toDB(self, val):
   5.139 +        return str(float(val))
   5.140 +
   5.141 +    def fromDB(self, data):
   5.142 +        return float(data)
   5.143 +    
   5.144 +FloatConverter()
   5.145 +    
   5.146 +class LongConverter(DBConverter):
   5.147 +
   5.148 +    name = "long"
   5.149 +    
   5.150 +    def toDB(self, val):
   5.151 +        return str(long(val))
   5.152 +
   5.153 +    def fromDB(self, data):
   5.154 +        return long(data)
   5.155 +    
   5.156 +LongConverter()
   5.157 +
   5.158 +class MacConverter(DBConverter):
   5.159 +
   5.160 +    name = "mac"
   5.161 +    
   5.162 +    def toDB(self, val):
   5.163 +        return macToString(val)
   5.164 +
   5.165 +    def fromDB(self, data):
   5.166 +        return macFromString(data)
   5.167 +    
   5.168 +MacConverter()
   5.169 +
   5.170 +class DBVar:
   5.171 +
   5.172 +    def __init__(self, var, ty=None, path=None):
   5.173 +        DBConverter.checkType(ty)
   5.174 +        if path is None:
   5.175 +            path = var
   5.176 +        self.var = var
   5.177 +        self.ty = ty
   5.178 +        self.path = path
   5.179 +        varpath = filter(bool, self.var.split())
   5.180 +        self.attrpath = varpath[:-1]
   5.181 +        self.attr = varpath[-1]
   5.182 +
   5.183 +    def exportToDB(self, db, obj):
   5.184 +        self.setDB(db, self.getObj(obj))
   5.185 +
   5.186 +    def importFromDB(self, db, obj):
   5.187 +        self.setObj(obj, self.getDB(db))
   5.188 +
   5.189 +    def getObj(self, obj):
   5.190 +        o = obj
   5.191 +        for x in self.attrpath:
   5.192 +            o = getAttr(o, x)
   5.193 +            if o is None:
   5.194 +                return None
   5.195 +        return getAttr(o, self.attr)
   5.196 +
   5.197 +    def setObj(self, obj, val):
   5.198 +        o = obj
   5.199 +        for x in self.attrpath:
   5.200 +            o = getAttr(o, x)
   5.201 +        # Don't set obj attr if val is None.
   5.202 +        if val is None and hasAttr(o, self.attr):
   5.203 +            return
   5.204 +        setAttr(o, self.attr, val)
   5.205 +
   5.206 +    def getDB(self, db):
   5.207 +        data = getattr(db, self.path)
   5.208 +        return DBConverter.convertFromDB(data, ty=self.ty)
   5.209 +
   5.210 +    def setDB(self, db, val):
   5.211 +        # Don't set in db if val is None.
   5.212 +        #print 'DBVar>setDB>', self.path, 'val=', val
   5.213 +        if val is None:
   5.214 +            return
   5.215 +        data = DBConverter.convertToDB(val, ty=self.ty)
   5.216 +        #print 'DBVar>setDB>', self.path, 'data=', data
   5.217 +        setattr(db, self.path, data)
   5.218 +        
   5.219 +
   5.220 +class DBMap(dict):
   5.221 +    """A persistent map. Extends dict with persistence.
   5.222 +    Set and get values using the usual map syntax:
   5.223 +
   5.224 +    m[k],     m.get(k)
   5.225 +    m[k] = v
   5.226 +
   5.227 +    Also supports being treated as an object with attributes.
   5.228 +    When 'k' is a legal identifier you may also use
   5.229 +
   5.230 +    m.k,     getattr(m, k)
   5.231 +    m.k = v, setattr(m, k)
   5.232 +    k in m,  hasattr(m, k)
   5.233 +
   5.234 +    When setting you can pass in a normal value, for example
   5.235 +
   5.236 +    m.x = 3
   5.237 +
   5.238 +    Getting works too:
   5.239 +
   5.240 +    m.x ==> 3
   5.241 +
   5.242 +    while m['x'] will return the map for x.
   5.243 +
   5.244 +    m['x'].getData() ==> 3
   5.245 +    
   5.246 +    To get values from subdirs use get() to get the subdir first:
   5.247 +
   5.248 +    get(m, 'foo').x
   5.249 +    m['foo'].x
   5.250 +
   5.251 +    instead of m.foo.x, because m.foo will return the data for field foo,
   5.252 +    not the directory.
   5.253 +
   5.254 +    You can assign values into a subdir by passing a map:
   5.255 +
   5.256 +    m.foo = {'x': 1, 'y':2 }
   5.257 +
   5.258 +    You can also use paths as keys:
   5.259 +
   5.260 +    m['foo/x'] = 1
   5.261 +
   5.262 +    sets field x in subdir foo.
   5.263 +    
   5.264 +    """
   5.265 +
   5.266 +    __db__          = None
   5.267 +    __data__        = None
   5.268 +    __perms__       = None
   5.269 +    __parent__      = None
   5.270 +    __name__        = ""
   5.271 +
   5.272 +    __transaction__ = False
   5.273 +
   5.274 +    # True if value set since saved (or never saved).
   5.275 +    __dirty__       = True
   5.276 +
   5.277 +    def __init__(self, parent=None, name="", db=None):
   5.278 +        if parent is None:
   5.279 +            self.__name__ = name
   5.280 +        else:
   5.281 +            if not isinstance(parent, DBMap):
   5.282 +                raise ValueError("invalid parent")
   5.283 +            self.__parent__ = parent
   5.284 +            self.__name__ = name
   5.285 +            db = self.__parent__.getChildDB(name)
   5.286 +        self.setDB(db)
   5.287 +
   5.288 +    def getName(self):
   5.289 +        return self.__name__
   5.290 +
   5.291 +    def getPath(self):
   5.292 +        return self.__db__ and self.__db__.relPath()
   5.293 +
   5.294 +    def introduceDomain(self, dom, page, evtchn, path=None):
   5.295 +        db = self.__db__
   5.296 +        if path is None:
   5.297 +            path = db.relPath()
   5.298 +        print 'DBMap>introduceDomain>', dom, page, evtchn, path
   5.299 +        try:
   5.300 +            db.introduceDomain(dom, page, evtchn, path)
   5.301 +        except Exception, ex:
   5.302 +            import traceback
   5.303 +            traceback.print_exc()
   5.304 +            print 'DBMap>introduceDomain>', ex
   5.305 +            pass # todo: don't ignore
   5.306 +        
   5.307 +    def releaseDomain(self, dom):
   5.308 +        db = self.__db__
   5.309 +        print 'DBMap>releaseDomain>', dom
   5.310 +        try:
   5.311 +            db.releaseDomain(dom)
   5.312 +        except Exception, ex:
   5.313 +            import traceback
   5.314 +            traceback.print_exc()
   5.315 +            print 'DBMap>releaseDomain>', ex
   5.316 +            pass # todo: don't ignore
   5.317 +        
   5.318 +    def transactionBegin(self):
   5.319 +        # Begin a transaction.
   5.320 +        pass
   5.321 +
   5.322 +    def transactionCommit(self):
   5.323 +        # Commit writes to db.
   5.324 +        pass
   5.325 +
   5.326 +    def transactionFail(self):
   5.327 +        # Fail a transaction.
   5.328 +        # We have changed values, what do we do?
   5.329 +        pass
   5.330 +
   5.331 +    def watch(self, fn):
   5.332 +        pass
   5.333 +
   5.334 +    def unwatch(self, watch):
   5.335 +        pass
   5.336 +        
   5.337 +    def checkName(self, k):
   5.338 +        if k == "":
   5.339 +            raise ValueError("invalid key, empty string")
   5.340 +        for c in k:
   5.341 +            if c in VALID_KEY_CHARS: continue
   5.342 +            raise ValueError("invalid key char '%s'" % c)
   5.343 +
   5.344 +    def _setData(self, v):
   5.345 +        #print 'DBMap>_setData>', self.getPath(), 'data=', v
   5.346 +        if v != self.__data__:
   5.347 +            self.__dirty__ = True
   5.348 +        self.__data__ = v
   5.349 +
   5.350 +    def setData(self, v):
   5.351 +        if isinstance(v, dict):
   5.352 +            for (key, val) in v.items():
   5.353 +                self[key] = val
   5.354 +        else:
   5.355 +            self._setData(v)
   5.356 +
   5.357 +    def getData(self):
   5.358 +        return self.__data__
   5.359 +
   5.360 +    def _set(self, k, v):
   5.361 +        dict.__setitem__(self, k, v)
   5.362 +
   5.363 +    def _get(self, k):
   5.364 +        try:
   5.365 +            return dict.__getitem__(self, k)
   5.366 +        except:
   5.367 +            return None
   5.368 +
   5.369 +    def _del(self, k, v):
   5.370 +        try:
   5.371 +            dict.__delitem__(self, k)
   5.372 +        except:
   5.373 +            pass
   5.374 +
   5.375 +    def _contains(self, k):
   5.376 +        return dict.__contains__(self, k)
   5.377 +        
   5.378 +    def __setitem__(self, k, v, save=False):
   5.379 +        node = self.addChild(k)
   5.380 +        node.setData(v)
   5.381 +        if save:
   5.382 +            node.saveDB()
   5.383 +
   5.384 +    def __getitem__(self, k):
   5.385 +        if self._contains(k):
   5.386 +            v = self._get(k)
   5.387 +        else:
   5.388 +            v = self.readChildDB(k)
   5.389 +            self._set(k, v)
   5.390 +        return v
   5.391 +
   5.392 +    def __delitem__(self, k):
   5.393 +        self._del(k)
   5.394 +        self.deleteChildDB(k)
   5.395 +
   5.396 +    def __repr__(self):
   5.397 +        if len(self):
   5.398 +            return dict.__repr__(self)
   5.399 +        else:
   5.400 +            return repr(self.__data__)
   5.401 +
   5.402 +    def __setattr__(self, k, v):
   5.403 +        if k.startswith("__"):
   5.404 +            object.__setattr__(self, k, v)
   5.405 +        else:
   5.406 +            self.__setitem__(k, v, save=True)
   5.407 +        return v
   5.408 +    
   5.409 +    def __getattr__(self, k):
   5.410 +        if k.startswith("__"):
   5.411 +            v = object.__getattr__(self, k)
   5.412 +        else:
   5.413 +            try:
   5.414 +                v = self.__getitem__(k).getData()
   5.415 +            except LookupError, ex:
   5.416 +                raise AttributeError(ex.args)
   5.417 +        return v
   5.418 +
   5.419 +    def __delattr__(self, k):
   5.420 +        return self.__delitem__(k)
   5.421 +
   5.422 +    def delete(self):
   5.423 +        dict.clear(self)
   5.424 +        self.__data__ = None
   5.425 +        if self.__db__:
   5.426 +            self.__db__.delete()
   5.427 +
   5.428 +    def clear(self):
   5.429 +        dict.clear(self)
   5.430 +        if self.__db__:
   5.431 +            self.__db__.deleteChildren()
   5.432 +
   5.433 +    def getChild(self, k):
   5.434 +        return self._get(k)
   5.435 +
   5.436 +    def getChildDB(self, k):
   5.437 +        self.checkName(k)
   5.438 +        return self.__db__ and self.__db__.getChild(k)
   5.439 +
   5.440 +    def deleteChildDB(self, k):
   5.441 +        if self.__db__:
   5.442 +            self.__db__.deleteChild(k)
   5.443 +
   5.444 +    def _addChild(self, k):
   5.445 +        kid = self._get(k)
   5.446 +        if kid is None:
   5.447 +            kid = DBMap(parent=self, name=k, db=self.getChildDB(k))
   5.448 +            self._set(k, kid)
   5.449 +        return kid
   5.450 +
   5.451 +    def addChild(self, path):
   5.452 +        l = path.split("/")
   5.453 +        n = self
   5.454 +        for x in l:
   5.455 +            if x == "": continue
   5.456 +            n = n._addChild(x)
   5.457 +        return n
   5.458 +
   5.459 +    def setDB(self, db):
   5.460 +        if (db is not None) and not isinstance(db, XenNode):
   5.461 +            raise ValueError("invalid db")
   5.462 +        self.__db__ = db
   5.463 +        for (k, v) in self.items():
   5.464 +            if v is None: continue
   5.465 +            if isinstance(v, DBMap):
   5.466 +                v._setDB(self.addChild(k), restore)
   5.467 +
   5.468 +    def readDB(self):
   5.469 +        if self.__db__ is None:
   5.470 +            return
   5.471 +        self.__data__ = self.__db__.getData()
   5.472 +        for k in self.__db__.ls():
   5.473 +            n = self.addChild(k)
   5.474 +            n.readDB()
   5.475 +        self.__dirty__ = False
   5.476 +
   5.477 +    def readChildDB(self, k):
   5.478 +        if self.__db__ and (k in self.__db__.ls()):
   5.479 +            n = self.addChild(k)
   5.480 +            n.readDB()
   5.481 +        raise LookupError("invalid key '%s'" % k)
   5.482 +
   5.483 +    def saveDB(self, sync=False, save=False):
   5.484 +        """Save unsaved data to db.
   5.485 +        If save or sync is true, saves whether dirty or not.
   5.486 +        If sync is true, removes db entries not in the map.
   5.487 +        """
   5.488 +        
   5.489 +        if self.__db__ is None:
   5.490 +            #print 'DBMap>saveDB>',self.getPath(), 'no db'
   5.491 +            return
   5.492 +        # Write data.
   5.493 +        #print 'DBMap>saveDB>', self.getPath(), 'dirty=', self.__dirty__, 'data=', self.__data__
   5.494 +        if ((self.__data__ is not None)
   5.495 +            and (sync or save or self.__dirty__)):
   5.496 +            self.__db__.setData(self.__data__)
   5.497 +            self.__dirty__ = False
   5.498 +        else:
   5.499 +            #print 'DBMap>saveDB>', self.getPath(), 'not written'
   5.500 +            pass
   5.501 +        # Write children.
   5.502 +        for (name, node) in self.items():
   5.503 +            if not isinstance(node, DBMap): continue
   5.504 +            node.saveDB(sync=sync, save=save)
   5.505 +        # Remove db nodes not in children.
   5.506 +        if sync:
   5.507 +            for name in self.__db__.ls():
   5.508 +                if name not in self:
   5.509 +                    self.__db__.delete(name)
   5.510 +
   5.511 +    def importFromDB(self, obj, fields):
   5.512 +        """Set fields in obj from db fields.
   5.513 +        """
   5.514 +        for f in fields:
   5.515 +            f.importFromDB(self, obj)
   5.516 +
   5.517 +    def exportToDB(self, obj, fields, save=False, sync=False):
   5.518 +        """Set fields in db from obj fields.
   5.519 +        """
   5.520 +        for f in fields:
   5.521 +            f.exportToDB(self, obj)
   5.522 +        self.saveDB(save=save, sync=sync)
     6.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     6.2 +++ b/tools/python/xen/xend/xenstore/xsresource.py	Tue Jun 07 13:38:16 2005 +0000
     6.3 @@ -0,0 +1,136 @@
     6.4 +#============================================================================
     6.5 +# Copyright (C) 2005 Mike Wray <mike.wray@hp.com>
     6.6 +#============================================================================
     6.7 +# HTTP interface onto xenstore (read-only).
     6.8 +# Mainly intended for testing.
     6.9 +
    6.10 +import os
    6.11 +import os.path
    6.12 +
    6.13 +from xen.web.httpserver import HttpServer, UnixHttpServer
    6.14 +from xen.web.SrvBase import SrvBase
    6.15 +from xen.web.SrvDir import SrvDir
    6.16 +from xen.xend.Args import FormFn
    6.17 +from xen.xend.xenstore import XenNode
    6.18 +
    6.19 +def pathurl(req):
    6.20 +    url = req.prePathURL()
    6.21 +    if not url.endswith('/'):
    6.22 +        url += '/'
    6.23 +    return url
    6.24 +    
    6.25 +def writelist(req, l):
    6.26 +    req.write('(')
    6.27 +    for k in l:
    6.28 +       req.write(' ' + k)
    6.29 +    req.write(')')
    6.30 +
    6.31 +def lsData(dbnode, req, url):
    6.32 +    v = dbnode.getData()
    6.33 +    if v is None:
    6.34 +        req.write('<p>No data')
    6.35 +    else:
    6.36 +        req.write('<p>Data: <pre>')
    6.37 +        req.write(str(v))
    6.38 +        req.write('</pre>')
    6.39 +    v = dbnode.getLock()
    6.40 +    if v is None:
    6.41 +        req.write("<p>Unlocked")
    6.42 +    else:
    6.43 +        req.write("<p>Lock = %s" % v)
    6.44 +
    6.45 +def lsChildren(dbnode, req, url):
    6.46 +    l = dbnode.ls()
    6.47 +    if l:
    6.48 +        req.write('<p>Children: <ul>')
    6.49 +        for key in l:
    6.50 +            child = dbnode.getChild(key)
    6.51 +            data = child.getData()
    6.52 +            if data is None: data = ""
    6.53 +            req.write('<li><a href="%(url)s%(key)s">%(key)s</a> %(data)s</li>'
    6.54 +                      % { "url": url, "key": key, "data": data })
    6.55 +        req.write('</ul>')
    6.56 +    else:
    6.57 +        req.write('<p>No children')
    6.58 +        
    6.59 +
    6.60 +class DBDataResource(SrvBase):
    6.61 +    """Resource for the node data.
    6.62 +    """
    6.63 +
    6.64 +    def __init__(self, dbnode):
    6.65 +        SrvBase.__init__(self)
    6.66 +        self.dbnode = dbnode
    6.67 +
    6.68 +    def render_GET(self, req):
    6.69 +        req.write('<html><head></head><body>')
    6.70 +        self.print_path(req)
    6.71 +        req.write("<pre>")
    6.72 +        req.write(self.getData() or self.getNoData())
    6.73 +        req.write("</pre>")
    6.74 +        req.write('</body></html>')
    6.75 +
    6.76 +    def getContentType(self):
    6.77 +        # Use content-type from metadata.
    6.78 +        return "text/plain"
    6.79 +
    6.80 +    def getData(self):
    6.81 +        v = self.dbnode.getData()
    6.82 +        if v is None: return v
    6.83 +        return str(v)
    6.84 +
    6.85 +    def getNoData(self):
    6.86 +        return ""
    6.87 +
    6.88 +class DBNodeResource(SrvDir):
    6.89 +    """Resource for a DB node.
    6.90 +    """
    6.91 +
    6.92 +    def __init__(self, dbnode):
    6.93 +        SrvDir.__init__(self)
    6.94 +        self.dbnode = dbnode
    6.95 +
    6.96 +    def get(self, x):
    6.97 +        val = None
    6.98 +        if x == "__data__":
    6.99 +            val = DBDataResource(self.dbnode)
   6.100 +        else:
   6.101 +            if self.dbnode.exists(x):
   6.102 +                child = self.dbnode.getChild(x, create=False)
   6.103 +            else:
   6.104 +                child = None
   6.105 +            if child is not None:
   6.106 +                val = DBNodeResource(child)
   6.107 +        return val
   6.108 +
   6.109 +    def render_POST(self, req):
   6.110 +        return self.perform(req)
   6.111 +
   6.112 +    def ls(self, req, use_sxp=0):
   6.113 +        if use_sxp:
   6.114 +            writelist(req, self.dbnode.getChildren())
   6.115 +        else:
   6.116 +            url = pathurl(req)
   6.117 +            req.write("<fieldset>")
   6.118 +            lsData(self.dbnode, req, url)
   6.119 +            lsChildren(self.dbnode, req, url)
   6.120 +            req.write("</fieldset>")
   6.121 +
   6.122 +    def form(self, req):
   6.123 +        url = req.prePathURL()
   6.124 +        pass
   6.125 +        
   6.126 +class DBRootResource(DBNodeResource):
   6.127 +    """Resource for the root of a DB.
   6.128 +    """
   6.129 +
   6.130 +    def __init__(self):
   6.131 +        DBNodeResource.__init__(self, XenNode())
   6.132 +
   6.133 +def main(argv):
   6.134 +    root = SrvDir()
   6.135 +    root.putChild('xenstore', DBRootResource())
   6.136 +    interface = ''
   6.137 +    port = 8003
   6.138 +    server = HttpServer(root=root, interface=interface, port=port)
   6.139 +    server.run()