Statistics
| Branch: | Tag: | Revision:

root / snf-cyclades-app / synnefo / tools / cloud.py @ 81e8cbf6

History | View | Annotate | Download (19.8 kB)

1 ab756200 Giorgos Verigakis
#!/usr/bin/env python
2 ab756200 Giorgos Verigakis
3 adee02b8 Giorgos Verigakis
# Copyright 2011 GRNET S.A. All rights reserved.
4 38d247df Kostas Papadimitriou
#
5 adee02b8 Giorgos Verigakis
# Redistribution and use in source and binary forms, with or
6 adee02b8 Giorgos Verigakis
# without modification, are permitted provided that the following
7 adee02b8 Giorgos Verigakis
# conditions are met:
8 38d247df Kostas Papadimitriou
#
9 adee02b8 Giorgos Verigakis
#   1. Redistributions of source code must retain the above
10 adee02b8 Giorgos Verigakis
#      copyright notice, this list of conditions and the following
11 adee02b8 Giorgos Verigakis
#      disclaimer.
12 38d247df Kostas Papadimitriou
#
13 adee02b8 Giorgos Verigakis
#   2. Redistributions in binary form must reproduce the above
14 adee02b8 Giorgos Verigakis
#      copyright notice, this list of conditions and the following
15 adee02b8 Giorgos Verigakis
#      disclaimer in the documentation and/or other materials
16 adee02b8 Giorgos Verigakis
#      provided with the distribution.
17 38d247df Kostas Papadimitriou
#
18 adee02b8 Giorgos Verigakis
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
19 adee02b8 Giorgos Verigakis
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 adee02b8 Giorgos Verigakis
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21 adee02b8 Giorgos Verigakis
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
22 adee02b8 Giorgos Verigakis
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 adee02b8 Giorgos Verigakis
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 adee02b8 Giorgos Verigakis
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
25 adee02b8 Giorgos Verigakis
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
26 adee02b8 Giorgos Verigakis
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 adee02b8 Giorgos Verigakis
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
28 adee02b8 Giorgos Verigakis
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 adee02b8 Giorgos Verigakis
# POSSIBILITY OF SUCH DAMAGE.
30 38d247df Kostas Papadimitriou
#
31 adee02b8 Giorgos Verigakis
# The views and conclusions contained in the software and
32 adee02b8 Giorgos Verigakis
# documentation are those of the authors and should not be
33 adee02b8 Giorgos Verigakis
# interpreted as representing official policies, either expressed
34 adee02b8 Giorgos Verigakis
# or implied, of GRNET S.A.
35 adee02b8 Giorgos Verigakis
36 fe29fb25 Giorgos Verigakis
from httplib import HTTPConnection, HTTPSConnection
37 ab756200 Giorgos Verigakis
from optparse import OptionParser
38 ab756200 Giorgos Verigakis
from os.path import basename
39 ab756200 Giorgos Verigakis
from sys import argv, exit
40 fe29fb25 Giorgos Verigakis
from urlparse import urlparse
41 ab756200 Giorgos Verigakis
42 ab756200 Giorgos Verigakis
import json
43 ab756200 Giorgos Verigakis
44 ab756200 Giorgos Verigakis
45 fe29fb25 Giorgos Verigakis
DEFAULT_API_URL = 'http://127.0.0.1:8000/api/v1.1'
46 40777cc8 Giorgos Verigakis
47 ebc913dc Giorgos Verigakis
MARGIN = 14
48 ab756200 Giorgos Verigakis
49 ab756200 Giorgos Verigakis
commands = {}
50 ab756200 Giorgos Verigakis
51 ab756200 Giorgos Verigakis
def command_name(name):
52 ab756200 Giorgos Verigakis
    def decorator(cls):
53 ab756200 Giorgos Verigakis
        commands[name] = cls
54 ab756200 Giorgos Verigakis
        return cls
55 ab756200 Giorgos Verigakis
    return decorator
56 ab756200 Giorgos Verigakis
57 ab756200 Giorgos Verigakis
58 d44c236b Giorgos Verigakis
def print_addresses(networks):
59 d44c236b Giorgos Verigakis
    for i, net in enumerate(networks):
60 ebc913dc Giorgos Verigakis
        key = 'addresses:'.rjust(MARGIN + 1) if i == 0 else ' ' * (MARGIN + 1)
61 d44c236b Giorgos Verigakis
        addr = ''
62 d44c236b Giorgos Verigakis
        if 'values' in net:
63 d44c236b Giorgos Verigakis
            addr = '[%s]' % ' '.join(ip['addr'] for ip in net['values'])
64 38d247df Kostas Papadimitriou
65 207b70d5 Giorgos Verigakis
        val = '%s/%s %s %s' % (net['id'], net['name'], net['mac'], addr)
66 46e42692 Giorgos Verigakis
        if 'firewallProfile' in net:
67 46e42692 Giorgos Verigakis
            val += ' - %s' % net['firewallProfile']
68 d44c236b Giorgos Verigakis
        print '%s %s' % (key, val)
69 ab756200 Giorgos Verigakis
70 ab756200 Giorgos Verigakis
def print_dict(d, show_empty=True):
71 ab756200 Giorgos Verigakis
    for key, val in sorted(d.items()):
72 ab756200 Giorgos Verigakis
        if key == 'metadata':
73 ab756200 Giorgos Verigakis
            val = ', '.join('%s="%s"' % x for x in val['values'].items())
74 0269afd6 Giorgos Verigakis
        elif key == 'addresses':
75 d44c236b Giorgos Verigakis
            print_addresses(val['values'])
76 d44c236b Giorgos Verigakis
            continue
77 0269afd6 Giorgos Verigakis
        elif key == 'servers':
78 0269afd6 Giorgos Verigakis
            val = ', '.join(str(server_id) for server_id in val['values'])
79 ab756200 Giorgos Verigakis
        if val or show_empty:
80 ebc913dc Giorgos Verigakis
            print '%s: %s' % (key.rjust(MARGIN), val)
