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
98 --mountfsoptions options
116 --fstype ldiskfs|ext3
117 --backfstype ldiskfs|ext3|tmpfs
120 --osdtype obdecho|obdfilter
122 --mkfsoptions options
123 --mountfsoptions options
126 --add mtpt - Mountpoint
131 --ost ost_name OR --lov lov_name
137 --gateway_cluster_id nid
138 --target_cluster_id nid
145 --add mgmt - Management/monitoring service
147 --mgmt mgmt_service_name
158 PARAM = Lustre.Options.PARAM
160 # lmc input/output options
161 ('reference', "Print short reference for commands."),
162 ('verbose,v', "Print system commands as they are run."),
163 ('merge,m', "Append to the specified config file.", PARAM),
164 ('output,o', "Write XML configuration into given output file. Overwrite existing content.", PARAM),
165 ('input,i', "", PARAM),
166 ('batch', "Used to execute lmc commands in batch mode.", PARAM),
172 ('node', "Add a new node in the cluster configuration.", PARAM),
173 ('timeout', "Set timeout to initiate recovery.", PARAM),
174 ('upcall', "Set both lustre and portals upcall scripts.", PARAM),
175 ('lustre_upcall', "Set location of lustre upcall script.", PARAM),
176 ('portals_upcall', "Set location of portals upcall script.", PARAM),
177 ('ptldebug', "Set the portals debug level", PARAM),
178 ('subsystem', "Specify which Lustre subsystems have debug output recorded in the log", PARAM),
181 ('nettype', "Specify the network type. This can be tcp/elan/gm.", PARAM),
182 ('nid', "Give the network ID, e.g ElanID/IP Address as used by portals.", PARAM),
183 ('tcpbuf', "Optional argument to specify the TCP buffer size.", PARAM, "0"),
184 ('port', "Optional argument to specify the TCP port number.", PARAM, DEFAULT_PORT),
185 ('irq_affinity', "Optional argument.", PARAM, 0),
186 ('hostaddr', "", PARAM,""),
187 ('cluster_id', "Specify the cluster ID", PARAM, "0"),
190 ('route', "Add a new route for the cluster.", PARAM),
191 ('router', "Optional flag to mark a node as router."),
192 ('gw', "Specify the nid of the gateway for a route.", PARAM),
193 ('gateway_cluster_id', "", PARAM, "0"),
194 ('target_cluster_id', "", PARAM, "0"),
195 ('lo', "For a range route, this is the low value nid.", PARAM),
196 ('hi', "For a range route, this is a hi value nid.", PARAM,""),
198 # servers: mds and ost
199 ('mds', "Specify MDS name.", PARAM,""),
200 ('ost', "Specify the OST name.", PARAM,""),
201 ('osdtype', "This could obdfilter or obdecho.", PARAM, "obdfilter"),
202 ('failover', "Enable failover support on OSTs or MDS?"),
203 ('group', "", PARAM),
204 ('dev', "Path of the device on local system.", PARAM,""),
205 ('backdev', "Path of the device for backing storage on local system.", PARAM,""),
206 ('size', "Specify the size of the device if needed.", PARAM,"0"),
207 ('journal_size', "Specify new journal size for underlying file system.", PARAM,"0"),
208 ('inode_size', "Specify new inode size for underlying file system.", PARAM,"0"),
209 ('fstype', "Optional argument to specify the filesystem type.", PARAM, "ext3"),
210 ('backfstype', "Optional argument to specify the backing filesystem type.", PARAM, "ext3"),
211 ('mkfsoptions', "Optional argument to mkfs.", PARAM, ""),
212 ('mountfsoptions', "Optional argument to mount fs.", PARAM, ""),
213 ('ostuuid', "", PARAM,""),
214 ('nspath', "Local mount point of server namespace.", PARAM,""),
217 # clients: mountpoint and echo
218 ('echo_client', "", PARAM),
219 ('path', "Specify the mountpoint for Lustre.", PARAM),
220 ('filesystem', "Lustre filesystem name", PARAM,""),
223 ('lov', "Specify LOV name.", PARAM,""),
224 ('stripe_sz', "Specify the stripe size in bytes.", PARAM),
225 ('stripe_cnt', "Specify the number of OSTs each file should be striped on.", PARAM, 0),
226 ('stripe_pattern', "Specify the stripe pattern. RAID 0 is the only one currently supported.", PARAM, 0),
230 ('real_obd', "Specify the real device for the cache obd system.", PARAM),
231 ('cache_obd', "Specify the cache device for the cache obd system.", PARAM),
232 ('cobd', "Specify COBD name", PARAM),
234 ('mgmt', "Specify management/monitoring service name.", PARAM, ""),
237 ('lmv', "Specify LMV name.", PARAM,""),
241 msg = string.join(map(str,args))
242 raise OptionError("Error: " + msg)
251 msg = string.join(map(str,args))
252 print "Warning: ", msg
255 # manage names and uuids
256 # need to initialize this by walking tree to ensure
257 # no duplicate names or uuids are created.
258 # this are just place holders for now.
259 # consider changing this to be like OBD-dev-host
263 while names.has_key(ret):
264 ret = "%s_%d" % (base, ctr)
271 ret = "%s_UUID" % (name)
272 if len(ret) > UUID_MAX_LENGTH:
273 ret = ret[-UUID_MAX_LENGTH:]
274 while uuids.has_key(ret):
275 ret = "%s_UUID_%d" % (name, ctr)
277 if len(ret) > UUID_MAX_LENGTH:
278 ret = ret[-UUID_MAX_LENGTH:]
284 ldlm_uuid = 'ldlm_UUID'
287 """Create a new empty lustre document"""
288 # adding ldlm here is a bit of a hack, but one is enough.
289 str = """<lustre version="%s">
290 <ldlm name="%s" uuid="%s"/>
291 </lustre>""" % (Lustre.CONFIG_VERSION, ldlm_name, ldlm_uuid)
292 return dom.parseString(str)
298 """initialize auto-name generation tables"""
300 # get all elements that contain a name attribute
301 for n in doc.childNodes:
302 if n.nodeType == n.ELEMENT_NODE:
304 names[getName(n)] = 1
305 uuids[getUUID(n)] = 1
308 def get_format_flag(options):
313 ############################################################
314 # Build config objects using DOM
319 def __init__(self, doc):
322 def ref(self, type, uuid):
323 """ generate <[type]_ref uuidref="[uuid]"/> """
324 tag = "%s_ref" % (type)
325 ref = self.doc.createElement(tag)
326 ref.setAttribute("uuidref", uuid)
329 def newService(self, tag, name, uuid):
330 """ create a new service elmement, which requires name and uuid attributes """
331 new = self.doc.createElement(tag)
332 new.setAttribute("uuid", uuid);
333 new.setAttribute("name", name);
336 def addText(self, node, str):
337 txt = self.doc.createTextNode(str)
338 node.appendChild(txt)
340 def addElement(self, node, tag, str=None):
341 """ create a new element and add it as a child to node. If str is passed,
342 a text node is created for the new element"""
343 new = self.doc.createElement(tag)
345 self.addText(new, str)
346 node.appendChild(new)
349 def network(self, name, uuid, nid, cluster_id, net, hostaddr="",
350 port=0, tcpbuf=0, irq_aff=0):
351 """create <network> node"""
352 network = self.newService("network", name, uuid)
353 network.setAttribute("nettype", net);
354 self.addElement(network, "nid", nid)
355 self.addElement(network, "clusterid", cluster_id)
357 self.addElement(network, "hostaddr", hostaddr)
359 self.addElement(network, "port", "%d" %(port))
361 self.addElement(network, "sendmem", "%d" %(tcpbuf))
362 self.addElement(network, "recvmem", "%d" %(tcpbuf))
364 self.addElement(network, "irqaffinity", "%d" %(irq_aff))
368 def routetbl(self, name, uuid):
369 """create <routetbl> node"""
370 rtbl = self.newService("routetbl", name, uuid)
373 def route(self, gw_net_type, gw, gw_cluster_id, tgt_cluster_id, lo, hi):
374 """ create one entry for the route table """
375 ref = self.doc.createElement('route')
376 ref.setAttribute("type", gw_net_type)
377 ref.setAttribute("gw", gw)
378 ref.setAttribute("gwclusterid", gw_cluster_id)
379 ref.setAttribute("tgtclusterid", tgt_cluster_id)
380 ref.setAttribute("lo", lo)
382 ref.setAttribute("hi", hi)
385 def profile(self, name, uuid):
386 """ create a host """
387 profile = self.newService("profile", name, uuid)
390 def node(self, name, uuid, prof_uuid):
391 """ create a host """
392 node = self.newService("node", name, uuid)
393 node.appendChild(self.ref("profile", prof_uuid))
396 def ldlm(self, name, uuid):
397 """ create a ldlm """
398 ldlm = self.newService("ldlm", name, uuid)
401 def osd(self, name, uuid, fstype, osdtype, devname, format, ost_uuid,
402 node_uuid, dev_size=0, journal_size=0, inode_size=0, nspath="",
403 mkfsoptions="", mountfsoptions="", backfstype="", backdevname=""):
404 osd = self.newService("osd", name, uuid)
405 osd.setAttribute('osdtype', osdtype)
406 osd.appendChild(self.ref("target", ost_uuid))
407 osd.appendChild(self.ref("node", node_uuid))
409 self.addElement(osd, "fstype", fstype)
411 self.addElement(osd, "backfstype", backfstype)
413 self.addElement(osd, "backdevpath", backdevname)
415 dev = self.addElement(osd, "devpath", devname)
416 self.addElement(osd, "autoformat", format)
418 self.addElement(osd, "devsize", "%s" % (dev_size))
420 self.addElement(osd, "journalsize", "%s" % (journal_size))
422 self.addElement(osd, "inodesize", "%s" % (inode_size))
424 self.addElement(osd, "mkfsoptions", mkfsoptions)
426 self.addElement(osd, "mountfsoptions", mountfsoptions)
428 self.addElement(osd, "nspath", nspath)
431 def cobd(self, name, uuid, real_uuid, cache_uuid):
432 cobd = self.newService("cobd", name, uuid)
433 cobd.appendChild(self.ref("realobd",real_uuid))
434 cobd.appendChild(self.ref("cacheobd",cache_uuid))
437 def ost(self, name, uuid, osd_uuid, group=""):
438 ost = self.newService("ost", name, uuid)
439 ost.appendChild(self.ref("active", osd_uuid))
441 self.addElement(ost, "group", group)
444 def oss(self, name, uuid):
445 oss = self.newService("oss", name, uuid)
448 def lov(self, name, uuid, mds_uuid, stripe_sz, stripe_cnt, pattern):
449 lov = self.newService("lov", name, uuid)
450 lov.appendChild(self.ref("mds", mds_uuid))
451 lov.setAttribute("stripesize", str(stripe_sz))
452 lov.setAttribute("stripecount", str(stripe_cnt))
453 lov.setAttribute("stripepattern", str(pattern))
456 def lovconfig(self, name, uuid, lov_uuid):
457 lovconfig = self.newService("lovconfig", name, uuid)
458 lovconfig.appendChild(self.ref("lov", lov_uuid))
461 def lmv(self, name, uuid):
462 lmv = self.newService("lmv", name, uuid)
465 def mds(self, name, uuid, mdd_uuid, group="", lmv=""):
466 mds = self.newService("mds", name, uuid)
467 mds.appendChild(self.ref("active",mdd_uuid))
469 self.addElement(mds, "group", group)
472 def mdsdev(self, name, uuid, fstype, devname, format, node_uuid,
473 mds_uuid, dev_size=0, journal_size=0, inode_size=256,
474 nspath="", mkfsoptions="", mountfsoptions="", backfstype="",
475 backdevname="", lmv_uuid=""):
476 mdd = self.newService("mdsdev", name, uuid)
477 self.addElement(mdd, "fstype", fstype)
479 self.addElement(mdd, "backfstype", backfstype)
480 dev = self.addElement(mdd, "devpath", devname)
482 self.addElement(mdd, "backdevpath", backdevname)
483 self.addElement(mdd, "autoformat", format)
485 self.addElement(mdd, "devsize", "%s" % (dev_size))
487 self.addElement(mdd, "journalsize", "%s" % (journal_size))
489 self.addElement(mdd, "inodesize", "%s" % (inode_size))
491 self.addElement(mdd, "nspath", nspath)
493 self.addElement(mdd, "mkfsoptions", mkfsoptions)
495 self.addElement(mdd, "mountfsoptions", mountfsoptions)
497 mdd.appendChild(self.ref("node", node_uuid))
498 mdd.appendChild(self.ref("target", mds_uuid))
500 mdd.appendChild(self.ref("lmv", lmv_uuid))
501 self.addElement(mdd, "lmv", lmv_uuid)
505 def mgmt(self, mgmt_name, mgmt_uuid, node_uuid):
506 mgmt = self.newService("mgmt", mgmt_name, mgmt_uuid)
507 mgmt.appendChild(self.ref("node", node_uuid))
508 # Placeholder until mgmt-service failover.
509 mgmt.appendChild(self.ref("active", mgmt_uuid))
512 def mountpoint(self, name, uuid, fs_uuid, path):
513 mtpt = self.newService("mountpoint", name, uuid)
514 mtpt.appendChild(self.ref("filesystem", fs_uuid))
515 self.addElement(mtpt, "path", path)
518 def filesystem(self, name, uuid, mds_uuid, obd_uuid, mgmt_uuid):
519 fs = self.newService("filesystem", name, uuid)
520 fs.appendChild(self.ref("mds", mds_uuid))
521 fs.appendChild(self.ref("obd", obd_uuid))
523 fs.appendChild(self.ref("mgmt", mgmt_uuid))
526 def echo_client(self, name, uuid, osc_uuid):
527 ec = self.newService("echoclient", name, uuid)
528 ec.appendChild(self.ref("obd", osc_uuid))
531 ############################################################
532 # Utilities to query a DOM tree
533 # Using this functions we can treat use config information
534 # directly as a database.
536 return n.getAttribute('name')
539 return node.getAttribute('uuid')
542 def findByName(lustre, name, tag = ""):
543 for n in lustre.childNodes:
544 if n.nodeType == n.ELEMENT_NODE:
545 if tag and n.nodeName != tag:
547 if getName(n) == name:
550 n = findByName(n, name)
555 def lookup(node, uuid):
556 for n in node.childNodes:
557 if n.nodeType == n.ELEMENT_NODE:
558 if getUUID(n) == uuid:
566 def name2uuid(lustre, name, tag="", fatal=1):
567 ret = findByName(lustre, name, tag)
570 error('name2uuid:', '"'+name+'"', tag, 'element not found.')
575 def lookup_filesystem(lustre, mds_uuid, ost_uuid):
576 for n in lustre.childNodes:
577 if n.nodeType == n.ELEMENT_NODE and n.nodeName == 'filesystem':
578 if ref_exists(n, mds_uuid) and ref_exists(n, ost_uuid):
582 # XXX: assumes only one network element per node. will fix this
583 # as soon as support for routers is added
584 def get_net_uuid(lustre, node_name):
585 """ get a network uuid for a node_name """
586 node = findByName(lustre, node_name, "node")
588 error ('get_net_uuid:', '"'+node_name+'"', "node element not found.")
589 net = node.getElementsByTagName('network')
591 return getUUID(net[0])
595 def lov_add_obd(gen, lov, osc_uuid):
596 lov.appendChild(gen.ref("obd", osc_uuid))
598 def lmv_add_obd(gen, lmv, mdc_uuid):
599 lmv.appendChild(gen.ref("mds", mdc_uuid))
601 def ref_exists(profile, uuid):
602 elist = profile.childNodes
604 if e.nodeType == e.ELEMENT_NODE:
605 ref = e.getAttribute('uuidref')
610 # ensure that uuid is not already in the profile
611 # return true if uuid is added
612 def node_add_profile(gen, node, ref, uuid):
613 refname = "%s_ref" % "profile"
614 ret = node.getElementsByTagName(refname)
616 error('node has no profile ref:', node)
617 prof_uuid = ret[0].getAttribute('uuidref')
618 profile = lookup(node.parentNode, prof_uuid)
620 error("no profile found:", prof_uuid)
621 if ref_exists(profile, uuid):
623 profile.appendChild(gen.ref(ref, uuid))
626 def get_attr(dom_node, attr, default=""):
627 v = dom_node.getAttribute(attr)
632 ############################################################
635 def set_node_options(gen, node, options):
637 node.setAttribute('router', '1')
639 gen.addElement(node, "timeout", get_option(options, 'timeout'))
641 default_upcall = get_option(options, 'upcall')
644 if default_upcall or options.lustre_upcall:
645 if options.lustre_upcall:
646 gen.addElement(node, 'lustreUpcall', options.lustre_upcall)
648 gen.addElement(node, 'lustreUpcall', default_upcall)
649 if default_upcall or options.portals_upcall:
650 if options.portals_upcall:
651 gen.addElement(node, 'portalsUpcall', options.portals_upcall)
653 gen.addElement(node, 'portalsUpcall', default_upcall)
655 gen.addElement(node, "ptldebug", get_option(options, 'ptldebug'))
656 if options.subsystem:
657 gen.addElement(node, "subsystem", get_option(options, 'subsystem'))
660 def do_add_node(gen, lustre, options, node_name):
661 uuid = new_uuid(node_name)
662 prof_name = new_name("PROFILE_" + node_name)
663 prof_uuid = new_uuid(prof_name)
664 profile = gen.profile(prof_name, prof_uuid)
665 node = gen.node(node_name, uuid, prof_uuid)
666 lustre.appendChild(node)
667 lustre.appendChild(profile)
669 node_add_profile(gen, node, 'ldlm', ldlm_uuid)
670 set_node_options(gen, node, options)
674 def add_node(gen, lustre, options):
675 """ create a node with a network config """
677 node_name = get_option(options, 'node')
678 ret = findByName(lustre, node_name, "node")
680 print "Node:", node_name, "exists."
682 do_add_node(gen, lustre, options, node_name)
685 def add_net(gen, lustre, options):
686 """ create a node with a network config """
688 node_name = get_option(options, 'node')
689 nid = get_option(options, 'nid')
690 cluster_id = get_option(options, 'cluster_id')
691 hostaddr = get_option(options, 'hostaddr')
692 net_type = get_option(options, 'nettype')
694 if net_type in ('tcp',):
695 port = get_option_int(options, 'port')
696 tcpbuf = get_option_int(options, 'tcpbuf')
697 irq_aff = get_option_int(options, 'irq_affinity')
698 elif net_type in ('elan', 'gm'):
703 print "Unknown net_type: ", net_type
706 ret = findByName(lustre, node_name, "node")
708 node = do_add_node(gen, lustre, options, node_name)
711 set_node_options(gen, node, options)
713 net_name = new_name('NET_'+ node_name +'_'+ net_type)
714 net_uuid = new_uuid(net_name)
715 node.appendChild(gen.network(net_name, net_uuid, nid, cluster_id, net_type,
716 hostaddr, port, tcpbuf, irq_aff))
717 node_add_profile(gen, node, "network", net_uuid)
720 def add_route(gen, lustre, options):
721 """ create a node with a network config """
723 node_name = get_option(options, 'node')
724 gw_net_type = get_option(options, 'nettype')
725 gw = get_option(options, 'gw')
726 gw_cluster_id = get_option(options, 'gateway_cluster_id')
727 tgt_cluster_id = get_option(options, 'target_cluster_id')
728 lo = get_option(options, 'lo')
729 hi = get_option(options, 'hi')
733 node = findByName(lustre, node_name, "node")
735 error (node_name, " not found.")
737 rlist = node.getElementsByTagName('routetbl')
741 rtbl_name = new_name("RTBL_" + node_name)
742 rtbl_uuid = new_uuid(rtbl_name)
743 rtbl = gen.routetbl(rtbl_name, rtbl_uuid)
744 node.appendChild(rtbl)
745 node_add_profile(gen, node, "routetbl", rtbl_uuid)
746 rtbl.appendChild(gen.route(gw_net_type, gw, gw_cluster_id, tgt_cluster_id,
750 def add_mds(gen, lustre, options):
751 node_name = get_option(options, 'node')
752 mds_name = get_option(options, 'mds')
753 lmv_name = get_option(options, 'lmv')
754 mdd_name = new_name("MDD_" + mds_name +"_" + node_name)
755 mdd_uuid = new_uuid(mdd_name)
759 lmv = findByName(lustre, lmv_name, "lmv")
761 error('add_mds:', '"' + lmv_name + '"', "lmv element not found.")
762 lmv_uuid = name2uuid(lustre, lmv_name, fatal=0)
764 mds_uuid = name2uuid(lustre, mds_name, 'mds', fatal=0)
766 mds_uuid = new_uuid(mds_name)
767 mds = gen.mds(mds_name, mds_uuid, mdd_uuid, options.group)
768 lustre.appendChild(mds)
770 lmv_add_obd(gen, lmv, mds_uuid)
772 mds = lookup(lustre, mds_uuid)
775 mds.setAttribute('failover', "1")
777 devname = get_option(options, 'dev')
778 backdevname = get_option(options, 'backdev')
779 size = get_option(options, 'size')
780 fstype = get_option(options, 'fstype')
781 backfstype = get_option(options, 'backfstype')
782 journal_size = get_option(options, 'journal_size')
783 inode_size = get_option(options, 'inode_size')
784 nspath = get_option(options, 'nspath')
785 mkfsoptions = get_option(options, 'mkfsoptions')
786 mountfsoptions = get_option(options, 'mountfsoptions')
788 node_uuid = name2uuid(lustre, node_name, 'node')
790 node = findByName(lustre, node_name, "node")
791 node_add_profile(gen, node, "mdsdev", mdd_uuid)
792 net_uuid = get_net_uuid(lustre, node_name)
794 error("NODE: ", node_name, "not found")
797 mds.appendChild(gen.ref("lmv", lmv_uuid))
799 mdd = gen.mdsdev(mdd_name, mdd_uuid, fstype, devname,
800 get_format_flag(options), node_uuid, mds_uuid,
801 size, journal_size, inode_size, nspath, mkfsoptions,
802 mountfsoptions, backfstype, backdevname, lmv_uuid)
803 lustre.appendChild(mdd)
806 def add_mgmt(gen, lustre, options):
807 node_name = get_option(options, 'node')
808 node_uuid = name2uuid(lustre, node_name, 'node')
809 mgmt_name = get_option(options, 'mgmt')
811 mgmt_name = new_name('MGMT_' + node_name)
812 mgmt_uuid = name2uuid(lustre, mgmt_name, 'mgmt', fatal=0)
814 mgmt_uuid = new_uuid(mgmt_name)
815 mgmt = gen.mgmt(mgmt_name, mgmt_uuid, node_uuid)
816 lustre.appendChild(mgmt)
818 mgmt = lookup(lustre, mgmt_uuid)
820 node = findByName(lustre, node_name, "node")
821 node_add_profile(gen, node, 'mgmt', mgmt_uuid)
823 def add_ost(gen, lustre, options):
824 node_name = get_option(options, 'node')
825 lovname = get_option(options, 'lov')
826 osdtype = get_option(options, 'osdtype')
828 node_uuid = name2uuid(lustre, node_name, 'node')
830 if osdtype == 'obdecho':
841 devname = get_option(options, 'dev') # can be unset for bluearcs
842 backdevname = get_option(options, 'backdev')
843 size = get_option(options, 'size')
844 fstype = get_option(options, 'fstype')
845 backfstype = get_option(options, 'backfstype')
846 journal_size = get_option(options, 'journal_size')
847 inode_size = get_option(options, 'inode_size')
848 mkfsoptions = get_option(options, 'mkfsoptions')
849 mountfsoptions = get_option(options, 'mountfsoptions')
851 nspath = get_option(options, 'nspath')
853 ostname = get_option(options, 'ost')
855 ostname = new_name('OST_'+ node_name)
857 osdname = new_name("OSD_" + ostname + "_" + node_name)
858 osd_uuid = new_uuid(osdname)
860 ost_uuid = name2uuid(lustre, ostname, 'ost', fatal=0)
862 ost_uuid = get_option(options, 'ostuuid')
864 if lookup(lustre, ost_uuid):
865 error("Duplicate OST UUID:", ost_uuid)
867 ost_uuid = new_uuid(ostname)
869 ost = gen.ost(ostname, ost_uuid, osd_uuid, options.group)
870 lustre.appendChild(ost)
872 lov = findByName(lustre, lovname, "lov")
874 error('add_ost:', '"'+lovname+'"', "lov element not found.")
875 lov_add_obd(gen, lov, ost_uuid)
877 ost = lookup(lustre, ost_uuid)
880 ost.setAttribute('failover', "1")
883 osd = gen.osd(osdname, osd_uuid, fstype, osdtype, devname,
884 get_format_flag(options), ost_uuid, node_uuid, size,
885 journal_size, inode_size, nspath, mkfsoptions,
886 mountfsoptions, backfstype, backdevname)
888 node = findByName(lustre, node_name, "node")
890 ## if node_add_profile(gen, node, 'oss', oss_uuid):
892 ## oss_uuid = new_uuid(ossname)
893 ## oss = gen.oss(ossname, oss_uuid)
894 ## lustre.appendChild(oss)
896 node_add_profile(gen, node, 'osd', osd_uuid)
897 lustre.appendChild(osd)
900 def add_cobd(gen, lustre, options):
901 node_name = get_option(options, 'node')
902 name = get_option(options, 'cobd')
903 uuid = new_uuid(name)
905 real_name = get_option(options, 'real_obd')
906 cache_name = get_option(options, 'cache_obd')
908 real_uuid = name2uuid(lustre, real_name, tag='lov', fatal=0)
909 cache_uuid = name2uuid(lustre, cache_name, tag='lov', fatal=0)
912 node = lookup(lustre, real_uuid)
913 rets = node.getElementsByTagName('obd_ref')
915 ost_uuid = ret.getAttribute('uuidref')
916 ost_node = lookup(lustre, ost_uuid)
917 ret = ost_node.getElementsByTagName('active_ref')
919 osd_uuid = ret[0].getAttribute('uuidref')
920 osd_node = lookup(lustre, osd_uuid)
921 gen.addElement(osd_node, 'cachetype', 'master')
924 node = lookup(lustre, cache_uuid)
925 rets = node.getElementsByTagName('obd_ref')
927 ost_uuid = ret.getAttribute('uuidref')
928 ost_node = lookup(lustre, ost_uuid)
929 ret = ost_node.getElementsByTagName('active_ref')
931 osd_uuid = ret[0].getAttribute('uuidref')
932 osd_node = lookup(lustre, osd_uuid)
933 gen.addElement(osd_node, 'cachetype', 'cache')
935 if not real_uuid or not cache_uuid:
936 real_uuid = name2uuid(lustre,real_name, tag='mds')
937 cache_uuid = name2uuid(lustre,cache_name, tag='mds')
939 mds_node = lookup(lustre, real_uuid)
940 ret = mds_node.getElementsByTagName('active_ref')
942 mdsdev_uuid = ret[0].getAttribute('uuidref')
943 mdsdev_node = lookup(lustre, mdsdev_uuid)
944 gen.addElement(mdsdev_node, 'cachetype', 'master')
946 mds_node = lookup(lustre, cache_uuid)
947 ret = mds_node.getElementsByTagName('active_ref')
949 mdsdev_uuid = ret[0].getAttribute('uuidref')
950 mdsdev_node = lookup(lustre, mdsdev_uuid)
951 gen.addElement(mdsdev_node, 'cachetype', 'cache')
953 node = findByName(lustre, node_name, "node")
954 cobd = gen.cobd(name, uuid, real_uuid, cache_uuid)
955 lustre.appendChild(cobd)
958 def add_echo_client(gen, lustre, options):
959 """ add an echo client to the profile for this node. """
960 node_name = get_option(options, 'node')
961 lov_name = get_option(options, 'ost')
963 node = findByName(lustre, node_name, 'node')
965 echoname = new_name('ECHO_'+ node_name)
966 echo_uuid = new_uuid(echoname)
967 node_add_profile(gen, node, 'echoclient', echo_uuid)
969 lov_uuid = name2uuid(lustre, lov_name, tag='lov', fatal=0)
971 lov_uuid = name2uuid(lustre, lov_name, tag='ost', fatal=1)
973 echo = gen.echo_client(echoname, echo_uuid, lov_uuid)
974 lustre.appendChild(echo)
977 def add_lov(gen, lustre, options):
980 lmv_name = get_option(options, 'lmv')
981 lov_orig = get_option(options, 'lov')
982 name = new_name(lov_orig)
984 warning("name:", lov_orig, "already used. using:", name)
986 mds_name = get_option(options, 'mds')
989 error("LOV: MDS or LMV must be specified.");
991 stripe_sz = get_option_int(options, 'stripe_sz')
992 stripe_cnt = get_option_int(options, 'stripe_cnt')
993 pattern = get_option_int(options, 'stripe_pattern')
994 uuid = new_uuid(name)
996 ret = findByName(lustre, name, "lov")
998 error("LOV: ", name, " already exists.")
1001 mds_uuid = name2uuid(lustre, lmv_name, 'lmv')
1003 mds_uuid = name2uuid(lustre, mds_name, 'mds')
1005 lov = gen.lov(name, uuid, mds_uuid, stripe_sz, stripe_cnt, pattern)
1006 lustre.appendChild(lov)
1008 # add an lovconfig entry to the active mdsdev profile
1009 lovconfig_name = new_name('LVCFG_' + name)
1010 lovconfig_uuid = new_uuid(lovconfig_name)
1012 mds = findByName(lustre, mds_name, "mds")
1013 mds.appendChild(gen.ref("lovconfig", lovconfig_uuid))
1015 lmv = findByName(lustre, lmv_name, "lmv")
1016 lmv.appendChild(gen.ref("lovconfig", lovconfig_uuid))
1017 lovconfig = gen.lovconfig(lovconfig_name, lovconfig_uuid, uuid)
1018 lustre.appendChild(lovconfig)
1020 def add_default_lov(gen, lustre, mds_name, lov_name):
1021 """ create a default lov """
1023 stripe_sz = DEFAULT_STRIPE_SZ
1024 stripe_cnt = DEFAULT_STRIPE_CNT
1025 pattern = DEFAULT_STRIPE_PATTERN
1026 uuid = new_uuid(lov_name)
1028 ret = findByName(lustre, lov_name, "lov")
1030 error("LOV: ", lov_name, " already exists.")
1032 mds_uuid = name2uuid(lustre, mds_name, 'mds')
1033 lov = gen.lov(lov_name, uuid, mds_uuid, stripe_sz, stripe_cnt, pattern)
1034 lustre.appendChild(lov)
1036 # add an lovconfig entry to the active mdsdev profile
1037 lovconfig_name = new_name('LVCFG_' + lov_name)
1038 lovconfig_uuid = new_uuid(lovconfig_name)
1039 mds = findByName(lustre, mds_name)
1040 mds.appendChild(gen.ref("lovconfig", lovconfig_uuid))
1041 lovconfig = gen.lovconfig(lovconfig_name, lovconfig_uuid, uuid)
1042 lustre.appendChild(lovconfig)
1044 def add_lmv(gen, lustre, options):
1045 """ create a lmv """
1047 lmv_orig = get_option(options, 'lmv')
1048 name = new_name(lmv_orig)
1049 if name != lmv_orig:
1050 warning("name:", lmv_orig, "already used. using:", name)
1052 uuid = new_uuid(name)
1053 ret = findByName(lustre, name, "lmv")
1055 error("LMV: ", name, " already exists.")
1057 lmv = gen.lmv(name, uuid)
1058 lustre.appendChild(lmv)
1060 def new_filesystem(gen, lustre, mds_uuid, obd_uuid, mgmt_uuid):
1061 fs_name = new_name("FS_fsname")
1062 fs_uuid = new_uuid(fs_name)
1063 cobd = lookup(lustre, mds_uuid)
1064 #SHOULD appendChild filesystem to real mds not cobd
1065 ret = cobd.getElementsByTagName("cacheobd_ref")
1067 cacheobd_uuid = ret[0].getAttribute('uuidref')
1068 cacheobd = lookup(lustre, cacheobd_uuid)
1069 cacheobd.appendChild(gen.ref("filesystem", fs_uuid))
1070 ret = cobd.getElementsByTagName("realobd_ref")
1072 realobd_uuid = ret[0].getAttribute('uuidref')
1073 realobd = lookup(lustre, realobd_uuid)
1074 realobd.appendChild(gen.ref("filesystem", fs_uuid))
1076 cobd.appendChild(gen.ref("filesystem", fs_uuid))
1077 fs = gen.filesystem(fs_name, fs_uuid, mds_uuid, obd_uuid, mgmt_uuid)
1078 lustre.appendChild(fs)
1081 def get_fs_uuid(gen, lustre, mds_name, obd_name, mgmt_name):
1082 mds_uuid = name2uuid(lustre, mds_name, tag='mds', fatal=0)
1084 mds_uuid = name2uuid(lustre, mds_name, tag='lmv', fatal=0)
1086 mds_uuid = name2uuid(lustre, mds_name, tag='cobd', fatal=1)
1087 obd_uuid = name2uuid(lustre, obd_name, tag='lov', fatal=0)
1089 obd_uuid = name2uuid(lustre, obd_name, tag='cobd')
1091 mgmt_uuid = name2uuid(lustre, mgmt_name, tag='mgmt', fatal=1)
1094 fs_uuid = lookup_filesystem(lustre, mds_uuid, obd_uuid)
1096 fs_uuid = new_filesystem(gen, lustre, mds_uuid, obd_uuid, mgmt_uuid)
1099 def add_mtpt(gen, lustre, options):
1100 """ create mtpt on a node """
1101 node_name = get_option(options, 'node')
1103 path = get_option(options, 'path')
1104 fs_name = get_option(options, 'filesystem')
1106 lov_name = get_option(options, 'lov')
1107 ost_name = get_option(options, 'ost')
1108 mds_name = get_option(options, 'mds')
1110 mds_name = get_option(options, 'lmv')
1112 error("--add mtpt requires either --mds or --lmv.")
1115 error("--add mtpt requires --lov lov_name or --ost ost_name")
1117 warning("use default value for lov, due no --lov lov_name provided")
1118 lov_name = new_name("lov_default")
1119 add_default_lov(gen, lustre, mds_name, lov_name)
1120 ost_uuid = name2uuid(lustre, ost_name, 'ost', fatal=0)
1122 error('add_mtpt:', '"'+ost_name+'"', "ost element not found.")
1123 lov = findByName(lustre, lov_name, "lov")
1124 lov_add_obd(gen, lov, ost_uuid)
1127 mgmt_name = get_option(options, 'mgmt')
1128 fs_uuid = get_fs_uuid(gen, lustre, mds_name, lov_name, mgmt_name)
1130 fs_uuid = name2uuid(lustre, fs_name, tag='filesystem')
1132 name = new_name('MNT_'+ node_name)
1134 ret = findByName(lustre, name, "mountpoint")
1136 # this can't happen, because new_name creates unique names
1137 error("MOUNTPOINT: ", name, " already exists.")
1139 uuid = new_uuid(name)
1140 mtpt = gen.mountpoint(name, uuid, fs_uuid, path)
1141 node = findByName(lustre, node_name, "node")
1143 error('node:', node_name, "not found.")
1144 node_add_profile(gen, node, "mountpoint", uuid)
1145 lustre.appendChild(mtpt)
1147 ############################################################
1148 # Command line processing
1150 class OptionError (exceptions.Exception):
1151 def __init__(self, args):
1154 def get_option(options, tag):
1155 """Look for tag in options hash and return the value if set. If not
1156 set, then if return default it is set, otherwise exception."""
1157 if options.__getattr__(tag) != None:
1158 return options.__getattr__(tag)
1160 raise OptionError("--add %s requires --%s <value>" % (options.add, tag))
1162 def get_option_int(options, tag):
1163 """Return an integer option. Raise exception if the value is not an int"""
1164 val = get_option(options, tag)
1168 raise OptionError("--%s <num> (value must be integer)" % (tag))
1171 # simple class for profiling
1178 self._start = time.time()
1179 def stop(self, msg=''):
1180 self._stop = time.time()
1184 return self._stop - self._start
1185 def display(self, msg):
1187 str = '%s: %g secs' % (msg, d)
1190 #################################################################
1191 # function cmdlinesplit used to split cmd line from batch file
1193 def cmdlinesplit(cmdline):
1195 double_quote = re.compile(r'"(([^"\\]|\\.)*)"')
1196 single_quote = re.compile(r"'(.*?)'")
1197 escaped = re.compile(r'\\(.)')
1198 esc_quote = re.compile(r'\\([\\"])')
1199 outside = re.compile(r"""([^\s\\'"]+)""")
1203 while i < len(cmdline):
1206 match = double_quote.match(cmdline, i)
1208 print "Unmatched double quote:", cmdline
1211 if arg is None: arg = esc_quote.sub(r'\1', match.group(1))
1212 else: arg = arg + esc_quote.sub(r'\1', match.group(1))
1215 match = single_quote.match(cmdline, i)
1217 print "Unmatched single quote:", cmdline
1220 if arg is None: arg = match.group(1)
1221 else: arg = arg + match.group(1)
1224 match = escaped.match(cmdline, i)
1226 print "Unmatched backslash", cmdline
1229 if arg is None: arg = match.group(1)
1230 else: arg = arg + match.group(1)
1232 elif c in string.whitespace:
1234 arg_list.append(str(arg))
1236 while i < len(cmdline) and cmdline[i] in string.whitespace:
1239 match = outside.match(cmdline, i)
1242 if arg is None: arg = match.group()
1243 else: arg = arg + match.group()
1245 if arg != None: arg_list.append(str(arg))
1249 ############################################################
1253 def add(devtype, gen, lustre, options):
1254 if devtype == 'net':
1255 add_net(gen, lustre, options)
1256 elif devtype == 'mtpt':
1257 add_mtpt(gen, lustre, options)
1258 elif devtype == 'mds':
1259 add_mds(gen, lustre, options)
1260 elif devtype == 'ost':
1261 add_ost(gen, lustre, options)
1262 elif devtype == 'lov':
1263 add_lov(gen, lustre, options)
1264 elif devtype == 'route':
1265 add_route(gen, lustre, options)
1266 elif devtype == 'node':
1267 add_node(gen, lustre, options)
1268 elif devtype == 'echo_client':
1269 add_echo_client(gen, lustre, options)
1270 elif devtype == 'cobd':
1271 add_cobd(gen, lustre, options)
1272 elif devtype == 'mgmt':
1273 add_mgmt(gen, lustre, options)
1274 elif devtype == 'lmv':
1275 add_lmv(gen, lustre, options)
1277 error("unknown device type:", devtype)
1279 def do_command(gen, lustre, options, args):
1281 add(options.add, gen, lustre, options)
1283 error("Missing command")
1286 cl = Lustre.Options("lmc", "", lmc_options)
1288 options, args = cl.parse(sys.argv[1:])
1289 except Lustre.OptionError, e:
1293 panic(string.join(sys.argv), "Unexpected extra arguments on command line: " + string.join(args))
1295 if options.reference:
1302 outFile = options.merge
1303 if os.access(outFile, os.R_OK):
1304 doc = xml.dom.minidom.parse(outFile)
1306 doc = new_lustre(xml.dom.minidom)
1308 doc = xml.dom.minidom.parse(options.input)
1310 doc = new_lustre(xml.dom.minidom)
1313 outFile = options.output
1315 lustre = doc.documentElement
1317 if lustre.tagName != "lustre":
1318 print "Existing config not valid."
1321 gen = GenConfig(doc)
1324 fp = open(options.batch)
1325 batchCommands = fp.readlines()
1327 for cmd in batchCommands:
1329 options, args = cl.parse(cmdlinesplit(cmd))
1330 if options.merge or options.input or options.output:
1331 print "The batchfile should not contain --merge, --input or --output."
1333 do_command(gen, lustre, options, args)
1334 except OptionError, e:
1336 except Lustre.OptionError, e:
1340 do_command(gen, lustre, options, args)
1341 except OptionError, e:
1342 panic(string.join(sys.argv),e)
1343 except Lustre.OptionError, e:
1349 printDoc(doc, open(outFile,"w"))
1351 if __name__ == "__main__":