- Python自动化运维:技术与最佳实践
- 刘天斯
- 372字
- 2023-07-14 21:06:10
第一部分 基础篇
第1章 系统基础信息模块详解
系统基础信息采集模块作为监控模块的重要组成部分,能够帮助运维人员了解当前系统的健康程度,同时也是衡量业务的服务质量的依据,比如系统资源吃紧,会直接影响业务的服务质量及用户体验,另外获取设备的流量信息,也可以让运维人员更好地评估带宽、设备资源是否应该扩容。本章通过运用Python第三方系统基础模块,可以轻松获取服务关键运营指标数据,包括Linux基本性能、块设备、网卡接口、系统信息、网络地址库等信息。在采集到这些数据后,我们就可以全方位了解系统服务的状态,再结合告警机制,可以在第一时间响应,将异常出现在苗头时就得以处理。
本章通过具体的示例来帮助读者学习、理解并掌握。在本章接下来的内容当中,我们的示例将在一个连续的Python交互环境中进行。
进入Python终端,执行python命令进入交互式的Python环境,像这样:
# python Python 2.6.6 (r266:84292, Nov 222013, 12:16:22) [GCC 4.4.720120313 (Red Hat 4.4.7-4)] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>>
1.1 系统性能信息模块psutil
psutil是一个跨平台库(http://code.google.com/p/psutil/),能够轻松实现获取系统运行的进程和系统利用率(包括CPU、内存、磁盘、网络等)信息。它主要应用于系统监控,分析和限制系统资源及进程的管理。它实现了同等命令行工具提供的功能,如ps、top、lsof、netstat、ifconfig、who、df、kill、free、nice、ionice、iostat、iotop、uptime、pidof、tty、taskset、pmap等。目前支持32位和64位的Linux、Windows、OS X、FreeBSD和Sun Solaris等操作系统,支持从2.4到3.4的Python版本,目前最新版本为2.0.0。通常我们获取操作系统信息往往采用编写shell来实现,如获取当前物理内存总大小及已使用大小,shell命令如下:
物理内存total值: free -m | grepMem | awk '{print $2}' 物理内存used值: free -m | grepMem | awk '{print $3}'
相比较而言,使用psutil库实现则更加简单明了。psutil大小单位一般都采用字节,如下:
>>> import psutil >>>mem = psutil.virtual_memory() >>>mem.total,mem.used (506277888L, 500367360L)
psutil的源码安装步骤如下:
#wget https://pypi.python.org/packages/source/p/psutil/psutil-2.0.0.tar.gz --no-check-certificate # tar -xzvf psutil-2.0.0.tar.gz # cd psutil-2.0.0 # python setup.py install
1.1.1 获取系统性能信息
采集系统的基本性能信息包括CPU、内存、磁盘、网络等,可以完整描述当前系统的运行状态及质量。psutil模块已经封装了这些方法,用户可以根据自身的应用场景,调用相应的方法来满足需求,非常简单实用。
(1)CPU信息
Linux操作系统的CPU利用率有以下几个部分:
❑User Time,执行用户进程的时间百分比;
❑System Time,执行内核进程和中断的时间百分比;
❑Wait IO,由于IO等待而使CPU处于idle(空闲)状态的时间百分比;
❑Idle,CPU处于idle状态的时间百分比。
我们使用Python的psutil.cpu_times()方法可以非常简单地得到这些信息,同时也可以获取CPU的硬件相关信息,比如CPU的物理个数与逻辑个数,具体见下面的操作例子:
>>> import psutil >>>psutil.cpu_times()#使用cpu_times方法获取CPU完整信息,需要显示所有逻辑CPU信息, >>>#指定方法变量percpu=True即可,如psutil.cpu_times(percpu=True) scputimes(user=38.039999999999999, nice=0.01, system=110.88, idle=177062.59, iowait=53.399999999999999, irq=2.9100000000000001, softirq=79.579999999999998, steal=0.0, guest=0.0) >>>psutil.cpu_times().user #获取单项数据信息,如用户user的CPU时间比 38.0 >>>psutil.cpu_count() #获取CPU的逻辑个数,默认logical=True4 >>>psutil.cpu_count(logical=False) #获取CPU的物理个数 2 >>>
(2)内存信息
Linux系统的内存利用率信息涉及total(内存总数)、used(已使用的内存数)、free(空闲内存数)、buffers(缓冲使用数)、cache(缓存使用数)、swap(交换分区使用数)等,分别使用psutil.virtual_memory()与psutil.swap_memory()方法获取这些信息,具体见下面的操作例子:
>>> import psutil >>>mem = psutil.virtual_memory() #使用psutil.virtual_memory方法获取内存完整信息 >>>mem svmem(total=506277888L, available=204951552L, percent=59.5, used=499867648L, free=6410240L, active=245858304, inactive=163733504, buffers=117035008L, cached=81506304) >>>mem.total #获取内存总数 506277888L >>>mem.free #获取空闲内存数 6410240L >>>psutil.swap_memory() #获取SWAP分区信息sswap(total=1073733632L, used=0L, free=1073733632L, percent=0.0, sin=0, sout=0) >>>
(3)磁盘信息
在系统的所有磁盘信息中,我们更加关注磁盘的利用率及IO信息,其中磁盘利用率使用psutil.disk_usage方法获取。磁盘IO信息包括read_count(读IO数)、write_count(写IO数)、read_bytes(IO读字节数)、write_bytes(IO写字节数)、read_time(磁盘读时间)、write_time(磁盘写时间)等。这些IO信息可以使用psutil.disk_io_counters()获取,具体见下面的操作例子:
>>>psutil.disk_partitions() #使用psutil.disk_partitions方法获取磁盘完整信息 [sdiskpart(device='/dev/sda1', mountpoint='/', fstype='ext4', opts='rw'), sdiskpart(device='/dev/sda3', mountpoint='/data', fstype='ext4', opts='rw')] >>> >>>psutil.disk_usage('/') #使用psutil.disk_usage方法获取分区(参数)的使用情况
sdiskusage(total=15481577472, used=4008087552, free=10687057920, percent=25.899999999999999) >>> >>>psutil.disk_io_counters() #使用psutil.disk_io_counters获取硬盘总的IO个数、 #读写信息 sdiskio(read_count=9424, write_count=35824, read_bytes=128006144, write_ bytes=204312576, read_time=72266, write_time=182485) >>> >>>psutil.disk_io_counters(perdisk=True) #“perdisk=True”参数获取单个分区IO个数、 #读写信息 {'sda2': sdiskio(read_count=322, write_count=0, read_bytes=1445888, write_ bytes=0, read_time=445, write_time=0), 'sda3': sdiskio(read_count=618, write_ count=3, read_bytes=2855936, write_bytes=12288, read_time=871, write_time=155), 'sda1': sdiskio(read_count=8484, write_count=35821, read_bytes=123704320, write_bytes=204300288, read_time=70950, write_time=182330)}
(4)网络信息
系统的网络信息与磁盘IO类似,涉及几个关键点,包括bytes_sent(发送字节数)、bytes_recv=28220119(接收字节数)、packets_sent=200978(发送数据包数)、packets_recv=212672(接收数据包数)等。这些网络信息使用psutil.net_io_counters()方法获取,具体见下面的操作例子:
>>>psutil.net_io_counters() #使用psutil.net_io_counters获取网络总的IO信息,默 #认pernic=False snetio(bytes_sent=27098178, bytes_recv=28220119, packets_sent=200978, packets_ recv=212672, errin=0, errout=0, dropin=0, dropout=0) >>>psutil.net_io_counters(pernic=True) #pernic=True输出每个网络接口的IO信息 {'lo': snetio(bytes_sent=26406824, bytes_recv=26406824, packets_sent=198526, packets_recv=198526, errin=0, errout=0, dropin=0, dropout=0), 'eth0': snetio(bytes_sent=694750, bytes_recv=1816743, packets_sent=2478, packets_ recv=14175, errin=0, errout=0, dropin=0, dropout=0)} >>>
(5)其他系统信息
除了前面介绍的几个获取系统基本信息的方法,psutil模块还支持获取用户登录、开机时间等信息,具体见下面的操作例子:
>>>psutil.users() #使用psutil.users方法返回当前登录系统的用户信息 [suser(name='root', terminal='pts/0', host='192.168.1.103', started=1394638720.0), suser(name='root', terminal='pts/1', host='192.168.1.103', started=1394723840.0)] >>> import psutil, datetime >>>psutil.boot_time() #使用psutil.boot_time方法获取开机时间,以Linux时间戳格式返回 1389563460.0 >>>datetime.datetime.fromtimestamp(psutil.boot_time()).strftime("%Y-%m-%d %H:%M:%S")
'2014-01-12 22:51:00' #转换成自然时间格式
1.1.2 系统进程管理方法
获得当前系统的进程信息,可以让运维人员得知应用程序的运行状态,包括进程的启动时间、查看或设置CPU亲和度、内存使用率、IO信息、socket连接、线程数等,这些信息可以呈现出指定进程是否存活、资源利用情况,为开发人员的代码优化、问题定位提供很好的数据参考。
(1)进程信息
psutil模块在获取进程信息方面也提供了很好的支持,包括使用psutil.pids()方法获取所有进程PID,使用psutil.Process()方法获取单个进程的名称、路径、状态、系统资源利用率等信息,具体见下面的操作例子:
>>> import psutil >>>psutil.pids() #列出所有进程PID [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19……] >>> p = psutil.Process(2424) #实例化一个Process对象,参数为一进程PID >>> p.name() #进程名 'java' >>> p.exe() #进程bin路径 '/usr/java/jdk1.6.0_45/bin/java' >>>p.cwd() #进程工作目录绝对路径 '/usr/local/hadoop-1.2.1' >>>p.status() #进程状态 'sleeping' >>>p.create_time() #进程创建时间,时间戳格式 1394852592.6900001 >>>p.uids() #进程uid信息 puids(real=0, effective=0, saved=0) >>>p.gids() #进程gid信息 pgids(real=0, effective=0, saved=0) >>>p.cpu_times() #进程CPU时间信息,包括user、system两个CPU时间 pcputimes(user=9.0500000000000007, system=20.25) >>>p.cpu_affinity() #get进程CPU亲和度,如要设置进程CPU亲和度,将CPU号作为参数即可 [0, 1] >>>p.memory_percent() #进程内存利用率 14.147714861289776 >>>p.memory_info() #进程内存rss、vms信息 pmem(rss=71626752, vms=1575665664) >>>p.io_counters() #进程IO信息,包括读写IO数及字节数 pio(read_count=41133, write_count=16811, read_bytes=37023744, write_ bytes=4722688) >>>p.connections() #返回打开进程socket的namedutples列表,包括fs、family、laddr #等信息 [pconn(fd=65, family=10, type=1, laddr=('::ffff:192.168.1.20', 9000),
raddr=(),……] >>>p.num_threads() #进程开启的线程数 33
(2)popen类的使用
psutil提供的popen类的作用是获取用户启动的应用程序进程信息,以便跟踪程序进程的运行状态。具体实现方法如下:
>>> import psutil >>>from subprocess import PIPE #通过psutil的Popen方法启动的应用程序,可以跟踪该程序运行的所有相关信息 >>> p = psutil.Popen(["/usr/bin/python", "-c", "print('hello')"], stdout=PIPE) >>>p.name() 'python' >>>p.username() 'root' >>>p.communicate() ('hello\n', None) >>>p.cpu_times() #得到进程运行的CPU时间,更多方法见上一小节 pcputimes(user=0.01, system=0.040000000000000001)
参考提示
❑ 1.1.1节示例参考https://github.com/giampaolo/psutil。
❑ 1.1.1节模块说明参考官网http://psutil.readthedocs.org/en/latest/。
1.2 实用的IP地址处理模块IPy
IP地址规划是网络设计中非常重要的一个环节,规划的好坏会直接影响路由协议算法的效率,包括网络性能、可扩展性等方面,在这个过程当中,免不了要计算大量的IP地址,包括网段、网络掩码、广播地址、子网数、IP类型等。Python提供了一个强大的第三方模块IPy(https://github.com/haypo/python-ipy/),最新版本为V0.81。IPy模块可以很好地辅助我们高效完成IP的规划工作,下面进行详细介绍。
以下是IPy模块的安装,这里采用源码的安装方式:
# wget https://pypi.python.org/packages/source/I/IPy/IPy-0.81.tar.gz --no- check-certificate # tar -zxvf IPy-0.81.tar.gz # cd IPy-0.81 # python setup.py install
1.2.1 IP地址、网段的基本处理
IPy模块包含IP类,使用它可以方便处理绝大部分格式为IPv6及IPv4的网络和地址。比如通过version方法就可以区分出IPv4与IPv6,如:
>>>IP('10.0.0.0/8').version() 4 #4代表IPv4类型 >>>IP('::1').version() 6 #6代表IPv6类型
通过指定的网段输出该网段的IP个数及所有IP地址清单,代码如下:
from IPy import IP ip = IP('192.168.0.0/16') print ip.len() #输出192.168.0.0/16网段的IP个数 for x in ip: #输出192.168.0.0/16网段的所有IP清单 print(x)
执行结果如下:
65536 192.168.0.0 192.168.0.1 192.168.0.2 192.168.0.3 192.168.0.4 192.168.0.5 192.168.0.6 192.168.0.7 192.168.0.8 ……
下面介绍IP类几个常见的方法,包括反向解析名称、IP类型、IP转换等。
>>>from IPy import IP >>>ip = IP('192.168.1.20') >>>ip.reverseNames() #反向解析地址格式 ['20.1.168.192.in-addr.arpa.'] >>>ip.iptype() #192.168.1.20为私网类型'PRIVATE' >>> IP('8.8.8.8').iptype() #8.8.8.8为公网类型 'PUBLIC' >>> IP("8.8.8.8").int() #转换成整型格式 134744072 >>> IP('8.8.8.8').strHex() #转换成十六进制格式 '0x8080808' >>> IP('8.8.8.8').strBin() #转换成二进制格式 '00001000000010000000100000001000' >>> print(IP(0x8080808)) #十六进制转成IP格式 8.8.8.8
IP方法也支持网络地址的转换,例如根据IP与掩码生产网段格式,如下:
>>>from IPy import IP >>>print(IP('192.168.1.0').make_net('255.255.255.0')) 192.168.1.0/24 >>>print(IP('192.168.1.0/255.255.255.0', make_net=True)) 192.168.1.0/24 >>>print(IP('192.168.1.0-192.168.1.255', make_net=True)) 192.168.1.0/24
也可以通过strNormal方法指定不同wantprefixlen参数值以定制不同输出类型的网段。输出类型为字符串,如下:
>>>IP('192.168.1.0/24').strNormal(0) '192.168.1.0' >>>IP('192.168.1.0/24').strNormal(1) '192.168.1.0/24' >>>IP('192.168.1.0/24').strNormal(2) '192.168.1.0/255.255.255.0' >>>IP('192.168.1.0/24').strNormal(3) '192.168.1.0-192.168.1.255'
wantprefixlen的取值及含义:
❑wantprefixlen = 0,无返回,如192.168.1.0;
❑wantprefixlen = 1,prefix格式,如192.168.1.0/24;
❑wantprefixlen = 2,decimalnetmask格式,如192.168.1.0/255.255.255.0;
❑wantprefixlen = 3,lastIP格式,如192.168.1.0-192.168.1.255。
1.2.2 多网络计算方法详解
有时候我们想比较两个网段是否存在包含、重叠等关系,比如同网络但不同prefixlen会认为是不相等的网段,如10.0.0.0/16不等于10.0.0.0/24,另外即使具有相同的prefixlen但处于不同的网络地址,同样也视为不相等,如10.0.0.0/16不等于192.0.0.0/16。IPy支持类似于数值型数据的比较,以帮助IP对象进行比较,如:
>>>IP('10.0.0.0/24') < IP('12.0.0.0/24') True
判断IP地址和网段是否包含于另一个网段中,如下:
>>> '192.168.1.100' in IP('192.168.1.0/24') >>>IP('192.168.1.0/24') in IP('192.168.0.0/16') True
True
判断两个网段是否存在重叠,采用IPy提供的overlaps方法,如:
>>>IP('192.168.0.0/23').overlaps('192.168.1.0/24') 1 #返回1代表存在重叠 >>>IP('192.168.1.0/24').overlaps('192.168.2.0') 0 #返回0代表不存在重叠
示例 根据输入的IP或子网返回网络、掩码、广播、反向解析、子网数、IP类型等信息。
#!/usr/bin/env python from IPy import IP ip_s = raw_input('Please input an IP or net-range: ') #接收用户输入,参数为IP 地址或网段地址 ips = IP(ip_s) if len(ips) > 1: #为一个网络地址 print('net: %s' % ips.net()) #输出网络地址 print('netmask: %s' % ips.netmask()) #输出网络掩码地址 print('broadcast: %s' % ips.broadcast()) #输出网络广播地址 print('reverse address: %s' % ips.reverseNames()[0]) #输出地址反向解析 print('subnet: %s' % len(ips)) #输出网络子网数 else: #为单个IP地址 print('reverse address: %s' % ips.reverseNames()[0]) #输出IP反向解析 print('hexadecimal: %s' % ips.strHex()) #输出十六进制地址 print('binary ip: %s' % ips.strBin()) #输出二进制地址 print('iptype: %s' % ips.iptype()) #输出地址类型,如PRIVATE、PUBLIC、LOOPBACK等
分别输入网段、IP地址的运行返回结果如下:
# python simple1.py Please input an IP or net-range: 192.168.1.0/24 net: 192.168.1.0 netmask: 255.255.255.0 broadcast: 192.168.1.255 reverse address: 1.168.192.in-addr.arpa. subnet: 256 hexadecimal: 0xc0a80100 binaryip: 11000000101010000000000100000000 iptype: PRIVATE # python simple1.py Please input an IP or net-range: 192.168.1.20 reverse address: 20.1.168.192.in-addr.arpa. hexadecimal: 0xc0a80114 binaryip: 11000000101010000000000100010100 iptype: PRIVATE
参考提示
❑ 1.2.1节官网文档与示例参考https://github.com/haypo/python-ipy/。
❑ 1.2.2节示例1参考http://blog.philippklaus.de/2012/12/ip-address-analysis-using-python/和http://www.sourcecodebrowser.com/ipy/0.62/class_i_py_1_1_i_pint.html等文章的IPy类说明。
1.3 DNS处理模块dnspython
dnspython(http://www.dnspython.org/)是Python实现的一个DNS工具包,它支持几乎所有的记录类型,可以用于查询、传输并动态更新ZONE信息,同时支持TSIG(事务签名)验证消息和EDNS0(扩展DNS)。在系统管理方面,我们可以利用其查询功能来实现DNS服务监控以及解析结果的校验,可以代替nslookup及dig等工具,轻松做到与现有平台的整合,下面进行详细介绍。
首先介绍dnspython模块的安装,这里采用源码的安装方式,最新版本为1.9.4,如下:
# http://www.dnspython.org/kits/1.9.4/dnspython-1.9.4.tar.gz # tar -zxvf dnspython-1.9.4.tar.gz # cd dnspython-1.9.4 # python setup.py install
1.3.1 模块域名解析方法详解
dnspython模块提供了大量的DNS处理方法,最常用的方法是域名查询。dnspython提供了一个DNS解析器类—resolver,使用它的query方法来实现域名的查询功能。query方法的定义如下:
query(self, qname, rdtype=1, rdclass=1, tcp=False, source=None, raise_on_no_ answer=True, source_port=0)
其中,qname参数为查询的域名。rdtype参数用来指定RR资源的类型,常用的有以下几种:
❑A记录,将主机名转换成IP地址;
❑MX记录,邮件交换记录,定义邮件服务器的域名;
❑CNAME记录,指别名记录,实现域名间的映射;
❑NS记录,标记区域的域名服务器及授权子域;
❑PTR记录,反向解析,与A记录相反,将IP转换成主机名;
❑SOA记录,SOA标记,一个起始授权区的定义。
rdclass参数用于指定网络类型,可选的值有IN、CH与HS,其中IN为默认,使用最广泛。tcp参数用于指定查询是否启用TCP协议,默认为False(不启用)。source与source_port参数作为指定查询源地址与端口,默认值为查询设备IP地址和0。raise_on_no_answer参数用于指定当查询无应答时是否触发异常,默认为True。
1.3.2 常见解析类型示例说明
常见的DNS解析类型包括A、MX、NS、CNAME等。利用dnspython的dns.resolver. query方法可以简单实现这些DNS类型的查询,为后面要实现的功能提供数据来源,比如对一个使用DNS轮循业务的域名进行可用性监控,需要得到当前的解析结果。下面一一进行介绍。
(1)A记录
实现A记录查询方法源码。
【/home/test/dnspython/simple1.py】
#!/usr/bin/env python import dns.resolver domain = raw_input('Please input an domain: ') #输入域名地址 A = dns.resolver.query(domain, 'A') #指定查询类型为A记录 for i in A.response.answer: #通过response.answer方法获取查询回应信息 for j in i.items: #遍历回应信息 printj.address
运行代码查看结果,这里以www.google.com域名为例:
# python simple1.py Please input an domain: www.google.com 173.194.127.180 173.194.127.178 173.194.127.176 173.194.127.179 173.194.127.177
(2)MX记录
实现MX记录查询方法源码。
【/home/test/dnspython/ simple2.py】
#!/usr/bin/env python import dns.resolver
domain = raw_input('Please input an domain: ') MX = dns.resolver.query(domain, 'MX') #指定查询类型为MX记录 for i in MX: #遍历回应结果,输出MX记录的preference及exchanger信息 print 'MX preference =', i.preference, 'mail exchanger =', i.exchange
运行代码查看结果,这里以163.com域名为例:
# python simple2.py Please input an domain: 163.com MX preference = 10 mail exchanger = 163mx03.mxmail.netease.com. MX preference = 50 mail exchanger = 163mx00.mxmail.netease.com. MX preference = 10 mail exchanger = 163mx01.mxmail.netease.com. MX preference = 10 mail exchanger = 163mx02.mxmail.netease.com.
(3)NS记录
实现NS记录查询方法源码。
【/home/test/dnspython/ simple3.py】
#!/usr/bin/env python import dns.resolver domain = raw_input('Please input an domain: ') ns = dns.resolver.query(domain, 'NS') #指定查询类型为NS记录 for i in ns.response.answer: for j in i.items: print j.to_text()
只限输入一级域名,如baidu.com。如果输入二级或多级域名,如www.baidu.com,则是错误的。
# python simple3.py Please input an domain: baidu.com ns4.baidu.com. dns.baidu.com. ns2.baidu.com. ns7.baidu.com. ns3.baidu.com.
(4)CNAME记录
实现CNAME记录查询方法源码。
【/home/test/dnspython/ simple4.py】
#!/usr/bin/env python import dns.resolver
domain = raw_input('Please input an domain: ') cname = dns.resolver.query(domain, 'CNAME') #指定查询类型为CNAME记录 for i in cname.response.answer: #结果将回应cname后的目标域名 for j in i.items: print j.to_text()
结果将返回cname后的目标域名。
1.3.3 实践:DNS域名轮循业务监控
大部分的DNS解析都是一个域名对应一个IP地址,但是通过DNS轮循技术可以做到一个域名对应多个IP,从而实现最简单且高效的负载平衡,不过此方案最大的弊端是目标主机不可用时无法被自动剔除,因此做好业务主机的服务可用监控至关重要。本示例通过分析当前域名的解析IP,再结合服务端口探测来实现自动监控,在域名解析中添加、删除IP时,无须对监控脚本进行更改。实现架构图如图1-1所示。
图1-1 DNS多域名业务服务监控架构图
1. 步骤
1)实现域名的解析,获取域名所有的A记录解析IP列表;
2)对IP列表进行HTTP级别的探测。
2. 代码解析
本示例第一步通过dns.resolver.query()方法获取业务域名A记录信息,查询出所有IP地址列表,再使用httplib模块的request()方法以GET方式请求监控页面,监控业务所有服务的IP是否服务正常。
【/home/test/dnspython/simple5.py】
#!/usr/bin/python import dns.resolver import os import httplib iplist=[] #定义域名IP列表变量 appdomain="www.google.com.hk" #定义业务域名 def get_iplist(domain=""): #域名解析函数,解析成功IP将被追加到iplist try: A = dns.resolver.query(domain, 'A') #解析A记录类型 except Exception,e: print "dns resolver error:"+str(e) return for i in A.response.answer: for j in i.items: iplist.append(j.address) #追加到iplist return True def checkip(ip): checkurl=ip+":80" getcontent="" httplib.socket.setdefaulttimeout(5) #定义http连接超时时间(5秒) conn=httplib.HTTPConnection(checkurl) #创建http连接对象 try: conn.request("GET", "/",headers = {"Host": appdomain}) #发起URL请求,添 #加host主机头 r=conn.getresponse() getcontent =r.read(15) #获取URL页面前15个字符,以便做可用性校验 finally: if getcontent=="<!doctype html>": #监控URL页的内容一般是事先定义好的,比如 #“HTTP200”等 print ip+" [OK]" else: print ip+" [Error]" #此处可放告警程序,可以是邮件、短信通知 if __name__=="__main__": if get_iplist(appdomain) and len(iplist)>0: #条件:域名解析正确且至少返回一个IP for ip in iplist: checkip(ip) else: print "dns resolver error."
我们可以将此脚本放到crontab中定时运行,再结合告警程序,这样一个基于域名轮循的业务监控已完成。运行程序,显示结果如下:
# python simple5.py 74.125.31.94 [OK] 74.125.128.199 [OK] 173.194.72.94 [OK]
从结果可以看出,域名www.google.com.hk解析出3个IP地址,并且服务都是正常的。