Revision f533f224 api/servers.py

b/api/servers.py
9 9
from django.template.loader import render_to_string
10 10
from django.utils import simplejson as json
11 11

  
12
from synnefo.api import util
12 13
from synnefo.api.actions import server_actions
13 14
from synnefo.api.common import method_not_allowed
14 15
from synnefo.api.faults import BadRequest, ItemNotFound, ServiceUnavailable
15
from synnefo.api.util import (isoformat, isoparse, random_password,
16
                                get_vm, get_vm_meta, get_image, get_flavor,
17
                                get_request_dict, render_metadata, render_meta, api_method)
18 16
from synnefo.db.models import VirtualMachine, VirtualMachineMetadata
19 17
from synnefo.logic.backend import create_instance, delete_instance
20 18
from synnefo.logic.utils import get_rsapi_state
......
70 68
        return method_not_allowed(request)
71 69

  
72 70

  
73
def address_to_dict(ipfour, ipsix):
74
    return {'id': 'public',
75
            'values': [{'version': 4, 'addr': ipfour}, {'version': 6, 'addr': ipsix}]}
71
def nic_to_dict(nic):
72
    network = nic.network
73
    network_id = str(network.id) if not network.public else 'public'
74
    d = {'id': network_id, 'name': network.name, 'mac': nic.mac}
75
    if nic.firewall_profile:
76
        d['firewallProfile'] = nic.firewall_profile
77
    if nic.ipv4 or nic.ipv6:
78
        d['values'] = []
79
        if nic.ipv4:
80
            d['values'].append({'version': 4, 'addr': nic.ipv4})
81
        if nic.ipv6:
82
            d['values'].append({'version': 6, 'addr': nic.ipv6})
83
    return d
76 84

  
77 85
def metadata_to_dict(vm):
78 86
    vm_meta = vm.virtualmachinemetadata_set.all()
......
84 92
        d['status'] = get_rsapi_state(vm)
85 93
        d['progress'] = 100 if get_rsapi_state(vm) == 'ACTIVE' else 0
86 94
        d['hostId'] = vm.hostid
87
        d['updated'] = isoformat(vm.updated)
88
        d['created'] = isoformat(vm.created)
95
        d['updated'] = util.isoformat(vm.updated)
96
        d['created'] = util.isoformat(vm.created)
89 97
        d['flavorRef'] = vm.flavor.id
90 98
        d['imageRef'] = vm.sourceimage.id
91 99

  
......
93 101
        if metadata:
94 102
            d['metadata'] = {'values': metadata}
95 103

  
96
        addresses = [address_to_dict(vm.ipfour, vm.ipsix)]
97
        addresses.extend({'id': str(network.id), 'values': []} for network in vm.network_set.all())
98
        d['addresses'] = {'values': addresses}
104
        addresses = [nic_to_dict(nic) for nic in vm.nics.all()]
105
        if addresses:
106
            d['addresses'] = {'values': addresses}
99 107
    return d
100 108

  
101 109

  
102 110
def render_server(request, server, status=200):
103 111
    if request.serialization == 'xml':
104
        data = render_to_string('server.xml', {'server': server, 'is_root': True})
112
        data = render_to_string('server.xml', {
113
            'server': server,
114
            'is_root': True})
105 115
    else:
106 116
        data = json.dumps({'server': server})
107 117
    return HttpResponse(data, status=status)
108 118

  
109 119

  
110
@api_method('GET')
120
@util.api_method('GET')
111 121
def list_servers(request, detail=False):
112 122
    # Normal Response Codes: 200, 203
113 123
    # Error Response Codes: computeFault (400, 500),
......
116 126
    #                       badRequest (400),
117 127
    #                       overLimit (413)
118 128

  
119
    since = isoparse(request.GET.get('changes-since'))
129
    since = util.isoparse(request.GET.get('changes-since'))
120 130

  
121 131
    if since:
122
        user_vms = VirtualMachine.objects.filter(owner=request.user, updated__gte=since)
132
        user_vms = VirtualMachine.objects.filter(owner=request.user,
133
                                                updated__gte=since)
123 134
        if not user_vms:
124 135
            return HttpResponse(status=304)
125 136
    else:
126
        user_vms = VirtualMachine.objects.filter(owner=request.user, deleted=False)
137
        user_vms = VirtualMachine.objects.filter(owner=request.user,
138
                                                deleted=False)
139
    
127 140
    servers = [vm_to_dict(server, detail) for server in user_vms]
128 141

  
129 142
    if request.serialization == 'xml':
130
        data = render_to_string('list_servers.xml', {'servers': servers, 'detail': detail})
143
        data = render_to_string('list_servers.xml', {
144
            'servers': servers,
145
            'detail': detail})
131 146
    else:
132 147
        data = json.dumps({'servers': {'values': servers}})
133 148

  
134 149
    return HttpResponse(data, status=200)
135 150

  
136
@api_method('POST')
151
@util.api_method('POST')
137 152
def create_server(request):
138 153
    # Normal Response Code: 202
139 154
    # Error Response Codes: computeFault (400, 500),
......
145 160
    #                       serverCapacityUnavailable (503),
146 161
    #                       overLimit (413)
147 162

  
148
    req = get_request_dict(request)
149

  
163
    req = util.get_request_dict(request)
164
    owner = request.user
165
    
150 166
    try:
151 167
        server = req['server']
152 168
        name = server['name']
......
156 172
        flavor_id = server['flavorRef']
157 173
    except (KeyError, AssertionError):
158 174
        raise BadRequest('Malformed request.')
159

  
160
    image = get_image(image_id, request.user)
161
    flavor = get_flavor(flavor_id)
162

  
175
    
176
    image = util.get_image(image_id, owner)
177
    flavor = util.get_flavor(flavor_id)
178
    password = util.random_password()
179
    
163 180
    # We must save the VM instance now, so that it gets a valid vm.backend_id.
164 181
    vm = VirtualMachine.objects.create(
165 182
        name=name,
166
        owner=request.user,
183
        owner=owner,
167 184
        sourceimage=image,
168
        ipfour='0.0.0.0',
169
        ipsix='::1',
170 185
        flavor=flavor)
171

  
172
    password = random_password()
173

  
186
    
174 187
    try:
175 188
        create_instance(vm, flavor, image, password)
176 189
    except GanetiApiError:
......
178 191
        raise ServiceUnavailable('Could not create server.')
179 192

  
180 193
    for key, val in metadata.items():
181
        VirtualMachineMetadata.objects.create(meta_key=key, meta_value=val, vm=vm)
182

  
194
        VirtualMachineMetadata.objects.create(
195
            meta_key=key,
196
            meta_value=val,
197
            vm=vm)
198
    
183 199
    logging.info('created vm with %s cpus, %s ram and %s storage',
184 200
                    flavor.cpu, flavor.ram, flavor.disk)
185 201

  
......
188 204
    server['adminPass'] = password
189 205
    return render_server(request, server, status=202)
190 206

  
191
@api_method('GET')
207
@util.api_method('GET')
192 208
def get_server_details(request, server_id):
193 209
    # Normal Response Codes: 200, 203
194 210
    # Error Response Codes: computeFault (400, 500),
......
198 214
    #                       itemNotFound (404),
199 215
    #                       overLimit (413)
200 216

  
201
    vm = get_vm(server_id, request.user)
217
    vm = util.get_vm(server_id, request.user)
202 218
    server = vm_to_dict(vm, detail=True)
203 219
    return render_server(request, server)
204 220

  
205
@api_method('PUT')
221
@util.api_method('PUT')
206 222
def update_server_name(request, server_id):
207 223
    # Normal Response Code: 204
208 224
    # Error Response Codes: computeFault (400, 500),
