# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
-# lmc - lustre configurtion data manager
-#
-import sys, getopt
+"""
+lmc - lustre configurtion data manager
+
+ Basic plan for lmc usage:
+ lmc --output config.xml --node nodename nid nettype [port=2346]
+ lmc --merge config.xml --lov lovname stripsize stripeoffset
+ lmc --merge config.xml --ost /dev/name nodename lovname [size=9999]
+ lmc --merge config.xml --mtpt /mnt/lustre lovname nodename
+"""
+
+import sys, getopt, string
import xml.dom.minidom
from xml.dom.ext import PrettyPrint
+from xml.xpath import Evaluate
+DEFAULT_PORT = 888 # XXX What is the right default acceptor port to use?
def usage():
- print """usage: lmc [--ost | --mtpt | --lov] cmd args
+ print """usage: lmc [--node --ost | --mtpt | --lov] args
Commands:
---ost "device" "host" [size]
+--node node_name hostname nettype [port]
+ Node_name is used to refer to this node during the configure process.
+ Nettype is either tcp, elan, or gm.
+
+--lov lov_name mdc_name stripe_sz stripe_off pattern
+ Creates a logical volume
+
+--mds node_name device [size]
+
+--ost device node_name lov_name [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.
+ If lov_name is used, this device is added to lov.
---osc "device" "host" [lov_name]
- Create an osc, and optionally add it to an lov.
-
---mtpt "mds" "ost/lov-name" /mnt/point
+--mtpt node_name mds_name lov_name /mnt/point
Creates a client mount point.
---lov lov_name mdc_name stripe_sz stripe_off pattern
- Produces a logical volum striped over the OSTs found in all-ost.xml.
-
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)
-"""
+"""
+ sys.exit(1)
+def error(*args):
+ msg = string.join(map(str,args))
+ print msg
+ sys.exit(1)
+
#
# 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.
# consider changing this to be like OBD-dev-host
-name_ctr = 1
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)
str = """<lustre> </lustre>"""
return dom.parseString(str)
+names = {}
+uuids = {}
+def init_names(lustre):
+ """initialize auto-name generation tables"""
+ global names, uuids
+ # get all elements that contain a name attribute
+ for n in Evaluate("//@name/..", lustre):
+ names[n.getAttribute("name")] = 1
+ uuids[n.getAttribute("uuid")] = 1
class GenConfig:
doc = None
node.appendChild(new)
return new
- def network(self, name, uuid, net, hostname, port=0):
+ def network(self, name, uuid, hostname, net, port=0):
"""create <network> node"""
network = self.newService("network", name, uuid)
network.setAttribute("type", net);
node = self.newService("node", name, uuid)
return node
- def obd(self, name, uuid, fs, devname, format, dev_size=0, dev_file=""):
+ 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)
def osc(self, name, uuid, obd_uuid, net_uuid):
osc = self.newService("osc", name, uuid)
- osc.appendChild(self.ref("network", net_uuid))
+ osc.appendChild(self.ref("ost", net_uuid))
osc.appendChild(self.ref("obd", obd_uuid))
return osc
ost.appendChild(self.ref("obd", obd_uuid))
return ost
+ def lov(self, name, uuid, stripe_sz, stripe_off, pattern):
+ lov = self.newService("lov", name, uuid)
+ devs = self.addElement(lov, "devices" )
+ devs.setAttribute("stripesize", stripe_sz)
+ devs.setAttribute("stripeoffset", stripe_off)
+ devs.setAttribute("pattern", pattern)
+ return lov
+
+ def mds(self, name, uuid, fs, devname, format, net_uuid, failover_uuid = "", dev_size=0 ):
+ 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))
+ if failover_uuid:
+ mds.appendChild(self.ref("failover", failover_uuid))
+ 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):
+ mtpt = self.newService("mtpt", name, uuid)
+ mtpt.appendChild(self.ref("mdc", mdc_uuid))
+ mtpt.appendChild(self.ref("osc", osc_uuid))
+ self.addElement(mtpt, "path", path)
+ return mtpt
+
+def findByName(lustre, name, tag = "*"):
+ path = '//%s[@name="%s"]' % (tag, name)
+ ret = Evaluate(path, lustre)
+ if ret:
+ return ret[0]
+ 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)
+ net = Evaluate("./network", node)
+ if net:
+ return net[0].getAttribute("uuid")
+ return None
+
+def lov_add_osc(gen, lov, osc_uuid):
+ devs = Evaluate("devices", lov)
+ if len(devs) == 1:
+ devs[0].appendChild(gen.ref("osc", osc_uuid))
+ else:
+ error("No devices element found for LOV:", lov)
+
+
#
# Create a new obd, osc, and ost. Add them to the DOM.
#
-def add_OST(doc, options, args):
- # XXX need some error checking
- gen = GenConfig(doc)
+def add_ost(gen, lustre, options, args):
+ if len(args) < 3:
+ usage()
+
devname = args[0]
- host = args[1]
- if len(args) > 2:
- size = args[2]
+ node_name = args[1]
+ lovname = args[2]
+ if len(args) > 3:
+ size = args[3]
else:
size = 0
- lustre = doc.getElementsByTagName("lustre")[0]
-
- obdname = new_name("obd")
- oscname = new_name("osc")
- ostname = new_name("ost")
- node_uuid = get_uuid(host)
- net_uuid = get_uuid("net")
+ obdname = new_name(node_name+"_" + "obd")
+ oscname = new_name(node_name+"_"+"osc")
+ ostname = new_name(node_name+"_"+"ost")
obd_uuid = get_uuid(obdname)
ost_uuid = get_uuid(ostname)
osc_uuid = get_uuid(oscname)
- node = gen.node(host, node_uuid)
- node.appendChild(gen.network(host, net_uuid, "tcp", host, port=2436))
+ net_uuid = get_net_uuid(lustre, node_name)
+ if not net_uuid:
+ error("NODE: ", node_name, "not found")
+
+ lov = findByName(lustre, lovname, "lov")
+ if not lov:
+ error("LOV:", lovname, "not found.")
+
obd = gen.obd(obdname, obd_uuid, "extN", devname, "no", size)
ost = gen.ost(ostname, ost_uuid, obd_uuid, net_uuid)
- osc = gen.osc(oscname, osc_uuid, obd_uuid, net_uuid)
+ osc = gen.osc(oscname, osc_uuid, obd_uuid, ost_uuid)
- lustre.appendChild(node)
+ lov_add_osc(gen, lov, osc_uuid)
lustre.appendChild(obd)
lustre.appendChild(osc)
lustre.appendChild(ost)
+def add_node(gen, lustre, options, args):
+ """ create a node with a network config """
+ if len(args) < 3:
+ usage()
+
+ name = args[0]
+ nid = args[1]
+ nettype = args[2]
+
+ if nettype == 'tcp':
+ if len(args) > 3:
+ port = int(args[3])
+ else:
+ port = DEFAULT_PORT
+
+ elif nettype in ('elan', 'gm'):
+ port = 0
+ else:
+ print "Unknown nettype: ", nettype
+ sys.exit(2)
+
+ uuid = get_uuid(name)
+ node = gen.node(name, uuid)
+ net_name = name+"_net"
+ net_uuid = get_uuid(net_name)
+ node.appendChild(gen.network(net_name, net_uuid, nid, nettype, port))
+ lustre.appendChild(node)
+
+
+def add_lov(gen, lustre, options, args):
+ """ create a lov """
+ if len(args) < 4:
+ usage()
+
+ name = args[0]
+ stripe_sz = args[1]
+ stripe_off = args[2]
+ pattern = args[3]
+
+ ret = findByName(lustre, name, "lov")
+ if ret:
+ error("LOV: ", name, " already exists.")
+
+ uuid = get_uuid(name)
+ lov = gen.lov(name,uuid,stripe_sz, stripe_off, pattern)
+ lustre.appendChild(lov)
+
+def add_mtpt(gen, lustre, options, args):
+ """ create mtpt on a node """
+ if len(args) < 4:
+ usage()
+
+ node_name = args[0]
+ mdc_name = args[1]
+ lov_name = args[2]
+ path = args[3]
+
+ name = new_name(node_name + "_mtpt")
+
+ ret = findByName(lustre, name, "mountpoint")
+ if ret:
+ error("MOUNTPOINT: ", name, " already exists.")
+
+ ret = findByName(lustre, lov_name, "lov")
+ if not ret:
+ error("LOV: ", lov_name, " not found.")
+ lov_uuid = ret.getAttribute("uuid")
+
+ ret = findByName(lustre, mdc_name, "mdc")
+ if not ret:
+ error("MDC: ", mdc_name, " not found.")
+ mdc_uuid = ret.getAttribute("uuid")
+
+ uuid = get_uuid(name)
+ mtpt = gen.mountpoint(name, uuid, mdc_uuid, lov_uuid, path)
+ lustre.appendChild(mtpt)
+
+
+def add_mds(gen, lustre, options, args):
+ if len(args) < 3:
+ usage()
+
+ node_name = args[0]
+ devname = args[1]
+ if len(args) > 3:
+ size = args[3]
+ else:
+ size = 0
+
+ ret = findByName(lustre, node_name, "node")
+
+ mds_name = new_name(node_name+"_" + "mds")
+ mdc_name = new_name(node_name+"_"+"mdc")
+ mds_uuid = get_uuid(mds_name)
+ mdc_uuid = get_uuid(mdc_name)
+
+ 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, "no", net_uuid)
+ mdc = gen.mdc(mdc_name, mdc_uuid, mds_uuid)
+ lustre.appendChild(mds)
+ lustre.appendChild(mdc)
+
#
# Command line processing
#
def parse_cmdline(argv):
- short_opts = "ho:"
- long_opts = ["ost", "mtpt", "lov",
+ short_opts = "ho:i:"
+ long_opts = ["ost", "mtpt", "lov", "node", "mds",
"merge=", "format", "reformat", "output=",
- "help"]
+ "in=", "help"]
opts = []
args = []
options = {}
except getopt.GetoptError:
print "invalid opt"
usage()
- sys.exit(2)
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 == "--mds":
+ options['mds'] = 1
+ if o == "--node":
+ options['node'] = 1
+ if o == "--lov":
+ options['lov'] = 1
+ if o == "--mtpt":
+ options['mtpt'] = 1
if o == "--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
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'])
else:
doc = new_lustre(xml.dom.minidom)
if options.has_key('output'):
outFile = options['output']
+ lustre = doc.documentElement
+ init_names(lustre)
+ lustre = doc.documentElement
+ if lustre.tagName != "lustre":
+ print "Existing config not valid."
+ sys.exit(1)
+
+ gen = GenConfig(doc)
if options.has_key('ost'):
- add_OST(doc, options, args)
+ add_ost(gen, lustre, options, args)
+ elif options.has_key('node'):
+ add_node(gen, lustre, options, args)
elif options.has_key('mtpt'):
- print "--mtpt not implemented"
+ add_mtpt(gen, lustre, options, args)
elif options.has_key('lov'):
- print "--lov not implemented"
+ add_lov(gen, lustre, options, args)
+ elif options.has_key('mds'):
+ add_mds(gen, lustre, options, args)
else:
print "Missing command"
usage()
- sys.exit(1)
if outFile == '-':
PrettyPrint(doc)