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
30 from xml.dom.ext import PrettyPrint
32 PYMOD_DIR = "/usr/lib/lustre/python"
34 def development_mode():
35 base = os.path.dirname(sys.argv[0])
36 if os.access(base+"/Makefile.am", os.R_OK):
40 if not development_mode():
41 sys.path.append(PYMOD_DIR)
46 DEFAULT_STRIPE_SZ = 65536
47 DEFAULT_STRIPE_CNT = 1
48 DEFAULT_STRIPE_PATTERN = 0
52 print """usage: lmc --add object [object parameters]
54 Object creation command summary:
62 --ptldebug debug_level
63 --subsystem subsystem_name
69 --nettype tcp|elan|gm|scimac
102 --obdtype obdecho|obdfilter
105 --add mtpt - Mountpoint
109 --ost ost_name OR --lov lov_name
121 --add mgmt - Management/monitoring service
123 --mgmt mgmt_service_name
126 PARAM = Lustre.Options.PARAM
128 # lmc input/output options
129 ('reference', "Print short reference for commands."),
130 ('verbose,v', "Print system commands as they are run."),
131 ('merge,m', "Append to the specified config file.", PARAM),
132 ('output,o', "Write XML configuration into given output file. Overwrite existing content.", PARAM),
133 ('input,i', "", PARAM),
134 ('batch', "Used to execute lmc commands in batch mode.", PARAM),
140 ('node', "Add a new node in the cluster configuration.", PARAM),
141 ('timeout', "Set timeout to initiate recovery.", PARAM),
142 ('upcall', "Set both lustre and portals upcall scripts.", PARAM),
143 ('lustre_upcall', "Set location of lustre upcall script.", PARAM),
144 ('portals_upcall', "Set location of portals upcall script.", PARAM),
145 ('ptldebug', "Set the portals debug level", PARAM),
146 ('subsystem', "Specify which Lustre subsystems have debug output recorded in the log", PARAM),
149 ('nettype', "Specify the network type. This can be tcp/elan/gm/scimac.", PARAM),
150 ('nid', "Give the network ID, e.g ElanID/IP Address as used by portals.", PARAM),
151 ('tcpbuf', "Optional argument to specify the TCP buffer size.", PARAM, "0"),
152 ('port', "Optional argument to specify the TCP port number.", PARAM, DEFAULT_PORT),
153 ('irq_affinity', "Optional argument.", PARAM, 0),
154 ('hostaddr', "", PARAM,""),
155 ('cluster_id', "Specify the cluster ID", PARAM, "0"),
158 ('route', "Add a new route for the cluster.", PARAM),
159 ('router', "Optional flag to mark a node as router."),
160 ('gw', "Specify the nid of the gateway for a route.", PARAM),
161 ('gateway_cluster_id', "", PARAM, "0"),
162 ('target_cluster_id', "", PARAM, "0"),
163 ('lo', "For a range route, this is the low value nid.", PARAM),
164 ('hi', "For a range route, this is a hi value nid.", PARAM,""),
166 # servers: mds and ost
167 ('mds', "Specify MDS name.", PARAM),
168 ('ost', "Specify the OST name.", PARAM,""),
169 ('osdtype', "This could obdfilter or obdecho.", PARAM, "obdfilter"),
170 ('failover', "Enable failover support on OSTs or MDS?"),
171 ('group', "", PARAM),
172 ('dev', "Path of the device on local system.", PARAM,""),
173 ('size', "Specify the size of the device if needed.", PARAM,"0"),
174 ('journal_size', "Specify new journal size for underlying ext3 file system.", PARAM,"0"),
175 ('inode_size', "Specify new inode size for underlying ext3 file system.", PARAM,"0"),
176 ('fstype', "Optional argument to specify the filesystem type.", PARAM, "ext3"),
177 ('mkfsoptions', "Optional argument to mkfs.", PARAM, ""),
178 ('ostuuid', "", PARAM,""),
179 ('nspath', "Local mount point of server namespace.", PARAM,""),
182 # clients: mountpoint and echo
183 ('echo_client', "", PARAM),
184 ('path', "Specify the mountpoint for Lustre.", PARAM),
185 ('filesystem', "Lustre filesystem name", PARAM,""),
188 ('lov', "Specify LOV name.", PARAM,""),
189 ('stripe_sz', "Specify the stripe size in bytes.", PARAM),
190 ('stripe_cnt', "Specify the number of OSTs each file should be striped on.", PARAM, 0),
191 ('stripe_pattern', "Specify the stripe pattern. RAID 0 is the only one currently supported.", PARAM, 0),
194 ('real_obd', "", PARAM),
195 ('cache_obd', "", PARAM),
197 ('mgmt', "Specify management/monitoring service name.", PARAM, ""),
201 msg = string.join(map(str,args))
202 raise OptionError("Error: " + msg)
211 msg = string.join(map(str,args))
212 print "Warning: ", msg
215 # manage names and uuids
216 # need to initialize this by walking tree to ensure
217 # no duplicate names or uuids are created.
218 # this are just place holders for now.
219 # consider changing this to be like OBD-dev-host
223 while names.has_key(ret):
224 ret = "%s_%d" % (base, ctr)
231 ret = "%s_UUID" % (name)
232 if len(ret) > UUID_MAX_LENGTH:
233 ret = ret[-UUID_MAX_LENGTH:]
234 while uuids.has_key(ret):
235 ret = "%s_UUID_%d" % (name, ctr)
237 if len(ret) > UUID_MAX_LENGTH:
238 ret = ret[-UUID_MAX_LENGTH:]
244 ldlm_uuid = 'ldlm_UUID'
247 """Create a new empty lustre document"""
248 # adding ldlm here is a bit of a hack, but one is enough.
249 str = """<lustre version="%s">
250 <ldlm name="%s" uuid="%s"/>
251 </lustre>""" % (Lustre.CONFIG_VERSION, ldlm_name, ldlm_uuid)
252 return dom.parseString(str)
258 """initialize auto-name generation tables"""
260 # get all elements that contain a name attribute
261 for n in doc.childNodes:
262 if n.nodeType == n.ELEMENT_NODE:
264 names[getName(n)] = 1
265 uuids[getUUID(n)] = 1
268 def get_format_flag(options):
273 ############################################################
274 # Build config objects using DOM
279 def __init__(self, doc):
282 def ref(self, type, uuid):
283 """ generate <[type]_ref uuidref="[uuid]"/> """
284 tag = "%s_ref" % (type)
285 ref = self.doc.createElement(tag)
286 ref.setAttribute("uuidref", uuid)
289 def newService(self, tag, name, uuid):
290 """ create a new service elmement, which requires name and uuid attributes """
291 new = self.doc.createElement(tag)
292 new.setAttribute("uuid", uuid);
293 new.setAttribute("name", name);
296 def addText(self, node, str):
297 txt = self.doc.createTextNode(str)
298 node.appendChild(txt)
300 def addElement(self, node, tag, str=None):
301 """ create a new element and add it as a child to node. If str is passed,
302 a text node is created for the new element"""
303 new = self.doc.createElement(tag)
305 self.addText(new, str)
306 node.appendChild(new)
309 def network(self, name, uuid, nid, cluster_id, net, hostaddr="",
310 port=0, tcpbuf=0, irq_aff=0):
311 """create <network> node"""
312 network = self.newService("network", name, uuid)
313 network.setAttribute("nettype", net);
314 self.addElement(network, "nid", nid)
315 self.addElement(network, "clusterid", cluster_id)
317 self.addElement(network, "hostaddr", hostaddr)
319 self.addElement(network, "port", "%d" %(port))
321 self.addElement(network, "sendmem", "%d" %(tcpbuf))
322 self.addElement(network, "recvmem", "%d" %(tcpbuf))
324 self.addElement(network, "irqaffinity", "%d" %(irq_aff))
328 def routetbl(self, name, uuid):
329 """create <routetbl> node"""
330 rtbl = self.newService("routetbl", name, uuid)
333 def route(self, gw_net_type, gw, gw_cluster_id, tgt_cluster_id, lo, hi):
334 """ create one entry for the route table """
335 ref = self.doc.createElement('route')
336 ref.setAttribute("type", gw_net_type)
337 ref.setAttribute("gw", gw)
338 ref.setAttribute("gwclusterid", gw_cluster_id)
339 ref.setAttribute("tgtclusterid", tgt_cluster_id)
340 ref.setAttribute("lo", lo)
342 ref.setAttribute("hi", hi)
345 def profile(self, name, uuid):
346 """ create a host """
347 profile = self.newService("profile", name, uuid)
350 def node(self, name, uuid, prof_uuid):
351 """ create a host """
352 node = self.newService("node", name, uuid)
353 node.appendChild(self.ref("profile", prof_uuid))
356 def ldlm(self, name, uuid):
357 """ create a ldlm """
358 ldlm = self.newService("ldlm", name, uuid)
361 def osd(self, name, uuid, fs, osdtype, devname, format, ost_uuid,
362 node_uuid, dev_size=0, journal_size=0, inode_size=0, nspath=""):
363 osd = self.newService("osd", name, uuid)
364 osd.setAttribute('osdtype', osdtype)
365 osd.appendChild(self.ref("target", ost_uuid))
366 osd.appendChild(self.ref("node", node_uuid))
368 self.addElement(osd, "fstype", fs)
370 dev = self.addElement(osd, "devpath", devname)
371 self.addElement(osd, "autoformat", format)
373 self.addElement(osd, "devsize", "%s" % (dev_size))
375 self.addElement(osd, "journalsize", "%s" % (journal_size))
377 self.addElement(osd, "inodesize", "%s" % (inode_size))
379 self.addElement(osd, "nspath", nspath)
382 def cobd(self, name, uuid, real_uuid, cache_uuid):
383 cobd = self.newService("cobd", name, uuid)
384 cobd.appendChild(self.ref("realobd",real_uuid))
385 cobd.appendChild(self.ref("cacheobd",cache_uuid))
388 def ost(self, name, uuid, osd_uuid, group=""):
389 ost = self.newService("ost", name, uuid)
390 ost.appendChild(self.ref("active", osd_uuid))
392 self.addElement(ost, "group", group)
395 def oss(self, name, uuid):
396 oss = self.newService("oss", name, uuid)
399 def lov(self, name, uuid, mds_uuid, stripe_sz, stripe_cnt, pattern):
400 lov = self.newService("lov", name, uuid)
401 lov.appendChild(self.ref("mds", mds_uuid))
402 lov.setAttribute("stripesize", str(stripe_sz))
403 lov.setAttribute("stripecount", str(stripe_cnt))
404 lov.setAttribute("stripepattern", str(pattern))
407 def lovconfig(self, name, uuid, lov_uuid):
408 lovconfig = self.newService("lovconfig", name, uuid)
409 lovconfig.appendChild(self.ref("lov", lov_uuid))
412 def mds(self, name, uuid, mdd_uuid, group=""):
413 mds = self.newService("mds", name, uuid)
414 mds.appendChild(self.ref("active",mdd_uuid))
416 self.addElement(mds, "group", group)
419 def mdsdev(self, name, uuid, fs, devname, format, node_uuid,
420 mds_uuid, dev_size=0, journal_size=0, inode_size=256,
421 nspath="", mkfsoptions=""):
422 mdd = self.newService("mdsdev", name, uuid)
423 self.addElement(mdd, "fstype", fs)
424 dev = self.addElement(mdd, "devpath", devname)
425 self.addElement(mdd, "autoformat", format)
427 self.addElement(mdd, "devsize", "%s" % (dev_size))
429 self.addElement(mdd, "journalsize", "%s" % (journal_size))
431 self.addElement(mdd, "inodesize", "%s" % (inode_size))
433 self.addElement(mdd, "nspath", nspath)
435 self.addElement(mdd, "mkfsoptions", mkfsoptions)
436 mdd.appendChild(self.ref("node", node_uuid))
437 mdd.appendChild(self.ref("target", mds_uuid))
440 def mgmt(self, mgmt_name, mgmt_uuid, node_uuid):
441 mgmt = self.newService("mgmt", mgmt_name, mgmt_uuid)
442 mgmt.appendChild(self.ref("node", node_uuid))
443 # Placeholder until mgmt-service failover.
444 mgmt.appendChild(self.ref("active", mgmt_uuid))
447 def mountpoint(self, name, uuid, fs_uuid, path):
448 mtpt = self.newService("mountpoint", name, uuid)
449 mtpt.appendChild(self.ref("filesystem", fs_uuid))
450 self.addElement(mtpt, "path", path)
453 def filesystem(self, name, uuid, mds_uuid, obd_uuid, mgmt_uuid):
454 fs = self.newService("filesystem", name, uuid)
455 fs.appendChild(self.ref("mds", mds_uuid))
456 fs.appendChild(self.ref("obd", obd_uuid))
458 fs.appendChild(self.ref("mgmt", mgmt_uuid))
461 def echo_client(self, name, uuid, osc_uuid):
462 ec = self.newService("echoclient", name, uuid)
463 ec.appendChild(self.ref("obd", osc_uuid))
466 ############################################################
467 # Utilities to query a DOM tree
468 # Using this functions we can treat use config information
469 # directly as a database.
471 return n.getAttribute('name')
474 return node.getAttribute('uuid')
477 def findByName(lustre, name, tag = ""):
478 for n in lustre.childNodes:
479 if n.nodeType == n.ELEMENT_NODE:
480 if tag and n.nodeName != tag:
482 if getName(n) == name:
485 n = findByName(n, name)
490 def lookup(node, uuid):
491 for n in node.childNodes:
492 if n.nodeType == n.ELEMENT_NODE:
493 if getUUID(n) == uuid:
501 def name2uuid(lustre, name, tag="", fatal=1):
502 ret = findByName(lustre, name, tag)
505 error('name2uuid:', '"'+name+'"', tag, 'element not found.')
510 def lookup_filesystem(lustre, mds_uuid, ost_uuid):
511 for n in lustre.childNodes:
512 if n.nodeType == n.ELEMENT_NODE and n.nodeName == 'filesystem':
513 if ref_exists(n, mds_uuid) and ref_exists(n, ost_uuid):
517 # XXX: assumes only one network element per node. will fix this
518 # as soon as support for routers is added
519 def get_net_uuid(lustre, node_name):
520 """ get a network uuid for a node_name """
521 node = findByName(lustre, node_name, "node")
523 error ('get_net_uuid:', '"'+node_name+'"', "node element not found.")
524 net = node.getElementsByTagName('network')
526 return getUUID(net[0])
530 def lov_add_obd(gen, lov, osc_uuid):
531 lov.appendChild(gen.ref("obd", osc_uuid))
533 def ref_exists(profile, uuid):
534 elist = profile.childNodes
536 if e.nodeType == e.ELEMENT_NODE:
537 ref = e.getAttribute('uuidref')
542 # ensure that uuid is not already in the profile
543 # return true if uuid is added
544 def node_add_profile(gen, node, ref, uuid):
545 refname = "%s_ref" % "profile"
546 ret = node.getElementsByTagName(refname)
548 error('node has no profile ref:', node)
549 prof_uuid = ret[0].getAttribute('uuidref')
550 profile = lookup(node.parentNode, prof_uuid)
552 error("no profile found:", prof_uuid)
553 if ref_exists(profile, uuid):
555 profile.appendChild(gen.ref(ref, uuid))
558 def get_attr(dom_node, attr, default=""):
559 v = dom_node.getAttribute(attr)
564 ############################################################
567 def set_node_options(gen, node, options):
569 node.setAttribute('router', '1')
571 gen.addElement(node, "timeout", get_option(options, 'timeout'))
573 default_upcall = get_option(options, 'upcall')
576 if default_upcall or options.lustre_upcall:
577 if options.lustre_upcall:
578 gen.addElement(node, 'lustreUpcall', options.lustre_upcall)
580 gen.addElement(node, 'lustreUpcall', default_upcall)
581 if default_upcall or options.portals_upcall:
582 if options.portals_upcall:
583 gen.addElement(node, 'portalsUpcall', options.portals_upcall)
585 gen.addElement(node, 'portalsUpcall', default_upcall)
587 gen.addElement(node, "ptldebug", get_option(options, 'ptldebug'))
588 if options.subsystem:
589 gen.addElement(node, "subsystem", get_option(options, 'subsystem'))
592 def do_add_node(gen, lustre, options, node_name):
593 uuid = new_uuid(node_name)
594 prof_name = new_name("PROFILE_" + node_name)
595 prof_uuid = new_uuid(prof_name)
596 profile = gen.profile(prof_name, prof_uuid)
597 node = gen.node(node_name, uuid, prof_uuid)
598 lustre.appendChild(node)
599 lustre.appendChild(profile)
601 node_add_profile(gen, node, 'ldlm', ldlm_uuid)
602 set_node_options(gen, node, options)
606 def add_node(gen, lustre, options):
607 """ create a node with a network config """
609 node_name = get_option(options, 'node')
610 ret = findByName(lustre, node_name, "node")
612 print "Node:", node_name, "exists."
614 do_add_node(gen, lustre, options, node_name)
617 def add_net(gen, lustre, options):
618 """ create a node with a network config """
620 node_name = get_option(options, 'node')
621 nid = get_option(options, 'nid')
622 cluster_id = get_option(options, 'cluster_id')
623 hostaddr = get_option(options, 'hostaddr')
624 net_type = get_option(options, 'nettype')
626 if net_type in ('tcp',):
627 port = get_option_int(options, 'port')
628 tcpbuf = get_option_int(options, 'tcpbuf')
629 irq_aff = get_option_int(options, 'irq_affinity')
630 elif net_type in ('elan', 'gm', 'scimac'):
635 print "Unknown net_type: ", net_type
638 ret = findByName(lustre, node_name, "node")
640 node = do_add_node(gen, lustre, options, node_name)
643 set_node_options(gen, node, options)
645 net_name = new_name('NET_'+ node_name +'_'+ net_type)
646 net_uuid = new_uuid(net_name)
647 node.appendChild(gen.network(net_name, net_uuid, nid, cluster_id, net_type,
648 hostaddr, port, tcpbuf, irq_aff))
649 node_add_profile(gen, node, "network", net_uuid)
652 def add_route(gen, lustre, options):
653 """ create a node with a network config """
655 node_name = get_option(options, 'node')
656 gw_net_type = get_option(options, 'nettype')
657 gw = get_option(options, 'gw')
658 gw_cluster_id = get_option(options, 'gateway_cluster_id')
659 tgt_cluster_id = get_option(options, 'target_cluster_id')
660 lo = get_option(options, 'lo')
661 hi = get_option(options, 'hi')
665 node = findByName(lustre, node_name, "node")
667 error (node_name, " not found.")
669 rlist = node.getElementsByTagName('routetbl')
673 rtbl_name = new_name("RTBL_" + node_name)
674 rtbl_uuid = new_uuid(rtbl_name)
675 rtbl = gen.routetbl(rtbl_name, rtbl_uuid)
676 node.appendChild(rtbl)
677 node_add_profile(gen, node, "routetbl", rtbl_uuid)
678 rtbl.appendChild(gen.route(gw_net_type, gw, gw_cluster_id, tgt_cluster_id,
682 def add_mds(gen, lustre, options):
683 node_name = get_option(options, 'node')
684 mds_name = get_option(options, 'mds')
685 mdd_name = new_name("MDD_" + mds_name +"_" + node_name)
686 mdd_uuid = new_uuid(mdd_name)
688 mds_uuid = name2uuid(lustre, mds_name, 'mds', fatal=0)
690 mds_uuid = new_uuid(mds_name)
691 mds = gen.mds(mds_name, mds_uuid, mdd_uuid, options.group)
692 lustre.appendChild(mds)
694 mds = lookup(lustre, mds_uuid)
696 mds.setAttribute('failover', "1")
698 devname = get_option(options, 'dev')
699 size = get_option(options, 'size')
700 fstype = get_option(options, 'fstype')
701 journal_size = get_option(options, 'journal_size')
702 inode_size = get_option(options, 'inode_size')
703 nspath = get_option(options, 'nspath')
704 mkfsoptions = get_option(options, 'mkfsoptions')
706 node_uuid = name2uuid(lustre, node_name, 'node')
708 node = findByName(lustre, node_name, "node")
709 node_add_profile(gen, node, "mdsdev", mdd_uuid)
710 net_uuid = get_net_uuid(lustre, node_name)
712 error("NODE: ", node_name, "not found")
714 mdd = gen.mdsdev(mdd_name, mdd_uuid, fstype, devname,
715 get_format_flag(options), node_uuid, mds_uuid,
716 size, journal_size, inode_size, nspath, mkfsoptions)
717 lustre.appendChild(mdd)
720 def add_mgmt(gen, lustre, options):
721 node_name = get_option(options, 'node')
722 node_uuid = name2uuid(lustre, node_name, 'node')
723 mgmt_name = get_option(options, 'mgmt')
725 mgmt_name = new_name('MGMT_' + node_name)
726 mgmt_uuid = name2uuid(lustre, mgmt_name, 'mgmt', fatal=0)
728 mgmt_uuid = new_uuid(mgmt_name)
729 mgmt = gen.mgmt(mgmt_name, mgmt_uuid, node_uuid)
730 lustre.appendChild(mgmt)
732 mgmt = lookup(lustre, mgmt_uuid)
734 node = findByName(lustre, node_name, "node")
735 node_add_profile(gen, node, 'mgmt', mgmt_uuid)
737 def add_ost(gen, lustre, options):
738 node_name = get_option(options, 'node')
739 lovname = get_option(options, 'lov')
740 osdtype = get_option(options, 'osdtype')
742 node_uuid = name2uuid(lustre, node_name, 'node')
744 if osdtype == 'obdecho':
752 devname = get_option(options, 'dev') # can be unset for bluearcs
753 size = get_option(options, 'size')
754 fstype = get_option(options, 'fstype')
755 journal_size = get_option(options, 'journal_size')
756 inode_size = get_option(options, 'inode_size')
758 nspath = get_option(options, 'nspath')
760 ostname = get_option(options, 'ost')
762 ostname = new_name('OST_'+ node_name)
764 osdname = new_name("OSD_" + ostname + "_" + node_name)
765 osd_uuid = new_uuid(osdname)
767 ost_uuid = name2uuid(lustre, ostname, 'ost', fatal=0)
769 ost_uuid = get_option(options, 'ostuuid')
771 if lookup(lustre, ost_uuid):
772 error("Duplicate OST UUID:", ost_uuid)
774 ost_uuid = new_uuid(ostname)
776 ost = gen.ost(ostname, ost_uuid, osd_uuid, options.group)
777 lustre.appendChild(ost)
779 lov = findByName(lustre, lovname, "lov")
781 error('add_ost:', '"'+lovname+'"', "lov element not found.")
782 lov_add_obd(gen, lov, ost_uuid)
784 ost = lookup(lustre, ost_uuid)
787 ost.setAttribute('failover', "1")
790 osd = gen.osd(osdname, osd_uuid, fstype, osdtype, devname,
791 get_format_flag(options), ost_uuid, node_uuid, size,
792 journal_size, inode_size, nspath)
794 node = findByName(lustre, node_name, "node")
796 ## if node_add_profile(gen, node, 'oss', oss_uuid):
798 ## oss_uuid = new_uuid(ossname)
799 ## oss = gen.oss(ossname, oss_uuid)
800 ## lustre.appendChild(oss)
802 node_add_profile(gen, node, 'osd', osd_uuid)
803 lustre.appendChild(osd)
806 def add_cobd(gen, lustre, options):
807 node_name = get_option(options, 'node')
808 name = new_name('COBD_' + node_name)
809 uuid = new_uuid(name)
811 real_name = get_option(options, 'real_obd')
812 cache_name = get_option(options, 'cache_obd')
814 real_uuid = name2uuid(lustre, real_name, tag='obd')
815 cache_uuid = name2uuid(lustre, cache_name, tag='obd')
817 node = findByName(lustre, node_name, "node")
818 node_add_profile(gen, node, "cobd", uuid)
819 cobd = gen.cobd(name, uuid, real_uuid, cache_uuid)
820 lustre.appendChild(cobd)
823 def add_echo_client(gen, lustre, options):
824 """ add an echo client to the profile for this node. """
825 node_name = get_option(options, 'node')
826 lov_name = get_option(options, 'ost')
828 node = findByName(lustre, node_name, 'node')
830 echoname = new_name('ECHO_'+ node_name)
831 echo_uuid = new_uuid(echoname)
832 node_add_profile(gen, node, 'echoclient', echo_uuid)
834 lov_uuid = name2uuid(lustre, lov_name, tag='lov', fatal=0)
836 lov_uuid = name2uuid(lustre, lov_name, tag='ost', fatal=1)
838 echo = gen.echo_client(echoname, echo_uuid, lov_uuid)
839 lustre.appendChild(echo)
842 def add_lov(gen, lustre, options):
845 lov_orig = get_option(options, 'lov')
846 name = new_name(lov_orig)
848 warning("name:", lov_orig, "already used. using:", name)
850 mds_name = get_option(options, 'mds')
851 stripe_sz = get_option_int(options, 'stripe_sz')
852 stripe_cnt = get_option_int(options, 'stripe_cnt')
853 pattern = get_option_int(options, 'stripe_pattern')
854 uuid = new_uuid(name)
856 ret = findByName(lustre, name, "lov")
858 error("LOV: ", name, " already exists.")
860 mds_uuid = name2uuid(lustre, mds_name, 'mds')
861 lov = gen.lov(name, uuid, mds_uuid, stripe_sz, stripe_cnt, pattern)
862 lustre.appendChild(lov)
864 # add an lovconfig entry to the active mdsdev profile
865 lovconfig_name = new_name('LVCFG_' + name)
866 lovconfig_uuid = new_uuid(lovconfig_name)
867 mds = findByName(lustre, mds_name)
868 mds.appendChild(gen.ref("lovconfig", lovconfig_uuid))
869 lovconfig = gen.lovconfig(lovconfig_name, lovconfig_uuid, uuid)
870 lustre.appendChild(lovconfig)
872 def add_default_lov(gen, lustre, mds_name, lov_name):
873 """ create a default lov """
875 stripe_sz = DEFAULT_STRIPE_SZ
876 stripe_cnt = DEFAULT_STRIPE_CNT
877 pattern = DEFAULT_STRIPE_PATTERN
878 uuid = new_uuid(lov_name)
880 ret = findByName(lustre, lov_name, "lov")
882 error("LOV: ", lov_name, " already exists.")
884 mds_uuid = name2uuid(lustre, mds_name, 'mds')
885 lov = gen.lov(lov_name, uuid, mds_uuid, stripe_sz, stripe_cnt, pattern)
886 lustre.appendChild(lov)
888 # add an lovconfig entry to the active mdsdev profile
889 lovconfig_name = new_name('LVCFG_' + lov_name)
890 lovconfig_uuid = new_uuid(lovconfig_name)
891 mds = findByName(lustre, mds_name)
892 mds.appendChild(gen.ref("lovconfig", lovconfig_uuid))
893 lovconfig = gen.lovconfig(lovconfig_name, lovconfig_uuid, uuid)
894 lustre.appendChild(lovconfig)
896 def new_filesystem(gen, lustre, mds_uuid, obd_uuid, mgmt_uuid):
897 fs_name = new_name("FS_fsname")
898 fs_uuid = new_uuid(fs_name)
899 mds = lookup(lustre, mds_uuid)
900 mds.appendChild(gen.ref("filesystem", fs_uuid))
901 fs = gen.filesystem(fs_name, fs_uuid, mds_uuid, obd_uuid, mgmt_uuid)
902 lustre.appendChild(fs)
905 def get_fs_uuid(gen, lustre, mds_name, obd_name, mgmt_name):
906 mds_uuid = name2uuid(lustre, mds_name, tag='mds')
907 obd_uuid = name2uuid(lustre, obd_name, tag='lov', fatal=0)
909 mgmt_uuid = name2uuid(lustre, mgmt_name, tag='mgmt', fatal=1)
912 fs_uuid = lookup_filesystem(lustre, mds_uuid, obd_uuid)
914 fs_uuid = new_filesystem(gen, lustre, mds_uuid, obd_uuid, mgmt_uuid)
917 def add_mtpt(gen, lustre, options):
918 """ create mtpt on a node """
919 node_name = get_option(options, 'node')
921 path = get_option(options, 'path')
922 fs_name = get_option(options, 'filesystem')
924 lov_name = get_option(options, 'lov')
925 ost_name = get_option(options, 'ost')
926 mds_name = get_option(options, 'mds')
929 error("--add mtpt requires --lov lov_name or --ost ost_name")
931 warning("use default value for lov, due no --lov lov_name provided")
932 lov_name = new_name("lov_default")
933 add_default_lov(gen, lustre, mds_name, lov_name)
934 ost_uuid = name2uuid(lustre, ost_name, 'ost', fatal=0)
936 error('add_mtpt:', '"'+ost_name+'"', "ost element not found.")
937 lov = findByName(lustre, lov_name, "lov")
938 lov_add_obd(gen, lov, ost_uuid)
941 mgmt_name = get_option(options, 'mgmt')
942 fs_uuid = get_fs_uuid(gen, lustre, mds_name, lov_name, mgmt_name)
944 fs_uuid = name2uuid(lustre, fs_name, tag='filesystem')
946 name = new_name('MNT_'+ node_name)
948 ret = findByName(lustre, name, "mountpoint")
950 # this can't happen, because new_name creates unique names
951 error("MOUNTPOINT: ", name, " already exists.")
953 uuid = new_uuid(name)
954 mtpt = gen.mountpoint(name, uuid, fs_uuid, path)
955 node = findByName(lustre, node_name, "node")
957 error('node:', node_name, "not found.")
958 node_add_profile(gen, node, "mountpoint", uuid)
959 lustre.appendChild(mtpt)
961 ############################################################
962 # Command line processing
964 class OptionError (exceptions.Exception):
965 def __init__(self, args):
968 def get_option(options, tag):
969 """Look for tag in options hash and return the value if set. If not
970 set, then if return default it is set, otherwise exception."""
971 if options.__getattr__(tag) != None:
972 return options.__getattr__(tag)
974 raise OptionError("--add %s requires --%s <value>" % (options.add, tag))
976 def get_option_int(options, tag):
977 """Return an integer option. Raise exception if the value is not an int"""
978 val = get_option(options, tag)
982 raise OptionError("--%s <num> (value must be integer)" % (tag))
985 # simple class for profiling
992 self._start = time.time()
993 def stop(self, msg=''):
994 self._stop = time.time()
998 return self._stop - self._start
999 def display(self, msg):
1001 str = '%s: %g secs' % (msg, d)
1004 #################################################################
1005 # function cmdlinesplit used to split cmd line from batch file
1007 def cmdlinesplit(cmdline):
1009 double_quote = re.compile(r'"(([^"\\]|\\.)*)"')
1010 single_quote = re.compile(r"'(.*?)'")
1011 escaped = re.compile(r'\\(.)')
1012 esc_quote = re.compile(r'\\([\\"])')
1013 outside = re.compile(r"""([^\s\\'"]+)""")
1017 while i < len(cmdline):
1020 match = double_quote.match(cmdline, i)
1022 print "Unmatched double quote:", cmdline
1025 if arg is None: arg = esc_quote.sub(r'\1', match.group(1))
1026 else: arg = arg + esc_quote.sub(r'\1', match.group(1))
1029 match = single_quote.match(cmdline, i)
1031 print "Unmatched single quote:", cmdline
1034 if arg is None: arg = match.group(1)
1035 else: arg = arg + match.group(1)
1038 match = escaped.match(cmdline, i)
1040 print "Unmatched backslash", cmdline
1043 if arg is None: arg = match.group(1)
1044 else: arg = arg + match.group(1)
1048 arg_list.append(str(arg))
1050 while i < len(cmdline) and cmdline[i].isspace():
1053 match = outside.match(cmdline, i)
1056 if arg is None: arg = match.group()
1057 else: arg = arg + match.group()
1059 if arg != None: arg_list.append(str(arg))
1063 ############################################################
1067 def add(devtype, gen, lustre, options):
1068 if devtype == 'net':
1069 add_net(gen, lustre, options)
1070 elif devtype == 'mtpt':
1071 add_mtpt(gen, lustre, options)
1072 elif devtype == 'mds':
1073 add_mds(gen, lustre, options)
1074 elif devtype == 'ost':
1075 add_ost(gen, lustre, options)
1076 elif devtype == 'lov':
1077 add_lov(gen, lustre, options)
1078 elif devtype == 'route':
1079 add_route(gen, lustre, options)
1080 elif devtype == 'node':
1081 add_node(gen, lustre, options)
1082 elif devtype == 'echo_client':
1083 add_echo_client(gen, lustre, options)
1084 elif devtype == 'cobd':
1085 add_cobd(gen, lustre, options)
1086 elif devtype == 'mgmt':
1087 add_mgmt(gen, lustre, options)
1089 error("unknown device type:", devtype)
1091 def do_command(gen, lustre, options, args):
1093 add(options.add, gen, lustre, options)
1095 error("Missing command")
1098 cl = Lustre.Options("lmc", "", lmc_options)
1100 options, args = cl.parse(sys.argv[1:])
1101 except Lustre.OptionError, e:
1105 panic(string.join(sys.argv), "Unexpected extra arguments on command line: " + string.join(args))
1107 if options.reference:
1114 outFile = options.merge
1115 if os.access(outFile, os.R_OK):
1116 doc = xml.dom.minidom.parse(outFile)
1118 doc = new_lustre(xml.dom.minidom)
1120 doc = xml.dom.minidom.parse(options.input)
1122 doc = new_lustre(xml.dom.minidom)
1125 outFile = options.output
1127 lustre = doc.documentElement
1129 if lustre.tagName != "lustre":
1130 print "Existing config not valid."
1133 gen = GenConfig(doc)
1136 fp = open(options.batch)
1137 batchCommands = fp.readlines()
1139 for cmd in batchCommands:
1141 options, args = cl.parse(cmdlinesplit(cmd))
1142 if options.merge or options.input or options.output:
1143 print "The batchfile should not contain --merge, --input or --output."
1145 do_command(gen, lustre, options, args)
1146 except OptionError, e:
1148 except Lustre.OptionError, e:
1152 do_command(gen, lustre, options, args)
1153 except OptionError, e:
1154 panic(string.join(sys.argv),e)
1155 except Lustre.OptionError, e:
1161 PrettyPrint(doc, open(outFile,"w"))
1163 if __name__ == "__main__":