Statistics
| Branch: | Tag: | Revision:

root / kamaki / cli.py @ 16ce7b91

History | View | Annotate | Download (42.8 kB)

1 5d1d131b Giorgos Verigakis
#!/usr/bin/env python
2 5d1d131b Giorgos Verigakis
3 43ca98ee 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 edbee9c8 Stavros Sachtouris
@command(api='compute')
47 edbee9c8 Stavros Sachtouris
class server_list(object):
48 edbee9c8 Stavros Sachtouris
//This command will be named 'list' under group 'server'
49 edbee9c8 Stavros Sachtouris
...
50 eb3ca8ca Giorgos Verigakis

51 edbee9c8 Stavros Sachtouris
@command(api='compute', name='ls')
52 edbee9c8 Stavros Sachtouris
class server_list(object):
53 edbee9c8 Stavros Sachtouris
//This command will be named 'ls' under group 'server'
54 edbee9c8 Stavros Sachtouris
...
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 edbee9c8 Stavros Sachtouris
def main(self, server_id, network=None):
63 edbee9c8 Stavros Sachtouris
// This syntax of this command will be: '<server id> [network]'
64 edbee9c8 Stavros Sachtouris
...
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 098ca087 Giorgos Verigakis
from __future__ import print_function
70 098ca087 Giorgos Verigakis
71 5d1d131b Giorgos Verigakis
import inspect
72 5d1d131b Giorgos Verigakis
import logging
73 8378faf2 Giorgos Verigakis
import sys
74 5d1d131b Giorgos Verigakis
75 8378faf2 Giorgos Verigakis
from argparse import ArgumentParser
76 57b8dd5a Giorgos Verigakis
from base64 import b64encode
77 d83a2834 Giorgos Verigakis
from os.path import abspath, basename, exists
78 8378faf2 Giorgos Verigakis
from sys import exit, stdout, stderr
79 5d1d131b Giorgos Verigakis
80 5f47b77d Giorgos Verigakis
try:
81 5f47b77d Giorgos Verigakis
    from collections import OrderedDict
82 5f47b77d Giorgos Verigakis
except ImportError:
83 5f47b77d Giorgos Verigakis
    from ordereddict import OrderedDict
84 5f47b77d Giorgos Verigakis
85 7879b932 Giorgos Verigakis
from colors import magenta, red, yellow
86 863dd770 Giorgos Verigakis
from progress.bar import IncrementalBar
87 6a0b1658 Giorgos Verigakis
from requests.exceptions import ConnectionError
88 6a0b1658 Giorgos Verigakis
89 5f47b77d Giorgos Verigakis
from . import clients
90 5f47b77d Giorgos Verigakis
from .config import Config
91 0f25af9f Stavros Sachtouris
from .utils import print_list, print_dict, print_items, format_size
92 5d1d131b Giorgos Verigakis
93 eb3ca8ca Giorgos Verigakis
_commands = OrderedDict()
94 eb3ca8ca Giorgos Verigakis
95 653b0597 Giorgos Verigakis
96 f3ddb705 Giorgos Verigakis
GROUPS = {
97 f3ddb705 Giorgos Verigakis
    'config': "Configuration commands",
98 f3ddb705 Giorgos Verigakis
    'server': "Compute API server commands",
99 f3ddb705 Giorgos Verigakis
    'flavor': "Compute API flavor commands",
100 cb813272 Giorgos Verigakis
    'image': "Compute or Glance API image commands",
101 f3ddb705 Giorgos Verigakis
    'network': "Compute API network commands (Cyclades extension)",
102 43ca98ee Giorgos Verigakis
    'store': "Storage API commands",
103 43ca98ee Giorgos Verigakis
    'astakos': "Astakos API commands"}
104 f3ddb705 Giorgos Verigakis
105 863dd770 Giorgos Verigakis
class ProgressBar(IncrementalBar):
106 863dd770 Giorgos Verigakis
    suffix = '%(percent)d%% - %(eta)ds'
107 863dd770 Giorgos Verigakis
108 f3ddb705 Giorgos Verigakis
def command(api=None, group=None, name=None, syntax=None):
109 eb3ca8ca Giorgos Verigakis
    """Class decorator that registers a class as a CLI command."""
110 44b8928d Giorgos Verigakis
111 eb3ca8ca Giorgos Verigakis
    def decorator(cls):
112 eb3ca8ca Giorgos Verigakis
        grp, sep, cmd = cls.__name__.partition('_')
113 eb3ca8ca Giorgos Verigakis
        if not sep:
114 eb3ca8ca Giorgos Verigakis
            grp, cmd = None, cls.__name__
115 44b8928d Giorgos Verigakis
116 eb3ca8ca Giorgos Verigakis
        cls.api = api
117 eb3ca8ca Giorgos Verigakis
        cls.group = group or grp
118 eb3ca8ca Giorgos Verigakis
        cls.name = name or cmd
119 44b8928d Giorgos Verigakis
120 f3ddb705 Giorgos Verigakis
        short_description, sep, long_description = cls.__doc__.partition('\n')
121 f3ddb705 Giorgos Verigakis
        cls.description = short_description
122 f3ddb705 Giorgos Verigakis
        cls.long_description = long_description or short_description
123 44b8928d Giorgos Verigakis
124 f3ddb705 Giorgos Verigakis
        cls.syntax = syntax
125 eb3ca8ca Giorgos Verigakis
        if cls.syntax is None:
126 eb3ca8ca Giorgos Verigakis
            # Generate a syntax string based on main's arguments
127 eb3ca8ca Giorgos Verigakis
            spec = inspect.getargspec(cls.main.im_func)
128 eb3ca8ca Giorgos Verigakis
            args = spec.args[1:]
129 eb3ca8ca Giorgos Verigakis
            n = len(args) - len(spec.defaults or ())
130 9aece4ba Stavros Sachtouris
            required = ' '.join('<%s>' % x.replace('____', '[:').replace('___', ':').replace('__',']').replace('_', ' ') for x in args[:n])
131 9aece4ba Stavros Sachtouris
            optional = ' '.join('[%s]' % x.replace('____', '[:').replace('___', ':').replace('__', ']').replace('_', ' ') for x in args[n:])
132 eb3ca8ca Giorgos Verigakis
            cls.syntax = ' '.join(x for x in [required, optional] if x)
133 8ab2c986 Giorgos Verigakis
            if spec.varargs:
134 8ab2c986 Giorgos Verigakis
                cls.syntax += ' <%s ...>' % spec.varargs
135 44b8928d Giorgos Verigakis
136 eb3ca8ca Giorgos Verigakis
        if cls.group not in _commands:
137 eb3ca8ca Giorgos Verigakis
            _commands[cls.group] = OrderedDict()
138 eb3ca8ca Giorgos Verigakis
        _commands[cls.group][cls.name] = cls
139 eb3ca8ca Giorgos Verigakis
        return cls
140 eb3ca8ca Giorgos Verigakis
    return decorator
141 5d1d131b Giorgos Verigakis
142 f3ddb705 Giorgos Verigakis
@command(api='config')
143 eb3ca8ca Giorgos Verigakis
class config_list(object):
144 f3ddb705 Giorgos Verigakis
    """List configuration options"""
145 44b8928d Giorgos Verigakis
146 77eaa0be Giorgos Verigakis
    def update_parser(self, parser):
147 8378faf2 Giorgos Verigakis
        parser.add_argument('-a', dest='all', action='store_true',
148 f3ddb705 Giorgos Verigakis
                          default=False, help='include default values')
149 8378faf2 Giorgos Verigakis
150 eb3ca8ca Giorgos Verigakis
    def main(self):
151 8378faf2 Giorgos Verigakis
        include_defaults = self.args.all
152 f3ddb705 Giorgos Verigakis
        for section in sorted(self.config.sections()):
153 f3ddb705 Giorgos Verigakis
            items = self.config.items(section, include_defaults)
154 f3ddb705 Giorgos Verigakis
            for key, val in sorted(items):
155 098ca087 Giorgos Verigakis
                print('%s.%s = %s' % (section, key, val))
156 5d1d131b Giorgos Verigakis
157 f3ddb705 Giorgos Verigakis
@command(api='config')
158 eb3ca8ca Giorgos Verigakis
class config_get(object):
159 f3ddb705 Giorgos Verigakis
    """Show a configuration option"""
160 44b8928d Giorgos Verigakis
161 f3ddb705 Giorgos Verigakis
    def main(self, option):
162 f3ddb705 Giorgos Verigakis
        section, sep, key = option.rpartition('.')
163 f3ddb705 Giorgos Verigakis
        section = section or 'global'
164 f3ddb705 Giorgos Verigakis
        value = self.config.get(section, key)
165 f3ddb705 Giorgos Verigakis
        if value is not None:
166 098ca087 Giorgos Verigakis
            print(value)
167 eb3ca8ca Giorgos Verigakis
168 f3ddb705 Giorgos Verigakis
@command(api='config')
169 eb3ca8ca Giorgos Verigakis
class config_set(object):
170 f3ddb705 Giorgos Verigakis
    """Set a configuration option"""
171 44b8928d Giorgos Verigakis
172 f3ddb705 Giorgos Verigakis
    def main(self, option, value):
173 f3ddb705 Giorgos Verigakis
        section, sep, key = option.rpartition('.')
174 f3ddb705 Giorgos Verigakis
        section = section or 'global'
175 f3ddb705 Giorgos Verigakis
        self.config.set(section, key, value)
176 f3ddb705 Giorgos Verigakis
        self.config.write()
177 eb3ca8ca Giorgos Verigakis
178 f3ddb705 Giorgos Verigakis
@command(api='config')
179 f3ddb705 Giorgos Verigakis
class config_delete(object):
180 f3ddb705 Giorgos Verigakis
    """Delete a configuration option (and use the default value)"""
181 44b8928d Giorgos Verigakis
182 f3ddb705 Giorgos Verigakis
    def main(self, option):
183 f3ddb705 Giorgos Verigakis
        section, sep, key = option.rpartition('.')
184 f3ddb705 Giorgos Verigakis
        section = section or 'global'
185 f3ddb705 Giorgos Verigakis
        self.config.remove_option(section, key)
186 f3ddb705 Giorgos Verigakis
        self.config.write()
187 eb3ca8ca Giorgos Verigakis
188 a1c50326 Giorgos Verigakis
@command(api='compute')
189 eb3ca8ca Giorgos Verigakis
class server_list(object):
190 6a0b1658 Giorgos Verigakis
    """List servers"""
191 44b8928d Giorgos Verigakis
192 77eaa0be Giorgos Verigakis
    def update_parser(self, parser):
193 8378faf2 Giorgos Verigakis
        parser.add_argument('-l', dest='detail', action='store_true',
194 eb3ca8ca Giorgos Verigakis
                default=False, help='show detailed output')
195 8378faf2 Giorgos Verigakis
196 5d1d131b Giorgos Verigakis
    def main(self):
197 8378faf2 Giorgos Verigakis
        servers = self.client.list_servers(self.args.detail)
198 a6757cbc Giorgos Verigakis
        print_items(servers)
199 5d1d131b Giorgos Verigakis
200 a1c50326 Giorgos Verigakis
@command(api='compute')
201 eb3ca8ca Giorgos Verigakis
class server_info(object):
202 6a0b1658 Giorgos Verigakis
    """Get server details"""
203 44b8928d Giorgos Verigakis
204 5d1d131b Giorgos Verigakis
    def main(self, server_id):
205 a2ed3c3e Stavros Sachtouris
        try:
206 a2ed3c3e Stavros Sachtouris
            server = self.client.get_server_details(int(server_id))
207 a2ed3c3e Stavros Sachtouris
        except ValueError:
208 edbee9c8 Stavros Sachtouris
            print(yellow('Server id must be a base10 integer'))
209 a2ed3c3e Stavros Sachtouris
            return
210 5d1d131b Giorgos Verigakis
        print_dict(server)
211 5d1d131b Giorgos Verigakis
212 a1c50326 Giorgos Verigakis
@command(api='compute')
213 eb3ca8ca Giorgos Verigakis
class server_create(object):
214 6a0b1658 Giorgos Verigakis
    """Create a server"""
215 44b8928d Giorgos Verigakis
216 77eaa0be Giorgos Verigakis
    def update_parser(self, parser):
217 8378faf2 Giorgos Verigakis
        parser.add_argument('--personality', dest='personalities',
218 6a0b1658 Giorgos Verigakis
                          action='append', default=[],
219 6a0b1658 Giorgos Verigakis
                          metavar='PATH[,SERVER PATH[,OWNER[,GROUP,[MODE]]]]',
220 6a0b1658 Giorgos Verigakis
                          help='add a personality file')
221 8378faf2 Giorgos Verigakis
222 eb3ca8ca Giorgos Verigakis
    def main(self, name, flavor_id, image_id):
223 57b8dd5a Giorgos Verigakis
        personalities = []
224 8378faf2 Giorgos Verigakis
        for personality in self.args.personalities:
225 57b8dd5a Giorgos Verigakis
            p = personality.split(',')
226 57b8dd5a Giorgos Verigakis
            p.extend([None] * (5 - len(p)))     # Fill missing fields with None
227 44b8928d Giorgos Verigakis
228 57b8dd5a Giorgos Verigakis
            path = p[0]
229 44b8928d Giorgos Verigakis
230 57b8dd5a Giorgos Verigakis
            if not path:
231 098ca087 Giorgos Verigakis
                print("Invalid personality argument '%s'" % p)
232 eb3ca8ca Giorgos Verigakis
                return 1
233 a1c50326 Giorgos Verigakis
            if not exists(path):
234 098ca087 Giorgos Verigakis
                print("File %s does not exist" % path)
235 eb3ca8ca Giorgos Verigakis
                return 1
236 44b8928d Giorgos Verigakis
237 57b8dd5a Giorgos Verigakis
            with open(path) as f:
238 57b8dd5a Giorgos Verigakis
                contents = b64encode(f.read())
239 cceda750 Giorgos Verigakis
240 cceda750 Giorgos Verigakis
            d = {'path': p[1] or abspath(path), 'contents': contents}
241 cceda750 Giorgos Verigakis
            if p[2]:
242 cceda750 Giorgos Verigakis
                d['owner'] = p[2]
243 cceda750 Giorgos Verigakis
            if p[3]:
244 cceda750 Giorgos Verigakis
                d['group'] = p[3]
245 cceda750 Giorgos Verigakis
            if p[4]:
246 cceda750 Giorgos Verigakis
                d['mode'] = int(p[4])
247 cceda750 Giorgos Verigakis
            personalities.append(d)
248 cceda750 Giorgos Verigakis
249 eb3ca8ca Giorgos Verigakis
        reply = self.client.create_server(name, int(flavor_id), image_id,
250 eb3ca8ca Giorgos Verigakis
                personalities)
251 5d1d131b Giorgos Verigakis
        print_dict(reply)
252 5d1d131b Giorgos Verigakis
253 a1c50326 Giorgos Verigakis
@command(api='compute')
254 eb3ca8ca Giorgos Verigakis
class server_rename(object):
255 6a0b1658 Giorgos Verigakis
    """Update a server's name"""
256 44b8928d Giorgos Verigakis
257 5d1d131b Giorgos Verigakis
    def main(self, server_id, new_name):
258 a2ed3c3e Stavros Sachtouris
        try:
259 a2ed3c3e Stavros Sachtouris
            self.client.update_server_name(int(server_id), new_name)
260 a2ed3c3e Stavros Sachtouris
        except ValueError:
261 edbee9c8 Stavros Sachtouris
            print(yellow('Server id must be a base10 integer'))
262 5d1d131b Giorgos Verigakis
263 a1c50326 Giorgos Verigakis
@command(api='compute')
264 eb3ca8ca Giorgos Verigakis
class server_delete(object):
265 6a0b1658 Giorgos Verigakis
    """Delete a server"""
266 44b8928d Giorgos Verigakis
267 5d1d131b Giorgos Verigakis
    def main(self, server_id):
268 a2ed3c3e Stavros Sachtouris
        try:
269 a2ed3c3e Stavros Sachtouris
            self.client.delete_server(int(server_id))
270 a2ed3c3e Stavros Sachtouris
        except ValueError:
271 edbee9c8 Stavros Sachtouris
            print(yellow('Server id must be a base10 integer'))
272 5d1d131b Giorgos Verigakis
273 a1c50326 Giorgos Verigakis
@command(api='compute')
274 eb3ca8ca Giorgos Verigakis
class server_reboot(object):
275 6a0b1658 Giorgos Verigakis
    """Reboot a server"""
276 44b8928d Giorgos Verigakis
277 77eaa0be Giorgos Verigakis
    def update_parser(self, parser):
278 8378faf2 Giorgos Verigakis
        parser.add_argument('-f', dest='hard', action='store_true',
279 eb3ca8ca Giorgos Verigakis
                default=False, help='perform a hard reboot')
280 8378faf2 Giorgos Verigakis
281 5d1d131b Giorgos Verigakis
    def main(self, server_id):
282 a2ed3c3e Stavros Sachtouris
        try:
283 a2ed3c3e Stavros Sachtouris
            self.client.reboot_server(int(server_id), self.args.hard)
284 a2ed3c3e Stavros Sachtouris
        except ValueError:
285 edbee9c8 Stavros Sachtouris
            print(yellow('Server id must be a base10 integer'))
286 5d1d131b Giorgos Verigakis
287 b3b32add Giorgos Verigakis
@command(api='cyclades')
288 eb3ca8ca Giorgos Verigakis
class server_start(object):
289 6a0b1658 Giorgos Verigakis
    """Start a server"""
290 44b8928d Giorgos Verigakis
291 5d1d131b Giorgos Verigakis
    def main(self, server_id):
292 a2ed3c3e Stavros Sachtouris
        try:
293 a2ed3c3e Stavros Sachtouris
            self.client.start_server(int(server_id))
294 a2ed3c3e Stavros Sachtouris
        except ValueError:
295 edbee9c8 Stavros Sachtouris
            print(yellow('Server id must be a base10 integer'))
296 5d1d131b Giorgos Verigakis
297 b3b32add Giorgos Verigakis
@command(api='cyclades')
298 eb3ca8ca Giorgos Verigakis
class server_shutdown(object):
299 6a0b1658 Giorgos Verigakis
    """Shutdown a server"""
300 44b8928d Giorgos Verigakis
301 5d1d131b Giorgos Verigakis
    def main(self, server_id):
302 a2ed3c3e Stavros Sachtouris
        try:
303 a2ed3c3e Stavros Sachtouris
            self.client.shutdown_server(int(server_id))
304 a2ed3c3e Stavros Sachtouris
        except ValueError:
305 edbee9c8 Stavros Sachtouris
            print(yellow('Server id must be a base10 integer'))
306 5d1d131b Giorgos Verigakis
307 b3b32add Giorgos Verigakis
@command(api='cyclades')
308 eb3ca8ca Giorgos Verigakis
class server_console(object):
309 6a0b1658 Giorgos Verigakis
    """Get a VNC console"""
310 44b8928d Giorgos Verigakis
311 5d1d131b Giorgos Verigakis
    def main(self, server_id):
312 a2ed3c3e Stavros Sachtouris
        try:
313 a2ed3c3e Stavros Sachtouris
            reply = self.client.get_server_console(int(server_id))
314 a2ed3c3e Stavros Sachtouris
        except ValueError:
315 edbee9c8 Stavros Sachtouris
            print(yellow('Server id must be a base10 integer'))
316 a2ed3c3e Stavros Sachtouris
            return
317 5d1d131b Giorgos Verigakis
        print_dict(reply)
318 5d1d131b Giorgos Verigakis
319 b3b32add Giorgos Verigakis
@command(api='cyclades')
320 eb3ca8ca Giorgos Verigakis
class server_firewall(object):
321 6a0b1658 Giorgos Verigakis
    """Set the server's firewall profile"""
322 44b8928d Giorgos Verigakis
323 5d1d131b Giorgos Verigakis
    def main(self, server_id, profile):
324 a2ed3c3e Stavros Sachtouris
        try:
325 a2ed3c3e Stavros Sachtouris
            self.client.set_firewall_profile(int(server_id), profile)
326 a2ed3c3e Stavros Sachtouris
        except ValueError:
327 edbee9c8 Stavros Sachtouris
            print(yellow('Server id must be a base10 integer'))
328 5d1d131b Giorgos Verigakis
329 b3b32add Giorgos Verigakis
@command(api='cyclades')
330 eb3ca8ca Giorgos Verigakis
class server_addr(object):
331 6a0b1658 Giorgos Verigakis
    """List a server's addresses"""
332 44b8928d Giorgos Verigakis
333 5d1d131b Giorgos Verigakis
    def main(self, server_id, network=None):
334 a2ed3c3e Stavros Sachtouris
        try:
335 a2ed3c3e Stavros Sachtouris
            reply = self.client.list_server_nic_details(int(server_id), network)
336 a2ed3c3e Stavros Sachtouris
        except ValueError:
337 edbee9c8 Stavros Sachtouris
            print(yellow('Server id must be a base10 integer'))
338 a2ed3c3e Stavros Sachtouris
            return
339 1b93846c Stavros Sachtouris
        print_list(reply)
340 5d1d131b Giorgos Verigakis
341 a1c50326 Giorgos Verigakis
@command(api='compute')
342 eb3ca8ca Giorgos Verigakis
class server_meta(object):
343 6a0b1658 Giorgos Verigakis
    """Get a server's metadata"""
344 44b8928d Giorgos Verigakis
345 5d1d131b Giorgos Verigakis
    def main(self, server_id, key=None):
346 a2ed3c3e Stavros Sachtouris
        try:
347 a2ed3c3e Stavros Sachtouris
            reply = self.client.get_server_metadata(int(server_id), key)
348 a2ed3c3e Stavros Sachtouris
        except ValueError:
349 edbee9c8 Stavros Sachtouris
            print(yellow('Server id must be a base10 integer'))
350 a2ed3c3e Stavros Sachtouris
            return
351 5d1d131b Giorgos Verigakis
        print_dict(reply)
352 5d1d131b Giorgos Verigakis
353 a1c50326 Giorgos Verigakis
@command(api='compute')
354 eb3ca8ca Giorgos Verigakis
class server_addmeta(object):
355 6a0b1658 Giorgos Verigakis
    """Add server metadata"""
356 44b8928d Giorgos Verigakis
357 5d1d131b Giorgos Verigakis
    def main(self, server_id, key, val):
358 a2ed3c3e Stavros Sachtouris
        try:
359 a2ed3c3e Stavros Sachtouris
            reply = self.client.create_server_metadata(int(server_id), key, val)
360 a2ed3c3e Stavros Sachtouris
        except ValueError:
361 edbee9c8 Stavros Sachtouris
            print(yellow('Server id must be a base10 integer'))
362 a2ed3c3e Stavros Sachtouris
            return
363 5d1d131b Giorgos Verigakis
        print_dict(reply)
364 5d1d131b Giorgos Verigakis
365 a1c50326 Giorgos Verigakis
@command(api='compute')
366 eb3ca8ca Giorgos Verigakis
class server_setmeta(object):
367 6a0b1658 Giorgos Verigakis
    """Update server's metadata"""
