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, random, 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
51 print """usage: lmc --add object [object parameters]
53 Object creation command summary:
61 --ptldebug debug_level
62 --subsystem subsystem_name
68 --nettype tcp|elan|gm|scimac
101 --obdtype obdecho|obdfilter
104 --add mtpt - Mountpoint
108 --ost ost_name OR --lov lov_name
120 --add mgmt - Management/monitoring service
122 --mgmt mgmt_service_name
125 PARAM = Lustre.Options.PARAM
127 # lmc input/output options
128 ('reference', "Print short reference for commands."),
129 ('verbose,v', "Print system commands as they are run."),
130 ('merge,m', "Append to the specified config file.", PARAM),
131 ('output,o', "Write XML configuration into given output file. Overwrite existing content.", PARAM),
132 ('input,i', "", PARAM),
133 ('batch', "Used to execute lmc commands in batch mode.", PARAM),
139 ('node', "Add a new node in the cluster configuration.", PARAM),
140 ('timeout', "Set timeout to initiate recovery.", PARAM),
141 ('upcall', "Set both lustre and portals upcall scripts.", PARAM),
142 ('lustre_upcall', "Set location of lustre upcall script.", PARAM),
143 ('portals_upcall', "Set location of portals upcall script.", PARAM),
144 ('ptldebug', "Set the portals debug level", PARAM),
145 ('subsystem', "Specify which Lustre subsystems have debug output recorded in the log", PARAM),
148 ('nettype', "Specify the network type. This can be tcp/elan/gm/scimac.", PARAM),
149 ('nid', "Give the network ID, e.g ElanID/IP Address as used by portals.", PARAM),
150 ('tcpbuf', "Optional argument to specify the TCP buffer size.", PARAM, "0"),
151 ('port', "Optional argument to specify the TCP port number.", PARAM, DEFAULT_PORT),
152 ('irq_affinity', "Optional argument.", PARAM, 0),
153 ('hostaddr', "", PARAM,""),
154 ('cluster_id', "Specify the cluster ID", PARAM, "0"),
157 ('route', "Add a new route for the cluster.", PARAM),
158 ('router', "Optional flag to mark a node as router."),
159 ('gw', "Specify the nid of the gateway for a route.", PARAM),
160 ('gateway_cluster_id', "", PARAM, "0"),
161 ('target_cluster_id', "", PARAM, "0"),
162 ('lo', "For a range route, this is the low value nid.", PARAM),
163 ('hi', "For a range route, this is a hi value nid.", PARAM,""),
165 # servers: mds and ost
166 ('mds', "Specify MDS name.", PARAM),
167 ('ost', "Specify the OST name.", PARAM,""),
168 ('osdtype', "This could obdfilter or obdecho.", PARAM, "obdfilter"),
169 ('failover', "Enable failover support on OSTs or MDS?"),
170 ('group', "", PARAM),
171 ('dev', "Path of the device on local system.", PARAM,""),
172 ('size', "Specify the size of the device if needed.", PARAM,"0"),
173 ('journal_size', "Specify new journal size for underlying ext3 file system.", PARAM,"0"),
174 ('inode_size', "Specify new inode size for underlying ext3 file system.", PARAM,"0"),
175 ('fstype', "Optional argument to specify the filesystem type.", PARAM, "ext3"),
176 ('mkfsoptions', "Optional argument to mkfs.", PARAM, ""),
177 ('ostuuid', "", PARAM,""),
178 ('nspath', "Local mount point of server namespace.", PARAM,""),
181 # clients: mountpoint and echo
182 ('echo_client', "", PARAM),
183 ('path', "Specify the mountpoint for Lustre.", PARAM),
184 ('filesystem', "Lustre filesystem name", PARAM,""),
187 ('lov', "Specify LOV name.", PARAM,""),
188 ('stripe_sz', "Specify the stripe size in bytes.", PARAM),
189 ('stripe_cnt', "Specify the number of OSTs each file should be striped on.", PARAM, 0),
190 ('stripe_pattern', "Specify the stripe pattern. RAID 0 is the only one currently supported.", PARAM, 0),
193 ('real_obd', "", PARAM),
194 ('cache_obd', "", PARAM),
196 ('mgmt', "Specify management/monitoring service name.", PARAM, ""),
200 msg = string.join(map(str,args))
201 raise OptionError("Error: " + msg)
210 msg = string.join(map(str,args))
211 print "Warning: ", msg
214 # manage names and uuids
215 # need to initialize this by walking tree to ensure
216 # no duplicate names or uuids are created.
217 # this are just place holders for now.
218 # consider changing this to be like OBD-dev-host
222 while names.has_key(ret):
223 ret = "%s_%d" % (base, ctr)
229 ret_uuid = '%05x_%.19s_%05x%05x' % (int(random.random() * 1048576),
231 int(random.random() * 1048576),
232 int(random.random() * 1048576))
236 ldlm_uuid = 'ldlm_UUID'
239 """Create a new empty lustre document"""
240 # adding ldlm here is a bit of a hack, but one is enough.
241 str = """<lustre version="%s">
242 <ldlm name="%s" uuid="%s"/>
243 </lustre>""" % (Lustre.CONFIG_VERSION, ldlm_name, ldlm_uuid)
244 return dom.parseString(str)
250 """initialize auto-name generation tables"""
252 # get all elements that contain a name attribute
253 for n in doc.childNodes:
254 if n.nodeType == n.ELEMENT_NODE:
256 names[getName(n)] = 1
257 uuids[getUUID(n)] = 1
260 def get_format_flag(options):
265 ############################################################
266 # Build config objects using DOM
271 def __init__(self, doc):
274 def ref(self, type, uuid):
275 """ generate <[type]_ref uuidref="[uuid]"/> """
276 tag = "%s_ref" % (type)
277 ref = self.doc.createElement(tag)
278 ref.setAttribute("uuidref", uuid)
281 def newService(self, tag, name, uuid):
282 """ create a new service elmement, which requires name and uuid attributes """
283 new = self.doc.createElement(tag)
284 new.setAttribute("uuid", uuid);
285 new.setAttribute("name", name);
288 def addText(self, node, str):
289 txt = self.doc.createTextNode(str)
290 node.appendChild(txt)
292 def addElement(self, node, tag, str=None):
293 """ create a new element and add it as a child to node. If str is passed,
294 a text node is created for the new element"""
295 new = self.doc.createElement(tag)
297 self.addText(new, str)
298 node.appendChild(new)
301 def network(self, name, uuid, nid, cluster_id, net, hostaddr="",
302 port=0, tcpbuf=0, irq_aff=0):
303 """create <network> node"""
304 network = self.newService("network", name, uuid)
305 network.setAttribute("nettype", net);
306 self.addElement(network, "nid", nid)
307 self.addElement(network, "clusterid", cluster_id)
309 self.addElement(network, "hostaddr", hostaddr)
311 self.addElement(network, "port", "%d" %(port))
313 self.addElement(network, "sendmem", "%d" %(tcpbuf))
314 self.addElement(network, "recvmem", "%d" %(tcpbuf))
316 self.addElement(network, "irqaffinity", "%d" %(irq_aff))
320 def routetbl(self, name, uuid):
321 """create <routetbl> node"""
322 rtbl = self.newService("routetbl", name, uuid)
325 def route(self, gw_net_type, gw, gw_cluster_id, tgt_cluster_id, lo, hi):
326 """ create one entry for the route table """
327 ref = self.doc.createElement('route')
328 ref.setAttribute("type", gw_net_type)
329 ref.setAttribute("gw", gw)
330 ref.setAttribute("gwclusterid", gw_cluster_id)
331 ref.setAttribute("tgtclusterid", tgt_cluster_id)
332 ref.setAttribute("lo", lo)
334 ref.setAttribute("hi", hi)
337 def profile(self, name, uuid):
338 """ create a host """
339 profile = self.newService("profile", name, uuid)
342 def node(self, name, uuid, prof_uuid):
343 """ create a host """
344 node = self.newService("node", name, uuid)
345 node.appendChild(self.ref("profile", prof_uuid))
348 def ldlm(self, name, uuid):
349 """ create a ldlm """
350 ldlm = self.newService("ldlm", name, uuid)
353 def osd(self, name, uuid, fs, osdtype, devname, format, ost_uuid,
354 node_uuid, dev_size=0, journal_size=0, inode_size=0, nspath=""):
355 osd = self.newService("osd", name, uuid)
356 osd.setAttribute('osdtype', osdtype)
357 osd.appendChild(self.ref("target", ost_uuid))
358 osd.appendChild(self.ref("node", node_uuid))
360 self.addElement(osd, "fstype", fs)
362 dev = self.addElement(osd, "devpath", devname)
363 self.addElement(osd, "autoformat", format)
365 self.addElement(osd, "devsize", "%s" % (dev_size))
367 self.addElement(osd, "journalsize", "%s" % (journal_size))
369 self.addElement(osd, "inodesize", "%s" % (inode_size))
371 self.addElement(osd, "nspath", nspath)
374 def cobd(self, name, uuid, real_uuid, cache_uuid):
375 cobd = self.newService("cobd", name, uuid)
376 cobd.appendChild(self.ref("realobd",real_uuid))
377 cobd.appendChild(self.ref("cacheobd",cache_uuid))
380 def ost(self, name, uuid, osd_uuid, group=""):
381 ost = self.newService("ost", name, uuid)
382 ost.appendChild(self.ref("active", osd_uuid))
384 self.addElement(ost, "group", group)
387 def oss(self, name, uuid):
388 oss = self.newService("oss", name, uuid)
391 def lov(self, name, uuid, mds_uuid, stripe_sz, stripe_cnt, pattern):
392 lov = self.newService("lov", name, uuid)
393 lov.appendChild(self.ref("mds", mds_uuid))
394 lov.setAttribute("stripesize", str(stripe_sz))
395 lov.setAttribute("stripecount", str(stripe_cnt))
396 lov.setAttribute("stripepattern", str(pattern))
399 def lovconfig(self, name, uuid, lov_uuid):
400 lovconfig = self.newService("lovconfig", name, uuid)
401 lovconfig.appendChild(self.ref("lov", lov_uuid))
404 def mds(self, name, uuid, mdd_uuid, group=""):
405 mds = self.newService("mds", name, uuid)
406 mds.appendChild(self.ref("active",mdd_uuid))
408 self.addElement(mds, "group", group)
411 def mdsdev(self, name, uuid, fs, devname, format, node_uuid,
412 mds_uuid, dev_size=0, journal_size=0, inode_size=256,
413 nspath="", mkfsoptions=""):
414 mdd = self.newService("mdsdev", name, uuid)
415 self.addElement(mdd, "fstype", fs)
416 dev = self.addElement(mdd, "devpath", devname)
417 self.addElement(mdd, "autoformat", format)
419 self.addElement(mdd, "devsize", "%s" % (dev_size))
421 self.addElement(mdd, "journalsize", "%s" % (journal_size))
423 self.addElement(mdd, "inodesize", "%s" % (inode_size))
425 self.addElement(mdd, "nspath", nspath)
427 self.addElement(mdd, "mkfsoptions", mkfsoptions)
428 mdd.appendChild(self.ref("node", node_uuid))
429 mdd.appendChild(self.ref("target", mds_uuid))
432 def mgmt(self, mgmt_name, mgmt_uuid, node_uuid):
433 mgmt = self.newService("mgmt", mgmt_name, mgmt_uuid)
434 mgmt.appendChild(self.ref("node", node_uuid))
435 # Placeholder until mgmt-service failover.
436 mgmt.appendChild(self.ref("active", mgmt_uuid))
439 def mountpoint(self, name, uuid, fs_uuid, path):
440 mtpt = self.newService("mountpoint", name, uuid)
441 mtpt.appendChild(self.ref("filesystem", fs_uuid))
442 self.addElement(mtpt, "path", path)
445 def filesystem(self, name, uuid, mds_uuid, obd_uuid, mgmt_uuid):
446 fs = self.newService("filesystem", name, uuid)
447 fs.appendChild(self.ref("mds", mds_uuid))
448 fs.appendChild(self.ref("obd", obd_uuid))
450 fs.appendChild(self.ref("mgmt", mgmt_uuid))
453 def echo_client(self, name, uuid, osc_uuid):
454 ec = self.newService("echoclient", name, uuid)
455 ec.appendChild(self.ref("obd", osc_uuid))
458 ############################################################
459 # Utilities to query a DOM tree
460 # Using this functions we can treat use config information
461 # directly as a database.
463 return n.getAttribute('name')
466 return node.getAttribute('uuid')
469 def findByName(lustre, name, tag = ""):
470 for n in lustre.childNodes:
471 if n.nodeType == n.ELEMENT_NODE:
472 if tag and n.nodeName != tag:
474 if getName(n) == name:
477 n = findByName(n, name)
482 def lookup(node, uuid):
483 for n in node.childNodes:
484 if n.nodeType == n.ELEMENT_NODE:
485 if getUUID(n) == uuid:
493 def name2uuid(lustre, name, tag="", fatal=1):
494 ret = findByName(lustre, name, tag)
497 error('name2uuid:', '"'+name+'"', tag, 'element not found.')
502 def lookup_filesystem(lustre, mds_uuid, ost_uuid):
503 for n in lustre.childNodes:
504 if n.nodeType == n.ELEMENT_NODE and n.nodeName == 'filesystem':
505 if ref_exists(n, mds_uuid) and ref_exists(n, ost_uuid):
509 # XXX: assumes only one network element per node. will fix this
510 # as soon as support for routers is added
511 def get_net_uuid(lustre, node_name):
512 """ get a network uuid for a node_name """
513 node = findByName(lustre, node_name, "node")
515 error ('get_net_uuid:', '"'+node_name+'"', "node element not found.")
516 net = node.getElementsByTagName('network')
518 return getUUID(net[0])
522 def lov_add_obd(gen, lov, osc_uuid):
523 lov.appendChild(gen.ref("obd", osc_uuid))
525 def ref_exists(profile, uuid):
526 elist = profile.childNodes
528 if e.nodeType == e.ELEMENT_NODE:
529 ref = e.getAttribute('uuidref')
534 # ensure that uuid is not already in the profile
535 # return true if uuid is added
536 def node_add_profile(gen, node, ref, uuid):
537 refname = "%s_ref" % "profile"
538 ret = node.getElementsByTagName(refname)
540 error('node has no profile ref:', node)
541 prof_uuid = ret[0].getAttribute('uuidref')
542 profile = lookup(node.parentNode, prof_uuid)
544 error("no profile found:", prof_uuid)
545 if ref_exists(profile, uuid):
547 profile.appendChild(gen.ref(ref, uuid))
550 def get_attr(dom_node, attr, default=""):
551 v = dom_node.getAttribute(attr)
556 ############################################################
559 def set_node_options(gen, node, options):
561 node.setAttribute('router', '1')
563 gen.addElement(node, "timeout", get_option(options, 'timeout'))
565 default_upcall = get_option(options, 'upcall')
568 if default_upcall or options.lustre_upcall:
569 if options.lustre_upcall:
570 gen.addElement(node, 'lustreUpcall', options.lustre_upcall)
572 gen.addElement(node, 'lustreUpcall', default_upcall)
573 if default_upcall or options.portals_upcall:
574 if options.portals_upcall:
575 gen.addElement(node, 'portalsUpcall', options.portals_upcall)
577 gen.addElement(node, 'portalsUpcall', default_upcall)
579 gen.addElement(node, "ptldebug", get_option(options, 'ptldebug'))
580 if options.subsystem:
581 gen.addElement(node, "subsystem", get_option(options, 'subsystem'))
584 def do_add_node(gen, lustre, options, node_name):
585 uuid = new_uuid(node_name)
586 prof_name = new_name("PROFILE_" + node_name)
587 prof_uuid = new_uuid(prof_name)
588 profile = gen.profile(prof_name, prof_uuid)
589 node = gen.node(node_name, uuid, prof_uuid)
590 lustre.appendChild(node)
591 lustre.appendChild(profile)
593 node_add_profile(gen, node, 'ldlm', ldlm_uuid)
594 set_node_options(gen, node, options)
598 def add_node(gen, lustre, options):
599 """ create a node with a network config """
601 node_name = get_option(options, 'node')
602 ret = findByName(lustre, node_name, "node")
604 print "Node:", node_name, "exists."
606 do_add_node(gen, lustre, options, node_name)
609 def add_net(gen, lustre, options):
610 """ create a node with a network config """
612 node_name = get_option(options, 'node')
613 nid = get_option(options, 'nid')
614 cluster_id = get_option(options, 'cluster_id')
615 hostaddr = get_option(options, 'hostaddr')
616 net_type = get_option(options, 'nettype')
618 if net_type in ('tcp',):
619 port = get_option_int(options, 'port')
620 tcpbuf = get_option_int(options, 'tcpbuf')
621 irq_aff = get_option_int(options, 'irq_affinity')
622 elif net_type in ('elan', 'gm', 'scimac'):
627 print "Unknown net_type: ", net_type
630 ret = findByName(lustre, node_name, "node")
632 node = do_add_node(gen, lustre, options, node_name)
635 set_node_options(gen, node, options)
637 net_name = new_name('NET_'+ node_name +'_'+ net_type)
638 net_uuid = new_uuid(net_name)
639 node.appendChild(gen.network(net_name, net_uuid, nid, cluster_id, net_type,
640 hostaddr, port, tcpbuf, irq_aff))
641 node_add_profile(gen, node, "network", net_uuid)
644 def add_route(gen, lustre, options):
645 """ create a node with a network config """
647 node_name = get_option(options, 'node')
648 gw_net_type = get_option(options, 'nettype')
649 gw = get_option(options, 'gw')
650 gw_cluster_id = get_option(options, 'gateway_cluster_id')
651 tgt_cluster_id = get_option(options, 'target_cluster_id')
652 lo = get_option(options, 'lo')
653 hi = get_option(options, 'hi')
657 node = findByName(lustre, node_name, "node")
659 error (node_name, " not found.")
661 rlist = node.getElementsByTagName('routetbl')
665 rtbl_name = new_name("RTBL_" + node_name)
666 rtbl_uuid = new_uuid(rtbl_name)
667 rtbl = gen.routetbl(rtbl_name, rtbl_uuid)
668 node.appendChild(rtbl)
669 node_add_profile(gen, node, "routetbl", rtbl_uuid)
670 rtbl.appendChild(gen.route(gw_net_type, gw, gw_cluster_id, tgt_cluster_id,
674 def add_mds(gen, lustre, options):
675 node_name = get_option(options, 'node')
676 mds_name = get_option(options, 'mds')
677 mdd_name = new_name("MDD_" + mds_name +"_" + node_name)
678 mdd_uuid = new_uuid(mdd_name)
680 mds_uuid = name2uuid(lustre, mds_name, 'mds', fatal=0)
682 mds_uuid = new_uuid(mds_name)
683 mds = gen.mds(mds_name, mds_uuid, mdd_uuid, options.group)
684 lustre.appendChild(mds)
686 mds = lookup(lustre, mds_uuid)
688 mds.setAttribute('failover', "1")
690 devname = get_option(options, 'dev')
691 size = get_option(options, 'size')
692 fstype = get_option(options, 'fstype')
693 journal_size = get_option(options, 'journal_size')
694 inode_size = get_option(options, 'inode_size')
695 nspath = get_option(options, 'nspath')
696 mkfsoptions = get_option(options, 'mkfsoptions')
698 node_uuid = name2uuid(lustre, node_name, 'node')
700 node = findByName(lustre, node_name, "node")
701 node_add_profile(gen, node, "mdsdev", mdd_uuid)
702 net_uuid = get_net_uuid(lustre, node_name)
704 error("NODE: ", node_name, "not found")
706 mdd = gen.mdsdev(mdd_name, mdd_uuid, fstype, devname,
707 get_format_flag(options), node_uuid, mds_uuid,
708 size, journal_size, inode_size, nspath, mkfsoptions)
709 lustre.appendChild(mdd)
712 def add_mgmt(gen, lustre, options):
713 node_name = get_option(options, 'node')
714 node_uuid = name2uuid(lustre, node_name, 'node')
715 mgmt_name = get_option(options, 'mgmt')
717 mgmt_name = new_name('MGMT_' + node_name)
718 mgmt_uuid = name2uuid(lustre, mgmt_name, 'mgmt', fatal=0)
720 mgmt_uuid = new_uuid(mgmt_name)
721 mgmt = gen.mgmt(mgmt_name, mgmt_uuid, node_uuid)
722 lustre.appendChild(mgmt)
724 mgmt = lookup(lustre, mgmt_uuid)
726 node = findByName(lustre, node_name, "node")
727 node_add_profile(gen, node, 'mgmt', mgmt_uuid)
729 def add_ost(gen, lustre, options):
730 node_name = get_option(options, 'node')
731 lovname = get_option(options, 'lov')
732 osdtype = get_option(options, 'osdtype')
734 node_uuid = name2uuid(lustre, node_name, 'node')
736 if osdtype == 'obdecho':
744 devname = get_option(options, 'dev') # can be unset for bluearcs
745 size = get_option(options, 'size')
746 fstype = get_option(options, 'fstype')
747 journal_size = get_option(options, 'journal_size')
748 inode_size = get_option(options, 'inode_size')
750 nspath = get_option(options, 'nspath')
752 ostname = get_option(options, 'ost')
754 ostname = new_name('OST_'+ node_name)
756 osdname = new_name("OSD_" + ostname + "_" + node_name)
757 osd_uuid = new_uuid(osdname)
759 ost_uuid = name2uuid(lustre, ostname, 'ost', fatal=0)
761 ost_uuid = get_option(options, 'ostuuid')
763 if lookup(lustre, ost_uuid):
764 error("Duplicate OST UUID:", ost_uuid)
766 ost_uuid = new_uuid(ostname)
768 ost = gen.ost(ostname, ost_uuid, osd_uuid, options.group)
769 lustre.appendChild(ost)
771 lov = findByName(lustre, lovname, "lov")
773 error('add_ost:', '"'+lovname+'"', "lov element not found.")
774 lov_add_obd(gen, lov, ost_uuid)
776 ost = lookup(lustre, ost_uuid)
779 ost.setAttribute('failover', "1")
782 osd = gen.osd(osdname, osd_uuid, fstype, osdtype, devname,
783 get_format_flag(options), ost_uuid, node_uuid, size,
784 journal_size, inode_size, nspath)
786 node = findByName(lustre, node_name, "node")
788 ## if node_add_profile(gen, node, 'oss', oss_uuid):
790 ## oss_uuid = new_uuid(ossname)
791 ## oss = gen.oss(ossname, oss_uuid)
792 ## lustre.appendChild(oss)
794 node_add_profile(gen, node, 'osd', osd_uuid)
795 lustre.appendChild(osd)
798 def add_cobd(gen, lustre, options):
799 node_name = get_option(options, 'node')
800 name = new_name('COBD_' + node_name)
801 uuid = new_uuid(name)
803 real_name = get_option(options, 'real_obd')
804 cache_name = get_option(options, 'cache_obd')
806 real_uuid = name2uuid(lustre, real_name, tag='obd')
807 cache_uuid = name2uuid(lustre, cache_name, tag='obd')
809 node = findByName(lustre, node_name, "node")
810 node_add_profile(gen, node, "cobd", uuid)
811 cobd = gen.cobd(name, uuid, real_uuid, cache_uuid)
812 lustre.appendChild(cobd)
815 def add_echo_client(gen, lustre, options):
816 """ add an echo client to the profile for this node. """
817 node_name = get_option(options, 'node')
818 lov_name = get_option(options, 'ost')
820 node = findByName(lustre, node_name, 'node')
822 echoname = new_name('ECHO_'+ node_name)
823 echo_uuid = new_uuid(echoname)
824 node_add_profile(gen, node, 'echoclient', echo_uuid)
826 lov_uuid = name2uuid(lustre, lov_name, tag='lov', fatal=0)
828 lov_uuid = name2uuid(lustre, lov_name, tag='ost', fatal=1)
830 echo = gen.echo_client(echoname, echo_uuid, lov_uuid)
831 lustre.appendChild(echo)
834 def add_lov(gen, lustre, options):
837 lov_orig = get_option(options, 'lov')
838 name = new_name(lov_orig)
840 warning("name:", lov_orig, "already used. using:", name)
842 mds_name = get_option(options, 'mds')
843 stripe_sz = get_option_int(options, 'stripe_sz')
844 stripe_cnt = get_option_int(options, 'stripe_cnt')
845 pattern = get_option_int(options, 'stripe_pattern')
846 uuid = new_uuid(name)
848 ret = findByName(lustre, name, "lov")
850 error("LOV: ", name, " already exists.")
852 mds_uuid = name2uuid(lustre, mds_name, 'mds')
853 lov = gen.lov(name, uuid, mds_uuid, stripe_sz, stripe_cnt, pattern)
854 lustre.appendChild(lov)
856 # add an lovconfig entry to the active mdsdev profile
857 lovconfig_name = new_name('LVCFG_' + name)
858 lovconfig_uuid = new_uuid(lovconfig_name)
859 mds = findByName(lustre, mds_name)
860 mds.appendChild(gen.ref("lovconfig", lovconfig_uuid))
861 lovconfig = gen.lovconfig(lovconfig_name, lovconfig_uuid, uuid)
862 lustre.appendChild(lovconfig)
864 def add_default_lov(gen, lustre, mds_name, lov_name):
865 """ create a default lov """
867 stripe_sz = DEFAULT_STRIPE_SZ
868 stripe_cnt = DEFAULT_STRIPE_CNT
869 pattern = DEFAULT_STRIPE_PATTERN
870 uuid = new_uuid(lov_name)
872 ret = findByName(lustre, lov_name, "lov")
874 error("LOV: ", lov_name, " already exists.")
876 mds_uuid = name2uuid(lustre, mds_name, 'mds')
877 lov = gen.lov(lov_name, uuid, mds_uuid, stripe_sz, stripe_cnt, pattern)
878 lustre.appendChild(lov)
880 # add an lovconfig entry to the active mdsdev profile
881 lovconfig_name = new_name('LVCFG_' + lov_name)
882 lovconfig_uuid = new_uuid(lovconfig_name)
883 mds = findByName(lustre, mds_name)
884 mds.appendChild(gen.ref("lovconfig", lovconfig_uuid))
885 lovconfig = gen.lovconfig(lovconfig_name, lovconfig_uuid, uuid)
886 lustre.appendChild(lovconfig)
888 def new_filesystem(gen, lustre, mds_uuid, obd_uuid, mgmt_uuid):
889 fs_name = new_name("FS_fsname")
890 fs_uuid = new_uuid(fs_name)
891 mds = lookup(lustre, mds_uuid)
892 mds.appendChild(gen.ref("filesystem", fs_uuid))
893 fs = gen.filesystem(fs_name, fs_uuid, mds_uuid, obd_uuid, mgmt_uuid)
894 lustre.appendChild(fs)
897 def get_fs_uuid(gen, lustre, mds_name, obd_name, mgmt_name):
898 mds_uuid = name2uuid(lustre, mds_name, tag='mds')
899 obd_uuid = name2uuid(lustre, obd_name, tag='lov', fatal=0)
901 mgmt_uuid = name2uuid(lustre, mgmt_name, tag='mgmt', fatal=1)
904 fs_uuid = lookup_filesystem(lustre, mds_uuid, obd_uuid)
906 fs_uuid = new_filesystem(gen, lustre, mds_uuid, obd_uuid, mgmt_uuid)
909 def add_mtpt(gen, lustre, options):
910 """ create mtpt on a node """
911 node_name = get_option(options, 'node')
913 path = get_option(options, 'path')
914 fs_name = get_option(options, 'filesystem')
916 lov_name = get_option(options, 'lov')
917 ost_name = get_option(options, 'ost')
918 mds_name = get_option(options, 'mds')
921 error("--add mtpt requires --lov lov_name or --ost ost_name")
923 warning("use default value for lov, due no --lov lov_name provided")
924 lov_name = new_name("lov_default")
925 add_default_lov(gen, lustre, mds_name, lov_name)
926 ost_uuid = name2uuid(lustre, ost_name, 'ost', fatal=0)
928 error('add_mtpt:', '"'+ost_name+'"', "ost element not found.")
929 lov = findByName(lustre, lov_name, "lov")
930 lov_add_obd(gen, lov, ost_uuid)
933 mgmt_name = get_option(options, 'mgmt')
934 fs_uuid = get_fs_uuid(gen, lustre, mds_name, lov_name, mgmt_name)
936 fs_uuid = name2uuid(lustre, fs_name, tag='filesystem')
938 name = new_name('MNT_'+ node_name)
940 ret = findByName(lustre, name, "mountpoint")
942 # this can't happen, because new_name creates unique names
943 error("MOUNTPOINT: ", name, " already exists.")
945 uuid = new_uuid(name)
946 mtpt = gen.mountpoint(name, uuid, fs_uuid, path)
947 node = findByName(lustre, node_name, "node")
949 error('node:', node_name, "not found.")
950 node_add_profile(gen, node, "mountpoint", uuid)
951 lustre.appendChild(mtpt)
953 ############################################################
954 # Command line processing
956 class OptionError (exceptions.Exception):
957 def __init__(self, args):
960 def get_option(options, tag):
961 """Look for tag in options hash and return the value if set. If not
962 set, then if return default it is set, otherwise exception."""
963 if options.__getattr__(tag) != None:
964 return options.__getattr__(tag)
966 raise OptionError("--add %s requires --%s <value>" % (options.add, tag))
968 def get_option_int(options, tag):
969 """Return an integer option. Raise exception if the value is not an int"""
970 val = get_option(options, tag)
974 raise OptionError("--%s <num> (value must be integer)" % (tag))
977 # simple class for profiling
984 self._start = time.time()
985 def stop(self, msg=''):
986 self._stop = time.time()
990 return self._stop - self._start
991 def display(self, msg):
993 str = '%s: %g secs' % (msg, d)
996 #################################################################
997 # function cmdlinesplit used to split cmd line from batch file
999 def cmdlinesplit(cmdline):
1001 double_quote = re.compile(r'"(([^"\\]|\\.)*)"')
1002 single_quote = re.compile(r"'(.*?)'")
1003 escaped = re.compile(r'\\(.)')
1004 esc_quote = re.compile(r'\\([\\"])')
1005 outside = re.compile(r"""([^\s\\'"]+)""")
1009 while i < len(cmdline):
1012 match = double_quote.match(cmdline, i)
1014 print "Unmatched double quote:", cmdline
1017 if arg is None: arg = esc_quote.sub(r'\1', match.group(1))
1018 else: arg += esc_quote.sub(r'\1', match.group(1))
1021 match = single_quote.match(cmdline, i)
1023 print "Unmatched single quote:", cmdline
1026 if arg is None: arg = match.group(1)
1027 else: arg += match.group(1)
1030 match = escaped.match(cmdline, i)
1032 print "Unmatched backslash", cmdline
1035 if arg is None: arg = match.group(1)
1036 else: arg += match.group(1)
1040 arg_list.append(str(arg))
1042 while i < len(cmdline) and cmdline[i].isspace():
1045 match = outside.match(cmdline, i)
1048 if arg is None: arg = match.group()
1049 else: arg += match.group()
1051 if arg != None: arg_list.append(str(arg))
1055 ############################################################
1059 def add(devtype, gen, lustre, options):
1060 if devtype == 'net':
1061 add_net(gen, lustre, options)
1062 elif devtype == 'mtpt':
1063 add_mtpt(gen, lustre, options)
1064 elif devtype == 'mds':
1065 add_mds(gen, lustre, options)
1066 elif devtype == 'ost':
1067 add_ost(gen, lustre, options)
1068 elif devtype == 'lov':
1069 add_lov(gen, lustre, options)
1070 elif devtype == 'route':
1071 add_route(gen, lustre, options)
1072 elif devtype == 'node':
1073 add_node(gen, lustre, options)
1074 elif devtype == 'echo_client':
1075 add_echo_client(gen, lustre, options)
1076 elif devtype == 'cobd':
1077 add_cobd(gen, lustre, options)
1078 elif devtype == 'mgmt':
1079 add_mgmt(gen, lustre, options)
1081 error("unknown device type:", devtype)
1083 def do_command(gen, lustre, options, args):
1085 add(options.add, gen, lustre, options)
1087 error("Missing command")
1090 cl = Lustre.Options("lmc", "", lmc_options)
1092 options, args = cl.parse(sys.argv[1:])
1093 except Lustre.OptionError, e:
1097 panic(string.join(sys.argv), "Unexpected extra arguments on command line: " + string.join(args))
1099 if options.reference:
1106 outFile = options.merge
1107 if os.access(outFile, os.R_OK):
1108 doc = xml.dom.minidom.parse(outFile)
1110 doc = new_lustre(xml.dom.minidom)
1112 doc = xml.dom.minidom.parse(options.input)
1114 doc = new_lustre(xml.dom.minidom)
1117 outFile = options.output
1119 lustre = doc.documentElement
1121 if lustre.tagName != "lustre":
1122 print "Existing config not valid."
1125 gen = GenConfig(doc)
1127 # the PRNG is normally seeded with time(), which is not so good for starting # time-synchronized clusters
1128 input = open('/dev/urandom', 'r')
1130 print 'Unable to open /dev/urandom!'
1132 seed = input.read(32)
1137 fp = open(options.batch)
1138 batchCommands = fp.readlines()
1140 for cmd in batchCommands:
1142 options, args = cl.parse(cmdlinesplit(cmd))
1143 if options.merge or options.input or options.output:
1144 print "The batchfile should not contain --merge, --input or --output."
1146 do_command(gen, lustre, options, args)
1147 except OptionError, e:
1149 except Lustre.OptionError, e:
1153 do_command(gen, lustre, options, args)
1154 except OptionError, e:
1155 panic(string.join(sys.argv),e)
1156 except Lustre.OptionError, e:
1162 PrettyPrint(doc, open(outFile,"w"))
1164 if __name__ == "__main__":