Statistics
| Branch: | Tag: | Revision:

root / commissioning / clients / http.py @ 9f1a1bd0

History | View | Annotate | Download (7.8 kB)

1 9f1a1bd0 Georgios D. Tsoukalas
#!/usr/bin/env python
2 9f1a1bd0 Georgios D. Tsoukalas
3 9f1a1bd0 Georgios D. Tsoukalas
from httplib import HTTPConnection, HTTPException
4 9f1a1bd0 Georgios D. Tsoukalas
from urlparse import urlparse
5 9f1a1bd0 Georgios D. Tsoukalas
from commissioning import Callpoint
6 9f1a1bd0 Georgios D. Tsoukalas
7 9f1a1bd0 Georgios D. Tsoukalas
import logging
8 9f1a1bd0 Georgios D. Tsoukalas
9 9f1a1bd0 Georgios D. Tsoukalas
from json import loads as json_loads, dumps as json_dumps
10 9f1a1bd0 Georgios D. Tsoukalas
11 9f1a1bd0 Georgios D. Tsoukalas
12 9f1a1bd0 Georgios D. Tsoukalas
def init_logger_file(name, level='DEBUG'):
13 9f1a1bd0 Georgios D. Tsoukalas
    logger = logging.getLogger(name)
14 9f1a1bd0 Georgios D. Tsoukalas
    handler = logging.FileHandler(name + '.log')
15 9f1a1bd0 Georgios D. Tsoukalas
    formatter = logging.Formatter('%(asctime)s %(levelname)s %(message)s')
16 9f1a1bd0 Georgios D. Tsoukalas
    handler.setFormatter(formatter)
17 9f1a1bd0 Georgios D. Tsoukalas
    logger.addHandler(handler)
18 9f1a1bd0 Georgios D. Tsoukalas
    level = getattr(logging, level, logging.DEBUG)
19 9f1a1bd0 Georgios D. Tsoukalas
    logger.setLevel(level)
20 9f1a1bd0 Georgios D. Tsoukalas
    return logger
21 9f1a1bd0 Georgios D. Tsoukalas
22 9f1a1bd0 Georgios D. Tsoukalas
def init_logger_stdout(name, level='DEBUG'):
23 9f1a1bd0 Georgios D. Tsoukalas
    logger = logging.getLogger(name)
24 9f1a1bd0 Georgios D. Tsoukalas
    from sys import stdout
25 9f1a1bd0 Georgios D. Tsoukalas
    handler = logging.StreamHandler(stdout)
26 9f1a1bd0 Georgios D. Tsoukalas
    formatter = logging.Formatter('%(asctime)s %(levelname)s %(message)s')
27 9f1a1bd0 Georgios D. Tsoukalas
    handler.setFormatter(formatter)
28 9f1a1bd0 Georgios D. Tsoukalas
    logger.addHandler(handler)
29 9f1a1bd0 Georgios D. Tsoukalas
    level = getattr(logging, level, logging.DEBUG)
30 9f1a1bd0 Georgios D. Tsoukalas
    logger.setLevel(level)
31 9f1a1bd0 Georgios D. Tsoukalas
    return logger
32 9f1a1bd0 Georgios D. Tsoukalas
33 9f1a1bd0 Georgios D. Tsoukalas
34 9f1a1bd0 Georgios D. Tsoukalas
class NULLConnection(object):
35 9f1a1bd0 Georgios D. Tsoukalas
36 9f1a1bd0 Georgios D. Tsoukalas
    def __init__(self, host, port):
37 9f1a1bd0 Georgios D. Tsoukalas
        self.host = host
38 9f1a1bd0 Georgios D. Tsoukalas
        self.port = port
39 9f1a1bd0 Georgios D. Tsoukalas
40 9f1a1bd0 Georgios D. Tsoukalas
    def request(self, *args):
41 9f1a1bd0 Georgios D. Tsoukalas
        return None
42 9f1a1bd0 Georgios D. Tsoukalas
43 9f1a1bd0 Georgios D. Tsoukalas
    def getresponse(self, *args):
44 9f1a1bd0 Georgios D. Tsoukalas
        return None
