Statistics
| Branch: | Tag: | Revision:

root / tools / cloud @ 529178b1

History | View | Annotate | Download (14.7 kB)

1 ab756200 Giorgos Verigakis
#!/usr/bin/env python
2 ab756200 Giorgos Verigakis
3 ab756200 Giorgos Verigakis
from functools import wraps
4 ab756200 Giorgos Verigakis
from httplib import HTTPConnection
5 ab756200 Giorgos Verigakis
from optparse import OptionParser
6 ab756200 Giorgos Verigakis
from os.path import basename
7 ab756200 Giorgos Verigakis
from sys import argv, exit
8 ab756200 Giorgos Verigakis
9 ab756200 Giorgos Verigakis
import json
10 ab756200 Giorgos Verigakis
11 ab756200 Giorgos Verigakis
DEFAULT_HOST = '127.0.0.1:8000'
12 d8e50a39 Giorgos Verigakis
DEFAULT_API = 'v1.1'
13 ab756200 Giorgos Verigakis
14 ab756200 Giorgos Verigakis
15 ab756200 Giorgos Verigakis
commands = {}
16 ab756200 Giorgos Verigakis
17 ab756200 Giorgos Verigakis
def command_name(name):
18 ab756200 Giorgos Verigakis
    def decorator(cls):
19 ab756200 Giorgos Verigakis
        commands[name] = cls
20 ab756200 Giorgos Verigakis
        return cls
21 ab756200 Giorgos Verigakis
    return decorator
22 ab756200 Giorgos Verigakis
23 ab756200 Giorgos Verigakis
24 ab756200 Giorgos Verigakis
def address_to_string(address):
25 ab756200 Giorgos Verigakis
    key = address['id']
26 ab756200 Giorgos Verigakis
    val = ' '.join(ip['addr'] for ip in address['values'])
27 ab756200 Giorgos Verigakis
    return '%s: %s' % (key, val)
28 ab756200 Giorgos Verigakis
29 ab756200 Giorgos Verigakis
def print_dict(d, show_empty=True):
30 ab756200 Giorgos Verigakis
    for key, val in sorted(d.items()):
31 ab756200 Giorgos Verigakis
        if key == 'metadata':
32 ab756200 Giorgos Verigakis
            val = ', '.join('%s="%s"' % x for x in val['values'].items())
33 ab756200 Giorgos Verigakis
        if key == 'addresses':
34 ab756200 Giorgos Verigakis
            val = ', '.join(address_to_string(address) for address in val['values'])
35 ab756200 Giorgos Verigakis
        if val or show_empty:
36 ab756200 Giorgos Verigakis
            print '%s: %s' % (key.rjust(12), val)
37 ab756200 Giorgos Verigakis
38 ab756200 Giorgos Verigakis
39 ab756200 Giorgos Verigakis
class Command(object):
40 ab756200 Giorgos Verigakis
    def __init__(self, argv):
41 ab756200 Giorgos Verigakis
        parser = OptionParser()
42 ab756200 Giorgos Verigakis
        parser.add_option('--host', dest='host', metavar='HOST', default=DEFAULT_HOST,
43 ab756200 Giorgos Verigakis
                            help='use server HOST')
44 ab756200 Giorgos Verigakis
        parser.add_option('--api', dest='api', metavar='API', default=DEFAULT_API,
45 ab756200 Giorgos Verigakis
                            help='use api API')
46 ab756200 Giorgos Verigakis
        parser.add_option('-v', action='store_true', dest='verbose', default=False,
47 ab756200 Giorgos Verigakis
                            help='use verbose output')
48 ab756200 Giorgos Verigakis
        self.add_options(parser)
49 ab756200 Giorgos Verigakis
        options, args = parser.parse_args(argv)
50 ab756200 Giorgos Verigakis
        
51 ab756200 Giorgos Verigakis
        # Add options to self
52 ab756200 Giorgos Verigakis
        for opt in parser.option_list:
53 ab756200 Giorgos Verigakis
            key = opt.dest
54 ab756200 Giorgos Verigakis
            if key:
55 ab756200 Giorgos Verigakis
                val = getattr(options, key)
56 ab756200 Giorgos Verigakis
                setattr(self, key, val)
57 ab756200 Giorgos Verigakis
        
58 ab756200 Giorgos Verigakis
        self.execute(*args)
59 ab756200 Giorgos Verigakis
    
60 ab756200 Giorgos Verigakis
    def add_options(self, parser):
61 ab756200 Giorgos Verigakis
        pass
62 ab756200 Giorgos Verigakis
    
