Statistics
| Branch: | Tag: | Revision:

root / api / servers.py @ 7584d408

History | View | Annotate | Download (14.1 kB)

1 7e2f9d4b Giorgos Verigakis
#
2 7e2f9d4b Giorgos Verigakis
# Copyright (c) 2010 Greek Research and Technology Network
3 7e2f9d4b Giorgos Verigakis
#
4 7e2f9d4b Giorgos Verigakis
5 b016b476 Giorgos Verigakis
from django.conf import settings
6 d8e50a39 Giorgos Verigakis
from django.conf.urls.defaults import patterns
7 7e2f9d4b Giorgos Verigakis
from django.http import HttpResponse
8 7e2f9d4b Giorgos Verigakis
from django.template.loader import render_to_string
9 29a59bc1 Giorgos Verigakis
from django.utils import simplejson as json
10 7e2f9d4b Giorgos Verigakis
11 0971fa71 Markos Gogoulos
from synnefo.api.actions import server_actions
12 d8e50a39 Giorgos Verigakis
from synnefo.api.common import method_not_allowed
13 d8e50a39 Giorgos Verigakis
from synnefo.api.faults import BadRequest, ItemNotFound
14 0971fa71 Markos Gogoulos
from synnefo.api.util import *
15 d8e50a39 Giorgos Verigakis
from synnefo.db.models import Image, Flavor, VirtualMachine, VirtualMachineMetadata
16 d8e50a39 Giorgos Verigakis
from synnefo.logic.utils import get_rsapi_state
17 0971fa71 Markos Gogoulos
from synnefo.util.rapi import GanetiRapiClient
18 d8e50a39 Giorgos Verigakis
from synnefo.logic import backend
19 d8e50a39 Giorgos Verigakis
20 d8e50a39 Giorgos Verigakis
import logging
21 d8e50a39 Giorgos Verigakis
22 7e2f9d4b Giorgos Verigakis
23 7e2f9d4b Giorgos Verigakis
rapi = GanetiRapiClient(*settings.GANETI_CLUSTER_INFO)
24 7e2f9d4b Giorgos Verigakis
25 7e2f9d4b Giorgos Verigakis
urlpatterns = patterns('synnefo.api.servers',
26 7e2f9d4b Giorgos Verigakis
    (r'^(?:/|.json|.xml)?$', 'demux'),
27 7e2f9d4b Giorgos Verigakis
    (r'^/detail(?:.json|.xml)?$', 'list_servers', {'detail': True}),
28 7e2f9d4b Giorgos Verigakis
    (r'^/(\d+)(?:.json|.xml)?$', 'server_demux'),
29 b016b476 Giorgos Verigakis
    (r'^/(\d+)/action(?:.json|.xml)?$', 'server_action'),
30 b016b476 Giorgos Verigakis
    (r'^/(\d+)/ips(?:.json|.xml)?$', 'list_addresses'),
31 b016b476 Giorgos Verigakis
    (r'^/(\d+)/ips/(.+?)(?:.json|.xml)?$', 'list_addresses_by_network'),
32 d8e50a39 Giorgos Verigakis
    (r'^/(\d+)/meta(?:.json|.xml)?$', 'metadata_demux'),
33 d8e50a39 Giorgos Verigakis
    (r'^/(\d+)/meta/(.+?)(?:.json|.xml)?$', 'metadata_item_demux'),
34 7e2f9d4b Giorgos Verigakis
)
35 7e2f9d4b Giorgos Verigakis
36 7e2f9d4b Giorgos Verigakis
37 7e2f9d4b Giorgos Verigakis
def demux(request):
38 7e2f9d4b Giorgos Verigakis
    if request.method == 'GET':
39 7e2f9d4b Giorgos Verigakis
        return list_servers(request)
40 7e2f9d4b Giorgos Verigakis
    elif request.method == 'POST':
41 7e2f9d4b Giorgos Verigakis
        return create_server(request)
42 7e2f9d4b Giorgos Verigakis
    else:
43 d8e50a39 Giorgos Verigakis
        return method_not_allowed(request)
44 7e2f9d4b Giorgos Verigakis
45 7e2f9d4b Giorgos Verigakis
def server_demux(request, server_id):
46 7e2f9d4b Giorgos Verigakis
    if request.method == 'GET':
