Statistics
| Branch: | Tag: | Revision:

root / kamaki / cli.py @ 5afb968b

History | View | Annotate | Download (30.9 kB)

1 5d1d131b Giorgos Verigakis
#!/usr/bin/env python
2 5d1d131b Giorgos Verigakis
3 dba6ec94 Giorgos Verigakis
# Copyright 2011-2012 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 8db3fc19 Giorgos Verigakis
from __future__ import print_function
70 8db3fc19 Giorgos Verigakis
71 5d1d131b Giorgos Verigakis
import inspect
72 5d1d131b Giorgos Verigakis
import logging
73 56ccdbee Giorgos Verigakis
import sys
74 5d1d131b Giorgos Verigakis
75 56ccdbee Giorgos Verigakis
from argparse import ArgumentParser
76 57b8dd5a Giorgos Verigakis
from base64 import b64encode
77 2d0b6dcc Giorgos Verigakis
from os.path import abspath, basename, exists
78 56ccdbee Giorgos Verigakis
from sys import exit, stdout, stderr
79 5d1d131b Giorgos Verigakis
80 5afb968b Giorgos Verigakis
try:
81 5afb968b Giorgos Verigakis
    from collections import OrderedDict
82 5afb968b Giorgos Verigakis
except ImportError:
83 5afb968b Giorgos Verigakis
    from ordereddict import OrderedDict
84 5afb968b Giorgos Verigakis
85 6422f717 Giorgos Verigakis
from colors import magenta, red, yellow
86 4ef14fb3 Giorgos Verigakis
from progress.bar import IncrementalBar
87 df79206f Giorgos Verigakis
from requests.exceptions import ConnectionError
88 df79206f Giorgos Verigakis
89 5afb968b Giorgos Verigakis
from . import clients
90 5afb968b Giorgos Verigakis
from .config import Config
91 5afb968b Giorgos Verigakis
from .utils import print_addresses, print_dict, print_items
92 5d1d131b Giorgos Verigakis
93 5d1d131b Giorgos Verigakis
94 eb3ca8ca Giorgos Verigakis
_commands = OrderedDict()
95 eb3ca8ca Giorgos Verigakis
96 653b0597 Giorgos Verigakis
97 cae67d7b Giorgos Verigakis
GROUPS = {
98 cae67d7b Giorgos Verigakis
    'config': "Configuration commands",
99 cae67d7b Giorgos Verigakis
    'server': "Compute API server commands",
100 cae67d7b Giorgos Verigakis
    'flavor': "Compute API flavor commands",
101 8f5f3101 Giorgos Verigakis
    'image': "Compute or Glance API image commands",
102 cae67d7b Giorgos Verigakis
    'network': "Compute API network commands (Cyclades extension)",
103 dba6ec94 Giorgos Verigakis
    'store': "Storage API commands",
104 dba6ec94 Giorgos Verigakis
    'astakos': "Astakos API commands"}
105 cae67d7b Giorgos Verigakis
106 cae67d7b Giorgos Verigakis
107 4ef14fb3 Giorgos Verigakis
class ProgressBar(IncrementalBar):
108 4ef14fb3 Giorgos Verigakis
    suffix = '%(percent)d%% - %(eta)ds'
109 4ef14fb3 Giorgos Verigakis
110 4ef14fb3 Giorgos Verigakis
111 cae67d7b Giorgos Verigakis
def command(api=None, group=None, name=None, syntax=None):
112 eb3ca8ca Giorgos Verigakis
    """Class decorator that registers a class as a CLI command."""
113 eb3ca8ca Giorgos Verigakis
    
114 eb3ca8ca Giorgos Verigakis
    def decorator(cls):
115 eb3ca8ca Giorgos Verigakis
        grp, sep, cmd = cls.__name__.partition('_')
116 eb3ca8ca Giorgos Verigakis
        if not sep:
117 eb3ca8ca Giorgos Verigakis
            grp, cmd = None, cls.__name__
118 5d1d131b Giorgos Verigakis
        
119 eb3ca8ca Giorgos Verigakis
        cls.api = api
120 eb3ca8ca Giorgos Verigakis
        cls.group = group or grp
121 eb3ca8ca Giorgos Verigakis
        cls.name = name or cmd
122 5d1d131b Giorgos Verigakis
        
123 cae67d7b Giorgos Verigakis
        short_description, sep, long_description = cls.__doc__.partition('\n')
124 cae67d7b Giorgos Verigakis
        cls.description = short_description
125 cae67d7b Giorgos Verigakis
        cls.long_description = long_description or short_description
126 cae67d7b Giorgos Verigakis
        
127 cae67d7b Giorgos Verigakis
        cls.syntax = syntax
128 eb3ca8ca Giorgos Verigakis
        if cls.syntax is None:
129 eb3ca8ca Giorgos Verigakis
            # Generate a syntax string based on main's arguments
130 eb3ca8ca Giorgos Verigakis
            spec = inspect.getargspec(cls.main.im_func)
131 eb3ca8ca Giorgos Verigakis
            args = spec.args[1:]
132 eb3ca8ca Giorgos Verigakis
            n = len(args) - len(spec.defaults or ())
133 eb3ca8ca Giorgos Verigakis
            required = ' '.join('<%s>' % x.replace('_', ' ') for x in args[:n])
134 eb3ca8ca Giorgos Verigakis
            optional = ' '.join('[%s]' % x.replace('_', ' ') for x in args[n:])
135 eb3ca8ca Giorgos Verigakis
            cls.syntax = ' '.join(x for x in [required, optional] if x)
136 8ab2c986 Giorgos Verigakis
            if spec.varargs:
137 8ab2c986 Giorgos Verigakis
                cls.syntax += ' <%s ...>' % spec.varargs
138 5d1d131b Giorgos Verigakis
        
139 eb3ca8ca Giorgos Verigakis
        if cls.group not in _commands:
140 eb3ca8ca Giorgos Verigakis
            _commands[cls.group] = OrderedDict()
141 eb3ca8ca Giorgos Verigakis
        _commands[cls.group][cls.name] = cls
142 eb3ca8ca Giorgos Verigakis
        return cls
143 eb3ca8ca Giorgos Verigakis
    return decorator
144 5d1d131b Giorgos Verigakis
145 5d1d131b Giorgos Verigakis
146 cae67d7b Giorgos Verigakis
@command(api='config')
147 eb3ca8ca Giorgos Verigakis
class config_list(object):
148 cae67d7b Giorgos Verigakis
    """List configuration options"""
149 eb3ca8ca Giorgos Verigakis
    
150 a4f3a88e Giorgos Verigakis
    def update_parser(self, parser):
151 56ccdbee Giorgos Verigakis
        parser.add_argument('-a', dest='all', action='store_true',
152 cae67d7b Giorgos Verigakis
                          default=False, help='include default values')
153 56ccdbee Giorgos Verigakis
154 eb3ca8ca Giorgos Verigakis
    def main(self):
155 56ccdbee Giorgos Verigakis
        include_defaults = self.args.all
156 cae67d7b Giorgos Verigakis
        for section in sorted(self.config.sections()):
157 cae67d7b Giorgos Verigakis
            items = self.config.items(section, include_defaults)
158 cae67d7b Giorgos Verigakis
            for key, val in sorted(items):
159 8db3fc19 Giorgos Verigakis
                print('%s.%s = %s' % (section, key, val))
160 5d1d131b Giorgos Verigakis
161 5d1d131b Giorgos Verigakis
162 cae67d7b Giorgos Verigakis
@command(api='config')
163 eb3ca8ca Giorgos Verigakis
class config_get(object):
164 cae67d7b Giorgos Verigakis
    """Show a configuration option"""
165 5d1d131b Giorgos Verigakis
    
166 cae67d7b Giorgos Verigakis
    def main(self, option):
167 cae67d7b Giorgos Verigakis
        section, sep, key = option.rpartition('.')
168 cae67d7b Giorgos Verigakis
        section = section or 'global'
169 cae67d7b Giorgos Verigakis
        value = self.config.get(section, key)
170 cae67d7b Giorgos Verigakis
        if value is not None:
171 8db3fc19 Giorgos Verigakis
            print(value)
172 eb3ca8ca Giorgos Verigakis
173 eb3ca8ca Giorgos Verigakis
174 cae67d7b Giorgos Verigakis
@command(api='config')
175 eb3ca8ca Giorgos Verigakis
class config_set(object):
176 cae67d7b Giorgos Verigakis
    """Set a configuration option"""
177 eb3ca8ca Giorgos Verigakis
    
178 cae67d7b Giorgos Verigakis
    def main(self, option, value):
179 cae67d7b Giorgos Verigakis
        section, sep, key = option.rpartition('.')