63 ab756200 Giorgos Verigakis
    def execute(self, *args):
64 ab756200 Giorgos Verigakis
        pass
65 ab756200 Giorgos Verigakis
    
66 ab756200 Giorgos Verigakis
    def http_cmd(self, method, path, body=None, expected_status=200):
67 ab756200 Giorgos Verigakis
        conn = HTTPConnection(self.host)
68 ab756200 Giorgos Verigakis
69 ab756200 Giorgos Verigakis
        kwargs = {}
70 ab756200 Giorgos Verigakis
        if body:
71 ab756200 Giorgos Verigakis
            kwargs['headers'] = {'Content-Type': 'application/json'}
72 ab756200 Giorgos Verigakis
            kwargs['body'] = body
73 ab756200 Giorgos Verigakis
        conn.request(method, path, **kwargs)
74 ab756200 Giorgos Verigakis
75 ab756200 Giorgos Verigakis
        resp = conn.getresponse()
76 ab756200 Giorgos Verigakis
        if self.verbose:
77 ab756200 Giorgos Verigakis
            print '%d %s' % (resp.status, resp.reason)
78 ab756200 Giorgos Verigakis
            for key, val in resp.getheaders():
79 ab756200 Giorgos Verigakis
                print '%s: %s' % (key.capitalize(), val)
80 ab756200 Giorgos Verigakis
            print
81 ab756200 Giorgos Verigakis
82 ab756200 Giorgos Verigakis
        buf = resp.read() or '{}'
83 ab756200 Giorgos Verigakis
        reply = json.loads(buf)
84 ab756200 Giorgos Verigakis
85 4cf8adf8 Vangelis Koukis
        # If the response status is not the expected one,
86 4cf8adf8 Vangelis Koukis
        # assume an error has occured and treat the body
87 4cf8adf8 Vangelis Koukis
        # as a cloudfault.
88 ab756200 Giorgos Verigakis
        if resp.status != expected_status:
89 ab756200 Giorgos Verigakis
            if len(reply) == 1:
90 ab756200 Giorgos Verigakis
                key = reply.keys()[0]
91 ab756200 Giorgos Verigakis
                val = reply[key]
92 d8e50a39 Giorgos Verigakis
                print '%s: %s' % (key, val.get('message', ''))
93 ab756200 Giorgos Verigakis
                if self.verbose:
94 ab756200 Giorgos Verigakis
                    print val.get('details', '')
95 ab756200 Giorgos Verigakis
                exit(1)
96 ab756200 Giorgos Verigakis
97 ab756200 Giorgos Verigakis
        return reply
98 ab756200 Giorgos Verigakis
99 ab756200 Giorgos Verigakis
    def http_get(self, path, expected_status=200):
100 ab756200 Giorgos Verigakis
        return self.http_cmd('GET', path, None, expected_status)
101 ab756200 Giorgos Verigakis
    
102 ab756200 Giorgos Verigakis
    def http_post(self, path, body, expected_status=202):
103 ab756200 Giorgos Verigakis
        return self.http_cmd('POST', path, body, expected_status)
104 ab756200 Giorgos Verigakis
105 ab756200 Giorgos Verigakis
    def http_put(self, path, body, expected_status=204):
106 ab756200 Giorgos Verigakis
        return self.http_cmd('PUT', path, body, expected_status)
107 ab756200 Giorgos Verigakis
108 ab756200 Giorgos Verigakis
    def http_delete(self, path, expected_status=204):
109 ab756200 Giorgos Verigakis
        return self.http_cmd('DELETE', path, None, expected_status)
110 ab756200 Giorgos Verigakis
111 ab756200 Giorgos Verigakis
112 ab756200 Giorgos Verigakis
@command_name('ls')
113 ab756200 Giorgos Verigakis
class ListServers(Command):
114 ab756200 Giorgos Verigakis
    description = 'list servers'
115 ab756200 Giorgos Verigakis
    
116 ab756200 Giorgos Verigakis
    def add_options(self, parser):
117 ab756200 Giorgos Verigakis
        parser.add_option('-l', action='store_true', dest='detail', default=False,
118 ab756200 Giorgos Verigakis
                            help='show detailed output')
119 ab756200 Giorgos Verigakis
        parser.add_option('-a', action='store_true', dest='show_empty', default=False,
120 ab756200 Giorgos Verigakis
                            help='include empty values')
121 ab756200 Giorgos Verigakis
    
122 ab756200 Giorgos Verigakis
    def execute(self):
123 ab756200 Giorgos Verigakis
        path = '/api/%s/servers' % self.api
