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 = 1048576
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
91 --backfstype ext3|tmpfs
97 --mountfsoptions options
115 --backfstype ext3|tmpfs
118 --osdtype obdecho|obdfilter
120 --mkfsoptions options
121 --mountfsoptions options
124 --add mtpt - Mountpoint
128 --ost ost_name OR --lov lov_name
134 --gateway_cluster_id nid
135 --target_cluster_id nid
142 --add mgmt - Management/monitoring service
144 --mgmt mgmt_service_name
152 PARAM = Lustre.Options.PARAM
154 # lmc input/output options
155 ('reference', "Print short reference for commands."),
156 ('verbose,v', "Print system commands as they are run."),
157 ('merge,m', "Append to the specified config file.", PARAM),
158 ('output,o', "Write XML configuration into given output file. Overwrite existing content.", PARAM),
159 ('input,i', "", PARAM),
160 ('batch', "Used to execute lmc commands in batch mode.", PARAM),
166 ('node', "Add a new node in the cluster configuration.", PARAM),
167 ('timeout', "Set timeout to initiate recovery.", PARAM),
168 ('upcall', "Set both lustre and portals upcall scripts.", PARAM),
169 ('lustre_upcall', "Set location of lustre upcall script.", PARAM),
170 ('portals_upcall', "Set location of portals upcall script.", PARAM),
171 ('ptldebug', "Set the portals debug level", PARAM),
172 ('subsystem', "Specify which Lustre subsystems have debug output recorded in the log", PARAM),
175 ('nettype', "Specify the network type. This can be tcp/elan/gm.", PARAM),
176 ('nid', "Give the network ID, e.g ElanID/IP Address as used by portals.", PARAM),
177 ('tcpbuf', "Optional argument to specify the TCP buffer size.", PARAM, "0"),
178 ('port', "Optional argument to specify the TCP port number.", PARAM, DEFAULT_PORT),
179 ('irq_affinity', "Optional argument.", PARAM, 0),
180 ('hostaddr', "", PARAM,""),
181 ('cluster_id', "Specify the cluster ID", PARAM, "0"),
184 ('route', "Add a new route for the cluster.", PARAM),
185 ('router', "Optional flag to mark a node as router."),
186 ('gw', "Specify the nid of the gateway for a route.", PARAM),
187 ('gateway_cluster_id', "", PARAM, "0"),
188 ('target_cluster_id', "", PARAM, "0"),
189 ('lo', "For a range route, this is the low value nid.", PARAM),
190 ('hi', "For a range route, this is a hi value nid.", PARAM,""),
192 # servers: mds and ost
193 ('mds', "Specify MDS name.", PARAM),
194 ('ost', "Specify the OST name.", PARAM,""),
195 ('osdtype', "This could obdfilter or obdecho.", PARAM, "obdfilter"),
196 ('failover', "Enable failover support on OSTs or MDS?"),
197 ('group', "", PARAM),
198 ('dev', "Path of the device on local system.", PARAM,""),
199 ('backdev', "Path of the device for backing storage on local system.", PARAM,""),
200 ('size', "Specify the size of the device if needed.", PARAM,"0"),
201 ('journal_size', "Specify new journal size for underlying ext3 file system.", PARAM,"0"),
202 ('inode_size', "Specify new inode size for underlying ext3 file system.", PARAM,"0"),
203 ('fstype', "Optional argument to specify the filesystem type.", PARAM, "ext3"),
204 ('backfstype', "Optional argument to specify the backing filesystem type.", PARAM, "ext3"),
205 ('mkfsoptions', "Optional argument to mkfs.", PARAM, ""),
206 ('mountfsoptions', "Optional argument to mount fs.", PARAM, ""),
207 ('ostuuid', "", PARAM,""),
208 ('nspath', "Local mount point of server namespace.", PARAM,""),
211 # clients: mountpoint and echo
212 ('echo_client', "", PARAM),
213 ('path', "Specify the mountpoint for Lustre.", PARAM),
214 ('filesystem', "Lustre filesystem name", PARAM,""),
217 ('lov', "Specify LOV name.", PARAM,""),
218 ('stripe_sz', "Specify the stripe size in bytes.", PARAM),
219 ('stripe_cnt', "Specify the number of OSTs each file should be striped on.", PARAM, 0),
220 ('stripe_pattern', "Specify the stripe pattern. RAID 0 is the only one currently supported.", PARAM, 0),
223 ('real_obd', "Specify the real device for the cache obd system.", PARAM),
224 ('cache_obd', "Specify the cache device for the cache obd system.", PARAM),
226 ('mgmt', "Specify management/monitoring service name.", PARAM, ""),
230 msg = string.join(map(str,args))
231 raise OptionError("Error: " + msg)
240 msg = string.join(map(str,args))
241 print "Warning: ", msg
244 # manage names and uuids
245 # need to initialize this by walking tree to ensure
246 # no duplicate names or uuids are created.
247 # this are just place holders for now.
248 # consider changing this to be like OBD-dev-host
252 while names.has_key(ret):
253 ret = "%s_%d" % (base, ctr)
260 ret = "%s_UUID" % (name)
261 if len(ret) > UUID_MAX_LENGTH:
262 ret = ret[-UUID_MAX_LENGTH:]
263 while uuids.has_key(ret):
264 ret = "%s_UUID_%d" % (name, ctr)
266 if len(ret) > UUID_MAX_LENGTH:
267 ret = ret[-UUID_MAX_LENGTH:]
273 ldlm_uuid = 'ldlm_UUID'
276 """Create a new empty lustre document"""
277 # adding ldlm here is a bit of a hack, but one is enough.
278 str = """<lustre version="%s">
279 <ldlm name="%s" uuid="%s"/>
280 </lustre>""" % (Lustre.CONFIG_VERSION, ldlm_name, ldlm_uuid)
281 return dom.parseString(str)
287 """initialize auto-name generation tables"""
289 # get all elements that contain a name attribute
290 for n in doc.childNodes:
291 if n.nodeType == n.ELEMENT_NODE:
293 names[getName(n)] = 1
294 uuids[getUUID(n)] = 1
297 def get_format_flag(options):
302 ############################################################
303 # Build config objects using DOM
308 def __init__(self, doc):
311 def ref(self, type, uuid):
312 """ generate <[type]_ref uuidref="[uuid]"/> """
313 tag = "%s_ref" % (type)
314 ref = self.doc.createElement(tag)
315 ref.setAttribute("uuidref", uuid)
318 def newService(self, tag, name, uuid):
319 """ create a new service elmement, which requires name and uuid attributes """
320 new = self.doc.createElement(tag)
321 new.setAttribute("uuid", uuid);
322 new.setAttribute("name", name);
325 def addText(self, node, str):
326 txt = self.doc.createTextNode(str)
327 node.appendChild(txt)
329 def addElement(self, node, tag, str=None):
330 """ create a new element and add it as a child to node. If str is passed,
331 a text node is created for the new element"""
332 new = self.doc.createElement(tag)
334 self.addText(new, str)
335 node.appendChild(new)
338 def network(self, name, uuid, nid, cluster_id, net, hostaddr="",
339 port=0, tcpbuf=0, irq_aff=0):
340 """create <network> node"""
341 network = self.newService("network", name, uuid)
342 network.setAttribute("nettype", net);
343 self.addElement(network, "nid", nid)
344 self.addElement(network, "clusterid", cluster_id)
346 self.addElement(network, "hostaddr", hostaddr)
348 self.addElement(network, "port", "%d" %(port))
350 self.addElement(network, "sendmem", "%d" %(tcpbuf))
351 self.addElement(network, "recvmem", "%d" %(tcpbuf))
353 self.addElement(network, "irqaffinity", "%d" %(irq_aff))
357 def routetbl(self, name, uuid):
358 """create <routetbl> node"""
359 rtbl = self.newService("routetbl", name, uuid)
362 def route(self, gw_net_type, gw, gw_cluster_id, tgt_cluster_id, lo, hi):
363 """ create one entry for the route table """
364 ref = self.doc.createElement('route')
365 ref.setAttribute("type", gw_net_type)
366 ref.setAttribute("gw", gw)
367 ref.setAttribute("gwclusterid", gw_cluster_id)
368 ref.setAttribute("tgtclusterid", tgt_cluster_id)
369 ref.setAttribute("lo", lo)
371 ref.setAttribute("hi", hi)
374 def profile(self, name, uuid):
375 """ create a host """
376 profile = self.newService("profile", name, uuid)
379 def node(self, name, uuid, prof_uuid):
380 """ create a host """
381 node = self.newService("node", name, uuid)
382 node.appendChild(self.ref("profile", prof_uuid))
385 def ldlm(self, name, uuid):
386 """ create a ldlm """
387 ldlm = self.newService("ldlm", name, uuid)
390 def osd(self, name, uuid, fs, osdtype, devname, format, ost_uuid,
391 node_uuid, dev_size=0, journal_size=0, inode_size=0, nspath="",
392 mkfsoptions="", mountfsoptions="", backfs="", backdevname=""):
393 osd = self.newService("osd", name, uuid)
394 osd.setAttribute('osdtype', osdtype)
395 osd.appendChild(self.ref("target", ost_uuid))
396 osd.appendChild(self.ref("node", node_uuid))
398 self.addElement(osd, "fstype", fs)
400 self.addElement(osd, "backfstype", backfs)
402 self.addElement(osd, "backdevpath", backdevname)
404 dev = self.addElement(osd, "devpath", devname)
405 self.addElement(osd, "autoformat", format)
407 self.addElement(osd, "devsize", "%s" % (dev_size))
409 self.addElement(osd, "journalsize", "%s" % (journal_size))
411 self.addElement(osd, "inodesize", "%s" % (inode_size))
413 self.addElement(osd, "mkfsoptions", mkfsoptions)
415 self.addElement(osd, "mountfsoptions", mountfsoptions)
417 self.addElement(osd, "nspath", nspath)
420 def cobd(self, name, uuid, real_uuid, cache_uuid):
421 cobd = self.newService("cobd", name, uuid)
422 cobd.appendChild(self.ref("realobd",real_uuid))
423 cobd.appendChild(self.ref("cacheobd",cache_uuid))
426 def ost(self, name, uuid, osd_uuid, group=""):
427 ost = self.newService("ost", name, uuid)
428 ost.appendChild(self.ref("active", osd_uuid))
430 self.addElement(ost, "group", group)
433 def oss(self, name, uuid):
434 oss = self.newService("oss", name, uuid)
437 def lov(self, name, uuid, mds_uuid, stripe_sz, stripe_cnt, pattern):
438 lov = self.newService("lov", name, uuid)
439 lov.appendChild(self.ref("mds", mds_uuid))
440 lov.setAttribute("stripesize", str(stripe_sz))
441 lov.setAttribute("stripecount", str(stripe_cnt))
442 lov.setAttribute("stripepattern", str(pattern))
445 def lovconfig(self, name, uuid, lov_uuid):
446 lovconfig = self.newService("lovconfig", name, uuid)
447 lovconfig.appendChild(self.ref("lov", lov_uuid))
450 def mds(self, name, uuid, mdd_uuid, group=""):
451 mds = self.newService("mds", name, uuid)
452 mds.appendChild(self.ref("active",mdd_uuid))
454 self.addElement(mds, "group", group)
457 def mdsdev(self, name, uuid, fs, devname, format, node_uuid,
458 mds_uuid, dev_size=0, journal_size=0, inode_size=256,
459 nspath="", mkfsoptions="", mountfsoptions="", backfs="",
461 mdd = self.newService("mdsdev", name, uuid)
462 self.addElement(mdd, "fstype", fs)
464 self.addElement(mdd, "backfstype", backfs)
465 dev = self.addElement(mdd, "devpath", devname)
467 self.addElement(mdd, "backdevpath", backdevname)
468 self.addElement(mdd, "autoformat", format)
470 self.addElement(mdd, "devsize", "%s" % (dev_size))
472 self.addElement(mdd, "journalsize", "%s" % (journal_size))
474 self.addElement(mdd, "inodesize", "%s" % (inode_size))
476 self.addElement(mdd, "nspath", nspath)
478 self.addElement(mdd, "mkfsoptions", mkfsoptions)
480 self.addElement(mdd, "mountfsoptions", mountfsoptions)
482 mdd.appendChild(self.ref("node", node_uuid))
483 mdd.appendChild(self.ref("target", mds_uuid))
486 def mgmt(self, mgmt_name, mgmt_uuid, node_uuid):
487 mgmt = self.newService("mgmt", mgmt_name, mgmt_uuid)
488 mgmt.appendChild(self.ref("node", node_uuid))
489 # Placeholder until mgmt-service failover.
490 mgmt.appendChild(self.ref("active", mgmt_uuid))
493 def mountpoint(self, name, uuid, fs_uuid, path):
494 mtpt = self.newService("mountpoint", name, uuid)
495 mtpt.appendChild(self.ref("filesystem", fs_uuid))
496 self.addElement(mtpt, "path", path)
499 def filesystem(self, name, uuid, mds_uuid, obd_uuid, mgmt_uuid):
500 fs = self.newService("filesystem", name, uuid)
501 fs.appendChild(self.ref("mds", mds_uuid))
502 fs.appendChild(self.ref("obd", obd_uuid))
504 fs.appendChild(self.ref("mgmt", mgmt_uuid))
507 def echo_client(self, name, uuid, osc_uuid):
508 ec = self.newService("echoclient", name, uuid)
509 ec.appendChild(self.ref("obd", osc_uuid))
512 ############################################################
513 # Utilities to query a DOM tree
514 # Using this functions we can treat use config information
515 # directly as a database.
517 return n.getAttribute('name')
520 return node.getAttribute('uuid')
523 def findByName(lustre, name, tag = ""):
524 for n in lustre.childNodes:
525 if n.nodeType == n.ELEMENT_NODE:
526 if tag and n.nodeName != tag:
528 if getName(n) == name:
531 n = findByName(n, name)
536 def lookup(node, uuid):
537 for n in node.childNodes:
538 if n.nodeType == n.ELEMENT_NODE:
539 if getUUID(n) == uuid:
547 def name2uuid(lustre, name, tag="", fatal=1):
548 ret = findByName(lustre, name, tag)
551 error('name2uuid:', '"'+name+'"', tag, 'element not found.')
556 def lookup_filesystem(lustre, mds_uuid, ost_uuid):
557 for n in lustre.childNodes:
558 if n.nodeType == n.ELEMENT_NODE and n.nodeName == 'filesystem':
559 if ref_exists(n, mds_uuid) and ref_exists(n, ost_uuid):
563 # XXX: assumes only one network element per node. will fix this
564 # as soon as support for routers is added
565 def get_net_uuid(lustre, node_name):
566 """ get a network uuid for a node_name """
567 node = findByName(lustre, node_name, "node")
569 error ('get_net_uuid:', '"'+node_name+'"', "node element not found.")
570 net = node.getElementsByTagName('network')
572 return getUUID(net[0])
576 def lov_add_obd(gen, lov, osc_uuid):
577 lov.appendChild(gen.ref("obd", osc_uuid))
579 def ref_exists(profile, uuid):
580 elist = profile.childNodes
582 if e.nodeType == e.ELEMENT_NODE:
583 ref = e.getAttribute('uuidref')
588 # ensure that uuid is not already in the profile
589 # return true if uuid is added
590 def node_add_profile(gen, node, ref, uuid):
591 refname = "%s_ref" % "profile"
592 ret = node.getElementsByTagName(refname)
594 error('node has no profile ref:', node)
595 prof_uuid = ret[0].getAttribute('uuidref')
596 profile = lookup(node.parentNode, prof_uuid)
598 error("no profile found:", prof_uuid)
599 if ref_exists(profile, uuid):
601 profile.appendChild(gen.ref(ref, uuid))
604 def get_attr(dom_node, attr, default=""):
605 v = dom_node.getAttribute(attr)
610 ############################################################
613 def set_node_options(gen, node, options):
615 node.setAttribute('router', '1')
617 gen.addElement(node, "timeout", get_option(options, 'timeout'))
619 default_upcall = get_option(options, 'upcall')
622 if default_upcall or options.lustre_upcall:
623 if options.lustre_upcall:
624 gen.addElement(node, 'lustreUpcall', options.lustre_upcall)
626 gen.addElement(node, 'lustreUpcall', default_upcall)
627 if default_upcall or options.portals_upcall:
628 if options.portals_upcall:
629 gen.addElement(node, 'portalsUpcall', options.portals_upcall)
631 gen.addElement(node, 'portalsUpcall', default_upcall)
633 gen.addElement(node, "ptldebug", get_option(options, 'ptldebug'))
634 if options.subsystem:
635 gen.addElement(node, "subsystem", get_option(options, 'subsystem'))
638 def do_add_node(gen, lustre, options, node_name):
639 uuid = new_uuid(node_name)
640 prof_name = new_name("PROFILE_" + node_name)
641 prof_uuid = new_uuid(prof_name)
642 profile = gen.profile(prof_name, prof_uuid)
643 node = gen.node(node_name, uuid, prof_uuid)
644 lustre.appendChild(node)
645 lustre.appendChild(profile)
647 node_add_profile(gen, node, 'ldlm', ldlm_uuid)
648 set_node_options(gen, node, options)
652 def add_node(gen, lustre, options):
653 """ create a node with a network config """
655 node_name = get_option(options, 'node')
656 ret = findByName(lustre, node_name, "node")
658 print "Node:", node_name, "exists."
660 do_add_node(gen, lustre, options, node_name)
663 def add_net(gen, lustre, options):
664 """ create a node with a network config """
666 node_name = get_option(options, 'node')
667 nid = get_option(options, 'nid')
668 cluster_id = get_option(options, 'cluster_id')
669 hostaddr = get_option(options, 'hostaddr')
670 net_type = get_option(options, 'nettype')
672 if net_type in ('tcp',):
673 port = get_option_int(options, 'port')
674 tcpbuf = get_option_int(options, 'tcpbuf')
675 irq_aff = get_option_int(options, 'irq_affinity')
676 elif net_type in ('elan', 'gm'):
681 print "Unknown net_type: ", net_type
684 ret = findByName(lustre, node_name, "node")
686 node = do_add_node(gen, lustre, options, node_name)
689 set_node_options(gen, node, options)
691 net_name = new_name('NET_'+ node_name +'_'+ net_type)
692 net_uuid = new_uuid(net_name)
693 node.appendChild(gen.network(net_name, net_uuid, nid, cluster_id, net_type,
694 hostaddr, port, tcpbuf, irq_aff))
695 node_add_profile(gen, node, "network", net_uuid)
698 def add_route(gen, lustre, options):
699 """ create a node with a network config """
701 node_name = get_option(options, 'node')
702 gw_net_type = get_option(options, 'nettype')
703 gw = get_option(options, 'gw')
704 gw_cluster_id = get_option(options, 'gateway_cluster_id')
705 tgt_cluster_id = get_option(options, 'target_cluster_id')
706 lo = get_option(options, 'lo')
707 hi = get_option(options, 'hi')
711 node = findByName(lustre, node_name, "node")
713 error (node_name, " not found.")
715 rlist = node.getElementsByTagName('routetbl')
719 rtbl_name = new_name("RTBL_" + node_name)
720 rtbl_uuid = new_uuid(rtbl_name)
721 rtbl = gen.routetbl(rtbl_name, rtbl_uuid)
722 node.appendChild(rtbl)
723 node_add_profile(gen, node, "routetbl", rtbl_uuid)
724 rtbl.appendChild(gen.route(gw_net_type, gw, gw_cluster_id, tgt_cluster_id,
728 def add_mds(gen, lustre, options):
729 node_name = get_option(options, 'node')
730 mds_name = get_option(options, 'mds')
731 mdd_name = new_name("MDD_" + mds_name +"_" + node_name)
732 mdd_uuid = new_uuid(mdd_name)
734 mds_uuid = name2uuid(lustre, mds_name, 'mds', fatal=0)
736 mds_uuid = new_uuid(mds_name)
737 mds = gen.mds(mds_name, mds_uuid, mdd_uuid, options.group)
738 lustre.appendChild(mds)
740 mds = lookup(lustre, mds_uuid)
742 mds.setAttribute('failover', "1")
744 devname = get_option(options, 'dev')
745 backdevname = get_option(options, 'backdev')
746 size = get_option(options, 'size')
747 fstype = get_option(options, 'fstype')
748 backfstype = get_option(options, 'backfstype')
749 journal_size = get_option(options, 'journal_size')
750 inode_size = get_option(options, 'inode_size')
751 nspath = get_option(options, 'nspath')
752 mkfsoptions = get_option(options, 'mkfsoptions')
753 mountfsoptions = get_option(options, 'mountfsoptions')
755 node_uuid = name2uuid(lustre, node_name, 'node')
757 node = findByName(lustre, node_name, "node")
758 node_add_profile(gen, node, "mdsdev", mdd_uuid)
759 net_uuid = get_net_uuid(lustre, node_name)
761 error("NODE: ", node_name, "not found")
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,
766 mountfsoptions, backfstype, backdevname)
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':
806 devname = get_option(options, 'dev') # can be unset for bluearcs
807 backdevname = get_option(options, 'backdev')
808 size = get_option(options, 'size')
809 fstype = get_option(options, 'fstype')
810 backfstype = get_option(options, 'backfstype')
811 journal_size = get_option(options, 'journal_size')
812 inode_size = get_option(options, 'inode_size')
813 mkfsoptions = get_option(options, 'mkfsoptions')
814 mountfsoptions = get_option(options, 'mountfsoptions')
816 nspath = get_option(options, 'nspath')
818 ostname = get_option(options, 'ost')
820 ostname = new_name('OST_'+ node_name)
822 osdname = new_name("OSD_" + ostname + "_" + node_name)
823 osd_uuid = new_uuid(osdname)
825 ost_uuid = name2uuid(lustre, ostname, 'ost', fatal=0)
827 ost_uuid = get_option(options, 'ostuuid')
829 if lookup(lustre, ost_uuid):
830 error("Duplicate OST UUID:", ost_uuid)
832 ost_uuid = new_uuid(ostname)
834 ost = gen.ost(ostname, ost_uuid, osd_uuid, options.group)
835 lustre.appendChild(ost)
837 lov = findByName(lustre, lovname, "lov")
839 error('add_ost:', '"'+lovname+'"', "lov element not found.")
840 lov_add_obd(gen, lov, ost_uuid)
842 ost = lookup(lustre, ost_uuid)
845 ost.setAttribute('failover', "1")
848 osd = gen.osd(osdname, osd_uuid, fstype, osdtype, devname,
849 get_format_flag(options), ost_uuid, node_uuid, size,
850 journal_size, inode_size, nspath, mkfsoptions,
851 mountfsoptions, backfstype, backdevname)
853 node = findByName(lustre, node_name, "node")
855 ## if node_add_profile(gen, node, 'oss', oss_uuid):
857 ## oss_uuid = new_uuid(ossname)
858 ## oss = gen.oss(ossname, oss_uuid)
859 ## lustre.appendChild(oss)
861 node_add_profile(gen, node, 'osd', osd_uuid)
862 lustre.appendChild(osd)
865 def add_cobd(gen, lustre, options):
866 node_name = get_option(options, 'node')
867 name = new_name('COBD_' + node_name)
868 uuid = new_uuid(name)
870 real_name = get_option(options, 'real_obd')
871 cache_name = get_option(options, 'cache_obd')
873 real_uuid = name2uuid(lustre, real_name, tag='obd')
874 cache_uuid = name2uuid(lustre, cache_name, tag='obd')
876 node = findByName(lustre, node_name, "node")
877 node_add_profile(gen, node, "cobd", uuid)
878 cobd = gen.cobd(name, uuid, real_uuid, cache_uuid)
879 lustre.appendChild(cobd)
882 def add_echo_client(gen, lustre, options):
883 """ add an echo client to the profile for this node. """
884 node_name = get_option(options, 'node')
885 lov_name = get_option(options, 'ost')
887 node = findByName(lustre, node_name, 'node')
889 echoname = new_name('ECHO_'+ node_name)
890 echo_uuid = new_uuid(echoname)
891 node_add_profile(gen, node, 'echoclient', echo_uuid)
893 lov_uuid = name2uuid(lustre, lov_name, tag='lov', fatal=0)
895 lov_uuid = name2uuid(lustre, lov_name, tag='ost', fatal=1)
897 echo = gen.echo_client(echoname, echo_uuid, lov_uuid)
898 lustre.appendChild(echo)
901 def add_lov(gen, lustre, options):
904 lov_orig = get_option(options, 'lov')
905 name = new_name(lov_orig)
907 warning("name:", lov_orig, "already used. using:", name)
909 mds_name = get_option(options, 'mds')
910 stripe_sz = get_option_int(options, 'stripe_sz')
911 stripe_cnt = get_option_int(options, 'stripe_cnt')
912 pattern = get_option_int(options, 'stripe_pattern')
913 uuid = new_uuid(name)
915 ret = findByName(lustre, name, "lov")
917 error("LOV: ", name, " already exists.")
919 mds_uuid = name2uuid(lustre, mds_name, 'mds')
920 lov = gen.lov(name, uuid, mds_uuid, stripe_sz, stripe_cnt, pattern)
921 lustre.appendChild(lov)
923 # add an lovconfig entry to the active mdsdev profile
924 lovconfig_name = new_name('LVCFG_' + name)
925 lovconfig_uuid = new_uuid(lovconfig_name)
926 mds = findByName(lustre, mds_name, "mds")
927 mds.appendChild(gen.ref("lovconfig", lovconfig_uuid))
928 lovconfig = gen.lovconfig(lovconfig_name, lovconfig_uuid, uuid)
929 lustre.appendChild(lovconfig)
931 def add_default_lov(gen, lustre, mds_name, lov_name):
932 """ create a default lov """
934 stripe_sz = DEFAULT_STRIPE_SZ
935 stripe_cnt = DEFAULT_STRIPE_CNT
936 pattern = DEFAULT_STRIPE_PATTERN
937 uuid = new_uuid(lov_name)
939 ret = findByName(lustre, lov_name, "lov")
941 error("LOV: ", lov_name, " already exists.")
943 mds_uuid = name2uuid(lustre, mds_name, 'mds')
944 lov = gen.lov(lov_name, uuid, mds_uuid, stripe_sz, stripe_cnt, pattern)
945 lustre.appendChild(lov)
947 # add an lovconfig entry to the active mdsdev profile
948 lovconfig_name = new_name('LVCFG_' + lov_name)
949 lovconfig_uuid = new_uuid(lovconfig_name)
950 mds = findByName(lustre, mds_name)
951 mds.appendChild(gen.ref("lovconfig", lovconfig_uuid))
952 lovconfig = gen.lovconfig(lovconfig_name, lovconfig_uuid, uuid)
953 lustre.appendChild(lovconfig)
955 def new_filesystem(gen, lustre, mds_uuid, obd_uuid, mgmt_uuid):
956 fs_name = new_name("FS_fsname")
957 fs_uuid = new_uuid(fs_name)
958 mds = lookup(lustre, mds_uuid)
959 mds.appendChild(gen.ref("filesystem", fs_uuid))
960 fs = gen.filesystem(fs_name, fs_uuid, mds_uuid, obd_uuid, mgmt_uuid)
961 lustre.appendChild(fs)
964 def get_fs_uuid(gen, lustre, mds_name, obd_name, mgmt_name):
965 mds_uuid = name2uuid(lustre, mds_name, tag='mds')
966 obd_uuid = name2uuid(lustre, obd_name, tag='lov', fatal=0)
968 mgmt_uuid = name2uuid(lustre, mgmt_name, tag='mgmt', fatal=1)
971 fs_uuid = lookup_filesystem(lustre, mds_uuid, obd_uuid)
973 fs_uuid = new_filesystem(gen, lustre, mds_uuid, obd_uuid, mgmt_uuid)
976 def add_mtpt(gen, lustre, options):
977 """ create mtpt on a node """
978 node_name = get_option(options, 'node')
980 path = get_option(options, 'path')
981 fs_name = get_option(options, 'filesystem')
983 lov_name = get_option(options, 'lov')
984 ost_name = get_option(options, 'ost')
985 mds_name = get_option(options, 'mds')
988 error("--add mtpt requires --lov lov_name or --ost ost_name")
990 warning("use default value for lov, due no --lov lov_name provided")
991 lov_name = new_name("lov_default")
992 add_default_lov(gen, lustre, mds_name, lov_name)
993 ost_uuid = name2uuid(lustre, ost_name, 'ost', fatal=0)
995 error('add_mtpt:', '"'+ost_name+'"', "ost element not found.")
996 lov = findByName(lustre, lov_name, "lov")
997 lov_add_obd(gen, lov, ost_uuid)
1000 mgmt_name = get_option(options, 'mgmt')
1001 fs_uuid = get_fs_uuid(gen, lustre, mds_name, lov_name, mgmt_name)
1003 fs_uuid = name2uuid(lustre, fs_name, tag='filesystem')
1005 name = new_name('MNT_'+ node_name)
1007 ret = findByName(lustre, name, "mountpoint")
1009 # this can't happen, because new_name creates unique names
1010 error("MOUNTPOINT: ", name, " already exists.")
1012 uuid = new_uuid(name)
1013 mtpt = gen.mountpoint(name, uuid, fs_uuid, path)
1014 node = findByName(lustre, node_name, "node")
1016 error('node:', node_name, "not found.")
1017 node_add_profile(gen, node, "mountpoint", uuid)
1018 lustre.appendChild(mtpt)
1020 ############################################################
1021 # Command line processing
1023 class OptionError (exceptions.Exception):
1024 def __init__(self, args):
1027 def get_option(options, tag):
1028 """Look for tag in options hash and return the value if set. If not
1029 set, then if return default it is set, otherwise exception."""
1030 if options.__getattr__(tag) != None:
1031 return options.__getattr__(tag)
1033 raise OptionError("--add %s requires --%s <value>" % (options.add, tag))
1035 def get_option_int(options, tag):
1036 """Return an integer option. Raise exception if the value is not an int"""
1037 val = get_option(options, tag)
1041 raise OptionError("--%s <num> (value must be integer)" % (tag))
1044 # simple class for profiling
1051 self._start = time.time()
1052 def stop(self, msg=''):
1053 self._stop = time.time()
1057 return self._stop - self._start
1058 def display(self, msg):
1060 str = '%s: %g secs' % (msg, d)
1063 #################################################################
1064 # function cmdlinesplit used to split cmd line from batch file
1066 def cmdlinesplit(cmdline):
1068 double_quote = re.compile(r'"(([^"\\]|\\.)*)"')
1069 single_quote = re.compile(r"'(.*?)'")
1070 escaped = re.compile(r'\\(.)')
1071 esc_quote = re.compile(r'\\([\\"])')
1072 outside = re.compile(r"""([^\s\\'"]+)""")
1076 while i < len(cmdline):
1079 match = double_quote.match(cmdline, i)
1081 print "Unmatched double quote:", cmdline
1084 if arg is None: arg = esc_quote.sub(r'\1', match.group(1))
1085 else: arg = arg + esc_quote.sub(r'\1', match.group(1))
1088 match = single_quote.match(cmdline, i)
1090 print "Unmatched single quote:", cmdline
1093 if arg is None: arg = match.group(1)
1094 else: arg = arg + match.group(1)
1097 match = escaped.match(cmdline, i)
1099 print "Unmatched backslash", cmdline
1102 if arg is None: arg = match.group(1)
1103 else: arg = arg + match.group(1)
1105 elif c in string.whitespace:
1107 arg_list.append(str(arg))
1109 while i < len(cmdline) and cmdline[i] in string.whitespace:
1112 match = outside.match(cmdline, i)
1115 if arg is None: arg = match.group()
1116 else: arg = arg + match.group()
1118 if arg != None: arg_list.append(str(arg))
1122 ############################################################
1126 def add(devtype, gen, lustre, options):
1127 if devtype == 'net':
1128 add_net(gen, lustre, options)
1129 elif devtype == 'mtpt':
1130 add_mtpt(gen, lustre, options)
1131 elif devtype == 'mds':
1132 add_mds(gen, lustre, options)
1133 elif devtype == 'ost':
1134 add_ost(gen, lustre, options)
1135 elif devtype == 'lov':
1136 add_lov(gen, lustre, options)
1137 elif devtype == 'route':
1138 add_route(gen, lustre, options)
1139 elif devtype == 'node':
1140 add_node(gen, lustre, options)
1141 elif devtype == 'echo_client':
1142 add_echo_client(gen, lustre, options)
1143 elif devtype == 'cobd':
1144 add_cobd(gen, lustre, options)
1145 elif devtype == 'mgmt':
1146 add_mgmt(gen, lustre, options)
1148 error("unknown device type:", devtype)
1150 def do_command(gen, lustre, options, args):
1152 add(options.add, gen, lustre, options)
1154 error("Missing command")
1157 cl = Lustre.Options("lmc", "", lmc_options)
1159 options, args = cl.parse(sys.argv[1:])
1160 except Lustre.OptionError, e:
1164 panic(string.join(sys.argv), "Unexpected extra arguments on command line: " + string.join(args))
1166 if options.reference:
1173 outFile = options.merge
1174 if os.access(outFile, os.R_OK):
1175 doc = xml.dom.minidom.parse(outFile)
1177 doc = new_lustre(xml.dom.minidom)
1179 doc = xml.dom.minidom.parse(options.input)
1181 doc = new_lustre(xml.dom.minidom)
1184 outFile = options.output
1186 lustre = doc.documentElement
1188 if lustre.tagName != "lustre":
1189 print "Existing config not valid."
1192 gen = GenConfig(doc)
1195 fp = open(options.batch)
1196 batchCommands = fp.readlines()
1198 for cmd in batchCommands:
1200 options, args = cl.parse(cmdlinesplit(cmd))
1201 if options.merge or options.input or options.output:
1202 print "The batchfile should not contain --merge, --input or --output."
1204 do_command(gen, lustre, options, args)
1205 except OptionError, e:
1207 except Lustre.OptionError, e:
1211 do_command(gen, lustre, options, args)
1212 except OptionError, e:
1213 panic(string.join(sys.argv),e)
1214 except Lustre.OptionError, e:
1220 printDoc(doc, open(outFile,"w"))
1222 if __name__ == "__main__":