180 cae67d7b Giorgos Verigakis
        section = section or 'global'
181 cae67d7b Giorgos Verigakis
        self.config.set(section, key, value)
182 cae67d7b Giorgos Verigakis
        self.config.write()
183 eb3ca8ca Giorgos Verigakis
184 eb3ca8ca Giorgos Verigakis
185 cae67d7b Giorgos Verigakis
@command(api='config')
186 cae67d7b Giorgos Verigakis
class config_delete(object):
187 cae67d7b Giorgos Verigakis
    """Delete a configuration option (and use the default value)"""
188 eb3ca8ca Giorgos Verigakis
    
189 cae67d7b Giorgos Verigakis
    def main(self, option):
190 cae67d7b Giorgos Verigakis
        section, sep, key = option.rpartition('.')
191 cae67d7b Giorgos Verigakis
        section = section or 'global'
192 cae67d7b Giorgos Verigakis
        self.config.remove_option(section, key)
193 cae67d7b Giorgos Verigakis
        self.config.write()
194 eb3ca8ca Giorgos Verigakis
195 eb3ca8ca Giorgos Verigakis
196 a1c50326 Giorgos Verigakis
@command(api='compute')
197 eb3ca8ca Giorgos Verigakis
class server_list(object):
198 df79206f Giorgos Verigakis
    """List servers"""
199 eb3ca8ca Giorgos Verigakis
    
200 a4f3a88e Giorgos Verigakis
    def update_parser(self, parser):
201 56ccdbee Giorgos Verigakis
        parser.add_argument('-l', dest='detail', action='store_true',
202 eb3ca8ca Giorgos Verigakis
                default=False, help='show detailed output')
203 56ccdbee Giorgos Verigakis
204 5d1d131b Giorgos Verigakis
    def main(self):
205 56ccdbee Giorgos Verigakis
        servers = self.client.list_servers(self.args.detail)
206 a6757cbc Giorgos Verigakis
        print_items(servers)
207 5d1d131b Giorgos Verigakis
208 5d1d131b Giorgos Verigakis
209 a1c50326 Giorgos Verigakis
@command(api='compute')
210 eb3ca8ca Giorgos Verigakis
class server_info(object):
211 df79206f Giorgos Verigakis
    """Get server details"""
212 5d1d131b Giorgos Verigakis
    
213 5d1d131b Giorgos Verigakis
    def main(self, server_id):
214 5d1d131b Giorgos Verigakis
        server = self.client.get_server_details(int(server_id))
215 5d1d131b Giorgos Verigakis
        print_dict(server)
216 5d1d131b Giorgos Verigakis
217 5d1d131b Giorgos Verigakis
218 a1c50326 Giorgos Verigakis
@command(api='compute')
219 eb3ca8ca Giorgos Verigakis
class server_create(object):
220 df79206f Giorgos Verigakis
    """Create a server"""
221 76f01c50 Giorgos Verigakis
    
222 a4f3a88e Giorgos Verigakis
    def update_parser(self, parser):
223 56ccdbee Giorgos Verigakis
        parser.add_argument('--personality', dest='personalities',
224 df79206f Giorgos Verigakis
                          action='append', default=[],
225 df79206f Giorgos Verigakis
                          metavar='PATH[,SERVER PATH[,OWNER[,GROUP,[MODE]]]]',
226 df79206f Giorgos Verigakis
                          help='add a personality file')
227 56ccdbee Giorgos Verigakis
228 eb3ca8ca Giorgos Verigakis
    def main(self, name, flavor_id, image_id):
229 57b8dd5a Giorgos Verigakis
        personalities = []
230 56ccdbee Giorgos Verigakis
        for personality in self.args.personalities:
231 57b8dd5a Giorgos Verigakis
            p = personality.split(',')
232 57b8dd5a Giorgos Verigakis
            p.extend([None] * (5 - len(p)))     # Fill missing fields with None
233 57b8dd5a Giorgos Verigakis
            
234 57b8dd5a Giorgos Verigakis
            path = p[0]
235 57b8dd5a Giorgos Verigakis
            
236 57b8dd5a Giorgos Verigakis
            if not path:
237 8db3fc19 Giorgos Verigakis
                print("Invalid personality argument '%s'" % p)
238 eb3ca8ca Giorgos Verigakis
                return 1
239 a1c50326 Giorgos Verigakis
            if not exists(path):
240 8db3fc19 Giorgos Verigakis
                print("File %s does not exist" % path)
241 eb3ca8ca Giorgos Verigakis
                return 1
242 57b8dd5a Giorgos Verigakis
            
243 57b8dd5a Giorgos Verigakis
            with open(path) as f:
244 57b8dd5a Giorgos Verigakis
                contents = b64encode(f.read())
245 f6d137ea Giorgos Verigakis
246 f6d137ea Giorgos Verigakis
            d = {'path': p[1] or abspath(path), 'contents': contents}
247 f6d137ea Giorgos Verigakis
            if p[2]:
248 f6d137ea Giorgos Verigakis
                d['owner'] = p[2]
249 f6d137ea Giorgos Verigakis
            if p[3]:
250 f6d137ea Giorgos Verigakis
                d['group'] = p[3]
251 f6d137ea Giorgos Verigakis
            if p[4]:
252 f6d137ea Giorgos Verigakis
                d['mode'] = int(p[4])
253 f6d137ea Giorgos Verigakis
            personalities.append(d)
254 f6d137ea Giorgos Verigakis
255 eb3ca8ca Giorgos Verigakis
        reply = self.client.create_server(name, int(flavor_id), image_id,
256 eb3ca8ca Giorgos Verigakis
                personalities)
257 5d1d131b Giorgos Verigakis
        print_dict(reply)
258 5d1d131b Giorgos Verigakis
259 5d1d131b Giorgos Verigakis
260 a1c50326 Giorgos Verigakis
@command(api='compute')
261 eb3ca8ca Giorgos Verigakis
class server_rename(object):
262 df79206f Giorgos Verigakis
    """Update a server's name"""
263 5d1d131b Giorgos Verigakis
    
264 5d1d131b Giorgos Verigakis
    def main(self, server_id, new_name):
265 5d1d131b Giorgos Verigakis
        self.client.update_server_name(int(server_id), new_name)
266 5d1d131b Giorgos Verigakis
267 5d1d131b Giorgos Verigakis
268 a1c50326 Giorgos Verigakis
@command(api='compute')
269 eb3ca8ca Giorgos Verigakis
class server_delete(object):
270 df79206f Giorgos Verigakis
    """Delete a server"""
271 5d1d131b Giorgos Verigakis
    
272 5d1d131b Giorgos Verigakis
    def main(self, server_id):
273 5d1d131b Giorgos Verigakis
        self.client.delete_server(int(server_id))
274 5d1d131b Giorgos Verigakis
275 5d1d131b Giorgos Verigakis
276 a1c50326 Giorgos Verigakis
@command(api='compute')
277 eb3ca8ca Giorgos Verigakis
class server_reboot(object):
278 df79206f Giorgos Verigakis
    """Reboot a server"""
279 5d1d131b Giorgos Verigakis
    
280 a4f3a88e Giorgos Verigakis
    def update_parser(self, parser):
281 56ccdbee Giorgos Verigakis
        parser.add_argument('-f', dest='hard', action='store_true',
282 eb3ca8ca Giorgos Verigakis
                default=False, help='perform a hard reboot')
283 56ccdbee Giorgos Verigakis
284 5d1d131b Giorgos Verigakis
    def main(self, server_id):
285 56ccdbee Giorgos Verigakis
        self.client.reboot_server(int(server_id), self.args.hard)
286 5d1d131b Giorgos Verigakis
287 5d1d131b Giorgos Verigakis
288 b3b32add Giorgos Verigakis
@command(api='cyclades')
289 eb3ca8ca Giorgos Verigakis
class server_start(object):
290 df79206f Giorgos Verigakis
    """Start a server"""
291 5d1d131b Giorgos Verigakis
    
292 5d1d131b Giorgos Verigakis
    def main(self, server_id):
293 5d1d131b Giorgos Verigakis
        self.client.start_server(int(server_id))
294 5d1d131b Giorgos Verigakis
295 5d1d131b Giorgos Verigakis
296 b3b32add Giorgos Verigakis
@command(api='cyclades')
297 eb3ca8ca Giorgos Verigakis
class server_shutdown(object):
298 df79206f Giorgos Verigakis
    """Shutdown a server"""
299 5d1d131b Giorgos Verigakis
    
300 5d1d131b Giorgos Verigakis
    def main(self, server_id):
301 5d1d131b Giorgos Verigakis
        self.client.shutdown_server(int(server_id))