124 ab756200 Giorgos Verigakis
        if self.detail:
125 ab756200 Giorgos Verigakis
            path += '/detail'
126 ab756200 Giorgos Verigakis
127 ab756200 Giorgos Verigakis
        reply = self.http_get(path)
128 ab756200 Giorgos Verigakis
129 ab756200 Giorgos Verigakis
        for server in reply['servers']['values']:
130 ab756200 Giorgos Verigakis
            id = server.pop('id')
131 ab756200 Giorgos Verigakis
            name = server.pop('name')
132 ab756200 Giorgos Verigakis
            if self.detail:
133 ab756200 Giorgos Verigakis
                print '%d %s' % (id, name)
134 ab756200 Giorgos Verigakis
                print_dict(server, self.show_empty)
135 ab756200 Giorgos Verigakis
                print
136 ab756200 Giorgos Verigakis
            else:
137 ab756200 Giorgos Verigakis
                print '%3d %s' % (id, name)
138 ab756200 Giorgos Verigakis
139 ab756200 Giorgos Verigakis
140 ab756200 Giorgos Verigakis
@command_name('info')
141 ab756200 Giorgos Verigakis
class GetServerDetails(Command):
142 ab756200 Giorgos Verigakis
    description = 'get server details'
143 ab756200 Giorgos Verigakis
    syntax = '<server id>'
144 ab756200 Giorgos Verigakis
    
145 ab756200 Giorgos Verigakis
    def add_options(self, parser):
146 ab756200 Giorgos Verigakis
        parser.add_option('-a', action='store_true', dest='show_empty', default=False,
147 ab756200 Giorgos Verigakis
                            help='include empty values')
148 ab756200 Giorgos Verigakis
    
149 ab756200 Giorgos Verigakis
    def execute(self, server_id):
150 ab756200 Giorgos Verigakis
        path = '/api/%s/servers/%d' % (self.api, int(server_id))
151 ab756200 Giorgos Verigakis
        reply = self.http_get(path)
152 ab756200 Giorgos Verigakis
        server = reply['server']
153 ab756200 Giorgos Verigakis
        server.pop('id')
154 ab756200 Giorgos Verigakis
        print_dict(server, self.show_empty)
155 ab756200 Giorgos Verigakis
        
156 ab756200 Giorgos Verigakis
157 ab756200 Giorgos Verigakis
@command_name('create')
158 ab756200 Giorgos Verigakis
class CreateServer(Command):
159 ab756200 Giorgos Verigakis
    description = 'create server'
160 ab756200 Giorgos Verigakis
    syntax = '<server name>'
161 ab756200 Giorgos Verigakis
    
162 ab756200 Giorgos Verigakis
    def add_options(self, parser):
163 ab756200 Giorgos Verigakis
        parser.add_option('-f', dest='flavor', metavar='FLAVOR_ID', default=1,
164 ab756200 Giorgos Verigakis
                            help='use flavor FLAVOR_ID')
165 ab756200 Giorgos Verigakis
        parser.add_option('-i', dest='image', metavar='IMAGE_ID', default=1,
166 ab756200 Giorgos Verigakis
                            help='use image IMAGE_ID')
167 ab756200 Giorgos Verigakis
    
168 ab756200 Giorgos Verigakis
    def execute(self, name):
169 ab756200 Giorgos Verigakis
        path = '/api/%s/servers' % self.api
170 ab756200 Giorgos Verigakis
        server = {'name': name, 'flavorRef': self.flavor, 'imageRef': self.image}
171 ab756200 Giorgos Verigakis
        body = json.dumps({'server': server})
172 ab756200 Giorgos Verigakis
        reply = self.http_post(path, body)
173 ab756200 Giorgos Verigakis
        server = reply['server']
174 ab756200 Giorgos Verigakis
        server.pop('id')
175 ab756200 Giorgos Verigakis
        print_dict(server)
176 ab756200 Giorgos Verigakis
177 ab756200 Giorgos Verigakis
178 ab756200 Giorgos Verigakis
@command_name('rename')
179 ab756200 Giorgos Verigakis
class UpdateServerName(Command):
180 ab756200 Giorgos Verigakis
    description = 'update server name'
181 ab756200 Giorgos Verigakis
    syntax = '<server id> <new name>'
182 ab756200 Giorgos Verigakis
    
183 ab756200 Giorgos Verigakis
    def execute(self, server_id, name):
184 ab756200 Giorgos Verigakis
        path = '/api/%s/servers/%d' % (self.api, int(server_id))
185 ab756200 Giorgos Verigakis
        body = json.dumps({'server': {'name': name}})
