Statistics
| Branch: | Tag: | Revision:

root / kamaki / cli.py @ c4ab2af9

History | View | Annotate | Download (24.8 kB)

1 5d1d131b Giorgos Verigakis
#!/usr/bin/env python
2 5d1d131b Giorgos Verigakis
3 5d1d131b Giorgos Verigakis
# Copyright 2011 GRNET S.A. All rights reserved.
4 5d1d131b Giorgos Verigakis
#
5 5d1d131b Giorgos Verigakis
# Redistribution and use in source and binary forms, with or
6 5d1d131b Giorgos Verigakis
# without modification, are permitted provided that the following
7 5d1d131b Giorgos Verigakis
# conditions are met:
8 5d1d131b Giorgos Verigakis
#
9 5d1d131b Giorgos Verigakis
#   1. Redistributions of source code must retain the above
10 5d1d131b Giorgos Verigakis
#      copyright notice, this list of conditions and the following
11 5d1d131b Giorgos Verigakis
#      disclaimer.
12 5d1d131b Giorgos Verigakis
#
13 5d1d131b Giorgos Verigakis
#   2. Redistributions in binary form must reproduce the above
14 5d1d131b Giorgos Verigakis
#      copyright notice, this list of conditions and the following
15 5d1d131b Giorgos Verigakis
#      disclaimer in the documentation and/or other materials
16 5d1d131b Giorgos Verigakis
#      provided with the distribution.
17 5d1d131b Giorgos Verigakis
#
18 5d1d131b Giorgos Verigakis
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
19 5d1d131b Giorgos Verigakis
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 5d1d131b Giorgos Verigakis
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21 5d1d131b Giorgos Verigakis
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
22 5d1d131b Giorgos Verigakis
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 5d1d131b Giorgos Verigakis
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 5d1d131b Giorgos Verigakis
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
25 5d1d131b Giorgos Verigakis
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
26 5d1d131b Giorgos Verigakis
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 5d1d131b Giorgos Verigakis
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
28 5d1d131b Giorgos Verigakis
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 5d1d131b Giorgos Verigakis
# POSSIBILITY OF SUCH DAMAGE.
30 5d1d131b Giorgos Verigakis
#
31 5d1d131b Giorgos Verigakis
# The views and conclusions contained in the software and
32 5d1d131b Giorgos Verigakis
# documentation are those of the authors and should not be
33 5d1d131b Giorgos Verigakis
# interpreted as representing official policies, either expressed
34 5d1d131b Giorgos Verigakis
# or implied, of GRNET S.A.
35 5d1d131b Giorgos Verigakis
36 eb3ca8ca Giorgos Verigakis
"""
37 eb3ca8ca Giorgos Verigakis
To add a command create a new class and add a 'command' decorator. The class
38 eb3ca8ca Giorgos Verigakis
must have a 'main' method which will contain the code to be executed.
39 eb3ca8ca Giorgos Verigakis
Optionally a command can implement an 'update_parser' class method in order
40 eb3ca8ca Giorgos Verigakis
to add command line arguments, or modify the OptionParser in any way.
41 eb3ca8ca Giorgos Verigakis

42 eb3ca8ca Giorgos Verigakis
The name of the class is important and it will determine the name and grouping
43 eb3ca8ca Giorgos Verigakis
of the command. This behavior can be overriden with the 'group' and 'name'
44 eb3ca8ca Giorgos Verigakis
decorator arguments:
45 eb3ca8ca Giorgos Verigakis

46 a1c50326 Giorgos Verigakis
    @command(api='compute')
47 eb3ca8ca Giorgos Verigakis
    class server_list(object):
48 eb3ca8ca Giorgos Verigakis
        # This command will be named 'list' under group 'server'
49 eb3ca8ca Giorgos Verigakis
        ...
50 eb3ca8ca Giorgos Verigakis

51 a1c50326 Giorgos Verigakis
    @command(api='compute', name='ls')
52 eb3ca8ca Giorgos Verigakis
    class server_list(object):
53 eb3ca8ca Giorgos Verigakis
        # This command will be named 'ls' under group 'server'
54 eb3ca8ca Giorgos Verigakis
        ...
55 eb3ca8ca Giorgos Verigakis

56 eb3ca8ca Giorgos Verigakis
The docstring of a command class will be used as the command description in
57 eb3ca8ca Giorgos Verigakis
help messages, unless overriden with the 'description' decorator argument.
58 eb3ca8ca Giorgos Verigakis

59 eb3ca8ca Giorgos Verigakis
The syntax of a command will be generated dynamically based on the signature
60 eb3ca8ca Giorgos Verigakis
of the 'main' method, unless overriden with the 'syntax' decorator argument:
61 eb3ca8ca Giorgos Verigakis

62 eb3ca8ca Giorgos Verigakis
    def main(self, server_id, network=None):
63 eb3ca8ca Giorgos Verigakis
        # This syntax of this command will be: '<server id> [network]'
64 eb3ca8ca Giorgos Verigakis
        ...
65 eb3ca8ca Giorgos Verigakis

66 eb3ca8ca Giorgos Verigakis
The order of commands is important, it will be preserved in the help output.
67 eb3ca8ca Giorgos Verigakis
"""
68 eb3ca8ca Giorgos Verigakis
69 5d1d131b Giorgos Verigakis
import inspect
70 5d1d131b Giorgos Verigakis
import logging
71 5d1d131b Giorgos Verigakis
import os
72 5d1d131b Giorgos Verigakis
73 57b8dd5a Giorgos Verigakis
from base64 import b64encode
74 57b8dd5a Giorgos Verigakis
from grp import getgrgid
75 5d1d131b Giorgos Verigakis
from optparse import OptionParser
76 a1c50326 Giorgos Verigakis
from os.path import abspath, basename, exists
77 57b8dd5a Giorgos Verigakis
from pwd import getpwuid
78 176894c1 Giorgos Verigakis
from sys import argv, exit, stdout
79 5d1d131b Giorgos Verigakis
80 a1c50326 Giorgos Verigakis
from kamaki import clients
81 614b80ce Giorgos Verigakis
from kamaki.config import Config, ConfigError
82 614b80ce Giorgos Verigakis
from kamaki.utils import OrderedDict, print_addresses, print_dict, print_items
83 5d1d131b Giorgos Verigakis
84 5d1d131b Giorgos Verigakis
85 653b0597 Giorgos Verigakis
log = logging.getLogger('kamaki')
86 653b0597 Giorgos Verigakis
87 eb3ca8ca Giorgos Verigakis
_commands = OrderedDict()
88 eb3ca8ca Giorgos Verigakis
89 653b0597 Giorgos Verigakis
90 eb3ca8ca Giorgos Verigakis
def command(api=None, group=None, name=None, description=None, syntax=None):
91 eb3ca8ca Giorgos Verigakis
    """Class decorator that registers a class as a CLI command."""
92 eb3ca8ca Giorgos Verigakis
    
93 eb3ca8ca Giorgos Verigakis
    def decorator(cls):
94 eb3ca8ca Giorgos Verigakis
        grp, sep, cmd = cls.__name__.partition('_')
95 eb3ca8ca Giorgos Verigakis
        if not sep:
96 eb3ca8ca Giorgos Verigakis
            grp, cmd = None, cls.__name__
97 5d1d131b Giorgos Verigakis
        
98 eb3ca8ca Giorgos Verigakis
        cls.api = api
99 eb3ca8ca Giorgos Verigakis
        cls.group = group or grp
100 eb3ca8ca Giorgos Verigakis
        cls.name = name or cmd
101 eb3ca8ca Giorgos Verigakis
        cls.description = description or cls.__doc__
102 eb3ca8ca Giorgos Verigakis
        cls.syntax = syntax
103 5d1d131b Giorgos Verigakis
        
104 eb3ca8ca Giorgos Verigakis
        if cls.syntax is None:
105 eb3ca8ca Giorgos Verigakis
            # Generate a syntax string based on main's arguments
106 eb3ca8ca Giorgos Verigakis
            spec = inspect.getargspec(cls.main.im_func)
107 eb3ca8ca Giorgos Verigakis
            args = spec.args[1:]
108 eb3ca8ca Giorgos Verigakis
            n = len(args) - len(spec.defaults or ())
109 eb3ca8ca Giorgos Verigakis
            required = ' '.join('<%s>' % x.replace('_', ' ') for x in args[:n])
110 eb3ca8ca Giorgos Verigakis
            optional = ' '.join('[%s]' % x.replace('_', ' ') for x in args[n:])
111 eb3ca8ca Giorgos Verigakis
            cls.syntax = ' '.join(x for x in [required, optional] if x)
112 8ab2c986 Giorgos Verigakis
            if spec.varargs:
113 8ab2c986 Giorgos Verigakis
                cls.syntax += ' <%s ...>' % spec.varargs
114 5d1d131b Giorgos Verigakis
        
115 eb3ca8ca Giorgos Verigakis
        if cls.group not in _commands:
116 eb3ca8ca Giorgos Verigakis
            _commands[cls.group] = OrderedDict()
117 eb3ca8ca Giorgos Verigakis
        _commands[cls.group][cls.name] = cls
118 eb3ca8ca Giorgos Verigakis
        return cls
119 eb3ca8ca Giorgos Verigakis
    return decorator
120 5d1d131b Giorgos Verigakis
121 5d1d131b Giorgos Verigakis
122 eb3ca8ca Giorgos Verigakis
@command()
123 eb3ca8ca Giorgos Verigakis
class config_list(object):
124 eb3ca8ca Giorgos Verigakis
    """list configuration options"""
125 eb3ca8ca Giorgos Verigakis
    
126 d2cea1e2 Giorgos Verigakis
    @classmethod
127 d2cea1e2 Giorgos Verigakis
    def update_parser(cls, parser):
128 d2cea1e2 Giorgos Verigakis
        parser.add_option('-a', dest='all', action='store_true',
129 d2cea1e2 Giorgos Verigakis
                default=False, help='include empty values')
130 d2cea1e2 Giorgos Verigakis
    
131 eb3ca8ca Giorgos Verigakis
    def main(self):
132 eb3ca8ca Giorgos Verigakis
        for key, val in sorted(self.config.items()):
133 d2cea1e2 Giorgos Verigakis
            if not val and not self.options.all:
134 d2cea1e2 Giorgos Verigakis
                continue
135 eb3ca8ca Giorgos Verigakis
            print '%s=%s' % (key, val)
136 5d1d131b Giorgos Verigakis
137 5d1d131b Giorgos Verigakis
138 eb3ca8ca Giorgos Verigakis
@command()
139 eb3ca8ca Giorgos Verigakis
class config_get(object):
140 eb3ca8ca Giorgos Verigakis
    """get a configuration option"""
141 5d1d131b Giorgos Verigakis
    
142 eb3ca8ca Giorgos Verigakis
    def main(self, key):
143 eb3ca8ca Giorgos Verigakis
        val = self.config.get(key)
144 eb3ca8ca Giorgos Verigakis
        if val is not None:
145 eb3ca8ca Giorgos Verigakis
            print val
146 eb3ca8ca Giorgos Verigakis
147 eb3ca8ca Giorgos Verigakis
148 eb3ca8ca Giorgos Verigakis
@command()
149 eb3ca8ca Giorgos Verigakis
class config_set(object):
150 eb3ca8ca Giorgos Verigakis
    """set a configuration option"""
151 eb3ca8ca Giorgos Verigakis
    
152 eb3ca8ca Giorgos Verigakis
    def main(self, key, val):
153 eb3ca8ca Giorgos Verigakis
        self.config.set(key, val)
154 eb3ca8ca Giorgos Verigakis
155 eb3ca8ca Giorgos Verigakis
156 eb3ca8ca Giorgos Verigakis
@command()
157 eb3ca8ca Giorgos Verigakis
class config_del(object):
158 eb3ca8ca Giorgos Verigakis
    """delete a configuration option"""
159 eb3ca8ca Giorgos Verigakis
    
160 eb3ca8ca Giorgos Verigakis
    def main(self, key):
161 eb3ca8ca Giorgos Verigakis
        self.config.delete(key)
162 eb3ca8ca Giorgos Verigakis
163 eb3ca8ca Giorgos Verigakis
164 a1c50326 Giorgos Verigakis
@command(api='compute')
165 eb3ca8ca Giorgos Verigakis
class server_list(object):
166 eb3ca8ca Giorgos Verigakis
    """list servers"""
167 eb3ca8ca Giorgos Verigakis
    
168 eb3ca8ca Giorgos Verigakis
    @classmethod
169 eb3ca8ca Giorgos Verigakis
    def update_parser(cls, parser):
170 eb3ca8ca Giorgos Verigakis
        parser.add_option('-l', dest='detail', action='store_true',
171 eb3ca8ca Giorgos Verigakis
                default=False, help='show detailed output')
172 5d1d131b Giorgos Verigakis
    
173 5d1d131b Giorgos Verigakis
    def main(self):
174 eb3ca8ca Giorgos Verigakis
        servers = self.client.list_servers(self.options.detail)
175 a6757cbc Giorgos Verigakis
        print_items(servers)
176 5d1d131b Giorgos Verigakis
177 5d1d131b Giorgos Verigakis
178 a1c50326 Giorgos Verigakis
@command(api='compute')
179 eb3ca8ca Giorgos Verigakis
class server_info(object):
180 eb3ca8ca Giorgos Verigakis
    """get server details"""
181 5d1d131b Giorgos Verigakis
    
182 5d1d131b Giorgos Verigakis
    def main(self, server_id):
183 5d1d131b Giorgos Verigakis
        server = self.client.get_server_details(int(server_id))
184 5d1d131b Giorgos Verigakis
        print_dict(server)
185 5d1d131b Giorgos Verigakis
186 5d1d131b Giorgos Verigakis
187 a1c50326 Giorgos Verigakis
@command(api='compute')
188 eb3ca8ca Giorgos Verigakis
class server_create(object):
189 eb3ca8ca Giorgos Verigakis
    """create server"""
190 76f01c50 Giorgos Verigakis
    
191 eb3ca8ca Giorgos Verigakis
    @classmethod
192 eb3ca8ca Giorgos Verigakis
    def update_parser(cls, parser):
193 eb3ca8ca Giorgos Verigakis
        parser.add_option('--personality', dest='personalities',
194 eb3ca8ca Giorgos Verigakis
                action='append', default=[],
195 eb3ca8ca Giorgos Verigakis
                metavar='PATH[,SERVER PATH[,OWNER[,GROUP,[MODE]]]]',
196 eb3ca8ca Giorgos Verigakis
                help='add a personality file')
197 eb3ca8ca Giorgos Verigakis
        parser.epilog = "If missing, optional personality values will be " \
198 eb3ca8ca Giorgos Verigakis
                "filled based on the file at PATH if missing."
199 eb3ca8ca Giorgos Verigakis
    
200 eb3ca8ca Giorgos Verigakis
    def main(self, name, flavor_id, image_id):
201 57b8dd5a Giorgos Verigakis
        personalities = []
202 eb3ca8ca Giorgos Verigakis
        for personality in self.options.personalities:
203 57b8dd5a Giorgos Verigakis
            p = personality.split(',')
204 57b8dd5a Giorgos Verigakis
            p.extend([None] * (5 - len(p)))     # Fill missing fields with None
205 57b8dd5a Giorgos Verigakis
            
206 57b8dd5a Giorgos Verigakis
            path = p[0]
207 57b8dd5a Giorgos Verigakis
            
208 57b8dd5a Giorgos Verigakis
            if not path:
209 57b8dd5a Giorgos Verigakis
                log.error("Invalid personality argument '%s'", p)
210 eb3ca8ca Giorgos Verigakis
                return 1
211 a1c50326 Giorgos Verigakis
            if not exists(path):
212 57b8dd5a Giorgos Verigakis
                log.error("File %s does not exist", path)
213 eb3ca8ca Giorgos Verigakis
                return 1
214 57b8dd5a Giorgos Verigakis
            
215 57b8dd5a Giorgos Verigakis
            with open(path) as f:
216 57b8dd5a Giorgos Verigakis
                contents = b64encode(f.read())
217 57b8dd5a Giorgos Verigakis
            
218 57b8dd5a Giorgos Verigakis
            st = os.stat(path)
219 57b8dd5a Giorgos Verigakis
            personalities.append({
220 a1c50326 Giorgos Verigakis
                'path': p[1] or abspath(path),
221 57b8dd5a Giorgos Verigakis
                'owner': p[2] or getpwuid(st.st_uid).pw_name,
222 57b8dd5a Giorgos Verigakis
                'group': p[3] or getgrgid(st.st_gid).gr_name,
223 57b8dd5a Giorgos Verigakis
                'mode': int(p[4]) if p[4] else 0x7777 & st.st_mode,
224 57b8dd5a Giorgos Verigakis
                'contents': contents})
225 76f01c50 Giorgos Verigakis
        
226 eb3ca8ca Giorgos Verigakis
        reply = self.client.create_server(name, int(flavor_id), image_id,
227 eb3ca8ca Giorgos Verigakis
                personalities)
228 5d1d131b Giorgos Verigakis
        print_dict(reply)
229 5d1d131b Giorgos Verigakis
230 5d1d131b Giorgos Verigakis
231 a1c50326 Giorgos Verigakis
@command(api='compute')
232 eb3ca8ca Giorgos Verigakis
class server_rename(object):
233 eb3ca8ca Giorgos Verigakis
    """update server name"""
234 5d1d131b Giorgos Verigakis
    
235 5d1d131b Giorgos Verigakis
    def main(self, server_id, new_name):
236 5d1d131b Giorgos Verigakis
        self.client.update_server_name(int(server_id), new_name)
237 5d1d131b Giorgos Verigakis
238 5d1d131b Giorgos Verigakis
239 a1c50326 Giorgos Verigakis
@command(api='compute')
240 eb3ca8ca Giorgos Verigakis
class server_delete(object):
241 eb3ca8ca Giorgos Verigakis
    """delete server"""
242 5d1d131b Giorgos Verigakis
    
243 5d1d131b Giorgos Verigakis
    def main(self, server_id):
244 5d1d131b Giorgos Verigakis
        self.client.delete_server(int(server_id))
245 5d1d131b Giorgos Verigakis
246 5d1d131b Giorgos Verigakis
247 a1c50326 Giorgos Verigakis
@command(api='compute')
248 eb3ca8ca Giorgos Verigakis
class server_reboot(object):
249 eb3ca8ca Giorgos Verigakis
    """reboot server"""
250 5d1d131b Giorgos Verigakis
    
251 eb3ca8ca Giorgos Verigakis
    @classmethod
252 eb3ca8ca Giorgos Verigakis
    def update_parser(cls, parser):
253 eb3ca8ca Giorgos Verigakis
        parser.add_option('-f', dest='hard', action='store_true',
254 eb3ca8ca Giorgos Verigakis
                default=False, help='perform a hard reboot')
255 5d1d131b Giorgos Verigakis
    
256 5d1d131b Giorgos Verigakis
    def main(self, server_id):
257 eb3ca8ca Giorgos Verigakis
        self.client.reboot_server(int(server_id), self.options.hard)
258 5d1d131b Giorgos Verigakis
259 5d1d131b Giorgos Verigakis
260 b3b32add Giorgos Verigakis
@command(api='cyclades')
261 eb3ca8ca Giorgos Verigakis
class server_start(object):
262 eb3ca8ca Giorgos Verigakis
    """start server"""
263 5d1d131b Giorgos Verigakis
    
264 5d1d131b Giorgos Verigakis
    def main(self, server_id):
265 5d1d131b Giorgos Verigakis
        self.client.start_server(int(server_id))
266 5d1d131b Giorgos Verigakis
267 5d1d131b Giorgos Verigakis
268 b3b32add Giorgos Verigakis
@command(api='cyclades')
269 eb3ca8ca Giorgos Verigakis
class server_shutdown(object):
270 eb3ca8ca Giorgos Verigakis
    """shutdown server"""
271 5d1d131b Giorgos Verigakis
    
272 5d1d131b Giorgos Verigakis
    def main(self, server_id):
273 5d1d131b Giorgos Verigakis
        self.client.shutdown_server(int(server_id))
274 5d1d131b Giorgos Verigakis
275 5d1d131b Giorgos Verigakis
276 b3b32add Giorgos Verigakis
@command(api='cyclades')
277 eb3ca8ca Giorgos Verigakis
class server_console(object):
278 eb3ca8ca Giorgos Verigakis
    """get a VNC console"""
279 eb3ca8ca Giorgos Verigakis
    
280 5d1d131b Giorgos Verigakis
    def main(self, server_id):
281 5d1d131b Giorgos Verigakis
        reply = self.client.get_server_console(int(server_id))
282 5d1d131b Giorgos Verigakis
        print_dict(reply)
283 5d1d131b Giorgos Verigakis
284 5d1d131b Giorgos Verigakis
285 b3b32add Giorgos Verigakis
@command(api='cyclades')
286 eb3ca8ca Giorgos Verigakis
class server_firewall(object):
287 eb3ca8ca Giorgos Verigakis
    """set the firewall profile"""
288 5d1d131b Giorgos Verigakis
    
289 5d1d131b Giorgos Verigakis
    def main(self, server_id, profile):
290 5d1d131b Giorgos Verigakis
        self.client.set_firewall_profile(int(server_id), profile)
291 5d1d131b Giorgos Verigakis
292 5d1d131b Giorgos Verigakis
293 b3b32add Giorgos Verigakis
@command(api='cyclades')
294 eb3ca8ca Giorgos Verigakis
class server_addr(object):
295 eb3ca8ca Giorgos Verigakis
    """list server addresses"""
296 5d1d131b Giorgos Verigakis
    
297 5d1d131b Giorgos Verigakis
    def main(self, server_id, network=None):
298 5d1d131b Giorgos Verigakis
        reply = self.client.list_server_addresses(int(server_id), network)
299 5d1d131b Giorgos Verigakis
        margin = max(len(x['name']) for x in reply)
300 5d1d131b Giorgos Verigakis
        print_addresses(reply, margin)
301 5d1d131b Giorgos Verigakis
302 5d1d131b Giorgos Verigakis
303 a1c50326 Giorgos Verigakis
@command(api='compute')
304 eb3ca8ca Giorgos Verigakis
class server_meta(object):
305 eb3ca8ca Giorgos Verigakis
    """get server metadata"""
306 5d1d131b Giorgos Verigakis
    
307 5d1d131b Giorgos Verigakis
    def main(self, server_id, key=None):
308 5d1d131b Giorgos Verigakis
        reply = self.client.get_server_metadata(int(server_id), key)
309 5d1d131b Giorgos Verigakis
        print_dict(reply)
310 5d1d131b Giorgos Verigakis
311 5d1d131b Giorgos Verigakis
312 a1c50326 Giorgos Verigakis
@command(api='compute')
313 eb3ca8ca Giorgos Verigakis
class server_addmeta(object):
314 eb3ca8ca Giorgos Verigakis
    """add server metadata"""
315 5d1d131b Giorgos Verigakis
    
316 5d1d131b Giorgos Verigakis
    def main(self, server_id, key, val):
317 5d1d131b Giorgos Verigakis
        reply = self.client.create_server_metadata(int(server_id), key, val)