368 44b8928d Giorgos Verigakis
369 5d1d131b Giorgos Verigakis
    def main(self, server_id, key, val):
370 ec52784d Giorgos Verigakis
        metadata = {key: val}
371 a2ed3c3e Stavros Sachtouris
        try:
372 a2ed3c3e Stavros Sachtouris
            reply = self.client.update_server_metadata(int(server_id), **metadata)
373 a2ed3c3e Stavros Sachtouris
        except ValueError:
374 edbee9c8 Stavros Sachtouris
            print(yellow('Server id must be a base10 integer'))
375 a2ed3c3e Stavros Sachtouris
            return
376 5d1d131b Giorgos Verigakis
        print_dict(reply)
377 5d1d131b Giorgos Verigakis
378 a1c50326 Giorgos Verigakis
@command(api='compute')
379 eb3ca8ca Giorgos Verigakis
class server_delmeta(object):
380 6a0b1658 Giorgos Verigakis
    """Delete server metadata"""
381 44b8928d Giorgos Verigakis
382 5d1d131b Giorgos Verigakis
    def main(self, server_id, key):
383 a2ed3c3e Stavros Sachtouris
        try:
384 a2ed3c3e Stavros Sachtouris
            self.client.delete_server_metadata(int(server_id), key)
385 a2ed3c3e Stavros Sachtouris
        except ValueError:
386 edbee9c8 Stavros Sachtouris
            print(yellow('Server id must be a base10 integer'))
387 a2ed3c3e Stavros Sachtouris
            return
388 5d1d131b Giorgos Verigakis
389 b3b32add Giorgos Verigakis
@command(api='cyclades')
390 eb3ca8ca Giorgos Verigakis
class server_stats(object):
391 6a0b1658 Giorgos Verigakis
    """Get server statistics"""
392 44b8928d Giorgos Verigakis
393 5d1d131b Giorgos Verigakis
    def main(self, server_id):
394 a2ed3c3e Stavros Sachtouris
        try:
395 a2ed3c3e Stavros Sachtouris
            reply = self.client.get_server_stats(int(server_id))
396 a2ed3c3e Stavros Sachtouris
        except ValueError:
397 edbee9c8 Stavros Sachtouris
            print(yellow('Server id must be a base10 integer'))
398 a2ed3c3e Stavros Sachtouris
            return
399 5d1d131b Giorgos Verigakis
        print_dict(reply, exclude=('serverRef',))
400 5d1d131b Giorgos Verigakis
401 a1c50326 Giorgos Verigakis
@command(api='compute')
402 eb3ca8ca Giorgos Verigakis
class flavor_list(object):
403 6a0b1658 Giorgos Verigakis
    """List flavors"""
404 44b8928d Giorgos Verigakis
405 77eaa0be Giorgos Verigakis
    def update_parser(self, parser):
406 8378faf2 Giorgos Verigakis
        parser.add_argument('-l', dest='detail', action='store_true',
407 eb3ca8ca Giorgos Verigakis
                default=False, help='show detailed output')
408 8378faf2 Giorgos Verigakis
409 5d1d131b Giorgos Verigakis
    def main(self):
410 8378faf2 Giorgos Verigakis
        flavors = self.client.list_flavors(self.args.detail)
411 a6757cbc Giorgos Verigakis
        print_items(flavors)
412 5d1d131b Giorgos Verigakis
413 a1c50326 Giorgos Verigakis
@command(api='compute')
414 eb3ca8ca Giorgos Verigakis
class flavor_info(object):
415 6a0b1658 Giorgos Verigakis
    """Get flavor details"""
416 44b8928d Giorgos Verigakis
417 5d1d131b Giorgos Verigakis
    def main(self, flavor_id):
418 edbee9c8 Stavros Sachtouris
        try:
419 edbee9c8 Stavros Sachtouris
            flavor = self.client.get_flavor_details(int(flavor_id))
420 edbee9c8 Stavros Sachtouris
        except ValueError:
421 edbee9c8 Stavros Sachtouris
            print(yellow('Flavor id must be a base10 integer'))
422 edbee9c8 Stavros Sachtouris
            return
423 5d1d131b Giorgos Verigakis
        print_dict(flavor)
424 5d1d131b Giorgos Verigakis
425 a1c50326 Giorgos Verigakis
@command(api='compute')
426 eb3ca8ca Giorgos Verigakis
class image_list(object):
427 6a0b1658 Giorgos Verigakis
    """List images"""
428 44b8928d Giorgos Verigakis
429 77eaa0be Giorgos Verigakis
    def update_parser(self, parser):
430 8378faf2 Giorgos Verigakis
        parser.add_argument('-l', dest='detail', action='store_true',
431 eb3ca8ca Giorgos Verigakis
                default=False, help='show detailed output')
432 8378faf2 Giorgos Verigakis
433 5d1d131b Giorgos Verigakis
    def main(self):
434 8378faf2 Giorgos Verigakis
        images = self.client.list_images(self.args.detail)
435 a6757cbc Giorgos Verigakis
        print_items(images)
436 5d1d131b Giorgos Verigakis
437 a1c50326 Giorgos Verigakis
@command(api='compute')
438 eb3ca8ca Giorgos Verigakis
class image_info(object):
439 6a0b1658 Giorgos Verigakis
    """Get image details"""
440 44b8928d Giorgos Verigakis
441 5d1d131b Giorgos Verigakis
    def main(self, image_id):
442 eb3ca8ca Giorgos Verigakis
        image = self.client.get_image_details(image_id)
443 5d1d131b Giorgos Verigakis
        print_dict(image)
444 5d1d131b Giorgos Verigakis
445 a1c50326 Giorgos Verigakis
@command(api='compute')
446 eb3ca8ca Giorgos Verigakis
class image_delete(object):
447 6a0b1658 Giorgos Verigakis
    """Delete image"""
448 44b8928d Giorgos Verigakis
449 5d1d131b Giorgos Verigakis
    def main(self, image_id):
450 eb3ca8ca Giorgos Verigakis
        self.client.delete_image(image_id)
451 5d1d131b Giorgos Verigakis
452 a1c50326 Giorgos Verigakis
@command(api='compute')
453 cb813272 Giorgos Verigakis
class image_properties(object):
454 cb813272 Giorgos Verigakis
    """Get image properties"""
455 44b8928d Giorgos Verigakis
456 5d1d131b Giorgos Verigakis
    def main(self, image_id, key=None):
457 eb3ca8ca Giorgos Verigakis
        reply = self.client.get_image_metadata(image_id, key)
458 5d1d131b Giorgos Verigakis
        print_dict(reply)
459 5d1d131b Giorgos Verigakis
460 a1c50326 Giorgos Verigakis
@command(api='compute')
461 cb813272 Giorgos Verigakis
class image_addproperty(object):
462 cb813272 Giorgos Verigakis
    """Add an image property"""
463 44b8928d Giorgos Verigakis
464 5d1d131b Giorgos Verigakis
    def main(self, image_id, key, val):
465 eb3ca8ca Giorgos Verigakis
        reply = self.client.create_image_metadata(image_id, key, val)
466 5d1d131b Giorgos Verigakis
        print_dict(reply)
467 5d1d131b Giorgos Verigakis
468 a1c50326 Giorgos Verigakis
@command(api='compute')
469 cb813272 Giorgos Verigakis
class image_setproperty(object):
470 cb813272 Giorgos Verigakis
    """Update an image property"""
471 44b8928d Giorgos Verigakis
472 5d1d131b Giorgos Verigakis
    def main(self, image_id, key, val):
473 ec52784d Giorgos Verigakis
        metadata = {key: val}
474 eb3ca8ca Giorgos Verigakis
        reply = self.client.update_image_metadata(image_id, **metadata)
475 5d1d131b Giorgos Verigakis
        print_dict(reply)
476 5d1d131b Giorgos Verigakis
477 a1c50326 Giorgos Verigakis
@command(api='compute')
478 cb813272 Giorgos Verigakis
class image_delproperty(object):
479 cb813272 Giorgos Verigakis
    """Delete an image property"""
480 44b8928d Giorgos Verigakis
481 5d1d131b Giorgos Verigakis
    def main(self, image_id, key):
482 eb3ca8ca Giorgos Verigakis
        self.client.delete_image_metadata(image_id, key)
483 5d1d131b Giorgos Verigakis
484 b3b32add Giorgos Verigakis
@command(api='cyclades')
485 eb3ca8ca Giorgos Verigakis
class network_list(object):
486 6a0b1658 Giorgos Verigakis
    """List networks"""
487 44b8928d Giorgos Verigakis
488 77eaa0be Giorgos Verigakis
    def update_parser(self, parser):
489 8378faf2 Giorgos Verigakis
        parser.add_argument('-l', dest='detail', action='store_true',
490 eb3ca8ca Giorgos Verigakis
                default=False, help='show detailed output')
491 8378faf2 Giorgos Verigakis
492 5d1d131b Giorgos Verigakis
    def main(self):
493 8378faf2 Giorgos Verigakis
        networks = self.client.list_networks(self.args.detail)
494 a6757cbc Giorgos Verigakis
        print_items(networks)
495 5d1d131b Giorgos Verigakis
496 b3b32add Giorgos Verigakis
@command(api='cyclades')
497 eb3ca8ca Giorgos Verigakis
class network_create(object):
498 6a0b1658 Giorgos Verigakis
    """Create a network"""
499 44b8928d Giorgos Verigakis
500 5d1d131b Giorgos Verigakis
    def main(self, name):
501 5d1d131b Giorgos Verigakis
        reply = self.client.create_network(name)
502 5d1d131b Giorgos Verigakis
        print_dict(reply)
503 5d1d131b Giorgos Verigakis
504 b3b32add Giorgos Verigakis
@command(api='cyclades')
505 eb3ca8ca Giorgos Verigakis
class network_info(object):
506 6a0b1658 Giorgos Verigakis
    """Get network details"""
507 44b8928d Giorgos Verigakis
508 5d1d131b Giorgos Verigakis
    def main(self, network_id):
509 5d1d131b Giorgos Verigakis
        network = self.client.get_network_details(network_id)
510 5d1d131b Giorgos Verigakis
        print_dict(network)
511 5d1d131b Giorgos Verigakis
512 b3b32add Giorgos Verigakis
@command(api='cyclades')
513 eb3ca8ca Giorgos Verigakis
class network_rename(object):
514 6a0b1658 Giorgos Verigakis
    """Update network name"""
515 44b8928d Giorgos Verigakis
516 eb3ca8ca Giorgos Verigakis
    def main(self, network_id, new_name):
517 eb3ca8ca Giorgos Verigakis
        self.client.update_network_name(network_id, new_name)
518 5d1d131b Giorgos Verigakis
519 b3b32add Giorgos Verigakis
@command(api='cyclades')
520 eb3ca8ca Giorgos Verigakis
class network_delete(object):
521 6a0b1658 Giorgos Verigakis
    """Delete a network"""
522 44b8928d Giorgos Verigakis
523 5d1d131b Giorgos Verigakis
    def main(self, network_id):
524 5d1d131b Giorgos Verigakis
        self.client.delete_network(network_id)
525 5d1d131b Giorgos Verigakis
526 b3b32add Giorgos Verigakis
@command(api='cyclades')
527 eb3ca8ca Giorgos Verigakis
class network_connect(object):
528 6a0b1658 Giorgos Verigakis
    """Connect a server to a network"""
529 44b8928d Giorgos Verigakis
530 5d1d131b Giorgos Verigakis
    def main(self, server_id, network_id):
531 5d1d131b Giorgos Verigakis
        self.client.connect_server(server_id, network_id)