45 9f1a1bd0 Georgios D. Tsoukalas
46 9f1a1bd0 Georgios D. Tsoukalas
47 9f1a1bd0 Georgios D. Tsoukalas
class quota_holder_allocation(object):
48 9f1a1bd0 Georgios D. Tsoukalas
    client = None
49 9f1a1bd0 Georgios D. Tsoukalas
    serial = None
50 9f1a1bd0 Georgios D. Tsoukalas
51 9f1a1bd0 Georgios D. Tsoukalas
    def __init__(self, *allocations, **pre_allocations):
52 9f1a1bd0 Georgios D. Tsoukalas
        allocations = canonify_list_of_allocations(allocations)
53 9f1a1bd0 Georgios D. Tsoukalas
        pre_allocations = pre_allocations.items()
54 9f1a1bd0 Georgios D. Tsoukalas
        pre_allocations = [(name, pre, 0) for name, pre in pre_allocations]
55 9f1a1bd0 Georgios D. Tsoukalas
        pre_allocations = canonify_list_of_allocations(pre_allocations)
56 9f1a1bd0 Georgios D. Tsoukalas
        allocations.extend(pre_allocations)
57 9f1a1bd0 Georgios D. Tsoukalas
        self.allocations = allocations
58 9f1a1bd0 Georgios D. Tsoukalas
59 9f1a1bd0 Georgios D. Tsoukalas
        if self.client is None:
60 9f1a1bd0 Georgios D. Tsoukalas
            self.client = QuotaholderClient.instance()
61 9f1a1bd0 Georgios D. Tsoukalas
62 9f1a1bd0 Georgios D. Tsoukalas
    def __call__(self, func):
63 9f1a1bd0 Georgios D. Tsoukalas
        def wrapped(*args, **kw):
64 9f1a1bd0 Georgios D. Tsoukalas
            client = self.client
65 9f1a1bd0 Georgios D. Tsoukalas
            serial = client.get_provision(self.allocations)
66 9f1a1bd0 Georgios D. Tsoukalas
            try:
67 9f1a1bd0 Georgios D. Tsoukalas
                ret = func(*args, **kw)
68 9f1a1bd0 Georgios D. Tsoukalas
            except Exception:
69 9f1a1bd0 Georgios D. Tsoukalas
                client.recall_provision(serial)
70 9f1a1bd0 Georgios D. Tsoukalas
                raise
71 9f1a1bd0 Georgios D. Tsoukalas
            else:
72 9f1a1bd0 Georgios D. Tsoukalas
                client.commit_provision(serial)
73 9f1a1bd0 Georgios D. Tsoukalas
74 9f1a1bd0 Georgios D. Tsoukalas
            return ret
75 9f1a1bd0 Georgios D. Tsoukalas
76 9f1a1bd0 Georgios D. Tsoukalas
        return wrapped
77 9f1a1bd0 Georgios D. Tsoukalas
78 9f1a1bd0 Georgios D. Tsoukalas
    def __enter__(self):
79 9f1a1bd0 Georgios D. Tsoukalas
        self.serial = self.client.get_provision(self.allocations)
80 9f1a1bd0 Georgios D. Tsoukalas
81 9f1a1bd0 Georgios D. Tsoukalas
    def __exit__(self, exctype, exc, traceback):
82 9f1a1bd0 Georgios D. Tsoukalas
        serial = self.serial
83 9f1a1bd0 Georgios D. Tsoukalas
        client = self.client
84 9f1a1bd0 Georgios D. Tsoukalas
85 9f1a1bd0 Georgios D. Tsoukalas
        if exctype is None:
86 9f1a1bd0 Georgios D. Tsoukalas
            client.commit_provision(serial)
87 9f1a1bd0 Georgios D. Tsoukalas
        else:
88 9f1a1bd0 Georgios D. Tsoukalas
            client.recall_provision(serial)
89 9f1a1bd0 Georgios D. Tsoukalas
            raise
90 9f1a1bd0 Georgios D. Tsoukalas
91 9f1a1bd0 Georgios D. Tsoukalas
92 9f1a1bd0 Georgios D. Tsoukalas
class GenericHTTPClient(Callpoint):
93 9f1a1bd0 Georgios D. Tsoukalas
    """Synchronous http client for quota holder API"""
94 9f1a1bd0 Georgios D. Tsoukalas
95 9f1a1bd0 Georgios D. Tsoukalas
    appname = 'http'