47 7e2f9d4b Giorgos Verigakis
        return get_server_details(request, server_id)
48 7e2f9d4b Giorgos Verigakis
    elif request.method == 'PUT':
49 7e2f9d4b Giorgos Verigakis
        return update_server_name(request, server_id)
50 7e2f9d4b Giorgos Verigakis
    elif request.method == 'DELETE':
51 7e2f9d4b Giorgos Verigakis
        return delete_server(request, server_id)
52 7e2f9d4b Giorgos Verigakis
    else:
53 d8e50a39 Giorgos Verigakis
        return method_not_allowed(request)
54 d8e50a39 Giorgos Verigakis
55 d8e50a39 Giorgos Verigakis
def metadata_demux(request, server_id):
56 d8e50a39 Giorgos Verigakis
    if request.method == 'GET':
57 d8e50a39 Giorgos Verigakis
        return list_metadata(request, server_id)
58 d8e50a39 Giorgos Verigakis
    elif request.method == 'POST':
59 d8e50a39 Giorgos Verigakis
        return update_metadata(request, server_id)
60 d8e50a39 Giorgos Verigakis
    else:
61 d8e50a39 Giorgos Verigakis
        return method_not_allowed(request)
62 d8e50a39 Giorgos Verigakis
63 d8e50a39 Giorgos Verigakis
def metadata_item_demux(request, server_id, key):
64 d8e50a39 Giorgos Verigakis
    if request.method == 'GET':
65 d8e50a39 Giorgos Verigakis
        return get_metadata_item(request, server_id, key)
66 d8e50a39 Giorgos Verigakis
    elif request.method == 'PUT':
67 d8e50a39 Giorgos Verigakis
        return create_metadata_item(request, server_id, key)
68 d8e50a39 Giorgos Verigakis
    elif request.method == 'DELETE':
69 d8e50a39 Giorgos Verigakis
        return delete_metadata_item(request, server_id, key)
70 d8e50a39 Giorgos Verigakis
    else:
71 d8e50a39 Giorgos Verigakis
        return method_not_allowed(request)
72 7e2f9d4b Giorgos Verigakis
73 c36934a7 Giorgos Verigakis
74 b016b476 Giorgos Verigakis
def address_to_dict(ipfour, ipsix):
75 b016b476 Giorgos Verigakis
    return {'id': 'public',
76 b016b476 Giorgos Verigakis
            'values': [{'version': 4, 'addr': ipfour}, {'version': 6, 'addr': ipsix}]}
77 b016b476 Giorgos Verigakis
78 d8e50a39 Giorgos Verigakis
def metadata_to_dict(vm):
79 d8e50a39 Giorgos Verigakis
    vm_meta = vm.virtualmachinemetadata_set.all()
80 d8e50a39 Giorgos Verigakis
    return dict((meta.meta_key, meta.meta_value) for meta in vm_meta)
81 d8e50a39 Giorgos Verigakis
82 d8e50a39 Giorgos Verigakis
def vm_to_dict(vm, detail=False):
83 d8e50a39 Giorgos Verigakis
    d = dict(id=vm.id, name=vm.name)
84 7e2f9d4b Giorgos Verigakis
    if detail:
85 d8e50a39 Giorgos Verigakis
        d['status'] = get_rsapi_state(vm)
86 d8e50a39 Giorgos Verigakis
        d['progress'] = 100 if get_rsapi_state(vm) == 'ACTIVE' else 0
87 d8e50a39 Giorgos Verigakis
        d['hostId'] = vm.hostid
88 d8e50a39 Giorgos Verigakis
        d['updated'] = isoformat(vm.updated)
89 d8e50a39 Giorgos Verigakis
        d['created'] = isoformat(vm.created)
90 d8e50a39 Giorgos Verigakis
        d['flavorRef'] = vm.flavor.id
91 d8e50a39 Giorgos Verigakis
        d['imageRef'] = vm.sourceimage.id
92 7e2f9d4b Giorgos Verigakis
        
93 d8e50a39 Giorgos Verigakis
        metadata = metadata_to_dict(vm)
94 7e2f9d4b Giorgos Verigakis
        if metadata:
95 b9a77976 Giorgos Verigakis
            d['metadata'] = {'values': metadata}
