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
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:
63 --nettype tcp|elan|toe|gm|scimac
96 --add mtpt - Mountpoint
100 --ost ost_name OR --lov lov_name
102 --add mgmt - Management/monitoring service
104 --mgmt mgmt_service_name
107 PARAM = Lustre.Options.PARAM
109 # lmc input/output options
110 ('reference', "Print short reference for commands."),
111 ('verbose,v', "Print system commands as they are run."),
112 ('merge,m', "Append to the specified config file.", PARAM),
113 ('output,o', "Write XML configuration into given output file. Overwrite existing content.", PARAM),
114 ('input,i', "", PARAM),
115 ('batch', "Used to execute lmc commands in batch mode.", PARAM),
121 ('node', "Add a new node in the cluster configuration.", PARAM),
122 ('timeout', "Set timeout to initiate recovery.", PARAM),
123 ('upcall', "Set both lustre and portals upcall scripts.", PARAM),
124 ('lustre_upcall', "Set location of lustre upcall script.", PARAM),
125 ('portals_upcall', "Set location of portals upcall script.", PARAM),
128 ('nettype', "Specify the network type. This can be tcp/elan/gm/scimac.", PARAM),
129 ('nid', "Give the network ID, e.g ElanID/IP Address as used by portals.", PARAM),
130 ('tcpbuf', "Optional argument to specify the TCP buffer size.", PARAM, "0"),
131 ('port', "Optional argument to specify the TCP port number.", PARAM, DEFAULT_PORT),
132 ('nid_exchange', "Optional argument to indicate if nid exchange should be done.", PARAM, 0),
133 ('irq_affinity', "Optional argument.", PARAM, 0),
134 ('hostaddr', "", PARAM,""),
135 ('cluster_id', "Specify the cluster ID", PARAM, "0"),
138 ('route', "Add a new route for the cluster.", PARAM),
139 ('router', "Optional flag to mark a node as router."),
140 ('gw', "Specify the nid of the gateway for a route.", PARAM),
141 ('gw_cluster_id', "", PARAM, "0"),
142 ('target_cluster_id', "", PARAM, "0"),
143 ('lo', "For a range route, this is the low value nid.", PARAM),
144 ('hi', "For a range route, this is a hi value nid.", PARAM,""),
146 # servers: mds and ost
147 ('mds', "Specify MDS name.", PARAM),
148 ('ost', "Specify the OST name.", PARAM,""),
149 ('osdtype', "This could obdfilter or obdecho.", PARAM, "obdfilter"),
150 ('failover', "Enable failover support on OSTs or MDS?"),
151 ('group', "", PARAM),
152 ('dev', "Path of the device on local system.", PARAM,""),
153 ('size', "Specify the size of the device if needed.", PARAM,"0"),
154 ('journal_size', "Specify new journal size for underlying ext3 file system.", PARAM,"0"),
155 ('fstype', "Optional argument to specify the filesystem type.", PARAM, "ext3"),
156 ('ostuuid', "", PARAM,""),
157 ('nspath', "Local mount point of server namespace.", PARAM,""),
160 # clients: mountpoint and echo
161 ('echo_client', "", PARAM),
162 ('path', "Specify the mountpoint for Lustre.", PARAM),
163 ('filesystem', "Lustre filesystem name", PARAM,""),
166 ('lov', "Specify LOV name.", PARAM,""),
167 ('stripe_sz', "Specify the stripe size in bytes.", PARAM),
168 ('stripe_cnt', "Specify the number of OSTs each file should be striped on.", PARAM, 0),
169 ('stripe_pattern', "Specify the stripe pattern. RAID 0 is the only one currently supported.", PARAM, 0),
172 ('real_obd', "", PARAM),
173 ('cache_obd', "", PARAM),
175 ('mgmt', "Specify management/monitoring service name.", PARAM, ""),
179 msg = string.join(map(str,args))
180 raise OptionError("Error: " + msg)
189 msg = string.join(map(str,args))
190 print "Warning: ", msg
193 # manage names and uuids
194 # need to initialize this by walking tree to ensure
195 # no duplicate names or uuids are created.
196 # this are just place holders for now.
197 # consider changing this to be like OBD-dev-host
201 while names.has_key(ret):
202 ret = "%s_%d" % (base, ctr)
208 return "%s_UUID" % (name)
211 ldlm_uuid = 'ldlm_UUID'
214 """Create a new empty lustre document"""
215 # adding ldlm here is a bit of a hack, but one is enough.
216 str = """<lustre version="%s">
217 <ldlm name="%s" uuid="%s"/>
218 </lustre>""" % (Lustre.CONFIG_VERSION, ldlm_name, ldlm_uuid)
219 return dom.parseString(str)
225 """initialize auto-name generation tables"""
227 # get all elements that contain a name attribute
228 for n in doc.childNodes:
229 if n.nodeType == n.ELEMENT_NODE:
231 names[getName(n)] = 1
232 uuids[getUUID(n)] = 1
235 def get_format_flag(options):
240 ############################################################
241 # Build config objects using DOM
246 def __init__(self, doc):
249 def ref(self, type, uuid):
250 """ generate <[type]_ref uuidref="[uuid]"/> """
251 tag = "%s_ref" % (type)
252 ref = self.doc.createElement(tag)
253 ref.setAttribute("uuidref", uuid)
256 def newService(self, tag, name, uuid):
257 """ create a new service elmement, which requires name and uuid attributes """
258 new = self.doc.createElement(tag)
259 new.setAttribute("uuid", uuid);
260 new.setAttribute("name", name);
263 def addText(self, node, str):
264 txt = self.doc.createTextNode(str)
265 node.appendChild(txt)
267 def addElement(self, node, tag, str=None):
268 """ create a new element and add it as a child to node. If str is passed,
269 a text node is created for the new element"""
270 new = self.doc.createElement(tag)
272 self.addText(new, str)
273 node.appendChild(new)
276 def network(self, name, uuid, nid, cluster_id, net, hostaddr="",
277 port=0, tcpbuf=0, irq_aff=0, nid_xchg=0):
278 """create <network> node"""
279 network = self.newService("network", name, uuid)
280 network.setAttribute("nettype", net);
281 self.addElement(network, "nid", nid)
282 self.addElement(network, "clusterid", cluster_id)
284 self.addElement(network, "hostaddr", hostaddr)
286 self.addElement(network, "port", "%d" %(port))
288 self.addElement(network, "sendmem", "%d" %(tcpbuf))
289 self.addElement(network, "recvmem", "%d" %(tcpbuf))
291 self.addElement(network, "irqaffinity", "%d" %(irq_aff))
293 self.addElement(network, "nidexchange", "%d" %(nid_xchg))
297 def routetbl(self, name, uuid):
298 """create <routetbl> node"""
299 rtbl = self.newService("routetbl", name, uuid)
302 def route(self, gw_net_type, gw, gw_cluster_id, tgt_cluster_id, lo, hi):
303 """ create one entry for the route table """
304 ref = self.doc.createElement('route')
305 ref.setAttribute("type", gw_net_type)
306 ref.setAttribute("gw", gw)
307 ref.setAttribute("gwclusterid", gw_cluster_id)
308 ref.setAttribute("tgtclusterid", tgt_cluster_id)
309 ref.setAttribute("lo", lo)
311 ref.setAttribute("hi", hi)
314 def profile(self, name, uuid):
315 """ create a host """
316 profile = self.newService("profile", name, uuid)
319 def node(self, name, uuid, prof_uuid):
320 """ create a host """
321 node = self.newService("node", name, uuid)
322 node.appendChild(self.ref("profile", prof_uuid))
325 def ldlm(self, name, uuid):
326 """ create a ldlm """
327 ldlm = self.newService("ldlm", name, uuid)
330 def osd(self, name, uuid, fs, osdtype, devname, format, ost_uuid,
331 node_uuid, dev_size=0, journal_size=0, nspath=""):
332 osd = self.newService("osd", name, uuid)
333 osd.setAttribute('osdtype', osdtype)
334 osd.appendChild(self.ref("target", ost_uuid))
335 osd.appendChild(self.ref("node", node_uuid))
337 self.addElement(osd, "fstype", fs)
339 dev = self.addElement(osd, "devpath", devname)
340 self.addElement(osd, "autoformat", format)
342 self.addElement(osd, "devsize", "%s" % (dev_size))
344 self.addElement(osd, "journalsize", "%s" % (journal_size))
346 self.addElement(osd, "nspath", nspath)
349 def cobd(self, name, uuid, real_uuid, cache_uuid):
350 cobd = self.newService("cobd", name, uuid)
351 cobd.appendChild(self.ref("realobd",real_uuid))
352 cobd.appendChild(self.ref("cacheobd",cache_uuid))
355 def ost(self, name, uuid, osd_uuid, group=""):
356 ost = self.newService("ost", name, uuid)
357 ost.appendChild(self.ref("active", osd_uuid))
359 self.addElement(ost, "group", group)
362 def oss(self, name, uuid):
363 oss = self.newService("oss", name, uuid)
366 def lov(self, name, uuid, mds_uuid, stripe_sz, stripe_cnt, pattern):
367 lov = self.newService("lov", name, uuid)
368 lov.appendChild(self.ref("mds", mds_uuid))
369 lov.setAttribute("stripesize", str(stripe_sz))
370 lov.setAttribute("stripecount", str(stripe_cnt))
371 lov.setAttribute("stripepattern", str(pattern))
374 def lovconfig(self, name, uuid, lov_uuid):
375 lovconfig = self.newService("lovconfig", name, uuid)
376 lovconfig.appendChild(self.ref("lov", lov_uuid))
379 def mds(self, name, uuid, mdd_uuid, group=""):
380 mds = self.newService("mds", name, uuid)
381 mds.appendChild(self.ref("active",mdd_uuid))
383 self.addElement(mds, "group", group)
386 def mdsdev(self, name, uuid, fs, devname, format, node_uuid,
387 mds_uuid, dev_size=0, journal_size=0, nspath=""):
388 mdd = self.newService("mdsdev", name, uuid)
389 self.addElement(mdd, "fstype", fs)
390 dev = self.addElement(mdd, "devpath", devname)
391 self.addElement(mdd, "autoformat", format)
393 self.addElement(mdd, "devsize", "%s" % (dev_size))
395 self.addElement(mdd, "journalsize", "%s" % (journal_size))
397 self.addElement(mdd, "nspath", nspath)
398 mdd.appendChild(self.ref("node", node_uuid))
399 mdd.appendChild(self.ref("target", mds_uuid))
402 def mgmt(self, mgmt_name, mgmt_uuid, node_uuid):
403 mgmt = self.newService("mgmt", mgmt_name, mgmt_uuid)
404 mgmt.appendChild(self.ref("node", node_uuid))
405 # Placeholder until mgmt-service failover.
406 mgmt.appendChild(self.ref("active", mgmt_uuid))
409 def mountpoint(self, name, uuid, fs_uuid, path):
410 mtpt = self.newService("mountpoint", name, uuid)
411 mtpt.appendChild(self.ref("filesystem", fs_uuid))
412 self.addElement(mtpt, "path", path)
415 def filesystem(self, name, uuid, mds_uuid, obd_uuid, mgmt_uuid):
416 fs = self.newService("filesystem", name, uuid)
417 fs.appendChild(self.ref("mds", mds_uuid))
418 fs.appendChild(self.ref("obd", obd_uuid))
420 fs.appendChild(self.ref("mgmt", mgmt_uuid))
423 def echo_client(self, name, uuid, osc_uuid):
424 ec = self.newService("echoclient", name, uuid)
425 ec.appendChild(self.ref("obd", osc_uuid))
428 ############################################################
429 # Utilities to query a DOM tree
430 # Using this functions we can treat use config information
431 # directly as a database.
433 return n.getAttribute('name')
436 return node.getAttribute('uuid')
439 def findByName(lustre, name, tag = ""):
440 for n in lustre.childNodes:
441 if n.nodeType == n.ELEMENT_NODE:
442 if tag and n.nodeName != tag:
444 if getName(n) == name:
447 n = findByName(n, name)
452 def lookup(node, uuid):
453 for n in node.childNodes:
454 if n.nodeType == n.ELEMENT_NODE:
455 if getUUID(n) == uuid:
463 def name2uuid(lustre, name, tag="", fatal=1):
464 ret = findByName(lustre, name, tag)
467 error('name2uuid:', '"'+name+'"', tag, 'element not found.')
472 def lookup_filesystem(lustre, mds_uuid, ost_uuid):
473 for n in lustre.childNodes:
474 if n.nodeType == n.ELEMENT_NODE and n.nodeName == 'filesystem':
475 if ref_exists(n, mds_uuid) and ref_exists(n, ost_uuid):
479 # XXX: assumes only one network element per node. will fix this
480 # as soon as support for routers is added
481 def get_net_uuid(lustre, node_name):
482 """ get a network uuid for a node_name """
483 node = findByName(lustre, node_name, "node")
485 error ('get_net_uuid:', '"'+node_name+'"', "node element not found.")
486 net = node.getElementsByTagName('network')
488 return getUUID(net[0])
492 def lov_add_obd(gen, lov, osc_uuid):
493 lov.appendChild(gen.ref("obd", osc_uuid))
495 def ref_exists(profile, uuid):
496 elist = profile.childNodes
498 if e.nodeType == e.ELEMENT_NODE:
499 ref = e.getAttribute('uuidref')
504 # ensure that uuid is not already in the profile
505 # return true if uuid is added
506 def node_add_profile(gen, node, ref, uuid):
507 refname = "%s_ref" % "profile"
508 ret = node.getElementsByTagName(refname)
510 error('node has no profile ref:', node)
511 prof_uuid = ret[0].getAttribute('uuidref')
512 profile = lookup(node.parentNode, prof_uuid)
514 error("no profile found:", prof_uuid)
515 if ref_exists(profile, uuid):
517 profile.appendChild(gen.ref(ref, uuid))
520 def get_attr(dom_node, attr, default=""):
521 v = dom_node.getAttribute(attr)
526 ############################################################
529 def set_node_options(gen, node, options):
531 node.setAttribute('router', '1')
533 gen.addElement(node, "timeout", get_option(options, 'timeout'))
535 default_upcall = get_option(options, 'upcall')
538 if default_upcall or options.lustre_upcall:
539 if options.lustre_upcall:
540 gen.addElement(node, 'lustreUpcall', options.lustre_upcall)
542 gen.addElement(node, 'lustreUpcall', default_upcall)
543 if default_upcall or options.portals_upcall:
544 if options.portals_upcall:
545 gen.addElement(node, 'portalsUpcall', options.portals_upcall)
547 gen.addElement(node, 'portalsUpcall', default_upcall)
550 def do_add_node(gen, lustre, options, node_name):
551 uuid = new_uuid(node_name)
552 prof_name = new_name("PROFILE_" + node_name)
553 prof_uuid = new_uuid(prof_name)
554 profile = gen.profile(prof_name, prof_uuid)
555 node = gen.node(node_name, uuid, prof_uuid)
556 lustre.appendChild(node)
557 lustre.appendChild(profile)
559 node_add_profile(gen, node, 'ldlm', ldlm_uuid)
560 set_node_options(gen, node, options)
564 def add_node(gen, lustre, options):
565 """ create a node with a network config """
567 node_name = get_option(options, 'node')
568 ret = findByName(lustre, node_name, "node")
570 print "Node:", node_name, "exists."
572 do_add_node(gen, lustre, options, node_name)
575 def add_net(gen, lustre, options):
576 """ create a node with a network config """
578 node_name = get_option(options, 'node')
579 nid = get_option(options, 'nid')
580 cluster_id = get_option(options, 'cluster_id')
581 hostaddr = get_option(options, 'hostaddr')
582 net_type = get_option(options, 'nettype')
584 if net_type in ('tcp', 'toe'):
585 port = get_option_int(options, 'port')
586 tcpbuf = get_option_int(options, 'tcpbuf')
587 irq_aff = get_option_int(options, 'irq_affinity')
588 nid_xchg = get_option_int(options, 'nid_exchange')
589 elif net_type in ('elan', 'gm', 'scimac'):
595 print "Unknown net_type: ", net_type
598 ret = findByName(lustre, node_name, "node")
600 node = do_add_node(gen, lustre, options, node_name)
603 set_node_options(gen, node, options)
605 net_name = new_name('NET_'+ node_name +'_'+ net_type)
606 net_uuid = new_uuid(net_name)
607 node.appendChild(gen.network(net_name, net_uuid, nid, cluster_id, net_type,
608 hostaddr, port, tcpbuf, irq_aff, nid_xchg))
609 node_add_profile(gen, node, "network", net_uuid)
612 def add_route(gen, lustre, options):
613 """ create a node with a network config """
615 node_name = get_option(options, 'node')
616 gw_net_type = get_option(options, 'nettype')
617 gw = get_option(options, 'gw')
618 gw_cluster_id = get_option(options, 'gw_cluster_id')
619 tgt_cluster_id = get_option(options, 'target_cluster_id')
620 lo = get_option(options, 'lo')
621 hi = get_option(options, 'hi')
625 node = findByName(lustre, node_name, "node")
627 error (node_name, " not found.")
629 rlist = node.getElementsByTagName('routetbl')
633 rtbl_name = new_name("RTBL_" + node_name)
634 rtbl_uuid = new_uuid(rtbl_name)
635 rtbl = gen.routetbl(rtbl_name, rtbl_uuid)
636 node.appendChild(rtbl)
637 node_add_profile(gen, node, "routetbl", rtbl_uuid)
638 rtbl.appendChild(gen.route(gw_net_type, gw, gw_cluster_id, tgt_cluster_id,
642 def add_mds(gen, lustre, options):
643 node_name = get_option(options, 'node')
644 mds_name = get_option(options, 'mds')
645 mdd_name = new_name("MDD_" + mds_name +"_" + node_name)
646 mdd_uuid = new_uuid(mdd_name)
648 mds_uuid = name2uuid(lustre, mds_name, fatal=0)
650 mds_uuid = new_uuid(mds_name)
651 mds = gen.mds(mds_name, mds_uuid, mdd_uuid, options.group)
652 lustre.appendChild(mds)
654 mds = lookup(lustre, mds_uuid)
656 mds.setAttribute('failover', "1")
658 devname = get_option(options, 'dev')
659 size = get_option(options, 'size')
660 fstype = get_option(options, 'fstype')
661 journal_size = get_option(options, 'journal_size')
662 nspath = get_option(options, 'nspath')
664 node_uuid = name2uuid(lustre, node_name, 'node')
666 node = findByName(lustre, node_name, "node")
667 node_add_profile(gen, node, "mdsdev", mdd_uuid)
668 net_uuid = get_net_uuid(lustre, node_name)
670 error("NODE: ", node_name, "not found")
672 mdd = gen.mdsdev(mdd_name, mdd_uuid, fstype, devname,
673 get_format_flag(options), node_uuid, mds_uuid,
674 size, journal_size, nspath)
675 lustre.appendChild(mdd)
678 def add_mgmt(gen, lustre, options):
679 node_name = get_option(options, 'node')
680 node_uuid = name2uuid(lustre, node_name)
681 mgmt_name = get_option(options, 'mgmt')
683 mgmt_name = new_name('MGMT_' + node_name)
684 mgmt_uuid = name2uuid(lustre, mgmt_name, fatal=0)
686 mgmt_uuid = new_uuid(mgmt_name)
687 mgmt = gen.mgmt(mgmt_name, mgmt_uuid, node_uuid)
688 lustre.appendChild(mgmt)
690 mgmt = lookup(lustre, mgmt_uuid)
692 node = findByName(lustre, node_name, "node")
693 node_add_profile(gen, node, 'mgmt', mgmt_uuid)
695 def add_ost(gen, lustre, options):
696 node_name = get_option(options, 'node')
697 lovname = get_option(options, 'lov')
698 osdtype = get_option(options, 'osdtype')
700 node_uuid = name2uuid(lustre, node_name)
702 if osdtype == 'obdecho':
709 devname = get_option(options, 'dev') # can be unset for bluearcs
710 size = get_option(options, 'size')
711 fstype = get_option(options, 'fstype')
712 journal_size = get_option(options, 'journal_size')
714 nspath = get_option(options, 'nspath')
716 ostname = get_option(options, 'ost')
718 ostname = new_name('OST_'+ node_name)
720 osdname = new_name("OSD_" + ostname + "_" + node_name)
721 osd_uuid = new_uuid(osdname)
723 ost_uuid = name2uuid(lustre, ostname, fatal=0)
725 ost_uuid = get_option(options, 'ostuuid')
727 if lookup(lustre, ost_uuid):
728 error("Duplicate OST UUID:", ost_uuid)
730 ost_uuid = new_uuid(ostname)
732 ost = gen.ost(ostname, ost_uuid, osd_uuid, options.group)
733 lustre.appendChild(ost)
735 lov = findByName(lustre, lovname, "lov")
737 error('add_ost:', '"'+lovname+'"', "lov element not found.")
738 lov_add_obd(gen, lov, ost_uuid)
740 ost = lookup(lustre, ost_uuid)
743 ost.setAttribute('failover', "1")
746 osd = gen.osd(osdname, osd_uuid, fstype, osdtype, devname,
747 get_format_flag(options), ost_uuid, node_uuid, size,
748 journal_size, nspath)
750 node = findByName(lustre, node_name, "node")
752 ## if node_add_profile(gen, node, 'oss', oss_uuid):
754 ## oss_uuid = new_uuid(ossname)
755 ## oss = gen.oss(ossname, oss_uuid)
756 ## lustre.appendChild(oss)
758 node_add_profile(gen, node, 'osd', osd_uuid)
759 lustre.appendChild(osd)
762 def add_cobd(gen, lustre, options):
763 node_name = get_option(options, 'node')
764 name = new_name('COBD_' + node_name)
765 uuid = new_uuid(name)
767 real_name = get_option(options, 'real_obd')
768 cache_name = get_option(options, 'cache_obd')
770 real_uuid = name2uuid(lustre, real_name, tag='obd')
771 cache_uuid = name2uuid(lustre, cache_name, tag='obd')
773 node = findByName(lustre, node_name, "node")
774 node_add_profile(gen, node, "cobd", uuid)
775 cobd = gen.cobd(name, uuid, real_uuid, cache_uuid)
776 lustre.appendChild(cobd)
779 def add_echo_client(gen, lustre, options):
780 """ add an echo client to the profile for this node. """
781 node_name = get_option(options, 'node')
782 lov_name = get_option(options, 'ost')
784 node = findByName(lustre, node_name, 'node')
786 echoname = new_name('ECHO_'+ node_name)
787 echo_uuid = new_uuid(echoname)
788 node_add_profile(gen, node, 'echoclient', echo_uuid)
790 lov_uuid = name2uuid(lustre, lov_name, tag='lov', fatal=0)
792 lov_uuid = name2uuid(lustre, lov_name, tag='ost', fatal=1)
794 echo = gen.echo_client(echoname, echo_uuid, lov_uuid)
795 lustre.appendChild(echo)
798 def add_lov(gen, lustre, options):
801 lov_orig = get_option(options, 'lov')
802 name = new_name(lov_orig)
804 warning("name:", lov_orig, "already used. using:", name)
806 mds_name = get_option(options, 'mds')
807 stripe_sz = get_option_int(options, 'stripe_sz')
808 stripe_cnt = get_option_int(options, 'stripe_cnt')
809 pattern = get_option_int(options, 'stripe_pattern')
810 uuid = new_uuid(name)
812 ret = findByName(lustre, name, "lov")
814 error("LOV: ", name, " already exists.")
816 mds_uuid = name2uuid(lustre, mds_name, 'mds')
817 lov = gen.lov(name, uuid, mds_uuid, stripe_sz, stripe_cnt, pattern)
818 lustre.appendChild(lov)
820 # add an lovconfig entry to the active mdsdev profile
821 lovconfig_name = new_name('LVCFG_' + name)
822 lovconfig_uuid = new_uuid(lovconfig_name)
823 mds = findByName(lustre, mds_name)
824 mds.appendChild(gen.ref("lovconfig", lovconfig_uuid))
825 lovconfig = gen.lovconfig(lovconfig_name, lovconfig_uuid, uuid)
826 lustre.appendChild(lovconfig)
828 def new_filesystem(gen, lustre, mds_uuid, obd_uuid, mgmt_uuid):
829 fs_name = new_name("FS_fsname")
830 fs_uuid = new_uuid(fs_name)
831 mds = lookup(lustre, mds_uuid)
832 mds.appendChild(gen.ref("filesystem", fs_uuid))
833 fs = gen.filesystem(fs_name, fs_uuid, mds_uuid, obd_uuid, mgmt_uuid)
834 lustre.appendChild(fs)
837 def get_fs_uuid(gen, lustre, mds_name, obd_name, mgmt_name):
838 mds_uuid = name2uuid(lustre, mds_name, tag='mds')
839 obd_uuid = name2uuid(lustre, obd_name, tag='lov', fatal=0)
841 obd_uuid = name2uuid(lustre, obd_name, tag='ost', fatal=1)
843 mgmt_uuid = name2uuid(lustre, mgmt_name, tag='mgmt', fatal=1)
846 fs_uuid = lookup_filesystem(lustre, mds_uuid, obd_uuid)
848 fs_uuid = new_filesystem(gen, lustre, mds_uuid, obd_uuid, mgmt_uuid)
851 def add_mtpt(gen, lustre, options):
852 """ create mtpt on a node """
853 node_name = get_option(options, 'node')
855 path = get_option(options, 'path')
856 fs_name = get_option(options, 'filesystem')
858 mds_name = get_option(options, 'mds')
859 lov_name = get_option(options, 'lov')
861 lov_name = get_option(options, 'ost')
863 error("--add mtpt requires either --filesystem or --mds with an --lov lov_name or --ost ost_name")
864 mgmt_name = get_option(options, 'mgmt')
865 fs_uuid = get_fs_uuid(gen, lustre, mds_name, lov_name, mgmt_name)
867 fs_uuid = name2uuid(lustre, fs_name, tag='filesystem')
869 name = new_name('MNT_'+ node_name)
871 ret = findByName(lustre, name, "mountpoint")
873 # this can't happen, because new_name creates unique names
874 error("MOUNTPOINT: ", name, " already exists.")
876 uuid = new_uuid(name)
877 mtpt = gen.mountpoint(name, uuid, fs_uuid, path)
878 node = findByName(lustre, node_name, "node")
880 error('node:', node_name, "not found.")
881 node_add_profile(gen, node, "mountpoint", uuid)
882 lustre.appendChild(mtpt)
884 ############################################################
885 # Command line processing
887 class OptionError (exceptions.Exception):
888 def __init__(self, args):
891 def get_option(options, tag):
892 """Look for tag in options hash and return the value if set. If not
893 set, then if return default it is set, otherwise exception."""
894 if options.__getattr__(tag) != None:
895 return options.__getattr__(tag)
897 raise OptionError("--add %s requires --%s <value>" % (options.add, tag))
899 def get_option_int(options, tag):
900 """Return an integer option. Raise exception if the value is not an int"""
901 val = get_option(options, tag)
905 raise OptionError("--%s <num> (value must be integer)" % (tag))
908 # simple class for profiling
915 self._start = time.time()
916 def stop(self, msg=''):
917 self._stop = time.time()
921 return self._stop - self._start
922 def display(self, msg):
924 str = '%s: %g secs' % (msg, d)
927 ############################################################
931 def add(devtype, gen, lustre, options):
933 add_net(gen, lustre, options)
934 elif devtype == 'mtpt':
935 add_mtpt(gen, lustre, options)
936 elif devtype == 'mds':
937 add_mds(gen, lustre, options)
938 elif devtype == 'ost':
939 add_ost(gen, lustre, options)
940 elif devtype == 'lov':
941 add_lov(gen, lustre, options)
942 elif devtype == 'route':
943 add_route(gen, lustre, options)
944 elif devtype == 'node':
945 add_node(gen, lustre, options)
946 elif devtype == 'echo_client':
947 add_echo_client(gen, lustre, options)
948 elif devtype == 'cobd':
949 add_cobd(gen, lustre, options)
950 elif devtype == 'mgmt':
951 add_mgmt(gen, lustre, options)
953 error("unknown device type:", devtype)
955 def do_command(gen, lustre, options, args):
957 add(options.add, gen, lustre, options)
959 error("Missing command")
962 cl = Lustre.Options("lmc", "", lmc_options)
964 options, args = cl.parse(sys.argv[1:])
965 except Lustre.OptionError, e:
969 panic(string.join(sys.argv), "Unexpected extra arguments on command line: " + string.join(args))
971 if options.reference:
978 outFile = options.merge
979 if os.access(outFile, os.R_OK):
980 doc = xml.dom.minidom.parse(outFile)
982 doc = new_lustre(xml.dom.minidom)
984 doc = xml.dom.minidom.parse(options.input)
986 doc = new_lustre(xml.dom.minidom)
989 outFile = options.output
991 lustre = doc.documentElement
993 if lustre.tagName != "lustre":
994 print "Existing config not valid."
1000 fp = open(options.batch)
1001 batchCommands = fp.readlines()
1003 for cmd in batchCommands:
1005 options, args = cl.parse(string.split(cmd))
1006 do_command(gen, lustre, options, args)
1007 except OptionError, e:
1009 except Lustre.OptionError, e:
1013 do_command(gen, lustre, options, args)
1014 except OptionError, e:
1015 panic(string.join(sys.argv),e)
1016 except Lustre.OptionError, e:
1022 PrettyPrint(doc, open(outFile,"w"))
1024 if __name__ == "__main__":