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
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)
48 print """usage: lmc --add object [object parameters]
50 Object creation command summary:
58 --ptldebug debug_level
59 --subsystem subsystem_name
65 --nettype tcp|elan|gm|scimac
96 --obdtype obdecho|obdfilter
99 --add mtpt - Mountpoint
103 --ost ost_name OR --lov lov_name
115 --add mgmt - Management/monitoring service
117 --mgmt mgmt_service_name
120 PARAM = Lustre.Options.PARAM
122 # lmc input/output options
123 ('reference', "Print short reference for commands."),
124 ('verbose,v', "Print system commands as they are run."),
125 ('merge,m', "Append to the specified config file.", PARAM),
126 ('output,o', "Write XML configuration into given output file. Overwrite existing content.", PARAM),
127 ('input,i', "", PARAM),
128 ('batch', "Used to execute lmc commands in batch mode.", PARAM),
134 ('node', "Add a new node in the cluster configuration.", PARAM),
135 ('timeout', "Set timeout to initiate recovery.", PARAM),
136 ('upcall', "Set both lustre and portals upcall scripts.", PARAM),
137 ('lustre_upcall', "Set location of lustre upcall script.", PARAM),
138 ('portals_upcall', "Set location of portals upcall script.", PARAM),
139 ('ptldebug', "Set the portals debug level", PARAM),
140 ('subsystem', "Specify which Lustre subsystems have debug output recorded in the log", PARAM),
143 ('nettype', "Specify the network type. This can be tcp/elan/gm/scimac.", PARAM),
144 ('nid', "Give the network ID, e.g ElanID/IP Address as used by portals.", PARAM),
145 ('tcpbuf', "Optional argument to specify the TCP buffer size.", PARAM, "0"),
146 ('port', "Optional argument to specify the TCP port number.", PARAM, DEFAULT_PORT),
147 ('irq_affinity', "Optional argument.", PARAM, 0),
148 ('hostaddr', "", PARAM,""),
149 ('cluster_id', "Specify the cluster ID", PARAM, "0"),
152 ('route', "Add a new route for the cluster.", PARAM),
153 ('router', "Optional flag to mark a node as router."),
154 ('gw', "Specify the nid of the gateway for a route.", PARAM),
155 ('gateway_cluster_id', "", PARAM, "0"),
156 ('target_cluster_id', "", PARAM, "0"),
157 ('lo', "For a range route, this is the low value nid.", PARAM),
158 ('hi', "For a range route, this is a hi value nid.", PARAM,""),
160 # servers: mds and ost
161 ('mds', "Specify MDS name.", PARAM),
162 ('ost', "Specify the OST name.", PARAM,""),
163 ('osdtype', "This could obdfilter or obdecho.", PARAM, "obdfilter"),
164 ('failover', "Enable failover support on OSTs or MDS?"),
165 ('group', "", PARAM),
166 ('dev', "Path of the device on local system.", PARAM,""),
167 ('size', "Specify the size of the device if needed.", PARAM,"0"),
168 ('journal_size', "Specify new journal size for underlying ext3 file system.", PARAM,"0"),
169 ('fstype', "Optional argument to specify the filesystem type.", PARAM, "ext3"),
170 ('mkfsoptions', "Optional argument to mkfs.", PARAM, ""),
171 ('ostuuid', "", PARAM,""),
172 ('nspath', "Local mount point of server namespace.", PARAM,""),
175 # clients: mountpoint and echo
176 ('echo_client', "", PARAM),
177 ('path', "Specify the mountpoint for Lustre.", PARAM),
178 ('filesystem', "Lustre filesystem name", PARAM,""),
181 ('lov', "Specify LOV name.", PARAM,""),
182 ('stripe_sz', "Specify the stripe size in bytes.", PARAM),
183 ('stripe_cnt', "Specify the number of OSTs each file should be striped on.", PARAM, 0),
184 ('stripe_pattern', "Specify the stripe pattern. RAID 0 is the only one currently supported.", PARAM, 0),
187 ('real_obd', "", PARAM),
188 ('cache_obd', "", PARAM),
190 ('mgmt', "Specify management/monitoring service name.", PARAM, ""),
194 msg = string.join(map(str,args))
195 raise OptionError("Error: " + msg)
204 msg = string.join(map(str,args))
205 print "Warning: ", msg
208 # manage names and uuids
209 # need to initialize this by walking tree to ensure
210 # no duplicate names or uuids are created.
211 # this are just place holders for now.
212 # consider changing this to be like OBD-dev-host
216 while names.has_key(ret):
217 ret = "%s_%d" % (base, ctr)
223 ret_uuid = '%05x_%.19s_%05x%05x' % (int(random.random() * 1048576),
225 int(random.random() * 1048576),
226 int(random.random() * 1048576))
230 ldlm_uuid = 'ldlm_UUID'
233 """Create a new empty lustre document"""
234 # adding ldlm here is a bit of a hack, but one is enough.
235 str = """<lustre version="%s">
236 <ldlm name="%s" uuid="%s"/>
237 </lustre>""" % (Lustre.CONFIG_VERSION, ldlm_name, ldlm_uuid)
238 return dom.parseString(str)
244 """initialize auto-name generation tables"""
246 # get all elements that contain a name attribute
247 for n in doc.childNodes:
248 if n.nodeType == n.ELEMENT_NODE:
250 names[getName(n)] = 1
251 uuids[getUUID(n)] = 1
254 def get_format_flag(options):
259 ############################################################
260 # Build config objects using DOM
265 def __init__(self, doc):
268 def ref(self, type, uuid):
269 """ generate <[type]_ref uuidref="[uuid]"/> """
270 tag = "%s_ref" % (type)
271 ref = self.doc.createElement(tag)
272 ref.setAttribute("uuidref", uuid)
275 def newService(self, tag, name, uuid):
276 """ create a new service elmement, which requires name and uuid attributes """
277 new = self.doc.createElement(tag)
278 new.setAttribute("uuid", uuid);
279 new.setAttribute("name", name);
282 def addText(self, node, str):
283 txt = self.doc.createTextNode(str)
284 node.appendChild(txt)
286 def addElement(self, node, tag, str=None):
287 """ create a new element and add it as a child to node. If str is passed,
288 a text node is created for the new element"""
289 new = self.doc.createElement(tag)
291 self.addText(new, str)
292 node.appendChild(new)
295 def network(self, name, uuid, nid, cluster_id, net, hostaddr="",
296 port=0, tcpbuf=0, irq_aff=0):
297 """create <network> node"""
298 network = self.newService("network", name, uuid)
299 network.setAttribute("nettype", net);
300 self.addElement(network, "nid", nid)
301 self.addElement(network, "clusterid", cluster_id)
303 self.addElement(network, "hostaddr", hostaddr)
305 self.addElement(network, "port", "%d" %(port))
307 self.addElement(network, "sendmem", "%d" %(tcpbuf))
308 self.addElement(network, "recvmem", "%d" %(tcpbuf))
310 self.addElement(network, "irqaffinity", "%d" %(irq_aff))
314 def routetbl(self, name, uuid):
315 """create <routetbl> node"""
316 rtbl = self.newService("routetbl", name, uuid)
319 def route(self, gw_net_type, gw, gw_cluster_id, tgt_cluster_id, lo, hi):
320 """ create one entry for the route table """
321 ref = self.doc.createElement('route')
322 ref.setAttribute("type", gw_net_type)
323 ref.setAttribute("gw", gw)
324 ref.setAttribute("gwclusterid", gw_cluster_id)
325 ref.setAttribute("tgtclusterid", tgt_cluster_id)
326 ref.setAttribute("lo", lo)
328 ref.setAttribute("hi", hi)
331 def profile(self, name, uuid):
332 """ create a host """
333 profile = self.newService("profile", name, uuid)
336 def node(self, name, uuid, prof_uuid):
337 """ create a host """
338 node = self.newService("node", name, uuid)
339 node.appendChild(self.ref("profile", prof_uuid))
342 def ldlm(self, name, uuid):
343 """ create a ldlm """
344 ldlm = self.newService("ldlm", name, uuid)
347 def osd(self, name, uuid, fs, osdtype, devname, format, ost_uuid,
348 node_uuid, dev_size=0, journal_size=0, nspath=""):
349 osd = self.newService("osd", name, uuid)
350 osd.setAttribute('osdtype', osdtype)
351 osd.appendChild(self.ref("target", ost_uuid))
352 osd.appendChild(self.ref("node", node_uuid))
354 self.addElement(osd, "fstype", fs)
356 dev = self.addElement(osd, "devpath", devname)
357 self.addElement(osd, "autoformat", format)
359 self.addElement(osd, "devsize", "%s" % (dev_size))
361 self.addElement(osd, "journalsize", "%s" % (journal_size))
363 self.addElement(osd, "nspath", nspath)
366 def cobd(self, name, uuid, real_uuid, cache_uuid):
367 cobd = self.newService("cobd", name, uuid)
368 cobd.appendChild(self.ref("realobd",real_uuid))
369 cobd.appendChild(self.ref("cacheobd",cache_uuid))
372 def ost(self, name, uuid, osd_uuid, group=""):
373 ost = self.newService("ost", name, uuid)
374 ost.appendChild(self.ref("active", osd_uuid))
376 self.addElement(ost, "group", group)
379 def oss(self, name, uuid):
380 oss = self.newService("oss", name, uuid)
383 def lov(self, name, uuid, mds_uuid, stripe_sz, stripe_cnt, pattern):
384 lov = self.newService("lov", name, uuid)
385 lov.appendChild(self.ref("mds", mds_uuid))
386 lov.setAttribute("stripesize", str(stripe_sz))
387 lov.setAttribute("stripecount", str(stripe_cnt))
388 lov.setAttribute("stripepattern", str(pattern))
391 def lovconfig(self, name, uuid, lov_uuid):
392 lovconfig = self.newService("lovconfig", name, uuid)
393 lovconfig.appendChild(self.ref("lov", lov_uuid))
396 def mds(self, name, uuid, mdd_uuid, group=""):
397 mds = self.newService("mds", name, uuid)
398 mds.appendChild(self.ref("active",mdd_uuid))
400 self.addElement(mds, "group", group)
403 def mdsdev(self, name, uuid, fs, devname, format, node_uuid,
404 mds_uuid, dev_size=0, journal_size=0, nspath="", mkfsoptions=""):
405 mdd = self.newService("mdsdev", name, uuid)
406 self.addElement(mdd, "fstype", fs)
407 dev = self.addElement(mdd, "devpath", devname)
408 self.addElement(mdd, "autoformat", format)
410 self.addElement(mdd, "devsize", "%s" % (dev_size))
412 self.addElement(mdd, "journalsize", "%s" % (journal_size))
414 self.addElement(mdd, "nspath", nspath)
416 self.addElement(mdd, "mkfsoptions", mkfsoptions)
417 mdd.appendChild(self.ref("node", node_uuid))
418 mdd.appendChild(self.ref("target", mds_uuid))
421 def mgmt(self, mgmt_name, mgmt_uuid, node_uuid):
422 mgmt = self.newService("mgmt", mgmt_name, mgmt_uuid)
423 mgmt.appendChild(self.ref("node", node_uuid))
424 # Placeholder until mgmt-service failover.
425 mgmt.appendChild(self.ref("active", mgmt_uuid))
428 def mountpoint(self, name, uuid, fs_uuid, path):
429 mtpt = self.newService("mountpoint", name, uuid)
430 mtpt.appendChild(self.ref("filesystem", fs_uuid))
431 self.addElement(mtpt, "path", path)
434 def filesystem(self, name, uuid, mds_uuid, obd_uuid, mgmt_uuid):
435 fs = self.newService("filesystem", name, uuid)
436 fs.appendChild(self.ref("mds", mds_uuid))
437 fs.appendChild(self.ref("obd", obd_uuid))
439 fs.appendChild(self.ref("mgmt", mgmt_uuid))
442 def echo_client(self, name, uuid, osc_uuid):
443 ec = self.newService("echoclient", name, uuid)
444 ec.appendChild(self.ref("obd", osc_uuid))
447 ############################################################
448 # Utilities to query a DOM tree
449 # Using this functions we can treat use config information
450 # directly as a database.
452 return n.getAttribute('name')
455 return node.getAttribute('uuid')
458 def findByName(lustre, name, tag = ""):
459 for n in lustre.childNodes:
460 if n.nodeType == n.ELEMENT_NODE:
461 if tag and n.nodeName != tag:
463 if getName(n) == name:
466 n = findByName(n, name)
471 def lookup(node, uuid):
472 for n in node.childNodes:
473 if n.nodeType == n.ELEMENT_NODE:
474 if getUUID(n) == uuid:
482 def name2uuid(lustre, name, tag="", fatal=1):
483 ret = findByName(lustre, name, tag)
486 error('name2uuid:', '"'+name+'"', tag, 'element not found.')
491 def lookup_filesystem(lustre, mds_uuid, ost_uuid):
492 for n in lustre.childNodes:
493 if n.nodeType == n.ELEMENT_NODE and n.nodeName == 'filesystem':
494 if ref_exists(n, mds_uuid) and ref_exists(n, ost_uuid):
498 # XXX: assumes only one network element per node. will fix this
499 # as soon as support for routers is added
500 def get_net_uuid(lustre, node_name):
501 """ get a network uuid for a node_name """
502 node = findByName(lustre, node_name, "node")
504 error ('get_net_uuid:', '"'+node_name+'"', "node element not found.")
505 net = node.getElementsByTagName('network')
507 return getUUID(net[0])
511 def lov_add_obd(gen, lov, osc_uuid):
512 lov.appendChild(gen.ref("obd", osc_uuid))
514 def ref_exists(profile, uuid):
515 elist = profile.childNodes
517 if e.nodeType == e.ELEMENT_NODE:
518 ref = e.getAttribute('uuidref')
523 # ensure that uuid is not already in the profile
524 # return true if uuid is added
525 def node_add_profile(gen, node, ref, uuid):
526 refname = "%s_ref" % "profile"
527 ret = node.getElementsByTagName(refname)
529 error('node has no profile ref:', node)
530 prof_uuid = ret[0].getAttribute('uuidref')
531 profile = lookup(node.parentNode, prof_uuid)
533 error("no profile found:", prof_uuid)
534 if ref_exists(profile, uuid):
536 profile.appendChild(gen.ref(ref, uuid))
539 def get_attr(dom_node, attr, default=""):
540 v = dom_node.getAttribute(attr)
545 ############################################################
548 def set_node_options(gen, node, options):
550 node.setAttribute('router', '1')
552 gen.addElement(node, "timeout", get_option(options, 'timeout'))
554 default_upcall = get_option(options, 'upcall')
557 if default_upcall or options.lustre_upcall:
558 if options.lustre_upcall:
559 gen.addElement(node, 'lustreUpcall', options.lustre_upcall)
561 gen.addElement(node, 'lustreUpcall', default_upcall)
562 if default_upcall or options.portals_upcall:
563 if options.portals_upcall:
564 gen.addElement(node, 'portalsUpcall', options.portals_upcall)
566 gen.addElement(node, 'portalsUpcall', default_upcall)
568 gen.addElement(node, "ptldebug", get_option(options, 'ptldebug'))
569 if options.subsystem:
570 gen.addElement(node, "subsystem", get_option(options, 'subsystem'))
573 def do_add_node(gen, lustre, options, node_name):
574 uuid = new_uuid(node_name)
575 prof_name = new_name("PROFILE_" + node_name)
576 prof_uuid = new_uuid(prof_name)
577 profile = gen.profile(prof_name, prof_uuid)
578 node = gen.node(node_name, uuid, prof_uuid)
579 lustre.appendChild(node)
580 lustre.appendChild(profile)
582 node_add_profile(gen, node, 'ldlm', ldlm_uuid)
583 set_node_options(gen, node, options)
587 def add_node(gen, lustre, options):
588 """ create a node with a network config """
590 node_name = get_option(options, 'node')
591 ret = findByName(lustre, node_name, "node")
593 print "Node:", node_name, "exists."
595 do_add_node(gen, lustre, options, node_name)
598 def add_net(gen, lustre, options):
599 """ create a node with a network config """
601 node_name = get_option(options, 'node')
602 nid = get_option(options, 'nid')
603 cluster_id = get_option(options, 'cluster_id')
604 hostaddr = get_option(options, 'hostaddr')
605 net_type = get_option(options, 'nettype')
607 if net_type in ('tcp',):
608 port = get_option_int(options, 'port')
609 tcpbuf = get_option_int(options, 'tcpbuf')
610 irq_aff = get_option_int(options, 'irq_affinity')
611 elif net_type in ('elan', 'gm', 'scimac'):
616 print "Unknown net_type: ", net_type
619 ret = findByName(lustre, node_name, "node")
621 node = do_add_node(gen, lustre, options, node_name)
624 set_node_options(gen, node, options)
626 net_name = new_name('NET_'+ node_name +'_'+ net_type)
627 net_uuid = new_uuid(net_name)
628 node.appendChild(gen.network(net_name, net_uuid, nid, cluster_id, net_type,
629 hostaddr, port, tcpbuf, irq_aff))
630 node_add_profile(gen, node, "network", net_uuid)
633 def add_route(gen, lustre, options):
634 """ create a node with a network config """
636 node_name = get_option(options, 'node')
637 gw_net_type = get_option(options, 'nettype')
638 gw = get_option(options, 'gw')
639 gw_cluster_id = get_option(options, 'gateway_cluster_id')
640 tgt_cluster_id = get_option(options, 'target_cluster_id')
641 lo = get_option(options, 'lo')
642 hi = get_option(options, 'hi')
646 node = findByName(lustre, node_name, "node")
648 error (node_name, " not found.")
650 rlist = node.getElementsByTagName('routetbl')
654 rtbl_name = new_name("RTBL_" + node_name)
655 rtbl_uuid = new_uuid(rtbl_name)
656 rtbl = gen.routetbl(rtbl_name, rtbl_uuid)
657 node.appendChild(rtbl)
658 node_add_profile(gen, node, "routetbl", rtbl_uuid)
659 rtbl.appendChild(gen.route(gw_net_type, gw, gw_cluster_id, tgt_cluster_id,
663 def add_mds(gen, lustre, options):
664 node_name = get_option(options, 'node')
665 mds_name = get_option(options, 'mds')
666 mdd_name = new_name("MDD_" + mds_name +"_" + node_name)
667 mdd_uuid = new_uuid(mdd_name)
669 mds_uuid = name2uuid(lustre, mds_name, 'mds', fatal=0)
671 mds_uuid = new_uuid(mds_name)
672 mds = gen.mds(mds_name, mds_uuid, mdd_uuid, options.group)
673 lustre.appendChild(mds)
675 mds = lookup(lustre, mds_uuid)
677 mds.setAttribute('failover', "1")
679 devname = get_option(options, 'dev')
680 size = get_option(options, 'size')
681 fstype = get_option(options, 'fstype')
682 journal_size = get_option(options, 'journal_size')
683 nspath = get_option(options, 'nspath')
684 mkfsoptions = get_option(options, 'mkfsoptions')
686 node_uuid = name2uuid(lustre, node_name, 'node')
688 node = findByName(lustre, node_name, "node")
689 node_add_profile(gen, node, "mdsdev", mdd_uuid)
690 net_uuid = get_net_uuid(lustre, node_name)
692 error("NODE: ", node_name, "not found")
694 mdd = gen.mdsdev(mdd_name, mdd_uuid, fstype, devname,
695 get_format_flag(options), node_uuid, mds_uuid,
696 size, journal_size, nspath, mkfsoptions)
697 lustre.appendChild(mdd)
700 def add_mgmt(gen, lustre, options):
701 node_name = get_option(options, 'node')
702 node_uuid = name2uuid(lustre, node_name, 'mode')
703 mgmt_name = get_option(options, 'mgmt')
705 mgmt_name = new_name('MGMT_' + node_name)
706 mgmt_uuid = name2uuid(lustre, mgmt_name, 'mgmt', fatal=0)
708 mgmt_uuid = new_uuid(mgmt_name)
709 mgmt = gen.mgmt(mgmt_name, mgmt_uuid, node_uuid)
710 lustre.appendChild(mgmt)
712 mgmt = lookup(lustre, mgmt_uuid)
714 node = findByName(lustre, node_name, "node")
715 node_add_profile(gen, node, 'mgmt', mgmt_uuid)
717 def add_ost(gen, lustre, options):
718 node_name = get_option(options, 'node')
719 lovname = get_option(options, 'lov')
720 osdtype = get_option(options, 'osdtype')
722 node_uuid = name2uuid(lustre, node_name, 'node')
724 if osdtype == 'obdecho':
731 devname = get_option(options, 'dev') # can be unset for bluearcs
732 size = get_option(options, 'size')
733 fstype = get_option(options, 'fstype')
734 journal_size = get_option(options, 'journal_size')
736 nspath = get_option(options, 'nspath')
738 ostname = get_option(options, 'ost')
740 ostname = new_name('OST_'+ node_name)
742 osdname = new_name("OSD_" + ostname + "_" + node_name)
743 osd_uuid = new_uuid(osdname)
745 ost_uuid = name2uuid(lustre, ostname, 'ost', fatal=0)
747 ost_uuid = get_option(options, 'ostuuid')
749 if lookup(lustre, ost_uuid):
750 error("Duplicate OST UUID:", ost_uuid)
752 ost_uuid = new_uuid(ostname)
754 ost = gen.ost(ostname, ost_uuid, osd_uuid, options.group)
755 lustre.appendChild(ost)
757 lov = findByName(lustre, lovname, "lov")
759 error('add_ost:', '"'+lovname+'"', "lov element not found.")
760 lov_add_obd(gen, lov, ost_uuid)
762 ost = lookup(lustre, ost_uuid)
765 ost.setAttribute('failover', "1")
768 osd = gen.osd(osdname, osd_uuid, fstype, osdtype, devname,
769 get_format_flag(options), ost_uuid, node_uuid, size,
770 journal_size, nspath)
772 node = findByName(lustre, node_name, "node")
774 ## if node_add_profile(gen, node, 'oss', oss_uuid):
776 ## oss_uuid = new_uuid(ossname)
777 ## oss = gen.oss(ossname, oss_uuid)
778 ## lustre.appendChild(oss)
780 node_add_profile(gen, node, 'osd', osd_uuid)
781 lustre.appendChild(osd)
784 def add_cobd(gen, lustre, options):
785 node_name = get_option(options, 'node')
786 name = new_name('COBD_' + node_name)
787 uuid = new_uuid(name)
789 real_name = get_option(options, 'real_obd')
790 cache_name = get_option(options, 'cache_obd')
792 real_uuid = name2uuid(lustre, real_name, tag='obd')
793 cache_uuid = name2uuid(lustre, cache_name, tag='obd')
795 node = findByName(lustre, node_name, "node")
796 node_add_profile(gen, node, "cobd", uuid)
797 cobd = gen.cobd(name, uuid, real_uuid, cache_uuid)
798 lustre.appendChild(cobd)
801 def add_echo_client(gen, lustre, options):
802 """ add an echo client to the profile for this node. """
803 node_name = get_option(options, 'node')
804 lov_name = get_option(options, 'ost')
806 node = findByName(lustre, node_name, 'node')
808 echoname = new_name('ECHO_'+ node_name)
809 echo_uuid = new_uuid(echoname)
810 node_add_profile(gen, node, 'echoclient', echo_uuid)
812 lov_uuid = name2uuid(lustre, lov_name, tag='lov', fatal=0)
814 lov_uuid = name2uuid(lustre, lov_name, tag='ost', fatal=1)
816 echo = gen.echo_client(echoname, echo_uuid, lov_uuid)
817 lustre.appendChild(echo)
820 def add_lov(gen, lustre, options):
823 lov_orig = get_option(options, 'lov')
824 name = new_name(lov_orig)
826 warning("name:", lov_orig, "already used. using:", name)
828 mds_name = get_option(options, 'mds')
829 stripe_sz = get_option_int(options, 'stripe_sz')
830 stripe_cnt = get_option_int(options, 'stripe_cnt')
831 pattern = get_option_int(options, 'stripe_pattern')
832 uuid = new_uuid(name)
834 ret = findByName(lustre, name, "lov")
836 error("LOV: ", name, " already exists.")
838 mds_uuid = name2uuid(lustre, mds_name, 'mds')
839 lov = gen.lov(name, uuid, mds_uuid, stripe_sz, stripe_cnt, pattern)
840 lustre.appendChild(lov)
842 # add an lovconfig entry to the active mdsdev profile
843 lovconfig_name = new_name('LVCFG_' + name)
844 lovconfig_uuid = new_uuid(lovconfig_name)
845 mds = findByName(lustre, mds_name)
846 mds.appendChild(gen.ref("lovconfig", lovconfig_uuid))
847 lovconfig = gen.lovconfig(lovconfig_name, lovconfig_uuid, uuid)
848 lustre.appendChild(lovconfig)
850 def new_filesystem(gen, lustre, mds_uuid, obd_uuid, mgmt_uuid):
851 fs_name = new_name("FS_fsname")
852 fs_uuid = new_uuid(fs_name)
853 mds = lookup(lustre, mds_uuid)
854 mds.appendChild(gen.ref("filesystem", fs_uuid))
855 fs = gen.filesystem(fs_name, fs_uuid, mds_uuid, obd_uuid, mgmt_uuid)
856 lustre.appendChild(fs)
859 def get_fs_uuid(gen, lustre, mds_name, obd_name, mgmt_name):
860 mds_uuid = name2uuid(lustre, mds_name, tag='mds')
861 obd_uuid = name2uuid(lustre, obd_name, tag='lov', fatal=0)
863 obd_uuid = name2uuid(lustre, obd_name, tag='ost', fatal=1)
865 mgmt_uuid = name2uuid(lustre, mgmt_name, tag='mgmt', fatal=1)
868 fs_uuid = lookup_filesystem(lustre, mds_uuid, obd_uuid)
870 fs_uuid = new_filesystem(gen, lustre, mds_uuid, obd_uuid, mgmt_uuid)
873 def add_mtpt(gen, lustre, options):
874 """ create mtpt on a node """
875 node_name = get_option(options, 'node')
877 path = get_option(options, 'path')
878 fs_name = get_option(options, 'filesystem')
880 mds_name = get_option(options, 'mds')
881 lov_name = get_option(options, 'lov')
883 lov_name = get_option(options, 'ost')
885 error("--add mtpt requires either --filesystem or --mds with an --lov lov_name or --ost ost_name")
886 mgmt_name = get_option(options, 'mgmt')
887 fs_uuid = get_fs_uuid(gen, lustre, mds_name, lov_name, mgmt_name)
889 fs_uuid = name2uuid(lustre, fs_name, tag='filesystem')
891 name = new_name('MNT_'+ node_name)
893 ret = findByName(lustre, name, "mountpoint")
895 # this can't happen, because new_name creates unique names
896 error("MOUNTPOINT: ", name, " already exists.")
898 uuid = new_uuid(name)
899 mtpt = gen.mountpoint(name, uuid, fs_uuid, path)
900 node = findByName(lustre, node_name, "node")
902 error('node:', node_name, "not found.")
903 node_add_profile(gen, node, "mountpoint", uuid)
904 lustre.appendChild(mtpt)
906 ############################################################
907 # Command line processing
909 class OptionError (exceptions.Exception):
910 def __init__(self, args):
913 def get_option(options, tag):
914 """Look for tag in options hash and return the value if set. If not
915 set, then if return default it is set, otherwise exception."""
916 if options.__getattr__(tag) != None:
917 return options.__getattr__(tag)
919 raise OptionError("--add %s requires --%s <value>" % (options.add, tag))
921 def get_option_int(options, tag):
922 """Return an integer option. Raise exception if the value is not an int"""
923 val = get_option(options, tag)
927 raise OptionError("--%s <num> (value must be integer)" % (tag))
930 # simple class for profiling
937 self._start = time.time()
938 def stop(self, msg=''):
939 self._stop = time.time()
943 return self._stop - self._start
944 def display(self, msg):
946 str = '%s: %g secs' % (msg, d)
949 ############################################################
953 def add(devtype, gen, lustre, options):
955 add_net(gen, lustre, options)
956 elif devtype == 'mtpt':
957 add_mtpt(gen, lustre, options)
958 elif devtype == 'mds':
959 add_mds(gen, lustre, options)
960 elif devtype == 'ost':
961 add_ost(gen, lustre, options)
962 elif devtype == 'lov':
963 add_lov(gen, lustre, options)
964 elif devtype == 'route':
965 add_route(gen, lustre, options)
966 elif devtype == 'node':
967 add_node(gen, lustre, options)
968 elif devtype == 'echo_client':
969 add_echo_client(gen, lustre, options)
970 elif devtype == 'cobd':
971 add_cobd(gen, lustre, options)
972 elif devtype == 'mgmt':
973 add_mgmt(gen, lustre, options)
975 error("unknown device type:", devtype)
977 def do_command(gen, lustre, options, args):
979 add(options.add, gen, lustre, options)
981 error("Missing command")
984 cl = Lustre.Options("lmc", "", lmc_options)
986 options, args = cl.parse(sys.argv[1:])
987 except Lustre.OptionError, e:
991 panic(string.join(sys.argv), "Unexpected extra arguments on command line: " + string.join(args))
993 if options.reference:
1000 outFile = options.merge
1001 if os.access(outFile, os.R_OK):
1002 doc = xml.dom.minidom.parse(outFile)
1004 doc = new_lustre(xml.dom.minidom)
1006 doc = xml.dom.minidom.parse(options.input)
1008 doc = new_lustre(xml.dom.minidom)
1011 outFile = options.output
1013 lustre = doc.documentElement
1015 if lustre.tagName != "lustre":
1016 print "Existing config not valid."
1019 gen = GenConfig(doc)
1021 # the PRNG is normally seeded with time(), which is not so good for starting # time-synchronized clusters
1022 input = open('/dev/urandom', 'r')
1024 print 'Unable to open /dev/urandom!'
1026 seed = input.read(32)
1031 fp = open(options.batch)
1032 batchCommands = fp.readlines()
1034 for cmd in batchCommands:
1036 options, args = cl.parse(string.split(cmd))
1037 do_command(gen, lustre, options, args)
1038 except OptionError, e:
1040 except Lustre.OptionError, e:
1044 do_command(gen, lustre, options, args)
1045 except OptionError, e:
1046 panic(string.join(sys.argv),e)
1047 except Lustre.OptionError, e:
1053 PrettyPrint(doc, open(outFile,"w"))
1055 if __name__ == "__main__":