96 7e2f9d4b Giorgos Verigakis
        
97 d8e50a39 Giorgos Verigakis
        addresses = [address_to_dict(vm.ipfour, vm.ipsix)]
98 b9a77976 Giorgos Verigakis
        d['addresses'] = {'values': addresses}
99 7e2f9d4b Giorgos Verigakis
    return d
100 7e2f9d4b Giorgos Verigakis
101 d8e50a39 Giorgos Verigakis
102 d8e50a39 Giorgos Verigakis
def render_server(request, server, status=200):
103 d8e50a39 Giorgos Verigakis
    if request.serialization == 'xml':
104 d8e50a39 Giorgos Verigakis
        data = render_to_string('server.xml', {'server': server, 'is_root': True})
105 7e2f9d4b Giorgos Verigakis
    else:
106 d8e50a39 Giorgos Verigakis
        data = json.dumps({'server': server})
107 c36934a7 Giorgos Verigakis
    return HttpResponse(data, status=status)
108 d8e50a39 Giorgos Verigakis
    
109 7e2f9d4b Giorgos Verigakis
110 c36934a7 Giorgos Verigakis
@api_method('GET')
111 7e2f9d4b Giorgos Verigakis
def list_servers(request, detail=False):
112 7e2f9d4b Giorgos Verigakis
    # Normal Response Codes: 200, 203
113 7e2f9d4b Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
114 7e2f9d4b Giorgos Verigakis
    #                       serviceUnavailable (503),
115 7e2f9d4b Giorgos Verigakis
    #                       unauthorized (401),
116 7e2f9d4b Giorgos Verigakis
    #                       badRequest (400),
117 7e2f9d4b Giorgos Verigakis
    #                       overLimit (413)
118 c36934a7 Giorgos Verigakis
    
119 7e2f9d4b Giorgos Verigakis
    owner = get_user()
120 d8e50a39 Giorgos Verigakis
    since = isoparse(request.GET.get('changes-since'))
121 d8e50a39 Giorgos Verigakis
    
122 d8e50a39 Giorgos Verigakis
    if since:
123 d8e50a39 Giorgos Verigakis
        user_vms = VirtualMachine.objects.filter(updated__gt=since)
124 d8e50a39 Giorgos Verigakis
        if not user_vms:
125 d8e50a39 Giorgos Verigakis
            return HttpResponse(status=304)
126 d8e50a39 Giorgos Verigakis
    else:
127 d8e50a39 Giorgos Verigakis
        user_vms = VirtualMachine.objects.filter(owner=owner, deleted=False)
128 d8e50a39 Giorgos Verigakis
    servers = [vm_to_dict(server, detail) for server in user_vms]
129 c36934a7 Giorgos Verigakis
    
130 d8e50a39 Giorgos Verigakis
    if request.serialization == 'xml':
131 d8e50a39 Giorgos Verigakis
        data = render_to_string('list_servers.xml', {'servers': servers, 'detail': detail})
132 7e2f9d4b Giorgos Verigakis
    else:
133 c36934a7 Giorgos Verigakis
        data = json.dumps({'servers': {'values': servers}})
134 c36934a7 Giorgos Verigakis
    
135 c36934a7 Giorgos Verigakis
    return HttpResponse(data, status=200)
136 7e2f9d4b Giorgos Verigakis
137 c36934a7 Giorgos Verigakis
@api_method('POST')
138 7e2f9d4b Giorgos Verigakis
def create_server(request):
139 7e2f9d4b Giorgos Verigakis
    # Normal Response Code: 202
140 7e2f9d4b Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
141 7e2f9d4b Giorgos Verigakis
    #                       serviceUnavailable (503),
142 7e2f9d4b Giorgos Verigakis
    #                       unauthorized (401),
143 7e2f9d4b Giorgos Verigakis
    #                       badMediaType(415),
144 7e2f9d4b Giorgos Verigakis
    #                       itemNotFound (404),
145 7e2f9d4b Giorgos Verigakis
    #                       badRequest (400),
146 7e2f9d4b Giorgos Verigakis
    #                       serverCapacityUnavailable (503),
147 7e2f9d4b Giorgos Verigakis
    #                       overLimit (413)
148 7e2f9d4b Giorgos Verigakis
    
