Statistics
| Branch: | Tag: | Revision:

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

History | View | Annotate | Download (22.4 kB)

1 234954d1 Stavros Sachtouris
# Copyright 2012 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 623a4ceb Stavros Sachtouris
from os.path import abspath
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 f5f35422 Stavros Sachtouris
from kamaki.cli.utils import print_dict, print_items, print_json
41 1395c40e Stavros Sachtouris
from kamaki.clients.image import ImageClient
42 00336c85 Stavros Sachtouris
from kamaki.clients.pithos import PithosClient
43 00336c85 Stavros Sachtouris
from kamaki.clients.astakos import AstakosClient
44 00336c85 Stavros Sachtouris
from kamaki.clients import ClientError
45 83c3ba87 Stavros Sachtouris
from kamaki.cli.argument import FlagArgument, ValueArgument, KeyValueArgument
46 83c3ba87 Stavros Sachtouris
from kamaki.cli.argument import IntArgument
47 bfb54881 Stavros Sachtouris
from kamaki.cli.commands.cyclades import _init_cyclades
48 f5f35422 Stavros Sachtouris
from kamaki.cli.commands import _command_init, errors, _optional_output_cmd
49 00336c85 Stavros Sachtouris
from kamaki.cli.errors import raiseCLIError
50 0b368c8c Stavros Sachtouris
51 234954d1 Stavros Sachtouris
52 a29d2f88 Stavros Sachtouris
image_cmds = CommandTree(
53 a29d2f88 Stavros Sachtouris
    'image',
54 a29d2f88 Stavros Sachtouris
    'Cyclades/Plankton API image commands\n'
55 a29d2f88 Stavros Sachtouris
    'image compute:\tCyclades/Compute API image commands')
56 d486baec Stavros Sachtouris
_commands = [image_cmds]
57 234954d1 Stavros Sachtouris
58 234954d1 Stavros Sachtouris
59 573be34f Stavros Sachtouris
about_image_id = [
60 573be34f Stavros Sachtouris
    'To see a list of available image ids: /image list']
61 15142309 Stavros Sachtouris
62 15142309 Stavros Sachtouris
63 623a4ceb Stavros Sachtouris
log = getLogger(__name__)
64 623a4ceb Stavros Sachtouris
65 623a4ceb Stavros Sachtouris
66 5eae854d Stavros Sachtouris
class _init_image(_command_init):
67 a03ade9e Stavros Sachtouris
    @errors.generic.all
68 a03ade9e Stavros Sachtouris
    def _run(self):
69 a03ade9e Stavros Sachtouris
        token = self.config.get('image', 'token')\
70 a03ade9e Stavros Sachtouris
            or self.config.get('compute', 'token')\
71 a03ade9e Stavros Sachtouris
            or self.config.get('global', 'token')
72 a03ade9e Stavros Sachtouris
        base_url = self.config.get('image', 'url')\
73 a03ade9e Stavros Sachtouris
            or self.config.get('compute', 'url')\
74 a03ade9e Stavros Sachtouris
            or self.config.get('global', 'url')
75 a03ade9e Stavros Sachtouris
        self.client = ImageClient(base_url=base_url, token=token)
76 f47417e7 Stavros Sachtouris
        self._set_log_params()
77 c5b9380c Stavros Sachtouris
        self._update_max_threads()
78 a03ade9e Stavros Sachtouris
79 7493ccb6 Stavros Sachtouris
    def main(self):
80 a03ade9e Stavros Sachtouris
        self._run()
81 7493ccb6 Stavros Sachtouris
82 234954d1 Stavros Sachtouris
83 573be34f Stavros Sachtouris
# Plankton Image Commands
84 573be34f Stavros Sachtouris
85 573be34f Stavros Sachtouris
86 623a4ceb Stavros Sachtouris
def _validate_image_props(json_dict, return_str=False):
87 623a4ceb Stavros Sachtouris
    """
88 623a4ceb Stavros Sachtouris
    :param json_dict" (dict) json-formated, of the form
89 623a4ceb Stavros Sachtouris
        {"key1": "val1", "key2": "val2", ...}
90 623a4ceb Stavros Sachtouris

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

93 623a4ceb Stavros Sachtouris
    :returns: (dict)
94 623a4ceb Stavros Sachtouris

95 623a4ceb Stavros Sachtouris
    :raises TypeError, AttributeError: Invalid json format
96 623a4ceb Stavros Sachtouris

97 623a4ceb Stavros Sachtouris
    :raises AssertionError: Valid json but invalid image properties dict
98 623a4ceb Stavros Sachtouris
    """
99 623a4ceb Stavros Sachtouris
    json_str = dumps(json_dict)
100 623a4ceb Stavros Sachtouris
    for k, v in json_dict.items():
101 623a4ceb Stavros Sachtouris
        dealbreaker = isinstance(v, dict) or isinstance(v, list)
102 623a4ceb Stavros Sachtouris
        assert not dealbreaker, 'Invalid property value for key %s' % k
103 623a4ceb Stavros Sachtouris
        dealbreaker = ' ' in k
104 623a4ceb Stavros Sachtouris
        assert not dealbreaker, 'Invalid key [%s]' % k
105 623a4ceb Stavros Sachtouris
        json_dict[k] = '%s' % v
106 623a4ceb Stavros Sachtouris
    return json_str if return_str else json_dict
107 623a4ceb Stavros Sachtouris
108 623a4ceb Stavros Sachtouris
109 623a4ceb Stavros Sachtouris
def _load_image_props(filepath):
110 623a4ceb Stavros Sachtouris
    """
111 623a4ceb Stavros Sachtouris
    :param filepath: (str) the (relative) path of the metafile
112 623a4ceb Stavros Sachtouris

113 623a4ceb Stavros Sachtouris
    :returns: (dict) json_formated
114 623a4ceb Stavros Sachtouris

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

117 623a4ceb Stavros Sachtouris
    :raises AssertionError: Valid json but invalid image properties dict
118 623a4ceb Stavros Sachtouris
    """
119 623a4ceb Stavros Sachtouris
    with open(abspath(filepath)) as f:
