X-Git-Url: https://git.whamcloud.com/?a=blobdiff_plain;ds=sidebyside;f=lustre%2Futils%2Flmc;h=335572af7cda90d9a1222ebd773160761360586b;hb=f01c9cd26f972e98460d7f3609ca575a30b4226e;hp=c68652d05481bd12b74a30b283686b18f87d16b2;hpb=ca9b9ab6dd3cf4045b9cfecbf312559cfde8b461;p=fs%2Flustre-release.git diff --git a/lustre/utils/lmc b/lustre/utils/lmc index c68652d..335572a 100755 --- a/lustre/utils/lmc +++ b/lustre/utils/lmc @@ -1,211 +1,1669 @@ #!/usr/bin/env python +# Copyright (C) 2002 Cluster File Systems, Inc. +# Author: Robert Read -import sys, getopt -import xml.dom.minidom - +# This file is part of Lustre, http://www.lustre.org. +# +# Lustre is free software; you can redistribute it and/or +# modify it under the terms of version 2 of the GNU General Public +# License as published by the Free Software Foundation. # -# Example of walking the tree +# Lustre is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. # -def handleLustre(lustre): - handleHost(lustre.getElementsByTagName("node")) +# You should have received a copy of the GNU General Public License +# along with Lustre; if not, write to the Free Software +# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +# + +""" +lmc - lustre configuration data manager + + See Lustre book (http://www.lustre.org/docs/lustre.pdf) for documentation on lmc. + +""" + +import sys, os, getopt, string, exceptions, re +import xml.dom.minidom + +def printDoc(doc, stream=sys.stdout): + try: + from xml.dom.ext import PrettyPrint + PrettyPrint(doc, stream) + except ImportError: + stream.write(doc.toxml()) + stream.write("\n") + + +PYMOD_DIR = "/usr/lib/lustre/python" + +def development_mode(): + base = os.path.dirname(sys.argv[0]) + if os.access(base+"/Makefile.am", os.R_OK): + return 1 + return 0 + +if not development_mode(): + sys.path.append(PYMOD_DIR) + +import Lustre + +DEFAULT_PORT = 988 +DEFAULT_STRIPE_SZ = 1048576 +DEFAULT_STRIPE_CNT = 1 +DEFAULT_STRIPE_PATTERN = 0 +UUID_MAX_LENGTH = 31 + +def reference(): + print """usage: lmc --add object [object parameters] + +Object creation command summary: + +--add node + --node node_name + --timeout num + --upcall path + --lustre_upcall path + --portals_upcall path + --ptldebug debug_level + --subsystem subsystem_name + +--add net + --node node_name + --nid nid + --cluster_id + --nettype tcp|elan|gm + --hostaddr addr + --port port + --tcpbuf size + --irq_affinity 0|1 + --router + +--add mds + --node node_name + --mds mds_name + --failover + --dev path + --backdev path + --fstype ldiskfs|ext3 + --backfstype ldiskfs|ext3|tmpfs + --size size + --nspath + --journal_size size + --inode_size size + --lmv lmv_name + --mkfsoptions options + --mountfsoptions options + +--add lov + --lov lov_name + --mds mds_name + --stripe_sz num + --stripe_cnt num + --stripe_pattern num + --lmv lmv_name + +--add ost + --node node_name + --ost ost_name + --failover + --lov lov_name + --index index + --dev path + --backdev path + --size size + --fstype ldiskfs|ext3 + --backfstype ldiskfs|ext3|tmpfs + --journal_size size + --inode_size size + --osdtype obdecho|obdfilter + --ostuuid uuid + --mkfsoptions options + --mountfsoptions options + --nspath + +--delete ost + --node node_name + --ost ost_name + --migrate +--deactivate ost + --node node_name + --ost ost_name + +--add mtpt - Mountpoint + --node node_name + --path /mnt/point + --mds mds_name + --lmv lmv_name + --ost ost_name OR --lov lov_name + --clientoptions options + +--add route + --node nodename + --router + --gw nid + --gateway_cluster_id nid + --target_cluster_id nid + --lo nid + --hi nid + +--add echo_client + --node nodename + +--add mgmt - Management/monitoring service + --node node_name + --mgmt mgmt_service_name + +--add lmv + --lmv lmv_name + +--add cobd + --node node_name + --real_obd obd_name + --cache_obd obd_name + +--add cmobd + --node node_name + --master_dev obd_name + --cache_dev obd_name + +--commit - Close a configuration version, and start a new one +""" -def handleHost(hosts): - for host in hosts: - name = host.getAttribute("name") - uuid = host.getAttribute("uuid") +PARAM = Lustre.Options.PARAM +lmc_options = [ + # lmc input/output options + ('reference', "Print short reference for commands."), + ('verbose,v', "Print system commands as they are run."), + ('merge,m', "Append to the specified config file.", PARAM), + ('output,o', "Write XML configuration into given output file. Overwrite existing content.", PARAM), + ('input,i', "", PARAM), + ('batch', "Used to execute lmc commands in batch mode.", PARAM), + + # commands + ('add', "", PARAM), + ('delete', "", PARAM), + ('deactivate', "", PARAM), + ('commit', "Commit all config changes and start a new version"), + + # node options + ('node', "Add a new node in the cluster configuration.", PARAM), + ('timeout', "Set timeout to initiate recovery.", PARAM), + ('upcall', "Set both lustre and portals upcall scripts.", PARAM), + ('lustre_upcall', "Set location of lustre upcall script.", PARAM), + ('portals_upcall', "Set location of portals upcall script.", PARAM), + ('ptldebug', "Set the portals debug level", PARAM), + ('subsystem', "Specify which Lustre subsystems have debug output recorded in the log", PARAM), + + # network + ('nettype', "Specify the network type. This can be tcp/elan/gm.", PARAM), + ('nid', "Give the network ID, e.g ElanID/IP Address as used by portals.", PARAM), + ('tcpbuf', "Optional argument to specify the TCP buffer size.", PARAM, "0"), + ('port', "Optional argument to specify the TCP port number.", PARAM, DEFAULT_PORT), + ('irq_affinity', "Optional argument.", PARAM, 0), + ('hostaddr', "", PARAM,""), + ('cluster_id', "Specify the cluster ID", PARAM, "0"), + + # routes + ('route', "Add a new route for the cluster.", PARAM), + ('router', "Optional flag to mark a node as router."), + ('gw', "Specify the nid of the gateway for a route.", PARAM), + ('gateway_cluster_id', "", PARAM, "0"), + ('target_cluster_id', "", PARAM, "0"), + ('lo', "For a range route, this is the low value nid.", PARAM), + ('hi', "For a range route, this is a hi value nid.", PARAM,""), + + # servers: mds and ost + ('mds', "Specify MDS name.", PARAM,""), + ('ost', "Specify the OST name.", PARAM,""), + ('osdtype', "This could obdfilter or obdecho.", PARAM, "obdfilter"), + ('failover', "Enable failover support on OSTs or MDS?"), + ('group', "", PARAM), + ('dev', "Path of the device on local system.", PARAM,""), + ('backdev', "Path of the device for backing storage on local system.", PARAM,""), + ('size', "Specify the size of the device if needed.", PARAM,"0"), + ('journal_size', "Specify new journal size for underlying file system.", PARAM,"0"), + ('inode_size', "Specify new inode size for underlying file system.", PARAM,"0"), + ('fstype', "Optional argument to specify the filesystem type.", PARAM, "ext3"), + ('backfstype', "Optional argument to specify the backing filesystem type.", PARAM, "ext3"), + ('mkfsoptions', "Optional argument to mkfs.", PARAM, ""), + ('mountfsoptions', "Optional argument to mount fs.", PARAM, ""), + ('ostuuid', "", PARAM,""), + ('nspath', "Local mount point of server namespace.", PARAM,""), + ('format', ""), + ('migrate', "used for offline migrate of an ost in conjunctio with add/delete"), + + # clients: mountpoint and echo + ('echo_client', "", PARAM), + ('path', "Specify the mountpoint for Lustre.", PARAM), + ('filesystem', "Lustre filesystem name", PARAM,""), + ('clientoptions', "Specify the options for Lustre, such as async.", PARAM, ""), + + # lov + ('lov', "Specify LOV name.", PARAM,""), + ('index', "Specify index for OBD in LOV target table.", PARAM), + ('stripe_sz', "Specify the stripe size in bytes.", PARAM), + ('stripe_cnt', "Specify the number of OSTs each file should be striped on.", PARAM, 0), + ('stripe_pattern', "Specify the stripe pattern. RAID 0 is the only one currently supported.", PARAM, 0), + + # cobd + + ('real_obd', "Specify the real device for the cache obd system.", PARAM), + ('cache_obd', "Specify the cache device for the cache obd system.", PARAM), + ('cobd', "Specify COBD name", PARAM), + + # cmobd + ('master_dev', "Specify the master device for the cmobd system.", PARAM), + ('cache_dev', "Specify the cache device for the cmobd obd system.", PARAM), + ('cmobd', "Specify COBD name", PARAM), + + + ('mgmt', "Specify management/monitoring service name.", PARAM, ""), + + # lmv + ('lmv', "Specify LMV name.", PARAM,""), + ] + +def error(*args): + msg = string.join(map(str,args)) + raise OptionError("Error: " + msg) + +def panic(cmd, msg): + print "! " + cmd + print msg + sys.exit(1) + + +def warning(*args): + msg = string.join(map(str,args)) + print "Warning: ", msg # # manage names and uuids # need to initialize this by walking tree to ensure # no duplicate names or uuids are created. # this are just place holders for now. -name_ctr = 1 +# consider changing this to be like OBD-dev-host def new_name(base): - global name_ctr - name = "%s_%d" % (base, name_ctr) - name_ctr += 1 - return name + ctr = 2 + ret = base + while names.has_key(ret): + ret = "%s_%d" % (base, ctr) + ctr = 1 + ctr + names[ret] = 1 + return ret -def get_uuid(name): - return "%s_UUID" % (name) +def new_uuid(name): + ctr = 2 + ret = "%s_UUID" % (name) + if len(ret) > UUID_MAX_LENGTH: + ret = ret[-UUID_MAX_LENGTH:] + while uuids.has_key(ret): + ret = "%s_UUID_%d" % (name, ctr) + ctr = 1 + ctr + if len(ret) > UUID_MAX_LENGTH: + ret = ret[-UUID_MAX_LENGTH:] + uuids[ret] = 1 + return ret -# -# Create a new empty lustre document -def new_Lustre(): - str = """ -""" - dom = xml.dom.minidom.parseString(str) - return dom -# -# Create a new object the "correct" way by using the DOM api. -# -def new_OBD(dom, name, fs, devname, format, dev_size=0, dev_file=""): - uuid = get_uuid(name) - - obd = dom.createElement("obd") - obd.setAttribute("name", name) - obd.setAttribute("uuid", uuid) - - fstype = dom.createElement("fstype") - txt= dom.createTextNode(fs) - fstype.appendChild(txt) - obd.appendChild(fstype) - - dev = dom.createElement("device") - if (dev_size): - dev.setAttribute("size", "%s" % (dev_size)) - txt = dom.createTextNode(devname) - dev.appendChild(txt) - obd.appendChild(dev) +ldlm_name = 'ldlm' +ldlm_uuid = 'ldlm_UUID' - fmt = dom.createElement("autoformat") - txt = dom.createTextNode(format) - fmt.appendChild(txt) - obd.appendChild(fmt) +def new_lustre(dom): + """Create a new empty lustre document""" + # adding ldlm here is a bit of a hack, but one is enough. + str = """ + + """ % (Lustre.CONFIG_VERSION, ldlm_name, ldlm_uuid) + return dom.parseString(str) - return obd +names = {} +uuids = {} -# -# Create new object the fast and easy way -# (note: dom is not needed for this way) -def new_OSC(dom, osc, obd): - osc_uuid = get_uuid(osc) - obd_uuid = get_uuid(obd) - - osc_str =""" - - - """ % (osc, osc_uuid, obd, obd_uuid) - osc = xml.dom.minidom.parseString(osc_str) - return osc.getElementsByTagName("osc")[0] +def init_names(doc): + """initialize auto-name generation tables""" + global names, uuids + # get all elements that contain a name attribute + for n in doc.childNodes: + if n.nodeType == n.ELEMENT_NODE: + if getName(n): + names[getName(n)] = 1 + uuids[getUUID(n)] = 1 + init_names(n) -# -# Create new object the fast and easy way -# -def new_OST(dom, ost, host, port, obd): - ost_uuid = get_uuid(ost) - obd_uuid = get_uuid(obd) - - str =""" - - - %s - %d - - - """ % (ost, ost_uuid, host, port, obd, obd_uuid) - node = xml.dom.minidom.parseString(str) - return node.getElementsByTagName("ost")[0] +def get_format_flag(options): + if options.format: + return 'yes' + return 'no' +############################################################ +# Build config objects using DOM # -# Create a new obd, osc, and ost. Add them to the DOM. -# -def add_OST(dom, options, args): - # XXX need some error checking - devname = args[0] - host = args[1] - - obdname = new_name("obd") - oscname = new_name("osc") - ostname = new_name("ost") - - obd = new_OBD(dom, obdname, "extN", devname, "no") - osc = new_OSC(dom, oscname, obdname) - ost = new_OST(dom, ostname, host, 2020, obdname) - - dom.getElementsByTagName("lustre")[0].appendChild(obd) - dom.getElementsByTagName("lustre")[0].appendChild(osc) - dom.getElementsByTagName("lustre")[0].appendChild(ost) +class GenConfig: + doc = None + dom = None + def __init__(self, doc): + self.doc = doc + + def ref(self, type, uuid): + """ generate <[type]_ref uuidref="[uuid]"/> """ + tag = "%s_ref" % (type) + ref = self.doc.createElement(tag) + ref.setAttribute("uuidref", uuid) + return ref + + def dev(self, devname): + """ generate """ + tgt = self.doc.createElement('dev') + tgt.setAttribute("dev", devname) + return tgt + + def newService(self, tag, name, uuid): + """ create a new service elmement, which requires name and uuid attributes """ + new = self.doc.createElement(tag) + new.setAttribute("uuid", uuid); + new.setAttribute("name", name); + return new + + def addText(self, node, str): + txt = self.doc.createTextNode(str) + node.appendChild(txt) + + def addElement(self, node, tag, str=None): + """ create a new element and add it as a child to node. If str is passed, + a text node is created for the new element""" + new = self.doc.createElement(tag) + if str: + self.addText(new, str) + node.appendChild(new) + return new + + def network(self, name, uuid, nid, cluster_id, net, hostaddr="", + port=0, tcpbuf=0, irq_aff=0): + """create node""" + network = self.newService("network", name, uuid) + network.setAttribute("nettype", net); + self.addElement(network, "nid", nid) + self.addElement(network, "clusterid", cluster_id) + if hostaddr: + self.addElement(network, "hostaddr", hostaddr) + if port: + self.addElement(network, "port", "%d" %(port)) + if tcpbuf: + self.addElement(network, "sendmem", "%d" %(tcpbuf)) + self.addElement(network, "recvmem", "%d" %(tcpbuf)) + if irq_aff: + self.addElement(network, "irqaffinity", "%d" %(irq_aff)) + + return network + def routetbl(self, name, uuid): + """create node""" + rtbl = self.newService("routetbl", name, uuid) + return rtbl + def route(self, gw_net_type, gw, gw_cluster_id, tgt_cluster_id, lo, hi): + """ create one entry for the route table """ + ref = self.doc.createElement('route') + ref.setAttribute("type", gw_net_type) + ref.setAttribute("gw", gw) + ref.setAttribute("gwclusterid", gw_cluster_id) + ref.setAttribute("tgtclusterid", tgt_cluster_id) + ref.setAttribute("lo", lo) + if hi: + ref.setAttribute("hi", hi) + return ref + + def profile(self, name, uuid): + """ create a host """ + profile = self.newService("profile", name, uuid) + return profile + + def node(self, name, uuid, prof_uuid): + """ create a host """ + node = self.newService("node", name, uuid) + node.appendChild(self.ref("profile", prof_uuid)) + return node + + def ldlm(self, name, uuid): + """ create a ldlm """ + ldlm = self.newService("ldlm", name, uuid) + return ldlm + + def osd(self, name, uuid, fstype, osdtype, devname, format, ost_uuid, + node_uuid, dev_size=0, journal_size=0, inode_size=0, nspath="", + mkfsoptions="", mountfsoptions="", backfstype="", backdevname=""): + osd = self.newService("osd", name, uuid) + osd.setAttribute('osdtype', osdtype) + osd.appendChild(self.ref("target", ost_uuid)) + osd.appendChild(self.ref("node", node_uuid)) + osd.appendChild(self.dev(devname)) + + if fstype: + self.addElement(osd, "fstype", fstype) + if backfstype: + self.addElement(osd, "backfstype", backfstype) + if backdevname: + self.addElement(osd, "backdevpath", backdevname) + if devname: + dev = self.addElement(osd, "devpath", devname) + self.addElement(osd, "autoformat", format) + if dev_size: + self.addElement(osd, "devsize", "%s" % (dev_size)) + if journal_size: + self.addElement(osd, "journalsize", "%s" % (journal_size)) + if inode_size: + self.addElement(osd, "inodesize", "%s" % (inode_size)) + if mkfsoptions: + self.addElement(osd, "mkfsoptions", mkfsoptions) + if mountfsoptions: + self.addElement(osd, "mountfsoptions", mountfsoptions) + if nspath: + self.addElement(osd, "nspath", nspath) + return osd + + def cobd(self, name, uuid, real_uuid, cache_uuid): + cobd = self.newService("cobd", name, uuid) + cobd.appendChild(self.ref("realobd",real_uuid)) + cobd.appendChild(self.ref("cacheobd",cache_uuid)) + return cobd + + def cmobd(self, name, uuid, real_uuid, cache_uuid): + cmobd = self.newService("cmobd", name, uuid) + cmobd.appendChild(self.ref("masterobd",real_uuid)) + cmobd.appendChild(self.ref("cacheobd",cache_uuid)) + return cmobd + + def ost(self, name, uuid, osd_uuid, group=""): + ost = self.newService("ost", name, uuid) + ost.appendChild(self.ref("active", osd_uuid)) + if group: + self.addElement(ost, "group", group) + return ost + + def oss(self, name, uuid): + oss = self.newService("oss", name, uuid) + return oss + + def lov(self, name, uuid, mds_uuid, stripe_sz, stripe_cnt, pattern): + lov = self.newService("lov", name, uuid) + lov.appendChild(self.ref("mds", mds_uuid)) + lov.setAttribute("stripesize", str(stripe_sz)) + lov.setAttribute("stripecount", str(stripe_cnt)) + lov.setAttribute("stripepattern", str(pattern)) + return lov + + def lov_tgt(self, obd_uuid, index, generation): + tgt = self.doc.createElement('lov_tgt') + tgt.setAttribute("uuidref", obd_uuid) + tgt.setAttribute("index", index) + tgt.setAttribute("generation", generation) + tgt.setAttribute("active", '1') + return tgt + + def lovconfig(self, name, uuid, lov_uuid): + lovconfig = self.newService("lovconfig", name, uuid) + lovconfig.appendChild(self.ref("lov", lov_uuid)) + return lovconfig + + def lmv(self, name, uuid): + lmv = self.newService("lmv", name, uuid) + return lmv + + def mds(self, name, uuid, mdd_uuid, group="", lmv=""): + mds = self.newService("mds", name, uuid) + mds.appendChild(self.ref("active",mdd_uuid)) + if group: + self.addElement(mds, "group", group) + return mds + + def mdsdev(self, name, uuid, fstype, devname, format, node_uuid, + mds_uuid, dev_size=0, journal_size=0, inode_size=256, + nspath="", mkfsoptions="", mountfsoptions="", backfstype="", + backdevname="", lmv_uuid=""): + mdd = self.newService("mdsdev", name, uuid) + self.addElement(mdd, "fstype", fstype) + if backfstype: + self.addElement(mdd, "backfstype", backfstype) + dev = self.addElement(mdd, "devpath", devname) + if backdevname: + self.addElement(mdd, "backdevpath", backdevname) + self.addElement(mdd, "autoformat", format) + if dev_size: + self.addElement(mdd, "devsize", "%s" % (dev_size)) + if journal_size: + self.addElement(mdd, "journalsize", "%s" % (journal_size)) + if inode_size: + self.addElement(mdd, "inodesize", "%s" % (inode_size)) + if nspath: + self.addElement(mdd, "nspath", nspath) + if mkfsoptions: + self.addElement(mdd, "mkfsoptions", mkfsoptions) + if mountfsoptions: + self.addElement(mdd, "mountfsoptions", mountfsoptions) + + mdd.appendChild(self.ref("node", node_uuid)) + mdd.appendChild(self.ref("target", mds_uuid)) + mdd.appendChild(self.dev(devname)) + + if lmv_uuid: + mdd.appendChild(self.ref("lmv", lmv_uuid)) + self.addElement(mdd, "lmv", lmv_uuid) + + return mdd + + def mgmt(self, mgmt_name, mgmt_uuid, node_uuid): + mgmt = self.newService("mgmt", mgmt_name, mgmt_uuid) + mgmt.appendChild(self.ref("node", node_uuid)) + # Placeholder until mgmt-service failover. + mgmt.appendChild(self.ref("active", mgmt_uuid)) + return mgmt + + def mountpoint(self, name, uuid, fs_uuid, path, clientoptions): + mtpt = self.newService("mountpoint", name, uuid) + mtpt.appendChild(self.ref("filesystem", fs_uuid)) + self.addElement(mtpt, "path", path) + if clientoptions: + self.addElement(mtpt, "clientoptions", clientoptions) + return mtpt + + def filesystem(self, name, uuid, mds_uuid, obd_uuid, mgmt_uuid): + fs = self.newService("filesystem", name, uuid) + fs.appendChild(self.ref("mds", mds_uuid)) + fs.appendChild(self.ref("obd", obd_uuid)) + if mgmt_uuid: + fs.appendChild(self.ref("mgmt", mgmt_uuid)) + return fs + + def echo_client(self, name, uuid, osc_uuid): + ec = self.newService("echoclient", name, uuid) + ec.appendChild(self.ref("obd", osc_uuid)) + return ec + + def update(self, version): + new = self.doc.createElement("update") + new.setAttribute("version", version) + return new + + def add(self, lov, ost, index, gen): + new = self.doc.createElement("add") + new.setAttribute("lov_uuidref", lov) + new.setAttribute("ost_uuidref", ost) + new.setAttribute("index", index) + new.setAttribute("generation", gen) + return new + + def delete(self, lov, ost, index, gen, options): + if options.delete: + new = self.doc.createElement("delete") + else: + new = self.doc.createElement("deactivate") + new.setAttribute("lov_uuidref", lov) + new.setAttribute("ost_uuidref", ost) + new.setAttribute("index", index) + new.setAttribute("generation", gen) + return new + +############################################################ +# Utilities to query a DOM tree +# Using this functions we can treat use config information +# directly as a database. +def getName(n): + return n.getAttribute('name') + +def getUUID(node): + return node.getAttribute('uuid') + +def findLastUpdate(lustre): + node = None + version = 0 + for n in lustre.childNodes: + if n.nodeType == n.ELEMENT_NODE: + if n.nodeName != 'update': + continue + tmp = int(n.getAttribute('version')) + if not tmp: + error('malformed XML: update tag without a version attribute') + if tmp != version + 1: + error('malformed XML: expecting update record '+str(version + 1)+', found '+str(tmp)+'.') + version = tmp + node = n + return node + +def addUpdate(gen, lustre, node): + update = findLastUpdate(lustre) + if not update: + return + #add_record = update.getElementsByTagName('add') + #if not add_record: + # add_record = gen.add() + # update.appendChild(add_record) + #else: + # add_record = add_record[0] + #add_record.appendChild(node) + update.appendChild(node) + +def delUpdate(gen, lustre, node): + update = findLastUpdate(lustre) + if not update: + return + update.appendChild(node) + +def findByName(lustre, name, tag = ""): + for n in lustre.childNodes: + if n.nodeType == n.ELEMENT_NODE: + if tag and n.nodeName != tag: + continue + if getName(n) == name: + return n + else: + n = findByName(n, name) + if n: return n + return None + + +def lookup(node, uuid): + for n in node.childNodes: + if n.nodeType == n.ELEMENT_NODE: + if getUUID(n) == uuid: + return n + else: + n = lookup(n, uuid) + if n: return n + return None + + +def name2uuid(lustre, name, tag="", fatal=1): + ret = findByName(lustre, name, tag) + if not ret: + if fatal: + error('name2uuid:', '"'+name+'"', tag, 'element not found.') + else: + return "" + return getUUID(ret) + +def lookup_filesystem(lustre, mds_uuid, ost_uuid): + for n in lustre.childNodes: + if n.nodeType == n.ELEMENT_NODE and n.nodeName == 'filesystem': + if ref_exists(n, mds_uuid) and ref_exists(n, ost_uuid): + return getUUID(n) + return None + +# XXX: assumes only one network element per node. will fix this +# as soon as support for routers is added +def get_net_uuid(lustre, node_name): + """ get a network uuid for a node_name """ + node = findByName(lustre, node_name, "node") + if not node: + error ('get_net_uuid:', '"'+node_name+'"', "node element not found.") + net = node.getElementsByTagName('network') + if net: + return getUUID(net[0]) + return None + +def lov_mod_obd(gen, lustre, lov, tgt, osc_uuid, options): + tgt.setAttribute('uuidref', osc_uuid) + if options.migrate: + gener = int(tgt.getAttribute('generation')) + else: + gener = int(tgt.getAttribute('generation')) + 1 + tgt.setAttribute('generation', str(gener)) + tgt.setAttribute('active', '1') + lov_index = int(tgt.getAttribute('index')) + addUpdate(gen, lustre, gen.add(getUUID(lov), osc_uuid, str(lov_index), + str(gener))) + return + +def lov_add_obd(gen, lustre, lov, osc_uuid, options): + lov_name = getName(lov) + if options.index: + lov_index = get_option_int(options, 'index') + for tgt in lustre.getElementsByTagName('lov_tgt'): + if str(lov_index) == tgt.getAttribute('index'): + uuidref = tgt.getAttribute('uuidref') + if uuidref != '': + raise OptionError("%s --index %d is still in use: %s" % + (lov_name, lov_index, uuidref)) + lov_mod_obd(gen, lustre, lov, tgt, osc_uuid, options) + return + else: + lov_index = 0 + for tgt in lustre.getElementsByTagName('lov_tgt'): + uuidref = tgt.getAttribute('uuidref') + tmp = int(tgt.getAttribute('index')) + if tmp != lov_index: + error('malformed xml: LOV targets are not ordered; found index '+str(tmp)+', expected '+str(lov_index)+'.') + uuidref = tgt.getAttribute('uuidref') + if uuidref == '': + lov_mod_obd(gen, lustre, lov, tgt, osc_uuid, options) + return + lov_index = lov_index + 1 + + lov.appendChild(gen.lov_tgt(osc_uuid, str(lov_index), '1')) + addUpdate(gen, lustre, gen.add(getUUID(lov), osc_uuid, str(lov_index), '1')) + +def lov_del_obd(gen, lustre, lov, osc_uuid, options): + lov_name = getName(lov) + if options.index: + lov_index = get_option_int(options, 'index') + for tgt in lustre.getElementsByTagName('lov_tgt'): + index = tgt.getAttribute('index') + if index == lov_index: + uuidref = tgt.getAttribute('uuidref') + if uuidref != osc_uuid: + raise OptionError("%s --index %d contains %s, not %s" % + (lov_name, lov_index, osc_uuid, uuidref)) + if options.delete: + tgt.setAttribute('uuidref', '') + + # bump the generation just in case... + if options.migrate: + gen = int(tgt.getAttribute('generation')) + else: + gen = int(tgt.getAttribute('generation')) + 1 + + tgt.setAttribute('active', '0') + tgt.setAttribute('generation', str(gen)) + return + raise OptionError("%s --index %d not in use by %s." % + (lov_name, lov_index, osc_uuid)) + + for tgt in lustre.getElementsByTagName('lov_tgt'): + uuidref = tgt.getAttribute('uuidref') + if uuidref == osc_uuid: + genera = int(tgt.getAttribute('generation')) + delete_rec = gen.delete(getUUID(lov), + osc_uuid,tgt.getAttribute('index'), + str(genera), options) + delUpdate(gen, lustre, delete_rec) + + if options.delete: + tgt.setAttribute('uuidref', '') + if not options.migrate: + genera = genera + 1 + tgt.setAttribute('active', '0') + tgt.setAttribute('generation', str(genera)) + +def lmv_add_obd(gen, lmv, mdc_uuid): + lmv.appendChild(gen.ref("mds", mdc_uuid)) + +def ref_exists(profile, uuid): + elist = profile.childNodes + for e in elist: + if e.nodeType == e.ELEMENT_NODE: + ref = e.getAttribute('uuidref') + if ref == uuid: + return 1 + return 0 + +# ensure that uuid is not already in the profile +# return true if uuid is added +def node_add_profile(gen, node, ref, uuid): + refname = "%s_ref" % "profile" + ret = node.getElementsByTagName(refname) + if not ret: + error('node has no profile ref:', node) + prof_uuid = ret[0].getAttribute('uuidref') + profile = lookup(node.parentNode, prof_uuid) + if not profile: + error("no profile found:", prof_uuid) + if ref_exists(profile, uuid): + return 0 + profile.appendChild(gen.ref(ref, uuid)) + return 1 + +# ensure that uuid is not already in the profile +# return true if uuid is added +def node_found_target_by_dev(gen, lustre, node, devname): + refname = "%s_ref" % "profile" + ret = node.getElementsByTagName(refname) + if not ret: + error('node has no profile ref:', node) + prof_uuid = ret[0].getAttribute('uuidref') + profile = lookup(node.parentNode, prof_uuid) + if not profile: + error("no profile found:", prof_uuid) + + osd_list = lustre.getElementsByTagName('osd') + + for osd in osd_list: + obd_dev = osd.getElementsByTagName('dev') + if obd_dev and obd_dev[0].getAttribute('dev') == devname: + for ost in lustre.getElementsByTagName('ost'): + active_ret = ost.getElementsByTagName('active_ref') + if active_ret[0].getAttribute('uuidref') == osd.getAttribute('uuid'): + return ost.getAttribute('uuid') + + mdsdev_list = lustre.getElementsByTagName('mdsdev') + + for mdsdev in mdsdev_list: + obd_dev = mdsdev.getElementsByTagName('dev') + if obd_dev and obd_dev[0].getAttribute('dev') == devname: + for mds in lustre.getElementsByTagName('mds'): + active_ret = mds.getElementsByTagName('active_ref') + if active_ret[0].getAttribute('uuidref') == mdsdev.getAttribute('uuid'): + return mds.getAttribute('uuid') + + return "" + +def get_attr(dom_node, attr, default=""): + v = dom_node.getAttribute(attr) + if v: + return v + return default + +############################################################ +# Top level commands # +def set_node_options(gen, node, options): + if options.router: + node.setAttribute('router', '1') + if options.timeout: + gen.addElement(node, "timeout", get_option(options, 'timeout')) + if options.upcall: + default_upcall = get_option(options, 'upcall') + else: + default_upcall = '' + if default_upcall or options.lustre_upcall: + if options.lustre_upcall: + gen.addElement(node, 'lustreUpcall', options.lustre_upcall) + else: + gen.addElement(node, 'lustreUpcall', default_upcall) + if default_upcall or options.portals_upcall: + if options.portals_upcall: + gen.addElement(node, 'portalsUpcall', options.portals_upcall) + else: + gen.addElement(node, 'portalsUpcall', default_upcall) + if options.ptldebug: + gen.addElement(node, "ptldebug", get_option(options, 'ptldebug')) + if options.subsystem: + gen.addElement(node, "subsystem", get_option(options, 'subsystem')) + return node + +def do_add_node(gen, lustre, options, node_name): + uuid = new_uuid(node_name) + prof_name = new_name("PROFILE_" + node_name) + prof_uuid = new_uuid(prof_name) + profile = gen.profile(prof_name, prof_uuid) + node = gen.node(node_name, uuid, prof_uuid) + lustre.appendChild(node) + lustre.appendChild(profile) + + node_add_profile(gen, node, 'ldlm', ldlm_uuid) + set_node_options(gen, node, options) + + return node + + +def add_node(gen, lustre, options): + """ create a node with a network config """ + + node_name = get_option(options, 'node') + ret = findByName(lustre, node_name, "node") + if ret: + print "Node:", node_name, "exists." + return + do_add_node(gen, lustre, options, node_name) + + +def add_net(gen, lustre, options): + """ create a node with a network config """ + + node_name = get_option(options, 'node') + nid = get_option(options, 'nid') + cluster_id = get_option(options, 'cluster_id') + hostaddr = get_option(options, 'hostaddr') + net_type = get_option(options, 'nettype') + + if net_type in ('tcp',): + port = get_option_int(options, 'port') + tcpbuf = get_option_int(options, 'tcpbuf') + irq_aff = get_option_int(options, 'irq_affinity') + elif net_type in ('elan', 'gm'): + port = 0 + tcpbuf = 0 + irq_aff = 0 + else: + print "Unknown net_type: ", net_type + sys.exit(2) + + ret = findByName(lustre, node_name, "node") + if not ret: + node = do_add_node(gen, lustre, options, node_name) + else: + node = ret + set_node_options(gen, node, options) + + net_name = new_name('NET_'+ node_name +'_'+ net_type) + net_uuid = new_uuid(net_name) + node.appendChild(gen.network(net_name, net_uuid, nid, cluster_id, net_type, + hostaddr, port, tcpbuf, irq_aff)) + node_add_profile(gen, node, "network", net_uuid) + + +def add_route(gen, lustre, options): + """ create a node with a network config """ + + node_name = get_option(options, 'node') + gw_net_type = get_option(options, 'nettype') + gw = get_option(options, 'gw') + gw_cluster_id = get_option(options, 'gateway_cluster_id') + tgt_cluster_id = get_option(options, 'target_cluster_id') + lo = get_option(options, 'lo') + hi = get_option(options, 'hi') + if not hi: + hi = lo + + node = findByName(lustre, node_name, "node") + if not node: + error (node_name, " not found.") + + rlist = node.getElementsByTagName('routetbl') + if len(rlist) > 0: + rtbl = rlist[0] + else: + rtbl_name = new_name("RTBL_" + node_name) + rtbl_uuid = new_uuid(rtbl_name) + rtbl = gen.routetbl(rtbl_name, rtbl_uuid) + node.appendChild(rtbl) + node_add_profile(gen, node, "routetbl", rtbl_uuid) + rtbl.appendChild(gen.route(gw_net_type, gw, gw_cluster_id, tgt_cluster_id, + lo, hi)) + + +def add_mds(gen, lustre, options): + node_name = get_option(options, 'node') + mds_name = get_option(options, 'mds') + lmv_name = get_option(options, 'lmv') + mdd_name = new_name("MDD_" + mds_name +"_" + node_name) + mdd_uuid = new_uuid(mdd_name) + + lmv_uuid = "" + if lmv_name: + lmv = findByName(lustre, lmv_name, "lmv") + if not lmv: + error('add_mds:', '"' + lmv_name + '"', "lmv element not found.") + lmv_uuid = name2uuid(lustre, lmv_name, fatal=0) + + mds_uuid = name2uuid(lustre, mds_name, 'mds', fatal=0) + if not mds_uuid: + mds_uuid = new_uuid(mds_name) + mds = gen.mds(mds_name, mds_uuid, mdd_uuid, options.group) + lustre.appendChild(mds) + if lmv_name: + lmv_add_obd(gen, lmv, mds_uuid) + else: + mds = lookup(lustre, mds_uuid) + + if options.failover: + mds.setAttribute('failover', "1") + + devname = get_option(options, 'dev') + backdevname = get_option(options, 'backdev') + size = get_option(options, 'size') + fstype = get_option(options, 'fstype') + backfstype = get_option(options, 'backfstype') + journal_size = get_option(options, 'journal_size') + inode_size = get_option(options, 'inode_size') + nspath = get_option(options, 'nspath') + mkfsoptions = get_option(options, 'mkfsoptions') + mountfsoptions = get_option(options, 'mountfsoptions') + + node_uuid = name2uuid(lustre, node_name, 'node') + + node = findByName(lustre, node_name, "node") + node_add_profile(gen, node, "mdsdev", mdd_uuid) + net_uuid = get_net_uuid(lustre, node_name) + if not net_uuid: + error("NODE: ", node_name, "not found") + + if lmv_name: + mds.appendChild(gen.ref("lmv", lmv_uuid)) + + mdd = gen.mdsdev(mdd_name, mdd_uuid, fstype, devname, + get_format_flag(options), node_uuid, mds_uuid, + size, journal_size, inode_size, nspath, mkfsoptions, + mountfsoptions, backfstype, backdevname, lmv_uuid) + lustre.appendChild(mdd) + + +def add_mgmt(gen, lustre, options): + node_name = get_option(options, 'node') + node_uuid = name2uuid(lustre, node_name, 'node') + mgmt_name = get_option(options, 'mgmt') + if not mgmt_name: + mgmt_name = new_name('MGMT_' + node_name) + mgmt_uuid = name2uuid(lustre, mgmt_name, 'mgmt', fatal=0) + if not mgmt_uuid: + mgmt_uuid = new_uuid(mgmt_name) + mgmt = gen.mgmt(mgmt_name, mgmt_uuid, node_uuid) + lustre.appendChild(mgmt) + else: + mgmt = lookup(lustre, mgmt_uuid) + + node = findByName(lustre, node_name, "node") + node_add_profile(gen, node, 'mgmt', mgmt_uuid) + +def add_ost(gen, lustre, options): + node_name = get_option(options, 'node') + lovname = get_option(options, 'lov') + osdtype = get_option(options, 'osdtype') + + node_uuid = name2uuid(lustre, node_name, 'node') + + if osdtype == 'obdecho': + fstype = '' + backfstype = '' + devname = '' + backdevname = '' + size = 0 + journal_size = '' + inode_size = '' + mkfsoptions = '' + mountfsoptions = '' + else: + devname = get_option(options, 'dev') # can be unset for bluearcs + backdevname = get_option(options, 'backdev') + size = get_option(options, 'size') + fstype = get_option(options, 'fstype') + backfstype = get_option(options, 'backfstype') + journal_size = get_option(options, 'journal_size') + inode_size = get_option(options, 'inode_size') + mkfsoptions = get_option(options, 'mkfsoptions') + mountfsoptions = get_option(options, 'mountfsoptions') + + nspath = get_option(options, 'nspath') + + ostname = get_option(options, 'ost') + if not ostname: + ostname = new_name('OST_'+ node_name) + + osdname = new_name("OSD_" + ostname + "_" + node_name) + osd_uuid = new_uuid(osdname) + + ost_uuid = name2uuid(lustre, ostname, 'ost', fatal=0) + if not ost_uuid: + ost_uuid = get_option(options, 'ostuuid') + if ost_uuid: + if lookup(lustre, ost_uuid): + error("Duplicate OST UUID:", ost_uuid) + else: + ost_uuid = new_uuid(ostname) + + ost = gen.ost(ostname, ost_uuid, osd_uuid, options.group) + lustre.appendChild(ost) + else: + ost = lookup(lustre, ost_uuid) + + if lovname: + lov = findByName(lustre, lovname, "lov") + if not lov: + error('add_ost:', '"'+lovname+'"', "lov element not found.") + lov_add_obd(gen, lustre, lov, ost_uuid, options) + + if options.failover: + ost.setAttribute('failover', "1") + + + osd = gen.osd(osdname, osd_uuid, fstype, osdtype, devname, + get_format_flag(options), ost_uuid, node_uuid, size, + journal_size, inode_size, nspath, mkfsoptions, + mountfsoptions, backfstype, backdevname) + + node = findByName(lustre, node_name, "node") + +## if node_add_profile(gen, node, 'oss', oss_uuid): +## ossname = 'OSS' +## oss_uuid = new_uuid(ossname) +## oss = gen.oss(ossname, oss_uuid) +## lustre.appendChild(oss) + + node_add_profile(gen, node, 'osd', osd_uuid) + lustre.appendChild(osd) + +def del_ost(gen, lustre, options): + ostname = get_option(options, 'ost') + if not ostname: + raise OptionError("del_ost: --ost requires a ") + ost = findByName(lustre, ostname, "ost") + if not ost: + error('del_ost: ', 'Unable to find ', ostname) + ost_uuid = name2uuid(lustre, ostname, fatal=0) + if not ost_uuid: + error('del_ost: ', 'Unable to find uuid for ', ostname) + lovname = get_option(options, 'lov') + if lovname: + lov = findByName(lustre, lovname, "lov") + if not lov: + error('del_ost:', '"'+lovname+'"', "lov element not found.") + lov_del_obd(gen, lustre, lov, ost_uuid, options) + # if the user specified a speficic LOV don't delete the OST itself + return + + # remove OSD references from all LOVs + for n in lustre.getElementsByTagName('lov'): + lov_del_obd(gen, lustre, n, ost_uuid, options) + if not options.migrate: + return + # delete the OSDs + for osd in lustre.getElementsByTagName('osd'): + if ref_exists(osd, ost_uuid): + osd_uuid = osd.getAttribute('uuid') + # delete all profile references to this OSD + for profile in lustre.getElementsByTagName('profile'): + for osd_ref in profile.getElementsByTagName('osd_ref'): + if osd_uuid == osd_ref.getAttribute('uuidref'): + profile.removeChild(osd_ref) + lustre.removeChild(osd) + + # delete the OST + lustre.removeChild(ost) + +def add_cmobd(gen, lustre, options): + node_name = get_option(options, 'node') + name = get_option(options, 'cmobd') + uuid = new_uuid(name) + + real_name = get_option(options, 'master_dev') + cache_name = get_option(options, 'cache_dev') + + node = findByName(lustre, node_name, "node") + node_add_profile(gen, node, "cmobd", uuid) + real_uuid = node_found_target_by_dev(gen, lustre, node, real_name) + cache_uuid = node_found_target_by_dev(gen, lustre, node, cache_name) + if not real_uuid: + panic("add_cmobd", "can not find real_uuid") + if not cache_uuid: + panic("add_cmobd", "can not find cache_uuid") + cmobd = gen.cmobd(name, uuid, real_uuid, cache_uuid) + lustre.appendChild(cmobd) + +def add_cobd(gen, lustre, options): + node_name = get_option(options, 'node') + name = get_option(options, 'cobd') + uuid = new_uuid(name) + + real_name = get_option(options, 'real_obd') + cache_name = get_option(options, 'cache_obd') + + real_uuid = name2uuid(lustre, real_name, tag='lov', fatal=0) + cache_uuid = name2uuid(lustre, cache_name, tag='lov', fatal=0) + + if real_uuid: + node = lookup(lustre, real_uuid) + rets = node.getElementsByTagName('lov_tgt') + for ret in rets: + ost_uuid = ret.getAttribute('uuidref') + ost_node = lookup(lustre, ost_uuid) + ret = ost_node.getElementsByTagName('active_ref') + if ret: + osd_uuid = ret[0].getAttribute('uuidref') + osd_node = lookup(lustre, osd_uuid) + gen.addElement(osd_node, 'cachetype', 'master') + + if cache_uuid: + node = lookup(lustre, cache_uuid) + rets = node.getElementsByTagName('lov_tgt') + for ret in rets: + ost_uuid = ret.getAttribute('uuidref') + ost_node = lookup(lustre, ost_uuid) + ret = ost_node.getElementsByTagName('active_ref') + if ret: + osd_uuid = ret[0].getAttribute('uuidref') + osd_node = lookup(lustre, osd_uuid) + gen.addElement(osd_node, 'cachetype', 'cache') + + if not real_uuid or not cache_uuid: + real_uuid = name2uuid(lustre,real_name, tag='mds') + cache_uuid = name2uuid(lustre,cache_name, tag='mds') + if real_uuid: + mds_node = lookup(lustre, real_uuid) + ret = mds_node.getElementsByTagName('active_ref') + if ret: + mdsdev_uuid = ret[0].getAttribute('uuidref') + mdsdev_node = lookup(lustre, mdsdev_uuid) + gen.addElement(mdsdev_node, 'cachetype', 'master') + if cache_uuid: + mds_node = lookup(lustre, cache_uuid) + ret = mds_node.getElementsByTagName('active_ref') + if ret: + mdsdev_uuid = ret[0].getAttribute('uuidref') + mdsdev_node = lookup(lustre, mdsdev_uuid) + gen.addElement(mdsdev_node, 'cachetype', 'cache') + + node = findByName(lustre, node_name, "node") + cobd = gen.cobd(name, uuid, real_uuid, cache_uuid) + lustre.appendChild(cobd) + + +def add_echo_client(gen, lustre, options): + """ add an echo client to the profile for this node. """ + node_name = get_option(options, 'node') + lov_name = get_option(options, 'ost') + + node = findByName(lustre, node_name, 'node') + + echoname = new_name('ECHO_'+ node_name) + echo_uuid = new_uuid(echoname) + node_add_profile(gen, node, 'echoclient', echo_uuid) + + lov_uuid = name2uuid(lustre, lov_name, tag='lov', fatal=0) + if not lov_uuid: + lov_uuid = name2uuid(lustre, lov_name, tag='ost', fatal=1) + + echo = gen.echo_client(echoname, echo_uuid, lov_uuid) + lustre.appendChild(echo) + + +def add_lov(gen, lustre, options): + """ create a lov """ + + lmv_name = get_option(options, 'lmv') + lov_orig = get_option(options, 'lov') + name = new_name(lov_orig) + if name != lov_orig: + warning("name:", lov_orig, "already used. using:", name) + + mds_name = get_option(options, 'mds') + if not mds_name: + if not lmv_name: + error("LOV: MDS or LMV must be specified."); + + stripe_sz = get_option_int(options, 'stripe_sz') + stripe_cnt = get_option_int(options, 'stripe_cnt') + pattern = get_option_int(options, 'stripe_pattern') + uuid = new_uuid(name) + + ret = findByName(lustre, name, "lov") + if ret: + error("LOV: ", name, " already exists.") + + if not mds_name: + mds_uuid = name2uuid(lustre, lmv_name, 'lmv') + else: + mds_uuid = name2uuid(lustre, mds_name, 'mds') + + lov = gen.lov(name, uuid, mds_uuid, stripe_sz, stripe_cnt, pattern) + lustre.appendChild(lov) + + # add an lovconfig entry to the active mdsdev profile + lovconfig_name = new_name('LVCFG_' + name) + lovconfig_uuid = new_uuid(lovconfig_name) + if mds_name: + mds = findByName(lustre, mds_name, "mds") + mds.appendChild(gen.ref("lovconfig", lovconfig_uuid)) + if lmv_name: + lmv = findByName(lustre, lmv_name, "lmv") + lmv.appendChild(gen.ref("lovconfig", lovconfig_uuid)) + lovconfig = gen.lovconfig(lovconfig_name, lovconfig_uuid, uuid) + lustre.appendChild(lovconfig) + +def add_default_lov(gen, lustre, mds_name, lov_name): + """ create a default lov """ + + stripe_sz = DEFAULT_STRIPE_SZ + stripe_cnt = DEFAULT_STRIPE_CNT + pattern = DEFAULT_STRIPE_PATTERN + uuid = new_uuid(lov_name) + + ret = findByName(lustre, lov_name, "lov") + if ret: + error("LOV: ", lov_name, " already exists.") + + mds_uuid = name2uuid(lustre, mds_name, 'mds') + lov = gen.lov(lov_name, uuid, mds_uuid, stripe_sz, stripe_cnt, pattern) + lustre.appendChild(lov) + + # add an lovconfig entry to the active mdsdev profile + lovconfig_name = new_name('LVCFG_' + lov_name) + lovconfig_uuid = new_uuid(lovconfig_name) + mds = findByName(lustre, mds_name) + mds.appendChild(gen.ref("lovconfig", lovconfig_uuid)) + lovconfig = gen.lovconfig(lovconfig_name, lovconfig_uuid, uuid) + lustre.appendChild(lovconfig) + +def add_lmv(gen, lustre, options): + """ create a lmv """ + + lmv_orig = get_option(options, 'lmv') + name = new_name(lmv_orig) + if name != lmv_orig: + warning("name:", lmv_orig, "already used. using:", name) + + uuid = new_uuid(name) + ret = findByName(lustre, name, "lmv") + if ret: + error("LMV: ", name, " already exists.") + + lmv = gen.lmv(name, uuid) + lustre.appendChild(lmv) + +def new_filesystem(gen, lustre, mds_uuid, obd_uuid, mgmt_uuid): + fs_name = new_name("FS_fsname") + fs_uuid = new_uuid(fs_name) + cobd = lookup(lustre, mds_uuid) + #SHOULD appendChild filesystem to real mds not cobd + ret = cobd.getElementsByTagName("cacheobd_ref") + if ret: + cacheobd_uuid = ret[0].getAttribute('uuidref') + cacheobd = lookup(lustre, cacheobd_uuid) + cacheobd.appendChild(gen.ref("filesystem", fs_uuid)) + ret = cobd.getElementsByTagName("realobd_ref") + if ret: + realobd_uuid = ret[0].getAttribute('uuidref') + realobd = lookup(lustre, realobd_uuid) + realobd.appendChild(gen.ref("filesystem", fs_uuid)) + else: + cobd.appendChild(gen.ref("filesystem", fs_uuid)) + fs = gen.filesystem(fs_name, fs_uuid, mds_uuid, obd_uuid, mgmt_uuid) + lustre.appendChild(fs) + return fs_uuid + +def get_fs_uuid(gen, lustre, mds_name, obd_name, mgmt_name): + mds_uuid = name2uuid(lustre, mds_name, tag='mds', fatal=0) + if not mds_uuid: + mds_uuid = name2uuid(lustre, mds_name, tag='lmv', fatal=0) + if not mds_uuid: + mds_uuid = name2uuid(lustre, mds_name, tag='cobd', fatal=1) + obd_uuid = name2uuid(lustre, obd_name, tag='lov', fatal=0) + if obd_uuid == '': + obd_uuid = name2uuid(lustre, obd_name, tag='cobd') + if mgmt_name: + mgmt_uuid = name2uuid(lustre, mgmt_name, tag='mgmt', fatal=1) + else: + mgmt_uuid = '' + fs_uuid = lookup_filesystem(lustre, mds_uuid, obd_uuid) + if not fs_uuid: + fs_uuid = new_filesystem(gen, lustre, mds_uuid, obd_uuid, mgmt_uuid) + return fs_uuid + +def add_mtpt(gen, lustre, options): + """ create mtpt on a node """ + node_name = get_option(options, 'node') + + path = get_option(options, 'path') + clientoptions = get_option(options, "clientoptions") + fs_name = get_option(options, 'filesystem') + + lov_name = get_option(options, 'lov') + ost_name = get_option(options, 'ost') + mds_name = get_option(options, 'mds') + if mds_name == '': + mds_name = get_option(options, 'lmv') + if mds_name == '': + error("--add mtpt requires either --mds or --lmv.") + if lov_name == '': + if ost_name == '': + error("--add mtpt requires --lov lov_name or --ost ost_name") + else: + warning("use default value for lov, due no --lov lov_name provided") + lov_name = new_name("lov_default") + add_default_lov(gen, lustre, mds_name, lov_name) + ost_uuid = name2uuid(lustre, ost_name, 'ost', fatal=0) + if not ost_uuid: + error('add_mtpt:', '"'+ost_name+'"', "ost element not found.") + lov = findByName(lustre, lov_name, "lov") + lov_add_obd(gen, lustre, lov, ost_uuid, options) + + if fs_name == '': + mgmt_name = get_option(options, 'mgmt') + fs_uuid = get_fs_uuid(gen, lustre, mds_name, lov_name, mgmt_name) + else: + fs_uuid = name2uuid(lustre, fs_name, tag='filesystem') + + name = new_name('MNT_'+ node_name) + + ret = findByName(lustre, name, "mountpoint") + if ret: + # this can't happen, because new_name creates unique names + error("MOUNTPOINT: ", name, " already exists.") + + uuid = new_uuid(name) + mtpt = gen.mountpoint(name, uuid, fs_uuid, path, clientoptions) + node = findByName(lustre, node_name, "node") + if not node: + error('node:', node_name, "not found.") + node_add_profile(gen, node, "mountpoint", uuid) + lustre.appendChild(mtpt) + +def commit_version(gen, lustre): + update = findLastUpdate(lustre) + if update: + version = int(update.getAttribute("version")) + 1 + else: + version = 1 + + new = gen.update(str(version)) + lustre.appendChild(new) + + +############################################################ # Command line processing # -def usage(): - print """usage: lmc [--ost | --mtpt | --lov] cmd args -Commands: ---ost "device" "host" - Creates an OBD/OST/OSC configuration triplet for a new device. - When used on "host", the device will be initialized and the OST - will be enabled. On client nodes, the OSC will be avaiable. - ---mtpt "mds" "ost/lov-name" /mnt/point - Creates a client mount point. - ---lov "mds" "lov name < "all-ost.xml" - Produces a logical volum striped over the OSTs found in all-ost.xml. - (Not sure how all-ost.xml is created, exactly.) - -Options: ---merge="xml file" Add the new objects to an existing file ---format Format the partitions if unformated ---reformat Reformat partitions (this should be an lconf arg, - I think) -(SCRIPT STILL UNDER DEVELOPMENT, MOST COMMANDS/OPTIONS UNIMPLEMENTED) -""" +class OptionError (exceptions.Exception): + def __init__(self, args): + self.args = args + +def get_option(options, tag): + """Look for tag in options hash and return the value if set. If not + set, then if return default it is set, otherwise exception.""" + if options.__getattr__(tag) != None: + return options.__getattr__(tag) + else: + raise OptionError("--add %s requires --%s " % (options.add, tag)) -def cmdline(argv): - short_opts = "ho:" - long_opts = ["ost", "mtpt", "lov", - "merge=", "format", "reformat", "output=", - "help"] - opts = [] - args = [] - options = {} +def get_option_int(options, tag): + """Return an integer option. Raise exception if the value is not an int""" + val = get_option(options, tag) try: - opts, args = getopt.getopt(argv, short_opts, long_opts) - except getopt.GetoptError: - print "invalid opt" - usage() - sys.exit(2) + n = int(val) + except ValueError: + raise OptionError("--%s (value must be integer)" % (tag)) + return n - for o, a in opts: - if o in ("-h", "--help"): - usage() - sys.exit() - if o in ("-o", "--output"): - options['output'] = a - if o == "--ost": - options['ost'] = 1 - if o == "--merge": - options['merge'] = a - if o == "--format": - options['format'] = 1 - if o == "--reformat": - options['reformat'] = 1 - - return options, args +# simple class for profiling +import time +class chrono: + def __init__(self): + self._start = 0 + def start(self): + self._stop = 0 + self._start = time.time() + def stop(self, msg=''): + self._stop = time.time() + if msg: + self.display(msg) + def dur(self): + return self._stop - self._start + def display(self, msg): + d = self.dur() + str = '%s: %g secs' % (msg, d) + print str -def main(): - options, args = cmdline(sys.argv[1:]) +################################################################# +# function cmdlinesplit used to split cmd line from batch file +# +def cmdlinesplit(cmdline): + + double_quote = re.compile(r'"(([^"\\]|\\.)*)"') + single_quote = re.compile(r"'(.*?)'") + escaped = re.compile(r'\\(.)') + esc_quote = re.compile(r'\\([\\"])') + outside = re.compile(r"""([^\s\\'"]+)""") #" fucking emacs. + + arg_list = [] + i = 0; arg = None + while i < len(cmdline): + c = cmdline[i] + if c == '"': + match = double_quote.match(cmdline, i) + if not match: + print "Unmatched double quote:", cmdline + sys.exit(1) + i = match.end() + if arg is None: arg = esc_quote.sub(r'\1', match.group(1)) + else: arg = arg + esc_quote.sub(r'\1', match.group(1)) + + elif c == "'": + match = single_quote.match(cmdline, i) + if not match: + print "Unmatched single quote:", cmdline + sys.exit(1) + i = match.end() + if arg is None: arg = match.group(1) + else: arg = arg + match.group(1) + + elif c == "\\": + match = escaped.match(cmdline, i) + if not match: + print "Unmatched backslash", cmdline + sys.exit(1) + i = match.end() + if arg is None: arg = match.group(1) + else: arg = arg + match.group(1) + + elif c in string.whitespace: + if arg != None: + arg_list.append(str(arg)) + arg = None + while i < len(cmdline) and cmdline[i] in string.whitespace: + i = i + 1 + else: + match = outside.match(cmdline, i) + assert match + i = match.end() + if arg is None: arg = match.group() + else: arg = arg + match.group() + + if arg != None: arg_list.append(str(arg)) + + return arg_list + +############################################################ +# Main +# + +def add(devtype, gen, lustre, options): + if devtype == 'net': + add_net(gen, lustre, options) + elif devtype == 'mtpt': + add_mtpt(gen, lustre, options) + elif devtype == 'mds': + add_mds(gen, lustre, options) + elif devtype == 'ost': + add_ost(gen, lustre, options) + elif devtype == 'lov': + add_lov(gen, lustre, options) + elif devtype == 'route': + add_route(gen, lustre, options) + elif devtype == 'node': + add_node(gen, lustre, options) + elif devtype == 'echo_client': + add_echo_client(gen, lustre, options) + elif devtype == 'cobd': + add_cobd(gen, lustre, options) + elif devtype == 'cmobd': + add_cmobd(gen, lustre, options) + elif devtype == 'mgmt': + add_mgmt(gen, lustre, options) + elif devtype == 'lmv': + add_lmv(gen, lustre, options) + else: + error("unknown device type:", devtype) + +def delete(devtype, gen, lustre, options): + if devtype == 'ost': + del_ost(gen, lustre, options) + elif options.delete: + error("delete not supported for device type:", devtype) + elif options.deactivate: + error("deactivate not supported for device type:", devtype) + else: + error("in delete(), but neither .delete nor .deactivate are set. Tell CFS.") + +def commit(gen, lustre): + commit_version(gen, lustre) - if options.has_key('merge'): - outFile = options['merge'] - dom = xml.dom.minidom.parse(outFile) +def do_command(gen, lustre, options, args): + if options.add: + add(options.add, gen, lustre, options) + elif options.delete: + delete(options.delete, gen, lustre, options) + elif options.deactivate: + delete(options.deactivate, gen, lustre, options) + elif options.commit: + commit(gen, lustre) else: - if options.has_key('output'): - outFile = options['output'] + error("Missing command") + +def main(): + cl = Lustre.Options("lmc", "", lmc_options) + try: + options, args = cl.parse(sys.argv[1:]) + except Lustre.OptionError, e: + panic("lmc", e) + + if len(args) > 0: + panic(string.join(sys.argv), "Unexpected extra arguments on command line: " + string.join(args)) + + if options.reference: + reference() + sys.exit(0) + + outFile = '-' + + if options.merge: + outFile = options.merge + if os.access(outFile, os.R_OK): + doc = xml.dom.minidom.parse(outFile) else: - outFile = '-' - dom = new_Lustre() - - if options.has_key('ost'): - add_OST(dom, options, args) - elif options.has_key('mtpt'): - print "--mtpt not implemented" - elif options.has_key('lov'): - print "--mtpt not implemented" - else: - print "Missing command" - usage() + doc = new_lustre(xml.dom.minidom) + elif options.input: + doc = xml.dom.minidom.parse(options.input) + else: + doc = new_lustre(xml.dom.minidom) + + if options.output: + outFile = options.output + + lustre = doc.documentElement + init_names(lustre) + if lustre.tagName != "lustre": + print "Existing config not valid." sys.exit(1) - + + gen = GenConfig(doc) + + if options.batch: + fp = open(options.batch) + batchCommands = fp.readlines() + fp.close() + for cmd in batchCommands: + try: + options, args = cl.parse(cmdlinesplit(cmd)) + if options.merge or options.input or options.output: + print "The batchfile should not contain --merge, --input or --output." + sys.exit(1) + do_command(gen, lustre, options, args) + except OptionError, e: + panic(cmd, e) + except Lustre.OptionError, e: + panic(cmd, e) + else: + try: + do_command(gen, lustre, options, args) + except OptionError, e: + panic(string.join(sys.argv),e) + except Lustre.OptionError, e: + panic("lmc", e) if outFile == '-': - print dom.toxml() + printDoc(doc) else: - dom.writexml(open(outFile,"w")) - + printDoc(doc, open(outFile,"w")) + if __name__ == "__main__": main()