149 7e2f9d4b Giorgos Verigakis
    req = get_request_dict(request)
150 7e2f9d4b Giorgos Verigakis
    
151 7e2f9d4b Giorgos Verigakis
    try:
152 7e2f9d4b Giorgos Verigakis
        server = req['server']
153 7e2f9d4b Giorgos Verigakis
        name = server['name']
154 bc855ce7 Giorgos Verigakis
        metadata = server.get('metadata', {})
155 bc855ce7 Giorgos Verigakis
        assert isinstance(metadata, dict)
156 90d90bd2 Giorgos Verigakis
        sourceimage = Image.objects.get(id=server['imageRef'])
157 90d90bd2 Giorgos Verigakis
        flavor = Flavor.objects.get(id=server['flavorRef'])
158 bc855ce7 Giorgos Verigakis
    except (KeyError, AssertionError):
159 d8e50a39 Giorgos Verigakis
        raise BadRequest('Malformed request.')
160 7e2f9d4b Giorgos Verigakis
    except Image.DoesNotExist:
161 7e2f9d4b Giorgos Verigakis
        raise ItemNotFound
162 7e2f9d4b Giorgos Verigakis
    except Flavor.DoesNotExist:
163 7e2f9d4b Giorgos Verigakis
        raise ItemNotFound
164 7e2f9d4b Giorgos Verigakis
    
165 bc855ce7 Giorgos Verigakis
    vm = VirtualMachine(
166 7e2f9d4b Giorgos Verigakis
        name=name,
167 7e2f9d4b Giorgos Verigakis
        owner=get_user(),
168 7e2f9d4b Giorgos Verigakis
        sourceimage=sourceimage,
169 7e2f9d4b Giorgos Verigakis
        ipfour='0.0.0.0',
170 7e2f9d4b Giorgos Verigakis
        ipsix='::1',
171 7e2f9d4b Giorgos Verigakis
        flavor=flavor)
172 7e2f9d4b Giorgos Verigakis
                
173 7e2f9d4b Giorgos Verigakis
    if request.META.get('SERVER_NAME', None) == 'testserver':
174 7e2f9d4b Giorgos Verigakis
        name = 'test-server'
175 7e2f9d4b Giorgos Verigakis
        dry_run = True
176 7e2f9d4b Giorgos Verigakis
    else:
177 d8e50a39 Giorgos Verigakis
        name = vm.backend_id
178 7e2f9d4b Giorgos Verigakis
        dry_run = False
179 7e2f9d4b Giorgos Verigakis
    
180 7e2f9d4b Giorgos Verigakis
    jobId = rapi.CreateInstance(
181 7e2f9d4b Giorgos Verigakis
        mode='create',
182 7e2f9d4b Giorgos Verigakis
        name=name,
183 7e2f9d4b Giorgos Verigakis
        disk_template='plain',
184 7e2f9d4b Giorgos Verigakis
        disks=[{"size": 2000}],         #FIXME: Always ask for a 2GB disk for now
185 7e2f9d4b Giorgos Verigakis
        nics=[{}],
186 90d90bd2 Giorgos Verigakis
        os='debootstrap+default',       #TODO: select OS from imageRef
187 7e2f9d4b Giorgos Verigakis
        ip_check=False,
188 90d90bd2 Giorgos Verigakis
        name_check=False,
189 7e2f9d4b Giorgos Verigakis
        pnode=rapi.GetNodes()[0],       #TODO: verify if this is necessary
190 7e2f9d4b Giorgos Verigakis
        dry_run=dry_run,
191 7e2f9d4b Giorgos Verigakis
        beparams=dict(auto_balance=True, vcpus=flavor.cpu, memory=flavor.ram))
192 7e2f9d4b Giorgos Verigakis
    
193 d8e50a39 Giorgos Verigakis
    vm.save()
194 bc855ce7 Giorgos Verigakis
    
195 bc855ce7 Giorgos Verigakis
    for key, val in metadata.items():
196 bc855ce7 Giorgos Verigakis
        VirtualMachineMetadata.objects.create(meta_key=key, meta_value=val, vm=vm)
197 bc855ce7 Giorgos Verigakis
    
198 d8e50a39 Giorgos Verigakis
    logging.info('created vm with %s cpus, %s ram and %s storage' % (flavor.cpu, flavor.ram, flavor.disk))