81 ab756200 Giorgos Verigakis
82 ab756200 Giorgos Verigakis
83 ab756200 Giorgos Verigakis
class Command(object):
84 ab756200 Giorgos Verigakis
    def __init__(self, argv):
85 ab756200 Giorgos Verigakis
        parser = OptionParser()
86 fe29fb25 Giorgos Verigakis
        parser.add_option('--apiurl',
87 fe29fb25 Giorgos Verigakis
                            dest='apiurl',
88 fe29fb25 Giorgos Verigakis
                            metavar='URL',
89 fe29fb25 Giorgos Verigakis
                            default=DEFAULT_API_URL,
90 ab756200 Giorgos Verigakis
                            help='use api API')
91 fe29fb25 Giorgos Verigakis
        parser.add_option('--token',
92 fe29fb25 Giorgos Verigakis
                            dest='token',
93 fe29fb25 Giorgos Verigakis
                            metavar='TOKEN',
94 fe29fb25 Giorgos Verigakis
                            help='use user token TOKEN')
95 fe29fb25 Giorgos Verigakis
        parser.add_option('-v',
96 fe29fb25 Giorgos Verigakis
                            action='store_true',
97 fe29fb25 Giorgos Verigakis
                            dest='verbose',
98 fe29fb25 Giorgos Verigakis
                            default=False,
99 ab756200 Giorgos Verigakis
                            help='use verbose output')
100 ab756200 Giorgos Verigakis
        self.add_options(parser)
101 ab756200 Giorgos Verigakis
        options, args = parser.parse_args(argv)
102 38d247df Kostas Papadimitriou
103 ab756200 Giorgos Verigakis
        # Add options to self
104 ab756200 Giorgos Verigakis
        for opt in parser.option_list:
105 ab756200 Giorgos Verigakis
            key = opt.dest
106 ab756200 Giorgos Verigakis
            if key:
107 ab756200 Giorgos Verigakis
                val = getattr(options, key)
108 ab756200 Giorgos Verigakis
                setattr(self, key, val)
109 38d247df Kostas Papadimitriou
110 ab756200 Giorgos Verigakis
        self.execute(*args)
111 38d247df Kostas Papadimitriou
112 ab756200 Giorgos Verigakis
    def add_options(self, parser):
113 ab756200 Giorgos Verigakis
        pass
114 38d247df Kostas Papadimitriou
115 ab756200 Giorgos Verigakis
    def execute(self, *args):
116 ab756200 Giorgos Verigakis
        pass
117 38d247df Kostas Papadimitriou
118 ab756200 Giorgos Verigakis
    def http_cmd(self, method, path, body=None, expected_status=200):
119 fe29fb25 Giorgos Verigakis
        p = urlparse(self.apiurl)
120 fe29fb25 Giorgos Verigakis
        if p.scheme == 'https':
121 fe29fb25 Giorgos Verigakis
            conn = HTTPSConnection(p.netloc)
122 fe29fb25 Giorgos Verigakis
        else:
123 fe29fb25 Giorgos Verigakis
            conn = HTTPConnection(p.netloc)
124 ab756200 Giorgos Verigakis
125 ab756200 Giorgos Verigakis
        kwargs = {}
126 fe29fb25 Giorgos Verigakis
        kwargs['headers'] = {'X-Auth-Token': self.token}
127 ab756200 Giorgos Verigakis
        if body:
128 40777cc8 Giorgos Verigakis
            kwargs['headers']['Content-Type'] = 'application/json'
129 ab756200 Giorgos Verigakis
            kwargs['body'] = body
130 fe29fb25 Giorgos Verigakis
        conn.request(method, p.path + path, **kwargs)
131 ab756200 Giorgos Verigakis
132 ab756200 Giorgos Verigakis
        resp = conn.getresponse()
133 ab756200 Giorgos Verigakis
        if self.verbose:
134 ab756200 Giorgos Verigakis
            print '%d %s' % (resp.status, resp.reason)
135 ab756200 Giorgos Verigakis
            for key, val in resp.getheaders():
136 ab756200 Giorgos Verigakis
                print '%s: %s' % (key.capitalize(), val)
137 ab756200 Giorgos Verigakis
            print
138 ab756200 Giorgos Verigakis
139 ab756200 Giorgos Verigakis
        buf = resp.read() or '{}'
140 0269afd6 Giorgos Verigakis
        try:
141 0269afd6 Giorgos Verigakis
            reply = json.loads(buf)
142 0269afd6 Giorgos Verigakis
        except ValueError:
143 0269afd6 Giorgos Verigakis
            print 'Invalid response from the server.'
144 0269afd6 Giorgos Verigakis
            if self.verbose:
145 0269afd6 Giorgos Verigakis
                print buf
146 0269afd6 Giorgos Verigakis
            exit(1)
147 ab756200 Giorgos Verigakis
148 4cf8adf8 Vangelis Koukis
        # If the response status is not the expected one,
149 4cf8adf8 Vangelis Koukis
        # assume an error has occured and treat the body
150 4cf8adf8 Vangelis Koukis
        # as a cloudfault.
151 ab756200 Giorgos Verigakis
        if resp.status != expected_status:
152 ab756200 Giorgos Verigakis
            if len(reply) == 1:
153 ab756200 Giorgos Verigakis
                key = reply.keys()[0]
154 ab756200 Giorgos Verigakis
                val = reply[key]
155 d8e50a39 Giorgos Verigakis
                print '%s: %s' % (key, val.get('message', ''))
156 ab756200 Giorgos Verigakis
                if self.verbose:
157 ab756200 Giorgos Verigakis
                    print val.get('details', '')
158 0269afd6 Giorgos Verigakis
            else:
159 0269afd6 Giorgos Verigakis
                print 'Invalid response from the server.'
160 0269afd6 Giorgos Verigakis
            exit(1)
161 ab756200 Giorgos Verigakis
162 ab756200 Giorgos Verigakis
        return reply
163 ab756200 Giorgos Verigakis
164 ab756200 Giorgos Verigakis
    def http_get(self, path, expected_status=200):
165 ab756200 Giorgos Verigakis
        return self.http_cmd('GET', path, None, expected_status)
