Statistics
| Branch: | Tag: | Revision:

root / kamaki / cli / commands / image_cli.py @ 939ef0f6

History | View | Annotate | Download (11.6 kB)

1
# Copyright 2012 GRNET S.A. All rights reserved.
2
#
3
# Redistribution and use in source and binary forms, with or
4
# without modification, are permitted provided that the following
5
# conditions are met:
6
#
7
#   1. Redistributions of source code must retain the above
8
#      copyright notice, this list of conditions and the following
9
#      disclaimer.
10
#
11
#   2. Redistributions in binary form must reproduce the above
12
#      copyright notice, this list of conditions and the following
13
#      disclaimer in the documentation and/or other materials
14
#      provided with the distribution.
15
#
16
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
17
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
20
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27
# POSSIBILITY OF SUCH DAMAGE.
28
#
29
# The views and conclusions contained in the software and
30
# documentation are those of the authors and should not be
31
# interpreted as representing official policies, either expressed
32
# or implied, of GRNET S.A.command
33

    
34
from kamaki.cli import command
35
from kamaki.cli.command_tree import CommandTree
36
from kamaki.cli.errors import raiseCLIError
37
from kamaki.cli.utils import print_dict, print_items, bold
38
from kamaki.clients.image import ImageClient, ClientError
39
from kamaki.cli.argument import\
40
    FlagArgument, ValueArgument, KeyValueArgument, IntArgument
41
from kamaki.cli.commands.cyclades_cli import _init_cyclades
42
from kamaki.cli.commands import _command_init
43

    
44

    
45
image_cmds = CommandTree('image',
46
    'Compute/Cyclades or Glance API image commands')
47
_commands = [image_cmds]
48

    
49

    
50
class _init_image(_command_init):
51
    def main(self):
52
        try:
53
            token = self.config.get('image', 'token')\
54
                or self.config.get('compute', 'token')\
55
                or self.config.get('global', 'token')
56
            base_url = self.config.get('image', 'url')\
57
                or self.config.get('compute', 'url')\
58
                or self.config.get('global', 'url')
59
            self.client = ImageClient(base_url=base_url, token=token)
60
        except ClientError as err:
61
            raiseCLIError(err)
62

    
63

    
64
@command(image_cmds)
65
class image_public(_init_image):
66
    """List public images"""
67

    
68
    def __init__(self, arguments={}):
69
        super(image_public, self).__init__(arguments)
70
        self.arguments['detail'] = FlagArgument('show detailed output', '-l')
71
        self.arguments['container_format'] =\
72
            ValueArgument('filter by container format', '--container-format')
73
        self.arguments['disk_format'] =\
74
            ValueArgument('filter by disk format', '--disk-format')
75
        self.arguments['name'] = ValueArgument('filter by name', '--name')
76
        self.arguments['size_min'] =\
77
            IntArgument('filter by minimum size', '--size-min')
78
        self.arguments['size_max'] =\
79
            IntArgument('filter by maximum size', '--size-max')
80
        self.arguments['status'] =\
81
            ValueArgument('filter by status', '--status')
82
        self.arguments['order'] =\
83
            ValueArgument('order by FIELD (use a - prefix to reverse order)',
84
            '--order', default='')
85

    
86
    def main(self):
87
        super(self.__class__, self).main()
88
        filters = {}
89
        for arg in ('container_format',
90
            'disk_format',
91
            'name',
92
            'size_min',
93
            'size_max',
94
            'status'):
95
            val = self.get_argument(arg)
96
            if val is not None:
97
                filters[arg] = val
98

    
99
        order = self.get_argument('order')
100
        detail = self.get_argument('detail')
101
        try:
102
            images = self.client.list_public(detail, filters, order)
103
        except ClientError as err:
104
            raiseCLIError(err)
105
        print_items(images, title=('name',))
106

    
107

    
108
@command(image_cmds)
109
class image_meta(_init_image):
110
    """Get image metadata"""