199 7e2f9d4b Giorgos Verigakis
    
200 d8e50a39 Giorgos Verigakis
    server = vm_to_dict(vm, detail=True)
201 d8e50a39 Giorgos Verigakis
    server['status'] = 'BUILD'
202 d8e50a39 Giorgos Verigakis
    server['adminPass'] = random_password()
203 d8e50a39 Giorgos Verigakis
    return render_server(request, server, status=202)
204 7e2f9d4b Giorgos Verigakis
205 c36934a7 Giorgos Verigakis
@api_method('GET')
206 7e2f9d4b Giorgos Verigakis
def get_server_details(request, server_id):
207 c36934a7 Giorgos Verigakis
    # Normal Response Codes: 200, 203
208 c36934a7 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
209 c36934a7 Giorgos Verigakis
    #                       serviceUnavailable (503),
210 c36934a7 Giorgos Verigakis
    #                       unauthorized (401),
211 c36934a7 Giorgos Verigakis
    #                       badRequest (400),
212 c36934a7 Giorgos Verigakis
    #                       itemNotFound (404),
213 c36934a7 Giorgos Verigakis
    #                       overLimit (413)
214 c36934a7 Giorgos Verigakis
    
215 d8e50a39 Giorgos Verigakis
    vm = get_vm(server_id)
216 d8e50a39 Giorgos Verigakis
    server = vm_to_dict(vm, detail=True)
217 d8e50a39 Giorgos Verigakis
    return render_server(request, server)
218 7e2f9d4b Giorgos Verigakis
219 c36934a7 Giorgos Verigakis
@api_method('PUT')
220 c36934a7 Giorgos Verigakis
def update_server_name(request, server_id):
221 c36934a7 Giorgos Verigakis
    # Normal Response Code: 204
222 c36934a7 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
223 c36934a7 Giorgos Verigakis
    #                       serviceUnavailable (503),
224 c36934a7 Giorgos Verigakis
    #                       unauthorized (401),
225 c36934a7 Giorgos Verigakis
    #                       badRequest (400),
226 c36934a7 Giorgos Verigakis
    #                       badMediaType(415),
227 c36934a7 Giorgos Verigakis
    #                       itemNotFound (404),
228 c36934a7 Giorgos Verigakis
    #                       buildInProgress (409),
229 c36934a7 Giorgos Verigakis
    #                       overLimit (413)
230 c36934a7 Giorgos Verigakis
    
231 7e2f9d4b Giorgos Verigakis
    req = get_request_dict(request)
232 7e2f9d4b Giorgos Verigakis
    
233 7e2f9d4b Giorgos Verigakis
    try:
234 7e2f9d4b Giorgos Verigakis
        name = req['server']['name']
235 7e2f9d4b Giorgos Verigakis
    except KeyError:
236 d8e50a39 Giorgos Verigakis
        raise BadRequest('Malformed request.')
237 7e2f9d4b Giorgos Verigakis
    
238 d8e50a39 Giorgos Verigakis
    vm = get_vm(server_id)
239 d8e50a39 Giorgos Verigakis
    vm.name = name
240 d8e50a39 Giorgos Verigakis
    vm.save()
241 7e2f9d4b Giorgos Verigakis
    
242 7e2f9d4b Giorgos Verigakis
    return HttpResponse(status=204)
243 7e2f9d4b Giorgos Verigakis
244 c36934a7 Giorgos Verigakis
@api_method('DELETE')
245 7e2f9d4b Giorgos Verigakis
def delete_server(request, server_id):
246 c36934a7 Giorgos Verigakis
    # Normal Response Codes: 204
247 c36934a7 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
248 c36934a7 Giorgos Verigakis
    #                       serviceUnavailable (503),
249 c36934a7 Giorgos Verigakis
    #                       unauthorized (401),
250 c36934a7 Giorgos Verigakis
    #                       itemNotFound (404),
251 c36934a7 Giorgos Verigakis
    #                       unauthorized (401),
252 c36934a7 Giorgos Verigakis
    #                       buildInProgress (409),
253 c36934a7 Giorgos Verigakis
    #                       overLimit (413)
254 c36934a7 Giorgos Verigakis
    
