基于Fabric+多线程写了一个公共类

背景

就是为了批量安装软件方便一点,使用方法

if __name__ == "__main__":
    options, args = opt()
    if len(args) == 0:
        parser.print_help()
        sys.exit(1)
    for project in args:
        try:
            # 加载项目
            mod = __import__('deploy.%s' % project, fromlist=True)
            servers = Projects.info(project)
            # 定义一个部署线程列表
            deploy_list = []
            for server in servers:
                deploy = mod.Setup(hostname=server[0], username=server[1], password=server[2],
                               port=server[3], args=args, kwargs=options)
                deploy_list.append(deploy)
            # 启用多线程部署
            for deploy in deploy_list:
                deploy.start()
            # 判断线程里面是否还有没结束的
            for deploy in deploy_list:
                while deploy.is_alive():
                    time.sleep(1)
        except ModuleNotFoundError:
            print("没有此项目部署方式")
            break

代码

class RoleRun(threading.Thread):
    logger = LogUtil().getLogger(__name__)

    def __init__(self, hostname=None, username=None, password=None, port=22, **kwargs):
        threading.Thread.__init__(self)
        self.c = Connection(host=hostname, user=username, connect_kwargs={'password': password}, port=port)
        self.cmd_list = []
        # success,message,curr组成了可以进度条展示的功能
        self.success = None
        self.message = "正在连接服务器"
        self.curr = 0
        self.osversion = "7"
        self.logfile = "logs/deploy.log"
        self.kwargs = kwargs

    def local(self, cmd=None, percent=0, message=None, skip_false=False):
        """执行本地命令
        :param cmd:  命令
        :param percent: 命令所占的百分比
        :param message: 命令含义
        :param skip_false: 失败是否影响后续的执行
        :return:
        """
        try:
            if self.success is False:
                return False
            res = run(cmd, warn=True, hide=True)
            self.local_log(res)
            if res.failed:
                if skip_false is False:
                    self.success = False
                return False
        except TimeoutError:
            self.success = False
            self.curr = 100
            self.message = "服务器超时"
            return False
        self.curr += percent
        return True

    def info(self, message):
        self.logger.info(message)

    def error(self, message):
        self.logger.error(message)

    def disable_friewalld(self):
        """禁用系统的防火墙
        :return:
        """
        if self.osversion == "7":
            self.run_cmd("systemctl disable firewalld")
            self.run_cmd("systemctl stop firewalld")

    def pre_check(self):
        """预检测
        :return:
        """
        if self.run_cmd("cat /etc/redhat-release |awk '{print $4}'|grep 7. | wc -l"):
            self.osversion = 7

    def run_cmd(self, cmd=None, percent=0, message=None, skip_false=False):
        """远程执行命令
        :param cmd: 命令
        :param percent: 命令所占的百分比
        :param message: 命令含义
        :param skip_false: 失败是否影响后续的执行
        :return:
        """
        try:
            if self.success is False:
                return False
            res = self.c.run(cmd, warn=True, hide=True)
            self.log(res)
            if res.failed:
                if skip_false is False:
                    self.success = False
                return False
        except TimeoutError:
            self.success = False
            self.curr = 100
            self.message = "服务器超时"
            return False
        self.curr += percent
        return res.stdout

    def set_process(self, message, percent=0):
        """实现百分比进度
        :param message:
        :param percent:
        :return:
        """
        self.message = message
        self.curr = percent

    def run(self):
        """ 多线程的入口
        :return:
        """
        try:
            self.c.open()
        except TimeoutError:
            self.curr = 100
            self.message = "服务器链接失败"
            self.success = False
            return False
        except AuthenticationException:
            self.set_process("用户名或者密码错误", percent=100)
            self.success = False
        if self.c.is_connected:
            pass
        else:
            self.success = False
            return False

    def get_template(self, name):
        """ 返回jinja模板
        :param name:
        :return:
        """
        env = Environment(loader=PackageLoader("deploy", "template"))
        return env.get_template(name)

    def set_service(self, service_name=None):
        """ 设置服务,目前只支持centos7以上
        :param service_name:
        :return:
        """
        self.message = "设置启停,开机自启"
        if self.osversion == "7":
            self.c.put("deploy/service/7/{0}.service".format(service_name), "/lib/systemd/system/")
            self.run_cmd("systemctl daemon-reload")
            self.run_cmd("systemctl enable {0}".format(service_name))
            self.run_cmd("systemctl start {0}".format(service_name))
        return True

    def get(self):
        """ 获取线程当前的状态
        :return:
        """
        return {"process": self.curr, "status": self.success, "message": self.message}

    def upload_and_unpack_gz(self, filename=None):
        """
        :param filename:
        :return:
        """
        self.message = "正在上传文件并解压"
        try:
            if self.c.run("test -f /usr/local/src/{0}".format(filename), warn=True).failed:
                self.c.put('deploy/packages/{0}'.format(filename), remote='/usr/local/src/')
            self.c.run('tar -zxf /usr/local/src/{0} -C /usr/local/src'.format(filename))
        except FileNotFoundError as e:
            self.logger.error(e)
            return False
        except OSError as e:
            self.logger.error(e)
        return True

    def upload(self, local_file=None, dest_file=None):
        """上传文件
        :param local_file: 本地文件路径
        :param dest_file: 远程文件路径
        :return:
        """
        try:
            self.c.put(local_file, remote=dest_file)
        except FileNotFoundError as e:
            self.logger.error(e)
            return False
        except OSError as e:
            self.logger.error(e)
        return True

    def upload_folder(self, local_dir=None, dest_dir=None):
        """上传文件夹
        :param local_dir: 本地目录路径
        :param dest_dir: 远程目录路径
        :return:
        """
        try:
            if self.c.run("mkdir -p {0}".format(dest_dir), warn=True).ok:
                self.c.put(local_dir, remote='.')
        except FileNotFoundError as e:
            self.logger.error(e)
            return False
        except OSError as e:
            self.logger.error(e)
        return True

你可能感兴趣的:(DevOps)