96 9f1a1bd0 Georgios D. Tsoukalas
    _http_client = None
97 9f1a1bd0 Georgios D. Tsoukalas
    quota_holder_allocation = quota_holder_allocation
98 9f1a1bd0 Georgios D. Tsoukalas
99 9f1a1bd0 Georgios D. Tsoukalas
    def init_connection(self, connection):
100 9f1a1bd0 Georgios D. Tsoukalas
        self.url = connection
101 9f1a1bd0 Georgios D. Tsoukalas
102 9f1a1bd0 Georgios D. Tsoukalas
        class quota_holder_allocator_class(quota_holder_allocation):
103 9f1a1bd0 Georgios D. Tsoukalas
            client = self
104 9f1a1bd0 Georgios D. Tsoukalas
105 9f1a1bd0 Georgios D. Tsoukalas
        self.quota_holder_allocation = quota_holder_allocator_class
106 9f1a1bd0 Georgios D. Tsoukalas
        self.logger = logging.getLogger(self.appname)
107 9f1a1bd0 Georgios D. Tsoukalas
108 9f1a1bd0 Georgios D. Tsoukalas
    @classmethod
109 9f1a1bd0 Georgios D. Tsoukalas
    def instance(cls):
110 9f1a1bd0 Georgios D. Tsoukalas
        client = cls._http_client
111 9f1a1bd0 Georgios D. Tsoukalas
        if client is None:
112 9f1a1bd0 Georgios D. Tsoukalas
            url = "http://127.0.0.1:8000/%s/%s" % (cls.appname, cls.version)
113 9f1a1bd0 Georgios D. Tsoukalas
            client = cls(url)
114 9f1a1bd0 Georgios D. Tsoukalas
            self._http_client = client
115 9f1a1bd0 Georgios D. Tsoukalas
116 9f1a1bd0 Georgios D. Tsoukalas
        return client
117 9f1a1bd0 Georgios D. Tsoukalas
118 9f1a1bd0 Georgios D. Tsoukalas
    def commit(self):
119 9f1a1bd0 Georgios D. Tsoukalas
        return
120 9f1a1bd0 Georgios D. Tsoukalas
121 9f1a1bd0 Georgios D. Tsoukalas
    def rollback(self):
122 9f1a1bd0 Georgios D. Tsoukalas
        return
123 9f1a1bd0 Georgios D. Tsoukalas
124 9f1a1bd0 Georgios D. Tsoukalas
    def debug(self, fmt, *args):
125 9f1a1bd0 Georgios D. Tsoukalas
        self.logger.debug(fmt % args)
126 9f1a1bd0 Georgios D. Tsoukalas
127 9f1a1bd0 Georgios D. Tsoukalas
    def do_make_call(self, api_call, data):
128 9f1a1bd0 Georgios D. Tsoukalas
        url = urlparse(self.url)
129 9f1a1bd0 Georgios D. Tsoukalas
        scheme = url.scheme
130 9f1a1bd0 Georgios D. Tsoukalas
        Connection = HTTPConnection
131 9f1a1bd0 Georgios D. Tsoukalas
        if scheme == 'http':
132 9f1a1bd0 Georgios D. Tsoukalas
            port = 80
133 9f1a1bd0 Georgios D. Tsoukalas
        elif scheme == 'https':
134 9f1a1bd0 Georgios D. Tsoukalas
            port = 443
135 9f1a1bd0 Georgios D. Tsoukalas
        elif scheme == 'null':
136 9f1a1bd0 Georgios D. Tsoukalas
            Connection = NULLConnection
137 9f1a1bd0 Georgios D. Tsoukalas
        else:
138 9f1a1bd0 Georgios D. Tsoukalas
            raise ValueError("Unsupported scheme %s" % (scheme,))
139 9f1a1bd0 Georgios D. Tsoukalas
140 9f1a1bd0 Georgios D. Tsoukalas
        path = url.path.strip('/')
141 9f1a1bd0 Georgios D. Tsoukalas
        path = ('/' + path + '/' + api_call) if path else ('/' + api_Call)
142 9f1a1bd0 Georgios D. Tsoukalas
143 9f1a1bd0 Georgios D. Tsoukalas
        netloc = url.netloc.rsplit(':', 1)
