blob: 22e73431d256cbda8132268f82404de8786b3ef7 [file] [log] [blame]
mblighe8819cd2008-02-15 16:48:40 +00001
2"""
3 Copyright (c) 2007 Jan-Klaas Kollhof
4
5 This file is part of jsonrpc.
6
7 jsonrpc is free software; you can redistribute it and/or modify
8 it under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
11
12 This software is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public License
18 along with this software; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20"""
21
Jakob Juelich1b22ff22014-09-18 16:02:49 -070022from django import conf as django_conf
23import os
mblighe8819cd2008-02-15 16:48:40 +000024import urllib2
Chris Masonef8b53062012-05-08 22:14:18 -070025from autotest_lib.client.common_lib import error as exceptions
mblighe8819cd2008-02-15 16:48:40 +000026
Jakob Juelich1b22ff22014-09-18 16:02:49 -070027from json import decoder
28
29
30# The serializers can't be imported if django isn't configured.
31# Using try except here doesn't work, as test_that initializes it's own
32# django environment (setup_django_lite_environment) which raises import errors
33# if the django dbutils have been previously imported, as importing them leaves
34# some state behind.
35# This the variable name must not be undefined or emtpy string.
36if os.environ.get(django_conf.ENVIRONMENT_VARIABLE, None):
37 # Django JSON encoder uses the standard json encoder but can handle DateTime
38 from django.core.serializers import json as django_encoder
39 json_encoder_class = django_encoder.DjangoJSONEncoder
40else:
41 from json import encoder as json_encoder
42 json_encoder_class = json_encoder.JSONEncoder
43
44
mblighe8819cd2008-02-15 16:48:40 +000045class JSONRPCException(Exception):
46 pass
47
Chris Masone47c9e642012-04-25 14:22:18 -070048class ValidationError(JSONRPCException):
49 """Raised when the RPC is malformed."""
50 def __init__(self, error, formatted_message):
51 """Constructor.
52
53 @param error: a dict of error info like so:
54 {error['name']: 'ErrorKind',
55 error['message']: 'Pithy error description.',
56 error['traceback']: 'Multi-line stack trace'}
57 @formatted_message: string representation of this exception.
58 """
59 self.problem_keys = eval(error['message'])
60 self.traceback = error['traceback']
61 super(ValidationError, self).__init__(formatted_message)
62
63def BuildException(error):
64 """Exception factory.
65
66 Given a dict of error info, determine which subclass of
67 JSONRPCException to build and return. If can't determine the right one,
68 just return a JSONRPCException with a pretty-printed error string.
69
70 @param error: a dict of error info like so:
71 {error['name']: 'ErrorKind',
72 error['message']: 'Pithy error description.',
73 error['traceback']: 'Multi-line stack trace'}
74 """
75 error_message = '%(name)s: %(message)s\n%(traceback)s' % error
76 for cls in JSONRPCException.__subclasses__():
77 if error['name'] == cls.__name__:
78 return cls(error, error_message)
Alex Miller4a193692013-08-21 13:59:01 -070079 for cls in (exceptions.CrosDynamicSuiteException.__subclasses__() +
80 exceptions.RPCException.__subclasses__()):
Chris Masonef8b53062012-05-08 22:14:18 -070081 if error['name'] == cls.__name__:
82 return cls(error_message)
Chris Masone47c9e642012-04-25 14:22:18 -070083 return JSONRPCException(error_message)
84
mblighe8819cd2008-02-15 16:48:40 +000085class ServiceProxy(object):
86 def __init__(self, serviceURL, serviceName=None, headers=None):
87 self.__serviceURL = serviceURL
88 self.__serviceName = serviceName
showard8e855a22008-04-15 17:32:20 +000089 self.__headers = headers or {}
mblighe8819cd2008-02-15 16:48:40 +000090
91 def __getattr__(self, name):
mblighd876f452008-12-03 15:09:17 +000092 if self.__serviceName is not None:
mblighe8819cd2008-02-15 16:48:40 +000093 name = "%s.%s" % (self.__serviceName, name)
94 return ServiceProxy(self.__serviceURL, name, self.__headers)
95
96 def __call__(self, *args, **kwargs):
Jakob Juelich1b22ff22014-09-18 16:02:49 -070097 postdata = json_encoder_class().encode({'method': self.__serviceName,
jadmanski08ff9ad2010-01-27 23:42:42 +000098 'params': args + (kwargs,),
Jakob Juelich1b22ff22014-09-18 16:02:49 -070099 'id': 'jsonrpc'})
jadmanski0afbb632008-06-06 21:10:57 +0000100 request = urllib2.Request(self.__serviceURL, data=postdata,
101 headers=self.__headers)
102 respdata = urllib2.urlopen(request).read()
103 try:
jadmanski08ff9ad2010-01-27 23:42:42 +0000104 resp = decoder.JSONDecoder().decode(respdata)
jadmanski0afbb632008-06-06 21:10:57 +0000105 except ValueError:
106 raise JSONRPCException('Error decoding JSON reponse:\n' + respdata)
mblighd876f452008-12-03 15:09:17 +0000107 if resp['error'] is not None:
Chris Masone47c9e642012-04-25 14:22:18 -0700108 raise BuildException(resp['error'])
jadmanski0afbb632008-06-06 21:10:57 +0000109 else:
110 return resp['result']