Statistics
| Branch: | Tag: | Revision:

root / kamaki / clients / compute / __init__.py @ bcef3ac9

History | View | Annotate | Download (9.2 kB)

1
# Copyright 2011-2013 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.
33

    
34
from kamaki.clients import ClientError
35
from kamaki.clients.compute.rest_api import ComputeRestClient
36
from kamaki.clients.utils import path4url
37

    
38

    
39
class ComputeClient(ComputeRestClient):
40
    """OpenStack Compute API 1.1 client"""
41

    
42
    def list_servers(self, detail=False):
43
        """
44
        :param detail: if true, append full server details to each item
45

46
        :returns: list of server ids and names
47
        """
48
        detail = 'detail' if detail else ''
49
        r = self.servers_get(command=detail)
50
        return r.json['servers']
51

    
52
    def get_server_details(self, server_id, **kwargs):
53
        """Return detailed info for a server
54

55
        :param server_id: integer (int or str)
56

57
        :returns: dict with server details
58
        """
59
        r = self.servers_get(server_id, **kwargs)
60
        return r.json['server']
61

    
62
    def create_server(self, name, flavor_id, image_id, personality=None):
63
        """Submit request to create a new server
64

65
        :param name: (str)
66

67
        :param flavor_id: integer id denoting a preset hardware configuration
68

69
        :param image_id: (str) id denoting the OS image to run on the VM
70

71
        :param personality: a list of (file path, file contents) tuples,
72
            describing files to be injected into VM upon creation.
73

74
        :returns: a dict with the new VMs details
75

76
        :raises ClientError: wraps request errors
77
        """
78
        req = {'server': {'name': name,
79
                          'flavorRef': flavor_id,
80
                          'imageRef': image_id}}
81

    
82
        image = self.get_image_details(image_id)
83
        metadata = {}
84
        for key in ('os', 'users'):
85
            try:
86
                metadata[key] = image['metadata'][key]
87
            except KeyError:
88
                pass
89
        if metadata:
90
            req['server']['metadata'] = metadata
91

    
92
        if personality:
93
            req['server']['personality'] = personality
94

    
95
        try:
96
            r = self.servers_post(json_data=req)
97
        except ClientError as err:
98
            try:
99
                if isinstance(err.details, list):
100
                    tmp_err = err.details
101
                else:
102
                    errd = '%s' % err.details
103
                    tmp_err = errd.split(',')
104
                tmp_err = tmp_err[0].split(':')
105
                tmp_err = tmp_err[2].split('"')
106
                err.message = tmp_err[1]
107
            finally:
108
                raise err
109
        return r.json['server']
110

    
111
    def update_server_name(self, server_id, new_name):
112
        """Update the name of the server as reported by the API (does not
113
            modify the hostname used inside the VM)
114

115
        :param server_id: integer (str or int)
116

117
        :param new_name: (str)
118

119
        :returns: (dict) response headers
120
        """
121
        req = {'server': {'name': new_name}}
122
        r = self.servers_put(server_id, json_data=req)
123
        return r.headers
124

    
125
    def delete_server(self, server_id):
126
        """Submit a deletion request for a server specified by id
127

128
        :param server_id: integer (str or int)
129

130
        :returns: (dict) response headers
131
        """
132
        r = self.servers_delete(server_id)
133
        return r.headers
134

    
135
    def reboot_server(self, server_id, hard=False):
136
        """
137
        :param server_id: integer (str or int)
138

139
        :param hard: perform a hard reboot if true, soft reboot otherwise
140
        """
141
        boot_type = 'HARD' if hard else 'SOFT'
142
        req = {'reboot': {'type': boot_type}}
143
        r = self.servers_post(server_id, 'action', json_data=req)
144
        return r.headers
145

    
146
    def get_server_metadata(self, server_id, key=''):
147
        """
148
        :param server_id: integer (str or int)
149

150
        :param key: (str) the metadatum key (all metadata if not given)
151

152
        :returns: a key:val dict of requests metadata
153
        """
154
        command = path4url('metadata', key)
155
        r = self.servers_get(server_id, command)
156
        return r.json['metadata']