166 38d247df Kostas Papadimitriou
167 ab756200 Giorgos Verigakis
    def http_post(self, path, body, expected_status=202):
168 ab756200 Giorgos Verigakis
        return self.http_cmd('POST', path, body, expected_status)
169 ab756200 Giorgos Verigakis
170 ab756200 Giorgos Verigakis
    def http_put(self, path, body, expected_status=204):
171 ab756200 Giorgos Verigakis
        return self.http_cmd('PUT', path, body, expected_status)
172 ab756200 Giorgos Verigakis
173 ab756200 Giorgos Verigakis
    def http_delete(self, path, expected_status=204):
174 ab756200 Giorgos Verigakis
        return self.http_cmd('DELETE', path, None, expected_status)
175 ab756200 Giorgos Verigakis
176 ab756200 Giorgos Verigakis
177 ab756200 Giorgos Verigakis
@command_name('ls')
178 ab756200 Giorgos Verigakis
class ListServers(Command):
179 ab756200 Giorgos Verigakis
    description = 'list servers'
180 38d247df Kostas Papadimitriou
181 ab756200 Giorgos Verigakis
    def add_options(self, parser):
182 ab756200 Giorgos Verigakis
        parser.add_option('-l', action='store_true', dest='detail', default=False,
183 ab756200 Giorgos Verigakis
                            help='show detailed output')
184 ab756200 Giorgos Verigakis
        parser.add_option('-a', action='store_true', dest='show_empty', default=False,
185 ab756200 Giorgos Verigakis
                            help='include empty values')
186 38d247df Kostas Papadimitriou
187 ab756200 Giorgos Verigakis
    def execute(self):
188 fe29fb25 Giorgos Verigakis
        path = '/servers/detail' if self.detail else '/servers'
189 ab756200 Giorgos Verigakis
        reply = self.http_get(path)
190 ab756200 Giorgos Verigakis
191 ab756200 Giorgos Verigakis
        for server in reply['servers']['values']:
192 ab756200 Giorgos Verigakis
            id = server.pop('id')
193 ab756200 Giorgos Verigakis
            name = server.pop('name')
194 ab756200 Giorgos Verigakis
            if self.detail:
195 ab756200 Giorgos Verigakis
                print '%d %s' % (id, name)
196 ab756200 Giorgos Verigakis
                print_dict(server, self.show_empty)
197 ab756200 Giorgos Verigakis
                print
198 ab756200 Giorgos Verigakis
            else:
199 ab756200 Giorgos Verigakis
                print '%3d %s' % (id, name)
200 ab756200 Giorgos Verigakis
201 ab756200 Giorgos Verigakis
202 ab756200 Giorgos Verigakis
@command_name('info')
203 ab756200 Giorgos Verigakis
class GetServerDetails(Command):
204 ab756200 Giorgos Verigakis
    description = 'get server details'
205 ab756200 Giorgos Verigakis
    syntax = '<server id>'
206 38d247df Kostas Papadimitriou
207 ab756200 Giorgos Verigakis
    def add_options(self, parser):
208 ab756200 Giorgos Verigakis
        parser.add_option('-a', action='store_true', dest='show_empty', default=False,
209 ab756200 Giorgos Verigakis
                            help='include empty values')
210 38d247df Kostas Papadimitriou
211 ab756200 Giorgos Verigakis
    def execute(self, server_id):
212 fe29fb25 Giorgos Verigakis
        path = '/servers/%d' % int(server_id)
213 ab756200 Giorgos Verigakis
        reply = self.http_get(path)
214 ab756200 Giorgos Verigakis
        server = reply['server']
215 ab756200 Giorgos Verigakis
        server.pop('id')
216 ab756200 Giorgos Verigakis
        print_dict(server, self.show_empty)
217 38d247df Kostas Papadimitriou
218 ab756200 Giorgos Verigakis
219 ab756200 Giorgos Verigakis
@command_name('create')
220 ab756200 Giorgos Verigakis
class CreateServer(Command):
221 ab756200 Giorgos Verigakis
    description = 'create server'
222 ab756200 Giorgos Verigakis
    syntax = '<server name>'
223 38d247df Kostas Papadimitriou
224 ab756200 Giorgos Verigakis
    def add_options(self, parser):
225 ab756200 Giorgos Verigakis
        parser.add_option('-f', dest='flavor', metavar='FLAVOR_ID', default=1,
226 ab756200 Giorgos Verigakis
                            help='use flavor FLAVOR_ID')
227 ab756200 Giorgos Verigakis
        parser.add_option('-i', dest='image', metavar='IMAGE_ID', default=1,
228 ab756200 Giorgos Verigakis
                            help='use image IMAGE_ID')
229 38d247df Kostas Papadimitriou
230 ab756200 Giorgos Verigakis
    def execute(self, name):
231 fe29fb25 Giorgos Verigakis
        server = {
232 fe29fb25 Giorgos Verigakis
            'name': name,
233 fe29fb25 Giorgos Verigakis
            'flavorRef': self.flavor,
234 fe29fb25 Giorgos Verigakis
            'imageRef': self.image}
235 ab756200 Giorgos Verigakis
        body = json.dumps({'server': server})
236 fe29fb25 Giorgos Verigakis
        reply = self.http_post('/servers', body)
237 ab756200 Giorgos Verigakis
        server = reply['server']
238 ab756200 Giorgos Verigakis
        print_dict(server)
239 ab756200 Giorgos Verigakis
240 ab756200 Giorgos Verigakis
241 ab756200 Giorgos Verigakis
@command_name('rename')
242 ab756200 Giorgos Verigakis
class UpdateServerName(Command):
243 ab756200 Giorgos Verigakis
    description = 'update server name'
244 ab756200 Giorgos Verigakis
    syntax = '<server id> <new name>'
245 38d247df Kostas Papadimitriou
246 ab756200 Giorgos Verigakis
    def execute(self, server_id, name):
247 fe29fb25 Giorgos Verigakis
        path = '/servers/%d' % int(server_id)