318 5d1d131b Giorgos Verigakis
        print_dict(reply)
319 5d1d131b Giorgos Verigakis
320 5d1d131b Giorgos Verigakis
321 a1c50326 Giorgos Verigakis
@command(api='compute')
322 eb3ca8ca Giorgos Verigakis
class server_setmeta(object):
323 eb3ca8ca Giorgos Verigakis
    """update server metadata"""
324 5d1d131b Giorgos Verigakis
    
325 5d1d131b Giorgos Verigakis
    def main(self, server_id, key, val):
326 ec52784d Giorgos Verigakis
        metadata = {key: val}
327 ec52784d Giorgos Verigakis
        reply = self.client.update_server_metadata(int(server_id), **metadata)
328 5d1d131b Giorgos Verigakis
        print_dict(reply)
329 5d1d131b Giorgos Verigakis
330 5d1d131b Giorgos Verigakis
331 a1c50326 Giorgos Verigakis
@command(api='compute')
332 eb3ca8ca Giorgos Verigakis
class server_delmeta(object):
333 eb3ca8ca Giorgos Verigakis
    """delete server metadata"""
334 5d1d131b Giorgos Verigakis
    
335 5d1d131b Giorgos Verigakis
    def main(self, server_id, key):
336 5d1d131b Giorgos Verigakis
        self.client.delete_server_metadata(int(server_id), key)
337 5d1d131b Giorgos Verigakis
338 5d1d131b Giorgos Verigakis
339 b3b32add Giorgos Verigakis
@command(api='cyclades')
340 eb3ca8ca Giorgos Verigakis
class server_stats(object):
341 eb3ca8ca Giorgos Verigakis
    """get server statistics"""
342 5d1d131b Giorgos Verigakis
    
343 5d1d131b Giorgos Verigakis
    def main(self, server_id):
344 5d1d131b Giorgos Verigakis
        reply = self.client.get_server_stats(int(server_id))
345 5d1d131b Giorgos Verigakis
        print_dict(reply, exclude=('serverRef',))
346 5d1d131b Giorgos Verigakis
347 5d1d131b Giorgos Verigakis
348 a1c50326 Giorgos Verigakis
@command(api='compute')
349 eb3ca8ca Giorgos Verigakis
class flavor_list(object):
350 eb3ca8ca Giorgos Verigakis
    """list flavors"""
351 eb3ca8ca Giorgos Verigakis
    
352 eb3ca8ca Giorgos Verigakis
    @classmethod
353 eb3ca8ca Giorgos Verigakis
    def update_parser(cls, parser):
354 eb3ca8ca Giorgos Verigakis
        parser.add_option('-l', dest='detail', action='store_true',
355 eb3ca8ca Giorgos Verigakis
                default=False, help='show detailed output')
356 5d1d131b Giorgos Verigakis
    
357 5d1d131b Giorgos Verigakis
    def main(self):
358 eb3ca8ca Giorgos Verigakis
        flavors = self.client.list_flavors(self.options.detail)
359 a6757cbc Giorgos Verigakis
        print_items(flavors)
360 5d1d131b Giorgos Verigakis
361 5d1d131b Giorgos Verigakis
362 a1c50326 Giorgos Verigakis
@command(api='compute')
363 eb3ca8ca Giorgos Verigakis
class flavor_info(object):
364 eb3ca8ca Giorgos Verigakis
    """get flavor details"""
365 5d1d131b Giorgos Verigakis
    
366 5d1d131b Giorgos Verigakis
    def main(self, flavor_id):
367 5d1d131b Giorgos Verigakis
        flavor = self.client.get_flavor_details(int(flavor_id))
368 5d1d131b Giorgos Verigakis
        print_dict(flavor)
369 5d1d131b Giorgos Verigakis
370 5d1d131b Giorgos Verigakis
371 a1c50326 Giorgos Verigakis
@command(api='compute')
372 eb3ca8ca Giorgos Verigakis
class image_list(object):
373 eb3ca8ca Giorgos Verigakis
    """list images"""
374 eb3ca8ca Giorgos Verigakis
    
375 eb3ca8ca Giorgos Verigakis
    @classmethod
376 eb3ca8ca Giorgos Verigakis
    def update_parser(cls, parser):
377 eb3ca8ca Giorgos Verigakis
        parser.add_option('-l', dest='detail', action='store_true',
378 eb3ca8ca Giorgos Verigakis
                default=False, help='show detailed output')
379 eb3ca8ca Giorgos Verigakis
    
380 5d1d131b Giorgos Verigakis
    def main(self):
381 eb3ca8ca Giorgos Verigakis
        images = self.client.list_images(self.options.detail)
382 a6757cbc Giorgos Verigakis
        print_items(images)
383 5d1d131b Giorgos Verigakis
384 5d1d131b Giorgos Verigakis
385 a1c50326 Giorgos Verigakis
@command(api='compute')
386 eb3ca8ca Giorgos Verigakis
class image_info(object):
387 eb3ca8ca Giorgos Verigakis
    """get image details"""
388 5d1d131b Giorgos Verigakis
    
389 5d1d131b Giorgos Verigakis
    def main(self, image_id):
390 eb3ca8ca Giorgos Verigakis
        image = self.client.get_image_details(image_id)
391 5d1d131b Giorgos Verigakis
        print_dict(image)
392 5d1d131b Giorgos Verigakis
393 5d1d131b Giorgos Verigakis
394 a1c50326 Giorgos Verigakis
@command(api='compute')
395 eb3ca8ca Giorgos Verigakis
class image_delete(object):
396 eb3ca8ca Giorgos Verigakis
    """delete image"""
397 5d1d131b Giorgos Verigakis
    
398 5d1d131b Giorgos Verigakis
    def main(self, image_id):
399 eb3ca8ca Giorgos Verigakis
        self.client.delete_image(image_id)
400 5d1d131b Giorgos Verigakis
401 5d1d131b Giorgos Verigakis
402 a1c50326 Giorgos Verigakis
@command(api='compute')
403 eb3ca8ca Giorgos Verigakis
class image_meta(object):
404 eb3ca8ca Giorgos Verigakis
    """get image metadata"""
405 5d1d131b Giorgos Verigakis
    
406 5d1d131b Giorgos Verigakis
    def main(self, image_id, key=None):
407 eb3ca8ca Giorgos Verigakis
        reply = self.client.get_image_metadata(image_id, key)
408 5d1d131b Giorgos Verigakis
        print_dict(reply)
409 5d1d131b Giorgos Verigakis
410 5d1d131b Giorgos Verigakis
411 a1c50326 Giorgos Verigakis
@command(api='compute')
412 eb3ca8ca Giorgos Verigakis
class image_addmeta(object):
413 eb3ca8ca Giorgos Verigakis
    """add image metadata"""
414 5d1d131b Giorgos Verigakis
    
415 5d1d131b Giorgos Verigakis
    def main(self, image_id, key, val):
416 eb3ca8ca Giorgos Verigakis
        reply = self.client.create_image_metadata(image_id, key, val)
417 5d1d131b Giorgos Verigakis
        print_dict(reply)
418 5d1d131b Giorgos Verigakis
419 5d1d131b Giorgos Verigakis
420 a1c50326 Giorgos Verigakis
@command(api='compute')
421 eb3ca8ca Giorgos Verigakis
class image_setmeta(object):
422 eb3ca8ca Giorgos Verigakis
    """update image metadata"""
423 5d1d131b Giorgos Verigakis
    
424 5d1d131b Giorgos Verigakis
    def main(self, image_id, key, val):
425 ec52784d Giorgos Verigakis
        metadata = {key: val}
426 eb3ca8ca Giorgos Verigakis
        reply = self.client.update_image_metadata(image_id, **metadata)
427 5d1d131b Giorgos Verigakis
        print_dict(reply)
