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="", mkfsoptions=""):
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, "mkfsoptions", mkfsoptions)
381 self.addElement(osd, "nspath", nspath)
384 def cobd(self, name, uuid, real_uuid, cache_uuid):
385 cobd = self.newService("cobd", name, uuid)
386 cobd.appendChild(self.ref("realobd",real_uuid))
387 cobd.appendChild(self.ref("cacheobd",cache_uuid))
390 def ost(self, name, uuid, osd_uuid, group=""):
391 ost = self.newService("ost", name, uuid)
392 ost.appendChild(self.ref("active", osd_uuid))
394 self.addElement(ost, "group", group)
397 def oss(self, name, uuid):
398 oss = self.newService("oss", name, uuid)
401 def lov(self, name, uuid, mds_uuid, stripe_sz, stripe_cnt, pattern):
402 lov = self.newService("lov", name, uuid)
403 lov.appendChild(self.ref("mds", mds_uuid))
404 lov.setAttribute("stripesize", str(stripe_sz))
405 lov.setAttribute("stripecount", str(stripe_cnt))
406 lov.setAttribute("stripepattern", str(pattern))
409 def lovconfig(self, name, uuid, lov_uuid):
410 lovconfig = self.newService("lovconfig", name, uuid)
411 lovconfig.appendChild(self.ref("lov", lov_uuid))
414 def mds(self, name, uuid, mdd_uuid, group=""):
415 mds = self.newService("mds", name, uuid)
416 mds.appendChild(self.ref("active",mdd_uuid))
418 self.addElement(mds, "group", group)
421 def mdsdev(self, name, uuid, fs, devname, format, node_uuid,
422 mds_uuid, dev_size=0, journal_size=0, inode_size=256,
423 nspath="", mkfsoptions=""):
424 mdd = self.newService("mdsdev", name, uuid)
425 self.addElement(mdd, "fstype", fs)
426 dev = self.addElement(mdd, "devpath", devname)
427 self.addElement(mdd, "autoformat", format)
429 self.addElement(mdd, "devsize", "%s" % (dev_size))
431 self.addElement(mdd, "journalsize", "%s" % (journal_size))
433 self.addElement(mdd, "inodesize", "%s" % (inode_size))
435 self.addElement(mdd, "nspath", nspath)
437 self.addElement(mdd, "mkfsoptions", mkfsoptions)
438 mdd.appendChild(self.ref("node", node_uuid))
439 mdd.appendChild(self.ref("target", mds_uuid))
442 def mgmt(self, mgmt_name, mgmt_uuid, node_uuid):
443 mgmt = self.newService("mgmt", mgmt_name, mgmt_uuid)
444 mgmt.appendChild(self.ref("node", node_uuid))
445 # Placeholder until mgmt-service failover.
446 mgmt.appendChild(self.ref("active", mgmt_uuid))
449 def mountpoint(self, name, uuid, fs_uuid, path):
450 mtpt = self.newService("mountpoint", name, uuid)
451 mtpt.appendChild(self.ref("filesystem", fs_uuid))
452 self.addElement(mtpt, "path", path)
455 def filesystem(self, name, uuid, mds_uuid, obd_uuid, mgmt_uuid):
456 fs = self.newService("filesystem", name, uuid)
457 fs.appendChild(self.ref("mds", mds_uuid))
458 fs.appendChild(self.ref("obd", obd_uuid))
460 fs.appendChild(self.ref("mgmt", mgmt_uuid))
463 def echo_client(self, name, uuid, osc_uuid):
464 ec = self.newService("echoclient", name, uuid)
465 ec.appendChild(self.ref("obd", osc_uuid))
468 ############################################################
469 # Utilities to query a DOM tree
470 # Using this functions we can treat use config information
471 # directly as a database.
473 return n.getAttribute('name')
476 return node.getAttribute('uuid')
479 def findByName(lustre, name, tag = ""):
480 for n in lustre.childNodes:
481 if n.nodeType == n.ELEMENT_NODE:
482 if tag and n.nodeName != tag:
484 if getName(n) == name:
487 n = findByName(n, name)
492 def lookup(node, uuid):
493 for n in node.childNodes:
494 if n.nodeType == n.ELEMENT_NODE:
495 if getUUID(n) == uuid:
503 def name2uuid(lustre, name, tag="", fatal=1):
504 ret = findByName(lustre, name, tag)
507 error('name2uuid:', '"'+name+'"', tag, 'element not found.')
512 def lookup_filesystem(lustre, mds_uuid, ost_uuid):
513 for n in lustre.childNodes:
514 if n.nodeType == n.ELEMENT_NODE and n.nodeName == 'filesystem':
515 if ref_exists(n, mds_uuid) and ref_exists(n, ost_uuid):
519 # XXX: assumes only one network element per node. will fix this
520 # as soon as support for routers is added
521 def get_net_uuid(lustre, node_name):
522 """ get a network uuid for a node_name """
523 node = findByName(lustre, node_name, "node")
525 error ('get_net_uuid:', '"'+node_name+'"', "node element not found.")
526 net = node.getElementsByTagName('network')
528 return getUUID(net[0])
532 def lov_add_obd(gen, lov, osc_uuid):
533 lov.appendChild(gen.ref("obd", osc_uuid))
535 def ref_exists(profile, uuid):
536 elist = profile.childNodes
538 if e.nodeType == e.ELEMENT_NODE:
539 ref = e.getAttribute('uuidref')
544 # ensure that uuid is not already in the profile
545 # return true if uuid is added
546 def node_add_profile(gen, node, ref, uuid):
547 refname = "%s_ref" % "profile"
548 ret = node.getElementsByTagName(refname)
550 error('node has no profile ref:', node)
551 prof_uuid = ret[0].getAttribute('uuidref')
552 profile = lookup(node.parentNode, prof_uuid)
554 error("no profile found:", prof_uuid)
555 if ref_exists(profile, uuid):
557 profile.appendChild(gen.ref(ref, uuid))
560 def get_attr(dom_node, attr, default=""):
561 v = dom_node.getAttribute(attr)
566 ############################################################
569 def set_node_options(gen, node, options):
571 node.setAttribute('router', '1')
573 gen.addElement(node, "timeout", get_option(options, 'timeout'))
575 default_upcall = get_option(options, 'upcall')
578 if default_upcall or options.lustre_upcall:
579 if options.lustre_upcall:
580 gen.addElement(node, 'lustreUpcall', options.lustre_upcall)
582 gen.addElement(node, 'lustreUpcall', default_upcall)
583 if default_upcall or options.portals_upcall:
584 if options.portals_upcall:
585 gen.addElement(node, 'portalsUpcall', options.portals_upcall)
587 gen.addElement(node, 'portalsUpcall', default_upcall)
589 gen.addElement(node, "ptldebug", get_option(options, 'ptldebug'))
590 if options.subsystem:
591 gen.addElement(node, "subsystem", get_option(options, 'subsystem'))
594 def do_add_node(gen, lustre, options, node_name):
595 uuid = new_uuid(node_name)
596 prof_name = new_name("PROFILE_" + node_name)
597 prof_uuid = new_uuid(prof_name)
598 profile = gen.profile(prof_name, prof_uuid)
599 node = gen.node(node_name, uuid, prof_uuid)
600 lustre.appendChild(node)
601 lustre.appendChild(profile)
603 node_add_profile(gen, node, 'ldlm', ldlm_uuid)
604 set_node_options(gen, node, options)
608 def add_node(gen, lustre, options):
609 """ create a node with a network config """
611 node_name = get_option(options, 'node')
612 ret = findByName(lustre, node_name, "node")
614 print "Node:", node_name, "exists."
616 do_add_node(gen, lustre, options, node_name)
619 def add_net(gen, lustre, options):
620 """ create a node with a network config """
622 node_name = get_option(options, 'node')
623 nid = get_option(options, 'nid')
624 cluster_id = get_option(options, 'cluster_id')
625 hostaddr = get_option(options, 'hostaddr')
626 net_type = get_option(options, 'nettype')
628 if net_type in ('tcp',):
629 port = get_option_int(options, 'port')
630 tcpbuf = get_option_int(options, 'tcpbuf')
631 irq_aff = get_option_int(options, 'irq_affinity')
632 elif net_type in ('elan', 'gm', 'scimac'):
637 print "Unknown net_type: ", net_type
640 ret = findByName(lustre, node_name, "node")
642 node = do_add_node(gen, lustre, options, node_name)
645 set_node_options(gen, node, options)
647 net_name = new_name('NET_'+ node_name +'_'+ net_type)
648 net_uuid = new_uuid(net_name)
649 node.appendChild(gen.network(net_name, net_uuid, nid, cluster_id, net_type,
650 hostaddr, port, tcpbuf, irq_aff))
651 node_add_profile(gen, node, "network", net_uuid)
654 def add_route(gen, lustre, options):
655 """ create a node with a network config """
657 node_name = get_option(options, 'node')
658 gw_net_type = get_option(options, 'nettype')
659 gw = get_option(options, 'gw')
660 gw_cluster_id = get_option(options, 'gateway_cluster_id')
661 tgt_cluster_id = get_option(options, 'target_cluster_id')
662 lo = get_option(options, 'lo')
663 hi = get_option(options, 'hi')
667 node = findByName(lustre, node_name, "node")
669 error (node_name, " not found.")
671 rlist = node.getElementsByTagName('routetbl')
675 rtbl_name = new_name("RTBL_" + node_name)
676 rtbl_uuid = new_uuid(rtbl_name)
677 rtbl = gen.routetbl(rtbl_name, rtbl_uuid)
678 node.appendChild(rtbl)
679 node_add_profile(gen, node, "routetbl", rtbl_uuid)
680 rtbl.appendChild(gen.route(gw_net_type, gw, gw_cluster_id, tgt_cluster_id,
684 def add_mds(gen, lustre, options):
685 node_name = get_option(options, 'node')
686 mds_name = get_option(options, 'mds')
687 mdd_name = new_name("MDD_" + mds_name +"_" + node_name)
688 mdd_uuid = new_uuid(mdd_name)
690 mds_uuid = name2uuid(lustre, mds_name, 'mds', fatal=0)
692 mds_uuid = new_uuid(mds_name)
693 mds = gen.mds(mds_name, mds_uuid, mdd_uuid, options.group)
694 lustre.appendChild(mds)
696 mds = lookup(lustre, mds_uuid)
698 mds.setAttribute('failover', "1")
700 devname = get_option(options, 'dev')
701 size = get_option(options, 'size')
702 fstype = get_option(options, 'fstype')
703 journal_size = get_option(options, 'journal_size')
704 inode_size = get_option(options, 'inode_size')
705 nspath = get_option(options, 'nspath')
706 mkfsoptions = get_option(options, 'mkfsoptions')
708 node_uuid = name2uuid(lustre, node_name, 'node')
710 node = findByName(lustre, node_name, "node")
711 node_add_profile(gen, node, "mdsdev", mdd_uuid)
712 net_uuid = get_net_uuid(lustre, node_name)
714 error("NODE: ", node_name, "not found")
716 mdd = gen.mdsdev(mdd_name, mdd_uuid, fstype, devname,
717 get_format_flag(options), node_uuid, mds_uuid,
718 size, journal_size, inode_size, nspath, mkfsoptions)
719 lustre.appendChild(mdd)
722 def add_mgmt(gen, lustre, options):
723 node_name = get_option(options, 'node')
724 node_uuid = name2uuid(lustre, node_name, 'node')
725 mgmt_name = get_option(options, 'mgmt')
727 mgmt_name = new_name('MGMT_' + node_name)
728 mgmt_uuid = name2uuid(lustre, mgmt_name, 'mgmt', fatal=0)
730 mgmt_uuid = new_uuid(mgmt_name)
731 mgmt = gen.mgmt(mgmt_name, mgmt_uuid, node_uuid)
732 lustre.appendChild(mgmt)
734 mgmt = lookup(lustre, mgmt_uuid)
736 node = findByName(lustre, node_name, "node")
737 node_add_profile(gen, node, 'mgmt', mgmt_uuid)
739 def add_ost(gen, lustre, options):
740 node_name = get_option(options, 'node')
741 lovname = get_option(options, 'lov')
742 osdtype = get_option(options, 'osdtype')
744 node_uuid = name2uuid(lustre, node_name, 'node')
746 if osdtype == 'obdecho':
755 devname = get_option(options, 'dev') # can be unset for bluearcs
756 size = get_option(options, 'size')
757 fstype = get_option(options, 'fstype')
758 journal_size = get_option(options, 'journal_size')
759 inode_size = get_option(options, 'inode_size')
760 mkfsoptions = get_option(options, 'mkfsoptions')
762 nspath = get_option(options, 'nspath')
764 ostname = get_option(options, 'ost')
766 ostname = new_name('OST_'+ node_name)
768 osdname = new_name("OSD_" + ostname + "_" + node_name)
769 osd_uuid = new_uuid(osdname)
771 ost_uuid = name2uuid(lustre, ostname, 'ost', fatal=0)
773 ost_uuid = get_option(options, 'ostuuid')
775 if lookup(lustre, ost_uuid):
776 error("Duplicate OST UUID:", ost_uuid)
778 ost_uuid = new_uuid(ostname)
780 ost = gen.ost(ostname, ost_uuid, osd_uuid, options.group)
781 lustre.appendChild(ost)
783 lov = findByName(lustre, lovname, "lov")
785 error('add_ost:', '"'+lovname+'"', "lov element not found.")
786 lov_add_obd(gen, lov, ost_uuid)
788 ost = lookup(lustre, ost_uuid)
791 ost.setAttribute('failover', "1")
794 osd = gen.osd(osdname, osd_uuid, fstype, osdtype, devname,
795 get_format_flag(options), ost_uuid, node_uuid, size,
796 journal_size, inode_size, nspath, mkfsoptions)
798 node = findByName(lustre, node_name, "node")
800 ## if node_add_profile(gen, node, 'oss', oss_uuid):
802 ## oss_uuid = new_uuid(ossname)
803 ## oss = gen.oss(ossname, oss_uuid)
804 ## lustre.appendChild(oss)
806 node_add_profile(gen, node, 'osd', osd_uuid)
807 lustre.appendChild(osd)
810 def add_cobd(gen, lustre, options):
811 node_name = get_option(options, 'node')
812 name = new_name('COBD_' + node_name)
813 uuid = new_uuid(name)
815 real_name = get_option(options, 'real_obd')
816 cache_name = get_option(options, 'cache_obd')
818 real_uuid = name2uuid(lustre, real_name, tag='obd')
819 cache_uuid = name2uuid(lustre, cache_name, tag='obd')
821 node = findByName(lustre, node_name, "node")
822 node_add_profile(gen, node, "cobd", uuid)
823 cobd = gen.cobd(name, uuid, real_uuid, cache_uuid)
824 lustre.appendChild(cobd)
827 def add_echo_client(gen, lustre, options):
828 """ add an echo client to the profile for this node. """
829 node_name = get_option(options, 'node')
830 lov_name = get_option(options, 'ost')
832 node = findByName(lustre, node_name, 'node')
834 echoname = new_name('ECHO_'+ node_name)
835 echo_uuid = new_uuid(echoname)
836 node_add_profile(gen, node, 'echoclient', echo_uuid)
838 lov_uuid = name2uuid(lustre, lov_name, tag='lov', fatal=0)
840 lov_uuid = name2uuid(lustre, lov_name, tag='ost', fatal=1)
842 echo = gen.echo_client(echoname, echo_uuid, lov_uuid)
843 lustre.appendChild(echo)
846 def add_lov(gen, lustre, options):
849 lov_orig = get_option(options, 'lov')
850 name = new_name(lov_orig)
852 warning("name:", lov_orig, "already used. using:", name)
854 mds_name = get_option(options, 'mds')
855 stripe_sz = get_option_int(options, 'stripe_sz')
856 stripe_cnt = get_option_int(options, 'stripe_cnt')
857 pattern = get_option_int(options, 'stripe_pattern')
858 uuid = new_uuid(name)
860 ret = findByName(lustre, name, "lov")
862 error("LOV: ", name, " already exists.")
864 mds_uuid = name2uuid(lustre, mds_name, 'mds')
865 lov = gen.lov(name, uuid, mds_uuid, stripe_sz, stripe_cnt, pattern)
866 lustre.appendChild(lov)
868 # add an lovconfig entry to the active mdsdev profile
869 lovconfig_name = new_name('LVCFG_' + name)
870 lovconfig_uuid = new_uuid(lovconfig_name)
871 mds = findByName(lustre, mds_name)
872 mds.appendChild(gen.ref("lovconfig", lovconfig_uuid))
873 lovconfig = gen.lovconfig(lovconfig_name, lovconfig_uuid, uuid)
874 lustre.appendChild(lovconfig)
876 def add_default_lov(gen, lustre, mds_name, lov_name):
877 """ create a default lov """
879 stripe_sz = DEFAULT_STRIPE_SZ
880 stripe_cnt = DEFAULT_STRIPE_CNT
881 pattern = DEFAULT_STRIPE_PATTERN
882 uuid = new_uuid(lov_name)
884 ret = findByName(lustre, lov_name, "lov")
886 error("LOV: ", lov_name, " already exists.")
888 mds_uuid = name2uuid(lustre, mds_name, 'mds')
889 lov = gen.lov(lov_name, uuid, mds_uuid, stripe_sz, stripe_cnt, pattern)
890 lustre.appendChild(lov)
892 # add an lovconfig entry to the active mdsdev profile
893 lovconfig_name = new_name('LVCFG_' + lov_name)
894 lovconfig_uuid = new_uuid(lovconfig_name)
895 mds = findByName(lustre, mds_name)
896 mds.appendChild(gen.ref("lovconfig", lovconfig_uuid))
897 lovconfig = gen.lovconfig(lovconfig_name, lovconfig_uuid, uuid)
898 lustre.appendChild(lovconfig)
900 def new_filesystem(gen, lustre, mds_uuid, obd_uuid, mgmt_uuid):
901 fs_name = new_name("FS_fsname")
902 fs_uuid = new_uuid(fs_name)
903 mds = lookup(lustre, mds_uuid)
904 mds.appendChild(gen.ref("filesystem", fs_uuid))
905 fs = gen.filesystem(fs_name, fs_uuid, mds_uuid, obd_uuid, mgmt_uuid)
906 lustre.appendChild(fs)
909 def get_fs_uuid(gen, lustre, mds_name, obd_name, mgmt_name):
910 mds_uuid = name2uuid(lustre, mds_name, tag='mds')
911 obd_uuid = name2uuid(lustre, obd_name, tag='lov', fatal=0)
913 mgmt_uuid = name2uuid(lustre, mgmt_name, tag='mgmt', fatal=1)
916 fs_uuid = lookup_filesystem(lustre, mds_uuid, obd_uuid)
918 fs_uuid = new_filesystem(gen, lustre, mds_uuid, obd_uuid, mgmt_uuid)
921 def add_mtpt(gen, lustre, options):
922 """ create mtpt on a node """
923 node_name = get_option(options, 'node')
925 path = get_option(options, 'path')
926 fs_name = get_option(options, 'filesystem')
928 lov_name = get_option(options, 'lov')
929 ost_name = get_option(options, 'ost')
930 mds_name = get_option(options, 'mds')
933 error("--add mtpt requires --lov lov_name or --ost ost_name")
935 warning("use default value for lov, due no --lov lov_name provided")
936 lov_name = new_name("lov_default")
937 add_default_lov(gen, lustre, mds_name, lov_name)
938 ost_uuid = name2uuid(lustre, ost_name, 'ost', fatal=0)
940 error('add_mtpt:', '"'+ost_name+'"', "ost element not found.")
941 lov = findByName(lustre, lov_name, "lov")
942 lov_add_obd(gen, lov, ost_uuid)
945 mgmt_name = get_option(options, 'mgmt')
946 fs_uuid = get_fs_uuid(gen, lustre, mds_name, lov_name, mgmt_name)
948 fs_uuid = name2uuid(lustre, fs_name, tag='filesystem')
950 name = new_name('MNT_'+ node_name)
952 ret = findByName(lustre, name, "mountpoint")
954 # this can't happen, because new_name creates unique names
955 error("MOUNTPOINT: ", name, " already exists.")
957 uuid = new_uuid(name)
958 mtpt = gen.mountpoint(name, uuid, fs_uuid, path)
959 node = findByName(lustre, node_name, "node")
961 error('node:', node_name, "not found.")
962 node_add_profile(gen, node, "mountpoint", uuid)
963 lustre.appendChild(mtpt)
965 ############################################################
966 # Command line processing
968 class OptionError (exceptions.Exception):
969 def __init__(self, args):
972 def get_option(options, tag):
973 """Look for tag in options hash and return the value if set. If not
974 set, then if return default it is set, otherwise exception."""
975 if options.__getattr__(tag) != None:
976 return options.__getattr__(tag)
978 raise OptionError("--add %s requires --%s <value>" % (options.add, tag))
980 def get_option_int(options, tag):
981 """Return an integer option. Raise exception if the value is not an int"""
982 val = get_option(options, tag)
986 raise OptionError("--%s <num> (value must be integer)" % (tag))
989 # simple class for profiling
996 self._start = time.time()
997 def stop(self, msg=''):
998 self._stop = time.time()
1002 return self._stop - self._start
1003 def display(self, msg):
1005 str = '%s: %g secs' % (msg, d)
1008 #################################################################
1009 # function cmdlinesplit used to split cmd line from batch file
1011 def cmdlinesplit(cmdline):
1013 double_quote = re.compile(r'"(([^"\\]|\\.)*)"')
1014 single_quote = re.compile(r"'(.*?)'")
1015 escaped = re.compile(r'\\(.)')
1016 esc_quote = re.compile(r'\\([\\"])')
1017 outside = re.compile(r"""([^\s\\'"]+)""")
1021 while i < len(cmdline):
1024 match = double_quote.match(cmdline, i)
1026 print "Unmatched double quote:", cmdline
1029 if arg is None: arg = esc_quote.sub(r'\1', match.group(1))
1030 else: arg = arg + esc_quote.sub(r'\1', match.group(1))
1033 match = single_quote.match(cmdline, i)
1035 print "Unmatched single quote:", cmdline
1038 if arg is None: arg = match.group(1)
1039 else: arg = arg + match.group(1)
1042 match = escaped.match(cmdline, i)
1044 print "Unmatched backslash", cmdline
1047 if arg is None: arg = match.group(1)
1048 else: arg = arg + match.group(1)
1052 arg_list.append(str(arg))
1054 while i < len(cmdline) and cmdline[i].isspace():
1057 match = outside.match(cmdline, i)
1060 if arg is None: arg = match.group()
1061 else: arg = arg + match.group()
1063 if arg != None: arg_list.append(str(arg))
1067 ############################################################
1071 def add(devtype, gen, lustre, options):
1072 if devtype == 'net':
1073 add_net(gen, lustre, options)
1074 elif devtype == 'mtpt':
1075 add_mtpt(gen, lustre, options)
1076 elif devtype == 'mds':
1077 add_mds(gen, lustre, options)
1078 elif devtype == 'ost':
1079 add_ost(gen, lustre, options)
1080 elif devtype == 'lov':
1081 add_lov(gen, lustre, options)
1082 elif devtype == 'route':
1083 add_route(gen, lustre, options)
1084 elif devtype == 'node':
1085 add_node(gen, lustre, options)
1086 elif devtype == 'echo_client':
1087 add_echo_client(gen, lustre, options)
1088 elif devtype == 'cobd':
1089 add_cobd(gen, lustre, options)
1090 elif devtype == 'mgmt':
1091 add_mgmt(gen, lustre, options)
1093 error("unknown device type:", devtype)
1095 def do_command(gen, lustre, options, args):
1097 add(options.add, gen, lustre, options)
1099 error("Missing command")
1102 cl = Lustre.Options("lmc", "", lmc_options)
1104 options, args = cl.parse(sys.argv[1:])
1105 except Lustre.OptionError, e:
1109 panic(string.join(sys.argv), "Unexpected extra arguments on command line: " + string.join(args))
1111 if options.reference:
1118 outFile = options.merge
1119 if os.access(outFile, os.R_OK):
1120 doc = xml.dom.minidom.parse(outFile)
1122 doc = new_lustre(xml.dom.minidom)
1124 doc = xml.dom.minidom.parse(options.input)
1126 doc = new_lustre(xml.dom.minidom)
1129 outFile = options.output
1131 lustre = doc.documentElement
1133 if lustre.tagName != "lustre":
1134 print "Existing config not valid."
1137 gen = GenConfig(doc)
1140 fp = open(options.batch)
1141 batchCommands = fp.readlines()
1143 for cmd in batchCommands:
1145 options, args = cl.parse(cmdlinesplit(cmd))
1146 if options.merge or options.input or options.output:
1147 print "The batchfile should not contain --merge, --input or --output."
1149 do_command(gen, lustre, options, args)
1150 except OptionError, e:
1152 except Lustre.OptionError, e:
1156 do_command(gen, lustre, options, args)
1157 except OptionError, e:
1158 panic(string.join(sys.argv),e)
1159 except Lustre.OptionError, e:
1165 PrettyPrint(doc, open(outFile,"w"))
1167 if __name__ == "__main__":