248 ab756200 Giorgos Verigakis
        body = json.dumps({'server': {'name': name}})
249 ab756200 Giorgos Verigakis
        self.http_put(path, body)
250 ab756200 Giorgos Verigakis
251 ab756200 Giorgos Verigakis
252 ab756200 Giorgos Verigakis
@command_name('delete')
253 ab756200 Giorgos Verigakis
class DeleteServer(Command):
254 ab756200 Giorgos Verigakis
    description = 'delete server'
255 ab756200 Giorgos Verigakis
    syntax = '<server id>'
256 38d247df Kostas Papadimitriou
257 ab756200 Giorgos Verigakis
    def execute(self, server_id):
258 fe29fb25 Giorgos Verigakis
        path = '/servers/%d' % int(server_id)
259 ab756200 Giorgos Verigakis
        self.http_delete(path)
260 ab756200 Giorgos Verigakis
261 ab756200 Giorgos Verigakis
262 ab756200 Giorgos Verigakis
@command_name('reboot')
263 ab756200 Giorgos Verigakis
class RebootServer(Command):
264 ab756200 Giorgos Verigakis
    description = 'reboot server'
265 ab756200 Giorgos Verigakis
    syntax = '<server id>'
266 38d247df Kostas Papadimitriou
267 ab756200 Giorgos Verigakis
    def add_options(self, parser):
268 ab756200 Giorgos Verigakis
        parser.add_option('-f', action='store_true', dest='hard', default=False,
269 ab756200 Giorgos Verigakis
                            help='perform a hard reboot')
270 38d247df Kostas Papadimitriou
271 ab756200 Giorgos Verigakis
    def execute(self, server_id):
272 fe29fb25 Giorgos Verigakis
        path = '/servers/%d/action' % int(server_id)
273 ab756200 Giorgos Verigakis
        type = 'HARD' if self.hard else 'SOFT'
274 ab756200 Giorgos Verigakis
        body = json.dumps({'reboot': {'type': type}})
275 ab756200 Giorgos Verigakis
        self.http_post(path, body)
276 38d247df Kostas Papadimitriou
277 ab756200 Giorgos Verigakis
278 ab756200 Giorgos Verigakis
@command_name('start')
279 ab756200 Giorgos Verigakis
class StartServer(Command):
280 ab756200 Giorgos Verigakis
    description = 'start server'
281 ab756200 Giorgos Verigakis
    syntax = '<server id>'
282 38d247df Kostas Papadimitriou
283 ab756200 Giorgos Verigakis
    def execute(self, server_id):
284 fe29fb25 Giorgos Verigakis
        path = '/servers/%d/action' % int(server_id)
285 ab756200 Giorgos Verigakis
        body = json.dumps({'start': {}})
286 ab756200 Giorgos Verigakis
        self.http_post(path, body)
287 ab756200 Giorgos Verigakis
288 ab756200 Giorgos Verigakis
289 ab756200 Giorgos Verigakis
@command_name('shutdown')
290 ab756200 Giorgos Verigakis
class StartServer(Command):
291 ab756200 Giorgos Verigakis
    description = 'shutdown server'
292 ab756200 Giorgos Verigakis
    syntax = '<server id>'
293 38d247df Kostas Papadimitriou
294 ab756200 Giorgos Verigakis
    def execute(self, server_id):
295 fe29fb25 Giorgos Verigakis
        path = '/servers/%d/action' % int(server_id)
296 ab756200 Giorgos Verigakis
        body = json.dumps({'shutdown': {}})
297 ab756200 Giorgos Verigakis
        self.http_post(path, body)
298 ab756200 Giorgos Verigakis
299 ab756200 Giorgos Verigakis
300 09471611 Vangelis Koukis
@command_name('console')
301 09471611 Vangelis Koukis
class ServerConsole(Command):
302 09471611 Vangelis Koukis
    description = 'get VNC console'
303 09471611 Vangelis Koukis
    syntax = '<server id>'
304 38d247df Kostas Papadimitriou
305 09471611 Vangelis Koukis
    def execute(self, server_id):
306 fe29fb25 Giorgos Verigakis
        path = '/servers/%d/action' % int(server_id)
307 529178b1 Giorgos Verigakis
        body = json.dumps({'console': {'type': 'vnc'}})
308 4cf8adf8 Vangelis Koukis
        reply = self.http_cmd('POST', path, body, 200)
309 529178b1 Giorgos Verigakis
        print_dict(reply['console'])
310 09471611 Vangelis Koukis
311 09471611 Vangelis Koukis
312 91826390 Giorgos Verigakis
@command_name('profile')
313 91826390 Giorgos Verigakis
class SetFirewallProfile(Command):
314 91826390 Giorgos Verigakis
    description = 'set the firewall profile'
315 91826390 Giorgos Verigakis
    syntax = '<server id> <profile>'
316 38d247df Kostas Papadimitriou
317 91826390 Giorgos Verigakis
    def execute(self, server_id, profile):
318 fe29fb25 Giorgos Verigakis
        path = '/servers/%d/action' % int(server_id)
319 91826390 Giorgos Verigakis
        body = json.dumps({'firewallProfile': {'profile': profile}})
320 91826390 Giorgos Verigakis
        self.http_cmd('POST', path, body, 202)
321 91826390 Giorgos Verigakis
322 91826390 Giorgos Verigakis
323 ab756200 Giorgos Verigakis
@command_name('lsaddr')
324 ab756200 Giorgos Verigakis
class ListAddresses(Command):
325 ab756200 Giorgos Verigakis
    description = 'list server addresses'
326 ab756200 Giorgos Verigakis
    syntax = '<server id> [network]'
327 38d247df Kostas Papadimitriou
328 ab756200 Giorgos Verigakis
    def execute(self, server_id, network=None):
329 fe29fb25 Giorgos Verigakis
        path = '/servers/%d/ips' % int(server_id)
330 ab756200 Giorgos Verigakis
        if network:
331 ab756200 Giorgos Verigakis
            path += '/%s' % network
332 ab756200 Giorgos Verigakis
        reply = self.http_get(path)