186 ab756200 Giorgos Verigakis
        self.http_put(path, body)
187 ab756200 Giorgos Verigakis
188 ab756200 Giorgos Verigakis
189 ab756200 Giorgos Verigakis
@command_name('delete')
190 ab756200 Giorgos Verigakis
class DeleteServer(Command):
191 ab756200 Giorgos Verigakis
    description = 'delete server'
192 ab756200 Giorgos Verigakis
    syntax = '<server id>'
193 ab756200 Giorgos Verigakis
    
194 ab756200 Giorgos Verigakis
    def execute(self, server_id):
195 ab756200 Giorgos Verigakis
        path = '/api/%s/servers/%d' % (self.api, int(server_id))
196 ab756200 Giorgos Verigakis
        self.http_delete(path)
197 ab756200 Giorgos Verigakis
198 ab756200 Giorgos Verigakis
199 ab756200 Giorgos Verigakis
@command_name('reboot')
200 ab756200 Giorgos Verigakis
class RebootServer(Command):
201 ab756200 Giorgos Verigakis
    description = 'reboot server'
202 ab756200 Giorgos Verigakis
    syntax = '<server id>'
203 ab756200 Giorgos Verigakis
    
204 ab756200 Giorgos Verigakis
    def add_options(self, parser):
205 ab756200 Giorgos Verigakis
        parser.add_option('-f', action='store_true', dest='hard', default=False,
206 ab756200 Giorgos Verigakis
                            help='perform a hard reboot')
207 ab756200 Giorgos Verigakis
    
208 ab756200 Giorgos Verigakis
    def execute(self, server_id):
209 ab756200 Giorgos Verigakis
        path = '/api/%s/servers/%d/action' % (self.api, int(server_id))
210 ab756200 Giorgos Verigakis
        type = 'HARD' if self.hard else 'SOFT'
211 ab756200 Giorgos Verigakis
        body = json.dumps({'reboot': {'type': type}})
212 ab756200 Giorgos Verigakis
        self.http_post(path, body)
213 ab756200 Giorgos Verigakis
    
214 ab756200 Giorgos Verigakis
215 ab756200 Giorgos Verigakis
@command_name('start')
216 ab756200 Giorgos Verigakis
class StartServer(Command):
217 ab756200 Giorgos Verigakis
    description = 'start server'
218 ab756200 Giorgos Verigakis
    syntax = '<server id>'
219 ab756200 Giorgos Verigakis
    
220 ab756200 Giorgos Verigakis
    def execute(self, server_id):
221 ab756200 Giorgos Verigakis
        path = '/api/%s/servers/%d/action' % (self.api, int(server_id))
222 ab756200 Giorgos Verigakis
        body = json.dumps({'start': {}})
223 ab756200 Giorgos Verigakis
        self.http_post(path, body)
224 ab756200 Giorgos Verigakis
225 ab756200 Giorgos Verigakis
226 ab756200 Giorgos Verigakis
@command_name('shutdown')
227 ab756200 Giorgos Verigakis
class StartServer(Command):
228 ab756200 Giorgos Verigakis
    description = 'shutdown server'
229 ab756200 Giorgos Verigakis
    syntax = '<server id>'
230 ab756200 Giorgos Verigakis
    
231 ab756200 Giorgos Verigakis
    def execute(self, server_id):
232 ab756200 Giorgos Verigakis
        path = '/api/%s/servers/%d/action' % (self.api, int(server_id))
233 ab756200 Giorgos Verigakis
        body = json.dumps({'shutdown': {}})
234 ab756200 Giorgos Verigakis
        self.http_post(path, body)
235 ab756200 Giorgos Verigakis
236 ab756200 Giorgos Verigakis
237 09471611 Vangelis Koukis
@command_name('console')
238 09471611 Vangelis Koukis
class ServerConsole(Command):
239 09471611 Vangelis Koukis
    description = 'get VNC console'
240 09471611 Vangelis Koukis
    syntax = '<server id>'
241 09471611 Vangelis Koukis
    
242 09471611 Vangelis Koukis
    def add_options(self, parser):
243 09471611 Vangelis Koukis
    	pass
244 09471611 Vangelis Koukis
    
245 09471611 Vangelis Koukis
    def execute(self, server_id):
246 09471611 Vangelis Koukis
        path = '/api/%s/servers/%d/action' % (self.api, int(server_id))
247 529178b1 Giorgos Verigakis
        body = json.dumps({'console': {'type': 'vnc'}})
248 4cf8adf8 Vangelis Koukis
        reply = self.http_cmd('POST', path, body, 200)
