3 # Copyright (C) 2002 Cluster File Systems, Inc.
4 # Author: Robert Read <rread@clusterfs.com>
6 # This file is part of Lustre, http://www.lustre.org.
8 # Lustre is free software; you can redistribute it and/or
9 # modify it under the terms of version 2 of the GNU General Public
10 # License as published by the Free Software Foundation.
12 # Lustre is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 # GNU General Public License for more details.
17 # You should have received a copy of the GNU General Public License
18 # along with Lustre; if not, write to the Free Software
19 # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 lmc - lustre configurtion data manager
25 Basic plan for lmc usage:
27 ./lmc --output config.xml --node server --net server1 tcp
28 ./lmc --merge config.xml --node client --net client1 tcp
32 ./lmc --merge config.xml --node server --mds /tmp/mds1 50000
33 ./lmc --merge config.xml --node server --mdc MDC_server
36 ./lmc --merge config.xml --lov lov1 MDC_server 65536 0 0
37 ./lmc --merge config.xml --node server --lov lov1 --ost /tmp/ost1 100000
38 ./lmc --merge config.xml --node server --lov lov1 --ost /tmp/ost2 100000
40 # create client config
41 ./lmc --merge config.xml --node client --mtpt /mnt/lustre MDC_server lov1
45 import sys, getopt, string
46 import xml.dom.minidom
47 from xml.dom.ext import PrettyPrint
48 from xml.xpath import Evaluate
50 DEFAULT_PORT = 888 # XXX What is the right default acceptor port to use?
53 print """usage: lmc [--node --ost | --mtpt | --lov] args
56 Node_name by itself it will create a new node. When used with other
57 commands it specifies the node to modify
59 --net hostname nettype [port, recv_buf, send_buf]
60 Nettype is either tcp, elan, or gm.
61 Requires a node argument
63 --lov lov_name [mdc_name stripe_sz stripe_off pattern]
64 Creates a logical volume
65 When used with other commands, it specifics the lov to modify
68 Create a MDS using the device
72 Configures a MDC for a node.
76 Creates an OBD/OST/OSC configuration triplet for a new device.
77 When used on "host", the device will be initialized and the OST
78 will be enabled. On client nodes, the OSC will be avaiable.
80 If --lov lov_name is used, this device is added to lov.
82 --mtpt /mnt/point mdc_name lov_name|osc_name
83 Creates a client mount point.
87 --merge="xml file" Add the new objects to an existing file
88 --format Format the partitions if unformated
89 --reformat Reformat partitions (this should be an lconf arg,
95 msg = string.join(map(str,args))
100 # manage names and uuids
101 # need to initialize this by walking tree to ensure
102 # no duplicate names or uuids are created.
103 # this are just place holders for now.
104 # consider changing this to be like OBD-dev-host
108 while names.has_key(ret):
109 ret = "%s_%d" % (base, ctr)
115 return "%s_UUID" % (name)
118 ldlm_uuid = 'ldlm_UUID'
120 """Create a new empty lustre document"""
121 # adding ldlm here is a bit of a hack, but one is enough.
122 str = """<lustre> <ldlm name="%s" uuid="%s"/> </lustre>""" % (ldlm_name, ldlm_uuid)
123 return dom.parseString(str)
127 def init_names(lustre):
128 """initialize auto-name generation tables"""
130 # get all elements that contain a name attribute
131 for n in Evaluate("//@name/..", lustre):
132 names[n.getAttribute("name")] = 1
133 uuids[n.getAttribute("uuid")] = 1
138 def __init__(self, doc):
141 def ref(self, type, uuid):
142 """ generate <[type]_ref uuidref="[uuid]"/> """
143 tag = "%s_ref" % (type)
144 ref = self.doc.createElement(tag)
145 ref.setAttribute("uuidref", uuid)
148 def newService(self, tag, name, uuid):
149 """ create a new service elmement, which requires name and uuid attributes """
150 new = self.doc.createElement(tag)
151 new.setAttribute("name", name);
152 new.setAttribute("uuid", uuid);
155 def addText(self, node, str):
156 txt = self.doc.createTextNode(str)
157 node.appendChild(txt)
159 def addElement(self, node, tag, str=None):
160 """ create a new element and add it as a child to node. If str is passed,
161 a text node is created for the new element"""
162 new = self.doc.createElement(tag)
164 self.addText(new, str)
165 node.appendChild(new)
168 def network(self, name, uuid, hostname, net, port=0):
169 """create <network> node"""
170 network = self.newService("network", name, uuid)
171 network.setAttribute("type", net);
172 self.addElement(network, "server", hostname)
174 self.addElement(network, "port", "%d" %(port))
177 def node(self, name, uuid):
178 """ create a host """
179 node = self.newService("node", name, uuid)
180 self.addElement(node, 'profile')
183 def ldlm(self, name, uuid):
184 """ create a ldlm """
185 ldlm = self.newService("ldlm", name, uuid)
188 def obd(self, name, uuid, fs, devname, format, dev_size=0):
189 obd = self.newService("obd", name, uuid)
190 obd.setAttribute('type', 'obdfilter')
191 self.addElement(obd, "fstype", fs)
192 dev = self.addElement(obd, "device", devname)
194 dev.setAttribute("size", "%s" % (dev_size))
195 self.addElement(obd, "autoformat", format)
198 def osc(self, name, uuid, obd_uuid, net_uuid):
199 osc = self.newService("osc", name, uuid)
200 osc.appendChild(self.ref("ost", net_uuid))
201 osc.appendChild(self.ref("obd", obd_uuid))
204 def ost(self, name, uuid, obd_uuid, net_uuid):
205 ost = self.newService("ost", name, uuid)
206 ost.appendChild(self.ref("network", net_uuid))
207 ost.appendChild(self.ref("obd", obd_uuid))
210 def lov(self, name, uuid, mdc_uuid, stripe_sz, stripe_off, pattern):
211 lov = self.newService("lov", name, uuid)
212 lov.appendChild(self.ref("mdc", mdc_uuid))
213 devs = self.addElement(lov, "devices" )
214 devs.setAttribute("stripesize", stripe_sz)
215 devs.setAttribute("stripeoffset", stripe_off)
216 devs.setAttribute("pattern", pattern)
219 def mds(self, name, uuid, fs, devname, format, net_uuid, failover_uuid = "", dev_size=0 ):
220 mds = self.newService("mds", name, uuid)
221 self.addElement(mds, "fstype", fs)
222 dev = self.addElement(mds, "device", devname)
224 dev.setAttribute("size", "%s" % (dev_size))
225 self.addElement(mds, "autoformat", format)
226 mds.appendChild(self.ref("network", net_uuid))
228 mds.appendChild(self.ref("failover", failover_uuid))
231 def mdc(self, name, uuid, mds_uuid):
232 mdc = self.newService("mdc", name, uuid)
233 mdc.appendChild(self.ref("mds", mds_uuid))
236 def mountpoint(self, name, uuid, mdc_uuid, osc_uuid, path):
237 mtpt = self.newService("mountpoint", name, uuid)
238 mtpt.appendChild(self.ref("mdc", mdc_uuid))
239 mtpt.appendChild(self.ref("osc", osc_uuid))
240 self.addElement(mtpt, "path", path)
243 def findByName(lustre, name, tag = "*"):
244 path = '//%s[@name="%s"]' % (tag, name)
245 ret = Evaluate(path, lustre)
250 # XXX: assumes only one network element per node. will fix this
251 # as soon as support for routers is added
252 def get_net_uuid(lustre, node_name):
253 """ get a network uuid for a node_name """
254 node = findByName(lustre, node_name, "node")
256 error ("node not found:", node_name)
257 net = Evaluate("./network", node)
259 return net[0].getAttribute("uuid")
262 def lov_add_osc(gen, lov, osc_uuid):
263 devs = Evaluate("devices", lov)
265 devs[0].appendChild(gen.ref("osc", osc_uuid))
267 error("No devices element found for LOV:", lov)
269 def node_add_profile(gen, node, ref, uuid):
270 ret = Evaluate("./profile", node)
272 error('node has no profile:', node)
273 ret[0].appendChild(gen.ref(ref, uuid))
276 # Create a new obd, osc, and ost. Add them to the DOM.
278 def add_ost(gen, lustre, options, args):
282 if options.has_key('node'):
283 node_name = options['node']
285 error("--ost requires a --node argument")
287 if options.has_key('lov'):
288 lovname = options['lov']
298 obdname = new_name('OBD_'+ node_name)
299 oscname = new_name('OSC_'+ node_name)
300 ostname = new_name('OST_'+ node_name)
301 obd_uuid = get_uuid(obdname)
302 ost_uuid = get_uuid(ostname)
303 osc_uuid = get_uuid(oscname)
305 net_uuid = get_net_uuid(lustre, node_name)
307 error("NODE: ", node_name, "not found")
309 obd = gen.obd(obdname, obd_uuid, "extN", devname, "no", size)
310 ost = gen.ost(ostname, ost_uuid, obd_uuid, net_uuid)
311 osc = gen.osc(oscname, osc_uuid, obd_uuid, ost_uuid)
314 lov = findByName(lustre, lovname, "lov")
316 error("LOV:", lovname, "not found.")
317 lov_add_osc(gen, lov, osc_uuid)
319 node = findByName(lustre, node_name, "node")
320 node_add_profile(gen, node, 'obd', obd_uuid)
321 node_add_profile(gen, node, 'ost', ost_uuid)
323 lustre.appendChild(obd)
324 lustre.appendChild(osc)
325 lustre.appendChild(ost)
327 def add_net(gen, lustre, options, args):
328 """ create a node with a network config """
332 node_name = options['node']
336 if net_type == 'tcp':
341 # add send, recv buffer size here
342 elif net_type in ('elan', 'gm'):
345 print "Unknown net_type: ", net_type
348 ret = findByName(lustre, node_name, "node")
350 node = do_add_node(gen, lustre, node_name)
353 net_name = new_name('NET_'+ node_name +'_'+ net_type)
354 net_uuid = get_uuid(net_name)
355 node.appendChild(gen.network(net_name, net_uuid, nid, net_type, port))
356 node_add_profile(gen, node, "network", net_uuid)
358 def do_add_node(gen, lustre, node_name):
359 uuid = get_uuid(node_name)
360 node = gen.node(node_name, uuid)
361 node_add_profile(gen, node, 'ldlm', ldlm_uuid)
362 lustre.appendChild(node)
365 def add_node(gen, lustre, options, args):
366 """ create a node with a network config """
370 node_name = options['node']
372 ret = findByName(lustre, node_name, "node")
374 print "Node:", node_name, "exists."
376 do_add_node(gen, lustre, node_name)
379 def add_lov(gen, lustre, options, args):
384 name = options['lov']
390 ret = findByName(lustre, name, "lov")
392 error("LOV: ", name, " already exists.")
394 ret = findByName(lustre, mdc_name, "mdc")
396 error(mdc_name, "not found.")
397 mdc_uuid = ret.getAttribute("uuid")
399 uuid = get_uuid(name)
400 lov = gen.lov(name, uuid, mdc_uuid, stripe_sz, stripe_off, pattern)
401 lustre.appendChild(lov)
403 def add_mtpt(gen, lustre, options, args):
404 """ create mtpt on a node """
408 if options.has_key('node'):
409 node_name = options['node']
411 error("--mtpt requires a --node argument")
417 name = new_name('MNT_'+ node_name)
419 ret = findByName(lustre, name, "mountpoint")
421 error("MOUNTPOINT: ", name, " already exists.")
423 ret = findByName(lustre, lov_name, "lov")
425 ret = findByName(lustre, lov_name, "osc")
427 error(lov_name, "not found.")
428 lov_uuid = ret.getAttribute("uuid")
430 ret = findByName(lustre, mdc_name, "mdc")
432 error("MDC: ", mdc_name, "not found.")
433 mdc_uuid = ret.getAttribute("uuid")
435 uuid = get_uuid(name)
436 mtpt = gen.mountpoint(name, uuid, mdc_uuid, lov_uuid, path)
437 node = findByName(lustre, node_name, "node")
439 error('node:', node_name, "not found.")
440 node_add_profile(gen, node, "mountpoint", uuid)
441 node_add_profile(gen, node, "mdc", mdc_uuid)
442 node_add_profile(gen, node, "lov", lov_uuid)
443 lustre.appendChild(mtpt)
445 def add_mdc(gen, lustre, options, args):
446 """ create mtpt on a node """
450 if options.has_key('node'):
451 node_name = options['node']
453 error("--mdc requires a --node argument")
457 ret = findByName(lustre, mdc_name, "mdc")
459 error("MDC: ", mdc_name, "not found.")
460 mdc_uuid = ret.getAttribute("uuid")
462 node = findByName(lustre, node_name, "node")
464 error('node:', node_name, "not found.")
465 node_add_profile(gen, node, "mdc", mdc_uuid)
467 def add_mds(gen, lustre, options, args):
471 if options.has_key('node'):
472 node_name = options['node']
474 error("--mds requires a --node argument")
482 mds_name = new_name('MDS_'+ node_name)
483 mdc_name = new_name('MDC_'+ node_name)
484 mds_uuid = get_uuid(mds_name)
485 mdc_uuid = get_uuid(mdc_name)
487 node = findByName(lustre, node_name, "node")
489 error('node:', node_name, 'not found')
490 node_add_profile(gen, node, "mds", mds_uuid)
492 net_uuid = get_net_uuid(lustre, node_name)
494 error("NODE: ", node_name, "not found")
497 mds = gen.mds(mds_name, mds_uuid, "extN", devname, "no", net_uuid, dev_size=size)
498 mdc = gen.mdc(mdc_name, mdc_uuid, mds_uuid)
499 lustre.appendChild(mds)
500 lustre.appendChild(mdc)
504 # Command line processing
507 def parse_cmdline(argv):
508 short_opts = "ho:i:m:"
509 long_opts = ["ost", "mtpt", "lov=", "node=", "mds", "net",
510 "mdc", "merge=", "format", "reformat", "output=",
516 opts, args = getopt.getopt(argv, short_opts, long_opts)
517 except getopt.GetoptError:
522 if o in ("-h", "--help"):
524 if o in ("-o", "--output"):
525 options['output'] = a
540 if o in ("-m", "--merge"):
543 options['format'] = 1
544 if o == "--reformat":
545 options['reformat'] = 1
546 if o in ("--in" , "-i"):
552 options, args = parse_cmdline(sys.argv[1:])
555 if options.has_key('merge'):
556 outFile = options['merge']
557 doc = xml.dom.minidom.parse(outFile)
558 elif options.has_key('in'):
559 doc = xml.dom.minidom.parse(options['in'])
561 doc = new_lustre(xml.dom.minidom)
563 if options.has_key('output'):
564 outFile = options['output']
566 lustre = doc.documentElement
568 lustre = doc.documentElement
569 if lustre.tagName != "lustre":
570 print "Existing config not valid."
574 if options.has_key('ost'):
575 add_ost(gen, lustre, options, args)
576 elif options.has_key('mtpt'):
577 add_mtpt(gen, lustre, options, args)
578 elif options.has_key('mds'):
579 add_mds(gen, lustre, options, args)
580 elif options.has_key('mdc'):
581 add_mdc(gen, lustre, options, args)
582 elif options.has_key('net'):
583 add_net(gen, lustre, options, args)
584 elif options.has_key('lov'):
585 add_lov(gen, lustre, options, args)
586 elif options.has_key('node'):
587 add_node(gen, lustre, options, args)
589 print "Missing command"
595 PrettyPrint(doc, open(outFile,"w"))
596 if __name__ == "__main__":