2 # Copyright (C) 2002 Cluster File Systems, Inc.
3 # Author: Robert Read <rread@clusterfs.com>
5 # This file is part of Lustre, http://www.lustre.org.
7 # Lustre is free software; you can redistribute it and/or
8 # modify it under the terms of version 2 of the GNU General Public
9 # License as published by the Free Software Foundation.
11 # Lustre is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
16 # You should have received a copy of the GNU General Public License
17 # along with Lustre; if not, write to the Free Software
18 # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 lmc - lustre configurtion data manager
24 See lustre book for documentation for lmc.
28 import sys, os, getopt, string, exceptions
29 import xml.dom.minidom
30 from xml.dom.ext import PrettyPrint
35 print """usage: lmc --add object [object parameters]
37 Object creation command summary:
42 --recovery_upcall path
47 --nettype tcp|elan|toe|gm
75 --add mtpt - Mountpoint
79 --obd obd_name OR --lov lovname
84 msg = string.join(map(str,args))
85 raise OptionError("Error: " + msg)
94 msg = string.join(map(str,args))
95 print "Warning: ", msg
98 # manage names and uuids
99 # need to initialize this by walking tree to ensure
100 # no duplicate names or uuids are created.
101 # this are just place holders for now.
102 # consider changing this to be like OBD-dev-host
106 while names.has_key(ret):
107 ret = "%s_%d" % (base, ctr)
113 return "%s_UUID" % (name)
116 ldlm_uuid = 'ldlm_UUID'
118 """Create a new empty lustre document"""
119 # adding ldlm here is a bit of a hack, but one is enough.
121 <ldlm name="%s" uuid="%s"/>
122 </lustre>""" % (ldlm_name, ldlm_uuid)
123 return dom.parseString(str)
129 """initialize auto-name generation tables"""
131 # get all elements that contain a name attribute
132 for n in doc.childNodes:
133 if n.nodeType == n.ELEMENT_NODE:
135 names[getName(n)] = 1
136 uuids[getUUID(n)] = 1
139 def get_format_flag(options):
140 if options.has_key('format'):
141 if options['format']:
145 ############################################################
146 # Build config objects using DOM
151 def __init__(self, doc):
154 def ref(self, type, uuid):
155 """ generate <[type]_ref uuidref="[uuid]"/> """
156 tag = "%s_ref" % (type)
157 ref = self.doc.createElement(tag)
158 ref.setAttribute("uuidref", uuid)
161 def newService(self, tag, name, uuid):
162 """ create a new service elmement, which requires name and uuid attributes """
163 new = self.doc.createElement(tag)
164 new.setAttribute("uuid", uuid);
165 new.setAttribute("name", name);
168 def addText(self, node, str):
169 txt = self.doc.createTextNode(str)
170 node.appendChild(txt)
172 def addElement(self, node, tag, str=None):
173 """ create a new element and add it as a child to node. If str is passed,
174 a text node is created for the new element"""
175 new = self.doc.createElement(tag)
177 self.addText(new, str)
178 node.appendChild(new)
181 def network(self, name, uuid, hostname, net, port=0, tcpbuf=0):
182 """create <network> node"""
183 network = self.newService("network", name, uuid)
184 network.setAttribute("nettype", net);
185 self.addElement(network, "nid", hostname)
187 self.addElement(network, "port", "%d" %(port))
189 self.addElement(network, "sendmem", "%d" %(tcpbuf))
190 self.addElement(network, "recvmem", "%d" %(tcpbuf))
194 def route(self, net_type, gw, lo, hi):
195 """ create one entry for the route table """
196 ref = self.doc.createElement('route')
197 ref.setAttribute("type", net_type)
198 ref.setAttribute("gw", gw)
199 ref.setAttribute("lo", lo)
201 ref.setAttribute("hi", hi)
204 def profile(self, name, uuid):
205 """ create a host """
206 profile = self.newService("profile", name, uuid)
209 def node(self, name, uuid, prof_uuid):
210 """ create a host """
211 node = self.newService("node", name, uuid)
212 node.appendChild(self.ref("profile", prof_uuid))
215 def ldlm(self, name, uuid):
216 """ create a ldlm """
217 ldlm = self.newService("ldlm", name, uuid)
220 def obd(self, name, uuid, fs, obdtype, devname, format, ost_uuid, dev_size=0):
221 obd = self.newService("obd", name, uuid)
222 obd.setAttribute('obdtype', obdtype)
223 obd.appendChild(self.ref("active", ost_uuid))
225 self.addElement(obd, "fstype", fs)
227 dev = self.addElement(obd, "devpath", devname)
228 self.addElement(obd, "autoformat", format)
230 self.addElement(obd, "devsize", "%s" % (dev_size))
233 def cobd(self, name, uuid, real_uuid, cache_uuid):
234 cobd = self.newService("cobd", name, uuid)
235 cobd.appendChild(self.ref("realobd",real_uuid))
236 cobd.appendChild(self.ref("cacheobd",cache_uuid))
239 def ost(self, name, uuid, obd_uuid, net_uuid):
240 ost = self.newService("ost", name, uuid)
241 ost.appendChild(self.ref("network", net_uuid))
242 ost.appendChild(self.ref("obd", obd_uuid))
245 def lov(self, name, uuid, mds_uuid, stripe_sz, stripe_cnt, pattern):
246 lov = self.newService("lov", name, uuid)
247 lov.appendChild(self.ref("mds", mds_uuid))
248 lov.setAttribute("stripesize", stripe_sz)
249 lov.setAttribute("stripecount", stripe_cnt)
250 lov.setAttribute("stripepattern", pattern)
253 def lovconfig(self, name, uuid, lov_uuid):
254 lovconfig = self.newService("lovconfig", name, uuid)
255 lovconfig.appendChild(self.ref("lov", lov_uuid))
258 def mds(self, name, uuid, mdd_uuid):
259 mds = self.newService("mds", name, uuid)
260 mds.appendChild(self.ref("active",mdd_uuid))
263 def mdsdev(self, name, uuid, fs, devname, format, net_uuid, node_uuid,
264 mds_uuid, dev_size=0 ):
265 mdd = self.newService("mdsdev", name, uuid)
266 self.addElement(mdd, "fstype", fs)
267 dev = self.addElement(mdd, "devpath", devname)
268 self.addElement(mdd, "autoformat", format)
270 self.addElement(mdd, "devsize", "%s" % (dev_size))
271 mdd.appendChild(self.ref("network", net_uuid))
272 mdd.appendChild(self.ref("mds", mds_uuid))
275 def mountpoint(self, name, uuid, mds_uuid, osc_uuid, path):
276 mtpt = self.newService("mountpoint", name, uuid)
277 mtpt.appendChild(self.ref("mds", mds_uuid))
278 mtpt.appendChild(self.ref("obd", osc_uuid))
279 self.addElement(mtpt, "path", path)
282 def echo_client(self, name, uuid, osc_uuid):
283 ec = self.newService("echoclient", name, uuid)
284 ec.appendChild(self.ref("obd", osc_uuid))
287 ############################################################
288 # Utilities to query a DOM tree
289 # Using this functions we can treat use config information
290 # directly as a database.
292 return n.getAttribute('name')
295 return node.getAttribute('uuid')
298 def findByName(lustre, name, tag = ""):
299 for n in lustre.childNodes:
300 if n.nodeType == n.ELEMENT_NODE:
301 if tag and n.nodeName != tag:
303 if getName(n) == name:
306 n = findByName(n, name)
311 def lookup(node, uuid):
312 for n in node.childNodes:
313 if n.nodeType == n.ELEMENT_NODE:
314 if getUUID(n) == uuid:
322 def name2uuid(lustre, name, tag="", fatal=1):
323 ret = findByName(lustre, name, tag)
326 error('name2uuid:', '"'+name+'"', tag, 'element not found.')
332 # XXX: assumes only one network element per node. will fix this
333 # as soon as support for routers is added
334 def get_net_uuid(lustre, node_name):
335 """ get a network uuid for a node_name """
336 node = findByName(lustre, node_name, "node")
338 error ('get_net_uuid:', '"'+node_name+'"', "node element not found.")
339 net = node.getElementsByTagName('network')
341 return getUUID(net[0])
345 def lov_add_obd(gen, lov, osc_uuid):
346 lov.appendChild(gen.ref("obd", osc_uuid))
348 def node_add_profile(gen, node, ref, uuid):
349 refname = "%s_ref" % "profile"
350 ret = node.getElementsByTagName(refname)
352 error('node has no profile ref:', node)
353 prof_uuid = ret[0].getAttribute('uuidref')
354 profile = lookup(node.parentNode, prof_uuid)
355 profile.appendChild(gen.ref(ref, uuid))
357 def get_attr(dom_node, attr, default=""):
358 v = dom_node.getAttribute(attr)
363 ############################################################
366 def do_add_node(gen, lustre, options, node_name):
367 uuid = new_uuid(node_name)
368 prof_name = new_name("PROFILE_" + node_name)
369 prof_uuid = new_uuid(prof_name)
370 profile = gen.profile(prof_name, prof_uuid)
371 node = gen.node(node_name, uuid, prof_uuid)
372 lustre.appendChild(node)
373 lustre.appendChild(profile)
375 node_add_profile(gen, node, 'ldlm', ldlm_uuid)
376 if has_option(options, 'router'):
377 node.setAttribute('router', '1')
378 if has_option(options, 'timeout'):
379 node.setAttribute('timeout', get_option(options, 'timeout'))
380 if has_option(options, 'recovery_upcall'):
381 node.setAttribute('recovery_upcall', get_option(options, 'recovery_upcall'))
385 def add_node(gen, lustre, options):
386 """ create a node with a network config """
388 node_name = get_option(options, 'node')
389 ret = findByName(lustre, node_name, "node")
391 print "Node:", node_name, "exists."
393 do_add_node(gen, lustre, options, node_name)
396 def add_net(gen, lustre, options):
397 """ create a node with a network config """
399 node_name = get_option(options, 'node')
400 nid = get_option(options, 'nid')
401 net_type = get_option(options, 'nettype')
403 if net_type == 'tcp':
404 port = get_option_int(options, 'port', DEFAULT_PORT)
405 tcpbuf = get_option_int(options, 'tcpbuf', 0)
406 elif net_type in ('elan', 'gm'):
410 print "Unknown net_type: ", net_type
413 ret = findByName(lustre, node_name, "node")
415 node = do_add_node(gen, lustre, options, node_name)
418 net_name = new_name('NET_'+ node_name +'_'+ net_type)
419 net_uuid = new_uuid(net_name)
420 node.appendChild(gen.network(net_name, net_uuid, nid, net_type, port, tcpbuf))
421 node_add_profile(gen, node, "network", net_uuid)
424 def add_route(gen, lustre, options):
425 """ create a node with a network config """
427 node_name = get_option(options, 'node')
428 net_type = get_option(options, 'nettype')
429 gw = get_option(options, 'gw')
430 lo = get_option(options, 'lo')
431 hi = get_option(options, 'hi', '')
433 node = findByName(lustre, node_name, "node")
435 error (node_name, " not found.")
437 netlist = node.getElementsByTagName('network')
439 rlist = net.getElementsByTagName('routetbl')
443 rtbl = gen.addElement(net, 'routetbl')
444 rtbl.appendChild(gen.route(net_type, gw, lo, hi))
447 def add_mds(gen, lustre, options):
448 node_name = get_option(options, 'node')
449 mds_name = get_option(options, 'mds')
450 mdd_name = new_name("MDD_" + mds_name +"_" + node_name)
451 mdd_uuid = new_uuid(mdd_name)
453 mds_uuid = name2uuid(lustre, mds_name, fatal=0)
455 mds_uuid = new_uuid(mds_name)
456 mds = gen.mds(mds_name, mds_uuid, mdd_uuid)
457 lustre.appendChild(mds)
459 devname = get_option(options, 'dev')
460 size = get_option(options, 'size', 0)
461 fstype = get_option(options, 'fstype', 'extN')
463 node_uuid = name2uuid(lustre, node_name, 'node')
465 node = findByName(lustre, node_name, "node")
466 node_add_profile(gen, node, "mdsdev", mdd_uuid)
467 net_uuid = get_net_uuid(lustre, node_name)
469 error("NODE: ", node_name, "not found")
471 mdd = gen.mdsdev(mdd_name, mdd_uuid, fstype, devname, get_format_flag(options),
472 net_uuid, node_uuid, mds_uuid, dev_size=size)
473 lustre.appendChild(mdd)
476 def add_ost(gen, lustre, options):
477 node_name = get_option(options, 'node')
478 lovname = get_option(options, 'lov', '')
479 obdtype = get_option(options, 'obdtype', 'obdfilter')
481 if obdtype == 'obdecho':
487 devname = get_option(options, 'dev', '') # can be unset for bluearcs
488 size = get_option(options, 'size', 0)
489 fstype = get_option(options, 'fstype', 'extN')
491 obdname = get_option(options, 'obd', 'OBD_'+ node_name)
492 obdname = new_name(obdname)
493 ostname = new_name('OST_'+ obdname)
494 if options.has_key('obduuid'):
495 obd_uuid = options['obduuid']
496 obd = lookup(lustre, obd_uuid)
498 error("Duplicate OBD UUID:", obd_uuid)
500 obd_uuid = new_uuid(obdname)
501 ost_uuid = new_uuid(ostname)
503 net_uuid = get_net_uuid(lustre, node_name)
505 error("NODE: ", node_name, "not found")
507 obd = gen.obd(obdname, obd_uuid, fstype, obdtype, devname, get_format_flag(options), ost_uuid,
509 ost = gen.ost(ostname, ost_uuid, obd_uuid, net_uuid)
512 lov = findByName(lustre, lovname, "lov")
514 error('add_ost:', '"'+lovname+'"', "lov element not found.")
515 lov_add_obd(gen, lov, obd_uuid)
517 node = findByName(lustre, node_name, "node")
518 node_add_profile(gen, node, 'obd', obd_uuid)
519 node_add_profile(gen, node, 'ost', ost_uuid)
521 lustre.appendChild(obd)
522 lustre.appendChild(ost)
525 def add_cobd(gen, lustre, options):
526 node_name = get_option(options, 'node')
527 name = new_name('COBD_' + node_name)
528 uuid = new_uuid(name)
530 real_name = get_option(options, 'real_obd')
531 cache_name = get_option(options, 'cache_obd')
533 real_uuid = name2uuid(lustre, real_name, tag='obd')
534 cache_uuid = name2uuid(lustre, cache_name, tag='obd')
536 node = findByName(lustre, node_name, "node")
537 node_add_profile(gen, node, "cobd", uuid)
538 cobd = gen.cobd(name, uuid, real_uuid, cache_uuid)
539 lustre.appendChild(cobd)
542 def add_echo_client(gen, lustre, options):
543 """ add an echo client to the profile for this node. """
544 node_name = get_option(options, 'node')
545 lov_name = get_option(options, 'obd')
547 node = findByName(lustre, node_name, 'node')
549 echoname = new_name('ECHO_'+ node_name)
550 echo_uuid = new_uuid(echoname)
551 node_add_profile(gen, node, 'echoclient', echo_uuid)
553 lov_uuid = name2uuid(lustre, lov_name, tag='lov', fatal=0)
555 lov_uuid = name2uuid(lustre, lov_name, tag='obd', fatal=1)
557 echo = gen.echo_client(echoname, echo_uuid, lov_uuid)
558 lustre.appendChild(echo)
561 def add_lov(gen, lustre, options):
564 lov_orig = get_option(options, 'lov')
565 name = new_name(lov_orig)
567 warning("name:", lov_orig, "already used. using:", name)
569 mds_name = get_option(options, 'mds')
570 stripe_sz = get_option(options, 'stripe_sz')
571 stripe_cnt = get_option(options, 'stripe_cnt', 0)
572 pattern = get_option(options, 'stripe_pattern', 0)
573 uuid = new_uuid(name)
575 ret = findByName(lustre, name, "lov")
577 error("LOV: ", name, " already exists.")
579 mds_uuid = name2uuid(lustre, mds_name, 'mds')
580 lov = gen.lov(name, uuid, mds_uuid, stripe_sz, stripe_cnt, pattern)
581 lustre.appendChild(lov)
583 # add an lovconfig entry to the active mdsdev profile
584 lovconfig_name = new_name('LVCFG_' + name)
585 lovconfig_uuid = new_uuid(lovconfig_name)
586 mds = findByName(lustre, mds_name)
587 mds.appendChild(gen.ref("lovconfig", lovconfig_uuid))
588 lovconfig = gen.lovconfig(lovconfig_name, lovconfig_uuid, uuid)
589 lustre.appendChild(lovconfig)
592 def add_mtpt(gen, lustre, options):
593 """ create mtpt on a node """
594 node_name = get_option(options, 'node')
596 path = get_option(options, 'path')
597 mds_name = get_option(options, 'mds')
598 lov_name = get_option(options, 'lov', '')
600 lov_name = get_option(options, 'obd', '')
602 error("--add mtpt requires either --lov lov_name or --obd obd_name")
604 name = new_name('MNT_'+ node_name)
606 ret = findByName(lustre, name, "mountpoint")
608 error("MOUNTPOINT: ", name, " already exists.")
610 mds_uuid = name2uuid(lustre, mds_name, tag='mds')
611 lov_uuid = name2uuid(lustre, lov_name, tag='lov', fatal=0)
613 lov_uuid = name2uuid(lustre, lov_name, tag='obd', fatal=1)
615 uuid = new_uuid(name)
616 mtpt = gen.mountpoint(name, uuid, mds_uuid, lov_uuid, path)
617 node = findByName(lustre, node_name, "node")
619 error('node:', node_name, "not found.")
620 node_add_profile(gen, node, "mountpoint", uuid)
621 lustre.appendChild(mtpt)
623 def add_oscref(gen, lustre, options):
624 """ create mtpt on a node """
625 node_name = get_option(options, 'node')
626 osc_name = get_option(options, 'osc')
628 osc_uuid = name2uuid(lustre, osc_name, tag='osc')
629 node = findByName(lustre, node_name, "node")
631 error('node:', node_name, "not found")
632 node_add_profile(gen, node, "osc",osc_uuid)
634 ############################################################
635 # Command line processing
637 class OptionError (exceptions.Exception):
638 def __init__(self, args):
641 def has_option(options, tag):
642 """Look for tag in options hash and return the true if set"""
643 if options.has_key(tag):
647 def get_option(options, tag, default = None):
648 """Look for tag in options hash and return the value if set. If not
649 set, then if return default it is set, otherwise exception."""
650 if options.has_key(tag):
652 elif default != None:
655 raise OptionError("--add %s requires --%s value" % (options['add'], tag))
656 # this exception should print an error like '--add blah requires --<tag> value'
658 def get_option_int(options, tag, default = None):
659 """Return an integer option. Raise exception if the value is not an int"""
660 val = get_option(options, tag, default)
663 def parse_cmdline(argv):
664 short_opts = "ho:i:m:"
665 long_opts = ["add=", "node=", "nettype=", "nid=", "tcpbuf=", "port=",
666 "echo_client=", "stripe_sz=", "stripe_cnt=", "stripe_pattern=",
667 "mds=", "route", "router", "merge=", "format", "reformat", "output=",
668 "dev=", "size=", "obd=", "obdtype=", "obduuid=", "in=",
669 "path=", "help", "batch=", "lov=", "gw=", "lo=", "hi=",
670 "oscref", "osc=", "real_obd=", "cache_obd=", "fstype=",
671 "timeout=", "recovery_upcall="]
676 opts, args = getopt.getopt(argv, short_opts, long_opts)
677 except getopt.error, e:
678 panic(string.join(sys.argv), e)
681 # Commands to create new devices
698 options['timeout'] = a
699 if o == "--recovery_upcall":
700 options['recovery_upcall'] = a
702 options['router'] = 1
708 options['nettype'] = a
712 options['tcpbuf'] = a
730 options['obdtype'] = a
732 options['fstype'] = a
734 options['obduuid'] = a
737 if o == "--stripe_sz":
738 options['stripe_sz'] = a
739 if o == "--stripe_cnt":
740 options['stripe_cnt'] = a
741 if o == "--stripe_pattern":
742 options['stripe_pattern'] = a
751 if o == "--cache_obd":
752 options['cache_obd'] = a
753 if o == "--real_obd":
754 options['real_obd'] = a
757 if o in ("-h", "--help"):
759 if o in ("-o", "--output"):
760 options['output'] = a
761 if o in ("-m", "--merge"):
764 options['format'] = 1
765 if o == "--reformat":
766 options['reformat'] = 1
769 if o in ("--in" , "-i"):
775 # simple class for profiling
782 self._start = time.time()
783 def stop(self, msg=''):
784 self._stop = time.time()
788 return self._stop - self._start
789 def display(self, msg):
791 str = '%s: %g secs' % (msg, d)
796 ############################################################
800 def add(devtype, gen, lustre, options):
802 add_net(gen, lustre, options)
803 elif devtype =='osc':
804 add_osc(gen, lustre, options)
805 elif devtype == 'mtpt':
806 add_mtpt(gen, lustre, options)
807 elif devtype == 'mds':
808 add_mds(gen, lustre, options)
809 elif devtype == 'ost':
810 add_ost(gen, lustre, options)
811 elif devtype == 'lov':
812 add_lov(gen, lustre, options)
813 elif devtype == 'route':
814 add_route(gen, lustre, options)
815 elif devtype == 'node':
816 add_node(gen, lustre, options)
817 elif devtype == 'echo_client':
818 add_echo_client(gen, lustre, options)
819 elif devtype == 'oscref':
820 add_oscref(gen, lustre, options)
821 elif devtype == 'cobd':
822 add_cobd(gen, lustre, options)
824 error("unknown device type:", devtype)
826 def do_command(gen, lustre, options, args):
827 if options.has_key('add'):
828 add(options['add'], gen, lustre, options)
830 error("Missing command")
833 options, args = parse_cmdline(sys.argv[1:])
836 if options.has_key('merge'):
837 outFile = options['merge']
838 if os.access(outFile, os.R_OK):
839 doc = xml.dom.minidom.parse(outFile)
841 doc = new_lustre(xml.dom.minidom)
842 elif options.has_key('in'):
843 doc = xml.dom.minidom.parse(options['in'])
845 doc = new_lustre(xml.dom.minidom)
847 if options.has_key('output'):
848 outFile = options['output']
850 lustre = doc.documentElement
852 if lustre.tagName != "lustre":
853 print "Existing config not valid."
858 if options.has_key('batch'):
859 fp = open(options['batch'])
860 batchCommands = fp.readlines()
862 for cmd in batchCommands:
863 options, args = parse_cmdline(string.split(cmd))
865 do_command(gen, lustre, options, args)
866 except OptionError, e:
870 do_command(gen, lustre, options, args)
871 except OptionError, e:
872 panic(string.join(sys.argv),e)
877 PrettyPrint(doc, open(outFile,"w"))
879 if __name__ == "__main__":