255 d8e50a39 Giorgos Verigakis
    vm = get_vm(server_id)
256 d8e50a39 Giorgos Verigakis
    backend.start_action(vm, 'DESTROY')
257 d8e50a39 Giorgos Verigakis
    rapi.DeleteInstance(vm.backend_id)
258 7e2f9d4b Giorgos Verigakis
    return HttpResponse(status=204)
259 b016b476 Giorgos Verigakis
260 b016b476 Giorgos Verigakis
@api_method('POST')
261 b016b476 Giorgos Verigakis
def server_action(request, server_id):
262 d8e50a39 Giorgos Verigakis
    vm = get_vm(server_id)
263 b016b476 Giorgos Verigakis
    req = get_request_dict(request)
264 b016b476 Giorgos Verigakis
    if len(req) != 1:
265 d8e50a39 Giorgos Verigakis
        raise BadRequest('Malformed request.')
266 b016b476 Giorgos Verigakis
    
267 b016b476 Giorgos Verigakis
    key = req.keys()[0]
268 d8e50a39 Giorgos Verigakis
    val = req[key]
269 b016b476 Giorgos Verigakis
    
270 d8e50a39 Giorgos Verigakis
    try:
271 d8e50a39 Giorgos Verigakis
        assert isinstance(val, dict)
272 20a51b1e Giorgos Verigakis
        return server_actions[key](request, vm, req[key])
273 d8e50a39 Giorgos Verigakis
    except KeyError:
274 d8e50a39 Giorgos Verigakis
        raise BadRequest('Unknown action.')
275 d8e50a39 Giorgos Verigakis
    except AssertionError:
276 d8e50a39 Giorgos Verigakis
        raise BadRequest('Invalid argument.')
277 b016b476 Giorgos Verigakis
278 b016b476 Giorgos Verigakis
@api_method('GET')
279 b016b476 Giorgos Verigakis
def list_addresses(request, server_id):
280 b016b476 Giorgos Verigakis
    # Normal Response Codes: 200, 203
281 b016b476 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
282 b016b476 Giorgos Verigakis
    #                       serviceUnavailable (503),
283 b016b476 Giorgos Verigakis
    #                       unauthorized (401),
284 b016b476 Giorgos Verigakis
    #                       badRequest (400),
285 b016b476 Giorgos Verigakis
    #                       overLimit (413)
286 b016b476 Giorgos Verigakis
    
287 d8e50a39 Giorgos Verigakis
    vm = get_vm(server_id)
288 d8e50a39 Giorgos Verigakis
    addresses = [address_to_dict(vm.ipfour, vm.ipsix)]
289 b016b476 Giorgos Verigakis
    
290 d8e50a39 Giorgos Verigakis
    if request.serialization == 'xml':
291 b016b476 Giorgos Verigakis
        data = render_to_string('list_addresses.xml', {'addresses': addresses})
292 b016b476 Giorgos Verigakis
    else:
293 b016b476 Giorgos Verigakis
        data = json.dumps({'addresses': {'values': addresses}})
294 b016b476 Giorgos Verigakis
    
295 b016b476 Giorgos Verigakis
    return HttpResponse(data, status=200)
296 b016b476 Giorgos Verigakis
297 b016b476 Giorgos Verigakis
@api_method('GET')
298 b016b476 Giorgos Verigakis
def list_addresses_by_network(request, server_id, network_id):
299 b016b476 Giorgos Verigakis
    # Normal Response Codes: 200, 203
300 b016b476 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
301 b016b476 Giorgos Verigakis
    #                       serviceUnavailable (503),
302 b016b476 Giorgos Verigakis
    #                       unauthorized (401),
303 b016b476 Giorgos Verigakis
    #                       badRequest (400),
304 b016b476 Giorgos Verigakis
    #                       itemNotFound (404),
305 b016b476 Giorgos Verigakis
    #                       overLimit (413)
306 b016b476 Giorgos Verigakis
    
307 d8e50a39 Giorgos Verigakis
    vm = get_vm(server_id)
308 b016b476 Giorgos Verigakis
    if network_id != 'public':
309 d8e50a39 Giorgos Verigakis
        raise ItemNotFound('Unknown network.')
310 b016b476 Giorgos Verigakis
    