302 5d1d131b Giorgos Verigakis
303 5d1d131b Giorgos Verigakis
304 b3b32add Giorgos Verigakis
@command(api='cyclades')
305 eb3ca8ca Giorgos Verigakis
class server_console(object):
306 df79206f Giorgos Verigakis
    """Get a VNC console"""
307 eb3ca8ca Giorgos Verigakis
    
308 5d1d131b Giorgos Verigakis
    def main(self, server_id):
309 5d1d131b Giorgos Verigakis
        reply = self.client.get_server_console(int(server_id))
310 5d1d131b Giorgos Verigakis
        print_dict(reply)
311 5d1d131b Giorgos Verigakis
312 5d1d131b Giorgos Verigakis
313 b3b32add Giorgos Verigakis
@command(api='cyclades')
314 eb3ca8ca Giorgos Verigakis
class server_firewall(object):
315 df79206f Giorgos Verigakis
    """Set the server's firewall profile"""
316 5d1d131b Giorgos Verigakis
    
317 5d1d131b Giorgos Verigakis
    def main(self, server_id, profile):
318 5d1d131b Giorgos Verigakis
        self.client.set_firewall_profile(int(server_id), profile)
319 5d1d131b Giorgos Verigakis
320 5d1d131b Giorgos Verigakis
321 b3b32add Giorgos Verigakis
@command(api='cyclades')
322 eb3ca8ca Giorgos Verigakis
class server_addr(object):
323 df79206f Giorgos Verigakis
    """List a server's addresses"""
324 5d1d131b Giorgos Verigakis
    
325 5d1d131b Giorgos Verigakis
    def main(self, server_id, network=None):
326 5d1d131b Giorgos Verigakis
        reply = self.client.list_server_addresses(int(server_id), network)
327 5d1d131b Giorgos Verigakis
        margin = max(len(x['name']) for x in reply)
328 5d1d131b Giorgos Verigakis
        print_addresses(reply, margin)
329 5d1d131b Giorgos Verigakis
330 5d1d131b Giorgos Verigakis
331 a1c50326 Giorgos Verigakis
@command(api='compute')
332 eb3ca8ca Giorgos Verigakis
class server_meta(object):
333 df79206f Giorgos Verigakis
    """Get a server's metadata"""
334 5d1d131b Giorgos Verigakis
    
335 5d1d131b Giorgos Verigakis
    def main(self, server_id, key=None):
336 5d1d131b Giorgos Verigakis
        reply = self.client.get_server_metadata(int(server_id), key)
337 5d1d131b Giorgos Verigakis
        print_dict(reply)
338 5d1d131b Giorgos Verigakis
339 5d1d131b Giorgos Verigakis
340 a1c50326 Giorgos Verigakis
@command(api='compute')
341 eb3ca8ca Giorgos Verigakis
class server_addmeta(object):
342 df79206f Giorgos Verigakis
    """Add server metadata"""
343 5d1d131b Giorgos Verigakis
    
344 5d1d131b Giorgos Verigakis
    def main(self, server_id, key, val):
345 5d1d131b Giorgos Verigakis
        reply = self.client.create_server_metadata(int(server_id), key, val)
346 5d1d131b Giorgos Verigakis
        print_dict(reply)
347 5d1d131b Giorgos Verigakis
348 5d1d131b Giorgos Verigakis
349 a1c50326 Giorgos Verigakis
@command(api='compute')
350 eb3ca8ca Giorgos Verigakis
class server_setmeta(object):
351 df79206f Giorgos Verigakis
    """Update server's metadata"""
352 5d1d131b Giorgos Verigakis
    
353 5d1d131b Giorgos Verigakis
    def main(self, server_id, key, val):
354 ec52784d Giorgos Verigakis
        metadata = {key: val}
355 ec52784d Giorgos Verigakis
        reply = self.client.update_server_metadata(int(server_id), **metadata)
356 5d1d131b Giorgos Verigakis
        print_dict(reply)
357 5d1d131b Giorgos Verigakis
358 5d1d131b Giorgos Verigakis
359 a1c50326 Giorgos Verigakis
@command(api='compute')
360 eb3ca8ca Giorgos Verigakis
class server_delmeta(object):
361 df79206f Giorgos Verigakis
    """Delete server metadata"""
362 5d1d131b Giorgos Verigakis
    
363 5d1d131b Giorgos Verigakis
    def main(self, server_id, key):
364 5d1d131b Giorgos Verigakis
        self.client.delete_server_metadata(int(server_id), key)
365 5d1d131b Giorgos Verigakis
366 5d1d131b Giorgos Verigakis
367 b3b32add Giorgos Verigakis
@command(api='cyclades')
368 eb3ca8ca Giorgos Verigakis
class server_stats(object):
369 df79206f Giorgos Verigakis
    """Get server statistics"""
370 5d1d131b Giorgos Verigakis
    
371 5d1d131b Giorgos Verigakis
    def main(self, server_id):
372 5d1d131b Giorgos Verigakis
        reply = self.client.get_server_stats(int(server_id))
373 5d1d131b Giorgos Verigakis
        print_dict(reply, exclude=('serverRef',))
374 5d1d131b Giorgos Verigakis
375 5d1d131b Giorgos Verigakis
376 a1c50326 Giorgos Verigakis
@command(api='compute')
377 eb3ca8ca Giorgos Verigakis
class flavor_list(object):
378 df79206f Giorgos Verigakis
    """List flavors"""
379 eb3ca8ca Giorgos Verigakis
    
380 a4f3a88e Giorgos Verigakis
    def update_parser(self, parser):
381 56ccdbee Giorgos Verigakis
        parser.add_argument('-l', dest='detail', action='store_true',
382 eb3ca8ca Giorgos Verigakis
                default=False, help='show detailed output')
383 56ccdbee Giorgos Verigakis
384 5d1d131b Giorgos Verigakis
    def main(self):
385 56ccdbee Giorgos Verigakis
        flavors = self.client.list_flavors(self.args.detail)
386 a6757cbc Giorgos Verigakis
        print_items(flavors)
387 5d1d131b Giorgos Verigakis
388 5d1d131b Giorgos Verigakis
389 a1c50326 Giorgos Verigakis
@command(api='compute')
390 eb3ca8ca Giorgos Verigakis
class flavor_info(object):
391 df79206f Giorgos Verigakis
    """Get flavor details"""
392 5d1d131b Giorgos Verigakis
    
393 5d1d131b Giorgos Verigakis
    def main(self, flavor_id):
394 5d1d131b Giorgos Verigakis
        flavor = self.client.get_flavor_details(int(flavor_id))
395 5d1d131b Giorgos Verigakis
        print_dict(flavor)
396 5d1d131b Giorgos Verigakis
397 5d1d131b Giorgos Verigakis
398 a1c50326 Giorgos Verigakis
@command(api='compute')
399 eb3ca8ca Giorgos Verigakis
class image_list(object):
400 df79206f Giorgos Verigakis
    """List images"""
401 eb3ca8ca Giorgos Verigakis
    
402 a4f3a88e Giorgos Verigakis
    def update_parser(self, parser):
403 56ccdbee Giorgos Verigakis
        parser.add_argument('-l', dest='detail', action='store_true',
404 eb3ca8ca Giorgos Verigakis
                default=False, help='show detailed output')
405 56ccdbee Giorgos Verigakis
406 5d1d131b Giorgos Verigakis
    def main(self):
407 56ccdbee Giorgos Verigakis
        images = self.client.list_images(self.args.detail)
408 a6757cbc Giorgos Verigakis
        print_items(images)
409 5d1d131b Giorgos Verigakis
410 5d1d131b Giorgos Verigakis
411 a1c50326 Giorgos Verigakis
@command(api='compute')
412 eb3ca8ca Giorgos Verigakis
class image_info(object):
413 df79206f Giorgos Verigakis
    """Get image details"""
414 5d1d131b Giorgos Verigakis
    
415 5d1d131b Giorgos Verigakis
    def main(self, image_id):
416 eb3ca8ca Giorgos Verigakis
        image = self.client.get_image_details(image_id)
417 5d1d131b Giorgos Verigakis
        print_dict(image)
418 5d1d131b Giorgos Verigakis
419 5d1d131b Giorgos Verigakis
420 a1c50326 Giorgos Verigakis
@command(api='compute')
421 eb3ca8ca Giorgos Verigakis
class image_delete(object):
422 df79206f Giorgos Verigakis
    """Delete image"""
423 5d1d131b Giorgos Verigakis
    
424 5d1d131b Giorgos Verigakis
    def main(self, image_id):
425 eb3ca8ca Giorgos Verigakis
        self.client.delete_image(image_id)