428 5d1d131b Giorgos Verigakis
429 5d1d131b Giorgos Verigakis
430 a1c50326 Giorgos Verigakis
@command(api='compute')
431 eb3ca8ca Giorgos Verigakis
class image_delmeta(object):
432 eb3ca8ca Giorgos Verigakis
    """delete image metadata"""
433 5d1d131b Giorgos Verigakis
    
434 5d1d131b Giorgos Verigakis
    def main(self, image_id, key):
435 eb3ca8ca Giorgos Verigakis
        self.client.delete_image_metadata(image_id, key)
436 5d1d131b Giorgos Verigakis
437 5d1d131b Giorgos Verigakis
438 b3b32add Giorgos Verigakis
@command(api='cyclades')
439 eb3ca8ca Giorgos Verigakis
class network_list(object):
440 eb3ca8ca Giorgos Verigakis
    """list networks"""
441 5d1d131b Giorgos Verigakis
    
442 eb3ca8ca Giorgos Verigakis
    @classmethod
443 eb3ca8ca Giorgos Verigakis
    def update_parser(cls, parser):
444 eb3ca8ca Giorgos Verigakis
        parser.add_option('-l', dest='detail', action='store_true',
445 eb3ca8ca Giorgos Verigakis
                default=False, help='show detailed output')
446 5d1d131b Giorgos Verigakis
    
447 5d1d131b Giorgos Verigakis
    def main(self):
448 eb3ca8ca Giorgos Verigakis
        networks = self.client.list_networks(self.options.detail)
449 a6757cbc Giorgos Verigakis
        print_items(networks)
450 5d1d131b Giorgos Verigakis
451 5d1d131b Giorgos Verigakis
452 b3b32add Giorgos Verigakis
@command(api='cyclades')
453 eb3ca8ca Giorgos Verigakis
class network_create(object):
454 eb3ca8ca Giorgos Verigakis
    """create a network"""
455 5d1d131b Giorgos Verigakis
    
456 5d1d131b Giorgos Verigakis
    def main(self, name):
457 5d1d131b Giorgos Verigakis
        reply = self.client.create_network(name)
458 5d1d131b Giorgos Verigakis
        print_dict(reply)
459 5d1d131b Giorgos Verigakis
460 5d1d131b Giorgos Verigakis
461 b3b32add Giorgos Verigakis
@command(api='cyclades')
462 eb3ca8ca Giorgos Verigakis
class network_info(object):
463 eb3ca8ca Giorgos Verigakis
    """get network details"""
464 eb3ca8ca Giorgos Verigakis
    
465 5d1d131b Giorgos Verigakis
    def main(self, network_id):
466 5d1d131b Giorgos Verigakis
        network = self.client.get_network_details(network_id)
467 5d1d131b Giorgos Verigakis
        print_dict(network)
468 5d1d131b Giorgos Verigakis
469 5d1d131b Giorgos Verigakis
470 b3b32add Giorgos Verigakis
@command(api='cyclades')
471 eb3ca8ca Giorgos Verigakis
class network_rename(object):
472 eb3ca8ca Giorgos Verigakis
    """update network name"""
473 5d1d131b Giorgos Verigakis
    
474 eb3ca8ca Giorgos Verigakis
    def main(self, network_id, new_name):
475 eb3ca8ca Giorgos Verigakis
        self.client.update_network_name(network_id, new_name)
476 5d1d131b Giorgos Verigakis
477 5d1d131b Giorgos Verigakis
478 b3b32add Giorgos Verigakis
@command(api='cyclades')
479 eb3ca8ca Giorgos Verigakis
class network_delete(object):
480 eb3ca8ca Giorgos Verigakis
    """delete a network"""
481 5d1d131b Giorgos Verigakis
    
482 5d1d131b Giorgos Verigakis
    def main(self, network_id):
483 5d1d131b Giorgos Verigakis
        self.client.delete_network(network_id)
484 5d1d131b Giorgos Verigakis
485 eb3ca8ca Giorgos Verigakis
486 b3b32add Giorgos Verigakis
@command(api='cyclades')
487 eb3ca8ca Giorgos Verigakis
class network_connect(object):
488 eb3ca8ca Giorgos Verigakis
    """connect a server to a network"""
489 5d1d131b Giorgos Verigakis
    
490 5d1d131b Giorgos Verigakis
    def main(self, server_id, network_id):
491 5d1d131b Giorgos Verigakis
        self.client.connect_server(server_id, network_id)
492 5d1d131b Giorgos Verigakis
493 5d1d131b Giorgos Verigakis
494 b3b32add Giorgos Verigakis
@command(api='cyclades')
495 eb3ca8ca Giorgos Verigakis
class network_disconnect(object):
496 eb3ca8ca Giorgos Verigakis
    """disconnect a server from a network"""
497 eb3ca8ca Giorgos Verigakis
    
498 5d1d131b Giorgos Verigakis
    def main(self, server_id, network_id):
499 5d1d131b Giorgos Verigakis
        self.client.disconnect_server(server_id, network_id)
500 5d1d131b Giorgos Verigakis
501 5d1d131b Giorgos Verigakis
502 a1c50326 Giorgos Verigakis
@command(api='image')
503 eb3ca8ca Giorgos Verigakis
class glance_list(object):
504 eb3ca8ca Giorgos Verigakis
    """list images"""
505 5d1d131b Giorgos Verigakis
    
506 a6757cbc Giorgos Verigakis
    @classmethod
507 a6757cbc Giorgos Verigakis
    def update_parser(cls, parser):
508 a6757cbc Giorgos Verigakis
        parser.add_option('-l', dest='detail', action='store_true',
509 a6757cbc Giorgos Verigakis
                default=False, help='show detailed output')
510 a6757cbc Giorgos Verigakis
        parser.add_option('--container-format', dest='container_format',
511 a6757cbc Giorgos Verigakis
                metavar='FORMAT', help='filter by container format')
512 a6757cbc Giorgos Verigakis
        parser.add_option('--disk-format', dest='disk_format',
513 a6757cbc Giorgos Verigakis
                metavar='FORMAT', help='filter by disk format')
514 a6757cbc Giorgos Verigakis
        parser.add_option('--name', dest='name', metavar='NAME',
515 a6757cbc Giorgos Verigakis
                help='filter by name')
516 a6757cbc Giorgos Verigakis
        parser.add_option('--size-min', dest='size_min', metavar='BYTES',
517 a6757cbc Giorgos Verigakis
                help='filter by minimum size')
518 a6757cbc Giorgos Verigakis
        parser.add_option('--size-max', dest='size_max', metavar='BYTES',
519 a6757cbc Giorgos Verigakis
                help='filter by maximum size')
520 a6757cbc Giorgos Verigakis
        parser.add_option('--status', dest='status', metavar='STATUS',
521 a6757cbc Giorgos Verigakis
                help='filter by status')
522 a6757cbc Giorgos Verigakis
        parser.add_option('--order', dest='order', metavar='FIELD',
523 a6757cbc Giorgos Verigakis
                help='order by FIELD (use a - prefix to reverse order)')
524 a6757cbc Giorgos Verigakis
    
525 eb3ca8ca Giorgos Verigakis
    def main(self):
526 a6757cbc Giorgos Verigakis
        filters = {}
527 a6757cbc Giorgos Verigakis
        for filter in ('container_format', 'disk_format', 'name', 'size_min',
528 a6757cbc Giorgos Verigakis
                       'size_max', 'status'):
529 a6757cbc Giorgos Verigakis
            val = getattr(self.options, filter, None)
530 a6757cbc Giorgos Verigakis
            if val is not None:
531 a6757cbc Giorgos Verigakis
                filters[filter] = val
532 a6757cbc Giorgos Verigakis
        
533 a6757cbc Giorgos Verigakis
        order = self.options.order or ''
534 a6757cbc Giorgos Verigakis
        images = self.client.list_public(self.options.detail, filters=filters,
535 a6757cbc Giorgos Verigakis
                                         order=order)