......
214 230
    #                       buildInProgress (409),
215 231
    #                       overLimit (413)
216 232

  
217
    req = get_request_dict(request)
233
    req = util.get_request_dict(request)
218 234

  
219 235
    try:
220 236
        name = req['server']['name']
221 237
    except (TypeError, KeyError):
222 238
        raise BadRequest('Malformed request.')
223 239

  
224
    vm = get_vm(server_id, request.user)
240
    vm = util.get_vm(server_id, request.user)
225 241
    vm.name = name
226 242
    vm.save()
227 243

  
228 244
    return HttpResponse(status=204)
229 245

  
230
@api_method('DELETE')
246
@util.api_method('DELETE')
231 247
def delete_server(request, server_id):
232 248
    # Normal Response Codes: 204
233 249
    # Error Response Codes: computeFault (400, 500),
......
238 254
    #                       buildInProgress (409),
239 255
    #                       overLimit (413)
240 256

  
241
    vm = get_vm(server_id, request.user)
257
    vm = util.get_vm(server_id, request.user)
242 258
    delete_instance(vm)
243 259
    return HttpResponse(status=204)
244 260

  
245
@api_method('POST')
261
@util.api_method('POST')
246 262
def server_action(request, server_id):
247
    vm = get_vm(server_id, request.user)
248
    req = get_request_dict(request)
263
    vm = util.get_vm(server_id, request.user)
264
    req = util.get_request_dict(request)
249 265
    if len(req) != 1:
250 266
        raise BadRequest('Malformed request.')
251 267

  
......
260 276
    except AssertionError:
261 277
        raise BadRequest('Invalid argument.')
262 278

  
263
@api_method('GET')
279
@util.api_method('GET')
264 280
def list_addresses(request, server_id):
265 281
    # Normal Response Codes: 200, 203
266 282
    # Error Response Codes: computeFault (400, 500),
......
269 285
    #                       badRequest (400),
270 286
    #                       overLimit (413)
271 287

  
272
    vm = get_vm(server_id, request.user)
273
    addresses = [address_to_dict(vm.ipfour, vm.ipsix)]
274

  
288
    vm = util.get_vm(server_id, request.user)
289
    addresses = [nic_to_dict(nic) for nic in vm.nics.all()]
290
    
275 291
    if request.serialization == 'xml':
276 292
        data = render_to_string('list_addresses.xml', {'addresses': addresses})
277 293
    else:
......
279 295

  
280 296
    return HttpResponse(data, status=200)
281 297

  
282
@api_method('GET')
298
@util.api_method('GET')
283 299
def list_addresses_by_network(request, server_id, network_id):
284 300
    # Normal Response Codes: 200, 203
285 301
    # Error Response Codes: computeFault (400, 500),
......
288 304
    #                       badRequest (400),
289 305
    #                       itemNotFound (404),
290 306
    #                       overLimit (413)
291

  
292
    vm = get_vm(server_id, request.user)
293
    if network_id != 'public':
294
        raise ItemNotFound('Unknown network.')
295

  
296
    address = address_to_dict(vm.ipfour, vm.ipsix)
297

  
307
    
308
    owner = request.user
309
    machine = util.get_vm(server_id, owner)
310
    network = util.get_network(network_id, owner)
311
    nic = util.get_nic(machine, network)
312
    address = nic_to_dict(nic)
313
    
298 314
    if request.serialization == 'xml':
299 315
        data = render_to_string('address.xml', {'address': address})
300 316
    else:
......
302 318

  
303 319
    return HttpResponse(data, status=200)
304 320

  
305
@api_method('GET')
321
@util.api_method('GET')
306 322
def list_metadata(request, server_id):
307 323
    # Normal Response Codes: 200, 203
308 324
    # Error Response Codes: computeFault (400, 500),
......
311 327
    #                       badRequest (400),
312 328
    #                       overLimit (413)