426 5d1d131b Giorgos Verigakis
427 5d1d131b Giorgos Verigakis
428 a1c50326 Giorgos Verigakis
@command(api='compute')
429 8f5f3101 Giorgos Verigakis
class image_properties(object):
430 8f5f3101 Giorgos Verigakis
    """Get image properties"""
431 5d1d131b Giorgos Verigakis
    
432 5d1d131b Giorgos Verigakis
    def main(self, image_id, key=None):
433 eb3ca8ca Giorgos Verigakis
        reply = self.client.get_image_metadata(image_id, key)
434 5d1d131b Giorgos Verigakis
        print_dict(reply)
435 5d1d131b Giorgos Verigakis
436 5d1d131b Giorgos Verigakis
437 a1c50326 Giorgos Verigakis
@command(api='compute')
438 8f5f3101 Giorgos Verigakis
class image_addproperty(object):
439 8f5f3101 Giorgos Verigakis
    """Add an image property"""
440 5d1d131b Giorgos Verigakis
    
441 5d1d131b Giorgos Verigakis
    def main(self, image_id, key, val):
442 eb3ca8ca Giorgos Verigakis
        reply = self.client.create_image_metadata(image_id, key, val)
443 5d1d131b Giorgos Verigakis
        print_dict(reply)
444 5d1d131b Giorgos Verigakis
445 5d1d131b Giorgos Verigakis
446 a1c50326 Giorgos Verigakis
@command(api='compute')
447 8f5f3101 Giorgos Verigakis
class image_setproperty(object):
448 8f5f3101 Giorgos Verigakis
    """Update an image property"""
449 5d1d131b Giorgos Verigakis
    
450 5d1d131b Giorgos Verigakis
    def main(self, image_id, key, val):
451 ec52784d Giorgos Verigakis
        metadata = {key: val}
452 eb3ca8ca Giorgos Verigakis
        reply = self.client.update_image_metadata(image_id, **metadata)
453 5d1d131b Giorgos Verigakis
        print_dict(reply)
454 5d1d131b Giorgos Verigakis
455 5d1d131b Giorgos Verigakis
456 a1c50326 Giorgos Verigakis
@command(api='compute')
457 8f5f3101 Giorgos Verigakis
class image_delproperty(object):
458 8f5f3101 Giorgos Verigakis
    """Delete an image property"""
459 5d1d131b Giorgos Verigakis
    
460 5d1d131b Giorgos Verigakis
    def main(self, image_id, key):
461 eb3ca8ca Giorgos Verigakis
        self.client.delete_image_metadata(image_id, key)
462 5d1d131b Giorgos Verigakis
463 5d1d131b Giorgos Verigakis
464 b3b32add Giorgos Verigakis
@command(api='cyclades')
465 eb3ca8ca Giorgos Verigakis
class network_list(object):
466 df79206f Giorgos Verigakis
    """List networks"""
467 5d1d131b Giorgos Verigakis
    
468 a4f3a88e Giorgos Verigakis
    def update_parser(self, parser):
469 56ccdbee Giorgos Verigakis
        parser.add_argument('-l', dest='detail', action='store_true',
470 eb3ca8ca Giorgos Verigakis
                default=False, help='show detailed output')
471 56ccdbee Giorgos Verigakis
472 5d1d131b Giorgos Verigakis
    def main(self):
473 56ccdbee Giorgos Verigakis
        networks = self.client.list_networks(self.args.detail)
474 a6757cbc Giorgos Verigakis
        print_items(networks)
475 5d1d131b Giorgos Verigakis
476 5d1d131b Giorgos Verigakis
477 b3b32add Giorgos Verigakis
@command(api='cyclades')
478 eb3ca8ca Giorgos Verigakis
class network_create(object):
479 df79206f Giorgos Verigakis
    """Create a network"""
480 5d1d131b Giorgos Verigakis
    
481 5d1d131b Giorgos Verigakis
    def main(self, name):
482 5d1d131b Giorgos Verigakis
        reply = self.client.create_network(name)
483 5d1d131b Giorgos Verigakis
        print_dict(reply)
484 5d1d131b Giorgos Verigakis
485 5d1d131b Giorgos Verigakis
486 b3b32add Giorgos Verigakis
@command(api='cyclades')
487 eb3ca8ca Giorgos Verigakis
class network_info(object):
488 df79206f Giorgos Verigakis
    """Get network details"""
489 eb3ca8ca Giorgos Verigakis
    
490 5d1d131b Giorgos Verigakis
    def main(self, network_id):
491 5d1d131b Giorgos Verigakis
        network = self.client.get_network_details(network_id)
492 5d1d131b Giorgos Verigakis
        print_dict(network)
493 5d1d131b Giorgos Verigakis
494 5d1d131b Giorgos Verigakis
495 b3b32add Giorgos Verigakis
@command(api='cyclades')
496 eb3ca8ca Giorgos Verigakis
class network_rename(object):
497 df79206f Giorgos Verigakis
    """Update network name"""
498 5d1d131b Giorgos Verigakis
    
499 eb3ca8ca Giorgos Verigakis
    def main(self, network_id, new_name):
500 eb3ca8ca Giorgos Verigakis
        self.client.update_network_name(network_id, new_name)
501 5d1d131b Giorgos Verigakis
502 5d1d131b Giorgos Verigakis
503 b3b32add Giorgos Verigakis
@command(api='cyclades')
504 eb3ca8ca Giorgos Verigakis
class network_delete(object):
505 df79206f Giorgos Verigakis
    """Delete a network"""
506 5d1d131b Giorgos Verigakis
    
507 5d1d131b Giorgos Verigakis
    def main(self, network_id):
508 5d1d131b Giorgos Verigakis
        self.client.delete_network(network_id)
509 5d1d131b Giorgos Verigakis
510 eb3ca8ca Giorgos Verigakis
511 b3b32add Giorgos Verigakis
@command(api='cyclades')
512 eb3ca8ca Giorgos Verigakis
class network_connect(object):
513 df79206f Giorgos Verigakis
    """Connect a server to a network"""
514 5d1d131b Giorgos Verigakis
    
515 5d1d131b Giorgos Verigakis
    def main(self, server_id, network_id):
516 5d1d131b Giorgos Verigakis
        self.client.connect_server(server_id, network_id)
517 5d1d131b Giorgos Verigakis
518 5d1d131b Giorgos Verigakis
519 b3b32add Giorgos Verigakis
@command(api='cyclades')
520 eb3ca8ca Giorgos Verigakis
class network_disconnect(object):
521 df79206f Giorgos Verigakis
    """Disconnect a server from a network"""
522 eb3ca8ca Giorgos Verigakis
    
523 5d1d131b Giorgos Verigakis
    def main(self, server_id, network_id):
524 5d1d131b Giorgos Verigakis
        self.client.disconnect_server(server_id, network_id)
525 5d1d131b Giorgos Verigakis
526 5d1d131b Giorgos Verigakis
527 a1c50326 Giorgos Verigakis
@command(api='image')
528 8f5f3101 Giorgos Verigakis
class image_public(object):
529 8f5f3101 Giorgos Verigakis
    """List public images"""
530 5d1d131b Giorgos Verigakis
    
531 a4f3a88e Giorgos Verigakis
    def update_parser(self, parser):
532 56ccdbee Giorgos Verigakis
        parser.add_argument('-l', dest='detail', action='store_true',
533 a6757cbc Giorgos Verigakis
                default=False, help='show detailed output')
534 56ccdbee Giorgos Verigakis
        parser.add_argument('--container-format', dest='container_format',
535 a6757cbc Giorgos Verigakis
                metavar='FORMAT', help='filter by container format')
536 56ccdbee Giorgos Verigakis
        parser.add_argument('--disk-format', dest='disk_format',
537 a6757cbc Giorgos Verigakis
                metavar='FORMAT', help='filter by disk format')
538 56ccdbee Giorgos Verigakis
        parser.add_argument('--name', dest='name', metavar='NAME',
539 a6757cbc Giorgos Verigakis
                help='filter by name')
540 56ccdbee Giorgos Verigakis
        parser.add_argument('--size-min', dest='size_min', metavar='BYTES',
541 a6757cbc Giorgos Verigakis
                help='filter by minimum size')
542 56ccdbee Giorgos Verigakis
        parser.add_argument('--size-max', dest='size_max', metavar='BYTES',
543 a6757cbc Giorgos Verigakis
                help='filter by maximum size')
544 56ccdbee Giorgos Verigakis
        parser.add_argument('--status', dest='status', metavar='STATUS',
545 a6757cbc Giorgos Verigakis
                help='filter by status')
546 56ccdbee Giorgos Verigakis
        parser.add_argument('--order', dest='order', metavar='FIELD',
547 a6757cbc Giorgos Verigakis
                help='order by FIELD (use a - prefix to reverse order)')