120 623a4ceb Stavros Sachtouris
        meta_dict = load(f)
121 623a4ceb Stavros Sachtouris
        try:
122 623a4ceb Stavros Sachtouris
            return _validate_image_props(meta_dict)
123 623a4ceb Stavros Sachtouris
        except AssertionError:
124 623a4ceb Stavros Sachtouris
            log.debug('Failed to load properties from file %s' % filepath)
125 623a4ceb Stavros Sachtouris
            raise
126 623a4ceb Stavros Sachtouris
127 623a4ceb Stavros Sachtouris
128 d486baec Stavros Sachtouris
@command(image_cmds)
129 573be34f Stavros Sachtouris
class image_list(_init_image):
130 573be34f Stavros Sachtouris
    """List images accessible by user"""
131 7493ccb6 Stavros Sachtouris
132 1ae79e60 Stavros Sachtouris
    arguments = dict(
133 f40f0cb7 Stavros Sachtouris
        detail=FlagArgument('show detailed output', ('-l', '--details')),
134 1ae79e60 Stavros Sachtouris
        container_format=ValueArgument(
135 1ae79e60 Stavros Sachtouris
            'filter by container format',
136 1ae79e60 Stavros Sachtouris
            '--container-format'),
137 1ae79e60 Stavros Sachtouris
        disk_format=ValueArgument('filter by disk format', '--disk-format'),
138 1ae79e60 Stavros Sachtouris
        name=ValueArgument('filter by name', '--name'),
139 faeccbf9 Stavros Sachtouris
        name_pref=ValueArgument(
140 faeccbf9 Stavros Sachtouris
            'filter by name prefix (case insensitive)',
141 faeccbf9 Stavros Sachtouris
            '--name-prefix'),
142 faeccbf9 Stavros Sachtouris
        name_suff=ValueArgument(
143 faeccbf9 Stavros Sachtouris
            'filter by name suffix (case insensitive)',
144 faeccbf9 Stavros Sachtouris
            '--name-suffix'),
145 faeccbf9 Stavros Sachtouris
        name_like=ValueArgument(
146 faeccbf9 Stavros Sachtouris
            'print only if name contains this (case insensitive)',
147 faeccbf9 Stavros Sachtouris
            '--name-like'),
148 1ae79e60 Stavros Sachtouris
        size_min=IntArgument('filter by minimum size', '--size-min'),
149 1ae79e60 Stavros Sachtouris
        size_max=IntArgument('filter by maximum size', '--size-max'),
150 1ae79e60 Stavros Sachtouris
        status=ValueArgument('filter by status', '--status'),
151 f9457c89 Stavros Sachtouris
        owner=ValueArgument('filter by owner', '--owner'),
152 1ae79e60 Stavros Sachtouris
        order=ValueArgument(
153 1ae79e60 Stavros Sachtouris
            'order by FIELD ( - to reverse order)',
154 1ae79e60 Stavros Sachtouris
            '--order',
155 83c3ba87 Stavros Sachtouris
            default=''),
156 f40f0cb7 Stavros Sachtouris
        limit=IntArgument('limit number of listed images', ('-n', '--number')),
157 83c3ba87 Stavros Sachtouris
        more=FlagArgument(
158 83c3ba87 Stavros Sachtouris
            'output results in pages (-n to set items per page, default 10)',
159 ed9af02c Stavros Sachtouris
            '--more'),
160 f5f35422 Stavros Sachtouris
        enum=FlagArgument('Enumerate results', '--enumerate'),
161 f5f35422 Stavros Sachtouris
        json_output=FlagArgument('Show results in json', ('-j', '--json'))
162 1ae79e60 Stavros Sachtouris
    )
163 7493ccb6 Stavros Sachtouris
164 f9457c89 Stavros Sachtouris
    def _filtered_by_owner(self, detail, *list_params):
165 f9457c89 Stavros Sachtouris
        images = []
166 f9457c89 Stavros Sachtouris
        MINKEYS = set([
167 f9457c89 Stavros Sachtouris
            'id', 'size', 'status', 'disk_format', 'container_format', 'name'])
168 f9457c89 Stavros Sachtouris
        for img in self.client.list_public(True, *list_params):
169 f9457c89 Stavros Sachtouris
            if img['owner'] == self['owner']:
170 f9457c89 Stavros Sachtouris
                if not detail:
171 f9457c89 Stavros Sachtouris
                    for key in set(img.keys()).difference(MINKEYS):
172 f9457c89 Stavros Sachtouris
                        img.pop(key)
173 f9457c89 Stavros Sachtouris
                images.append(img)
174 f9457c89 Stavros Sachtouris
        return images
175 f9457c89 Stavros Sachtouris
176 faeccbf9 Stavros Sachtouris
    def _filtered_by_name(self, images):
177 faeccbf9 Stavros Sachtouris
        np, ns, nl = self['name_pref'], self['name_suff'], self['name_like']
178 faeccbf9 Stavros Sachtouris
        return [img for img in images if (
179 faeccbf9 Stavros Sachtouris
            (not np) or img['name'].lower().startswith(np.lower())) and (
180 faeccbf9 Stavros Sachtouris
            (not ns) or img['name'].lower().endswith(ns.lower())) and (
181 faeccbf9 Stavros Sachtouris
            (not nl) or nl.lower() in img['name'].lower())]
182 faeccbf9 Stavros Sachtouris
183 a03ade9e Stavros Sachtouris
    @errors.generic.all
184 a03ade9e Stavros Sachtouris
    @errors.cyclades.connection
185 a03ade9e Stavros Sachtouris
    def _run(self):
186 a03ade9e Stavros Sachtouris
        super(self.__class__, self)._run()
187 7493ccb6 Stavros Sachtouris
        filters = {}
188 fa984c2c Stavros Sachtouris
        for arg in set([
189 1ae79e60 Stavros Sachtouris
                'container_format',
190 1ae79e60 Stavros Sachtouris
                'disk_format',
191 1ae79e60 Stavros Sachtouris
                'name',
192 1ae79e60 Stavros Sachtouris
                'size_min',
193 1ae79e60 Stavros Sachtouris
                'size_max',
194 de73876b Stavros Sachtouris
                'status']).intersection(self.arguments):