249 529178b1 Giorgos Verigakis
        print_dict(reply['console'])
250 09471611 Vangelis Koukis
251 09471611 Vangelis Koukis
252 ab756200 Giorgos Verigakis
@command_name('lsaddr')
253 ab756200 Giorgos Verigakis
class ListAddresses(Command):
254 ab756200 Giorgos Verigakis
    description = 'list server addresses'
255 ab756200 Giorgos Verigakis
    syntax = '<server id> [network]'
256 ab756200 Giorgos Verigakis
    
257 ab756200 Giorgos Verigakis
    def execute(self, server_id, network=None):
258 ab756200 Giorgos Verigakis
        path = '/api/%s/servers/%d/ips' % (self.api, int(server_id))
259 ab756200 Giorgos Verigakis
        if network:
260 ab756200 Giorgos Verigakis
            path += '/%s' % network
261 ab756200 Giorgos Verigakis
        reply = self.http_get(path)
262 ab756200 Giorgos Verigakis
        
263 ab756200 Giorgos Verigakis
        addresses = [reply['network']] if network else reply['addresses']['values']
264 ab756200 Giorgos Verigakis
        for address in addresses:
265 ab756200 Giorgos Verigakis
            print address_to_string(address)
266 ab756200 Giorgos Verigakis
267 ab756200 Giorgos Verigakis
268 ab756200 Giorgos Verigakis
@command_name('lsflv')
269 ab756200 Giorgos Verigakis
class ListFlavors(Command):
270 ab756200 Giorgos Verigakis
    description = 'list flavors'
271 ab756200 Giorgos Verigakis
    
272 ab756200 Giorgos Verigakis
    def add_options(self, parser):
273 ab756200 Giorgos Verigakis
        parser.add_option('-l', action='store_true', dest='detail', default=False,
274 ab756200 Giorgos Verigakis
                            help='show detailed output')
275 ab756200 Giorgos Verigakis
    
276 ab756200 Giorgos Verigakis
    def execute(self):
277 ab756200 Giorgos Verigakis
        path = '/api/%s/flavors' % self.api
278 ab756200 Giorgos Verigakis
        if self.detail:
279 ab756200 Giorgos Verigakis
            path += '/detail'
280 ab756200 Giorgos Verigakis
        reply = self.http_get(path)
281 ab756200 Giorgos Verigakis
        
282 ab756200 Giorgos Verigakis
        for flavor in reply['flavors']['values']:
283 ab756200 Giorgos Verigakis
            id = flavor.pop('id')
284 ab756200 Giorgos Verigakis
            name = flavor.pop('name')
285 ab756200 Giorgos Verigakis
            details = ' '.join('%s=%s' % item for item in sorted(flavor.items()))
286 ab756200 Giorgos Verigakis
            print '%3d %s %s' % (id, name, details)
287 ab756200 Giorgos Verigakis
288 ab756200 Giorgos Verigakis
289 d8e50a39 Giorgos Verigakis
@command_name('flvinfo')
290 ab756200 Giorgos Verigakis
class GetFlavorDetails(Command):
291 ab756200 Giorgos Verigakis
    description = 'get flavor details'
292 ab756200 Giorgos Verigakis
    syntax = '<flavor id>'
293 ab756200 Giorgos Verigakis
    
294 ab756200 Giorgos Verigakis
    def execute(self, flavor_id):
295 ab756200 Giorgos Verigakis
        path = '/api/%s/flavors/%d' % (self.api, int(flavor_id))
296 ab756200 Giorgos Verigakis
        reply = self.http_get(path)
297 ab756200 Giorgos Verigakis
        
298 ab756200 Giorgos Verigakis
        flavor = reply['flavor']
299 ab756200 Giorgos Verigakis
        id = flavor.pop('id')
300 ab756200 Giorgos Verigakis
        name = flavor.pop('name')
301 ab756200 Giorgos Verigakis
        details = ' '.join('%s=%s' % item for item in sorted(flavor.items()))
302 ab756200 Giorgos Verigakis
        print '%3d %s %s' % (id, name, details)
303 ab756200 Giorgos Verigakis
304 ab756200 Giorgos Verigakis
305 ab756200 Giorgos Verigakis
@command_name('lsimg')
306 ab756200 Giorgos Verigakis
class ListImages(Command):
307 ab756200 Giorgos Verigakis
    description = 'list images'
308 ab756200 Giorgos Verigakis
    
309 ab756200 Giorgos Verigakis
    def add_options(self, parser):