536 a6757cbc Giorgos Verigakis
        print_items(images, title=('name',))
537 a6757cbc Giorgos Verigakis
538 a6757cbc Giorgos Verigakis
539 a1c50326 Giorgos Verigakis
@command(api='image')
540 8ab2c986 Giorgos Verigakis
class glance_meta(object):
541 8ab2c986 Giorgos Verigakis
    """get image metadata"""
542 8ab2c986 Giorgos Verigakis
    
543 8ab2c986 Giorgos Verigakis
    def main(self, image_id):
544 8ab2c986 Giorgos Verigakis
        image = self.client.get_meta(image_id)
545 8ab2c986 Giorgos Verigakis
        print_dict(image)
546 8ab2c986 Giorgos Verigakis
547 8ab2c986 Giorgos Verigakis
548 a1c50326 Giorgos Verigakis
@command(api='image')
549 a6757cbc Giorgos Verigakis
class glance_register(object):
550 a6757cbc Giorgos Verigakis
    """register an image"""
551 a6757cbc Giorgos Verigakis
    
552 a6757cbc Giorgos Verigakis
    @classmethod
553 a6757cbc Giorgos Verigakis
    def update_parser(cls, parser):
554 a6757cbc Giorgos Verigakis
        parser.add_option('--checksum', dest='checksum', metavar='CHECKSUM',
555 a6757cbc Giorgos Verigakis
                help='set image checksum')
556 a6757cbc Giorgos Verigakis
        parser.add_option('--container-format', dest='container_format',
557 a6757cbc Giorgos Verigakis
                metavar='FORMAT', help='set container format')
558 a6757cbc Giorgos Verigakis
        parser.add_option('--disk-format', dest='disk_format',
559 a6757cbc Giorgos Verigakis
                metavar='FORMAT', help='set disk format')
560 a6757cbc Giorgos Verigakis
        parser.add_option('--id', dest='id',
561 a6757cbc Giorgos Verigakis
                metavar='ID', help='set image ID')
562 a6757cbc Giorgos Verigakis
        parser.add_option('--owner', dest='owner',
563 a6757cbc Giorgos Verigakis
                metavar='USER', help='set image owner (admin only)')
564 a6757cbc Giorgos Verigakis
        parser.add_option('--property', dest='properties', action='append',
565 a6757cbc Giorgos Verigakis
                metavar='KEY=VAL',
566 a6757cbc Giorgos Verigakis
                help='add a property (can be used multiple times)')
567 a6757cbc Giorgos Verigakis
        parser.add_option('--public', dest='is_public', action='store_true',
568 a6757cbc Giorgos Verigakis
                help='mark image as public')
569 a6757cbc Giorgos Verigakis
        parser.add_option('--size', dest='size', metavar='SIZE',
570 a6757cbc Giorgos Verigakis
                help='set image size')
571 a6757cbc Giorgos Verigakis
    
572 a6757cbc Giorgos Verigakis
    def main(self, name, location):
573 a6757cbc Giorgos Verigakis
        params = {}
574 a6757cbc Giorgos Verigakis
        for key in ('checksum', 'container_format', 'disk_format', 'id',
575 a6757cbc Giorgos Verigakis
                    'owner', 'is_public', 'size'):
576 a6757cbc Giorgos Verigakis
            val = getattr(self.options, key)
577 a6757cbc Giorgos Verigakis
            if val is not None:
578 a6757cbc Giorgos Verigakis
                params[key] = val
579 a6757cbc Giorgos Verigakis
        
580 a6757cbc Giorgos Verigakis
        properties = {}
581 a6757cbc Giorgos Verigakis
        for property in self.options.properties or []:
582 a6757cbc Giorgos Verigakis
            key, sep, val = property.partition('=')
583 a6757cbc Giorgos Verigakis
            if not sep:
584 a6757cbc Giorgos Verigakis
                log.error("Invalid property '%s'", property)
585 a6757cbc Giorgos Verigakis
                return 1
586 a6757cbc Giorgos Verigakis
            properties[key.strip()] = val.strip()
587 a6757cbc Giorgos Verigakis
        
588 a6757cbc Giorgos Verigakis
        self.client.register(name, location, params, properties)
589 eb3ca8ca Giorgos Verigakis
590 eb3ca8ca Giorgos Verigakis
591 a1c50326 Giorgos Verigakis
@command(api='image')
592 8ab2c986 Giorgos Verigakis
class glance_members(object):
593 8ab2c986 Giorgos Verigakis
    """get image members"""
594 8ab2c986 Giorgos Verigakis
    
595 8ab2c986 Giorgos Verigakis
    def main(self, image_id):
596 8ab2c986 Giorgos Verigakis
        members = self.client.list_members(image_id)
597 8ab2c986 Giorgos Verigakis
        for member in members:
598 8ab2c986 Giorgos Verigakis
            print member['member_id']
599 8ab2c986 Giorgos Verigakis
600 8ab2c986 Giorgos Verigakis
601 a1c50326 Giorgos Verigakis
@command(api='image')
602 8ab2c986 Giorgos Verigakis
class glance_shared(object):
603 8ab2c986 Giorgos Verigakis
    """list shared images"""
604 8ab2c986 Giorgos Verigakis
    
605 8ab2c986 Giorgos Verigakis
    def main(self, member):
606 8ab2c986 Giorgos Verigakis
        images = self.client.list_shared(member)
607 8ab2c986 Giorgos Verigakis
        for image in images:
608 8ab2c986 Giorgos Verigakis
            print image['image_id']
609 8ab2c986 Giorgos Verigakis
610 8ab2c986 Giorgos Verigakis
611 a1c50326 Giorgos Verigakis
@command(api='image')
612 8ab2c986 Giorgos Verigakis
class glance_addmember(object):
613 8ab2c986 Giorgos Verigakis
    """add a member to an image"""
614 8ab2c986 Giorgos Verigakis
    
615 8ab2c986 Giorgos Verigakis
    def main(self, image_id, member):
616 8ab2c986 Giorgos Verigakis
        self.client.add_member(image_id, member)
617 8ab2c986 Giorgos Verigakis
618 8ab2c986 Giorgos Verigakis
619 a1c50326 Giorgos Verigakis
@command(api='image')
620 8ab2c986 Giorgos Verigakis
class glance_delmember(object):
621 8ab2c986 Giorgos Verigakis
    """remove a member from an image"""
622 8ab2c986 Giorgos Verigakis
    
623 8ab2c986 Giorgos Verigakis
    def main(self, image_id, member):
624 8ab2c986 Giorgos Verigakis
        self.client.remove_member(image_id, member)
625 8ab2c986 Giorgos Verigakis
626 8ab2c986 Giorgos Verigakis
627 a1c50326 Giorgos Verigakis
@command(api='image')
628 8ab2c986 Giorgos Verigakis
class glance_setmembers(object):
629 8ab2c986 Giorgos Verigakis
    """set the members of an image"""
630 8ab2c986 Giorgos Verigakis
    
631 8ab2c986 Giorgos Verigakis
    def main(self, image_id, *member):
632 8ab2c986 Giorgos Verigakis
        self.client.set_members(image_id, member)
633 8ab2c986 Giorgos Verigakis
634 8ab2c986 Giorgos Verigakis
635 176894c1 Giorgos Verigakis
class store_command(object):
636 176894c1 Giorgos Verigakis
    """base class for all store_* commands"""
637 d2cea1e2 Giorgos Verigakis
    
638 d2cea1e2 Giorgos Verigakis
    @classmethod
639 d2cea1e2 Giorgos Verigakis
    def update_parser(cls, parser):
640 60560d7c Giorgos Verigakis
        parser.add_option('--account', dest='account', metavar='NAME',
641 60560d7c Giorgos Verigakis
                help='use account NAME')
642 60560d7c Giorgos Verigakis
        parser.add_option('--container', dest='container', metavar='NAME',
643 60560d7c Giorgos Verigakis
                help='use container NAME')