195 1ae79e60 Stavros Sachtouris
            filters[arg] = self[arg]
196 1ae79e60 Stavros Sachtouris
197 1ae79e60 Stavros Sachtouris
        order = self['order']
198 1ae79e60 Stavros Sachtouris
        detail = self['detail']
199 f9457c89 Stavros Sachtouris
        if self['owner']:
200 f9457c89 Stavros Sachtouris
            images = self._filtered_by_owner(detail, filters, order)
201 f9457c89 Stavros Sachtouris
        else:
202 f9457c89 Stavros Sachtouris
            images = self.client.list_public(detail, filters, order)
203 f9457c89 Stavros Sachtouris
204 f5f35422 Stavros Sachtouris
        if self['json_output']:
205 f5f35422 Stavros Sachtouris
            print_json(images)
206 f5f35422 Stavros Sachtouris
            return
207 f5f35422 Stavros Sachtouris
        images = self._filtered_by_name(images)
208 83c3ba87 Stavros Sachtouris
        if self['more']:
209 83c3ba87 Stavros Sachtouris
            print_items(
210 83c3ba87 Stavros Sachtouris
                images,
211 ed9af02c Stavros Sachtouris
                with_enumeration=self['enum'], page_size=self['limit'] or 10)
212 83c3ba87 Stavros Sachtouris
        elif self['limit']:
213 ed9af02c Stavros Sachtouris
            print_items(images[:self['limit']], with_enumeration=self['enum'])
214 83c3ba87 Stavros Sachtouris
        else:
215 ed9af02c Stavros Sachtouris
            print_items(images, with_enumeration=self['enum'])
216 7493ccb6 Stavros Sachtouris
217 a03ade9e Stavros Sachtouris
    def main(self):
218 a03ade9e Stavros Sachtouris
        super(self.__class__, self)._run()
219 a03ade9e Stavros Sachtouris
        self._run()
220 a03ade9e Stavros Sachtouris
221 234954d1 Stavros Sachtouris
222 d486baec Stavros Sachtouris
@command(image_cmds)
223 7493ccb6 Stavros Sachtouris
class image_meta(_init_image):
224 15142309 Stavros Sachtouris
    """Get image metadata
225 15142309 Stavros Sachtouris
    Image metadata include:
226 439826ec Stavros Sachtouris
    - image file information (location, size, etc.)
227 439826ec Stavros Sachtouris
    - image information (id, name, etc.)
228 439826ec Stavros Sachtouris
    - image os properties (os, fs, etc.)
229 15142309 Stavros Sachtouris
    """
230 7493ccb6 Stavros Sachtouris
231 f5f35422 Stavros Sachtouris
    arguments = dict(
232 f5f35422 Stavros Sachtouris
        json_output=FlagArgument('Show results in json', ('-j', '--json'))
233 f5f35422 Stavros Sachtouris
    )
234 f5f35422 Stavros Sachtouris
235 a03ade9e Stavros Sachtouris
    @errors.generic.all
236 a03ade9e Stavros Sachtouris
    @errors.plankton.connection
237 a03ade9e Stavros Sachtouris
    @errors.plankton.id
238 a03ade9e Stavros Sachtouris
    def _run(self, image_id):
239 f5f35422 Stavros Sachtouris
        printer = print_json if self['json_output'] else print_dict
240 f5f35422 Stavros Sachtouris
        printer(self.client.get_meta(image_id))
241 7493ccb6 Stavros Sachtouris
242 a03ade9e Stavros Sachtouris
    def main(self, image_id):
243 a03ade9e Stavros Sachtouris
        super(self.__class__, self)._run()
244 b04288f7 Stavros Sachtouris
        self._run(image_id=image_id)
245 a03ade9e Stavros Sachtouris
246 234954d1 Stavros Sachtouris
247 d486baec Stavros Sachtouris
@command(image_cmds)
248 7493ccb6 Stavros Sachtouris
class image_register(_init_image):
249 fc903073 Stavros Sachtouris
    """(Re)Register an image"""
250 7493ccb6 Stavros Sachtouris
251 1ae79e60 Stavros Sachtouris
    arguments = dict(
252 1ae79e60 Stavros Sachtouris
        checksum=ValueArgument('set image checksum', '--checksum'),
253 1ae79e60 Stavros Sachtouris
        container_format=ValueArgument(
254 1ae79e60 Stavros Sachtouris
            'set container format',
255 1ae79e60 Stavros Sachtouris
            '--container-format'),
256 1ae79e60 Stavros Sachtouris
        disk_format=ValueArgument('set disk format', '--disk-format'),
257 2dc39c27 Stavros Sachtouris
        #id=ValueArgument('set image ID', '--id'),
258 1ae79e60 Stavros Sachtouris
        owner=ValueArgument('set image owner (admin only)', '--owner'),
259 1ae79e60 Stavros Sachtouris
        properties=KeyValueArgument(
260 1ae79e60 Stavros Sachtouris
            'add property in key=value form (can be repeated)',
261 1736e06d Stavros Sachtouris
            ('-p', '--property')),
262 1ae79e60 Stavros Sachtouris
        is_public=FlagArgument('mark image as public', '--public'),
263 1ae79e60 Stavros Sachtouris
        size=IntArgument('set image size', '--size'),
264 f5f35422 Stavros Sachtouris
        #update=FlagArgument(
265 f5f35422 Stavros Sachtouris
        #    'update existing image properties',
266 f5f35422 Stavros Sachtouris
        #    ('-u', '--update')),
267 623a4ceb Stavros Sachtouris
        json_output=FlagArgument('Show results in json', ('-j', '--json')),
268 623a4ceb Stavros Sachtouris
        property_file=ValueArgument(
269 00336c85 Stavros Sachtouris
            'Load properties from a json-formated file <img-file>.meta :'
270 623a4ceb Stavros Sachtouris
            '{"key1": "val1", "key2": "val2", ...}',
271 00336c85 Stavros Sachtouris
            ('--property-file')),
272 00336c85 Stavros Sachtouris
        prop_file_force=FlagArgument(
273 00336c85 Stavros Sachtouris
            'Store remote property object, even it already exists',
274 00336c85 Stavros Sachtouris
            ('-f', '--force-upload-property-file')),
275 00336c85 Stavros Sachtouris
        no_prop_file_upload=FlagArgument(
276 00336c85 Stavros Sachtouris
            'Do not store properties in remote property file',
277 00336c85 Stavros Sachtouris
            ('--no-property-file-upload')),
278 00336c85 Stavros Sachtouris
        container=ValueArgument(
279 00336c85 Stavros Sachtouris
            'Remote image container', ('-C', '--container')),
280 00336c85 Stavros Sachtouris
        fileowner=ValueArgument(
281 00336c85 Stavros Sachtouris
            'UUID of the user who owns the image file', ('--fileowner'))
282 1ae79e60 Stavros Sachtouris
    )