144 9f1a1bd0 Georgios D. Tsoukalas
        netloclen = len(netloc)
145 9f1a1bd0 Georgios D. Tsoukalas
        if netloclen == 1:
146 9f1a1bd0 Georgios D. Tsoukalas
            host = netloc[0]
147 9f1a1bd0 Georgios D. Tsoukalas
        elif netloclen == 2:
148 9f1a1bd0 Georgios D. Tsoukalas
            host, port = netloc
149 9f1a1bd0 Georgios D. Tsoukalas
        else:
150 9f1a1bd0 Georgios D. Tsoukalas
            msg = "Unsupported network location type '%s'" % (netloc,)
151 9f1a1bd0 Georgios D. Tsoukalas
            raise ValueError(msg)
152 9f1a1bd0 Georgios D. Tsoukalas
153 9f1a1bd0 Georgios D. Tsoukalas
        self.debug("Connecting to %s:%s\n>>>", host, port)
154 9f1a1bd0 Georgios D. Tsoukalas
        conn = Connection(host, port)
155 9f1a1bd0 Georgios D. Tsoukalas
156 9f1a1bd0 Georgios D. Tsoukalas
        if (api_call.startswith('list') or
157 9f1a1bd0 Georgios D. Tsoukalas
            api_call.startswith('get') or
158 9f1a1bd0 Georgios D. Tsoukalas
            api_call.startswith('read')):
159 9f1a1bd0 Georgios D. Tsoukalas
160 9f1a1bd0 Georgios D. Tsoukalas
                method = 'GET'
161 9f1a1bd0 Georgios D. Tsoukalas
        else:
162 9f1a1bd0 Georgios D. Tsoukalas
                method = 'POST'
163 9f1a1bd0 Georgios D. Tsoukalas
164 9f1a1bd0 Georgios D. Tsoukalas
        json_data = self.json_dumps(data)
165 9f1a1bd0 Georgios D. Tsoukalas
        self.debug("%s %s\n%s\n<<<\n", method, path, json_data)
166 9f1a1bd0 Georgios D. Tsoukalas
167 9f1a1bd0 Georgios D. Tsoukalas
        req = conn.request(method, path, body=json_data)
168 9f1a1bd0 Georgios D. Tsoukalas
        resp = conn.getresponse()
169 9f1a1bd0 Georgios D. Tsoukalas
        self.debug(">>>\nStatus: %s", resp.status)
170 9f1a1bd0 Georgios D. Tsoukalas
171 9f1a1bd0 Georgios D. Tsoukalas
        for name, value in resp.getheaders():
172 9f1a1bd0 Georgios D. Tsoukalas
            self.debug("%s: %s", name, value)
173 9f1a1bd0 Georgios D. Tsoukalas
174 9f1a1bd0 Georgios D. Tsoukalas
        body = ''
175 9f1a1bd0 Georgios D. Tsoukalas
        while 1:
176 9f1a1bd0 Georgios D. Tsoukalas
            s = resp.read() 
177 9f1a1bd0 Georgios D. Tsoukalas
            if not s:
178 9f1a1bd0 Georgios D. Tsoukalas
                break
179 9f1a1bd0 Georgios D. Tsoukalas
            body += s
180 9f1a1bd0 Georgios D. Tsoukalas
181 9f1a1bd0 Georgios D. Tsoukalas
        self.debug("\n%s\n<<<\n", body)
182 9f1a1bd0 Georgios D. Tsoukalas
183 9f1a1bd0 Georgios D. Tsoukalas
        status = int(resp.status)
184 9f1a1bd0 Georgios D. Tsoukalas
        if status == 200:
185 9f1a1bd0 Georgios D. Tsoukalas
            if body:
186 9f1a1bd0 Georgios D. Tsoukalas
                body = json_loads(body)
187 9f1a1bd0 Georgios D. Tsoukalas
            return body
188 9f1a1bd0 Georgios D. Tsoukalas
        else:
189 9f1a1bd0 Georgios D. Tsoukalas
            return body
190 9f1a1bd0 Georgios D. Tsoukalas
191 9f1a1bd0 Georgios D. Tsoukalas
        raise IOError("Call Failed", str(resp.status))
