Statistics
| Branch: | Tag: | Revision:

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

History | View | Annotate | Download (33.2 kB)

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

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

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

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

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

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

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

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

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

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