Python RPC 远程调用脚本之 RPyC 简介

最近有个监控需求,需要远程执行集群每个节点上的脚本,并获取脚本执行结果,为了安全起见不需要账号密码登陆节点主机,要求只需要调用远程脚本模块的方法就能实现。

总结下python进行远程调用脚本方法:

  • 登陆主机执行脚本,python模块支持如 pssh、pexpect、paramiko

  • 远程方法调用(不需要登陆主机),python模块 rpyc,支持分布式

  • socket 方式,稍显复杂,需要熟悉网络协议,起点比较高

rpyc支持远程调用、分布式计算,以较少代码量实现复杂socket编程,本文主要介绍 rpyc 并用它来实现一个 demo。

以代码方式介绍:

需求:分别执行集群每个节点上 server 端的脚本,并返回执行结果给 client 端

#Monitor_RPC_Client.py
...
hostDict = {'*.*.*.189': 12345, '*.*.*..188': 12345, '*.*.*..187': 12345}

class ProcessWorker(Thread):
    def __init__(self, queue):
        Thread.__init__(self)
        self.queue = queue

    def run(self):
        while True:
            host, port, localPath = self.queue.get()
            try:
                c = rpyc.connect(host, port)
                localFileSize = c.root.getLocalFileSize(localPath, glob30minAgo)
                localFileSizeDict[host] = localFileSize
                c.close()
            except Exception, e:
                print '{0} → {1}:{2} occur a Error:{3}\n'.format(self.getName(), host, port, e)

def getLocalSize(localPath):
    queue = Queue()
    for x in range(3):
        worker = ProcessWorker(queue)
        worker.daemon = True
        worker.start()
    for (host, port) in hostDict.items():
        queue.put((host, port, localPath))
    time.sleep(3)
    # queue.join()
...


#Monitor_RPC_Server.py
...
datePattern = re.compile(r'\d{4}(?:-\d{2}){4}')

def get_ip_address(ifname):
    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    return socket.inet_ntoa(fcntl.ioctl(
        s.fileno(),
        0x8915,  # SIOCGIFADDR
        struct.pack('256s', ifname[:15])
    )[20:24])

class remote_call_func(Service):

    def on_connect(self):
        print "[{0}]\t--------------<<< on_connect".format(getNowTime())

    def on_disconnect(self):
        print "[{0}]\t-------------->>> on_disconnect".format(getNowTime())


    def exposed_getLocalFileSize(self, path, glob30minAgo):
        exitCode, execResult = commands.getstatusoutput("ls -lrt " + path + "`|awk '{s+=$5}END{print s}'")
        dateTime30minAgo = (datetime.datetime.now() - datetime.timedelta(minutes=30)).strftime("%Y-%m-%d %H:%M:%S")
        print "[{0}] → {1} → {2}".format(dateTime30minAgo, path, format(execResult, ','))
        return execResult

rpycServer = ThreadedServer(remote_call_func, hostname=get_ip_address('eth0'), port=12345, auto_register=False)
rpycServer.start()

官方文档中类似例子很多,就不详细介绍了,需注意3点:

  • server端定义方法需要被client调用,必须定义以exposed 开头的方法,不然会报错AttributeError: ‘remote_call_script’ object has no attribute ‘exposed_iamshell’

  • server端默认不设认证机制,如果需要认证有推荐两种方法: ThreadedServer的authenticator参数与SSL模块

  • pip install rpyc ,如果 import rpyc 报错则 yum install openssl-devel,然后重新编译、安装 python

当然还需要考虑很多异常处理,如超时、验证失败等。

Refer:

[1] python远程调用脚本(一)

http://www.dbunix.com/?p=3262

http://rpyc.readthedocs.org/en/latest/tutorial.html

[2] python学习——python中执行shell命令

http://zhou123.blog.51cto.com/4355617/1312791

[3] celery实现任务统一收集、分发执行 

http://blog.csdn.net/vintage_1/article/details/47664187

你可能感兴趣的:(Python RPC 远程调用脚本之 RPyC 简介)