111

    
112
    def main(self, image_id):
113
        super(self.__class__, self).main()
114
        try:
115
            image = self.client.get_meta(image_id)
116
        except ClientError as err:
117
            raiseCLIError(err)
118
        print_dict(image)
119

    
120

    
121
@command(image_cmds)
122
class image_register(_init_image):
123
    """(Re)Register an image
124
        call with --update or without an image name to update image properties
125
    """
126

    
127
    def __init__(self, arguments={}):
128
        super(image_register, self).__init__(arguments)
129
        self.arguments['checksum'] =\
130
            ValueArgument('set image checksum', '--checksum')
131
        self.arguments['container_format'] =\
132
            ValueArgument('set container format', '--container-format')
133
        self.arguments['disk_format'] =\
134
            ValueArgument('set disk format', '--disk-format')
135
        self.arguments['id'] = ValueArgument('set image ID', '--id')
136
        self.arguments['owner'] =\
137
            ValueArgument('set image owner (admin only)', '--owner')
138
        self.arguments['properties'] =\
139
            KeyValueArgument(parsed_name='--property',
140
            help='add property in key=value form (can be repeated)')
141
        self.arguments['is_public'] =\
142
            FlagArgument('mark image as public', '--public')
143
        self.arguments['size'] = IntArgument('set image size', '--size')
144
        self.arguments['update'] = FlagArgument(
145
            'update an existing image properties', '--update')
146

    
147
    def main(self, location, name=None):
148
        super(self.__class__, self).main()
149
        if not location.startswith('pithos://'):
150
            account = self.config.get('store', 'account') \
151
                or self.config.get('global', 'account')
152
            if account[-1] == '/':
153
                account = account[:-1]
154
            container = self.config.get('store', 'container') \
155
                or self.config.get('global', 'container')
156
            if container is None or len(container) == 0:
157
                location = 'pithos://%s/%s' % (account, location)
158
            else:
159
                location = 'pithos://%s/%s/%s' % (account, container, location)
160

    
161
        params = {}
162
        for key in ('checksum',
163
            'container_format',
164
            'disk_format', 'id',
165
            'owner',
166
            'size',
167
            'is_public'):
168
            val = self.get_argument(key)
169
            if val is not None:
170
                params[key] = val
171

    
172
        update = self.get_argument('update')
173
        properties = self.get_argument('properties')
174
        try:
175
            if name and not update:
176
                self.client.register(name, location, params, properties)
177
            else:
178
                self.client.reregister(location, name, params, properties)
179
        except ClientError as err:
180
            raiseCLIError(err)
181

    
182

    
183
@command(image_cmds)
184
class image_members(_init_image):
185
    """Get image members"""
186

    
187
    def main(self, image_id):
188
        super(self.__class__, self).main()
189
        try:
190
            members = self.client.list_members(image_id)
191
        except ClientError as err:
192
            raiseCLIError(err)
193
        for member in members:
194
            print(member['member_id'])
195

    
196

    
197
@command(image_cmds)
198
class image_shared(_init_image):
199
    """List shared images"""
200

    
201
    def main(self, member):
202
        super(self.__class__, self).main()
203
        try:
204
            images = self.client.list_shared(member)
205
        except ClientError as err:
206
            raiseCLIError(err)
207
        for image in images:
208
            print(image['image_id'])
209

    
210

    
211
@command(image_cmds)
212
class image_addmember(_init_image):
213
    """Add a member to an image"""
214

    
215
    def main(self, image_id, member):
216
        super(self.__class__, self).main()
217
        try:
218
            self.client.add_member(image_id, member)
219
        except ClientError as err:
220
            raiseCLIError(err)
221

    
222

    
223
@command(image_cmds)
224
class image_delmember(_init_image):
225
    """Remove a member from an image"""
226

    
227
    def main(self, image_id, member):
