Statistics
| Branch: | Tag: | Revision:

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

History | View | Annotate | Download (8.9 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
        self.servers_put(server_id, json_data=req)
122

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

126
        :param server_id: integer (str or int)
127
        """
128
        self.servers_delete(server_id)
129

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

134
        :param hard: perform a hard reboot if true, soft reboot otherwise
135
        """
136
        boot_type = 'HARD' if hard else 'SOFT'
137
        req = {'reboot': {'type': boot_type}}
138
        self.servers_post(server_id, 'action', json_data=req)
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(
164
            server_id,
165
            'meta/' + key,
166
            json_data=req,
167
            success=201)
168
        return r.json['meta']
169

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

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

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

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

186
        :param key: (str) the meta key
187
        """
188
        self.servers_delete(server_id, 'meta/' + key)
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
        r = self.flavors_get(command='detail' if detail else '')
197
        return r.json['flavors']['values']
198

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

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

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

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

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

222
        :returns: dict
223

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

    
233
    def delete_image(self, image_id):
234
        """
235
        :param image_id: (str)
236
        """
237
        self.images_delete(image_id)
238

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

243
        :param key: (str) the metadatum key
244

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

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

255
        :param key: (str) metadatum key
256

257
        :param val: (str) metadatum value
258

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

    
265
    def update_image_metadata(self, image_id, **metadata):
266
        """
267
        :param image_id: (str)
268

269
        :param metadata: dict
270

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

    
277
    def delete_image_metadata(self, image_id, key):
278
        """
279
        :param image_id: (str)
280

281
        :param key: (str) metadatum key
282
        """
283
        command = path4url('meta', key)
284
        self.images_delete(image_id, command)