644 d2cea1e2 Giorgos Verigakis
    
645 d2cea1e2 Giorgos Verigakis
    def main(self):
646 d2cea1e2 Giorgos Verigakis
        self.config.override('storage_account', self.options.account)
647 d2cea1e2 Giorgos Verigakis
        self.config.override('storage_container', self.options.container)
648 176894c1 Giorgos Verigakis
        
649 176894c1 Giorgos Verigakis
        # Use the more efficient Pithos client if available
650 176894c1 Giorgos Verigakis
        if 'pithos' in self.config.get('apis').split():
651 176894c1 Giorgos Verigakis
            self.client = clients.PithosClient(self.config)
652 176894c1 Giorgos Verigakis
653 176894c1 Giorgos Verigakis
654 176894c1 Giorgos Verigakis
@command(api='storage')
655 60560d7c Giorgos Verigakis
class store_create(object):
656 60560d7c Giorgos Verigakis
    """create a container"""
657 60560d7c Giorgos Verigakis
    
658 60560d7c Giorgos Verigakis
    @classmethod
659 60560d7c Giorgos Verigakis
    def update_parser(cls, parser):
660 60560d7c Giorgos Verigakis
        parser.add_option('--account', dest='account', metavar='ACCOUNT',
661 60560d7c Giorgos Verigakis
                help='use account ACCOUNT')
662 60560d7c Giorgos Verigakis
    
663 60560d7c Giorgos Verigakis
    def main(self, container):
664 60560d7c Giorgos Verigakis
        self.config.override('storage_account', self.options.account)
665 60560d7c Giorgos Verigakis
        self.client.create_container(container)
666 60560d7c Giorgos Verigakis
667 60560d7c Giorgos Verigakis
668 60560d7c Giorgos Verigakis
@command(api='storage')
669 176894c1 Giorgos Verigakis
class store_container(store_command):
670 176894c1 Giorgos Verigakis
    """get container info"""
671 176894c1 Giorgos Verigakis
    
672 176894c1 Giorgos Verigakis
    def main(self):
673 176894c1 Giorgos Verigakis
        store_command.main(self)
674 d2cea1e2 Giorgos Verigakis
        reply = self.client.get_container_meta()
675 d2cea1e2 Giorgos Verigakis
        print_dict(reply)
676 d2cea1e2 Giorgos Verigakis
677 d2cea1e2 Giorgos Verigakis
678 d2cea1e2 Giorgos Verigakis
@command(api='storage')
679 176894c1 Giorgos Verigakis
class store_upload(store_command):
680 a1c50326 Giorgos Verigakis
    """upload a file"""
681 a1c50326 Giorgos Verigakis
    
682 a1c50326 Giorgos Verigakis
    def main(self, path, remote_path=None):
683 176894c1 Giorgos Verigakis
        store_command.main(self)
684 a1c50326 Giorgos Verigakis
        if remote_path is None:
685 a1c50326 Giorgos Verigakis
            remote_path = basename(path)
686 a1c50326 Giorgos Verigakis
        with open(path) as f:
687 d2cea1e2 Giorgos Verigakis
            self.client.create_object(remote_path, f)
688 d2cea1e2 Giorgos Verigakis
689 d2cea1e2 Giorgos Verigakis
690 d2cea1e2 Giorgos Verigakis
@command(api='storage')
691 176894c1 Giorgos Verigakis
class store_download(store_command):
692 176894c1 Giorgos Verigakis
    """download a file"""
693 d2cea1e2 Giorgos Verigakis
    
694 176894c1 Giorgos Verigakis
    def main(self, remote_path, local_path):
695 176894c1 Giorgos Verigakis
        store_command.main(self)
696 176894c1 Giorgos Verigakis
        f = self.client.get_object(remote_path)
697 176894c1 Giorgos Verigakis
        out = open(local_path, 'w') if local_path != '-' else stdout
698 176894c1 Giorgos Verigakis
        block = 4096
699 176894c1 Giorgos Verigakis
        data = f.read(block)
700 176894c1 Giorgos Verigakis
        while data:
701 176894c1 Giorgos Verigakis
            out.write(data)
702 176894c1 Giorgos Verigakis
            data = f.read(block)
703 176894c1 Giorgos Verigakis
704 176894c1 Giorgos Verigakis
705 176894c1 Giorgos Verigakis
@command(api='storage')
706 176894c1 Giorgos Verigakis
class store_delete(store_command):
707 176894c1 Giorgos Verigakis
    """delete a file"""
708 d2cea1e2 Giorgos Verigakis
    
709 d2cea1e2 Giorgos Verigakis
    def main(self, path):
710 176894c1 Giorgos Verigakis
        store_command.main(self)
711 d2cea1e2 Giorgos Verigakis
        self.client.delete_object(path)
712 a1c50326 Giorgos Verigakis
713 a1c50326 Giorgos Verigakis
714 eb3ca8ca Giorgos Verigakis
def print_groups(groups):
715 eb3ca8ca Giorgos Verigakis
    print
716 eb3ca8ca Giorgos Verigakis
    print 'Groups:'
717 eb3ca8ca Giorgos Verigakis
    for group in groups:
718 eb3ca8ca Giorgos Verigakis
        print '  %s' % group
719 eb3ca8ca Giorgos Verigakis
720 eb3ca8ca Giorgos Verigakis
721 eb3ca8ca Giorgos Verigakis
def print_commands(group, commands):
722 5d1d131b Giorgos Verigakis
    print
723 5d1d131b Giorgos Verigakis
    print 'Commands:'
724 eb3ca8ca Giorgos Verigakis
    for name, cls in _commands[group].items():
725 eb3ca8ca Giorgos Verigakis
        if name in commands:
726 eb3ca8ca Giorgos Verigakis
            print '  %s %s' % (name.ljust(10), cls.description)
727 5d1d131b Giorgos Verigakis
728 5d1d131b Giorgos Verigakis
729 5d1d131b Giorgos Verigakis
def main():
730 a1c50326 Giorgos Verigakis
    ch = logging.StreamHandler()
731 a1c50326 Giorgos Verigakis
    ch.setFormatter(logging.Formatter('%(message)s'))
732 a1c50326 Giorgos Verigakis
    log.addHandler(ch)
733 a1c50326 Giorgos Verigakis
    
734 eb3ca8ca Giorgos Verigakis
    parser = OptionParser(add_help_option=False)
735 eb3ca8ca Giorgos Verigakis
    parser.usage = '%prog <group> <command> [options]'
736 eb3ca8ca Giorgos Verigakis
    parser.add_option('--help', dest='help', action='store_true',
737 eb3ca8ca Giorgos Verigakis
            default=False, help='show this help message and exit')
738 eb3ca8ca Giorgos Verigakis
    parser.add_option('-v', dest='verbose', action='store_true', default=False,
739 eb3ca8ca Giorgos Verigakis
            help='use verbose output')
740 eb3ca8ca Giorgos Verigakis
    parser.add_option('-d', dest='debug', action='store_true', default=False,
741 eb3ca8ca Giorgos Verigakis
            help='use debug output')
742 21cf6792 Giorgos Verigakis
    parser.add_option('-o', dest='options', action='append',
743 21cf6792 Giorgos Verigakis
            metavar='KEY=VAL',
744 21cf6792 Giorgos Verigakis
            help='override a config value (can be used multiple times)')
745 eb3ca8ca Giorgos Verigakis
    
746 eb3ca8ca Giorgos Verigakis
    # Do a preliminary parsing, ignore any errors since we will print help
747 eb3ca8ca Giorgos Verigakis
    # anyway if we don't reach the main parsing.
748 eb3ca8ca Giorgos Verigakis
    _error = parser.error
749 eb3ca8ca Giorgos Verigakis
    parser.error = lambda msg: None
