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, re
29 import xml.dom.minidom
31 def printDoc(doc, stream=sys.stdout):
33 from xml.dom.ext import PrettyPrint
34 PrettyPrint(doc, stream)
36 stream.write(doc.toxml())
40 PYMOD_DIR = "/usr/lib/lustre/python"
42 def development_mode():
43 base = os.path.dirname(sys.argv[0])
44 if os.access(base+"/Makefile.am", os.R_OK):
48 if not development_mode():
49 sys.path.append(PYMOD_DIR)
54 DEFAULT_STRIPE_SZ = 1048576
55 DEFAULT_STRIPE_CNT = 1
56 DEFAULT_STRIPE_PATTERN = 0
60 print """usage: lmc --add object [object parameters]
62 Object creation command summary:
70 --ptldebug debug_level
71 --subsystem subsystem_name
77 --nettype tcp|elan|gm|openib|iib
78 --hostaddr ip[/netmask]
95 --mountfsoptions options
113 --osdtype obdecho|obdfilter
115 --mkfsoptions options
116 --mountfsoptions options
118 --add mtpt - Mountpoint
122 --ost ost_name OR --lov lov_name
123 --clientoptions options
129 --gateway_cluster_id nid
130 --target_cluster_id nid
137 --add mgmt - Management/monitoring service
139 --mgmt mgmt_service_name
142 PARAM = Lustre.Options.PARAM
143 PARAMLIST = Lustre.Options.PARAMLIST
145 # lmc input/output options
146 ('reference', "Print short reference for commands."),
147 ('verbose,v', "Print system commands as they are run."),
148 ('merge,m', "Append to the specified config file.", PARAM),
149 ('output,o', "Write XML configuration into given output file. Overwrite existing content.", PARAM),
150 ('input,i', "", PARAM),
151 ('batch', "Used to execute lmc commands in batch mode.", PARAM),
157 ('node', "Add a new node in the cluster configuration.", PARAM),
158 ('timeout', "Set timeout to initiate recovery.", PARAM),
159 ('upcall', "Set both lustre and portals upcall scripts.", PARAM),
160 ('lustre_upcall', "Set location of lustre upcall script.", PARAM),
161 ('portals_upcall', "Set location of portals upcall script.", PARAM),
162 ('ptldebug', "Set the portals debug level", PARAM),
163 ('subsystem', "Specify which Lustre subsystems have debug output recorded in the log", PARAM),
166 ('nettype', "Specify the network type. This can be tcp/elan/gm/openib/iib.", PARAM),
167 ('nid', "Give the network ID, e.g ElanID/IP Address as used by portals.", PARAM),
168 ('port', "Optional argument to specify the TCP port number.", PARAM, DEFAULT_PORT),
169 ('hostaddr', "Optional argument to specify the host address.", PARAMLIST),
170 ('cluster_id', "Specify the cluster ID", PARAM, "0"),
173 ('route', "Add a new route for the cluster.", PARAM),
174 ('router', "Optional flag to mark a node as router."),
175 ('gw', "Specify the nid of the gateway for a route.", PARAM),
176 ('gateway_cluster_id', "", PARAM, "0"),
177 ('target_cluster_id', "", PARAM, "0"),
178 ('lo', "For a range route, this is the low value nid.", PARAM),
179 ('hi', "For a range route, this is a hi value nid.", PARAM,""),
181 # servers: mds and ost
182 ('mds', "Specify MDS name.", PARAM),
183 ('ost', "Specify the OST name.", PARAM,""),
184 ('osdtype', "This could obdfilter or obdecho.", PARAM, "obdfilter"),
185 ('failover', "Enable failover support on OSTs or MDS?"),
186 ('group', "", PARAM),
187 ('dev', "Path of the device on local system.", PARAM,""),
188 ('size', "Specify the size of the device if needed.", PARAM,"0"),
189 ('journal_size', "Specify new journal size for underlying ext3 file system.", PARAM,"0"),
190 ('inode_size', "Specify new inode size for underlying ext3 file system.", PARAM,"0"),
191 ('fstype', "Optional argument to specify the filesystem type.", PARAM, "ext3"),
192 ('mkfsoptions', "Optional argument to mkfs.", PARAM, ""),
193 ('mountfsoptions', "Optional argument to mount fs.", PARAM, ""),
194 ('ostuuid', "Optional argument to specify OST UUID", PARAM,""),
195 ('mdsuuid', "Optional argument to specify MDS UUID", PARAM,""),
196 ('nspath', "Local mount point of server namespace.", PARAM,""),
199 # clients: mountpoint and echo
200 ('echo_client', "", PARAM),
201 ('path', "Specify the mountpoint for Lustre.", PARAM),
202 ('filesystem', "Lustre filesystem name", PARAM,""),
203 ('clientoptions', "Specify the options for Lustre, such as async.", PARAM, ""),
206 ('lov', "Specify LOV name.", PARAM,""),
207 ('stripe_sz', "Specify the stripe size in bytes.", PARAM),
208 ('stripe_cnt', "Specify the number of OSTs each file should be striped on.", PARAM, 0),
209 ('stripe_pattern', "Specify the stripe pattern. RAID 0 is the only one currently supported.", PARAM, 0),
212 ('real_obd', "", PARAM),
213 ('cache_obd', "", PARAM),
215 ('mgmt', "Specify management/monitoring service name.", PARAM, ""),
219 msg = string.join(map(str,args))
220 raise OptionError("Error: " + msg)
229 msg = string.join(map(str,args))
230 print "Warning: ", msg
233 # manage names and uuids
234 # need to initialize this by walking tree to ensure
235 # no duplicate names or uuids are created.
236 # this are just place holders for now.
237 # consider changing this to be like OBD-dev-host
241 while names.has_key(ret):
242 ret = "%s_%d" % (base, ctr)
249 ret = "%s_UUID" % (name)
250 if len(ret) > UUID_MAX_LENGTH:
251 ret = ret[-UUID_MAX_LENGTH:]
252 while uuids.has_key(ret):
253 ret = "%s_UUID_%d" % (name, ctr)
255 if len(ret) > UUID_MAX_LENGTH:
256 ret = ret[-UUID_MAX_LENGTH:]
262 ldlm_uuid = 'ldlm_UUID'
265 """Create a new empty lustre document"""
266 # adding ldlm here is a bit of a hack, but one is enough.
267 str = """<lustre version="%s">
268 <ldlm name="%s" uuid="%s"/>
269 </lustre>""" % (Lustre.CONFIG_VERSION, ldlm_name, ldlm_uuid)
270 return dom.parseString(str)
276 """initialize auto-name generation tables"""
278 # get all elements that contain a name attribute
279 for n in doc.childNodes:
280 if n.nodeType == n.ELEMENT_NODE:
282 names[getName(n)] = 1
283 uuids[getUUID(n)] = 1
286 def get_format_flag(options):
291 ############################################################
292 # Build config objects using DOM
297 def __init__(self, doc):
300 def ref(self, type, uuid):
301 """ generate <[type]_ref uuidref="[uuid]"/> """
302 tag = "%s_ref" % (type)
303 ref = self.doc.createElement(tag)
304 ref.setAttribute("uuidref", uuid)
307 def newService(self, tag, name, uuid):
308 """ create a new service elmement, which requires name and uuid attributes """
309 new = self.doc.createElement(tag)
310 new.setAttribute("uuid", uuid);
311 new.setAttribute("name", name);
314 def addText(self, node, str):
315 txt = self.doc.createTextNode(str)
316 node.appendChild(txt)
318 def addElement(self, node, tag, str=None):
319 """ create a new element and add it as a child to node. If str is passed,
320 a text node is created for the new element"""
321 new = self.doc.createElement(tag)
323 self.addText(new, str)
324 node.appendChild(new)
327 def network(self, name, uuid, nid, cluster_id, net, hostaddr="",
329 """create <network> node"""
330 network = self.newService("network", name, uuid)
331 network.setAttribute("nettype", net);
332 self.addElement(network, "nid", nid)
333 self.addElement(network, "clusterid", cluster_id)
334 for host in hostaddr:
335 self.addElement(network, "hostaddr", host)
337 self.addElement(network, "port", "%d" %(port))
341 def routetbl(self, name, uuid):
342 """create <routetbl> node"""
343 rtbl = self.newService("routetbl", name, uuid)
346 def route(self, gw_net_type, gw, gw_cluster_id, tgt_cluster_id, lo, hi):
347 """ create one entry for the route table """
348 ref = self.doc.createElement('route')
349 ref.setAttribute("type", gw_net_type)
350 ref.setAttribute("gw", gw)
351 ref.setAttribute("gwclusterid", gw_cluster_id)
352 ref.setAttribute("tgtclusterid", tgt_cluster_id)
353 ref.setAttribute("lo", lo)
355 ref.setAttribute("hi", hi)
358 def profile(self, name, uuid):
359 """ create a host """
360 profile = self.newService("profile", name, uuid)
363 def node(self, name, uuid, prof_uuid):
364 """ create a host """
365 node = self.newService("node", name, uuid)
366 node.appendChild(self.ref("profile", prof_uuid))
369 def ldlm(self, name, uuid):
370 """ create a ldlm """
371 ldlm = self.newService("ldlm", name, uuid)
374 def osd(self, name, uuid, fs, osdtype, devname, format, ost_uuid,
375 node_uuid, dev_size=0, journal_size=0, inode_size=0, nspath="",
376 mkfsoptions="", mountfsoptions=""):
377 osd = self.newService("osd", name, uuid)
378 osd.setAttribute('osdtype', osdtype)
379 osd.appendChild(self.ref("target", ost_uuid))
380 osd.appendChild(self.ref("node", node_uuid))
382 self.addElement(osd, "fstype", fs)
384 dev = self.addElement(osd, "devpath", devname)
385 self.addElement(osd, "autoformat", format)
387 self.addElement(osd, "devsize", "%s" % (dev_size))
389 self.addElement(osd, "journalsize", "%s" % (journal_size))
391 self.addElement(osd, "inodesize", "%s" % (inode_size))
393 self.addElement(osd, "mkfsoptions", mkfsoptions)
395 self.addElement(osd, "mountfsoptions", mountfsoptions)
397 self.addElement(osd, "nspath", nspath)
400 def cobd(self, name, uuid, real_uuid, cache_uuid):
401 cobd = self.newService("cobd", name, uuid)
402 cobd.appendChild(self.ref("realobd",real_uuid))
403 cobd.appendChild(self.ref("cacheobd",cache_uuid))
406 def ost(self, name, uuid, osd_uuid, group=""):
407 ost = self.newService("ost", name, uuid)
408 ost.appendChild(self.ref("active", osd_uuid))
410 self.addElement(ost, "group", group)
413 def oss(self, name, uuid):
414 oss = self.newService("oss", name, uuid)
417 def lov(self, name, uuid, mds_uuid, stripe_sz, stripe_cnt, pattern):
418 lov = self.newService("lov", name, uuid)
419 lov.appendChild(self.ref("mds", mds_uuid))
420 lov.setAttribute("stripesize", str(stripe_sz))
421 lov.setAttribute("stripecount", str(stripe_cnt))
422 lov.setAttribute("stripepattern", str(pattern))
425 def lovconfig(self, name, uuid, lov_uuid):
426 lovconfig = self.newService("lovconfig", name, uuid)
427 lovconfig.appendChild(self.ref("lov", lov_uuid))
430 def mds(self, name, uuid, mdd_uuid, group=""):
431 mds = self.newService("mds", name, uuid)
432 mds.appendChild(self.ref("active",mdd_uuid))
434 self.addElement(mds, "group", group)
437 def mdsdev(self, name, uuid, fs, devname, format, node_uuid,
438 mds_uuid, dev_size=0, journal_size=0, inode_size=256,
439 nspath="", mkfsoptions="", mountfsoptions=""):
440 mdd = self.newService("mdsdev", name, uuid)
441 self.addElement(mdd, "fstype", fs)
442 dev = self.addElement(mdd, "devpath", devname)
443 self.addElement(mdd, "autoformat", format)
445 self.addElement(mdd, "devsize", "%s" % (dev_size))
447 self.addElement(mdd, "journalsize", "%s" % (journal_size))
449 self.addElement(mdd, "inodesize", "%s" % (inode_size))
451 self.addElement(mdd, "nspath", nspath)
453 self.addElement(mdd, "mkfsoptions", mkfsoptions)
455 self.addElement(mdd, "mountfsoptions", mountfsoptions)
457 mdd.appendChild(self.ref("node", node_uuid))
458 mdd.appendChild(self.ref("target", mds_uuid))
461 def mgmt(self, mgmt_name, mgmt_uuid, node_uuid):
462 mgmt = self.newService("mgmt", mgmt_name, mgmt_uuid)
463 mgmt.appendChild(self.ref("node", node_uuid))
464 # Placeholder until mgmt-service failover.
465 mgmt.appendChild(self.ref("active", mgmt_uuid))
468 def mountpoint(self, name, uuid, fs_uuid, path, clientoptions):
469 mtpt = self.newService("mountpoint", name, uuid)
470 mtpt.appendChild(self.ref("filesystem", fs_uuid))
471 self.addElement(mtpt, "path", path)
473 self.addElement(mtpt, "clientoptions", clientoptions)
476 def filesystem(self, name, uuid, mds_uuid, obd_uuid, mgmt_uuid):
477 fs = self.newService("filesystem", name, uuid)
478 fs.appendChild(self.ref("mds", mds_uuid))
479 fs.appendChild(self.ref("obd", obd_uuid))
481 fs.appendChild(self.ref("mgmt", mgmt_uuid))
484 def echo_client(self, name, uuid, osc_uuid):
485 ec = self.newService("echoclient", name, uuid)
486 ec.appendChild(self.ref("obd", osc_uuid))
489 ############################################################
490 # Utilities to query a DOM tree
491 # Using this functions we can treat use config information
492 # directly as a database.
494 return n.getAttribute('name')
497 return node.getAttribute('uuid')
500 def findByName(lustre, name, tag = ""):
501 for n in lustre.childNodes:
502 if n.nodeType == n.ELEMENT_NODE:
503 if tag and n.nodeName != tag:
505 if getName(n) == name:
508 n = findByName(n, name)
513 def lookup(node, uuid):
514 for n in node.childNodes:
515 if n.nodeType == n.ELEMENT_NODE:
516 if getUUID(n) == uuid:
524 def name2uuid(lustre, name, tag="", fatal=1):
525 ret = findByName(lustre, name, tag)
528 error('name2uuid:', '"'+name+'"', tag, 'element not found.')
533 def lookup_filesystem(lustre, mds_uuid, ost_uuid):
534 for n in lustre.childNodes:
535 if n.nodeType == n.ELEMENT_NODE and n.nodeName == 'filesystem':
536 if ref_exists(n, mds_uuid) and ref_exists(n, ost_uuid):
540 # XXX: assumes only one network element per node. will fix this
541 # as soon as support for routers is added
542 def get_net_uuid(lustre, node_name):
543 """ get a network uuid for a node_name """
544 node = findByName(lustre, node_name, "node")
546 error ('get_net_uuid:', '"'+node_name+'"', "node element not found.")
547 net = node.getElementsByTagName('network')
549 return getUUID(net[0])
553 def lov_add_obd(gen, lov, osc_uuid):
554 lov.appendChild(gen.ref("obd", osc_uuid))
556 def ref_exists(profile, uuid):
557 elist = profile.childNodes
559 if e.nodeType == e.ELEMENT_NODE:
560 ref = e.getAttribute('uuidref')
565 # ensure that uuid is not already in the profile
566 # return true if uuid is added
567 def node_add_profile(gen, node, ref, uuid):
568 refname = "%s_ref" % "profile"
569 ret = node.getElementsByTagName(refname)
571 error('node has no profile ref:', node)
572 prof_uuid = ret[0].getAttribute('uuidref')
573 profile = lookup(node.parentNode, prof_uuid)
575 error("no profile found:", prof_uuid)
576 if ref_exists(profile, uuid):
578 profile.appendChild(gen.ref(ref, uuid))
581 def get_attr(dom_node, attr, default=""):
582 v = dom_node.getAttribute(attr)
587 ############################################################
590 def set_node_options(gen, node, options):
592 node.setAttribute('router', '1')
594 gen.addElement(node, "timeout", get_option(options, 'timeout'))
596 default_upcall = get_option(options, 'upcall')
599 if default_upcall or options.lustre_upcall:
600 if options.lustre_upcall:
601 gen.addElement(node, 'lustreUpcall', options.lustre_upcall)
603 gen.addElement(node, 'lustreUpcall', default_upcall)
604 if default_upcall or options.portals_upcall:
605 if options.portals_upcall:
606 gen.addElement(node, 'portalsUpcall', options.portals_upcall)
608 gen.addElement(node, 'portalsUpcall', default_upcall)
610 gen.addElement(node, "ptldebug", get_option(options, 'ptldebug'))
611 if options.subsystem:
612 gen.addElement(node, "subsystem", get_option(options, 'subsystem'))
615 def do_add_node(gen, lustre, options, node_name):
616 uuid = new_uuid(node_name)
617 prof_name = new_name("PROFILE_" + node_name)
618 prof_uuid = new_uuid(prof_name)
619 profile = gen.profile(prof_name, prof_uuid)
620 node = gen.node(node_name, uuid, prof_uuid)
621 lustre.appendChild(node)
622 lustre.appendChild(profile)
624 node_add_profile(gen, node, 'ldlm', ldlm_uuid)
625 set_node_options(gen, node, options)
629 def add_node(gen, lustre, options):
630 """ create a node with a network config """
632 node_name = get_option(options, 'node')
633 ret = findByName(lustre, node_name, "node")
635 print "Node:", node_name, "exists."
637 do_add_node(gen, lustre, options, node_name)
640 def add_net(gen, lustre, options):
641 """ create a node with a network config """
643 node_name = get_option(options, 'node')
644 nid = get_option(options, 'nid')
645 cluster_id = get_option(options, 'cluster_id')
646 hostaddr = get_option(options, 'hostaddr')
647 net_type = get_option(options, 'nettype')
649 if net_type in ('tcp',):
650 port = get_option_int(options, 'port')
651 elif net_type in ('elan', 'gm', 'openib','iib'):
654 print "Unknown net_type: ", net_type
657 ret = findByName(lustre, node_name, "node")
659 node = do_add_node(gen, lustre, options, node_name)
662 set_node_options(gen, node, options)
664 net_name = new_name('NET_'+ node_name +'_'+ net_type)
665 net_uuid = new_uuid(net_name)
666 node.appendChild(gen.network(net_name, net_uuid, nid, cluster_id, net_type,
668 node_add_profile(gen, node, "network", net_uuid)
671 def add_route(gen, lustre, options):
672 """ create a node with a network config """
674 node_name = get_option(options, 'node')
675 gw_net_type = get_option(options, 'nettype')
676 gw = get_option(options, 'gw')
677 gw_cluster_id = get_option(options, 'gateway_cluster_id')
678 tgt_cluster_id = get_option(options, 'target_cluster_id')
679 lo = get_option(options, 'lo')
680 hi = get_option(options, 'hi')
684 node = findByName(lustre, node_name, "node")
686 error (node_name, " not found.")
688 rlist = node.getElementsByTagName('routetbl')
692 rtbl_name = new_name("RTBL_" + node_name)
693 rtbl_uuid = new_uuid(rtbl_name)
694 rtbl = gen.routetbl(rtbl_name, rtbl_uuid)
695 node.appendChild(rtbl)
696 node_add_profile(gen, node, "routetbl", rtbl_uuid)
697 rtbl.appendChild(gen.route(gw_net_type, gw, gw_cluster_id, tgt_cluster_id,
701 def add_mds(gen, lustre, options):
702 node_name = get_option(options, 'node')
703 mds_name = get_option(options, 'mds')
704 mdd_name = new_name("MDD_" + mds_name +"_" + node_name)
705 mdd_uuid = new_uuid(mdd_name)
707 mds_uuid = name2uuid(lustre, mds_name, 'mds', fatal=0)
709 mds_uuid = get_option(options, 'mdsuuid')
711 if lookup(lustre, mds_uuid):
712 error("Duplicate MDS UUID:", mds_uuid)
714 mds_uuid = new_uuid(mds_name)
716 mds = gen.mds(mds_name, mds_uuid, mdd_uuid, options.group)
717 lustre.appendChild(mds)
719 mds = lookup(lustre, mds_uuid)
721 mds.setAttribute('failover', "1")
723 devname = get_option(options, 'dev')
724 size = get_option(options, 'size')
725 fstype = get_option(options, 'fstype')
726 journal_size = get_option(options, 'journal_size')
727 inode_size = get_option(options, 'inode_size')
728 nspath = get_option(options, 'nspath')
729 mkfsoptions = get_option(options, 'mkfsoptions')
730 mountfsoptions = get_option(options, 'mountfsoptions')
732 node_uuid = name2uuid(lustre, node_name, 'node')
734 node = findByName(lustre, node_name, "node")
735 node_add_profile(gen, node, "mdsdev", mdd_uuid)
736 net_uuid = get_net_uuid(lustre, node_name)
738 error("NODE: ", node_name, "not found")
740 mdd = gen.mdsdev(mdd_name, mdd_uuid, fstype, devname,
741 get_format_flag(options), node_uuid, mds_uuid,
742 size, journal_size, inode_size, nspath, mkfsoptions,
744 lustre.appendChild(mdd)
747 def add_mgmt(gen, lustre, options):
748 node_name = get_option(options, 'node')
749 node_uuid = name2uuid(lustre, node_name, 'node')
750 mgmt_name = get_option(options, 'mgmt')
752 mgmt_name = new_name('MGMT_' + node_name)
753 mgmt_uuid = name2uuid(lustre, mgmt_name, 'mgmt', fatal=0)
755 mgmt_uuid = new_uuid(mgmt_name)
756 mgmt = gen.mgmt(mgmt_name, mgmt_uuid, node_uuid)
757 lustre.appendChild(mgmt)
759 mgmt = lookup(lustre, mgmt_uuid)
761 node = findByName(lustre, node_name, "node")
762 node_add_profile(gen, node, 'mgmt', mgmt_uuid)
764 def add_ost(gen, lustre, options):
765 node_name = get_option(options, 'node')
766 lovname = get_option(options, 'lov')
767 osdtype = get_option(options, 'osdtype')
769 node_uuid = name2uuid(lustre, node_name, 'node')
771 if osdtype == 'obdecho':
781 devname = get_option(options, 'dev') # can be unset for bluearcs
782 size = get_option(options, 'size')
783 fstype = get_option(options, 'fstype')
784 journal_size = get_option(options, 'journal_size')
785 inode_size = get_option(options, 'inode_size')
786 mkfsoptions = get_option(options, 'mkfsoptions')
787 mountfsoptions = get_option(options, 'mountfsoptions')
789 nspath = get_option(options, 'nspath')
791 ostname = get_option(options, 'ost')
793 ostname = new_name('OST_'+ node_name)
795 osdname = new_name("OSD_" + ostname + "_" + node_name)
796 osd_uuid = new_uuid(osdname)
798 ost_uuid = name2uuid(lustre, ostname, 'ost', fatal=0)
800 ost_uuid = get_option(options, 'ostuuid')
802 if lookup(lustre, ost_uuid):
803 error("Duplicate OST UUID:", ost_uuid)
805 ost_uuid = new_uuid(ostname)
807 ost = gen.ost(ostname, ost_uuid, osd_uuid, options.group)
808 lustre.appendChild(ost)
810 lov = findByName(lustre, lovname, "lov")
812 error('add_ost:', '"'+lovname+'"', "lov element not found.")
813 lov_add_obd(gen, lov, ost_uuid)
815 ost = lookup(lustre, ost_uuid)
818 ost.setAttribute('failover', "1")
821 osd = gen.osd(osdname, osd_uuid, fstype, osdtype, devname,
822 get_format_flag(options), ost_uuid, node_uuid, size,
823 journal_size, inode_size, nspath, mkfsoptions,
826 node = findByName(lustre, node_name, "node")
828 ## if node_add_profile(gen, node, 'oss', oss_uuid):
830 ## oss_uuid = new_uuid(ossname)
831 ## oss = gen.oss(ossname, oss_uuid)
832 ## lustre.appendChild(oss)
834 node_add_profile(gen, node, 'osd', osd_uuid)
835 lustre.appendChild(osd)
838 def add_cobd(gen, lustre, options):
839 node_name = get_option(options, 'node')
840 name = new_name('COBD_' + node_name)
841 uuid = new_uuid(name)
843 real_name = get_option(options, 'real_obd')
844 cache_name = get_option(options, 'cache_obd')
846 real_uuid = name2uuid(lustre, real_name, tag='obd')
847 cache_uuid = name2uuid(lustre, cache_name, tag='obd')
849 node = findByName(lustre, node_name, "node")
850 node_add_profile(gen, node, "cobd", uuid)
851 cobd = gen.cobd(name, uuid, real_uuid, cache_uuid)
852 lustre.appendChild(cobd)
855 def add_echo_client(gen, lustre, options):
856 """ add an echo client to the profile for this node. """
857 node_name = get_option(options, 'node')
858 lov_name = get_option(options, 'ost')
860 node = findByName(lustre, node_name, 'node')
862 echoname = new_name('ECHO_'+ node_name)
863 echo_uuid = new_uuid(echoname)
864 node_add_profile(gen, node, 'echoclient', echo_uuid)
866 lov_uuid = name2uuid(lustre, lov_name, tag='lov', fatal=0)
868 lov_uuid = name2uuid(lustre, lov_name, tag='ost', fatal=1)
870 echo = gen.echo_client(echoname, echo_uuid, lov_uuid)
871 lustre.appendChild(echo)
874 def add_lov(gen, lustre, options):
877 lov_orig = get_option(options, 'lov')
878 name = new_name(lov_orig)
880 warning("name:", lov_orig, "already used. using:", name)
882 mds_name = get_option(options, 'mds')
883 stripe_sz = get_option_int(options, 'stripe_sz')
884 stripe_cnt = get_option_int(options, 'stripe_cnt')
885 pattern = get_option_int(options, 'stripe_pattern')
886 uuid = new_uuid(name)
888 ret = findByName(lustre, name, "lov")
890 error("LOV: ", name, " already exists.")
892 mds_uuid = name2uuid(lustre, mds_name, 'mds')
893 lov = gen.lov(name, uuid, mds_uuid, stripe_sz, stripe_cnt, pattern)
894 lustre.appendChild(lov)
896 # add an lovconfig entry to the active mdsdev profile
897 lovconfig_name = new_name('LVCFG_' + name)
898 lovconfig_uuid = new_uuid(lovconfig_name)
899 mds = findByName(lustre, mds_name, "mds")
900 mds.appendChild(gen.ref("lovconfig", lovconfig_uuid))
901 lovconfig = gen.lovconfig(lovconfig_name, lovconfig_uuid, uuid)
902 lustre.appendChild(lovconfig)
904 def add_default_lov(gen, lustre, mds_name, lov_name):
905 """ create a default lov """
907 stripe_sz = DEFAULT_STRIPE_SZ
908 stripe_cnt = DEFAULT_STRIPE_CNT
909 pattern = DEFAULT_STRIPE_PATTERN
910 uuid = new_uuid(lov_name)
912 ret = findByName(lustre, lov_name, "lov")
914 error("LOV: ", lov_name, " already exists.")
916 mds_uuid = name2uuid(lustre, mds_name, 'mds')
917 lov = gen.lov(lov_name, uuid, mds_uuid, stripe_sz, stripe_cnt, pattern)
918 lustre.appendChild(lov)
920 # add an lovconfig entry to the active mdsdev profile
921 lovconfig_name = new_name('LVCFG_' + lov_name)
922 lovconfig_uuid = new_uuid(lovconfig_name)
923 mds = findByName(lustre, mds_name)
924 mds.appendChild(gen.ref("lovconfig", lovconfig_uuid))
925 lovconfig = gen.lovconfig(lovconfig_name, lovconfig_uuid, uuid)
926 lustre.appendChild(lovconfig)
928 def new_filesystem(gen, lustre, mds_uuid, obd_uuid, mgmt_uuid):
929 fs_name = new_name("FS_fsname")
930 fs_uuid = new_uuid(fs_name)
931 mds = lookup(lustre, mds_uuid)
932 mds.appendChild(gen.ref("filesystem", fs_uuid))
933 fs = gen.filesystem(fs_name, fs_uuid, mds_uuid, obd_uuid, mgmt_uuid)
934 lustre.appendChild(fs)
937 def get_fs_uuid(gen, lustre, mds_name, obd_name, mgmt_name):
938 mds_uuid = name2uuid(lustre, mds_name, tag='mds')
939 obd_uuid = name2uuid(lustre, obd_name, tag='lov', fatal=0)
941 mgmt_uuid = name2uuid(lustre, mgmt_name, tag='mgmt', fatal=1)
944 fs_uuid = lookup_filesystem(lustre, mds_uuid, obd_uuid)
946 fs_uuid = new_filesystem(gen, lustre, mds_uuid, obd_uuid, mgmt_uuid)
949 def add_mtpt(gen, lustre, options):
950 """ create mtpt on a node """
951 node_name = get_option(options, 'node')
953 path = get_option(options, 'path')
954 clientoptions = get_option(options, "clientoptions")
955 fs_name = get_option(options, 'filesystem')
957 lov_name = get_option(options, 'lov')
958 ost_name = get_option(options, 'ost')
959 mds_name = get_option(options, 'mds')
962 error("--add mtpt requires --lov lov_name or --ost ost_name")
964 warning("use default value for lov, due no --lov lov_name provided")
965 lov_name = new_name("lov_default")
966 add_default_lov(gen, lustre, mds_name, lov_name)
967 ost_uuid = name2uuid(lustre, ost_name, 'ost', fatal=0)
969 error('add_mtpt:', '"'+ost_name+'"', "ost element not found.")
970 lov = findByName(lustre, lov_name, "lov")
971 lov_add_obd(gen, lov, ost_uuid)
974 mgmt_name = get_option(options, 'mgmt')
975 fs_uuid = get_fs_uuid(gen, lustre, mds_name, lov_name, mgmt_name)
977 fs_uuid = name2uuid(lustre, fs_name, tag='filesystem')
979 name = new_name('MNT_'+ node_name)
981 ret = findByName(lustre, name, "mountpoint")
983 # this can't happen, because new_name creates unique names
984 error("MOUNTPOINT: ", name, " already exists.")
986 uuid = new_uuid(name)
987 mtpt = gen.mountpoint(name, uuid, fs_uuid, path, clientoptions)
988 node = findByName(lustre, node_name, "node")
990 error('node:', node_name, "not found.")
991 node_add_profile(gen, node, "mountpoint", uuid)
992 lustre.appendChild(mtpt)
994 ############################################################
995 # Command line processing
997 class OptionError (exceptions.Exception):
998 def __init__(self, args):
1001 def get_option(options, tag):
1002 """Look for tag in options hash and return the value if set. If not
1003 set, then if return default it is set, otherwise exception."""
1004 if options.__getattr__(tag) != None:
1005 return options.__getattr__(tag)
1007 raise OptionError("--add %s requires --%s <value>" % (options.add, tag))
1009 def get_option_int(options, tag):
1010 """Return an integer option. Raise exception if the value is not an int"""
1011 val = get_option(options, tag)
1015 raise OptionError("--%s <num> (value must be integer)" % (tag))
1018 # simple class for profiling
1025 self._start = time.time()
1026 def stop(self, msg=''):
1027 self._stop = time.time()
1031 return self._stop - self._start
1032 def display(self, msg):
1034 str = '%s: %g secs' % (msg, d)
1037 #################################################################
1038 # function cmdlinesplit used to split cmd line from batch file
1040 def cmdlinesplit(cmdline):
1042 double_quote = re.compile(r'"(([^"\\]|\\.)*)"')
1043 single_quote = re.compile(r"'(.*?)'")
1044 escaped = re.compile(r'\\(.)')
1045 esc_quote = re.compile(r'\\([\\"])')
1046 outside = re.compile(r"""([^\s\\'"]+)""")
1050 while i < len(cmdline):
1053 match = double_quote.match(cmdline, i)
1055 print "Unmatched double quote:", cmdline
1058 if arg is None: arg = esc_quote.sub(r'\1', match.group(1))
1059 else: arg = arg + esc_quote.sub(r'\1', match.group(1))
1062 match = single_quote.match(cmdline, i)
1064 print "Unmatched single quote:", cmdline
1067 if arg is None: arg = match.group(1)
1068 else: arg = arg + match.group(1)
1071 match = escaped.match(cmdline, i)
1073 print "Unmatched backslash", cmdline
1076 if arg is None: arg = match.group(1)
1077 else: arg = arg + match.group(1)
1079 elif c in string.whitespace:
1081 arg_list.append(str(arg))
1083 while i < len(cmdline) and cmdline[i] in string.whitespace:
1086 match = outside.match(cmdline, i)
1089 if arg is None: arg = match.group()
1090 else: arg = arg + match.group()
1092 if arg != None: arg_list.append(str(arg))
1096 ############################################################
1100 def add(devtype, gen, lustre, options):
1101 if devtype == 'net':
1102 add_net(gen, lustre, options)
1103 elif devtype == 'mtpt':
1104 add_mtpt(gen, lustre, options)
1105 elif devtype == 'mds':
1106 add_mds(gen, lustre, options)
1107 elif devtype == 'ost':
1108 add_ost(gen, lustre, options)
1109 elif devtype == 'lov':
1110 add_lov(gen, lustre, options)
1111 elif devtype == 'route':
1112 add_route(gen, lustre, options)
1113 elif devtype == 'node':
1114 add_node(gen, lustre, options)
1115 elif devtype == 'echo_client':
1116 add_echo_client(gen, lustre, options)
1117 elif devtype == 'cobd':
1118 add_cobd(gen, lustre, options)
1119 elif devtype == 'mgmt':
1120 add_mgmt(gen, lustre, options)
1122 error("unknown device type:", devtype)
1124 def do_command(gen, lustre, options, args):
1126 add(options.add, gen, lustre, options)
1128 error("Missing command")
1131 cl = Lustre.Options("lmc", "", lmc_options)
1133 options, args = cl.parse(sys.argv[1:])
1134 except Lustre.OptionError, e:
1138 panic(string.join(sys.argv), "Unexpected extra arguments on command line: " + string.join(args))
1140 if options.reference:
1147 outFile = options.merge
1148 if os.access(outFile, os.R_OK):
1149 doc = xml.dom.minidom.parse(outFile)
1151 doc = new_lustre(xml.dom.minidom)
1153 doc = xml.dom.minidom.parse(options.input)
1155 doc = new_lustre(xml.dom.minidom)
1158 outFile = options.output
1160 lustre = doc.documentElement
1162 if lustre.tagName != "lustre":
1163 print "Existing config not valid."
1166 gen = GenConfig(doc)
1169 fp = open(options.batch)
1170 batchCommands = fp.readlines()
1172 for cmd in batchCommands:
1174 options, args = cl.parse(cmdlinesplit(cmd))
1175 if options.merge or options.input or options.output:
1176 print "The batchfile should not contain --merge, --input or --output."
1178 do_command(gen, lustre, options, args)
1179 except OptionError, e:
1181 except Lustre.OptionError, e:
1185 do_command(gen, lustre, options, args)
1186 except OptionError, e:
1187 panic(string.join(sys.argv),e)
1188 except Lustre.OptionError, e:
1194 printDoc(doc, open(outFile,"w"))
1196 if __name__ == "__main__":