Statistics
| Branch: | Tag: | Revision:

root / api / servers.py @ 432fc8c3

History | View | Annotate | Download (13.9 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 90d90bd2 Giorgos Verigakis
        sourceimage = Image.objects.get(id=server['imageRef'])
155 90d90bd2 Giorgos Verigakis
        flavor = Flavor.objects.get(id=server['flavorRef'])
156 7e2f9d4b Giorgos Verigakis
    except KeyError:
157 d8e50a39 Giorgos Verigakis
        raise BadRequest('Malformed request.')
158 7e2f9d4b Giorgos Verigakis
    except Image.DoesNotExist:
159 7e2f9d4b Giorgos Verigakis
        raise ItemNotFound
160 7e2f9d4b Giorgos Verigakis
    except Flavor.DoesNotExist:
161 7e2f9d4b Giorgos Verigakis
        raise ItemNotFound
162 7e2f9d4b Giorgos Verigakis
    
163 d8e50a39 Giorgos Verigakis
    vm = VirtualMachine.objects.create(
164 7e2f9d4b Giorgos Verigakis
        name=name,
165 7e2f9d4b Giorgos Verigakis
        owner=get_user(),
166 7e2f9d4b Giorgos Verigakis
        sourceimage=sourceimage,
167 7e2f9d4b Giorgos Verigakis
        ipfour='0.0.0.0',
168 7e2f9d4b Giorgos Verigakis
        ipsix='::1',
169 7e2f9d4b Giorgos Verigakis
        flavor=flavor)
170 7e2f9d4b Giorgos Verigakis
                
171 7e2f9d4b Giorgos Verigakis
    if request.META.get('SERVER_NAME', None) == 'testserver':
172 7e2f9d4b Giorgos Verigakis
        name = 'test-server'
173 7e2f9d4b Giorgos Verigakis
        dry_run = True
174 7e2f9d4b Giorgos Verigakis
    else:
175 d8e50a39 Giorgos Verigakis
        name = vm.backend_id
176 7e2f9d4b Giorgos Verigakis
        dry_run = False
177 7e2f9d4b Giorgos Verigakis
    
178 7e2f9d4b Giorgos Verigakis
    jobId = rapi.CreateInstance(
179 7e2f9d4b Giorgos Verigakis
        mode='create',
180 7e2f9d4b Giorgos Verigakis
        name=name,
181 7e2f9d4b Giorgos Verigakis
        disk_template='plain',
182 7e2f9d4b Giorgos Verigakis
        disks=[{"size": 2000}],         #FIXME: Always ask for a 2GB disk for now
183 7e2f9d4b Giorgos Verigakis
        nics=[{}],
184 90d90bd2 Giorgos Verigakis
        os='debootstrap+default',       #TODO: select OS from imageRef
185 7e2f9d4b Giorgos Verigakis
        ip_check=False,
186 90d90bd2 Giorgos Verigakis
        name_check=False,
187 7e2f9d4b Giorgos Verigakis
        pnode=rapi.GetNodes()[0],       #TODO: verify if this is necessary
188 7e2f9d4b Giorgos Verigakis
        dry_run=dry_run,
189 7e2f9d4b Giorgos Verigakis
        beparams=dict(auto_balance=True, vcpus=flavor.cpu, memory=flavor.ram))
190 7e2f9d4b Giorgos Verigakis
    
191 d8e50a39 Giorgos Verigakis
    vm.save()
192 7e2f9d4b Giorgos Verigakis
        
193 d8e50a39 Giorgos Verigakis
    logging.info('created vm with %s cpus, %s ram and %s storage' % (flavor.cpu, flavor.ram, flavor.disk))
194 7e2f9d4b Giorgos Verigakis
    
195 d8e50a39 Giorgos Verigakis
    server = vm_to_dict(vm, detail=True)
196 d8e50a39 Giorgos Verigakis
    server['status'] = 'BUILD'
197 d8e50a39 Giorgos Verigakis
    server['adminPass'] = random_password()
198 d8e50a39 Giorgos Verigakis
    return render_server(request, server, status=202)
199 7e2f9d4b Giorgos Verigakis
200 c36934a7 Giorgos Verigakis
@api_method('GET')
201 7e2f9d4b Giorgos Verigakis
def get_server_details(request, server_id):
202 c36934a7 Giorgos Verigakis
    # Normal Response Codes: 200, 203
203 c36934a7 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
204 c36934a7 Giorgos Verigakis
    #                       serviceUnavailable (503),
205 c36934a7 Giorgos Verigakis
    #                       unauthorized (401),
206 c36934a7 Giorgos Verigakis
    #                       badRequest (400),
207 c36934a7 Giorgos Verigakis
    #                       itemNotFound (404),
208 c36934a7 Giorgos Verigakis
    #                       overLimit (413)
209 c36934a7 Giorgos Verigakis
    
210 d8e50a39 Giorgos Verigakis
    vm = get_vm(server_id)
211 d8e50a39 Giorgos Verigakis
    server = vm_to_dict(vm, detail=True)
212 d8e50a39 Giorgos Verigakis
    return render_server(request, server)
213 7e2f9d4b Giorgos Verigakis
214 c36934a7 Giorgos Verigakis
@api_method('PUT')
215 c36934a7 Giorgos Verigakis
def update_server_name(request, server_id):
216 c36934a7 Giorgos Verigakis
    # Normal Response Code: 204
217 c36934a7 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
218 c36934a7 Giorgos Verigakis
    #                       serviceUnavailable (503),
219 c36934a7 Giorgos Verigakis
    #                       unauthorized (401),
220 c36934a7 Giorgos Verigakis
    #                       badRequest (400),
221 c36934a7 Giorgos Verigakis
    #                       badMediaType(415),
222 c36934a7 Giorgos Verigakis
    #                       itemNotFound (404),
223 c36934a7 Giorgos Verigakis
    #                       buildInProgress (409),
224 c36934a7 Giorgos Verigakis
    #                       overLimit (413)
225 c36934a7 Giorgos Verigakis
    
226 7e2f9d4b Giorgos Verigakis
    req = get_request_dict(request)
227 7e2f9d4b Giorgos Verigakis
    
228 7e2f9d4b Giorgos Verigakis
    try:
229 7e2f9d4b Giorgos Verigakis
        name = req['server']['name']
230 7e2f9d4b Giorgos Verigakis
    except KeyError:
231 d8e50a39 Giorgos Verigakis
        raise BadRequest('Malformed request.')
232 7e2f9d4b Giorgos Verigakis
    
233 d8e50a39 Giorgos Verigakis
    vm = get_vm(server_id)
234 d8e50a39 Giorgos Verigakis
    vm.name = name
235 d8e50a39 Giorgos Verigakis
    vm.save()
236 7e2f9d4b Giorgos Verigakis
    
237 7e2f9d4b Giorgos Verigakis
    return HttpResponse(status=204)
238 7e2f9d4b Giorgos Verigakis
239 c36934a7 Giorgos Verigakis
@api_method('DELETE')
240 7e2f9d4b Giorgos Verigakis
def delete_server(request, server_id):
241 c36934a7 Giorgos Verigakis
    # Normal Response Codes: 204
242 c36934a7 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
243 c36934a7 Giorgos Verigakis
    #                       serviceUnavailable (503),
244 c36934a7 Giorgos Verigakis
    #                       unauthorized (401),
245 c36934a7 Giorgos Verigakis
    #                       itemNotFound (404),
246 c36934a7 Giorgos Verigakis
    #                       unauthorized (401),
247 c36934a7 Giorgos Verigakis
    #                       buildInProgress (409),
248 c36934a7 Giorgos Verigakis
    #                       overLimit (413)
249 c36934a7 Giorgos Verigakis
    
250 d8e50a39 Giorgos Verigakis
    vm = get_vm(server_id)
251 d8e50a39 Giorgos Verigakis
    backend.start_action(vm, 'DESTROY')
252 d8e50a39 Giorgos Verigakis
    rapi.DeleteInstance(vm.backend_id)
253 7e2f9d4b Giorgos Verigakis
    return HttpResponse(status=204)
254 b016b476 Giorgos Verigakis
255 b016b476 Giorgos Verigakis
@api_method('POST')
256 b016b476 Giorgos Verigakis
def server_action(request, server_id):
257 d8e50a39 Giorgos Verigakis
    vm = get_vm(server_id)
258 b016b476 Giorgos Verigakis
    req = get_request_dict(request)
259 b016b476 Giorgos Verigakis
    if len(req) != 1:
260 d8e50a39 Giorgos Verigakis
        raise BadRequest('Malformed request.')
261 b016b476 Giorgos Verigakis
    
262 b016b476 Giorgos Verigakis
    key = req.keys()[0]
263 d8e50a39 Giorgos Verigakis
    val = req[key]
264 b016b476 Giorgos Verigakis
    
265 d8e50a39 Giorgos Verigakis
    try:
266 d8e50a39 Giorgos Verigakis
        assert isinstance(val, dict)
267 20a51b1e Giorgos Verigakis
        return server_actions[key](request, vm, req[key])
268 d8e50a39 Giorgos Verigakis
    except KeyError:
269 d8e50a39 Giorgos Verigakis
        raise BadRequest('Unknown action.')
270 d8e50a39 Giorgos Verigakis
    except AssertionError:
271 d8e50a39 Giorgos Verigakis
        raise BadRequest('Invalid argument.')
272 b016b476 Giorgos Verigakis
273 b016b476 Giorgos Verigakis
@api_method('GET')
274 b016b476 Giorgos Verigakis
def list_addresses(request, server_id):
275 b016b476 Giorgos Verigakis
    # Normal Response Codes: 200, 203
276 b016b476 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
277 b016b476 Giorgos Verigakis
    #                       serviceUnavailable (503),
278 b016b476 Giorgos Verigakis
    #                       unauthorized (401),
279 b016b476 Giorgos Verigakis
    #                       badRequest (400),
280 b016b476 Giorgos Verigakis
    #                       overLimit (413)
281 b016b476 Giorgos Verigakis
    
282 d8e50a39 Giorgos Verigakis
    vm = get_vm(server_id)
283 d8e50a39 Giorgos Verigakis
    addresses = [address_to_dict(vm.ipfour, vm.ipsix)]
284 b016b476 Giorgos Verigakis
    
285 d8e50a39 Giorgos Verigakis
    if request.serialization == 'xml':
286 b016b476 Giorgos Verigakis
        data = render_to_string('list_addresses.xml', {'addresses': addresses})
287 b016b476 Giorgos Verigakis
    else:
288 b016b476 Giorgos Verigakis
        data = json.dumps({'addresses': {'values': addresses}})
289 b016b476 Giorgos Verigakis
    
290 b016b476 Giorgos Verigakis
    return HttpResponse(data, status=200)
291 b016b476 Giorgos Verigakis
292 b016b476 Giorgos Verigakis
@api_method('GET')
293 b016b476 Giorgos Verigakis
def list_addresses_by_network(request, server_id, network_id):
294 b016b476 Giorgos Verigakis
    # Normal Response Codes: 200, 203
295 b016b476 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
296 b016b476 Giorgos Verigakis
    #                       serviceUnavailable (503),
297 b016b476 Giorgos Verigakis
    #                       unauthorized (401),
298 b016b476 Giorgos Verigakis
    #                       badRequest (400),
299 b016b476 Giorgos Verigakis
    #                       itemNotFound (404),
300 b016b476 Giorgos Verigakis
    #                       overLimit (413)
301 b016b476 Giorgos Verigakis
    
302 d8e50a39 Giorgos Verigakis
    vm = get_vm(server_id)
303 b016b476 Giorgos Verigakis
    if network_id != 'public':
304 d8e50a39 Giorgos Verigakis
        raise ItemNotFound('Unknown network.')
305 b016b476 Giorgos Verigakis
    
306 d8e50a39 Giorgos Verigakis
    address = address_to_dict(vm.ipfour, vm.ipsix)
307 b016b476 Giorgos Verigakis
    
308 d8e50a39 Giorgos Verigakis
    if request.serialization == 'xml':
309 b016b476 Giorgos Verigakis
        data = render_to_string('address.xml', {'address': address})
310 b016b476 Giorgos Verigakis
    else:
311 b016b476 Giorgos Verigakis
        data = json.dumps({'network': address})
312 b016b476 Giorgos Verigakis
    
313 b016b476 Giorgos Verigakis
    return HttpResponse(data, status=200)
314 d8e50a39 Giorgos Verigakis
315 d8e50a39 Giorgos Verigakis
@api_method('GET')
316 d8e50a39 Giorgos Verigakis
def list_metadata(request, server_id):
317 d8e50a39 Giorgos Verigakis
    # Normal Response Codes: 200, 203
318 d8e50a39 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
319 d8e50a39 Giorgos Verigakis
    #                       serviceUnavailable (503),
320 d8e50a39 Giorgos Verigakis
    #                       unauthorized (401),
321 d8e50a39 Giorgos Verigakis
    #                       badRequest (400),
322 d8e50a39 Giorgos Verigakis
    #                       overLimit (413)
323 d8e50a39 Giorgos Verigakis
324 d8e50a39 Giorgos Verigakis
    vm = get_vm(server_id)
325 d8e50a39 Giorgos Verigakis
    metadata = metadata_to_dict(vm)
326 432fc8c3 Giorgos Verigakis
    return render_metadata(request, metadata, use_values=True, status=200)
327 d8e50a39 Giorgos Verigakis
328 d8e50a39 Giorgos Verigakis
@api_method('POST')
329 d8e50a39 Giorgos Verigakis
def update_metadata(request, server_id):
330 d8e50a39 Giorgos Verigakis
    # Normal Response Code: 201
331 d8e50a39 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
332 d8e50a39 Giorgos Verigakis
    #                       serviceUnavailable (503),
333 d8e50a39 Giorgos Verigakis
    #                       unauthorized (401),
334 d8e50a39 Giorgos Verigakis
    #                       badRequest (400),
335 d8e50a39 Giorgos Verigakis
    #                       buildInProgress (409),
336 d8e50a39 Giorgos Verigakis
    #                       badMediaType(415),
337 d8e50a39 Giorgos Verigakis
    #                       overLimit (413)
338 d8e50a39 Giorgos Verigakis
339 d8e50a39 Giorgos Verigakis
    vm = get_vm(server_id)
340 d8e50a39 Giorgos Verigakis
    req = get_request_dict(request)
341 d8e50a39 Giorgos Verigakis
    try:
342 d8e50a39 Giorgos Verigakis
        metadata = req['metadata']
343 d8e50a39 Giorgos Verigakis
        assert isinstance(metadata, dict)
344 d8e50a39 Giorgos Verigakis
    except (KeyError, AssertionError):
345 d8e50a39 Giorgos Verigakis
        raise BadRequest('Malformed request.')
346 d8e50a39 Giorgos Verigakis
    
347 d8e50a39 Giorgos Verigakis
    updated = {}
348 d8e50a39 Giorgos Verigakis
    
349 d8e50a39 Giorgos Verigakis
    for key, val in metadata.items():
350 d8e50a39 Giorgos Verigakis
        try:
351 d8e50a39 Giorgos Verigakis
            meta = VirtualMachineMetadata.objects.get(meta_key=key, vm=vm)
352 d8e50a39 Giorgos Verigakis
            meta.meta_value = val
353 d8e50a39 Giorgos Verigakis
            meta.save()
354 d8e50a39 Giorgos Verigakis
            updated[key] = val
355 d8e50a39 Giorgos Verigakis
        except VirtualMachineMetadata.DoesNotExist:
356 d8e50a39 Giorgos Verigakis
            pass    # Ignore non-existent metadata
357 d8e50a39 Giorgos Verigakis
    
358 432fc8c3 Giorgos Verigakis
    return render_metadata(request, metadata, status=201)
359 d8e50a39 Giorgos Verigakis
360 d8e50a39 Giorgos Verigakis
@api_method('GET')
361 d8e50a39 Giorgos Verigakis
def get_metadata_item(request, server_id, key):
362 d8e50a39 Giorgos Verigakis
    # Normal Response Codes: 200, 203
363 d8e50a39 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
364 d8e50a39 Giorgos Verigakis
    #                       serviceUnavailable (503),
365 d8e50a39 Giorgos Verigakis
    #                       unauthorized (401),
366 d8e50a39 Giorgos Verigakis
    #                       itemNotFound (404),
367 d8e50a39 Giorgos Verigakis
    #                       badRequest (400),
368 d8e50a39 Giorgos Verigakis
    #                       overLimit (413)
369 d8e50a39 Giorgos Verigakis
370 d8e50a39 Giorgos Verigakis
    meta = get_vm_meta(server_id, key)
371 432fc8c3 Giorgos Verigakis
    return render_meta(request, meta, status=200)
372 d8e50a39 Giorgos Verigakis
373 d8e50a39 Giorgos Verigakis
@api_method('PUT')
374 d8e50a39 Giorgos Verigakis
def create_metadata_item(request, server_id, key):
375 d8e50a39 Giorgos Verigakis
    # Normal Response Code: 201
376 d8e50a39 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
377 d8e50a39 Giorgos Verigakis
    #                       serviceUnavailable (503),
378 d8e50a39 Giorgos Verigakis
    #                       unauthorized (401),
379 d8e50a39 Giorgos Verigakis
    #                       itemNotFound (404),
380 d8e50a39 Giorgos Verigakis
    #                       badRequest (400),
381 d8e50a39 Giorgos Verigakis
    #                       buildInProgress (409),
382 d8e50a39 Giorgos Verigakis
    #                       badMediaType(415),
383 d8e50a39 Giorgos Verigakis
    #                       overLimit (413)
384 d8e50a39 Giorgos Verigakis
385 d8e50a39 Giorgos Verigakis
    vm = get_vm(server_id)
386 d8e50a39 Giorgos Verigakis
    req = get_request_dict(request)
387 d8e50a39 Giorgos Verigakis
    try:
388 d8e50a39 Giorgos Verigakis
        metadict = req['meta']
389 d8e50a39 Giorgos Verigakis
        assert isinstance(metadict, dict)
390 d8e50a39 Giorgos Verigakis
        assert len(metadict) == 1
391 d8e50a39 Giorgos Verigakis
        assert key in metadict
392 d8e50a39 Giorgos Verigakis
    except (KeyError, AssertionError):
393 d8e50a39 Giorgos Verigakis
        raise BadRequest('Malformed request.')
394 d8e50a39 Giorgos Verigakis
    
395 d8e50a39 Giorgos Verigakis
    meta, created = VirtualMachineMetadata.objects.get_or_create(meta_key=key, vm=vm)
396 d8e50a39 Giorgos Verigakis
    meta.meta_value = metadict[key]
397 d8e50a39 Giorgos Verigakis
    meta.save()
398 432fc8c3 Giorgos Verigakis
    return render_meta(request, meta, status=201)
399 d8e50a39 Giorgos Verigakis
400 d8e50a39 Giorgos Verigakis
@api_method('DELETE')
401 d8e50a39 Giorgos Verigakis
def delete_metadata_item(request, server_id, key):
402 d8e50a39 Giorgos Verigakis
    # Normal Response Code: 204
403 d8e50a39 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
404 d8e50a39 Giorgos Verigakis
    #                       serviceUnavailable (503),
405 d8e50a39 Giorgos Verigakis
    #                       unauthorized (401),
406 d8e50a39 Giorgos Verigakis
    #                       itemNotFound (404),
407 d8e50a39 Giorgos Verigakis
    #                       badRequest (400),
408 d8e50a39 Giorgos Verigakis
    #                       buildInProgress (409),
409 d8e50a39 Giorgos Verigakis
    #                       badMediaType(415),
410 d8e50a39 Giorgos Verigakis
    #                       overLimit (413),
411 d8e50a39 Giorgos Verigakis
412 d8e50a39 Giorgos Verigakis
    meta = get_vm_meta(server_id, key)
413 d8e50a39 Giorgos Verigakis
    meta.delete()
414 d8e50a39 Giorgos Verigakis
    return HttpResponse(status=204)