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