source: trunk/packages/xen-3.1/xen-3.1/tools/python/xen/xend/xenstore/xstransact.py @ 34

Last change on this file since 34 was 34, checked in by hartmans, 18 years ago

Add xen and xen-common

File size: 12.2 KB
Line 
1# Copyright (C) 2005 Christian Limpach <Christian.Limpach@cl.cam.ac.uk>
2# Copyright (C) 2005 XenSource Ltd
3
4# This file is subject to the terms and conditions of the GNU General
5# Public License.  See the file "COPYING" in the main directory of
6# this archive for more details.
7
8from xen.xend.xenstore.xsutil import xshandle
9
10
11class xstransact:
12
13    def __init__(self, path = ""):
14       
15        self.in_transaction = False # Set this temporarily -- if this
16                                    # constructor fails, then we need to
17                                    # protect __del__.
18
19        assert path is not None
20        self.path = path.rstrip("/")
21        self.transaction = xshandle().transaction_start()
22        self.in_transaction = True
23
24    def __del__(self):
25        if self.in_transaction:
26            xshandle().transaction_end(self.transaction, True)
27
28    def commit(self):
29        if not self.in_transaction:
30            raise RuntimeError
31        self.in_transaction = False
32        rc = xshandle().transaction_end(self.transaction, False)
33        self.transaction = "0"
34        return rc
35
36    def abort(self):
37        if not self.in_transaction:
38            return True
39        self.in_transaction = False
40        rc = xshandle().transaction_end(self.transaction, True)
41        self.transaction = "0"
42        return rc
43
44    def _read(self, key):
45        path = self.prependPath(key)
46        try:
47            return xshandle().read(self.transaction, path)
48        except RuntimeError, ex:
49            raise RuntimeError(ex.args[0],
50                               '%s, while reading %s' % (ex.args[1], path))
51
52    def read(self, *args):
53        """If no arguments are given, return the value at this transaction's
54        path.  If one argument is given, treat that argument as a subpath to
55        this transaction's path, and return the value at that path.
56        Otherwise, treat each argument as a subpath to this transaction's
57        path, and return a list composed of the values at each of those
58        instead.
59        """
60        if len(args) == 0:
61            return xshandle().read(self.transaction, self.path)
62        if len(args) == 1:
63            return self._read(args[0])
64        ret = []
65        for key in args:
66            ret.append(self._read(key))
67        return ret
68
69    def _write(self, key, data):
70        path = self.prependPath(key)
71        try:
72            xshandle().write(self.transaction, path, data)
73        except RuntimeError, ex:
74            raise RuntimeError(ex.args[0],
75                               ('%s, while writing %s : %s' %
76                                (ex.args[1], path, str(data))))
77
78    def write(self, *args):
79        if len(args) == 0:
80            raise TypeError
81        if isinstance(args[0], dict):
82            for d in args:
83                if not isinstance(d, dict):
84                    raise TypeError
85                for key in d.keys():
86                    try:
87                        self._write(key, d[key])
88                    except TypeError, msg:
89                        raise TypeError('Writing %s: %s: %s' %
90                                        (key, str(d[key]), msg))
91        elif isinstance(args[0], list):
92            for l in args:
93                if not len(l) == 2:
94                    raise TypeError
95                self._write(l[0], l[1])
96        elif len(args) % 2 == 0:
97            for i in range(len(args) / 2):
98                self._write(args[i * 2], args[i * 2 + 1])
99        else:
100            raise TypeError
101
102    def _remove(self, key):
103        path = self.prependPath(key)
104        return xshandle().rm(self.transaction, path)
105
106    def remove(self, *args):
107        """If no arguments are given, remove this transaction's path.
108        Otherwise, treat each argument as a subpath to this transaction's
109        path, and remove each of those instead.
110        """
111        if len(args) == 0:
112            xshandle().rm(self.transaction, self.path)
113        else:
114            for key in args:
115                self._remove(key)
116
117    def _list(self, key):
118        path = self.prependPath(key)
119        l = xshandle().ls(self.transaction, path)
120        if l:
121            return map(lambda x: key + "/" + x, l)
122        return []
123
124    def list(self, *args):
125        """If no arguments are given, list this transaction's path, returning
126        the entries therein, or the empty list if no entries are found.
127        Otherwise, treat each argument as a subpath to this transaction's
128        path, and return the cumulative listing of each of those instead.
129        """
130        if len(args) == 0:
131            ret = xshandle().ls(self.transaction, self.path)
132            if ret is None:
133                return []
134            else:
135                return ret
136        else:
137            ret = []
138            for key in args:
139                ret.extend(self._list(key))
140            return ret
141
142
143    def list_recursive_(self, subdir, keys):
144        ret = []
145        for key in keys:
146            new_subdir = subdir + "/" + key
147            l = xshandle().ls(self.transaction, new_subdir)
148            if l:
149                ret.append([key, self.list_recursive_(new_subdir, l)])
150            else:
151                ret.append([key, xshandle().read(self.transaction, new_subdir)])
152        return ret
153
154
155    def list_recursive(self, *args):
156        """If no arguments are given, list this transaction's path, returning
157        the entries therein, or the empty list if no entries are found.
158        Otherwise, treat each argument as a subpath to this transaction's
159        path, and return the cumulative listing of each of those instead.
160        """
161        if len(args) == 0:
162            args = self.list()
163            if args is None or len(args) == 0:
164                return []
165
166        return self.list_recursive_(self.path, args)
167
168
169    def gather(self, *args):
170        if len(args) and type(args[0]) != tuple:
171            args = args,
172        ret = []
173        for tup in args:
174            if len(tup) == 2:
175                (key, fn) = tup
176                defval = None
177            else:
178                (key, fn, defval) = tup
179
180            val = self._read(key)
181            # If fn is str, then this will successfully convert None to 'None'
182            # (which we don't want).  If it is int or float, then it will
183            # throw ValueError on any non-convertible value.  We check
184            # explicitly for None, using defval instead, but allow ValueError
185            # to propagate.
186            if val is None:
187                val = defval
188            else:
189                val = fn(val)
190            ret.append(val)
191        if len(ret) == 1:
192            return ret[0]
193        return ret
194
195    def store(self, *args):
196        if len(args) and type(args[0]) != tuple:
197            args = args,
198        for tup in args:
199            if len(tup) == 2:
200                (key, val) = tup
201                try:
202                    fmt = { str        : "%s",
203                            int        : "%i",
204                            float      : "%f",
205                            long       : "%li",
206                            type(None) : None }[type(val)]
207                except KeyError:
208                    raise TypeError
209            else:
210                (key, val, fmt) = tup
211            if val is None:
212                self._remove(key)
213            else:
214                self._write(key, fmt % val)
215
216
217    def mkdir(self, *args):
218        if len(args) == 0:
219            xshandle().mkdir(self.transaction, self.path)
220        else:
221            for key in args:
222                xshandle().mkdir(self.transaction, self.prependPath(key))
223
224
225    def get_permissions(self, *args):
226        """If no arguments are given, return the permissions at this
227        transaction's path.  If one argument is given, treat that argument as
228        a subpath to this transaction's path, and return the permissions at
229        that path.  Otherwise, treat each argument as a subpath to this
230        transaction's path, and return a list composed of the permissions at
231        each of those instead.
232        """
233        if len(args) == 0:
234            return xshandle().get_permissions(self.transaction, self.path)
235        if len(args) == 1:
236            return self._get_permissions(args[0])
237        ret = []
238        for key in args:
239            ret.append(self._get_permissions(key))
240        return ret
241
242
243    def _get_permissions(self, key):
244        path = self.prependPath(key)
245        try:
246            return xshandle().get_permissions(self.transaction, path)
247        except RuntimeError, ex:
248            raise RuntimeError(ex.args[0],
249                               '%s, while getting permissions from %s' %
250                               (ex.args[1], path))
251
252
253    def set_permissions(self, *args):
254        if len(args) == 0:
255            raise TypeError
256        elif isinstance(args[0], str):
257            self.callRebased(args[0], self.set_permissions, *args[1:])
258        else:
259            if not self.path:
260                raise RuntimeError('Cannot set permissions on the root')
261
262            xshandle().set_permissions(self.transaction, self.path,
263                                       list(args))
264
265
266    def remove2(self, middlePath, *args):
267        self.callRebased(middlePath, self.remove, *args)
268
269
270    def write2(self, middlePath, *args):
271        self.callRebased(middlePath, self.write, *args)
272
273
274    def callRebased(self, middlePath, func, *args):
275        oldpath = self.path
276        self.path = self.prependPath(middlePath)
277        try:
278            func(*args)
279        finally:
280            self.path = oldpath
281
282
283    def prependPath(self, key):
284        if self.path:
285            return self.path + '/' + key
286        else:
287            return key
288
289
290    def Read(cls, path, *args):
291        """If only one argument is given (path), return the value stored at
292        that path.  If two arguments are given, treat the second argument as a
293        subpath within the first, and return the value at the composed path.
294        Otherwise, treat each argument after the first as a subpath to the
295        given path, and return a list composed of the values at each of those
296        instead.  This operation is performed inside a transaction.
297        """
298        return complete(path, lambda t: t.read(*args))
299    Read = classmethod(Read)
300
301    def Write(cls, path, *args):
302        complete(path, lambda t: t.write(*args))
303    Write = classmethod(Write)
304
305    def Remove(cls, path, *args):
306        """If only one argument is given (path), remove it.  Otherwise, treat
307        each further argument as a subpath to the given path, and remove each
308        of those instead.  This operation is performed inside a transaction.
309        """
310        complete(path, lambda t: t.remove(*args))
311    Remove = classmethod(Remove)
312
313    def List(cls, path, *args):
314        """If only one argument is given (path), list its contents, returning
315        the entries therein, or the empty list if no entries are found.
316        Otherwise, treat each further argument as a subpath to the given path,
317        and return the cumulative listing of each of those instead.  This
318        operation is performed inside a transaction.
319        """
320        return complete(path, lambda t: t.list(*args))
321    List = classmethod(List)
322
323    def ListRecursive(cls, path, *args):
324        """If only one argument is given (path), list its contents
325        recursively, returning the entries therein, or the empty list if no
326        entries are found.  Otherwise, treat each further argument as a
327        subpath to the given path, and return the cumulative listing of each
328        of those instead.  This operation is performed inside a transaction.
329        """
330        return complete(path, lambda t: t.list_recursive(*args))
331    ListRecursive = classmethod(ListRecursive)
332
333    def Gather(cls, path, *args):
334        return complete(path, lambda t: t.gather(*args))
335    Gather = classmethod(Gather)
336
337    def Store(cls, path, *args):
338        complete(path, lambda t: t.store(*args))
339    Store = classmethod(Store)
340
341    def SetPermissions(cls, path, *args):
342        complete(path, lambda t: t.set_permissions(*args))
343    SetPermissions = classmethod(SetPermissions)
344
345    def Mkdir(cls, path, *args):
346        complete(path, lambda t: t.mkdir(*args))
347    Mkdir = classmethod(Mkdir)
348
349
350def complete(path, f):
351    while True:
352        t = xstransact(path)
353        try:
354            result = f(t)
355            if t.commit():
356                return result
357        except:
358            t.abort()
359            raise
Note: See TracBrowser for help on using the repository browser.