美文网首页这篇就够了
python使用fabric之只看这篇就够了

python使用fabric之只看这篇就够了

作者: 小肥爬爬 | 来源:发表于2021-06-01 15:40 被阅读0次

    fabric 是什么

    项目地址在: https://gitee.com/xiaofeipapa/fabric-tutorial

    建议先下载代码, 边看边运行.

    fabric 是python的一个组件, 能够在远程服务器运行你写好的脚本, 也就是说这是一个运维自动化工具.

    以前运维人员在远程服务器上安装软件, 要先登录 -> 写脚本(如果习惯本地写程序, 那么还要上传程序到服务器) -> 针对服务器反馈输入数据 -> 调试 ..

    如果用fabric, 这个流程就是全部自动化了. fabric的程序开发流程一般是这样:

    1. 先在远程服务器试验你的脚本/想法.
    2. 用python fabric 实现它们.
    3. 运行结果, 观察是否正确.

    如果只需要操作一两台服务器, 那么手动操作肯定比写程序快. 如果要操作几十上百台机器, 那么当然是写好程序, 然后让他们自动在几十台服务器上面跑更方便. (程序员就是要学会偷懒! )

    2021版教程说明

    网上能找到的fabric 大多东摘西抄, 程序不能运行. 锅主要由fabric 来背, 一开始他们并不支持 python3, 所以当python3 流行之后, 以前针对 python2 的fabric教程就基本不能用了; 于是有热心程序员们搞了个非官方的fabric3 , 写了一些教程(很少且很多文章是错的), 但后来fabric 官方支持了 python3 , 也出了个教程....

    于是在互联网上至少存在3种fabric 教程. 针对python2的, 针对非官方python3版本的, 还有官方python3 官方版本的, 初学者大概会被弄得要发疯了吧....

    所以我将这份教程命名为2021版, 表示这是今年最新的版本. 同时这是针对官方python3版本的教材, 如果你不熟悉fabric, 就不用看网上其他教程了, 看这一篇即可.

    最后, 这篇教程用的是 python3 的fabric 版本. 因此你本机要先安装python3. 如果是linux 版本, 一般是这样:

    sudo apt install python3-pip
    

    安装完成之后, 只要用:

    sudo pip3 install xxx
    

    所安装的包/组件就都是python3版本了.

    如果是windows系统, 假设你下载安装的就是python3的软件, 那么当你使用 pip install 的时候, 这个pip 就是3的版本. 所以不需要再多设置.

    如何安装

    linux:

    sudo pip3 install fabric
    

    windows:

    pip install fabric
    

    实验环境

    如果你很熟悉docker 或者自己就有云服务器, 那么试验环境就有了. 如果你没有(特别是windows 用户, 很难装好docker) 怎么办.

    你可以使用我的这个虚拟机镜像. 首先你要安装 virtualbox, 下载地址在这里: https://www.virtualbox.org/wiki/Downloads

    在某云盘下载我的这个虚拟机镜像:
    这是个 xubuntu 系统(ubuntu的变种), 我最爱的系统之一.

    安装之后用virtualbox 把它导入, 一步步操作如下:

    打开virtualbox之后, 选择New


    image.png

    Type选择Linux, Version 选择Ubuntu(64bit) , 然后点击Next.

    image.png

    内存默认 1024 就够了, 点Next

    image.png

    选择"Use an existing ... " , 然后点右边那个文件夹图标

    在打开的界面中, 选择 Add


    image.png

    然后选择刚才下载的xub.vdi文件, 如图:


    image.png

    然后点 choose


    image.png

    这时候你会看到 create 已经变得可选了, 点它. 就会看到虚拟机已经成功创建.

    image.png

    点击右上方的Settings, 然后在弹出的界面设置网卡:


    image.png

    (中文名字应该是桥接网络) . 这样选了之后, 你的电脑(称为宿主机) 就可以访问虚拟机里的操作系统了.

    双击xub 启动系统, 你会看到 xubuntu的界面. 这个系统有两个用户的信息, 分别是:
    xiaofeipapa / 密码 aa
    root / 密码 test

    在xubuntu的桌面点击鼠标右键, 选择 Open Terminal Here, 打开命令行, 输入:

    ifconfig 
    

    查看自己的ip是多少. 在我这里是 192.168.135.24 .

    然后在宿主机里打开命令行, 输入:

    ssh root@192.168.135.24 
    

    然后输入root的密码(test ) , 就可以看到ssh 登录成功了. 好了, 你拥有一个实验环境, 可以在上面试验fabric了.

    实验环境信息总结

    ip : 192.168.135.24 ( 也许你的机器会不同, 在虚拟机里用ifconfig来查看)
    用户: root / test

    fabric 基础

    以下程序的参数都针对我那个虚拟机镜像, 如果你有自己的虚拟机或者云服务器, 改相应参数即可.

    起步: 连接服务器, 执行命令

    #! /usr/bin/python3
    # -*- coding: UTF-8 -*-
    """
      作者: 小肥爬爬
      简书: https://www.jianshu.com/u/db796a501972
      gitee: https://gitee.com/xiaofeipapa/python-toolkit
      您可以自由转载此博客文章, 恳请保留原链接, 谢谢!
    """
    from fabric import Connection
    
    
    def do_it():
    
        host = '192.168.135.24'
        user = 'root'
        password = 'test'
    
        # ssh 连接的正确姿势
        conn = Connection(host=host, user=user, connect_kwargs={'password': password})
    
        # 在远程机器运行命令(用run方法), 并获得返回结果
        # hide 表示隐藏远程机器在控制台的输出, 达到静默的效果
        # 默认 warn是False, 如果远程机器运行命令出错, 那么本地会抛出异常堆栈. 设为True 则不显示这堆栈.
        cmd = 'ls /tmp'
        result = conn.run(cmd, hide=True, warn=True, encoding='utf-8')
    
        # 正常运行时, 信息在 stdout里
        print('-------- 下面是 stdout 信息')
        print(result.stdout.strip())
    
        # 出错时, 信息在 stderr 里
        print('-------- 下面是 stderr 信息')
        print(result.stderr.strip())
    
    
    if __name__ == '__main__':
        do_it()
    
    

    注释里已经把api用法说得很清楚了. 请阅读并运行程序加深印象.

    封装工具类 fab_utils.py

    在我们写程序的时候, 其实大部分时候都运行正常. 如果每次run之后都去判断 stdout, stderr ... 代码很快变得混乱不堪. 所以我的选择是将之封装成方法, 使之更加轻便. 这个文件命名为 fab_utils.py, 内容如下:

    #! /usr/bin/python3
    # -*- coding: UTF-8 -*-
    """
      作者: 小肥爬爬
      简书: https://www.jianshu.com/u/db796a501972
      gitee: https://gitee.com/xiaofeipapa/python-toolkit
      您可以自由转载此博客文章, 恳请保留原链接, 谢谢!
    
      将fabric api 再封装一层, 使之更好用
    """
    
    
    class FabException(Exception):
        def __init__(self, msg):
            Exception.__init__(self, msg)
    
    
    # 运行远程命令
    def run(conn, cmd, hide=True, warn=True):
    
        r = conn.run(cmd, encoding='utf8', hide=hide, warn=warn)
    
        result, err = r.stdout.strip(), r.stderr.strip()
        if err:
            raise FabException(err)
    
        return result
    

    以后, 我会把这个工具库逐渐扩大, 加入更多有用的方法. 经过这种方式, fabric的大多数功能就变成你的工具库, 可以轻松写出大多数的运维程序.

    写一个程序 s2_test_fab_utils.py 来测试:

    #! /usr/bin/python3
    # -*- coding: UTF-8 -*-
    """
      作者: 小肥爬爬
      简书: https://www.jianshu.com/u/db796a501972
      gitee: https://gitee.com/xiaofeipapa/python-toolkit
      您可以自由转载此博客文章, 恳请保留原链接, 谢谢!
    """
    from fabric import Connection
    import fab_utils
    
    
    def do_it():
    
        host = '192.168.135.24'
        user = 'root'
        password = 'test'
    
        # ssh 连接的正确姿势
        conn = Connection(host=host, user=user, connect_kwargs={'password': password})
    
        # 结果变得更简单了
        cmd = 'ls /tmp'
        result = fab_utils.run(conn, cmd)
    
        # 正常运行时, 信息在 stdout里
        print('-------- 下面是结果')
        print(result)
    
        # 出错时, 程序会抛出异常
        # 来一个出错的例子, tmp/xiaofeipapa 目录不存在
        cmd = 'ls /tmp/xiaofeipapa'
        result = fab_utils.run(conn, cmd)
        print(result)
    
    
    if __name__ == '__main__':
        do_it()
    

    运行这个结果, 你能看到第一个例子成功输出结果, 第二个例子抛出异常, 这就是我想要的效果.

    ssh无密码登录ssh

    登录密码写在参数里当然不安全. 用linux 系统的同学都知道, 可以配置无密码方式访问服务器, 避免暴露密码明文在参数里. (windows我暂时不知道怎么办, 有待请教. )

    首先在宿主机生成密钥, 一路按回车:

    ssh-keygen -t rsa
    

    然后运行这个脚本:

    ssh-copy-id root@192.168.135.24
    

    输入root的登录密码 test, 以后就可以无密码访问服务器了. 相应地, fabric的连接变成如下:

    conn = Connection(host=host, user=user)
    

    不用输入密码了.

    运行自定义shell脚本

    像ls, cd 都是bash 预先提供的命令. 如果要运行自己写的shell怎么办? 有两个办法: 如果sh 文件很大, 那么先在本地写好, 然后传到服务器上运行. 如果shell很少, 直接用这个方式运行:

    conn.client.exec_command(cmd)
    

    下面的这个例子演示了如何运行短的shell脚本:

    #! /usr/bin/python3
    # -*- coding: UTF-8 -*-
    """
      作者: 小肥爬爬
      简书: https://www.jianshu.com/u/db796a501972
      gitee: https://gitee.com/xiaofeipapa/python-toolkit
      您可以自由转载此博客文章, 恳请保留原链接, 谢谢!
    """
    from fabric import Connection
    import fab_utils
    
    
    def do_it():
    
        host = '192.168.0.12'
        user = 'root'
    
        # ssh 连接的正确姿势
        conn = Connection(host=host, user=user)
    
        # 运行shell之前, 要随便运行一个命令, 获得运行环境
        fab_utils.run(conn, 'uname -a')
    
        # 运行shell脚本
        # 在shell里 [ -d xxx ] 表示检查文件夹是否存在
        # [ -d xxx ] 表示检查文件是否存在
        cmd = '[ -d /tmp ] && echo ok'
        _stdin, _stdout, _stderr = conn.client.exec_command(cmd)
        result = _stdout.read().strip().decode('utf8')
    
        print('--- std out: ')
        print(result)
    
    
    if __name__ == '__main__':
        do_it()
    
    
    

    检查文件/夹是否存在

    bash没有提供检查文件夹是否存在, 文件是否存在的方法, 而这两个方法是经常需要使用的. 所以我们可以用简单的shell脚本来封装这两个方法. 在 fab_utils.py 里加入如下方法:

    
    # 检查文件夹是否存在
    def is_dir_exists(conn, dir_path):
        cmd = '[ -d ' + dir_path + ' ] && echo ok'
        _stdin, _stdout, _stderr = conn.client.exec_command(cmd)
        result = _stdout.read().strip().decode('utf8')
    
        return result == 'ok'
    
    
    # 检查文件文件是否存在
    def is_file_exists(conn, file_path):
        cmd = '[ -f ' + file_path + ' ] && echo ok'
        _stdin, _stdout, _stderr = conn.client.exec_command(cmd)
        result = _stdout.read().strip().decode('utf8')
    
        return result == 'ok'
    
    
    # 判断是否有该文件夹, 不存在时可以通过参数控制生成文件夹
    def check_has_dir(conn, dir_path, create_if_not_exist=True):
    
        if not is_dir_exists(conn, dir_path):
            if create_if_not_exist:
                run(conn, 'mkdir -p ' + dir_path)
    
    
    # 判断是否有该文件, 不存在时可以通过参数控制生成文件夹
    def check_has_file(conn, file_path, create_if_not_exist=True):
    
        if not is_dir_exists(conn, file_path):
            if create_if_not_exist:
                run(conn, 'touch ' + file_path)
    

    然后写一个python文件来检查:

    #! /usr/bin/python3
    # -*- coding: UTF-8 -*-
    """
      作者: 小肥爬爬
      简书: https://www.jianshu.com/u/db796a501972
      gitee: https://gitee.com/xiaofeipapa/python-toolkit
      您可以自由转载此博客文章, 恳请保留原链接, 谢谢!
    """
    from fabric import Connection
    import fab_utils
    import os, os.path
    
    
    def do_it():
    
        host = '192.168.0.12'
        user = 'root'
    
        # ssh 连接的正确姿势
        conn = Connection(host=host, user=user)
    
        # 运行shell之前, 要随便运行一个命令, 获得运行环境
        fab_utils.run(conn, 'uname -a')
    
        # 检查文件夹
        dir_path = '/root/data'
        fab_utils.check_has_dir(conn, dir_path)
    
        # 查看创建文件夹结果
        result = fab_utils.run(conn, 'ls ' + dir_path)
        print(result)
    
        # 检查文件
        file_path = os.path.join(dir_path, 'done.txt')
        fab_utils.check_has_file(conn, file_path)
    
        # 查看创建文件结果
        result = fab_utils.run(conn, 'ls ' + file_path)
        print(result)
    
    
    if __name__ == '__main__':
        do_it()
    

    安全的删除

    我们都知道在服务器上尽量不要用rm命令, 否则删错文件那就完了. 所以在用fabric的时候我们同样要注意这个问题. 在fab_utils.py 里加入这个方法:

    # 在服务器安全删除文件/文件夹的方法
    def safe_rm(conn, file_path):
    
        # 先检查是否存在
        try:
            run(conn, 'ls ' + file_path)
        except FabException:
            print(file_path + ' 不存在')
            return
    
        # 在/tmp下生成当天目录
        result = run(conn, 'date +%Y-%m-%d')
    
        trash_dir = '/tmp/my_trash/' + result
        check_has_dir(conn, trash_dir)
    
        # 在当天下生成uuid, 确保mv 不会失败
        result = run(conn, 'uuidgen')
        trash_dir = trash_dir + '/' + result
        check_has_dir(conn, trash_dir)
    
        run(conn, 'mv ' + file_path + ' ' + trash_dir)
    

    写一个文件来测试. 程序在 s5_rm_test.py

    #! /usr/bin/python3
    # -*- coding: UTF-8 -*-
    """
      作者: 小肥爬爬
      简书: https://www.jianshu.com/u/db796a501972
      gitee: https://gitee.com/xiaofeipapa/python-toolkit
      您可以自由转载此博客文章, 恳请保留原链接, 谢谢!
    """
    from fabric import Connection
    import fab_utils
    import os, os.path
    
    
    def do_it():
    
        host = '192.168.0.12'
        user = 'root'
    
        # ssh 连接的正确姿势
        conn = Connection(host=host, user=user)
    
        # 运行shell之前, 要随便运行一个命令, 获得运行环境
        fab_utils.run(conn, 'uname -a')
    
        # 删除之前创建的文件夹 /root/data
        dir_path = '/root/data'
        fab_utils.safe_rm(conn, dir_path)
    
        if fab_utils.is_dir_exists(conn, dir_path):
            print('--- 文件夹还在')
        else:
            print('--- 文件夹已经删除')
    
    
    if __name__ == '__main__':
        do_it()
    

    写入文本文件

    在服务器上我们通常会有写文件的任务, 例如写入环境变量到配置文件, 在fabric 里可以用简单的shell命令来完成:

    conn.run("echo 'hello' >> /tmp/test.txt")
    

    这个命令又是双引号又是单引号, 所以还是封装起来更好用. 在fab_utils.py 里加入如下方法:

    # 追加一行到文件末尾
    def append_line(conn, file_path, content):
        if not is_file_exists(conn, file_path):
            return
    
        cmd = "echo '" + content + "' >> " + file_path
        run(conn, cmd)
    

    然后写一个文件来测试, 代码在 s6_env_var.py

    #! /usr/bin/python3
    # -*- coding: UTF-8 -*-
    """
      作者: 小肥爬爬
      简书: https://www.jianshu.com/u/db796a501972
      gitee: https://gitee.com/xiaofeipapa/python-toolkit
      您可以自由转载此博客文章, 恳请保留原链接, 谢谢!
    """
    from fabric import Connection
    import fab_utils
    
    
    def do_it():
    
        host = '192.168.0.12'
        user = 'root'
    
        # ssh 连接的正确姿势
        conn = Connection(host=host, user=user)
    
        # 运行shell之前, 要随便运行一个命令, 获得运行环境
        fab_utils.run(conn, 'uname -a')
    
        # 在/tmp 下生成 test_rc 文件,
        file_path = '/root/test_rc'
        fab_utils.check_has_file(conn, file_path)
    
        # 写入内容到文件里
    
        fab_utils.append_line(conn, file_path, "#==其他配置信息1")
        fab_utils.append_line(conn, file_path, "#==其他配置信息2")
        fab_utils.append_line(conn, file_path, "#==其他配置信息3")
        fab_utils.append_line(conn, file_path, "\n")
        fab_utils.append_line(conn, file_path, "#==JAVA安装信息")
        fab_utils.append_line(conn, file_path, "JAVA_HOME=XXX")
        fab_utils.append_line(conn, file_path, "CLASS_PATH=YYY")
        fab_utils.append_line(conn, file_path, "export PATH=$PATH:JAVA_HOME/bin")
    
        # 查看文件内容
        result = fab_utils.run(conn, 'cat ' + file_path)
        print(result)
    
    
    if __name__ == '__main__':
        do_it()
    

    自动响应

    有些命令如 passwd , adduser 会等候你继续输入下一步. 像这种需要手动响应的自动化程序应该怎么写? 在fabric 里这样做:

    
    from invoke import Responder
    
    # 其他代码
    resp1 = Responder(
            pattern=r'Enter new UNIX password:',
            response=pwd + '\n'
        )
    
        resp2 = Responder(
            pattern=r'Retype new UNIX password:',
            response=pwd + '\n'
        )
    
        conn.run('passwd ' + username, pty=True, hide=True, watchers=[resp1, resp2])
    

    Responder 是 invoke 框架的一部分(fabric 已经包括invoke框架) . 它的使用方法如下:

    1. pattern: 正则表达式, 用来匹配命令行的输出. 如果里面有需要转义的字符, 千万要记得转义.
    2. response: 需要输入的内容.
      这两个参数结合起来的意思是: 如果匹配到命令输出, 需要输入信息的时候, 就自动输入response定好的字符串.

    如果不确定某些命令的pattern和resonse 是什么. 可以先在服务器手动输入命令看看结果, 然后再写程序. 如果程序多次需要输入, 那么就要写多个responder, 用个数组包起来.

    注意: 如果程序长时间没有反馈, 证明你的pattern 写得有问题.

    最常见的原因就是转义字符没有进行处理. 下面这是一个例子:

    
    # 在yum上安装软件
    def yum_install(conn, cmd):
    
        resp = Responder(
            # pattern=r'Is this ok [y/d/N]:',   # 错误例子: 没有正则转义
            pattern=r'Is this ok \[y/d/N\]:',
            response='y\n'
        )
    
        conn.run(cmd, pty=True, watchers=[resp], hide=True)
    

    下面是一个完整的例子: 我们将用户xiaofeipapa的密码改为 bb, 整个过程是自动化无人工干预的:

    #! /usr/bin/python3
    # -*- coding: UTF-8 -*-
    """
      作者: 小肥爬爬
      简书: https://www.jianshu.com/u/db796a501972
      gitee: https://gitee.com/xiaofeipapa/python-toolkit
      您可以自由转载此博客文章, 恳请保留原链接, 谢谢!
    """
    from fabric import Connection
    import fab_utils
    from invoke import Responder
    
    
    def do_it():
    
        host = '192.168.0.12'
        user = 'root'
    
        # ssh 连接的正确姿势
        conn = Connection(host=host, user=user)
    
        # 运行shell之前, 要随便运行一个命令, 获得运行环境
        fab_utils.run(conn, 'uname -a')
    
        # 将密码改成bb
        username = 'xiaofeipapa'
        pwd = 'bb'
        resp1 = Responder(
            pattern=r'Enter new UNIX password:',
            response=pwd + '\n'
        )
    
        resp2 = Responder(
            pattern=r'Retype new UNIX password:',
            response=pwd + '\n'
        )
    
        conn.run('passwd ' + username, pty=True, hide=True, watchers=[resp1, resp2])
    
    
    if __name__ == '__main__':
        do_it()
    

    fabric 实战案例: 在远程服务器上安装 jdk环境

    前面零零散散地介绍了很多fabric的用法, 现在用这个案例把它综合起来: 在远程服务器(虚拟机) 里安装jdk环境.

    这个任务做开发/运维的同学应该都不陌生. java技术栈的运维架构通常是1个nginx, 后端挂若干个安装jdk服务器, 以此达到负载均衡的目的.它的任务可以分解为:

    1. 在远程服务器上下载解压jdk包.
    2. 在配置文件写入若干个环境变量(如JAVA_HOME, CLASSPATH) , 指向jdk的解压路径.
    3. 创建新的登录用户, 开发者用它来登录机器, 发布jar 包.

    当然其中还包括一些弯弯绕绕的必要任务. 例如怎么判断任务已经运行过, 所以不会再重复运行? 怎么判断jdk包已经存在, 不用再重新下载? 怎么判断环境变量已经写入到配置文件, 不用重复写入?

    这些技巧一一列举如下.

    怎么知道任务是否第一次执行?

    思路: 给任务一个名字, 例如 install_jdk. 第一次在目标机器运行之后, 就会在 /root 目录下生成这个文件: /root/data/install_jdk/done.txt . 所以程序可以判断这个文件是否存在, 如果不存在表示此任务还没执行过. 如果存在, 那么可以通过命令行参数来指定是否再次运行任务.

    代码如下:

    
        def _prepare(self, rerun):
            """
            检查任务是否已经启动过
            :return:
            """
            # 必须要先run连接远程服务器, 否则 conn.client.exec_command 会报错
            fab_utils.run(self.conn, 'ls /tmp')
    
            # 生成 /root/data 目录
            base_dir = '/root/data'
            fab_utils.create_if_remote_dir_not_exist(self.conn, base_dir)
    
            # 检查该task 是否已经执行过. 如果已经执行过, 在 /root/data/task 目录下有 done.txt 文件
            task_home = base_dir + '/' + self.task
            fab_utils.create_if_remote_dir_not_exist(self.conn, task_home)
            self.task_home = task_home
    
            task_file = task_home + '/done.txt'
            if not fab_utils.is_remote_file_exist(self.conn, task_file):
                return
    
            # 如果存在, 又不指定重新运行, 则退出
            if not rerun:
                title('此程序已经在目标机器运行过了. 如果想再次运行, 请设置启动参数 -r true')
                exit(0)
    
    # ...... 其他代码
    # 命令行指定启动参数
    
    if __name__ == '__main__':
    
        import argparse
    
        parser = argparse.ArgumentParser('传入参数:***.py')
        parser.add_argument('-r', '--rerun', default=True)    # 开发时用
        # parser.add_argument('-r', '--rerun', default=False)
    
        args = parser.parse_args()
    
        rerun = args.rerun
    
        print('---- 参数 rerun: ', rerun)
    
        do_it(args)
    

    判断jdk存在,不用重复下载

    思路: 当第一次下载好jdk包的时候, 我们可以拿到该包的md5, 然后如果服务器上已经存在jdk包并且md5一致, 那么就不用再下载. 否则开始下载jdk.

    代码如下:

    
            with self.conn.cd(self.task_home):
    
                # 检查下载jdk
                file_path = self.task_home + '/' + jdk_file
                file_md5 = 'ef599e322eee42f6769991dd3e3b1a31'
                down_link = 'wget https://repo.huaweicloud.com/java/jdk/8u181-b13/' + jdk_file
                fab_utils.check_download(self.conn, file_path, file_md5, down_link)
    
                # 创建jvm目录
                fab_utils.create_if_remote_dir_not_exist(self.conn, jvm_dir)
    
                # 解压. 华为的这个包解压后名字不同, 所以手动指定一个目录
                hint('正在解压 jdk ......')
                fab_utils.run(self.conn, 'tar xvf ' + jdk_file + ' -C ' + jvm_dir + '  --strip-components 1 ')
    
    

    写入配置文件与重复检查

    有两个思路:

    1. 利用sed, 如果发现已经有相应的环境变量, 将之删除重新写入.
    2. 用 echo 显示 JAVA_HOME, 如果有值

    第一个思路容易错删其他内容, 所以后来采用了第二个思路. 代码如下:

    
            run_result = conn.run('echo $JAVA_HOME ', hide=True).stdout.strip()
            if run_result == jvm_dir:
                hint(system_file + ' 已经包含 JAVA_HOME, 不需要重新设置')
            else:
                # 追加内容到系统配置
                conn.run("echo '# ===== java 配置' >> " + system_file)
                conn.run("echo 'export JAVA_HOME=" + jvm_dir + "' >> " + system_file)
    
                # 将 exporter jar 也加入到 classpath 里
                export = 'export CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar:$JAVA_HOME/jre/lib/rt.jar:'\
                         + exporter_jar_path
                conn.run("echo '" + export + "' >> " + system_file)
                conn.run("echo 'export PATH=$PATH:$JAVA_HOME/bin' >> " + system_file)
    
                # 使环境变量生效
                conn.run('source ' + system_file)
    

    这里还有个小窍门, linux 那么多配置文件如 /etc/profile , /etc/bashrc , 究竟应该写到哪个文件? 查了一下资料, /etc/profile 只在用户第一次登录的时候起作用, 所以应该写到 /etc/bashrc 里.

    怎么生成新用户

    思路: 生成新用户很简单, 需要考虑的是给它设定密码. 考察了一下linux上生成密码的方式, 最后决定用 pwgen . 用法:

    # 生成10个字符的密码, 个数为1
    sudo apt install pwgen 
    pwgen -s 10 1
    

    代码大概长这样:

        def add_user(self, username):
            """
            增加用户, 并设置密码.
            :param username: 用户名
            :return: 登录密码
            """
    
            if self._is_user_exist(username):
                title('用户 ' + username + ' 已经存在')
                fab_utils.close_connection(self.conn)
                return None
    
            # 生成用户. 该命令只在centos 测试过
            fab_utils.run(self.conn, 'adduser ' + username)
    
            # 生成10位密码
            cmd = 'pwgen -s 10 1'
            password = fab_utils.run(self.conn, cmd)
    
            # 更改密码
            fab_utils.yum_passwd(self.conn, username, password)
    
            # 退出登录
            fab_utils.close_connection(self.conn)
    
            # 登录进行测试
            self.verify_login(username, self.host, password)
    
            return password
    

    完整代码

    项目地址: https://gitee.com/xiaofeipapa/fabric-tutorial

    请看 setup_java.py 文件

    总结

    通过这么多方法和整个案例的展示, 你应该掌握了fabric 90%的用法, 剩下的就靠你自己探索了. 希望你用fabric玩得愉快~

    记得给个star和赞啊, 少年~

    相关文章

      网友评论

        本文标题:python使用fabric之只看这篇就够了

        本文链接:https://www.haomeiwen.com/subject/cbiglltx.html