Statistics
| Branch: | Tag: | Revision:

root / kamaki / clients / compute / __init__.py @ 55faa0bc

History | View | Annotate | Download (9.1 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']['values']
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
        img_meta = image['metadata']['values']
84
        metadata = {}
85
        for key in ('os', 'users'):
86
            try:
87
                metadata[key] = img_meta[key]
88
            except KeyError:
89
                pass
90
        if metadata:
91
            req['server']['metadata'] = metadata
92

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

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

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

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

118
        :param new_name: (str)
119
        """
120
        req = {'server': {'name': new_name}}
121
        r = self.servers_put(server_id, json_data=req)
122
        r.release()
123

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

127
        :param server_id: integer (str or int)
128
        """
129
        r = self.servers_delete(server_id)
130
        r.release()
131

    
132
    def reboot_server(self, server_id, hard=False):
133
        """
134
        :param server_id: integer (str or int)
135

136
        :param hard: perform a hard reboot if true, soft reboot otherwise
137
        """
138
        boot_type = 'HARD' if hard else 'SOFT'
139
        req = {'reboot': {'type': boot_type}}
140
        r = self.servers_post(server_id, 'action', json_data=req)
141
        r.release()
142

    
143
    def get_server_metadata(self, server_id, key=''):
144
        """
145
        :param server_id: integer (str or int)
146

147
        :param key: (str) the metadatum key (all metadata if not given)
148

149
        :returns: a key:val dict of requests metadata
150
        """
151
        command = path4url('meta', key)
152
        r = self.servers_get(server_id, command)
153
        return r.json['meta'] if key else r.json['metadata']['values']
154

    
155
    def create_server_metadata(self, server_id, key, val):
156
        """
157
        :param server_id: integer (str or int)
158

159
        :param key: (str)
160

161
        :param val: (str)
162

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

    
173
    def update_server_metadata(self, server_id, **metadata):
174
        """
175
        :param server_id: integer (str or int)
176

177
        :param metadata: dict of key:val metadata
178

179
        :returns: dict of updated key:val metadata
180
        """
181
        req = {'metadata': metadata}
182
        r = self.servers_post(server_id, 'meta', json_data=req, success=201)
183
        return r.json['metadata']
184

    
185
    def delete_server_metadata(self, server_id, key):
186
        """
187
        :param server_id: integer (str or int)
188

189
        :param key: (str) the meta key
190
        """
191
        r = self.servers_delete(server_id, 'meta/' + key)
192
        r.release()
193

    
194
    def list_flavors(self, detail=False):
195
        """
196
        :param detail: (bool) detailed flavor info if set, short if not
197

198
        :returns: (dict) flavor info
199
        """
200
        r = self.flavors_get(command='detail' if detail else '')
201
        return r.json['flavors']['values']
202

    
203
    def get_flavor_details(self, flavor_id):
204
        """
205
        :param flavor_id: integer (str or int)
206

207
        :returns: dict
208
        """
209
        r = self.flavors_get(flavor_id)
210
        return r.json['flavor']
211

    
212
    def list_images(self, detail=False):
213
        """
214
        :param detail: (bool) detailed info if set, short if not
215

216
        :returns: dict id,name + full info if detail
217
        """
218
        detail = 'detail' if detail else ''
219
        r = self.images_get(command=detail)
220
        return r.json['images']['values']
221

    
222
    def get_image_details(self, image_id, **kwargs):
223
        """
224
        :param image_id: integer (str or int)
225

226
        :returns: dict
227

228
        :raises ClientError: 404 if image not available
229
        """
230
        r = self.images_get(image_id, **kwargs)
231
        try:
232
            return r.json['image']
233
        except KeyError:
234
            raise ClientError('Image not available', 404, details=[
235
                'Image %d not found or not accessible'])
236

    
237
    def delete_image(self, image_id):
238
        """
239
        :param image_id: (str)
240
        """
241
        r = self.images_delete(image_id)
242
        r.release()
243

    
244
    def get_image_metadata(self, image_id, key=''):
245
        """
246
        :param image_id: (str)
247

248
        :param key: (str) the metadatum key
249

250
        :returns (dict) metadata if key not set, specific metadatum otherwise
251
        """
252
        command = path4url('meta', key)
253
        r = self.images_get(image_id, command)
254
        return r.json['meta'] if key else r.json['metadata']['values']
255

    
256
    def create_image_metadata(self, image_id, key, val):
257
        """
258
        :param image_id: integer (str or int)
259

260
        :param key: (str) metadatum key
261

262
        :param val: (str) metadatum value
263

264
        :returns: (dict) updated metadata
265
        """
266
        req = {'meta': {key: val}}
267
        r = self.images_put(image_id, 'meta/' + key, json_data=req)
268
        return r.json['meta']
269

    
270
    def update_image_metadata(self, image_id, **metadata):
271
        """
272
        :param image_id: (str)
273

274
        :param metadata: dict
275

276
        :returns: updated metadata
277
        """
278
        req = {'metadata': metadata}
279
        r = self.images_post(image_id, 'meta', json_data=req)
280
        return r.json['metadata']
281

    
282
    def delete_image_metadata(self, image_id, key):
283
        """
284
        :param image_id: (str)
285

286
        :param key: (str) metadatum key
287
        """
288
        command = path4url('meta', key)
289
        r = self.images_delete(image_id, command)
290
        r.release()