精通Python自动化脚本-运维人员宝典完整目录:
第一章 Python脚本概述
第二章 Python脚本调试和性能测试
第三章 单元测试-单元测试框架的介绍
第四章 自动化常规运维活动
第五章 文件、目录和数据处理
第六章 文件存档、加密和解密
第七章 文本处理和正则表达式
第八章 文档和报告
第九章 操作各类文件
第十章 网络基础 – Socket编程
第十一章 使用Python脚本处理邮件
第十二章 使用Telnet和SSH远程监控主机
第十三章 创建图形化用户界面
第十四章 处理Apache和其它的日志文件
第十五章 SOAP和REST API通讯
第十六章 网络抓取 – 从网站上提取有用的信息
第十七章 数据收集及报表
第十八章 MySQL和SQLite数据库管理
本章中我们将学习如何在服务器通过配置Telnet和SSH来实现基本配置。我们从Telnet模块开始,然后使用推荐的方法来实现相同的配置:使用Python的不同模块来完成SSH连接。我们还将学习telnetlib, subprocess, fabric, Netmiko和paramiko的运行方式。学习本章,读取必须要有网络的基础知识。
本章将涉及如下课题:
- telnetlib()模块
- subprocess.Popen()模块
- SSH之使用fabric模块
- SSH之使用Paramiko库
- SSH之使用Netmiko库
telnetlib()模块
这部分中,我们将学习Telnet协议,然后使用telnetlib模块对远程服务器进行Telnet的操作。
Telnet是一个允许用户与远程服务器通讯的网络协议。它多由网络管理员用来远程访问和管理设备。要访问设备,在终端中运行Telnet命令并加上远程服务器的IP地址或主机名。
Telnet使用TCP,默认端口为23。要使用,确保在系统中进行了安装,如未安装,运行如下命令来完成安装:
1 |
sudo apt-get install telnetd |
通过终端快速运行Telnet命令,可输入如下命令:
1 |
$ telnet ip_address_of_your_remote_server |
Python带有一个telnetlib模块,可通过Python脚本执行Telnet函数。在对远程设备或交换机进行Telnet之前,确保进行了适当的配置,如果未配置,我们可以在交换机终端中使用如下命令:
1 2 3 4 5 6 7 8 9 10 11 |
configure terminal enable password 'set_Your_password_to_access_router' username '设置用户名' password '设置远程访问密码' line vty 0 4 login local transport input all interface f0/0 ip add 'set_ip_address_to_the_router' 'put_subnet_mask' no shut end show ip interface brief |
译者注:以上代码与交换机相关,Ubuntu 开启 Telnet 命令如下:
1 2 3 4 5 6 7 8 |
# 安装openbsd-inetd sudo apt-get -y install openbsd-inetd # 安装telnetd sudo apt-get -y install telnetd # 重启openbsd-inetd sudo /etc/init.d/openbsd-inetd restart |
下面我们来看一个Telnet远程设备的示例。创建脚本telnet_example.py 并在其中编写如下内容:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
import telnetlib, getpass, sys HOST_IP = "你的主机 IP 地址" host_user = input("Enter your telnet username: ") password = getpass.getpass() t = telnetlib.Telnet(HOST_IP) # t.read_until(b"Username:") # t.read_until(b"login:") t.write(host_user.encode("ascii") + b"\n") if password: t.read_until(b"Password:") t.write(password.encode("ascii") + b"\n") t.write(b"enable\n") t.write(b"enter_remote_device_password\n") # 远程设备密码 t.write(b"conf t\n") t.write(b"int loop 1\n") t.write(b"ip add 10.1.1.1 255.255.255.255\n") t.write(b"int loop 2\n") t.write(b"ip add 20.2.2.2 255.255.255.255\n") t.write(b"end\n") t.write(b"exit\n") print(t.read_all().decode("ascii")) |
运行脚本,我们将得到如下输出:
1 2 3 4 5 |
$ python3 telnet_example2.py Enter your telnet username: student Password: ... |
译者注:原文测试对象为交换机,上例中 Alan 使用了 Ubuntu 进行测试,因此需将第一处的读取改为 login,命令执行部分省略,读者可替换为其它 Linux 命令来进行测试。
上例中,我们使用telnetlib模块访问并配置了Cisco交换机。该脚本中,首先我们接收用户输入用户名和密码来初始化远程设备的Telnet连接。一旦建立了连接,我们对远程设备进行了更进一步的配置。Telnet连接后,我们就能够访问远程服务器或设备。但Telnet协议有一个很重要的缺点,那就是所有的数据,包括用户和密码,都以文本的形式在网络中传输,这就可能会带来安全风险。因此,现在很少会使用Telnet,转而由名为Secure Shell的安全协议在替代,常称为SSH。
SSH
SSH是一个通过远程访问来管理设备或服务器的网络协议。SSH使用公钥加密来保证安全。Telnet和SSH之间的重要区别是SSH使用了加密,也就是说数据在网络上的传输都受保护不被未授权实时拦截。
用户访问远程服务器或设备时应使用SSH客户端。在终端中通过如下命令可安装SSH:
1 |
sudo apt install ssh |
同时在用户要远程连接的远程服务器上需要安装和运行SSH服务端。SSH使用TCP协议并且默认运行在22端口上。
我们可以通过终端运行ssh命令如下:
1 |
ssh host_name@host_ip_address |
下面我们来学习使用Python中的不同模块来进行SSH连接,如subprocess, fabric, Netmiko和Paramiko。接下来我们就逐一学习这些模块。
subprocess.Popen()模块
Popen类处理进程的创建和管理。通过使用这一模块,开发人员可处理不太常见的用例。子程序将在新的进程中进行。要在Unix/Linux上执行子程序,该类会使用os.execvp()函数。要在Windows上执行子程序,该类会使用CreateProcess()函数。
下面我们来看subprocess.Popen()的一些有用的参数:
1 2 3 4 5 6 7 |
class subprocess.Popen(args, bufsize=-1, executable=None, stdin=None, stdout=None, stderr=None, preexec_fn=None, close_fds=_PLATFORM_DEFAULT_CLOSE_FDS, shell=False, cwd=None, env=None, universal_newlines=False, startupinfo=None, creationflags=0, restore_signals=True, start_new_session=False, pass_fds=(), *, encoding=None, errors=None): |
我们来看下各个参数:
- args:可以是一个程序参数序列或单个字符串。如果args是一个序列,args中的第一项会被执行。如果args是一个字符,它推荐以序列传入args。
- shell:shell参数默认设为False,它指定是否使用shell来执行程序。如果shell的值为True,它推荐以字符串传入args。在Linux中,如果shell=True,shell默认为/bin/sh。如果args是一个字符串,字符串指定通过shell执行的命令。
- bufsize:如果bufsize为0(默认值为0,译者注:Alan 本地3.6和3.7的默认值均为-1),这表示未缓冲,如果bufsize值为1,则表示行缓冲。若bufsize为任意其它正值,使用指定大小的缓冲。如果bufsize为任意其它负值,表示全量缓冲。
- executable:它指定要执行的替代程序。
- stdin, stdout, and stderr:这些参数分别定义标准输入、标准输出和标准错误。
- preexec_fn:设置为可调用对象,会在执行子进程之前调用。
- close_fds:在Linux中,如果close_fds为真,所以除0, 1和2以外的文件描述符都会在子进程执行之前关闭。在Windows中,如果close_fds为真那么子进程将不继承指针。
- env:如果其值不为None,那么映射会定义新进程的环境变量。
- universal_newlines:若值为True,那么stdout和stderr会以新行模式的文本文件打开。
下面我们来看一个subprocess.Popen()的示例。为此创建一个脚本ssh_using_sub.py并在其中编写如下内容:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
import subprocess, sys HOST="主机用户名@主机 IP" COMMAND = "ls" ssh_obj = subprocess.Popen(["ssh", "%s" % HOST, COMMAND], shell=False, stdout=subprocess.PIPE, stderr=subprocess.PIPE) result = ssh_obj.stdout.readlines() if result == []: err = ssh_obj.stderr.readlines() print(sys.stderr, "ERROR: %s" % err) else: print(result) |
运行脚本,我们将得到如下输出:
1 2 3 4 5 6 7 8 |
$ python3 ssh_using_sub2.py # 输出结果(第一次需确认连接): The authenticity of host '192.168.0.14 (192.168.0.14)' can't be established. ECDSA key fingerprint is SHA256:0Yzjg/Ipsb3ilbpABfih6b55ET6ub0c2MkgtbWqwm/8. Are you sure you want to continue connecting (yes/no)? yes student@192.168.0.14's password: [b'testing\n', b'work\n'] |
上例中,首先我们导入了subprocess模块,然后定义了想要建立SSH连接的主机地址。接着我们添加了一条在远程设备上执行的简单命令。一切设置完成后,我们将这一信息传入到subprocess.Popen()函数中。该函数执行定义在函数内的参数来创建与远程设备的连接。在建立了SSH连接之后,我们所定义的命令被执行并返回结果。然后我们在终端中打印出了SSH的返回结果,参见输出。
SSH之使用fabric模块
Fabric是一个Python库,并且是一个可用于SSH的命令行工具。它用于系统运维及在网上部署应用。我们也可以在SSH之上执行shell命令。
要使用fabric模块,首先我们要使用如下命令来进行安装:
1 |
pip3 install fabric3 |
下面我们来看一个示例。创建脚本fabfile.py并在其中编写如下内容:
1 2 3 4 5 6 7 8 9 10 11 |
from fabric.api import * env.hosts = ["用户名@主机ip"] env.password = '你的密码' def dir(): run('mkdir fabric') print('Directory named fabric has been created on your host network') def diskspace(): run('df') |
运行脚本,我们将得到如下输出:
1 2 3 4 5 6 7 8 9 10 |
$ fab -f fabfile.py dir # 输出结果: [student@192.168.0.14] Executing task 'dir' [student@192.168.0.14] run: mkdir fabric ... Directory named fabric has been created on your host network Done. Disconnecting from student@192.168.0.14... done. |
上例中,首先我们导入了fabric.api模块,然后我们设置了主机名和密码来与网络上主机进行连接。接着,我们设置了通过SSH执行的任务。因此,执行我们的程序不是使用Python3 fabfile.py,而是要使用fab工具,然后上述的任务就会从fabfile.py文件中进行执行。本例中,我们执行了dir,在远程主机上创建了一个名为fabric目录。你也可以在Python文件中添加你自己的任务。它可通过fabric模块中的fab工具来进行执行。
SSH之使用Paramiko库
Paramiko是一个实现了安全连接远程设备SSHv2协议的库。Paramiko是针对SSH的纯Python接口。
在使用Paramiko之前,确保正确地在系统中进行了安装。如未安装,我们可以通过在终端中运行如下命令来进行安装:
1 |
sudo pip3 install paramiko |
下面我们来看一个使用paramiko的示例。对于paramiko连接,我们使用Cisco设备(译者注:Alan 将继续使用本地虚拟机)。Paramiko既支持密码验证也支持密钥对验来对主机进行安全连接。我们的脚本中,会使用密码验证,也即对密码进行检测,如存在则尝试使用用户名/密码来进行验证。在使用SSH连接远程设备或多层交换机时,首先确保对它们进行了适当的配置,若未配置,可使用如下命令在多层交换机中进行基本配置:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
configure t ip domain-name cciepython.com crypto key generate rsa How many bits in the modulus [512]: 1024 interface range f0/0 - 1 switchport mode access switchport access vlan 1 no shut int vlan 1 ip add 'set_ip_address_to_the_router' 'put_subnet_mask' no shut exit enable password 'set_Your_password_to_access_router' username 'set_username' password 'set_password_for_remote_access' username 'username' privilege 15 line vty 0 4 login local transport input all end |
译者注:有相应设备的朋友请自行验证配置命令
下面,创建一个脚本pmiko.py并在其中编写如下内容:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
import paramiko, time ip_address = '主机 IP' usr = '主机用户名' pwd = '主机密码' c = paramiko.SSHClient() c.set_missing_host_key_policy(paramiko.AutoAddPolicy()) c.connect(hostname=ip_address, username=usr, password=pwd) print("SSH connection is successfully established with ", ip_address) rc = c.invoke_shell() for n in range(2, 6): print("Creating VLAN " + str(n)) rc.send("vlan database\n") rc.send("vlan " + str(n) + "\n") rc.send("exit\n") time.sleep(0.5) time.sleep(1) output = rc.recv(65535) print(output) c.close() |
运行脚本,我们将得到如下输出:
1 2 3 4 5 6 7 |
$ python3 pmiko.py SSH connection is successfully established with 192.168.0.14 Creating VLAN 2 Creating VLAN 3 Creating VLAN 4 # 测试连接正常,但会报错OSError: Socket is closed,可考虑修改为其它命令 |
上例中,首先我们导入了paramiko模块,然后定义了需要远程连接设备的SSH认证信息。在传入身份信息后,我们创建了一个paramiko.SSHclient()的实例c,它是用于连接远程设备和执行命令或运算的主客户端。SSHClient对象的创建允许我们使用.connect()函数来建立远程连接。然后,我们设置了 paramiko连接的策略,因为默认paramiko.SSHclientu将SSH策略设置为拒绝状态。这会让策略拒绝任何未验证的SSH连接。我们的脚本中通过使用AutoAddPolicy()函数来自动添加主机的密钥而不进行弹出,忽略了这种SSH连接断掉的可能性。我们使用策略来进行测试,但出于安全目的不推荐在生产环境使用。
SSH连接建立之后,我们可以进行想在设备上进行的配置或运算。这里,我们在远程设备上创建了几个虚拟LAN。在创VLAN之后,我们关闭了连接。
SSH之使用Netmiko库
这部分中我们将学习Netmiko。Netmiko库是Paramiko的一个高级版本。这是一个基于Paramiko的多供应商(multi_vendor)库。Netmiko简化了网络设备的SSH连接及对设备的具体操作。在通过SSH连接远程设备或多层交换机之前,确保对它们进行了相应的配置,若未配置,我们可以使用在Paramiko一节中使用的命令来进行基本配置。
下面我们来看一个示例。创建一个脚本nmiko.py并在其中编写如下代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
from netmiko import ConnectHandler remote_device = { 'device_type': 'cisco_ios', # 'device_type': 'linux', 'ip': '远程设备 IP地址', 'username': '用户名', 'password': '密码' } remote_connection = ConnectHandler(**remote_device) # net_connect.find_prompt() for n in range(2, 6): print("Creating VLAN " + str(n)) commands = ['exit', 'vlan database', 'vlan ' + str(n), 'exit'] output = remote_connection.send_config_set(commands) print(output) command = remote_connection.send_command('show vlan-switch brief') # command = remote_connection.send_command('ls') print(command) |
运行脚本,将得到如下输出:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
~$ python3 nmiko.py Output: Creating VLAN 2 config term Enter configuration commands, one per line. End with CNTL/Z. server(config)#exit server #vlan database server (vlan)#vlan 2 VLAN 2 modified: server (vlan)#exit APPLY completed. Exiting.... server # .. .. .. .. switch# Creating VLAN 5 config term Enter configuration commands, one per line. End with CNTL/Z. server (config)#exit server #vlan database server (vlan)#vlan 5 VLAN 5 modified: server (vlan)#exit APPLY completed. Exiting.... VLAN Name ---- 1 default active Fa0/0, Fa0/1, Fa0/2, Fa0/3, Fa0/4, Fa0/5, Fa0/6, Fa0/7, Fa0/8, Fa0/9, Fa0/10, Fa0/11, Fa0/12, Fa0/13, Fa0/14, Fa0/15 2 VLAN0002 active 3 VLAN0003 active 4 VLAN0004 active 5 VLAN0005 active 1002 fddi-default active 1003 token-ring-default active 1004 fddinet-default active 1005 trnet-default active |
译者注:以上代码未验证,仅使用ls 代码进行了简单验证
1 2 |
$ python3 nmiko.py fabric testing work |
上例中,我们使用了Netmiko库来代替Paramiko进行SSH连接。该脚本中首先我们从Netmiko库中导入了ConnectHandler,用于以SSH连接远程网络设备,在设备字典中进行传入。本例中的字典为remote_device。在建立了连接之后,我们执行了配置命令来使用send_config_set()函数创建一些虚拟LAN。
在使用这类.send_config_set()函数向远程设备传递命令,它自动设置我们的设备为配置模式。在发送配置命令之后,我们还传递了一些简单命令来获取所配置设备的相关信息。
总结
本章中我们学习Telnet和SSH。我们还学习不同的Python模块,如 telnetlib, subprocess, fabric, Netmiko和Paramiko,使用它们我们执行了Telnet和SSH连接。SSH使用公钥加密来保持安全,要比Telnet安全的多。
下一章中我们会使用不同的Python库,通过它们来生成图形化用户界面。
课后问题
- 使用是客户端-服务端架构?
- 如何在Python代码中运行指定操作系统命令?
- LAN和VLAN之间的区别是什么?
- 如下代码的输出是什么?
12list = ['a', 'b', 'c', 'd', 'e']print(list[10:]) - 编写一个Python程序来显示日历(提示:使用calendar模块)
- 编写一个Python程序来对文本文件的行进行计数
扩展阅读
- Paramiko文档: https://github.com/paramiko/paramiko
- Fabric文档: http://www.fabfile.org/