当前位置: 首页 > 科技观察

Python自动化运维实践:从Linux系统收集数据

时间:2023-03-12 16:22:21 科技观察

使用Linux命令查看当前系统状态和运行情况的相关数据。但是,个别Linux命令和应用程序只能访问系统数据的某些方面。我们需要利用Python模块将这些详细信息反馈给管理员,并生成有用的系统报告。我们将报告分为两部分。第一部分是使用平台模块获取的一般系统信息,第二部分是硬件资源,如CPU和内存。首先导入平台模块,这是一个内置的Python库。平台模块中有许多方法可用于获取有关当前运行Python命令的操作系统的详细信息。importplatformsystem=platform.system()print(system)上面代码的结果如下。该脚本返回当前系统的类型,同一个脚本在Windows系统上运行会得到不同的结果。当它在Windows系统上运行时,输出变为Windows。常用函数uname()与linux命令(uname-a)功能相同:获取机器的hostname、architecture和kernel信息,但uname()采用结构化格式,使得对应的值可以被引用序列号。importplatformfrompprintimportpprintuname=platform.uname()pprint(uname)以上代码运行结果如下。system()方法获取的第一个值是系统类型,第二个是当前机器的主机名。使用PyCharm中的自动补全功能浏览并列出平台模块中所有可用的函数,按下Ctrl+Q组合键可以查看每个函数的文档(见下图)。然后,使用Linux文件提供的信息列出Linux机器中的硬件配置。请记住,/proc/目录提供了对CPU、内存和网络相关信息的访问;我们将读取此信息并使用Python中的标准open()函数访问它。有关详细信息,请参阅/proc/目录。具体脚本如下。首先,导入平台模块,该模块只在当前任务中使用。#!/usr/bin/python__author__="BassimAly"__EMAIL__="basim.alyy@gmail.com"importplatform然后定义函数。以下代码包含本练习所需的两个函数-check_feature()和get_value_from_string()。defcheck_feature(feature,string):iffeatureinstring.lower():returnTrueelse:returnFalsedefget_value_from_string(key,string):value="NONE"forlineinstring.split("\n"):ifkeyinline:value=line.split(":")[1.strip()返回值最后是Python脚本的主体部分,其中包含了用于获取所需信息的Python代码。cpu_features=[]withopen('/proc/cpuinfo')ascpus:cpu_data=cpus.read()num_of_cpus=cpu_data.count("processor")cpu_features.append("NumberofProcessors:{0}".format(num_of_cpus))one_processor_data=cpu_data.split("processor")[1]printone_processor_dataifcheck_feature("vmx",one_processor_data):cpu_features.append("CPUVirtualization:enabled")ifcheck_feature("cpu_meltdown",one_processor_data):cpu_features.append("KnownBugs:CPUMetldown")model_name=get_value_from_string("modelname",one_processor_data)cpu_features.append("ModelName:{0}".format(model_name))cpu_mhz=get_value_from_string("cpuMHz",one_processor_data)cpu_features.append("CPUMHz:{0}".format((cpu_mhz)))memory_features=[]withopen('/proc/meminfo')asmemory:memory_data=memory.read()total_memory=get_value_from_string("MemTotal",memory_data).replace("kB","")free_memory=get_value_from_string("MemFree",memory_data).replace("kB","")swap_memory=get_value_from_string("SwapTotal",memory_data).replace("kB","")total_memory_in_gb="TotalMemoryingGB:{0}".format(int(total_memory)/1024)free_memory_in_gb="FreeMemoryingGB:{0}".format(int(free_memory)/1024)swap_memory_in_gb="SWAPMemoryinGB:{0}".format(int(swap_memory)/1024)memory_features=[total_memory_in_gb,free_memory_in_gb,swap_memory_in_gb]这部分代码用于输出上一节代码得到的信息print("=============系统信息============")print("""系统类型:{0}主机名:{1}内核版本:{2}SystemVersion:{3}MachineArchitecture:{4}Pythonversion:{5}""".format(platform.system(),platform.uname()[1],platform.uname()[2],platform.version(),platform.machine(),platform.python_version()))print("=============CPUInformation===========")print("\n".join(cpu_features))print("=============内存信息============")print("\n".join(memory_features))在我们的示例中,我们完成了以下任务。(1)打开/proc/cpuinfo,读取其内容,将结果存入cpu_data。(2)用字符串函数count()统计文件中关键字处理器的个数,从而知道机器上有多少个处理器。(3)要获取每个处理器支持的选项和功能,我们只需要读取其中一个处理器的信息(因为通常所有处理器的属性都是一样的),并传递给check_feature()函数。该方法的一个参数是我们期望处理器支持的功能,另一个参数是处理器的属性信息。如果处理器的属性支持第一个参数指定的功能,则此方法返回True。(4)由于处理器的属性数据是以键值对的形式呈现的,我们设计了get_value_from_string()方法。该方法根据输入的键名,遍历处理器属性数据,查找对应的值,然后根据冒号拆分返回的键值对,得到值。(5)使用append()方法将所有值添加到cpu_feature列表中。(6)对内存信息重复同样的操作,得到总内存、空闲内存和交换内存的大小。(7)使用平台内置方法(如system()、uname()、python_version()等)获取系统相关信息。(8)输出包含上述信息的报告。脚本输出如下图所示。另一种呈现数据的方式是使用第5章介绍的Matplotlib库可视化随时间变化的数据。11.1.1 通过电子邮件发送收集的数据从上一节生成的报告中,您可以看到系统中的当前资源。在本节中,我们调整脚本并增强其功能,例如,通过电子邮件发送此信息。此功能对于网络运营中心(NOC)团队非常有用。他们希望受监控的系统在发生特定事件(如HDD故障、高CPU或数据包丢失)时自动向他们发送电子邮件。Python有一个内置库smtplib,它利用简单邮件传输协议(SMTP)从邮件服务器发送和接收电子邮件。使用此功能需要在计算机上安装本地电子邮件服务器,或者能够使用免费的在线电子邮件服务,例如Gmail或Outlook。在此示例中,我们将使用SMTP登录Gmail网站并通过电子邮件发送数据。接下来,开始修改脚本以向其添加SMTP功能。将所需模块导入Python,这次导入smtplib和平台。#!/usr/bin/python__author__="BassemAly"__EMAIL__="basim.alyy@gmail.com"importsmtplibimportplatform下面是check_feature()和get_value_from_string()这两个函数的代码。defcheck_feature(feature,string):iffeatureinstring.lower():returnTrueelse:returnFalsedefget_value_from_string(key,string):value="NONE"forlineinstring.split("\n"):ifkeyinline:value=line.split(":")[1.strip()returnvalue最后是Python脚本的主体,里面包含了获取所需信息的Python代码。cpu_features=[]withopen('/proc/cpuinfo')ascpus:cpu_data=cpus.read()num_of_cpus=cpu_data.count("processor")cpu_features.append("NumberofProcessors:{0}".format(num_of_cpus))one_processor_data=cpu_data.split("processor")[1]ifcheck_feature("vmx",one_processor_data):cpu_features.append("CPUVirtualization:enabled")ifcheck_feature("cpu_meltdown",one_processor_data):cpu_features.append("KnownBugs:CPUMetldown")model_name=get_value_from_string("modelname",one_processor_data)cpu_features.append("ModelName:{0}".format(model_name))cpu_mhz=get_value_from_string("cpuMHz",one_processor_data)cpu_features.append("CPUMHz:{0}".format((cpu_mhz)))memory_features=[]withopen('/proc/meminfo')asmemory:memory_data=memory.read()total_memory=get_value_from_string("MemTotal",memory_data).replace("kB","")free_memory=get_value_from_string("MemFree",memory_data).replace("kB","")swap_memory=get_value_from_string("SwapTotal",memory_data).replace("kB","")total_memory_in_gb="TotalMemoryinGB:{0}".format(int(total_memory)/1024)free_memory_in_gb="FreeMemoryinGB:{0}".format(int(free_memory)/1024)swap_memory_in_gb="SWAPMemoryinGB:{0}".format(int(swap_memory)/1024)memory_features=[total_memory_in_gb,free_gbmemory_in_in_,swap_memory_in_gb]Data_Sent_in_Email=""Header="""From:PythonEnterpriseAutomationBotTo:ToAdministratorSubject:MonitoringSystemReport"""Data_Sent_in_Email+=HeaderData_Sent_in_Email+="============SystemInformation============"Data_Sent_in_Email+="""SystemType:{0}主机名:{1}KernelVersion:{2}SystemVersion:{3}MachineArchitecture:{4}Python版本:{5}""".format(platform.system(),platform.uname()[1],platform.uname()[2],platform.version(),platform.machine(),platform.python_version())Data_Sent_in_Email+="============CPUInformation=============\n"Data_Sent_in_Email+="\n".join(cpu_features)Data_Sent_in_Email+="\n============MemoryInformation=============\n"Data_Sent_in_Email+="\n".join(memory_features)下面给出连接gmail服务器所需的信息fromaddr='yyyyyyyyyyy@gmail.com'toaddrs='basim.alyy@gmail.com'用户名='yyyyyyyyyyy@gmail.com'密码='xxxxxxxxxx'server=smtplib.SMTP('smtp.gmail.com:587')server.ehlo()server.starttls()server.login(username,password)server.sendmail(fromaddr,toaddrs,Data_Sent_in_Email)server.quit()实现了前面例子中的以下功能。(1)第一部分和前面的例子一样,只不过不是把数据输出到终端,而是添加到Data_Sent_in_Email变量中。(2)Header变量表示邮件标题,包括发件人地址、收件人地址和邮件主题。(3)使用smtplib模块中的SMTP()类连接到公共GmailSMTP服务器,完成TTLS连接。这也是连接到Gmail服务器的默认方法。我们将SMTP连接保存在服务器变量中。(4)使用login()方法登录服务器,最后使用sendmail()函数发送邮件。sendmail()有3个输入参数-发件人、收件人和电子邮件文本。(5)关闭与服务器的连接。脚本输出如下图所示。11.1.2 使用时间和日期模块到目前为止,我们已经能够通过电子邮件发送从服务器生成的自定义数据。但由于网络拥堵、邮件系统故障或其他问题,生成的数据与邮件的送达时间可能存在时间差,因此我们无法根据收到邮件的时间来估计实际生成数据的时间电子邮件。基于以上原因,需要使用Python中的datetime模块来获取被监控系统的当前时间。该模块可以使用年、月、日、小时和分钟等各种字段来格式化时间。另外,datetime模块中的datetime实例在Python中实际上是一个独立的对象(如int、string、boolean等),所以datetime实例在Python中有自己的属性。可以使用strftime()方法将日期时间对象转换为字符串。此方法使用下表中的格式符号来格式化时间。修改脚本以将下面的代码片段添加到代码中。fromdatetimeimportdatetimetime_now=datetime.now()time_now_string=time_now.strftime("%Y-%m-%d%H:%M:%S")Data_Sent_in_Email+="====TimeNowis{0}====\n".format(time_now_string)在此代码中,首先从日期时间模块导入日期时间类。然后使用datetime类和now()函数创建一个time_now对象,它返回系统的当前时间。最后使用带有格式化符号的strftime()对时间进行格式化,并转换为字符串输出(注意这个对象包含一个datetime对象)。脚本的输出如下。11.1.3 定期路由脚本在脚本的最后一步,设置运行脚本的时间间隔,可以是每天、每周、每小时或特定时间。该函数使用了Linux系统上的cron服务。cron用于安排定期重复发生的事件,例如,清理目录、备份数据库、转储日志或任何其他事件。使用以下命令查看当前的计划任务。crontab-l需要使用-e选项来编辑crontab。当您第一次运行cron时,系统会提示您选择您喜欢的编辑器(nano或vi)。典型的crontab由5颗星组成,每颗星代表一个时间条目(见下表)。如果您需要在每周五晚上9:00运行任务,您可以使用以下配置。021**5/path/to/command如果你需要在每天0:00运行某个命令(比如备份),使用这个配置。00***/path/to/command另外,你也可以让cron在特定的时间间隔运行。如果您需要每5分钟运行一次命令,则可以使用此配置。*/5****/path/to/command返回脚本,如果我们希望它在每天早上7:30运行,使用这个配置。307***/usr/bin/python/root/Send_Email.py最后记得在退出前保存cron配置。最好使用Linux命令的绝对路径而不是相对路径,以避免任何潜在的问题。