283 7493ccb6 Stavros Sachtouris
284 00336c85 Stavros Sachtouris
    def _get_uuid(self):
285 00336c85 Stavros Sachtouris
        uuid = self['fileowner'] or self.config.get('image', 'fileowner')
286 00336c85 Stavros Sachtouris
        if uuid:
287 00336c85 Stavros Sachtouris
            return uuid
288 00336c85 Stavros Sachtouris
        atoken = self.client.token
289 00336c85 Stavros Sachtouris
        user = AstakosClient(self.config.get('user', 'url'), atoken)
290 00336c85 Stavros Sachtouris
        return user.term('uuid')
291 00336c85 Stavros Sachtouris
292 00336c85 Stavros Sachtouris
    def _get_pithos_client(self, uuid, container):
293 00336c85 Stavros Sachtouris
        purl = self.config.get('file', 'url')
294 00336c85 Stavros Sachtouris
        ptoken = self.client.token
295 00336c85 Stavros Sachtouris
        return PithosClient(purl, ptoken, uuid, container)
296 00336c85 Stavros Sachtouris
297 00336c85 Stavros Sachtouris
    def _store_remote_property_file(self, pclient, remote_path, properties):
298 00336c85 Stavros Sachtouris
        return pclient.upload_from_string(
299 00336c85 Stavros Sachtouris
            remote_path, _validate_image_props(properties, return_str=True))
300 00336c85 Stavros Sachtouris
301 00336c85 Stavros Sachtouris
    def _get_container_path(self, container_path):
302 00336c85 Stavros Sachtouris
        container = self['container'] or self.config.get('image', 'container')
303 00336c85 Stavros Sachtouris
        if container:
304 00336c85 Stavros Sachtouris
            return container, container_path
305 00336c85 Stavros Sachtouris
306 00336c85 Stavros Sachtouris
        container, sep, path = container_path.partition(':')
307 00336c85 Stavros Sachtouris
        if not sep or not container or not path:
308 00336c85 Stavros Sachtouris
            raiseCLIError(
309 f7a37648 Stavros Sachtouris
                '%s is not a valid pithos+ remote location' % container_path,
310 00336c85 Stavros Sachtouris
                details=[
311 00336c85 Stavros Sachtouris
                    'To set "image" as container and "my_dir/img.diskdump" as',
312 00336c85 Stavros Sachtouris
                    'the image path, try one of the following as '
313 00336c85 Stavros Sachtouris
                    'container:path',
314 00336c85 Stavros Sachtouris
                    '- <image container>:<remote path>',
315 00336c85 Stavros Sachtouris
                    '    e.g. image:/my_dir/img.diskdump',
316 00336c85 Stavros Sachtouris
                    '- <remote path> -C <image container>',
317 00336c85 Stavros Sachtouris
                    '    e.g. /my_dir/img.diskdump -C image'])
318 00336c85 Stavros Sachtouris
        return container, path
319 00336c85 Stavros Sachtouris
320 a03ade9e Stavros Sachtouris
    @errors.generic.all
321 a03ade9e Stavros Sachtouris
    @errors.plankton.connection
322 00336c85 Stavros Sachtouris
    def _run(self, name, container_path):
323 00336c85 Stavros Sachtouris
        container, path = self._get_container_path(container_path)
324 00336c85 Stavros Sachtouris
        uuid = self._get_uuid()
325 00336c85 Stavros Sachtouris
        prop_path = '%s.meta' % path
326 00336c85 Stavros Sachtouris
327 00336c85 Stavros Sachtouris
        pclient = None if (
328 00336c85 Stavros Sachtouris
            self['no_prop_file_upload']) else self._get_pithos_client(
329 00336c85 Stavros Sachtouris
                uuid, container)
330 00336c85 Stavros Sachtouris
        if pclient and not self['prop_file_force']:
331 00336c85 Stavros Sachtouris
            try:
332 00336c85 Stavros Sachtouris
                pclient.get_object_info(prop_path)
333 00336c85 Stavros Sachtouris
                raiseCLIError('Property file %s: %s already exists' % (
334 00336c85 Stavros Sachtouris
                    container, prop_path))
335 00336c85 Stavros Sachtouris
            except ClientError as ce:
336 00336c85 Stavros Sachtouris
                if ce.status != 404:
337 00336c85 Stavros Sachtouris
                    raise
338 00336c85 Stavros Sachtouris
339 00336c85 Stavros Sachtouris
        location = 'pithos://%s/%s/%s' % (uuid, container, path)
340 7493ccb6 Stavros Sachtouris
341 7493ccb6 Stavros Sachtouris
        params = {}
342 f769a16a Stavros Sachtouris
        for key in set([
343 1ae79e60 Stavros Sachtouris
                'checksum',
344 1ae79e60 Stavros Sachtouris
                'container_format',
345 1ae79e60 Stavros Sachtouris
                'disk_format',
346 1ae79e60 Stavros Sachtouris
                'owner',
347 1ae79e60 Stavros Sachtouris
                'size',
348 de73876b Stavros Sachtouris
                'is_public']).intersection(self.arguments):
349 1ae79e60 Stavros Sachtouris
            params[key] = self[key]
