Statistics
| Branch: | Tag: | Revision:

root / kamaki / cli / commands / image.py @ 854222c7

History | View | Annotate | Download (29.2 kB)

1 e3f01d64 Stavros Sachtouris
# Copyright 2012-2013 GRNET S.A. All rights reserved.
2 7493ccb6 Stavros Sachtouris
#
3 7493ccb6 Stavros Sachtouris
# Redistribution and use in source and binary forms, with or
4 7493ccb6 Stavros Sachtouris
# without modification, are permitted provided that the following
5 7493ccb6 Stavros Sachtouris
# conditions are met:
6 7493ccb6 Stavros Sachtouris
#
7 7493ccb6 Stavros Sachtouris
#   1. Redistributions of source code must retain the above
8 7493ccb6 Stavros Sachtouris
#      copyright notice, this list of conditions and the following
9 7493ccb6 Stavros Sachtouris
#      disclaimer.
10 7493ccb6 Stavros Sachtouris
#
11 7493ccb6 Stavros Sachtouris
#   2. Redistributions in binary form must reproduce the above
12 7493ccb6 Stavros Sachtouris
#      copyright notice, this list of conditions and the following
13 7493ccb6 Stavros Sachtouris
#      disclaimer in the documentation and/or other materials
14 7493ccb6 Stavros Sachtouris
#      provided with the distribution.
15 7493ccb6 Stavros Sachtouris
#
16 7493ccb6 Stavros Sachtouris
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
17 7493ccb6 Stavros Sachtouris
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 7493ccb6 Stavros Sachtouris
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 7493ccb6 Stavros Sachtouris
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
20 7493ccb6 Stavros Sachtouris
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 7493ccb6 Stavros Sachtouris
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 7493ccb6 Stavros Sachtouris
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23 7493ccb6 Stavros Sachtouris
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24 7493ccb6 Stavros Sachtouris
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 7493ccb6 Stavros Sachtouris
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26 7493ccb6 Stavros Sachtouris
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 7493ccb6 Stavros Sachtouris
# POSSIBILITY OF SUCH DAMAGE.
28 7493ccb6 Stavros Sachtouris
#
29 7493ccb6 Stavros Sachtouris
# The views and conclusions contained in the software and
30 7493ccb6 Stavros Sachtouris
# documentation are those of the authors and should not be
31 7493ccb6 Stavros Sachtouris
# interpreted as representing official policies, either expressed
32 7493ccb6 Stavros Sachtouris
# or implied, of GRNET S.A.command
33 7493ccb6 Stavros Sachtouris
34 623a4ceb Stavros Sachtouris
from json import load, dumps
35 d77e33d4 Stavros Sachtouris
from os import path
36 623a4ceb Stavros Sachtouris
from logging import getLogger
37 623a4ceb Stavros Sachtouris
38 f3e94e06 Stavros Sachtouris
from kamaki.cli import command
39 d486baec Stavros Sachtouris
from kamaki.cli.command_tree import CommandTree
40 854222c7 Stavros Sachtouris
from kamaki.cli.utils import print_dict, print_json, filter_dicts_by_dict
41 1395c40e Stavros Sachtouris
from kamaki.clients.image import ImageClient
42 00336c85 Stavros Sachtouris
from kamaki.clients.pithos import PithosClient
43 00336c85 Stavros Sachtouris
from kamaki.clients.astakos import AstakosClient
44 00336c85 Stavros Sachtouris
from kamaki.clients import ClientError
45 83c3ba87 Stavros Sachtouris
from kamaki.cli.argument import FlagArgument, ValueArgument, KeyValueArgument
46 d77e33d4 Stavros Sachtouris
from kamaki.cli.argument import IntArgument, ProgressBarArgument
47 bfb54881 Stavros Sachtouris
from kamaki.cli.commands.cyclades import _init_cyclades
48 8cec3671 Stavros Sachtouris
from kamaki.cli.errors import raiseCLIError, CLIBaseUrlError
49 b4f69041 Stavros Sachtouris
from kamaki.cli.commands import _command_init, errors, addLogSettings
50 545c6c29 Stavros Sachtouris
from kamaki.cli.commands import _optional_output_cmd, _optional_json
51 0b368c8c Stavros Sachtouris
52 234954d1 Stavros Sachtouris
53 a29d2f88 Stavros Sachtouris
image_cmds = CommandTree(
54 a29d2f88 Stavros Sachtouris
    'image',
55 a29d2f88 Stavros Sachtouris
    'Cyclades/Plankton API image commands\n'
56 a29d2f88 Stavros Sachtouris
    'image compute:\tCyclades/Compute API image commands')
57 d486baec Stavros Sachtouris
_commands = [image_cmds]
58 234954d1 Stavros Sachtouris
59 234954d1 Stavros Sachtouris
60 aa82dd5a Stavros Sachtouris
howto_image_file = [
61 aa82dd5a Stavros Sachtouris
    'Kamaki commands to:',
62 c626151a Stavros Sachtouris
    ' get current user id: /user authenticate',
63 aa82dd5a Stavros Sachtouris
    ' check available containers: /file list',
64 aa82dd5a Stavros Sachtouris
    ' create a new container: /file create <container>',
65 aa82dd5a Stavros Sachtouris
    ' check container contents: /file list <container>',
66 aa82dd5a Stavros Sachtouris
    ' upload files: /file upload <image file> <container>']
67 aa82dd5a Stavros Sachtouris
68 aa82dd5a Stavros Sachtouris
about_image_id = ['To see a list of available image ids: /image list']
69 15142309 Stavros Sachtouris
70 15142309 Stavros Sachtouris
71 623a4ceb Stavros Sachtouris
log = getLogger(__name__)
72 623a4ceb Stavros Sachtouris
73 623a4ceb Stavros Sachtouris
74 5eae854d Stavros Sachtouris
class _init_image(_command_init):
75 a03ade9e Stavros Sachtouris
    @errors.generic.all
76 b4f69041 Stavros Sachtouris
    @addLogSettings
77 a03ade9e Stavros Sachtouris
    def _run(self):
78 b4f69041 Stavros Sachtouris
        if getattr(self, 'cloud', None):
79 b4f69041 Stavros Sachtouris
            img_url = self._custom_url('image') or self._custom_url('plankton')
80 b4f69041 Stavros Sachtouris
            if img_url:
81 b4f69041 Stavros Sachtouris
                token = self._custom_token('image')\
82 b4f69041 Stavros Sachtouris
                    or self._custom_token('plankton')\
83 144b3551 Stavros Sachtouris
                    or self.config.get_cloud(self.cloud, 'token')
84 b4f69041 Stavros Sachtouris
                self.client = ImageClient(base_url=img_url, token=token)
85 b4f69041 Stavros Sachtouris
                return
86 8cec3671 Stavros Sachtouris
        if getattr(self, 'auth_base', False):
87 8cec3671 Stavros Sachtouris
            plankton_endpoints = self.auth_base.get_service_endpoints(
88 72fa0010 Stavros Sachtouris
                self._custom_type('image') or self._custom_type(
89 72fa0010 Stavros Sachtouris
                    'plankton') or 'image',
90 72fa0010 Stavros Sachtouris
                self._custom_version('image') or self._custom_version(
91 72fa0010 Stavros Sachtouris
                    'plankton') or '')
92 8cec3671 Stavros Sachtouris
            base_url = plankton_endpoints['publicURL']
93 b4f69041 Stavros Sachtouris
            token = self.auth_base.token
94 8cec3671 Stavros Sachtouris
        else:
95 8cec3671 Stavros Sachtouris
            raise CLIBaseUrlError(service='plankton')
96 a03ade9e Stavros Sachtouris
        self.client = ImageClient(base_url=base_url, token=token)
97 a03ade9e Stavros Sachtouris
98 7493ccb6 Stavros Sachtouris
    def main(self):
99 a03ade9e Stavros Sachtouris
        self._run()
