Change in vdsm[master]: add a jsonrpcSeverClient for jsonRPC Server functional test

shaohef at linux.vnet.ibm.com shaohef at linux.vnet.ibm.com
Tue Jan 22 15:37:42 UTC 2013


ShaoHe Feng has uploaded a new change for review.

Change subject: add a jsonrpcSeverClient for jsonRPC Server functional test
......................................................................

add a jsonrpcSeverClient for jsonRPC Server functional test

This jsonrpcSeverClient is easy to call the jsonRPC server.
And it is an example for user to call the jsonRPC server.

The jsonrpcSeverClient will parser the vdsmapi-schema.json.
It will generate the method of vdsm-api dynamically.

Then we can easy call the vdsm-api, refer to vdsm-api.html.
vdsm-api.html is in the vdsm doc path.

Some comments tell us how to call the vdsm-api at the end of
jsonrpcSeverClient.py

Change-Id: Ib081e26203638114d7d632489432a50eeea45dd4
Signed-off-by: ShaoHe Feng <shaohef at linux.vnet.ibm.com>
---
M tests/functional/Makefile.am
A tests/functional/jsonrpcSeverClient.py
2 files changed, 144 insertions(+), 0 deletions(-)


  git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/83/11283/1

diff --git a/tests/functional/Makefile.am b/tests/functional/Makefile.am
index 030242b..e3374e8 100644
--- a/tests/functional/Makefile.am
+++ b/tests/functional/Makefile.am
@@ -21,6 +21,7 @@
 vdsmfunctestsdir = ${vdsmtestsdir}/functional
 
 dist_vdsmfunctests_PYTHON = \
+	jsonrpcSeverClient.py \
 	momTests.py \
 	sosPluginTests.py \
 	xmlrpcTests.py \
diff --git a/tests/functional/jsonrpcSeverClient.py b/tests/functional/jsonrpcSeverClient.py
new file mode 100644
index 0000000..77af03b
--- /dev/null
+++ b/tests/functional/jsonrpcSeverClient.py
@@ -0,0 +1,143 @@
+#
+# Copyright 2012 Red Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA
+#
+# Refer to the README and COPYING files for full details of the license
+#
+
+import json
+import os
+import socket
+import ssl
+import struct
+import vdsmapi
+from functools import partial
+from contextlib import closing
+from vdsm.config import config
+from vdsm import constants
+
+
+class ConnectionError(Exception):
+    pass
+
+
+class ProtocolError(Exception):
+    pass
+
+
+class jsonRpcServerClient(object):
+
+    #TODO: spport ssl
+    def __init__(self, ip, port, certReq=False, tsPath=None):
+        self._ip = ip
+        self._port = port
+        self._tsPath = tsPath
+        self._Size = struct.Struct("!Q")
+        self._cert_reqs = ssl.CERT_REQUIRED if certReq else ssl.CERT_NONE
+        schema = os.path.join(constants.P_VDSM, 'vdsmapi-schema.json')
+        self._dynamicAttribute(schema)
+
+    def buildMessage(self, data):
+        msg = json.dumps(data)
+        msg = msg.encode('utf-8')
+        msize = self._Size.pack(len(msg))
+        resp = msize + msg
+        return resp
+
+    def _createRequest(self, method, reqId=None, params=()):
+        return {'jsonrpc': '2.0', "id": reqId, "method": method,
+                "params": params}
+
+    def sendMessage(self, msg):
+        with closing(socket.socket(socket.AF_INET,
+                                   socket.SOCK_STREAM)) as tcp_sock:
+            if self._cert_reqs == ssl.CERT_REQUIRED:
+                if self._tsPath is None:
+                    self._tsPath = config.get('vars', 'trust_store_path')
+                KEYFILE = self._tsPath + '/keys/vdsmkey.pem'
+                CERTFILE = self._tsPath + '/certs/vdsmcert.pem'
+                CACERT = self._tsPath + '/certs/cacert.pem'
+                sock = ssl.wrap_socket(tcp_sock,
+                                       keyfile=KEYFILE,
+                                       certfile=CERTFILE,
+                                       ca_certs=CACERT,
+                                       cert_reqs=self._cert_reqs)
+            else:
+                sock = tcp_sock
+            sock.settimeout(3)  # TBD timeout
+            try:
+                sock.connect((self._ip, self._port))
+            except socket.error as e:
+                raise ConnectionError("Unable to connect to server: %s", e)
+            try:
+                sock.sendall(msg)
+            except (socket.error, socket.timeout), e:
+                raise ProtocolError("Unable to send request: %s", e)
+            try:
+                data = sock.recv(self._Size.size)
+            except socket.error as e:
+                raise ProtocolError("Unable to read response length: %s", e)
+            if not data:
+                raise ProtocolError("No data received")
+            msgLen = self._Size.unpack(data)[0]
+            try:
+                data = sock.recv(msgLen)
+            except socket.error as e:
+                raise ProtocolError("Unable to read response body: %s", e)
+            if len(data) != msgLen:
+                raise ProtocolError("Response body length mismatch")
+            return json.loads(data)
+
+    def call(self, method, reqId=None, params=()):
+        msg = self.buildMessage(self._createRequest(method, reqId, params))
+        reply = self.sendMessage(msg)
+        return reply
+
+    def _dynamicAttribute(self, schema):
+        self.dynamicAttr = {}
+        with open(schema) as f:
+            symbols = vdsmapi.parse_schema(f)
+            for s in symbols:
+                if 'command' in s:
+                    className = s['command']['class']
+                    functionName = s['command']['name']
+                    if className not in self.dynamicAttr.keys():
+                        self.dynamicAttr[className] = []
+                    self.dynamicAttr[className].append(functionName)
+            for key, funs in self.dynamicAttr.items():
+                funDicts = {}
+                for fun in funs:
+                    method = ".".join((key, fun))
+                    funDicts[fun] = partial(self.call, method)
+                cls = type(key, (object,), funDicts)
+                setattr(self, key, cls())
+
+
+if __name__ == '__main__':
+    if not config.getboolean('vars', 'jsonrpc_enable'):
+        exit(1)
+
+    ip = "127.0.0.1"
+    port = config.getint('addresses', 'json_port')
+    rpcIns = jsonRpcServerClient(ip, port)
+
+    # test the RpcClient
+    # you can open vdsm-api.html by your browser, such as by firefox
+    # firefox /usr/share/doc/vdsm-*/vdsm-api.html
+    # vdsm-api.html is in the vdsm doc path.
+    # then can call the API show in vdsm-api.html as follow
+    print rpcIns.call("Host.getAllTasksInfo", 1)
+    print rpcIns.Host.getAllTasksInfo(1)


--
To view, visit http://gerrit.ovirt.org/11283
To unsubscribe, visit http://gerrit.ovirt.org/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: Ib081e26203638114d7d632489432a50eeea45dd4
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: ShaoHe Feng <shaohef at linux.vnet.ibm.com>


More information about the vdsm-patches mailing list