From 056aa4ca6e40a453e19043982d6604590e070386 Mon Sep 17 00:00:00 2001 From: pschwan Date: Mon, 31 Mar 2003 18:33:36 +0000 Subject: [PATCH] landing b_recovery on b_devel * bug fixes - imports and exports cleanup too early, need refcounts (349, 879, 1045) - per-import/export recovery handling (958, 931, 959) - multiple last-rcvd slots, for serving multiple FSes (949) - connections are again shared between multiple imp/exports (963, 964) - "umount -f" would hang if any requests needed to be sent (393, 978) - avoid pinning large req buffer by copying for queued messages (989) - add "uuid" to "lctl device" command to help upcalls (991) - "open" RPCs with transnos would confuse recovery counters (1037) * major user-visible changes - fail out/fail over policy now controlled by the upcall (993) * protocol changes - add OBD_PING to check server availability and failure (954) --- lustre/ptlrpc/ptlrpc_internal.h | 43 +++++ lustre/ptlrpc/ptlrpc_module.c | 192 ++++++++++++++++++++ lustre/utils/Lustre/.cvsignore | 4 + lustre/utils/Lustre/Makefile.am | 2 + lustre/utils/Lustre/__init__.py | 5 + lustre/utils/Lustre/cmdline.py | 167 +++++++++++++++++ lustre/utils/Lustre/error.py | 10 ++ lustre/utils/Lustre/lustredb.py | 389 ++++++++++++++++++++++++++++++++++++++++ lustre/utils/lactive | 73 ++++++++ lustre/utils/load_ldap.sh | 41 +++++ 10 files changed, 926 insertions(+) create mode 100644 lustre/ptlrpc/ptlrpc_internal.h create mode 100644 lustre/ptlrpc/ptlrpc_module.c create mode 100644 lustre/utils/Lustre/.cvsignore create mode 100644 lustre/utils/Lustre/Makefile.am create mode 100644 lustre/utils/Lustre/__init__.py create mode 100644 lustre/utils/Lustre/cmdline.py create mode 100644 lustre/utils/Lustre/error.py create mode 100644 lustre/utils/Lustre/lustredb.py create mode 100644 lustre/utils/lactive create mode 100755 lustre/utils/load_ldap.sh diff --git a/lustre/ptlrpc/ptlrpc_internal.h b/lustre/ptlrpc/ptlrpc_internal.h new file mode 100644 index 0000000..e04f7ee --- /dev/null +++ b/lustre/ptlrpc/ptlrpc_internal.h @@ -0,0 +1,43 @@ +/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*- + * vim:expandtab:shiftwidth=8:tabstop=8: + * + * Copyright (C) 2003 Cluster File Systems, Inc. + * + * This file is part of Lustre, http://www.lustre.org. + * + * Lustre is free software; you can redistribute it and/or + * modify it under the terms of version 2 of the GNU General Public + * License as published by the Free Software Foundation. + * + * Lustre is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Lustre; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +/* Intramodule declarations for ptlrpc. */ + +#ifndef PTLRPC_INTERNAL_H +#define PTLRPC_INTERNAL_H + +struct ldlm_namespace; +struct obd_import; +struct ldlm_res_id; + +/* ldlm hooks that we need, managed via inter_module_{get,put} */ +extern int (*ptlrpc_ldlm_namespace_cleanup)(struct ldlm_namespace *, int); +extern int (*ptlrpc_ldlm_cli_cancel_unused)(struct ldlm_namespace *, + struct ldlm_res_id *, int); +extern int (*ptlrpc_ldlm_replay_locks)(struct obd_import *); + +int ptlrpc_get_ldlm_hooks(void); +void ptlrpc_put_ldlm_hooks(void); + +int ptlrpc_import_handle_eviction(struct obd_import *); + +#endif /* PTLRPC_INTERNAL_H */ diff --git a/lustre/ptlrpc/ptlrpc_module.c b/lustre/ptlrpc/ptlrpc_module.c new file mode 100644 index 0000000..df5ab06 --- /dev/null +++ b/lustre/ptlrpc/ptlrpc_module.c @@ -0,0 +1,192 @@ +/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*- + * vim:expandtab:shiftwidth=8:tabstop=8: + * + * Copyright (c) 2002, 2003 Cluster File Systems, Inc. + * + * This file is part of Lustre, http://www.lustre.org. + * + * Lustre is free software; you can redistribute it and/or + * modify it under the terms of version 2 of the GNU General Public + * License as published by the Free Software Foundation. + * + * Lustre is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Lustre; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#define EXPORT_SYMTAB +#define DEBUG_SUBSYSTEM S_RPC + +#ifdef __KERNEL__ +# include +# include +#else +# include +#endif + +#include +#include +#include + +#include "ptlrpc_internal.h" + +extern int ptlrpc_init_portals(void); +extern void ptlrpc_exit_portals(void); + +int (*ptlrpc_ldlm_namespace_cleanup)(struct ldlm_namespace *, int); +int (*ptlrpc_ldlm_cli_cancel_unused)(struct ldlm_namespace *, + struct ldlm_res_id *, int); +int (*ptlrpc_ldlm_replay_locks)(struct obd_import *); + +#define GET_HOOK(name) \ +if (!ptlrpc_##name) { \ + if (!(ptlrpc_##name = inter_module_get(#name))) { \ + CERROR("can't i_m_g(\"" #name "\")\n"); \ + return 0; \ + } \ +} + +/* This is called from ptlrpc_get_connection, which runs after all the modules + * are loaded, but before anything else interesting happens. + */ +int ptlrpc_get_ldlm_hooks(void) +{ + static int ensured = 0; + + if (ensured) + return 1; + + GET_HOOK(ldlm_cli_cancel_unused); + GET_HOOK(ldlm_namespace_cleanup); + GET_HOOK(ldlm_replay_locks); + + ensured = 1; + RETURN(1); +} + +#undef GET_HOOK + +#define PUT_HOOK(hook) \ +if (ptlrpc_##hook) { \ + inter_module_put(#hook); \ + ptlrpc_##hook = NULL; \ +} + +void ptlrpc_put_ldlm_hooks(void) +{ + ENTRY; + + PUT_HOOK(ldlm_cli_cancel_unused); + PUT_HOOK(ldlm_namespace_cleanup); + PUT_HOOK(ldlm_replay_locks); +} + +#undef PUT_HOOK + +__init int ptlrpc_init(void) +{ + int rc; + ENTRY; + + rc = ptlrpc_init_portals(); + if (rc) + RETURN(rc); + + ptlrpc_init_connection(); + + ptlrpc_put_connection_superhack = ptlrpc_put_connection; + ptlrpc_abort_inflight_superhack = ptlrpc_abort_inflight; + RETURN(0); +} + +static void __exit ptlrpc_exit(void) +{ + ptlrpc_exit_portals(); + ptlrpc_cleanup_connection(); +} + +/* connection.c */ +EXPORT_SYMBOL(ptlrpc_readdress_connection); +EXPORT_SYMBOL(ptlrpc_get_connection); +EXPORT_SYMBOL(ptlrpc_put_connection); +EXPORT_SYMBOL(ptlrpc_connection_addref); +EXPORT_SYMBOL(ptlrpc_init_connection); +EXPORT_SYMBOL(ptlrpc_cleanup_connection); + +/* niobuf.c */ +EXPORT_SYMBOL(ptlrpc_bulk_put); +EXPORT_SYMBOL(ptlrpc_bulk_get); +EXPORT_SYMBOL(ptlrpc_register_bulk_put); +EXPORT_SYMBOL(ptlrpc_register_bulk_get); +EXPORT_SYMBOL(ptlrpc_abort_bulk); +EXPORT_SYMBOL(ptlrpc_reply); +EXPORT_SYMBOL(ptlrpc_error); +EXPORT_SYMBOL(ptlrpc_resend_req); +EXPORT_SYMBOL(ptl_send_rpc); +EXPORT_SYMBOL(ptlrpc_link_svc_me); +EXPORT_SYMBOL(obd_brw_set_new); +EXPORT_SYMBOL(obd_brw_set_add); +EXPORT_SYMBOL(obd_brw_set_del); +EXPORT_SYMBOL(obd_brw_set_decref); +EXPORT_SYMBOL(obd_brw_set_addref); + +/* client.c */ +EXPORT_SYMBOL(ptlrpc_init_client); +EXPORT_SYMBOL(ptlrpc_cleanup_client); +EXPORT_SYMBOL(ptlrpc_req_to_uuid); +EXPORT_SYMBOL(ptlrpc_uuid_to_connection); +EXPORT_SYMBOL(ptlrpc_queue_wait); +EXPORT_SYMBOL(ptlrpc_continue_req); +EXPORT_SYMBOL(ptlrpc_replay_req); +EXPORT_SYMBOL(ptlrpc_restart_req); +EXPORT_SYMBOL(ptlrpc_prep_req); +EXPORT_SYMBOL(ptlrpc_free_req); +EXPORT_SYMBOL(ptlrpc_abort); +EXPORT_SYMBOL(ptlrpc_req_finished); +EXPORT_SYMBOL(ptlrpc_request_addref); +EXPORT_SYMBOL(ptlrpc_prep_bulk_imp); +EXPORT_SYMBOL(ptlrpc_prep_bulk_exp); +EXPORT_SYMBOL(ptlrpc_free_bulk); +EXPORT_SYMBOL(ptlrpc_prep_bulk_page); +EXPORT_SYMBOL(ptlrpc_free_bulk_page); +EXPORT_SYMBOL(ll_brw_sync_wait); +EXPORT_SYMBOL(ptlrpc_abort_inflight); +EXPORT_SYMBOL(ptlrpc_retain_replayable_request); +EXPORT_SYMBOL(ptlrpc_next_xid); + +/* service.c */ +EXPORT_SYMBOL(ptlrpc_init_svc); +EXPORT_SYMBOL(ptlrpc_stop_all_threads); +EXPORT_SYMBOL(ptlrpc_start_thread); +EXPORT_SYMBOL(ptlrpc_unregister_service); + +/* pack_generic.c */ +EXPORT_SYMBOL(lustre_pack_msg); +EXPORT_SYMBOL(lustre_msg_size); +EXPORT_SYMBOL(lustre_unpack_msg); +EXPORT_SYMBOL(lustre_msg_buf); + +/* recover.c */ +EXPORT_SYMBOL(ptlrpc_run_recovery_upcall); +EXPORT_SYMBOL(ptlrpc_reconnect_import); +EXPORT_SYMBOL(ptlrpc_replay); +EXPORT_SYMBOL(ptlrpc_resend); +EXPORT_SYMBOL(ptlrpc_wake_delayed); +EXPORT_SYMBOL(ptlrpc_fail_import); +EXPORT_SYMBOL(ptlrpc_fail_export); +EXPORT_SYMBOL(ptlrpc_recover_import); + +#ifdef __KERNEL__ +MODULE_AUTHOR("Cluster File Systems, Inc. "); +MODULE_DESCRIPTION("Lustre Request Processor"); +MODULE_LICENSE("GPL"); + +module_init(ptlrpc_init); +module_exit(ptlrpc_exit); +#endif diff --git a/lustre/utils/Lustre/.cvsignore b/lustre/utils/Lustre/.cvsignore new file mode 100644 index 0000000..97e22b9 --- /dev/null +++ b/lustre/utils/Lustre/.cvsignore @@ -0,0 +1,4 @@ +Makefile +Makefile.in +.deps +*.pyc diff --git a/lustre/utils/Lustre/Makefile.am b/lustre/utils/Lustre/Makefile.am new file mode 100644 index 0000000..061adfd --- /dev/null +++ b/lustre/utils/Lustre/Makefile.am @@ -0,0 +1,2 @@ + +pymod_SCRIPTS = __init__.py lustredb.py error.py diff --git a/lustre/utils/Lustre/__init__.py b/lustre/utils/Lustre/__init__.py new file mode 100644 index 0000000..a4f4367 --- /dev/null +++ b/lustre/utils/Lustre/__init__.py @@ -0,0 +1,5 @@ +__all__ = ["lustredb"] + +from lustredb import LustreDB, LustreDB_XML, LustreDB_LDAP +from error import LconfError, OptionError +from cmdline import Options diff --git a/lustre/utils/Lustre/cmdline.py b/lustre/utils/Lustre/cmdline.py new file mode 100644 index 0000000..fa1e611 --- /dev/null +++ b/lustre/utils/Lustre/cmdline.py @@ -0,0 +1,167 @@ +#!/usr/bin/env python +# +# Copyright (C) 2002 Cluster File Systems, Inc. +# Author: Robert Read +# This file is part of Lustre, http://www.lustre.org. +# +# Lustre is free software; you can redistribute it and/or +# modify it under the terms of version 2 of the GNU General Public +# License as published by the Free Software Foundation. +# +# Lustre is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Lustre; if not, write to the Free Software +# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +# + +# Standard the comand line handling for all the python tools. + +import sys, getopt, types +import string +import error + +class Options: + FLAG = 1 + PARAM = 2 + def __init__(self, cmd, remain_help, options): + self.options = options + shorts = "" + longs = [] + options.append(('help,h', "Print this help")) + for opt in options: + long = self.long(opt) + short = self.short(opt) + if self.type(opt) == Options.PARAM: + if short: short = short + ':' + if long: long = long + '=' + shorts = shorts + short + longs.append(long) + self.short_opts = shorts + self.long_opts = longs + self.cmd = cmd + self.remain_help = remain_help + + def init_values(self): + values = {} + for opt in self.options: + values[self.long(opt)] = self.default(opt) + return values + + def long(self, option): + n = string.find(option[0], ',') + if n < 0: return option[0] + else: return option[0][0:n] + + def short(self, option): + n = string.find(option[0], ',') + if n < 0: return '' + else: return option[0][n+1:] + + def help(self, option): + return option[1] + + def type(self, option): + if len(option) >= 3: + return option[2] + return Options.FLAG + + def default(self, option): + if len(option) >= 4: + return option[3] + return None + + def lookup_option(self, key, key_func): + for opt in self.options: + if key_func(opt) == key: + return opt + + def lookup_short(self, key): + return self.lookup_option(key, self.short) + + def lookup_long(self, key): + return self.lookup_option(key, self.long) + + def handle_opts(self, opts): + values = self.init_values() + for o, a in opts: + if o[0:2] != '--': + option = self.lookup_short(o[1:]) + else: + option = self.lookup_long(o[2:]) + if self.type(option) == Options.PARAM: + val = a + else: + val = 1 + values[self.long(option)] = val + return values + + class option_wrapper: + def __init__(self, values): + self.__dict__['values'] = values + def __getattr__(self, name): + if self.values.has_key(name): + return self.values[name] + else: + raise error.OptionError("bad option name: " + name) + def __setattr__(self, name, value): + self.values[name] = value + + def parse(self, argv): + try: + opts, args = getopt.getopt(argv, self.short_opts, self.long_opts) + values = self.handle_opts(opts) + if values["help"]: + self.usage() + sys.exit(0) + return self.option_wrapper(values), args + except getopt.error, e: + raise error.OptionError(e) + + def usage(self): + ret = 'usage: %s [options] %s\n' % (self.cmd, self.remain_help) + for opt in self.options: + s = self.short(opt) + if s: str = "-%s|--%s" % (s,self.long(opt)) + else: str = "--%s" % (self.long(opt),) + if self.type(opt) == Options.PARAM: + str = "%s " % (str,) + help = self.help(opt) + n = string.find(help, '\n') + if self.default(opt) != None: + if n < 0: + str = "%-15s %s (default=%s)" %(str, help, + self.default(opt)) + else: + str = "%-15s %s (default=%s)%s" %(str, help[0:n], + self.default(opt), + help[n:]) + else: + str = "%-15s %s" %(str, help) + ret = ret + str + "\n" + print ret + +# Test driver +if __name__ == "__main__": + cl = Options("test", "xml_file", [ + ('verbose,v', "verbose ", Options.FLAG, 0), + ('cleanup,d', "shutdown"), + ('gdb', "Display gdb module file ", Options.FLAG, 0), + ('device', "device path ", Options.PARAM), + ('ldapurl', "LDAP server URL ", Options.PARAM), + ('lustre', "Lustre source dir ", Options.PARAM), + ('portals', "Portals source dir ", Options.PARAM), + ('maxlevel', """Specify the maximum level + Levels are aproximatly like: + 70 - mountpoint, echo_client, osc, mdc, lov""", + Options.PARAM, 100), + + ]) + + conf, args = cl.parse(sys.argv[1:]) + + for key in conf.values.keys(): + print "%-10s = %s" % (key, conf.values[key]) diff --git a/lustre/utils/Lustre/error.py b/lustre/utils/Lustre/error.py new file mode 100644 index 0000000..6c30416 --- /dev/null +++ b/lustre/utils/Lustre/error.py @@ -0,0 +1,10 @@ +import exceptions + +class LconfError (exceptions.Exception): + def __init__(self, args): + self.args = args + +class OptionError (exceptions.Exception): + def __init__(self, args): + self.args = args + diff --git a/lustre/utils/Lustre/lustredb.py b/lustre/utils/Lustre/lustredb.py new file mode 100644 index 0000000..14be906 --- /dev/null +++ b/lustre/utils/Lustre/lustredb.py @@ -0,0 +1,389 @@ +import sys, types, string, os +import re, exceptions +import xml.dom.minidom +import Lustre + +# ============================================================ +# XML processing and query + +class LustreDB: + def lookup(self, uuid): + """ lookup returns a new LustreDB instance""" + return self._lookup_by_uuid(uuid) + + def lookup_name(self, name, class_name = ""): + """ lookup returns a new LustreDB instance""" + return self._lookup_by_name(name, class_name) + + def lookup_class(self, class_name): + """ lookup returns a new LustreDB instance""" + return self._lookup_by_class(class_name) + + def get_val(self, tag, default=None): + v = self._get_val(tag) + if v: + return v + if default != None: + return default + return None + + def get_class(self): + return self._get_class() + + def get_val_int(self, tag, default=0): + str = self._get_val(tag) + try: + if str: + return int(str) + return default + except ValueError: + raise LconfError("text value is not integer:", str) + + def get_first_ref(self, tag): + """ Get the first uuidref of the type TAG. Only + one is expected. Returns the uuid.""" + uuids = self._get_refs(tag) + if len(uuids) > 0: + return uuids[0] + return None + + def get_refs(self, tag): + """ Get all the refs of type TAG. Returns list of uuids. """ + uuids = self._get_refs(tag) + return uuids + + def get_all_refs(self): + """ Get all the refs. Returns list of uuids. """ + uuids = self._get_all_refs() + return uuids + + def nid2server(self, nid, net_type): + netlist = self.lookup_class('network') + for net_db in netlist: + if net_db.get_val('nid') == nid and net_db.get_val('nettype') == net_type: + return net_db + return None + + # Find the target_device for target on a node + # node->profiles->device_refs->target + def get_node_tgt_dev(self, node_name, target_uuid): + node_db = self.lookup_name(node_name) + if not node_db: + return None + return self.get_tgt_dev(target_uuid) + + # get all network uuids for this node + def get_networks(self): + ret = [] + prof_list = self.get_refs('profile') + for prof_uuid in prof_list: + prof_db = self.lookup(prof_uuid) + net_list = prof_db.get_refs('network') + for net_uuid in net_list: + ret.append(net_uuid) + return ret + + def get_active_dev(self, tgtuuid): + tgt = self.lookup(tgtuuid) + tgt_dev_uuid =tgt.get_first_ref('active') + return tgt_dev_uuid + + def get_tgt_dev(self, tgtuuid): + prof_list = self.get_refs('profile') + for prof_uuid in prof_list: + prof_db = self.lookup(prof_uuid) + if not prof_db: + panic("profile:", profile, "not found.") + for ref_class, ref_uuid in prof_db.get_all_refs(): + if ref_class in ('osd', 'mdsdev'): + devdb = self.lookup(ref_uuid) + uuid = devdb.get_first_ref('target') + if tgtuuid == uuid: + return ref_uuid + return None + + # Change the current active device for a target + def update_active(self, tgtuuid, new_uuid): + self._update_active(tgtuuid, new_uuid) + +class LustreDB_XML(LustreDB): + def __init__(self, dom, root_node): + # init xmlfile + self.dom_node = dom + self.root_node = root_node + + def xmltext(self, dom_node, tag): + list = dom_node.getElementsByTagName(tag) + if len(list) > 0: + dom_node = list[0] + dom_node.normalize() + if dom_node.firstChild: + txt = string.strip(dom_node.firstChild.data) + if txt: + return txt + + def xmlattr(self, dom_node, attr): + return dom_node.getAttribute(attr) + + def _get_val(self, tag): + """a value could be an attribute of the current node + or the text value in a child node""" + ret = self.xmlattr(self.dom_node, tag) + if not ret: + ret = self.xmltext(self.dom_node, tag) + return ret + + def _get_class(self): + return self.dom_node.nodeName + + def get_ref_type(self, ref_tag): + res = string.split(ref_tag, '_') + return res[0] + + # + # [(ref_class, ref_uuid),] + def _get_all_refs(self): + list = [] + for n in self.dom_node.childNodes: + if n.nodeType == n.ELEMENT_NODE: + ref_uuid = self.xml_get_ref(n) + ref_class = self.get_ref_type(n.nodeName) + list.append((ref_class, ref_uuid)) + + list.sort() + return list + + def _get_refs(self, tag): + """ Get all the refs of type TAG. Returns list of uuids. """ + uuids = [] + refname = '%s_ref' % tag + reflist = self.dom_node.getElementsByTagName(refname) + for r in reflist: + uuids.append(self.xml_get_ref(r)) + return uuids + + def xmllookup_by_uuid(self, dom_node, uuid): + for n in dom_node.childNodes: + if n.nodeType == n.ELEMENT_NODE: + if self.xml_get_uuid(n) == uuid: + return n + else: + n = self.xmllookup_by_uuid(n, uuid) + if n: return n + return None + + def _lookup_by_uuid(self, uuid): + dom = self. xmllookup_by_uuid(self.root_node, uuid) + if dom: + return LustreDB_XML(dom, self.root_node) + + def xmllookup_by_name(self, dom_node, name): + for n in dom_node.childNodes: + if n.nodeType == n.ELEMENT_NODE: + if self.xml_get_name(n) == name: + return n + else: + n = self.xmllookup_by_name(n, name) + if n: return n + return None + + def _lookup_by_name(self, name, class_name): + dom = self.xmllookup_by_name(self.root_node, name) + if dom: + return LustreDB_XML(dom, self.root_node) + + def xmllookup_by_class(self, dom_node, class_name): + return dom_node.getElementsByTagName(class_name) + + def _lookup_by_class(self, class_name): + ret = [] + domlist = self.xmllookup_by_class(self.root_node, class_name) + for node in domlist: + ret.append(LustreDB_XML(node, self.root_node)) + return ret + + def xml_get_name(self, n): + return n.getAttribute('name') + + def getName(self): + return self.xml_get_name(self.dom_node) + + def xml_get_ref(self, n): + return n.getAttribute('uuidref') + + def xml_get_uuid(self, dom_node): + return dom_node.getAttribute('uuid') + + def getUUID(self): + return self.xml_get_uuid(self.dom_node) + + def get_routes(self, type, gw): + """ Return the routes as a list of tuples of the form: + [(type, gw, lo, hi),]""" + res = [] + tbl = self.dom_node.getElementsByTagName('routetbl') + for t in tbl: + routes = t.getElementsByTagName('route') + for r in routes: + net_type = self.xmlattr(r, 'type') + if type != net_type: + lo = self.xmlattr(r, 'lo') + hi = self.xmlattr(r, 'hi') + res.append((type, gw, lo, hi)) + return res + + def get_route_tbl(self): + ret = [] + for r in self.dom_node.getElementsByTagName('route'): + net_type = self.xmlattr(r, 'type') + gw = self.xmlattr(r, 'gw') + lo = self.xmlattr(r, 'lo') + hi = self.xmlattr(r, 'hi') + ret.append((net_type, gw, lo, hi)) + return ret + + def _update_active(self, tgt, new): + raise LconfError("updates not implemented for XML") + +# ================================================================ +# LDAP Support +class LustreDB_LDAP(LustreDB): + def __init__(self, name, attrs, + base = "fs=lustre", + parent = None, + url = "ldap://localhost", + user = "cn=Manager, fs=lustre", + pw = "secret" + ): + self._name = name + self._attrs = attrs + self._base = base + self._parent = parent + self._url = url + self._user = user + self._pw = pw + if parent: + self.l = parent.l + self._base = parent._base + else: + self.open() + + def open(self): + import ldap + try: + self.l = ldap.initialize(self._url) + # Set LDAP protocol version used + self.l.protocol_version=ldap.VERSION3 + # user and pw only needed if modifying db + self.l.bind_s(self._user, self._pw, ldap.AUTH_SIMPLE); + except ldap.LDAPError, e: + raise LconfError(e) + # FIXME, do something useful here + + def close(self): + self.l.unbind_s() + + def ldap_search(self, filter): + """Return list of uuids matching the filter.""" + import ldap + dn = self._base + ret = [] + uuids = [] + try: + for name, attrs in self.l.search_s(dn, ldap.SCOPE_ONELEVEL, + filter, ["uuid"]): + for v in attrs['uuid']: + uuids.append(v) + except ldap.NO_SUCH_OBJECT, e: + pass + except ldap.LDAPError, e: + print e # FIXME: die here? + if len(uuids) > 0: + for uuid in uuids: + ret.append(self._lookup_by_uuid(uuid)) + return ret + + def _lookup_by_name(self, name, class_name): + list = self.ldap_search("lustreName=%s" %(name)) + if len(list) == 1: + return list[0] + return None + + def _lookup_by_class(self, class_name): + return self.ldap_search("objectclass=%s" %(string.upper(class_name))) + + def _lookup_by_uuid(self, uuid): + import ldap + dn = "uuid=%s,%s" % (uuid, self._base) + ret = None + try: + for name, attrs in self.l.search_s(dn, ldap.SCOPE_BASE, + "objectclass=*"): + ret = LustreDB_LDAP(name, attrs, parent = self) + + except ldap.NO_SUCH_OBJECT, e: + pass # just return empty list + except ldap.LDAPError, e: + print e # FIXME: die here? + return ret + + + def _get_val(self, k): + ret = None + if self._attrs.has_key(k): + v = self._attrs[k] + if type(v) == types.ListType: + ret = str(v[0]) + else: + ret = str(v) + return ret + + def _get_class(self): + return string.lower(self._attrs['objectClass'][0]) + + def get_ref_type(self, ref_tag): + return ref_tag[:-3] + + # + # [(ref_class, ref_uuid),] + def _get_all_refs(self): + list = [] + for k in self._attrs.keys(): + if re.search('.*Ref', k): + for uuid in self._attrs[k]: + ref_class = self.get_ref_type(k) + list.append((ref_class, uuid)) + return list + + def _get_refs(self, tag): + """ Get all the refs of type TAG. Returns list of uuids. """ + uuids = [] + refname = '%sRef' % tag + if self._attrs.has_key(refname): + return self._attrs[refname] + return [] + + def getName(self): + return self._get_val('lustreName') + + def getUUID(self): + return self._get_val('uuid') + + def get_route_tbl(self): + return [] + + def _update_active(self, tgtuuid, newuuid): + """Return list of uuids matching the filter.""" + import ldap + dn = "uuid=%s,%s" %(tgtuuid, self._base) + ret = [] + uuids = [] + try: + self.l.modify_s(dn, [(ldap.MOD_REPLACE, "activeRef", newuuid)]) + except ldap.NO_SUCH_OBJECT, e: + print e + except ldap.LDAPError, e: + print e # FIXME: die here? + return + + diff --git a/lustre/utils/lactive b/lustre/utils/lactive new file mode 100644 index 0000000..6fd5815 --- /dev/null +++ b/lustre/utils/lactive @@ -0,0 +1,73 @@ +#!/usr/bin/env python +# +# Copyright (C) 2002 Cluster File Systems, Inc. +# Author: Robert Read +# This file is part of Lustre, http://www.lustre.org. +# +# Lustre is free software; you can redistribute it and/or +# modify it under the terms of version 2 of the GNU General Public +# License as published by the Free Software Foundation. +# +# Lustre is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Lustre; if not, write to the Free Software +# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +# + +# Make the new node the active node for all devices it shares with the +# old. The bulk of this code is for figuring out which devices to +# change, and what to change them to. + +# XXX add error checking +# XXX make this code less ugly + +import sys, getopt, types +import string, os +import ldap +import Lustre + +lactive_options = [ + ('ldapurl',"LDAP server URL, eg. ldap://localhost", Lustre.Options.PARAM), + ('config', "Cluster config name used for LDAP query", Lustre.Options.PARAM), + ('old', "The old, failed node name", Lustre.Options.PARAM), + ('new', "The new node name", Lustre.Options.PARAM), + ] + +cl = Lustre.Options("lactive","", lactive_options) +config, args = cl.parse(sys.argv[1:]) + +base = "config=%s,fs=lustre" % (config.config,) +db = Lustre.LustreDB_LDAP('', {}, base=base, url = config.ldapurl) + +old = db.lookup_name(config.old) +new = db.lookup_name(config.new) + +print "old:", old.getUUID() +print "new:", new.getUUID() + +# find all the targets on the failed node and, change the active +# pointers to point to the devices on the new node. +prof_list = old.get_refs('profile') +for prof_uuid in prof_list: + prof_db = db.lookup(prof_uuid) + if not prof_db: + panic("profile:", profile, "not found.") + for ref_class, ref_uuid in prof_db.get_all_refs(): + if ref_class in ('osd', 'mdsdev'): + devdb = db.lookup(ref_uuid) + tgtuuid = devdb.get_first_ref('target') + active_uuid = old.get_active_dev(tgtuuid) + if ref_uuid != active_uuid: + continue + inactive_uuid = new.get_tgt_dev(tgtuuid) + print ("%s: changing active %s:%s to %s:%s" + % (tgtuuid, config.old, active_uuid, + config.new, inactive_uuid)) + db.update_active(tgtuuid, inactive_uuid) + + + diff --git a/lustre/utils/load_ldap.sh b/lustre/utils/load_ldap.sh new file mode 100755 index 0000000..531d385 --- /dev/null +++ b/lustre/utils/load_ldap.sh @@ -0,0 +1,41 @@ +#!/bin/bash +# +# Load a lustre config xml into an openldap database. +# See https://projects.clusterfs.com/lustre/LustreLDAP +# for more details. +# +# Usage: load_ldap.sh +set -e + +LDAP_BASE=${LDAP_BASE:-fs=lustre} +LDAP_ROOTDN=${LDAP_ROOTDN:-cn=Manager,fs=lustre} +LDAP_PW=${LDAP_PW:-secret} +LDAP_AUTH="-x -D $LDAP_ROOTDN -w $LDAP_PW" +LUSTRE=${LUSTRE:-`dirname $0`/..} + +[ ! -z $LDAPURL ] && LDAP_AUTH="$LDAP_AUTH -H $LDAPURL" + +XML=${XML:-$1} + +if [ -z "$XML" ] || [ ! -r $XML ]; then + echo "usage: $0 xmlfile" + exit 1 +fi + +NAME=`basename $XML .xml` +LDIF=/tmp/$NAME.ldif + +# add the top level record, if needed +ldapsearch $LDAP_AUTH -b $LDAP_BASE > /dev/null 2>&1 || + ldapadd $LDAP_AUTH -f $LUSTRE/conf/top.ldif + +# If this config already exists, then delete it +ldapsearch $LDAP_AUTH -b config=$NAME,$LDAP_BASE > /dev/null 2>&1 && + ldapdelete $LDAP_AUTH -r config=$NAME,$LDAP_BASE + +4xslt -D config=$NAME $XML $LUSTRE/conf/lustre2ldif.xsl > $LDIF + +echo "Loading config to 'config=$NAME,$LDAP_BASE' ..." +ldapadd $LDAP_AUTH -f $LDIF + +rm -f $LDIF -- 1.8.3.1