350 1ae79e60 Stavros Sachtouris
351 f7a37648 Stavros Sachtouris
        #load properties
352 f7a37648 Stavros Sachtouris
        properties = dict()
353 f7a37648 Stavros Sachtouris
        if self['property_file']:
354 f7a37648 Stavros Sachtouris
            for k, v in _load_image_props(self['property_file']).items():
355 f7a37648 Stavros Sachtouris
                properties[k.lower()] = v
356 f7a37648 Stavros Sachtouris
        for k, v in self['properties'].items():
357 f7a37648 Stavros Sachtouris
            properties[k.lower()] = v
358 f5f35422 Stavros Sachtouris
359 f5f35422 Stavros Sachtouris
        printer = print_json if self['json_output'] else print_dict
360 f5f35422 Stavros Sachtouris
        printer(self.client.register(name, location, params, properties))
361 a03ade9e Stavros Sachtouris
362 00336c85 Stavros Sachtouris
        if pclient:
363 00336c85 Stavros Sachtouris
            prop_headers = pclient.upload_from_string(
364 00336c85 Stavros Sachtouris
                prop_path, _validate_image_props(properties, return_str=True))
365 00336c85 Stavros Sachtouris
            print('Property file location is %s: %s' % (container, prop_path))
366 00336c85 Stavros Sachtouris
            print('\twith version %s' % prop_headers['x-object-version'])
367 00336c85 Stavros Sachtouris
368 00336c85 Stavros Sachtouris
    def main(self, name, container___path):
369 a03ade9e Stavros Sachtouris
        super(self.__class__, self)._run()
370 00336c85 Stavros Sachtouris
        self._run(name, container___path)
371 7493ccb6 Stavros Sachtouris
372 234954d1 Stavros Sachtouris
373 d486baec Stavros Sachtouris
@command(image_cmds)
374 f5f35422 Stavros Sachtouris
class image_unregister(_init_image, _optional_output_cmd):
375 4a17d307 Stavros Sachtouris
    """Unregister an image (does not delete the image file)"""
376 4a17d307 Stavros Sachtouris
377 4a17d307 Stavros Sachtouris
    @errors.generic.all
378 4a17d307 Stavros Sachtouris
    @errors.plankton.connection
379 4a17d307 Stavros Sachtouris
    @errors.plankton.id
380 4a17d307 Stavros Sachtouris
    def _run(self, image_id):
381 f5f35422 Stavros Sachtouris
        self._optional_output(self.client.unregister(image_id))
382 4a17d307 Stavros Sachtouris
383 4a17d307 Stavros Sachtouris
    def main(self, image_id):
384 4a17d307 Stavros Sachtouris
        super(self.__class__, self)._run()
385 4a17d307 Stavros Sachtouris
        self._run(image_id=image_id)
386 4a17d307 Stavros Sachtouris
387 4a17d307 Stavros Sachtouris
388 4a17d307 Stavros Sachtouris
@command(image_cmds)
389 f5f35422 Stavros Sachtouris
class image_shared(_init_image):
390 f5f35422 Stavros Sachtouris
    """List images shared by a member"""
391 f5f35422 Stavros Sachtouris
392 f5f35422 Stavros Sachtouris
    arguments = dict(
393 f5f35422 Stavros Sachtouris
        json_output=FlagArgument('Show results in json', ('-j', '--json'))
394 f5f35422 Stavros Sachtouris
    )
395 7493ccb6 Stavros Sachtouris
396 236e7d08 Stavros Sachtouris
    @errors.generic.all
397 236e7d08 Stavros Sachtouris
    @errors.plankton.connection
398 f5f35422 Stavros Sachtouris
    def _run(self, member):
399 f5f35422 Stavros Sachtouris
        r = self.client.list_shared(member)
400 f5f35422 Stavros Sachtouris
        if self['json_output']:
401 f5f35422 Stavros Sachtouris
            print_json(r)
402 f5f35422 Stavros Sachtouris
        else:
403 f5f35422 Stavros Sachtouris
            print_items(r, title=('image_id',))
404 7493ccb6 Stavros Sachtouris
405 f5f35422 Stavros Sachtouris
    def main(self, member):
406 236e7d08 Stavros Sachtouris
        super(self.__class__, self)._run()
407 f5f35422 Stavros Sachtouris
        self._run(member)
408 236e7d08 Stavros Sachtouris
409 234954d1 Stavros Sachtouris
410 d486baec Stavros Sachtouris
@command(image_cmds)
411 f5f35422 Stavros Sachtouris
class image_members(_init_image):
412 f5f35422 Stavros Sachtouris
    """Manage members. Members of an image are users who can modify it"""
413 f5f35422 Stavros Sachtouris
414 f5f35422 Stavros Sachtouris
415 f5f35422 Stavros Sachtouris
@command(image_cmds)
416 f5f35422 Stavros Sachtouris
class image_members_list(_init_image):
417 f5f35422 Stavros Sachtouris
    """List members of an image"""
418 f5f35422 Stavros Sachtouris
419 f5f35422 Stavros Sachtouris
    arguments = dict(
420 f5f35422 Stavros Sachtouris
        json_output=FlagArgument('Show results in json', ('-j', '--json'))
421 f5f35422 Stavros Sachtouris
    )
422 7493ccb6 Stavros Sachtouris
423 236e7d08 Stavros Sachtouris
    @errors.generic.all
424 236e7d08 Stavros Sachtouris
    @errors.plankton.connection
425 f5f35422 Stavros Sachtouris
    @errors.plankton.id
426 f5f35422 Stavros Sachtouris
    def _run(self, image_id):
427 f5f35422 Stavros Sachtouris
        members = self.client.list_members(image_id)
428 f5f35422 Stavros Sachtouris
        if self['json_output']:
429 f5f35422 Stavros Sachtouris
            print_json(members)
430 f5f35422 Stavros Sachtouris
        else:
431 f5f35422 Stavros Sachtouris
            print_items(members, title=('member_id',), with_redundancy=True)
432 7493ccb6 Stavros Sachtouris
433 f5f35422 Stavros Sachtouris
    def main(self, image_id):
