#!/usr/bin/env python # archipelagos tool # Copyright 2012 GRNET S.A. All rights reserved. # # Redistribution and use in source and binary forms, with or # without modification, are permitted provided that the following # conditions are met: # # 1. Redistributions of source code must retain the above # copyright notice, this list of conditions and the following # disclaimer. # 2. Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following # disclaimer in the documentation and/or other materials # provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS # OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF # USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED # AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. # # The views and conclusions contained in the software and # documentation are those of the authors and should not be # interpreted as representing official policies, either expressed # or implied, of GRNET S.A. # from xseg.xseg_api import * from xseg.xprotocol import * from ctypes import CFUNCTYPE, cast, c_void_p, addressof, string_at, memmove, \ create_string_buffer, pointer, sizeof, POINTER, c_char_p, c_char, byref cb_null_ptrtype = CFUNCTYPE(None, uint32_t) import os, sys, subprocess, argparse, time, psutil, signal, errno from subprocess import call, check_call, Popen, PIPE DEFAULTS='/etc/default/archipelago' VLMC_LOCK_FILE='/tmp/vlmc.lock' ARCHIP_PREFIX='archip_' #system defaults PIDFILE_PATH="/var/run/archipelago" LOGS_PATH="/var/log/archipelago" DEVICE_PREFIX="/dev/xsegbd" XSEGBD_SYSFS="/sys/bus/xsegbd/" CHARDEV_NAME="/dev/segdev" CHARDEV_MAJOR=60 CHARDEV_MINOR=0 REQS=512 FILE_BLOCKER='mt-pfiled' RADOS_BLOCKER='mt-sosd' MAPPER='mt-mapperd' VLMC='st-vlmcd' BLOCKER='' available_storage = {'files': FILE_BLOCKER, 'rados': RADOS_BLOCKER} peers = [] modules = ["xseg", "segdev", "xseg_posix", "xseg_pthread", "xseg_segdev"] xsegbd = "xsegbd" XSEGBD_START=0 XSEGBD_END=199 VPORT_START=200 VPORT_END=399 BPORT=500 MPORT=501 MBPORT=502 VTOOL=503 #RESERVED 511 #default config SPEC="segdev:xsegbd:512:2048:12" NR_OPS_BLOCKERB="" NR_OPS_BLOCKERM="" NR_OPS_VLMC="" NR_OPS_MAPPER="" VERBOSITY_BLOCKERB="" VERBOSITY_BLOCKERM="" VERBOSITY_MAPPER="" VERBOSITY_VLMC="" #mt-pfiled specific options FILED_IMAGES="" FILED_MAPS="" PITHOS="" PITHOSMAPS="" #mt-sosd specific options RADOS_POOL_MAPS="" RADOS_POOL_BLOCKS="" FIRST_COLUMN_WIDTH = 23 SECOND_COLUMN_WIDTH = 23 def green(s): return '\x1b[32m' + s + '\x1b[0m' def red(s): return '\x1b[31m' + s + '\x1b[0m' def yellow(s): return '\x1b[33m' + s + '\x1b[0m' def pretty_print(cid, status): sys.stdout.write(cid.ljust(FIRST_COLUMN_WIDTH)) sys.stdout.write(status.ljust(SECOND_COLUMN_WIDTH)) sys.stdout.write('\n') return def check_conf(): def isExec(file_path): return os.path.isfile(file_path) and os.access(file_path, os.X_OK) def validExec(program): for path in os.environ["PATH"].split(os.pathsep): exe_file = os.path.join(path, program) if isExec(exe_file): return True return False def validPort(port, limit, name): try: if int(port) >= limit: print red(str(port) + " >= " + limit) return False except: print red("Invalid port "+name+" : " + str(port)) return False return True if not LOGS_PATH: print red("LOGS_PATH is not set") return False if not PIDFILE_PATH: print red("PIDFILE_PATH is not set") return False try: if not os.path.isdir(str(LOGS_PATH)): print red("LOGS_PATH "+str(LOGS_PATH)+" does not exist") return False except: print red("LOGS_PATH doesn't exist or is not a directory") return False try: os.makedirs(str(PIDFILE_PATH)) except OSError as e: if e.errno == errno.EEXIST: if os.path.isdir(str(PIDFILE_PATH)): pass else: print red(str(PIDFILE_PATH) + " is not a directory") return False else: print red("Cannot create " + str(PIDFILE_PATH)) return False except: print red("PIDFILE_PATH is not set") return False splitted_spec = str(SPEC).split(':') if len(splitted_spec) < 5: print red("Invalid spec") return False xseg_type=splitted_spec[0] xseg_name=splitted_spec[1] xseg_ports=int(splitted_spec[2]) xseg_heapsize=int(splitted_spec[3]) xseg_align=int(splitted_spec[4]) if xseg_type != "segdev": print red("Segment type not segdev") return False if xseg_name != "xsegbd": print red("Segment name not equal xsegbd") return False if xseg_align != 12: print red("Wrong alignemt") return False for v in [VERBOSITY_BLOCKERB, VERBOSITY_BLOCKERM, VERBOSITY_MAPPER, VERBOSITY_VLMC]: if v is None: print red("Verbosity missing") try: if (int(v) > 3 or int(v) < 0): print red("Invalid verbosity " + str(v)) return False except: print red("Invalid verbosity " + str(v)) return False for n in [NR_OPS_BLOCKERB, NR_OPS_BLOCKERM, NR_OPS_VLMC, NR_OPS_MAPPER]: if n is None: print red("Nr ops missing") try: if (int(n) <= 0): print red("Invalid nr_ops " + str(n)) return False except: print red("Invalid nr_ops " + str(n)) return False if not validPort(VTOOL, xseg_ports, "VTOOL"): return False if not validPort(MPORT, xseg_ports, "MPORT"): return False if not validPort(BPORT, xseg_ports, "BPORT"): return False if not validPort(MBPORT, xseg_ports, "MBPORT"): return False if not validPort(VPORT_START, xseg_ports, "VPORT_START"): return False if not validPort(VPORT_END, xseg_ports, "VPORT_END"): return False if not validPort(XSEGBD_START, xseg_ports, "XSEGBD_START"): return False if not validPort(XSEGBD_END, xseg_ports, "XSEGBD_END"): return False if not XSEGBD_START < XSEGBD_END: print red("XSEGBD_START should be less than XSEGBD_END") return False if not VPORT_START < VPORT_END: print red("VPORT_START should be less than VPORT_END") return False #TODO check than no other port is set in the above ranges global BLOCKER try: BLOCKER = available_storage[str(STORAGE)] except: print red("Invalid storage " + str(STORAGE)) print "Available storage: \"" + ', "'.join(available_storage) + "\"" return False if STORAGE=="files": if FILED_IMAGES and not os.path.isdir(str(FILED_IMAGES)): print red("FILED_IMAGES invalid") return False if FILED_MAPS and not os.path.isdir(str(FILED_MAPS)): print red("FILED_PATH invalid") return False if PITHOS and not os.path.isdir(str(PITHOS)): print red("PITHOS invalid ") return False if PITHOSMAPS and not os.path.isdir(str(PITHOSMAPS)): print red("PITHOSMAPS invalid") return False for p in [BLOCKER, MAPPER, VLMC]: if not validExec(p): print red(p + "is not a valid executable") return False return True def construct_peers(): if BLOCKER == "pfiled": peer_blockerb = [BLOCKER, ["-p" , str(BPORT), "-g", str(SPEC), "-n", str(NR_OPS_BLOCKERB), str(PITHOS), str(FILED_IMAGES), "-d", "-f", os.path.join(PIDFILE_PATH, "blockerb.pid")], "blockerb"] peer_blockerm = [BLOCKER, ["-p" , str(MBPORT), "-g", str(SPEC), "-n", str(NR_OPS_BLOCKERM), str(PITHOSMAPS), str(FILED_MAPS), "-d", "-f", os.path.join(PIDFILE_PATH, "blockerm.pid")], "blockerm" ] elif BLOCKER == "mt-sosd": peer_blockerb = [BLOCKER, ["-p" , str(BPORT), "-g", str(SPEC), "-n", str(NR_OPS_BLOCKERB), "--pool", str(RADOS_POOL_BLOCKS), "-v", str(VERBOSITY_BLOCKERB), "-d", "--pidfile", os.path.join(PIDFILE_PATH, "blockerb.pid"), "-l", os.path.join(str(LOGS_PATH), "blockerb.log"), "-t", "3"], "blockerb"] peer_blockerm = [BLOCKER, ["-p" , str(MBPORT), "-g", str(SPEC), "-n", str(NR_OPS_BLOCKERM), "--pool", str(RADOS_POOL_MAPS), "-v", str(VERBOSITY_BLOCKERM), "-d", "--pidfile", os.path.join(PIDFILE_PATH, "blockerm.pid"), "-l", os.path.join(str(LOGS_PATH), "blockerm.log"), "-t", "3"], "blockerm"] elif BLOCKER == "mt-pfiled": peer_blockerb = [BLOCKER, ["-p" , str(BPORT), "-g", str(SPEC), "-n", str(NR_OPS_BLOCKERB), "--pithos", str(PITHOS), "--archip", str(FILED_IMAGES), "-v", str(VERBOSITY_BLOCKERB), "-d", "--pidfile", os.path.join(PIDFILE_PATH, "blockerb.pid"), "-l", os.path.join(str(LOGS_PATH), "blockerb.log"), "-t", str(NR_OPS_BLOCKERB), "--prefix", ARCHIP_PREFIX], "blockerb"] peer_blockerm = [BLOCKER, ["-p" , str(MBPORT), "-g", str(SPEC), "-n", str(NR_OPS_BLOCKERM), "--pithos", str(PITHOSMAPS), "--archip", str(FILED_MAPS), "-v", str(VERBOSITY_BLOCKERM), "-d", "--pidfile", os.path.join(PIDFILE_PATH, "blockerm.pid"), "-l", os.path.join(str(LOGS_PATH), "blockerm.log"), "-t", str(NR_OPS_BLOCKERM), "--prefix", ARCHIP_PREFIX], "blockerm"] else: sys.exit(-1) peer_vlmcd = [VLMC, ["-t" , "1", "-sp", str(VPORT_START), "-ep", str(VPORT_END), "-g", str(SPEC), "-n", str(NR_OPS_VLMC), "-bp", str(BPORT), "-mp", str(MPORT), "-d", "-v", str(VERBOSITY_VLMC), "--pidfile", os.path.join(PIDFILE_PATH, "vlmcd.pid"), "-l", os.path.join(str(LOGS_PATH), "vlmcd.log") ], "vlmcd"] peer_mapperd = [MAPPER, ["-t" , "1", "-p", str(MPORT), "-mbp", str(MBPORT), "-g", str(SPEC), "-n", str(NR_OPS_MAPPER), "-bp", str(BPORT), "--pidfile", os.path.join(PIDFILE_PATH, "mapperd.pid"), "-v", str(VERBOSITY_MAPPER), "-d", "-l", os.path.join(str(LOGS_PATH), "mapperd.log") ], "mapperd"] peers = [] peers.append(peer_blockerb) peers.append(peer_blockerm) peers.append(peer_vlmcd) peers.append(peer_mapperd) return peers def exclusive(fn): def exclusive_args(args): while True: try: fd = os.open(VLMC_LOCK_FILE, os.O_CREAT|os.O_EXCL|os.O_WRONLY) break; except OSError, (err, reason): print >> sys.stderr, reason if err == errno.EEXIST: time.sleep(0.05) else: raise OSError(err, VLMC_LOCK_FILE + ' ' + reason) try: r = fn(args) finally: os.close(fd) os.unlink(VLMC_LOCK_FILE) return r return exclusive_args def loadrc(rc): try: if rc == None: execfile(os.path.expanduser(DEFAULTS), globals()) else: execfile(rc, globals()) except: sys.stderr.write("Cannot read config file\n") sys.exit(1) if not check_conf(): sys.exit(1) def loaded_modules(): lines = open("/proc/modules").read().split("\n") modules = [f.split(" ")[0] for f in lines] return modules def loaded_module(name): return name in loaded_modules() def load_module(name, args): s = "Loading %s " % name sys.stdout.write(s.ljust(FIRST_COLUMN_WIDTH)) modules = loaded_modules() if name in modules: sys.stdout.write(yellow("Already loaded".ljust(SECOND_COLUMN_WIDTH))) sys.stdout.write("\n") return 0 cmd = ["modprobe", "%s" % name] if args: for arg in args: cmd.extend(["%s=%s" % (arg)]) try: check_call(cmd, shell=False); except Exception: sys.stdout.write(red("FAILED".ljust(SECOND_COLUMN_WIDTH))) sys.stdout.write("\n") return -1 sys.stdout.write(green("OK".ljust(SECOND_COLUMN_WIDTH))) sys.stdout.write("\n") return 0 def unload_module(name): s = "Unloading %s " % name sys.stdout.write(s.ljust(FIRST_COLUMN_WIDTH)) modules = loaded_modules() if name not in modules: sys.stdout.write(yellow("Not loaded".ljust(SECOND_COLUMN_WIDTH))) sys.stdout.write("\n") return 0 cmd = ["modprobe -r %s" % name] try: check_call(cmd, shell=True); except Exception: sys.stdout.write(red("FAILED".ljust(SECOND_COLUMN_WIDTH))) sys.stdout.write("\n") return -1 sys.stdout.write(green("OK".ljust(SECOND_COLUMN_WIDTH))) sys.stdout.write("\n") return 0 def create_segment(): #fixme blocking.... cmd = ["xseg", str(SPEC), "create"] try: check_call(cmd, shell=False); except Exception: sys.stderr.write(red("Cannot create segment. \n")) return -1 return 0 def destroy_segment(): #fixme blocking.... cmd = ["xseg", str(SPEC), "destroy"] try: check_call(cmd, shell=False); except Exception: sys.stderr.write(red("Cannot destroy segment. \n")) return 0 return 0 def check_running(name, pid = -1): for p in psutil.process_iter(): if p.name == name: if pid != -1: if pid == p.pid: return pid else: return pid return -1 def check_pidfile(name): pidfile = os.path.join(PIDFILE_PATH, name + ".pid") pf = None try: pf = open(pidfile, "r") pid = int(pf.read()) pf.close() except: if pf: pf.close() return -1 return pid def start_peer(peer): cmd = [peer[0]] + peer[1] s = "Starting %s " % peer[2] sys.stdout.write(s.ljust(FIRST_COLUMN_WIDTH)) try: check_call(cmd, shell=False); except Exception: sys.stdout.write(red("FAILED".ljust(SECOND_COLUMN_WIDTH))) sys.stdout.write("\n") return -1 sys.stdout.write(green("OK".ljust(SECOND_COLUMN_WIDTH))) sys.stdout.write("\n") return 0 def stop_peer(peer): pid = check_pidfile(peer[2]) if pid < 0: pretty_print(peer[2], yellow("not running")) return -1 s = "Stopping %s " % peer[2] sys.stdout.write(s.ljust(FIRST_COLUMN_WIDTH)) os.kill(pid, signal.SIGTERM) i = 0 while check_running(peer[0], pid) > 0: time.sleep(0.1) i += 1 if i > 150: sys.stdout.write(red("FAILED".ljust(SECOND_COLUMN_WIDTH))) sys.stdout.write("\n") return -1 sys.stdout.write(green("OK".ljust(SECOND_COLUMN_WIDTH))) sys.stdout.write("\n") return 0 def peer_running(peer): pid = check_pidfile(peer[2]) if pid < 0: return -1 r = check_running(peer[0], pid) if r < 0: pretty_print(peer[2], yellow("Has valid pidfile but does not seem to be active")) return 0 def make_segdev(): try: os.stat(str(CHARDEV_NAME)) return -2 except: pass cmd = ["mknod", str(CHARDEV_NAME), "c", str(CHARDEV_MAJOR), str(CHARDEV_MINOR)] print ' '.join(cmd) try: check_call(cmd, shell=False); except Exception: sys.stderr.write(red("Segdev device creation failed.\n")) return -1 return 0 def remove_segdev(): try: os.stat(str(CHARDEV_NAME)) except: return -2 try: os.unlink(str(CHARDEV_NAME)) except: sys.stderr.write(red("Segdev device removal failed.\n")) return -1 def start_peers(peers): for m in modules: if not loaded_module(m): print red("Cannot start userspace peers. " + m + " module not loaded") return -1 for p in peers: if start_peer(p) < 0: return -1 return 0 def stop_peers(peers): for p in reversed(peers): stop_peer(p) return 0 def start(args): if args.user: return start_peers(peers) if status(args) > 0: return -1 for m in modules: if load_module(m, None) < 0: stop(args) return -1 time.sleep(0.5) if make_segdev() < 0: stop(args) return -1 time.sleep(0.5) if create_segment() < 0: stop(args) return -1 time.sleep(0.5) if start_peers(peers) < 0: stop(args) return -1 if load_module(xsegbd, xsegbd_args) < 0: stop(args) return -1 return 0 def stop(args): if args.user: return stop_peers(peers) #check devices if vlmc_showmapped(args) > 0: print "Cannot stop archipelago. Mapped volumes exist" return -1 if unload_module(xsegbd): return -1 r = 0 stop_peers(peers) remove_segdev() for m in reversed(modules): unload_module(m) return 0 def status(args): r = 0 if vlmc_showmapped(args) >= 0: r += 1 if loaded_module(xsegbd): pretty_print(xsegbd, green('Loaded')) r += 1 else: pretty_print(xsegbd, red('Not loaded')) for m in reversed(modules): if loaded_module(m): pretty_print(m, green('Loaded')) r += 1 else: pretty_print(m, red('Not loaded')) for p in reversed(peers): if peer_running(p) < 0: pretty_print(p[0], red('not running')) else: pretty_print(p[0], green('running')) r += 1 return r def restart(args): r = stop(args) if r < 0: return r return start(args) class Xseg_ctx(object): ctx = None port = None portno = None def __init__(self, spec, portno): xseg_initialize() xconf = xseg_config() xseg_parse_spec(spec, xconf) ctx = xseg_join(xconf.type, xconf.name, "posix", cast(0, cb_null_ptrtype)) if not ctx: raise Exception("Cannot join segment") port = xseg_bind_port(ctx, portno, c_void_p(0)) if not port: raise Exception("Cannot bind to port") xseg_init_local_signal(ctx, portno) self.ctx = ctx self.port = port self.portno = portno def __del__(self): return def __enter__(self): if not self.ctx: raise Exception("No segment") return self def __exit__(self, type_, value, traceback): self.shutdown() return False def shutdown(self): if self.ctx: xseg_quit_local_signal(self.ctx, self.portno) xseg_leave(self.ctx) self.ctx = None class Request(object): xseg_ctx = None req = None def __init__(self, xseg_ctx, dst_portno, targetlen, datalen): ctx = xseg_ctx.ctx if not ctx: raise Exception("No context") req = xseg_get_request(ctx, xseg_ctx.portno, dst_portno, X_ALLOC) if not req: raise Exception("Cannot get request") r = xseg_prep_request(ctx, req, targetlen, datalen) if r < 0: xseg_put_request(ctx, req, xseg_ctx.portno) raise Exception("Cannot prepare request") # print hex(addressof(req.contents)) self.req = req self.xseg_ctx = xseg_ctx return def __del__(self): if self.req: if xq_count(byref(self.req.contents.path)) == 0: xseg_put_request(self.xseg_ctx.ctx, self.req, self.xseg_ctx.portno) self.req = None return False def __enter__(self): if not self.req: raise Exception("xseg request not set") return self def __exit__(self, type_, value, traceback): if self.req: if xq_count(byref(self.req.contents.path)) == 0: xseg_put_request(self.xseg_ctx.ctx, self.req, self.xseg_ctx.portno) self.req = None return False def set_op(self, op): self.req.contents.op = op def get_op(self): return self.req.contents.op def set_offset(self, offset): self.req.contents.offset = offset def get_offset(self): return self.req.contents.offset def get_size(self): return self.req.contents.size def set_size(self, size): self.req.contents.size = size def set_flags(self, flags): self.req.contents.flags = flags def get_flags(self): return self.req.contents.flags def set_target(self, target): """Sets the target of the request, respecting request's targetlen""" if len(target) != self.req.contents.targetlen: return False c_target = xseg_get_target_nonstatic(self.xseg_ctx.ctx, self.req) p_target = create_string_buffer(target) # print hex(addressof(c_target.contents)) memmove(c_target, p_target, len(target)) return True def get_target(self): """Return a string to the target of the request""" c_target = xseg_get_target_nonstatic(self.xseg_ctx.ctx, self.req) # print "target_addr " + str(addressof(c_target.contents)) return string_at(c_target, self.req.contents.targetlen) def set_data(self, data): """Sets requests data. Data should be a xseg protocol structure""" if sizeof(data) != self.req.contents.datalen: return False c_data = xseg_get_data_nonstatic(self.xseg_ctx.ctx, self.req) p_data = pointer(data) memmove(c_data, p_data, self.req.contents.datalen) return True def get_data(self, _type): """return a pointer to the data buffer of the request, casted to the selected type""" # print "data addr " + str(addressof(xseg_get_data_nonstatic(self.xseg_ctx.ctx, self.req).contents)) # ret = cast(xseg_get_data_nonstatic(self.xseg_ctx.ctx, self.req), _type) # print addressof(ret.contents) # return ret if _type: return cast(xseg_get_data_nonstatic(self.xseg_ctx.ctx, self.req),\ POINTER(_type)) else: return cast(xseg_get_data_nonstatic(self.xseg_ctx.ctx, self.req), \ c_void_p) def submit(self): """Submit the associated xseg_request""" p = xseg_submit(self.xseg_ctx.ctx, self.req, self.xseg_ctx.portno, X_ALLOC) if p == NoPort: raise Exception xseg_signal(self.xseg_ctx.ctx, p) def wait(self): """Wait until the associated xseg_request is responded, discarding any other requests that may be received in the meantime""" while True: received = xseg_receive(self.xseg_ctx.ctx, self.xseg_ctx.portno, 0) if received: # print addressof(cast(self.req, c_void_p)) # print addressof(cast(received, c_void_p)) # print addressof(self.req.contents) # print addressof(received.contents) if addressof(received.contents) == addressof(self.req.contents): # if addressof(cast(received, c_void_p)) == addressof(cast(self.req, c_void_p)): break else: p = xseg_respond(self.xseg_ctx.ctx, received, self.xseg_ctx.portno, X_ALLOC) if p == NoPort: xseg_put_request(self.xseg_ctx.ctx, received, self.xseg_ctx.portno) else: xseg_signal(self.xseg_ctx.ctx, p) else: xseg_prepare_wait(self.xseg_ctx.ctx, self.xseg_ctx.portno) xseg_wait_signal(self.xseg_ctx.ctx, 10000000) xseg_cancel_wait(self.xseg_ctx.ctx, self.xseg_ctx.portno) return True def success(self): return bool((self.req.contents.state & XS_SERVED) and not (self.req.contents.state & XS_FAILED)) @exclusive def vlmc_showmapped(args): try: devices = os.listdir(os.path.join(XSEGBD_SYSFS, "devices/")) except: return -1 print "id\tpool\timage\tsnap\tdevice" if not devices: print "No volumes mapped\n" return 0 try: for f in devices: d_id = open(XSEGBD_SYSFS + "devices/" + f + "/id").read().strip() target = open(XSEGBD_SYSFS + "devices/"+ f + "/target").read().strip() print "%s\t%s\t%s\t%s\t%s" % (d_id, '-', target, '-', DEVICE_PREFIX + d_id) except Exception, reason: print >> sys.stderr, reason return -2 return len(devices) def vlmc_showmapped_wrapper(args): r = vlmc_showmapped(args) if r < 0: return r return 0 @exclusive def vlmc_create(args): name = args.name[0] size = args.size snap = args.snap if len(name) < 6: print >> sys.stderr, "Name should have at least len 6" sys.exit(-1) if size == None and snap == None: print >> sys.stderr, "At least one of the size/snap args must be provided" sys.exit(-1) ret = False xseg_ctx = Xseg_ctx(SPEC, VTOOL) with Request(xseg_ctx, MPORT, len(name), sizeof(xseg_request_clone)) as req: req.set_op(X_CLONE) req.set_size(sizeof(xseg_request_clone)) req.set_offset(0) req.set_target(name) xclone = xseg_request_clone() if snap: xclone.target = snap xclone.targetlen = len(snap) else: xclone.target = "" xclone.targetlen = 0 if size: xclone.size = size << 20 else: xclone.size = -1 req.set_data(xclone) req.submit() req.wait() ret = req.success() xseg_ctx.shutdown() if not ret: sys.stderr.write("vlmc creation failed\n") sys.exit(-1) @exclusive def vlmc_snapshot(args): # snapshot name = args.name[0] if len(name) < 6: print >> sys.stderr, "Name should have at least len 6" sys.exit(-1) ret = False xseg_ctx = Xseg_ctx(SPEC, VTOOL) with Request(xseg_ctx, VPORT_START, len(name), sizeof(xseg_request_snapshot)) as req: req.set_op(X_SNAPSHOT) req.set_size(sizeof(xseg_request_snapshot)) req.set_offset(0) req.set_target(name) xsnapshot = xseg_request_snapshot() xsnapshot.target = "" xsnapshot.targetlen = 0 req.set_data(xsnapshot) req.submit() req.wait() ret = req.success() reply = string_at(req.get_data(xseg_reply_snapshot).contents.target, 64) xseg_ctx.shutdown() if not ret: sys.stderr.write("vlmc snapshot failed\n") sys.exit(-1) sys.stdout.write("Snapshot name: %s\n" % reply) return def vlmc_list(args): if STORAGE == "rados": cmd = [ 'rados', '-p', '%s' % RADOS_POOL_MAPS, 'ls' ] proc = Popen(cmd, stdout = PIPE) while proc.poll() is None: output = proc.stdout.readline() if output.startswith(ARCHIP_PREFIX) and not output.endswith('_lock\n'): print output.lstrip(ARCHIP_PREFIX), elif STORAGE == "files": print >> sys.stderr, "Vlmc list not supported for files yet" return 0 else: print >> sys.stderr, "Invalid storage" sys.exit(-1) return @exclusive def vlmc_remove(args): name = args.name[0] try: for f in os.listdir(XSEGBD_SYSFS + "devices/"): d_id = open(XSEGBD_SYSFS + "devices/" + f + "/id").read().strip() target = open(XSEGBD_SYSFS + "devices/"+ f + "/target").read().strip() if target == name: sys.stderr.write("Volume mapped on device %s%s\n" % (DEVICE_PREFIX, d_id)) sys.exit(-1) except Exception, reason: print >> sys.stderr, reason sys.exit(-1) ret = False xseg_ctx = Xseg_ctx(SPEC, VTOOL) with Request(xseg_ctx, MPORT, len(name), 0) as req: req.set_op(X_DELETE) req.set_size(0) req.set_offset(0) req.set_target(name) req.submit() req.wait() ret = req.success() xseg_ctx.shutdown() if not ret: sys.stderr.write("vlmc removal failed\n") sys.exit(-1) @exclusive def vlmc_map(args): if not loaded_module(xsegbd): sys.stderr.write("Xsegbd module not loaded\n") sys.exit(-1) name = args.name[0] prev = XSEGBD_START try: result = [int(open(XSEGBD_SYSFS + "devices/" + f + "/srcport").read().strip()) for f in os.listdir(XSEGBD_SYSFS + "devices/")] result.sort() for p in result: if p - prev > 1: break else: prev = p port = prev + 1 if port > XSEGBD_END: print >> sys.stderr, "Max xsegbd devices reached" sys.exit(-1) fd = os.open(XSEGBD_SYSFS + "add", os.O_WRONLY) print >> sys.stderr, "write to %s : %s %d:%d:%d" %( XSEGBD_SYSFS + "add", name, port, port - XSEGBD_START + VPORT_START, REQS ) os.write(fd, "%s %d:%d:%d" % (name, port, port - XSEGBD_START + VPORT_START, REQS)) os.close(fd) except Exception, reason: print >> sys.stderr, reason sys.exit(-1) @exclusive def vlmc_unmap(args): if not loaded_module(xsegbd): sys.stderr.write("Xsegbd module not loaded\n") sys.exit(-1) device = args.name[0] try: for f in os.listdir(XSEGBD_SYSFS + "devices/"): d_id = open(XSEGBD_SYSFS + "devices/" + f + "/id").read().strip() name = open(XSEGBD_SYSFS + "devices/"+ f + "/target").read().strip() if device == DEVICE_PREFIX + d_id: fd = os.open(XSEGBD_SYSFS + "remove", os.O_WRONLY) os.write(fd, d_id) os.close(fd) sys.exit(0) print >> sys.stderr, "Device %s doesn't exist" % device sys.exit(-1) except Exception, reason: print >> sys.stderr, reason sys.exit(-1) # FIXME: def vlmc_resize(args): if not loaded_module(xsegbd): sys.stderr.write("Xsegbd module not loaded\n") sys.exit(-1) name = args.name[0] size = args.size[0] try: for f in os.listdir(XSEGBD_SYSFS + "devices/"): d_id = open(XSEGBD_SYSFS + "devices/" + f + "/id").read().strip() d_name = open(XSEGBD_SYSFS + "devices/"+ f + "/name").read().strip() if name == d_name: fd = os.open(XSEGBD_SYSFS + "devices/" + d_id +"/refresh", os.O_WRONLY) os.write(fd, "1") os.close(fd) sys.exit(0) except Exception, reason: print >> sys.stderr, reason sys.exit(-1) @exclusive def vlmc_lock(args): name = args.name[0] if len(name) < 6: print >> sys.stderr, "Name should have at least len 6" sys.exit(-1) name = ARCHIP_PREFIX + name ret = False xseg_ctx = Xseg_ctx(SPEC, VTOOL) with Request(xseg_ctx, MBPORT, len(name), 0) as req: req.set_op(X_ACQUIRE) req.set_size(0) req.set_offset(0) req.set_flags(XF_NOSYNC) req.set_target(name) req.submit() req.wait() ret = req.success() xseg_ctx.shutdown() if not ret: sys.stderr.write("vlmc lock failed\n") sys.exit(-1) else: sys.stdout.write("Volume locked\n") @exclusive def vlmc_unlock(args): name = args.name[0] force = args.force if len(name) < 6: print >> sys.stderr, "Name should have at least len 6" sys.exit(-1) name = ARCHIP_PREFIX + name ret = False xseg_ctx = Xseg_ctx(SPEC, VTOOL) with Request(xseg_ctx, MBPORT, len(name), 0) as req: req.set_op(X_RELEASE) req.set_size(0) req.set_offset(0) req.set_target(name) if force: req.set_flags(XF_NOSYNC|XF_FORCE) else: req.set_flags(XF_NOSYNC) req.submit() req.wait() ret = req.success() xseg_ctx.shutdown() if not ret: sys.stderr.write("vlmc unlock failed\n") sys.exit(-1) else: sys.stdout.write("Volume unlocked\n") @exclusive def vlmc_open(args): name = args.name[0] if len(name) < 6: print >> sys.stderr, "Name should have at least len 6" sys.exit(-1) ret = False xseg_ctx = Xseg_ctx(SPEC, VTOOL) with Request(xseg_ctx, VPORT, len(name), 0) as req: req.set_op(X_OPEN) req.set_size(0) req.set_offset(0) req.set_target(name) req.submit() req.wait() ret = req.success() xseg_ctx.shutdown() if not ret: sys.stderr.write("vlmc open failed\n") sys.exit(-1) else: sys.stdout.write("Volume opened\n") @exclusive def vlmc_close(args): name = args.name[0] if len(name) < 6: print >> sys.stderr, "Name should have at least len 6" sys.exit(-1) ret = False xseg_ctx = Xseg_ctx(SPEC, VTOOL) with Request(xseg_ctx, VPORT, len(name), 0) as req: req.set_op(X_CLOSE) req.set_size(0) req.set_offset(0) req.set_target(name) req.submit() req.wait() ret = req.success() xseg_ctx.shutdown() if not ret: sys.stderr.write("vlmc close failed\n") sys.exit(-1) else: sys.stdout.write("Volume closed\n") def archipelago(): parser = argparse.ArgumentParser(description='Archipelago tool') parser.add_argument('-c', '--config', type=str, nargs='?', help='config file') parser.add_argument('-u', '--user', action='store_true', default=False , help='affect only userspace peers') subparsers = parser.add_subparsers() start_parser = subparsers.add_parser('start', help='Start archipelago') start_parser.set_defaults(func=start) stop_parser = subparsers.add_parser('stop', help='Stop archipelago') stop_parser.set_defaults(func=stop) status_parser = subparsers.add_parser('status', help='Archipelago status') status_parser.set_defaults(func=status) restart_parser = subparsers.add_parser('restart', help='Restart archipelago') restart_parser.set_defaults(func=restart) return parser def vlmc(): parser = argparse.ArgumentParser(description='vlmc tool') parser.add_argument('-c', '--config', type=str, nargs='?', help='config file') subparsers = parser.add_subparsers() create_parser = subparsers.add_parser('create', help='Create volume') #group = create_parser.add_mutually_exclusive_group(required=True) create_parser.add_argument('-s', '--size', type=int, nargs='?', help='requested size in MB for create') create_parser.add_argument('--snap', type=str, nargs='?', help='create from snapshot') create_parser.add_argument('-p', '--pool', type=str, nargs='?', help='for backwards compatiblity with rbd') create_parser.add_argument('name', type=str, nargs=1, help='volume/device name') create_parser.set_defaults(func=vlmc_create) remove_parser = subparsers.add_parser('remove', help='Delete volume') remove_parser.add_argument('name', type=str, nargs=1, help='volume/device name') remove_parser.set_defaults(func=vlmc_remove) remove_parser.add_argument('-p', '--pool', type=str, nargs='?', help='for backwards compatiblity with rbd') rm_parser = subparsers.add_parser('rm', help='Delete volume') rm_parser.add_argument('name', type=str, nargs=1, help='volume/device name') rm_parser.set_defaults(func=vlmc_remove) rm_parser.add_argument('-p', '--pool', type=str, nargs='?', help='for backwards compatiblity with rbd') map_parser = subparsers.add_parser('map', help='Map volume') map_parser.add_argument('name', type=str, nargs=1, help='volume/device name') map_parser.set_defaults(func=vlmc_map) map_parser.add_argument('-p', '--pool', type=str, nargs='?', help='for backwards compatiblity with rbd') unmap_parser = subparsers.add_parser('unmap', help='Unmap volume') unmap_parser.add_argument('name', type=str, nargs=1, help='volume/device name') unmap_parser.set_defaults(func=vlmc_unmap) unmap_parser.add_argument('-p', '--pool', type=str, nargs='?', help='for backwards compatiblity with rbd') showmapped_parser = subparsers.add_parser('showmapped', help='Show mapped volumes') showmapped_parser.set_defaults(func=vlmc_showmapped_wrapper) showmapped_parser.add_argument('-p', '--pool', type=str, nargs='?', help='for backwards compatiblity with rbd') list_parser = subparsers.add_parser('list', help='List volumes') list_parser.set_defaults(func=vlmc_list) list_parser.add_argument('-p', '--pool', type=str, nargs='?', help='for backwards compatiblity with rbd') snapshot_parser = subparsers.add_parser('snapshot', help='snapshot volume') #group = snapshot_parser.add_mutually_exclusive_group(required=True) snapshot_parser.add_argument('-p', '--pool', type=str, nargs='?', help='for backwards compatiblity with rbd') snapshot_parser.add_argument('name', type=str, nargs=1, help='volume/device name') snapshot_parser.set_defaults(func=vlmc_snapshot) ls_parser = subparsers.add_parser('ls', help='List volumes') ls_parser.set_defaults(func=vlmc_list) ls_parser.add_argument('-p', '--pool', type=str, nargs='?', help='for backwards compatiblity with rbd') resize_parser = subparsers.add_parser('resize', help='Resize volume') resize_parser.add_argument('-s', '--size', type=int, nargs=1, help='requested size in MB for resize') resize_parser.add_argument('name', type=str, nargs=1, help='volume/device name') resize_parser.set_defaults(func=vlmc_resize) resize_parser.add_argument('-p', '--pool', type=str, nargs='?', help='for backwards compatiblity with rbd') open_parser = subparsers.add_parser('open', help='open volume') open_parser.add_argument('name', type=str, nargs=1, help='volume/device name') open_parser.set_defaults(func=vlmc_open) open_parser.add_argument('-p', '--pool', type=str, nargs='?', help='for backwards compatiblity with rbd') close_parser = subparsers.add_parser('close', help='close volume') close_parser.add_argument('name', type=str, nargs=1, help='volume/device name') close_parser.set_defaults(func=vlmc_close) close_parser.add_argument('-p', '--pool', type=str, nargs='?', help='for backwards compatiblity with rbd') lock_parser = subparsers.add_parser('lock', help='lock volume') lock_parser.add_argument('name', type=str, nargs=1, help='volume/device name') lock_parser.set_defaults(func=vlmc_lock) lock_parser.add_argument('-p', '--pool', type=str, nargs='?', help='for backwards compatiblity with rbd') unlock_parser = subparsers.add_parser('unlock', help='unlock volume') unlock_parser.add_argument('name', type=str, nargs=1, help='volume/device name') unlock_parser.add_argument('-f', '--force', action='store_true', default=False , help='break lock') unlock_parser.set_defaults(func=vlmc_unlock) unlock_parser.add_argument('-p', '--pool', type=str, nargs='?', help='for backwards compatiblity with rbd') return parser if __name__ == "__main__": # parse arguments and discpatch to the correct func try: parser_func = { 'archipelago' : archipelago, 'vlmc' : vlmc, }[os.path.basename(sys.argv[0])] parser = parser_func() except Exception as e: sys.stderr.write("Invalid basename\n") sys.exit(-1) args = parser.parse_args() loadrc(args.config) if parser_func == archipelago: peers = construct_peers() xsegbd_args = [('start_portno', str(XSEGBD_START)), ('end_portno', str(XSEGBD_END))] sys.exit(args.func(args))