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