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
77 --nettype tcp|elan|gm|scimac
110 --obdtype obdecho|obdfilter
113 --add mtpt - Mountpoint
117 --ost ost_name OR --lov lov_name
129 --add mgmt - Management/monitoring service
131 --mgmt mgmt_service_name
134 PARAM = Lustre.Options.PARAM
136 # lmc input/output options
137 ('reference', "Print short reference for commands."),
138 ('verbose,v', "Print system commands as they are run."),
139 ('merge,m', "Append to the specified config file.", PARAM),
140 ('output,o', "Write XML configuration into given output file. Overwrite existing content.", PARAM),
141 ('input,i', "", PARAM),
142 ('batch', "Used to execute lmc commands in batch mode.", PARAM),
148 ('node', "Add a new node in the cluster configuration.", PARAM),
149 ('timeout', "Set timeout to initiate recovery.", PARAM),
150 ('upcall', "Set both lustre and portals upcall scripts.", PARAM),
151 ('lustre_upcall', "Set location of lustre upcall script.", PARAM),
152 ('portals_upcall', "Set location of portals upcall script.", PARAM),
153 ('ptldebug', "Set the portals debug level", PARAM),
154 ('subsystem', "Specify which Lustre subsystems have debug output recorded in the log", PARAM),
157 ('nettype', "Specify the network type. This can be tcp/elan/gm/scimac.", PARAM),
158 ('nid', "Give the network ID, e.g ElanID/IP Address as used by portals.", PARAM),
159 ('tcpbuf', "Optional argument to specify the TCP buffer size.", PARAM, "0"),
160 ('port', "Optional argument to specify the TCP port number.", PARAM, DEFAULT_PORT),
161 ('irq_affinity', "Optional argument.", PARAM, 0),
162 ('hostaddr', "", PARAM,""),
163 ('cluster_id', "Specify the cluster ID", PARAM, "0"),
166 ('route', "Add a new route for the cluster.", PARAM),
167 ('router', "Optional flag to mark a node as router."),
168 ('gw', "Specify the nid of the gateway for a route.", PARAM),
169 ('gateway_cluster_id', "", PARAM, "0"),
170 ('target_cluster_id', "", PARAM, "0"),
171 ('lo', "For a range route, this is the low value nid.", PARAM),
172 ('hi', "For a range route, this is a hi value nid.", PARAM,""),
174 # servers: mds and ost
175 ('mds', "Specify MDS name.", PARAM),
176 ('ost', "Specify the OST name.", PARAM,""),
177 ('osdtype', "This could obdfilter or obdecho.", PARAM, "obdfilter"),
178 ('failover', "Enable failover support on OSTs or MDS?"),
179 ('group', "", PARAM),
180 ('dev', "Path of the device on local system.", PARAM,""),
181 ('size', "Specify the size of the device if needed.", PARAM,"0"),
182 ('journal_size', "Specify new journal size for underlying ext3 file system.", PARAM,"0"),
183 ('inode_size', "Specify new inode size for underlying ext3 file system.", PARAM,"0"),
184 ('fstype', "Optional argument to specify the filesystem type.", PARAM, "ext3"),
185 ('mkfsoptions', "Optional argument to mkfs.", PARAM, ""),
186 ('ostuuid', "", PARAM,""),
187 ('nspath', "Local mount point of server namespace.", PARAM,""),
190 # clients: mountpoint and echo
191 ('echo_client', "", PARAM),
192 ('path', "Specify the mountpoint for Lustre.", PARAM),
193 ('filesystem', "Lustre filesystem name", PARAM,""),
196 ('lov', "Specify LOV name.", PARAM,""),
197 ('stripe_sz', "Specify the stripe size in bytes.", PARAM),
198 ('stripe_cnt', "Specify the number of OSTs each file should be striped on.", PARAM, 0),
199 ('stripe_pattern', "Specify the stripe pattern. RAID 0 is the only one currently supported.", PARAM, 0),
202 ('real_obd', "", PARAM),
203 ('cache_obd', "", PARAM),
205 ('mgmt', "Specify management/monitoring service name.", PARAM, ""),
209 msg = string.join(map(str,args))
210 raise OptionError("Error: " + msg)
219 msg = string.join(map(str,args))
220 print "Warning: ", msg
223 # manage names and uuids
224 # need to initialize this by walking tree to ensure
225 # no duplicate names or uuids are created.
226 # this are just place holders for now.
227 # consider changing this to be like OBD-dev-host
231 while names.has_key(ret):
232 ret = "%s_%d" % (base, ctr)
239 ret = "%s_UUID" % (name)
240 if len(ret) > UUID_MAX_LENGTH:
241 ret = ret[-UUID_MAX_LENGTH:]
242 while uuids.has_key(ret):
243 ret = "%s_UUID_%d" % (name, ctr)
245 if len(ret) > UUID_MAX_LENGTH:
246 ret = ret[-UUID_MAX_LENGTH:]
252 ldlm_uuid = 'ldlm_UUID'
255 """Create a new empty lustre document"""
256 # adding ldlm here is a bit of a hack, but one is enough.
257 str = """<lustre version="%s">
258 <ldlm name="%s" uuid="%s"/>
259 </lustre>""" % (Lustre.CONFIG_VERSION, ldlm_name, ldlm_uuid)
260 return dom.parseString(str)
266 """initialize auto-name generation tables"""
268 # get all elements that contain a name attribute
269 for n in doc.childNodes:
270 if n.nodeType == n.ELEMENT_NODE:
272 names[getName(n)] = 1
273 uuids[getUUID(n)] = 1
276 def get_format_flag(options):
281 ############################################################
282 # Build config objects using DOM
287 def __init__(self, doc):
290 def ref(self, type, uuid):
291 """ generate <[type]_ref uuidref="[uuid]"/> """
292 tag = "%s_ref" % (type)
293 ref = self.doc.createElement(tag)
294 ref.setAttribute("uuidref", uuid)
297 def newService(self, tag, name, uuid):
298 """ create a new service elmement, which requires name and uuid attributes """
299 new = self.doc.createElement(tag)
300 new.setAttribute("uuid", uuid);
301 new.setAttribute("name", name);
304 def addText(self, node, str):
305 txt = self.doc.createTextNode(str)
306 node.appendChild(txt)
308 def addElement(self, node, tag, str=None):
309 """ create a new element and add it as a child to node. If str is passed,
310 a text node is created for the new element"""
311 new = self.doc.createElement(tag)
313 self.addText(new, str)
314 node.appendChild(new)
317 def network(self, name, uuid, nid, cluster_id, net, hostaddr="",
318 port=0, tcpbuf=0, irq_aff=0):
319 """create <network> node"""
320 network = self.newService("network", name, uuid)
321 network.setAttribute("nettype", net);
322 self.addElement(network, "nid", nid)
323 self.addElement(network, "clusterid", cluster_id)
325 self.addElement(network, "hostaddr", hostaddr)
327 self.addElement(network, "port", "%d" %(port))
329 self.addElement(network, "sendmem", "%d" %(tcpbuf))
330 self.addElement(network, "recvmem", "%d" %(tcpbuf))
332 self.addElement(network, "irqaffinity", "%d" %(irq_aff))
336 def routetbl(self, name, uuid):
337 """create <routetbl> node"""
338 rtbl = self.newService("routetbl", name, uuid)
341 def route(self, gw_net_type, gw, gw_cluster_id, tgt_cluster_id, lo, hi):
342 """ create one entry for the route table """
343 ref = self.doc.createElement('route')
344 ref.setAttribute("type", gw_net_type)
345 ref.setAttribute("gw", gw)
346 ref.setAttribute("gwclusterid", gw_cluster_id)
347 ref.setAttribute("tgtclusterid", tgt_cluster_id)
348 ref.setAttribute("lo", lo)
350 ref.setAttribute("hi", hi)
353 def profile(self, name, uuid):
354 """ create a host """
355 profile = self.newService("profile", name, uuid)
358 def node(self, name, uuid, prof_uuid):
359 """ create a host """
360 node = self.newService("node", name, uuid)
361 node.appendChild(self.ref("profile", prof_uuid))
364 def ldlm(self, name, uuid):
365 """ create a ldlm """
366 ldlm = self.newService("ldlm", name, uuid)
369 def osd(self, name, uuid, fs, osdtype, devname, format, ost_uuid,
370 node_uuid, dev_size=0, journal_size=0, inode_size=0, nspath="", mkfsoptions=""):
371 osd = self.newService("osd", name, uuid)
372 osd.setAttribute('osdtype', osdtype)
373 osd.appendChild(self.ref("target", ost_uuid))
374 osd.appendChild(self.ref("node", node_uuid))
376 self.addElement(osd, "fstype", fs)
378 dev = self.addElement(osd, "devpath", devname)
379 self.addElement(osd, "autoformat", format)
381 self.addElement(osd, "devsize", "%s" % (dev_size))
383 self.addElement(osd, "journalsize", "%s" % (journal_size))
385 self.addElement(osd, "inodesize", "%s" % (inode_size))
387 self.addElement(osd, "mkfsoptions", mkfsoptions)
389 self.addElement(osd, "nspath", nspath)
392 def cobd(self, name, uuid, real_uuid, cache_uuid):
393 cobd = self.newService("cobd", name, uuid)
394 cobd.appendChild(self.ref("realobd",real_uuid))
395 cobd.appendChild(self.ref("cacheobd",cache_uuid))
398 def ost(self, name, uuid, osd_uuid, group=""):
399 ost = self.newService("ost", name, uuid)
400 ost.appendChild(self.ref("active", osd_uuid))
402 self.addElement(ost, "group", group)
405 def oss(self, name, uuid):
406 oss = self.newService("oss", name, uuid)
409 def lov(self, name, uuid, mds_uuid, stripe_sz, stripe_cnt, pattern):
410 lov = self.newService("lov", name, uuid)
411 lov.appendChild(self.ref("mds", mds_uuid))
412 lov.setAttribute("stripesize", str(stripe_sz))
413 lov.setAttribute("stripecount", str(stripe_cnt))
414 lov.setAttribute("stripepattern", str(pattern))
417 def lovconfig(self, name, uuid, lov_uuid):
418 lovconfig = self.newService("lovconfig", name, uuid)
419 lovconfig.appendChild(self.ref("lov", lov_uuid))
422 def mds(self, name, uuid, mdd_uuid, group=""):
423 mds = self.newService("mds", name, uuid)
424 mds.appendChild(self.ref("active",mdd_uuid))
426 self.addElement(mds, "group", group)
429 def mdsdev(self, name, uuid, fs, devname, format, node_uuid,
430 mds_uuid, dev_size=0, journal_size=0, inode_size=256,
431 nspath="", mkfsoptions=""):
432 mdd = self.newService("mdsdev", name, uuid)
433 self.addElement(mdd, "fstype", fs)
434 dev = self.addElement(mdd, "devpath", devname)
435 self.addElement(mdd, "autoformat", format)
437 self.addElement(mdd, "devsize", "%s" % (dev_size))
439 self.addElement(mdd, "journalsize", "%s" % (journal_size))
441 self.addElement(mdd, "inodesize", "%s" % (inode_size))
443 self.addElement(mdd, "nspath", nspath)
445 self.addElement(mdd, "mkfsoptions", mkfsoptions)
446 mdd.appendChild(self.ref("node", node_uuid))
447 mdd.appendChild(self.ref("target", mds_uuid))
450 def mgmt(self, mgmt_name, mgmt_uuid, node_uuid):
451 mgmt = self.newService("mgmt", mgmt_name, mgmt_uuid)
452 mgmt.appendChild(self.ref("node", node_uuid))
453 # Placeholder until mgmt-service failover.
454 mgmt.appendChild(self.ref("active", mgmt_uuid))
457 def mountpoint(self, name, uuid, fs_uuid, path):
458 mtpt = self.newService("mountpoint", name, uuid)
459 mtpt.appendChild(self.ref("filesystem", fs_uuid))
460 self.addElement(mtpt, "path", path)
463 def filesystem(self, name, uuid, mds_uuid, obd_uuid, mgmt_uuid):
464 fs = self.newService("filesystem", name, uuid)
465 fs.appendChild(self.ref("mds", mds_uuid))
466 fs.appendChild(self.ref("obd", obd_uuid))
468 fs.appendChild(self.ref("mgmt", mgmt_uuid))
471 def echo_client(self, name, uuid, osc_uuid):
472 ec = self.newService("echoclient", name, uuid)
473 ec.appendChild(self.ref("obd", osc_uuid))
476 ############################################################
477 # Utilities to query a DOM tree
478 # Using this functions we can treat use config information
479 # directly as a database.
481 return n.getAttribute('name')
484 return node.getAttribute('uuid')
487 def findByName(lustre, name, tag = ""):
488 for n in lustre.childNodes:
489 if n.nodeType == n.ELEMENT_NODE:
490 if tag and n.nodeName != tag:
492 if getName(n) == name:
495 n = findByName(n, name)
500 def lookup(node, uuid):
501 for n in node.childNodes:
502 if n.nodeType == n.ELEMENT_NODE:
503 if getUUID(n) == uuid:
511 def name2uuid(lustre, name, tag="", fatal=1):
512 ret = findByName(lustre, name, tag)
515 error('name2uuid:', '"'+name+'"', tag, 'element not found.')
520 def lookup_filesystem(lustre, mds_uuid, ost_uuid):
521 for n in lustre.childNodes:
522 if n.nodeType == n.ELEMENT_NODE and n.nodeName == 'filesystem':
523 if ref_exists(n, mds_uuid) and ref_exists(n, ost_uuid):
527 # XXX: assumes only one network element per node. will fix this
528 # as soon as support for routers is added
529 def get_net_uuid(lustre, node_name):
530 """ get a network uuid for a node_name """
531 node = findByName(lustre, node_name, "node")
533 error ('get_net_uuid:', '"'+node_name+'"', "node element not found.")
534 net = node.getElementsByTagName('network')
536 return getUUID(net[0])
540 def lov_add_obd(gen, lov, osc_uuid):
541 lov.appendChild(gen.ref("obd", osc_uuid))
543 def ref_exists(profile, uuid):
544 elist = profile.childNodes
546 if e.nodeType == e.ELEMENT_NODE:
547 ref = e.getAttribute('uuidref')
552 # ensure that uuid is not already in the profile
553 # return true if uuid is added
554 def node_add_profile(gen, node, ref, uuid):
555 refname = "%s_ref" % "profile"
556 ret = node.getElementsByTagName(refname)
558 error('node has no profile ref:', node)
559 prof_uuid = ret[0].getAttribute('uuidref')
560 profile = lookup(node.parentNode, prof_uuid)
562 error("no profile found:", prof_uuid)
563 if ref_exists(profile, uuid):
565 profile.appendChild(gen.ref(ref, uuid))
568 def get_attr(dom_node, attr, default=""):
569 v = dom_node.getAttribute(attr)
574 ############################################################
577 def set_node_options(gen, node, options):
579 node.setAttribute('router', '1')
581 gen.addElement(node, "timeout", get_option(options, 'timeout'))
583 default_upcall = get_option(options, 'upcall')
586 if default_upcall or options.lustre_upcall:
587 if options.lustre_upcall:
588 gen.addElement(node, 'lustreUpcall', options.lustre_upcall)
590 gen.addElement(node, 'lustreUpcall', default_upcall)
591 if default_upcall or options.portals_upcall:
592 if options.portals_upcall:
593 gen.addElement(node, 'portalsUpcall', options.portals_upcall)
595 gen.addElement(node, 'portalsUpcall', default_upcall)
597 gen.addElement(node, "ptldebug", get_option(options, 'ptldebug'))
598 if options.subsystem:
599 gen.addElement(node, "subsystem", get_option(options, 'subsystem'))
602 def do_add_node(gen, lustre, options, node_name):
603 uuid = new_uuid(node_name)
604 prof_name = new_name("PROFILE_" + node_name)
605 prof_uuid = new_uuid(prof_name)
606 profile = gen.profile(prof_name, prof_uuid)
607 node = gen.node(node_name, uuid, prof_uuid)
608 lustre.appendChild(node)
609 lustre.appendChild(profile)
611 node_add_profile(gen, node, 'ldlm', ldlm_uuid)
612 set_node_options(gen, node, options)
616 def add_node(gen, lustre, options):
617 """ create a node with a network config """
619 node_name = get_option(options, 'node')
620 ret = findByName(lustre, node_name, "node")
622 print "Node:", node_name, "exists."
624 do_add_node(gen, lustre, options, node_name)
627 def add_net(gen, lustre, options):
628 """ create a node with a network config """
630 node_name = get_option(options, 'node')
631 nid = get_option(options, 'nid')
632 cluster_id = get_option(options, 'cluster_id')
633 hostaddr = get_option(options, 'hostaddr')
634 net_type = get_option(options, 'nettype')
636 if net_type in ('tcp',):
637 port = get_option_int(options, 'port')
638 tcpbuf = get_option_int(options, 'tcpbuf')
639 irq_aff = get_option_int(options, 'irq_affinity')
640 elif net_type in ('elan', 'gm', 'scimac'):
645 print "Unknown net_type: ", net_type
648 ret = findByName(lustre, node_name, "node")
650 node = do_add_node(gen, lustre, options, node_name)
653 set_node_options(gen, node, options)
655 net_name = new_name('NET_'+ node_name +'_'+ net_type)
656 net_uuid = new_uuid(net_name)
657 node.appendChild(gen.network(net_name, net_uuid, nid, cluster_id, net_type,
658 hostaddr, port, tcpbuf, irq_aff))
659 node_add_profile(gen, node, "network", net_uuid)
662 def add_route(gen, lustre, options):
663 """ create a node with a network config """
665 node_name = get_option(options, 'node')
666 gw_net_type = get_option(options, 'nettype')
667 gw = get_option(options, 'gw')
668 gw_cluster_id = get_option(options, 'gateway_cluster_id')
669 tgt_cluster_id = get_option(options, 'target_cluster_id')
670 lo = get_option(options, 'lo')
671 hi = get_option(options, 'hi')
675 node = findByName(lustre, node_name, "node")
677 error (node_name, " not found.")
679 rlist = node.getElementsByTagName('routetbl')
683 rtbl_name = new_name("RTBL_" + node_name)
684 rtbl_uuid = new_uuid(rtbl_name)
685 rtbl = gen.routetbl(rtbl_name, rtbl_uuid)
686 node.appendChild(rtbl)
687 node_add_profile(gen, node, "routetbl", rtbl_uuid)
688 rtbl.appendChild(gen.route(gw_net_type, gw, gw_cluster_id, tgt_cluster_id,
692 def add_mds(gen, lustre, options):
693 node_name = get_option(options, 'node')
694 mds_name = get_option(options, 'mds')
695 mdd_name = new_name("MDD_" + mds_name +"_" + node_name)
696 mdd_uuid = new_uuid(mdd_name)
698 mds_uuid = name2uuid(lustre, mds_name, 'mds', fatal=0)
700 mds_uuid = new_uuid(mds_name)
701 mds = gen.mds(mds_name, mds_uuid, mdd_uuid, options.group)
702 lustre.appendChild(mds)
704 mds = lookup(lustre, mds_uuid)
706 mds.setAttribute('failover', "1")
708 devname = get_option(options, 'dev')
709 size = get_option(options, 'size')
710 fstype = get_option(options, 'fstype')
711 journal_size = get_option(options, 'journal_size')
712 inode_size = get_option(options, 'inode_size')
713 nspath = get_option(options, 'nspath')
714 mkfsoptions = get_option(options, 'mkfsoptions')
716 node_uuid = name2uuid(lustre, node_name, 'node')
718 node = findByName(lustre, node_name, "node")
719 node_add_profile(gen, node, "mdsdev", mdd_uuid)
720 net_uuid = get_net_uuid(lustre, node_name)
722 error("NODE: ", node_name, "not found")
724 mdd = gen.mdsdev(mdd_name, mdd_uuid, fstype, devname,
725 get_format_flag(options), node_uuid, mds_uuid,
726 size, journal_size, inode_size, nspath, mkfsoptions)
727 lustre.appendChild(mdd)
730 def add_mgmt(gen, lustre, options):
731 node_name = get_option(options, 'node')
732 node_uuid = name2uuid(lustre, node_name, 'node')
733 mgmt_name = get_option(options, 'mgmt')
735 mgmt_name = new_name('MGMT_' + node_name)
736 mgmt_uuid = name2uuid(lustre, mgmt_name, 'mgmt', fatal=0)
738 mgmt_uuid = new_uuid(mgmt_name)
739 mgmt = gen.mgmt(mgmt_name, mgmt_uuid, node_uuid)
740 lustre.appendChild(mgmt)
742 mgmt = lookup(lustre, mgmt_uuid)
744 node = findByName(lustre, node_name, "node")
745 node_add_profile(gen, node, 'mgmt', mgmt_uuid)
747 def add_ost(gen, lustre, options):
748 node_name = get_option(options, 'node')
749 lovname = get_option(options, 'lov')
750 osdtype = get_option(options, 'osdtype')
752 node_uuid = name2uuid(lustre, node_name, 'node')
754 if osdtype == 'obdecho':
763 devname = get_option(options, 'dev') # can be unset for bluearcs
764 size = get_option(options, 'size')
765 fstype = get_option(options, 'fstype')
766 journal_size = get_option(options, 'journal_size')
767 inode_size = get_option(options, 'inode_size')
768 mkfsoptions = get_option(options, 'mkfsoptions')
770 nspath = get_option(options, 'nspath')
772 ostname = get_option(options, 'ost')
774 ostname = new_name('OST_'+ node_name)
776 osdname = new_name("OSD_" + ostname + "_" + node_name)
777 osd_uuid = new_uuid(osdname)
779 ost_uuid = name2uuid(lustre, ostname, 'ost', fatal=0)
781 ost_uuid = get_option(options, 'ostuuid')
783 if lookup(lustre, ost_uuid):
784 error("Duplicate OST UUID:", ost_uuid)
786 ost_uuid = new_uuid(ostname)
788 ost = gen.ost(ostname, ost_uuid, osd_uuid, options.group)
789 lustre.appendChild(ost)
791 lov = findByName(lustre, lovname, "lov")
793 error('add_ost:', '"'+lovname+'"', "lov element not found.")
794 lov_add_obd(gen, lov, ost_uuid)
796 ost = lookup(lustre, ost_uuid)
799 ost.setAttribute('failover', "1")
802 osd = gen.osd(osdname, osd_uuid, fstype, osdtype, devname,
803 get_format_flag(options), ost_uuid, node_uuid, size,
804 journal_size, inode_size, nspath, mkfsoptions)
806 node = findByName(lustre, node_name, "node")
808 ## if node_add_profile(gen, node, 'oss', oss_uuid):
810 ## oss_uuid = new_uuid(ossname)
811 ## oss = gen.oss(ossname, oss_uuid)
812 ## lustre.appendChild(oss)
814 node_add_profile(gen, node, 'osd', osd_uuid)
815 lustre.appendChild(osd)
818 def add_cobd(gen, lustre, options):
819 node_name = get_option(options, 'node')
820 name = new_name('COBD_' + node_name)
821 uuid = new_uuid(name)
823 real_name = get_option(options, 'real_obd')
824 cache_name = get_option(options, 'cache_obd')
826 real_uuid = name2uuid(lustre, real_name, tag='obd')
827 cache_uuid = name2uuid(lustre, cache_name, tag='obd')
829 node = findByName(lustre, node_name, "node")
830 node_add_profile(gen, node, "cobd", uuid)
831 cobd = gen.cobd(name, uuid, real_uuid, cache_uuid)
832 lustre.appendChild(cobd)
835 def add_echo_client(gen, lustre, options):
836 """ add an echo client to the profile for this node. """
837 node_name = get_option(options, 'node')
838 lov_name = get_option(options, 'ost')
840 node = findByName(lustre, node_name, 'node')
842 echoname = new_name('ECHO_'+ node_name)
843 echo_uuid = new_uuid(echoname)
844 node_add_profile(gen, node, 'echoclient', echo_uuid)
846 lov_uuid = name2uuid(lustre, lov_name, tag='lov', fatal=0)
848 lov_uuid = name2uuid(lustre, lov_name, tag='ost', fatal=1)
850 echo = gen.echo_client(echoname, echo_uuid, lov_uuid)
851 lustre.appendChild(echo)
854 def add_lov(gen, lustre, options):
857 lov_orig = get_option(options, 'lov')
858 name = new_name(lov_orig)
860 warning("name:", lov_orig, "already used. using:", name)
862 mds_name = get_option(options, 'mds')
863 stripe_sz = get_option_int(options, 'stripe_sz')
864 stripe_cnt = get_option_int(options, 'stripe_cnt')
865 pattern = get_option_int(options, 'stripe_pattern')
866 uuid = new_uuid(name)
868 ret = findByName(lustre, name, "lov")
870 error("LOV: ", name, " already exists.")
872 mds_uuid = name2uuid(lustre, mds_name, 'mds')
873 lov = gen.lov(name, uuid, mds_uuid, stripe_sz, stripe_cnt, pattern)
874 lustre.appendChild(lov)
876 # add an lovconfig entry to the active mdsdev profile
877 lovconfig_name = new_name('LVCFG_' + name)
878 lovconfig_uuid = new_uuid(lovconfig_name)
879 mds = findByName(lustre, mds_name, "mds")
880 mds.appendChild(gen.ref("lovconfig", lovconfig_uuid))
881 lovconfig = gen.lovconfig(lovconfig_name, lovconfig_uuid, uuid)
882 lustre.appendChild(lovconfig)
884 def add_default_lov(gen, lustre, mds_name, lov_name):
885 """ create a default lov """
887 stripe_sz = DEFAULT_STRIPE_SZ
888 stripe_cnt = DEFAULT_STRIPE_CNT
889 pattern = DEFAULT_STRIPE_PATTERN
890 uuid = new_uuid(lov_name)
892 ret = findByName(lustre, lov_name, "lov")
894 error("LOV: ", lov_name, " already exists.")
896 mds_uuid = name2uuid(lustre, mds_name, 'mds')
897 lov = gen.lov(lov_name, uuid, mds_uuid, stripe_sz, stripe_cnt, pattern)
898 lustre.appendChild(lov)
900 # add an lovconfig entry to the active mdsdev profile
901 lovconfig_name = new_name('LVCFG_' + lov_name)
902 lovconfig_uuid = new_uuid(lovconfig_name)
903 mds = findByName(lustre, mds_name)
904 mds.appendChild(gen.ref("lovconfig", lovconfig_uuid))
905 lovconfig = gen.lovconfig(lovconfig_name, lovconfig_uuid, uuid)
906 lustre.appendChild(lovconfig)
908 def new_filesystem(gen, lustre, mds_uuid, obd_uuid, mgmt_uuid):
909 fs_name = new_name("FS_fsname")
910 fs_uuid = new_uuid(fs_name)
911 mds = lookup(lustre, mds_uuid)
912 mds.appendChild(gen.ref("filesystem", fs_uuid))
913 fs = gen.filesystem(fs_name, fs_uuid, mds_uuid, obd_uuid, mgmt_uuid)
914 lustre.appendChild(fs)
917 def get_fs_uuid(gen, lustre, mds_name, obd_name, mgmt_name):
918 mds_uuid = name2uuid(lustre, mds_name, tag='mds')
919 obd_uuid = name2uuid(lustre, obd_name, tag='lov', fatal=0)
921 mgmt_uuid = name2uuid(lustre, mgmt_name, tag='mgmt', fatal=1)
924 fs_uuid = lookup_filesystem(lustre, mds_uuid, obd_uuid)
926 fs_uuid = new_filesystem(gen, lustre, mds_uuid, obd_uuid, mgmt_uuid)
929 def add_mtpt(gen, lustre, options):
930 """ create mtpt on a node """
931 node_name = get_option(options, 'node')
933 path = get_option(options, 'path')
934 fs_name = get_option(options, 'filesystem')
936 lov_name = get_option(options, 'lov')
937 ost_name = get_option(options, 'ost')
938 mds_name = get_option(options, 'mds')
941 error("--add mtpt requires --lov lov_name or --ost ost_name")
943 warning("use default value for lov, due no --lov lov_name provided")
944 lov_name = new_name("lov_default")
945 add_default_lov(gen, lustre, mds_name, lov_name)
946 ost_uuid = name2uuid(lustre, ost_name, 'ost', fatal=0)
948 error('add_mtpt:', '"'+ost_name+'"', "ost element not found.")
949 lov = findByName(lustre, lov_name, "lov")
950 lov_add_obd(gen, lov, ost_uuid)
953 mgmt_name = get_option(options, 'mgmt')
954 fs_uuid = get_fs_uuid(gen, lustre, mds_name, lov_name, mgmt_name)
956 fs_uuid = name2uuid(lustre, fs_name, tag='filesystem')
958 name = new_name('MNT_'+ node_name)
960 ret = findByName(lustre, name, "mountpoint")
962 # this can't happen, because new_name creates unique names
963 error("MOUNTPOINT: ", name, " already exists.")
965 uuid = new_uuid(name)
966 mtpt = gen.mountpoint(name, uuid, fs_uuid, path)
967 node = findByName(lustre, node_name, "node")
969 error('node:', node_name, "not found.")
970 node_add_profile(gen, node, "mountpoint", uuid)
971 lustre.appendChild(mtpt)
973 ############################################################
974 # Command line processing
976 class OptionError (exceptions.Exception):
977 def __init__(self, args):
980 def get_option(options, tag):
981 """Look for tag in options hash and return the value if set. If not
982 set, then if return default it is set, otherwise exception."""
983 if options.__getattr__(tag) != None:
984 return options.__getattr__(tag)
986 raise OptionError("--add %s requires --%s <value>" % (options.add, tag))
988 def get_option_int(options, tag):
989 """Return an integer option. Raise exception if the value is not an int"""
990 val = get_option(options, tag)
994 raise OptionError("--%s <num> (value must be integer)" % (tag))
997 # simple class for profiling
1004 self._start = time.time()
1005 def stop(self, msg=''):
1006 self._stop = time.time()
1010 return self._stop - self._start
1011 def display(self, msg):
1013 str = '%s: %g secs' % (msg, d)
1016 #################################################################
1017 # function cmdlinesplit used to split cmd line from batch file
1019 def cmdlinesplit(cmdline):
1021 double_quote = re.compile(r'"(([^"\\]|\\.)*)"')
1022 single_quote = re.compile(r"'(.*?)'")
1023 escaped = re.compile(r'\\(.)')
1024 esc_quote = re.compile(r'\\([\\"])')
1025 outside = re.compile(r"""([^\s\\'"]+)""")
1029 while i < len(cmdline):
1032 match = double_quote.match(cmdline, i)
1034 print "Unmatched double quote:", cmdline
1037 if arg is None: arg = esc_quote.sub(r'\1', match.group(1))
1038 else: arg = arg + esc_quote.sub(r'\1', match.group(1))
1041 match = single_quote.match(cmdline, i)
1043 print "Unmatched single quote:", cmdline
1046 if arg is None: arg = match.group(1)
1047 else: arg = arg + match.group(1)
1050 match = escaped.match(cmdline, i)
1052 print "Unmatched backslash", cmdline
1055 if arg is None: arg = match.group(1)
1056 else: arg = arg + match.group(1)
1058 elif c in string.whitespace:
1060 arg_list.append(str(arg))
1062 while i < len(cmdline) and cmdline[i] in string.whitespace:
1065 match = outside.match(cmdline, i)
1068 if arg is None: arg = match.group()
1069 else: arg = arg + match.group()
1071 if arg != None: arg_list.append(str(arg))
1075 ############################################################
1079 def add(devtype, gen, lustre, options):
1080 if devtype == 'net':
1081 add_net(gen, lustre, options)
1082 elif devtype == 'mtpt':
1083 add_mtpt(gen, lustre, options)
1084 elif devtype == 'mds':
1085 add_mds(gen, lustre, options)
1086 elif devtype == 'ost':
1087 add_ost(gen, lustre, options)
1088 elif devtype == 'lov':
1089 add_lov(gen, lustre, options)
1090 elif devtype == 'route':
1091 add_route(gen, lustre, options)
1092 elif devtype == 'node':
1093 add_node(gen, lustre, options)
1094 elif devtype == 'echo_client':
1095 add_echo_client(gen, lustre, options)
1096 elif devtype == 'cobd':
1097 add_cobd(gen, lustre, options)
1098 elif devtype == 'mgmt':
1099 add_mgmt(gen, lustre, options)
1101 error("unknown device type:", devtype)
1103 def do_command(gen, lustre, options, args):
1105 add(options.add, gen, lustre, options)
1107 error("Missing command")
1110 cl = Lustre.Options("lmc", "", lmc_options)
1112 options, args = cl.parse(sys.argv[1:])
1113 except Lustre.OptionError, e:
1117 panic(string.join(sys.argv), "Unexpected extra arguments on command line: " + string.join(args))
1119 if options.reference:
1126 outFile = options.merge
1127 if os.access(outFile, os.R_OK):
1128 doc = xml.dom.minidom.parse(outFile)
1130 doc = new_lustre(xml.dom.minidom)
1132 doc = xml.dom.minidom.parse(options.input)
1134 doc = new_lustre(xml.dom.minidom)
1137 outFile = options.output
1139 lustre = doc.documentElement
1141 if lustre.tagName != "lustre":
1142 print "Existing config not valid."
1145 gen = GenConfig(doc)
1148 fp = open(options.batch)
1149 batchCommands = fp.readlines()
1151 for cmd in batchCommands:
1153 options, args = cl.parse(cmdlinesplit(cmd))
1154 if options.merge or options.input or options.output:
1155 print "The batchfile should not contain --merge, --input or --output."
1157 do_command(gen, lustre, options, args)
1158 except OptionError, e:
1160 except Lustre.OptionError, e:
1164 do_command(gen, lustre, options, args)
1165 except OptionError, e:
1166 panic(string.join(sys.argv),e)
1167 except Lustre.OptionError, e:
1173 printDoc(doc, open(outFile,"w"))
1175 if __name__ == "__main__":