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 configuration data manager
24 See Lustre book (http://www.lustre.org/docs/lustre.pdf) for documentation on lmc.
28 import sys, os, getopt, string, exceptions, re
29 import xml.dom.minidom
31 def printDoc(doc, stream=sys.stdout):
33 from xml.dom.ext import PrettyPrint
34 PrettyPrint(doc, stream)
36 stream.write(doc.toxml())
40 PYMOD_DIR = "/usr/lib/lustre/python"
42 def development_mode():
43 base = os.path.dirname(sys.argv[0])
44 if os.access(base+"/Makefile.am", os.R_OK):
48 if not development_mode():
49 sys.path.append(PYMOD_DIR)
54 DEFAULT_STRIPE_SZ = 65536
55 DEFAULT_STRIPE_CNT = 1
56 DEFAULT_STRIPE_PATTERN = 0
60 print """usage: lmc --add object [object parameters]
62 Object creation command summary:
70 --ptldebug debug_level
71 --subsystem subsystem_name
77 --nettype tcp|elan|gm|scimac
113 --obdtype obdecho|obdfilter
116 --add mtpt - Mountpoint
121 --ost ost_name OR --lov lov_name
133 --add mgmt - Management/monitoring service
135 --mgmt mgmt_service_name
142 PARAM = Lustre.Options.PARAM
144 # lmc input/output options
145 ('reference', "Print short reference for commands."),
146 ('verbose,v', "Print system commands as they are run."),
147 ('merge,m', "Append to the specified config file.", PARAM),
148 ('output,o', "Write XML configuration into given output file. Overwrite existing content.", PARAM),
149 ('input,i', "", PARAM),
150 ('batch', "Used to execute lmc commands in batch mode.", PARAM),
156 ('node', "Add a new node in the cluster configuration.", PARAM),
157 ('timeout', "Set timeout to initiate recovery.", PARAM),
158 ('upcall', "Set both lustre and portals upcall scripts.", PARAM),
159 ('lustre_upcall', "Set location of lustre upcall script.", PARAM),
160 ('portals_upcall', "Set location of portals upcall script.", PARAM),
161 ('ptldebug', "Set the portals debug level", PARAM),
162 ('subsystem', "Specify which Lustre subsystems have debug output recorded in the log", PARAM),
165 ('nettype', "Specify the network type. This can be tcp/elan/gm/scimac.", PARAM),
166 ('nid', "Give the network ID, e.g ElanID/IP Address as used by portals.", PARAM),
167 ('tcpbuf', "Optional argument to specify the TCP buffer size.", PARAM, "0"),
168 ('port', "Optional argument to specify the TCP port number.", PARAM, DEFAULT_PORT),
169 ('irq_affinity', "Optional argument.", PARAM, 0),
170 ('hostaddr', "", PARAM,""),
171 ('cluster_id', "Specify the cluster ID", PARAM, "0"),
174 ('route', "Add a new route for the cluster.", PARAM),
175 ('router', "Optional flag to mark a node as router."),
176 ('gw', "Specify the nid of the gateway for a route.", PARAM),
177 ('gateway_cluster_id', "", PARAM, "0"),
178 ('target_cluster_id', "", PARAM, "0"),
179 ('lo', "For a range route, this is the low value nid.", PARAM),
180 ('hi', "For a range route, this is a hi value nid.", PARAM,""),
182 # servers: mds and ost
183 ('mds', "Specify MDS name.", PARAM,""),
184 ('ost', "Specify the OST name.", PARAM,""),
185 ('osdtype', "This could obdfilter or obdecho.", PARAM, "obdfilter"),
186 ('failover', "Enable failover support on OSTs or MDS?"),
187 ('group', "", PARAM),
188 ('dev', "Path of the device on local system.", PARAM,""),
189 ('size', "Specify the size of the device if needed.", PARAM,"0"),
190 ('journal_size', "Specify new journal size for underlying ext3 file system.", PARAM,"0"),
191 ('inode_size', "Specify new inode size for underlying ext3 file system.", PARAM,"0"),
192 ('fstype', "Optional argument to specify the filesystem type.", PARAM, "ext3"),
193 ('mkfsoptions', "Optional argument to mkfs.", PARAM, ""),
194 ('ostuuid', "", PARAM,""),
195 ('nspath', "Local mount point of server namespace.", PARAM,""),
198 # clients: mountpoint and echo
199 ('echo_client', "", PARAM),
200 ('path', "Specify the mountpoint for Lustre.", PARAM),
201 ('filesystem', "Lustre filesystem name", PARAM,""),
204 ('lov', "Specify LOV name.", PARAM,""),
205 ('stripe_sz', "Specify the stripe size in bytes.", PARAM),
206 ('stripe_cnt', "Specify the number of OSTs each file should be striped on.", PARAM, 0),
207 ('stripe_pattern', "Specify the stripe pattern. RAID 0 is the only one currently supported.", PARAM, 0),
210 ('real_obd', "", PARAM),
211 ('cache_obd', "", PARAM),
213 ('mgmt', "Specify management/monitoring service name.", PARAM, ""),
216 ('lmv', "Specify LMV name.", PARAM,""),
217 ('master', "Specify master MDS in LMV"),
221 msg = string.join(map(str,args))
222 raise OptionError("Error: " + msg)
231 msg = string.join(map(str,args))
232 print "Warning: ", msg
235 # manage names and uuids
236 # need to initialize this by walking tree to ensure
237 # no duplicate names or uuids are created.
238 # this are just place holders for now.
239 # consider changing this to be like OBD-dev-host
243 while names.has_key(ret):
244 ret = "%s_%d" % (base, ctr)
251 ret = "%s_UUID" % (name)
252 if len(ret) > UUID_MAX_LENGTH:
253 ret = ret[-UUID_MAX_LENGTH:]
254 while uuids.has_key(ret):
255 ret = "%s_UUID_%d" % (name, ctr)
257 if len(ret) > UUID_MAX_LENGTH:
258 ret = ret[-UUID_MAX_LENGTH:]
264 ldlm_uuid = 'ldlm_UUID'
267 """Create a new empty lustre document"""
268 # adding ldlm here is a bit of a hack, but one is enough.
269 str = """<lustre version="%s">
270 <ldlm name="%s" uuid="%s"/>
271 </lustre>""" % (Lustre.CONFIG_VERSION, ldlm_name, ldlm_uuid)
272 return dom.parseString(str)
278 """initialize auto-name generation tables"""
280 # get all elements that contain a name attribute
281 for n in doc.childNodes:
282 if n.nodeType == n.ELEMENT_NODE:
284 names[getName(n)] = 1
285 uuids[getUUID(n)] = 1
288 def get_format_flag(options):
293 ############################################################
294 # Build config objects using DOM
299 def __init__(self, doc):
302 def ref(self, type, uuid):
303 """ generate <[type]_ref uuidref="[uuid]"/> """
304 tag = "%s_ref" % (type)
305 ref = self.doc.createElement(tag)
306 ref.setAttribute("uuidref", uuid)
309 def newService(self, tag, name, uuid):
310 """ create a new service elmement, which requires name and uuid attributes """
311 new = self.doc.createElement(tag)
312 new.setAttribute("uuid", uuid);
313 new.setAttribute("name", name);
316 def addText(self, node, str):
317 txt = self.doc.createTextNode(str)
318 node.appendChild(txt)
320 def addElement(self, node, tag, str=None):
321 """ create a new element and add it as a child to node. If str is passed,
322 a text node is created for the new element"""
323 new = self.doc.createElement(tag)
325 self.addText(new, str)
326 node.appendChild(new)
329 def network(self, name, uuid, nid, cluster_id, net, hostaddr="",
330 port=0, tcpbuf=0, irq_aff=0):
331 """create <network> node"""
332 network = self.newService("network", name, uuid)
333 network.setAttribute("nettype", net);
334 self.addElement(network, "nid", nid)
335 self.addElement(network, "clusterid", cluster_id)
337 self.addElement(network, "hostaddr", hostaddr)
339 self.addElement(network, "port", "%d" %(port))
341 self.addElement(network, "sendmem", "%d" %(tcpbuf))
342 self.addElement(network, "recvmem", "%d" %(tcpbuf))
344 self.addElement(network, "irqaffinity", "%d" %(irq_aff))
348 def routetbl(self, name, uuid):
349 """create <routetbl> node"""
350 rtbl = self.newService("routetbl", name, uuid)
353 def route(self, gw_net_type, gw, gw_cluster_id, tgt_cluster_id, lo, hi):
354 """ create one entry for the route table """
355 ref = self.doc.createElement('route')
356 ref.setAttribute("type", gw_net_type)
357 ref.setAttribute("gw", gw)
358 ref.setAttribute("gwclusterid", gw_cluster_id)
359 ref.setAttribute("tgtclusterid", tgt_cluster_id)
360 ref.setAttribute("lo", lo)
362 ref.setAttribute("hi", hi)
365 def profile(self, name, uuid):
366 """ create a host """
367 profile = self.newService("profile", name, uuid)
370 def node(self, name, uuid, prof_uuid):
371 """ create a host """
372 node = self.newService("node", name, uuid)
373 node.appendChild(self.ref("profile", prof_uuid))
376 def ldlm(self, name, uuid):
377 """ create a ldlm """
378 ldlm = self.newService("ldlm", name, uuid)
381 def osd(self, name, uuid, fs, osdtype, devname, format, ost_uuid,
382 node_uuid, dev_size=0, journal_size=0, inode_size=0, nspath="", mkfsoptions=""):
383 osd = self.newService("osd", name, uuid)
384 osd.setAttribute('osdtype', osdtype)
385 osd.appendChild(self.ref("target", ost_uuid))
386 osd.appendChild(self.ref("node", node_uuid))
388 self.addElement(osd, "fstype", fs)
390 dev = self.addElement(osd, "devpath", devname)
391 self.addElement(osd, "autoformat", format)
393 self.addElement(osd, "devsize", "%s" % (dev_size))
395 self.addElement(osd, "journalsize", "%s" % (journal_size))
397 self.addElement(osd, "inodesize", "%s" % (inode_size))
399 self.addElement(osd, "mkfsoptions", mkfsoptions)
401 self.addElement(osd, "nspath", nspath)
404 def cobd(self, name, uuid, real_uuid, cache_uuid):
405 cobd = self.newService("cobd", name, uuid)
406 cobd.appendChild(self.ref("realobd",real_uuid))
407 cobd.appendChild(self.ref("cacheobd",cache_uuid))
410 def ost(self, name, uuid, osd_uuid, group=""):
411 ost = self.newService("ost", name, uuid)
412 ost.appendChild(self.ref("active", osd_uuid))
414 self.addElement(ost, "group", group)
417 def oss(self, name, uuid):
418 oss = self.newService("oss", name, uuid)
421 def lov(self, name, uuid, mds_uuid, stripe_sz, stripe_cnt, pattern):
422 lov = self.newService("lov", name, uuid)
423 lov.appendChild(self.ref("mds", mds_uuid))
424 lov.setAttribute("stripesize", str(stripe_sz))
425 lov.setAttribute("stripecount", str(stripe_cnt))
426 lov.setAttribute("stripepattern", str(pattern))
429 def lovconfig(self, name, uuid, lov_uuid):
430 lovconfig = self.newService("lovconfig", name, uuid)
431 lovconfig.appendChild(self.ref("lov", lov_uuid))
434 def lmv(self, name, uuid):
435 lmv = self.newService("lmv", name, uuid)
438 def mds(self, name, uuid, mdd_uuid, group="", lmv=""):
439 mds = self.newService("mds", name, uuid)
440 mds.appendChild(self.ref("active",mdd_uuid))
442 self.addElement(mds, "group", group)
444 lmv.appendChild(self.ref("active", uuid))
447 def mdsdev(self, name, uuid, fs, devname, format, node_uuid,
448 mds_uuid, dev_size=0, journal_size=0, inode_size=256,
449 nspath="", mkfsoptions="", lmv_uuid=""):
450 mdd = self.newService("mdsdev", name, uuid)
451 self.addElement(mdd, "fstype", fs)
452 dev = self.addElement(mdd, "devpath", devname)
453 self.addElement(mdd, "autoformat", format)
455 self.addElement(mdd, "devsize", "%s" % (dev_size))
457 self.addElement(mdd, "journalsize", "%s" % (journal_size))
459 self.addElement(mdd, "inodesize", "%s" % (inode_size))
461 self.addElement(mdd, "nspath", nspath)
463 self.addElement(mdd, "mkfsoptions", mkfsoptions)
464 mdd.appendChild(self.ref("node", node_uuid))
465 mdd.appendChild(self.ref("target", mds_uuid))
467 mdd.appendChild(self.ref("lmv", lmv_uuid))
468 self.addElement(mdd, "lmv", lmv_uuid)
472 def mgmt(self, mgmt_name, mgmt_uuid, node_uuid):
473 mgmt = self.newService("mgmt", mgmt_name, mgmt_uuid)
474 mgmt.appendChild(self.ref("node", node_uuid))
475 # Placeholder until mgmt-service failover.
476 mgmt.appendChild(self.ref("active", mgmt_uuid))
479 def mountpoint(self, name, uuid, fs_uuid, path):
480 mtpt = self.newService("mountpoint", name, uuid)
481 mtpt.appendChild(self.ref("filesystem", fs_uuid))
482 self.addElement(mtpt, "path", path)
485 def filesystem(self, name, uuid, mds_uuid, obd_uuid, mgmt_uuid):
486 fs = self.newService("filesystem", name, uuid)
487 fs.appendChild(self.ref("mds", mds_uuid))
488 fs.appendChild(self.ref("obd", obd_uuid))
490 fs.appendChild(self.ref("mgmt", mgmt_uuid))
493 def echo_client(self, name, uuid, osc_uuid):
494 ec = self.newService("echoclient", name, uuid)
495 ec.appendChild(self.ref("obd", osc_uuid))
498 ############################################################
499 # Utilities to query a DOM tree
500 # Using this functions we can treat use config information
501 # directly as a database.
503 return n.getAttribute('name')
506 return node.getAttribute('uuid')
509 def findByName(lustre, name, tag = ""):
510 for n in lustre.childNodes:
511 if n.nodeType == n.ELEMENT_NODE:
512 if tag and n.nodeName != tag:
514 if getName(n) == name:
517 n = findByName(n, name)
522 def lookup(node, uuid):
523 for n in node.childNodes:
524 if n.nodeType == n.ELEMENT_NODE:
525 if getUUID(n) == uuid:
533 def name2uuid(lustre, name, tag="", fatal=1):
534 ret = findByName(lustre, name, tag)
537 error('name2uuid:', '"'+name+'"', tag, 'element not found.')
542 def lookup_filesystem(lustre, mds_uuid, ost_uuid):
543 for n in lustre.childNodes:
544 if n.nodeType == n.ELEMENT_NODE and n.nodeName == 'filesystem':
545 if ref_exists(n, mds_uuid) and ref_exists(n, ost_uuid):
549 # XXX: assumes only one network element per node. will fix this
550 # as soon as support for routers is added
551 def get_net_uuid(lustre, node_name):
552 """ get a network uuid for a node_name """
553 node = findByName(lustre, node_name, "node")
555 error ('get_net_uuid:', '"'+node_name+'"', "node element not found.")
556 net = node.getElementsByTagName('network')
558 return getUUID(net[0])
562 def lov_add_obd(gen, lov, osc_uuid):
563 lov.appendChild(gen.ref("obd", osc_uuid))
565 def ref_exists(profile, uuid):
566 elist = profile.childNodes
568 if e.nodeType == e.ELEMENT_NODE:
569 ref = e.getAttribute('uuidref')
574 # ensure that uuid is not already in the profile
575 # return true if uuid is added
576 def node_add_profile(gen, node, ref, uuid):
577 refname = "%s_ref" % "profile"
578 ret = node.getElementsByTagName(refname)
580 error('node has no profile ref:', node)
581 prof_uuid = ret[0].getAttribute('uuidref')
582 profile = lookup(node.parentNode, prof_uuid)
584 error("no profile found:", prof_uuid)
585 if ref_exists(profile, uuid):
587 profile.appendChild(gen.ref(ref, uuid))
590 def get_attr(dom_node, attr, default=""):
591 v = dom_node.getAttribute(attr)
596 ############################################################
599 def set_node_options(gen, node, options):
601 node.setAttribute('router', '1')
603 gen.addElement(node, "timeout", get_option(options, 'timeout'))
605 default_upcall = get_option(options, 'upcall')
608 if default_upcall or options.lustre_upcall:
609 if options.lustre_upcall:
610 gen.addElement(node, 'lustreUpcall', options.lustre_upcall)
612 gen.addElement(node, 'lustreUpcall', default_upcall)
613 if default_upcall or options.portals_upcall:
614 if options.portals_upcall:
615 gen.addElement(node, 'portalsUpcall', options.portals_upcall)
617 gen.addElement(node, 'portalsUpcall', default_upcall)
619 gen.addElement(node, "ptldebug", get_option(options, 'ptldebug'))
620 if options.subsystem:
621 gen.addElement(node, "subsystem", get_option(options, 'subsystem'))
624 def do_add_node(gen, lustre, options, node_name):
625 uuid = new_uuid(node_name)
626 prof_name = new_name("PROFILE_" + node_name)
627 prof_uuid = new_uuid(prof_name)
628 profile = gen.profile(prof_name, prof_uuid)
629 node = gen.node(node_name, uuid, prof_uuid)
630 lustre.appendChild(node)
631 lustre.appendChild(profile)
633 node_add_profile(gen, node, 'ldlm', ldlm_uuid)
634 set_node_options(gen, node, options)
638 def add_node(gen, lustre, options):
639 """ create a node with a network config """
641 node_name = get_option(options, 'node')
642 ret = findByName(lustre, node_name, "node")
644 print "Node:", node_name, "exists."
646 do_add_node(gen, lustre, options, node_name)
649 def add_net(gen, lustre, options):
650 """ create a node with a network config """
652 node_name = get_option(options, 'node')
653 nid = get_option(options, 'nid')
654 cluster_id = get_option(options, 'cluster_id')
655 hostaddr = get_option(options, 'hostaddr')
656 net_type = get_option(options, 'nettype')
658 if net_type in ('tcp',):
659 port = get_option_int(options, 'port')
660 tcpbuf = get_option_int(options, 'tcpbuf')
661 irq_aff = get_option_int(options, 'irq_affinity')
662 elif net_type in ('elan', 'gm', 'scimac'):
667 print "Unknown net_type: ", net_type
670 ret = findByName(lustre, node_name, "node")
672 node = do_add_node(gen, lustre, options, node_name)
675 set_node_options(gen, node, options)
677 net_name = new_name('NET_'+ node_name +'_'+ net_type)
678 net_uuid = new_uuid(net_name)
679 node.appendChild(gen.network(net_name, net_uuid, nid, cluster_id, net_type,
680 hostaddr, port, tcpbuf, irq_aff))
681 node_add_profile(gen, node, "network", net_uuid)
684 def add_route(gen, lustre, options):
685 """ create a node with a network config """
687 node_name = get_option(options, 'node')
688 gw_net_type = get_option(options, 'nettype')
689 gw = get_option(options, 'gw')
690 gw_cluster_id = get_option(options, 'gateway_cluster_id')
691 tgt_cluster_id = get_option(options, 'target_cluster_id')
692 lo = get_option(options, 'lo')
693 hi = get_option(options, 'hi')
697 node = findByName(lustre, node_name, "node")
699 error (node_name, " not found.")
701 rlist = node.getElementsByTagName('routetbl')
705 rtbl_name = new_name("RTBL_" + node_name)
706 rtbl_uuid = new_uuid(rtbl_name)
707 rtbl = gen.routetbl(rtbl_name, rtbl_uuid)
708 node.appendChild(rtbl)
709 node_add_profile(gen, node, "routetbl", rtbl_uuid)
710 rtbl.appendChild(gen.route(gw_net_type, gw, gw_cluster_id, tgt_cluster_id,
714 def add_mds(gen, lustre, options):
715 node_name = get_option(options, 'node')
716 mds_name = get_option(options, 'mds')
717 lmv_name = get_option(options, 'lmv')
718 mdd_name = new_name("MDD_" + mds_name +"_" + node_name)
719 mdd_uuid = new_uuid(mdd_name)
723 lmv = findByName(lustre, lmv_name, "lmv")
725 error('add_mds:', '"'+lmv_name+'"', "lmv element not found.")
726 lmv_uuid = name2uuid(lustre, lmv_name, fatal=0)
728 mds_uuid = name2uuid(lustre, mds_name, 'mds', fatal=0)
730 mds_uuid = new_uuid(mds_name)
732 mds = gen.mds(mds_name, mds_uuid, mdd_uuid, options.group)
734 mds = gen.mds(mds_name, mds_uuid, mdd_uuid, options.group, lmv)
735 lustre.appendChild(mds)
737 mds = lookup(lustre, mds_uuid)
739 mds.setAttribute('failover', "1")
741 devname = get_option(options, 'dev')
742 size = get_option(options, 'size')
743 fstype = get_option(options, 'fstype')
744 journal_size = get_option(options, 'journal_size')
745 inode_size = get_option(options, 'inode_size')
746 nspath = get_option(options, 'nspath')
747 mkfsoptions = get_option(options, 'mkfsoptions')
749 node_uuid = name2uuid(lustre, node_name, 'node')
751 node = findByName(lustre, node_name, "node")
752 node_add_profile(gen, node, "mdsdev", mdd_uuid)
753 net_uuid = get_net_uuid(lustre, node_name)
755 error("NODE: ", node_name, "not found")
758 lmv.appendChild(gen.ref("mds", mds_uuid))
759 mds.appendChild(gen.ref("lmv", lmv_uuid))
761 mds.setAttribute('master', "1")
763 mdd = gen.mdsdev(mdd_name, mdd_uuid, fstype, devname,
764 get_format_flag(options), node_uuid, mds_uuid,
765 size, journal_size, inode_size, nspath, mkfsoptions,
767 lustre.appendChild(mdd)
770 def add_mgmt(gen, lustre, options):
771 node_name = get_option(options, 'node')
772 node_uuid = name2uuid(lustre, node_name, 'node')
773 mgmt_name = get_option(options, 'mgmt')
775 mgmt_name = new_name('MGMT_' + node_name)
776 mgmt_uuid = name2uuid(lustre, mgmt_name, 'mgmt', fatal=0)
778 mgmt_uuid = new_uuid(mgmt_name)
779 mgmt = gen.mgmt(mgmt_name, mgmt_uuid, node_uuid)
780 lustre.appendChild(mgmt)
782 mgmt = lookup(lustre, mgmt_uuid)
784 node = findByName(lustre, node_name, "node")
785 node_add_profile(gen, node, 'mgmt', mgmt_uuid)
787 def add_ost(gen, lustre, options):
788 node_name = get_option(options, 'node')
789 lovname = get_option(options, 'lov')
790 osdtype = get_option(options, 'osdtype')
792 node_uuid = name2uuid(lustre, node_name, 'node')
794 if osdtype == 'obdecho':
803 devname = get_option(options, 'dev') # can be unset for bluearcs
804 size = get_option(options, 'size')
805 fstype = get_option(options, 'fstype')
806 journal_size = get_option(options, 'journal_size')
807 inode_size = get_option(options, 'inode_size')
808 mkfsoptions = get_option(options, 'mkfsoptions')
810 nspath = get_option(options, 'nspath')
812 ostname = get_option(options, 'ost')
814 ostname = new_name('OST_'+ node_name)
816 osdname = new_name("OSD_" + ostname + "_" + node_name)
817 osd_uuid = new_uuid(osdname)
819 ost_uuid = name2uuid(lustre, ostname, 'ost', fatal=0)
821 ost_uuid = get_option(options, 'ostuuid')
823 if lookup(lustre, ost_uuid):
824 error("Duplicate OST UUID:", ost_uuid)
826 ost_uuid = new_uuid(ostname)
828 ost = gen.ost(ostname, ost_uuid, osd_uuid, options.group)
829 lustre.appendChild(ost)
831 lov = findByName(lustre, lovname, "lov")
833 error('add_ost:', '"'+lovname+'"', "lov element not found.")
834 lov_add_obd(gen, lov, ost_uuid)
836 ost = lookup(lustre, ost_uuid)
839 ost.setAttribute('failover', "1")
842 osd = gen.osd(osdname, osd_uuid, fstype, osdtype, devname,
843 get_format_flag(options), ost_uuid, node_uuid, size,
844 journal_size, inode_size, nspath, mkfsoptions)
846 node = findByName(lustre, node_name, "node")
848 ## if node_add_profile(gen, node, 'oss', oss_uuid):
850 ## oss_uuid = new_uuid(ossname)
851 ## oss = gen.oss(ossname, oss_uuid)
852 ## lustre.appendChild(oss)
854 node_add_profile(gen, node, 'osd', osd_uuid)
855 lustre.appendChild(osd)
858 def add_cobd(gen, lustre, options):
859 node_name = get_option(options, 'node')
860 name = new_name('COBD_' + node_name)
861 uuid = new_uuid(name)
863 real_name = get_option(options, 'real_obd')
864 cache_name = get_option(options, 'cache_obd')
866 real_uuid = name2uuid(lustre, real_name, tag='obd')
867 cache_uuid = name2uuid(lustre, cache_name, tag='obd')
869 node = findByName(lustre, node_name, "node")
870 node_add_profile(gen, node, "cobd", uuid)
871 cobd = gen.cobd(name, uuid, real_uuid, cache_uuid)
872 lustre.appendChild(cobd)
875 def add_echo_client(gen, lustre, options):
876 """ add an echo client to the profile for this node. """
877 node_name = get_option(options, 'node')
878 lov_name = get_option(options, 'ost')
880 node = findByName(lustre, node_name, 'node')
882 echoname = new_name('ECHO_'+ node_name)
883 echo_uuid = new_uuid(echoname)
884 node_add_profile(gen, node, 'echoclient', echo_uuid)
886 lov_uuid = name2uuid(lustre, lov_name, tag='lov', fatal=0)
888 lov_uuid = name2uuid(lustre, lov_name, tag='ost', fatal=1)
890 echo = gen.echo_client(echoname, echo_uuid, lov_uuid)
891 lustre.appendChild(echo)
894 def add_lov(gen, lustre, options):
897 lov_orig = get_option(options, 'lov')
898 name = new_name(lov_orig)
900 warning("name:", lov_orig, "already used. using:", name)
902 mds_name = get_option(options, 'mds')
904 lmv_name = get_option(options, 'lmv')
906 error("LOV: MDS or LMV must be specified.");
908 stripe_sz = get_option_int(options, 'stripe_sz')
909 stripe_cnt = get_option_int(options, 'stripe_cnt')
910 pattern = get_option_int(options, 'stripe_pattern')
911 uuid = new_uuid(name)
913 ret = findByName(lustre, name, "lov")
915 error("LOV: ", name, " already exists.")
918 mds_uuid = name2uuid(lustre, lmv_name, 'lmv')
920 mds_uuid = name2uuid(lustre, mds_name, 'mds')
922 lov = gen.lov(name, uuid, mds_uuid, stripe_sz, stripe_cnt, pattern)
923 lustre.appendChild(lov)
925 # add an lovconfig entry to the active mdsdev profile
926 lovconfig_name = new_name('LVCFG_' + name)
927 lovconfig_uuid = new_uuid(lovconfig_name)
929 mds = findByName(lustre, mds_name, "mds")
930 mds.appendChild(gen.ref("lovconfig", lovconfig_uuid))
932 lmv = findByName(lustre, lmv_name, "lmv")
933 lmv.appendChild(gen.ref("lovconfig", lovconfig_uuid))
934 lovconfig = gen.lovconfig(lovconfig_name, lovconfig_uuid, uuid)
935 lustre.appendChild(lovconfig)
937 def add_default_lov(gen, lustre, mds_name, lov_name):
938 """ create a default lov """
940 stripe_sz = DEFAULT_STRIPE_SZ
941 stripe_cnt = DEFAULT_STRIPE_CNT
942 pattern = DEFAULT_STRIPE_PATTERN
943 uuid = new_uuid(lov_name)
945 ret = findByName(lustre, lov_name, "lov")
947 error("LOV: ", lov_name, " already exists.")
949 mds_uuid = name2uuid(lustre, mds_name, 'mds')
950 lov = gen.lov(lov_name, uuid, mds_uuid, stripe_sz, stripe_cnt, pattern)
951 lustre.appendChild(lov)
953 # add an lovconfig entry to the active mdsdev profile
954 lovconfig_name = new_name('LVCFG_' + lov_name)
955 lovconfig_uuid = new_uuid(lovconfig_name)
956 mds = findByName(lustre, mds_name)
957 mds.appendChild(gen.ref("lovconfig", lovconfig_uuid))
958 lovconfig = gen.lovconfig(lovconfig_name, lovconfig_uuid, uuid)
959 lustre.appendChild(lovconfig)
961 def add_lmv(gen, lustre, options):
964 lmv_orig = get_option(options, 'lmv')
965 name = new_name(lmv_orig)
967 warning("name:", lmv_orig, "already used. using:", name)
969 uuid = new_uuid(name)
970 ret = findByName(lustre, name, "lmv")
972 error("LMV: ", name, " already exists.")
974 lmv = gen.lmv(name, uuid)
975 lustre.appendChild(lmv)
977 def new_filesystem(gen, lustre, mds_uuid, obd_uuid, mgmt_uuid):
978 fs_name = new_name("FS_fsname")
979 fs_uuid = new_uuid(fs_name)
980 mds = lookup(lustre, mds_uuid)
981 mds.appendChild(gen.ref("filesystem", fs_uuid))
982 fs = gen.filesystem(fs_name, fs_uuid, mds_uuid, obd_uuid, mgmt_uuid)
983 lustre.appendChild(fs)
986 def get_fs_uuid(gen, lustre, mds_name, obd_name, mgmt_name):
987 mds_uuid = name2uuid(lustre, mds_name, tag='mds', fatal=0)
989 mds_uuid = name2uuid(lustre, mds_name, tag='lmv', fatal=1)
990 obd_uuid = name2uuid(lustre, obd_name, tag='lov', fatal=0)
992 mgmt_uuid = name2uuid(lustre, mgmt_name, tag='mgmt', fatal=1)
995 fs_uuid = lookup_filesystem(lustre, mds_uuid, obd_uuid)
997 fs_uuid = new_filesystem(gen, lustre, mds_uuid, obd_uuid, mgmt_uuid)
1000 def add_mtpt(gen, lustre, options):
1001 """ create mtpt on a node """
1002 node_name = get_option(options, 'node')
1004 path = get_option(options, 'path')
1005 fs_name = get_option(options, 'filesystem')
1007 lov_name = get_option(options, 'lov')
1008 ost_name = get_option(options, 'ost')
1009 mds_name = get_option(options, 'mds')
1011 mds_name = get_option(options, 'lmv')
1013 error("--add mtpt requires either --mds or --lmv.")
1016 error("--add mtpt requires --lov lov_name or --ost ost_name")
1018 warning("use default value for lov, due no --lov lov_name provided")
1019 lov_name = new_name("lov_default")
1020 add_default_lov(gen, lustre, mds_name, lov_name)
1021 ost_uuid = name2uuid(lustre, ost_name, 'ost', fatal=0)
1023 error('add_mtpt:', '"'+ost_name+'"', "ost element not found.")
1024 lov = findByName(lustre, lov_name, "lov")
1025 lov_add_obd(gen, lov, ost_uuid)
1028 mgmt_name = get_option(options, 'mgmt')
1029 fs_uuid = get_fs_uuid(gen, lustre, mds_name, lov_name, mgmt_name)
1031 fs_uuid = name2uuid(lustre, fs_name, tag='filesystem')
1033 name = new_name('MNT_'+ node_name)
1035 ret = findByName(lustre, name, "mountpoint")
1037 # this can't happen, because new_name creates unique names
1038 error("MOUNTPOINT: ", name, " already exists.")
1040 uuid = new_uuid(name)
1041 mtpt = gen.mountpoint(name, uuid, fs_uuid, path)
1042 node = findByName(lustre, node_name, "node")
1044 error('node:', node_name, "not found.")
1045 node_add_profile(gen, node, "mountpoint", uuid)
1046 lustre.appendChild(mtpt)
1048 ############################################################
1049 # Command line processing
1051 class OptionError (exceptions.Exception):
1052 def __init__(self, args):
1055 def get_option(options, tag):
1056 """Look for tag in options hash and return the value if set. If not
1057 set, then if return default it is set, otherwise exception."""
1058 if options.__getattr__(tag) != None:
1059 return options.__getattr__(tag)
1061 raise OptionError("--add %s requires --%s <value>" % (options.add, tag))
1063 def get_option_int(options, tag):
1064 """Return an integer option. Raise exception if the value is not an int"""
1065 val = get_option(options, tag)
1069 raise OptionError("--%s <num> (value must be integer)" % (tag))
1072 # simple class for profiling
1079 self._start = time.time()
1080 def stop(self, msg=''):
1081 self._stop = time.time()
1085 return self._stop - self._start
1086 def display(self, msg):
1088 str = '%s: %g secs' % (msg, d)
1091 #################################################################
1092 # function cmdlinesplit used to split cmd line from batch file
1094 def cmdlinesplit(cmdline):
1096 double_quote = re.compile(r'"(([^"\\]|\\.)*)"')
1097 single_quote = re.compile(r"'(.*?)'")
1098 escaped = re.compile(r'\\(.)')
1099 esc_quote = re.compile(r'\\([\\"])')
1100 outside = re.compile(r"""([^\s\\'"]+)""")
1104 while i < len(cmdline):
1107 match = double_quote.match(cmdline, i)
1109 print "Unmatched double quote:", cmdline
1112 if arg is None: arg = esc_quote.sub(r'\1', match.group(1))
1113 else: arg = arg + esc_quote.sub(r'\1', match.group(1))
1116 match = single_quote.match(cmdline, i)
1118 print "Unmatched single quote:", cmdline
1121 if arg is None: arg = match.group(1)
1122 else: arg = arg + match.group(1)
1125 match = escaped.match(cmdline, i)
1127 print "Unmatched backslash", cmdline
1130 if arg is None: arg = match.group(1)
1131 else: arg = arg + match.group(1)
1133 elif c in string.whitespace:
1135 arg_list.append(str(arg))
1137 while i < len(cmdline) and cmdline[i] in string.whitespace:
1140 match = outside.match(cmdline, i)
1143 if arg is None: arg = match.group()
1144 else: arg = arg + match.group()
1146 if arg != None: arg_list.append(str(arg))
1150 ############################################################
1154 def add(devtype, gen, lustre, options):
1155 if devtype == 'net':
1156 add_net(gen, lustre, options)
1157 elif devtype == 'mtpt':
1158 add_mtpt(gen, lustre, options)
1159 elif devtype == 'mds':
1160 add_mds(gen, lustre, options)
1161 elif devtype == 'ost':
1162 add_ost(gen, lustre, options)
1163 elif devtype == 'lov':
1164 add_lov(gen, lustre, options)
1165 elif devtype == 'route':
1166 add_route(gen, lustre, options)
1167 elif devtype == 'node':
1168 add_node(gen, lustre, options)
1169 elif devtype == 'echo_client':
1170 add_echo_client(gen, lustre, options)
1171 elif devtype == 'cobd':
1172 add_cobd(gen, lustre, options)
1173 elif devtype == 'mgmt':
1174 add_mgmt(gen, lustre, options)
1175 elif devtype == 'lmv':
1176 add_lmv(gen, lustre, options)
1178 error("unknown device type:", devtype)
1180 def do_command(gen, lustre, options, args):
1182 add(options.add, gen, lustre, options)
1184 error("Missing command")
1187 cl = Lustre.Options("lmc", "", lmc_options)
1189 options, args = cl.parse(sys.argv[1:])
1190 except Lustre.OptionError, e:
1194 panic(string.join(sys.argv), "Unexpected extra arguments on command line: " + string.join(args))
1196 if options.reference:
1203 outFile = options.merge
1204 if os.access(outFile, os.R_OK):
1205 doc = xml.dom.minidom.parse(outFile)
1207 doc = new_lustre(xml.dom.minidom)
1209 doc = xml.dom.minidom.parse(options.input)
1211 doc = new_lustre(xml.dom.minidom)
1214 outFile = options.output
1216 lustre = doc.documentElement
1218 if lustre.tagName != "lustre":
1219 print "Existing config not valid."
1222 gen = GenConfig(doc)
1225 fp = open(options.batch)
1226 batchCommands = fp.readlines()
1228 for cmd in batchCommands:
1230 options, args = cl.parse(cmdlinesplit(cmd))
1231 if options.merge or options.input or options.output:
1232 print "The batchfile should not contain --merge, --input or --output."
1234 do_command(gen, lustre, options, args)
1235 except OptionError, e:
1237 except Lustre.OptionError, e:
1241 do_command(gen, lustre, options, args)
1242 except OptionError, e:
1243 panic(string.join(sys.argv),e)
1244 except Lustre.OptionError, e:
1250 printDoc(doc, open(outFile,"w"))
1252 if __name__ == "__main__":