333 38d247df Kostas Papadimitriou
334 ab756200 Giorgos Verigakis
        addresses = [reply['network']] if network else reply['addresses']['values']
335 d44c236b Giorgos Verigakis
        print_addresses(addresses)
336 ab756200 Giorgos Verigakis
337 ab756200 Giorgos Verigakis
338 ab756200 Giorgos Verigakis
@command_name('lsflv')
339 ab756200 Giorgos Verigakis
class ListFlavors(Command):
340 ab756200 Giorgos Verigakis
    description = 'list flavors'
341 38d247df Kostas Papadimitriou
342 ab756200 Giorgos Verigakis
    def add_options(self, parser):
343 ab756200 Giorgos Verigakis
        parser.add_option('-l', action='store_true', dest='detail', default=False,
344 ab756200 Giorgos Verigakis
                            help='show detailed output')
345 38d247df Kostas Papadimitriou
346 ab756200 Giorgos Verigakis
    def execute(self):
347 fe29fb25 Giorgos Verigakis
        path = '/flavors/detail' if self.detail else '/flavors'
348 ab756200 Giorgos Verigakis
        reply = self.http_get(path)
349 38d247df Kostas Papadimitriou
350 ab756200 Giorgos Verigakis
        for flavor in reply['flavors']['values']:
351 ab756200 Giorgos Verigakis
            id = flavor.pop('id')
352 ab756200 Giorgos Verigakis
            name = flavor.pop('name')
353 ab756200 Giorgos Verigakis
            details = ' '.join('%s=%s' % item for item in sorted(flavor.items()))
354 ab756200 Giorgos Verigakis
            print '%3d %s %s' % (id, name, details)
355 ab756200 Giorgos Verigakis
356 ab756200 Giorgos Verigakis
357 d8e50a39 Giorgos Verigakis
@command_name('flvinfo')
358 ab756200 Giorgos Verigakis
class GetFlavorDetails(Command):
359 ab756200 Giorgos Verigakis
    description = 'get flavor details'
360 ab756200 Giorgos Verigakis
    syntax = '<flavor id>'
361 38d247df Kostas Papadimitriou
362 ab756200 Giorgos Verigakis
    def execute(self, flavor_id):
363 fe29fb25 Giorgos Verigakis
        path = '/flavors/%d' % int(flavor_id)
364 ab756200 Giorgos Verigakis
        reply = self.http_get(path)
365 38d247df Kostas Papadimitriou
366 ab756200 Giorgos Verigakis
        flavor = reply['flavor']
367 ab756200 Giorgos Verigakis
        id = flavor.pop('id')
368 ab756200 Giorgos Verigakis
        name = flavor.pop('name')
369 ab756200 Giorgos Verigakis
        details = ' '.join('%s=%s' % item for item in sorted(flavor.items()))
370 ab756200 Giorgos Verigakis
        print '%3d %s %s' % (id, name, details)
371 ab756200 Giorgos Verigakis
372 ab756200 Giorgos Verigakis
373 ab756200 Giorgos Verigakis
@command_name('lsimg')
374 ab756200 Giorgos Verigakis
class ListImages(Command):
375 ab756200 Giorgos Verigakis
    description = 'list images'
376 38d247df Kostas Papadimitriou
377 ab756200 Giorgos Verigakis
    def add_options(self, parser):
378 ab756200 Giorgos Verigakis
        parser.add_option('-l', action='store_true', dest='detail', default=False,
379 ab756200 Giorgos Verigakis
                            help='show detailed output')
380 38d247df Kostas Papadimitriou
381 ab756200 Giorgos Verigakis
    def execute(self):
382 fe29fb25 Giorgos Verigakis
        path = '/images/detail' if self.detail else '/images'
383 ab756200 Giorgos Verigakis
        reply = self.http_get(path)
384 38d247df Kostas Papadimitriou
385 ab756200 Giorgos Verigakis
        for image in reply['images']['values']:
386 ab756200 Giorgos Verigakis
            id = image.pop('id')
387 ab756200 Giorgos Verigakis
            name = image.pop('name')
388 ab756200 Giorgos Verigakis
            if self.detail:
389 ab756200 Giorgos Verigakis
                print '%d %s' % (id, name)
390 ab756200 Giorgos Verigakis
                print_dict(image)
391 ab756200 Giorgos Verigakis
                print
392 ab756200 Giorgos Verigakis
            else:
393 b19653d1 Giorgos Verigakis
                print '%3d %s' % (id, name)
394 ab756200 Giorgos Verigakis
395 ab756200 Giorgos Verigakis
396 ab756200 Giorgos Verigakis
@command_name('imginfo')
397 ab756200 Giorgos Verigakis
class GetImageDetails(Command):
398 ab756200 Giorgos Verigakis
    description = 'get image details'
399 ab756200 Giorgos Verigakis
    syntax = '<image id>'
400 38d247df Kostas Papadimitriou
401 ab756200 Giorgos Verigakis
    def execute(self, image_id):
402 fe29fb25 Giorgos Verigakis
        path = '/images/%d' % int(image_id)
403 ab756200 Giorgos Verigakis
        reply = self.http_get(path)
404 ab756200 Giorgos Verigakis
        image = reply['image']
405 ab756200 Giorgos Verigakis
        image.pop('id')
406 ab756200 Giorgos Verigakis
        print_dict(image)
407 ab756200 Giorgos Verigakis
408 ab756200 Giorgos Verigakis
409 ab756200 Giorgos Verigakis
@command_name('createimg')
410 ab756200 Giorgos Verigakis
class CreateImage(Command):
411 ab756200 Giorgos Verigakis
    description = 'create image'
412 ab756200 Giorgos Verigakis
    syntax = '<server id> <image name>'
413 38d247df Kostas Papadimitriou
414 ab756200 Giorgos Verigakis
    def execute(self, server_id, name):
415 ab756200 Giorgos Verigakis
        image = {'name': name, 'serverRef': int(server_id)}
416 ab756200 Giorgos Verigakis
        body = json.dumps({'image': image})