434 236e7d08 Stavros Sachtouris
        super(self.__class__, self)._run()
435 f5f35422 Stavros Sachtouris
        self._run(image_id=image_id)
436 236e7d08 Stavros Sachtouris
437 234954d1 Stavros Sachtouris
438 d486baec Stavros Sachtouris
@command(image_cmds)
439 f5f35422 Stavros Sachtouris
class image_members_add(_init_image, _optional_output_cmd):
440 7493ccb6 Stavros Sachtouris
    """Add a member to an image"""
441 7493ccb6 Stavros Sachtouris
442 236e7d08 Stavros Sachtouris
    @errors.generic.all
443 236e7d08 Stavros Sachtouris
    @errors.plankton.connection
444 236e7d08 Stavros Sachtouris
    @errors.plankton.id
445 b04288f7 Stavros Sachtouris
    def _run(self, image_id=None, member=None):
446 f5f35422 Stavros Sachtouris
            self._optional_output(self.client.add_member(image_id, member))
447 236e7d08 Stavros Sachtouris
448 236e7d08 Stavros Sachtouris
    def main(self, image_id, member):
449 236e7d08 Stavros Sachtouris
        super(self.__class__, self)._run()
450 b04288f7 Stavros Sachtouris
        self._run(image_id=image_id, member=member)
451 7493ccb6 Stavros Sachtouris
452 234954d1 Stavros Sachtouris
453 d486baec Stavros Sachtouris
@command(image_cmds)
454 f5f35422 Stavros Sachtouris
class image_members_delete(_init_image, _optional_output_cmd):
455 7493ccb6 Stavros Sachtouris
    """Remove a member from an image"""
456 7493ccb6 Stavros Sachtouris
457 236e7d08 Stavros Sachtouris
    @errors.generic.all
458 236e7d08 Stavros Sachtouris
    @errors.plankton.connection
459 236e7d08 Stavros Sachtouris
    @errors.plankton.id
460 b04288f7 Stavros Sachtouris
    def _run(self, image_id=None, member=None):
461 f5f35422 Stavros Sachtouris
            self._optional_output(self.client.remove_member(image_id, member))
462 236e7d08 Stavros Sachtouris
463 236e7d08 Stavros Sachtouris
    def main(self, image_id, member):
464 236e7d08 Stavros Sachtouris
        super(self.__class__, self)._run()
465 b04288f7 Stavros Sachtouris
        self._run(image_id=image_id, member=member)
466 7493ccb6 Stavros Sachtouris
467 234954d1 Stavros Sachtouris
468 d486baec Stavros Sachtouris
@command(image_cmds)
469 f5f35422 Stavros Sachtouris
class image_members_set(_init_image, _optional_output_cmd):
470 7493ccb6 Stavros Sachtouris
    """Set the members of an image"""
471 7493ccb6 Stavros Sachtouris
472 236e7d08 Stavros Sachtouris
    @errors.generic.all
473 236e7d08 Stavros Sachtouris
    @errors.plankton.connection
474 236e7d08 Stavros Sachtouris
    @errors.plankton.id
475 b04288f7 Stavros Sachtouris
    def _run(self, image_id, members):
476 f5f35422 Stavros Sachtouris
            self._optional_output(self.client.set_members(image_id, members))
477 236e7d08 Stavros Sachtouris
478 236e7d08 Stavros Sachtouris
    def main(self, image_id, *members):
479 236e7d08 Stavros Sachtouris
        super(self.__class__, self)._run()
480 b04288f7 Stavros Sachtouris
        self._run(image_id=image_id, members=members)
481 f3e94e06 Stavros Sachtouris
482 f3e94e06 Stavros Sachtouris
483 573be34f Stavros Sachtouris
# Compute Image Commands
484 573be34f Stavros Sachtouris
485 573be34f Stavros Sachtouris
486 d486baec Stavros Sachtouris
@command(image_cmds)
487 8741c407 Stavros Sachtouris
class image_compute(_init_cyclades):
488 a29d2f88 Stavros Sachtouris
    """Cyclades/Compute API image commands"""
489 8741c407 Stavros Sachtouris
490 8741c407 Stavros Sachtouris
491 8741c407 Stavros Sachtouris
@command(image_cmds)
492 8741c407 Stavros Sachtouris
class image_compute_list(_init_cyclades):
493 f3e94e06 Stavros Sachtouris
    """List images"""
494 f3e94e06 Stavros Sachtouris
495 1ae79e60 Stavros Sachtouris
    arguments = dict(
496 f40f0cb7 Stavros Sachtouris
        detail=FlagArgument('show detailed output', ('-l', '--details')),
497 f40f0cb7 Stavros Sachtouris
        limit=IntArgument('limit number listed images', ('-n', '--number')),
498 15142309 Stavros Sachtouris
        more=FlagArgument(
499 15142309 Stavros Sachtouris
            'output results in pages (-n to set items per page, default 10)',
500 ed9af02c Stavros Sachtouris
            '--more'),
501 f5f35422 Stavros Sachtouris
        enum=FlagArgument('Enumerate results', '--enumerate'),
502 f5f35422 Stavros Sachtouris
        json_output=FlagArgument('Show results in json', ('-j', '--json'))
503 1ae79e60 Stavros Sachtouris
    )
504 f3e94e06 Stavros Sachtouris
505 15142309 Stavros Sachtouris
    def _make_results_pretty(self, images):
506 f3e94e06 Stavros Sachtouris
        for img in images:
507 15142309 Stavros Sachtouris
            if 'metadata' in img:
508 15142309 Stavros Sachtouris
                img['metadata'] = img['metadata']['values']
509 f3e94e06 Stavros Sachtouris
510 236e7d08 Stavros Sachtouris
    @errors.generic.all
511 236e7d08 Stavros Sachtouris
    @errors.cyclades.connection
512 236e7d08 Stavros Sachtouris
    def _run(self):
513 236e7d08 Stavros Sachtouris
        images = self.client.list_images(self['detail'])
514 f5f35422 Stavros Sachtouris
        if self['json_output']:
515 f5f35422 Stavros Sachtouris
            print_json(images)
