Statistics
| Branch: | Tag: | Revision:

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