417 fe29fb25 Giorgos Verigakis
        reply = self.http_post('/images', body)
418 ab756200 Giorgos Verigakis
        print_dict(reply['image'])
419 ab756200 Giorgos Verigakis
420 ab756200 Giorgos Verigakis
@command_name('deleteimg')
421 ab756200 Giorgos Verigakis
class DeleteImage(Command):
422 ab756200 Giorgos Verigakis
    description = 'delete image'
423 ab756200 Giorgos Verigakis
    syntax = '<image id>'
424 38d247df Kostas Papadimitriou
425 ab756200 Giorgos Verigakis
    def execute(self, image_id):
426 fe29fb25 Giorgos Verigakis
        path = '/images/%d' % int(image_id)
427 ab756200 Giorgos Verigakis
        self.http_delete(path)
428 ab756200 Giorgos Verigakis
429 d8e50a39 Giorgos Verigakis
@command_name('lsmeta')
430 d8e50a39 Giorgos Verigakis
class ListServerMeta(Command):
431 d8e50a39 Giorgos Verigakis
    description = 'list server meta'
432 d8e50a39 Giorgos Verigakis
    syntax = '<server id> [key]'
433 d8e50a39 Giorgos Verigakis
434 d8e50a39 Giorgos Verigakis
    def execute(self, server_id, key=None):
435 fe29fb25 Giorgos Verigakis
        path = '/servers/%d/meta' % int(server_id)
436 d8e50a39 Giorgos Verigakis
        if key:
437 d8e50a39 Giorgos Verigakis
            path += '/' + key
438 d8e50a39 Giorgos Verigakis
        reply = self.http_get(path)
439 d8e50a39 Giorgos Verigakis
        if key:
440 d8e50a39 Giorgos Verigakis
            print_dict(reply['meta'])
441 d8e50a39 Giorgos Verigakis
        else:
442 d8e50a39 Giorgos Verigakis
            print_dict(reply['metadata']['values'])
443 d8e50a39 Giorgos Verigakis
444 d8e50a39 Giorgos Verigakis
@command_name('setmeta')
445 d8e50a39 Giorgos Verigakis
class UpdateServerMeta(Command):
446 d8e50a39 Giorgos Verigakis
    description = 'update server meta'
447 d8e50a39 Giorgos Verigakis
    syntax = '<server id> <key> <val>'
448 d8e50a39 Giorgos Verigakis
449 d8e50a39 Giorgos Verigakis
    def execute(self, server_id, key, val):
450 fe29fb25 Giorgos Verigakis
        path = '/servers/%d/meta' % int(server_id)
451 d8e50a39 Giorgos Verigakis
        metadata = {key: val}
452 d8e50a39 Giorgos Verigakis
        body = json.dumps({'metadata': metadata})
453 d8e50a39 Giorgos Verigakis
        reply = self.http_post(path, body, expected_status=201)
454 d8e50a39 Giorgos Verigakis
        print_dict(reply['metadata'])
455 d8e50a39 Giorgos Verigakis
456 d8e50a39 Giorgos Verigakis
@command_name('addmeta')
457 d8e50a39 Giorgos Verigakis
class CreateServerMeta(Command):
458 d8e50a39 Giorgos Verigakis
    description = 'add server meta'
459 d8e50a39 Giorgos Verigakis
    syntax = '<server id> <key> <val>'
460 d8e50a39 Giorgos Verigakis
461 d8e50a39 Giorgos Verigakis
    def execute(self, server_id, key, val):
462 fe29fb25 Giorgos Verigakis
        path = '/servers/%d/meta/%s' % (int(server_id), key)
463 d8e50a39 Giorgos Verigakis
        meta = {key: val}
464 d8e50a39 Giorgos Verigakis
        body = json.dumps({'meta': meta})
465 d8e50a39 Giorgos Verigakis
        reply = self.http_put(path, body, expected_status=201)
466 d8e50a39 Giorgos Verigakis
        print_dict(reply['meta'])
467 d8e50a39 Giorgos Verigakis
468 d8e50a39 Giorgos Verigakis
@command_name('delmeta')
469 d8e50a39 Giorgos Verigakis
class DeleteServerMeta(Command):
470 d8e50a39 Giorgos Verigakis
    description = 'delete server meta'
471 d8e50a39 Giorgos Verigakis
    syntax = '<server id> <key>'
472 d8e50a39 Giorgos Verigakis
473 d8e50a39 Giorgos Verigakis
    def execute(self, server_id, key):
474 fe29fb25 Giorgos Verigakis
        path = '/servers/%d/meta/%s' % (int(server_id), key)
475 d8e50a39 Giorgos Verigakis
        reply = self.http_delete(path)
476 d8e50a39 Giorgos Verigakis
477 432fc8c3 Giorgos Verigakis
@command_name('lsimgmeta')
478 432fc8c3 Giorgos Verigakis
class ListImageMeta(Command):
479 432fc8c3 Giorgos Verigakis
    description = 'list image meta'
480 432fc8c3 Giorgos Verigakis
    syntax = '<image id> [key]'
481 432fc8c3 Giorgos Verigakis
482 432fc8c3 Giorgos Verigakis
    def execute(self, image_id, key=None):
483 fe29fb25 Giorgos Verigakis
        path = '/images/%d/meta' % int(image_id)
484 432fc8c3 Giorgos Verigakis
        if key:
485 432fc8c3 Giorgos Verigakis
            path += '/' + key
486 432fc8c3 Giorgos Verigakis
        reply = self.http_get(path)
487 432fc8c3 Giorgos Verigakis
        if key:
488 432fc8c3 Giorgos Verigakis
            print_dict(reply['meta'])
489 432fc8c3 Giorgos Verigakis
        else:
490 432fc8c3 Giorgos Verigakis
            print_dict(reply['metadata']['values'])
491 432fc8c3 Giorgos Verigakis
492 432fc8c3 Giorgos Verigakis
@command_name('setimgmeta')
493 432fc8c3 Giorgos Verigakis
class UpdateImageMeta(Command):
494 432fc8c3 Giorgos Verigakis
    description = 'update image meta'
