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 ldiskfs|ext3|tmpfs
97 --mountfsoptions options
114 --fstype ldiskfs|ext3
115 --backfstype ldiskfs|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 file system.", PARAM,"0"),
202 ('inode_size', "Specify new inode size for underlying 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, fstype, osdtype, devname, format, ost_uuid,
391 node_uuid, dev_size=0, journal_size=0, inode_size=0, nspath="",
392 mkfsoptions="", mountfsoptions="", backfstype="", 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", fstype)
400 self.addElement(osd, "backfstype", backfstype)
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, fstype, devname, format, node_uuid,
458 mds_uuid, dev_size=0, journal_size=0, inode_size=256,
459 nspath="", mkfsoptions="", mountfsoptions="", backfstype="",
461 mdd = self.newService("mdsdev", name, uuid)
462 self.addElement(mdd, "fstype", fstype)
464 self.addElement(mdd, "backfstype", backfstype)
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':
805 devname = get_option(options, 'dev') # can be unset for bluearcs
806 backdevname = get_option(options, 'backdev')
807 size = get_option(options, 'size')
808 fstype = get_option(options, 'fstype')
809 backfstype = get_option(options, 'backfstype')
810 journal_size = get_option(options, 'journal_size')
811 inode_size = get_option(options, 'inode_size')
812 mkfsoptions = get_option(options, 'mkfsoptions')
813 mountfsoptions = get_option(options, 'mountfsoptions')
815 nspath = get_option(options, 'nspath')
817 ostname = get_option(options, 'ost')
819 ostname = new_name('OST_'+ node_name)
821 osdname = new_name("OSD_" + ostname + "_" + node_name)
822 osd_uuid = new_uuid(osdname)
824 ost_uuid = name2uuid(lustre, ostname, 'ost', fatal=0)
826 ost_uuid = get_option(options, 'ostuuid')
828 if lookup(lustre, ost_uuid):
829 error("Duplicate OST UUID:", ost_uuid)
831 ost_uuid = new_uuid(ostname)
833 ost = gen.ost(ostname, ost_uuid, osd_uuid, options.group)
834 lustre.appendChild(ost)
836 lov = findByName(lustre, lovname, "lov")
838 error('add_ost:', '"'+lovname+'"', "lov element not found.")
839 lov_add_obd(gen, lov, ost_uuid)
841 ost = lookup(lustre, ost_uuid)
844 ost.setAttribute('failover', "1")
847 osd = gen.osd(osdname, osd_uuid, fstype, osdtype, devname,
848 get_format_flag(options), ost_uuid, node_uuid, size,
849 journal_size, inode_size, nspath, mkfsoptions,
850 mountfsoptions, backfstype, backdevname)
852 node = findByName(lustre, node_name, "node")
854 ## if node_add_profile(gen, node, 'oss', oss_uuid):
856 ## oss_uuid = new_uuid(ossname)
857 ## oss = gen.oss(ossname, oss_uuid)
858 ## lustre.appendChild(oss)
860 node_add_profile(gen, node, 'osd', osd_uuid)
861 lustre.appendChild(osd)
864 def add_cobd(gen, lustre, options):
865 node_name = get_option(options, 'node')
866 name = new_name('COBD_' + node_name)
867 uuid = new_uuid(name)
869 real_name = get_option(options, 'real_obd')
870 cache_name = get_option(options, 'cache_obd')
872 real_uuid = name2uuid(lustre, real_name, tag='obd')
873 cache_uuid = name2uuid(lustre, cache_name, tag='obd')
875 node = findByName(lustre, node_name, "node")
876 node_add_profile(gen, node, "cobd", uuid)
877 cobd = gen.cobd(name, uuid, real_uuid, cache_uuid)
878 lustre.appendChild(cobd)
881 def add_echo_client(gen, lustre, options):
882 """ add an echo client to the profile for this node. """
883 node_name = get_option(options, 'node')
884 lov_name = get_option(options, 'ost')
886 node = findByName(lustre, node_name, 'node')
888 echoname = new_name('ECHO_'+ node_name)
889 echo_uuid = new_uuid(echoname)
890 node_add_profile(gen, node, 'echoclient', echo_uuid)
892 lov_uuid = name2uuid(lustre, lov_name, tag='lov', fatal=0)
894 lov_uuid = name2uuid(lustre, lov_name, tag='ost', fatal=1)
896 echo = gen.echo_client(echoname, echo_uuid, lov_uuid)
897 lustre.appendChild(echo)
900 def add_lov(gen, lustre, options):
903 lov_orig = get_option(options, 'lov')
904 name = new_name(lov_orig)
906 warning("name:", lov_orig, "already used. using:", name)
908 mds_name = get_option(options, 'mds')
909 stripe_sz = get_option_int(options, 'stripe_sz')
910 stripe_cnt = get_option_int(options, 'stripe_cnt')
911 pattern = get_option_int(options, 'stripe_pattern')
912 uuid = new_uuid(name)
914 ret = findByName(lustre, name, "lov")
916 error("LOV: ", name, " already exists.")
918 mds_uuid = name2uuid(lustre, mds_name, 'mds')
919 lov = gen.lov(name, uuid, mds_uuid, stripe_sz, stripe_cnt, pattern)
920 lustre.appendChild(lov)
922 # add an lovconfig entry to the active mdsdev profile
923 lovconfig_name = new_name('LVCFG_' + name)
924 lovconfig_uuid = new_uuid(lovconfig_name)
925 mds = findByName(lustre, mds_name, "mds")
926 mds.appendChild(gen.ref("lovconfig", lovconfig_uuid))
927 lovconfig = gen.lovconfig(lovconfig_name, lovconfig_uuid, uuid)
928 lustre.appendChild(lovconfig)
930 def add_default_lov(gen, lustre, mds_name, lov_name):
931 """ create a default lov """
933 stripe_sz = DEFAULT_STRIPE_SZ
934 stripe_cnt = DEFAULT_STRIPE_CNT
935 pattern = DEFAULT_STRIPE_PATTERN
936 uuid = new_uuid(lov_name)
938 ret = findByName(lustre, lov_name, "lov")
940 error("LOV: ", lov_name, " already exists.")
942 mds_uuid = name2uuid(lustre, mds_name, 'mds')
943 lov = gen.lov(lov_name, uuid, mds_uuid, stripe_sz, stripe_cnt, pattern)
944 lustre.appendChild(lov)
946 # add an lovconfig entry to the active mdsdev profile
947 lovconfig_name = new_name('LVCFG_' + lov_name)
948 lovconfig_uuid = new_uuid(lovconfig_name)
949 mds = findByName(lustre, mds_name)
950 mds.appendChild(gen.ref("lovconfig", lovconfig_uuid))
951 lovconfig = gen.lovconfig(lovconfig_name, lovconfig_uuid, uuid)
952 lustre.appendChild(lovconfig)
954 def new_filesystem(gen, lustre, mds_uuid, obd_uuid, mgmt_uuid):
955 fs_name = new_name("FS_fsname")
956 fs_uuid = new_uuid(fs_name)
957 mds = lookup(lustre, mds_uuid)
958 mds.appendChild(gen.ref("filesystem", fs_uuid))
959 fs = gen.filesystem(fs_name, fs_uuid, mds_uuid, obd_uuid, mgmt_uuid)
960 lustre.appendChild(fs)
963 def get_fs_uuid(gen, lustre, mds_name, obd_name, mgmt_name):
964 mds_uuid = name2uuid(lustre, mds_name, tag='mds')
965 obd_uuid = name2uuid(lustre, obd_name, tag='lov', fatal=0)
967 mgmt_uuid = name2uuid(lustre, mgmt_name, tag='mgmt', fatal=1)
970 fs_uuid = lookup_filesystem(lustre, mds_uuid, obd_uuid)
972 fs_uuid = new_filesystem(gen, lustre, mds_uuid, obd_uuid, mgmt_uuid)
975 def add_mtpt(gen, lustre, options):
976 """ create mtpt on a node """
977 node_name = get_option(options, 'node')
979 path = get_option(options, 'path')
980 fs_name = get_option(options, 'filesystem')
982 lov_name = get_option(options, 'lov')
983 ost_name = get_option(options, 'ost')
984 mds_name = get_option(options, 'mds')
987 error("--add mtpt requires --lov lov_name or --ost ost_name")
989 warning("use default value for lov, due no --lov lov_name provided")
990 lov_name = new_name("lov_default")
991 add_default_lov(gen, lustre, mds_name, lov_name)
992 ost_uuid = name2uuid(lustre, ost_name, 'ost', fatal=0)
994 error('add_mtpt:', '"'+ost_name+'"', "ost element not found.")
995 lov = findByName(lustre, lov_name, "lov")
996 lov_add_obd(gen, lov, ost_uuid)
999 mgmt_name = get_option(options, 'mgmt')
1000 fs_uuid = get_fs_uuid(gen, lustre, mds_name, lov_name, mgmt_name)
1002 fs_uuid = name2uuid(lustre, fs_name, tag='filesystem')
1004 name = new_name('MNT_'+ node_name)
1006 ret = findByName(lustre, name, "mountpoint")
1008 # this can't happen, because new_name creates unique names
1009 error("MOUNTPOINT: ", name, " already exists.")
1011 uuid = new_uuid(name)
1012 mtpt = gen.mountpoint(name, uuid, fs_uuid, path)
1013 node = findByName(lustre, node_name, "node")
1015 error('node:', node_name, "not found.")
1016 node_add_profile(gen, node, "mountpoint", uuid)
1017 lustre.appendChild(mtpt)
1019 ############################################################
1020 # Command line processing
1022 class OptionError (exceptions.Exception):
1023 def __init__(self, args):
1026 def get_option(options, tag):
1027 """Look for tag in options hash and return the value if set. If not
1028 set, then if return default it is set, otherwise exception."""
1029 if options.__getattr__(tag) != None:
1030 return options.__getattr__(tag)
1032 raise OptionError("--add %s requires --%s <value>" % (options.add, tag))
1034 def get_option_int(options, tag):
1035 """Return an integer option. Raise exception if the value is not an int"""
1036 val = get_option(options, tag)
1040 raise OptionError("--%s <num> (value must be integer)" % (tag))
1043 # simple class for profiling
1050 self._start = time.time()
1051 def stop(self, msg=''):
1052 self._stop = time.time()
1056 return self._stop - self._start
1057 def display(self, msg):
1059 str = '%s: %g secs' % (msg, d)
1062 #################################################################
1063 # function cmdlinesplit used to split cmd line from batch file
1065 def cmdlinesplit(cmdline):
1067 double_quote = re.compile(r'"(([^"\\]|\\.)*)"')
1068 single_quote = re.compile(r"'(.*?)'")
1069 escaped = re.compile(r'\\(.)')
1070 esc_quote = re.compile(r'\\([\\"])')
1071 outside = re.compile(r"""([^\s\\'"]+)""")
1075 while i < len(cmdline):
1078 match = double_quote.match(cmdline, i)
1080 print "Unmatched double quote:", cmdline
1083 if arg is None: arg = esc_quote.sub(r'\1', match.group(1))
1084 else: arg = arg + esc_quote.sub(r'\1', match.group(1))
1087 match = single_quote.match(cmdline, i)
1089 print "Unmatched single quote:", cmdline
1092 if arg is None: arg = match.group(1)
1093 else: arg = arg + match.group(1)
1096 match = escaped.match(cmdline, i)
1098 print "Unmatched backslash", cmdline
1101 if arg is None: arg = match.group(1)
1102 else: arg = arg + match.group(1)
1104 elif c in string.whitespace:
1106 arg_list.append(str(arg))
1108 while i < len(cmdline) and cmdline[i] in string.whitespace:
1111 match = outside.match(cmdline, i)
1114 if arg is None: arg = match.group()
1115 else: arg = arg + match.group()
1117 if arg != None: arg_list.append(str(arg))
1121 ############################################################
1125 def add(devtype, gen, lustre, options):
1126 if devtype == 'net':
1127 add_net(gen, lustre, options)
1128 elif devtype == 'mtpt':
1129 add_mtpt(gen, lustre, options)
1130 elif devtype == 'mds':
1131 add_mds(gen, lustre, options)
1132 elif devtype == 'ost':
1133 add_ost(gen, lustre, options)
1134 elif devtype == 'lov':
1135 add_lov(gen, lustre, options)
1136 elif devtype == 'route':
1137 add_route(gen, lustre, options)
1138 elif devtype == 'node':
1139 add_node(gen, lustre, options)
1140 elif devtype == 'echo_client':
1141 add_echo_client(gen, lustre, options)
1142 elif devtype == 'cobd':
1143 add_cobd(gen, lustre, options)
1144 elif devtype == 'mgmt':
1145 add_mgmt(gen, lustre, options)
1147 error("unknown device type:", devtype)
1149 def do_command(gen, lustre, options, args):
1151 add(options.add, gen, lustre, options)
1153 error("Missing command")
1156 cl = Lustre.Options("lmc", "", lmc_options)
1158 options, args = cl.parse(sys.argv[1:])
1159 except Lustre.OptionError, e:
1163 panic(string.join(sys.argv), "Unexpected extra arguments on command line: " + string.join(args))
1165 if options.reference:
1172 outFile = options.merge
1173 if os.access(outFile, os.R_OK):
1174 doc = xml.dom.minidom.parse(outFile)
1176 doc = new_lustre(xml.dom.minidom)
1178 doc = xml.dom.minidom.parse(options.input)
1180 doc = new_lustre(xml.dom.minidom)
1183 outFile = options.output
1185 lustre = doc.documentElement
1187 if lustre.tagName != "lustre":
1188 print "Existing config not valid."
1191 gen = GenConfig(doc)
1194 fp = open(options.batch)
1195 batchCommands = fp.readlines()
1197 for cmd in batchCommands:
1199 options, args = cl.parse(cmdlinesplit(cmd))
1200 if options.merge or options.input or options.output:
1201 print "The batchfile should not contain --merge, --input or --output."
1203 do_command(gen, lustre, options, args)
1204 except OptionError, e:
1206 except Lustre.OptionError, e:
1210 do_command(gen, lustre, options, args)
1211 except OptionError, e:
1212 panic(string.join(sys.argv),e)
1213 except Lustre.OptionError, e:
1219 printDoc(doc, open(outFile,"w"))
1221 if __name__ == "__main__":