[TOC]
神马是Fabric
- 一个让你通过命令行执行无参数Python函数的工具
- 一个让通过ssh执行的shell命令更加容器、更符合Python的命令库
- 自然而然地,大部分用户把这两件事结合着用,使用 Fabric 来写和执行 Python 函数或 task
安装
-
建议安装pyenv使用python的虚拟环境
-
pip安装,必须是python2.7版本以上不然不支持
pip3 install fabric3 #安装python3以上版本
pip install fabric #安装python3以下版本
fab常用参数
- fab选项参数
-l 显示定义好的任何函数列表
-f 执行fab入口文件,默认入口文件为fabfile.py
-g 指定网关
-H 指定目标主机,多个主机使用,分隔
-P 以异步并行方式运行多主机任务,默认为串行任务,也就是依次执行
-u 指定主机用户名
-P 执行主机密码
案例: fab -p 密码 -H 主机1,主机2... '命令'
- fab操作案例
(fabric) [fabric@MAILCCOD ~]$ fab -H root@192.168.127.1:22 -- "pwd" #远程执行pwd命令
[root@192.168.127.1:22] Executing task '<remainder>'
[root@192.168.127.1:22] run: pwd
[root@192.168.127.1:22] Login password for 'root':
[root@192.168.127.1:22] out: /root
[root@192.168.127.1:22] out:
Done.
编写fabfile文件
-
全局属性的设置
-
env对象的作用定义了fabfile的全局设置,支持多个属性,包括目标主机、用户、密码、角色
-
env.hosts定义多个目标主机、用ip或者主机名的列表
格式: env.hosts= ["192.168.127.1","192.168.127.2"]
-
env.user: 定义用户名
格式: env.user = "root"
-
env.port: 定义端口
格式: env.port = 22
-
env.password:定义密码
格式:env.password = "1"
-
env.passwords: 定义多台主机的用户名、ip地址、端口、密码
格式: env.passwords = { "root@192.168.127.1:22":"passwd", "root@192.168.127.2:22":"passwd", }
-
env.gatewayd定义网关
格式:env.gateway = "192.168.127.1"
-
env.roledefs:定义角色分组
格式: env.roledefs = { "web":["192.168.127.2","192.168.127.3"] "Mysql":["192.168.127.4","192.168.127.5"] }
-
单机操作
- 编写fabfile文件
fabfile.py
#coding:utf8
from fabric.api import * #导出api方法
env.hosts = ["127.0.0.1"] #声明定义host主机
env.user = "root" #声明定义用户名
env.password = "ChannelSoft*ccod4.5" #声明定义密码
env.port = 20001 #声明定义密码
@task #使用装饰器
def show(): #编写show函数,远程运行linux命令
run("ls /home")
run("ps -ef|rep resin")
@task
def Mem():
run("free -m")
@task
def run_all(): #执行所有任务
execute(show)
execute(Mem)
if __name__ == "__main__": #使用Python直接执行
execute(run_all)
- 运行fabfile文件
fab -f fabfile.py show
运行show任务
fab -f fabfile.py -l
显示执行的任务
./fabfile.py
#执行调用
多机操作
- 多机操作
#!/usr/bin/python
#coding:utf8
from fabric.api import *
env.user = "root"
env.hosts = ["192.168.127.1","192.168.127.2"]
env.passwords = {
"root@192.168.127.1:22":"qnsoft",
"root@192.168.127.2:22":"qnsoft",
}
#roledefs是定义角色分组
env.roledefs = {
"Web":["192.168.127.1"],
"DB":["192.168.127.2"]
}
@task
def show():
run("df -h")
@task
@roles("Web") #使用角色
def Echo():
run("ifconfig ")
@task
@roles("DB")
def run_all():
execute(show) #此命令是调用上面定义的函数
run("ifconfig")
if __name__ == "__main__":
execute(run_all)
- 运行代码
[auto@mongodb1 fabric]$ fab -f Fabric1-0.py -l #使用fab命令显示可执行的任务
Available commands:
Echo
run_all
show
[auto@mongodb1 fabric]$ fab -f Fabric1-0.py Echo #执行Echo任务
常用的fabric的API
-
local: 执行本地命令
格式: local(本地命令)
-
lcd: 切换到本地目录
格式: lcd(本地目录)
-
cd: 切换远程目录
格式: cd(远程目录)
-
run: 执行远程命令
格式: run(远程命令)
-
sudo: sudo方式执行远程命令
格式: sudo(远程命令)
-
put: 上传本地文件到远程主机
格式: put(本地文件,远程文件)
-
get:从远程主机下载文件到本地
格式: get(远程文件,本地文件)
-
prompt: 获取用户输入信息
格式: prompt("please input user password:")
-
confirm: 获得提示信息确认
格式: confirm("continue[Y/N]?")
-
reboot: 重启远程主机
格式: reboot()
-
@task: 函数修饰符,标注过的
fab
命令可见,非标注过的fab命令不可见 -
@runs_once: 函数修饰符,标识的函数只会执行一次,不受多台主机影响
颜色输出
- from fabric.colors import * 导入颜色函数
- fabric.colors.blue(text, bold=False)
- fabric.colors.cyan(text, bold=False)
- fabric.colors.green(text, bold=False)
- fabric.colors.magenta(text, bold=False)
- fabric.colors.red(text, bold=False)
- fabric.colors.white(text, bold=False)
- fabric.colors.yellow(text, bold=False)
文件上传下载校验
- 源代码
upload_file.py
#!/usr/bin/python
#coding:utf8
from fabric.api import *
from fabric.contrib.console import confirm
from fabric.colors import * #导入颜色函数
env.user = "root"
env.hosts = ["192.168.127.26"]
env.passwords = {
"root@192.168.127.2:22":"ChannelSoft*ccod4.5"
}
#roledefs是定义角色分组
env.roledefs = {
"fps":["192.168.127.2"]
}
#定义文件上传任务
@task
def upload_file():
with settings(warn_only=True): #异常处理
local("tar zcf FPS.tar.gz /home/auto/fabric/Fps.py")
result = put("FPS.tar.gz","/root/FPS.tar.gz")
if result.failed and not confirm("continue[y/n]"): #异常处理,如果上传失败是否继续
abort("Put tar file Failed")
#获取本地和上传远端文件的m5d值是否一致
with settings(warn_only=True):
local_file = local("md5sum FPS.tar.gz",capture=True).split(" ")[0]
remote_file = run("md5sum /root/FPS.tar.gz").split(" ")[0]
if local_file == remote_file:
print(green("Yes upload Acss , M5D Ok"))
else:
print(read("Upload file Failed MD5 NO !!!"))
#定义文件下载任务
@task
def download_file():
with settings(warn_only=True):
get("/root/FPS.tar.gz","FPS.tar.gz")
local("tar -zxf FPS.tar.gz -C ./ && cat Fps.py ")
@task
def run_all():
execute(upload_file)
execute(download_file)
if __name__ == "__main__":
execute(run_all)
并行执行
-
如何运作
默认情况下,fabric会默认顺序执行所有的任务,为了任务函数之间并不会产生交互,该功能实现是基于Python multiprocessing模块,它为每个主机和任务组合创建一个线程,同时提供一个可选的弹窗用于阻止创建过多的进程 -
如何使用装饰器
由于并行执行影响的最小单位是任务,所有功能的启动和禁用也是以任务为单位使用parallel
或者serial
装饰器,如下所示:
#!/usr/bin/python
#coding:utf8
from fabric.api import *
@parallel
def runs_in_parallel():
pass
def runs_serially():
pass
如果这样执行:
$ fab -H host1,host2,host3 runs_in_parallel runs_serially
将会按照这样的流程执行:
runs_in_parallel 运行在 host1、host2 和 host3 上
runs_serially 运行在 host1 上
runs_serially 运行在 host2 上
runs_serially 运行在 host3 上
- 命令行操作
你也可以使用命令行选项 -P 或者环境变量 env.parallel <env-parallel>强制所有任务并行执行。不过被装饰器 `~fabric.decorators.serial 封装的任务会忽略该设置,仍旧保持顺序执行。
例如,下面的 fabfile 会产生和上面同样的执行顺序:
from fabric.api import *
def runs_in_parallel():
pass
@serial
def runs_serially():
pass
在这样调用时:
$ fab -H host1,host2,host3 -P runs_in_parallel runs_serially
和上面一样,runs_in_parallel 将会并行执行,runs_serially 顺序执行。
- bubble大小
主机列表很大时,用户的机器可能会因为并发运行了太多的 Fabric 进程而被压垮,因此,你可能会选择 moving bubble 方法来限制 Fabric 并发执行的活跃进程数。
默认情况下没有使用 bubble 限制,所有主机都运行在并发池中。你可以在任务级别指定parallel 的关键字参数 pool_size 来覆盖该设置,或者使用选项 -z 全局设置。
例如同时在 5 个主机上运行:
from fabric.api import *
@parallel(pool_size=5)
def heavy_task():
# lots of heavy local lifting or lots of IO here
或者不使用关键字参数 pool_size:
$ fab -P -z 5 heavy_task
- 案例
并行执行
#!/usr/bin/python
#coding:utf8
from fabric.api import *
from Hosts import *
@task
@roles("Web")
@parallel(pool_size=5) #意思说最大线程是为5个
def File():
with prefix("cd /home") :
run("ls -htrl")
#类似执行 cd /home && ls ccodrunner 的linux命令
if __name__ == "__main__":
execute(File)
上下文切换
-使用with语句的上下文管理器
#!/usr/bin/python
#coding:utf8
from fabric.api import *
env.hosts = ["127.0.0.1"] #声明定义host主机
env.user = "root" #声明定义用户名
env.password = "qnsoft" #声明定义密码
env.port = 10000 #声明定义密码
@task
def File():
with prefix("cd /home") : #with上下文切换
run("ls ccodrunner")
#类似执行 cd /home && ls ccodrunner 的linux命令
if __name__ == "__main__":
execute(File)
网友评论