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