310 ab756200 Giorgos Verigakis
        parser.add_option('-l', action='store_true', dest='detail', default=False,
311 ab756200 Giorgos Verigakis
                            help='show detailed output')
312 ab756200 Giorgos Verigakis
    
313 ab756200 Giorgos Verigakis
    def execute(self):
314 ab756200 Giorgos Verigakis
        path = '/api/%s/images' % self.api
315 ab756200 Giorgos Verigakis
        if self.detail:
316 ab756200 Giorgos Verigakis
            path += '/detail'
317 ab756200 Giorgos Verigakis
        reply = self.http_get(path)
318 ab756200 Giorgos Verigakis
        
319 ab756200 Giorgos Verigakis
        for image in reply['images']['values']:
320 ab756200 Giorgos Verigakis
            id = image.pop('id')
321 ab756200 Giorgos Verigakis
            name = image.pop('name')
322 ab756200 Giorgos Verigakis
            if self.detail:
323 ab756200 Giorgos Verigakis
                print '%d %s' % (id, name)
324 ab756200 Giorgos Verigakis
                print_dict(image)
325 ab756200 Giorgos Verigakis
                print
326 ab756200 Giorgos Verigakis
            else:
327 ab756200 Giorgos Verigakis
                print '%3d %s' % (id, name)        
328 ab756200 Giorgos Verigakis
329 ab756200 Giorgos Verigakis
330 ab756200 Giorgos Verigakis
@command_name('imginfo')
331 ab756200 Giorgos Verigakis
class GetImageDetails(Command):
332 ab756200 Giorgos Verigakis
    description = 'get image details'
333 ab756200 Giorgos Verigakis
    syntax = '<image id>'
334 ab756200 Giorgos Verigakis
    
335 ab756200 Giorgos Verigakis
    def execute(self, image_id):
336 ab756200 Giorgos Verigakis
        path = '/api/%s/images/%d' % (self.api, int(image_id))
337 ab756200 Giorgos Verigakis
        reply = self.http_get(path)
338 ab756200 Giorgos Verigakis
        image = reply['image']
339 ab756200 Giorgos Verigakis
        image.pop('id')
340 ab756200 Giorgos Verigakis
        print_dict(image)
341 ab756200 Giorgos Verigakis
342 ab756200 Giorgos Verigakis
343 ab756200 Giorgos Verigakis
@command_name('createimg')
344 ab756200 Giorgos Verigakis
class CreateImage(Command):
345 ab756200 Giorgos Verigakis
    description = 'create image'
346 ab756200 Giorgos Verigakis
    syntax = '<server id> <image name>'
347 ab756200 Giorgos Verigakis
    
348 ab756200 Giorgos Verigakis
    def execute(self, server_id, name):
349 ab756200 Giorgos Verigakis
        path = '/api/%s/images' % self.api
350 ab756200 Giorgos Verigakis
        image = {'name': name, 'serverRef': int(server_id)}
351 ab756200 Giorgos Verigakis
        body = json.dumps({'image': image})
352 ab756200 Giorgos Verigakis
        reply = self.http_post(path, body)
353 ab756200 Giorgos Verigakis
        print_dict(reply['image'])
354 ab756200 Giorgos Verigakis
355 ab756200 Giorgos Verigakis
@command_name('deleteimg')
356 ab756200 Giorgos Verigakis
class DeleteImage(Command):
357 ab756200 Giorgos Verigakis
    description = 'delete image'
358 ab756200 Giorgos Verigakis
    syntax = '<image id>'
359 ab756200 Giorgos Verigakis
    
360 ab756200 Giorgos Verigakis
    def execute(self, image_id):
361 ab756200 Giorgos Verigakis
        path = '/api/%s/images/%d' % (self.api, int(image_id))
362 ab756200 Giorgos Verigakis
        self.http_delete(path)
363 ab756200 Giorgos Verigakis
364 d8e50a39 Giorgos Verigakis
@command_name('lsmeta')
365 d8e50a39 Giorgos Verigakis
class ListServerMeta(Command):
366 d8e50a39 Giorgos Verigakis
    description = 'list server meta'
367 d8e50a39 Giorgos Verigakis
    syntax = '<server id> [key]'
368 d8e50a39 Giorgos Verigakis
369 d8e50a39 Giorgos Verigakis
    def execute(self, server_id, key=None):
370 d8e50a39 Giorgos Verigakis
        path = '/api/%s/servers/%d/meta' % (self.api, int(server_id))
371 d8e50a39 Giorgos Verigakis
        if key:
372 d8e50a39 Giorgos Verigakis
            path += '/' + key