192 9f1a1bd0 Georgios D. Tsoukalas
193 9f1a1bd0 Georgios D. Tsoukalas
API_Callpoint = GenericHTTPClient
194 9f1a1bd0 Georgios D. Tsoukalas
195 9f1a1bd0 Georgios D. Tsoukalas
196 9f1a1bd0 Georgios D. Tsoukalas
def main():
197 9f1a1bd0 Georgios D. Tsoukalas
    from sys import argv, stdout
198 9f1a1bd0 Georgios D. Tsoukalas
    from os.path import basename, expanduser
199 9f1a1bd0 Georgios D. Tsoukalas
    from time import time
200 9f1a1bd0 Georgios D. Tsoukalas
    from commissioning import get_callpoint
201 9f1a1bd0 Georgios D. Tsoukalas
202 9f1a1bd0 Georgios D. Tsoukalas
    progname = basename(argv[0])
203 9f1a1bd0 Georgios D. Tsoukalas
    if progname == 'http.py':
204 9f1a1bd0 Georgios D. Tsoukalas
        if len(argv) < 2:
205 9f1a1bd0 Georgios D. Tsoukalas
            usage = "./http.py <appname> <app args...>"
206 9f1a1bd0 Georgios D. Tsoukalas
            print(usage)
207 9f1a1bd0 Georgios D. Tsoukalas
            raise SystemExit
208 9f1a1bd0 Georgios D. Tsoukalas
209 9f1a1bd0 Georgios D. Tsoukalas
        argv = argv[1:]
210 9f1a1bd0 Georgios D. Tsoukalas
        progname = basename(argv[0])
211 9f1a1bd0 Georgios D. Tsoukalas
212 9f1a1bd0 Georgios D. Tsoukalas
    init_logger_stdout(progname)
213 9f1a1bd0 Georgios D. Tsoukalas
214 9f1a1bd0 Georgios D. Tsoukalas
    pointname = 'clients.' + progname
215 9f1a1bd0 Georgios D. Tsoukalas
    API_Callpoint = get_callpoint(pointname, automake='http')
216 9f1a1bd0 Georgios D. Tsoukalas
    api = API_Callpoint.api_spec
217 9f1a1bd0 Georgios D. Tsoukalas
218 9f1a1bd0 Georgios D. Tsoukalas
    usage = "API Calls:\n\n"
219 9f1a1bd0 Georgios D. Tsoukalas
220 9f1a1bd0 Georgios D. Tsoukalas
    for call_name in sorted(api.call_names()):
221 9f1a1bd0 Georgios D. Tsoukalas
        canonical = api.input_canonical(call_name)
222 9f1a1bd0 Georgios D. Tsoukalas
        argstring = canonical.tostring(multiline=1, showopts=0)
223 9f1a1bd0 Georgios D. Tsoukalas
        usage += call_name + '.' + argstring + '\n\n'
224 9f1a1bd0 Georgios D. Tsoukalas
225 9f1a1bd0 Georgios D. Tsoukalas
    import argparse
226 9f1a1bd0 Georgios D. Tsoukalas
    parser = argparse.ArgumentParser    (
227 9f1a1bd0 Georgios D. Tsoukalas
            formatter_class =   argparse.RawDescriptionHelpFormatter,
228 9f1a1bd0 Georgios D. Tsoukalas
            description     =   "%s http client" % (progname,),
229 9f1a1bd0 Georgios D. Tsoukalas
            epilog          =   usage,
230 9f1a1bd0 Georgios D. Tsoukalas
    )
231 9f1a1bd0 Georgios D. Tsoukalas
232 9f1a1bd0 Georgios D. Tsoukalas
    urlhelp = 'set %s server base url' % (progname,)
233 9f1a1bd0 Georgios D. Tsoukalas
    parser.add_argument('--url', type=str, dest='url',
234 9f1a1bd0 Georgios D. Tsoukalas
                        action='store', help=urlhelp)
235 9f1a1bd0 Georgios D. Tsoukalas
236 9f1a1bd0 Georgios D. Tsoukalas
    jsonhelp = 'intepret data as json'
237 9f1a1bd0 Georgios D. Tsoukalas
    parser.add_argument('--json', dest='json_data', action='store_false',
238 9f1a1bd0 Georgios D. Tsoukalas
                        default=True, help=jsonhelp)
