Statistics
| Branch: | Tag: | Revision:

root / tools / cloud @ c0f6fb49

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