548 56ccdbee Giorgos Verigakis
549 eb3ca8ca Giorgos Verigakis
    def main(self):
550 a6757cbc Giorgos Verigakis
        filters = {}
551 a6757cbc Giorgos Verigakis
        for filter in ('container_format', 'disk_format', 'name', 'size_min',
552 a6757cbc Giorgos Verigakis
                       'size_max', 'status'):
553 56ccdbee Giorgos Verigakis
            val = getattr(self.args, filter, None)
554 a6757cbc Giorgos Verigakis
            if val is not None:
555 a6757cbc Giorgos Verigakis
                filters[filter] = val
556 a6757cbc Giorgos Verigakis
        
557 56ccdbee Giorgos Verigakis
        order = self.args.order or ''
558 56ccdbee Giorgos Verigakis
        images = self.client.list_public(self.args.detail, filters=filters,
559 a6757cbc Giorgos Verigakis
                                         order=order)
560 a6757cbc Giorgos Verigakis
        print_items(images, title=('name',))
561 a6757cbc Giorgos Verigakis
562 a6757cbc Giorgos Verigakis
563 a1c50326 Giorgos Verigakis
@command(api='image')
564 8f5f3101 Giorgos Verigakis
class image_meta(object):
565 df79206f Giorgos Verigakis
    """Get image metadata"""
566 8ab2c986 Giorgos Verigakis
    
567 8ab2c986 Giorgos Verigakis
    def main(self, image_id):
568 8ab2c986 Giorgos Verigakis
        image = self.client.get_meta(image_id)
569 8ab2c986 Giorgos Verigakis
        print_dict(image)
570 8ab2c986 Giorgos Verigakis
571 8ab2c986 Giorgos Verigakis
572 a1c50326 Giorgos Verigakis
@command(api='image')
573 8f5f3101 Giorgos Verigakis
class image_register(object):
574 df79206f Giorgos Verigakis
    """Register an image"""
575 a6757cbc Giorgos Verigakis
    
576 a4f3a88e Giorgos Verigakis
    def update_parser(self, parser):
577 56ccdbee Giorgos Verigakis
        parser.add_argument('--checksum', dest='checksum', metavar='CHECKSUM',
578 a6757cbc Giorgos Verigakis
                help='set image checksum')
579 56ccdbee Giorgos Verigakis
        parser.add_argument('--container-format', dest='container_format',
580 a6757cbc Giorgos Verigakis
                metavar='FORMAT', help='set container format')
581 56ccdbee Giorgos Verigakis
        parser.add_argument('--disk-format', dest='disk_format',
582 a6757cbc Giorgos Verigakis
                metavar='FORMAT', help='set disk format')
583 56ccdbee Giorgos Verigakis
        parser.add_argument('--id', dest='id',
584 a6757cbc Giorgos Verigakis
                metavar='ID', help='set image ID')
585 56ccdbee Giorgos Verigakis
        parser.add_argument('--owner', dest='owner',
586 a6757cbc Giorgos Verigakis
                metavar='USER', help='set image owner (admin only)')
587 56ccdbee Giorgos Verigakis
        parser.add_argument('--property', dest='properties', action='append',
588 a6757cbc Giorgos Verigakis
                metavar='KEY=VAL',
589 a6757cbc Giorgos Verigakis
                help='add a property (can be used multiple times)')
590 56ccdbee Giorgos Verigakis
        parser.add_argument('--public', dest='is_public', action='store_true',
591 a6757cbc Giorgos Verigakis
                help='mark image as public')
592 56ccdbee Giorgos Verigakis
        parser.add_argument('--size', dest='size', metavar='SIZE',
593 a6757cbc Giorgos Verigakis
                help='set image size')
594 56ccdbee Giorgos Verigakis
595 a6757cbc Giorgos Verigakis
    def main(self, name, location):
596 8f5f3101 Giorgos Verigakis
        if not location.startswith('pithos://'):
597 8f5f3101 Giorgos Verigakis
            account = self.config.get('storage', 'account')
598 8f5f3101 Giorgos Verigakis
            container = self.config.get('storage', 'container')
599 8f5f3101 Giorgos Verigakis
            location = 'pithos://%s/%s/%s' % (account, container, location)
600 8f5f3101 Giorgos Verigakis
        
601 a6757cbc Giorgos Verigakis
        params = {}
602 a6757cbc Giorgos Verigakis
        for key in ('checksum', 'container_format', 'disk_format', 'id',
603 df79206f Giorgos Verigakis
                    'owner', 'size'):
604 56ccdbee Giorgos Verigakis
            val = getattr(self.args, key)
605 a6757cbc Giorgos Verigakis
            if val is not None:
606 a6757cbc Giorgos Verigakis
                params[key] = val
607 a6757cbc Giorgos Verigakis
        
608 56ccdbee Giorgos Verigakis
        if self.args.is_public:
609 df79206f Giorgos Verigakis
            params['is_public'] = 'true'
610 df79206f Giorgos Verigakis
        
611 a6757cbc Giorgos Verigakis
        properties = {}
612 56ccdbee Giorgos Verigakis
        for property in self.args.properties or []:
613 a6757cbc Giorgos Verigakis
            key, sep, val = property.partition('=')
614 a6757cbc Giorgos Verigakis
            if not sep:
615 8db3fc19 Giorgos Verigakis
                print("Invalid property '%s'" % property)
616 a6757cbc Giorgos Verigakis
                return 1
617 a6757cbc Giorgos Verigakis
            properties[key.strip()] = val.strip()
618 a6757cbc Giorgos Verigakis
        
619 a6757cbc Giorgos Verigakis
        self.client.register(name, location, params, properties)
620 eb3ca8ca Giorgos Verigakis
621 eb3ca8ca Giorgos Verigakis
622 a1c50326 Giorgos Verigakis
@command(api='image')
623 8f5f3101 Giorgos Verigakis
class image_members(object):
624 df79206f Giorgos Verigakis
    """Get image members"""
625 8ab2c986 Giorgos Verigakis
    
626 8ab2c986 Giorgos Verigakis
    def main(self, image_id):
627 8ab2c986 Giorgos Verigakis
        members = self.client.list_members(image_id)
628 8ab2c986 Giorgos Verigakis
        for member in members:
629 8db3fc19 Giorgos Verigakis
            print(member['member_id'])
630 8ab2c986 Giorgos Verigakis
631 8ab2c986 Giorgos Verigakis
632 a1c50326 Giorgos Verigakis
@command(api='image')
633 8f5f3101 Giorgos Verigakis
class image_shared(object):
634 df79206f Giorgos Verigakis
    """List shared images"""
635 8ab2c986 Giorgos Verigakis
    
636 8ab2c986 Giorgos Verigakis
    def main(self, member):
637 8ab2c986 Giorgos Verigakis
        images = self.client.list_shared(member)
638 8ab2c986 Giorgos Verigakis
        for image in images:
639 8db3fc19 Giorgos Verigakis
            print(image['image_id'])
640 8ab2c986 Giorgos Verigakis
641 8ab2c986 Giorgos Verigakis
642 a1c50326 Giorgos Verigakis
@command(api='image')
643 8f5f3101 Giorgos Verigakis
class image_addmember(object):
644 df79206f Giorgos Verigakis
    """Add a member to an image"""
645 8ab2c986 Giorgos Verigakis
    
646 8ab2c986 Giorgos Verigakis
    def main(self, image_id, member):
647 8ab2c986 Giorgos Verigakis
        self.client.add_member(image_id, member)
648 8ab2c986 Giorgos Verigakis
649 8ab2c986 Giorgos Verigakis
650 a1c50326 Giorgos Verigakis
@command(api='image')
651 8f5f3101 Giorgos Verigakis
class image_delmember(object):
652 df79206f Giorgos Verigakis
    """Remove a member from an image"""
653 8ab2c986 Giorgos Verigakis
    
654 8ab2c986 Giorgos Verigakis
    def main(self, image_id, member):
655 8ab2c986 Giorgos Verigakis
        self.client.remove_member(image_id, member)
656 8ab2c986 Giorgos Verigakis
657 8ab2c986 Giorgos Verigakis
658 a1c50326 Giorgos Verigakis
@command(api='image')
659 8f5f3101 Giorgos Verigakis
class image_setmembers(object):
660 df79206f Giorgos Verigakis
    """Set the members of an image"""
661 8ab2c986 Giorgos Verigakis
    
662 8ab2c986 Giorgos Verigakis
    def main(self, image_id, *member):
663 8ab2c986 Giorgos Verigakis
        self.client.set_members(image_id, member)
664 8ab2c986 Giorgos Verigakis
665 8ab2c986 Giorgos Verigakis
666 a591a7b4 Giorgos Verigakis
class _store_account_command(object):
667 a591a7b4 Giorgos Verigakis
    """Base class for account level storage commands"""
