Python实用示例:DNS管理、LDAP使用、日志报告与FTP镜像
1. 使用Python管理DNS
在数据中心和网络托管服务提供商的工作中,进行大规模的DNS更改是一项具有挑战性的任务。Python的 dnspython 模块可以很好地解决这个问题。
1.1 安装 dnspython
由于 dnspython 包列在Python包索引中,你可以使用 easy_install 进行安装:
ngift@Macintosh-8][H:10048][J:0]# sudo easy_install dnspython
Password:
Searching for dnspython
Reading http://pypi.python.org/simple/dnspython/
[output supressed]
1.2 探索 dnspython 模块
使用IPython探索该模块,获取 oreilly.com 的A和MX记录:
import dns.resolver
ip = dns.resolver.query("oreilly.com","A")
mail = dns.resolver.query("oreilly.com","MX")
for i,p in ip,mail:
print i,p
输出结果如下:
208.201.239.37 208.201.239.36
20 smtp1.oreilly.com. 20 smtp2.oreilly.com.
1.3 查询一组主机的A记录
以下是一个查询一组主机A记录的脚本:
import dns.resolver
hosts = ["oreilly.com", "yahoo.com", "google.com", "microsoft.com", "cnn.com"]
def query(host_list=hosts):
collection = []
for host in host_list:
ip = dns.resolver.query(host,"A")
for i in ip:
collection.append(str(i))
return collection
if __name__ == "__main__":
for arec in query():
print arec
运行该脚本,你将得到这些主机的所有A记录。
1.4 dnspython 的更多功能
dnspython 还可以管理DNS区域并执行更复杂的查询。如果你想了解更多示例,请参考官方文档: http://www.dnspython.org/ 以及 http://vallista.idyll.org/~grig/articles/ 。
2. 使用Python与OpenLDAP、Active Directory等进行LDAP操作
LDAP(Lightweight Directory Access Protocol)是大多数企业中常见的术语。Python的 python-ldap API支持与OpenLDAP和Active Directory进行通信。
2.1 安装 python-ldap
你需要从 http://python-ldap.sourceforge.net/download.shtml 下载该包。
2.2 探索 python-ldap 库
使用IPython进行交互式会话,尝试成功绑定到公共LDAP服务器和失败绑定的情况:
import ldap
l = ldap.open("ldap.itd.umich.edu")
l.simple_bind()
成功绑定的输出为:
Out[3]: 1
失败绑定的示例:
try:
l = ldap.open("127.0.0.1")
except Exception,err:
print err
l.simple_bind()
输出结果会显示 SERVER_DOWN 错误。
2.3 导入LDIF文件
以下是一个异步LDIF导入的示例:
import ldap
import ldap.modlist as modlist
ldif = "somefile.ldif"
def create():
l = ldap.initialize("ldaps://localhost:636/")
l.simple_bind_s("cn=manager,dc=example,dc=com","secret")
dn="cn=root,dc=example,dc=com"
rec = {}
rec['objectclass'] = ['top','organizationalRole','simpleSecurityObject']
rec['cn'] = 'root'
rec['userPassword'] = 'SecretHash'
rec['description'] = 'User object for replication using slurpd'
ldif = modlist.addModlist(attrs)
l.add_s(dn,ldif)
l.unbind_s()
这个示例首先初始化到本地LDAP服务器,然后创建一个对象类,用于在大规模异步导入LDIF文件时映射到LDAP数据库。
2.4 其他资源
关于使用 python-ldap 的更多信息,你可以参考前面提到的资源。此外,还有一个名为 web2ldap 的工具,它是由 python-ldap 的同一作者开发的基于Python的LDAP Web前端。你可以访问 http://www.web2ldap.de/ 获取官方文档。
3. Apache日志报告
目前,Apache是互联网上约50%域名使用的Web服务器。以下示例展示了如何对Apache日志文件进行报告。
3.1 脚本代码
#!/usr/bin/env python
from optparse import OptionParser
def open_files(files):
for f in files:
yield (f, open(f))
def combine_lines(files):
for f, f_obj in files:
for line in f_obj:
yield line
def obfuscate_ipaddr(addr):
return ".".join(str((int(n) / 10) * 10) for n in addr.split('.'))
if __name__ == '__main__':
parser = OptionParser()
parser.add_option("-c", "--consolidate", dest="consolidate", default=False,
action='store_true', help="consolidate log files")
parser.add_option("-r", "--regex", dest="regex", default=False,
action='store_true', help="use regex parser")
(options, args) = parser.parse_args()
logfiles = args
if options.regex:
from apache_log_parser_regex import generate_log_report
else:
from apache_log_parser_split import generate_log_report
opened_files = open_files(logfiles)
if options.consolidate:
opened_files = (('CONSOLIDATED', combine_lines(opened_files)),)
for filename, file_obj in opened_files:
print "*" * 60
print filename
print "-" * 60
print "%-20s%s" % ("IP ADDRESS", "BYTES TRANSFERRED")
print "-" * 60
report_dict = generate_log_report(file_obj)
for ip_addr, bytes in report_dict.items():
print "%-20s%s" % (obfuscate_ipaddr(ip_addr), sum(bytes))
print "=" * 60
3.2 脚本功能说明
-
open_files():一个生成器函数,接受文件名列表,为每个文件名生成一个包含文件名和对应打开文件对象的元组。 -
combine_lines():接受一个打开文件对象的可迭代对象,迭代每个文件的每一行并生成。 - 使用
optparse解析命令行参数,支持两个布尔参数:consolidate(合并日志文件)和regex(使用正则表达式解析器)。 - 根据参数选择使用不同的解析模块生成日志报告。
- 可以单独处理每个日志文件,也可以将日志文件合并生成一个单一报告。
3.3 脚本性能测试
在Ubuntu Gutsy服务器上对一个约1GB的文件进行测试:
- 使用正则表达式版本的脚本运行时间约为46秒。
- 使用 string.split() 版本的脚本运行时间约为34秒,但内存使用量高达约130MB。
3.4 低内存版本的解析库
#!/usr/bin/env python
def dictify_logline(line):
split_line = line.split()
return {'remote_host': split_line[0],
'status': split_line[8],
'bytes_sent': split_line[9],
}
def generate_log_report(logfile):
report_dict = {}
for line in logfile:
line_dict = dictify_logline(line)
host = line_dict['remote_host']
try:
bytes_sent = int(line_dict['bytes_sent'])
except ValueError:
continue
report_dict[host] = report_dict.setdefault(host, 0) + bytes_sent
return report_dict
这个版本的解析库在运行过程中累加字节数,而不是让调用函数进行累加。
3.5 修改后的脚本
#!/usr/bin/env python
from optparse import OptionParser
def open_files(files):
for f in files:
yield (f, open(f))
def combine_lines(files):
for f, f_obj in files:
for line in f_obj:
yield line
def obfuscate_ipaddr(addr):
return ".".join(str((int(n) / 10) * 10) for n in addr.split('.'))
if __name__ == '__main__':
parser = OptionParser()
parser.add_option("-c", "--consolidate", dest="consolidate", default=False,
action='store_true', help="consolidate log files")
parser.add_option("-r", "--regex", dest="regex", default=False,
action='store_true', help="use regex parser")
parser.add_option("-m", "--mem", dest="mem", default=False,
action='store_true', help="use mem parser")
(options, args) = parser.parse_args()
logfiles = args
if options.regex:
from apache_log_parser_regex import generate_log_report
elif options.mem:
from apache_log_parser_split_mem import generate_log_report
else:
from apache_log_parser_split import generate_log_report
opened_files = open_files(logfiles)
if options.consolidate:
opened_files = (('CONSOLIDATED', combine_lines(opened_files)),)
for filename, file_obj in opened_files:
print "*" * 60
print filename
print "-" * 60
print "%-20s%s" % ("IP ADDRESS", "BYTES TRANSFERRED")
print "-" * 60
report_dict = generate_log_report(file_obj)
for ip_addr, bytes in report_dict.items():
if options.mem:
print "%-20s%s" % (obfuscate_ipaddr(ip_addr), bytes)
else:
print "%-20s%s" % (obfuscate_ipaddr(ip_addr), sum(bytes))
print "=" * 60
运行这个修改后的脚本,耗时约30.508秒,内存使用量稳定在约4MB。该脚本每分钟可处理约2GB的日志文件。理论上,文件大小可以无限大,内存不会像之前的版本那样增长。不过,由于使用了字典,每个键是唯一的IP地址,内存使用量会随着唯一IP地址的增加而增长。如果内存消耗成为问题,可以使用持久数据库(如关系数据库或Berkeley DB)替换字典。
4. FTP镜像
这个示例展示了如何连接到FTP服务器并递归地从指定目录开始检索该服务器上的所有文件,还允许在检索文件后删除它们。
4.1 脚本代码
#!/usr/bin/env python
import ftplib
import os
class FTPSync(object):
def __init__(self, host, username, password, ftp_base_dir,
local_base_dir, delete=False):
self.host = host
self.username = username
self.password = password
self.ftp_base_dir = ftp_base_dir
self.local_base_dir = local_base_dir
self.delete = delete
self.conn = ftplib.FTP(host, username, password)
self.conn.cwd(ftp_base_dir)
try:
os.makedirs(local_base_dir)
except OSError:
pass
os.chdir(local_base_dir)
def get_dirs_files(self):
dir_res = []
self.conn.dir('.', dir_res.append)
files = [f.split(None, 8)[-1] for f in dir_res if f.startswith('-')]
dirs = [f.split(None, 8)[-1] for f in dir_res if f.startswith('d')]
return (files, dirs)
def walk(self, next_dir):
print "Walking to", next_dir
self.conn.cwd(next_dir)
try:
os.mkdir(next_dir)
except OSError:
pass
os.chdir(next_dir)
ftp_curr_dir = self.conn.pwd()
local_curr_dir = os.getcwd()
files, dirs = self.get_dirs_files()
print "FILES:", files
print "DIRS:", dirs
for f in files:
print next_dir, ':', f
outf = open(f, 'wb')
try:
self.conn.retrbinary('RETR %s' % f, outf.write)
finally:
outf.close()
if self.delete:
print "Deleting", f
self.conn.delete(f)
for d in dirs:
os.chdir(local_curr_dir)
self.conn.cwd(ftp_curr_dir)
self.walk(d)
def run(self):
self.walk('.')
if __name__ == '__main__':
from optparse import OptionParser
parser = OptionParser()
parser.add_option("-o", "--host", dest="host",
action='store', help="FTP host")
parser.add_option("-u", "--username", dest="username",
action='store', help="FTP username")
parser.add_option("-p", "--password", dest="password",
action='store', help="FTP password")
parser.add_option("-r", "--remote_dir", dest="remote_dir",
action='store', help="FTP remote starting directory")
parser.add_option("-l", "--local_dir", dest="local_dir",
action='store', help="Local starting directory")
parser.add_option("-d", "--delete", dest="delete", default=False,
action='store_true', help="use regex parser")
(options, args) = parser.parse_args()
f = FTPSync(options.host, options.username, options.password,
options.remote_dir, options.local_dir, options.delete)
f.run()
4.2 脚本功能说明
- 类
FTPSync: - 构造函数
__init__:接受多个参数,包括主机、用户名、密码、FTP基础目录、本地基础目录和删除标志。连接到指定的FTP服务器并登录,切换到指定的起始目录,尝试创建本地起始目录。 - 方法
get_dirs_files:确定当前目录中的文件和目录。通过查看目录列表每行的第一个字符来判断是文件还是目录。 - 方法
walk:递归地遍历目录。首先切换到指定目录,创建本地目录,获取当前目录中的文件和目录,下载文件并根据删除标志决定是否删除文件,然后递归调用自身处理子目录。 - 方法
run:调用walk方法并传入当前FTP目录。
4.3 脚本的错误处理
该脚本的错误和异常处理比较基础:
- 没有检查所有命令行参数,确保至少传入主机、用户名和密码。如果未指定这些参数,脚本会很快出错。
- 如果下载过程中出现异常,不会尝试再次下载文件,程序会终止。不过,这样做的好处是不会删除只下载了部分的文件。
4.4 流程图
graph TD;
A[开始] --> B[初始化FTPSync对象];
B --> C[连接到FTP服务器并登录];
C --> D[切换到FTP起始目录];
D --> E[尝试创建本地起始目录];
E --> F[调用walk方法];
F --> G[获取当前目录中的文件和目录];
G --> H{是否有文件};
H -- 是 --> I[下载文件];
I --> J{是否删除文件};
J -- 是 --> K[删除文件];
J -- 否 --> L[处理下一个文件];
H -- 否 --> M{是否有目录};
M -- 是 --> N[递归调用walk方法处理子目录];
M -- 否 --> O[结束];
L --> G;
K --> L;
N --> G;
通过以上这些实用示例,我们可以看到Python在DNS管理、LDAP操作、日志报告和FTP镜像等方面都有着强大的功能和广泛的应用。希望这些示例能帮助你更好地利用Python进行相关的开发和管理工作。
4.5 操作步骤总结
以下是使用该脚本进行FTP镜像操作的详细步骤:
1. 准备工作 :
- 确定FTP服务器的主机名、用户名、密码、远程起始目录和本地起始目录。
- 确保Python环境已安装,并且可以运行脚本。
2. 运行脚本 :
- 将上述脚本保存为一个Python文件,例如 ftp_mirror.py 。
- 打开终端,进入脚本所在的目录。
- 运行脚本并传入必要的参数,示例命令如下:
python ftp_mirror.py -o ftp.example.com -u username -p password -r /remote/dir -l /local/dir -d
- 参数说明:
- `-o`:指定FTP主机名。
- `-u`:指定FTP用户名。
- `-p`:指定FTP密码。
- `-r`:指定FTP远程起始目录。
- `-l`:指定本地起始目录。
- `-d`:可选参数,指定是否在下载文件后删除远程文件。
4.6 对比分析
为了更清晰地了解该脚本的特点,我们将其与 rsync 进行对比,如下表所示:
| 功能 | FTP镜像脚本 | rsync |
| ---- | ---- | ---- |
| 适用场景 | 当服务器未安装 rsync 或没有SSH、 rsync 访问权限时使用 | 服务器支持且有相应权限时优先使用 |
| 操作方式 | 通过Python脚本实现,可定制性高 | 命令行工具,操作相对简单 |
| 错误处理 | 基础的错误处理,部分异常会导致程序终止 | 有更完善的错误处理机制 |
| 功能特性 | 支持递归下载和删除文件 | 支持增量同步、文件权限和时间戳保留等 |
5. 总结与建议
5.1 总结
本文介绍了Python在多个实用场景中的应用,包括DNS管理、LDAP操作、Apache日志报告和FTP镜像。每个场景都有详细的代码示例和操作说明,具体总结如下:
- DNS管理 :使用 dnspython 模块可以方便地进行DNS查询和管理,支持对一组主机的A记录查询。
- LDAP操作 : python-ldap API允许与OpenLDAP和Active Directory进行通信,可实现简单绑定、LDIF文件导入等操作。
- Apache日志报告 :通过编写Python脚本,可以对Apache日志文件进行处理和报告,支持合并日志文件和不同的解析方式,还提供了低内存版本的解析库。
- FTP镜像 :使用 ftplib 库编写的脚本可以连接到FTP服务器,递归地下载文件,并可根据需要删除远程文件。
5.2 建议
- 学习与实践 :对于每个示例,建议读者亲自运行代码,理解其原理和实现方式。通过实践,可以更好地掌握Python在不同场景中的应用。
- 优化与扩展 :在实际应用中,可以根据具体需求对代码进行优化和扩展。例如,在Apache日志报告中,可以添加更多的统计信息;在FTP镜像脚本中,可以完善错误处理机制。
- 资源利用 :充分利用官方文档和相关资源,深入了解各个模块的功能和使用方法。例如,
dnspython和python-ldap的官方文档提供了更多的示例和详细的说明。
5.3 未来展望
随着技术的不断发展,Python在系统管理和网络编程领域的应用将越来越广泛。未来,我们可以期待更多的功能和工具被集成到现有的模块中,进一步提高开发效率和系统性能。同时,也可以探索将这些示例与其他技术结合,实现更复杂的应用场景。
5.4 流程图汇总
为了更直观地展示各个示例的流程,下面汇总了本文中涉及的流程图:
graph LR
classDef startend fill:#F5EBFF,stroke:#BE8FED,stroke-width:2px
classDef process fill:#E5F6FF,stroke:#73A6FF,stroke-width:2px
classDef decision fill:#FFF6CC,stroke:#FFBC52,stroke-width:2px
A([开始]):::startend --> B(DNS管理):::process
A --> C(LDAP操作):::process
A --> D(Apache日志报告):::process
A --> E(FTP镜像):::process
B --> B1(安装dnspython):::process
B --> B2(探索模块):::process
B --> B3(查询主机A记录):::process
B --> B4(更多功能探索):::process
C --> C1(安装python-ldap):::process
C --> C2(探索库):::process
C --> C3(导入LDIF文件):::process
C --> C4(其他资源利用):::process
D --> D1(编写脚本):::process
D --> D2(功能说明):::process
D --> D3(性能测试):::process
D --> D4(低内存版本):::process
D --> D5(修改脚本):::process
E --> E1(编写脚本):::process
E --> E2(功能说明):::process
E --> E3(错误处理):::process
E --> E4(操作步骤):::process
E --> E5(对比分析):::process
B4 --> F([结束]):::startend
C4 --> F
D5 --> F
E5 --> F
通过以上的总结和建议,希望读者能够更好地理解和应用这些Python示例,在实际工作中发挥它们的作用。同时,也鼓励读者不断探索和创新,将Python的强大功能应用到更多的场景中。
超级会员免费看
86

被折叠的 条评论
为什么被折叠?



