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)
46 DEFAULT_STRIPE_SZ = 65536
47 DEFAULT_STRIPE_CNT = 1
48 DEFAULT_STRIPE_PATTERN = 0
51 print """usage: lmc --add object [object parameters]
53 Object creation command summary:
61 --ptldebug debug_level
62 --subsystem subsystem_name
68 --nettype tcp|elan|gm|scimac
99 --obdtype obdecho|obdfilter
102 --add mtpt - Mountpoint
106 --ost ost_name OR --lov lov_name
118 --add mgmt - Management/monitoring service
120 --mgmt mgmt_service_name
123 PARAM = Lustre.Options.PARAM
125 # lmc input/output options
126 ('reference', "Print short reference for commands."),
127 ('verbose,v', "Print system commands as they are run."),
128 ('merge,m', "Append to the specified config file.", PARAM),
129 ('output,o', "Write XML configuration into given output file. Overwrite existing content.", PARAM),
130 ('input,i', "", PARAM),
131 ('batch', "Used to execute lmc commands in batch mode.", PARAM),
137 ('node', "Add a new node in the cluster configuration.", PARAM),
138 ('timeout', "Set timeout to initiate recovery.", PARAM),
139 ('upcall', "Set both lustre and portals upcall scripts.", PARAM),
140 ('lustre_upcall', "Set location of lustre upcall script.", PARAM),
141 ('portals_upcall', "Set location of portals upcall script.", PARAM),
142 ('ptldebug', "Set the portals debug level", PARAM),
143 ('subsystem', "Specify which Lustre subsystems have debug output recorded in the log", PARAM),
146 ('nettype', "Specify the network type. This can be tcp/elan/gm/scimac.", PARAM),
147 ('nid', "Give the network ID, e.g ElanID/IP Address as used by portals.", PARAM),
148 ('tcpbuf', "Optional argument to specify the TCP buffer size.", PARAM, "0"),
149 ('port', "Optional argument to specify the TCP port number.", PARAM, DEFAULT_PORT),
150 ('irq_affinity', "Optional argument.", PARAM, 0),
151 ('hostaddr', "", PARAM,""),
152 ('cluster_id', "Specify the cluster ID", PARAM, "0"),
155 ('route', "Add a new route for the cluster.", PARAM),
156 ('router', "Optional flag to mark a node as router."),
157 ('gw', "Specify the nid of the gateway for a route.", PARAM),
158 ('gateway_cluster_id', "", PARAM, "0"),
159 ('target_cluster_id', "", PARAM, "0"),
160 ('lo', "For a range route, this is the low value nid.", PARAM),
161 ('hi', "For a range route, this is a hi value nid.", PARAM,""),
163 # servers: mds and ost
164 ('mds', "Specify MDS name.", PARAM),
165 ('ost', "Specify the OST name.", PARAM,""),
166 ('osdtype', "This could obdfilter or obdecho.", PARAM, "obdfilter"),
167 ('failover', "Enable failover support on OSTs or MDS?"),
168 ('group', "", PARAM),
169 ('dev', "Path of the device on local system.", PARAM,""),
170 ('size', "Specify the size of the device if needed.", PARAM,"0"),
171 ('journal_size', "Specify new journal size for underlying ext3 file system.", PARAM,"0"),
172 ('fstype', "Optional argument to specify the filesystem type.", PARAM, "ext3"),
173 ('mkfsoptions', "Optional argument to mkfs.", PARAM, ""),
174 ('ostuuid', "", PARAM,""),
175 ('nspath', "Local mount point of server namespace.", PARAM,""),
178 # clients: mountpoint and echo
179 ('echo_client', "", PARAM),
180 ('path', "Specify the mountpoint for Lustre.", PARAM),
181 ('filesystem', "Lustre filesystem name", PARAM,""),
184 ('lov', "Specify LOV name.", PARAM,""),
185 ('stripe_sz', "Specify the stripe size in bytes.", PARAM),
186 ('stripe_cnt', "Specify the number of OSTs each file should be striped on.", PARAM, 0),
187 ('stripe_pattern', "Specify the stripe pattern. RAID 0 is the only one currently supported.", PARAM, 0),
190 ('real_obd', "", PARAM),
191 ('cache_obd', "", PARAM),
193 ('mgmt', "Specify management/monitoring service name.", PARAM, ""),
197 msg = string.join(map(str,args))
198 raise OptionError("Error: " + msg)
207 msg = string.join(map(str,args))
208 print "Warning: ", msg
211 # manage names and uuids
212 # need to initialize this by walking tree to ensure
213 # no duplicate names or uuids are created.
214 # this are just place holders for now.
215 # consider changing this to be like OBD-dev-host
219 while names.has_key(ret):
220 ret = "%s_%d" % (base, ctr)
226 ret_uuid = '%05x_%.19s_%05x%05x' % (int(random.random() * 1048576),
228 int(random.random() * 1048576),
229 int(random.random() * 1048576))
233 ldlm_uuid = 'ldlm_UUID'
236 """Create a new empty lustre document"""
237 # adding ldlm here is a bit of a hack, but one is enough.
238 str = """<lustre version="%s">
239 <ldlm name="%s" uuid="%s"/>
240 </lustre>""" % (Lustre.CONFIG_VERSION, ldlm_name, ldlm_uuid)
241 return dom.parseString(str)
247 """initialize auto-name generation tables"""
249 # get all elements that contain a name attribute
250 for n in doc.childNodes:
251 if n.nodeType == n.ELEMENT_NODE:
253 names[getName(n)] = 1
254 uuids[getUUID(n)] = 1
257 def get_format_flag(options):
262 ############################################################
263 # Build config objects using DOM
268 def __init__(self, doc):
271 def ref(self, type, uuid):
272 """ generate <[type]_ref uuidref="[uuid]"/> """
273 tag = "%s_ref" % (type)
274 ref = self.doc.createElement(tag)
275 ref.setAttribute("uuidref", uuid)
278 def newService(self, tag, name, uuid):
279 """ create a new service elmement, which requires name and uuid attributes """
280 new = self.doc.createElement(tag)
281 new.setAttribute("uuid", uuid);
282 new.setAttribute("name", name);
285 def addText(self, node, str):
286 txt = self.doc.createTextNode(str)
287 node.appendChild(txt)
289 def addElement(self, node, tag, str=None):
290 """ create a new element and add it as a child to node. If str is passed,
291 a text node is created for the new element"""
292 new = self.doc.createElement(tag)
294 self.addText(new, str)
295 node.appendChild(new)
298 def network(self, name, uuid, nid, cluster_id, net, hostaddr="",
299 port=0, tcpbuf=0, irq_aff=0):
300 """create <network> node"""
301 network = self.newService("network", name, uuid)
302 network.setAttribute("nettype", net);
303 self.addElement(network, "nid", nid)
304 self.addElement(network, "clusterid", cluster_id)
306 self.addElement(network, "hostaddr", hostaddr)
308 self.addElement(network, "port", "%d" %(port))
310 self.addElement(network, "sendmem", "%d" %(tcpbuf))
311 self.addElement(network, "recvmem", "%d" %(tcpbuf))
313 self.addElement(network, "irqaffinity", "%d" %(irq_aff))
317 def routetbl(self, name, uuid):
318 """create <routetbl> node"""
319 rtbl = self.newService("routetbl", name, uuid)
322 def route(self, gw_net_type, gw, gw_cluster_id, tgt_cluster_id, lo, hi):
323 """ create one entry for the route table """
324 ref = self.doc.createElement('route')
325 ref.setAttribute("type", gw_net_type)
326 ref.setAttribute("gw", gw)
327 ref.setAttribute("gwclusterid", gw_cluster_id)
328 ref.setAttribute("tgtclusterid", tgt_cluster_id)
329 ref.setAttribute("lo", lo)
331 ref.setAttribute("hi", hi)
334 def profile(self, name, uuid):
335 """ create a host """
336 profile = self.newService("profile", name, uuid)
339 def node(self, name, uuid, prof_uuid):
340 """ create a host """
341 node = self.newService("node", name, uuid)
342 node.appendChild(self.ref("profile", prof_uuid))
345 def ldlm(self, name, uuid):
346 """ create a ldlm """
347 ldlm = self.newService("ldlm", name, uuid)
350 def osd(self, name, uuid, fs, osdtype, devname, format, ost_uuid,
351 node_uuid, dev_size=0, journal_size=0, nspath=""):
352 osd = self.newService("osd", name, uuid)
353 osd.setAttribute('osdtype', osdtype)
354 osd.appendChild(self.ref("target", ost_uuid))
355 osd.appendChild(self.ref("node", node_uuid))
357 self.addElement(osd, "fstype", fs)
359 dev = self.addElement(osd, "devpath", devname)
360 self.addElement(osd, "autoformat", format)
362 self.addElement(osd, "devsize", "%s" % (dev_size))
364 self.addElement(osd, "journalsize", "%s" % (journal_size))
366 self.addElement(osd, "nspath", nspath)
369 def cobd(self, name, uuid, real_uuid, cache_uuid):
370 cobd = self.newService("cobd", name, uuid)
371 cobd.appendChild(self.ref("realobd",real_uuid))
372 cobd.appendChild(self.ref("cacheobd",cache_uuid))
375 def ost(self, name, uuid, osd_uuid, group=""):
376 ost = self.newService("ost", name, uuid)
377 ost.appendChild(self.ref("active", osd_uuid))
379 self.addElement(ost, "group", group)
382 def oss(self, name, uuid):
383 oss = self.newService("oss", name, uuid)
386 def lov(self, name, uuid, mds_uuid, stripe_sz, stripe_cnt, pattern):
387 lov = self.newService("lov", name, uuid)
388 lov.appendChild(self.ref("mds", mds_uuid))
389 lov.setAttribute("stripesize", str(stripe_sz))
390 lov.setAttribute("stripecount", str(stripe_cnt))
391 lov.setAttribute("stripepattern", str(pattern))
394 def lovconfig(self, name, uuid, lov_uuid):
395 lovconfig = self.newService("lovconfig", name, uuid)
396 lovconfig.appendChild(self.ref("lov", lov_uuid))
399 def mds(self, name, uuid, mdd_uuid, group=""):
400 mds = self.newService("mds", name, uuid)
401 mds.appendChild(self.ref("active",mdd_uuid))
403 self.addElement(mds, "group", group)
406 def mdsdev(self, name, uuid, fs, devname, format, node_uuid,
407 mds_uuid, dev_size=0, journal_size=0, nspath="", mkfsoptions=""):
408 mdd = self.newService("mdsdev", name, uuid)
409 self.addElement(mdd, "fstype", fs)
410 dev = self.addElement(mdd, "devpath", devname)
411 self.addElement(mdd, "autoformat", format)
413 self.addElement(mdd, "devsize", "%s" % (dev_size))
415 self.addElement(mdd, "journalsize", "%s" % (journal_size))
417 self.addElement(mdd, "nspath", nspath)
419 self.addElement(mdd, "mkfsoptions", mkfsoptions)
420 mdd.appendChild(self.ref("node", node_uuid))
421 mdd.appendChild(self.ref("target", mds_uuid))
424 def mgmt(self, mgmt_name, mgmt_uuid, node_uuid):
425 mgmt = self.newService("mgmt", mgmt_name, mgmt_uuid)
426 mgmt.appendChild(self.ref("node", node_uuid))
427 # Placeholder until mgmt-service failover.
428 mgmt.appendChild(self.ref("active", mgmt_uuid))
431 def mountpoint(self, name, uuid, fs_uuid, path):
432 mtpt = self.newService("mountpoint", name, uuid)
433 mtpt.appendChild(self.ref("filesystem", fs_uuid))
434 self.addElement(mtpt, "path", path)
437 def filesystem(self, name, uuid, mds_uuid, obd_uuid, mgmt_uuid):
438 fs = self.newService("filesystem", name, uuid)
439 fs.appendChild(self.ref("mds", mds_uuid))
440 fs.appendChild(self.ref("obd", obd_uuid))
442 fs.appendChild(self.ref("mgmt", mgmt_uuid))
445 def echo_client(self, name, uuid, osc_uuid):
446 ec = self.newService("echoclient", name, uuid)
447 ec.appendChild(self.ref("obd", osc_uuid))
450 ############################################################
451 # Utilities to query a DOM tree
452 # Using this functions we can treat use config information
453 # directly as a database.
455 return n.getAttribute('name')
458 return node.getAttribute('uuid')
461 def findByName(lustre, name, tag = ""):
462 for n in lustre.childNodes:
463 if n.nodeType == n.ELEMENT_NODE:
464 if tag and n.nodeName != tag:
466 if getName(n) == name:
469 n = findByName(n, name)
474 def lookup(node, uuid):
475 for n in node.childNodes:
476 if n.nodeType == n.ELEMENT_NODE:
477 if getUUID(n) == uuid:
485 def name2uuid(lustre, name, tag="", fatal=1):
486 ret = findByName(lustre, name, tag)
489 error('name2uuid:', '"'+name+'"', tag, 'element not found.')
494 def lookup_filesystem(lustre, mds_uuid, ost_uuid):
495 for n in lustre.childNodes:
496 if n.nodeType == n.ELEMENT_NODE and n.nodeName == 'filesystem':
497 if ref_exists(n, mds_uuid) and ref_exists(n, ost_uuid):
501 # XXX: assumes only one network element per node. will fix this
502 # as soon as support for routers is added
503 def get_net_uuid(lustre, node_name):
504 """ get a network uuid for a node_name """
505 node = findByName(lustre, node_name, "node")
507 error ('get_net_uuid:', '"'+node_name+'"', "node element not found.")
508 net = node.getElementsByTagName('network')
510 return getUUID(net[0])
514 def lov_add_obd(gen, lov, osc_uuid):
515 lov.appendChild(gen.ref("obd", osc_uuid))
517 def ref_exists(profile, uuid):
518 elist = profile.childNodes
520 if e.nodeType == e.ELEMENT_NODE:
521 ref = e.getAttribute('uuidref')
526 # ensure that uuid is not already in the profile
527 # return true if uuid is added
528 def node_add_profile(gen, node, ref, uuid):
529 refname = "%s_ref" % "profile"
530 ret = node.getElementsByTagName(refname)
532 error('node has no profile ref:', node)
533 prof_uuid = ret[0].getAttribute('uuidref')
534 profile = lookup(node.parentNode, prof_uuid)
536 error("no profile found:", prof_uuid)
537 if ref_exists(profile, uuid):
539 profile.appendChild(gen.ref(ref, uuid))
542 def get_attr(dom_node, attr, default=""):
543 v = dom_node.getAttribute(attr)
548 ############################################################
551 def set_node_options(gen, node, options):
553 node.setAttribute('router', '1')
555 gen.addElement(node, "timeout", get_option(options, 'timeout'))
557 default_upcall = get_option(options, 'upcall')
560 if default_upcall or options.lustre_upcall:
561 if options.lustre_upcall:
562 gen.addElement(node, 'lustreUpcall', options.lustre_upcall)
564 gen.addElement(node, 'lustreUpcall', default_upcall)
565 if default_upcall or options.portals_upcall:
566 if options.portals_upcall:
567 gen.addElement(node, 'portalsUpcall', options.portals_upcall)
569 gen.addElement(node, 'portalsUpcall', default_upcall)
571 gen.addElement(node, "ptldebug", get_option(options, 'ptldebug'))
572 if options.subsystem:
573 gen.addElement(node, "subsystem", get_option(options, 'subsystem'))
576 def do_add_node(gen, lustre, options, node_name):
577 uuid = new_uuid(node_name)
578 prof_name = new_name("PROFILE_" + node_name)
579 prof_uuid = new_uuid(prof_name)
580 profile = gen.profile(prof_name, prof_uuid)
581 node = gen.node(node_name, uuid, prof_uuid)
582 lustre.appendChild(node)
583 lustre.appendChild(profile)
585 node_add_profile(gen, node, 'ldlm', ldlm_uuid)
586 set_node_options(gen, node, options)
590 def add_node(gen, lustre, options):
591 """ create a node with a network config """
593 node_name = get_option(options, 'node')
594 ret = findByName(lustre, node_name, "node")
596 print "Node:", node_name, "exists."
598 do_add_node(gen, lustre, options, node_name)
601 def add_net(gen, lustre, options):
602 """ create a node with a network config """
604 node_name = get_option(options, 'node')
605 nid = get_option(options, 'nid')
606 cluster_id = get_option(options, 'cluster_id')
607 hostaddr = get_option(options, 'hostaddr')
608 net_type = get_option(options, 'nettype')
610 if net_type in ('tcp',):
611 port = get_option_int(options, 'port')
612 tcpbuf = get_option_int(options, 'tcpbuf')
613 irq_aff = get_option_int(options, 'irq_affinity')
614 elif net_type in ('elan', 'gm', 'scimac'):
619 print "Unknown net_type: ", net_type
622 ret = findByName(lustre, node_name, "node")
624 node = do_add_node(gen, lustre, options, node_name)
627 set_node_options(gen, node, options)
629 net_name = new_name('NET_'+ node_name +'_'+ net_type)
630 net_uuid = new_uuid(net_name)
631 node.appendChild(gen.network(net_name, net_uuid, nid, cluster_id, net_type,
632 hostaddr, port, tcpbuf, irq_aff))
633 node_add_profile(gen, node, "network", net_uuid)
636 def add_route(gen, lustre, options):
637 """ create a node with a network config """
639 node_name = get_option(options, 'node')
640 gw_net_type = get_option(options, 'nettype')
641 gw = get_option(options, 'gw')
642 gw_cluster_id = get_option(options, 'gateway_cluster_id')
643 tgt_cluster_id = get_option(options, 'target_cluster_id')
644 lo = get_option(options, 'lo')
645 hi = get_option(options, 'hi')
649 node = findByName(lustre, node_name, "node")
651 error (node_name, " not found.")
653 rlist = node.getElementsByTagName('routetbl')
657 rtbl_name = new_name("RTBL_" + node_name)
658 rtbl_uuid = new_uuid(rtbl_name)
659 rtbl = gen.routetbl(rtbl_name, rtbl_uuid)
660 node.appendChild(rtbl)
661 node_add_profile(gen, node, "routetbl", rtbl_uuid)
662 rtbl.appendChild(gen.route(gw_net_type, gw, gw_cluster_id, tgt_cluster_id,
666 def add_mds(gen, lustre, options):
667 node_name = get_option(options, 'node')
668 mds_name = get_option(options, 'mds')
669 mdd_name = new_name("MDD_" + mds_name +"_" + node_name)
670 mdd_uuid = new_uuid(mdd_name)
672 mds_uuid = name2uuid(lustre, mds_name, 'mds', fatal=0)
674 mds_uuid = new_uuid(mds_name)
675 mds = gen.mds(mds_name, mds_uuid, mdd_uuid, options.group)
676 lustre.appendChild(mds)
678 mds = lookup(lustre, mds_uuid)
680 mds.setAttribute('failover', "1")
682 devname = get_option(options, 'dev')
683 size = get_option(options, 'size')
684 fstype = get_option(options, 'fstype')
685 journal_size = get_option(options, 'journal_size')
686 nspath = get_option(options, 'nspath')
687 mkfsoptions = get_option(options, 'mkfsoptions')
689 node_uuid = name2uuid(lustre, node_name, 'node')
691 node = findByName(lustre, node_name, "node")
692 node_add_profile(gen, node, "mdsdev", mdd_uuid)
693 net_uuid = get_net_uuid(lustre, node_name)
695 error("NODE: ", node_name, "not found")
697 mdd = gen.mdsdev(mdd_name, mdd_uuid, fstype, devname,
698 get_format_flag(options), node_uuid, mds_uuid,
699 size, journal_size, nspath, mkfsoptions)
700 lustre.appendChild(mdd)
703 def add_mgmt(gen, lustre, options):
704 node_name = get_option(options, 'node')
705 node_uuid = name2uuid(lustre, node_name, 'node')
706 mgmt_name = get_option(options, 'mgmt')
708 mgmt_name = new_name('MGMT_' + node_name)
709 mgmt_uuid = name2uuid(lustre, mgmt_name, 'mgmt', fatal=0)
711 mgmt_uuid = new_uuid(mgmt_name)
712 mgmt = gen.mgmt(mgmt_name, mgmt_uuid, node_uuid)
713 lustre.appendChild(mgmt)
715 mgmt = lookup(lustre, mgmt_uuid)
717 node = findByName(lustre, node_name, "node")
718 node_add_profile(gen, node, 'mgmt', mgmt_uuid)
720 def add_ost(gen, lustre, options):
721 node_name = get_option(options, 'node')
722 lovname = get_option(options, 'lov')
723 osdtype = get_option(options, 'osdtype')
725 node_uuid = name2uuid(lustre, node_name, 'node')
727 if osdtype == 'obdecho':
734 devname = get_option(options, 'dev') # can be unset for bluearcs
735 size = get_option(options, 'size')
736 fstype = get_option(options, 'fstype')
737 journal_size = get_option(options, 'journal_size')
739 nspath = get_option(options, 'nspath')
741 ostname = get_option(options, 'ost')
743 ostname = new_name('OST_'+ node_name)
745 osdname = new_name("OSD_" + ostname + "_" + node_name)
746 osd_uuid = new_uuid(osdname)
748 ost_uuid = name2uuid(lustre, ostname, 'ost', fatal=0)
750 ost_uuid = get_option(options, 'ostuuid')
752 if lookup(lustre, ost_uuid):
753 error("Duplicate OST UUID:", ost_uuid)
755 ost_uuid = new_uuid(ostname)
757 ost = gen.ost(ostname, ost_uuid, osd_uuid, options.group)
758 lustre.appendChild(ost)
760 lov = findByName(lustre, lovname, "lov")
762 error('add_ost:', '"'+lovname+'"', "lov element not found.")
763 lov_add_obd(gen, lov, ost_uuid)
765 ost = lookup(lustre, ost_uuid)
768 ost.setAttribute('failover', "1")
771 osd = gen.osd(osdname, osd_uuid, fstype, osdtype, devname,
772 get_format_flag(options), ost_uuid, node_uuid, size,
773 journal_size, nspath)
775 node = findByName(lustre, node_name, "node")
777 ## if node_add_profile(gen, node, 'oss', oss_uuid):
779 ## oss_uuid = new_uuid(ossname)
780 ## oss = gen.oss(ossname, oss_uuid)
781 ## lustre.appendChild(oss)
783 node_add_profile(gen, node, 'osd', osd_uuid)
784 lustre.appendChild(osd)
787 def add_cobd(gen, lustre, options):
788 node_name = get_option(options, 'node')
789 name = new_name('COBD_' + node_name)
790 uuid = new_uuid(name)
792 real_name = get_option(options, 'real_obd')
793 cache_name = get_option(options, 'cache_obd')
795 real_uuid = name2uuid(lustre, real_name, tag='obd')
796 cache_uuid = name2uuid(lustre, cache_name, tag='obd')
798 node = findByName(lustre, node_name, "node")
799 node_add_profile(gen, node, "cobd", uuid)
800 cobd = gen.cobd(name, uuid, real_uuid, cache_uuid)
801 lustre.appendChild(cobd)
804 def add_echo_client(gen, lustre, options):
805 """ add an echo client to the profile for this node. """
806 node_name = get_option(options, 'node')
807 lov_name = get_option(options, 'ost')
809 node = findByName(lustre, node_name, 'node')
811 echoname = new_name('ECHO_'+ node_name)
812 echo_uuid = new_uuid(echoname)
813 node_add_profile(gen, node, 'echoclient', echo_uuid)
815 lov_uuid = name2uuid(lustre, lov_name, tag='lov', fatal=0)
817 lov_uuid = name2uuid(lustre, lov_name, tag='ost', fatal=1)
819 echo = gen.echo_client(echoname, echo_uuid, lov_uuid)
820 lustre.appendChild(echo)
823 def add_lov(gen, lustre, options):
826 lov_orig = get_option(options, 'lov')
827 name = new_name(lov_orig)
829 warning("name:", lov_orig, "already used. using:", name)
831 mds_name = get_option(options, 'mds')
832 stripe_sz = get_option_int(options, 'stripe_sz')
833 stripe_cnt = get_option_int(options, 'stripe_cnt')
834 pattern = get_option_int(options, 'stripe_pattern')
835 uuid = new_uuid(name)
837 ret = findByName(lustre, name, "lov")
839 error("LOV: ", name, " already exists.")
841 mds_uuid = name2uuid(lustre, mds_name, 'mds')
842 lov = gen.lov(name, uuid, mds_uuid, stripe_sz, stripe_cnt, pattern)
843 lustre.appendChild(lov)
845 # add an lovconfig entry to the active mdsdev profile
846 lovconfig_name = new_name('LVCFG_' + name)
847 lovconfig_uuid = new_uuid(lovconfig_name)
848 mds = findByName(lustre, mds_name)
849 mds.appendChild(gen.ref("lovconfig", lovconfig_uuid))
850 lovconfig = gen.lovconfig(lovconfig_name, lovconfig_uuid, uuid)
851 lustre.appendChild(lovconfig)
853 def add_default_lov(gen, lustre, mds_name, lov_name):
854 """ create a default lov """
856 stripe_sz = DEFAULT_STRIPE_SZ
857 stripe_cnt = DEFAULT_STRIPE_CNT
858 pattern = DEFAULT_STRIPE_PATTERN
859 uuid = new_uuid(lov_name)
861 ret = findByName(lustre, lov_name, "lov")
863 error("LOV: ", lov_name, " already exists.")
865 mds_uuid = name2uuid(lustre, mds_name, 'mds')
866 lov = gen.lov(lov_name, uuid, mds_uuid, stripe_sz, stripe_cnt, pattern)
867 lustre.appendChild(lov)
869 # add an lovconfig entry to the active mdsdev profile
870 lovconfig_name = new_name('LVCFG_' + lov_name)
871 lovconfig_uuid = new_uuid(lovconfig_name)
872 mds = findByName(lustre, mds_name)
873 mds.appendChild(gen.ref("lovconfig", lovconfig_uuid))
874 lovconfig = gen.lovconfig(lovconfig_name, lovconfig_uuid, uuid)
875 lustre.appendChild(lovconfig)
877 def new_filesystem(gen, lustre, mds_uuid, obd_uuid, mgmt_uuid):
878 fs_name = new_name("FS_fsname")
879 fs_uuid = new_uuid(fs_name)
880 mds = lookup(lustre, mds_uuid)
881 mds.appendChild(gen.ref("filesystem", fs_uuid))
882 fs = gen.filesystem(fs_name, fs_uuid, mds_uuid, obd_uuid, mgmt_uuid)
883 lustre.appendChild(fs)
886 def get_fs_uuid(gen, lustre, mds_name, obd_name, mgmt_name):
887 mds_uuid = name2uuid(lustre, mds_name, tag='mds')
888 obd_uuid = name2uuid(lustre, obd_name, tag='lov', fatal=0)
890 mgmt_uuid = name2uuid(lustre, mgmt_name, tag='mgmt', fatal=1)
893 fs_uuid = lookup_filesystem(lustre, mds_uuid, obd_uuid)
895 fs_uuid = new_filesystem(gen, lustre, mds_uuid, obd_uuid, mgmt_uuid)
898 def add_mtpt(gen, lustre, options):
899 """ create mtpt on a node """
900 node_name = get_option(options, 'node')
902 path = get_option(options, 'path')
903 fs_name = get_option(options, 'filesystem')
905 lov_name = get_option(options, 'lov')
906 ost_name = get_option(options, 'ost')
907 mds_name = get_option(options, 'mds')
910 error("--add mtpt requires --lov lov_name or --ost ost_name")
912 warning("use default value for lov, due no --lov lov_name provided")
913 lov_name = new_name("lov_default")
914 add_default_lov(gen, lustre, mds_name, lov_name)
915 ost_uuid = name2uuid(lustre, ost_name, 'ost', fatal=0)
917 error('add_mtpt:', '"'+ost_name+'"', "ost element not found.")
918 lov = findByName(lustre, lov_name, "lov")
919 lov_add_obd(gen, lov, ost_uuid)
922 mgmt_name = get_option(options, 'mgmt')
923 fs_uuid = get_fs_uuid(gen, lustre, mds_name, lov_name, mgmt_name)
925 fs_uuid = name2uuid(lustre, fs_name, tag='filesystem')
927 name = new_name('MNT_'+ node_name)
929 ret = findByName(lustre, name, "mountpoint")
931 # this can't happen, because new_name creates unique names
932 error("MOUNTPOINT: ", name, " already exists.")
934 uuid = new_uuid(name)
935 mtpt = gen.mountpoint(name, uuid, fs_uuid, path)
936 node = findByName(lustre, node_name, "node")
938 error('node:', node_name, "not found.")
939 node_add_profile(gen, node, "mountpoint", uuid)
940 lustre.appendChild(mtpt)
942 ############################################################
943 # Command line processing
945 class OptionError (exceptions.Exception):
946 def __init__(self, args):
949 def get_option(options, tag):
950 """Look for tag in options hash and return the value if set. If not
951 set, then if return default it is set, otherwise exception."""
952 if options.__getattr__(tag) != None:
953 return options.__getattr__(tag)
955 raise OptionError("--add %s requires --%s <value>" % (options.add, tag))
957 def get_option_int(options, tag):
958 """Return an integer option. Raise exception if the value is not an int"""
959 val = get_option(options, tag)
963 raise OptionError("--%s <num> (value must be integer)" % (tag))
966 # simple class for profiling
973 self._start = time.time()
974 def stop(self, msg=''):
975 self._stop = time.time()
979 return self._stop - self._start
980 def display(self, msg):
982 str = '%s: %g secs' % (msg, d)
985 ############################################################
989 def add(devtype, gen, lustre, options):
991 add_net(gen, lustre, options)
992 elif devtype == 'mtpt':
993 add_mtpt(gen, lustre, options)
994 elif devtype == 'mds':
995 add_mds(gen, lustre, options)
996 elif devtype == 'ost':
997 add_ost(gen, lustre, options)
998 elif devtype == 'lov':
999 add_lov(gen, lustre, options)
1000 elif devtype == 'route':
1001 add_route(gen, lustre, options)
1002 elif devtype == 'node':
1003 add_node(gen, lustre, options)
1004 elif devtype == 'echo_client':
1005 add_echo_client(gen, lustre, options)
1006 elif devtype == 'cobd':
1007 add_cobd(gen, lustre, options)
1008 elif devtype == 'mgmt':
1009 add_mgmt(gen, lustre, options)
1011 error("unknown device type:", devtype)
1013 def do_command(gen, lustre, options, args):
1015 add(options.add, gen, lustre, options)
1017 error("Missing command")
1020 cl = Lustre.Options("lmc", "", lmc_options)
1022 options, args = cl.parse(sys.argv[1:])
1023 except Lustre.OptionError, e:
1027 panic(string.join(sys.argv), "Unexpected extra arguments on command line: " + string.join(args))
1029 if options.reference:
1036 outFile = options.merge
1037 if os.access(outFile, os.R_OK):
1038 doc = xml.dom.minidom.parse(outFile)
1040 doc = new_lustre(xml.dom.minidom)
1042 doc = xml.dom.minidom.parse(options.input)
1044 doc = new_lustre(xml.dom.minidom)
1047 outFile = options.output
1049 lustre = doc.documentElement
1051 if lustre.tagName != "lustre":
1052 print "Existing config not valid."
1055 gen = GenConfig(doc)
1057 # the PRNG is normally seeded with time(), which is not so good for starting # time-synchronized clusters
1058 input = open('/dev/urandom', 'r')
1060 print 'Unable to open /dev/urandom!'
1062 seed = input.read(32)
1067 fp = open(options.batch)
1068 batchCommands = fp.readlines()
1070 for cmd in batchCommands:
1072 options, args = cl.parse(string.split(cmd))
1073 do_command(gen, lustre, options, args)
1074 except OptionError, e:
1076 except Lustre.OptionError, e:
1080 do_command(gen, lustre, options, args)
1081 except OptionError, e:
1082 panic(string.join(sys.argv),e)
1083 except Lustre.OptionError, e:
1089 PrettyPrint(doc, open(outFile,"w"))
1091 if __name__ == "__main__":