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
91 --backfstype ldiskfs|ext3|tmpfs
98 --mountfsoptions options
117 --fstype ldiskfs|ext3
118 --backfstype ldiskfs|ext3|tmpfs
121 --osdtype obdecho|obdfilter
123 --mkfsoptions options
124 --mountfsoptions options
134 --add mtpt - Mountpoint
139 --ost ost_name OR --lov lov_name
145 --gateway_cluster_id nid
146 --target_cluster_id nid
153 --add mgmt - Management/monitoring service
155 --mgmt mgmt_service_name
165 --commit - Close a configuration version, and start a new one
168 PARAM = Lustre.Options.PARAM
170 # lmc input/output options
171 ('reference', "Print short reference for commands."),
172 ('verbose,v', "Print system commands as they are run."),
173 ('merge,m', "Append to the specified config file.", PARAM),
174 ('output,o', "Write XML configuration into given output file. Overwrite existing content.", PARAM),
175 ('input,i', "", PARAM),
176 ('batch', "Used to execute lmc commands in batch mode.", PARAM),
180 ('delete', "", PARAM),
181 ('deactivate', "", PARAM),
182 ('commit', "Commit all config changes and start a new version"),
185 ('node', "Add a new node in the cluster configuration.", PARAM),
186 ('timeout', "Set timeout to initiate recovery.", PARAM),
187 ('upcall', "Set both lustre and portals upcall scripts.", PARAM),
188 ('lustre_upcall', "Set location of lustre upcall script.", PARAM),
189 ('portals_upcall', "Set location of portals upcall script.", PARAM),
190 ('ptldebug', "Set the portals debug level", PARAM),
191 ('subsystem', "Specify which Lustre subsystems have debug output recorded in the log", PARAM),
194 ('nettype', "Specify the network type. This can be tcp/elan/gm.", PARAM),
195 ('nid', "Give the network ID, e.g ElanID/IP Address as used by portals.", PARAM),
196 ('tcpbuf', "Optional argument to specify the TCP buffer size.", PARAM, "0"),
197 ('port', "Optional argument to specify the TCP port number.", PARAM, DEFAULT_PORT),
198 ('irq_affinity', "Optional argument.", PARAM, 0),
199 ('hostaddr', "", PARAM,""),
200 ('cluster_id', "Specify the cluster ID", PARAM, "0"),
203 ('route', "Add a new route for the cluster.", PARAM),
204 ('router', "Optional flag to mark a node as router."),
205 ('gw', "Specify the nid of the gateway for a route.", PARAM),
206 ('gateway_cluster_id', "", PARAM, "0"),
207 ('target_cluster_id', "", PARAM, "0"),
208 ('lo', "For a range route, this is the low value nid.", PARAM),
209 ('hi', "For a range route, this is a hi value nid.", PARAM,""),
211 # servers: mds and ost
212 ('mds', "Specify MDS name.", PARAM,""),
213 ('ost', "Specify the OST name.", PARAM,""),
214 ('osdtype', "This could obdfilter or obdecho.", PARAM, "obdfilter"),
215 ('failover', "Enable failover support on OSTs or MDS?"),
216 ('group', "", PARAM),
217 ('dev', "Path of the device on local system.", PARAM,""),
218 ('backdev', "Path of the device for backing storage on local system.", PARAM,""),
219 ('size', "Specify the size of the device if needed.", PARAM,"0"),
220 ('journal_size', "Specify new journal size for underlying file system.", PARAM,"0"),
221 ('inode_size', "Specify new inode size for underlying file system.", PARAM,"0"),
222 ('fstype', "Optional argument to specify the filesystem type.", PARAM, "ext3"),
223 ('backfstype', "Optional argument to specify the backing filesystem type.", PARAM, "ext3"),
224 ('mkfsoptions', "Optional argument to mkfs.", PARAM, ""),
225 ('mountfsoptions', "Optional argument to mount fs.", PARAM, ""),
226 ('ostuuid', "", PARAM,""),
227 ('nspath', "Local mount point of server namespace.", PARAM,""),
230 # clients: mountpoint and echo
231 ('echo_client', "", PARAM),
232 ('path', "Specify the mountpoint for Lustre.", PARAM),
233 ('filesystem', "Lustre filesystem name", PARAM,""),
236 ('lov', "Specify LOV name.", PARAM,""),
237 ('index', "Specify index for OBD in LOV target table.", PARAM),
238 ('stripe_sz', "Specify the stripe size in bytes.", PARAM),
239 ('stripe_cnt', "Specify the number of OSTs each file should be striped on.", PARAM, 0),
240 ('stripe_pattern', "Specify the stripe pattern. RAID 0 is the only one currently supported.", PARAM, 0),
244 ('real_obd', "Specify the real device for the cache obd system.", PARAM),
245 ('cache_obd', "Specify the cache device for the cache obd system.", PARAM),
246 ('cobd', "Specify COBD name", PARAM),
248 ('mgmt', "Specify management/monitoring service name.", PARAM, ""),
251 ('lmv', "Specify LMV name.", PARAM,""),
255 msg = string.join(map(str,args))
256 raise OptionError("Error: " + msg)
265 msg = string.join(map(str,args))
266 print "Warning: ", msg
269 # manage names and uuids
270 # need to initialize this by walking tree to ensure
271 # no duplicate names or uuids are created.
272 # this are just place holders for now.
273 # consider changing this to be like OBD-dev-host
277 while names.has_key(ret):
278 ret = "%s_%d" % (base, ctr)
285 ret = "%s_UUID" % (name)
286 if len(ret) > UUID_MAX_LENGTH:
287 ret = ret[-UUID_MAX_LENGTH:]
288 while uuids.has_key(ret):
289 ret = "%s_UUID_%d" % (name, ctr)
291 if len(ret) > UUID_MAX_LENGTH:
292 ret = ret[-UUID_MAX_LENGTH:]
298 ldlm_uuid = 'ldlm_UUID'
301 """Create a new empty lustre document"""
302 # adding ldlm here is a bit of a hack, but one is enough.
303 str = """<lustre version="%s">
304 <ldlm name="%s" uuid="%s"/>
305 </lustre>""" % (Lustre.CONFIG_VERSION, ldlm_name, ldlm_uuid)
306 return dom.parseString(str)
312 """initialize auto-name generation tables"""
314 # get all elements that contain a name attribute
315 for n in doc.childNodes:
316 if n.nodeType == n.ELEMENT_NODE:
318 names[getName(n)] = 1
319 uuids[getUUID(n)] = 1
322 def get_format_flag(options):
327 ############################################################
328 # Build config objects using DOM
333 def __init__(self, doc):
336 def ref(self, type, uuid):
337 """ generate <[type]_ref uuidref="[uuid]"/> """
338 tag = "%s_ref" % (type)
339 ref = self.doc.createElement(tag)
340 ref.setAttribute("uuidref", uuid)
343 def newService(self, tag, name, uuid):
344 """ create a new service elmement, which requires name and uuid attributes """
345 new = self.doc.createElement(tag)
346 new.setAttribute("uuid", uuid);
347 new.setAttribute("name", name);
350 def addText(self, node, str):
351 txt = self.doc.createTextNode(str)
352 node.appendChild(txt)
354 def addElement(self, node, tag, str=None):
355 """ create a new element and add it as a child to node. If str is passed,
356 a text node is created for the new element"""
357 new = self.doc.createElement(tag)
359 self.addText(new, str)
360 node.appendChild(new)
363 def network(self, name, uuid, nid, cluster_id, net, hostaddr="",
364 port=0, tcpbuf=0, irq_aff=0):
365 """create <network> node"""
366 network = self.newService("network", name, uuid)
367 network.setAttribute("nettype", net);
368 self.addElement(network, "nid", nid)
369 self.addElement(network, "clusterid", cluster_id)
371 self.addElement(network, "hostaddr", hostaddr)
373 self.addElement(network, "port", "%d" %(port))
375 self.addElement(network, "sendmem", "%d" %(tcpbuf))
376 self.addElement(network, "recvmem", "%d" %(tcpbuf))
378 self.addElement(network, "irqaffinity", "%d" %(irq_aff))
382 def routetbl(self, name, uuid):
383 """create <routetbl> node"""
384 rtbl = self.newService("routetbl", name, uuid)
387 def route(self, gw_net_type, gw, gw_cluster_id, tgt_cluster_id, lo, hi):
388 """ create one entry for the route table """
389 ref = self.doc.createElement('route')
390 ref.setAttribute("type", gw_net_type)
391 ref.setAttribute("gw", gw)
392 ref.setAttribute("gwclusterid", gw_cluster_id)
393 ref.setAttribute("tgtclusterid", tgt_cluster_id)
394 ref.setAttribute("lo", lo)
396 ref.setAttribute("hi", hi)
399 def profile(self, name, uuid):
400 """ create a host """
401 profile = self.newService("profile", name, uuid)
404 def node(self, name, uuid, prof_uuid):
405 """ create a host """
406 node = self.newService("node", name, uuid)
407 node.appendChild(self.ref("profile", prof_uuid))
410 def ldlm(self, name, uuid):
411 """ create a ldlm """
412 ldlm = self.newService("ldlm", name, uuid)
415 def osd(self, name, uuid, fstype, osdtype, devname, format, ost_uuid,
416 node_uuid, dev_size=0, journal_size=0, inode_size=0, nspath="",
417 mkfsoptions="", mountfsoptions="", backfstype="", backdevname=""):
418 osd = self.newService("osd", name, uuid)
419 osd.setAttribute('osdtype', osdtype)
420 osd.appendChild(self.ref("target", ost_uuid))
421 osd.appendChild(self.ref("node", node_uuid))
423 self.addElement(osd, "fstype", fstype)
425 self.addElement(osd, "backfstype", backfstype)
427 self.addElement(osd, "backdevpath", backdevname)
429 dev = self.addElement(osd, "devpath", devname)
430 self.addElement(osd, "autoformat", format)
432 self.addElement(osd, "devsize", "%s" % (dev_size))
434 self.addElement(osd, "journalsize", "%s" % (journal_size))
436 self.addElement(osd, "inodesize", "%s" % (inode_size))
438 self.addElement(osd, "mkfsoptions", mkfsoptions)
440 self.addElement(osd, "mountfsoptions", mountfsoptions)
442 self.addElement(osd, "nspath", nspath)
445 def cobd(self, name, uuid, real_uuid, cache_uuid):
446 cobd = self.newService("cobd", name, uuid)
447 cobd.appendChild(self.ref("realobd",real_uuid))
448 cobd.appendChild(self.ref("cacheobd",cache_uuid))
451 def ost(self, name, uuid, osd_uuid, group=""):
452 ost = self.newService("ost", name, uuid)
453 ost.appendChild(self.ref("active", osd_uuid))
455 self.addElement(ost, "group", group)
458 def oss(self, name, uuid):
459 oss = self.newService("oss", name, uuid)
462 def lov(self, name, uuid, mds_uuid, stripe_sz, stripe_cnt, pattern):
463 lov = self.newService("lov", name, uuid)
464 lov.appendChild(self.ref("mds", mds_uuid))
465 lov.setAttribute("stripesize", str(stripe_sz))
466 lov.setAttribute("stripecount", str(stripe_cnt))
467 lov.setAttribute("stripepattern", str(pattern))
470 def lov_tgt(self, obd_uuid, index, generation):
471 tgt = self.doc.createElement('lov_tgt')
472 tgt.setAttribute("uuidref", obd_uuid)
473 tgt.setAttribute("index", index)
474 tgt.setAttribute("generation", generation)
475 tgt.setAttribute("active", '1')
478 def lovconfig(self, name, uuid, lov_uuid):
479 lovconfig = self.newService("lovconfig", name, uuid)
480 lovconfig.appendChild(self.ref("lov", lov_uuid))
483 def lmv(self, name, uuid):
484 lmv = self.newService("lmv", name, uuid)
487 def mds(self, name, uuid, mdd_uuid, group="", lmv=""):
488 mds = self.newService("mds", name, uuid)
489 mds.appendChild(self.ref("active",mdd_uuid))
491 self.addElement(mds, "group", group)
494 def mdsdev(self, name, uuid, fstype, devname, format, node_uuid,
495 mds_uuid, dev_size=0, journal_size=0, inode_size=256,
496 nspath="", mkfsoptions="", mountfsoptions="", backfstype="",
497 backdevname="", lmv_uuid=""):
498 mdd = self.newService("mdsdev", name, uuid)
499 self.addElement(mdd, "fstype", fstype)
501 self.addElement(mdd, "backfstype", backfstype)
502 dev = self.addElement(mdd, "devpath", devname)
504 self.addElement(mdd, "backdevpath", backdevname)
505 self.addElement(mdd, "autoformat", format)
507 self.addElement(mdd, "devsize", "%s" % (dev_size))
509 self.addElement(mdd, "journalsize", "%s" % (journal_size))
511 self.addElement(mdd, "inodesize", "%s" % (inode_size))
513 self.addElement(mdd, "nspath", nspath)
515 self.addElement(mdd, "mkfsoptions", mkfsoptions)
517 self.addElement(mdd, "mountfsoptions", mountfsoptions)
519 mdd.appendChild(self.ref("node", node_uuid))
520 mdd.appendChild(self.ref("target", mds_uuid))
522 mdd.appendChild(self.ref("lmv", lmv_uuid))
523 self.addElement(mdd, "lmv", lmv_uuid)
527 def mgmt(self, mgmt_name, mgmt_uuid, node_uuid):
528 mgmt = self.newService("mgmt", mgmt_name, mgmt_uuid)
529 mgmt.appendChild(self.ref("node", node_uuid))
530 # Placeholder until mgmt-service failover.
531 mgmt.appendChild(self.ref("active", mgmt_uuid))
534 def mountpoint(self, name, uuid, fs_uuid, path):
535 mtpt = self.newService("mountpoint", name, uuid)
536 mtpt.appendChild(self.ref("filesystem", fs_uuid))
537 self.addElement(mtpt, "path", path)
540 def filesystem(self, name, uuid, mds_uuid, obd_uuid, mgmt_uuid):
541 fs = self.newService("filesystem", name, uuid)
542 fs.appendChild(self.ref("mds", mds_uuid))
543 fs.appendChild(self.ref("obd", obd_uuid))
545 fs.appendChild(self.ref("mgmt", mgmt_uuid))
548 def echo_client(self, name, uuid, osc_uuid):
549 ec = self.newService("echoclient", name, uuid)
550 ec.appendChild(self.ref("obd", osc_uuid))
553 def update(self, version):
554 new = self.doc.createElement("update")
555 new.setAttribute("version", version)
558 def add(self, lov, ost, index, gen):
559 new = self.doc.createElement("add")
560 new.setAttribute("lov_uuidref", lov)
561 new.setAttribute("ost_uuidref", ost)
562 new.setAttribute("index", index)
563 new.setAttribute("generation", gen)
566 def delete(self, lov, ost, index, gen, options):
568 new = self.doc.createElement("delete")
570 new = self.doc.createElement("deactivate")
571 new.setAttribute("lov_uuidref", lov)
572 new.setAttribute("ost_uuidref", ost)
573 new.setAttribute("index", index)
574 new.setAttribute("generation", gen)
577 ############################################################
578 # Utilities to query a DOM tree
579 # Using this functions we can treat use config information
580 # directly as a database.
582 return n.getAttribute('name')
585 return node.getAttribute('uuid')
587 def findLastUpdate(lustre):
590 for n in lustre.childNodes:
591 if n.nodeType == n.ELEMENT_NODE:
592 if n.nodeName != 'update':
594 tmp = int(n.getAttribute('version'))
596 error('malformed XML: update tag without a version attribute')
597 if tmp != version + 1:
598 error('malformed XML: expecting update record '+str(version + 1)+', found '+str(tmp)+'.')
603 def addUpdate(gen, lustre, node):
604 update = findLastUpdate(lustre)
607 #add_record = update.getElementsByTagName('add')
609 # add_record = gen.add()
610 # update.appendChild(add_record)
612 # add_record = add_record[0]
613 #add_record.appendChild(node)
614 update.appendChild(node)
616 def delUpdate(gen, lustre, node):
617 update = findLastUpdate(lustre)
620 update.appendChild(node)
622 def findByName(lustre, name, tag = ""):
623 for n in lustre.childNodes:
624 if n.nodeType == n.ELEMENT_NODE:
625 if tag and n.nodeName != tag:
627 if getName(n) == name:
630 n = findByName(n, name)
635 def lookup(node, uuid):
636 for n in node.childNodes:
637 if n.nodeType == n.ELEMENT_NODE:
638 if getUUID(n) == uuid:
646 def name2uuid(lustre, name, tag="", fatal=1):
647 ret = findByName(lustre, name, tag)
650 error('name2uuid:', '"'+name+'"', tag, 'element not found.')
655 def lookup_filesystem(lustre, mds_uuid, ost_uuid):
656 for n in lustre.childNodes:
657 if n.nodeType == n.ELEMENT_NODE and n.nodeName == 'filesystem':
658 if ref_exists(n, mds_uuid) and ref_exists(n, ost_uuid):
662 # XXX: assumes only one network element per node. will fix this
663 # as soon as support for routers is added
664 def get_net_uuid(lustre, node_name):
665 """ get a network uuid for a node_name """
666 node = findByName(lustre, node_name, "node")
668 error ('get_net_uuid:', '"'+node_name+'"', "node element not found.")
669 net = node.getElementsByTagName('network')
671 return getUUID(net[0])
674 def lov_add_obd(gen, lustre, lov, osc_uuid, options):
675 lov_name = getName(lov)
677 lov_index = get_option_int(options, 'index')
678 for tgt in lustre.getElementsByTagName('lov_tgt'):
679 if str(lov_index) == tgt.getAttribute('index'):
680 uuidref = tgt.getAttribute('uuidref')
682 raise OptionError("%s --index %d is still in use: %s" %
683 (lov_name, lov_index, uuidref))
684 tgt.setAttribute('uuidref', osc_uuid)
685 gener = int(tgt.getAttribute('generation')) + 1
686 tgt.setAttribute('generation', str(gener))
687 addUpdate(gen, lustre, gen.add(getUUID(lov), osc_uuid,
688 str(lov_index), str(gener)))
690 lov.appendChild(gen.lov_tgt(osc_uuid, str(lov_index), '1'))
691 addUpdate(gen, lustre, gen.add(getUUID(lov), osc_uuid, str(lov_index),
696 for tgt in lustre.getElementsByTagName('lov_tgt'):
697 uuidref = tgt.getAttribute('uuidref')
698 tmp = int(tgt.getAttribute('index'))
700 error('malformed xml: LOV targets are not ordered; found index '+str(tmp)+', expected '+str(index + 1)+'.')
703 lov.appendChild(gen.lov_tgt(osc_uuid, str(index + 1), '1'))
704 addUpdate(gen, lustre, gen.add(getUUID(lov), osc_uuid, str(index + 1), '1'))
706 def lov_del_obd(gen, lustre, lov, osc_uuid, options):
707 lov_name = getName(lov)
709 lov_index = get_option_int(options, 'index')
710 for tgt in lustre.getElementsByTagName('lov_tgt'):
711 index = tgt.getAttribute('index')
712 if index == lov_index:
713 uuidref = tgt.getAttribute('uuidref')
714 if uuidref != osc_uuid:
715 raise OptionError("%s --index %d contains %s, not %s" %
716 (lov_name, lov_index, osc_uuid, uuidref))
718 tgt.setAttribute('uuidref', '')
720 tgt.setAttribute('active', '0')
721 # bump the generation just in case...
722 gen = int(tgt.getAttribute('generation')) + 1
723 tgt.setAttribute('generation', str(gen))
725 raise OptionError("%s --index %d not in use by %s." %
726 (lov_name, lov_index, osc_uuid))
728 for tgt in lustre.getElementsByTagName('lov_tgt'):
729 uuidref = tgt.getAttribute('uuidref')
730 if uuidref == osc_uuid:
731 genera = int(tgt.getAttribute('generation'))
732 delete_rec = gen.delete(getUUID(lov),
733 osc_uuid,tgt.getAttribute('index'),
734 str(genera), options)
735 delUpdate(gen, lustre, delete_rec)
738 tgt.setAttribute('uuidref', '')
740 tgt.setAttribute('active', '0')
742 tgt.setAttribute('generation', str(genera))
744 def lmv_add_obd(gen, lmv, mdc_uuid):
745 lmv.appendChild(gen.ref("mds", mdc_uuid))
747 def ref_exists(profile, uuid):
748 elist = profile.childNodes
750 if e.nodeType == e.ELEMENT_NODE:
751 ref = e.getAttribute('uuidref')
756 # ensure that uuid is not already in the profile
757 # return true if uuid is added
758 def node_add_profile(gen, node, ref, uuid):
759 refname = "%s_ref" % "profile"
760 ret = node.getElementsByTagName(refname)
762 error('node has no profile ref:', node)
763 prof_uuid = ret[0].getAttribute('uuidref')
764 profile = lookup(node.parentNode, prof_uuid)
766 error("no profile found:", prof_uuid)
767 if ref_exists(profile, uuid):
769 profile.appendChild(gen.ref(ref, uuid))
772 def get_attr(dom_node, attr, default=""):
773 v = dom_node.getAttribute(attr)
778 ############################################################
781 def set_node_options(gen, node, options):
783 node.setAttribute('router', '1')
785 gen.addElement(node, "timeout", get_option(options, 'timeout'))
787 default_upcall = get_option(options, 'upcall')
790 if default_upcall or options.lustre_upcall:
791 if options.lustre_upcall:
792 gen.addElement(node, 'lustreUpcall', options.lustre_upcall)
794 gen.addElement(node, 'lustreUpcall', default_upcall)
795 if default_upcall or options.portals_upcall:
796 if options.portals_upcall:
797 gen.addElement(node, 'portalsUpcall', options.portals_upcall)
799 gen.addElement(node, 'portalsUpcall', default_upcall)
801 gen.addElement(node, "ptldebug", get_option(options, 'ptldebug'))
802 if options.subsystem:
803 gen.addElement(node, "subsystem", get_option(options, 'subsystem'))
806 def do_add_node(gen, lustre, options, node_name):
807 uuid = new_uuid(node_name)
808 prof_name = new_name("PROFILE_" + node_name)
809 prof_uuid = new_uuid(prof_name)
810 profile = gen.profile(prof_name, prof_uuid)
811 node = gen.node(node_name, uuid, prof_uuid)
812 lustre.appendChild(node)
813 lustre.appendChild(profile)
815 node_add_profile(gen, node, 'ldlm', ldlm_uuid)
816 set_node_options(gen, node, options)
821 def add_node(gen, lustre, options):
822 """ create a node with a network config """
824 node_name = get_option(options, 'node')
825 ret = findByName(lustre, node_name, "node")
827 print "Node:", node_name, "exists."
829 do_add_node(gen, lustre, options, node_name)
832 def add_net(gen, lustre, options):
833 """ create a node with a network config """
835 node_name = get_option(options, 'node')
836 nid = get_option(options, 'nid')
837 cluster_id = get_option(options, 'cluster_id')
838 hostaddr = get_option(options, 'hostaddr')
839 net_type = get_option(options, 'nettype')
841 if net_type in ('tcp',):
842 port = get_option_int(options, 'port')
843 tcpbuf = get_option_int(options, 'tcpbuf')
844 irq_aff = get_option_int(options, 'irq_affinity')
845 elif net_type in ('elan', 'gm'):
850 print "Unknown net_type: ", net_type
853 ret = findByName(lustre, node_name, "node")
855 node = do_add_node(gen, lustre, options, node_name)
858 set_node_options(gen, node, options)
860 net_name = new_name('NET_'+ node_name +'_'+ net_type)
861 net_uuid = new_uuid(net_name)
862 node.appendChild(gen.network(net_name, net_uuid, nid, cluster_id, net_type,
863 hostaddr, port, tcpbuf, irq_aff))
864 node_add_profile(gen, node, "network", net_uuid)
867 def add_route(gen, lustre, options):
868 """ create a node with a network config """
870 node_name = get_option(options, 'node')
871 gw_net_type = get_option(options, 'nettype')
872 gw = get_option(options, 'gw')
873 gw_cluster_id = get_option(options, 'gateway_cluster_id')
874 tgt_cluster_id = get_option(options, 'target_cluster_id')
875 lo = get_option(options, 'lo')
876 hi = get_option(options, 'hi')
880 node = findByName(lustre, node_name, "node")
882 error (node_name, " not found.")
884 rlist = node.getElementsByTagName('routetbl')
888 rtbl_name = new_name("RTBL_" + node_name)
889 rtbl_uuid = new_uuid(rtbl_name)
890 rtbl = gen.routetbl(rtbl_name, rtbl_uuid)
891 node.appendChild(rtbl)
892 node_add_profile(gen, node, "routetbl", rtbl_uuid)
893 rtbl.appendChild(gen.route(gw_net_type, gw, gw_cluster_id, tgt_cluster_id,
897 def add_mds(gen, lustre, options):
898 node_name = get_option(options, 'node')
899 mds_name = get_option(options, 'mds')
900 lmv_name = get_option(options, 'lmv')
901 mdd_name = new_name("MDD_" + mds_name +"_" + node_name)
902 mdd_uuid = new_uuid(mdd_name)
906 lmv = findByName(lustre, lmv_name, "lmv")
908 error('add_mds:', '"' + lmv_name + '"', "lmv element not found.")
909 lmv_uuid = name2uuid(lustre, lmv_name, fatal=0)
911 mds_uuid = name2uuid(lustre, mds_name, 'mds', fatal=0)
913 mds_uuid = new_uuid(mds_name)
914 mds = gen.mds(mds_name, mds_uuid, mdd_uuid, options.group)
915 lustre.appendChild(mds)
917 lmv_add_obd(gen, lmv, mds_uuid)
919 mds = lookup(lustre, mds_uuid)
922 mds.setAttribute('failover', "1")
924 devname = get_option(options, 'dev')
925 backdevname = get_option(options, 'backdev')
926 size = get_option(options, 'size')
927 fstype = get_option(options, 'fstype')
928 backfstype = get_option(options, 'backfstype')
929 journal_size = get_option(options, 'journal_size')
930 inode_size = get_option(options, 'inode_size')
931 nspath = get_option(options, 'nspath')
932 mkfsoptions = get_option(options, 'mkfsoptions')
933 mountfsoptions = get_option(options, 'mountfsoptions')
935 node_uuid = name2uuid(lustre, node_name, 'node')
937 node = findByName(lustre, node_name, "node")
938 node_add_profile(gen, node, "mdsdev", mdd_uuid)
939 net_uuid = get_net_uuid(lustre, node_name)
941 error("NODE: ", node_name, "not found")
944 mds.appendChild(gen.ref("lmv", lmv_uuid))
946 mdd = gen.mdsdev(mdd_name, mdd_uuid, fstype, devname,
947 get_format_flag(options), node_uuid, mds_uuid,
948 size, journal_size, inode_size, nspath, mkfsoptions,
949 mountfsoptions, backfstype, backdevname, lmv_uuid)
950 lustre.appendChild(mdd)
953 def add_mgmt(gen, lustre, options):
954 node_name = get_option(options, 'node')
955 node_uuid = name2uuid(lustre, node_name, 'node')
956 mgmt_name = get_option(options, 'mgmt')
958 mgmt_name = new_name('MGMT_' + node_name)
959 mgmt_uuid = name2uuid(lustre, mgmt_name, 'mgmt', fatal=0)
961 mgmt_uuid = new_uuid(mgmt_name)
962 mgmt = gen.mgmt(mgmt_name, mgmt_uuid, node_uuid)
963 lustre.appendChild(mgmt)
965 mgmt = lookup(lustre, mgmt_uuid)
967 node = findByName(lustre, node_name, "node")
968 node_add_profile(gen, node, 'mgmt', mgmt_uuid)
970 def add_ost(gen, lustre, options):
971 node_name = get_option(options, 'node')
972 lovname = get_option(options, 'lov')
973 osdtype = get_option(options, 'osdtype')
975 node_uuid = name2uuid(lustre, node_name, 'node')
977 if osdtype == 'obdecho':
988 devname = get_option(options, 'dev') # can be unset for bluearcs
989 backdevname = get_option(options, 'backdev')
990 size = get_option(options, 'size')
991 fstype = get_option(options, 'fstype')
992 backfstype = get_option(options, 'backfstype')
993 journal_size = get_option(options, 'journal_size')
994 inode_size = get_option(options, 'inode_size')
995 mkfsoptions = get_option(options, 'mkfsoptions')
996 mountfsoptions = get_option(options, 'mountfsoptions')
998 nspath = get_option(options, 'nspath')
1000 ostname = get_option(options, 'ost')
1002 ostname = new_name('OST_'+ node_name)
1004 osdname = new_name("OSD_" + ostname + "_" + node_name)
1005 osd_uuid = new_uuid(osdname)
1007 ost_uuid = name2uuid(lustre, ostname, 'ost', fatal=0)
1009 ost_uuid = get_option(options, 'ostuuid')
1011 if lookup(lustre, ost_uuid):
1012 error("Duplicate OST UUID:", ost_uuid)
1014 ost_uuid = new_uuid(ostname)
1016 ost = gen.ost(ostname, ost_uuid, osd_uuid, options.group)
1017 lustre.appendChild(ost)
1020 lov = findByName(lustre, lovname, "lov")
1022 error('add_ost:', '"'+lovname+'"', "lov element not found.")
1023 lov_add_obd(gen, lustre, lov, ost_uuid, options)
1025 ost = lookup(lustre, ost_uuid)
1027 if options.failover:
1028 ost.setAttribute('failover', "1")
1031 osd = gen.osd(osdname, osd_uuid, fstype, osdtype, devname,
1032 get_format_flag(options), ost_uuid, node_uuid, size,
1033 journal_size, inode_size, nspath, mkfsoptions,
1034 mountfsoptions, backfstype, backdevname)
1036 node = findByName(lustre, node_name, "node")
1038 ## if node_add_profile(gen, node, 'oss', oss_uuid):
1040 ## oss_uuid = new_uuid(ossname)
1041 ## oss = gen.oss(ossname, oss_uuid)
1042 ## lustre.appendChild(oss)
1044 node_add_profile(gen, node, 'osd', osd_uuid)
1045 lustre.appendChild(osd)
1047 def del_ost(gen, lustre, options):
1048 ostname = get_option(options, 'ost')
1050 raise OptionError("del_ost: --ost requires a <ost name>")
1051 ost = findByName(lustre, ostname, "ost")
1053 error('del_ost: ', 'Unable to find ', ostname)
1054 ost_uuid = name2uuid(lustre, ostname, fatal=0)
1056 error('del_ost: ', 'Unable to find uuid for ', ostname)
1057 lovname = get_option(options, 'lov')
1059 lov = findByName(lustre, lovname, "lov")
1061 error('del_ost:', '"'+lovname+'"', "lov element not found.")
1062 lov_del_obd(gen, lustre, lov, ost_uuid, options)
1063 # if the user specified a speficic LOV don't delete the OST itself
1066 # remove OSD references from all LOVs
1067 for n in lustre.getElementsByTagName('lov'):
1068 lov_del_obd(gen, lustre, n, ost_uuid, options)
1071 for osd in lustre.getElementsByTagName('osd'):
1072 if ref_exists(osd, ost_uuid):
1073 osd_uuid = osd.getAttribute('uuid')
1074 # delete all profile references to this OSD
1075 for profile in lustre.getElementsByTagName('profile'):
1076 for osd_ref in profile.getElementsByTagName('osd_ref'):
1077 if osd_uuid == osd_ref.getAttribute('uuidref'):
1078 profile.removeChild(osd_ref)
1079 lustre.removeChild(osd)
1082 lustre.removeChild(ost)
1084 def add_cobd(gen, lustre, options):
1085 node_name = get_option(options, 'node')
1086 name = get_option(options, 'cobd')
1087 uuid = new_uuid(name)
1089 real_name = get_option(options, 'real_obd')
1090 cache_name = get_option(options, 'cache_obd')
1092 real_uuid = name2uuid(lustre, real_name, tag='lov', fatal=0)
1093 cache_uuid = name2uuid(lustre, cache_name, tag='lov', fatal=0)
1096 node = lookup(lustre, real_uuid)
1097 rets = node.getElementsByTagName('obd_ref')
1099 ost_uuid = ret.getAttribute('uuidref')
1100 ost_node = lookup(lustre, ost_uuid)
1101 ret = ost_node.getElementsByTagName('active_ref')
1103 osd_uuid = ret[0].getAttribute('uuidref')
1104 osd_node = lookup(lustre, osd_uuid)
1105 gen.addElement(osd_node, 'cachetype', 'master')
1108 node = lookup(lustre, cache_uuid)
1109 rets = node.getElementsByTagName('obd_ref')
1111 ost_uuid = ret.getAttribute('uuidref')
1112 ost_node = lookup(lustre, ost_uuid)
1113 ret = ost_node.getElementsByTagName('active_ref')
1115 osd_uuid = ret[0].getAttribute('uuidref')
1116 osd_node = lookup(lustre, osd_uuid)
1117 gen.addElement(osd_node, 'cachetype', 'cache')
1119 if not real_uuid or not cache_uuid:
1120 real_uuid = name2uuid(lustre,real_name, tag='mds')
1121 cache_uuid = name2uuid(lustre,cache_name, tag='mds')
1123 mds_node = lookup(lustre, real_uuid)
1124 ret = mds_node.getElementsByTagName('active_ref')
1126 mdsdev_uuid = ret[0].getAttribute('uuidref')
1127 mdsdev_node = lookup(lustre, mdsdev_uuid)
1128 gen.addElement(mdsdev_node, 'cachetype', 'master')
1130 mds_node = lookup(lustre, cache_uuid)
1131 ret = mds_node.getElementsByTagName('active_ref')
1133 mdsdev_uuid = ret[0].getAttribute('uuidref')
1134 mdsdev_node = lookup(lustre, mdsdev_uuid)
1135 gen.addElement(mdsdev_node, 'cachetype', 'cache')
1137 node = findByName(lustre, node_name, "node")
1138 cobd = gen.cobd(name, uuid, real_uuid, cache_uuid)
1139 lustre.appendChild(cobd)
1142 def add_echo_client(gen, lustre, options):
1143 """ add an echo client to the profile for this node. """
1144 node_name = get_option(options, 'node')
1145 lov_name = get_option(options, 'ost')
1147 node = findByName(lustre, node_name, 'node')
1149 echoname = new_name('ECHO_'+ node_name)
1150 echo_uuid = new_uuid(echoname)
1151 node_add_profile(gen, node, 'echoclient', echo_uuid)
1153 lov_uuid = name2uuid(lustre, lov_name, tag='lov', fatal=0)
1155 lov_uuid = name2uuid(lustre, lov_name, tag='ost', fatal=1)
1157 echo = gen.echo_client(echoname, echo_uuid, lov_uuid)
1158 lustre.appendChild(echo)
1161 def add_lov(gen, lustre, options):
1162 """ create a lov """
1164 lmv_name = get_option(options, 'lmv')
1165 lov_orig = get_option(options, 'lov')
1166 name = new_name(lov_orig)
1167 if name != lov_orig:
1168 warning("name:", lov_orig, "already used. using:", name)
1170 mds_name = get_option(options, 'mds')
1173 error("LOV: MDS or LMV must be specified.");
1175 stripe_sz = get_option_int(options, 'stripe_sz')
1176 stripe_cnt = get_option_int(options, 'stripe_cnt')
1177 pattern = get_option_int(options, 'stripe_pattern')
1178 uuid = new_uuid(name)
1180 ret = findByName(lustre, name, "lov")
1182 error("LOV: ", name, " already exists.")
1185 mds_uuid = name2uuid(lustre, lmv_name, 'lmv')
1187 mds_uuid = name2uuid(lustre, mds_name, 'mds')
1189 lov = gen.lov(name, uuid, mds_uuid, stripe_sz, stripe_cnt, pattern)
1190 lustre.appendChild(lov)
1192 # add an lovconfig entry to the active mdsdev profile
1193 lovconfig_name = new_name('LVCFG_' + name)
1194 lovconfig_uuid = new_uuid(lovconfig_name)
1196 mds = findByName(lustre, mds_name, "mds")
1197 mds.appendChild(gen.ref("lovconfig", lovconfig_uuid))
1199 lmv = findByName(lustre, lmv_name, "lmv")
1200 lmv.appendChild(gen.ref("lovconfig", lovconfig_uuid))
1201 lovconfig = gen.lovconfig(lovconfig_name, lovconfig_uuid, uuid)
1202 lustre.appendChild(lovconfig)
1204 def add_default_lov(gen, lustre, mds_name, lov_name):
1205 """ create a default lov """
1207 stripe_sz = DEFAULT_STRIPE_SZ
1208 stripe_cnt = DEFAULT_STRIPE_CNT
1209 pattern = DEFAULT_STRIPE_PATTERN
1210 uuid = new_uuid(lov_name)
1212 ret = findByName(lustre, lov_name, "lov")
1214 error("LOV: ", lov_name, " already exists.")
1216 mds_uuid = name2uuid(lustre, mds_name, 'mds')
1217 lov = gen.lov(lov_name, uuid, mds_uuid, stripe_sz, stripe_cnt, pattern)
1218 lustre.appendChild(lov)
1220 # add an lovconfig entry to the active mdsdev profile
1221 lovconfig_name = new_name('LVCFG_' + lov_name)
1222 lovconfig_uuid = new_uuid(lovconfig_name)
1223 mds = findByName(lustre, mds_name)
1224 mds.appendChild(gen.ref("lovconfig", lovconfig_uuid))
1225 lovconfig = gen.lovconfig(lovconfig_name, lovconfig_uuid, uuid)
1226 lustre.appendChild(lovconfig)
1228 def add_lmv(gen, lustre, options):
1229 """ create a lmv """
1231 lmv_orig = get_option(options, 'lmv')
1232 name = new_name(lmv_orig)
1233 if name != lmv_orig:
1234 warning("name:", lmv_orig, "already used. using:", name)
1236 uuid = new_uuid(name)
1237 ret = findByName(lustre, name, "lmv")
1239 error("LMV: ", name, " already exists.")
1241 lmv = gen.lmv(name, uuid)
1242 lustre.appendChild(lmv)
1244 def new_filesystem(gen, lustre, mds_uuid, obd_uuid, mgmt_uuid):
1245 fs_name = new_name("FS_fsname")
1246 fs_uuid = new_uuid(fs_name)
1247 cobd = lookup(lustre, mds_uuid)
1248 #SHOULD appendChild filesystem to real mds not cobd
1249 ret = cobd.getElementsByTagName("cacheobd_ref")
1251 cacheobd_uuid = ret[0].getAttribute('uuidref')
1252 cacheobd = lookup(lustre, cacheobd_uuid)
1253 cacheobd.appendChild(gen.ref("filesystem", fs_uuid))
1254 ret = cobd.getElementsByTagName("realobd_ref")
1256 realobd_uuid = ret[0].getAttribute('uuidref')
1257 realobd = lookup(lustre, realobd_uuid)
1258 realobd.appendChild(gen.ref("filesystem", fs_uuid))
1260 cobd.appendChild(gen.ref("filesystem", fs_uuid))
1261 fs = gen.filesystem(fs_name, fs_uuid, mds_uuid, obd_uuid, mgmt_uuid)
1262 lustre.appendChild(fs)
1265 def get_fs_uuid(gen, lustre, mds_name, obd_name, mgmt_name):
1266 mds_uuid = name2uuid(lustre, mds_name, tag='mds', fatal=0)
1268 mds_uuid = name2uuid(lustre, mds_name, tag='lmv', fatal=0)
1270 mds_uuid = name2uuid(lustre, mds_name, tag='cobd', fatal=1)
1271 obd_uuid = name2uuid(lustre, obd_name, tag='lov', fatal=0)
1273 obd_uuid = name2uuid(lustre, obd_name, tag='cobd')
1275 mgmt_uuid = name2uuid(lustre, mgmt_name, tag='mgmt', fatal=1)
1278 fs_uuid = lookup_filesystem(lustre, mds_uuid, obd_uuid)
1280 fs_uuid = new_filesystem(gen, lustre, mds_uuid, obd_uuid, mgmt_uuid)
1283 def add_mtpt(gen, lustre, options):
1284 """ create mtpt on a node """
1285 node_name = get_option(options, 'node')
1287 path = get_option(options, 'path')
1288 fs_name = get_option(options, 'filesystem')
1290 lov_name = get_option(options, 'lov')
1291 ost_name = get_option(options, 'ost')
1292 mds_name = get_option(options, 'mds')
1294 mds_name = get_option(options, 'lmv')
1296 error("--add mtpt requires either --mds or --lmv.")
1299 error("--add mtpt requires --lov lov_name or --ost ost_name")
1301 warning("use default value for lov, due no --lov lov_name provided")
1302 lov_name = new_name("lov_default")
1303 add_default_lov(gen, lustre, mds_name, lov_name)
1304 ost_uuid = name2uuid(lustre, ost_name, 'ost', fatal=0)
1306 error('add_mtpt:', '"'+ost_name+'"', "ost element not found.")
1307 lov = findByName(lustre, lov_name, "lov")
1308 lov_add_obd(gen, lustre, lov, ost_uuid, options)
1311 mgmt_name = get_option(options, 'mgmt')
1312 fs_uuid = get_fs_uuid(gen, lustre, mds_name, lov_name, mgmt_name)
1314 fs_uuid = name2uuid(lustre, fs_name, tag='filesystem')
1316 name = new_name('MNT_'+ node_name)
1318 ret = findByName(lustre, name, "mountpoint")
1320 # this can't happen, because new_name creates unique names
1321 error("MOUNTPOINT: ", name, " already exists.")
1323 uuid = new_uuid(name)
1324 mtpt = gen.mountpoint(name, uuid, fs_uuid, path)
1325 node = findByName(lustre, node_name, "node")
1327 error('node:', node_name, "not found.")
1328 node_add_profile(gen, node, "mountpoint", uuid)
1329 lustre.appendChild(mtpt)
1331 def commit_version(gen, lustre):
1332 update = findLastUpdate(lustre)
1334 version = int(update.getAttribute("version")) + 1
1338 new = gen.update(str(version))
1339 lustre.appendChild(new)
1342 ############################################################
1343 # Command line processing
1345 class OptionError (exceptions.Exception):
1346 def __init__(self, args):
1349 def get_option(options, tag):
1350 """Look for tag in options hash and return the value if set. If not
1351 set, then if return default it is set, otherwise exception."""
1352 if options.__getattr__(tag) != None:
1353 return options.__getattr__(tag)
1355 raise OptionError("--add %s requires --%s <value>" % (options.add, tag))
1357 def get_option_int(options, tag):
1358 """Return an integer option. Raise exception if the value is not an int"""
1359 val = get_option(options, tag)
1363 raise OptionError("--%s <num> (value must be integer)" % (tag))
1366 # simple class for profiling
1373 self._start = time.time()
1374 def stop(self, msg=''):
1375 self._stop = time.time()
1379 return self._stop - self._start
1380 def display(self, msg):
1382 str = '%s: %g secs' % (msg, d)
1385 #################################################################
1386 # function cmdlinesplit used to split cmd line from batch file
1388 def cmdlinesplit(cmdline):
1390 double_quote = re.compile(r'"(([^"\\]|\\.)*)"')
1391 single_quote = re.compile(r"'(.*?)'")
1392 escaped = re.compile(r'\\(.)')
1393 esc_quote = re.compile(r'\\([\\"])')
1394 outside = re.compile(r"""([^\s\\'"]+)""") #" fucking emacs.
1398 while i < len(cmdline):
1401 match = double_quote.match(cmdline, i)
1403 print "Unmatched double quote:", cmdline
1406 if arg is None: arg = esc_quote.sub(r'\1', match.group(1))
1407 else: arg = arg + esc_quote.sub(r'\1', match.group(1))
1410 match = single_quote.match(cmdline, i)
1412 print "Unmatched single quote:", cmdline
1415 if arg is None: arg = match.group(1)
1416 else: arg = arg + match.group(1)
1419 match = escaped.match(cmdline, i)
1421 print "Unmatched backslash", cmdline
1424 if arg is None: arg = match.group(1)
1425 else: arg = arg + match.group(1)
1427 elif c in string.whitespace:
1429 arg_list.append(str(arg))
1431 while i < len(cmdline) and cmdline[i] in string.whitespace:
1434 match = outside.match(cmdline, i)
1437 if arg is None: arg = match.group()
1438 else: arg = arg + match.group()
1440 if arg != None: arg_list.append(str(arg))
1444 ############################################################
1448 def add(devtype, gen, lustre, options):
1449 if devtype == 'net':
1450 add_net(gen, lustre, options)
1451 elif devtype == 'mtpt':
1452 add_mtpt(gen, lustre, options)
1453 elif devtype == 'mds':
1454 add_mds(gen, lustre, options)
1455 elif devtype == 'ost':
1456 add_ost(gen, lustre, options)
1457 elif devtype == 'lov':
1458 add_lov(gen, lustre, options)
1459 elif devtype == 'route':
1460 add_route(gen, lustre, options)
1461 elif devtype == 'node':
1462 add_node(gen, lustre, options)
1463 elif devtype == 'echo_client':
1464 add_echo_client(gen, lustre, options)
1465 elif devtype == 'cobd':
1466 add_cobd(gen, lustre, options)
1467 elif devtype == 'mgmt':
1468 add_mgmt(gen, lustre, options)
1469 elif devtype == 'lmv':
1470 add_lmv(gen, lustre, options)
1472 error("unknown device type:", devtype)
1474 def delete(devtype, gen, lustre, options):
1475 if devtype == 'ost':
1476 del_ost(gen, lustre, options)
1477 elif options.delete:
1478 error("delete not supported for device type:", devtype)
1479 elif options.deactivate:
1480 error("deactivate not supported for device type:", devtype)
1482 error("in delete(), but neither .delete nor .deactivate are set. Tell CFS.")
1484 def commit(gen, lustre):
1485 commit_version(gen, lustre)
1487 def do_command(gen, lustre, options, args):
1489 add(options.add, gen, lustre, options)
1490 elif options.delete:
1491 delete(options.delete, gen, lustre, options)
1492 elif options.deactivate:
1493 delete(options.deactivate, gen, lustre, options)
1494 elif options.commit:
1497 error("Missing command")
1500 cl = Lustre.Options("lmc", "", lmc_options)
1502 options, args = cl.parse(sys.argv[1:])
1503 except Lustre.OptionError, e:
1507 panic(string.join(sys.argv), "Unexpected extra arguments on command line: " + string.join(args))
1509 if options.reference:
1516 outFile = options.merge
1517 if os.access(outFile, os.R_OK):
1518 doc = xml.dom.minidom.parse(outFile)
1520 doc = new_lustre(xml.dom.minidom)
1522 doc = xml.dom.minidom.parse(options.input)
1524 doc = new_lustre(xml.dom.minidom)
1527 outFile = options.output
1529 lustre = doc.documentElement
1531 if lustre.tagName != "lustre":
1532 print "Existing config not valid."
1535 gen = GenConfig(doc)
1538 fp = open(options.batch)
1539 batchCommands = fp.readlines()
1541 for cmd in batchCommands:
1543 options, args = cl.parse(cmdlinesplit(cmd))
1544 if options.merge or options.input or options.output:
1545 print "The batchfile should not contain --merge, --input or --output."
1547 do_command(gen, lustre, options, args)
1548 except OptionError, e:
1550 except Lustre.OptionError, e:
1554 do_command(gen, lustre, options, args)
1555 except OptionError, e:
1556 panic(string.join(sys.argv),e)
1557 except Lustre.OptionError, e:
1563 printDoc(doc, open(outFile,"w"))
1565 if __name__ == "__main__":