668 d2cea1e2 Giorgos Verigakis
    
669 a591a7b4 Giorgos Verigakis
    def update_parser(self, parser):
670 56ccdbee Giorgos Verigakis
        parser.add_argument('--account', dest='account', metavar='NAME',
671 df79206f Giorgos Verigakis
                          help="Specify an account to use")
672 56ccdbee Giorgos Verigakis
673 df79206f Giorgos Verigakis
    def progress(self, message):
674 df79206f Giorgos Verigakis
        """Return a generator function to be used for progress tracking"""
675 df79206f Giorgos Verigakis
        
676 df79206f Giorgos Verigakis
        MESSAGE_LENGTH = 25
677 df79206f Giorgos Verigakis
        
678 df79206f Giorgos Verigakis
        def progress_gen(n):
679 df79206f Giorgos Verigakis
            msg = message.ljust(MESSAGE_LENGTH)
680 4ef14fb3 Giorgos Verigakis
            for i in ProgressBar(msg).iter(range(n)):
681 df79206f Giorgos Verigakis
                yield
682 df79206f Giorgos Verigakis
            yield
683 176894c1 Giorgos Verigakis
        
684 df79206f Giorgos Verigakis
        return progress_gen
685 df79206f Giorgos Verigakis
    
686 df79206f Giorgos Verigakis
    def main(self):
687 56ccdbee Giorgos Verigakis
        if self.args.account is not None:
688 56ccdbee Giorgos Verigakis
            self.client.account = self.args.account
689 a591a7b4 Giorgos Verigakis
690 a591a7b4 Giorgos Verigakis
691 a591a7b4 Giorgos Verigakis
class _store_container_command(_store_account_command):
692 a591a7b4 Giorgos Verigakis
    """Base class for container level storage commands"""
693 a591a7b4 Giorgos Verigakis
    
694 a591a7b4 Giorgos Verigakis
    def update_parser(self, parser):
695 a591a7b4 Giorgos Verigakis
        super(_store_container_command, self).update_parser(parser)
696 56ccdbee Giorgos Verigakis
        parser.add_argument('--container', dest='container', metavar='NAME',
697 a591a7b4 Giorgos Verigakis
                          help="Specify a container to use")
698 56ccdbee Giorgos Verigakis
699 a591a7b4 Giorgos Verigakis
    def main(self):
700 a591a7b4 Giorgos Verigakis
        super(_store_container_command, self).main()
701 56ccdbee Giorgos Verigakis
        if self.args.container is not None:
702 56ccdbee Giorgos Verigakis
            self.client.container = self.args.container
703 176894c1 Giorgos Verigakis
704 176894c1 Giorgos Verigakis
705 176894c1 Giorgos Verigakis
@command(api='storage')
706 a591a7b4 Giorgos Verigakis
class store_create(_store_account_command):
707 df79206f Giorgos Verigakis
    """Create a container"""
708 60560d7c Giorgos Verigakis
    
709 60560d7c Giorgos Verigakis
    def main(self, container):
710 7b3a2fa3 Giorgos Verigakis
        super(store_create, self).main()
711 60560d7c Giorgos Verigakis
        self.client.create_container(container)
712 60560d7c Giorgos Verigakis
713 60560d7c Giorgos Verigakis
714 60560d7c Giorgos Verigakis
@command(api='storage')
715 a591a7b4 Giorgos Verigakis
class store_container(_store_account_command):
716 df79206f Giorgos Verigakis
    """Get container info"""
717 176894c1 Giorgos Verigakis
    
718 df79206f Giorgos Verigakis
    def main(self, container):
719 7b3a2fa3 Giorgos Verigakis
        super(store_container, self).main()
720 df79206f Giorgos Verigakis
        reply = self.client.get_container_meta(container)
721 d2cea1e2 Giorgos Verigakis
        print_dict(reply)
722 d2cea1e2 Giorgos Verigakis
723 d2cea1e2 Giorgos Verigakis
724 d2cea1e2 Giorgos Verigakis
@command(api='storage')
725 a591a7b4 Giorgos Verigakis
class store_list(_store_container_command):
726 a591a7b4 Giorgos Verigakis
    """List objects"""
727 a591a7b4 Giorgos Verigakis
    
728 a591a7b4 Giorgos Verigakis
    def format_size(self, size):
729 a591a7b4 Giorgos Verigakis
        units = ('B', 'K', 'M', 'G', 'T')
730 a591a7b4 Giorgos Verigakis
        size = float(size)
731 a591a7b4 Giorgos Verigakis
        for unit in units:
732 a591a7b4 Giorgos Verigakis
            if size <= 1024:
733 a591a7b4 Giorgos Verigakis
                break
734 a591a7b4 Giorgos Verigakis
            size /= 1024
735 a591a7b4 Giorgos Verigakis
        s = ('%.1f' % size).rstrip('.0')
736 a591a7b4 Giorgos Verigakis
        return s + unit
737 a591a7b4 Giorgos Verigakis
    
738 a591a7b4 Giorgos Verigakis
    
739 a591a7b4 Giorgos Verigakis
    def main(self, path=''):
740 a591a7b4 Giorgos Verigakis
        super(store_list, self).main()
741 a591a7b4 Giorgos Verigakis
        for object in self.client.list_objects():
742 a591a7b4 Giorgos Verigakis
            size = self.format_size(object['bytes'])
743 8db3fc19 Giorgos Verigakis
            print('%6s %s' % (size, object['name']))
744 a591a7b4 Giorgos Verigakis
        
745 a591a7b4 Giorgos Verigakis
746 a591a7b4 Giorgos Verigakis
@command(api='storage')
747 a591a7b4 Giorgos Verigakis
class store_upload(_store_container_command):
748 df79206f Giorgos Verigakis
    """Upload a file"""
749 a1c50326 Giorgos Verigakis
    
750 a1c50326 Giorgos Verigakis
    def main(self, path, remote_path=None):
751 df79206f Giorgos Verigakis
        super(store_upload, self).main()
752 df79206f Giorgos Verigakis
        
753 a1c50326 Giorgos Verigakis
        if remote_path is None:
754 a1c50326 Giorgos Verigakis
            remote_path = basename(path)
755 a1c50326 Giorgos Verigakis
        with open(path) as f:
756 df79206f Giorgos Verigakis
            hash_cb = self.progress('Calculating block hashes')
757 df79206f Giorgos Verigakis
            upload_cb = self.progress('Uploading blocks')
758 df79206f Giorgos Verigakis
            self.client.create_object(remote_path, f, hash_cb=hash_cb,
759 df79206f Giorgos Verigakis
                                      upload_cb=upload_cb)
760 d2cea1e2 Giorgos Verigakis
761 d2cea1e2 Giorgos Verigakis
762 d2cea1e2 Giorgos Verigakis
@command(api='storage')
763 a591a7b4 Giorgos Verigakis
class store_download(_store_container_command):
764 df79206f Giorgos Verigakis
    """Download a file"""
765 df79206f Giorgos Verigakis
        
766 df79206f Giorgos Verigakis
    def main(self, remote_path, local_path='-'):
767 df79206f Giorgos Verigakis
        super(store_download, self).main()
768 df79206f Giorgos Verigakis
        
769 df79206f Giorgos Verigakis
        f, size = self.client.get_object(remote_path)
770 176894c1 Giorgos Verigakis
        out = open(local_path, 'w') if local_path != '-' else stdout
771 df79206f Giorgos Verigakis
        
772 df79206f Giorgos Verigakis
        blocksize = 4 * 1024**2
773 df79206f Giorgos Verigakis
        nblocks = 1 + (size - 1) // blocksize
774 df79206f Giorgos Verigakis
        
775 df79206f Giorgos Verigakis
        cb = self.progress('Downloading blocks') if local_path != '-' else None
776 df79206f Giorgos Verigakis
        if cb:
777 df79206f Giorgos Verigakis
            gen = cb(nblocks)
778 df79206f Giorgos Verigakis
            gen.next()
779 df79206f Giorgos Verigakis
        
780 df79206f Giorgos Verigakis
        data = f.read(blocksize)
781 176894c1 Giorgos Verigakis
        while data:
782 176894c1 Giorgos Verigakis
            out.write(data)
783 df79206f Giorgos Verigakis
            data = f.read(blocksize)
784 df79206f Giorgos Verigakis
            if cb:
785 df79206f Giorgos Verigakis
                gen.next()
786 176894c1 Giorgos Verigakis
787 176894c1 Giorgos Verigakis
788 176894c1 Giorgos Verigakis
@command(api='storage')
789 a591a7b4 Giorgos Verigakis
class store_delete(_store_container_command):
790 df79206f Giorgos Verigakis
    """Delete a file"""