311 d8e50a39 Giorgos Verigakis
    address = address_to_dict(vm.ipfour, vm.ipsix)
312 b016b476 Giorgos Verigakis
    
313 d8e50a39 Giorgos Verigakis
    if request.serialization == 'xml':
314 b016b476 Giorgos Verigakis
        data = render_to_string('address.xml', {'address': address})
315 b016b476 Giorgos Verigakis
    else:
316 b016b476 Giorgos Verigakis
        data = json.dumps({'network': address})
317 b016b476 Giorgos Verigakis
    
318 b016b476 Giorgos Verigakis
    return HttpResponse(data, status=200)
319 d8e50a39 Giorgos Verigakis
320 d8e50a39 Giorgos Verigakis
@api_method('GET')
321 d8e50a39 Giorgos Verigakis
def list_metadata(request, server_id):
322 d8e50a39 Giorgos Verigakis
    # Normal Response Codes: 200, 203
323 d8e50a39 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
324 d8e50a39 Giorgos Verigakis
    #                       serviceUnavailable (503),
325 d8e50a39 Giorgos Verigakis
    #                       unauthorized (401),
326 d8e50a39 Giorgos Verigakis
    #                       badRequest (400),
327 d8e50a39 Giorgos Verigakis
    #                       overLimit (413)
328 d8e50a39 Giorgos Verigakis
329 d8e50a39 Giorgos Verigakis
    vm = get_vm(server_id)
330 d8e50a39 Giorgos Verigakis
    metadata = metadata_to_dict(vm)
331 432fc8c3 Giorgos Verigakis
    return render_metadata(request, metadata, use_values=True, status=200)
332 d8e50a39 Giorgos Verigakis
333 d8e50a39 Giorgos Verigakis
@api_method('POST')
334 d8e50a39 Giorgos Verigakis
def update_metadata(request, server_id):
335 d8e50a39 Giorgos Verigakis
    # Normal Response Code: 201
336 d8e50a39 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
337 d8e50a39 Giorgos Verigakis
    #                       serviceUnavailable (503),
338 d8e50a39 Giorgos Verigakis
    #                       unauthorized (401),
339 d8e50a39 Giorgos Verigakis
    #                       badRequest (400),
340 d8e50a39 Giorgos Verigakis
    #                       buildInProgress (409),
341 d8e50a39 Giorgos Verigakis
    #                       badMediaType(415),
342 d8e50a39 Giorgos Verigakis
    #                       overLimit (413)
343 d8e50a39 Giorgos Verigakis
344 d8e50a39 Giorgos Verigakis
    vm = get_vm(server_id)
345 d8e50a39 Giorgos Verigakis
    req = get_request_dict(request)
346 d8e50a39 Giorgos Verigakis
    try:
347 d8e50a39 Giorgos Verigakis
        metadata = req['metadata']
348 d8e50a39 Giorgos Verigakis
        assert isinstance(metadata, dict)
349 d8e50a39 Giorgos Verigakis
    except (KeyError, AssertionError):
350 d8e50a39 Giorgos Verigakis
        raise BadRequest('Malformed request.')
351 d8e50a39 Giorgos Verigakis
    
352 d8e50a39 Giorgos Verigakis
    updated = {}
353 d8e50a39 Giorgos Verigakis
    
354 d8e50a39 Giorgos Verigakis
    for key, val in metadata.items():
355 d8e50a39 Giorgos Verigakis
        try:
356 d8e50a39 Giorgos Verigakis
            meta = VirtualMachineMetadata.objects.get(meta_key=key, vm=vm)
357 d8e50a39 Giorgos Verigakis
            meta.meta_value = val
358 d8e50a39 Giorgos Verigakis
            meta.save()
359 d8e50a39 Giorgos Verigakis
            updated[key] = val
360 d8e50a39 Giorgos Verigakis
        except VirtualMachineMetadata.DoesNotExist:
361 d8e50a39 Giorgos Verigakis
            pass    # Ignore non-existent metadata
362 d8e50a39 Giorgos Verigakis
    
363 432fc8c3 Giorgos Verigakis
    return render_metadata(request, metadata, status=201)
