6f05f1e1ff256ff1c518e1c4dacf394779cea583
[kamaki] / kamaki / clients / image_cli.py
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 from kamaki.cli import command, set_api_description
35 set_api_description('image', "Compute/Cyclades or Glance API image commands")
36 from .image import ImageClient
37
38 class _init_image(object):
39     def main(self):
40         token = self.config.get('store', 'token') or self.config.get('global', 'token')
41         base_url = self.config.get('store', 'url') or self.config.get('global', 'url')
42         self.client = ImageClient(base_url=base_url, token=token)
43
44 @command()
45 class image_public(_init_image):
46     """List public images"""
47
48     def update_parser(self, parser):
49         parser.add_argument('-l', dest='detail', action='store_true',
50                 default=False, help='show detailed output')
51         parser.add_argument('--container-format', dest='container_format',
52                 metavar='FORMAT', help='filter by container format')
53         parser.add_argument('--disk-format', dest='disk_format',
54                 metavar='FORMAT', help='filter by disk format')
55         parser.add_argument('--name', dest='name', metavar='NAME',
56                 help='filter by name')
57         parser.add_argument('--size-min', dest='size_min', metavar='BYTES',
58                 help='filter by minimum size')
59         parser.add_argument('--size-max', dest='size_max', metavar='BYTES',
60                 help='filter by maximum size')
61         parser.add_argument('--status', dest='status', metavar='STATUS',
62                 help='filter by status')
63         parser.add_argument('--order', dest='order', metavar='FIELD',
64                 help='order by FIELD (use a - prefix to reverse order)')
65
66     def main(self):
67         super(self.__class__, self).main()
68         filters = {}
69         for filter in ('container_format', 'disk_format', 'name', 'size_min',
70                        'size_max', 'status'):
71             val = getattr(self.args, filter, None)
72             if val is not None:
73                 filters[filter] = val
74
75         order = self.args.order or ''
76         images = self.client.list_public(self.args.detail, filters=filters,
77                                          order=order)
78         print_items(images, title=('name',))
79
80 @command()
81 class image_meta(_init_image):
82     """Get image metadata"""
83
84     def main(self, image_id):
85         super(self.__class__, self).main()
86         print('HELLO!')
87         image = self.client.get_meta(image_id)
88         print_dict(image)
89
90 @command()
91 class image_register(_init_image):
92     """Register an image"""
93
94     def update_parser(self, parser):
95         parser.add_argument('--checksum', dest='checksum', metavar='CHECKSUM',
96                 help='set image checksum')
97         parser.add_argument('--container-format', dest='container_format',
98                 metavar='FORMAT', help='set container format')
99         parser.add_argument('--disk-format', dest='disk_format',
100                 metavar='FORMAT', help='set disk format')
101         parser.add_argument('--id', dest='id',
102                 metavar='ID', help='set image ID')
103         parser.add_argument('--owner', dest='owner',
104                 metavar='USER', help='set image owner (admin only)')
105         parser.add_argument('--property', dest='properties', action='append',
106                 metavar='KEY=VAL',
107                 help='add a property (can be used multiple times)')
108         parser.add_argument('--public', dest='is_public', action='store_true',
109                 help='mark image as public')
110         parser.add_argument('--size', dest='size', metavar='SIZE',
111                 help='set image size')
112
113     def main(self, name, location):
114         super(self.__class__, self).main()
115         if not location.startswith('pithos://'):
116             account = self.config.get('storage', 'account').split()[0]
117             if account[-1] == '/':
118                 account = account[:-1]
119             container = self.config.get('storage', 'container')
120             location = 'pithos://%s/%s'%(account, location) \
121                 if container is None or len(container) == 0 \
122                 else 'pithos://%s/%s/%s' % (account, container, location)
123
124         params = {}
125         for key in ('checksum', 'container_format', 'disk_format', 'id',
126                     'owner', 'size'):
127             val = getattr(self.args, key)
128             if val is not None:
129                 params[key] = val
130
131         if self.args.is_public:
132             params['is_public'] = 'true'
133
134         properties = {}
135         for property in self.args.properties or []:
136             key, sep, val = property.partition('=')
137             if not sep:
138                 print("Invalid property '%s'" % property)
139                 return 1
140             properties[key.strip()] = val.strip()
141
142         self.client.register(name, location, params, properties)
143
144 @command()
145 class image_members(_init_image):
146     """Get image members"""
147
148     def main(self, image_id):
149         super(self.__class__, self).main()
150         members = self.client.list_members(image_id)
151         for member in members:
152             print(member['member_id'])
153
154 @command()
155 class image_shared(_init_image):
156     """List shared images"""
157
158     def main(self, member):
159         super(self.__class__, self).main()
160         images = self.client.list_shared(member)
161         for image in images:
162             print(image['image_id'])
163
164 @command()
165 class image_addmember(_init_image):
166     """Add a member to an image"""
167
168     def main(self, image_id, member):
169         super(self.__class__, self).main()
170         self.client.add_member(image_id, member)
171
172 @command()
173 class image_delmember(_init_image):
174     """Remove a member from an image"""
175
176     def main(self, image_id, member):
177         super(self.__class__, self).main()
178         self.client.remove_member(image_id, member)
179
180 @command()
181 class image_setmembers(_init_image):
182     """Set the members of an image"""
183
184     def main(self, image_id, *member):
185         super(self.__class__, self).main()
186         self.client.set_members(image_id, member)