Statistics
| Branch: | Tag: | Revision:

root / kamaki / cli / commands / image.py @ 89ea97e1

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