100 7493ccb6 Stavros Sachtouris
101 234954d1 Stavros Sachtouris
102 573be34f Stavros Sachtouris
# Plankton Image Commands
103 573be34f Stavros Sachtouris
104 573be34f Stavros Sachtouris
105 aa82dd5a Stavros Sachtouris
def _validate_image_meta(json_dict, return_str=False):
106 623a4ceb Stavros Sachtouris
    """
107 623a4ceb Stavros Sachtouris
    :param json_dict" (dict) json-formated, of the form
108 623a4ceb Stavros Sachtouris
        {"key1": "val1", "key2": "val2", ...}
109 623a4ceb Stavros Sachtouris

110 623a4ceb Stavros Sachtouris
    :param return_str: (boolean) if true, return a json dump
111 623a4ceb Stavros Sachtouris

112 aa82dd5a Stavros Sachtouris
    :returns: (dict) if return_str is not True, else return str
113 623a4ceb Stavros Sachtouris

114 623a4ceb Stavros Sachtouris
    :raises TypeError, AttributeError: Invalid json format
115 623a4ceb Stavros Sachtouris

116 623a4ceb Stavros Sachtouris
    :raises AssertionError: Valid json but invalid image properties dict
117 623a4ceb Stavros Sachtouris
    """
118 9553da85 Stavros Sachtouris
    json_str = dumps(json_dict, indent=2)
119 623a4ceb Stavros Sachtouris
    for k, v in json_dict.items():
120 aa82dd5a Stavros Sachtouris
        if k.lower() == 'properties':
121 aa82dd5a Stavros Sachtouris
            for pk, pv in v.items():
122 aa82dd5a Stavros Sachtouris
                prop_ok = not (isinstance(pv, dict) or isinstance(pv, list))
123 aa82dd5a Stavros Sachtouris
                assert prop_ok, 'Invalid property value for key %s' % pk
124 aa82dd5a Stavros Sachtouris
                key_ok = not (' ' in k or '-' in k)
125 aa82dd5a Stavros Sachtouris
                assert key_ok, 'Invalid property key %s' % k
126 aa82dd5a Stavros Sachtouris
            continue
127 aa82dd5a Stavros Sachtouris
        meta_ok = not (isinstance(v, dict) or isinstance(v, list))
128 aa82dd5a Stavros Sachtouris
        assert meta_ok, 'Invalid value for meta key %s' % k
129 aa82dd5a Stavros Sachtouris
        meta_ok = ' ' not in k
130 aa82dd5a Stavros Sachtouris
        assert meta_ok, 'Invalid meta key [%s]' % k
131 623a4ceb Stavros Sachtouris
        json_dict[k] = '%s' % v
132 623a4ceb Stavros Sachtouris
    return json_str if return_str else json_dict
133 623a4ceb Stavros Sachtouris
134 623a4ceb Stavros Sachtouris
135 aa82dd5a Stavros Sachtouris
def _load_image_meta(filepath):
136 623a4ceb Stavros Sachtouris
    """
137 623a4ceb Stavros Sachtouris
    :param filepath: (str) the (relative) path of the metafile
138 623a4ceb Stavros Sachtouris

139 623a4ceb Stavros Sachtouris
    :returns: (dict) json_formated
140 623a4ceb Stavros Sachtouris

141 623a4ceb Stavros Sachtouris
    :raises TypeError, AttributeError: Invalid json format
142 623a4ceb Stavros Sachtouris

143 623a4ceb Stavros Sachtouris
    :raises AssertionError: Valid json but invalid image properties dict
144 623a4ceb Stavros Sachtouris
    """
145 d77e33d4 Stavros Sachtouris
    with open(path.abspath(filepath)) as f:
146 623a4ceb Stavros Sachtouris
        meta_dict = load(f)
147 623a4ceb Stavros Sachtouris
        try:
148 aa82dd5a Stavros Sachtouris
            return _validate_image_meta(meta_dict)
149 623a4ceb Stavros Sachtouris
        except AssertionError:
150 623a4ceb Stavros Sachtouris
            log.debug('Failed to load properties from file %s' % filepath)
151 623a4ceb Stavros Sachtouris
            raise
152 623a4ceb Stavros Sachtouris
153 623a4ceb Stavros Sachtouris
154 aa82dd5a Stavros Sachtouris
def _validate_image_location(location):
155 aa82dd5a Stavros Sachtouris
    """
156 f2ea1314 Stavros Sachtouris
    :param location: (str) pithos://<user-id>/<container>/<image-path>
157 aa82dd5a Stavros Sachtouris

158 f2ea1314 Stavros Sachtouris
    :returns: (<user-id>, <container>, <image-path>)
159 aa82dd5a Stavros Sachtouris

160 aa82dd5a Stavros Sachtouris
    :raises AssertionError: if location is invalid
161 aa82dd5a Stavros Sachtouris
    """
162 aa82dd5a Stavros Sachtouris
    prefix = 'pithos://'
163 aa82dd5a Stavros Sachtouris
    msg = 'Invalid prefix for location %s , try: %s' % (location, prefix)
164 aa82dd5a Stavros Sachtouris
    assert location.startswith(prefix), msg
165 aa82dd5a Stavros Sachtouris
    service, sep, rest = location.partition('://')
166 c626151a Stavros Sachtouris
    assert sep and rest, 'Location %s is missing user-id' % location
167 aa82dd5a Stavros Sachtouris
    uuid, sep, rest = rest.partition('/')
168 aa82dd5a Stavros Sachtouris
    assert sep and rest, 'Location %s is missing container' % location
169 aa82dd5a Stavros Sachtouris
    container, sep, img_path = rest.partition('/')
170 aa82dd5a Stavros Sachtouris
    assert sep and img_path, 'Location %s is missing image path' % location
171 aa82dd5a Stavros Sachtouris
    return uuid, container, img_path
172 aa82dd5a Stavros Sachtouris
173 aa82dd5a Stavros Sachtouris
174 d486baec Stavros Sachtouris
@command(image_cmds)
175 545c6c29 Stavros Sachtouris
class image_list(_init_image, _optional_json):
176 573be34f Stavros Sachtouris
    """List images accessible by user"""
177 7493ccb6 Stavros Sachtouris
178 2d1202ee Stavros Sachtouris
    PERMANENTS = (
179 2d1202ee Stavros Sachtouris
        'id', 'name',
180 2d1202ee Stavros Sachtouris
        'status', 'container_format', 'disk_format', 'size')
181 2d1202ee Stavros Sachtouris
182 1ae79e60 Stavros Sachtouris
    arguments = dict(
183 f40f0cb7 Stavros Sachtouris
        detail=FlagArgument('show detailed output', ('-l', '--details')),
184 1ae79e60 Stavros Sachtouris
        container_format=ValueArgument(
185 1ae79e60 Stavros Sachtouris
            'filter by container format',
186 1ae79e60 Stavros Sachtouris
            '--container-format'),
187 1ae79e60 Stavros Sachtouris
        disk_format=ValueArgument('filter by disk format', '--disk-format'),
188 1ae79e60 Stavros Sachtouris
        name=ValueArgument('filter by name', '--name'),
189 faeccbf9 Stavros Sachtouris
        name_pref=ValueArgument(
190 faeccbf9 Stavros Sachtouris
            'filter by name prefix (case insensitive)',
191 faeccbf9 Stavros Sachtouris
            '--name-prefix'),
192 faeccbf9 Stavros Sachtouris
        name_suff=ValueArgument(
193 faeccbf9 Stavros Sachtouris
            'filter by name suffix (case insensitive)',
194 faeccbf9 Stavros Sachtouris
            '--name-suffix'),
195 faeccbf9 Stavros Sachtouris
        name_like=ValueArgument(
196 faeccbf9 Stavros Sachtouris
            'print only if name contains this (case insensitive)',
197 faeccbf9 Stavros Sachtouris
            '--name-like'),
198 1ae79e60 Stavros Sachtouris
        size_min=IntArgument('filter by minimum size', '--size-min'),
199 1ae79e60 Stavros Sachtouris
        size_max=IntArgument('filter by maximum size', '--size-max'),
200 1ae79e60 Stavros Sachtouris
        status=ValueArgument('filter by status', '--status'),
201 f9457c89 Stavros Sachtouris
        owner=ValueArgument('filter by owner', '--owner'),
202 95641ecc Stavros Sachtouris
        owner_name=ValueArgument('filter by owners username', '--owner-name'),
203 1ae79e60 Stavros Sachtouris
        order=ValueArgument(
204 1ae79e60 Stavros Sachtouris
            'order by FIELD ( - to reverse order)',
205 1ae79e60 Stavros Sachtouris
            '--order',
206 83c3ba87 Stavros Sachtouris
            default=''),
207 f40f0cb7 Stavros Sachtouris
        limit=IntArgument('limit number of listed images', ('-n', '--number')),
208 83c3ba87 Stavros Sachtouris
        more=FlagArgument(
209 83c3ba87 Stavros Sachtouris
            'output results in pages (-n to set items per page, default 10)',
210 ed9af02c Stavros Sachtouris
            '--more'),
211 2d1202ee Stavros Sachtouris
        enum=FlagArgument('Enumerate results', '--enumerate'),
212 5576a4eb Stavros Sachtouris
        prop=KeyValueArgument('filter by property key=value', ('--property')),
213 5576a4eb Stavros Sachtouris
        prop_like=KeyValueArgument(
214 5576a4eb Stavros Sachtouris
            'fliter by property key=value where value is part of actual value',
215 1716a15d Stavros Sachtouris
            ('--property-like')),
216 1ae79e60 Stavros Sachtouris
    )
