Statistics
| Branch: | Tag: | Revision:

root / kamaki / cli / commands / image.py @ d07e6fc2

History | View | Annotate | Download (29.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 6430d3a0 Stavros Sachtouris
from io import StringIO
38 76f58e2e Stavros Sachtouris
from pydoc import pager
39 623a4ceb Stavros Sachtouris
40 f3e94e06 Stavros Sachtouris
from kamaki.cli import command
41 d486baec Stavros Sachtouris
from kamaki.cli.command_tree import CommandTree
42 76f58e2e Stavros Sachtouris
from kamaki.cli.utils import filter_dicts_by_dict
43 1395c40e Stavros Sachtouris
from kamaki.clients.image import ImageClient
44 00336c85 Stavros Sachtouris
from kamaki.clients.pithos import PithosClient
45 00336c85 Stavros Sachtouris
from kamaki.clients import ClientError
46 ca5528f1 Stavros Sachtouris
from kamaki.cli.argument import (
47 ca5528f1 Stavros Sachtouris
    FlagArgument, ValueArgument, RepeatableArgument, KeyValueArgument,
48 ca5528f1 Stavros Sachtouris
    IntArgument, ProgressBarArgument)
49 bfb54881 Stavros Sachtouris
from kamaki.cli.commands.cyclades import _init_cyclades
50 432cea25 Stavros Sachtouris
from kamaki.cli.errors import (
51 432cea25 Stavros Sachtouris
    raiseCLIError, CLIBaseUrlError, CLIInvalidArgument)
52 b4f69041 Stavros Sachtouris
from kamaki.cli.commands import _command_init, errors, addLogSettings
53 6d190dd1 Stavros Sachtouris
from kamaki.cli.commands import (
54 6d190dd1 Stavros Sachtouris
    _optional_output_cmd, _optional_json, _name_filter, _id_filter)
55 0b368c8c Stavros Sachtouris
56 234954d1 Stavros Sachtouris
57 5c5eb675 Stavros Sachtouris
image_cmds = CommandTree('image', 'Cyclades/Plankton API image commands')
58 5c5eb675 Stavros Sachtouris
imagecompute_cmds = CommandTree(
59 5c5eb675 Stavros Sachtouris
    'imagecompute', 'Cyclades/Compute API image commands')
60 5c5eb675 Stavros Sachtouris
_commands = [image_cmds, imagecompute_cmds]
61 234954d1 Stavros Sachtouris
62 234954d1 Stavros Sachtouris
63 aa82dd5a Stavros Sachtouris
howto_image_file = [
64 aa82dd5a Stavros Sachtouris
    'Kamaki commands to:',
65 c626151a Stavros Sachtouris
    ' get current user id: /user authenticate',
66 aa82dd5a Stavros Sachtouris
    ' check available containers: /file list',
67 aa82dd5a Stavros Sachtouris
    ' create a new container: /file create <container>',
68 aa82dd5a Stavros Sachtouris
    ' check container contents: /file list <container>',
69 7bbfeb1a Stavros Sachtouris
    ' upload files: /file upload <image file> <container>',
70 7bbfeb1a Stavros Sachtouris
    ' register an image: /image register <image name> <container>:<path>']
71 aa82dd5a Stavros Sachtouris
72 aa82dd5a Stavros Sachtouris
about_image_id = ['To see a list of available image ids: /image list']
73 15142309 Stavros Sachtouris
74 15142309 Stavros Sachtouris
75 623a4ceb Stavros Sachtouris
log = getLogger(__name__)
76 623a4ceb Stavros Sachtouris
77 623a4ceb Stavros Sachtouris
78 5eae854d Stavros Sachtouris
class _init_image(_command_init):
79 a03ade9e Stavros Sachtouris
    @errors.generic.all
80 b4f69041 Stavros Sachtouris
    @addLogSettings
81 a03ade9e Stavros Sachtouris
    def _run(self):
82 b4f69041 Stavros Sachtouris
        if getattr(self, 'cloud', None):
83 b4f69041 Stavros Sachtouris
            img_url = self._custom_url('image') or self._custom_url('plankton')
84 b4f69041 Stavros Sachtouris
            if img_url:
85 1d0f1ffa Stavros Sachtouris
                token = self._custom_token('image') or self._custom_token(
86 1d0f1ffa Stavros Sachtouris
                    'plankton') or self.config.get_cloud(self.cloud, 'token')
87 b4f69041 Stavros Sachtouris
                self.client = ImageClient(base_url=img_url, token=token)
88 b4f69041 Stavros Sachtouris
                return
89 8cec3671 Stavros Sachtouris
        if getattr(self, 'auth_base', False):
90 8cec3671 Stavros Sachtouris
            plankton_endpoints = self.auth_base.get_service_endpoints(
91 72fa0010 Stavros Sachtouris
                self._custom_type('image') or self._custom_type(
92 72fa0010 Stavros Sachtouris
                    'plankton') or 'image',
93 72fa0010 Stavros Sachtouris
                self._custom_version('image') or self._custom_version(
94 72fa0010 Stavros Sachtouris
                    'plankton') or '')
95 8cec3671 Stavros Sachtouris
            base_url = plankton_endpoints['publicURL']
96 b4f69041 Stavros Sachtouris
            token = self.auth_base.token
97 8cec3671 Stavros Sachtouris
        else:
98 8cec3671 Stavros Sachtouris
            raise CLIBaseUrlError(service='plankton')
99 a03ade9e Stavros Sachtouris
        self.client = ImageClient(base_url=base_url, token=token)
100 a03ade9e Stavros Sachtouris
101 7493ccb6 Stavros Sachtouris
    def main(self):
102 a03ade9e Stavros Sachtouris
        self._run()
103 7493ccb6 Stavros Sachtouris
104 234954d1 Stavros Sachtouris
105 573be34f Stavros Sachtouris
# Plankton Image Commands
106 573be34f Stavros Sachtouris
107 573be34f Stavros Sachtouris
108 aa82dd5a Stavros Sachtouris
def _validate_image_meta(json_dict, return_str=False):
109 623a4ceb Stavros Sachtouris
    """
110 623a4ceb Stavros Sachtouris
    :param json_dict" (dict) json-formated, of the form
111 623a4ceb Stavros Sachtouris
        {"key1": "val1", "key2": "val2", ...}
112 623a4ceb Stavros Sachtouris

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

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

117 623a4ceb Stavros Sachtouris
    :raises TypeError, AttributeError: Invalid json format
118 623a4ceb Stavros Sachtouris

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

142 623a4ceb Stavros Sachtouris
    :returns: (dict) json_formated
143 623a4ceb Stavros Sachtouris

144 623a4ceb Stavros Sachtouris
    :raises TypeError, AttributeError: Invalid json format
145 623a4ceb Stavros Sachtouris

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

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

163 aa82dd5a Stavros Sachtouris
    :raises AssertionError: if location is invalid
164 aa82dd5a Stavros Sachtouris
    """
165 aa82dd5a Stavros Sachtouris
    prefix = 'pithos://'
166 aa82dd5a Stavros Sachtouris
    msg = 'Invalid prefix for location %s , try: %s' % (location, prefix)
167 aa82dd5a Stavros Sachtouris
    assert location.startswith(prefix), msg
168 aa82dd5a Stavros Sachtouris
    service, sep, rest = location.partition('://')
169 c626151a Stavros Sachtouris
    assert sep and rest, 'Location %s is missing user-id' % location
170 aa82dd5a Stavros Sachtouris
    uuid, sep, rest = rest.partition('/')
171 aa82dd5a Stavros Sachtouris
    assert sep and rest, 'Location %s is missing container' % location
172 aa82dd5a Stavros Sachtouris
    container, sep, img_path = rest.partition('/')
173 aa82dd5a Stavros Sachtouris
    assert sep and img_path, 'Location %s is missing image path' % location
174 aa82dd5a Stavros Sachtouris
    return uuid, container, img_path
175 aa82dd5a Stavros Sachtouris
176 aa82dd5a Stavros Sachtouris
177 d486baec Stavros Sachtouris
@command(image_cmds)
178 6d190dd1 Stavros Sachtouris
class image_list(_init_image, _optional_json, _name_filter, _id_filter):
179 573be34f Stavros Sachtouris
    """List images accessible by user"""
180 7493ccb6 Stavros Sachtouris
181 2d1202ee Stavros Sachtouris
    PERMANENTS = (
182 2d1202ee Stavros Sachtouris
        'id', 'name',
183 2d1202ee Stavros Sachtouris
        'status', 'container_format', 'disk_format', 'size')
184 2d1202ee Stavros Sachtouris
185 1ae79e60 Stavros Sachtouris
    arguments = dict(
186 f40f0cb7 Stavros Sachtouris
        detail=FlagArgument('show detailed output', ('-l', '--details')),
187 1ae79e60 Stavros Sachtouris
        container_format=ValueArgument(
188 1ae79e60 Stavros Sachtouris
            'filter by container format',
189 1ae79e60 Stavros Sachtouris
            '--container-format'),
190 1ae79e60 Stavros Sachtouris
        disk_format=ValueArgument('filter by disk format', '--disk-format'),
191 1ae79e60 Stavros Sachtouris
        size_min=IntArgument('filter by minimum size', '--size-min'),
192 1ae79e60 Stavros Sachtouris
        size_max=IntArgument('filter by maximum size', '--size-max'),
193 1ae79e60 Stavros Sachtouris
        status=ValueArgument('filter by status', '--status'),
194 f9457c89 Stavros Sachtouris
        owner=ValueArgument('filter by owner', '--owner'),
195 95641ecc Stavros Sachtouris
        owner_name=ValueArgument('filter by owners username', '--owner-name'),
196 1ae79e60 Stavros Sachtouris
        order=ValueArgument(
197 1ae79e60 Stavros Sachtouris
            'order by FIELD ( - to reverse order)',
198 1ae79e60 Stavros Sachtouris
            '--order',
199 83c3ba87 Stavros Sachtouris
            default=''),
200 f40f0cb7 Stavros Sachtouris
        limit=IntArgument('limit number of listed images', ('-n', '--number')),
201 83c3ba87 Stavros Sachtouris
        more=FlagArgument(
202 83c3ba87 Stavros Sachtouris
            'output results in pages (-n to set items per page, default 10)',
203 ed9af02c Stavros Sachtouris
            '--more'),
204 2d1202ee Stavros Sachtouris
        enum=FlagArgument('Enumerate results', '--enumerate'),
205 5576a4eb Stavros Sachtouris
        prop=KeyValueArgument('filter by property key=value', ('--property')),
206 5576a4eb Stavros Sachtouris
        prop_like=KeyValueArgument(
207 5576a4eb Stavros Sachtouris
            'fliter by property key=value where value is part of actual value',
208 1716a15d Stavros Sachtouris
            ('--property-like')),
209 5c5eb675 Stavros Sachtouris
        image_ID_for_members=ValueArgument(
210 5c5eb675 Stavros Sachtouris
            'List members of an image', '--members-of')
211 1ae79e60 Stavros Sachtouris
    )
212 7493ccb6 Stavros Sachtouris
213 6d190dd1 Stavros Sachtouris
    def _filter_by_owner(self, images):
214 95641ecc Stavros Sachtouris
        ouuid = self['owner'] or self._username2uuid(self['owner_name'])
215 854222c7 Stavros Sachtouris
        return filter_dicts_by_dict(images, dict(owner=ouuid))
216 f9457c89 Stavros Sachtouris
217 5576a4eb Stavros Sachtouris
    def _add_owner_name(self, images):
218 5576a4eb Stavros Sachtouris
        uuids = self._uuids2usernames(
219 5576a4eb Stavros Sachtouris
            list(set([img['owner'] for img in images])))
220 5576a4eb Stavros Sachtouris
        for img in images:
221 5576a4eb Stavros Sachtouris
            img['owner'] += ' (%s)' % uuids[img['owner']]
222 5576a4eb Stavros Sachtouris
        return images
223 f1e5b343 Stavros Sachtouris
224 6d190dd1 Stavros Sachtouris
    def _filter_by_properties(self, images):
225 2d1202ee Stavros Sachtouris
        new_images = []
226 2d1202ee Stavros Sachtouris
        for img in images:
227 854222c7 Stavros Sachtouris
            props = [dict(img['properties'])]
228 854222c7 Stavros Sachtouris
            if self['prop']:
229 854222c7 Stavros Sachtouris
                props = filter_dicts_by_dict(props, self['prop'])
230 854222c7 Stavros Sachtouris
            if props and self['prop_like']:
231 854222c7 Stavros Sachtouris
                props = filter_dicts_by_dict(
232 854222c7 Stavros Sachtouris
                    props, self['prop_like'], exact_match=False)
233 854222c7 Stavros Sachtouris
            if props:
234 854222c7 Stavros Sachtouris
                new_images.append(img)
235 2d1202ee Stavros Sachtouris
        return new_images
236 2d1202ee Stavros Sachtouris
237 5c5eb675 Stavros Sachtouris
    def _members(self, image_id):
238 5c5eb675 Stavros Sachtouris
        members = self.client.list_members(image_id)
239 5c5eb675 Stavros Sachtouris
        if not (self['json_output'] or self['output_format']):
240 5c5eb675 Stavros Sachtouris
            uuids = [member['member_id'] for member in members]
241 5c5eb675 Stavros Sachtouris
            usernames = self._uuids2usernames(uuids)
242 5c5eb675 Stavros Sachtouris
            for member in members:
243 5c5eb675 Stavros Sachtouris
                member['member_id'] += ' (%s)' % usernames[member['member_id']]
244 5c5eb675 Stavros Sachtouris
        self._print(members, title=('member_id',))
245 5c5eb675 Stavros Sachtouris
246 a03ade9e Stavros Sachtouris
    @errors.generic.all
247 a03ade9e Stavros Sachtouris
    @errors.cyclades.connection
248 a03ade9e Stavros Sachtouris
    def _run(self):
249 a03ade9e Stavros Sachtouris
        super(self.__class__, self)._run()
250 5c5eb675 Stavros Sachtouris
        if self['image_ID_for_members']:
251 5c5eb675 Stavros Sachtouris
            return self._members(self['image_ID_for_members'])
252 7493ccb6 Stavros Sachtouris
        filters = {}
253 fa984c2c Stavros Sachtouris
        for arg in set([
254 1ae79e60 Stavros Sachtouris
                'container_format',
255 1ae79e60 Stavros Sachtouris
                'disk_format',
256 1ae79e60 Stavros Sachtouris
                'name',
257 1ae79e60 Stavros Sachtouris
                'size_min',
258 1ae79e60 Stavros Sachtouris
                'size_max',
259 de73876b Stavros Sachtouris
                'status']).intersection(self.arguments):
260 1ae79e60 Stavros Sachtouris
            filters[arg] = self[arg]
261 1ae79e60 Stavros Sachtouris
262 1ae79e60 Stavros Sachtouris
        order = self['order']
263 854222c7 Stavros Sachtouris
        detail = self['detail'] or (
264 854222c7 Stavros Sachtouris
            self['prop'] or self['prop_like']) or (
265 854222c7 Stavros Sachtouris
            self['owner'] or self['owner_name'])
266 f9457c89 Stavros Sachtouris
267 854222c7 Stavros Sachtouris
        images = self.client.list_public(detail, filters, order)
268 854222c7 Stavros Sachtouris
269 854222c7 Stavros Sachtouris
        if self['owner'] or self['owner_name']:
270 6d190dd1 Stavros Sachtouris
            images = self._filter_by_owner(images)
271 854222c7 Stavros Sachtouris
        if self['prop'] or self['prop_like']:
272 6d190dd1 Stavros Sachtouris
            images = self._filter_by_properties(images)
273 6d190dd1 Stavros Sachtouris
        images = self._filter_by_id(images)
274 6d190dd1 Stavros Sachtouris
        images = self._non_exact_name_filter(images)
275 854222c7 Stavros Sachtouris
276 f76c6bbc Stavros Sachtouris
        if self['detail'] and not (
277 f76c6bbc Stavros Sachtouris
                self['json_output'] or self['output_format']):
278 5576a4eb Stavros Sachtouris
            images = self._add_owner_name(images)
279 854222c7 Stavros Sachtouris
        elif detail and not self['detail']:
280 854222c7 Stavros Sachtouris
            for img in images:
281 854222c7 Stavros Sachtouris
                for key in set(img).difference(self.PERMANENTS):
282 854222c7 Stavros Sachtouris
                    img.pop(key)
283 545c6c29 Stavros Sachtouris
        kwargs = dict(with_enumeration=self['enum'])
284 6430d3a0 Stavros Sachtouris
        if self['limit']:
285 545c6c29 Stavros Sachtouris
            images = images[:self['limit']]
286 6430d3a0 Stavros Sachtouris
        if self['more']:
287 6430d3a0 Stavros Sachtouris
            kwargs['out'] = StringIO()
288 6430d3a0 Stavros Sachtouris
            kwargs['title'] = ()
289 545c6c29 Stavros Sachtouris
        self._print(images, **kwargs)
290 6430d3a0 Stavros Sachtouris
        if self['more']:
291 6430d3a0 Stavros Sachtouris
            pager(kwargs['out'].getvalue())
292 7493ccb6 Stavros Sachtouris
293 a03ade9e Stavros Sachtouris
    def main(self):
294 a03ade9e Stavros Sachtouris
        super(self.__class__, self)._run()
295 a03ade9e Stavros Sachtouris
        self._run()
296 a03ade9e Stavros Sachtouris
297 234954d1 Stavros Sachtouris
298 d486baec Stavros Sachtouris
@command(image_cmds)
299 82cc4b8f Stavros Sachtouris
class image_info(_init_image, _optional_json):
300 00b1248e Stavros Sachtouris
    """Get image metadata"""
301 7493ccb6 Stavros Sachtouris
302 a03ade9e Stavros Sachtouris
    @errors.generic.all
303 a03ade9e Stavros Sachtouris
    @errors.plankton.connection
304 a03ade9e Stavros Sachtouris
    @errors.plankton.id
305 a03ade9e Stavros Sachtouris
    def _run(self, image_id):
306 ca5528f1 Stavros Sachtouris
        meta = self.client.get_meta(image_id)
307 f76c6bbc Stavros Sachtouris
        if not (self['json_output'] or self['output_format']):
308 ca5528f1 Stavros Sachtouris
            meta['owner'] += ' (%s)' % self._uuid2username(meta['owner'])
309 76f58e2e Stavros Sachtouris
        self._print(meta, self.print_dict)
310 ca5528f1 Stavros Sachtouris
311 ca5528f1 Stavros Sachtouris
    def main(self, image_id):
312 ca5528f1 Stavros Sachtouris
        super(self.__class__, self)._run()
313 ca5528f1 Stavros Sachtouris
        self._run(image_id=image_id)
314 ca5528f1 Stavros Sachtouris
315 ca5528f1 Stavros Sachtouris
316 ca5528f1 Stavros Sachtouris
@command(image_cmds)
317 5c5eb675 Stavros Sachtouris
class image_modify(_init_image, _optional_output_cmd):
318 ca5528f1 Stavros Sachtouris
    """Add / update metadata and properties for an image
319 ca5528f1 Stavros Sachtouris
    The original image preserves the values that are not affected
320 ca5528f1 Stavros Sachtouris
    """
321 ca5528f1 Stavros Sachtouris
322 ca5528f1 Stavros Sachtouris
    arguments = dict(
323 00b1248e Stavros Sachtouris
        image_name=ValueArgument('Change name', '--name'),
324 00b1248e Stavros Sachtouris
        disk_format=ValueArgument('Change disk format', '--disk-format'),
325 ca5528f1 Stavros Sachtouris
        container_format=ValueArgument(
326 00b1248e Stavros Sachtouris
            'Change container format', '--container-format'),
327 00b1248e Stavros Sachtouris
        status=ValueArgument('Change status', '--status'),
328 00b1248e Stavros Sachtouris
        publish=FlagArgument('Publish the image', '--publish'),
329 00b1248e Stavros Sachtouris
        unpublish=FlagArgument('Unpublish the image', '--unpublish'),
330 00b1248e Stavros Sachtouris
        property_to_set=KeyValueArgument(
331 ca5528f1 Stavros Sachtouris
            'set property in key=value form (can be repeated)',
332 00b1248e Stavros Sachtouris
            ('-p', '--property-set')),
333 00b1248e Stavros Sachtouris
        property_to_del=RepeatableArgument(
334 5c5eb675 Stavros Sachtouris
            'Delete property by key (can be repeated)', '--property-del'),
335 5c5eb675 Stavros Sachtouris
        member_ID_to_add=RepeatableArgument(
336 5c5eb675 Stavros Sachtouris
            'Add member to image (can be repeated)', '--member-add'),
337 5c5eb675 Stavros Sachtouris
        member_ID_to_remove=RepeatableArgument(
338 5c5eb675 Stavros Sachtouris
            'Remove a member (can be repeated)', '--member-del'),
339 ca5528f1 Stavros Sachtouris
    )
340 00b1248e Stavros Sachtouris
    required = [
341 00b1248e Stavros Sachtouris
        'image_name', 'disk_format', 'container_format', 'status', 'publish',
342 5c5eb675 Stavros Sachtouris
        'unpublish', 'property_to_set', 'member_ID_to_add',
343 5c5eb675 Stavros Sachtouris
        'member_ID_to_remove']
344 ca5528f1 Stavros Sachtouris
345 ca5528f1 Stavros Sachtouris
    @errors.generic.all
346 ca5528f1 Stavros Sachtouris
    @errors.plankton.connection
347 ca5528f1 Stavros Sachtouris
    @errors.plankton.id
348 ca5528f1 Stavros Sachtouris
    def _run(self, image_id):
349 f084bdc8 Stavros Sachtouris
        for mid in (self['member_ID_to_add'] or []):
350 5c5eb675 Stavros Sachtouris
            self.client.add_member(image_id, mid)
351 f084bdc8 Stavros Sachtouris
        for mid in (self['member_ID_to_remove'] or []):
352 5c5eb675 Stavros Sachtouris
            self.client.remove_member(image_id, mid)
353 f084bdc8 Stavros Sachtouris
        meta = self.client.get_meta(image_id)
354 f084bdc8 Stavros Sachtouris
        for k, v in self['property_to_set'].items():
355 f084bdc8 Stavros Sachtouris
            meta['properties'][k.upper()] = v
356 f084bdc8 Stavros Sachtouris
        for k in (self['property_to_del'] or []):
357 f084bdc8 Stavros Sachtouris
            meta['properties'][k.upper()] = None
358 f084bdc8 Stavros Sachtouris
        self._optional_output(self.client.update_image(
359 f084bdc8 Stavros Sachtouris
            image_id,
360 f084bdc8 Stavros Sachtouris
            name=self['image_name'],
361 f084bdc8 Stavros Sachtouris
            disk_format=self['disk_format'],
362 f084bdc8 Stavros Sachtouris
            container_format=self['container_format'],
363 f084bdc8 Stavros Sachtouris
            status=self['status'],
364 f084bdc8 Stavros Sachtouris
            public=self['publish'] or self['unpublish'] or None,
365 f084bdc8 Stavros Sachtouris
            **meta['properties']))
366 5c5eb675 Stavros Sachtouris
        if self['with_output']:
367 5c5eb675 Stavros Sachtouris
            self._optional_output(self.get_image_details(image_id))
368 ca5528f1 Stavros Sachtouris
369 ca5528f1 Stavros Sachtouris
    def main(self, image_id):
370 ca5528f1 Stavros Sachtouris
        super(self.__class__, self)._run()
371 b04288f7 Stavros Sachtouris
        self._run(image_id=image_id)
372 a03ade9e Stavros Sachtouris
373 234954d1 Stavros Sachtouris
374 432cea25 Stavros Sachtouris
class PithosLocationArgument(ValueArgument):
375 432cea25 Stavros Sachtouris
    """Resolve pithos url, return in the form pithos://uuid/container/path"""
376 432cea25 Stavros Sachtouris
377 432cea25 Stavros Sachtouris
    def __init__(
378 432cea25 Stavros Sachtouris
            self, help=None, parsed_name=None, default=None, user_uuid=None):
379 432cea25 Stavros Sachtouris
        super(PithosLocationArgument, self).__init__(
380 432cea25 Stavros Sachtouris
            help=help, parsed_name=parsed_name, default=default)
381 432cea25 Stavros Sachtouris
        self.uuid, self.container, self.path = user_uuid, None, None
382 432cea25 Stavros Sachtouris
383 432cea25 Stavros Sachtouris
    def setdefault(self, term, value):
384 432cea25 Stavros Sachtouris
        if not getattr(self, term, None):
385 432cea25 Stavros Sachtouris
            setattr(self, term, value)
386 432cea25 Stavros Sachtouris
387 432cea25 Stavros Sachtouris
    @property
388 432cea25 Stavros Sachtouris
    def value(self):
389 432cea25 Stavros Sachtouris
        return 'pithos://%s/%s/%s' % (self.uuid, self.container, self.path)
390 432cea25 Stavros Sachtouris
391 432cea25 Stavros Sachtouris
    @value.setter
392 432cea25 Stavros Sachtouris
    def value(self, location):
393 432cea25 Stavros Sachtouris
        if location:
394 432cea25 Stavros Sachtouris
            from kamaki.cli.commands.pithos import _pithos_container as pc
395 432cea25 Stavros Sachtouris
            try:
396 432cea25 Stavros Sachtouris
                uuid, self.container, self.path = pc._resolve_pithos_url(
397 432cea25 Stavros Sachtouris
                    location)
398 432cea25 Stavros Sachtouris
                self.uuid = uuid or self.uuid
399 432cea25 Stavros Sachtouris
                for term in ('container', 'path'):
400 432cea25 Stavros Sachtouris
                    assert getattr(self, term, None), 'No %s' % term
401 432cea25 Stavros Sachtouris
            except Exception as e:
402 432cea25 Stavros Sachtouris
                raise CLIInvalidArgument(
403 432cea25 Stavros Sachtouris
                    'Invalid Pithos+ location %s (%s)' % (location, e),
404 432cea25 Stavros Sachtouris
                    details=[
405 432cea25 Stavros Sachtouris
                        'The image location must be a valid Pithos+',
406 432cea25 Stavros Sachtouris
                        'location. There are two valid formats:',
407 432cea25 Stavros Sachtouris
                        '  pithos://USER_UUID/CONTAINER/PATH',
408 432cea25 Stavros Sachtouris
                        'OR',
409 432cea25 Stavros Sachtouris
                        '  /CONTAINER/PATH',
410 432cea25 Stavros Sachtouris
                        'To see all containers:',
411 432cea25 Stavros Sachtouris
                        '  [kamaki] container list',
412 432cea25 Stavros Sachtouris
                        'To list the contents of a container:',
413 432cea25 Stavros Sachtouris
                        '  [kamaki] container list CONTAINER'])
414 432cea25 Stavros Sachtouris
415 432cea25 Stavros Sachtouris
416 d486baec Stavros Sachtouris
@command(image_cmds)
417 545c6c29 Stavros Sachtouris
class image_register(_init_image, _optional_json):
418 38db356b Stavros Sachtouris
    """(Re)Register an image file to an Image service
419 38db356b Stavros Sachtouris
    The image file must be stored at a pithos repository
420 16d7b9ff Stavros Sachtouris
    Some metadata can be set by user (e.g., disk-format) while others are set
421 16d7b9ff Stavros Sachtouris
    only automatically (e.g., image id). There are also some custom user
422 38db356b Stavros Sachtouris
    metadata, called properties.
423 38db356b Stavros Sachtouris
    A register command creates a remote meta file at
424 432cea25 Stavros Sachtouris
    /<container>/<image path>.meta
425 38db356b Stavros Sachtouris
    Users may download and edit this file and use it to re-register one or more
426 38db356b Stavros Sachtouris
    images.
427 38db356b Stavros Sachtouris
    In case of a meta file, runtime arguments for metadata or properties
428 38db356b Stavros Sachtouris
    override meta file settings.
429 38db356b Stavros Sachtouris
    """
430 7493ccb6 Stavros Sachtouris
431 d77e33d4 Stavros Sachtouris
    container_info_cache = {}
432 d77e33d4 Stavros Sachtouris
433 1ae79e60 Stavros Sachtouris
    arguments = dict(
434 38db356b Stavros Sachtouris
        checksum=ValueArgument('Set image checksum', '--checksum'),
435 1ae79e60 Stavros Sachtouris
        container_format=ValueArgument(
436 1d0f1ffa Stavros Sachtouris
            'Set container format', '--container-format'),
437 38db356b Stavros Sachtouris
        disk_format=ValueArgument('Set disk format', '--disk-format'),
438 38db356b Stavros Sachtouris
        owner_name=ValueArgument('Set user uuid by user name', '--owner-name'),
439 1ae79e60 Stavros Sachtouris
        properties=KeyValueArgument(
440 38db356b Stavros Sachtouris
            'Add property (user-specified metadata) in key=value form'
441 38db356b Stavros Sachtouris
            '(can be repeated)',
442 1736e06d Stavros Sachtouris
            ('-p', '--property')),
443 38db356b Stavros Sachtouris
        is_public=FlagArgument('Mark image as public', '--public'),
444 38db356b Stavros Sachtouris
        size=IntArgument('Set image size in bytes', '--size'),
445 aa82dd5a Stavros Sachtouris
        metafile=ValueArgument(
446 aa82dd5a Stavros Sachtouris
            'Load metadata from a json-formated file <img-file>.meta :'
447 aa82dd5a Stavros Sachtouris
            '{"key1": "val1", "key2": "val2", ..., "properties: {...}"}',
448 aa82dd5a Stavros Sachtouris
            ('--metafile')),
449 aa82dd5a Stavros Sachtouris
        metafile_force=FlagArgument(
450 38db356b Stavros Sachtouris
            'Overide remote metadata file', ('-f', '--force')),
451 aa82dd5a Stavros Sachtouris
        no_metafile_upload=FlagArgument(
452 aa82dd5a Stavros Sachtouris
            'Do not store metadata in remote meta file',
453 aa82dd5a Stavros Sachtouris
            ('--no-metafile-upload')),
454 f2ea1314 Stavros Sachtouris
        container=ValueArgument(
455 f2ea1314 Stavros Sachtouris
            'Pithos+ container containing the image file',
456 f2ea1314 Stavros Sachtouris
            ('-C', '--container')),
457 d77e33d4 Stavros Sachtouris
        uuid=ValueArgument('Custom user uuid', '--uuid'),
458 d77e33d4 Stavros Sachtouris
        local_image_path=ValueArgument(
459 d77e33d4 Stavros Sachtouris
            'Local image file path to upload and register '
460 432cea25 Stavros Sachtouris
            '(still need target file in the form /ontainer/remote-path )',
461 d77e33d4 Stavros Sachtouris
            '--upload-image-file'),
462 d77e33d4 Stavros Sachtouris
        progress_bar=ProgressBarArgument(
463 432cea25 Stavros Sachtouris
            'Do not use progress bar', '--no-progress-bar', default=False),
464 432cea25 Stavros Sachtouris
        name=ValueArgument('The name of the new image', '--name'),
465 432cea25 Stavros Sachtouris
        pithos_location=PithosLocationArgument(
466 432cea25 Stavros Sachtouris
            'The Pithos+ image location to put the image at. Format:       '
467 432cea25 Stavros Sachtouris
            'pithos://USER_UUID/CONTAINER/IMAGE                  or   '
468 432cea25 Stavros Sachtouris
            '/CONTAINER/IMAGE',
469 432cea25 Stavros Sachtouris
            '--location')
470 1ae79e60 Stavros Sachtouris
    )
471 432cea25 Stavros Sachtouris
    required = ('name', 'pithos_location')
472 7493ccb6 Stavros Sachtouris
473 432cea25 Stavros Sachtouris
    def _get_pithos_client(self, locator):
474 aa82dd5a Stavros Sachtouris
        if self['no_metafile_upload']:
475 aa82dd5a Stavros Sachtouris
            return None
476 00336c85 Stavros Sachtouris
        ptoken = self.client.token
477 ef00bc31 Stavros Sachtouris
        if getattr(self, 'auth_base', False):
478 ef00bc31 Stavros Sachtouris
            pithos_endpoints = self.auth_base.get_service_endpoints(
479 df0045d8 Stavros Sachtouris
                'object-store')
480 ef00bc31 Stavros Sachtouris
            purl = pithos_endpoints['publicURL']
481 ef00bc31 Stavros Sachtouris
        else:
482 df0045d8 Stavros Sachtouris
            purl = self.config.get_cloud('pithos', 'url')
483 df0045d8 Stavros Sachtouris
        if not purl:
484 df0045d8 Stavros Sachtouris
            raise CLIBaseUrlError(service='pithos')
485 432cea25 Stavros Sachtouris
        return PithosClient(purl, ptoken, locator.uuid, locator.container)
486 00336c85 Stavros Sachtouris
487 aa82dd5a Stavros Sachtouris
    def _load_params_from_file(self, location):
488 aa82dd5a Stavros Sachtouris
        params, properties = dict(), dict()
489 aa82dd5a Stavros Sachtouris
        pfile = self['metafile']
490 aa82dd5a Stavros Sachtouris
        if pfile:
491 00336c85 Stavros Sachtouris
            try:
492 aa82dd5a Stavros Sachtouris
                for k, v in _load_image_meta(pfile).items():
493 aa82dd5a Stavros Sachtouris
                    key = k.lower().replace('-', '_')
494 1d0f1ffa Stavros Sachtouris
                    if key == 'properties':
495 aa82dd5a Stavros Sachtouris
                        for pk, pv in v.items():
496 aa82dd5a Stavros Sachtouris
                            properties[pk.upper().replace('-', '_')] = pv
497 aa82dd5a Stavros Sachtouris
                    elif key == 'name':
498 aa82dd5a Stavros Sachtouris
                            continue
499 aa82dd5a Stavros Sachtouris
                    elif key == 'location':
500 aa82dd5a Stavros Sachtouris
                        if location:
501 aa82dd5a Stavros Sachtouris
                            continue
502 aa82dd5a Stavros Sachtouris
                        location = v
503 aa82dd5a Stavros Sachtouris
                    else:
504 aa82dd5a Stavros Sachtouris
                        params[key] = v
505 aa82dd5a Stavros Sachtouris
            except Exception as e:
506 aa82dd5a Stavros Sachtouris
                raiseCLIError(e, 'Invalid json metadata config file')
507 aa82dd5a Stavros Sachtouris
        return params, properties, location
508 7493ccb6 Stavros Sachtouris
509 aa82dd5a Stavros Sachtouris
    def _load_params_from_args(self, params, properties):
510 f769a16a Stavros Sachtouris
        for key in set([
511 1ae79e60 Stavros Sachtouris
                'checksum',
512 1ae79e60 Stavros Sachtouris
                'container_format',
513 1ae79e60 Stavros Sachtouris
                'disk_format',
514 1ae79e60 Stavros Sachtouris
                'owner',
515 1ae79e60 Stavros Sachtouris
                'size',
516 de73876b Stavros Sachtouris
                'is_public']).intersection(self.arguments):
517 1ae79e60 Stavros Sachtouris
            params[key] = self[key]
518 aa82dd5a Stavros Sachtouris
        for k, v in self['properties'].items():
519 aa82dd5a Stavros Sachtouris
            properties[k.upper().replace('-', '_')] = v
520 1ae79e60 Stavros Sachtouris
521 aa82dd5a Stavros Sachtouris
    @errors.generic.all
522 aa82dd5a Stavros Sachtouris
    @errors.plankton.connection
523 432cea25 Stavros Sachtouris
    def _run(self, name, location):
524 432cea25 Stavros Sachtouris
        locator = self.arguments['pithos_location']
525 d77e33d4 Stavros Sachtouris
        if self['local_image_path']:
526 d77e33d4 Stavros Sachtouris
            with open(self['local_image_path']) as f:
527 432cea25 Stavros Sachtouris
                pithos = self._get_pithos_client(locator)
528 d77e33d4 Stavros Sachtouris
                (pbar, upload_cb) = self._safe_progress_bar('Uploading')
529 d77e33d4 Stavros Sachtouris
                if pbar:
530 d77e33d4 Stavros Sachtouris
                    hash_bar = pbar.clone()
531 d77e33d4 Stavros Sachtouris
                    hash_cb = hash_bar.get_generator('Calculating hashes')
532 d77e33d4 Stavros Sachtouris
                pithos.upload_object(
533 432cea25 Stavros Sachtouris
                    locator.path, f,
534 d77e33d4 Stavros Sachtouris
                    hash_cb=hash_cb, upload_cb=upload_cb,
535 d77e33d4 Stavros Sachtouris
                    container_info_cache=self.container_info_cache)
536 d77e33d4 Stavros Sachtouris
                pbar.finish()
537 d77e33d4 Stavros Sachtouris
538 f2ea1314 Stavros Sachtouris
        (params, properties, new_loc) = self._load_params_from_file(location)
539 f2ea1314 Stavros Sachtouris
        if location != new_loc:
540 432cea25 Stavros Sachtouris
            locator.value = new_loc
541 aa82dd5a Stavros Sachtouris
        self._load_params_from_args(params, properties)
542 432cea25 Stavros Sachtouris
        pclient = self._get_pithos_client(locator)
543 aa82dd5a Stavros Sachtouris
544 aa82dd5a Stavros Sachtouris
        #check if metafile exists
545 432cea25 Stavros Sachtouris
        meta_path = '%s.meta' % locator.path
546 aa82dd5a Stavros Sachtouris
        if pclient and not self['metafile_force']:
547 c4aefeaf Stavros Sachtouris
            try:
548 aa82dd5a Stavros Sachtouris
                pclient.get_object_info(meta_path)
549 81b0838d Stavros Sachtouris
                raiseCLIError(
550 432cea25 Stavros Sachtouris
                    'Metadata file /%s/%s already exists, abort' % (
551 432cea25 Stavros Sachtouris
                        locator.container, meta_path),
552 81b0838d Stavros Sachtouris
                    details=['Registration ABORTED', 'Try -f to overwrite'])
553 aa82dd5a Stavros Sachtouris
            except ClientError as ce:
554 aa82dd5a Stavros Sachtouris
                if ce.status != 404:
555 aa82dd5a Stavros Sachtouris
                    raise
556 aa82dd5a Stavros Sachtouris
557 aa82dd5a Stavros Sachtouris
        #register the image
558 aa82dd5a Stavros Sachtouris
        try:
559 aa82dd5a Stavros Sachtouris
            r = self.client.register(name, location, params, properties)
560 aa82dd5a Stavros Sachtouris
        except ClientError as ce:
561 7bbfeb1a Stavros Sachtouris
            if ce.status in (400, 404):
562 c4aefeaf Stavros Sachtouris
                raiseCLIError(
563 7bbfeb1a Stavros Sachtouris
                    ce, 'Nonexistent image file location\n\t%s' % location,
564 c4aefeaf Stavros Sachtouris
                    details=[
565 7bbfeb1a Stavros Sachtouris
                        'Does the image file %s exist at container %s ?' % (
566 432cea25 Stavros Sachtouris
                            locator.path,
567 432cea25 Stavros Sachtouris
                            locator.container)] + howto_image_file)
568 aa82dd5a Stavros Sachtouris
            raise
569 6b8a403c Stavros Sachtouris
        r['owner'] += ' (%s)' % self._uuid2username(r['owner'])
570 76f58e2e Stavros Sachtouris
        self._print(r, self.print_dict)
571 a03ade9e Stavros Sachtouris
572 aa82dd5a Stavros Sachtouris
        #upload the metadata file
573 00336c85 Stavros Sachtouris
        if pclient:
574 aa82dd5a Stavros Sachtouris
            try:
575 aa82dd5a Stavros Sachtouris
                meta_headers = pclient.upload_from_string(
576 d77e33d4 Stavros Sachtouris
                    meta_path, dumps(r, indent=2),
577 d77e33d4 Stavros Sachtouris
                    container_info_cache=self.container_info_cache)
578 aa82dd5a Stavros Sachtouris
            except TypeError:
579 1d0f1ffa Stavros Sachtouris
                self.error(
580 432cea25 Stavros Sachtouris
                    'Failed to dump metafile /%s/%s' % (
581 432cea25 Stavros Sachtouris
                        locator.container, meta_path))
582 aa82dd5a Stavros Sachtouris
                return
583 f76c6bbc Stavros Sachtouris
            if self['json_output'] or self['output_format']:
584 76f58e2e Stavros Sachtouris
                self.print_json(dict(
585 432cea25 Stavros Sachtouris
                    metafile_location='/%s/%s' % (
586 432cea25 Stavros Sachtouris
                        locator.container, meta_path),
587 aa82dd5a Stavros Sachtouris
                    headers=meta_headers))
588 9553da85 Stavros Sachtouris
            else:
589 432cea25 Stavros Sachtouris
                self.error('Metadata file uploaded as /%s/%s (version %s)' % (
590 432cea25 Stavros Sachtouris
                    locator.container,
591 432cea25 Stavros Sachtouris
                    meta_path,
592 432cea25 Stavros Sachtouris
                    meta_headers['x-object-version']))
593 00336c85 Stavros Sachtouris
594 432cea25 Stavros Sachtouris
    def main(self):
595 a03ade9e Stavros Sachtouris
        super(self.__class__, self)._run()
596 432cea25 Stavros Sachtouris
        self.arguments['pithos_location'].setdefault(
597 432cea25 Stavros Sachtouris
            'uuid', self.auth_base.user_term('id'))
598 432cea25 Stavros Sachtouris
        self._run(self['name'], self['pithos_location'])
599 7493ccb6 Stavros Sachtouris
600 234954d1 Stavros Sachtouris
601 d486baec Stavros Sachtouris
@command(image_cmds)
602 f5f35422 Stavros Sachtouris
class image_unregister(_init_image, _optional_output_cmd):
603 4a17d307 Stavros Sachtouris
    """Unregister an image (does not delete the image file)"""
604 4a17d307 Stavros Sachtouris
605 4a17d307 Stavros Sachtouris
    @errors.generic.all
606 4a17d307 Stavros Sachtouris
    @errors.plankton.connection
607 4a17d307 Stavros Sachtouris
    @errors.plankton.id
608 4a17d307 Stavros Sachtouris
    def _run(self, image_id):
609 f5f35422 Stavros Sachtouris
        self._optional_output(self.client.unregister(image_id))
610 4a17d307 Stavros Sachtouris
611 4a17d307 Stavros Sachtouris
    def main(self, image_id):
612 4a17d307 Stavros Sachtouris
        super(self.__class__, self)._run()
613 4a17d307 Stavros Sachtouris
        self._run(image_id=image_id)
614 4a17d307 Stavros Sachtouris
615 4a17d307 Stavros Sachtouris
616 573be34f Stavros Sachtouris
# Compute Image Commands
617 573be34f Stavros Sachtouris
618 5c5eb675 Stavros Sachtouris
@command(imagecompute_cmds)
619 5c5eb675 Stavros Sachtouris
class imagecompute_list(
620 6d190dd1 Stavros Sachtouris
        _init_cyclades, _optional_json, _name_filter, _id_filter):
621 f3e94e06 Stavros Sachtouris
    """List images"""
622 f3e94e06 Stavros Sachtouris
623 1716a15d Stavros Sachtouris
    PERMANENTS = ('id', 'name')
624 1716a15d Stavros Sachtouris
625 1ae79e60 Stavros Sachtouris
    arguments = dict(
626 f40f0cb7 Stavros Sachtouris
        detail=FlagArgument('show detailed output', ('-l', '--details')),
627 f40f0cb7 Stavros Sachtouris
        limit=IntArgument('limit number listed images', ('-n', '--number')),
628 1d0f1ffa Stavros Sachtouris
        more=FlagArgument('handle long lists of results', '--more'),
629 1716a15d Stavros Sachtouris
        enum=FlagArgument('Enumerate results', '--enumerate'),
630 fc48b144 Stavros Sachtouris
        user_id=ValueArgument('filter by user_id', '--user-id'),
631 fc48b144 Stavros Sachtouris
        user_name=ValueArgument('filter by username', '--user-name'),
632 1716a15d Stavros Sachtouris
        meta=KeyValueArgument(
633 1716a15d Stavros Sachtouris
            'filter by metadata key=value (can be repeated)', ('--metadata')),
634 1716a15d Stavros Sachtouris
        meta_like=KeyValueArgument(
635 1716a15d Stavros Sachtouris
            'filter by metadata key=value (can be repeated)',
636 1716a15d Stavros Sachtouris
            ('--metadata-like'))
637 1ae79e60 Stavros Sachtouris
    )
638 f3e94e06 Stavros Sachtouris
639 1716a15d Stavros Sachtouris
    def _filter_by_metadata(self, images):
640 1716a15d Stavros Sachtouris
        new_images = []
641 1716a15d Stavros Sachtouris
        for img in images:
642 854222c7 Stavros Sachtouris
            meta = [dict(img['metadata'])]
643 854222c7 Stavros Sachtouris
            if self['meta']:
644 854222c7 Stavros Sachtouris
                meta = filter_dicts_by_dict(meta, self['meta'])
645 854222c7 Stavros Sachtouris
            if meta and self['meta_like']:
646 854222c7 Stavros Sachtouris
                meta = filter_dicts_by_dict(
647 854222c7 Stavros Sachtouris
                    meta, self['meta_like'], exact_match=False)
648 854222c7 Stavros Sachtouris
            if meta:
649 854222c7 Stavros Sachtouris
                new_images.append(img)
650 1716a15d Stavros Sachtouris
        return new_images
651 1716a15d Stavros Sachtouris
652 fc48b144 Stavros Sachtouris
    def _filter_by_user(self, images):
653 fc48b144 Stavros Sachtouris
        uuid = self['user_id'] or self._username2uuid(self['user_name'])
654 fc48b144 Stavros Sachtouris
        return filter_dicts_by_dict(images, dict(user_id=uuid))
655 fc48b144 Stavros Sachtouris
656 1716a15d Stavros Sachtouris
    def _add_name(self, images, key='user_id'):
657 1716a15d Stavros Sachtouris
        uuids = self._uuids2usernames(
658 1716a15d Stavros Sachtouris
            list(set([img[key] for img in images])))
659 1716a15d Stavros Sachtouris
        for img in images:
660 1716a15d Stavros Sachtouris
            img[key] += ' (%s)' % uuids[img[key]]
661 1716a15d Stavros Sachtouris
        return images
662 1716a15d Stavros Sachtouris
663 236e7d08 Stavros Sachtouris
    @errors.generic.all
664 236e7d08 Stavros Sachtouris
    @errors.cyclades.connection
665 236e7d08 Stavros Sachtouris
    def _run(self):
666 1716a15d Stavros Sachtouris
        withmeta = bool(self['meta'] or self['meta_like'])
667 fc48b144 Stavros Sachtouris
        withuser = bool(self['user_id'] or self['user_name'])
668 fc48b144 Stavros Sachtouris
        detail = self['detail'] or withmeta or withuser
669 1716a15d Stavros Sachtouris
        images = self.client.list_images(detail)
670 6d190dd1 Stavros Sachtouris
        images = self._filter_by_name(images)
671 6d190dd1 Stavros Sachtouris
        images = self._filter_by_id(images)
672 fc48b144 Stavros Sachtouris
        if withuser:
673 fc48b144 Stavros Sachtouris
            images = self._filter_by_user(images)
674 1716a15d Stavros Sachtouris
        if withmeta:
675 1716a15d Stavros Sachtouris
            images = self._filter_by_metadata(images)
676 f76c6bbc Stavros Sachtouris
        if self['detail'] and not (
677 f76c6bbc Stavros Sachtouris
                self['json_output'] or self['output_format']):
678 1716a15d Stavros Sachtouris
            images = self._add_name(self._add_name(images, 'tenant_id'))
679 fc48b144 Stavros Sachtouris
        elif detail and not self['detail']:
680 fc48b144 Stavros Sachtouris
            for img in images:
681 fc48b144 Stavros Sachtouris
                for key in set(img).difference(self.PERMANENTS):
682 fc48b144 Stavros Sachtouris
                    img.pop(key)
683 545c6c29 Stavros Sachtouris
        kwargs = dict(with_enumeration=self['enum'])
684 6430d3a0 Stavros Sachtouris
        if self['limit']:
685 545c6c29 Stavros Sachtouris
            images = images[:self['limit']]
686 6430d3a0 Stavros Sachtouris
        if self['more']:
687 6430d3a0 Stavros Sachtouris
            kwargs['out'] = StringIO()
688 6430d3a0 Stavros Sachtouris
            kwargs['title'] = ()
689 545c6c29 Stavros Sachtouris
        self._print(images, **kwargs)
690 6430d3a0 Stavros Sachtouris
        if self['more']:
691 6430d3a0 Stavros Sachtouris
            pager(kwargs['out'].getvalue())
692 236e7d08 Stavros Sachtouris
693 f3e94e06 Stavros Sachtouris
    def main(self):
694 236e7d08 Stavros Sachtouris
        super(self.__class__, self)._run()
695 236e7d08 Stavros Sachtouris
        self._run()
696 f3e94e06 Stavros Sachtouris
697 234954d1 Stavros Sachtouris
698 5c5eb675 Stavros Sachtouris
@command(imagecompute_cmds)
699 5c5eb675 Stavros Sachtouris
class imagecompute_info(_init_cyclades, _optional_json):
700 15142309 Stavros Sachtouris
    """Get detailed information on an image"""
701 f3e94e06 Stavros Sachtouris
702 236e7d08 Stavros Sachtouris
    @errors.generic.all
703 236e7d08 Stavros Sachtouris
    @errors.cyclades.connection
704 236e7d08 Stavros Sachtouris
    @errors.plankton.id
705 236e7d08 Stavros Sachtouris
    def _run(self, image_id):
706 236e7d08 Stavros Sachtouris
        image = self.client.get_image_details(image_id)
707 cf115aed Stavros Sachtouris
        uuids = [image['user_id'], image['tenant_id']]
708 cf115aed Stavros Sachtouris
        usernames = self._uuids2usernames(uuids)
709 cf115aed Stavros Sachtouris
        image['user_id'] += ' (%s)' % usernames[image['user_id']]
710 cf115aed Stavros Sachtouris
        image['tenant_id'] += ' (%s)' % usernames[image['tenant_id']]
711 76f58e2e Stavros Sachtouris
        self._print(image, self.print_dict)
712 f3e94e06 Stavros Sachtouris
713 f3e94e06 Stavros Sachtouris
    def main(self, image_id):
714 236e7d08 Stavros Sachtouris
        super(self.__class__, self)._run()
715 b04288f7 Stavros Sachtouris
        self._run(image_id=image_id)
716 f3e94e06 Stavros Sachtouris
717 234954d1 Stavros Sachtouris
718 5c5eb675 Stavros Sachtouris
@command(imagecompute_cmds)
719 5c5eb675 Stavros Sachtouris
class imagecompute_delete(_init_cyclades, _optional_output_cmd):
720 24ff0a35 Stavros Sachtouris
    """Delete an image (WARNING: image file is also removed)"""
721 f3e94e06 Stavros Sachtouris
722 236e7d08 Stavros Sachtouris
    @errors.generic.all
723 236e7d08 Stavros Sachtouris
    @errors.cyclades.connection
724 236e7d08 Stavros Sachtouris
    @errors.plankton.id
725 236e7d08 Stavros Sachtouris
    def _run(self, image_id):
726 f5f35422 Stavros Sachtouris
        self._optional_output(self.client.delete_image(image_id))
727 236e7d08 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 5c5eb675 Stavros Sachtouris
@command(imagecompute_cmds)
734 5c5eb675 Stavros Sachtouris
class imagecompute_modify(_init_cyclades, _optional_output_cmd):
735 5c5eb675 Stavros Sachtouris
    """Modify image properties (metadata)"""
736 f5f35422 Stavros Sachtouris
737 5c5eb675 Stavros Sachtouris
    arguments = dict(
738 5c5eb675 Stavros Sachtouris
        property_to_add=KeyValueArgument(
739 5c5eb675 Stavros Sachtouris
            'Add property in key=value format (can be repeated)',
740 5c5eb675 Stavros Sachtouris
            ('--property-add')),
741 5c5eb675 Stavros Sachtouris
        property_to_del=RepeatableArgument(
742 5c5eb675 Stavros Sachtouris
            'Delete property by key (can be repeated)',
743 5c5eb675 Stavros Sachtouris
            ('--property-del'))
744 5c5eb675 Stavros Sachtouris
    )
745 5c5eb675 Stavros Sachtouris
    required = ['property_to_add', 'property_to_del']
746 f5f35422 Stavros Sachtouris
747 f5f35422 Stavros Sachtouris
    @errors.generic.all
748 f5f35422 Stavros Sachtouris
    @errors.cyclades.connection
749 f5f35422 Stavros Sachtouris
    @errors.plankton.id
750 f5f35422 Stavros Sachtouris
    def _run(self, image_id):
751 5c5eb675 Stavros Sachtouris
        if self['property_to_add']:
752 5c5eb675 Stavros Sachtouris
            self.client.update_image_metadata(
753 5c5eb675 Stavros Sachtouris
                image_id, **self['property_to_add'])
754 f084bdc8 Stavros Sachtouris
        for key in (self['property_to_del'] or []):
755 5c5eb675 Stavros Sachtouris
            self.client.delete_image_metadata(image_id, key)
756 5c5eb675 Stavros Sachtouris
        if self['with_output']:
757 5c5eb675 Stavros Sachtouris
            self._optional_output(self.client.get_image_details(image_id))
758 f5f35422 Stavros Sachtouris
759 f5f35422 Stavros Sachtouris
    def main(self, image_id):
760 f5f35422 Stavros Sachtouris
        super(self.__class__, self)._run()
761 f5f35422 Stavros Sachtouris
        self._run(image_id=image_id)