ia64/xen-unstable

view tools/python/xen/xend/xenstore/xsobj.py @ 6049:eb98d18771ca

xend prints out some messages when starting, which is annoying. This
patch send those to xend log file instead - people want them always
know where to find them.

Signed-off-by: Nguyen Anh Quynh <aquynh@gmail.com>
author kaf24@firebug.cl.cam.ac.uk
date Sat Aug 06 15:45:41 2005 +0000 (2005-08-06)
parents 999293916aa7
children f40c6650152e
line source
1 import string
2 import types
4 from xen.xend.XendLogging import log
6 from xen.xend import sxp
7 from xsnode import XenNode
8 from xen.util.mac import macToString, macFromString
10 VALID_KEY_CHARS = string.ascii_letters + string.digits + "_-@"
12 def hasAttr(obj, attr):
13 if isinstance(obj, dict):
14 return obj.contains(attr)
15 else:
16 return hasattr(obj, attr)
18 def getAttr(obj, attr):
19 try:
20 if isinstance(obj, dict):
21 return obj.get(attr)
22 else:
23 return getattr(obj, attr, None)
24 except AttributeError:
25 return None
26 except LookupError:
27 return None
29 def setAttr(obj, attr, val):
30 if isinstance(obj, dict):
31 obj[attr] = val
32 else:
33 setattr(obj, attr, val)
35 class DBConverter:
36 """Conversion of values to and from strings in xenstore.
37 """
39 converters = {}
41 def checkType(cls, ty):
42 if ty is None or ty in cls.converters:
43 return
44 raise ValueError("invalid converter type: '%s'" % ty)
46 checkType = classmethod(checkType)
48 def getConverter(cls, ty=None):
49 if ty is None:
50 ty = "str"
51 conv = cls.converters.get(ty)
52 if not conv:
53 raise ValueError("no converter for type: '%s'" % ty)
54 return conv
56 getConverter = classmethod(getConverter)
58 def exportTypeToDB(cls, db, path, val, ty=None):
59 return cls.getConverter(ty).exportToDB(db, path, val)
61 exportTypeToDB = classmethod(exportTypeToDB)
63 def importTypeFromDB(cls, db, path, ty=None):
64 return cls.getConverter(ty).importFromDB(db, path)
66 importTypeFromDB = classmethod(importTypeFromDB)
68 # Must define in subclass.
69 name = None
71 def __init__(self):
72 self.register()
74 def register(self):
75 if not self.name:
76 raise ValueError("invalid converter name: '%s'" % self.name)
77 self.converters[self.name] = self
79 def exportToDB(self, db, path, val):
80 if val is None:
81 return
82 try:
83 data = self.toDB(val)
84 except Exception, ex:
85 raise
86 setattr(db, path, data)
88 def importFromDB(self, db, path):
89 data = getAttr(db, path)
90 if data is None:
91 val = None
92 else:
93 try:
94 val = self.fromDB(data.getData())
95 except Exception, ex:
96 raise
97 return val
99 def toDB(self, val):
100 raise NotImplementedError()
102 def fromDB(self, val):
103 raise NotImplementedError()
105 class StrConverter(DBConverter):
107 name = "str"
109 def toDB(self, val):
110 # Convert True/False to 1/0, otherwise they convert to
111 # 'True' and 'False' rather than '1' and '0', even though
112 # isinstance(True/False, int) is true.
113 if isinstance(val, bool):
114 val = int(val)
115 return str(val)
117 def fromDB(self, data):
118 return data
120 StrConverter()
122 class BoolConverter(DBConverter):
124 name = "bool"
126 def toDB(self, val):
127 return str(int(bool(val)))
129 def fromDB(self, data):
130 return bool(int(data))
132 BoolConverter()
134 class SxprConverter(DBConverter):
136 name = "sxpr"
138 def toDB(self, val):
139 return sxp.to_string(val)
141 def fromDB(self, data):
142 return sxp.from_string(data)
144 SxprConverter()
146 class IntConverter(DBConverter):
148 name = "int"
150 def toDB(self, val):
151 return str(int(val))
153 def fromDB(self, data):
154 return int(data)
156 IntConverter()
158 class FloatConverter(DBConverter):
160 name = "float"
162 def toDB(self, val):
163 return str(float(val))
165 def fromDB(self, data):
166 return float(data)
168 FloatConverter()
170 class LongConverter(DBConverter):
172 name = "long"
174 def toDB(self, val):
175 return str(long(val))
177 def fromDB(self, data):
178 return long(data)
180 LongConverter()
182 class MacConverter(DBConverter):
184 name = "mac"
186 def toDB(self, val):
187 return macToString(val)
189 def fromDB(self, data):
190 return macFromString(data)
192 MacConverter()
194 class DBVar:
196 def __init__(self, var, ty=None, path=None):
197 DBConverter.checkType(ty)
198 if path is None:
199 path = var
200 self.var = var
201 self.ty = ty
202 self.path = path
203 varpath = filter(bool, self.var.split())
204 self.attrpath = varpath[:-1]
205 self.attr = varpath[-1]
207 def exportToDB(self, db, obj):
208 val = self.getObj(obj)
209 DBConverter.exportTypeToDB(db, self.path, val, ty=self.ty)
211 def importFromDB(self, db, obj):
212 val = DBConverter.importTypeFromDB(db, self.path, ty=self.ty)
213 self.setObj(obj, val)
215 def getObj(self, obj):
216 o = obj
217 for x in self.attrpath:
218 o = getAttr(o, x)
219 if o is None:
220 return None
221 return getAttr(o, self.attr)
223 def setObj(self, obj, val):
224 o = obj
225 for x in self.attrpath:
226 o = getAttr(o, x)
227 # Don't set obj attr if val is None.
228 if val is None and hasAttr(o, self.attr):
229 return
230 setAttr(o, self.attr, val)
232 class DBMap(dict):
233 """A persistent map. Extends dict with persistence.
234 Set and get values using the usual map syntax:
236 m[k], m.get(k)
237 m[k] = v
239 Also supports being treated as an object with attributes.
240 When 'k' is a legal identifier you may also use
242 m.k, getattr(m, k)
243 m.k = v, setattr(m, k)
244 k in m, hasattr(m, k)
246 When setting you can pass in a normal value, for example
248 m.x = 3
250 Getting works too:
252 m.x ==> 3
254 while m['x'] will return the map for x.
256 m['x'].getData() ==> 3
258 To get values from subdirs use get() to get the subdir first:
260 get(m, 'foo').x
261 m['foo'].x
263 instead of m.foo.x, because m.foo will return the data for field foo,
264 not the directory.
266 You can assign values into a subdir by passing a map:
268 m.foo = {'x': 1, 'y':2 }
270 You can also use paths as keys:
272 m['foo/x'] = 1
274 sets field x in subdir foo.
276 """
278 __db__ = None
279 __data__ = None
280 __perms__ = None
281 __parent__ = None
282 __name__ = ""
284 __transaction__ = False
286 # True if value set since saved (or never saved).
287 __dirty__ = True
289 def __init__(self, parent=None, name="", db=None):
290 if parent is None:
291 self.__name__ = name
292 else:
293 if not isinstance(parent, DBMap):
294 raise ValueError("invalid parent")
295 self.__parent__ = parent
296 self.__name__ = name
297 db = self.__parent__.getChildDB(name)
298 self.setDB(db)
300 def getName(self):
301 return self.__name__
303 def getPath(self):
304 return self.__db__ and self.__db__.relPath()
306 def introduceDomain(self, dom, page, evtchn, path=None):
307 db = self.__db__
308 if path is None:
309 path = db.relPath()
310 log.info("DBMap>introduceDomain> %d %d %s %s" %(dom, page, evtchn, path))
311 try:
312 db.introduceDomain(dom, page, evtchn, path)
313 except Exception, ex:
314 import traceback
315 traceback.print_exc()
316 log.info("DBMap>introduceDomain> %s" %ex)
317 pass # todo: don't ignore
319 def releaseDomain(self, dom):
320 db = self.__db__
321 log.info("DBMap>releaseDomain> %d" %dom)
322 try:
323 db.releaseDomain(dom)
324 except Exception, ex:
325 import traceback
326 traceback.print_exc()
327 log.info("DBMap>releaseDomain> %s" %ex)
328 pass # todo: don't ignore
330 def watch(self, fn, path=""):
331 return self.__db__.watch(fn, path=path)
333 def unwatch(self, sid):
334 return self.__db__.unwatch(sid)
336 def subscribe(self, event, fn):
337 return self.__db__.subscribe(event, fn)
339 def unsubscribe(self, sid):
340 return self.__db__.unsubscribe(sid)
342 def sendEvent(self, event, val):
343 return self.__db__.sendEvent(event, val)
345 def transactionBegin(self):
346 # Begin a transaction.
347 pass
349 def transactionCommit(self):
350 # Commit writes to db.
351 pass
353 def transactionFail(self):
354 # Fail a transaction.
355 # We have changed values, what do we do?
356 pass
358 def checkName(self, k):
359 if k == "":
360 raise ValueError("invalid key, empty string")
361 for c in k:
362 if c in VALID_KEY_CHARS: continue
363 raise ValueError("invalid key char '%s'" % c)
365 def _setData(self, v):
366 #print 'DBMap>_setData>', self.getPath(), 'data=', v
367 if v != self.__data__:
368 self.__dirty__ = True
369 self.__data__ = v
371 def setData(self, v):
372 if isinstance(v, dict):
373 for (key, val) in v.items():
374 self[key] = val
375 else:
376 self._setData(v)
378 def getData(self):
379 return self.__data__
381 def _set(self, k, v):
382 dict.__setitem__(self, k, v)
384 def _get(self, k):
385 try:
386 return dict.__getitem__(self, k)
387 except:
388 return None
390 def _del(self, k, v):
391 try:
392 dict.__delitem__(self, k)
393 except:
394 pass
396 def _contains(self, k):
397 return dict.__contains__(self, k)
399 def __setitem__(self, k, v, save=False):
400 node = self.addChild(k)
401 node.setData(v)
402 if save:
403 node.saveDB()
405 def __getitem__(self, k):
406 if self._contains(k):
407 v = self._get(k)
408 else:
409 v = self.readChildDB(k)
410 self._set(k, v)
411 return v
413 def __delitem__(self, k):
414 self._del(k)
415 self.deleteChildDB(k)
417 def __repr__(self):
418 if len(self):
419 return dict.__repr__(self)
420 else:
421 return repr(self.__data__)
423 def __setattr__(self, k, v):
424 if k.startswith("__"):
425 object.__setattr__(self, k, v)
426 else:
427 self.__setitem__(k, v, save=True)
428 return v
430 def __getattr__(self, k):
431 if k.startswith("__"):
432 v = object.__getattr__(self, k)
433 else:
434 try:
435 v = self.__getitem__(k).getData()
436 except LookupError, ex:
437 raise AttributeError(ex.args)
438 return v
440 def __delattr__(self, k):
441 return self.__delitem__(k)
443 def delete(self):
444 dict.clear(self)
445 self.__data__ = None
446 if self.__db__:
447 self.__db__.delete()
449 def clear(self):
450 dict.clear(self)
451 if self.__db__:
452 self.__db__.deleteChildren()
454 def getChild(self, k):
455 return self._get(k)
457 def getChildDB(self, k):
458 self.checkName(k)
459 return self.__db__ and self.__db__.getChild(k)
461 def deleteChildDB(self, k):
462 if self.__db__:
463 self.__db__.deleteChild(k)
465 def _addChild(self, k):
466 kid = self._get(k)
467 if kid is None:
468 kid = DBMap(parent=self, name=k, db=self.getChildDB(k))
469 self._set(k, kid)
470 return kid
472 def addChild(self, path):
473 l = path.split("/")
474 n = self
475 for x in l:
476 if x == "": continue
477 n = n._addChild(x)
478 return n
480 def getDB(self):
481 return self.__db__
483 def setDB(self, db):
484 if (db is not None) and not isinstance(db, XenNode):
485 raise ValueError("invalid db")
486 self.__db__ = db
487 for (k, v) in self.items():
488 if v is None: continue
489 if isinstance(v, DBMap):
490 v._setDB(self.addChild(k), restore)
492 def readDB(self):
493 if self.__db__ is None:
494 return
495 self.__data__ = self.__db__.getData()
496 for k in self.__db__.ls():
497 n = self.addChild(k)
498 n.readDB()
499 self.__dirty__ = False
501 def readChildDB(self, k):
502 if self.__db__ and (k in self.__db__.ls()):
503 n = self.addChild(k)
504 n.readDB()
505 raise LookupError("invalid key '%s'" % k)
507 def saveDB(self, sync=False, save=False):
508 """Save unsaved data to db.
509 If save or sync is true, saves whether dirty or not.
510 If sync is true, removes db entries not in the map.
511 """
513 if self.__db__ is None:
514 #print 'DBMap>saveDB>',self.getPath(), 'no db'
515 return
516 # Write data.
517 #print 'DBMap>saveDB>', self.getPath(), 'dirty=', self.__dirty__, 'data=', self.__data__
518 if ((self.__data__ is not None)
519 and (sync or save or self.__dirty__)):
520 self.__db__.setData(self.__data__)
521 self.__dirty__ = False
522 else:
523 #print 'DBMap>saveDB>', self.getPath(), 'not written'
524 pass
525 # Write children.
526 for (name, node) in self.items():
527 if not isinstance(node, DBMap): continue
528 node.saveDB(sync=sync, save=save)
529 # Remove db nodes not in children.
530 if sync:
531 for name in self.__db__.ls():
532 if name not in self:
533 self.__db__.delete(name)
535 def importFromDB(self, obj, fields):
536 """Set fields in obj from db fields.
537 """
538 for f in fields:
539 f.importFromDB(self, obj)
541 def exportToDB(self, obj, fields, save=False, sync=False):
542 """Set fields in db from obj fields.
543 """
544 for f in fields:
545 f.exportToDB(self, obj)
546 self.saveDB(save=save, sync=sync)