516 f5f35422 Stavros Sachtouris
            return
517 236e7d08 Stavros Sachtouris
        if self['detail']:
518 236e7d08 Stavros Sachtouris
            self._make_results_pretty(images)
519 236e7d08 Stavros Sachtouris
        if self['more']:
520 ed9af02c Stavros Sachtouris
            print_items(
521 ed9af02c Stavros Sachtouris
                images,
522 ed9af02c Stavros Sachtouris
                page_size=self['limit'] or 10, with_enumeration=self['enum'])
523 236e7d08 Stavros Sachtouris
        else:
524 ed9af02c Stavros Sachtouris
            print_items(images[:self['limit']], with_enumeration=self['enum'])
525 236e7d08 Stavros Sachtouris
526 f3e94e06 Stavros Sachtouris
    def main(self):
527 236e7d08 Stavros Sachtouris
        super(self.__class__, self)._run()
528 236e7d08 Stavros Sachtouris
        self._run()
529 f3e94e06 Stavros Sachtouris
530 234954d1 Stavros Sachtouris
531 d486baec Stavros Sachtouris
@command(image_cmds)
532 8741c407 Stavros Sachtouris
class image_compute_info(_init_cyclades):
533 15142309 Stavros Sachtouris
    """Get detailed information on an image"""
534 f3e94e06 Stavros Sachtouris
535 f5f35422 Stavros Sachtouris
    arguments = dict(
536 f5f35422 Stavros Sachtouris
        json_output=FlagArgument('Show results in json', ('-j', '--json'))
537 f5f35422 Stavros Sachtouris
    )
538 f5f35422 Stavros Sachtouris
539 236e7d08 Stavros Sachtouris
    @errors.generic.all
540 236e7d08 Stavros Sachtouris
    @errors.cyclades.connection
541 236e7d08 Stavros Sachtouris
    @errors.plankton.id
542 236e7d08 Stavros Sachtouris
    def _run(self, image_id):
543 236e7d08 Stavros Sachtouris
        image = self.client.get_image_details(image_id)
544 f5f35422 Stavros Sachtouris
        if self['json_output']:
545 f5f35422 Stavros Sachtouris
            print_json(image)
546 f5f35422 Stavros Sachtouris
            return
547 234954d1 Stavros Sachtouris
        if 'metadata' in image:
548 f3e94e06 Stavros Sachtouris
            image['metadata'] = image['metadata']['values']
549 236e7d08 Stavros Sachtouris
        print_dict(image)
550 f3e94e06 Stavros Sachtouris
551 f3e94e06 Stavros Sachtouris
    def main(self, image_id):
552 236e7d08 Stavros Sachtouris
        super(self.__class__, self)._run()
553 b04288f7 Stavros Sachtouris
        self._run(image_id=image_id)
554 f3e94e06 Stavros Sachtouris
555 234954d1 Stavros Sachtouris
556 d486baec Stavros Sachtouris
@command(image_cmds)
557 f5f35422 Stavros Sachtouris
class image_compute_delete(_init_cyclades, _optional_output_cmd):
558 24ff0a35 Stavros Sachtouris
    """Delete an image (WARNING: image file is also removed)"""
559 f3e94e06 Stavros Sachtouris
560 236e7d08 Stavros Sachtouris
    @errors.generic.all
561 236e7d08 Stavros Sachtouris
    @errors.cyclades.connection
562 236e7d08 Stavros Sachtouris
    @errors.plankton.id
563 236e7d08 Stavros Sachtouris
    def _run(self, image_id):
564 f5f35422 Stavros Sachtouris
        self._optional_output(self.client.delete_image(image_id))
565 236e7d08 Stavros Sachtouris
566 f3e94e06 Stavros Sachtouris
    def main(self, image_id):
567 236e7d08 Stavros Sachtouris
        super(self.__class__, self)._run()
568 b04288f7 Stavros Sachtouris
        self._run(image_id=image_id)
569 f3e94e06 Stavros Sachtouris
570 234954d1 Stavros Sachtouris
571 d486baec Stavros Sachtouris
@command(image_cmds)
572 8741c407 Stavros Sachtouris
class image_compute_properties(_init_cyclades):
573 395fbf9e Stavros Sachtouris
    """Manage properties related to OS installation in an image"""
574 f5f35422 Stavros Sachtouris
575 f5f35422 Stavros Sachtouris
576 f5f35422 Stavros Sachtouris
@command(image_cmds)
577 f5f35422 Stavros Sachtouris
class image_compute_properties_list(_init_cyclades):
578 f5f35422 Stavros Sachtouris
    """List all image properties"""
579 f5f35422 Stavros Sachtouris
580 f5f35422 Stavros Sachtouris
    arguments = dict(
581 f5f35422 Stavros Sachtouris
        json_output=FlagArgument('Show results in json', ('-j', '--json'))
582 f5f35422 Stavros Sachtouris
    )
583 f5f35422 Stavros Sachtouris
584 f5f35422 Stavros Sachtouris
    @errors.generic.all
585 f5f35422 Stavros Sachtouris
    @errors.cyclades.connection
586 f5f35422 Stavros Sachtouris
    @errors.plankton.id
587 f5f35422 Stavros Sachtouris
    def _run(self, image_id):
588 f5f35422 Stavros Sachtouris
        printer = print_json if self['json_output'] else print_dict
589 f5f35422 Stavros Sachtouris
        printer(self.client.get_image_metadata(image_id))
590 f5f35422 Stavros Sachtouris
591 f5f35422 Stavros Sachtouris
    def main(self, image_id):
592 f5f35422 Stavros Sachtouris
        super(self.__class__, self)._run()
593 f5f35422 Stavros Sachtouris
        self._run(image_id=image_id)
594 f5f35422 Stavros Sachtouris
595 f5f35422 Stavros Sachtouris
596 f5f35422 Stavros Sachtouris
@command(image_cmds)
597 f5f35422 Stavros Sachtouris
class image_compute_properties_get(_init_cyclades):
598 f5f35422 Stavros Sachtouris
    """Get an image property"""
