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
94 --obdtype obdecho|obdfilter
97 --add mtpt - Mountpoint
101 --ost ost_name OR --lov lov_name
113 --add mgmt - Management/monitoring service
115 --mgmt mgmt_service_name
118 PARAM = Lustre.Options.PARAM
120 # lmc input/output options
121 ('reference', "Print short reference for commands."),
122 ('verbose,v', "Print system commands as they are run."),
123 ('merge,m', "Append to the specified config file.", PARAM),
124 ('output,o', "Write XML configuration into given output file. Overwrite existing content.", PARAM),
125 ('input,i', "", PARAM),
126 ('batch', "Used to execute lmc commands in batch mode.", PARAM),
132 ('node', "Add a new node in the cluster configuration.", PARAM),
133 ('timeout', "Set timeout to initiate recovery.", PARAM),
134 ('upcall', "Set both lustre and portals upcall scripts.", PARAM),
135 ('lustre_upcall', "Set location of lustre upcall script.", PARAM),
136 ('portals_upcall', "Set location of portals upcall script.", PARAM),
139 ('nettype', "Specify the network type. This can be tcp/elan/gm/scimac.", PARAM),
140 ('nid', "Give the network ID, e.g ElanID/IP Address as used by portals.", PARAM),
141 ('tcpbuf', "Optional argument to specify the TCP buffer size.", PARAM, "0"),
142 ('port', "Optional argument to specify the TCP port number.", PARAM, DEFAULT_PORT),
143 ('irq_affinity', "Optional argument.", PARAM, 0),
144 ('hostaddr', "", PARAM,""),
145 ('cluster_id', "Specify the cluster ID", PARAM, "0"),
148 ('route', "Add a new route for the cluster.", PARAM),
149 ('router', "Optional flag to mark a node as router."),
150 ('gw', "Specify the nid of the gateway for a route.", PARAM),
151 ('gateway_cluster_id', "", PARAM, "0"),
152 ('target_cluster_id', "", PARAM, "0"),
153 ('lo', "For a range route, this is the low value nid.", PARAM),
154 ('hi', "For a range route, this is a hi value nid.", PARAM,""),
156 # servers: mds and ost
157 ('mds', "Specify MDS name.", PARAM),
158 ('ost', "Specify the OST name.", PARAM,""),
159 ('osdtype', "This could obdfilter or obdecho.", PARAM, "obdfilter"),
160 ('failover', "Enable failover support on OSTs or MDS?"),
161 ('group', "", PARAM),
162 ('dev', "Path of the device on local system.", PARAM,""),
163 ('size', "Specify the size of the device if needed.", PARAM,"0"),
164 ('journal_size', "Specify new journal size for underlying ext3 file system.", PARAM,"0"),
165 ('fstype', "Optional argument to specify the filesystem type.", PARAM, "ext3"),
166 ('mkfsoptions', "Optional argument to mkfs.", PARAM, ""),
167 ('ostuuid', "", PARAM,""),
168 ('nspath', "Local mount point of server namespace.", PARAM,""),
171 # clients: mountpoint and echo
172 ('echo_client', "", PARAM),
173 ('path', "Specify the mountpoint for Lustre.", PARAM),
174 ('filesystem', "Lustre filesystem name", PARAM,""),
177 ('lov', "Specify LOV name.", PARAM,""),
178 ('stripe_sz', "Specify the stripe size in bytes.", PARAM),
179 ('stripe_cnt', "Specify the number of OSTs each file should be striped on.", PARAM, 0),
180 ('stripe_pattern', "Specify the stripe pattern. RAID 0 is the only one currently supported.", PARAM, 0),
183 ('real_obd', "", PARAM),
184 ('cache_obd', "", PARAM),
186 ('mgmt', "Specify management/monitoring service name.", PARAM, ""),
190 msg = string.join(map(str,args))
191 raise OptionError("Error: " + msg)
200 msg = string.join(map(str,args))
201 print "Warning: ", msg
204 # manage names and uuids
205 # need to initialize this by walking tree to ensure
206 # no duplicate names or uuids are created.
207 # this are just place holders for now.
208 # consider changing this to be like OBD-dev-host
212 while names.has_key(ret):
213 ret = "%s_%d" % (base, ctr)
219 return "%s_UUID" % (name)
222 ldlm_uuid = 'ldlm_UUID'
225 """Create a new empty lustre document"""
226 # adding ldlm here is a bit of a hack, but one is enough.
227 str = """<lustre version="%s">
228 <ldlm name="%s" uuid="%s"/>
229 </lustre>""" % (Lustre.CONFIG_VERSION, ldlm_name, ldlm_uuid)
230 return dom.parseString(str)
236 """initialize auto-name generation tables"""
238 # get all elements that contain a name attribute
239 for n in doc.childNodes:
240 if n.nodeType == n.ELEMENT_NODE:
242 names[getName(n)] = 1
243 uuids[getUUID(n)] = 1
246 def get_format_flag(options):
251 ############################################################
252 # Build config objects using DOM
257 def __init__(self, doc):
260 def ref(self, type, uuid):
261 """ generate <[type]_ref uuidref="[uuid]"/> """
262 tag = "%s_ref" % (type)
263 ref = self.doc.createElement(tag)
264 ref.setAttribute("uuidref", uuid)
267 def newService(self, tag, name, uuid):
268 """ create a new service elmement, which requires name and uuid attributes """
269 new = self.doc.createElement(tag)
270 new.setAttribute("uuid", uuid);
271 new.setAttribute("name", name);
274 def addText(self, node, str):
275 txt = self.doc.createTextNode(str)
276 node.appendChild(txt)
278 def addElement(self, node, tag, str=None):
279 """ create a new element and add it as a child to node. If str is passed,
280 a text node is created for the new element"""
281 new = self.doc.createElement(tag)
283 self.addText(new, str)
284 node.appendChild(new)
287 def network(self, name, uuid, nid, cluster_id, net, hostaddr="",
288 port=0, tcpbuf=0, irq_aff=0):
289 """create <network> node"""
290 network = self.newService("network", name, uuid)
291 network.setAttribute("nettype", net);
292 self.addElement(network, "nid", nid)
293 self.addElement(network, "clusterid", cluster_id)
295 self.addElement(network, "hostaddr", hostaddr)
297 self.addElement(network, "port", "%d" %(port))
299 self.addElement(network, "sendmem", "%d" %(tcpbuf))
300 self.addElement(network, "recvmem", "%d" %(tcpbuf))
302 self.addElement(network, "irqaffinity", "%d" %(irq_aff))
306 def routetbl(self, name, uuid):
307 """create <routetbl> node"""
308 rtbl = self.newService("routetbl", name, uuid)
311 def route(self, gw_net_type, gw, gw_cluster_id, tgt_cluster_id, lo, hi):
312 """ create one entry for the route table """
313 ref = self.doc.createElement('route')
314 ref.setAttribute("type", gw_net_type)
315 ref.setAttribute("gw", gw)
316 ref.setAttribute("gwclusterid", gw_cluster_id)
317 ref.setAttribute("tgtclusterid", tgt_cluster_id)
318 ref.setAttribute("lo", lo)
320 ref.setAttribute("hi", hi)
323 def profile(self, name, uuid):
324 """ create a host """
325 profile = self.newService("profile", name, uuid)
328 def node(self, name, uuid, prof_uuid):
329 """ create a host """
330 node = self.newService("node", name, uuid)
331 node.appendChild(self.ref("profile", prof_uuid))
334 def ldlm(self, name, uuid):
335 """ create a ldlm """
336 ldlm = self.newService("ldlm", name, uuid)
339 def osd(self, name, uuid, fs, osdtype, devname, format, ost_uuid,
340 node_uuid, dev_size=0, journal_size=0, nspath=""):
341 osd = self.newService("osd", name, uuid)
342 osd.setAttribute('osdtype', osdtype)
343 osd.appendChild(self.ref("target", ost_uuid))
344 osd.appendChild(self.ref("node", node_uuid))
346 self.addElement(osd, "fstype", fs)
348 dev = self.addElement(osd, "devpath", devname)
349 self.addElement(osd, "autoformat", format)
351 self.addElement(osd, "devsize", "%s" % (dev_size))
353 self.addElement(osd, "journalsize", "%s" % (journal_size))
355 self.addElement(osd, "nspath", nspath)
358 def cobd(self, name, uuid, real_uuid, cache_uuid):
359 cobd = self.newService("cobd", name, uuid)
360 cobd.appendChild(self.ref("realobd",real_uuid))
361 cobd.appendChild(self.ref("cacheobd",cache_uuid))
364 def ost(self, name, uuid, osd_uuid, group=""):
365 ost = self.newService("ost", name, uuid)
366 ost.appendChild(self.ref("active", osd_uuid))
368 self.addElement(ost, "group", group)
371 def oss(self, name, uuid):
372 oss = self.newService("oss", name, uuid)
375 def lov(self, name, uuid, mds_uuid, stripe_sz, stripe_cnt, pattern):
376 lov = self.newService("lov", name, uuid)
377 lov.appendChild(self.ref("mds", mds_uuid))
378 lov.setAttribute("stripesize", str(stripe_sz))
379 lov.setAttribute("stripecount", str(stripe_cnt))
380 lov.setAttribute("stripepattern", str(pattern))
383 def lovconfig(self, name, uuid, lov_uuid):
384 lovconfig = self.newService("lovconfig", name, uuid)
385 lovconfig.appendChild(self.ref("lov", lov_uuid))
388 def mds(self, name, uuid, mdd_uuid, group=""):
389 mds = self.newService("mds", name, uuid)
390 mds.appendChild(self.ref("active",mdd_uuid))
392 self.addElement(mds, "group", group)
395 def mdsdev(self, name, uuid, fs, devname, format, node_uuid,
396 mds_uuid, dev_size=0, journal_size=0, nspath="", mkfsoptions=""):
397 mdd = self.newService("mdsdev", name, uuid)
398 self.addElement(mdd, "fstype", fs)
399 dev = self.addElement(mdd, "devpath", devname)
400 self.addElement(mdd, "autoformat", format)
402 self.addElement(mdd, "devsize", "%s" % (dev_size))
404 self.addElement(mdd, "journalsize", "%s" % (journal_size))
406 self.addElement(mdd, "nspath", nspath)
408 self.addElement(mdd, "mkfsoptions", mkfsoptions)
409 mdd.appendChild(self.ref("node", node_uuid))
410 mdd.appendChild(self.ref("target", mds_uuid))
413 def mgmt(self, mgmt_name, mgmt_uuid, node_uuid):
414 mgmt = self.newService("mgmt", mgmt_name, mgmt_uuid)
415 mgmt.appendChild(self.ref("node", node_uuid))
416 # Placeholder until mgmt-service failover.
417 mgmt.appendChild(self.ref("active", mgmt_uuid))
420 def mountpoint(self, name, uuid, fs_uuid, path):
421 mtpt = self.newService("mountpoint", name, uuid)
422 mtpt.appendChild(self.ref("filesystem", fs_uuid))
423 self.addElement(mtpt, "path", path)
426 def filesystem(self, name, uuid, mds_uuid, obd_uuid, mgmt_uuid):
427 fs = self.newService("filesystem", name, uuid)
428 fs.appendChild(self.ref("mds", mds_uuid))
429 fs.appendChild(self.ref("obd", obd_uuid))
431 fs.appendChild(self.ref("mgmt", mgmt_uuid))
434 def echo_client(self, name, uuid, osc_uuid):
435 ec = self.newService("echoclient", name, uuid)
436 ec.appendChild(self.ref("obd", osc_uuid))
439 ############################################################
440 # Utilities to query a DOM tree
441 # Using this functions we can treat use config information
442 # directly as a database.
444 return n.getAttribute('name')
447 return node.getAttribute('uuid')
450 def findByName(lustre, name, tag = ""):
451 for n in lustre.childNodes:
452 if n.nodeType == n.ELEMENT_NODE:
453 if tag and n.nodeName != tag:
455 if getName(n) == name:
458 n = findByName(n, name)
463 def lookup(node, uuid):
464 for n in node.childNodes:
465 if n.nodeType == n.ELEMENT_NODE:
466 if getUUID(n) == uuid:
474 def name2uuid(lustre, name, tag="", fatal=1):
475 ret = findByName(lustre, name, tag)
478 error('name2uuid:', '"'+name+'"', tag, 'element not found.')
483 def lookup_filesystem(lustre, mds_uuid, ost_uuid):
484 for n in lustre.childNodes:
485 if n.nodeType == n.ELEMENT_NODE and n.nodeName == 'filesystem':
486 if ref_exists(n, mds_uuid) and ref_exists(n, ost_uuid):
490 # XXX: assumes only one network element per node. will fix this
491 # as soon as support for routers is added
492 def get_net_uuid(lustre, node_name):
493 """ get a network uuid for a node_name """
494 node = findByName(lustre, node_name, "node")
496 error ('get_net_uuid:', '"'+node_name+'"', "node element not found.")
497 net = node.getElementsByTagName('network')
499 return getUUID(net[0])
503 def lov_add_obd(gen, lov, osc_uuid):
504 lov.appendChild(gen.ref("obd", osc_uuid))
506 def ref_exists(profile, uuid):
507 elist = profile.childNodes
509 if e.nodeType == e.ELEMENT_NODE:
510 ref = e.getAttribute('uuidref')
515 # ensure that uuid is not already in the profile
516 # return true if uuid is added
517 def node_add_profile(gen, node, ref, uuid):
518 refname = "%s_ref" % "profile"
519 ret = node.getElementsByTagName(refname)
521 error('node has no profile ref:', node)
522 prof_uuid = ret[0].getAttribute('uuidref')
523 profile = lookup(node.parentNode, prof_uuid)
525 error("no profile found:", prof_uuid)
526 if ref_exists(profile, uuid):
528 profile.appendChild(gen.ref(ref, uuid))
531 def get_attr(dom_node, attr, default=""):
532 v = dom_node.getAttribute(attr)
537 ############################################################
540 def set_node_options(gen, node, options):
542 node.setAttribute('router', '1')
544 gen.addElement(node, "timeout", get_option(options, 'timeout'))
546 default_upcall = get_option(options, 'upcall')
549 if default_upcall or options.lustre_upcall:
550 if options.lustre_upcall:
551 gen.addElement(node, 'lustreUpcall', options.lustre_upcall)
553 gen.addElement(node, 'lustreUpcall', default_upcall)
554 if default_upcall or options.portals_upcall:
555 if options.portals_upcall:
556 gen.addElement(node, 'portalsUpcall', options.portals_upcall)
558 gen.addElement(node, 'portalsUpcall', default_upcall)
561 def do_add_node(gen, lustre, options, node_name):
562 uuid = new_uuid(node_name)
563 prof_name = new_name("PROFILE_" + node_name)
564 prof_uuid = new_uuid(prof_name)
565 profile = gen.profile(prof_name, prof_uuid)
566 node = gen.node(node_name, uuid, prof_uuid)
567 lustre.appendChild(node)
568 lustre.appendChild(profile)
570 node_add_profile(gen, node, 'ldlm', ldlm_uuid)
571 set_node_options(gen, node, options)
575 def add_node(gen, lustre, options):
576 """ create a node with a network config """
578 node_name = get_option(options, 'node')
579 ret = findByName(lustre, node_name, "node")
581 print "Node:", node_name, "exists."
583 do_add_node(gen, lustre, options, node_name)
586 def add_net(gen, lustre, options):
587 """ create a node with a network config """
589 node_name = get_option(options, 'node')
590 nid = get_option(options, 'nid')
591 cluster_id = get_option(options, 'cluster_id')
592 hostaddr = get_option(options, 'hostaddr')
593 net_type = get_option(options, 'nettype')
595 if net_type in ('tcp', 'toe'):
596 port = get_option_int(options, 'port')
597 tcpbuf = get_option_int(options, 'tcpbuf')
598 irq_aff = get_option_int(options, 'irq_affinity')
599 elif net_type in ('elan', 'gm', 'scimac'):
604 print "Unknown net_type: ", net_type
607 ret = findByName(lustre, node_name, "node")
609 node = do_add_node(gen, lustre, options, node_name)
612 set_node_options(gen, node, options)
614 net_name = new_name('NET_'+ node_name +'_'+ net_type)
615 net_uuid = new_uuid(net_name)
616 node.appendChild(gen.network(net_name, net_uuid, nid, cluster_id, net_type,
617 hostaddr, port, tcpbuf, irq_aff))
618 node_add_profile(gen, node, "network", net_uuid)
621 def add_route(gen, lustre, options):
622 """ create a node with a network config """
624 node_name = get_option(options, 'node')
625 gw_net_type = get_option(options, 'nettype')
626 gw = get_option(options, 'gw')
627 gw_cluster_id = get_option(options, 'gateway_cluster_id')
628 tgt_cluster_id = get_option(options, 'target_cluster_id')
629 lo = get_option(options, 'lo')
630 hi = get_option(options, 'hi')
634 node = findByName(lustre, node_name, "node")
636 error (node_name, " not found.")
638 rlist = node.getElementsByTagName('routetbl')
642 rtbl_name = new_name("RTBL_" + node_name)
643 rtbl_uuid = new_uuid(rtbl_name)
644 rtbl = gen.routetbl(rtbl_name, rtbl_uuid)
645 node.appendChild(rtbl)
646 node_add_profile(gen, node, "routetbl", rtbl_uuid)
647 rtbl.appendChild(gen.route(gw_net_type, gw, gw_cluster_id, tgt_cluster_id,
651 def add_mds(gen, lustre, options):
652 node_name = get_option(options, 'node')
653 mds_name = get_option(options, 'mds')
654 mdd_name = new_name("MDD_" + mds_name +"_" + node_name)
655 mdd_uuid = new_uuid(mdd_name)
657 mds_uuid = name2uuid(lustre, mds_name, fatal=0)
659 mds_uuid = new_uuid(mds_name)
660 mds = gen.mds(mds_name, mds_uuid, mdd_uuid, options.group)
661 lustre.appendChild(mds)
663 mds = lookup(lustre, mds_uuid)
665 mds.setAttribute('failover', "1")
667 devname = get_option(options, 'dev')
668 size = get_option(options, 'size')
669 fstype = get_option(options, 'fstype')
670 journal_size = get_option(options, 'journal_size')
671 nspath = get_option(options, 'nspath')
672 mkfsoptions = get_option(options, 'mkfsoptions')
674 node_uuid = name2uuid(lustre, node_name, 'node')
676 node = findByName(lustre, node_name, "node")
677 node_add_profile(gen, node, "mdsdev", mdd_uuid)
678 net_uuid = get_net_uuid(lustre, node_name)
680 error("NODE: ", node_name, "not found")
682 mdd = gen.mdsdev(mdd_name, mdd_uuid, fstype, devname,
683 get_format_flag(options), node_uuid, mds_uuid,
684 size, journal_size, nspath, mkfsoptions)
685 lustre.appendChild(mdd)
688 def add_mgmt(gen, lustre, options):
689 node_name = get_option(options, 'node')
690 node_uuid = name2uuid(lustre, node_name)
691 mgmt_name = get_option(options, 'mgmt')
693 mgmt_name = new_name('MGMT_' + node_name)
694 mgmt_uuid = name2uuid(lustre, mgmt_name, fatal=0)
696 mgmt_uuid = new_uuid(mgmt_name)
697 mgmt = gen.mgmt(mgmt_name, mgmt_uuid, node_uuid)
698 lustre.appendChild(mgmt)
700 mgmt = lookup(lustre, mgmt_uuid)
702 node = findByName(lustre, node_name, "node")
703 node_add_profile(gen, node, 'mgmt', mgmt_uuid)
705 def add_ost(gen, lustre, options):
706 node_name = get_option(options, 'node')
707 lovname = get_option(options, 'lov')
708 osdtype = get_option(options, 'osdtype')
710 node_uuid = name2uuid(lustre, node_name)
712 if osdtype == 'obdecho':
719 devname = get_option(options, 'dev') # can be unset for bluearcs
720 size = get_option(options, 'size')
721 fstype = get_option(options, 'fstype')
722 journal_size = get_option(options, 'journal_size')
724 nspath = get_option(options, 'nspath')
726 ostname = get_option(options, 'ost')
728 ostname = new_name('OST_'+ node_name)
730 osdname = new_name("OSD_" + ostname + "_" + node_name)
731 osd_uuid = new_uuid(osdname)
733 ost_uuid = name2uuid(lustre, ostname, fatal=0)
735 ost_uuid = get_option(options, 'ostuuid')
737 if lookup(lustre, ost_uuid):
738 error("Duplicate OST UUID:", ost_uuid)
740 ost_uuid = new_uuid(ostname)
742 ost = gen.ost(ostname, ost_uuid, osd_uuid, options.group)
743 lustre.appendChild(ost)
745 lov = findByName(lustre, lovname, "lov")
747 error('add_ost:', '"'+lovname+'"', "lov element not found.")
748 lov_add_obd(gen, lov, ost_uuid)
750 ost = lookup(lustre, ost_uuid)
753 ost.setAttribute('failover', "1")
756 osd = gen.osd(osdname, osd_uuid, fstype, osdtype, devname,
757 get_format_flag(options), ost_uuid, node_uuid, size,
758 journal_size, nspath)
760 node = findByName(lustre, node_name, "node")
762 ## if node_add_profile(gen, node, 'oss', oss_uuid):
764 ## oss_uuid = new_uuid(ossname)
765 ## oss = gen.oss(ossname, oss_uuid)
766 ## lustre.appendChild(oss)
768 node_add_profile(gen, node, 'osd', osd_uuid)
769 lustre.appendChild(osd)
772 def add_cobd(gen, lustre, options):
773 node_name = get_option(options, 'node')
774 name = new_name('COBD_' + node_name)
775 uuid = new_uuid(name)
777 real_name = get_option(options, 'real_obd')
778 cache_name = get_option(options, 'cache_obd')
780 real_uuid = name2uuid(lustre, real_name, tag='obd')
781 cache_uuid = name2uuid(lustre, cache_name, tag='obd')
783 node = findByName(lustre, node_name, "node")
784 node_add_profile(gen, node, "cobd", uuid)
785 cobd = gen.cobd(name, uuid, real_uuid, cache_uuid)
786 lustre.appendChild(cobd)
789 def add_echo_client(gen, lustre, options):
790 """ add an echo client to the profile for this node. """
791 node_name = get_option(options, 'node')
792 lov_name = get_option(options, 'ost')
794 node = findByName(lustre, node_name, 'node')
796 echoname = new_name('ECHO_'+ node_name)
797 echo_uuid = new_uuid(echoname)
798 node_add_profile(gen, node, 'echoclient', echo_uuid)
800 lov_uuid = name2uuid(lustre, lov_name, tag='lov', fatal=0)
802 lov_uuid = name2uuid(lustre, lov_name, tag='ost', fatal=1)
804 echo = gen.echo_client(echoname, echo_uuid, lov_uuid)
805 lustre.appendChild(echo)
808 def add_lov(gen, lustre, options):
811 lov_orig = get_option(options, 'lov')
812 name = new_name(lov_orig)
814 warning("name:", lov_orig, "already used. using:", name)
816 mds_name = get_option(options, 'mds')
817 stripe_sz = get_option_int(options, 'stripe_sz')
818 stripe_cnt = get_option_int(options, 'stripe_cnt')
819 pattern = get_option_int(options, 'stripe_pattern')
820 uuid = new_uuid(name)
822 ret = findByName(lustre, name, "lov")
824 error("LOV: ", name, " already exists.")
826 mds_uuid = name2uuid(lustre, mds_name, 'mds')
827 lov = gen.lov(name, uuid, mds_uuid, stripe_sz, stripe_cnt, pattern)
828 lustre.appendChild(lov)
830 # add an lovconfig entry to the active mdsdev profile
831 lovconfig_name = new_name('LVCFG_' + name)
832 lovconfig_uuid = new_uuid(lovconfig_name)
833 mds = findByName(lustre, mds_name)
834 mds.appendChild(gen.ref("lovconfig", lovconfig_uuid))
835 lovconfig = gen.lovconfig(lovconfig_name, lovconfig_uuid, uuid)
836 lustre.appendChild(lovconfig)
838 def new_filesystem(gen, lustre, mds_uuid, obd_uuid, mgmt_uuid):
839 fs_name = new_name("FS_fsname")
840 fs_uuid = new_uuid(fs_name)
841 mds = lookup(lustre, mds_uuid)
842 mds.appendChild(gen.ref("filesystem", fs_uuid))
843 fs = gen.filesystem(fs_name, fs_uuid, mds_uuid, obd_uuid, mgmt_uuid)
844 lustre.appendChild(fs)
847 def get_fs_uuid(gen, lustre, mds_name, obd_name, mgmt_name):
848 mds_uuid = name2uuid(lustre, mds_name, tag='mds')
849 obd_uuid = name2uuid(lustre, obd_name, tag='lov', fatal=0)
851 obd_uuid = name2uuid(lustre, obd_name, tag='ost', fatal=1)
853 mgmt_uuid = name2uuid(lustre, mgmt_name, tag='mgmt', fatal=1)
856 fs_uuid = lookup_filesystem(lustre, mds_uuid, obd_uuid)
858 fs_uuid = new_filesystem(gen, lustre, mds_uuid, obd_uuid, mgmt_uuid)
861 def add_mtpt(gen, lustre, options):
862 """ create mtpt on a node """
863 node_name = get_option(options, 'node')
865 path = get_option(options, 'path')
866 fs_name = get_option(options, 'filesystem')
868 mds_name = get_option(options, 'mds')
869 lov_name = get_option(options, 'lov')
871 lov_name = get_option(options, 'ost')
873 error("--add mtpt requires either --filesystem or --mds with an --lov lov_name or --ost ost_name")
874 mgmt_name = get_option(options, 'mgmt')
875 fs_uuid = get_fs_uuid(gen, lustre, mds_name, lov_name, mgmt_name)
877 fs_uuid = name2uuid(lustre, fs_name, tag='filesystem')
879 name = new_name('MNT_'+ node_name)
881 ret = findByName(lustre, name, "mountpoint")
883 # this can't happen, because new_name creates unique names
884 error("MOUNTPOINT: ", name, " already exists.")
886 uuid = new_uuid(name)
887 mtpt = gen.mountpoint(name, uuid, fs_uuid, path)
888 node = findByName(lustre, node_name, "node")
890 error('node:', node_name, "not found.")
891 node_add_profile(gen, node, "mountpoint", uuid)
892 lustre.appendChild(mtpt)
894 ############################################################
895 # Command line processing
897 class OptionError (exceptions.Exception):
898 def __init__(self, args):
901 def get_option(options, tag):
902 """Look for tag in options hash and return the value if set. If not
903 set, then if return default it is set, otherwise exception."""
904 if options.__getattr__(tag) != None:
905 return options.__getattr__(tag)
907 raise OptionError("--add %s requires --%s <value>" % (options.add, tag))
909 def get_option_int(options, tag):
910 """Return an integer option. Raise exception if the value is not an int"""
911 val = get_option(options, tag)
915 raise OptionError("--%s <num> (value must be integer)" % (tag))
918 # simple class for profiling
925 self._start = time.time()
926 def stop(self, msg=''):
927 self._stop = time.time()
931 return self._stop - self._start
932 def display(self, msg):
934 str = '%s: %g secs' % (msg, d)
937 ############################################################
941 def add(devtype, gen, lustre, options):
943 add_net(gen, lustre, options)
944 elif devtype == 'mtpt':
945 add_mtpt(gen, lustre, options)
946 elif devtype == 'mds':
947 add_mds(gen, lustre, options)
948 elif devtype == 'ost':
949 add_ost(gen, lustre, options)
950 elif devtype == 'lov':
951 add_lov(gen, lustre, options)
952 elif devtype == 'route':
953 add_route(gen, lustre, options)
954 elif devtype == 'node':
955 add_node(gen, lustre, options)
956 elif devtype == 'echo_client':
957 add_echo_client(gen, lustre, options)
958 elif devtype == 'cobd':
959 add_cobd(gen, lustre, options)
960 elif devtype == 'mgmt':
961 add_mgmt(gen, lustre, options)
963 error("unknown device type:", devtype)
965 def do_command(gen, lustre, options, args):
967 add(options.add, gen, lustre, options)
969 error("Missing command")
972 cl = Lustre.Options("lmc", "", lmc_options)
974 options, args = cl.parse(sys.argv[1:])
975 except Lustre.OptionError, e:
979 panic(string.join(sys.argv), "Unexpected extra arguments on command line: " + string.join(args))
981 if options.reference:
988 outFile = options.merge
989 if os.access(outFile, os.R_OK):
990 doc = xml.dom.minidom.parse(outFile)
992 doc = new_lustre(xml.dom.minidom)
994 doc = xml.dom.minidom.parse(options.input)
996 doc = new_lustre(xml.dom.minidom)
999 outFile = options.output
1001 lustre = doc.documentElement
1003 if lustre.tagName != "lustre":
1004 print "Existing config not valid."
1007 gen = GenConfig(doc)
1010 fp = open(options.batch)
1011 batchCommands = fp.readlines()
1013 for cmd in batchCommands:
1015 options, args = cl.parse(string.split(cmd))
1016 do_command(gen, lustre, options, args)
1017 except OptionError, e:
1019 except Lustre.OptionError, e:
1023 do_command(gen, lustre, options, args)
1024 except OptionError, e:
1025 panic(string.join(sys.argv),e)
1026 except Lustre.OptionError, e:
1032 PrettyPrint(doc, open(outFile,"w"))
1034 if __name__ == "__main__":