Python备份linux文件至本地

正文如下:

目录结构:

  • config
    • run.yaml 用来配置远程信息
  • core
    • connect.py 用来远程连接
    • read_yaml.py 用来解析yaml文件
    • sample_log.py 用来记录日志
    • ssh_run.py 用来运行备份程序
  1. requirements的支持:

asn1crypto==0.24.0
bcrypt==3.1.7
cffi==1.12.3
Click==7.0
cryptography==2.7
Flask==1.1.1
itsdangerous==1.1.0
Jinja2==2.10.1
MarkupSafe==1.1.1
paramiko==2.6.0
pycparser==2.19
PyNaCl==1.3.0
PyYAML==5.1.1
six==1.12.0
Werkzeug==0.15.4
# 安装方法:pip install -r requirements.txt
  1. run.yaml结构:

---
# 一个连接的记录

- 
  #任务的名称,方便日志记录
  task_name: test1
  #远程连接的ip地址
  host: 0.0.0.0
  #远程连接的端口号
  port: 22
  #远程连接的用户名
  user: root
  #远程连接的密码(和私钥二选一)
  passwd:
  #远程连接的私钥路径(和密码二选一)
  key: xxx\.ssh\id.pem
  #私钥的密码(选填)
  key_passwd: 
  get:
    #本地到本地的文件路径${%Y%m%d_%H%M}使用时间格式转换
    local_file: d:/tmp/${%Y%m%d_%H%M}/test1.zip
    #远程需要备份的路径
    remote_file: /opt/xxx
    #远程存放和生成临时文件的路径
    remote_tmp_file: /tmp/a/zz.zip
  1. connect.py的代码:

import paramiko
import os
import time

class kong:
    def add(self, s):
        pass

#远程连接方法
class SSH:
    def __init__(self, host, port, user, passwd=None, key=None, key_passwd=None, log=kong()):
        self.log = log

        transport = paramiko.Transport((str(host), int(port)))
        if key is None and passwd is None:
            raise Exception('passwd or key must input one~')
        elif key is None:
            transport.connect(username=str(user), password=str(passwd))
        else:
            if key_passwd is None:
                private_key = paramiko.RSAKey.from_private_key_file(str(key))
            else:
                private_key = paramiko.RSAKey.from_private_key_file(str(key), str(key_passwd))
            transport.connect(username='root', pkey=private_key)
        ssh = paramiko.SSHClient()
        # 允许连接不在know_hosts文件中的主机
        ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
        ssh._transport = transport
        sftp = ssh.open_sftp()
        self.ssh_value = ssh
        self.sftp_value = sftp
        self.transport = transport

    def ssh(self, cmd, inp=None):
        stdin, stdout, stderr = self.ssh_value.exec_command(str(cmd))
        if inp is not None:
            stdin.write(str(inp))
        if len(stderr.read().decode()) > 0:
            raise Exception(stderr.read().decode())
        return stderr.read().decode()

    def sftp(self):
        return self.sftp_value

    def put(self, local_file, remote_file):
        if not os.path.exists(local_file):
            raise Exception(local_file + ',文件不存在')
        if not self.is_exist(os.path.dirname(remote_file)):
            self.mkdirs(os.path.dirname(remote_file))
        self.sftp_value.put(local_file, remote_file)

    def get(self, local_file, remote_file):
        if os.path.exists(local_file):
            t = time.strftime('%Y%m%d_%H%M%S', time.localtime())
            os.rename(local_file, local_file + '_backup' + t)
        else:
            if not os.path.exists(os.path.dirname(local_file)):
                raise Exception(os.path.dirname(local_file) + ',目录不存在')
        if not self.is_exist(remote_file):
            raise Exception(remote_file + '文件不存在')
        self.sftp_value.get(remote_file, local_file)

    def is_exist(self, path):
        try:
            self.ssh('ls ' + str(path))
            return True
        except:
            return False

    def mkdirs(self, path):

        if self.is_exist(path):
            pass
        else:
            if path == '/':
                raise Exception('创建文件夹失败')
            else:
                try:
                    self.sftp_value.mkdir(path)
                    self.log.add('创建文件夹成功:' + path)
                    print('创建文件夹成功:', path)
                except:
                    self.mkdirs(os.path.dirname(path))
                    self.mkdirs(path)

    def close(self):
        self.sftp_value.close()
        self.ssh_value.close()
        self.transport.close()
  1. read_yaml.py的代码:

import yaml
import re
import time
import os


class kong:
    def add(self, s):
        pass