791 d2cea1e2 Giorgos Verigakis
    
792 d2cea1e2 Giorgos Verigakis
    def main(self, path):
793 49919699 Giorgos Verigakis
        super(store_delete, self).main()
794 d2cea1e2 Giorgos Verigakis
        self.client.delete_object(path)
795 a1c50326 Giorgos Verigakis
796 a1c50326 Giorgos Verigakis
797 7b3a2fa3 Giorgos Verigakis
@command(api='storage')
798 7b3a2fa3 Giorgos Verigakis
class store_purge(_store_account_command):
799 7b3a2fa3 Giorgos Verigakis
    """Purge a container"""
800 7b3a2fa3 Giorgos Verigakis
    
801 7b3a2fa3 Giorgos Verigakis
    def main(self, container):
802 7b3a2fa3 Giorgos Verigakis
        super(store_purge, self).main()
803 7b3a2fa3 Giorgos Verigakis
        self.client.purge_container(container)
804 7b3a2fa3 Giorgos Verigakis
805 7b3a2fa3 Giorgos Verigakis
806 dba6ec94 Giorgos Verigakis
@command(api='astakos')
807 dba6ec94 Giorgos Verigakis
class astakos_authenticate(object):
808 dba6ec94 Giorgos Verigakis
    """Authenticate a user"""
809 dba6ec94 Giorgos Verigakis
    
810 dba6ec94 Giorgos Verigakis
    def main(self):
811 dba6ec94 Giorgos Verigakis
        reply = self.client.authenticate()
812 dba6ec94 Giorgos Verigakis
        print_dict(reply)
813 dba6ec94 Giorgos Verigakis
814 dba6ec94 Giorgos Verigakis
815 cae67d7b Giorgos Verigakis
def print_groups():
816 8db3fc19 Giorgos Verigakis
    print('\nGroups:')
817 8db3fc19 Giorgos Verigakis
    for group in _commands:
818 8db3fc19 Giorgos Verigakis
        description = GROUPS.get(group, '')
819 8db3fc19 Giorgos Verigakis
        print(' ', group.ljust(12), description)
820 eb3ca8ca Giorgos Verigakis
821 eb3ca8ca Giorgos Verigakis
822 cae67d7b Giorgos Verigakis
def print_commands(group):
823 cae67d7b Giorgos Verigakis
    description = GROUPS.get(group, '')
824 cae67d7b Giorgos Verigakis
    if description:
825 8db3fc19 Giorgos Verigakis
        print('\n' + description)
826 cae67d7b Giorgos Verigakis
    
827 8db3fc19 Giorgos Verigakis
    print('\nCommands:')
828 8db3fc19 Giorgos Verigakis
    for name, cls in _commands[group].items():
829 8db3fc19 Giorgos Verigakis
        print(' ', name.ljust(14), cls.description)
830 5d1d131b Giorgos Verigakis
831 5d1d131b Giorgos Verigakis
832 df79206f Giorgos Verigakis
def add_handler(name, level, prefix=''):
833 df79206f Giorgos Verigakis
    h = logging.StreamHandler()
834 df79206f Giorgos Verigakis
    fmt = logging.Formatter(prefix + '%(message)s')
835 df79206f Giorgos Verigakis
    h.setFormatter(fmt)
836 df79206f Giorgos Verigakis
    logger = logging.getLogger(name)
837 df79206f Giorgos Verigakis
    logger.addHandler(h)
838 df79206f Giorgos Verigakis
    logger.setLevel(level)
839 df79206f Giorgos Verigakis
840 df79206f Giorgos Verigakis
841 5d1d131b Giorgos Verigakis
def main():
842 56ccdbee Giorgos Verigakis
    exe = basename(sys.argv[0])
843 56ccdbee Giorgos Verigakis
    parser = ArgumentParser(add_help=False)
844 56ccdbee Giorgos Verigakis
    parser.prog = '%s <group> <command>' % exe
845 56ccdbee Giorgos Verigakis
    parser.add_argument('-h', '--help', dest='help', action='store_true',
846 cae67d7b Giorgos Verigakis
                      default=False,
847 cae67d7b Giorgos Verigakis
                      help="Show this help message and exit")
848 56ccdbee Giorgos Verigakis
    parser.add_argument('--config', dest='config', metavar='PATH',
849 cae67d7b Giorgos Verigakis
                      help="Specify the path to the configuration file")
850 56ccdbee Giorgos Verigakis
    parser.add_argument('-d', '--debug', dest='debug', action='store_true',
851 df79206f Giorgos Verigakis
                      default=False,
852 df79206f Giorgos Verigakis
                      help="Include debug output")
853 56ccdbee Giorgos Verigakis
    parser.add_argument('-i', '--include', dest='include', action='store_true',
854 cae67d7b Giorgos Verigakis
                      default=False,
855 cae67d7b Giorgos Verigakis
                      help="Include protocol headers in the output")
856 56ccdbee Giorgos Verigakis
    parser.add_argument('-s', '--silent', dest='silent', action='store_true',
857 cae67d7b Giorgos Verigakis
                      default=False,
858 cae67d7b Giorgos Verigakis
                      help="Silent mode, don't output anything")
859 56ccdbee Giorgos Verigakis
    parser.add_argument('-v', '--verbose', dest='verbose', action='store_true',
860 cae67d7b Giorgos Verigakis
                      default=False,
861 cae67d7b Giorgos Verigakis
                      help="Make the operation more talkative")
862 56ccdbee Giorgos Verigakis
    parser.add_argument('-V', '--version', dest='version', action='store_true',
863 cae67d7b Giorgos Verigakis
                      default=False,
864 cae67d7b Giorgos Verigakis
                      help="Show version number and quit")
865 56ccdbee Giorgos Verigakis
    parser.add_argument('-o', dest='options', action='append',
866 cae67d7b Giorgos Verigakis
                      default=[], metavar="KEY=VAL",
867 cae67d7b Giorgos Verigakis
                      help="Override a config values")
868 56ccdbee Giorgos Verigakis
869 56ccdbee Giorgos Verigakis
    args, argv = parser.parse_known_args()
870 56ccdbee Giorgos Verigakis
871 56ccdbee Giorgos Verigakis
    if args.version:
872 cae67d7b Giorgos Verigakis
        import kamaki
873 8db3fc19 Giorgos Verigakis
        print("kamaki %s" % kamaki.__version__)
874 cae67d7b Giorgos Verigakis
        exit(0)
875 2d0b6dcc Giorgos Verigakis
876 56ccdbee Giorgos Verigakis
    config = Config(args.config) if args.config else Config()
877 56ccdbee Giorgos Verigakis
878 56ccdbee Giorgos Verigakis
    for option in args.options:
879 cae67d7b Giorgos Verigakis
        keypath, sep, val = option.partition('=')
880 cae67d7b Giorgos Verigakis
        if not sep:
881 8db3fc19 Giorgos Verigakis
            print("Invalid option '%s'" % option)
882 cae67d7b Giorgos Verigakis
            exit(1)
883 cae67d7b Giorgos Verigakis
        section, sep, key = keypath.partition('.')
884 cae67d7b Giorgos Verigakis
        if not sep:
885 8db3fc19 Giorgos Verigakis
            print("Invalid option '%s'" % option)
886 cae67d7b Giorgos Verigakis
            exit(1)
887 cae67d7b Giorgos Verigakis
        config.override(section.strip(), key.strip(), val.strip())
888 cae67d7b Giorgos Verigakis
    
889 cae67d7b Giorgos Verigakis
    apis = set(['config'])
890 dba6ec94 Giorgos Verigakis
    for api in ('compute', 'image', 'storage', 'astakos'):
891 cae67d7b Giorgos Verigakis
        if config.getboolean(api, 'enable'):
892 cae67d7b Giorgos Verigakis
            apis.add(api)
893 cae67d7b Giorgos Verigakis
    if config.getboolean('compute', 'cyclades_extensions'):
894 cae67d7b Giorgos Verigakis
        apis.add('cyclades')
895 cae67d7b Giorgos Verigakis
    if config.getboolean('storage', 'pithos_extensions'):
896 cae67d7b Giorgos Verigakis
        apis.add('pithos')
897 cae67d7b Giorgos Verigakis
    
898 cae67d7b Giorgos Verigakis
    # Remove commands that belong to APIs that are not included
899 eb3ca8ca Giorgos Verigakis
    for group, group_commands in _commands.items():
900 eb3ca8ca Giorgos Verigakis
        for name, cls in group_commands.items():
901 cae67d7b Giorgos Verigakis
            if cls.api not in apis:
902 cae67d7b Giorgos Verigakis
                del group_commands[name]
903 cae67d7b Giorgos Verigakis
        if not group_commands:
904 cae67d7b Giorgos Verigakis
            del _commands[group]
905 56ccdbee Giorgos Verigakis
906 56ccdbee Giorgos Verigakis
    group = argv.pop(0) if argv else None
907 56ccdbee Giorgos Verigakis
908 56ccdbee Giorgos Verigakis
    if not group:
909 eb3ca8ca Giorgos Verigakis
        parser.print_help()
910 cae67d7b Giorgos Verigakis
        print_groups()
911 a1c50326 Giorgos Verigakis
        exit(0)
912 56ccdbee Giorgos Verigakis
913 cae67d7b Giorgos Verigakis
    if group not in _commands:
914 eb3ca8ca Giorgos Verigakis
        parser.print_help()
915 cae67d7b Giorgos Verigakis
        print_groups()
916 a1c50326 Giorgos Verigakis
        exit(1)
917 56ccdbee Giorgos Verigakis
918 56ccdbee Giorgos Verigakis
    parser.prog = '%s %s <command>' % (exe, group)
919 56ccdbee Giorgos Verigakis
    command = argv.pop(0) if argv else None
920 56ccdbee Giorgos Verigakis
921 56ccdbee Giorgos Verigakis
    if not command:
922 eb3ca8ca Giorgos Verigakis
        parser.print_help()
923 cae67d7b Giorgos Verigakis
        print_commands(group)
924 a1c50326 Giorgos Verigakis
        exit(0)
925 56ccdbee Giorgos Verigakis
926 56ccdbee Giorgos Verigakis
    if command not in _commands[group]:
927 eb3ca8ca Giorgos Verigakis
        parser.print_help()
928 cae67d7b Giorgos Verigakis
        print_commands(group)
929 a1c50326 Giorgos Verigakis
        exit(1)
930 5d1d131b Giorgos Verigakis
    
931 56ccdbee Giorgos Verigakis
    cmd = _commands[group][command]()
932 56ccdbee Giorgos Verigakis
933 56ccdbee Giorgos Verigakis
    parser.prog = '%s %s %s' % (exe, group, command)
934 56ccdbee Giorgos Verigakis
    if cmd.syntax:
935 56ccdbee Giorgos Verigakis
        parser.prog += '  %s' % cmd.syntax
936 cae67d7b Giorgos Verigakis
    parser.description = cmd.description
937 eb3ca8ca Giorgos Verigakis
    parser.epilog = ''
938 cae67d7b Giorgos Verigakis
    if hasattr(cmd, 'update_parser'):
939 cae67d7b Giorgos Verigakis
        cmd.update_parser(parser)
940 eb3ca8ca Giorgos Verigakis
    
941 56ccdbee Giorgos Verigakis
    args, argv = parser.parse_known_args()
942 df79206f Giorgos Verigakis
    
943 56ccdbee Giorgos Verigakis
    if args.help:
944 eb3ca8ca Giorgos Verigakis
        parser.print_help()
945 a1c50326 Giorgos Verigakis
        exit(0)
946 eb3ca8ca Giorgos Verigakis
    
947 56ccdbee Giorgos Verigakis
    if args.silent:
948 df79206f Giorgos Verigakis
        add_handler('', logging.CRITICAL)
949 56ccdbee Giorgos Verigakis
    elif args.debug:
950 df79206f Giorgos Verigakis
        add_handler('requests', logging.INFO, prefix='* ')
951 df79206f Giorgos Verigakis
        add_handler('clients.send', logging.DEBUG, prefix='> ')
952 df79206f Giorgos Verigakis
        add_handler('clients.recv', logging.DEBUG, prefix='< ')
953 56ccdbee Giorgos Verigakis
    elif args.verbose:
954 df79206f Giorgos Verigakis
        add_handler('requests', logging.INFO, prefix='* ')
955 df79206f Giorgos Verigakis
        add_handler('clients.send', logging.INFO, prefix='> ')
956 df79206f Giorgos Verigakis
        add_handler('clients.recv', logging.INFO, prefix='< ')
957 56ccdbee Giorgos Verigakis
    elif args.include:
958 df79206f Giorgos Verigakis
        add_handler('clients.recv', logging.INFO)
959 df79206f Giorgos Verigakis
    else:
960 df79206f Giorgos Verigakis
        add_handler('', logging.WARNING)
961 5d1d131b Giorgos Verigakis
    
962 cae67d7b Giorgos Verigakis
    api = cmd.api
963 df79206f Giorgos Verigakis
    if api in ('compute', 'cyclades'):
964 df79206f Giorgos Verigakis
        url = config.get('compute', 'url')
965 df79206f Giorgos Verigakis
        token = config.get('compute', 'token') or config.get('global', 'token')
966 df79206f Giorgos Verigakis
        if config.getboolean('compute', 'cyclades_extensions'):
967 df79206f Giorgos Verigakis
            cmd.client = clients.cyclades(url, token)
968 df79206f Giorgos Verigakis
        else:
969 df79206f Giorgos Verigakis
            cmd.client = clients.compute(url, token)
970 df79206f Giorgos Verigakis
    elif api in ('storage', 'pithos'):
971 df79206f Giorgos Verigakis
        url = config.get('storage', 'url')
972 df79206f Giorgos Verigakis
        token = config.get('storage', 'token') or config.get('global', 'token')
973 df79206f Giorgos Verigakis
        account = config.get('storage', 'account')
974 df79206f Giorgos Verigakis
        container = config.get('storage', 'container')
975 df79206f Giorgos Verigakis
        if config.getboolean('storage', 'pithos_extensions'):
976 df79206f Giorgos Verigakis
            cmd.client = clients.pithos(url, token, account, container)
977 df79206f Giorgos Verigakis
        else:
978 df79206f Giorgos Verigakis
            cmd.client = clients.storage(url, token, account, container)
979 df79206f Giorgos Verigakis
    elif api == 'image':
980 df79206f Giorgos Verigakis
        url = config.get('image', 'url')
981 df79206f Giorgos Verigakis
        token = config.get('image', 'token') or config.get('global', 'token')
982 df79206f Giorgos Verigakis
        cmd.client = clients.image(url, token)
983 dba6ec94 Giorgos Verigakis
    elif api == 'astakos':
984 dba6ec94 Giorgos Verigakis
        url = config.get('astakos', 'url')
985 dba6ec94 Giorgos Verigakis
        token = config.get('astakos', 'token') or config.get('global', 'token')
986 dba6ec94 Giorgos Verigakis
        cmd.client = clients.astakos(url, token)
987 df79206f Giorgos Verigakis
    
988 56ccdbee Giorgos Verigakis
    cmd.args = args
989 df79206f Giorgos Verigakis
    cmd.config = config
990 df79206f Giorgos Verigakis
    
991 5d1d131b Giorgos Verigakis
    try:
992 56ccdbee Giorgos Verigakis
        ret = cmd.main(*argv[2:])
993 a1c50326 Giorgos Verigakis
        exit(ret)
994 a6757cbc Giorgos Verigakis
    except TypeError as e:
995 a6757cbc Giorgos Verigakis
        if e.args and e.args[0].startswith('main()'):
996 a6757cbc Giorgos Verigakis
            parser.print_help()
997 a1c50326 Giorgos Verigakis
            exit(1)
998 a6757cbc Giorgos Verigakis
        else:
999 a6757cbc Giorgos Verigakis
            raise
1000 df79206f Giorgos Verigakis
    except clients.ClientError as err:
1001 df79206f Giorgos Verigakis
        if err.status == 404:
1002 56ccdbee Giorgos Verigakis
            message = yellow(err.message)
1003 df79206f Giorgos Verigakis
        elif 500 <= err.status < 600:
1004 56ccdbee Giorgos Verigakis
            message = magenta(err.message)
1005 df79206f Giorgos Verigakis
        else:
1006 56ccdbee Giorgos Verigakis
            message = red(err.message)
1007 df79206f Giorgos Verigakis
        
1008 56ccdbee Giorgos Verigakis
        print(message, file=stderr)
1009 56ccdbee Giorgos Verigakis
        if err.details and (args.verbose or args.debug):
1010 8db3fc19 Giorgos Verigakis
            print(err.details, file=stderr)
1011 a1c50326 Giorgos Verigakis
        exit(2)
1012 df79206f Giorgos Verigakis
    except ConnectionError as err:
1013 8db3fc19 Giorgos Verigakis
        print(red("Connection error"), file=stderr)
1014 df79206f Giorgos Verigakis
        exit(1)
1015 5d1d131b Giorgos Verigakis
1016 5d1d131b Giorgos Verigakis
1017 5d1d131b Giorgos Verigakis
if __name__ == '__main__':
1018 a1c50326 Giorgos Verigakis
    main()