495 432fc8c3 Giorgos Verigakis
    syntax = '<image id> <key> <val>'
496 432fc8c3 Giorgos Verigakis
497 432fc8c3 Giorgos Verigakis
    def execute(self, image_id, key, val):
498 fe29fb25 Giorgos Verigakis
        path = '/images/%d/meta' % int(image_id)
499 432fc8c3 Giorgos Verigakis
        metadata = {key: val}
500 432fc8c3 Giorgos Verigakis
        body = json.dumps({'metadata': metadata})
501 432fc8c3 Giorgos Verigakis
        reply = self.http_post(path, body, expected_status=201)
502 432fc8c3 Giorgos Verigakis
        print_dict(reply['metadata'])
503 432fc8c3 Giorgos Verigakis
504 432fc8c3 Giorgos Verigakis
@command_name('addimgmeta')
505 432fc8c3 Giorgos Verigakis
class CreateImageMeta(Command):
506 432fc8c3 Giorgos Verigakis
    description = 'add image meta'
507 432fc8c3 Giorgos Verigakis
    syntax = '<image id> <key> <val>'
508 432fc8c3 Giorgos Verigakis
509 432fc8c3 Giorgos Verigakis
    def execute(self, image_id, key, val):
510 fe29fb25 Giorgos Verigakis
        path = '/images/%d/meta/%s' % (int(image_id), key)
511 432fc8c3 Giorgos Verigakis
        meta = {key: val}
512 432fc8c3 Giorgos Verigakis
        body = json.dumps({'meta': meta})
513 432fc8c3 Giorgos Verigakis
        reply = self.http_put(path, body, expected_status=201)
514 432fc8c3 Giorgos Verigakis
        print_dict(reply['meta'])
515 432fc8c3 Giorgos Verigakis
516 432fc8c3 Giorgos Verigakis
@command_name('delimgmeta')
517 432fc8c3 Giorgos Verigakis
class DeleteImageMeta(Command):
518 432fc8c3 Giorgos Verigakis
    description = 'delete image meta'
519 432fc8c3 Giorgos Verigakis
    syntax = '<image id> <key>'
520 432fc8c3 Giorgos Verigakis
521 432fc8c3 Giorgos Verigakis
    def execute(self, image_id, key):
522 fe29fb25 Giorgos Verigakis
        path = '/images/%d/meta/%s' % (int(image_id), key)
523 432fc8c3 Giorgos Verigakis
        reply = self.http_delete(path)
524 432fc8c3 Giorgos Verigakis
525 ab756200 Giorgos Verigakis
526 0269afd6 Giorgos Verigakis
@command_name('lsnet')
527 0269afd6 Giorgos Verigakis
class ListNetworks(Command):
528 0269afd6 Giorgos Verigakis
    description = 'list networks'
529 0269afd6 Giorgos Verigakis
530 0269afd6 Giorgos Verigakis
    def add_options(self, parser):
531 0269afd6 Giorgos Verigakis
        parser.add_option('-l', action='store_true', dest='detail', default=False,
532 0269afd6 Giorgos Verigakis
                            help='show detailed output')
533 0269afd6 Giorgos Verigakis
534 0269afd6 Giorgos Verigakis
    def execute(self):
535 fe29fb25 Giorgos Verigakis
        path = '/networks/detail' if self.detail else '/networks'
536 0269afd6 Giorgos Verigakis
        reply = self.http_get(path)
537 0269afd6 Giorgos Verigakis
538 0269afd6 Giorgos Verigakis
        for network in reply['networks']['values']:
539 b19653d1 Giorgos Verigakis
            id = network.pop('id')
540 0269afd6 Giorgos Verigakis
            name = network.pop('name')
541 0269afd6 Giorgos Verigakis
            if self.detail:
542 f7ace0a4 Giorgos Verigakis
                print '%s %s' % (id, name)
543 b19653d1 Giorgos Verigakis
                print_dict(network)
544 b19653d1 Giorgos Verigakis
                print
545 0269afd6 Giorgos Verigakis
            else:
546 f7ace0a4 Giorgos Verigakis
                print '%3s %s' % (id, name)
547 0269afd6 Giorgos Verigakis
548 0269afd6 Giorgos Verigakis
549 0269afd6 Giorgos Verigakis
@command_name('createnet')
550 0269afd6 Giorgos Verigakis
class CreateNetwork(Command):
551 0269afd6 Giorgos Verigakis
    description = 'create network'
552 0269afd6 Giorgos Verigakis
    syntax = '<network name>'
553 0269afd6 Giorgos Verigakis
554 0269afd6 Giorgos Verigakis
    def execute(self, name):
555 0269afd6 Giorgos Verigakis
        network = {'name': name}
556 0269afd6 Giorgos Verigakis
        body = json.dumps({'network': network})
557 fe29fb25 Giorgos Verigakis
        reply = self.http_post('/networks', body)
558 0269afd6 Giorgos Verigakis
        print_dict(reply['network'])
559 0269afd6 Giorgos Verigakis
560 0269afd6 Giorgos Verigakis
561 0269afd6 Giorgos Verigakis
@command_name('netinfo')
562 0269afd6 Giorgos Verigakis
class GetNetworkDetails(Command):
563 0269afd6 Giorgos Verigakis
    description = 'get network details'
564 b19653d1 Giorgos Verigakis
    syntax = '<network id>'
565 0269afd6 Giorgos Verigakis
566 b19653d1 Giorgos Verigakis
    def execute(self, network_id):
567 fe29fb25 Giorgos Verigakis
        path = '/networks/%d' % int(network_id)
568 0269afd6 Giorgos Verigakis
        reply = self.http_get(path)
569 0269afd6 Giorgos Verigakis
        net = reply['network']
570 b19653d1 Giorgos Verigakis
        name = net.pop('id')
571 0269afd6 Giorgos Verigakis
        print_dict(net)