157

    
158
    def create_server_metadata(self, server_id, key, val):
159
        """
160
        :param server_id: integer (str or int)
161

162
        :param key: (str)
163

164
        :param val: (str)
165

166
        :returns: dict of updated key:val metadata
167
        """
168
        req = {'metadata': {key: val}}
169
        r = self.servers_put(
170
            server_id,
171
            'metadata/' + key,
172
            json_data=req,
173
            success=201)
174
        return r.json['metadata']
175

    
176
    def update_server_metadata(self, server_id, **metadata):
177
        """
178
        :param server_id: integer (str or int)
179

180
        :param metadata: dict of key:val metadata
181

182
        :returns: dict of updated key:val metadata
183
        """
184
        req = {'metadata': metadata}
185
        r = self.servers_post(
186
            server_id, 'metadata',
187
            json_data=req, success=201)
188
        return r.json['metadata']
189

    
190
    def delete_server_metadata(self, server_id, key):
191
        """
192
        :param server_id: integer (str or int)
193

194
        :param key: (str) the meta key
195

196
        :returns: (dict) response headers
197
        """
198
        r = self.servers_delete(server_id, 'metadata/' + key)
199
        return r.headers
200

    
201
    def list_flavors(self, detail=False):
202
        """
203
        :param detail: (bool) detailed flavor info if set, short if not
204

205
        :returns: (list) flavor info
206
        """
207
        r = self.flavors_get(command='detail' if detail else '')
208
        return r.json['flavors']
209

    
210
    def get_flavor_details(self, flavor_id):
211
        """
212
        :param flavor_id: integer (str or int)
213

214
        :returns: dict
215
        """
216
        r = self.flavors_get(flavor_id)
217
        return r.json['flavor']
218

    
219
    def list_images(self, detail=False):
220
        """
221
        :param detail: (bool) detailed info if set, short if not
222

223
        :returns: dict id,name + full info if detail
224
        """
225
        detail = 'detail' if detail else ''
226
        r = self.images_get(command=detail)
227
        return r.json['images']
228

    
229
    def get_image_details(self, image_id, **kwargs):
230
        """
231
        :param image_id: integer (str or int)
232

233
        :returns: dict
234

235
        :raises ClientError: 404 if image not available
236
        """
237
        r = self.images_get(image_id, **kwargs)
238
        try:
239
            return r.json['image']
240
        except KeyError:
241
            raise ClientError('Image not available', 404, details=[
242
                'Image %d not found or not accessible'])
243

    
244
    def delete_image(self, image_id):
245
        """
246
        :param image_id: (str)
247
        """
248
        r = self.images_delete(image_id)
249
        return r.headers
250

    
251
    def get_image_metadata(self, image_id, key=''):
252
        """
253
        :param image_id: (str)
254

255
        :param key: (str) the metadatum key
256

257
        :returns (dict) metadata if key not set, specific metadatum otherwise
258
        """
259
        command = path4url('metadata', key)
260
        r = self.images_get(image_id, command)
261
        return r.json['metadata']
262

    
263
    def create_image_metadata(self, image_id, key, val):
264
        """
265
        :param image_id: integer (str or int)
266

267
        :param key: (str) metadatum key
268

269
        :param val: (str) metadatum value
270

271
        :returns: (dict) updated metadata
272
        """
273
        req = {'metadata': {key: val}}
274
        r = self.images_put(image_id, 'metadata/' + key, json_data=req)
275
        return r.json['metadata']
276

    
277
    def update_image_metadata(self, image_id, **metadata):
278
        """
279
        :param image_id: (str)
280

281
        :param metadata: dict
282

283
        :returns: updated metadata
284
        """
285
        req = {'metadata': metadata}
286
        r = self.images_post(image_id, 'metadata', json_data=req)
287
        return r.json['metadata']
288

    
289
    def delete_image_metadata(self, image_id, key):
290
        """
291
        :param image_id: (str)
292

293
        :param key: (str) metadatum key
294

295
        :returns: (dict) response headers
296
        """
297
        command = path4url('metadata', key)
298
        r = self.images_delete(image_id, command)
299
        return r.headers