Statistics
| Branch: | Tag: | Revision:

root / kamaki / cli / commands / image_cli.py @ 03fd7ddb

History | View | Annotate | Download (10.4 kB)

1
# Copyright 2011-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
API_DESCRIPTION = {'image':'Compute/Cyclades or Glance API image commands'}
35

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

    
44
class _init_image(_command_init):
45
    def main(self):
46
        try:
47
            token = self.config.get('image', 'token') or self.config.get('global', 'token')
48
            base_url = self.config.get('image', 'url') or self.config.get('global', 'url')
49
            self.client = ImageClient(base_url=base_url, token=token)
50
        except ClientError as err:
51
            raiseCLIError(err)
52

    
53
@command()
54
class image_public(_init_image):
55
    """List public images"""
56

    
57
    def __init__(self, arguments={}):
58
        super(image_public, self).__init__(arguments)
59
        self.arguments['detail'] = FlagArgument('show detailed output', '-l')
60
        self.arguments['container_format'] = ValueArgument('filter by container format',
61
            '--container-format')
62
        self.arguments['disk_format'] = ValueArgument('filter by disk format', '--disk-format')
63
        self.arguments['name'] = ValueArgument('filter by name', '--name')
64
        self.arguments['size_min'] = IntArgument('filter by minimum size', '--size-min')
65
        self.arguments['size_max'] = IntArgument('filter by maximum size', '--size-max')
66
        self.arguments['status'] = ValueArgument('filter by status', '--status')
67
        self.arguments['order'] = ValueArgument('order by FIELD (use a - prefix to reverse order)',
68
            '--order', default='')
69

    
70
    def main(self):
71
        super(self.__class__, self).main()
72
        filters = {}
73
        for arg in ('container_format', 'disk_format', 'name', 'size_min', 'size_max', 'status'):
74
            val = self.get_argument(arg)
75
            if val is not None:
76
                filters[arg] = val
77

    
78
        order = self.get_argument('order')
79
        try:
80
            images = self.client.list_public(self.get_argument('detail'), filters=filters,
81
                order=order)
82
        except ClientError as err:
83
            raiseCLIError(err)
84
        print_items(images, title=('name',))
85

    
86
@command()
87
class image_meta(_init_image):
88
    """Get image metadata"""
89

    
90
    def main(self, image_id):
91
        super(self.__class__, self).main()
92
        try:
93
            image = self.client.get_meta(image_id)
94
        except ClientError as err:
95
            raiseCLIError(err)
96
        print_dict(image)
97

    
98
@command()
99
class image_register(_init_image):
100
    """Register an image"""
101

    
102
    def __init__(self, arguments={}):
103
        super(image_register, self).__init__(arguments)
104
        self.arguments['checksum'] = ValueArgument('set image checksum', '--checksum')
105
        self.arguments['container_format'] = ValueArgument('set container format',
106
            '--container-format')
107
        self.arguments['disk_format'] = ValueArgument('set disk format', '--disk-format')
108
        self.arguments['id'] = ValueArgument('set image ID', '--id')
109
        self.arguments['owner'] = ValueArgument('set image owner (admin only)', '--owner')
110
        self.arguments['properties'] = KeyValueArgument(parsed_name='--properties',
111
            help = 'add properties in the form "key1=val1 key2=val2 ..."')
112
        self.arguments['is_public'] = FlagArgument('mark image as public', '--public')
113
        self.arguments['size'] = IntArgument('set image size', '--size')
114

    
115
    def main(self, name, location):
116
        super(self.__class__, self).main()
117
        if not location.startswith('pithos://'):
118
            account = self.config.get('store', 'account') \
119
                or self.config.get('global', 'account')
120
            if account[-1] == '/':
121
                account = account[:-1]
122
            container = self.config.get('store', 'container') \
123
                or self.config.get('global', 'container')
124
            location = 'pithos://%s/%s'%(account, location) \
125
                if container is None or len(container) == 0 \
126
                else 'pithos://%s/%s/%s' % (account, container, location)
127

    
128
        params = {}
129
        for key in ('checksum','container_format','disk_format','id','owner','size','is_public'):
130
            val = self.get_argument(key)
131
            if val is not None:
132
                params[key] = val
133

    
134
        try:
135
            self.client.register(name, location, params, self.get_argument('properties'))
136
        except ClientError as err:
137
            raiseCLIError(err)
138

    
139
@command()
140
class image_members(_init_image):
141
    """Get image members"""
142

    
143
    def main(self, image_id):
144
        super(self.__class__, self).main()
145
        try:
146
            members = self.client.list_members(image_id)
147
        except ClientError as err:
148
            raiseCLIError(err)
149
        for member in members:
150
            print(member['member_id'])
151

    
152
@command()
153
class image_shared(_init_image):
154
    """List shared images"""
155

    
156
    def main(self, member):
157
        super(self.__class__, self).main()
158
        try:
159
            images = self.client.list_shared(member)
160
        except ClientError as err:
161
            raiseCLIError(err)
162
        for image in images:
163
            print(image['image_id'])
164

    
165
@command()
166
class image_addmember(_init_image):
167
    """Add a member to an image"""
168

    
169
    def main(self, image_id, member):
170
        super(self.__class__, self).main()
171
        try:
172
            self.client.add_member(image_id, member)
173
        except ClientError as err:
174
            raiseCLIError(err)
175

    
176
@command()
177
class image_delmember(_init_image):
178
    """Remove a member from an image"""
179

    
180
    def main(self, image_id, member):
181
        super(self.__class__, self).main()
182
        try:
183
            self.client.remove_member(image_id, member)
184
        except ClientError as err:
185
            raiseCLIError(err)
186

    
187
@command()
188
class image_setmembers(_init_image):
189
    """Set the members of an image"""
190

    
191
    def main(self, image_id, *member):
192
        super(self.__class__, self).main()
193
        try:
194
            self.client.set_members(image_id, member)
195
        except ClientError as err:
196
            raiseCLIError(err)
197

    
198

    
199
@command()
200
class image_list(_init_cyclades):
201
    """List images"""
202

    
203
    def __init__(self, arguments={}):
204
        super(image_list, self).__init__(arguments)
205
        self.arguments['detail'] = FlagArgument('show detailed output', '-l')
206

    
207
    def _print(self, images):
208
        for img in images:
209
            iname = img.pop('name')
210
            iid = img.pop('id')
211
            print('%s (%s)'%(bold(iname), bold(unicode(iid))))
212
            if self.get_argument('detail'):
213
                image_info._print(img)
214

    
215
    def main(self):
216
        super(self.__class__, self).main()
217
        try:
218
            images = self.client.list_images(self.get_argument('detail'))
219
        except ClientError as err:
220
            raiseCLIError(err)
221
        self._print(images)
222

    
223
@command()
224
class image_info(_init_cyclades):
225
    """Get image details"""
226

    
227
    @classmethod
228
    def _print(self, image):
229
        if image.has_key('metadata'):
230
            image['metadata'] = image['metadata']['values']
231
        print_dict(image, ident=14)
232

    
233
    def main(self, image_id):
234
        super(self.__class__, self).main()
235
        try:
236
            image = self.client.get_image_details(image_id)
237
        except ClientError as err:
238
            raiseCLIError(err)
239
        self._print(image)
240

    
241
@command()
242
class image_delete(_init_cyclades):
243
    """Delete image"""
244

    
245
    def main(self, image_id):
246
        super(self.__class__, self).main()
247
        try:
248
            self.client.delete_image(image_id)
249
        except ClientError as err:
250
            raiseCLIError(err)
251

    
252
@command()
253
class image_properties(_init_cyclades):
254
    """Get image properties"""
255

    
256
    def main(self, image_id, key=None):
257
        super(self.__class__, self).main()
258
        try:
259
            reply = self.client.get_image_metadata(image_id, key)
260
        except ClientError as err:
261
            raiseCLIError(err)
262
        print_dict(reply)
263

    
264
@command()
265
class image_addproperty(_init_cyclades):
266
    """Add an image property"""
267

    
268
    def main(self, image_id, key, val):
269
        super(self.__class__, self).main()
270
        try:
271
            reply = self.client.create_image_metadata(image_id, key, val)
272
        except ClientError as err:
273
            raiseCLIError(err)
274
        print_dict(reply)
275

    
276
@command()
277
class image_setproperty(_init_cyclades):
278
    """Update an image property"""
279

    
280
    def main(self, image_id, key, val):
281
        super(self.__class__, self).main()
282
        metadata = {key: val}
283
        try:
284
            reply = self.client.update_image_metadata(image_id, **metadata)
285
        except ClientError as err:
286
            raiseCLIError(err)
287
        print_dict(reply)
288

    
289
@command()
290
class image_delproperty(_init_cyclades):
291
    """Delete an image property"""
292

    
293
    def main(self, image_id, key):
294
        super(self.__class__, self).main()
295
        try:
296
            self.client.delete_image_metadata(image_id, key)
297
        except ClientError as err:
298
            raiseCLIError(err)