217 7493ccb6 Stavros Sachtouris
218 854222c7 Stavros Sachtouris
    def _filtered_by_owner(self, images):
219 95641ecc Stavros Sachtouris
        ouuid = self['owner'] or self._username2uuid(self['owner_name'])
220 854222c7 Stavros Sachtouris
        return filter_dicts_by_dict(images, dict(owner=ouuid))
221 f9457c89 Stavros Sachtouris
222 faeccbf9 Stavros Sachtouris
    def _filtered_by_name(self, images):
223 faeccbf9 Stavros Sachtouris
        np, ns, nl = self['name_pref'], self['name_suff'], self['name_like']
224 5576a4eb Stavros Sachtouris
        return [img for img in images if (
225 faeccbf9 Stavros Sachtouris
            (not np) or img['name'].lower().startswith(np.lower())) and (
226 faeccbf9 Stavros Sachtouris
            (not ns) or img['name'].lower().endswith(ns.lower())) and (
227 faeccbf9 Stavros Sachtouris
            (not nl) or nl.lower() in img['name'].lower())]
228 faeccbf9 Stavros Sachtouris
229 5576a4eb Stavros Sachtouris
    def _add_owner_name(self, images):
230 5576a4eb Stavros Sachtouris
        uuids = self._uuids2usernames(
231 5576a4eb Stavros Sachtouris
            list(set([img['owner'] for img in images])))
232 5576a4eb Stavros Sachtouris
        for img in images:
233 5576a4eb Stavros Sachtouris
            img['owner'] += ' (%s)' % uuids[img['owner']]
234 5576a4eb Stavros Sachtouris
        return images
235 f1e5b343 Stavros Sachtouris
236 2d1202ee Stavros Sachtouris
    def _filtered_by_properties(self, images):
237 2d1202ee Stavros Sachtouris
        new_images = []
238 5576a4eb Stavros Sachtouris
239 854222c7 Stavros Sachtouris
        # def like_properties(props):
240 854222c7 Stavros Sachtouris
        #     plike = self['prop_like']
241 854222c7 Stavros Sachtouris
        #     for k, v in plike.items():
242 854222c7 Stavros Sachtouris
        #         likestr = props.get(k, '').lower()
243 854222c7 Stavros Sachtouris
        #         if v.lower() not in likestr:
244 854222c7 Stavros Sachtouris
        #             return False
245 854222c7 Stavros Sachtouris
        #     return True
246 5576a4eb Stavros Sachtouris
247 2d1202ee Stavros Sachtouris
        for img in images:
248 854222c7 Stavros Sachtouris
            props = [dict(img['properties'])]
249 854222c7 Stavros Sachtouris
            if self['prop']:
250 854222c7 Stavros Sachtouris
                props = filter_dicts_by_dict(props, self['prop'])
251 854222c7 Stavros Sachtouris
            if props and self['prop_like']:
252 854222c7 Stavros Sachtouris
                props = filter_dicts_by_dict(
253 854222c7 Stavros Sachtouris
                    props, self['prop_like'], exact_match=False)
254 854222c7 Stavros Sachtouris
            if props:
255 854222c7 Stavros Sachtouris
                new_images.append(img)
256 854222c7 Stavros Sachtouris
257 854222c7 Stavros Sachtouris
            #if (
258 854222c7 Stavros Sachtouris
            #        self['prop'] and set(
259 854222c7 Stavros Sachtouris
            #            self['prop'].items()).difference(props.items())) or (
260 854222c7 Stavros Sachtouris
            #        self['prop_like'] and not like_properties(props)):
261 854222c7 Stavros Sachtouris
            #    continue
262 854222c7 Stavros Sachtouris
            #new_images.append(img)
263 2d1202ee Stavros Sachtouris
        return new_images
264 2d1202ee Stavros Sachtouris
265 a03ade9e Stavros Sachtouris
    @errors.generic.all
266 a03ade9e Stavros Sachtouris
    @errors.cyclades.connection
267 a03ade9e Stavros Sachtouris
    def _run(self):
268 a03ade9e Stavros Sachtouris
        super(self.__class__, self)._run()
269 7493ccb6 Stavros Sachtouris
        filters = {}
270 fa984c2c Stavros Sachtouris
        for arg in set([
271 1ae79e60 Stavros Sachtouris
                'container_format',
272 1ae79e60 Stavros Sachtouris
                'disk_format',
273 1ae79e60 Stavros Sachtouris
                'name',
274 1ae79e60 Stavros Sachtouris
                'size_min',
275 1ae79e60 Stavros Sachtouris
                'size_max',
276 de73876b Stavros Sachtouris
                'status']).intersection(self.arguments):
277 1ae79e60 Stavros Sachtouris
            filters[arg] = self[arg]
278 1ae79e60 Stavros Sachtouris
279 1ae79e60 Stavros Sachtouris
        order = self['order']
280 854222c7 Stavros Sachtouris
        detail = self['detail'] or (
281 854222c7 Stavros Sachtouris
            self['prop'] or self['prop_like']) or (
282 854222c7 Stavros Sachtouris
            self['owner'] or self['owner_name'])
283 f9457c89 Stavros Sachtouris
284 854222c7 Stavros Sachtouris
        images = self.client.list_public(detail, filters, order)
285 854222c7 Stavros Sachtouris
286 854222c7 Stavros Sachtouris
        if self['owner'] or self['owner_name']:
287 854222c7 Stavros Sachtouris
            images = self._filtered_by_owner(images)
288 854222c7 Stavros Sachtouris
        if self['prop'] or self['prop_like']:
289 854222c7 Stavros Sachtouris
            images = self._filtered_by_properties(images)
290 f5f35422 Stavros Sachtouris
        images = self._filtered_by_name(images)
291 854222c7 Stavros Sachtouris
292 5576a4eb Stavros Sachtouris
        if self['detail'] and not self['json_output']:
293 5576a4eb Stavros Sachtouris
            images = self._add_owner_name(images)
294 854222c7 Stavros Sachtouris
        elif detail and not self['detail']:
295 854222c7 Stavros Sachtouris
            for img in images:
296 854222c7 Stavros Sachtouris
                for key in set(img).difference(self.PERMANENTS):
297 854222c7 Stavros Sachtouris
                    img.pop(key)
298 545c6c29 Stavros Sachtouris
        kwargs = dict(with_enumeration=self['enum'])
299 83c3ba87 Stavros Sachtouris
        if self['more']:
300 545c6c29 Stavros Sachtouris
            kwargs['page_size'] = self['limit'] or 10
301 83c3ba87 Stavros Sachtouris
        elif self['limit']:
302 545c6c29 Stavros Sachtouris
            images = images[:self['limit']]
303 545c6c29 Stavros Sachtouris
        self._print(images, **kwargs)
