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