一.安装Fabric
使用pip install Fabric来安装,安装需要paramiko包和Crypto包
安装完成之后使用import fabric来查看是否完成安装
二.fab常用参数
-l,显示定义好的函数名
-f, 指定fab的入口文件,默认为fabfile.py
-g,指定网关设备,比如堡垒机环境,填写堡垒机IP即可
-H,指定目标主机,多台主机用,分隔
-P,以异步的方式运行多个任务,默认为串行
-R,指定role角色,以角色名区分不同的业务组设备
-t,设置设备连接超时时间
-T,设置远程主机命令执行超时时间
-w,当命令失败的时候发出告警,而非默认的终止任务
三.fabfile文件编写
1.全局属性设置
env对象是全局设定,支持多个属性,包括目标主机,用户名,密码,角色等
env.host,定义目标主机,可以使用ip或者主机名,例如env.hosts=['192.168.1.1','192.168.1.2']
env.exclude_hosts,定义排除主机,例如env.exlucde_hosts=['192.168.1.1']
env.user,定义用户名,例如env.user='root'
env.port,定义目标端主机端口号,默认为22,如env.port='22'
env.password,定义密码,例如env.password='root'
env.passwords,与password一样,区别在于对不同步的主机设置不同的密码,需要注意的是,配置passwords的时候需要配置用户名,主机,端口号等信息,例如
env.passwords={
'root@192.168.1.1:22':'root',
'root@192.168.1.2:22':'password'
}
env.gateway,定义网关ip,例如env.gateway='192.168.1.1'
env.deploy_release_dir,自定义全局变量,格式:env.+'变量名称',如env.deploy_release_dir,env.age,env.sex
env.reledefs,自定义角色分组,比如web组和db组的主机区分开来,定义如下:
env.roledefs={
'webservers'=['192.168.1.1','192.168.1.2','192.168.1.3'],
'dbservers'=['192.168.1.10','192.168.1.11']
}
@为python修饰符,角色修饰符下面的函数任务为其作用域,例如
@roles('webservers')
def get_host:
run('uname -a')
那么在执行的时候只有webservers下的主机才会执行这个函数
2.常用api
local,执行本地命令,如local('uname -a')
lcd,切换本地目录,如lcd('/home')
cd,切换远程目录,如cd('/home')
run,执行远程命令,如run('uname -r')
sudo,sudo的方式执行远程命令,如sudo('/etc/init.d/httpd start')
put,上传本地文件到远程主机,如put('/root/1.sql','home/oracle')
get,从远程主机下载文件到本地,如get('/home/oracle/1.sql','/home')
confirm,获得提示信息确认,如confirm("tests failed,continue[Y/N]")
prompt,获得用户输入提示信息,如prompt('please input password:')
reboot,重启远程主机,如:reboot()
@task,函数修饰符,标识的函数才能被fab调用,非标识的函数fab不可见
@runs_once,函数修饰符,标识的函数只会执行一次,不受多台主机的影响
四.fab示例
1.查看本地和远程主机的内存使用大小
192.168.56.30是本机,192.168.56.45是远程主机
[root@python suq]# cat fab1.py
#!/usr/bin/env python
from fabric.api import *
env.hosts=['192.168.56.45','192.168.56.201']
env.user='root'
env.passwords={'root@192.168.56.45:22':'rooter',
'root@192.168.56.201:22':'rooter'}
@runs_once #本地的只执行一次
def local_mem():
local('free -m')
def remote_mem():
run('free -m')
查看可以执行的命令:
[root@python suq]# fab -f fab1.py -l
Available commands:
local_mem
remote_mem
下面是执行结果:
[root@python suq]# fab -f fab1.py local_mem
[192.168.56.45] Executing task 'local_mem'
[localhost] local: free -m
total used free shared buffers cached
Mem: 996 305 691 0 66 92
-/+ buffers/cache: 146 850
Swap: 2015 0 2015
Done.
[root@python suq]# fab -f fab1.py remote_mem
[192.168.56.45] Executing task 'remote_mem'
[192.168.56.45] run: free -m
[192.168.56.45] out: total used free shared buffers cached
[192.168.56.45] out: Mem: 2002 1712 289 0 94 1245
[192.168.56.45] out: -/+ buffers/cache: 372 1629
[192.168.56.45] out: Swap: 2015 0 2015
[192.168.56.45] out:
[192.168.56.201] Executing task 'remote_mem'
[192.168.56.201] run: free -m
[192.168.56.201] out: total used free shared buffers cached
[192.168.56.201] out: Mem: 996 928 68 0 31 81
[192.168.56.201] out: -/+ buffers/cache: 814 181
[192.168.56.201] out: Swap: 2015 90 1925
[192.168.56.201] out:
Done.
Disconnecting from 192.168.56.45... done.
Disconnecting from 192.168.56.201... done.
2.动态获得远程目录列表
[root@python suq]# cat fab2.py
#!/usr/bin/env python
from fabric.api import *
env.hosts=['192.168.56.45','192.168.56.201']
env.passwords={'root@192.168.56.45:22':'rooter',
'root@192.168.56.201:22':'rooter'}
@runs_once
def input_raw():
return prompt("please input directory name:",default="/home")
def worktask(dirname):
run('ls -l '+dirname)
@task #这里使用了@task,对fab来说就只能用go命令
def go():
getdirname=input_raw()
worktask(getdirname)
只有一个go命令可用:
[root@python suq]# fab -f fab2.py -l
Available commands:
go
下面是运行结果:
[root@python suq]# fab -f fab2.py go
[192.168.56.45] Executing task 'go'
please input directory name: [/home]
[192.168.56.45] run: ls -l /home
[192.168.56.45] out: total 12
[192.168.56.45] out: drwx------ 3 grid oinstall 4096 Jun 23 2014 grid
[192.168.56.45] out: drwx------ 7 oracle oinstall 4096 Apr 14 19:38 oracle
[192.168.56.45] out: drwx------ 3 zabbix zabbix 4096 Dec 13 12:35 zabbix
[192.168.56.45] out:
[192.168.56.201] Executing task 'go'
[192.168.56.201] run: ls -l /home
[192.168.56.201] out: total 0
[192.168.56.201] out:
Done.
Disconnecting from 192.168.56.45... done.
Disconnecting from 192.168.56.201... done.
对于上面的结果做了一些测试发现:
1.设置了默认值,不输入就是以默认值为准,如果不设置默认值,那么dirname就是空的,ls -l的就是你登录用户的家目录,例如是root就是/root
2.对于写在go函数下的内容,有多少主机就会循环多少次,他是以主机为循环的.
3.这个脚本是对于所有的主机列出同一个目录,对于不同的主机让选择不同的目录,可以简单的修改为:
def worktask(dirname):
run('ls -l '+dirname)
@task
def go():
getdirname=raw_input("please input directory:")
worktask(getdirname)
3.文件打包上传校验
[root@py suq]# cat fab1.py
#!/usr/bin/env python
from fabric.api import *
from fabric.colors import *
env.hosts=['192.168.56.30']
env.user='root'
env.passwords={'root@192.168.56.30:22':'rooter'}
@runs_once
@task
def tarfile():
print yellow('tar file ...')
#使用with lcd命令,否则需要写全路径,直接lcd没用
with lcd('/var/log'):
local('tar czf messages.tar.gz messages')
@task
def putfile():
print blue('put file ...')
run('mkdir -p /tmp/log')
with cd('/tmp/log'):
#warn_only当出现异常的时候继续执行
with settings(warn_only=True):
result=put('/var/log/messages.tar.gz','/tmp/log')
if result.failed and not confirm('put file filed,Continue[Y/N]?'):
abort('Aborting file put task!')
@task
def checkfile():
print red('check file ...')
with settings(warn_only=True):
#本地local命令需要配置capture=True才能获取返回值
lmd5=local('md5sum /var/log/messages.tar.gz',capture=True).split(' ')[0]
rmd5=run('md5sum /tmp/log/messages.tar.gz').split(' ')[0]
if lmd5==rmd5:
print 'ok'
else:
print 'error'
@task
def go():
tarfile()
putfile()
checkfile()
下面是运行结果,有颜色的区别:
[192.168.56.30] Executing task 'go'
tar file ...
[localhost] local: tar czf messages.tar.gz messages
put file ...
[192.168.56.30] run: mkdir -p /tmp/log
[192.168.56.30] put: /var/log/messages.tar.gz -> /tmp/log/messages.tar.gz
check file ...
[localhost] local: md5sum /var/log/messages.tar.gz
[192.168.56.30] run: md5sum /tmp/log/messages.tar.gz
[192.168.56.30] out: 958b813fd7bdaa61cc206aa1012d8129 /tmp/log/messages.tar.gz
[192.168.56.30] out:
ok
Done.
Disconnecting from 192.168.56.30... done.
对于目录还可以使用env.xxxx这种全局变量来替换.