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:
63 --nettype tcp|elan|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 ret_uuid = '%05x_%.19s_%05x%05x' % (int(random.random() * 1048576),
221 int(random.random() * 1048576),
222 int(random.random() * 1048576))
226 ldlm_uuid = 'ldlm_UUID'
229 """Create a new empty lustre document"""
230 # adding ldlm here is a bit of a hack, but one is enough.
231 str = """<lustre version="%s">
232 <ldlm name="%s" uuid="%s"/>
233 </lustre>""" % (Lustre.CONFIG_VERSION, ldlm_name, ldlm_uuid)
234 return dom.parseString(str)
240 """initialize auto-name generation tables"""
242 # get all elements that contain a name attribute
243 for n in doc.childNodes:
244 if n.nodeType == n.ELEMENT_NODE:
246 names[getName(n)] = 1
247 uuids[getUUID(n)] = 1
250 def get_format_flag(options):
255 ############################################################
256 # Build config objects using DOM
261 def __init__(self, doc):
264 def ref(self, type, uuid):
265 """ generate <[type]_ref uuidref="[uuid]"/> """
266 tag = "%s_ref" % (type)
267 ref = self.doc.createElement(tag)
268 ref.setAttribute("uuidref", uuid)
271 def newService(self, tag, name, uuid):
272 """ create a new service elmement, which requires name and uuid attributes """
273 new = self.doc.createElement(tag)
274 new.setAttribute("uuid", uuid);
275 new.setAttribute("name", name);
278 def addText(self, node, str):
279 txt = self.doc.createTextNode(str)
280 node.appendChild(txt)
282 def addElement(self, node, tag, str=None):
283 """ create a new element and add it as a child to node. If str is passed,
284 a text node is created for the new element"""
285 new = self.doc.createElement(tag)
287 self.addText(new, str)
288 node.appendChild(new)
291 def network(self, name, uuid, nid, cluster_id, net, hostaddr="",
292 port=0, tcpbuf=0, irq_aff=0):
293 """create <network> node"""
294 network = self.newService("network", name, uuid)
295 network.setAttribute("nettype", net);
296 self.addElement(network, "nid", nid)
297 self.addElement(network, "clusterid", cluster_id)
299 self.addElement(network, "hostaddr", hostaddr)
301 self.addElement(network, "port", "%d" %(port))
303 self.addElement(network, "sendmem", "%d" %(tcpbuf))
304 self.addElement(network, "recvmem", "%d" %(tcpbuf))
306 self.addElement(network, "irqaffinity", "%d" %(irq_aff))
310 def routetbl(self, name, uuid):
311 """create <routetbl> node"""
312 rtbl = self.newService("routetbl", name, uuid)
315 def route(self, gw_net_type, gw, gw_cluster_id, tgt_cluster_id, lo, hi):
316 """ create one entry for the route table """
317 ref = self.doc.createElement('route')
318 ref.setAttribute("type", gw_net_type)
319 ref.setAttribute("gw", gw)
320 ref.setAttribute("gwclusterid", gw_cluster_id)
321 ref.setAttribute("tgtclusterid", tgt_cluster_id)
322 ref.setAttribute("lo", lo)
324 ref.setAttribute("hi", hi)
327 def profile(self, name, uuid):
328 """ create a host """
329 profile = self.newService("profile", name, uuid)
332 def node(self, name, uuid, prof_uuid):
333 """ create a host """
334 node = self.newService("node", name, uuid)
335 node.appendChild(self.ref("profile", prof_uuid))
338 def ldlm(self, name, uuid):
339 """ create a ldlm """
340 ldlm = self.newService("ldlm", name, uuid)
343 def osd(self, name, uuid, fs, osdtype, devname, format, ost_uuid,
344 node_uuid, dev_size=0, journal_size=0, nspath=""):
345 osd = self.newService("osd", name, uuid)
346 osd.setAttribute('osdtype', osdtype)
347 osd.appendChild(self.ref("target", ost_uuid))
348 osd.appendChild(self.ref("node", node_uuid))
350 self.addElement(osd, "fstype", fs)
352 dev = self.addElement(osd, "devpath", devname)
353 self.addElement(osd, "autoformat", format)
355 self.addElement(osd, "devsize", "%s" % (dev_size))
357 self.addElement(osd, "journalsize", "%s" % (journal_size))
359 self.addElement(osd, "nspath", nspath)
362 def cobd(self, name, uuid, real_uuid, cache_uuid):
363 cobd = self.newService("cobd", name, uuid)
364 cobd.appendChild(self.ref("realobd",real_uuid))
365 cobd.appendChild(self.ref("cacheobd",cache_uuid))
368 def ost(self, name, uuid, osd_uuid, group=""):
369 ost = self.newService("ost", name, uuid)
370 ost.appendChild(self.ref("active", osd_uuid))
372 self.addElement(ost, "group", group)
375 def oss(self, name, uuid):
376 oss = self.newService("oss", name, uuid)
379 def lov(self, name, uuid, mds_uuid, stripe_sz, stripe_cnt, pattern):
380 lov = self.newService("lov", name, uuid)
381 lov.appendChild(self.ref("mds", mds_uuid))
382 lov.setAttribute("stripesize", str(stripe_sz))
383 lov.setAttribute("stripecount", str(stripe_cnt))
384 lov.setAttribute("stripepattern", str(pattern))
387 def lovconfig(self, name, uuid, lov_uuid):
388 lovconfig = self.newService("lovconfig", name, uuid)
389 lovconfig.appendChild(self.ref("lov", lov_uuid))
392 def mds(self, name, uuid, mdd_uuid, group=""):
393 mds = self.newService("mds", name, uuid)
394 mds.appendChild(self.ref("active",mdd_uuid))
396 self.addElement(mds, "group", group)
399 def mdsdev(self, name, uuid, fs, devname, format, node_uuid,
400 mds_uuid, dev_size=0, journal_size=0, nspath="", mkfsoptions=""):
401 mdd = self.newService("mdsdev", name, uuid)
402 self.addElement(mdd, "fstype", fs)
403 dev = self.addElement(mdd, "devpath", devname)
404 self.addElement(mdd, "autoformat", format)
406 self.addElement(mdd, "devsize", "%s" % (dev_size))
408 self.addElement(mdd, "journalsize", "%s" % (journal_size))
410 self.addElement(mdd, "nspath", nspath)
412 self.addElement(mdd, "mkfsoptions", mkfsoptions)
413 mdd.appendChild(self.ref("node", node_uuid))
414 mdd.appendChild(self.ref("target", mds_uuid))
417 def mgmt(self, mgmt_name, mgmt_uuid, node_uuid):
418 mgmt = self.newService("mgmt", mgmt_name, mgmt_uuid)
419 mgmt.appendChild(self.ref("node", node_uuid))
420 # Placeholder until mgmt-service failover.
421 mgmt.appendChild(self.ref("active", mgmt_uuid))
424 def mountpoint(self, name, uuid, fs_uuid, path):
425 mtpt = self.newService("mountpoint", name, uuid)
426 mtpt.appendChild(self.ref("filesystem", fs_uuid))
427 self.addElement(mtpt, "path", path)
430 def filesystem(self, name, uuid, mds_uuid, obd_uuid, mgmt_uuid):
431 fs = self.newService("filesystem", name, uuid)
432 fs.appendChild(self.ref("mds", mds_uuid))
433 fs.appendChild(self.ref("obd", obd_uuid))
435 fs.appendChild(self.ref("mgmt", mgmt_uuid))
438 def echo_client(self, name, uuid, osc_uuid):
439 ec = self.newService("echoclient", name, uuid)
440 ec.appendChild(self.ref("obd", osc_uuid))
443 ############################################################
444 # Utilities to query a DOM tree
445 # Using this functions we can treat use config information
446 # directly as a database.
448 return n.getAttribute('name')
451 return node.getAttribute('uuid')
454 def findByName(lustre, name, tag = ""):
455 for n in lustre.childNodes:
456 if n.nodeType == n.ELEMENT_NODE:
457 if tag and n.nodeName != tag:
459 if getName(n) == name:
462 n = findByName(n, name)
467 def lookup(node, uuid):
468 for n in node.childNodes:
469 if n.nodeType == n.ELEMENT_NODE:
470 if getUUID(n) == uuid:
478 def name2uuid(lustre, name, tag="", fatal=1):
479 ret = findByName(lustre, name, tag)
482 error('name2uuid:', '"'+name+'"', tag, 'element not found.')
487 def lookup_filesystem(lustre, mds_uuid, ost_uuid):
488 for n in lustre.childNodes:
489 if n.nodeType == n.ELEMENT_NODE and n.nodeName == 'filesystem':
490 if ref_exists(n, mds_uuid) and ref_exists(n, ost_uuid):
494 # XXX: assumes only one network element per node. will fix this
495 # as soon as support for routers is added
496 def get_net_uuid(lustre, node_name):
497 """ get a network uuid for a node_name """
498 node = findByName(lustre, node_name, "node")
500 error ('get_net_uuid:', '"'+node_name+'"', "node element not found.")
501 net = node.getElementsByTagName('network')
503 return getUUID(net[0])
507 def lov_add_obd(gen, lov, osc_uuid):
508 lov.appendChild(gen.ref("obd", osc_uuid))
510 def ref_exists(profile, uuid):
511 elist = profile.childNodes
513 if e.nodeType == e.ELEMENT_NODE:
514 ref = e.getAttribute('uuidref')
519 # ensure that uuid is not already in the profile
520 # return true if uuid is added
521 def node_add_profile(gen, node, ref, uuid):
522 refname = "%s_ref" % "profile"
523 ret = node.getElementsByTagName(refname)
525 error('node has no profile ref:', node)
526 prof_uuid = ret[0].getAttribute('uuidref')
527 profile = lookup(node.parentNode, prof_uuid)
529 error("no profile found:", prof_uuid)
530 if ref_exists(profile, uuid):
532 profile.appendChild(gen.ref(ref, uuid))
535 def get_attr(dom_node, attr, default=""):
536 v = dom_node.getAttribute(attr)
541 ############################################################
544 def set_node_options(gen, node, options):
546 node.setAttribute('router', '1')
548 gen.addElement(node, "timeout", get_option(options, 'timeout'))
550 default_upcall = get_option(options, 'upcall')
553 if default_upcall or options.lustre_upcall:
554 if options.lustre_upcall:
555 gen.addElement(node, 'lustreUpcall', options.lustre_upcall)
557 gen.addElement(node, 'lustreUpcall', default_upcall)
558 if default_upcall or options.portals_upcall:
559 if options.portals_upcall:
560 gen.addElement(node, 'portalsUpcall', options.portals_upcall)
562 gen.addElement(node, 'portalsUpcall', default_upcall)
565 def do_add_node(gen, lustre, options, node_name):
566 uuid = new_uuid(node_name)
567 prof_name = new_name("PROFILE_" + node_name)
568 prof_uuid = new_uuid(prof_name)
569 profile = gen.profile(prof_name, prof_uuid)
570 node = gen.node(node_name, uuid, prof_uuid)
571 lustre.appendChild(node)
572 lustre.appendChild(profile)
574 node_add_profile(gen, node, 'ldlm', ldlm_uuid)
575 set_node_options(gen, node, options)
579 def add_node(gen, lustre, options):
580 """ create a node with a network config """
582 node_name = get_option(options, 'node')
583 ret = findByName(lustre, node_name, "node")
585 print "Node:", node_name, "exists."
587 do_add_node(gen, lustre, options, node_name)
590 def add_net(gen, lustre, options):
591 """ create a node with a network config """
593 node_name = get_option(options, 'node')
594 nid = get_option(options, 'nid')
595 cluster_id = get_option(options, 'cluster_id')
596 hostaddr = get_option(options, 'hostaddr')
597 net_type = get_option(options, 'nettype')
599 if net_type in ('tcp',):
600 port = get_option_int(options, 'port')
601 tcpbuf = get_option_int(options, 'tcpbuf')
602 irq_aff = get_option_int(options, 'irq_affinity')
603 elif net_type in ('elan', 'gm', 'scimac'):
608 print "Unknown net_type: ", net_type
611 ret = findByName(lustre, node_name, "node")
613 node = do_add_node(gen, lustre, options, node_name)
616 set_node_options(gen, node, options)
618 net_name = new_name('NET_'+ node_name +'_'+ net_type)
619 net_uuid = new_uuid(net_name)
620 node.appendChild(gen.network(net_name, net_uuid, nid, cluster_id, net_type,
621 hostaddr, port, tcpbuf, irq_aff))
622 node_add_profile(gen, node, "network", net_uuid)
625 def add_route(gen, lustre, options):
626 """ create a node with a network config """
628 node_name = get_option(options, 'node')
629 gw_net_type = get_option(options, 'nettype')
630 gw = get_option(options, 'gw')
631 gw_cluster_id = get_option(options, 'gateway_cluster_id')
632 tgt_cluster_id = get_option(options, 'target_cluster_id')
633 lo = get_option(options, 'lo')
634 hi = get_option(options, 'hi')
638 node = findByName(lustre, node_name, "node")
640 error (node_name, " not found.")
642 rlist = node.getElementsByTagName('routetbl')
646 rtbl_name = new_name("RTBL_" + node_name)
647 rtbl_uuid = new_uuid(rtbl_name)
648 rtbl = gen.routetbl(rtbl_name, rtbl_uuid)
649 node.appendChild(rtbl)
650 node_add_profile(gen, node, "routetbl", rtbl_uuid)
651 rtbl.appendChild(gen.route(gw_net_type, gw, gw_cluster_id, tgt_cluster_id,
655 def add_mds(gen, lustre, options):
656 node_name = get_option(options, 'node')
657 mds_name = get_option(options, 'mds')
658 mdd_name = new_name("MDD_" + mds_name +"_" + node_name)
659 mdd_uuid = new_uuid(mdd_name)
661 mds_uuid = name2uuid(lustre, mds_name, fatal=0)
663 mds_uuid = new_uuid(mds_name)
664 mds = gen.mds(mds_name, mds_uuid, mdd_uuid, options.group)
665 lustre.appendChild(mds)
667 mds = lookup(lustre, mds_uuid)
669 mds.setAttribute('failover', "1")
671 devname = get_option(options, 'dev')
672 size = get_option(options, 'size')
673 fstype = get_option(options, 'fstype')
674 journal_size = get_option(options, 'journal_size')
675 nspath = get_option(options, 'nspath')
676 mkfsoptions = get_option(options, 'mkfsoptions')
678 node_uuid = name2uuid(lustre, node_name, 'node')
680 node = findByName(lustre, node_name, "node")
681 node_add_profile(gen, node, "mdsdev", mdd_uuid)
682 net_uuid = get_net_uuid(lustre, node_name)
684 error("NODE: ", node_name, "not found")
686 mdd = gen.mdsdev(mdd_name, mdd_uuid, fstype, devname,
687 get_format_flag(options), node_uuid, mds_uuid,
688 size, journal_size, nspath, mkfsoptions)
689 lustre.appendChild(mdd)
692 def add_mgmt(gen, lustre, options):
693 node_name = get_option(options, 'node')
694 node_uuid = name2uuid(lustre, node_name)
695 mgmt_name = get_option(options, 'mgmt')
697 mgmt_name = new_name('MGMT_' + node_name)
698 mgmt_uuid = name2uuid(lustre, mgmt_name, fatal=0)
700 mgmt_uuid = new_uuid(mgmt_name)
701 mgmt = gen.mgmt(mgmt_name, mgmt_uuid, node_uuid)
702 lustre.appendChild(mgmt)
704 mgmt = lookup(lustre, mgmt_uuid)
706 node = findByName(lustre, node_name, "node")
707 node_add_profile(gen, node, 'mgmt', mgmt_uuid)
709 def add_ost(gen, lustre, options):
710 node_name = get_option(options, 'node')
711 lovname = get_option(options, 'lov')
712 osdtype = get_option(options, 'osdtype')
714 node_uuid = name2uuid(lustre, node_name)
716 if osdtype == 'obdecho':
723 devname = get_option(options, 'dev') # can be unset for bluearcs
724 size = get_option(options, 'size')
725 fstype = get_option(options, 'fstype')
726 journal_size = get_option(options, 'journal_size')
728 nspath = get_option(options, 'nspath')
730 ostname = get_option(options, 'ost')
732 ostname = new_name('OST_'+ node_name)
734 osdname = new_name("OSD_" + ostname + "_" + node_name)
735 osd_uuid = new_uuid(osdname)
737 ost_uuid = name2uuid(lustre, ostname, fatal=0)
739 ost_uuid = get_option(options, 'ostuuid')
741 if lookup(lustre, ost_uuid):
742 error("Duplicate OST UUID:", ost_uuid)
744 ost_uuid = new_uuid(ostname)
746 ost = gen.ost(ostname, ost_uuid, osd_uuid, options.group)
747 lustre.appendChild(ost)
749 lov = findByName(lustre, lovname, "lov")
751 error('add_ost:', '"'+lovname+'"', "lov element not found.")
752 lov_add_obd(gen, lov, ost_uuid)
754 ost = lookup(lustre, ost_uuid)
757 ost.setAttribute('failover', "1")
760 osd = gen.osd(osdname, osd_uuid, fstype, osdtype, devname,
761 get_format_flag(options), ost_uuid, node_uuid, size,
762 journal_size, nspath)
764 node = findByName(lustre, node_name, "node")
766 ## if node_add_profile(gen, node, 'oss', oss_uuid):
768 ## oss_uuid = new_uuid(ossname)
769 ## oss = gen.oss(ossname, oss_uuid)
770 ## lustre.appendChild(oss)
772 node_add_profile(gen, node, 'osd', osd_uuid)
773 lustre.appendChild(osd)
776 def add_cobd(gen, lustre, options):
777 node_name = get_option(options, 'node')
778 name = new_name('COBD_' + node_name)
779 uuid = new_uuid(name)
781 real_name = get_option(options, 'real_obd')
782 cache_name = get_option(options, 'cache_obd')
784 real_uuid = name2uuid(lustre, real_name, tag='obd')
785 cache_uuid = name2uuid(lustre, cache_name, tag='obd')
787 node = findByName(lustre, node_name, "node")
788 node_add_profile(gen, node, "cobd", uuid)
789 cobd = gen.cobd(name, uuid, real_uuid, cache_uuid)
790 lustre.appendChild(cobd)
793 def add_echo_client(gen, lustre, options):
794 """ add an echo client to the profile for this node. """
795 node_name = get_option(options, 'node')
796 lov_name = get_option(options, 'ost')
798 node = findByName(lustre, node_name, 'node')
800 echoname = new_name('ECHO_'+ node_name)
801 echo_uuid = new_uuid(echoname)
802 node_add_profile(gen, node, 'echoclient', echo_uuid)
804 lov_uuid = name2uuid(lustre, lov_name, tag='lov', fatal=0)
806 lov_uuid = name2uuid(lustre, lov_name, tag='ost', fatal=1)
808 echo = gen.echo_client(echoname, echo_uuid, lov_uuid)
809 lustre.appendChild(echo)
812 def add_lov(gen, lustre, options):
815 lov_orig = get_option(options, 'lov')
816 name = new_name(lov_orig)
818 warning("name:", lov_orig, "already used. using:", name)
820 mds_name = get_option(options, 'mds')
821 stripe_sz = get_option_int(options, 'stripe_sz')
822 stripe_cnt = get_option_int(options, 'stripe_cnt')
823 pattern = get_option_int(options, 'stripe_pattern')
824 uuid = new_uuid(name)
826 ret = findByName(lustre, name, "lov")
828 error("LOV: ", name, " already exists.")
830 mds_uuid = name2uuid(lustre, mds_name, 'mds')
831 lov = gen.lov(name, uuid, mds_uuid, stripe_sz, stripe_cnt, pattern)
832 lustre.appendChild(lov)
834 # add an lovconfig entry to the active mdsdev profile
835 lovconfig_name = new_name('LVCFG_' + name)
836 lovconfig_uuid = new_uuid(lovconfig_name)
837 mds = findByName(lustre, mds_name)
838 mds.appendChild(gen.ref("lovconfig", lovconfig_uuid))
839 lovconfig = gen.lovconfig(lovconfig_name, lovconfig_uuid, uuid)
840 lustre.appendChild(lovconfig)
842 def new_filesystem(gen, lustre, mds_uuid, obd_uuid, mgmt_uuid):
843 fs_name = new_name("FS_fsname")
844 fs_uuid = new_uuid(fs_name)
845 mds = lookup(lustre, mds_uuid)
846 mds.appendChild(gen.ref("filesystem", fs_uuid))
847 fs = gen.filesystem(fs_name, fs_uuid, mds_uuid, obd_uuid, mgmt_uuid)
848 lustre.appendChild(fs)
851 def get_fs_uuid(gen, lustre, mds_name, obd_name, mgmt_name):
852 mds_uuid = name2uuid(lustre, mds_name, tag='mds')
853 obd_uuid = name2uuid(lustre, obd_name, tag='lov', fatal=0)
855 obd_uuid = name2uuid(lustre, obd_name, tag='ost', fatal=1)
857 mgmt_uuid = name2uuid(lustre, mgmt_name, tag='mgmt', fatal=1)
860 fs_uuid = lookup_filesystem(lustre, mds_uuid, obd_uuid)
862 fs_uuid = new_filesystem(gen, lustre, mds_uuid, obd_uuid, mgmt_uuid)
865 def add_mtpt(gen, lustre, options):
866 """ create mtpt on a node """
867 node_name = get_option(options, 'node')
869 path = get_option(options, 'path')
870 fs_name = get_option(options, 'filesystem')
872 mds_name = get_option(options, 'mds')
873 lov_name = get_option(options, 'lov')
875 lov_name = get_option(options, 'ost')
877 error("--add mtpt requires either --filesystem or --mds with an --lov lov_name or --ost ost_name")
878 mgmt_name = get_option(options, 'mgmt')
879 fs_uuid = get_fs_uuid(gen, lustre, mds_name, lov_name, mgmt_name)
881 fs_uuid = name2uuid(lustre, fs_name, tag='filesystem')
883 name = new_name('MNT_'+ node_name)
885 ret = findByName(lustre, name, "mountpoint")
887 # this can't happen, because new_name creates unique names
888 error("MOUNTPOINT: ", name, " already exists.")
890 uuid = new_uuid(name)
891 mtpt = gen.mountpoint(name, uuid, fs_uuid, path)
892 node = findByName(lustre, node_name, "node")
894 error('node:', node_name, "not found.")
895 node_add_profile(gen, node, "mountpoint", uuid)
896 lustre.appendChild(mtpt)
898 ############################################################
899 # Command line processing
901 class OptionError (exceptions.Exception):
902 def __init__(self, args):
905 def get_option(options, tag):
906 """Look for tag in options hash and return the value if set. If not
907 set, then if return default it is set, otherwise exception."""
908 if options.__getattr__(tag) != None:
909 return options.__getattr__(tag)
911 raise OptionError("--add %s requires --%s <value>" % (options.add, tag))
913 def get_option_int(options, tag):
914 """Return an integer option. Raise exception if the value is not an int"""
915 val = get_option(options, tag)
919 raise OptionError("--%s <num> (value must be integer)" % (tag))
922 # simple class for profiling
929 self._start = time.time()
930 def stop(self, msg=''):
931 self._stop = time.time()
935 return self._stop - self._start
936 def display(self, msg):
938 str = '%s: %g secs' % (msg, d)
941 ############################################################
945 def add(devtype, gen, lustre, options):
947 add_net(gen, lustre, options)
948 elif devtype == 'mtpt':
949 add_mtpt(gen, lustre, options)
950 elif devtype == 'mds':
951 add_mds(gen, lustre, options)
952 elif devtype == 'ost':
953 add_ost(gen, lustre, options)
954 elif devtype == 'lov':
955 add_lov(gen, lustre, options)
956 elif devtype == 'route':
957 add_route(gen, lustre, options)
958 elif devtype == 'node':
959 add_node(gen, lustre, options)
960 elif devtype == 'echo_client':
961 add_echo_client(gen, lustre, options)
962 elif devtype == 'cobd':
963 add_cobd(gen, lustre, options)
964 elif devtype == 'mgmt':
965 add_mgmt(gen, lustre, options)
967 error("unknown device type:", devtype)
969 def do_command(gen, lustre, options, args):
971 add(options.add, gen, lustre, options)
973 error("Missing command")
976 cl = Lustre.Options("lmc", "", lmc_options)
978 options, args = cl.parse(sys.argv[1:])
979 except Lustre.OptionError, e:
983 panic(string.join(sys.argv), "Unexpected extra arguments on command line: " + string.join(args))
985 if options.reference:
992 outFile = options.merge
993 if os.access(outFile, os.R_OK):
994 doc = xml.dom.minidom.parse(outFile)
996 doc = new_lustre(xml.dom.minidom)
998 doc = xml.dom.minidom.parse(options.input)
1000 doc = new_lustre(xml.dom.minidom)
1003 outFile = options.output
1005 lustre = doc.documentElement
1007 if lustre.tagName != "lustre":
1008 print "Existing config not valid."
1011 gen = GenConfig(doc)
1013 # the PRNG is normally seeded with time(), which is not so good for starting # time-synchronized clusters
1014 input = open('/dev/urandom', 'r')
1016 print 'Unable to open /dev/urandom!'
1018 seed = input.read(32)
1023 fp = open(options.batch)
1024 batchCommands = fp.readlines()
1026 for cmd in batchCommands:
1028 options, args = cl.parse(string.split(cmd))
1029 do_command(gen, lustre, options, args)
1030 except OptionError, e:
1032 except Lustre.OptionError, e:
1036 do_command(gen, lustre, options, args)
1037 except OptionError, e:
1038 panic(string.join(sys.argv),e)
1039 except Lustre.OptionError, e:
1045 PrettyPrint(doc, open(outFile,"w"))
1047 if __name__ == "__main__":