228
        super(self.__class__, self).main()
229
        try:
230
            self.client.remove_member(image_id, member)
231
        except ClientError as err:
232
            raiseCLIError(err)
233

    
234

    
235
@command(image_cmds)
236
class image_setmembers(_init_image):
237
    """Set the members of an image"""
238

    
239
    def main(self, image_id, *member):
240
        super(self.__class__, self).main()
241
        try:
242
            self.client.set_members(image_id, member)
243
        except ClientError as err:
244
            raiseCLIError(err)
245

    
246

    
247
@command(image_cmds)
248
class image_list(_init_cyclades):
249
    """List images"""
250

    
251
    def __init__(self, arguments={}):
252
        super(image_list, self).__init__(arguments)
253
        self.arguments['detail'] = FlagArgument('show detailed output', '-l')
254

    
255
    def _print(self, images):
256
        for img in images:
257
            iname = img.pop('name')
258
            iid = img.pop('id')
259
            print('%s (%s)' % (unicode(iid), bold(iname)))
260
            if self.get_argument('detail'):
261
                if 'metadata' in img:
262
                    img['metadata'] = img['metadata']['values']
263
                print_dict(img, ident=2)
264
            print(' ')
265

    
266
    def main(self):
267
        super(self.__class__, self).main()
268
        try:
269
            images = self.client.list_images(self.get_argument('detail'))
270
        except ClientError as err:
271
            raiseCLIError(err)
272
        self._print(images)
273

    
274

    
275
@command(image_cmds)
276
class image_info(_init_cyclades):
277
    """Get image details"""
278

    
279
    @classmethod
280
    def _print(self, image):
281
        if 'metadata' in image:
282
            image['metadata'] = image['metadata']['values']
283
        print_dict(image)
284

    
285
    def main(self, image_id):
286
        super(self.__class__, self).main()
287
        try:
288
            image = self.client.get_image_details(image_id)
289
        except ClientError as err:
290
            raiseCLIError(err)
291
        self._print(image)
292

    
293

    
294
@command(image_cmds)
295
class image_delete(_init_cyclades):
296
    """Delete image"""
297

    
298
    def main(self, image_id):
299
        super(self.__class__, self).main()
300
        try:
301
            self.client.delete_image(image_id)
302
        except ClientError as err:
303
            raiseCLIError(err)
304

    
305

    
306
@command(image_cmds)
307
class image_properties(_init_cyclades):
308
    """Get image properties"""
309

    
310
    def main(self, image_id, key=None):
311
        super(self.__class__, self).main()
312
        try:
313
            reply = self.client.get_image_metadata(image_id, key)
314
        except ClientError as err:
315
            raiseCLIError(err)
316
        print_dict(reply)
317

    
318

    
319
@command(image_cmds)
320
class image_addproperty(_init_cyclades):
321
    """Add an image property"""
322

    
323
    def main(self, image_id, key, val):
324
        super(self.__class__, self).main()
325
        try:
326
            reply = self.client.create_image_metadata(image_id, key, val)
327
        except ClientError as err:
328
            raiseCLIError(err)
329
        print_dict(reply)
330

    
331

    
332
@command(image_cmds)
333
class image_setproperty(_init_cyclades):
334
    """Update an image property"""
335

    
336
    def main(self, image_id, key, val):
337
        super(self.__class__, self).main()
338
        metadata = {key: val}
339
        try:
340
            reply = self.client.update_image_metadata(image_id, **metadata)
341
        except ClientError as err:
342
            raiseCLIError(err)
343
        print_dict(reply)
344

    
345

    
346
@command(image_cmds)
347
class image_delproperty(_init_cyclades):
348
    """Delete an image property"""
349

    
350
    def main(self, image_id, key):
351
        super(self.__class__, self).main()
352
        try:
353
            self.client.delete_image_metadata(image_id, key)
354
        except ClientError as err:
355
            raiseCLIError(err)