599 f5f35422 Stavros Sachtouris
600 f5f35422 Stavros Sachtouris
    arguments = dict(
601 f5f35422 Stavros Sachtouris
        json_output=FlagArgument('Show results in json', ('-j', '--json'))
602 f5f35422 Stavros Sachtouris
    )
603 f3e94e06 Stavros Sachtouris
604 236e7d08 Stavros Sachtouris
    @errors.generic.all
605 236e7d08 Stavros Sachtouris
    @errors.cyclades.connection
606 236e7d08 Stavros Sachtouris
    @errors.plankton.id
607 236e7d08 Stavros Sachtouris
    @errors.plankton.metadata
608 236e7d08 Stavros Sachtouris
    def _run(self, image_id, key):
609 f5f35422 Stavros Sachtouris
        printer = print_json if self['json_output'] else print_dict
610 f5f35422 Stavros Sachtouris
        printer(self.client.get_image_metadata(image_id, key))
611 236e7d08 Stavros Sachtouris
612 f5f35422 Stavros Sachtouris
    def main(self, image_id, key):
613 236e7d08 Stavros Sachtouris
        super(self.__class__, self)._run()
614 b04288f7 Stavros Sachtouris
        self._run(image_id=image_id, key=key)
615 f3e94e06 Stavros Sachtouris
616 234954d1 Stavros Sachtouris
617 d486baec Stavros Sachtouris
@command(image_cmds)
618 f5f35422 Stavros Sachtouris
class image_compute_properties_add(_init_cyclades):
619 f5f35422 Stavros Sachtouris
    """Add a property to an image"""
620 f5f35422 Stavros Sachtouris
621 f5f35422 Stavros Sachtouris
    arguments = dict(
622 f5f35422 Stavros Sachtouris
        json_output=FlagArgument('Show results in json', ('-j', '--json'))
623 f5f35422 Stavros Sachtouris
    )
624 f3e94e06 Stavros Sachtouris
625 236e7d08 Stavros Sachtouris
    @errors.generic.all
626 236e7d08 Stavros Sachtouris
    @errors.cyclades.connection
627 236e7d08 Stavros Sachtouris
    @errors.plankton.id
628 b04288f7 Stavros Sachtouris
    @errors.plankton.metadata
629 236e7d08 Stavros Sachtouris
    def _run(self, image_id, key, val):
630 f5f35422 Stavros Sachtouris
        printer = print_json if self['json_output'] else print_dict
631 f5f35422 Stavros Sachtouris
        printer(self.client.create_image_metadata(image_id, key, val))
632 236e7d08 Stavros Sachtouris
633 f3e94e06 Stavros Sachtouris
    def main(self, image_id, key, val):
634 236e7d08 Stavros Sachtouris
        super(self.__class__, self)._run()
635 b04288f7 Stavros Sachtouris
        self._run(image_id=image_id, key=key, val=val)
636 f3e94e06 Stavros Sachtouris
637 234954d1 Stavros Sachtouris
638 d486baec Stavros Sachtouris
@command(image_cmds)
639 f5f35422 Stavros Sachtouris
class image_compute_properties_set(_init_cyclades):
640 f5f35422 Stavros Sachtouris
    """Add / update a set of properties for an image
641 f5f35422 Stavros Sachtouris
    proeprties must be given in the form key=value, e.v.
642 f5f35422 Stavros Sachtouris
    /image compute properties set <image-id> key1=val1 key2=val2
643 f5f35422 Stavros Sachtouris
    """
644 f5f35422 Stavros Sachtouris
    arguments = dict(
645 f5f35422 Stavros Sachtouris
        json_output=FlagArgument('Show results in json', ('-j', '--json'))
646 f5f35422 Stavros Sachtouris
    )
647 f3e94e06 Stavros Sachtouris
648 236e7d08 Stavros Sachtouris
    @errors.generic.all
649 236e7d08 Stavros Sachtouris
    @errors.cyclades.connection
650 236e7d08 Stavros Sachtouris
    @errors.plankton.id
651 f5f35422 Stavros Sachtouris
    def _run(self, image_id, keyvals):
652 f5f35422 Stavros Sachtouris
        metadata = dict()
653 f5f35422 Stavros Sachtouris
        for keyval in keyvals:
654 f5f35422 Stavros Sachtouris
            key, val = keyval.split('=')
655 f5f35422 Stavros Sachtouris
            metadata[key] = val
656 f5f35422 Stavros Sachtouris
        printer = print_json if self['json_output'] else print_dict
657 f5f35422 Stavros Sachtouris
        printer(self.client.update_image_metadata(image_id, **metadata))
658 f5f35422 Stavros Sachtouris
659 f5f35422 Stavros Sachtouris
    def main(self, image_id, *key_equals_value):
660 236e7d08 Stavros Sachtouris
        super(self.__class__, self)._run()
661 f5f35422 Stavros Sachtouris
        self._run(image_id=image_id, keyvals=key_equals_value)
662 f3e94e06 Stavros Sachtouris
663 234954d1 Stavros Sachtouris
664 d486baec Stavros Sachtouris
@command(image_cmds)
665 f5f35422 Stavros Sachtouris
class image_compute_properties_delete(_init_cyclades, _optional_output_cmd):
666 f5f35422 Stavros Sachtouris
    """Delete a property from an image"""
667 f3e94e06 Stavros Sachtouris
668 236e7d08 Stavros Sachtouris
    @errors.generic.all
669 236e7d08 Stavros Sachtouris
    @errors.cyclades.connection
670 236e7d08 Stavros Sachtouris
    @errors.plankton.id
671 236e7d08 Stavros Sachtouris
    @errors.plankton.metadata
672 236e7d08 Stavros Sachtouris
    def _run(self, image_id, key):
673 f5f35422 Stavros Sachtouris
        self._optional_output(self.client.delete_image_metadata(image_id, key))
674 236e7d08 Stavros Sachtouris
675 f3e94e06 Stavros Sachtouris
    def main(self, image_id, key):
676 236e7d08 Stavros Sachtouris
        super(self.__class__, self)._run()
677 b04288f7 Stavros Sachtouris
        self._run(image_id=image_id, key=key)