Statistics
| Branch: | Tag: | Revision:

root / snf-tools / cloud @ fe29fb25

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