Statistics
| Branch: | Tag: | Revision:

root / kamaki / clients / compute.py @ a2ef112e

History | View | Annotate | Download (8.9 kB)

1
# Copyright 2011 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 ComputeClientApi
36
from kamaki.clients.utils import path4url
37
import json
38

    
39

    
40
class ComputeClient(ComputeClientApi):
41
    """OpenStack Compute API 1.1 client"""
42

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

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

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

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

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

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

66
        :param name: (str)
67

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

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

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

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

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

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

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

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

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

113
        :param server_id: integer (str or int)
114

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

    
121
    def delete_server(self, server_id):
122
        """Submit a deletion request for a server specified by id
123

124
        :param server_id: integer (str or int)
125
        """
126
        r = self.servers_delete(server_id)
127
        r.release()
128

    
129
    def reboot_server(self, server_id, hard=False):
130
        """
131
        :param server_id: integer (str or int)
132

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

    
140
    def get_server_metadata(self, server_id, key=''):
141
        """
142
        :param server_id: integer (str or int)
143

144
        :param key: (str) the metadatum key (all metadata if not given)
145

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

    
152
    def create_server_metadata(self, server_id, key, val):
153
        """
154
        :param server_id: integer (str or int)
155

156
        :param key: (str)
157

158
        :param val: (str)
159

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

    
169
    def update_server_metadata(self, server_id, **metadata):
170
        """
171
        :param server_id: integer (str or int)
172

173
        :param metadata: dict of key:val metadata
174

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

    
181
    def delete_server_metadata(self, server_id, key):
182
        """
183
        :param server_id: integer (str or int)
184

185
        :param key: (str) the meta key
186
        """
187
        r = self.servers_delete(server_id, 'meta/' + key)
188
        r.release()
189

    
190
    def list_flavors(self, detail=False):
191
        """
192
        :param detail: (bool) detailed flavor info if set, short if not
193

194
        :returns: (dict) flavor info
195
        """
196
        detail = 'detail' if detail else ''
197
        r = self.flavors_get(command='detail')
198
        return r.json['flavors']['values']
199

    
200
    def get_flavor_details(self, flavor_id):
201
        """
202
        :param flavor_id: integer (str or int)
203

204
        :returns: dict
205
        """
206
        r = self.flavors_get(flavor_id)
207
        return r.json['flavor']
208

    
209
    def list_images(self, detail=False):
210
        """
211
        :param detail: (bool) detailed info if set, short if not
212

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

    
219
    def get_image_details(self, image_id, **kwargs):
220
        """
221
        :param image_id: integer (str or int)
222

223
        :returns: dict
224

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

    
234
    def delete_image(self, image_id):
235
        """
236
        :param image_id: (str)
237
        """
238
        r = self.images_delete(image_id)
239
        r.release()
240

    
241
    def get_image_metadata(self, image_id, key=''):
242
        """
243
        :param image_id: (str)
244

245
        :param key: (str) the metadatum key
246

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

    
253
    def create_image_metadata(self, image_id, key, val):
254
        """
255
        :param image_id: integer (str or int)
256

257
        :param key: (str) metadatum key
258

259
        :param val: (str) metadatum value
260

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

    
267
    def update_image_metadata(self, image_id, **metadata):
268
        """
269
        :param image_id: (str)
270

271
        :param metadata: dict
272

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

    
279
    def delete_image_metadata(self, image_id, key):
280
        """
281
        :param image_id: (str)
282

283
        :param key: (str) metadatum key
284
        """
285
        command = path4url('meta', key)
286
        r = self.images_delete(image_id, command)
287
        r.release()