304 7493ccb6 Stavros Sachtouris
305 a03ade9e Stavros Sachtouris
    def main(self):
306 a03ade9e Stavros Sachtouris
        super(self.__class__, self)._run()
307 a03ade9e Stavros Sachtouris
        self._run()
308 a03ade9e Stavros Sachtouris
309 234954d1 Stavros Sachtouris
310 d486baec Stavros Sachtouris
@command(image_cmds)
311 545c6c29 Stavros Sachtouris
class image_meta(_init_image, _optional_json):
312 15142309 Stavros Sachtouris
    """Get image metadata
313 15142309 Stavros Sachtouris
    Image metadata include:
314 439826ec Stavros Sachtouris
    - image file information (location, size, etc.)
315 439826ec Stavros Sachtouris
    - image information (id, name, etc.)
316 439826ec Stavros Sachtouris
    - image os properties (os, fs, etc.)
317 15142309 Stavros Sachtouris
    """
318 7493ccb6 Stavros Sachtouris
319 a03ade9e Stavros Sachtouris
    @errors.generic.all
320 a03ade9e Stavros Sachtouris
    @errors.plankton.connection
321 a03ade9e Stavros Sachtouris
    @errors.plankton.id
322 a03ade9e Stavros Sachtouris
    def _run(self, image_id):
323 545c6c29 Stavros Sachtouris
        self._print([self.client.get_meta(image_id)])
324 7493ccb6 Stavros Sachtouris
325 a03ade9e Stavros Sachtouris
    def main(self, image_id):
326 a03ade9e Stavros Sachtouris
        super(self.__class__, self)._run()
327 b04288f7 Stavros Sachtouris
        self._run(image_id=image_id)
328 a03ade9e Stavros Sachtouris
329 234954d1 Stavros Sachtouris
330 d486baec Stavros Sachtouris
@command(image_cmds)
331 545c6c29 Stavros Sachtouris
class image_register(_init_image, _optional_json):
332 fc903073 Stavros Sachtouris
    """(Re)Register an image"""
333 7493ccb6 Stavros Sachtouris
334 d77e33d4 Stavros Sachtouris
    container_info_cache = {}
335 d77e33d4 Stavros Sachtouris
336 1ae79e60 Stavros Sachtouris
    arguments = dict(
337 1ae79e60 Stavros Sachtouris
        checksum=ValueArgument('set image checksum', '--checksum'),
338 1ae79e60 Stavros Sachtouris
        container_format=ValueArgument(
339 1ae79e60 Stavros Sachtouris
            'set container format',
340 1ae79e60 Stavros Sachtouris
            '--container-format'),
341 1ae79e60 Stavros Sachtouris
        disk_format=ValueArgument('set disk format', '--disk-format'),
342 1ae79e60 Stavros Sachtouris
        owner=ValueArgument('set image owner (admin only)', '--owner'),
343 1ae79e60 Stavros Sachtouris
        properties=KeyValueArgument(
344 1ae79e60 Stavros Sachtouris
            'add property in key=value form (can be repeated)',
345 1736e06d Stavros Sachtouris
            ('-p', '--property')),
346 1ae79e60 Stavros Sachtouris
        is_public=FlagArgument('mark image as public', '--public'),
347 1ae79e60 Stavros Sachtouris
        size=IntArgument('set image size', '--size'),
348 aa82dd5a Stavros Sachtouris
        metafile=ValueArgument(
349 aa82dd5a Stavros Sachtouris
            'Load metadata from a json-formated file <img-file>.meta :'
350 aa82dd5a Stavros Sachtouris
            '{"key1": "val1", "key2": "val2", ..., "properties: {...}"}',
351 aa82dd5a Stavros Sachtouris
            ('--metafile')),
352 aa82dd5a Stavros Sachtouris
        metafile_force=FlagArgument(
353 aa82dd5a Stavros Sachtouris
            'Store remote metadata object, even if it already exists',
354 aa82dd5a Stavros Sachtouris
            ('-f', '--force')),
355 aa82dd5a Stavros Sachtouris
        no_metafile_upload=FlagArgument(
356 aa82dd5a Stavros Sachtouris
            'Do not store metadata in remote meta file',
357 aa82dd5a Stavros Sachtouris
            ('--no-metafile-upload')),
358 f2ea1314 Stavros Sachtouris
        container=ValueArgument(
359 f2ea1314 Stavros Sachtouris
            'Pithos+ container containing the image file',
360 f2ea1314 Stavros Sachtouris
            ('-C', '--container')),
361 d77e33d4 Stavros Sachtouris
        uuid=ValueArgument('Custom user uuid', '--uuid'),
362 d77e33d4 Stavros Sachtouris
        local_image_path=ValueArgument(
363 d77e33d4 Stavros Sachtouris
            'Local image file path to upload and register '
364 d77e33d4 Stavros Sachtouris
            '(still need target file in the form container:remote-path )',
365 d77e33d4 Stavros Sachtouris
            '--upload-image-file'),
366 d77e33d4 Stavros Sachtouris
        progress_bar=ProgressBarArgument(
367 d77e33d4 Stavros Sachtouris
            'Do not use progress bar', '--no-progress-bar', default=False)
368 1ae79e60 Stavros Sachtouris
    )
369 7493ccb6 Stavros Sachtouris
370 f5c28bfa Stavros Sachtouris
    def _get_user_id(self):
371 00336c85 Stavros Sachtouris
        atoken = self.client.token
372 ef00bc31 Stavros Sachtouris
        if getattr(self, 'auth_base', False):
373 9d8737a2 Stavros Sachtouris
            return self.auth_base.term('id', atoken)
374 ef00bc31 Stavros Sachtouris
        else:
375 f5c28bfa Stavros Sachtouris
            astakos_url = self.config.get('user', 'url')\
376 f5c28bfa Stavros Sachtouris
                or self.config.get('astakos', 'url')
377 ef00bc31 Stavros Sachtouris
            if not astakos_url:
378 ef00bc31 Stavros Sachtouris
                raise CLIBaseUrlError(service='astakos')
379 ef00bc31 Stavros Sachtouris
            user = AstakosClient(astakos_url, atoken)
380 819311d3 Stavros Sachtouris
            return user.term('id')
381 00336c85 Stavros Sachtouris
382 aa82dd5a Stavros Sachtouris
    def _get_pithos_client(self, container):
383 aa82dd5a Stavros Sachtouris
        if self['no_metafile_upload']:
384 aa82dd5a Stavros Sachtouris
            return None
385 00336c85 Stavros Sachtouris
        ptoken = self.client.token
386 ef00bc31 Stavros Sachtouris
        if getattr(self, 'auth_base', False):
387 ef00bc31 Stavros Sachtouris
            pithos_endpoints = self.auth_base.get_service_endpoints(
388 df0045d8 Stavros Sachtouris
                'object-store')
389 ef00bc31 Stavros Sachtouris
            purl = pithos_endpoints['publicURL']
390 ef00bc31 Stavros Sachtouris
        else:
391 df0045d8 Stavros Sachtouris
            purl = self.config.get_cloud('pithos', 'url')
392 df0045d8 Stavros Sachtouris
        if not purl:
393 df0045d8 Stavros Sachtouris
            raise CLIBaseUrlError(service='pithos')
394 f5c28bfa Stavros Sachtouris
        return PithosClient(purl, ptoken, self._get_user_id(), container)
395 00336c85 Stavros Sachtouris
396 aa82dd5a Stavros Sachtouris
    def _store_remote_metafile(self, pclient, remote_path, metadata):
397 00336c85 Stavros Sachtouris
        return pclient.upload_from_string(
398 d77e33d4 Stavros Sachtouris
            remote_path, _validate_image_meta(metadata, return_str=True),
399 d77e33d4 Stavros Sachtouris
            container_info_cache=self.container_info_cache)
400 00336c85 Stavros Sachtouris
401 aa82dd5a Stavros Sachtouris
    def _load_params_from_file(self, location):
402 aa82dd5a Stavros Sachtouris
        params, properties = dict(), dict()
403 aa82dd5a Stavros Sachtouris
        pfile = self['metafile']