373 d8e50a39 Giorgos Verigakis
        reply = self.http_get(path)
374 d8e50a39 Giorgos Verigakis
        if key:
375 d8e50a39 Giorgos Verigakis
            print_dict(reply['meta'])
376 d8e50a39 Giorgos Verigakis
        else:
377 d8e50a39 Giorgos Verigakis
            print_dict(reply['metadata']['values'])
378 d8e50a39 Giorgos Verigakis
379 d8e50a39 Giorgos Verigakis
@command_name('setmeta')
380 d8e50a39 Giorgos Verigakis
class UpdateServerMeta(Command):
381 d8e50a39 Giorgos Verigakis
    description = 'update server meta'
382 d8e50a39 Giorgos Verigakis
    syntax = '<server id> <key> <val>'
383 d8e50a39 Giorgos Verigakis
384 d8e50a39 Giorgos Verigakis
    def execute(self, server_id, key, val):
385 d8e50a39 Giorgos Verigakis
        path = '/api/%s/servers/%d/meta' % (self.api, int(server_id))
386 d8e50a39 Giorgos Verigakis
        metadata = {key: val}
387 d8e50a39 Giorgos Verigakis
        body = json.dumps({'metadata': metadata})
388 d8e50a39 Giorgos Verigakis
        reply = self.http_post(path, body, expected_status=201)
389 d8e50a39 Giorgos Verigakis
        print_dict(reply['metadata'])
390 d8e50a39 Giorgos Verigakis
391 d8e50a39 Giorgos Verigakis
@command_name('addmeta')
392 d8e50a39 Giorgos Verigakis
class CreateServerMeta(Command):
393 d8e50a39 Giorgos Verigakis
    description = 'add server meta'
394 d8e50a39 Giorgos Verigakis
    syntax = '<server id> <key> <val>'
395 d8e50a39 Giorgos Verigakis
396 d8e50a39 Giorgos Verigakis
    def execute(self, server_id, key, val):
397 d8e50a39 Giorgos Verigakis
        path = '/api/%s/servers/%d/meta/%s' % (self.api, int(server_id), key)
398 d8e50a39 Giorgos Verigakis
        meta = {key: val}
399 d8e50a39 Giorgos Verigakis
        body = json.dumps({'meta': meta})
400 d8e50a39 Giorgos Verigakis
        reply = self.http_put(path, body, expected_status=201)
401 d8e50a39 Giorgos Verigakis
        print_dict(reply['meta'])
402 d8e50a39 Giorgos Verigakis
403 d8e50a39 Giorgos Verigakis
@command_name('delmeta')
404 d8e50a39 Giorgos Verigakis
class DeleteServerMeta(Command):
405 d8e50a39 Giorgos Verigakis
    description = 'delete server meta'
406 d8e50a39 Giorgos Verigakis
    syntax = '<server id> <key>'
407 d8e50a39 Giorgos Verigakis
408 d8e50a39 Giorgos Verigakis
    def execute(self, server_id, key):
409 d8e50a39 Giorgos Verigakis
        path = '/api/%s/servers/%d/meta/%s' % (self.api, int(server_id), key)
410 d8e50a39 Giorgos Verigakis
        reply = self.http_delete(path)
411 d8e50a39 Giorgos Verigakis
412 432fc8c3 Giorgos Verigakis
@command_name('lsimgmeta')
413 432fc8c3 Giorgos Verigakis
class ListImageMeta(Command):
414 432fc8c3 Giorgos Verigakis
    description = 'list image meta'
415 432fc8c3 Giorgos Verigakis
    syntax = '<image id> [key]'
416 432fc8c3 Giorgos Verigakis
417 432fc8c3 Giorgos Verigakis
    def execute(self, image_id, key=None):
418 432fc8c3 Giorgos Verigakis
        path = '/api/%s/images/%d/meta' % (self.api, int(image_id))
419 432fc8c3 Giorgos Verigakis
        if key:
420 432fc8c3 Giorgos Verigakis
            path += '/' + key
421 432fc8c3 Giorgos Verigakis
        reply = self.http_get(path)
422 432fc8c3 Giorgos Verigakis
        if key:
423 432fc8c3 Giorgos Verigakis
            print_dict(reply['meta'])
424 432fc8c3 Giorgos Verigakis
        else:
425 432fc8c3 Giorgos Verigakis
            print_dict(reply['metadata']['values'])
426 432fc8c3 Giorgos Verigakis
427 432fc8c3 Giorgos Verigakis
@command_name('setimgmeta')
428 432fc8c3 Giorgos Verigakis
class UpdateImageMeta(Command):
429 432fc8c3 Giorgos Verigakis
    description = 'update image meta'
