本篇博客为了实现一个文件同步的脚本,其实在前面已经有铺垫,专门有两遍博客介绍了watchdog和paramiko模块,分别用于文件监控和SSH连接。如果对这两个模块不太熟悉,请先了解一下。
需求
1、将服务器B上指定目录同步到服务器A的指定目录 2、实时监控服务器A的此目录,并将更新同步到服务器B 3、更新信息打印到日志文件 4、脚本服务化
创建一个SSH功能的类
关键代码:
class ParamikoClient:
def __init__(self, host, port, username, key):
self.host = host
self.port = port
self.username = username
self.pkey = paramiko.RSAKey.from_private_key_file(key)
@property
def sftp(self):
transport = paramiko.Transport((self.host, self.port))
transport.connect(username=self.username, pkey=self.pkey)
sftp = paramiko.SFTPClient.from_transport(transport)
return sftp
这里返回一个sftp对象,用来操作远程主机的文件。
创建一个监控类
关键代码:
class MyHandler(FileSystemEventHandler):
# 初始化传入一个sftp对象
def __init__(self, sftp):
self.sftp = sftp
# 文件变化
def on_modified(self, event):
if not_hidden(event.src_path):
if not event.is_directory:
self.on_created(event)
# 文件改名
def on_moved(self, event):
rename(self.sftp, event.src_path, event.dest_path)
# 创建文件
def on_created(self, event):
if not_hidden(event.src_path):
if not event.is_directory:
put(self.sftp, event.src_path)
else:
mkdir(self.sftp, event.src_path)
# 删除文件
def on_deleted(self, event):
if not event.is_directory:
delete(self.sftp, event.src_path)
else:
delete_dir(self.sftp, event.src_path)
监控本地文件的修改,然后调用不同的方法。
创建一个打印日志的类
关键代码:
class Logger():
def __init__(self, name):
# 创建一个logger实例
self._logger = logging.getLogger(name)
# 指定最低输出级别
self._logger.setLevel(logging.DEBUG)
# 创建一个StreamHandler
ch = logging.StreamHandler()
ch.setLevel(logging.WARN)
# 创建一个FileHandler
# 指定日志文件目录
log_path = './logging.log'
ch2 = logging.FileHandler(log_path)
ch2.setLevel(logging.INFO)
# 设置日志输出格式
formatter = logging.Formatter(
'%(asctime)s - %(name)s - %(levelname)s - %(message)s')
ch.setFormatter(formatter)
ch2.setFormatter(formatter)
self._logger.addHandler(ch)
self._logger.addHandler(ch2)
logging模块的使用方法,还有一点复杂的,建议先了解一下。
递归搜索
由于paramiko的sftp不支持递归搜索,所以需要自己实现,代码如下:
def walk(sftp, path):
all_files = []
all_dirs = []
files = sftp.listdir_attr(path)
for f in files:
filename = path + '/' + f.filename
if stat.S_ISDIR(f.st_mode):
file_list, dir_list = walk(sftp, filename)
all_files.extend(file_list)
all_dirs.extend(dir_list)
all_dirs.append(filename)
else:
all_files.append(filename)
return all_files, all_dirs
还有很多其他的操作方法,这里就不一一列举了。完整代码,已更新到github. https://github.com/pangerl/python/tree/master/inotify
服务化
python脚本服务化这里用的supervisor。配置比较简单,就不详细说了。 下次再写一遍专门介绍supervisor的文章。