404 aa82dd5a Stavros Sachtouris
        if pfile:
405 00336c85 Stavros Sachtouris
            try:
406 aa82dd5a Stavros Sachtouris
                for k, v in _load_image_meta(pfile).items():
407 aa82dd5a Stavros Sachtouris
                    key = k.lower().replace('-', '_')
408 aa82dd5a Stavros Sachtouris
                    if k == 'properties':
409 aa82dd5a Stavros Sachtouris
                        for pk, pv in v.items():
410 aa82dd5a Stavros Sachtouris
                            properties[pk.upper().replace('-', '_')] = pv
411 aa82dd5a Stavros Sachtouris
                    elif key == 'name':
412 aa82dd5a Stavros Sachtouris
                            continue
413 aa82dd5a Stavros Sachtouris
                    elif key == 'location':
414 aa82dd5a Stavros Sachtouris
                        if location:
415 aa82dd5a Stavros Sachtouris
                            continue
416 aa82dd5a Stavros Sachtouris
                        location = v
417 aa82dd5a Stavros Sachtouris
                    else:
418 aa82dd5a Stavros Sachtouris
                        params[key] = v
419 aa82dd5a Stavros Sachtouris
            except Exception as e:
420 aa82dd5a Stavros Sachtouris
                raiseCLIError(e, 'Invalid json metadata config file')
421 aa82dd5a Stavros Sachtouris
        return params, properties, location
422 7493ccb6 Stavros Sachtouris
423 aa82dd5a Stavros Sachtouris
    def _load_params_from_args(self, params, properties):
424 f769a16a Stavros Sachtouris
        for key in set([
425 1ae79e60 Stavros Sachtouris
                'checksum',
426 1ae79e60 Stavros Sachtouris
                'container_format',
427 1ae79e60 Stavros Sachtouris
                'disk_format',
428 1ae79e60 Stavros Sachtouris
                'owner',
429 1ae79e60 Stavros Sachtouris
                'size',
430 de73876b Stavros Sachtouris
                'is_public']).intersection(self.arguments):
431 1ae79e60 Stavros Sachtouris
            params[key] = self[key]
432 aa82dd5a Stavros Sachtouris
        for k, v in self['properties'].items():
433 aa82dd5a Stavros Sachtouris
            properties[k.upper().replace('-', '_')] = v
434 1ae79e60 Stavros Sachtouris
435 aa82dd5a Stavros Sachtouris
    def _validate_location(self, location):
436 aa82dd5a Stavros Sachtouris
        if not location:
437 aa82dd5a Stavros Sachtouris
            raiseCLIError(
438 aa82dd5a Stavros Sachtouris
                'No image file location provided',
439 aa82dd5a Stavros Sachtouris
                importance=2, details=[
440 aa82dd5a Stavros Sachtouris
                    'An image location is needed. Image location format:',
441 c626151a Stavros Sachtouris
                    '  pithos://<user-id>/<container>/<path>',
442 f2ea1314 Stavros Sachtouris
                    ' where an image file at the above location must exist.'
443 aa82dd5a Stavros Sachtouris
                    ] + howto_image_file)
444 aa82dd5a Stavros Sachtouris
        try:
445 aa82dd5a Stavros Sachtouris
            return _validate_image_location(location)
446 aa82dd5a Stavros Sachtouris
        except AssertionError as ae:
447 aa82dd5a Stavros Sachtouris
            raiseCLIError(
448 aa82dd5a Stavros Sachtouris
                ae, 'Invalid image location format',
449 aa82dd5a Stavros Sachtouris
                importance=1, details=[
450 aa82dd5a Stavros Sachtouris
                    'Valid image location format:',
451 c626151a Stavros Sachtouris
                    '  pithos://<user-id>/<container>/<img-file-path>'
452 aa82dd5a Stavros Sachtouris
                    ] + howto_image_file)
453 aa82dd5a Stavros Sachtouris
454 f2ea1314 Stavros Sachtouris
    def _mine_location(self, container_path):
455 f2ea1314 Stavros Sachtouris
        uuid = self['uuid'] or self._get_user_id()
456 f2ea1314 Stavros Sachtouris
        if self['container']:
457 f2ea1314 Stavros Sachtouris
            return uuid, self['container'], container_path
458 f2ea1314 Stavros Sachtouris
        container, sep, path = container_path.partition(':')
459 f2ea1314 Stavros Sachtouris
        if not (bool(container) and bool(path)):
460 f2ea1314 Stavros Sachtouris
            raiseCLIError(
461 f2ea1314 Stavros Sachtouris
                'Incorrect container-path format', importance=1, details=[
462 f2ea1314 Stavros Sachtouris
                'Use : to seperate container form path',
463 f2ea1314 Stavros Sachtouris
                '  <container>:<image-path>',
464 f2ea1314 Stavros Sachtouris
                'OR',
465 f2ea1314 Stavros Sachtouris
                'Use -C to specifiy a container',
466 f2ea1314 Stavros Sachtouris
                '  -C <container> <image-path>'] + howto_image_file)
467 f2ea1314 Stavros Sachtouris
468 f2ea1314 Stavros Sachtouris
        return uuid, container, path
469 f2ea1314 Stavros Sachtouris
470 aa82dd5a Stavros Sachtouris
    @errors.generic.all
471 aa82dd5a Stavros Sachtouris
    @errors.plankton.connection
472 f2ea1314 Stavros Sachtouris
    def _run(self, name, uuid, container, img_path):
473 d77e33d4 Stavros Sachtouris
        if self['local_image_path']:
474 d77e33d4 Stavros Sachtouris
            with open(self['local_image_path']) as f:
475 d77e33d4 Stavros Sachtouris
                pithos = self._get_pithos_client(container)
476 d77e33d4 Stavros Sachtouris
                (pbar, upload_cb) = self._safe_progress_bar('Uploading')
477 d77e33d4 Stavros Sachtouris
                if pbar:
478 d77e33d4 Stavros Sachtouris
                    hash_bar = pbar.clone()
479 d77e33d4 Stavros Sachtouris
                    hash_cb = hash_bar.get_generator('Calculating hashes')
480 d77e33d4 Stavros Sachtouris
                pithos.upload_object(
481 d77e33d4 Stavros Sachtouris
                    img_path, f,
482 d77e33d4 Stavros Sachtouris
                    hash_cb=hash_cb, upload_cb=upload_cb,
483 d77e33d4 Stavros Sachtouris
                    container_info_cache=self.container_info_cache)
484 d77e33d4 Stavros Sachtouris
                pbar.finish()
485 d77e33d4 Stavros Sachtouris
486 f2ea1314 Stavros Sachtouris
        location = 'pithos://%s/%s/%s' % (uuid, container, img_path)
487 f2ea1314 Stavros Sachtouris
        (params, properties, new_loc) = self._load_params_from_file(location)
488 f2ea1314 Stavros Sachtouris
        if location != new_loc:
489 f2ea1314 Stavros Sachtouris
            uuid, container, img_path = self._validate_location(new_loc)
490 aa82dd5a Stavros Sachtouris
        self._load_params_from_args(params, properties)
491 aa82dd5a Stavros Sachtouris
        pclient = self._get_pithos_client(container)
492 aa82dd5a Stavros Sachtouris
493 aa82dd5a Stavros Sachtouris
        #check if metafile exists
494 aa82dd5a Stavros Sachtouris
        meta_path = '%s.meta' % img_path
495 aa82dd5a Stavros Sachtouris
        if pclient and not self['metafile_force']:
496 c4aefeaf Stavros Sachtouris
            try:
497 aa82dd5a Stavros Sachtouris
                pclient.get_object_info(meta_path)
498 81b0838d Stavros Sachtouris
                raiseCLIError(
499 81b0838d Stavros Sachtouris
                    'Metadata file %s:%s already exists, abort' % (
500 81b0838d Stavros Sachtouris
                        container, meta_path),
501 81b0838d Stavros Sachtouris
                    details=['Registration ABORTED', 'Try -f to overwrite'])
502 aa82dd5a Stavros Sachtouris
            except ClientError as ce:
503 aa82dd5a Stavros Sachtouris
                if ce.status != 404:
504 aa82dd5a Stavros Sachtouris
                    raise
505 aa82dd5a Stavros Sachtouris
506 aa82dd5a Stavros Sachtouris
        #register the image
507 aa82dd5a Stavros Sachtouris
        try:
508 aa82dd5a Stavros Sachtouris
            r = self.client.register(name, location, params, properties)
509 aa82dd5a Stavros Sachtouris
        except ClientError as ce:
510 aa82dd5a Stavros Sachtouris
            if ce.status in (400, ):
511 c4aefeaf Stavros Sachtouris
                raiseCLIError(
512 aa82dd5a Stavros Sachtouris
                    ce, 'Nonexistent image file location %s' % location,
513 c4aefeaf Stavros Sachtouris
                    details=[
514 aa82dd5a Stavros Sachtouris
                        'Make sure the image file exists'] + howto_image_file)
515 aa82dd5a Stavros Sachtouris
            raise
516 aa82dd5a Stavros Sachtouris
        self._print(r, print_dict)
517 a03ade9e Stavros Sachtouris
518 aa82dd5a Stavros Sachtouris
        #upload the metadata file
519 00336c85 Stavros Sachtouris
        if pclient:
520 aa82dd5a Stavros Sachtouris
            try:
521 aa82dd5a Stavros Sachtouris
                meta_headers = pclient.upload_from_string(
522 d77e33d4 Stavros Sachtouris
                    meta_path, dumps(r, indent=2),
523 d77e33d4 Stavros Sachtouris
                    container_info_cache=self.container_info_cache)
524 aa82dd5a Stavros Sachtouris
            except TypeError:
525 aa82dd5a Stavros Sachtouris
                print('Failed to dump metafile %s:%s' % (container, meta_path))
526 aa82dd5a Stavros Sachtouris
                return
527 9553da85 Stavros Sachtouris
            if self['json_output']:
528 9553da85 Stavros Sachtouris
                print_json(dict(
529 aa82dd5a Stavros Sachtouris
                    metafile_location='%s:%s' % (container, meta_path),
530 aa82dd5a Stavros Sachtouris
                    headers=meta_headers))
531 9553da85 Stavros Sachtouris
            else:
532 aa82dd5a Stavros Sachtouris
                print('Metadata file uploaded as %s:%s (version %s)' % (
533 aa82dd5a Stavros Sachtouris
                    container, meta_path, meta_headers['x-object-version']))
534 00336c85 Stavros Sachtouris
535 f2ea1314 Stavros Sachtouris
    def main(self, name, container___image_path):
536 a03ade9e Stavros Sachtouris
        super(self.__class__, self)._run()
537 f2ea1314 Stavros Sachtouris
        self._run(name, *self._mine_location(container___image_path))
538 7493ccb6 Stavros Sachtouris
539 234954d1 Stavros Sachtouris
540 d486baec Stavros Sachtouris
@command(image_cmds)
541 f5f35422 Stavros Sachtouris
class image_unregister(_init_image, _optional_output_cmd):
542 4a17d307 Stavros Sachtouris
    """Unregister an image (does not delete the image file)"""
543 4a17d307 Stavros Sachtouris
544 4a17d307 Stavros Sachtouris
    @errors.generic.all
545 4a17d307 Stavros Sachtouris
    @errors.plankton.connection
546 4a17d307 Stavros Sachtouris
    @errors.plankton.id
547 4a17d307 Stavros Sachtouris
    def _run(self, image_id):
548 f5f35422 Stavros Sachtouris
        self._optional_output(self.client.unregister(image_id))
549 4a17d307 Stavros Sachtouris
550 4a17d307 Stavros Sachtouris
    def main(self, image_id):
551 4a17d307 Stavros Sachtouris
        super(self.__class__, self)._run()
552 4a17d307 Stavros Sachtouris
        self._run(image_id=image_id)
553 4a17d307 Stavros Sachtouris
554 4a17d307 Stavros Sachtouris
555 4a17d307 Stavros Sachtouris
@command(image_cmds)
556 545c6c29 Stavros Sachtouris
class image_shared(_init_image, _optional_json):
557 f5f35422 Stavros Sachtouris
    """List images shared by a member"""
558 f5f35422 Stavros Sachtouris
559 236e7d08 Stavros Sachtouris
    @errors.generic.all
560 236e7d08 Stavros Sachtouris
    @errors.plankton.connection
561 f5f35422 Stavros Sachtouris
    def _run(self, member):
562 545c6c29 Stavros Sachtouris
        self._print(self.client.list_shared(member), title=('image_id',))
563 7493ccb6 Stavros Sachtouris
564 f5f35422 Stavros Sachtouris
    def main(self, member):
565 236e7d08 Stavros Sachtouris
        super(self.__class__, self)._run()
566 f5f35422 Stavros Sachtouris
        self._run(member)
567 236e7d08 Stavros Sachtouris
568 234954d1 Stavros Sachtouris
569 d486baec Stavros Sachtouris
@command(image_cmds)
570 f5f35422 Stavros Sachtouris
class image_members(_init_image):
571 f5f35422 Stavros Sachtouris
    """Manage members. Members of an image are users who can modify it"""
572 f5f35422 Stavros Sachtouris
573 f5f35422 Stavros Sachtouris
574 f5f35422 Stavros Sachtouris
@command(image_cmds)
575 545c6c29 Stavros Sachtouris
class image_members_list(_init_image, _optional_json):
576 f5f35422 Stavros Sachtouris
    """List members of an image"""
577 f5f35422 Stavros Sachtouris
578 236e7d08 Stavros Sachtouris
    @errors.generic.all
579 236e7d08 Stavros Sachtouris
    @errors.plankton.connection
580 f5f35422 Stavros Sachtouris
    @errors.plankton.id
581 f5f35422 Stavros Sachtouris
    def _run(self, image_id):
582 545c6c29 Stavros Sachtouris
        self._print(self.client.list_members(image_id), title=('member_id',))
583 7493ccb6 Stavros Sachtouris
584 f5f35422 Stavros Sachtouris
    def main(self, image_id):
585 236e7d08 Stavros Sachtouris
        super(self.__class__, self)._run()
586 f5f35422 Stavros Sachtouris
        self._run(image_id=image_id)
587 236e7d08 Stavros Sachtouris
588 234954d1 Stavros Sachtouris
589 d486baec Stavros Sachtouris
@command(image_cmds)
590 f5f35422 Stavros Sachtouris
class image_members_add(_init_image, _optional_output_cmd):
591 7493ccb6 Stavros Sachtouris
    """Add a member to an image"""
592 7493ccb6 Stavros Sachtouris
593 236e7d08 Stavros Sachtouris
    @errors.generic.all
594 236e7d08 Stavros Sachtouris
    @errors.plankton.connection
595 236e7d08 Stavros Sachtouris
    @errors.plankton.id
596 b04288f7 Stavros Sachtouris
    def _run(self, image_id=None, member=None):
597 f5f35422 Stavros Sachtouris
            self._optional_output(self.client.add_member(image_id, member))
598 236e7d08 Stavros Sachtouris
599 236e7d08 Stavros Sachtouris
    def main(self, image_id, member):
600 236e7d08 Stavros Sachtouris
        super(self.__class__, self)._run()
601 b04288f7 Stavros Sachtouris
        self._run(image_id=image_id, member=member)
602 7493ccb6 Stavros Sachtouris
603 234954d1 Stavros Sachtouris
604 d486baec Stavros Sachtouris
@command(image_cmds)
605 f5f35422 Stavros Sachtouris
class image_members_delete(_init_image, _optional_output_cmd):
606 7493ccb6 Stavros Sachtouris
    """Remove a member from an image"""
607 7493ccb6 Stavros Sachtouris
608 236e7d08 Stavros Sachtouris
    @errors.generic.all
609 236e7d08 Stavros Sachtouris
    @errors.plankton.connection
610 236e7d08 Stavros Sachtouris
    @errors.plankton.id
611 b04288f7 Stavros Sachtouris
    def _run(self, image_id=None, member=None):
