root / commissioning / clients / http.py @ 0c75cbf7
History | View | Annotate | Download (5.7 kB)
1 |
#!/usr/bin/env python
|
---|---|
2 |
|
3 |
from synnefo.lib.pool.http import get_http_connection |
4 |
from urlparse import urlparse |
5 |
from commissioning import Callpoint |
6 |
from commissioning.utils.clijson import clijson |
7 |
|
8 |
import logging |
9 |
|
10 |
from json import loads as json_loads, dumps as json_dumps |
11 |
|
12 |
_logger = None
|
13 |
|
14 |
def init_logger_file(name, level='DEBUG'): |
15 |
logger = logging.getLogger(name) |
16 |
handler = logging.FileHandler(name + '.log')
|
17 |
formatter = logging.Formatter('%(asctime)s %(levelname)s %(message)s')
|
18 |
handler.setFormatter(formatter) |
19 |
logger.addHandler(handler) |
20 |
level = getattr(logging, level, logging.DEBUG)
|
21 |
logger.setLevel(level) |
22 |
global _logger
|
23 |
_logger = logger |
24 |
return logger
|
25 |
|
26 |
def init_logger_stderr(name, level='DEBUG'): |
27 |
logger = logging.getLogger(name) |
28 |
from sys import stderr |
29 |
handler = logging.StreamHandler(stderr) |
30 |
formatter = logging.Formatter('%(asctime)s %(levelname)s %(message)s')
|
31 |
handler.setFormatter(formatter) |
32 |
logger.addHandler(handler) |
33 |
level = getattr(logging, level, logging.DEBUG)
|
34 |
logger.setLevel(level) |
35 |
global _logger
|
36 |
_logger = logger |
37 |
return logger
|
38 |
|
39 |
|
40 |
def debug(fmt, *args): |
41 |
global _logger
|
42 |
if _logger is None: |
43 |
init_logger_stderr('logger')
|
44 |
_logger.debug(fmt % args) |
45 |
|
46 |
|
47 |
class HTTP_API_Client(Callpoint): |
48 |
"""Synchronous http client for quota holder API"""
|
49 |
|
50 |
appname = 'http'
|
51 |
|
52 |
def init_connection(self, connection): |
53 |
self.url = connection
|
54 |
|
55 |
def commit(self): |
56 |
return
|
57 |
|
58 |
def rollback(self): |
59 |
return
|
60 |
|
61 |
def do_make_call(self, api_call, data): |
62 |
url = urlparse(self.url)
|
63 |
scheme = url.scheme |
64 |
path = url.path.strip('/')
|
65 |
path = ('/' + path + '/' + api_call) if path else ('/' + api_call) |
66 |
netloc = url.netloc |
67 |
|
68 |
conn = None
|
69 |
try:
|
70 |
debug("Connecting to %s\n>>>", netloc)
|
71 |
conn = get_http_connection(netloc=netloc, scheme=scheme) |
72 |
if (api_call.startswith('list') or |
73 |
api_call.startswith('get') or |
74 |
api_call.startswith('read')):
|
75 |
|
76 |
method = 'GET'
|
77 |
else:
|
78 |
method = 'POST'
|
79 |
|
80 |
json_data = self.json_dumps(data)
|
81 |
debug("%s %s\n%s\n<<<\n", method, path, json_data)
|
82 |
|
83 |
req = conn.request(method, path, body=json_data) |
84 |
resp = conn.getresponse() |
85 |
debug(">>>\nStatus: %s", resp.status)
|
86 |
|
87 |
for name, value in resp.getheaders(): |
88 |
debug("%s: %s", name, value)
|
89 |
|
90 |
body = ''
|
91 |
while 1: |
92 |
s = resp.read() |
93 |
if not s: |
94 |
break
|
95 |
body += s |
96 |
|
97 |
debug("\n%r\n<<<\n", body)
|
98 |
|
99 |
status = int(resp.status)
|
100 |
if status == 200: |
101 |
if body:
|
102 |
body = json_loads(body) |
103 |
return body
|
104 |
else:
|
105 |
return body
|
106 |
|
107 |
raise IOError("Call Failed", str(resp.status)) |
108 |
finally:
|
109 |
if conn is not None: |
110 |
conn.close() |
111 |
|
112 |
API_Callpoint = HTTP_API_Client |
113 |
|
114 |
|
115 |
def main(): |
116 |
from sys import argv, stdout |
117 |
from os.path import basename, expanduser |
118 |
from time import time |
119 |
from commissioning import get_callpoint |
120 |
|
121 |
progname = basename(argv[0])
|
122 |
h, s, t = progname.rpartition('.')
|
123 |
if t == 'py': |
124 |
progname = h |
125 |
|
126 |
if progname == 'http': |
127 |
if len(argv) < 2: |
128 |
usage = "./http <appname> <app args...>"
|
129 |
print(usage) |
130 |
raise SystemExit |
131 |
|
132 |
argv = argv[1:]
|
133 |
progname = basename(argv[0])
|
134 |
|
135 |
init_logger_stderr(progname) |
136 |
|
137 |
pointname = 'clients.' + progname
|
138 |
API_Callpoint = get_callpoint(pointname, automake='http')
|
139 |
api = API_Callpoint.api_spec |
140 |
|
141 |
usage = "API Calls:\n\n"
|
142 |
|
143 |
for call_name in sorted(api.call_names()): |
144 |
canonical = api.input_canonical(call_name) |
145 |
argstring = canonical.tostring(multiline=1, showopts=0) |
146 |
usage += call_name + '.' + argstring + '\n\n' |
147 |
|
148 |
import argparse |
149 |
parser = argparse.ArgumentParser ( |
150 |
formatter_class = argparse.RawDescriptionHelpFormatter, |
151 |
description = "%s http client" % (progname,),
|
152 |
epilog = usage, |
153 |
) |
154 |
|
155 |
urlhelp = 'set %s server base url' % (progname,)
|
156 |
parser.add_argument('--url', type=str, dest='url', |
157 |
action='store', help=urlhelp)
|
158 |
|
159 |
jsonhelp = 'intepret data as json'
|
160 |
parser.add_argument('--json', dest='json_data', action='store_false', |
161 |
default=True, help=jsonhelp)
|
162 |
|
163 |
callhelp = 'api call to perform'
|
164 |
parser.add_argument('api_call', type=str, action='store', nargs=1, |
165 |
help=callhelp) |
166 |
|
167 |
arghelp = 'data to provide to api call'
|
168 |
parser.add_argument('data', type=str, action='store', nargs='*', |
169 |
help=callhelp) |
170 |
|
171 |
urlfilepath = expanduser('~/.%s.urlrc' % progname)
|
172 |
|
173 |
def get_url(): |
174 |
try:
|
175 |
with open(urlfilepath) as f: |
176 |
url = f.read().strip() |
177 |
except Exception: |
178 |
m = "Cannot load url from %s. Try --url." % (urlfilepath,)
|
179 |
raise ValueError(m) |
180 |
return url
|
181 |
|
182 |
def set_url(url): |
183 |
url = url.strip('/')
|
184 |
with open(urlfilepath, "w") as f: |
185 |
f.write(url) |
186 |
print "Base URL set to '%s'" % (url,) |
187 |
|
188 |
args = parser.parse_args(argv[1:])
|
189 |
|
190 |
if args.url:
|
191 |
set_url(args.url) |
192 |
|
193 |
api_call = args.api_call[0]
|
194 |
api.input_canonical(api_call) |
195 |
|
196 |
url = get_url() |
197 |
|
198 |
data = args.data |
199 |
if data:
|
200 |
if data[0] == '-': |
201 |
from sys import stdin |
202 |
data = stdin.read() |
203 |
else:
|
204 |
data = clijson(data) |
205 |
|
206 |
if not data: |
207 |
data = None
|
208 |
|
209 |
client = API_Callpoint(url) |
210 |
print(client.make_call_from_json(api_call, data)) |
211 |
|
212 |
|
213 |
if __name__ == '__main__': |
214 |
main() |
215 |
|