430 432fc8c3 Giorgos Verigakis
    syntax = '<image id> <key> <val>'
431 432fc8c3 Giorgos Verigakis
432 432fc8c3 Giorgos Verigakis
    def execute(self, image_id, key, val):
433 432fc8c3 Giorgos Verigakis
        path = '/api/%s/images/%d/meta' % (self.api, int(image_id))
434 432fc8c3 Giorgos Verigakis
        metadata = {key: val}
435 432fc8c3 Giorgos Verigakis
        body = json.dumps({'metadata': metadata})
436 432fc8c3 Giorgos Verigakis
        reply = self.http_post(path, body, expected_status=201)
437 432fc8c3 Giorgos Verigakis
        print_dict(reply['metadata'])
438 432fc8c3 Giorgos Verigakis
439 432fc8c3 Giorgos Verigakis
@command_name('addimgmeta')
440 432fc8c3 Giorgos Verigakis
class CreateImageMeta(Command):
441 432fc8c3 Giorgos Verigakis
    description = 'add image meta'
442 432fc8c3 Giorgos Verigakis
    syntax = '<image id> <key> <val>'
443 432fc8c3 Giorgos Verigakis
444 432fc8c3 Giorgos Verigakis
    def execute(self, image_id, key, val):
445 432fc8c3 Giorgos Verigakis
        path = '/api/%s/images/%d/meta/%s' % (self.api, int(image_id), key)
446 432fc8c3 Giorgos Verigakis
        meta = {key: val}
447 432fc8c3 Giorgos Verigakis
        body = json.dumps({'meta': meta})
448 432fc8c3 Giorgos Verigakis
        reply = self.http_put(path, body, expected_status=201)
449 432fc8c3 Giorgos Verigakis
        print_dict(reply['meta'])
450 432fc8c3 Giorgos Verigakis
451 432fc8c3 Giorgos Verigakis
@command_name('delimgmeta')
452 432fc8c3 Giorgos Verigakis
class DeleteImageMeta(Command):
453 432fc8c3 Giorgos Verigakis
    description = 'delete image meta'
454 432fc8c3 Giorgos Verigakis
    syntax = '<image id> <key>'
455 432fc8c3 Giorgos Verigakis
456 432fc8c3 Giorgos Verigakis
    def execute(self, image_id, key):
457 432fc8c3 Giorgos Verigakis
        path = '/api/%s/images/%d/meta/%s' % (self.api, int(image_id), key)
458 432fc8c3 Giorgos Verigakis
        reply = self.http_delete(path)
459 432fc8c3 Giorgos Verigakis
460 ab756200 Giorgos Verigakis
461 ab756200 Giorgos Verigakis
def main():
462 ab756200 Giorgos Verigakis
    try:
463 ab756200 Giorgos Verigakis
        name = argv[1]    
464 ab756200 Giorgos Verigakis
        cls = commands[name]
465 ab756200 Giorgos Verigakis
    except (IndexError, KeyError):
466 ab756200 Giorgos Verigakis
        print 'Usage: %s <command>' % basename(argv[0])
467 ab756200 Giorgos Verigakis
        print
468 ab756200 Giorgos Verigakis
        print 'Commands:'
469 ab756200 Giorgos Verigakis
        for name, cls in sorted(commands.items()):
470 ab756200 Giorgos Verigakis
            description = getattr(cls, 'description', '')
471 ab756200 Giorgos Verigakis
            print '  %s %s' % (name.ljust(12), description)
472 ab756200 Giorgos Verigakis
        exit(1)
473 ab756200 Giorgos Verigakis
    
474 ab756200 Giorgos Verigakis
    try:
475 ab756200 Giorgos Verigakis
        commands[name](argv[2:])
476 ab756200 Giorgos Verigakis
    except TypeError:
477 ab756200 Giorgos Verigakis
        syntax = getattr(cls, 'syntax', '')
478 ab756200 Giorgos Verigakis
        if syntax:
479 ab756200 Giorgos Verigakis
            print 'Syntax: %s %s' % (name, syntax)
480 ab756200 Giorgos Verigakis
        else:
481 ab756200 Giorgos Verigakis
            print 'Invalid syntax'
482 ab756200 Giorgos Verigakis
        exit(1)
483 ab756200 Giorgos Verigakis
484 ab756200 Giorgos Verigakis
485 ab756200 Giorgos Verigakis
if __name__ == '__main__':
486 ab756200 Giorgos Verigakis
    main()