[关闭]
@tony-yin 2018-04-25T02:18:04.000000Z 字数 3894 阅读 6160

python连接nas服务进行读写(nfs、cifs、ftp)

Ceph Nas


最近公司有个集群一直在跑着,领导想要测测它上面NAS服务的稳定性,也就是看看正常持续的读写会不会导致NAS服务异常,这个其实通过fio或者cosbench这类的工具测试起来很容易,但是这样一是没有挑战性,二是比较机械,可扩展性低。比如并行测试、进程保护和异常通知等等这些是机械地运用工具测试所做不到的,所以我们尝试做了一套基于NAS稳定性测试的框架。

概述

整个测试框架打包和发布都是通过RPM的方式,方便测试人员一键部署。部署之后测试工作由supervisor管理,实时监控后台进程的运行状态,发生异常时可以进行重启等自动化操作。所有读写操作都是通过python 连接NAS服务,无需做任何挂载工作。主要测试工作是通过celery实现任务调度,支持并行多个NAS服务的读写测试,brokerbackend store都采用了rabbitmq。后端注册了registernfscifsftp四个job,定时每10分钟执行一次,设置最大开启worker数为5个。Job注册进消息队列中后,celery worker会自动去消费,针对服务器中不同的NAS服务进行读写操作,每个任务的执行结果最后都会记录在日志中,出了异常通过邮件通知管理员。

系统架构

整个项目的框架图如下:

Nas_Stable_Test架构图

NAS服务读写流程

由于每个NAS服务的测试方式是一致的,所以下面就以单个NAS服务的流程来介绍。首先client端向serverNAS服务端口发起连接,server端接收到client端的请求后建立连接。Client/tmp目录下生成固定大小1G的文件,并且记录该文件的MD5值,然后将该文件上传至远端NAS服务目录(即对NAS服务进行写操作),上传完成后将该文件从本地删除。接着对之前上传至NAS服务目录的文件进行下载(即对NAS服务进行读操作),下载完成后再次记录文件MD5值,并删除掉远端NAS服务目录对应的文件。最后对两次记录的MD5值进行比较,判断上传和下载的文件是否一致,并将比较结果记录在日志中,再次删除本地下载的文件。NAS服务读写流程图如下:

Nas_Stable_Test流程图

准备工作

安装libnfs

通过pip安装:

  1. pip install libnfs

一般会报这个错:

  1. libnfs/libnfs_wrap.c:2969:25: fatal error: nfsc/libnfs.h: No such file or directory

这个错看起来是缺少这个头文件的包,但是通过yum search libnfs是找不到相关的包的,所以我们只能去官网下载rpm包然后在安装:

  1. ## 下载rpm
  2. wget http://li.nux.ro/download/nux/dextop/el7/x86_64//libnfs-1.9.8-1.el7.nux.x86_64.rpm
  3. wget http://li.nux.ro/download/nux/dextop/el7/x86_64//libnfs-devel-1.9.8-1.el7.nux.x86_64.rpm
  4. ## 安装rpm
  5. yum localinstall libnfs-1.9.8-1.el7.nux.x86_64.rpm
  6. yum localinstall libnfs-devel-1.9.8-1.el7.nux.x86_64.rpm

安装pysmb

这个比较简单,直接pip安装就可以了,也没遇到什么问题。

  1. pip install pysmb

NAS服务相关代码实现

这里只贴出部分python连接或者操作具体Nas服务的代码实现,如果想要了解或者贡献整个项目,请关注:Github python_nas项目

NFS

Connect

  1. def open(self):
  2. self.nfs = libnfs.NFS('nfs://{}'.format(self.mount_point))
  3. log.info('nfs connect successfully!')

Read

这里有个关键点就是分段读写文件,避免内存溢出。

  1. def read(self):
  2. log.info('nfs read start...')
  3. a = self.nfs.open('/{}'.format(self.filename), mode='r')
  4. with open(self.download_path, 'a') as f:
  5. while True:
  6. content = a.read(1024*1024)
  7. if content == '':
  8. break
  9. f.write(content)
  10. a.close()
  11. log.info('nfs read end...')

Write

  1. def write(self, content):
  2. log.info('nfs write start...')
  3. a = self.nfs.open('/{}'.format(self.filename), mode='w+')
  4. a.seek(self.file_size)
  5. a.write(content)
  6. a.close()
  7. log.info('nfs write end...')

Delete

  1. def delete(self):
  2. log.info('nfs file delete start...')
  3. self.nfs.unlink('/{}'.format(self.filename))
  4. log.info('nfs file delete end...')

CIFS

Connect

  1. def open(self):
  2. self.smb = SMBConnection(
  3. self.username,
  4. self.password,
  5. self.my_name.encode('utf-8'),
  6. self.remote_name.encode('utf-8'),
  7. use_ntlm_v2=True
  8. )
  9. self.smb.connect(self.host, self.port)
  10. log.info('cifs connect successfully!')

Read

  1. def read(self):
  2. log.info('cifs read start...')
  3. file_obj = open(self.download_path, 'wb')
  4. self.smb.retrieveFile(
  5. self.directory,
  6. self.filename,
  7. file_obj
  8. )
  9. file_obj.close()
  10. log.info('cifs read end...')

Write

  1. def write(self):
  2. log.info('cifs write start...')
  3. file_obj = open(self.client_path, 'rb')
  4. self.smb.storeFile(
  5. self.directory,
  6. self.filename,
  7. file_obj
  8. )
  9. file_obj.close()
  10. log.info('cifs write end...')

Delete

  1. def delete(self):
  2. log.info('cifs delete start...')
  3. self.smb.deleteFiles('path3', self.filename)
  4. log.info('cifs delete end...')

Close

  1. def close(self):
  2. self.smb.close()

FTP

Connect

  1. def open(self):
  2. self.ftp = FTP()
  3. self.ftp.connect(
  4. host=self.host.encode('utf-8'),
  5. port=self.port.encode('utf-8')
  6. )
  7. self.ftp.login(self.username, self.password)
  8. log.info('ftp connect successfully!')

Read

  1. def read(self):
  2. log.info('ftp read start...')
  3. buff_size = 1024
  4. fp = open(self.download_path, "wb")
  5. self.ftp.retrbinary(
  6. "RETR {}".format(self.filename),
  7. fp.write,
  8. buff_size
  9. )
  10. fp.close()
  11. log.info('ftp read end...')

Write

  1. def write(self):
  2. log.info('ftp write start...')
  3. buff_size = 1024
  4. fp = open(self.client_path, "rb")
  5. self.ftp.storbinary(
  6. "STOR {}".format(self.filename),
  7. fp,
  8. buff_size
  9. )
  10. fp.close()
  11. log.info('ftp write end...')

Delete

  1. def delete(self):
  2. log.info('ftp delete start...')
  3. self.ftp.delete(self.filename)
  4. log.info('ftp delete end...')

Close

  1. def close(self):
  2. self.ftp.quit(self.filename)

总结

还有一些其他的API接口就不一一赘述了,具体实现细节大家可以查看github上面的项目代码,具体地址我会在文末贴出。整个项目的核心是通过celery实现任务的调度,还有全程通过python连接和操作nas服务,后续还会不断完善~~~

项目地址:https://github.com/tony-yin/python_nas


参考列表:
python 操作samba文件服务器
python libnfs

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注