532 5d1d131b Giorgos Verigakis
533 b3b32add Giorgos Verigakis
@command(api='cyclades')
534 eb3ca8ca Giorgos Verigakis
class network_disconnect(object):
535 c7083665 Stavros Sachtouris
    """Disconnect a nic that connects a server to a network"""
536 5d1d131b Giorgos Verigakis
537 c7083665 Stavros Sachtouris
    def main(self, nic_id):
538 c7083665 Stavros Sachtouris
        try:
539 c7083665 Stavros Sachtouris
            server_id = nic_id.split('-')[1]
540 c7083665 Stavros Sachtouris
            self.client.disconnect_server(server_id, nic_id)
541 c7083665 Stavros Sachtouris
        except IndexError:
542 edbee9c8 Stavros Sachtouris
            print(yellow('nid_id format: nic-<server_id>-<nic_index>'))
543 5d1d131b Giorgos Verigakis
544 a1c50326 Giorgos Verigakis
@command(api='image')
545 cb813272 Giorgos Verigakis
class image_public(object):
546 cb813272 Giorgos Verigakis
    """List public images"""
547 44b8928d Giorgos Verigakis
548 77eaa0be Giorgos Verigakis
    def update_parser(self, parser):
549 8378faf2 Giorgos Verigakis
        parser.add_argument('-l', dest='detail', action='store_true',
550 a6757cbc Giorgos Verigakis
                default=False, help='show detailed output')
551 8378faf2 Giorgos Verigakis
        parser.add_argument('--container-format', dest='container_format',
552 a6757cbc Giorgos Verigakis
                metavar='FORMAT', help='filter by container format')
553 8378faf2 Giorgos Verigakis
        parser.add_argument('--disk-format', dest='disk_format',
554 a6757cbc Giorgos Verigakis
                metavar='FORMAT', help='filter by disk format')
555 8378faf2 Giorgos Verigakis
        parser.add_argument('--name', dest='name', metavar='NAME',
556 a6757cbc Giorgos Verigakis
                help='filter by name')
557 8378faf2 Giorgos Verigakis
        parser.add_argument('--size-min', dest='size_min', metavar='BYTES',
558 a6757cbc Giorgos Verigakis
                help='filter by minimum size')
559 8378faf2 Giorgos Verigakis
        parser.add_argument('--size-max', dest='size_max', metavar='BYTES',
560 a6757cbc Giorgos Verigakis
                help='filter by maximum size')
561 8378faf2 Giorgos Verigakis
        parser.add_argument('--status', dest='status', metavar='STATUS',
562 a6757cbc Giorgos Verigakis
                help='filter by status')
563 8378faf2 Giorgos Verigakis
        parser.add_argument('--order', dest='order', metavar='FIELD',
564 a6757cbc Giorgos Verigakis
                help='order by FIELD (use a - prefix to reverse order)')
565 8378faf2 Giorgos Verigakis
566 eb3ca8ca Giorgos Verigakis
    def main(self):
567 a6757cbc Giorgos Verigakis
        filters = {}
568 a6757cbc Giorgos Verigakis
        for filter in ('container_format', 'disk_format', 'name', 'size_min',
569 a6757cbc Giorgos Verigakis
                       'size_max', 'status'):
570 8378faf2 Giorgos Verigakis
            val = getattr(self.args, filter, None)
571 a6757cbc Giorgos Verigakis
            if val is not None:
572 a6757cbc Giorgos Verigakis
                filters[filter] = val
573 44b8928d Giorgos Verigakis
574 8378faf2 Giorgos Verigakis
        order = self.args.order or ''
575 8378faf2 Giorgos Verigakis
        images = self.client.list_public(self.args.detail, filters=filters,
576 a6757cbc Giorgos Verigakis
                                         order=order)
577 a6757cbc Giorgos Verigakis
        print_items(images, title=('name',))
578 a6757cbc Giorgos Verigakis
579 a1c50326 Giorgos Verigakis
@command(api='image')
580 cb813272 Giorgos Verigakis
class image_meta(object):
581 6a0b1658 Giorgos Verigakis
    """Get image metadata"""
582 44b8928d Giorgos Verigakis
583 8ab2c986 Giorgos Verigakis
    def main(self, image_id):
584 8ab2c986 Giorgos Verigakis
        image = self.client.get_meta(image_id)
585 8ab2c986 Giorgos Verigakis
        print_dict(image)
586 8ab2c986 Giorgos Verigakis
587 a1c50326 Giorgos Verigakis
@command(api='image')
588 cb813272 Giorgos Verigakis
class image_register(object):
589 6a0b1658 Giorgos Verigakis
    """Register an image"""
590 44b8928d Giorgos Verigakis
591 77eaa0be Giorgos Verigakis
    def update_parser(self, parser):
592 8378faf2 Giorgos Verigakis
        parser.add_argument('--checksum', dest='checksum', metavar='CHECKSUM',
593 a6757cbc Giorgos Verigakis
                help='set image checksum')
594 8378faf2 Giorgos Verigakis
        parser.add_argument('--container-format', dest='container_format',
595 a6757cbc Giorgos Verigakis
                metavar='FORMAT', help='set container format')
596 8378faf2 Giorgos Verigakis
        parser.add_argument('--disk-format', dest='disk_format',
597 a6757cbc Giorgos Verigakis
                metavar='FORMAT', help='set disk format')
598 8378faf2 Giorgos Verigakis
        parser.add_argument('--id', dest='id',
599 a6757cbc Giorgos Verigakis
                metavar='ID', help='set image ID')
600 8378faf2 Giorgos Verigakis
        parser.add_argument('--owner', dest='owner',
601 a6757cbc Giorgos Verigakis
                metavar='USER', help='set image owner (admin only)')
602 8378faf2 Giorgos Verigakis
        parser.add_argument('--property', dest='properties', action='append',
603 a6757cbc Giorgos Verigakis
                metavar='KEY=VAL',
604 a6757cbc Giorgos Verigakis
                help='add a property (can be used multiple times)')
605 8378faf2 Giorgos Verigakis
        parser.add_argument('--public', dest='is_public', action='store_true',
606 a6757cbc Giorgos Verigakis
                help='mark image as public')
607 8378faf2 Giorgos Verigakis
        parser.add_argument('--size', dest='size', metavar='SIZE',
608 a6757cbc Giorgos Verigakis
                help='set image size')
609 8378faf2 Giorgos Verigakis
610 a6757cbc Giorgos Verigakis
    def main(self, name, location):
611 cb813272 Giorgos Verigakis
        if not location.startswith('pithos://'):
612 4ca97333 Stavros Sachtouris
            account = self.config.get('storage', 'account').split()[0]
613 4ca97333 Stavros Sachtouris
            if account[-1] == '/':
614 4ca97333 Stavros Sachtouris
                account = account[:-1]
615 cb813272 Giorgos Verigakis
            container = self.config.get('storage', 'container')
616 4ca97333 Stavros Sachtouris
            location = 'pithos://%s/%s'%(account, location) \
617 4ca97333 Stavros Sachtouris
                if container is None or len(container) == 0 \
618 4ca97333 Stavros Sachtouris
                else 'pithos://%s/%s/%s' % (account, container, location)
619 44b8928d Giorgos Verigakis
620 a6757cbc Giorgos Verigakis
        params = {}
621 a6757cbc Giorgos Verigakis
        for key in ('checksum', 'container_format', 'disk_format', 'id',
622 6a0b1658 Giorgos Verigakis
                    'owner', 'size'):
623 8378faf2 Giorgos Verigakis
            val = getattr(self.args, key)
624 a6757cbc Giorgos Verigakis
            if val is not None:
625 a6757cbc Giorgos Verigakis
                params[key] = val
626 44b8928d Giorgos Verigakis
627 8378faf2 Giorgos Verigakis
        if self.args.is_public:
628 6a0b1658 Giorgos Verigakis
            params['is_public'] = 'true'
629 44b8928d Giorgos Verigakis
630 a6757cbc Giorgos Verigakis
        properties = {}
631 8378faf2 Giorgos Verigakis
        for property in self.args.properties or []:
632 a6757cbc Giorgos Verigakis
            key, sep, val = property.partition('=')
633 a6757cbc Giorgos Verigakis
            if not sep:
634 098ca087 Giorgos Verigakis
                print("Invalid property '%s'" % property)
635 a6757cbc Giorgos Verigakis
                return 1
636 a6757cbc Giorgos Verigakis
            properties[key.strip()] = val.strip()
637 44b8928d Giorgos Verigakis
638 a6757cbc Giorgos Verigakis
        self.client.register(name, location, params, properties)
639 eb3ca8ca Giorgos Verigakis
640 a1c50326 Giorgos Verigakis
@command(api='image')
641 cb813272 Giorgos Verigakis
class image_members(object):
642 6a0b1658 Giorgos Verigakis
    """Get image members"""
643 44b8928d Giorgos Verigakis
644 8ab2c986 Giorgos Verigakis
    def main(self, image_id):
645 8ab2c986 Giorgos Verigakis
        members = self.client.list_members(image_id)
646 8ab2c986 Giorgos Verigakis
        for member in members:
647 098ca087 Giorgos Verigakis
            print(member['member_id'])
648 8ab2c986 Giorgos Verigakis
649 a1c50326 Giorgos Verigakis
@command(api='image')
650 cb813272 Giorgos Verigakis
class image_shared(object):
651 6a0b1658 Giorgos Verigakis
    """List shared images"""
652 44b8928d Giorgos Verigakis
653 8ab2c986 Giorgos Verigakis
    def main(self, member):
654 8ab2c986 Giorgos Verigakis
        images = self.client.list_shared(member)
655 8ab2c986 Giorgos Verigakis
        for image in images:
656 098ca087 Giorgos Verigakis
            print(image['image_id'])
657 8ab2c986 Giorgos Verigakis
658 a1c50326 Giorgos Verigakis
@command(api='image')
659 cb813272 Giorgos Verigakis
class image_addmember(object):
660 6a0b1658 Giorgos Verigakis
    """Add a member to an image"""
661 44b8928d Giorgos Verigakis
662 8ab2c986 Giorgos Verigakis
    def main(self, image_id, member):
663 8ab2c986 Giorgos Verigakis
        self.client.add_member(image_id, member)
664 8ab2c986 Giorgos Verigakis
665 a1c50326 Giorgos Verigakis
@command(api='image')
666 cb813272 Giorgos Verigakis
class image_delmember(object):
667 6a0b1658 Giorgos Verigakis
    """Remove a member from an image"""
668 44b8928d Giorgos Verigakis
669 8ab2c986 Giorgos Verigakis
    def main(self, image_id, member):
670 8ab2c986 Giorgos Verigakis
        self.client.remove_member(image_id, member)
671 8ab2c986 Giorgos Verigakis
672 a1c50326 Giorgos Verigakis
@command(api='image')
673 cb813272 Giorgos Verigakis
class image_setmembers(object):
674 6a0b1658 Giorgos Verigakis
    """Set the members of an image"""
675 44b8928d Giorgos Verigakis
676 8ab2c986 Giorgos Verigakis
    def main(self, image_id, *member):
677 8ab2c986 Giorgos Verigakis
        self.client.set_members(image_id, member)
678 8ab2c986 Giorgos Verigakis
679 2bcb595a Giorgos Verigakis
class _store_account_command(object):
680 2bcb595a Giorgos Verigakis
    """Base class for account level storage commands"""
681 44b8928d Giorgos Verigakis
682 2bcb595a Giorgos Verigakis
    def update_parser(self, parser):
683 8378faf2 Giorgos Verigakis
        parser.add_argument('--account', dest='account', metavar='NAME',
684 6a0b1658 Giorgos Verigakis
                          help="Specify an account to use")