612 f5f35422 Stavros Sachtouris
            self._optional_output(self.client.remove_member(image_id, member))
613 236e7d08 Stavros Sachtouris
614 236e7d08 Stavros Sachtouris
    def main(self, image_id, member):
615 236e7d08 Stavros Sachtouris
        super(self.__class__, self)._run()
616 b04288f7 Stavros Sachtouris
        self._run(image_id=image_id, member=member)
617 7493ccb6 Stavros Sachtouris
618 234954d1 Stavros Sachtouris
619 d486baec Stavros Sachtouris
@command(image_cmds)
620 f5f35422 Stavros Sachtouris
class image_members_set(_init_image, _optional_output_cmd):
621 7493ccb6 Stavros Sachtouris
    """Set the members of an image"""
622 7493ccb6 Stavros Sachtouris
623 236e7d08 Stavros Sachtouris
    @errors.generic.all
624 236e7d08 Stavros Sachtouris
    @errors.plankton.connection
625 236e7d08 Stavros Sachtouris
    @errors.plankton.id
626 b04288f7 Stavros Sachtouris
    def _run(self, image_id, members):
627 f5f35422 Stavros Sachtouris
            self._optional_output(self.client.set_members(image_id, members))
628 236e7d08 Stavros Sachtouris
629 236e7d08 Stavros Sachtouris
    def main(self, image_id, *members):
630 236e7d08 Stavros Sachtouris
        super(self.__class__, self)._run()
631 b04288f7 Stavros Sachtouris
        self._run(image_id=image_id, members=members)
632 f3e94e06 Stavros Sachtouris
633 f3e94e06 Stavros Sachtouris
634 573be34f Stavros Sachtouris
# Compute Image Commands
635 573be34f Stavros Sachtouris
636 573be34f Stavros Sachtouris
637 d486baec Stavros Sachtouris
@command(image_cmds)
638 8741c407 Stavros Sachtouris
class image_compute(_init_cyclades):
639 a29d2f88 Stavros Sachtouris
    """Cyclades/Compute API image commands"""
640 8741c407 Stavros Sachtouris
641 8741c407 Stavros Sachtouris
642 8741c407 Stavros Sachtouris
@command(image_cmds)
643 545c6c29 Stavros Sachtouris
class image_compute_list(_init_cyclades, _optional_json):
644 f3e94e06 Stavros Sachtouris
    """List images"""
645 f3e94e06 Stavros Sachtouris
646 1716a15d Stavros Sachtouris
    PERMANENTS = ('id', 'name')
647 1716a15d Stavros Sachtouris
648 1ae79e60 Stavros Sachtouris
    arguments = dict(
649 f40f0cb7 Stavros Sachtouris
        detail=FlagArgument('show detailed output', ('-l', '--details')),
650 f40f0cb7 Stavros Sachtouris
        limit=IntArgument('limit number listed images', ('-n', '--number')),
651 15142309 Stavros Sachtouris
        more=FlagArgument(
652 15142309 Stavros Sachtouris
            'output results in pages (-n to set items per page, default 10)',
653 ed9af02c Stavros Sachtouris
            '--more'),
654 1716a15d Stavros Sachtouris
        enum=FlagArgument('Enumerate results', '--enumerate'),
655 1716a15d Stavros Sachtouris
        meta=KeyValueArgument(
656 1716a15d Stavros Sachtouris
            'filter by metadata key=value (can be repeated)', ('--metadata')),
657 1716a15d Stavros Sachtouris
        meta_like=KeyValueArgument(
658 1716a15d Stavros Sachtouris
            'filter by metadata key=value (can be repeated)',
659 1716a15d Stavros Sachtouris
            ('--metadata-like'))
660 1ae79e60 Stavros Sachtouris
    )
661 f3e94e06 Stavros Sachtouris
662 1716a15d Stavros Sachtouris
    def _filter_by_metadata(self, images):
663 1716a15d Stavros Sachtouris
        new_images = []
664 1716a15d Stavros Sachtouris
665 1716a15d Stavros Sachtouris
        for img in images:
666 854222c7 Stavros Sachtouris
            meta = [dict(img['metadata'])]
667 854222c7 Stavros Sachtouris
            if self['meta']:
668 854222c7 Stavros Sachtouris
                meta = filter_dicts_by_dict(meta, self['meta'])
669 854222c7 Stavros Sachtouris
            if meta and self['meta_like']:
670 854222c7 Stavros Sachtouris
                meta = filter_dicts_by_dict(
671 854222c7 Stavros Sachtouris
                    meta, self['meta_like'], exact_match=False)
672 854222c7 Stavros Sachtouris
            if meta:
673 854222c7 Stavros Sachtouris
                new_images.append(img)
674 1716a15d Stavros Sachtouris
        return new_images
675 1716a15d Stavros Sachtouris
676 1716a15d Stavros Sachtouris
    def _add_name(self, images, key='user_id'):
677 1716a15d Stavros Sachtouris
        uuids = self._uuids2usernames(
678 1716a15d Stavros Sachtouris
            list(set([img[key] for img in images])))
679 1716a15d Stavros Sachtouris
        for img in images:
680 1716a15d Stavros Sachtouris
            img[key] += ' (%s)' % uuids[img[key]]
681 1716a15d Stavros Sachtouris
        return images
682 1716a15d Stavros Sachtouris
683 236e7d08 Stavros Sachtouris
    @errors.generic.all
684 236e7d08 Stavros Sachtouris
    @errors.cyclades.connection
685 236e7d08 Stavros Sachtouris
    def _run(self):
686 1716a15d Stavros Sachtouris
        withmeta = bool(self['meta'] or self['meta_like'])
687 1716a15d Stavros Sachtouris
        detail = self['detail'] or withmeta
688 1716a15d Stavros Sachtouris
        images = self.client.list_images(detail)
689 1716a15d Stavros Sachtouris
        if withmeta:
690 1716a15d Stavros Sachtouris
            images = self._filter_by_metadata(images)
691 1716a15d Stavros Sachtouris
        if self['detail'] and not self['json_output']:
692 1716a15d Stavros Sachtouris
            images = self._add_name(self._add_name(images, 'tenant_id'))
693 545c6c29 Stavros Sachtouris
        kwargs = dict(with_enumeration=self['enum'])
694 236e7d08 Stavros Sachtouris
        if self['more']:
695 545c6c29 Stavros Sachtouris
            kwargs['page_size'] = self['limit'] or 10
696 bcef3ac9 Stavros Sachtouris
        elif self['limit']:
697 545c6c29 Stavros Sachtouris
            images = images[:self['limit']]
698 545c6c29 Stavros Sachtouris
        self._print(images, **kwargs)
699 236e7d08 Stavros Sachtouris
700 f3e94e06 Stavros Sachtouris
    def main(self):
701 236e7d08 Stavros Sachtouris
        super(self.__class__, self)._run()
702 236e7d08 Stavros Sachtouris
        self._run()
703 f3e94e06 Stavros Sachtouris
704 234954d1 Stavros Sachtouris
705 d486baec Stavros Sachtouris
@command(image_cmds)
706 545c6c29 Stavros Sachtouris
class image_compute_info(_init_cyclades, _optional_json):
707 15142309 Stavros Sachtouris
    """Get detailed information on an image"""
708 f3e94e06 Stavros Sachtouris
709 236e7d08 Stavros Sachtouris
    @errors.generic.all
710 236e7d08 Stavros Sachtouris
    @errors.cyclades.connection
711 236e7d08 Stavros Sachtouris
    @errors.plankton.id
712 236e7d08 Stavros Sachtouris
    def _run(self, image_id):
713 236e7d08 Stavros Sachtouris
        image = self.client.get_image_details(image_id)
714 bcef3ac9 Stavros Sachtouris
        self._print(image, print_dict)
715 f3e94e06 Stavros Sachtouris
716 f3e94e06 Stavros Sachtouris
    def main(self, image_id):
717 236e7d08 Stavros Sachtouris
        super(self.__class__, self)._run()
718 b04288f7 Stavros Sachtouris
        self._run(image_id=image_id)