239 9f1a1bd0 Georgios D. Tsoukalas
240 9f1a1bd0 Georgios D. Tsoukalas
    callhelp = 'api call to perform'
241 9f1a1bd0 Georgios D. Tsoukalas
    parser.add_argument('api_call', type=str, action='store', nargs=1,
242 9f1a1bd0 Georgios D. Tsoukalas
                        help=callhelp)
243 9f1a1bd0 Georgios D. Tsoukalas
244 9f1a1bd0 Georgios D. Tsoukalas
    arghelp = 'data to provide to api call'
245 9f1a1bd0 Georgios D. Tsoukalas
    parser.add_argument('data', type=str, action='store', nargs='?',
246 9f1a1bd0 Georgios D. Tsoukalas
                        help=callhelp)
247 9f1a1bd0 Georgios D. Tsoukalas
248 9f1a1bd0 Georgios D. Tsoukalas
    urlfilepath = expanduser('~/.qholderrc')
249 9f1a1bd0 Georgios D. Tsoukalas
250 9f1a1bd0 Georgios D. Tsoukalas
    def get_url():
251 9f1a1bd0 Georgios D. Tsoukalas
        try:
252 9f1a1bd0 Georgios D. Tsoukalas
            with open(urlfilepath) as f:
253 9f1a1bd0 Georgios D. Tsoukalas
                url = f.read()
254 9f1a1bd0 Georgios D. Tsoukalas
        except Exception:
255 9f1a1bd0 Georgios D. Tsoukalas
            m = "Cannot load url from %s. Try --url." % (urlfilepath,)
256 9f1a1bd0 Georgios D. Tsoukalas
            raise ValueError(m)
257 9f1a1bd0 Georgios D. Tsoukalas
        return url
258 9f1a1bd0 Georgios D. Tsoukalas
259 9f1a1bd0 Georgios D. Tsoukalas
    def set_url(url):
260 9f1a1bd0 Georgios D. Tsoukalas
        url = url.strip('/')
261 9f1a1bd0 Georgios D. Tsoukalas
        with open(urlfilepath, "w") as f:
262 9f1a1bd0 Georgios D. Tsoukalas
            f.write(url)
263 9f1a1bd0 Georgios D. Tsoukalas
        print "Base URL set to '%s'" % (url,)
264 9f1a1bd0 Georgios D. Tsoukalas
265 9f1a1bd0 Georgios D. Tsoukalas
    args = parser.parse_args(argv[1:])
266 9f1a1bd0 Georgios D. Tsoukalas
267 9f1a1bd0 Georgios D. Tsoukalas
    api_call = args.api_call[0]
268 9f1a1bd0 Georgios D. Tsoukalas
    api.input_canonical(api_call)
269 9f1a1bd0 Georgios D. Tsoukalas
270 9f1a1bd0 Georgios D. Tsoukalas
    if args.url:
271 9f1a1bd0 Georgios D. Tsoukalas
        set_url(args.url)
272 9f1a1bd0 Georgios D. Tsoukalas
273 9f1a1bd0 Georgios D. Tsoukalas
    url = get_url()
274 9f1a1bd0 Georgios D. Tsoukalas
275 9f1a1bd0 Georgios D. Tsoukalas
    data = args.data
276 9f1a1bd0 Georgios D. Tsoukalas
277 9f1a1bd0 Georgios D. Tsoukalas
    if data == '-':
278 9f1a1bd0 Georgios D. Tsoukalas
        from sys import stdin
279 9f1a1bd0 Georgios D. Tsoukalas
        data = stdin.read()
280 9f1a1bd0 Georgios D. Tsoukalas
281 9f1a1bd0 Georgios D. Tsoukalas
    if not data:
282 9f1a1bd0 Georgios D. Tsoukalas
        data = None
283 9f1a1bd0 Georgios D. Tsoukalas
284 9f1a1bd0 Georgios D. Tsoukalas
    client = API_Callpoint(url)
285 9f1a1bd0 Georgios D. Tsoukalas
    print(client.make_call_from_json(api_call, data))
286 9f1a1bd0 Georgios D. Tsoukalas
287 9f1a1bd0 Georgios D. Tsoukalas
288 9f1a1bd0 Georgios D. Tsoukalas
if __name__ == '__main__':
289 9f1a1bd0 Georgios D. Tsoukalas
    main()