685 8378faf2 Giorgos Verigakis
686 6a0b1658 Giorgos Verigakis
    def progress(self, message):
687 6a0b1658 Giorgos Verigakis
        """Return a generator function to be used for progress tracking"""
688 44b8928d Giorgos Verigakis
689 6a0b1658 Giorgos Verigakis
        MESSAGE_LENGTH = 25
690 44b8928d Giorgos Verigakis
691 6a0b1658 Giorgos Verigakis
        def progress_gen(n):
692 6a0b1658 Giorgos Verigakis
            msg = message.ljust(MESSAGE_LENGTH)
693 863dd770 Giorgos Verigakis
            for i in ProgressBar(msg).iter(range(n)):
694 6a0b1658 Giorgos Verigakis
                yield
695 6a0b1658 Giorgos Verigakis
            yield
696 44b8928d Giorgos Verigakis
697 6a0b1658 Giorgos Verigakis
        return progress_gen
698 44b8928d Giorgos Verigakis
699 6a0b1658 Giorgos Verigakis
    def main(self):
700 8378faf2 Giorgos Verigakis
        if self.args.account is not None:
701 8378faf2 Giorgos Verigakis
            self.client.account = self.args.account
702 2bcb595a Giorgos Verigakis
703 2bcb595a Giorgos Verigakis
class _store_container_command(_store_account_command):
704 2bcb595a Giorgos Verigakis
    """Base class for container level storage commands"""
705 44b8928d Giorgos Verigakis
706 2bcb595a Giorgos Verigakis
    def update_parser(self, parser):
707 2bcb595a Giorgos Verigakis
        super(_store_container_command, self).update_parser(parser)
708 8378faf2 Giorgos Verigakis
        parser.add_argument('--container', dest='container', metavar='NAME',
709 2bcb595a Giorgos Verigakis
                          help="Specify a container to use")
710 8378faf2 Giorgos Verigakis
711 9aece4ba Stavros Sachtouris
    def extract_container_and_path(self, container_with_path):
712 9aece4ba Stavros Sachtouris
        assert isinstance(container_with_path, str)
713 9aece4ba Stavros Sachtouris
        cnp = container_with_path.split(':')
714 9aece4ba Stavros Sachtouris
        self.container = cnp[0]
715 9aece4ba Stavros Sachtouris
        self.path = cnp[1] if len(cnp) > 1 else None
716 9aece4ba Stavros Sachtouris
            
717 9aece4ba Stavros Sachtouris
718 9aece4ba Stavros Sachtouris
    def main(self, container_with_path=None):
719 2bcb595a Giorgos Verigakis
        super(_store_container_command, self).main()
720 9aece4ba Stavros Sachtouris
        if container_with_path is not None:
721 9aece4ba Stavros Sachtouris
            self.extract_container_and_path(container_with_path)
722 9aece4ba Stavros Sachtouris
            self.client.container = self.container
723 9aece4ba Stavros Sachtouris
        elif self.args.container is not None:
724 8378faf2 Giorgos Verigakis
            self.client.container = self.args.container
725 9aece4ba Stavros Sachtouris
        else:
726 9aece4ba Stavros Sachtouris
            self.container = None
727 176894c1 Giorgos Verigakis
728 f3a722d4 Stavros Sachtouris
@command(api='storage')
729 dd9a5d7c Stavros Sachtouris
class store_list(_store_container_command):
730 9aece4ba Stavros Sachtouris
    """List containers, object trees or objects in a directory
731 9aece4ba Stavros Sachtouris
    """
732 e2bd16d5 Stavros Sachtouris
733 dd9a5d7c Stavros Sachtouris
    def print_objects(self, object_list):
734 dd9a5d7c Stavros Sachtouris
        for obj in object_list:
735 d2dec8b1 Stavros Sachtouris
            size = format_size(obj['bytes']) if 0 < obj['bytes'] else 'D'
736 e2bd16d5 Stavros Sachtouris
            print('%6s %s' % (size, obj['name']))
737 e2bd16d5 Stavros Sachtouris
738 dd9a5d7c Stavros Sachtouris
    def print_containers(self, container_list):
739 dd9a5d7c Stavros Sachtouris
        for container in container_list:
740 dd9a5d7c Stavros Sachtouris
            size = format_size(container['bytes'])
741 dd9a5d7c Stavros Sachtouris
            print('%s (%s, %s objects)' % (container['name'], size, container['count']))
742 dd9a5d7c Stavros Sachtouris
            
743 9aece4ba Stavros Sachtouris
    def main(self, container____path__=None):
744 9aece4ba Stavros Sachtouris
        super(store_list, self).main(container____path__)
745 9aece4ba Stavros Sachtouris
        if self.container is None:
746 dd9a5d7c Stavros Sachtouris
            reply = self.client.list_containers()
747 dd9a5d7c Stavros Sachtouris
            self.print_containers(reply)
748 dd9a5d7c Stavros Sachtouris
        else:
749 9aece4ba Stavros Sachtouris
            reply = self.client.list_objects() if self.path is None \
750 9aece4ba Stavros Sachtouris
                else self.client.list_objects_in_path(path_prefix=self.path)
751 dd9a5d7c Stavros Sachtouris
            self.print_objects(reply)
752 44b8928d Giorgos Verigakis
753 2bcb595a Giorgos Verigakis
@command(api='storage')
754 9aece4ba Stavros Sachtouris
class store_create(_store_container_command):
755 9aece4ba Stavros Sachtouris
    """Create a container or a directory object"""
756 eb903ba7 Stavros Sachtouris
757 9aece4ba Stavros Sachtouris
    def main(self, container____directory__):
758 9aece4ba Stavros Sachtouris
        super(store_create, self).main(container____directory__)
759 9aece4ba Stavros Sachtouris
        if self.path is None:
760 9aece4ba Stavros Sachtouris
            self.client.create_container(self.container)
761 eb903ba7 Stavros Sachtouris
        else:
762 9aece4ba Stavros Sachtouris
            self.client.create_directory(self.path)
763 eb903ba7 Stavros Sachtouris
764 eb903ba7 Stavros Sachtouris
@command(api='storage')
765 9aece4ba Stavros Sachtouris
class store_copy(_store_container_command):
766 eed330ab Stavros Sachtouris
    """Copy an object"""
767 c2867610 Stavros Sachtouris
768 9aece4ba Stavros Sachtouris
    def main(self, source_container___path, destination_container____path__):
769 9aece4ba Stavros Sachtouris
        super(store_copy, self).main(source_container___path)
770 9aece4ba Stavros Sachtouris
        dst = destination_container____path__.split(':')
771 9aece4ba Stavros Sachtouris
        dst_cont = dst[0]
772 9aece4ba Stavros Sachtouris
        dst_path = dst[1] if len(dst) > 1 else False
773 9aece4ba Stavros Sachtouris
        self.client.copy_object(src_container = self.container, src_object = self.path, dst_container = dst_cont, dst_object = dst_path)
774 eed330ab Stavros Sachtouris
775 eed330ab Stavros Sachtouris
@command(api='storage')
776 9aece4ba Stavros Sachtouris
class store_move(_store_container_command):
777 eed330ab Stavros Sachtouris
    """Move an object"""
778 eed330ab Stavros Sachtouris
779 9aece4ba Stavros Sachtouris
    def main(self, source_container___path, destination_container____path__):
780 9aece4ba Stavros Sachtouris
        super(store_move, self).main(source_container___path)
781 9aece4ba Stavros Sachtouris
        dst = destination_container____path__.split(':')
782 9aece4ba Stavros Sachtouris
        dst_cont = dst[0]
783 9aece4ba Stavros Sachtouris
        dst_path = dst[1] if len(dst) > 1 else False
784 9aece4ba Stavros Sachtouris
        self.client.move_object(src_container = self.container, src_object = self.path, dst_container = dst_cont, dst_object = dst_path)
785 c2867610 Stavros Sachtouris
786 c2867610 Stavros Sachtouris
@command(api='storage')
787 f49084df Stavros Sachtouris
class store_append(_store_container_command):
788 f49084df Stavros Sachtouris
    """Append local file to (existing) remote object"""
789 f49084df Stavros Sachtouris
790 9aece4ba Stavros Sachtouris
    def main(self, local_path, container___path):
791 9aece4ba Stavros Sachtouris
        super(store_append, self).main(container___path)
792 f49084df Stavros Sachtouris
        f = open(local_path, 'r')
793 bcabbc35 Stavros Sachtouris
        upload_cb = self.progress('Appending blocks')
794 9aece4ba Stavros Sachtouris
        self.client.append_object(object=self.path, source_file = f, upload_cb = upload_cb)
795 f49084df Stavros Sachtouris
796 f49084df Stavros Sachtouris
@command(api='storage')
797 f49084df Stavros Sachtouris
class store_truncate(_store_container_command):
798 f49084df Stavros Sachtouris
    """Truncate remote file up to a size"""
799 f49084df Stavros Sachtouris
800 9aece4ba Stavros Sachtouris
    def main(self, container___path, size=0):
801 9aece4ba Stavros Sachtouris
        super(store_truncate, self).main(container___path)
802 9aece4ba Stavros Sachtouris
        self.client.truncate_object(self.path, size)
803 ee62607e Stavros Sachtouris
804 ee62607e Stavros Sachtouris
@command(api='storage')
805 ee62607e Stavros Sachtouris
class store_overwrite(_store_container_command):
806 ee62607e Stavros Sachtouris
    """Overwrite part (from start to end) of a remote file"""
807 ee62607e Stavros Sachtouris
808 9aece4ba Stavros Sachtouris
    def main(self, local_path, container___path, start, end):
809 9aece4ba Stavros Sachtouris
        super(store_overwrite, self).main(container___path)
810 ee62607e Stavros Sachtouris
        f = open(local_path, 'r')
811 bcabbc35 Stavros Sachtouris
        upload_cb = self.progress('Overwritting blocks')
812 9aece4ba Stavros Sachtouris
        self.client.overwrite_object(object=self.path, start=start, end=end, source_file=f, upload_cb = upload_cb)
813 f49084df Stavros Sachtouris
814 f49084df Stavros Sachtouris
@command(api='storage')
815 2bcb595a Giorgos Verigakis
class store_upload(_store_container_command):
816 6a0b1658 Giorgos Verigakis
    """Upload a file"""
817 44b8928d Giorgos Verigakis
818 9aece4ba Stavros Sachtouris
    def main(self, local_path, container____path__):
819 9aece4ba Stavros Sachtouris
        super(store_upload, self).main(container____path__)
820 9aece4ba Stavros Sachtouris
        remote_path = basename(local_path) if self.path is None else self.path
821 9aece4ba Stavros Sachtouris
        with open(local_path) as f:
822 6a0b1658 Giorgos Verigakis
            hash_cb = self.progress('Calculating block hashes')
823 6a0b1658 Giorgos Verigakis
            upload_cb = self.progress('Uploading blocks')
824 eb903ba7 Stavros Sachtouris
            self.client.create_object(remote_path, f, hash_cb=hash_cb, upload_cb=upload_cb)
825 d2cea1e2 Giorgos Verigakis
826 d2cea1e2 Giorgos Verigakis
@command(api='storage')
827 2bcb595a Giorgos Verigakis
class store_download(_store_container_command):
828 6a0b1658 Giorgos Verigakis
    """Download a file"""
829 44b8928d Giorgos Verigakis
830 9aece4ba Stavros Sachtouris
    def main(self, container___path, local_path='-'):
831 9aece4ba Stavros Sachtouris
        super(store_download, self).main(container___path)
832 9aece4ba Stavros Sachtouris
        f, size = self.client.get_object(self.path)