750 a1c50326 Giorgos Verigakis
    options, args = parser.parse_args(argv)
751 eb3ca8ca Giorgos Verigakis
    parser.error = _error
752 eb3ca8ca Giorgos Verigakis
    
753 eb3ca8ca Giorgos Verigakis
    if options.debug:
754 eb3ca8ca Giorgos Verigakis
        log.setLevel(logging.DEBUG)
755 eb3ca8ca Giorgos Verigakis
    elif options.verbose:
756 eb3ca8ca Giorgos Verigakis
        log.setLevel(logging.INFO)
757 eb3ca8ca Giorgos Verigakis
    else:
758 eb3ca8ca Giorgos Verigakis
        log.setLevel(logging.WARNING)
759 5d1d131b Giorgos Verigakis
    
760 eb3ca8ca Giorgos Verigakis
    try:
761 a1c50326 Giorgos Verigakis
        config = Config()
762 eb3ca8ca Giorgos Verigakis
    except ConfigError, e:
763 eb3ca8ca Giorgos Verigakis
        log.error('%s', e.args[0])
764 a1c50326 Giorgos Verigakis
        exit(1)
765 eb3ca8ca Giorgos Verigakis
    
766 21cf6792 Giorgos Verigakis
    for option in options.options or []:
767 21cf6792 Giorgos Verigakis
        key, sep, val = option.partition('=')
768 21cf6792 Giorgos Verigakis
        if not sep:
769 21cf6792 Giorgos Verigakis
            log.error('Invalid option "%s"', option)
770 21cf6792 Giorgos Verigakis
            exit(1)
771 21cf6792 Giorgos Verigakis
        config.override(key.strip(), val.strip())
772 21cf6792 Giorgos Verigakis
    
773 eb3ca8ca Giorgos Verigakis
    apis = config.get('apis').split()
774 eb3ca8ca Giorgos Verigakis
    
775 eb3ca8ca Giorgos Verigakis
    # Find available groups based on the given APIs
776 eb3ca8ca Giorgos Verigakis
    available_groups = []
777 eb3ca8ca Giorgos Verigakis
    for group, group_commands in _commands.items():
778 eb3ca8ca Giorgos Verigakis
        for name, cls in group_commands.items():
779 eb3ca8ca Giorgos Verigakis
            if cls.api is None or cls.api in apis:
780 eb3ca8ca Giorgos Verigakis
                available_groups.append(group)
781 eb3ca8ca Giorgos Verigakis
                break
782 eb3ca8ca Giorgos Verigakis
    
783 eb3ca8ca Giorgos Verigakis
    if len(args) < 2:
784 eb3ca8ca Giorgos Verigakis
        parser.print_help()
785 eb3ca8ca Giorgos Verigakis
        print_groups(available_groups)
786 a1c50326 Giorgos Verigakis
        exit(0)
787 eb3ca8ca Giorgos Verigakis
    
788 eb3ca8ca Giorgos Verigakis
    group = args[1]
789 eb3ca8ca Giorgos Verigakis
    
790 eb3ca8ca Giorgos Verigakis
    if group not in available_groups:
791 eb3ca8ca Giorgos Verigakis
        parser.print_help()
792 eb3ca8ca Giorgos Verigakis
        print_groups(available_groups)
793 a1c50326 Giorgos Verigakis
        exit(1)
794 eb3ca8ca Giorgos Verigakis
    
795 eb3ca8ca Giorgos Verigakis
    # Find available commands based on the given APIs
796 eb3ca8ca Giorgos Verigakis
    available_commands = []
797 eb3ca8ca Giorgos Verigakis
    for name, cls in _commands[group].items():
798 eb3ca8ca Giorgos Verigakis
        if cls.api is None or cls.api in apis:
799 eb3ca8ca Giorgos Verigakis
            available_commands.append(name)
800 eb3ca8ca Giorgos Verigakis
            continue
801 eb3ca8ca Giorgos Verigakis
    
802 eb3ca8ca Giorgos Verigakis
    parser.usage = '%%prog %s <command> [options]' % group
803 eb3ca8ca Giorgos Verigakis
    
804 eb3ca8ca Giorgos Verigakis
    if len(args) < 3:
805 eb3ca8ca Giorgos Verigakis
        parser.print_help()
806 eb3ca8ca Giorgos Verigakis
        print_commands(group, available_commands)
807 a1c50326 Giorgos Verigakis
        exit(0)
808 eb3ca8ca Giorgos Verigakis
    
809 eb3ca8ca Giorgos Verigakis
    name = args[2]
810 5d1d131b Giorgos Verigakis
    
811 eb3ca8ca Giorgos Verigakis
    if name not in available_commands:
812 eb3ca8ca Giorgos Verigakis
        parser.print_help()
813 eb3ca8ca Giorgos Verigakis
        print_commands(group, available_commands)
814 a1c50326 Giorgos Verigakis
        exit(1)
815 5d1d131b Giorgos Verigakis
    
816 eb3ca8ca Giorgos Verigakis
    cls = _commands[group][name]
817 5d1d131b Giorgos Verigakis
    
818 eb3ca8ca Giorgos Verigakis
    syntax = '%s [options]' % cls.syntax if cls.syntax else '[options]'
819 eb3ca8ca Giorgos Verigakis
    parser.usage = '%%prog %s %s %s' % (group, name, syntax)
820 eb3ca8ca Giorgos Verigakis
    parser.epilog = ''
821 eb3ca8ca Giorgos Verigakis
    if hasattr(cls, 'update_parser'):
822 eb3ca8ca Giorgos Verigakis
        cls.update_parser(parser)
823 eb3ca8ca Giorgos Verigakis
    
824 a1c50326 Giorgos Verigakis
    options, args = parser.parse_args(argv)
825 eb3ca8ca Giorgos Verigakis
    if options.help:
826 eb3ca8ca Giorgos Verigakis
        parser.print_help()
827 a1c50326 Giorgos Verigakis
        exit(0)
828 eb3ca8ca Giorgos Verigakis
    
829 eb3ca8ca Giorgos Verigakis
    cmd = cls()
830 eb3ca8ca Giorgos Verigakis
    cmd.config = config
831 eb3ca8ca Giorgos Verigakis
    cmd.options = options
832 eb3ca8ca Giorgos Verigakis
    
833 d2cea1e2 Giorgos Verigakis
    if cmd.api:
834 d2cea1e2 Giorgos Verigakis
        client_name = cmd.api.capitalize() + 'Client'
835 d2cea1e2 Giorgos Verigakis
        client = getattr(clients, client_name, None)
836 d2cea1e2 Giorgos Verigakis
        if client:
837 d2cea1e2 Giorgos Verigakis
            cmd.client = client(config)
838 5d1d131b Giorgos Verigakis
    
839 5d1d131b Giorgos Verigakis
    try:
840 a1c50326 Giorgos Verigakis
        ret = cmd.main(*args[3:])
841 a1c50326 Giorgos Verigakis
        exit(ret)
842 a6757cbc Giorgos Verigakis
    except TypeError as e:
843 a6757cbc Giorgos Verigakis
        if e.args and e.args[0].startswith('main()'):
844 a6757cbc Giorgos Verigakis
            parser.print_help()
845 a1c50326 Giorgos Verigakis
            exit(1)
846 a6757cbc Giorgos Verigakis
        else:
847 a6757cbc Giorgos Verigakis
            raise
848 a1c50326 Giorgos Verigakis
    except clients.ClientError, err:
849 653b0597 Giorgos Verigakis
        log.error('%s', err.message)
850 653b0597 Giorgos Verigakis
        log.info('%s', err.details)
851 a1c50326 Giorgos Verigakis
        exit(2)
852 5d1d131b Giorgos Verigakis
853 5d1d131b Giorgos Verigakis
854 5d1d131b Giorgos Verigakis
if __name__ == '__main__':
855 a1c50326 Giorgos Verigakis
    main()