X-Git-Url: https://git.whamcloud.com/?a=blobdiff_plain;f=lustre%2Futils%2Flmc;h=a341dd86daaec1479292fe44bea547b66acee980;hb=9f59ef764e80542d82f3b78902615124ddac1020;hp=66f046a5b782448752bd20b840fa57d1d5772dad;hpb=38ea697f11b7ccb2c00e769b10128db40ab6e6dd;p=fs%2Flustre-release.git diff --git a/lustre/utils/lmc b/lustre/utils/lmc index 66f046a..a341dd8 100755 --- a/lustre/utils/lmc +++ b/lustre/utils/lmc @@ -1,7 +1,6 @@ #!/usr/bin/env python -# -# Copyright (C) 2002 Cluster File Systems, Inc. -# Author: Robert Read +# Copyright (C) 2002 Cluster File Systems, Inc. +# Author: Robert Read # This file is part of Lustre, http://www.lustre.org. # @@ -20,80 +19,205 @@ # """ -lmc - lustre configurtion data manager - - Basic plan for lmc usage: -# create nodes -./lmc --output config.xml --node server --net server1 tcp -./lmc --merge config.xml --node client --net client1 tcp +lmc - lustre configuration data manager + See Lustre book (http://www.lustre.org/docs/lustre.pdf) for documentation on lmc. -# configure server -./lmc --merge config.xml --node server --mds mds1 /tmp/mds1 50000 +""" -# create lov -./lmc --merge config.xml --lov lov1 mds1 65536 0 0 -./lmc --merge config.xml --node server --lov lov1 --ost /tmp/ost1 100000 -./lmc --merge config.xml --node server --lov lov1 --ost /tmp/ost2 100000 +import sys, os, getopt, string, exceptions, re +import xml.dom.minidom -# create client config -./lmc --merge config.xml --node client --mtpt /mnt/lustre mds1 lov1 +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|scimac + --hostaddr addr + --port port + --tcpbuf size + --irq_affinity 0|1 + --router + +--add mds + --node node_name + --mds mds_name + --dev path + --fstype extN|ext3 + --size size + --nspath + --journal_size size + --inode_size size + +--add lov + --lov lov_name + --mds mds_name + --stripe_sz num + --stripe_cnt num + --stripe_pattern num + +--add ost + --node node_name + --ost ost_name + --lov lov_name + --dev path + --size size + --fstype extN|ext3 + --journal_size size + --inode_size size + --obdtype obdecho|obdfilter + --ostuuid uuid + +--add mtpt - Mountpoint + --node node_name + --path /mnt/point + --mds mds_name + --ost ost_name OR --lov lov_name + +--add route + --node nodename + --gw nid + --tgt nid + --lo nid + --hi nid + +--add echo_client + --node nodename + +--add mgmt - Management/monitoring service + --node node_name + --mgmt mgmt_service_name """ -import sys, getopt, string -import xml.dom.minidom -from xml.dom.ext import PrettyPrint - - -DEFAULT_PORT = 988 # XXX What is the right default acceptor port to use? - -def usage(): - print """usage: lmc [--node --ost | --mtpt | --lov] args -Commands: ---node node_name - Node_name by itself it will create a new node. When used with other - commands it specifies the node to modify - ---net hostname nettype [port, recv_buf, send_buf] - Nettype is either tcp, elan, or gm. - Requires a node argument - ---lov lov_name [mdc_name stripe_sz stripe_off pattern] - Creates a logical volume - When used with other commands, it specifics the lov to modify - ---mds device [size] - Create a MDS using the device - Requires --node - ---mdc mdc_name - Configures a MDC for a node. - Requires --node - ---ost device [size] - 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. - Requires --node - If --lov lov_name is used, this device is added to lov. - ---mtpt /mnt/point mdc_name lov_name|osc_name - Creates a client mount point. - Requires --node - -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) -""" - sys.exit(1) +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), + + # 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/scimac.", 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,""), + ('size', "Specify the size of the device if needed.", PARAM,"0"), + ('journal_size', "Specify new journal size for underlying ext3 file system.", PARAM,"0"), + ('inode_size', "Specify new inode size for underlying ext3 file system.", PARAM,"0"), + ('fstype', "Optional argument to specify the filesystem type.", PARAM, "ext3"), + ('mkfsoptions', "Optional argument to mkfs.", PARAM, ""), + ('ostuuid', "", PARAM,""), + ('nspath', "Local mount point of server namespace.", PARAM,""), + ('format', ""), + + # clients: mountpoint and echo + ('echo_client', "", PARAM), + ('path', "Specify the mountpoint for Lustre.", PARAM), + ('filesystem', "Lustre filesystem name", PARAM,""), + + # lov + ('lov', "Specify LOV name.", 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', "", PARAM), + ('cache_obd', "", PARAM), + + ('mgmt', "Specify management/monitoring service 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 @@ -110,15 +234,29 @@ def new_name(base): 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 + ldlm_name = 'ldlm' ldlm_uuid = 'ldlm_UUID' + def new_lustre(dom): """Create a new empty lustre document""" # adding ldlm here is a bit of a hack, but one is enough. - str = """ """ % (ldlm_name, ldlm_uuid) + str = """ + + """ % (Lustre.CONFIG_VERSION, ldlm_name, ldlm_uuid) return dom.parseString(str) names = {} @@ -136,11 +274,13 @@ def init_names(doc): init_names(n) def get_format_flag(options): - if options.has_key('format'): - if options['format']: - return 'yes' + if options.format: + return 'yes' return 'no' +############################################################ +# Build config objects using DOM +# class GenConfig: doc = None dom = None @@ -157,8 +297,8 @@ class GenConfig: def newService(self, tag, name, uuid): """ create a new service elmement, which requires name and uuid attributes """ new = self.doc.createElement(tag) - new.setAttribute("name", name); new.setAttribute("uuid", uuid); + new.setAttribute("name", name); return new def addText(self, node, str): @@ -174,19 +314,51 @@ class GenConfig: node.appendChild(new) return new - def network(self, name, uuid, hostname, net, port=0): + 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("type", net); - self.addElement(network, "server", hostname) + 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 node(self, name, uuid): + 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) - self.addElement(node, 'profile') + node.appendChild(self.ref("profile", prof_uuid)) return node def ldlm(self, name, uuid): @@ -194,63 +366,117 @@ class GenConfig: ldlm = self.newService("ldlm", name, uuid) return ldlm - def obd(self, name, uuid, fs, devname, format, dev_size=0): - obd = self.newService("obd", name, uuid) - obd.setAttribute('type', 'obdfilter') - self.addElement(obd, "fstype", fs) - dev = self.addElement(obd, "device", devname) - if (dev_size): - dev.setAttribute("size", "%s" % (dev_size)) - self.addElement(obd, "autoformat", format) - return obd - - def osc(self, name, uuid, obd_uuid, net_uuid): - osc = self.newService("osc", name, uuid) - osc.appendChild(self.ref("ost", net_uuid)) - osc.appendChild(self.ref("obd", obd_uuid)) - return osc - - def ost(self, name, uuid, obd_uuid, net_uuid): + def osd(self, name, uuid, fs, osdtype, devname, format, ost_uuid, + node_uuid, dev_size=0, journal_size=0, inode_size=0, nspath="", mkfsoptions=""): + osd = self.newService("osd", name, uuid) + osd.setAttribute('osdtype', osdtype) + osd.appendChild(self.ref("target", ost_uuid)) + osd.appendChild(self.ref("node", node_uuid)) + if fs: + self.addElement(osd, "fstype", fs) + 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 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 ost(self, name, uuid, osd_uuid, group=""): ost = self.newService("ost", name, uuid) - ost.appendChild(self.ref("network", net_uuid)) - ost.appendChild(self.ref("obd", obd_uuid)) + ost.appendChild(self.ref("active", osd_uuid)) + if group: + self.addElement(ost, "group", group) return ost - def lov(self, name, uuid, mds_uuid, stripe_sz, stripe_off, pattern): + 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)) - devs = self.addElement(lov, "devices" ) - devs.setAttribute("stripesize", stripe_sz) - devs.setAttribute("stripeoffset", stripe_off) - devs.setAttribute("pattern", pattern) + lov.setAttribute("stripesize", str(stripe_sz)) + lov.setAttribute("stripecount", str(stripe_cnt)) + lov.setAttribute("stripepattern", str(pattern)) return lov - def mds(self, name, uuid, fs, devname, format, net_uuid, node_uuid, - failover_uuid = "", dev_size=0 ): + def lovconfig(self, name, uuid, lov_uuid): + lovconfig = self.newService("lovconfig", name, uuid) + lovconfig.appendChild(self.ref("lov", lov_uuid)) + return lovconfig + + def mds(self, name, uuid, mdd_uuid, group=""): mds = self.newService("mds", name, uuid) - self.addElement(mds, "fstype", fs) - dev = self.addElement(mds, "device", devname) - if dev_size: - dev.setAttribute("size", "%s" % (dev_size)) - self.addElement(mds, "autoformat", format) - mds.appendChild(self.ref("network", net_uuid)) - mds.appendChild(self.ref("node", node_uuid)) - if failover_uuid: - mds.appendChild(self.ref("failover", failover_uuid)) + mds.appendChild(self.ref("active",mdd_uuid)) + if group: + self.addElement(mds, "group", group) return mds - def mdc(self, name, uuid, mds_uuid): - mdc = self.newService("mdc", name, uuid) - mdc.appendChild(self.ref("mds", mds_uuid)) - return mdc - - def mountpoint(self, name, uuid, mdc_uuid, osc_uuid, path): + def mdsdev(self, name, uuid, fs, devname, format, node_uuid, + mds_uuid, dev_size=0, journal_size=0, inode_size=256, + nspath="", mkfsoptions=""): + mdd = self.newService("mdsdev", name, uuid) + self.addElement(mdd, "fstype", fs) + dev = self.addElement(mdd, "devpath", devname) + 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) + mdd.appendChild(self.ref("node", node_uuid)) + mdd.appendChild(self.ref("target", mds_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): mtpt = self.newService("mountpoint", name, uuid) - mtpt.appendChild(self.ref("mdc", mdc_uuid)) - mtpt.appendChild(self.ref("osc", osc_uuid)) + mtpt.appendChild(self.ref("filesystem", fs_uuid)) self.addElement(mtpt, "path", path) 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 + +############################################################ +# 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') @@ -270,6 +496,7 @@ def findByName(lustre, name, tag = ""): if n: return n return None + def lookup(node, uuid): for n in node.childNodes: if n.nodeType == n.ELEMENT_NODE: @@ -279,319 +506,495 @@ def lookup(node, uuid): n = lookup(n, uuid) if n: return n return None - -def mds2node(lustre, mds_name): - """ Find the node a MDS is configured on """ - mds = findByName(lustre, mds_name, 'mds') - ref = mds.getElementsByTagName('node_ref') - if not ref: - error("no node found for:", mds_name) - node_uuid = ref[0].getAttribute('uuidref') - node = lookup(lustre, node_uuid) - if not node: - error("no node found for :", mds_name) - return node def name2uuid(lustre, name, tag="", fatal=1): ret = findByName(lustre, name, tag) if not ret: if fatal: - error('name2uuid:', name, "not found.") + 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 ("node not found:", node_name) + error ('get_net_uuid:', '"'+node_name+'"', "node element not found.") net = node.getElementsByTagName('network') if net: return getUUID(net[0]) return None -def lov_add_osc(gen, lov, osc_uuid): - devs = lov.getElementsByTagName('devices') - if len(devs) == 1: - devs[0].appendChild(gen.ref("osc", osc_uuid)) - else: - error("No devices element found for LOV:", lov) + +def lov_add_obd(gen, lov, osc_uuid): + lov.appendChild(gen.ref("obd", osc_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): - ret = node.getElementsByTagName('profile') + refname = "%s_ref" % "profile" + ret = node.getElementsByTagName(refname) if not ret: - error('node has no profile:', node) - ret[0].appendChild(gen.ref(ref, uuid)) + 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 +def get_attr(dom_node, attr, default=""): + v = dom_node.getAttribute(attr) + if v: + return v + return default + +############################################################ +# Top level commands # -# Create a new obd, osc, and ost. Add them to the DOM. -# -def add_ost(gen, lustre, options, args): - if len(args) < 1: - usage() - - if options.has_key('node'): - node_name = options['node'] - else: - error("--ost requires a --node argument") - - if options.has_key('lov'): - lovname = options['lov'] +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: - lovname = '' + 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 - devname = args[0] - if len(args) > 1: - size = args[1] - else: - size = 0 +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) - obdname = new_name('OBD_'+ node_name) - oscname = new_name('OSC_'+ node_name) - ostname = new_name('OST_'+ node_name) - obd_uuid = get_uuid(obdname) - ost_uuid = get_uuid(ostname) - osc_uuid = get_uuid(oscname) + node_add_profile(gen, node, 'ldlm', ldlm_uuid) + set_node_options(gen, node, options) + return node - net_uuid = get_net_uuid(lustre, node_name) - if not net_uuid: - error("NODE: ", node_name, "not found") - - obd = gen.obd(obdname, obd_uuid, "extN", devname, get_format_flag(options), size) - ost = gen.ost(ostname, ost_uuid, obd_uuid, net_uuid) - osc = gen.osc(oscname, osc_uuid, obd_uuid, ost_uuid) - if lovname: - lov = findByName(lustre, lovname, "lov") - if not lov: - error("LOV:", lovname, "not found.") - lov_add_osc(gen, lov, osc_uuid) +def add_node(gen, lustre, options): + """ create a node with a network config """ - node = findByName(lustre, node_name, "node") - node_add_profile(gen, node, 'obd', obd_uuid) - node_add_profile(gen, node, 'ost', ost_uuid) + 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) - lustre.appendChild(obd) - lustre.appendChild(osc) - lustre.appendChild(ost) - -def add_net(gen, lustre, options, args): - """ create a node with a network config """ - if len(args) < 2: - usage() - node_name = options['node'] - nid = args[0] - net_type = args[1] +def add_net(gen, lustre, options): + """ create a node with a network config """ - if net_type == 'tcp': - if len(args) > 2: - port = int(args[2]) - else: - port = DEFAULT_PORT - # add send, recv buffer size here - elif net_type in ('elan', 'gm'): + 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', 'scimac'): 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, node_name) + 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 = get_uuid(net_name) - node.appendChild(gen.network(net_name, net_uuid, nid, net_type, port)) + 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 do_add_node(gen, lustre, node_name): - uuid = get_uuid(node_name) - node = gen.node(node_name, uuid) - node_add_profile(gen, node, 'ldlm', ldlm_uuid) - lustre.appendChild(node) - return node - -def add_node(gen, lustre, options, args): + +def add_route(gen, lustre, options): """ create a node with a network config """ - if len(args) > 1: - usage() - node_name = options['node'] + 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 - ret = findByName(lustre, node_name, "node") - if ret: - print "Node:", node_name, "exists." - return - do_add_node(gen, lustre, node_name) + 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') + mdd_name = new_name("MDD_" + mds_name +"_" + node_name) + mdd_uuid = new_uuid(mdd_name) + + 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) + else: + mds = lookup(lustre, mds_uuid) + if options.failover: + mds.setAttribute('failover', "1") + devname = get_option(options, 'dev') + size = get_option(options, 'size') + fstype = get_option(options, 'fstype') + journal_size = get_option(options, 'journal_size') + inode_size = get_option(options, 'inode_size') + nspath = get_option(options, 'nspath') + mkfsoptions = get_option(options, 'mkfsoptions') -def add_lov(gen, lustre, options, args): - """ create a lov """ - if len(args) < 4: - usage() + 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") - name = options['lov'] - mds_name = args[0] - stripe_sz = args[1] - stripe_off = args[2] - pattern = args[3] - uuid = get_uuid(name) + mdd = gen.mdsdev(mdd_name, mdd_uuid, fstype, devname, + get_format_flag(options), node_uuid, mds_uuid, + size, journal_size, inode_size, nspath, mkfsoptions) + lustre.appendChild(mdd) + - ret = findByName(lustre, name, "lov") - if ret: - error("LOV: ", name, " already exists.") +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) - mds_uuid = name2uuid(lustre, mds_name) + node = findByName(lustre, node_name, "node") + node_add_profile(gen, node, 'mgmt', mgmt_uuid) - node = mds2node(lustre, mds_name) - node_add_profile(gen, node, "lov", uuid) - lov = gen.lov(name, uuid, mds_uuid, stripe_sz, stripe_off, pattern) - lustre.appendChild(lov) +def add_ost(gen, lustre, options): + node_name = get_option(options, 'node') + lovname = get_option(options, 'lov') + osdtype = get_option(options, 'osdtype') -def add_mtpt(gen, lustre, options, args): - """ create mtpt on a node """ - if len(args) < 3: - usage() + node_uuid = name2uuid(lustre, node_name, 'node') - if options.has_key('node'): - node_name = options['node'] + if osdtype == 'obdecho': + fstype = '' + devname = '' + size = 0 + fstype = '' + journal_size = '' + inode_size = '' + mkfsoptions = '' + else: + devname = get_option(options, 'dev') # can be unset for bluearcs + size = get_option(options, 'size') + fstype = get_option(options, 'fstype') + journal_size = get_option(options, 'journal_size') + inode_size = get_option(options, 'inode_size') + mkfsoptions = get_option(options, 'mkfsoptions') + + 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) + if lovname: + lov = findByName(lustre, lovname, "lov") + if not lov: + error('add_ost:', '"'+lovname+'"', "lov element not found.") + lov_add_obd(gen, lov, ost_uuid) else: - error("--mtpt requires a --node argument") + ost = lookup(lustre, ost_uuid) - path = args[0] - mds_name = args[1] - lov_name = args[2] - mdc_name = 'MDC_' + mds_name + if options.failover: + ost.setAttribute('failover', "1") + - name = new_name('MNT_'+ node_name) + osd = gen.osd(osdname, osd_uuid, fstype, osdtype, devname, + get_format_flag(options), ost_uuid, node_uuid, size, + journal_size, inode_size, nspath, mkfsoptions) - ret = findByName(lustre, name, "mountpoint") - if ret: - error("MOUNTPOINT: ", name, " already exists.") + 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 add_cobd(gen, lustre, options): + node_name = get_option(options, 'node') + name = new_name('COBD_' + node_name) + 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='obd') + cache_uuid = name2uuid(lustre, cache_name, tag='obd') + + node = findByName(lustre, node_name, "node") + node_add_profile(gen, node, "cobd", uuid) + 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) - mdc_uuid = name2uuid(lustre, mdc_name) lov_uuid = name2uuid(lustre, lov_name, tag='lov', fatal=0) if not lov_uuid: - lov_uuid = name2uuid(lustre, lov_name, tag='osc', fatal=1) + lov_uuid = name2uuid(lustre, lov_name, tag='ost', fatal=1) - uuid = get_uuid(name) - mtpt = gen.mountpoint(name, uuid, mdc_uuid, lov_uuid, path) - node = findByName(lustre, node_name, "node") - if not node: - error('node:', node_name, "not found.") - node_add_profile(gen, node, "mountpoint", uuid) - node_add_profile(gen, node, "mdc", mdc_uuid) - lustre.appendChild(mtpt) + echo = gen.echo_client(echoname, echo_uuid, lov_uuid) + lustre.appendChild(echo) -def add_mdc(gen, lustre, options, args): - """ create mtpt on a node """ - if len(args) < 1: - usage() - if options.has_key('node'): - node_name = options['node'] - else: - error("--mdc requires a --node argument") +def add_lov(gen, lustre, options): + """ create a lov """ - mdc_name = args[0] - mdc_uuid = name2uuid(lustre, mdc_name) + lov_orig = get_option(options, 'lov') + name = new_name(lov_orig) + if name != lov_orig: + warning("name:", lov_orig, "already used. using:", name) - node = findByName(lustre, node_name, "node") - if not node: - error('node:', node_name, "not found.") - node_add_profile(gen, node, "mdc", mdc_uuid) + mds_name = get_option(options, 'mds') + 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) -def add_mds(gen, lustre, options, args): - if len(args) < 1: - usage() + ret = findByName(lustre, name, "lov") + if ret: + error("LOV: ", name, " already exists.") - if options.has_key('node'): - node_name = options['node'] + 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) + mds = findByName(lustre, mds_name, "mds") + mds.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 new_filesystem(gen, lustre, mds_uuid, obd_uuid, mgmt_uuid): + fs_name = new_name("FS_fsname") + fs_uuid = new_uuid(fs_name) + mds = lookup(lustre, mds_uuid) + mds.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') + obd_uuid = name2uuid(lustre, obd_name, tag='lov', fatal=0) + if mgmt_name: + mgmt_uuid = name2uuid(lustre, mgmt_name, tag='mgmt', fatal=1) else: - error("--mds requires a --node argument") + 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') + fs_name = get_option(options, 'filesystem') - mds_name = new_name(options['mds']) - devname = args[0] - if len(args) > 1: - size = args[1] + lov_name = get_option(options, 'lov') + ost_name = get_option(options, 'ost') + mds_name = get_option(options, 'mds') + 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, lov, ost_uuid) + + if fs_name == '': + mgmt_name = get_option(options, 'mgmt') + fs_uuid = get_fs_uuid(gen, lustre, mds_name, lov_name, mgmt_name) else: - size = 0 + fs_uuid = name2uuid(lustre, fs_name, tag='filesystem') - mdc_name = 'MDC_' + mds_name - mds_uuid = get_uuid(mds_name) - mdc_uuid = get_uuid(mdc_name) + name = new_name('MNT_'+ node_name) - node_uuid = name2uuid(lustre, 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) node = findByName(lustre, node_name, "node") - node_add_profile(gen, node, "mds", mds_uuid) - net_uuid = get_net_uuid(lustre, node_name) - if not net_uuid: - error("NODE: ", node_name, "not found") - - - mds = gen.mds(mds_name, mds_uuid, "extN", devname, get_format_flag(options), - net_uuid, node_uuid, dev_size=size) - mdc = gen.mdc(mdc_name, mdc_uuid, mds_uuid) - lustre.appendChild(mds) - lustre.appendChild(mdc) - + if not node: + error('node:', node_name, "not found.") + node_add_profile(gen, node, "mountpoint", uuid) + lustre.appendChild(mtpt) -# +############################################################ # Command line processing # +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 parse_cmdline(argv): - short_opts = "ho:i:m:" - long_opts = ["ost", "mtpt", "lov=", "node=", "mds=", "net", - "mdc", "merge=", "format", "reformat", "output=", - "in=", "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.error: - print "invalid opt" - usage() - - for o, a in opts: - if o in ("-h", "--help"): - usage() - if o in ("-o", "--output"): - options['output'] = a - if o == "--ost": - options['ost'] = 1 - if o == "--mds": - options['mds'] = a - if o == "--mdc": - options['mdc'] = 1 - if o == "--net": - options['net'] = 1 - if o == "--mtpt": - options['mtpt'] = 1 - if o == "--node": - options['node'] = a - if o == "--lov": - options['lov'] = a - if o in ("-m", "--merge"): - options['merge'] = a - if o == "--format": - options['format'] = 1 - if o == "--reformat": - options['reformat'] = 1 - if o in ("--in" , "-i"): - options['in'] = a - - return options, args - + n = int(val) + except ValueError: + raise OptionError("--%s (value must be integer)" % (tag)) + return n +# simple class for profiling import time class chrono: def __init__(self): @@ -610,21 +1013,128 @@ class chrono: str = '%s: %g secs' % (msg, d) print str +################################################################# +# 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\\'"]+)""") + + 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 == 'mgmt': + add_mgmt(gen, lustre, options) + else: + error("unknown device type:", devtype) + +def do_command(gen, lustre, options, args): + if options.add: + add(options.add, gen, lustre, options) + else: + error("Missing command") def main(): - options, args = parse_cmdline(sys.argv[1:]) + 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.has_key('merge'): - outFile = options['merge'] - doc = xml.dom.minidom.parse(outFile) - elif options.has_key('in'): - doc = xml.dom.minidom.parse(options['in']) + if options.merge: + outFile = options.merge + if os.access(outFile, os.R_OK): + doc = xml.dom.minidom.parse(outFile) + else: + 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.has_key('output'): - outFile = options['output'] + if options.output: + outFile = options.output lustre = doc.documentElement init_names(lustre) @@ -633,30 +1143,34 @@ def main(): sys.exit(1) gen = GenConfig(doc) - if options.has_key('ost'): - add_ost(gen, lustre, options, args) - elif options.has_key('mtpt'): - add_mtpt(gen, lustre, options, args) - elif options.has_key('mds'): - add_mds(gen, lustre, options, args) - elif options.has_key('mdc'): - add_mdc(gen, lustre, options, args) - elif options.has_key('net'): - add_net(gen, lustre, options, args) - elif options.has_key('lov'): - add_lov(gen, lustre, options, args) - elif options.has_key('node'): - add_node(gen, lustre, options, args) + + 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: - print "Missing command" - usage() + 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 == '-': - PrettyPrint(doc) + printDoc(doc) else: - PrettyPrint(doc, open(outFile,"w")) + printDoc(doc, open(outFile,"w")) if __name__ == "__main__": main() - -