719 f3e94e06 Stavros Sachtouris
720 234954d1 Stavros Sachtouris
721 d486baec Stavros Sachtouris
@command(image_cmds)
722 f5f35422 Stavros Sachtouris
class image_compute_delete(_init_cyclades, _optional_output_cmd):
723 24ff0a35 Stavros Sachtouris
    """Delete an image (WARNING: image file is also removed)"""
724 f3e94e06 Stavros Sachtouris
725 236e7d08 Stavros Sachtouris
    @errors.generic.all
726 236e7d08 Stavros Sachtouris
    @errors.cyclades.connection
727 236e7d08 Stavros Sachtouris
    @errors.plankton.id
728 236e7d08 Stavros Sachtouris
    def _run(self, image_id):
729 f5f35422 Stavros Sachtouris
        self._optional_output(self.client.delete_image(image_id))
730 236e7d08 Stavros Sachtouris
731 f3e94e06 Stavros Sachtouris
    def main(self, image_id):
732 236e7d08 Stavros Sachtouris
        super(self.__class__, self)._run()
733 b04288f7 Stavros Sachtouris
        self._run(image_id=image_id)
734 f3e94e06 Stavros Sachtouris
735 234954d1 Stavros Sachtouris
736 d486baec Stavros Sachtouris
@command(image_cmds)
737 8741c407 Stavros Sachtouris
class image_compute_properties(_init_cyclades):
738 395fbf9e Stavros Sachtouris
    """Manage properties related to OS installation in an image"""
739 f5f35422 Stavros Sachtouris
740 f5f35422 Stavros Sachtouris
741 f5f35422 Stavros Sachtouris
@command(image_cmds)
742 545c6c29 Stavros Sachtouris
class image_compute_properties_list(_init_cyclades, _optional_json):
743 f5f35422 Stavros Sachtouris
    """List all image properties"""
744 f5f35422 Stavros Sachtouris
745 f5f35422 Stavros Sachtouris
    @errors.generic.all
746 f5f35422 Stavros Sachtouris
    @errors.cyclades.connection
747 f5f35422 Stavros Sachtouris
    @errors.plankton.id
748 f5f35422 Stavros Sachtouris
    def _run(self, image_id):
749 545c6c29 Stavros Sachtouris
        self._print(self.client.get_image_metadata(image_id), print_dict)
750 f5f35422 Stavros Sachtouris
751 f5f35422 Stavros Sachtouris
    def main(self, image_id):
752 f5f35422 Stavros Sachtouris
        super(self.__class__, self)._run()
753 f5f35422 Stavros Sachtouris
        self._run(image_id=image_id)
754 f5f35422 Stavros Sachtouris
755 f5f35422 Stavros Sachtouris
756 f5f35422 Stavros Sachtouris
@command(image_cmds)
757 545c6c29 Stavros Sachtouris
class image_compute_properties_get(_init_cyclades, _optional_json):
758 f5f35422 Stavros Sachtouris
    """Get an image property"""
759 f5f35422 Stavros Sachtouris
760 236e7d08 Stavros Sachtouris
    @errors.generic.all
761 236e7d08 Stavros Sachtouris
    @errors.cyclades.connection
762 236e7d08 Stavros Sachtouris
    @errors.plankton.id
763 236e7d08 Stavros Sachtouris
    @errors.plankton.metadata
764 236e7d08 Stavros Sachtouris
    def _run(self, image_id, key):
765 545c6c29 Stavros Sachtouris
        self._print(self.client.get_image_metadata(image_id, key), print_dict)
766 236e7d08 Stavros Sachtouris
767 f5f35422 Stavros Sachtouris
    def main(self, image_id, key):
768 236e7d08 Stavros Sachtouris
        super(self.__class__, self)._run()
769 b04288f7 Stavros Sachtouris
        self._run(image_id=image_id, key=key)
770 f3e94e06 Stavros Sachtouris
771 234954d1 Stavros Sachtouris
772 d486baec Stavros Sachtouris
@command(image_cmds)
773 545c6c29 Stavros Sachtouris
class image_compute_properties_add(_init_cyclades, _optional_json):
774 f5f35422 Stavros Sachtouris
    """Add a property to an image"""
775 f5f35422 Stavros Sachtouris
776 236e7d08 Stavros Sachtouris
    @errors.generic.all
777 236e7d08 Stavros Sachtouris
    @errors.cyclades.connection
778 236e7d08 Stavros Sachtouris
    @errors.plankton.id
779 b04288f7 Stavros Sachtouris
    @errors.plankton.metadata
780 236e7d08 Stavros Sachtouris
    def _run(self, image_id, key, val):
781 545c6c29 Stavros Sachtouris
        self._print(
782 545c6c29 Stavros Sachtouris
            self.client.create_image_metadata(image_id, key, val), print_dict)
783 236e7d08 Stavros Sachtouris
784 f3e94e06 Stavros Sachtouris
    def main(self, image_id, key, val):
785 236e7d08 Stavros Sachtouris
        super(self.__class__, self)._run()
786 b04288f7 Stavros Sachtouris
        self._run(image_id=image_id, key=key, val=val)
787 f3e94e06 Stavros Sachtouris
788 234954d1 Stavros Sachtouris
789 d486baec Stavros Sachtouris
@command(image_cmds)
790 545c6c29 Stavros Sachtouris
class image_compute_properties_set(_init_cyclades, _optional_json):
791 f5f35422 Stavros Sachtouris
    """Add / update a set of properties for an image
792 f5f35422 Stavros Sachtouris
    proeprties must be given in the form key=value, e.v.
793 f5f35422 Stavros Sachtouris
    /image compute properties set <image-id> key1=val1 key2=val2
794 f5f35422 Stavros Sachtouris
    """
795 f3e94e06 Stavros Sachtouris
796 236e7d08 Stavros Sachtouris
    @errors.generic.all
797 236e7d08 Stavros Sachtouris
    @errors.cyclades.connection
798 236e7d08 Stavros Sachtouris
    @errors.plankton.id
799 f5f35422 Stavros Sachtouris
    def _run(self, image_id, keyvals):
800 545c6c29 Stavros Sachtouris
        meta = dict()
801 f5f35422 Stavros Sachtouris
        for keyval in keyvals:
802 f5f35422 Stavros Sachtouris
            key, val = keyval.split('=')
803 545c6c29 Stavros Sachtouris
            meta[key] = val
804 545c6c29 Stavros Sachtouris
        self._print(
805 545c6c29 Stavros Sachtouris
            self.client.update_image_metadata(image_id, **meta), print_dict)
806 f5f35422 Stavros Sachtouris
807 f5f35422 Stavros Sachtouris
    def main(self, image_id, *key_equals_value):
808 236e7d08 Stavros Sachtouris
        super(self.__class__, self)._run()
809 f5f35422 Stavros Sachtouris
        self._run(image_id=image_id, keyvals=key_equals_value)
810 f3e94e06 Stavros Sachtouris
811 234954d1 Stavros Sachtouris
812 d486baec Stavros Sachtouris
@command(image_cmds)
813 f5f35422 Stavros Sachtouris
class image_compute_properties_delete(_init_cyclades, _optional_output_cmd):
814 f5f35422 Stavros Sachtouris
    """Delete a property from an image"""
815 f3e94e06 Stavros Sachtouris
816 236e7d08 Stavros Sachtouris
    @errors.generic.all
817 236e7d08 Stavros Sachtouris
    @errors.cyclades.connection
818 236e7d08 Stavros Sachtouris
    @errors.plankton.id
819 236e7d08 Stavros Sachtouris
    @errors.plankton.metadata
820 236e7d08 Stavros Sachtouris
    def _run(self, image_id, key):
821 f5f35422 Stavros Sachtouris
        self._optional_output(self.client.delete_image_metadata(image_id, key))
822 236e7d08 Stavros Sachtouris
823 f3e94e06 Stavros Sachtouris
    def main(self, image_id, key):
824 236e7d08 Stavros Sachtouris
        super(self.__class__, self)._run()
825 b04288f7 Stavros Sachtouris
        self._run(image_id=image_id, key=key)