364 d8e50a39 Giorgos Verigakis
365 d8e50a39 Giorgos Verigakis
@api_method('GET')
366 d8e50a39 Giorgos Verigakis
def get_metadata_item(request, server_id, key):
367 d8e50a39 Giorgos Verigakis
    # Normal Response Codes: 200, 203
368 d8e50a39 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
369 d8e50a39 Giorgos Verigakis
    #                       serviceUnavailable (503),
370 d8e50a39 Giorgos Verigakis
    #                       unauthorized (401),
371 d8e50a39 Giorgos Verigakis
    #                       itemNotFound (404),
372 d8e50a39 Giorgos Verigakis
    #                       badRequest (400),
373 d8e50a39 Giorgos Verigakis
    #                       overLimit (413)
374 d8e50a39 Giorgos Verigakis
375 d8e50a39 Giorgos Verigakis
    meta = get_vm_meta(server_id, key)
376 432fc8c3 Giorgos Verigakis
    return render_meta(request, meta, status=200)
377 d8e50a39 Giorgos Verigakis
378 d8e50a39 Giorgos Verigakis
@api_method('PUT')
379 d8e50a39 Giorgos Verigakis
def create_metadata_item(request, server_id, key):
380 d8e50a39 Giorgos Verigakis
    # Normal Response Code: 201
381 d8e50a39 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
382 d8e50a39 Giorgos Verigakis
    #                       serviceUnavailable (503),
383 d8e50a39 Giorgos Verigakis
    #                       unauthorized (401),
384 d8e50a39 Giorgos Verigakis
    #                       itemNotFound (404),
385 d8e50a39 Giorgos Verigakis
    #                       badRequest (400),
386 d8e50a39 Giorgos Verigakis
    #                       buildInProgress (409),
387 d8e50a39 Giorgos Verigakis
    #                       badMediaType(415),
388 d8e50a39 Giorgos Verigakis
    #                       overLimit (413)
389 d8e50a39 Giorgos Verigakis
390 d8e50a39 Giorgos Verigakis
    vm = get_vm(server_id)
391 d8e50a39 Giorgos Verigakis
    req = get_request_dict(request)
392 d8e50a39 Giorgos Verigakis
    try:
393 d8e50a39 Giorgos Verigakis
        metadict = req['meta']
394 d8e50a39 Giorgos Verigakis
        assert isinstance(metadict, dict)
395 d8e50a39 Giorgos Verigakis
        assert len(metadict) == 1
396 d8e50a39 Giorgos Verigakis
        assert key in metadict
397 d8e50a39 Giorgos Verigakis
    except (KeyError, AssertionError):
398 d8e50a39 Giorgos Verigakis
        raise BadRequest('Malformed request.')
399 d8e50a39 Giorgos Verigakis
    
400 d8e50a39 Giorgos Verigakis
    meta, created = VirtualMachineMetadata.objects.get_or_create(meta_key=key, vm=vm)
401 d8e50a39 Giorgos Verigakis
    meta.meta_value = metadict[key]
402 d8e50a39 Giorgos Verigakis
    meta.save()
403 432fc8c3 Giorgos Verigakis
    return render_meta(request, meta, status=201)
404 d8e50a39 Giorgos Verigakis
405 d8e50a39 Giorgos Verigakis
@api_method('DELETE')
406 d8e50a39 Giorgos Verigakis
def delete_metadata_item(request, server_id, key):
407 d8e50a39 Giorgos Verigakis
    # Normal Response Code: 204
408 d8e50a39 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
409 d8e50a39 Giorgos Verigakis
    #                       serviceUnavailable (503),
410 d8e50a39 Giorgos Verigakis
    #                       unauthorized (401),
411 d8e50a39 Giorgos Verigakis
    #                       itemNotFound (404),
412 d8e50a39 Giorgos Verigakis
    #                       badRequest (400),
413 d8e50a39 Giorgos Verigakis
    #                       buildInProgress (409),
414 d8e50a39 Giorgos Verigakis
    #                       badMediaType(415),
415 d8e50a39 Giorgos Verigakis
    #                       overLimit (413),
416 d8e50a39 Giorgos Verigakis
417 d8e50a39 Giorgos Verigakis
    meta = get_vm_meta(server_id, key)
418 d8e50a39 Giorgos Verigakis
    meta.delete()
419 d8e50a39 Giorgos Verigakis
    return HttpResponse(status=204)