python的ssh管理工具可以看以下
1.paramiko
2.pexpect
3.fabric
4.ansilbe
5.salt-stack
今天我选了fabirc操作,比起1和2来,他有自己的命令fab,不用像他们写那么多复杂的脚本。
对于4和5,用于更复杂的操作环境可以考虑。
!!!但是今天我只要每台机器上返回一个命令,不用搞得那么复杂
环境为windows python3
安装方法只要配好了pip(pip的安装网上都有,记得配系统路径就行),就简单的敲pip install Fabric3就可以了
以下我已经装好
PS C:\Users\Administrator\Desktop\python_script> pip show Fabric3
Name: Fabric3
Version: 1.14.post1
Summary: Fabric is a simple, Pythonic tool for remote execution and deployment (py2.7/py3.4+ compatible fork).
Home-page: https://github.com/mathiasertl/fabric/
Author: Mathias Ertl
Author-email: mati@er.tl
License: UNKNOWN
Location: c:\users\administrator\appdata\local\programs\python\python36\lib\site-packages
Requires: paramiko, six
装好了以后,用fab -V看有fab命令没有
PS C:\Users\Administrator\Desktop\python_script> fab -V
Fabric3 1.14.post1
Paramiko 2.4.1
现在写一个fabric脚本
from fabric.api import *
import getpass
env.user = input("input userid: ")
env.password = getpass.getpass("input passwd: ")
env.warn_only = True
def bash(cmd):
run(cmd)
def scpsh(localpath,repath):
put(localpath,repath)
我对于脚本这东西的习惯时
1.写了就别乱改脚本,要常变动的常数尽量改成屏幕输入或是参数,再不济就用配置文件。
2.密码输入不回显是标准操作,所以getpass是必须的,当然ssh_key是最好的,但生产环境就算了。
!python3里屏幕输入是input,python2里常用raw_input,这点是坑点
!getpass这个模块在python3里一样换了名字,请注意
PS C:\Users\Administrator\Desktop\python_script> pip show getpass3
Name: getpass3
Version: 1.2
Summary: The getpass3 is similar like getpass except it encrypts the echo of what you write in the terminal and display it.
Home-page: https://github.com/J16N/getpass3
Author: Jishan Bhattacharya
Author-email: scientistjishan@gmail.com
License: UNKNOWN
Location: c:\users\administrator\appdata\local\programs\python\python36\lib\site-packages
Requires:
脚本里有两个task,一个是命令,一个是传文件。
以下可以看效果
PS C:\Users\Administrator\Desktop\python_script> fab -H 192.168.8.82,192.168.8.81,192.168.8.83 -f resh.py bash:cmd="uname -n;ls"
input userid: vagrant
input passwd:
[192.168.8.82] Executing task 'bash'
[192.168.8.82] run: uname -n;ls
[192.168.8.82] out: anodest01
[192.168.8.82] out: from_master_docker_py3
[192.168.8.82] out:
[192.168.8.81] Executing task 'bash'
[192.168.8.81] run: uname -n;ls
[192.168.8.81] out: amainst
[192.168.8.81] out: jenkins nginx_study perltest python27 python3 vimst
[192.168.8.81] out:
[192.168.8.83] Executing task 'bash'
[192.168.8.83] run: uname -n;ls
[192.168.8.83] out: anodest02
[192.168.8.83] out:
Done.
Disconnecting from 192.168.8.82... done.
Disconnecting from 192.168.8.81... done.
Disconnecting from 192.168.8.83... done.
参数说明
-H 后面接的是机器名,用,号连接
-f 接的是脚本
脚本后面就是task,task后加变量
试试put方法
PS C:\Users\Administrator\Desktop\python_script> fab -H 192.168.8.82,192.168.8.81 -f resh.py scpsh:localpath="testfile",repath="/tmp/testfile"
input userid: vagrant
input passwd:
[192.168.8.82] Executing task 'scpsh'
[192.168.8.82] put: testfile -> /tmp/testfile
[192.168.8.81] Executing task 'scpsh'
[192.168.8.81] put: testfile -> /tmp/testfile
Done.
Disconnecting from 192.168.8.82... done.
Disconnecting from 192.168.8.81... done.
看是不是传成功了,有台没有,下面会做个提示
PS C:\Users\Administrator\Desktop\python_script> fab -H 192.168.8.82,192.168.8.81,192.168.8.83 -f resh.py bash:cmd="ls -l /tmp/testfile"
input userid: vagrant
input passwd:
[192.168.8.82] Executing task 'bash'
[192.168.8.82] run: ls -l /tmp/testfile
[192.168.8.82] out: -rw-rw-r--. 1 vagrant vagrant 18 Apr 12 14:46 /tmp/testfile
[192.168.8.82] out:
[192.168.8.81] Executing task 'bash'
[192.168.8.81] run: ls -l /tmp/testfile
[192.168.8.81] out: -rw-rw-r--. 1 vagrant vagrant 18 Apr 12 14:46 /tmp/testfile
[192.168.8.81] out:
[192.168.8.83] Executing task 'bash'
[192.168.8.83] run: ls -l /tmp/testfile
[192.168.8.83] out: ls: cannot access /tmp/testfile: No such file or directory
[192.168.8.83] out:
Warning: run() received nonzero return code 2 while executing 'ls -l /tmp/testfile'!
Done.
Disconnecting from 192.168.8.82... done.
Disconnecting from 192.168.8.81... done.
Disconnecting from 192.168.8.83... done.
要注意env.warn_only这个参数(默认是false),fabric的执行顺序里如果中间有个返回值是非0的时候,执行就会中断
注释掉这个参数运行一下
PS C:\Users\Administrator\Desktop\python_script> gc resh.py
from fabric.api import *
import getpass
env.user = input("input userid: ")
env.password = getpass.getpass("input passwd: ")
#env.warn_only = True
def bash(cmd):
run(cmd)
def scpsh(localpath,repath):
put(localpath,repath)
PS C:\Users\Administrator\Desktop\python_script> fab -H 192.168.8.83,192.168.8.81 -f resh.py bash:cmd="ls -l /tmp|grep testfile"
input userid: vagrant
input passwd:
[192.168.8.83] Executing task 'bash'
[192.168.8.83] run: ls -l /tmp|grep testfile
Fatal error: run() received nonzero return code 1 while executing!
Requested: ls -l /tmp|grep testfile
Executed: /bin/bash -l -c "ls -l /tmp|grep testfile"
Aborting.
Disconnecting from 192.168.8.83... done.
如何,grep找不到一般屏幕只会显示空,为啥就报错了,因为找不到啊,返回值非零,那自然fabric会判断为失败,就不在第二台执行了
去掉注释执行一下
PS C:\Users\Administrator\Desktop\python_script> gc resh.py
from fabric.api import *
import getpass
env.user = input("input userid: ")
env.password = getpass.getpass("input passwd: ")
env.warn_only = True
def bash(cmd):
run(cmd)
def scpsh(localpath,repath):
put(localpath,repath)
PS C:\Users\Administrator\Desktop\python_script> fab -H 192.168.8.83,192.168.8.81 -f resh.py bash:cmd="ls -l /tmp|grep testfile"
input userid: vagrant
input passwd:
[192.168.8.83] Executing task 'bash'
[192.168.8.83] run: ls -l /tmp|grep testfile
Warning: run() received nonzero return code 1 while executing 'ls -l /tmp|grep testfile'!
[192.168.8.81] Executing task 'bash'
[192.168.8.81] run: ls -l /tmp|grep testfile
[192.168.8.81] out: -rw-rw-r--. 1 vagrant vagrant 18 Apr 12 14:46 testfile
[192.168.8.81] out:
Done.
Disconnecting from 192.168.8.83... done.
Disconnecting from 192.168.8.81... done.
脚本就能顺利执行了,fabric本意是没有错的,但偏偏我们经常以为grep无结果不算报错。所以
env.warn_only=True这项写上有助于脚本的顺利执行。
env的文档可以参考http://docs.fabfile.org/en/1.8/usage/env.html#env-vars
最后,不得不说一个遗憾,本来fabric是支持并行的,但是在windows里不知道为什么会报错,目前没有找到解决方法。
PS C:\Users\Administrator\Desktop\python_script> fab -P -H 192.168.8.82,192.168.8.81 -f resh.py bash:cmd="ls -l /tmp|grep testfile"
input userid: vagrant
input passwd:
[192.168.8.82] Executing task 'bash'
[192.168.8.81] Executing task 'bash'
Traceback (most recent call last):
File "c:\users\administrator\appdata\local\programs\python\python36\lib\site-packages\fabric\main.py", line 763, in main
*args, **kwargs
File "c:\users\administrator\appdata\local\programs\python\python36\lib\site-packages\fabric\tasks.py", line 412, in execute
ran_jobs = jobs.run()
File "c:\users\administrator\appdata\local\programs\python\python36\lib\site-packages\fabric\job_queue.py", line 138, in run
_advance_the_queue()
File "c:\users\administrator\appdata\local\programs\python\python36\lib\site-packages\fabric\job_queue.py", line 123, in _advance_the_queue
job.start()
File "c:\users\administrator\appdata\local\programs\python\python36\lib\multiprocessing\process.py", line 105, in start
self._popen = self._Popen(self)
File "c:\users\administrator\appdata\local\programs\python\python36\lib\multiprocessing\context.py", line 223, in _Popen
return _default_context.get_context().Process._Popen(process_obj)
File "c:\users\administrator\appdata\local\programs\python\python36\lib\multiprocessing\context.py", line 322, in _Popen
return Popen(process_obj)
File "c:\users\administrator\appdata\local\programs\python\python36\lib\multiprocessing\popen_spawn_win32.py", line 65, in __init__
reduction.dump(process_obj, to_child)
File "c:\users\administrator\appdata\local\programs\python\python36\lib\multiprocessing\reduction.py", line 60, in dump
ForkingPickler(file, protocol).dump(obj)
AttributeError: Can't pickle local object '_execute.<locals>.inner'
PS C:\Users\Administrator\Desktop\python_script> Traceback (most recent call last):
File "<string>", line 1, in <module>
File "c:\users\administrator\appdata\local\programs\python\python36\lib\multiprocessing\spawn.py", line 99, in spawn_main
new_handle = reduction.steal_handle(parent_pid, pipe_handle)
File "c:\users\administrator\appdata\local\programs\python\python36\lib\multiprocessing\reduction.py", line 82, in steal_handle
_winapi.PROCESS_DUP_HANDLE, False, source_pid)
OSError: [WinError 87] 参数错误。
PS C:\Users\Administrator\Desktop\python_script> ^C