最近项目上遇到一个这样的场景:
在A服务器上,我有一个监控脚本monitor.py,可以用来监控远程服务器的资源消耗情况,比如CPU,内存,IO等信息。

输入参数为服务器名hostname或ip,比如执行

1
python monitor.py 198.111.11.11

即可输出该远程机器资源消耗信息

既然要获得远程服务器的资源占用情况,我的做法是事先在A服务器上生成我自己的公密钥对,然后把公钥复制到所有监控的服务器上。达到在monitor脚本中,从A服务器免密登录到所有其他监控机器的目的。既然登录到指定机器了,那获得资源消耗情况就很简单了,一个top命令,然后正则提取出来想要的信息。

现在的问题是:我要从前端一个的URL提交监控参数hostname,调用后端的监控脚本。这种情况下,监控脚本就不能正常工作了,为什么呢?来分析下流程:

前端提交URL,比如输入http://xxx.net/monitor.php?p=hostname,后端monitor.php脚本接收到hostname参数,执行了

1
exec(‘python monitor.py hostname’)

该代码执行跟在命令行中执行python monitor.py hostname是一样的,但却无法成功,因为这行代码的执行者,是服务器而不是我本人,如果你给apache服务器起的名字为daemon,那么执行monitor.py脚本的就是daemon,而我monitor里免密登录到远程机器,用的是我自己的账户,daemon用户是个虚拟的,远程机器根本就不存在这个用户,就算存在,你不知道daemon的密码,也是没法登录的,执行monitor会得到一个超时或者请输入daemon的密码之类的错误。这种方式是不可行。

其实这里,如果在apache配置文件中,把apache用户改为我自己的用户,也是可以的,但这样影响面就有点大,因为这会改变这台机器web目录中所有文件的所有者为你自己的名字,可能影响到其他用户涉及到权限的操作。

后来换了个思路,不直接从前端启动脚本,而是通过写文件的方式,我把前端的参数写入到一个文件里,然后监控这个文件的变化,如果文件有新内容写入,把内容提取出来,然后去执行monitor脚本,这样我在后端必须要在起一个监控脚本,该脚本在后台一直运行着,用来监测文件变化,一旦文件变化,就执行monitor,由于这个监控脚本是我本人执行的,那么最后monitor当然也就是我执行的,问题解决。
监控文件或目录变化,python中有个库,叫pyinotify,用法如下,代码一看就懂,不解释了

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
import os
from pyinotify import WatchManager, Notifier, ProcessEvent, IN_DELETE, IN_CREATE, IN_MODIFY

class EventHandler(ProcessEvent):
def process_IN_CREATE(self, event): #监控是否有文件创建,如果有,则进入该函数
print "Create file:%s." %os.path.join(event.path,event.name)
os.system('cp -rf %s /tmp/bak/'%(os.path.join(event.path,event.name)))
def process_IN_DELETE(self, event): #监控是否有文件被删除,如果有,则进入该函数
print "Delete file:%s." %os.path.join(event.path,event.name)
def process_IN_MODIFY(self, event): #监控是否有文件修改,如果有,则进入该函数
print "Modify file:%s." %os.path.join(event.path,event.name)
#监控文件变化,在这里执行monitor.py
with open('/home/zhangsan/monit') as f:
hostname = f.readlines()[-1]
order = 'python monitor.py %s' % hostname
os.system(order)

def FsMonitor(path='.'):
wm = WatchManager()
mask = IN_DELETE | IN_CREATE | IN_MODIFY
notifier = Notifier(wm, EventHandler())
wm.add_watch(path, mask, auto_add= True, rec=True)
print "now starting monitor %s." %path

while True:
try:
notifier.process_events()
if notifier.check_events():
print "check event true."
notifier.read_events()
except KeyboardInterrupt:
print "keyboard Interrupt."
notifier.stop()
break

if __name__ == "__main__":
FsMonitor("/home/zhangsan/") #监控该目录,若该目录文件有变化,比如创建,更改,删除,则会进入到相应处理事件