Whamcloud - gitweb
land v0.9.1 on HEAD, in preparation for a 1.0.x branch
[fs/lustre-release.git] / lustre / utils / Lustre / lustredb.py
1 import sys, types, string, os
2 import re, exceptions
3 import xml.dom.minidom
4 import Lustre
5
6 # ============================================================
7 # XML processing and query
8
9 class LustreDB:
10     def lookup(self, uuid):
11         """ lookup returns a new LustreDB instance"""
12         return self._lookup_by_uuid(uuid)
13
14     def lookup_name(self, name, class_name = ""):
15         """ lookup returns a new LustreDB instance"""
16         return self._lookup_by_name(name, class_name)
17
18     def lookup_class(self, class_name):
19         """ lookup returns a new LustreDB instance"""
20         return self._lookup_by_class(class_name)
21
22     def get_val(self, tag, default=None):
23         v =  self._get_val(tag)
24         if v:
25             return v
26         if default != None:
27             return default
28         return None
29
30     def get_class(self):
31         return self._get_class()
32
33     def get_val_int(self, tag, default=0):
34         str = self._get_val(tag)
35         try:
36             if str:
37                 return int(str)
38             return default
39         except ValueError:
40             raise Lustre.LconfError("text value is not integer: " + str)
41             
42     def get_first_ref(self, tag):
43         """ Get the first uuidref of the type TAG. Only
44         one is expected.  Returns the uuid."""
45         uuids = self._get_refs(tag)
46         if len(uuids) > 0:
47             return  uuids[0]
48         return None
49     
50     def get_refs(self, tag):
51         """ Get all the refs of type TAG.  Returns list of uuids. """
52         uuids = self._get_refs(tag)
53         return uuids
54
55     def get_all_refs(self):
56         """ Get all the refs.  Returns list of uuids. """
57         uuids = self._get_all_refs()
58         return uuids
59
60     def nid2server(self, nid, net_type, cluster_id):
61         netlist = self.lookup_class('network')
62         for net_db in netlist:
63             if (net_db.get_val('nid') == nid and
64                 net_db.get_val('nettype') == net_type and
65                 net_db.get_val('clusterid') == cluster_id):
66                 return net_db
67         return None
68     
69     # Find the target_device for target on a node
70     # node->profiles->device_refs->target
71     def get_node_tgt_dev(self, node_name, target_uuid):
72         node_db = self.lookup_name(node_name)
73         if not node_db:
74             return None
75         return node_db.get_tgt_dev(target_uuid)
76
77     # get all network uuids for this node
78     def get_networks(self):
79         ret = []
80         prof_list = self.get_refs('profile')
81         for prof_uuid in prof_list:
82             prof_db = self.lookup(prof_uuid)
83             net_list = prof_db.get_refs('network')
84             for net_uuid in net_list:
85                 ret.append(net_uuid)
86         return ret
87
88     def get_active_dev(self, tgtuuid):
89         tgt = self.lookup(tgtuuid)
90         tgt_dev_uuid =tgt.get_first_ref('active')
91         return tgt_dev_uuid
92
93     def get_tgt_dev(self, tgtuuid):
94         prof_list = self.get_refs('profile')
95         for prof_uuid in prof_list:
96             prof_db = self.lookup(prof_uuid)
97             if not prof_db:
98                 panic("profile:", profile, "not found.")
99             for ref_class, ref_uuid in prof_db.get_all_refs(): 
100                 if ref_class in ('osd', 'mdsdev'):
101                     devdb = self.lookup(ref_uuid)
102                     uuid = devdb.get_first_ref('target')
103                     if tgtuuid == uuid:
104                         return ref_uuid
105         return None
106
107     def get_group(self, group):
108         ret = []
109         devs = self.lookup_class('mds')
110         for tgt in devs:
111             if tgt.get_val('group', "") == group:
112                 ret.append(tgt.getUUID())
113         devs = self.lookup_class('ost')
114         for tgt in devs:
115             if tgt.get_val('group', "") == group:
116                 ret.append(tgt.getUUID())
117         return ret
118
119     # Change the current active device for a target
120     def update_active(self, tgtuuid, new_uuid):
121         self._update_active(tgtuuid, new_uuid)
122
123     def get_version(self):
124         return self.get_val('version')
125
126 class LustreDB_XML(LustreDB):
127     def __init__(self, dom, root_node):
128         # init xmlfile
129         self.dom_node = dom
130         self.root_node = root_node
131
132     def xmltext(self, dom_node, tag):
133         list = dom_node.getElementsByTagName(tag)
134         if len(list) > 0:
135             dom_node = list[0]
136             dom_node.normalize()
137             if dom_node.firstChild:
138                 txt = string.strip(dom_node.firstChild.data)
139                 if txt:
140                     return txt
141
142     def xmlattr(self, dom_node, attr):
143         return dom_node.getAttribute(attr)
144
145     def _get_val(self, tag):
146         """a value could be an attribute of the current node
147         or the text value in a child node"""
148         ret  = self.xmlattr(self.dom_node, tag)
149         if not ret:
150             ret = self.xmltext(self.dom_node, tag)
151         return ret
152
153     def _get_class(self):
154         return self.dom_node.nodeName
155
156     def get_ref_type(self, ref_tag):
157         res = string.split(ref_tag, '_')
158         return res[0]
159
160     #
161     # [(ref_class, ref_uuid),]
162     def _get_all_refs(self):
163         list = []
164         for n in self.dom_node.childNodes: 
165             if n.nodeType == n.ELEMENT_NODE:
166                 ref_uuid = self.xml_get_ref(n)
167                 ref_class = self.get_ref_type(n.nodeName)
168                 list.append((ref_class, ref_uuid))
169                     
170         list.sort()
171         return list
172
173     def _get_refs(self, tag):
174         """ Get all the refs of type TAG.  Returns list of uuids. """
175         uuids = []
176         refname = '%s_ref' % tag
177         reflist = self.dom_node.getElementsByTagName(refname)
178         for r in reflist:
179             uuids.append(self.xml_get_ref(r))
180         return uuids
181
182     def xmllookup_by_uuid(self, dom_node, uuid):
183         for n in dom_node.childNodes:
184             if n.nodeType == n.ELEMENT_NODE:
185                 if self.xml_get_uuid(n) == uuid:
186                     return n
187                 else:
188                     n = self.xmllookup_by_uuid(n, uuid)
189                     if n: return n
190         return None
191
192     def _lookup_by_uuid(self, uuid):
193         dom = self. xmllookup_by_uuid(self.root_node, uuid)
194         if dom:
195             return LustreDB_XML(dom, self.root_node)
196
197     def xmllookup_by_name(self, dom_node, name):
198         for n in dom_node.childNodes:
199             if n.nodeType == n.ELEMENT_NODE:
200                 if self.xml_get_name(n) == name:
201                     return n
202                 else:
203                     n = self.xmllookup_by_name(n, name)
204                     if n: return n
205         return None
206
207     def _lookup_by_name(self, name, class_name):
208         dom = self.xmllookup_by_name(self.root_node, name)
209         if dom:
210             return LustreDB_XML(dom, self.root_node)
211
212     def xmllookup_by_class(self, dom_node, class_name):
213         return dom_node.getElementsByTagName(class_name)
214
215     def _lookup_by_class(self, class_name):
216         ret = []
217         domlist = self.xmllookup_by_class(self.root_node, class_name)
218         for node in domlist:
219             ret.append(LustreDB_XML(node, self.root_node))
220         return ret
221
222     def xml_get_name(self, n):
223         return n.getAttribute('name')
224         
225     def getName(self):
226         return self.xml_get_name(self.dom_node)
227
228     def xml_get_ref(self, n):
229         return n.getAttribute('uuidref')
230
231     def xml_get_uuid(self, dom_node):
232         return dom_node.getAttribute('uuid')
233
234     def getUUID(self):
235         return self.xml_get_uuid(self.dom_node)
236
237     # Convert routes from the router to a route that will be used
238     # on the local system.  The network type and gw are changed to the
239     # interface on the router the local system will connect to.
240     def get_local_routes(self, type, gw):
241         """ Return the routes as a list of tuples of the form:
242         [(type, gw, lo, hi),]"""
243         res = []
244         tbl = self.dom_node.getElementsByTagName('routetbl')
245         for t in tbl:
246             routes = t.getElementsByTagName('route')
247             for r in routes:
248                 net_type = self.xmlattr(r, 'type')
249                 if type != net_type:
250                     lo = self.xmlattr(r, 'lo')
251                     hi = self.xmlattr(r, 'hi')
252                     tgt_cluster_id = self.xmlattr(r, 'tgtclusterid')
253                     res.append((type, gw, tgt_cluster_id, lo, hi))
254         return res
255
256     def get_route_tbl(self):
257         ret = []
258         for r in self.dom_node.getElementsByTagName('route'):
259             net_type = self.xmlattr(r, 'type')
260             gw = self.xmlattr(r, 'gw')
261             gw_cluster_id = self.xmlattr(r, 'gwclusterid')
262             tgt_cluster_id = self.xmlattr(r, 'tgtclusterid')
263             lo = self.xmlattr(r, 'lo')
264             hi = self.xmlattr(r, 'hi')
265             ret.append((net_type, gw, gw_cluster_id, tgt_cluster_id, lo, hi))
266         return ret
267
268     def _update_active(self, tgt, new):
269         raise Lustre.LconfError("updates not implemented for XML")
270
271 # ================================================================    
272 # LDAP Support
273 class LustreDB_LDAP(LustreDB):
274     def __init__(self, name, attrs,
275                  base = "fs=lustre",
276                  parent = None,
277                  url  = "ldap://localhost",
278                  user = "cn=Manager, fs=lustre",
279                  pw   = ""
280                  ):
281         self._name = name
282         self._attrs = attrs
283         self._base = base
284         self._parent = parent
285         self._url  = url
286         self._user = user
287         self._pw   = pw
288         if parent:
289             self.l = parent.l
290             self._base = parent._base
291         else:
292             self.open()
293
294     def open(self):
295         import ldap
296         try:
297             self.l = ldap.initialize(self._url)
298             # Set LDAP protocol version used
299             self.l.protocol_version=ldap.VERSION3
300             # user and pw only needed if modifying db
301             self.l.bind_s(self._user, self._pw, ldap.AUTH_SIMPLE);
302         except ldap.LDAPError, e:
303             raise Lustre.LconfError('Unable to connect to ldap server:' + self._url)
304
305         try:
306             self._name, self._attrs = self.l.search_s(self._base,
307                                                       ldap.SCOPE_BASE)[0]
308         except ldap.LDAPError, e:
309             raise Lustre.LconfError("no config found in ldap: %s"
310                                       % (self._base,))
311     def close(self):
312         self.l.unbind_s()
313
314     def ldap_search(self, filter):
315         """Return list of uuids matching the filter."""
316         import ldap
317         dn = self._base
318         ret = []
319         uuids = []
320         try:
321             for name, attrs in self.l.search_s(dn, ldap.SCOPE_ONELEVEL,
322                                         filter, ["uuid"]):
323                 for v in attrs['uuid']:
324                     uuids.append(v)
325         except ldap.NO_SUCH_OBJECT, e:
326             pass
327         except ldap.LDAPError, e:
328             print e                     # FIXME: die here?
329         if len(uuids) > 0:
330             for uuid in uuids:
331                 ret.append(self._lookup_by_uuid(uuid))
332         return ret
333
334     def _lookup_by_name(self, name, class_name):
335         list =  self.ldap_search("lustreName=%s" %(name))
336         if len(list) == 1:
337             return list[0]
338         return None
339
340     def _lookup_by_class(self, class_name):
341         return self.ldap_search("objectclass=%s" %(string.upper(class_name)))
342
343     def _lookup_by_uuid(self, uuid):
344         import ldap
345         dn = "uuid=%s,%s" % (uuid, self._base)
346         ret = None
347         try:
348             for name, attrs in self.l.search_s(dn, ldap.SCOPE_BASE,
349                                                "objectclass=*"):
350                 ret = LustreDB_LDAP(name, attrs,  parent = self)
351                         
352         except ldap.NO_SUCH_OBJECT, e:
353             pass                        # just return empty list
354         except ldap.LDAPError, e:
355             print e                     # FIXME: die here?
356         return ret
357
358
359     def _get_val(self, k):
360         ret = None
361         if self._attrs.has_key(k):
362             v = self._attrs[k]
363             if type(v) == types.ListType:
364                 ret = str(v[0])
365             else:
366                 ret = str(v)
367         return ret
368
369     def _get_class(self):
370         return string.lower(self._attrs['objectClass'][0])
371
372     def get_ref_type(self, ref_tag):
373         return ref_tag[:-3]
374
375     #
376     # [(ref_class, ref_uuid),]
377     def _get_all_refs(self):
378         list = []
379         for k in self._attrs.keys():
380             if re.search('.*Ref', k):
381                 for uuid in self._attrs[k]:
382                     ref_class = self.get_ref_type(k)
383                     list.append((ref_class, uuid))
384         return list
385
386     def _get_refs(self, tag):
387         """ Get all the refs of type TAG.  Returns list of uuids. """
388         uuids = []
389         refname = '%sRef' % tag
390         if self._attrs.has_key(refname):
391             return self._attrs[refname]
392         return []
393
394     def getName(self):
395         return self._get_val('lustreName')
396
397     def getUUID(self):
398         return self._get_val('uuid')
399
400     def get_route_tbl(self):
401         return []
402
403     def _update_active(self, tgtuuid, newuuid):
404         """Return list of uuids matching the filter."""
405         import ldap
406         dn = "uuid=%s,%s" %(tgtuuid, self._base)
407         ret = []
408         uuids = []
409         try:
410             self.l.modify_s(dn, [(ldap.MOD_REPLACE, "activeRef", newuuid)])
411         except ldap.NO_SUCH_OBJECT, e:
412             print e
413         except ldap.LDAPError, e:
414             print e                     # FIXME: die here?
415         return