833 176894c1 Giorgos Verigakis
        out = open(local_path, 'w') if local_path != '-' else stdout
834 44b8928d Giorgos Verigakis
835 44b8928d Giorgos Verigakis
        blocksize = 4 * 1024 ** 2
836 6a0b1658 Giorgos Verigakis
        nblocks = 1 + (size - 1) // blocksize
837 44b8928d Giorgos Verigakis
838 6a0b1658 Giorgos Verigakis
        cb = self.progress('Downloading blocks') if local_path != '-' else None
839 6a0b1658 Giorgos Verigakis
        if cb:
840 6a0b1658 Giorgos Verigakis
            gen = cb(nblocks)
841 6a0b1658 Giorgos Verigakis
            gen.next()
842 44b8928d Giorgos Verigakis
843 6a0b1658 Giorgos Verigakis
        data = f.read(blocksize)
844 176894c1 Giorgos Verigakis
        while data:
845 176894c1 Giorgos Verigakis
            out.write(data)
846 6a0b1658 Giorgos Verigakis
            data = f.read(blocksize)
847 6a0b1658 Giorgos Verigakis
            if cb:
848 6a0b1658 Giorgos Verigakis
                gen.next()
849 176894c1 Giorgos Verigakis
850 176894c1 Giorgos Verigakis
@command(api='storage')
851 2bcb595a Giorgos Verigakis
class store_delete(_store_container_command):
852 bebdd0d6 Stavros Sachtouris
    """Delete a container [or an object]"""
853 44b8928d Giorgos Verigakis
854 9aece4ba Stavros Sachtouris
    def main(self, container____path__):
855 9aece4ba Stavros Sachtouris
        super(store_delete, self).main(container____path__)
856 3e544e5b Stavros Sachtouris
        if self.path is None:
857 9aece4ba Stavros Sachtouris
            self.client.delete_container(self.container)
858 bebdd0d6 Stavros Sachtouris
        else:
859 9aece4ba Stavros Sachtouris
            self.client.delete_object(self.path)
860 a1c50326 Giorgos Verigakis
861 a91e0293 Giorgos Verigakis
@command(api='storage')
862 a91e0293 Giorgos Verigakis
class store_purge(_store_account_command):
863 a91e0293 Giorgos Verigakis
    """Purge a container"""
864 44b8928d Giorgos Verigakis
865 a91e0293 Giorgos Verigakis
    def main(self, container):
866 a91e0293 Giorgos Verigakis
        super(store_purge, self).main()
867 17edd3f4 Stavros Sachtouris
        self.client.container = container
868 17edd3f4 Stavros Sachtouris
        self.client.purge_container()
869 a91e0293 Giorgos Verigakis
870 87688514 Stavros Sachtouris
@command(api='storage')
871 87688514 Stavros Sachtouris
class store_publish(_store_container_command):
872 87688514 Stavros Sachtouris
    """Publish an object"""
873 87688514 Stavros Sachtouris
874 9aece4ba Stavros Sachtouris
    def main(self, container___path):
875 9aece4ba Stavros Sachtouris
        super(store_publish, self).main(container___path)
876 9aece4ba Stavros Sachtouris
        self.client.publish_object(self.path)
877 87688514 Stavros Sachtouris
878 87688514 Stavros Sachtouris
@command(api='storage')
879 87688514 Stavros Sachtouris
class store_unpublish(_store_container_command):
880 87688514 Stavros Sachtouris
    """Unpublish an object"""
881 87688514 Stavros Sachtouris
882 9aece4ba Stavros Sachtouris
    def main(self, container___path):
883 9aece4ba Stavros Sachtouris
        super(store_unpublish, self).main(container___path)
884 9aece4ba Stavros Sachtouris
        self.client.unpublish_object(self.path)
885 87688514 Stavros Sachtouris
886 eb903ba7 Stavros Sachtouris
@command(api='storage')
887 f49084df Stavros Sachtouris
class store_permitions(_store_container_command):
888 f49084df Stavros Sachtouris
    """Get object read/write permitions"""
889 f49084df Stavros Sachtouris
890 9aece4ba Stavros Sachtouris
    def main(self, container___path):
891 9aece4ba Stavros Sachtouris
        super(store_permitions, self).main(container___path)
892 9aece4ba Stavros Sachtouris
        reply = self.client.get_object_sharing(self.path)
893 f49084df Stavros Sachtouris
        print_dict(reply)
894 f49084df Stavros Sachtouris
895 f49084df Stavros Sachtouris
@command(api='storage')
896 28470086 Stavros Sachtouris
class store_setpermitions(_store_container_command):
897 28470086 Stavros Sachtouris
    """Set sharing permitions"""
898 28470086 Stavros Sachtouris
899 9aece4ba Stavros Sachtouris
    def main(self, container___path, *permitions):
900 9aece4ba Stavros Sachtouris
        super(store_setpermitions, self).main(container___path)
901 28470086 Stavros Sachtouris
        read = False
902 28470086 Stavros Sachtouris
        write = False
903 28470086 Stavros Sachtouris
        for perms in permitions:
904 28470086 Stavros Sachtouris
            splstr = perms.split('=')
905 28470086 Stavros Sachtouris
            if 'read' == splstr[0]:
906 28470086 Stavros Sachtouris
                read = [user_or_group.strip() for user_or_group in splstr[1].split(',')]
907 28470086 Stavros Sachtouris
            elif 'write' == splstr[0]:
908 28470086 Stavros Sachtouris
                write = [user_or_group.strip() for user_or_group in splstr[1].split(',')]
909 28470086 Stavros Sachtouris
            else:
910 28470086 Stavros Sachtouris
                read = False
911 28470086 Stavros Sachtouris
                write = False
912 28470086 Stavros Sachtouris
        if not read and not write:
913 28470086 Stavros Sachtouris
            print(u'Read/write permitions are given in the following format:')
914 28470086 Stavros Sachtouris
            print(u'\tread=username,groupname,...')
915 28470086 Stavros Sachtouris
            print(u'and/or')
916 28470086 Stavros Sachtouris
            print(u'\twrite=username,groupname,...')
917 28470086 Stavros Sachtouris
            return
918 9aece4ba Stavros Sachtouris
        self.client.set_object_sharing(self.path, read_permition=read, write_permition=write)
919 28470086 Stavros Sachtouris
920 28470086 Stavros Sachtouris
@command(api='storage')
921 28470086 Stavros Sachtouris
class store_delpermitions(_store_container_command):
922 28470086 Stavros Sachtouris
    """Delete all sharing permitions"""
923 28470086 Stavros Sachtouris
924 9aece4ba Stavros Sachtouris
    def main(self, container___path):
925 9aece4ba Stavros Sachtouris
        super(store_delpermitions, self).main(container___path)
926 9aece4ba Stavros Sachtouris
        self.client.del_object_sharing(self.path)
927 28470086 Stavros Sachtouris
928 28470086 Stavros Sachtouris
@command(api='storage')
929 9aece4ba Stavros Sachtouris
class store_info(_store_container_command):
930 eb903ba7 Stavros Sachtouris
    """Get information for account [, container [or object]]"""
931 eb903ba7 Stavros Sachtouris
932 9aece4ba Stavros Sachtouris
    def main(self, container____path__=None):
933 9aece4ba Stavros Sachtouris
        super(store_info, self).main(container____path__)
934 9aece4ba Stavros Sachtouris
        if self.container is None:
935 eb903ba7 Stavros Sachtouris
            reply = self.client.get_account_info()
936 9aece4ba Stavros Sachtouris
        elif self.path is None:
937 9aece4ba Stavros Sachtouris
            reply = self.client.get_container_info(self.container)
938 eb903ba7 Stavros Sachtouris
        else:
939 9aece4ba Stavros Sachtouris
            reply = self.client.get_object_info(self.path)
940 eb903ba7 Stavros Sachtouris
        print_dict(reply)
941 eb903ba7 Stavros Sachtouris
942 eb903ba7 Stavros Sachtouris
@command(api='storage')
943 9aece4ba Stavros Sachtouris
class store_meta(_store_container_command):
944 eb903ba7 Stavros Sachtouris
    """Get custom meta-content for account [, container [or object]]"""
945 eb903ba7 Stavros Sachtouris
946 9aece4ba Stavros Sachtouris
    def main(self, container____path__ = None):
947 9aece4ba Stavros Sachtouris
        super(store_meta, self).main(container____path__)
948 9aece4ba Stavros Sachtouris
        if self.container is None:
949 eb903ba7 Stavros Sachtouris
            reply = self.client.get_account_meta()
950 9aece4ba Stavros Sachtouris
        elif self.path is None:
951 9aece4ba Stavros Sachtouris
            reply = self.client.get_container_object_meta(self.container)
952 eb903ba7 Stavros Sachtouris
            print_dict(reply)
953 9aece4ba Stavros Sachtouris
            reply = self.client.get_container_meta(self.container)
954 eb903ba7 Stavros Sachtouris
        else:
955 9aece4ba Stavros Sachtouris
            reply = self.client.get_object_meta(self.path)
956 eb903ba7 Stavros Sachtouris
        print_dict(reply)
957 eb903ba7 Stavros Sachtouris
958 eb903ba7 Stavros Sachtouris
@command(api='storage')
959 9aece4ba Stavros Sachtouris
class store_setmeta(_store_container_command):
960 eb903ba7 Stavros Sachtouris
    """Set a new metadatum for account [, container [or object]]"""
961 eb903ba7 Stavros Sachtouris
962 9aece4ba Stavros Sachtouris
    def main(self, metakey, metavalue, container____path__=None):
963 9aece4ba Stavros Sachtouris
        super(store_setmeta, self).main(container____path__)
964 9aece4ba Stavros Sachtouris
        if self.container is None:
965 eb903ba7 Stavros Sachtouris
            self.client.set_account_meta({metakey:metavalue})
966 9aece4ba Stavros Sachtouris
        elif self.path is None:
967 9aece4ba Stavros Sachtouris
            self.client.set_container_meta({metakey:metavalue})
968 eb903ba7 Stavros Sachtouris
        else:
969 9aece4ba Stavros Sachtouris
            self.client.set_object_meta(self.path, {metakey:metavalue})
970 eb903ba7 Stavros Sachtouris
971 eb903ba7 Stavros Sachtouris
@command(api='storage')
972 9aece4ba Stavros Sachtouris
class store_delmeta(_store_container_command):
973 eb903ba7 Stavros Sachtouris
    """Delete an existing metadatum of account [, container [or object]]"""
974 eb903ba7 Stavros Sachtouris
975 9aece4ba Stavros Sachtouris
    def main(self, metakey, container____path__=None):
976 9aece4ba Stavros Sachtouris
        super(store_delmeta, self).main(container____path__)
977 9aece4ba Stavros Sachtouris
        if self.container is None:
978 379cd4bb Stavros Sachtouris
            self.client.del_account_meta(metakey)
979 9aece4ba Stavros Sachtouris
        elif self.path is None:
980 3e544e5b Stavros Sachtouris
            self.client.del_container_meta(metakey)
981 eb903ba7 Stavros Sachtouris
        else:
982 89c2e77b Stavros Sachtouris
            self.client.del_object_meta(metakey, self.path)
983 eb903ba7 Stavros Sachtouris
984 eb903ba7 Stavros Sachtouris
@command(api='storage')
985 eb903ba7 Stavros Sachtouris
class store_quota(_store_account_command):
986 eb903ba7 Stavros Sachtouris
    """Get  quota for account [or container]"""
987 eb903ba7 Stavros Sachtouris
988 eb903ba7 Stavros Sachtouris
    def main(self, container = None):
