fabric
Fabric是一个python的远程执行shell的库,同时它也是一个命令行工具。它提供了丰富的同 SSH 交互的接口,可以用来在本地或远程机器上自动化、流水化地执行 Shell 命令。
#python3 安装时使用的是fabric3 :( 安装fabric3之前,需要先卸载fabric.)
# fabric3 支持 python3
pip uninstall fabric
pip3 install fabric3
fabric 不只是一个Python 模块,fabric 还是一个命令行工具,可以使用fab -h查看帮助信息
E:\my_data\hk-project>fab -V Fabric3 1.14.post1 Paramiko 2.9.2 E:\my_data\hk-project>fab -h
入门使用
fabric常用参数
-l:显示定义好的任务函数名
-f:指定fab人口文件,默认人口文件名为fabfile.py
-H:指定目标主机,多台主机用“,”号分割
fab -H localhost -f host_type.py function
fabric常用API
local:执行本地命令,如:local('uname -s')
lcd:切换本地目录,如:lcd('/home')
cd:切换远程目录,如:cd('/etc')
run:执行远程命令,如:run('free -m')
sudo:sudo方式执行远程命令,如:sudo('touch /abc')
put:上传本地文件到远程主机,如:put('/hello', '/home/itcast/hello')
get:从远程主机下载文件到本地,如:get('/home/python/world', '/home/itcase/world')
reboot:重启远程主机,如:reboot()
@task:函数装饰器,标识的函数为fab可调用的,非标记的对fab不可见,纯业务逻辑
@runs_once:函数装饰器,标识的函数只会执行一次,不受多台主机影响
fabric全局属性设定
env.host:定义目标主机,如:env.host=['192.168.17.192','192.168.17.193']
env.user:定义用户名,如:env.user="root"
env.port:定义目标主机端口,默认为22,如:env.port=“22”
env.password:定义密码,如:env.password="chuanzhi"
env.passwords:不同的主机不同的密码,如:
env.passowrds={
'root@192.168.117.92:22':'passwd',
'admin@192.168.117.93:22':'password'
}
示例1:动态获取远程目录列表
$ cat simple2.py
#!/usr/bin/env python
from fabric.api import *
env.user = 'root'
env.hosts = ['192.168.0.121']
env.password = '1234567'
def remote_task():
#"with"的作用是让后面的语句继承当前状态,实现"cd /root/ && ls -l'的效果
with cd('/root'):
run('ls -l')
===========================================================================
$ fab -f simple2.py remote_task
[192.168.0.121] Executing task 'remote_task'
[192.168.0.121] run: ls -l
[192.168.0.121] out: total 4
[192.168.0.121] out: -rw-------. 1 root root 1273 May 29 11:47 anaconda-ks.cfg
[192.168.0.121] out:
Done.
Disconnecting from 192.168.0.121... done.
示例2:部署LNMP业务服务环境
#!/usr/bin/env python
from fabric.colors import *
from fabric.api import *
env.user = 'root'
env.roledefs = {
'webservers':['192.168.56.11','192.168.56.12'],
'dbservers':['192.168.56.13']
}
env.passwords = {
'root@192.168.56.11:22':'1234567',
'root@192.168.56.12:22':'1234567',
'root@192.168.56.13:22':'1234567',
}
@roles('webservers') #使用webtask任务函数引用'webservers'角色修复符
def webtask():
print(yellow('Install nginx php php-fpm...'))
with settings(warn_only=True):
run("yum -y install nginx")
run("yum -y install php-fpm php-mysql php-mbstring php-xml php-mcrypt php-gd")
run("chkconfig --levels 235 php-fpm on")
run("chkconfig --levels 235 nginx on")
@roles('dbservers') #dbtask任务函数引用'dbservers'角色修复符
def dbtask():
print(yellow("Install Mysql..."))
with settings(warn_only=True):
run("yum -y install mysql mysql-server")
run("chkconfig --levels 235 mysqld on")
@roles('webservers','dbservers') #publictask任务函数同时引用两个角色修复符
def publictask(): #部署公共类环境,如epel、ntp等
print(yellow("Install epel ntp...."))
with settings(warn_only=True):
run("wget -O /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo")
run("yum -y install ntp")
def deploy():
execute(publictask)
execute(webtask)
execute(dbtask)
==================================================================================
$ fab -Pf simple6.py deploy
[192.168.56.11] Executing task 'publictask'
[192.168.56.12] Executing task 'publictask'
[192.168.56.13] Executing task 'publictask'Install epel ntp....
[192.168.56.13] run: wget -O /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repoInstall epel ntp....
[192.168.56.12] run: wget -O /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repoInstall epel ntp....
[192.168.56.11] run: wget -O /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo
[192.168.56.12] out: --2021-06-23 20:32:30-- http://mirrors.aliyun.com/repo/epel-7.repo
[192.168.56.11] out: --2021-06-23 20:32:30-- http://mirrors.aliyun.com/repo/epel-7.repo
[192.168.56.13] out: --2021-06-23 20:32:30-- http://mirrors.aliyun.com/repo/epel-7.repo....
[192.168.56.13] run: yum -y install ntp
[192.168.56.12] run: yum -y install ntp
[192.168.56.11] run: yum -y install ntp
....
....
....
[192.168.56.11] Executing task 'webtask'
[192.168.56.12] Executing task 'webtask'Install nginx php php-fpm...
[192.168.56.11] run: yum -y install nginx
Install nginx php php-fpm...
[192.168.56.12] run: yum -y install nginx
....
....
....
[192.168.56.13] Executing task 'dbtask'Install Mysql...
[192.168.56.13] run: rpm -ivh http://dev.mysql.com/get/mysql-community-release-el6-5.noarch.rpm.....
.....
.....
[192.168.56.13] run: chkconfig --levels 235 mysqld on
paramiko
1)实现了ssh协议
2)实现ssh远程控制
3)实现sftp功能
import paramiko #安装后导入模块
#创建实例
ssh = paramiko.SSHClient()
#相当于在询问是否接受服务器秘钥时自动回答yes
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect('192.168.59.112',username='root',password='211314')
"""
stdin.标准输入 用于实现交互式命令
stdout.标准输出 保存命令的正确执行结果
stderr.标准错误输出 保存命令的错误信息
"""
stdin ,stdout ,stderr = ssh.exec_command('mkdir /root/newdir')
print(str(stdout.read()))
ssh.close
案例代码,查看多台服务器的磁盘使用率(此代码演示查看192.168.59.131-132)
import paramiko
import sys
def sshExecCMD(ip , uesrname , password ):
ssh_client = paramiko.SSHClient()
ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy)
print("请求%s:" % ip)
try:
ssh_client.connect(hostname=ip ,username=uesrname ,password=password)
except Exception as e:
print("服务器%s连接失败!!!" % ip)
print(e)
sys.exit()
stdin ,stdout ,stderr = ssh_client.exec_command("df -h")
print(stdout.read().decode("utf-8"))
ssh_client.close()
if __name__ == '__main__':
for i in range(131, 133):
server = {
'192.168.59.' + str(i): {
"username": "root",
"password": "211314",
#"port": 22
}
}
for ip, info in server.items():
sshExecCMD(
ip=ip,
uesrname=info.get("username"),
password=info.get("password"),
#port=info.get("port")
)
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
/usr/bin/python3.7 /root/PycharmProjects/pythonProject/webone.py
请求192.168.59.131:
文件系统 容量 已用 可用 已用% 挂载点
devtmpfs 1.9G 0 1.9G 0% /dev
tmpfs 1.9G 0 1.9G 0% /dev/shm
tmpfs 1.9G 12M 1.9G 1% /run
tmpfs 1.9G 0 1.9G 0% /sys/fs/cgroup
/dev/mapper/centos-root 4.4G 3.7G 744M 84% /
/dev/sda1 1014M 151M 864M 15% /boot
tmpfs 1.9G 12K 1.9G 1% /var/lib/kubelet/pods/33185cf6-cdfe-4e1e-9a31-e8de94263fa3/volumes/kubernetes.io~secret/flannel-token-xkp6d
tmpfs 1.9G 12K 1.9G 1% /var/lib/kubelet/pods/846866a4-0983-4977-946b-0d91e5576b90/volumes/kubernetes.io~secret/kube-proxy-token-nxmps
overlay 4.4G 3.7G 744M 84% /var/lib/docker/overlay2/c585e004fd183248031ba2bd41ceaeca30aba69e4c29842c61c5b33caace5827/merged
shm 64M 0 64M 0% /var/lib/docker/containers/2bf609ddce0c66f1313210b63aa03997ac073b56466a3426504b2ce6005c0193/mounts/shm
overlay 4.4G 3.7G 744M 84% /var/lib/docker/overlay2/0e1cf81dbe957116a576033c11cb2d470517eac9daf8071488a43826e7740d7c/merged
overlay 4.4G 3.7G 744M 84% /var/lib/docker/overlay2/6cff54918ae7b8ba0f9acc38ae2481aa9602039a4471c01f651a301df163a01a/merged
shm 64M 0 64M 0% /var/lib/docker/containers/94f5576393ba10fc9e7515d5c70722e3738ebed8ebf1a4d98bcde259f15ff50a/mounts/shm
overlay 4.4G 3.7G 744M 84% /var/lib/docker/overlay2/c709ceeb38a5fe3f310466607d79d74f6cde1bf0089384f214a7322d3d366207/merged
tmpfs 378M 0 378M 0% /run/user/0
请求192.168.59.132:
服务器192.168.59.132连接失败!!!
[Errno None] Unable to connect to port 22 on 192.168.59.132
进程已结束,退出代码为 0
paramiko上传下载文件
#coding:utf-8
import paramiko
def sshFile():
#与服务器创建ssh连接
ssh_conn = paramiko.Transport(("192.168.59.128", 22))
ssh_conn.connect(username="root", password="211314")
#基于ssh连接创建ftp客户端
ftp_client = paramiko.SFTPClient.from_transport(ssh_conn)
#下载文件 上传和下载要保证客户端和服务端的文件名一致 ./.*?/name == .\.*?\name
ftp_client.get('/etc/hosts',r'E:\learndj\hosts')
#上传文件
#ftp_client.put(r"E:\learndj\hosts","/mnt/hosts")
ssh_conn.close()
if __name__ == '__main__':
sshFile()
paramiko往多个服务器上传案例
# coding:utf-8
import paramiko
import os
# localfile:本地文件夹名
# remotedir:服务器目录名称
def sshPutFile(ip, port, username, password, localfile, remotedir):
# 创建ssh链接
ssh_conn = paramiko.Transport((ip, port))
ssh_conn.connect(username=username, password=password)
# 获取源文件的文件名
file_name = os.path.basename(localfile)
# 处理服务器目录名称 /etc/
if not remotedir.endswith("/"):
remotedir = remotedir + "/"
system_file = remotedir + file_name
ftp_client = paramiko.SFTPClient.from_transport(ssh_conn)
ftp_client.put(localfile, system_file)
ssh_conn.close()
if __name__ == '__main__':
servers = {
"192.168.59.128":{
"username": "root",
"password": "211314",
"port": 22
},
"192.168.59.130": {
"username": "root",
"password": "211314",
"port": 22
},
"192.168.59.131": {
"username": "root",
"password": "211314",
"port": 22
}
}
source_file = input("源文件名称(绝对路径):")
server_dir = input("服务器目录路径:")
for ip,info in servers.items():
sshPutFile(
ip= ip,
port= info.get("port"),
username= info.get("username"),
password= info.get("password"),
localfile = source_file,
remotedir= server_dir,
)
查看是否上传成功,根据需求写获取ip的方式,此方式仅供参考,配置数量较大是可以采用多线程的方式增加效率。
import paramiko
ips_info = [
#("ip","username","password")
("101.43.129.109","root","Zgy666.."),
("10.1.128.14","root","rootroot"),
]
cmds = """
ls
free -h
df -h
"""
class ssh_Client:
def __init__(self):
self.cmd = cmds
for ip_info in ips_info:
self.ip = ip_info[0]
self.username = ip_info[1]
self.passwd = ip_info[2]
print("请求%s:" % self.ip)
try:
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy)
ssh.connect(hostname=self.ip, username=self.username, password=self.passwd)
stdin, stdout, stderr = ssh.exec_command(self.cmd)
print(stdout.read().decode("utf-8"))
except Exception as e:
print(self.ip, "连接失败,", e)
ssh.close()
if __name__ == '__main__':
ssh_Client()
# coding:utf-8
import os
import sys
from concurrent.futures import ThreadPoolExecutor
import paramiko
from pathlib import Path
self_name = sys.argv[0].rsplit('/', 1)[1]
self_dir = os.listdir()
self_dir.remove(self_name)
localhost = {
# "192.168.0.50":("root","rootroot"),
"101.43.129.109": ("root", "Zgy666.."),
# "10.1.128.13": ("root", "rootroot"),
}
BASE_DIR = Path(__file__).resolve().parent
# 服务端接收文件路径
server_path = "/mnt/"
def printTotals(transferred, toBeTransferred):
print("\r", end="")
# print("Download progress: {}%: ".format(transferred*100//toBeTransferred), "▋" * (transferred*50 // toBeTransferred), end="")
print(f"进度:{'▋' * (transferred * 50 // toBeTransferred)} {transferred * 100 // toBeTransferred}% ", end="")
sys.stdout.flush()
# print("Transferred: {0}\tOut of: {1}".format(transferred, toBeTransferred) )
def sshFile(localhost, username, password, put_path, load_path):
try:
# 与服务器创建ssh连接
ssh_conn = paramiko.Transport((localhost, 22))
ssh_conn.connect(username=username, password=password)
# 基于ssh连接创建ftp客户端
ftp_client = paramiko.SFTPClient.from_transport(ssh_conn)
# 上传文件
local_nowfile = put_path.split("/")[-1]
print("\n%s =====> %s \n" % (localhost, local_nowfile), end="")
ftp_client.put(put_path, load_path, callback=printTotals)
print("\n%s %s 传输完成!\n" % (localhost, local_nowfile), end="")
ssh_conn.close()
except Exception as e:
print(localhost,e)
def put_File(hostname, username, password):
for path_file in self_dir:
user_path_file = os.path.join(BASE_DIR, path_file)
server_path_file = os.path.join(server_path, path_file)
sshFile(hostname, username, password, user_path_file, server_path_file)
def pool_run():
pool = ThreadPoolExecutor(10)
for host, user_info in localhost.items():
try:
pool.submit(put_File, host, user_info[0], user_info[1])
except Exception as e:
print(host, e)
def run():
for host, user_info in localhost.items():
put_File(host,user_info[0],user_info[1])
if __name__ == '__main__':
run()