tcler's blog --- 其实我是一个程序员
Show me your flowcharts and conceal your tables, and I shall continue to be mystified. Show me your tables, and I won’t usually need your flowcharts; they’ll be obvious.

pynfs 介绍

简介

http://wiki.linux-nfs.org/wiki/index.php/Pynfs

pynfs 是一款用来测试 NFSv4.0 和 NFSv4.1 的测试工具,跟 Connectathon 测试套件不同,它知道如何解析和生成协议报文,可以直接跟 client 和 server 交互来进行测试。 这些特性使得它特别适合用来做下列测试:

  • 错误或恶意的协议响应报文
  • 对异常错误的响应
  • 协议的一致性
  • (模拟尚未实现的客户端或服务端)来验证新功能的正确性

目前server测试的代码比client测试代码更成熟一些。 请注意,测试结果并不能作为相关协议正确性的权威声明 – 如果你发现有测试项测试失败 请在断定是bug之前详细阅读相关 RFC 并仔细思考。

下载

目前 pynfs 由 J. Bruce Fields 开发维护,源代码地址:

url=git://git.linux-nfs.org/projects/bfields/pynfs.git
git clone $url

安装使用

dependency install python2 #最近的版本(2020/05之后)已经不再支持 python2

yum install krb5-devel python-devel swig screen python-ply python-gssapi

# or if there isn't python-ply or python-gssaip, please install them from pip
rpm -q python-ply || {
  OSVER=$(rpm -E %rhel)
  yum install https://dl.fedoraproject.org/pub/epel/epel-release-latest-${OSVER}.noarch.rpm
  yum install -y python-pip && pip2 install ply gssapi
}

dependency install python3

yum install krb5-devel python3-devel swig screen python3-ply python3-gssapi
# or if there isn't python3-ply or python3-gssaip, please install them from pip
rpm -q python3-ply || {
  OSVER=$(rpm -E %rhel)
  yum install https://dl.fedoraproject.org/pub/epel/epel-release-latest-${OSVER}.noarch.rpm
  yum install -y python3-pip && pip3 install ply gssapi
}

see also: https://github.com/tcler/kiss-vm-ns/blob/master/utils/pynfs-install.sh

server test

(cd pynfs/; python setup.py install)
cd pynfs/nfs4.0 # or cd pynfs/nfs4.1

mkdir -p /exportdir && echo '/exportdir *(rw,no_root_squash,insecure)' >/etc/exports && systemctl restart nfs-server
./testserver.py --outfile ${logf:-log.txt} --maketree ${serv:-localhost}:${export:-/exportdir} all
#                                                                                              ^^^
# 注: all 是测试用例的 flags 之一,表示运行所有 flags 里带有 all 标记的 测试用例
# 有些测试用例的 FLAGS 里没有 all flag,跑这些 case 需要指定其特有的 flag 或 显式的指定case的 CODE

./testserver.py --outfile ${logf:-log.txt} --maketree ${serv:-localhost}:${export:-/exportdir} WRT16 RD4 --rundeps
#                                                                                              ^^^    ^^^
# 注: 上面的 WRT16b RD4 是 case 的唯一标识, --rundeps 告诉程序自动运行依赖的 case 

pnfs client test # 目前(2020/07)还有 bug: mds 跑不起来,开发正在调查中

systemctl stop nfs-server
(cd pynfs; python setup.py install)
cd pynfs/nfs4.1  # nfs4.1 开始支持 pnfs
echo "${IP:-127.0.0.1}:12345/pynfs_mds" >dataservers.conf
\cp -f sample_code/ds_exports.py .
screen -dm bash -c "./nfs4server.py -r -v --is_ds --exports=ds_exports --port=12345 &>ds.log"
screen -dm bash -c "./nfs4server.py -r -v --use_files --dataservers=dataservers.conf &>mds.log"
nfsmp=/mnt/nfsmp; mkdir -p $nfsmp
mount -o minorversion=1 ${IP:-127.0.0.1}:/ ${nfsmp}
echo 88888 >${nfsmp}/a/testfile
: <<-COM
$ cat sample_code/ds_exports.py 
"""
A very simple exports file intended for use with a files-layout dataserver.
"""

from fs import StubFS_Mem

def mount_stuff(server, opts):
    B = StubFS_Mem(2)
    server.mount(B, path="/pynfs_mds")
COM

pnfs nfsproxy

service nfs stop
(cd pynfs; python setup.py install)
cd pynfs/nfs4.1  # nfs4.1 开始支持 pnfs

pnfs_server=<your pnfs server address>
nfsmp=/mnt/nfsmp
mkdir -p $nfsmp
echo '<errorconf>
<error>
<name>layoutget</name>
<operation>LAYOUTGET</operation>
<errorcode>NFS4ERR_LAYOUTUNAVAILABLE</errorcode>
<frequency>1</frequency>
<delay>0</delay>
</error>
</errorconf>' >error.xml

./nfs4proxy.py --dserver=$pnfs_server &>nfsproxy.log &
pid=$!
mount -o vers=4.1 127.0.0.1:/ $nfsmp

echo '#define _GNU_SOURCE
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <stdio.h>
#include <errno.h>
#include <unistd.h>

void main(int ac, char*av[])
{
        int fd2, ret;
        char *wrbuf;

        fd2 = open(av[1], O_WRONLY | O_CREAT | O_DIRECT);
        if (fd2 < 0) {
                perror("OPEN fd1 error\n");
                return;
        }
        printf("opened %s write\n", av[1]);

        wrbuf = malloc(6);
        memset(wrbuf, 0xa, 6);
        ret = write(fd2, wrbuf, 6);
        if (ret <=0) {
                perror("write error\n");
                return;
        } else printf("write succeeded\n");
        if (fsync(fd2) < 0) printf("fsync failed\n");
        if (close(fd2) < 0) printf("close failed\n");

        return;
}' >test.c
gcc test.c -o test
./test $nfsmp/testfile

troubleshooting

testmod.FailureException: Could not LOOKUP /exportdir/tmp, should return NFS4_OK, instead got NFS4ERR_PERM
检查 server 端 export option, 通常添加 insecure 后, 重启服务 即可
nfs4lib.BadCompoundRes: Trying to remove 'testfile': operation OP_REMOVE should return NFS4_OK, instead got NFS4ERR_GRACE
server 在 GRACE duration, 等 90 秒 再执行就好了