572 0269afd6 Giorgos Verigakis
573 0269afd6 Giorgos Verigakis
574 0269afd6 Giorgos Verigakis
@command_name('renamenet')
575 0269afd6 Giorgos Verigakis
class UpdateNetworkName(Command):
576 0269afd6 Giorgos Verigakis
    description = 'update network name'
577 b19653d1 Giorgos Verigakis
    syntax = '<network_id> <new name>'
578 0269afd6 Giorgos Verigakis
579 b19653d1 Giorgos Verigakis
    def execute(self, network_id, name):
580 fe29fb25 Giorgos Verigakis
        path = '/networks/%d' % int(network_id)
581 0269afd6 Giorgos Verigakis
        body = json.dumps({'network': {'name': name}})
582 0269afd6 Giorgos Verigakis
        self.http_put(path, body)
583 0269afd6 Giorgos Verigakis
584 0269afd6 Giorgos Verigakis
585 0269afd6 Giorgos Verigakis
@command_name('deletenet')
586 0269afd6 Giorgos Verigakis
class DeleteNetwork(Command):
587 0269afd6 Giorgos Verigakis
    description = 'delete network'
588 b19653d1 Giorgos Verigakis
    syntax = '<network id>'
589 0269afd6 Giorgos Verigakis
590 b19653d1 Giorgos Verigakis
    def execute(self, network_id):
591 fe29fb25 Giorgos Verigakis
        path = '/networks/%d' % int(network_id)
592 0269afd6 Giorgos Verigakis
        self.http_delete(path)
593 0269afd6 Giorgos Verigakis
594 0269afd6 Giorgos Verigakis
595 f7ace0a4 Giorgos Verigakis
@command_name('connect')
596 0269afd6 Giorgos Verigakis
class AddNetwork(Command):
597 f7ace0a4 Giorgos Verigakis
    description = 'connect a server to a network'
598 b19653d1 Giorgos Verigakis
    syntax = '<server id> <network id>'
599 0269afd6 Giorgos Verigakis
600 b19653d1 Giorgos Verigakis
    def execute(self, server_id, network_id):
601 fe29fb25 Giorgos Verigakis
        path = '/networks/%d/action' % int(network_id)
602 dca6520b Giorgos Verigakis
        body = json.dumps({'add': {'serverRef': server_id}})
603 0269afd6 Giorgos Verigakis
        self.http_post(path, body, expected_status=202)
604 0269afd6 Giorgos Verigakis
605 0269afd6 Giorgos Verigakis
606 f7ace0a4 Giorgos Verigakis
@command_name('disconnect')
607 0269afd6 Giorgos Verigakis
class RemoveNetwork(Command):
608 f7ace0a4 Giorgos Verigakis
    description = 'disconnect a server from a network'
609 b19653d1 Giorgos Verigakis
    syntax = '<server id> <network id>'
610 0269afd6 Giorgos Verigakis
611 b19653d1 Giorgos Verigakis
    def execute(self, server_id, network_id):
612 fe29fb25 Giorgos Verigakis
        path = '/networks/%s/action' % int(network_id)
613 dca6520b Giorgos Verigakis
        body = json.dumps({'remove': {'serverRef': server_id}})
614 0269afd6 Giorgos Verigakis
        self.http_post(path, body, expected_status=202)
615 0269afd6 Giorgos Verigakis
616 334c1b75 Giorgos Verigakis
@command_name('stats')
617 334c1b75 Giorgos Verigakis
class ServerStats(Command):
618 334c1b75 Giorgos Verigakis
    description = 'get server stats'
619 334c1b75 Giorgos Verigakis
    syntax = '<server id>'
620 334c1b75 Giorgos Verigakis
621 334c1b75 Giorgos Verigakis
    def execute(self, server_id):
622 fe29fb25 Giorgos Verigakis
        path = '/servers/%d/stats' % int(server_id)
623 334c1b75 Giorgos Verigakis
        reply = self.http_get(path)
624 334c1b75 Giorgos Verigakis
        stats = reply['stats']
625 334c1b75 Giorgos Verigakis
        stats.pop('serverRef')
626 334c1b75 Giorgos Verigakis
        print_dict(stats)
627 334c1b75 Giorgos Verigakis
628 0269afd6 Giorgos Verigakis
629 faae285d Giorgos Verigakis
def print_usage():
630 faae285d Giorgos Verigakis
    print 'Usage: %s <command>' % basename(argv[0])
631 faae285d Giorgos Verigakis
    print
632 faae285d Giorgos Verigakis
    print 'Commands:'
633 faae285d Giorgos Verigakis
    for name, cls in sorted(commands.items()):
634 faae285d Giorgos Verigakis
        description = getattr(cls, 'description', '')
635 faae285d Giorgos Verigakis
        print '  %s %s' % (name.ljust(12), description)
636 faae285d Giorgos Verigakis
637 ab756200 Giorgos Verigakis
def main():
638 ab756200 Giorgos Verigakis
    try:
639 38d247df Kostas Papadimitriou
        name = argv[1]
640 ab756200 Giorgos Verigakis
        cls = commands[name]
641 ab756200 Giorgos Verigakis
    except (IndexError, KeyError):
642 faae285d Giorgos Verigakis
        print_usage()
643 ab756200 Giorgos Verigakis
        exit(1)
644 38d247df Kostas Papadimitriou
645 ab756200 Giorgos Verigakis
    try:
646 faae285d Giorgos Verigakis
        cls(argv[2:])
647 ab756200 Giorgos Verigakis
    except TypeError:
648 ab756200 Giorgos Verigakis
        syntax = getattr(cls, 'syntax', '')
649 ab756200 Giorgos Verigakis
        if syntax:
650 ab756200 Giorgos Verigakis
            print 'Syntax: %s %s' % (name, syntax)
651 ab756200 Giorgos Verigakis
        else:
652 ab756200 Giorgos Verigakis
            print 'Invalid syntax'
653 ab756200 Giorgos Verigakis
        exit(1)
654 ab756200 Giorgos Verigakis
655 ab756200 Giorgos Verigakis
656 ab756200 Giorgos Verigakis
if __name__ == '__main__':
657 ab756200 Giorgos Verigakis
    main()