313 329

  
314
    vm = get_vm(server_id, request.user)
330
    vm = util.get_vm(server_id, request.user)
315 331
    metadata = metadata_to_dict(vm)
316
    return render_metadata(request, metadata, use_values=True, status=200)
332
    return util.render_metadata(request, metadata, use_values=True, status=200)
317 333

  
318
@api_method('POST')
334
@util.api_method('POST')
319 335
def update_metadata(request, server_id):
320 336
    # Normal Response Code: 201
321 337
    # Error Response Codes: computeFault (400, 500),
......
326 342
    #                       badMediaType(415),
327 343
    #                       overLimit (413)
328 344

  
329
    vm = get_vm(server_id, request.user)
330
    req = get_request_dict(request)
345
    vm = util.get_vm(server_id, request.user)
346
    req = util.get_request_dict(request)
331 347
    try:
332 348
        metadata = req['metadata']
333 349
        assert isinstance(metadata, dict)
......
344 360
            updated[key] = val
345 361
        except VirtualMachineMetadata.DoesNotExist:
346 362
            pass    # Ignore non-existent metadata
363
    
364
    if updated:
365
        vm.save()
366
    
367
    return util.render_metadata(request, updated, status=201)
347 368

  
348
    return render_metadata(request, updated, status=201)
349

  
350
@api_method('GET')
369
@util.api_method('GET')
351 370
def get_metadata_item(request, server_id, key):
352 371
    # Normal Response Codes: 200, 203
353 372
    # Error Response Codes: computeFault (400, 500),
......
357 376
    #                       badRequest (400),
358 377
    #                       overLimit (413)
359 378

  
360
    vm = get_vm(server_id, request.user)
361
    meta = get_vm_meta(vm, key)
362
    return render_meta(request, meta, status=200)
379
    vm = util.get_vm(server_id, request.user)
380
    meta = util.get_vm_meta(vm, key)
381
    return util.render_meta(request, meta, status=200)
363 382

  
364
@api_method('PUT')
383
@util.api_method('PUT')
365 384
def create_metadata_item(request, server_id, key):
366 385
    # Normal Response Code: 201
367 386
    # Error Response Codes: computeFault (400, 500),
......
373 392
    #                       badMediaType(415),
374 393
    #                       overLimit (413)
375 394

  
376
    vm = get_vm(server_id, request.user)
377
    req = get_request_dict(request)
395
    vm = util.get_vm(server_id, request.user)
396
    req = util.get_request_dict(request)
378 397
    try:
379 398
        metadict = req['meta']
380 399
        assert isinstance(metadict, dict)
......
382 401
        assert key in metadict
383 402
    except (KeyError, AssertionError):
384 403
        raise BadRequest('Malformed request.')
385

  
386
    meta, created = VirtualMachineMetadata.objects.get_or_create(meta_key=key, vm=vm)
404
    
405
    meta, created = VirtualMachineMetadata.objects.get_or_create(
406
        meta_key=key,
407
        vm=vm)
408
    
387 409
    meta.meta_value = metadict[key]
388 410
    meta.save()
389
    return render_meta(request, meta, status=201)
411
    vm.save()
412
    return util.render_meta(request, meta, status=201)
390 413

  
391
@api_method('DELETE')
414
@util.api_method('DELETE')
392 415
def delete_metadata_item(request, server_id, key):
393 416
    # Normal Response Code: 204
394 417
    # Error Response Codes: computeFault (400, 500),
......
400 423
    #                       badMediaType(415),
401 424
    #                       overLimit (413),
402 425

  
403
    vm = get_vm(server_id, request.user)
404
    meta = get_vm_meta(vm, key)
426
    vm = util.get_vm(server_id, request.user)
427
    meta = util.get_vm_meta(vm, key)
405 428
    meta.delete()
429
    vm.save()
406 430
    return HttpResponse(status=204)

Also available in: Unified diff