Whamcloud - gitweb
landing b_cmobd_merge on HEAD
[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 close(self):
133         # do nothing
134         return None
135
136     def xmltext(self, dom_node, tag):
137         list = dom_node.getElementsByTagName(tag)
138         if len(list) > 0:
139             dom_node = list[0]
140             dom_node.normalize()
141             if dom_node.firstChild:
142                 txt = string.strip(dom_node.firstChild.data)
143                 if txt:
144                     return txt
145
146     def xmlattr(self, dom_node, attr):
147         return dom_node.getAttribute(attr)
148
149     def _get_val(self, tag):
150         """a value could be an attribute of the current node
151         or the text value in a child node"""
152         ret  = self.xmlattr(self.dom_node, tag)
153         if not ret:
154             ret = self.xmltext(self.dom_node, tag)
155         return ret
156
157     def _get_class(self):
158         return self.dom_node.nodeName
159
160     def get_ref_type(self, ref_tag):
161         res = string.split(ref_tag, '_')
162         return res[0]
163
164     #
165     # [(ref_class, ref_uuid),]
166     def _get_all_refs(self):
167         list = []
168         for n in self.dom_node.childNodes: 
169             if n.nodeType == n.ELEMENT_NODE:
170                 ref_uuid = self.xml_get_ref(n)
171                 ref_class = self.get_ref_type(n.nodeName)
172                 list.append((ref_class, ref_uuid))
173                     
174         list.sort()
175         return list
176
177     def _get_refs(self, tag):
178         """ Get all the refs of type TAG.  Returns list of uuids. """
179         uuids = []
180         refname = '%s_ref' % tag
181         reflist = self.dom_node.getElementsByTagName(refname)
182         for r in reflist:
183             uuids.append(self.xml_get_ref(r))
184         return uuids
185
186     def xmllookup_by_uuid(self, dom_node, uuid):
187         for n in dom_node.childNodes:
188             if n.nodeType == n.ELEMENT_NODE:
189                 if self.xml_get_uuid(n) == uuid:
190                     return n
191                 else:
192                     n = self.xmllookup_by_uuid(n, uuid)
193                     if n: return n
194         return None
195
196     def _lookup_by_uuid(self, uuid):
197         dom = self. xmllookup_by_uuid(self.root_node, uuid)
198         if dom:
199             return LustreDB_XML(dom, self.root_node)
200
201     def xmllookup_by_name(self, dom_node, name):
202         for n in dom_node.childNodes:
203             if n.nodeType == n.ELEMENT_NODE:
204                 if self.xml_get_name(n) == name:
205                     return n
206                 else:
207                     n = self.xmllookup_by_name(n, name)
208                     if n: return n
209         return None
210
211     def _lookup_by_name(self, name, class_name):
212         dom = self.xmllookup_by_name(self.root_node, name)
213         if dom:
214             return LustreDB_XML(dom, self.root_node)
215
216     def xmllookup_by_class(self, dom_node, class_name):
217         return dom_node.getElementsByTagName(class_name)
218
219     def _lookup_by_class(self, class_name):
220         ret = []
221         domlist = self.xmllookup_by_class(self.root_node, class_name)
222         for node in domlist:
223             ret.append(LustreDB_XML(node, self.root_node))
224         return ret
225
226     def xml_get_name(self, n):
227         return n.getAttribute('name')
228         
229     def getName(self):
230         return self.xml_get_name(self.dom_node)
231
232     def xml_get_ref(self, n):
233         return n.getAttribute('uuidref')
234
235     def xml_get_uuid(self, dom_node):
236         return dom_node.getAttribute('uuid')
237
238     def getUUID(self):
239         return self.xml_get_uuid(self.dom_node)
240
241     # Convert routes from the router to a route that will be used
242     # on the local system.  The network type and gw are changed to the
243     # interface on the router the local system will connect to.
244     def get_local_routes(self, type, gw):
245         """ Return the routes as a list of tuples of the form:
246         [(type, gw, lo, hi),]"""
247         res = []
248         tbl = self.dom_node.getElementsByTagName('routetbl')
249         for t in tbl:
250             routes = t.getElementsByTagName('route')
251             for r in routes:
252                 net_type = self.xmlattr(r, 'type')
253                 if type != net_type:
254                     lo = self.xmlattr(r, 'lo')
255                     hi = self.xmlattr(r, 'hi')
256                     tgt_cluster_id = self.xmlattr(r, 'tgtclusterid')
257                     res.append((type, gw, tgt_cluster_id, lo, hi))
258         return res
259
260     def get_route_tbl(self):
261         ret = []
262         for r in self.dom_node.getElementsByTagName('route'):
263             net_type = self.xmlattr(r, 'type')
264             gw = self.xmlattr(r, 'gw')
265             gw_cluster_id = self.xmlattr(r, 'gwclusterid')
266             tgt_cluster_id = self.xmlattr(r, 'tgtclusterid')
267             lo = self.xmlattr(r, 'lo')
268             hi = self.xmlattr(r, 'hi')
269             ret.append((net_type, gw, gw_cluster_id, tgt_cluster_id, lo, hi))
270         return ret
271
272     def _update_active(self, tgt, new):
273         raise Lustre.LconfError("updates not implemented for XML")
274
275 # ================================================================    
276 # LDAP Support
277 class LustreDB_LDAP(LustreDB):
278     def __init__(self, name, attrs,
279                  base = "fs=lustre",
280                  parent = None,
281                  url  = "ldap://localhost",
282                  user = "cn=Manager, fs=lustre",
283                  pw   = ""
284                  ):
285         self._name = name
286         self._attrs = attrs
287         self._base = base
288         self._parent = parent
289         self._url  = url
290         self._user = user
291         self._pw   = pw
292         if parent:
293             self.l = parent.l
294             self._base = parent._base
295         else:
296             self.open()
297
298     def open(self):
299         import ldap
300         try:
301             self.l = ldap.initialize(self._url)
302             # Set LDAP protocol version used
303             self.l.protocol_version=ldap.VERSION3
304             # user and pw only needed if modifying db
305             self.l.bind_s(self._user, self._pw, ldap.AUTH_SIMPLE);
306         except ldap.LDAPError, e:
307             raise Lustre.LconfError('Unable to connect to ldap server:' + self._url)
308
309         try:
310             self._name, self._attrs = self.l.search_s(self._base,
311                                                       ldap.SCOPE_BASE)[0]
312         except ldap.LDAPError, e:
313             raise Lustre.LconfError("no config found in ldap: %s"
314                                       % (self._base,))
315     def close(self):
316         self.l.unbind_s()
317
318     def ldap_search(self, filter):
319         """Return list of uuids matching the filter."""
320         import ldap
321         dn = self._base
322         ret = []
323         uuids = []
324         try:
325             for name, attrs in self.l.search_s(dn, ldap.SCOPE_ONELEVEL,
326                                         filter, ["uuid"]):
327                 for v in attrs['uuid']:
328                     uuids.append(v)
329         except ldap.NO_SUCH_OBJECT, e:
330             pass
331         except ldap.LDAPError, e:
332             print e                     # FIXME: die here?
333         if len(uuids) > 0:
334             for uuid in uuids:
335                 ret.append(self._lookup_by_uuid(uuid))
336         return ret
337
338     def _lookup_by_name(self, name, class_name):
339         list =  self.ldap_search("lustreName=%s" %(name))
340         if len(list) == 1:
341             return list[0]
342         return None
343
344     def _lookup_by_class(self, class_name):
345         return self.ldap_search("objectclass=%s" %(string.upper(class_name)))
346
347     def _lookup_by_uuid(self, uuid):
348         import ldap
349         dn = "uuid=%s,%s" % (uuid, self._base)
350         ret = None
351         try:
352             for name, attrs in self.l.search_s(dn, ldap.SCOPE_BASE,
353                                                "objectclass=*"):
354                 ret = LustreDB_LDAP(name, attrs,  parent = self)
355                         
356         except ldap.NO_SUCH_OBJECT, e:
357             pass                        # just return empty list
358         except ldap.LDAPError, e:
359             print e                     # FIXME: die here?
360         return ret
361
362
363     def _get_val(self, k):
364         ret = None
365         if self._attrs.has_key(k):
366             v = self._attrs[k]
367             if type(v) == types.ListType:
368                 ret = str(v[0])
369             else:
370                 ret = str(v)
371         return ret
372
373     def _get_class(self):
374         return string.lower(self._attrs['objectClass'][0])
375
376     def get_ref_type(self, ref_tag):
377         return ref_tag[:-3]
378
379     #
380     # [(ref_class, ref_uuid),]
381     def _get_all_refs(self):
382         list = []
383         for k in self._attrs.keys():
384             if re.search('.*Ref', k):
385                 for uuid in self._attrs[k]:
386                     ref_class = self.get_ref_type(k)
387                     list.append((ref_class, uuid))
388         return list
389
390     def _get_refs(self, tag):
391         """ Get all the refs of type TAG.  Returns list of uuids. """
392         uuids = []
393         refname = '%sRef' % tag
394         if self._attrs.has_key(refname):
395             return self._attrs[refname]
396         return []
397
398     def getName(self):
399         return self._get_val('lustreName')
400
401     def getUUID(self):
402         return self._get_val('uuid')
403
404     def get_route_tbl(self):
405         return []
406
407     def _update_active(self, tgtuuid, newuuid):
408         """Return list of uuids matching the filter."""
409         import ldap
410         dn = "uuid=%s,%s" %(tgtuuid, self._base)
411         ret = []
412         uuids = []
413         try:
414             self.l.modify_s(dn, [(ldap.MOD_REPLACE, "activeRef", newuuid)])
415         except ldap.NO_SUCH_OBJECT, e:
416             print e
417         except ldap.LDAPError, e:
418             print e                     # FIXME: die here?
419         return