From patchwork Wed Jun 4 21:01:56 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Weston Andros Adamson X-Patchwork-Id: 4297011 Return-Path: X-Original-To: patchwork-linux-nfs@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork1.web.kernel.org (Postfix) with ESMTP id 995089F1D6 for ; Wed, 4 Jun 2014 21:03:13 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 7284320142 for ; Wed, 4 Jun 2014 21:03:12 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 2D97D2012E for ; Wed, 4 Jun 2014 21:03:11 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751823AbaFDVDF (ORCPT ); Wed, 4 Jun 2014 17:03:05 -0400 Received: from mail-ig0-f176.google.com ([209.85.213.176]:59816 "EHLO mail-ig0-f176.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751979AbaFDVCY (ORCPT ); Wed, 4 Jun 2014 17:02:24 -0400 Received: by mail-ig0-f176.google.com with SMTP id a13so2456260igq.3 for ; Wed, 04 Jun 2014 14:02:24 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=Hguz2JO/4UF4qbUHLpB+ivgF1aco3gllFMWvbXmaKoU=; b=WR4a/4QX7o3c9ZRzInPr1N0csrrV6xghkLdne1w+VMa29Ja81scMoh388O1zAKP5to cQ85+PZrZ/sdrDSLv+QQMBkMzXNLLMjx5HjX3kSdqW/lPq4jQpUHSjdW/qmTA+tn+FnU do3L81Ongt/EeSPKzVvoTeQbFv15aM68JwIwMuO+jOhu/WJF8tTZi9LAjMCIbZIPDGGd b+4lx1Y+7DShbLtAetxL9PE8Nm+zr9D25iapfrlqNSZ1saia4dHj2oRHd9do/qdQDBK/ asHnq1kxEyQHFE6bq02UUZlkrs4mXo1dGRaED/vFz3TrSGSGmplXMFFGohkP7DdS7ZB0 w2XQ== X-Gm-Message-State: ALoCoQnZk12FpWRuj4rXFDGRJ9TQMbKN3jbZD1/idGkLyjLJDosbl02pR6WAJcYIDCnY85XCYxH6 X-Received: by 10.50.9.104 with SMTP id y8mr11257409iga.43.1401915744305; Wed, 04 Jun 2014 14:02:24 -0700 (PDT) Received: from gavrio-wifi.robotsandstuff.fake (c-98-209-19-144.hsd1.mi.comcast.net. [98.209.19.144]) by mx.google.com with ESMTPSA id qh3sm47684584igb.17.2014.06.04.14.02.22 for (version=TLSv1 cipher=RC4-SHA bits=128/128); Wed, 04 Jun 2014 14:02:23 -0700 (PDT) From: Weston Andros Adamson To: bfields@fieldses.org Cc: linux-nfs@vger.kernel.org, Weston Andros Adamson Subject: [PATCH pynfs 08/17] 4.1 server: add -s option to print summary of ops Date: Wed, 4 Jun 2014 17:01:56 -0400 Message-Id: <1401915726-29092-9-git-send-email-dros@primarydata.com> X-Mailer: git-send-email 1.8.5.2 (Apple Git-48) In-Reply-To: <1401915726-29092-1-git-send-email-dros@primarydata.com> References: <1401915726-29092-1-git-send-email-dros@primarydata.com> Sender: linux-nfs-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-nfs@vger.kernel.org X-Spam-Status: No, score=-7.5 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_HI, RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=ham version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP As a middle ground between verbose (-v) mode and silent mode, add "-s" (aka "--show_summary") to print one line per operation. The summary mode will print a "role" header whenever the role changes. Example output - mds starts, talks to v3 ds (.200), client (.11) mounts, touches an existing file: call v3 172.16.200.200:2049 access Mounting (2, 6) on '/files' handle v4.1 ::ffff:172.16.200.11:758 exchange_id create_session sequence, reclaim_complete sequence, putrootfh, secinfo_no_name sequence, putrootfh, getfh, getattr sequence, putfh, getattr (repeated 6 times) sequence, putfh, access, getattr sequence, putfh, lookup, getfh, getattr (repeated 1 times) sequence, putfh, secinfo -> NFS4ERR_NOTSUPP sequence, putfh, getattr (repeated 4 times) sequence, putfh, access, getattr call v3 172.16.200.200:2049 create -> NFS3ERR_EXIST lookup getattr (repeated 1 times) handle v4.1 ::ffff:172.16.200.11:758 sequence, putfh, open, getfh, access, getattr call v3 172.16.200.200:2049 getattr (repeated 1 times) handle v4.1 ::ffff:172.16.200.11:758 sequence, putfh, setattr, getattr sequence, putfh, close, getattr Signed-off-by: Weston Andros Adamson --- nfs4.1/dataserver.py | 16 ++++++++++------ nfs4.1/nfs4client.py | 7 ++++++- nfs4.1/nfs4server.py | 47 ++++++++++++++++++++++++++++++++++++++++++++++- nfs4.1/server_exports.py | 7 ++++--- 4 files changed, 66 insertions(+), 11 deletions(-) diff --git a/nfs4.1/dataserver.py b/nfs4.1/dataserver.py index d697631..9b0462d 100644 --- a/nfs4.1/dataserver.py +++ b/nfs4.1/dataserver.py @@ -13,8 +13,8 @@ import socket log = logging.getLogger("Dataserver Manager") -class DataServer(object): - def __init__(self, server, port, path, flavor=rpc.AUTH_SYS, active=True, mdsds=True, multipath_servers=None): +class DataServer41(object): + def __init__(self, server, port, path, flavor=rpc.AUTH_SYS, active=True, mdsds=True, multipath_servers=None, summary=None): self.mdsds = mdsds self.server = server self.port = int(port) @@ -32,6 +32,8 @@ class DataServer(object): else: self.multipath_servers = [] + self.summary = summary + if active: self.up() @@ -47,7 +49,8 @@ class DataServer(object): # only support root with AUTH_SYS for now s1 = rpc.security.instance(rpc.AUTH_SYS) self.cred1 = s1.init_cred(uid=0, gid=0) - self.c1 = nfs4client.NFS4Client(self.server, self.port) + self.c1 = nfs4client.NFS4Client(self.server, self.port, + summary=self.summary) self.c1.set_cred(self.cred1) self.c1.null() c = self.c1.new_client("DS.init_%s" % self.server) @@ -172,7 +175,7 @@ class DSDevice(object): self.address_body = None # set by load() self.mdsds = mdsds # if you are both the DS and the MDS we are the only server - def load(self, filename): + def load(self, filename, server_obj): """ Read dataservers from configuration file: where each line has format e.g. server[:[port][/path]] """ @@ -194,8 +197,9 @@ class DSDevice(object): try: log.info("Adding dataserver ip:%s port:%s path:%s" % (server, port, '/'.join(path))) - ds = DataServer(server, port, path, mdsds=self.mdsds, - multipath_servers=server_list) + ds = DataServer41(server, port, path, mdsds=self.mdsds, + multipath_servers=server_list, + summary=server_obj.summary) self.list.append(ds) except socket.error: log.critical("cannot access %s:%i/%s" % diff --git a/nfs4.1/nfs4client.py b/nfs4.1/nfs4client.py index e504362..f5d2006 100644 --- a/nfs4.1/nfs4client.py +++ b/nfs4.1/nfs4client.py @@ -21,7 +21,7 @@ logging.basicConfig(level=logging.INFO, log_cb = logging.getLogger("nfs.client.cb") class NFS4Client(rpc.Client, rpc.Server): - def __init__(self, host='localhost', port=2049, minorversion=1, ctrl_proc=16): + def __init__(self, host='localhost', port=2049, minorversion=1, ctrl_proc=16, summary=None): rpc.Client.__init__(self, 100003, 4) self.prog = 0x40000000 self.versions = [1] # List of supported versions of prog @@ -36,6 +36,7 @@ class NFS4Client(rpc.Client, rpc.Server): self.c1 = self.connect(self.server_address) self.sessions = {} # XXX Really, this should be per server self.ctrl_proc = ctrl_proc + self.summary = summary def set_cred(self, credinfo): self.default_cred = credinfo @@ -83,6 +84,10 @@ class NFS4Client(rpc.Client, rpc.Server): pipe = kwargs.get("pipe", None) res = self.listen(xid, pipe=pipe) log_cb.info("compound result = %r" % (res,)) + if self.summary: + self.summary.show_op('call v4.1 %s:%s' % self.server_address, + [ nfs_opnum4[a.argop].lower()[3:] for a in args[0] ], + nfsstat4[res.status]) return res def listen(self, xid, pipe=None, timeout=10.0): diff --git a/nfs4.1/nfs4server.py b/nfs4.1/nfs4server.py index 67adbf1..088e8c4 100755 --- a/nfs4.1/nfs4server.py +++ b/nfs4.1/nfs4server.py @@ -502,6 +502,41 @@ class Slot(object): # STUB - for client, need to track slot usage +class SummaryOutput: + def __init__(self, enabled=True): + self._enabled = enabled + self._last = None + self._last_role = None + self._repeat_count = 0 + + def show_op(self, role, opnames, status): + if not self._enabled: + return + + summary_line = " %s" % ', '.join(opnames) + + if status != "NFS4_OK" and status != "NFS3_OK": + summary_line += " -> %s" % (status,) + + print_summary_line = True + if summary_line != self._last or role != self._last_role: + if self._last and self._repeat_count: + print " (repeated %u times)" % self._repeat_count + self._last = summary_line + self._repeat_count = 0 + else: + print_summary_line = False + self._repeat_count += 1 + + if self._last_role != role: + print + print role + self._last_role = role + + if print_summary_line: + print summary_line + + ################################################## # The primary class - it is excessively long # ################################################## @@ -527,6 +562,8 @@ class NFS4Server(rpc.Server): log_41.setLevel(9) log_cfg.setLevel(20) + self.summary = SummaryOutput(kwargs.pop('show_summary', False)) + rpc.Server.__init__(self, prog=NFS4_PROGRAM, versions=[4], port=port, **kwargs) self.root = RootFS().root # Root of exported filesystem tree @@ -776,6 +813,7 @@ class NFS4Server(rpc.Server): return env # Handle the individual operations status = NFS4_OK + opnames = [] for arg in args.argarray: opname = nfs_opnum4.get(arg.argop, 'op_illegal') log_41.info("*** %s (%d) ***" % (opname, arg.argop)) @@ -805,10 +843,14 @@ class NFS4Server(rpc.Server): result = encode_status_by_name(opname.lower()[3:], NFS4ERR_SERVERFAULT) env.results.append(result) + opnames.append(opname.lower()[3:]) status = result.status if status != NFS4_OK: break log_41.info("Replying. Status %s (%d)" % (nfsstat4[status], status)) + client_addr = '%s:%s' % cred.connection._s.getpeername()[:2] + self.summary.show_op('handle v4.1 %s' % client_addr, + opnames, nfsstat4[status]) return env def delete_session(self, session, sessionid): @@ -2062,6 +2104,8 @@ def scan_options(): help="Reset and clear any disk-based filesystems") p.add_option("-v", "--verbose", action="store_true", default=False, help="Print debug info to screen and enter interpreter on ^C") + p.add_option("-s", "--show_summary", action="store_true", default=False, + help="Print short summary of operations") p.add_option("--use_block", action="store_true", default=False, help="Mount a block-pnfs fs") p.add_option("--use_files", action="store_true", default=False, @@ -2095,7 +2139,8 @@ if __name__ == "__main__": S = NFS4Server(port=opts.port, is_mds=opts.use_block or opts.use_files, is_ds = opts.is_ds, - verbose = opts.verbose) + verbose = opts.verbose, + show_summary = opts.show_summary) read_exports(S, opts) if True: S.start() diff --git a/nfs4.1/server_exports.py b/nfs4.1/server_exports.py index d96b27b..ef857ee 100644 --- a/nfs4.1/server_exports.py +++ b/nfs4.1/server_exports.py @@ -15,7 +15,7 @@ def mount_stuff(server, opts): E = BlockLayoutFS(5, backing_device=dev) server.mount(E, path="/block") if opts.use_files: - dservers = _load_dataservers(opts.dataservers, server.is_ds and server.is_mds) + dservers = _load_dataservers(opts.dataservers, server) if dservers is None: return F = FileLayoutFS(6, dservers) @@ -33,7 +33,8 @@ def _create_simple_block_dev(): c1 = Concat([s3, s1]) return BlockVolume(c1) -def _load_dataservers(file, connect_to_ds=False): +def _load_dataservers(filename, server): + connect_to_ds = server.is_ds and server.is_mds dss = DSDevice(connect_to_ds) - dss.load(file) + dss.load(filename, server) return dss;