989 eb903ba7 Stavros Sachtouris
        super(store_quota, self).main()
990 eb903ba7 Stavros Sachtouris
        if container is None:
991 eb903ba7 Stavros Sachtouris
            reply = self.client.get_account_quota()
992 eb903ba7 Stavros Sachtouris
        else:
993 eb903ba7 Stavros Sachtouris
            reply = self.client.get_container_quota(container)
994 eb903ba7 Stavros Sachtouris
        print_dict(reply)
995 eb903ba7 Stavros Sachtouris
996 eb903ba7 Stavros Sachtouris
@command(api='storage')
997 eb903ba7 Stavros Sachtouris
class store_setquota(_store_account_command):
998 eb903ba7 Stavros Sachtouris
    """Set new quota (in KB) for account [or container]"""
999 eb903ba7 Stavros Sachtouris
1000 eb903ba7 Stavros Sachtouris
    def main(self, quota, container = None):
1001 eb903ba7 Stavros Sachtouris
        super(store_setquota, self).main()
1002 eb903ba7 Stavros Sachtouris
        if container is None:
1003 eb903ba7 Stavros Sachtouris
            self.client.set_account_quota(quota)
1004 eb903ba7 Stavros Sachtouris
        else:
1005 eb903ba7 Stavros Sachtouris
            self.client.container = container
1006 eb903ba7 Stavros Sachtouris
            self.client.set_container_quota(quota)
1007 eb903ba7 Stavros Sachtouris
1008 eb903ba7 Stavros Sachtouris
@command(api='storage')
1009 eb903ba7 Stavros Sachtouris
class store_versioning(_store_account_command):
1010 eb903ba7 Stavros Sachtouris
    """Get  versioning for account [or container ]"""
1011 eb903ba7 Stavros Sachtouris
1012 eb903ba7 Stavros Sachtouris
    def main(self, container = None):
1013 eb903ba7 Stavros Sachtouris
        super(store_versioning, self).main()
1014 eb903ba7 Stavros Sachtouris
        if container is None:
1015 eb903ba7 Stavros Sachtouris
            reply = self.client.get_account_versioning()
1016 eb903ba7 Stavros Sachtouris
        else:
1017 eb903ba7 Stavros Sachtouris
            reply = self.client.get_container_versioning(container)
1018 eb903ba7 Stavros Sachtouris
        print_dict(reply)
1019 eb903ba7 Stavros Sachtouris
1020 eb903ba7 Stavros Sachtouris
@command(api='storage')
1021 eb903ba7 Stavros Sachtouris
class store_setversioning(_store_account_command):
1022 eb903ba7 Stavros Sachtouris
    """Set new versioning (auto, none) for account [or container]"""
1023 eb903ba7 Stavros Sachtouris
1024 eb903ba7 Stavros Sachtouris
    def main(self, versioning, container = None):
1025 eb903ba7 Stavros Sachtouris
        super(store_setversioning, self).main()
1026 eb903ba7 Stavros Sachtouris
        if container is None:
1027 eb903ba7 Stavros Sachtouris
            self.client.set_account_versioning(versioning)
1028 eb903ba7 Stavros Sachtouris
        else:
1029 eb903ba7 Stavros Sachtouris
            self.client.container = container
1030 eb903ba7 Stavros Sachtouris
            self.client.set_container_versioning(versioning)
1031 eb903ba7 Stavros Sachtouris
1032 9f74ca46 Stavros Sachtouris
@command(api='storage')
1033 9f74ca46 Stavros Sachtouris
class store_test(_store_account_command):
1034 9f74ca46 Stavros Sachtouris
    """Perform a developer-level custom test"""
1035 9f74ca46 Stavros Sachtouris
    def main(self):
1036 9f74ca46 Stavros Sachtouris
        super(store_test, self).main()
1037 16ce7b91 Stavros Sachtouris
        DATE_FORMATS = ["%a %b %d %H:%M:%S %Y",
1038 16ce7b91 Stavros Sachtouris
            "%A, %d-%b-%y %H:%M:%S GMT",
1039 16ce7b91 Stavros Sachtouris
            "%a, %d %b %Y %H:%M:%S GMT"]
1040 16ce7b91 Stavros Sachtouris
        import time, datetime
1041 16ce7b91 Stavros Sachtouris
        t = datetime.datetime.utcnow()
1042 16ce7b91 Stavros Sachtouris
        ts = t.strftime(self.client.DATE_FORMATS[0])
1043 16ce7b91 Stavros Sachtouris
        p = t - datetime.timedelta(minutes=15000000)
1044 16ce7b91 Stavros Sachtouris
        past = p.strftime(self.client.DATE_FORMATS[0])
1045 16ce7b91 Stavros Sachtouris
        self.client.container = 'testCo'
1046 16ce7b91 Stavros Sachtouris
        self.client.container_head(until=100000000)
1047 379cd4bb Stavros Sachtouris
1048 eb903ba7 Stavros Sachtouris
@command(api='storage')
1049 c2867610 Stavros Sachtouris
class store_group(_store_account_command):
1050 c2867610 Stavros Sachtouris
    """Get user groups details for account"""
1051 c2867610 Stavros Sachtouris
1052 c2867610 Stavros Sachtouris
    def main(self):
1053 c2867610 Stavros Sachtouris
        super(store_group, self).main()
1054 c2867610 Stavros Sachtouris
        reply = self.client.get_account_group()
1055 c2867610 Stavros Sachtouris
        print_dict(reply)
1056 c2867610 Stavros Sachtouris
1057 c2867610 Stavros Sachtouris
@command(api='storage')
1058 eb903ba7 Stavros Sachtouris
class store_setgroup(_store_account_command):
1059 c2867610 Stavros Sachtouris
    """Create/update a new user group on account"""
1060 eb903ba7 Stavros Sachtouris
1061 eb903ba7 Stavros Sachtouris
    def main(self, groupname, *users):
1062 eb903ba7 Stavros Sachtouris
        super(store_setgroup, self).main()
1063 eb903ba7 Stavros Sachtouris
        self.client.set_account_group(groupname, users)
1064 eb903ba7 Stavros Sachtouris
1065 c2867610 Stavros Sachtouris
@command(api='storage')
1066 c2867610 Stavros Sachtouris
class store_delgroup(_store_account_command):
1067 c2867610 Stavros Sachtouris
    """Delete a user group on an account"""
1068 c2867610 Stavros Sachtouris
1069 c2867610 Stavros Sachtouris
    def main(self, groupname):
1070 c2867610 Stavros Sachtouris
        super(store_delgroup, self).main()
1071 c2867610 Stavros Sachtouris
        self.client.del_account_group(groupname)
1072 c2867610 Stavros Sachtouris
1073 43ca98ee Giorgos Verigakis
@command(api='astakos')
1074 43ca98ee Giorgos Verigakis
class astakos_authenticate(object):
1075 43ca98ee Giorgos Verigakis
    """Authenticate a user"""
1076 44b8928d Giorgos Verigakis
1077 43ca98ee Giorgos Verigakis
    def main(self):
1078 43ca98ee Giorgos Verigakis
        reply = self.client.authenticate()
1079 43ca98ee Giorgos Verigakis
        print_dict(reply)
1080 43ca98ee Giorgos Verigakis
1081 f3ddb705 Giorgos Verigakis
def print_groups():
1082 098ca087 Giorgos Verigakis
    print('\nGroups:')
1083 098ca087 Giorgos Verigakis
    for group in _commands:
1084 098ca087 Giorgos Verigakis
        description = GROUPS.get(group, '')
1085 098ca087 Giorgos Verigakis
        print(' ', group.ljust(12), description)
1086 eb3ca8ca Giorgos Verigakis
1087 f3ddb705 Giorgos Verigakis
def print_commands(group):
1088 f3ddb705 Giorgos Verigakis
    description = GROUPS.get(group, '')
1089 f3ddb705 Giorgos Verigakis
    if description:
1090 098ca087 Giorgos Verigakis
        print('\n' + description)
1091 44b8928d Giorgos Verigakis
1092 098ca087 Giorgos Verigakis
    print('\nCommands:')
1093 098ca087 Giorgos Verigakis
    for name, cls in _commands[group].items():
1094 098ca087 Giorgos Verigakis
        print(' ', name.ljust(14), cls.description)
1095 5d1d131b Giorgos Verigakis
1096 6a0b1658 Giorgos Verigakis
def add_handler(name, level, prefix=''):
1097 6a0b1658 Giorgos Verigakis
    h = logging.StreamHandler()
1098 6a0b1658 Giorgos Verigakis
    fmt = logging.Formatter(prefix + '%(message)s')
1099 6a0b1658 Giorgos Verigakis
    h.setFormatter(fmt)
1100 6a0b1658 Giorgos Verigakis
    logger = logging.getLogger(name)
1101 6a0b1658 Giorgos Verigakis
    logger.addHandler(h)
1102 6a0b1658 Giorgos Verigakis
    logger.setLevel(level)
1103 6a0b1658 Giorgos Verigakis
1104 5d1d131b Giorgos Verigakis
def main():
1105 8378faf2 Giorgos Verigakis
    exe = basename(sys.argv[0])
1106 8378faf2 Giorgos Verigakis
    parser = ArgumentParser(add_help=False)
1107 8378faf2 Giorgos Verigakis
    parser.prog = '%s <group> <command>' % exe
1108 8378faf2 Giorgos Verigakis
    parser.add_argument('-h', '--help', dest='help', action='store_true',
1109 f3ddb705 Giorgos Verigakis
                      default=False,
1110 f3ddb705 Giorgos Verigakis
                      help="Show this help message and exit")
1111 8378faf2 Giorgos Verigakis
    parser.add_argument('--config', dest='config', metavar='PATH',
1112 f3ddb705 Giorgos Verigakis
                      help="Specify the path to the configuration file")
1113 8378faf2 Giorgos Verigakis
    parser.add_argument('-d', '--debug', dest='debug', action='store_true',
1114 6a0b1658 Giorgos Verigakis
                      default=False,
1115 6a0b1658 Giorgos Verigakis
                      help="Include debug output")
1116 8378faf2 Giorgos Verigakis
    parser.add_argument('-i', '--include', dest='include', action='store_true',
1117 f3ddb705 Giorgos Verigakis
                      default=False,
1118 f3ddb705 Giorgos Verigakis
                      help="Include protocol headers in the output")
1119 8378faf2 Giorgos Verigakis
    parser.add_argument('-s', '--silent', dest='silent', action='store_true',
1120 f3ddb705 Giorgos Verigakis
                      default=False,
1121 f3ddb705 Giorgos Verigakis
                      help="Silent mode, don't output anything")
1122 8378faf2 Giorgos Verigakis
    parser.add_argument('-v', '--verbose', dest='verbose', action='store_true',
1123 f3ddb705 Giorgos Verigakis
                      default=False,
1124 f3ddb705 Giorgos Verigakis
                      help="Make the operation more talkative")
1125 8378faf2 Giorgos Verigakis
    parser.add_argument('-V', '--version', dest='version', action='store_true',
1126 f3ddb705 Giorgos Verigakis
                      default=False,
1127 f3ddb705 Giorgos Verigakis
                      help="Show version number and quit")
1128 8378faf2 Giorgos Verigakis
    parser.add_argument('-o', dest='options', action='append',
1129 f3ddb705 Giorgos Verigakis
                      default=[], metavar="KEY=VAL",
1130 f3ddb705 Giorgos Verigakis
                      help="Override a config values")
1131 8378faf2 Giorgos Verigakis
1132 8378faf2 Giorgos Verigakis
    args, argv = parser.parse_known_args()
1133 8378faf2 Giorgos Verigakis
1134 8378faf2 Giorgos Verigakis
    if args.version:
1135 f3ddb705 Giorgos Verigakis
        import kamaki
1136 098ca087 Giorgos Verigakis
        print("kamaki %s" % kamaki.__version__)
1137 f3ddb705 Giorgos Verigakis
        exit(0)
1138 d83a2834 Giorgos Verigakis
1139 8378faf2 Giorgos Verigakis
    config = Config(args.config) if args.config else Config()
1140 8378faf2 Giorgos Verigakis
1141 8378faf2 Giorgos Verigakis
    for option in args.options:
1142 f3ddb705 Giorgos Verigakis
        keypath, sep, val = option.partition('=')
1143 f3ddb705 Giorgos Verigakis
        if not sep:
1144 098ca087 Giorgos Verigakis
            print("Invalid option '%s'" % option)
1145 f3ddb705 Giorgos Verigakis
            exit(1)
1146 f3ddb705 Giorgos Verigakis
        section, sep, key = keypath.partition('.')
1147 f3ddb705 Giorgos Verigakis
        if not sep:
1148 098ca087 Giorgos Verigakis
            print("Invalid option '%s'" % option)
1149 f3ddb705 Giorgos Verigakis
            exit(1)
1150 f3ddb705 Giorgos Verigakis
        config.override(section.strip(), key.strip(), val.strip())
1151 44b8928d Giorgos Verigakis
1152 f3ddb705 Giorgos Verigakis
    apis = set(['config'])
1153 43ca98ee Giorgos Verigakis
    for api in ('compute', 'image', 'storage', 'astakos'):
1154 f3ddb705 Giorgos Verigakis
        if config.getboolean(api, 'enable'):
1155 f3ddb705 Giorgos Verigakis
            apis.add(api)
1156 f3ddb705 Giorgos Verigakis
    if config.getboolean('compute', 'cyclades_extensions'):
1157 f3ddb705 Giorgos Verigakis
        apis.add('cyclades')
1158 f3ddb705 Giorgos Verigakis
    if config.getboolean('storage', 'pithos_extensions'):
1159 f3ddb705 Giorgos Verigakis
        apis.add('pithos')
1160 44b8928d Giorgos Verigakis
1161 f3ddb705 Giorgos Verigakis
    # Remove commands that belong to APIs that are not included
1162 eb3ca8ca Giorgos Verigakis
    for group, group_commands in _commands.items():
1163 eb3ca8ca Giorgos Verigakis
        for name, cls in group_commands.items():
1164 f3ddb705 Giorgos Verigakis
            if cls.api not in apis:
1165 f3ddb705 Giorgos Verigakis
                del group_commands[name]
1166 f3ddb705 Giorgos Verigakis
        if not group_commands:
1167 f3ddb705 Giorgos Verigakis
            del _commands[group]
1168 8378faf2 Giorgos Verigakis
1169 8378faf2 Giorgos Verigakis
    group = argv.pop(0) if argv else None
1170 8378faf2 Giorgos Verigakis
1171 8378faf2 Giorgos Verigakis
    if not group:
1172 eb3ca8ca Giorgos Verigakis
        parser.print_help()
1173 f3ddb705 Giorgos Verigakis
        print_groups()
1174 a1c50326 Giorgos Verigakis
        exit(0)
1175 8378faf2 Giorgos Verigakis
1176 f3ddb705 Giorgos Verigakis
    if group not in _commands:
1177 eb3ca8ca Giorgos Verigakis
        parser.print_help()
1178 f3ddb705 Giorgos Verigakis
        print_groups()
1179 a1c50326 Giorgos Verigakis
        exit(1)
1180 8378faf2 Giorgos Verigakis
1181 8378faf2 Giorgos Verigakis
    parser.prog = '%s %s <command>' % (exe, group)
1182 8378faf2 Giorgos Verigakis
    command = argv.pop(0) if argv else None
1183 8378faf2 Giorgos Verigakis
1184 8378faf2 Giorgos Verigakis
    if not command:
1185 eb3ca8ca Giorgos Verigakis
        parser.print_help()
1186 f3ddb705 Giorgos Verigakis
        print_commands(group)
1187 a1c50326 Giorgos Verigakis
        exit(0)
1188 8378faf2 Giorgos Verigakis
1189 8378faf2 Giorgos Verigakis
    if command not in _commands[group]:
1190 eb3ca8ca Giorgos Verigakis
        parser.print_help()
1191 f3ddb705 Giorgos Verigakis
        print_commands(group)
1192 a1c50326 Giorgos Verigakis
        exit(1)
1193 44b8928d Giorgos Verigakis
1194 8378faf2 Giorgos Verigakis
    cmd = _commands[group][command]()
1195 8378faf2 Giorgos Verigakis
1196 8378faf2 Giorgos Verigakis
    parser.prog = '%s %s %s' % (exe, group, command)
1197 8378faf2 Giorgos Verigakis
    if cmd.syntax:
1198 8378faf2 Giorgos Verigakis
        parser.prog += '  %s' % cmd.syntax
1199 f3ddb705 Giorgos Verigakis
    parser.description = cmd.description
1200 eb3ca8ca Giorgos Verigakis
    parser.epilog = ''
1201 f3ddb705 Giorgos Verigakis
    if hasattr(cmd, 'update_parser'):
1202 f3ddb705 Giorgos Verigakis
        cmd.update_parser(parser)
1203 44b8928d Giorgos Verigakis
1204 8378faf2 Giorgos Verigakis
    args, argv = parser.parse_known_args()
1205 44b8928d Giorgos Verigakis
1206 8378faf2 Giorgos Verigakis
    if args.help:
1207 eb3ca8ca Giorgos Verigakis
        parser.print_help()
1208 a1c50326 Giorgos Verigakis
        exit(0)
1209 44b8928d Giorgos Verigakis
1210 8378faf2 Giorgos Verigakis
    if args.silent:
1211 6a0b1658 Giorgos Verigakis
        add_handler('', logging.CRITICAL)
1212 8378faf2 Giorgos Verigakis
    elif args.debug:
1213 6a0b1658 Giorgos Verigakis
        add_handler('requests', logging.INFO, prefix='* ')
1214 6a0b1658 Giorgos Verigakis
        add_handler('clients.send', logging.DEBUG, prefix='> ')
1215 6a0b1658 Giorgos Verigakis
        add_handler('clients.recv', logging.DEBUG, prefix='< ')
1216 8378faf2 Giorgos Verigakis
    elif args.verbose:
1217 6a0b1658 Giorgos Verigakis
        add_handler('requests', logging.INFO, prefix='* ')
1218 6a0b1658 Giorgos Verigakis
        add_handler('clients.send', logging.INFO, prefix='> ')
1219 6a0b1658 Giorgos Verigakis
        add_handler('clients.recv', logging.INFO, prefix='< ')
1220 8378faf2 Giorgos Verigakis
    elif args.include:
1221 6a0b1658 Giorgos Verigakis
        add_handler('clients.recv', logging.INFO)
1222 6a0b1658 Giorgos Verigakis
    else:
1223 6a0b1658 Giorgos Verigakis
        add_handler('', logging.WARNING)
1224 44b8928d Giorgos Verigakis
1225 f3ddb705 Giorgos Verigakis
    api = cmd.api
1226 6a0b1658 Giorgos Verigakis
    if api in ('compute', 'cyclades'):
1227 6a0b1658 Giorgos Verigakis
        url = config.get('compute', 'url')
1228 6a0b1658 Giorgos Verigakis
        token = config.get('compute', 'token') or config.get('global', 'token')
1229 6a0b1658 Giorgos Verigakis
        if config.getboolean('compute', 'cyclades_extensions'):
1230 6a0b1658 Giorgos Verigakis
            cmd.client = clients.cyclades(url, token)
1231 6a0b1658 Giorgos Verigakis
        else:
1232 6a0b1658 Giorgos Verigakis
            cmd.client = clients.compute(url, token)
1233 6a0b1658 Giorgos Verigakis
    elif api in ('storage', 'pithos'):
1234 6a0b1658 Giorgos Verigakis
        url = config.get('storage', 'url')
1235 6a0b1658 Giorgos Verigakis
        token = config.get('storage', 'token') or config.get('global', 'token')
1236 6a0b1658 Giorgos Verigakis
        account = config.get('storage', 'account')
1237 6a0b1658 Giorgos Verigakis
        container = config.get('storage', 'container')
1238 6a0b1658 Giorgos Verigakis
        if config.getboolean('storage', 'pithos_extensions'):
1239 6a0b1658 Giorgos Verigakis
            cmd.client = clients.pithos(url, token, account, container)
1240 6a0b1658 Giorgos Verigakis
        else:
1241 6a0b1658 Giorgos Verigakis
            cmd.client = clients.storage(url, token, account, container)
1242 6a0b1658 Giorgos Verigakis
    elif api == 'image':
1243 6a0b1658 Giorgos Verigakis
        url = config.get('image', 'url')
1244 6a0b1658 Giorgos Verigakis
        token = config.get('image', 'token') or config.get('global', 'token')
1245 6a0b1658 Giorgos Verigakis
        cmd.client = clients.image(url, token)
1246 43ca98ee Giorgos Verigakis
    elif api == 'astakos':
1247 43ca98ee Giorgos Verigakis
        url = config.get('astakos', 'url')
1248 43ca98ee Giorgos Verigakis
        token = config.get('astakos', 'token') or config.get('global', 'token')
1249 43ca98ee Giorgos Verigakis
        cmd.client = clients.astakos(url, token)
1250 44b8928d Giorgos Verigakis
1251 8378faf2 Giorgos Verigakis
    cmd.args = args
1252 6a0b1658 Giorgos Verigakis
    cmd.config = config
1253 44b8928d Giorgos Verigakis
1254 5d1d131b Giorgos Verigakis
    try:
1255 8378faf2 Giorgos Verigakis
        ret = cmd.main(*argv[2:])
1256 a1c50326 Giorgos Verigakis
        exit(ret)
1257 a6757cbc Giorgos Verigakis
    except TypeError as e:
1258 a6757cbc Giorgos Verigakis
        if e.args and e.args[0].startswith('main()'):
1259 a6757cbc Giorgos Verigakis
            parser.print_help()
1260 a1c50326 Giorgos Verigakis
            exit(1)
1261 a6757cbc Giorgos Verigakis
        else:
1262 a6757cbc Giorgos Verigakis
            raise
1263 6a0b1658 Giorgos Verigakis
    except clients.ClientError as err:
1264 6a0b1658 Giorgos Verigakis
        if err.status == 404:
1265 8378faf2 Giorgos Verigakis
            message = yellow(err.message)
1266 6a0b1658 Giorgos Verigakis
        elif 500 <= err.status < 600:
1267 8378faf2 Giorgos Verigakis
            message = magenta(err.message)
1268 6a0b1658 Giorgos Verigakis
        else:
1269 8378faf2 Giorgos Verigakis
            message = red(err.message)
1270 44b8928d Giorgos Verigakis
1271 8378faf2 Giorgos Verigakis
        print(message, file=stderr)
1272 8378faf2 Giorgos Verigakis
        if err.details and (args.verbose or args.debug):
1273 098ca087 Giorgos Verigakis
            print(err.details, file=stderr)
1274 a1c50326 Giorgos Verigakis
        exit(2)
1275 6a0b1658 Giorgos Verigakis
    except ConnectionError as err:
1276 098ca087 Giorgos Verigakis
        print(red("Connection error"), file=stderr)
1277 6a0b1658 Giorgos Verigakis
        exit(1)
1278 5d1d131b Giorgos Verigakis
1279 5d1d131b Giorgos Verigakis
if __name__ == '__main__':
1280 a1c50326 Giorgos Verigakis
    main()