class Yaml:
    def __init__(self, path='../config/run.yaml', log=kong()):
        if not os.path.exists(path):
            if path.startswith('../'):
                path = path[3:]
        self.path = path
        self.da = []
        self.time = time.localtime()
        self.log = log

    def read(self):
        with open(self.path, encoding='utf-8') as f:
            self.da = yaml.full_load(f)

    def mkdirs(self, path, is_chird=False):
        if not is_chird:
            path = os.path.dirname(path)
        if os.path.exists(path):
            pass
            # if not is_chird:
            #     print('存在文件夹:', path)
        else:
            if path == '/':
                raise Exception('创建文件夹失败,路径:' + path)
            else:
                try:
                    os.mkdir(path)
                    self.log.add('创建文件夹成功:' + path)
                    print('创建文件夹成功:', path)
                except:
                    self.mkdirs(os.path.dirname(path), is_chird=True)
                    self.mkdirs(path, is_chird=True)

    def check(self):
        temp_list = []
        for inf in self.da:
            if inf.get('host') is None or inf.get('port') is None or inf.get('user') is None or (
                    inf.get('passwd') is None and inf.get('key') is None or inf.get('get') is None):
                self.log.add(inf['task_name'] + ',信息不全,无法执行' + str(inf))
                print(inf['task_name'] + ',信息不全,无法执行' + str(inf))
                continue
            else:
                if inf.get('get').get('local_file') is None:
                    print(inf['task_name'] + '本地备份路径为空,请检查:' + str(inf))
                    self.log.add(inf['task_name'] + '本地备份路径为空,请检查:' + str(inf))
                    continue
                elif inf.get('get').get('remote_file') is None:
                    print(inf['task_name'] + '远程文件为空,请检查:' + str(inf))
                    self.log.add(inf['task_name'] + '远程文件为空,请检查:' + str(inf))
                    continue
                elif inf.get('get').get('remote_tmp_file') is None:
                    print(inf['task_name'] + '远程临时文件为空,请检查;' + str(inf))
                    self.log.add(inf['task_name'] + '远程临时文件为空,请检查;' + str(inf))
                    continue
                else:
                    local_path = inf['get']['local_file']
                    pas = re.findall(r"\$\{(.+?)\}", local_path)
                    for time1 in pas:
                        local_path = local_path.replace('${' + time1 + '}', time.strftime(time1, self.time))

                    inf['get']['local_file'] = local_path
                    self.mkdirs(local_path)
                    tmp_path = inf['get']['remote_tmp_file']
                    pas = re.findall(r"\$\{(.+?)\}", tmp_path)
                    for time1 in pas:
                        tmp_path = tmp_path.replace('${' + time1 + '}', time.strftime(time1, self.time))

                    inf['get']['remote_tmp_file'] = tmp_path
                    temp_list.append(inf)
        print('校验数据,有{}条数据填写正确'.format(str(len(temp_list))))
        self.log.add('校验数据,有{}条数据填写正确'.format(str(len(temp_list))))
        return temp_list
  1. sample_log.py的代码:

import time
import os


class SampleLog:
    def __init__(self):
        t = time.strftime('%Y%m%d', time.localtime())
        self.t = t
        if not os.path.exists(os.path.join(os.path.dirname(os.path.dirname(__file__)), 'log', self.t, 'log.txt')):
            if not os.path.exists(os.path.join(os.path.dirname(os.path.dirname(__file__)), 'log')):
                os.mkdir(os.path.join(os.path.dirname(os.path.dirname(__file__)), 'log'))
            with open(os.path.join(os.path.dirname(os.path.dirname(__file__)), 'log', self.t + '.log'), 'w', encoding='utf8') as f:
                f.write('#create time :' + time.strftime('%Y%m%d %H:%M:%S', time.localtime()) + '\n')

    def add(self, s):
        with open(os.path.join(os.path.dirname(os.path.dirname(__file__)), 'log', self.t + '.log'), 'a', encoding='utf8') as f:
            f.write(time.strftime('%Y%m%d %H:%M:%S', time.localtime()) + '>>\t' + str(s) + '\n')
  1. ssh_run.py的代码:

import os, sys

sys.path.append(os.path.dirname(os.path.abspath('')))
sys.path.append(os.path.abspath(''))
from core.connect import SSH
from core.read_yaml import Yaml
from core.sample_log import SampleLog

s = SampleLog()
try:
    y = Yaml(log=s)
    y.read()
    da = y.check()
    print('_' * 30)
except Exception as e:
    print(e)
    raise Exception('读取文件错误')

for inf in da:
    try:
        ssh = SSH(inf['host'], inf['port'], inf['user'], inf['passwd'], inf['key'], inf['key_passwd'], s)
        print(inf['task_name'] + '连接成功,正在远程生成压缩包')
        s.add(inf['task_name'] + '连接成功')
        ssh.ssh('rm -f ' + inf['get']['remote_tmp_file'])
        ssh.ssh('cd {};tar cPf {} *'.format(inf['get']['remote_file'], inf['get']['remote_tmp_file']))
        print(inf['task_name'] + '生成压缩包在' + inf['get']['remote_tmp_file'] + ',正在复制文件到本地')
        s.add(inf['task_name'] + '生成压缩包在' + inf['get']['remote_tmp_file'])
        ssh.get(inf['get']['local_file'], inf['get']['remote_tmp_file'])
        print(inf['task_name'] + '复制到本地:' + inf['get']['local_file'])
        s.add(inf['task_name'] + '复制到本地:' + inf['get']['local_file'])
        ssh.close()
    except Exception as e:
        print(e)
        s.add(str(e))

你可能感兴趣的:(Python备份linux文件至本地)