Statistics
| Branch: | Tag: | Revision:

root / api / servers.py @ f4fe8796

History | View | Annotate | Download (17.2 kB)

1 adee02b8 Giorgos Verigakis
# Copyright 2011 GRNET S.A. All rights reserved.
2 adee02b8 Giorgos Verigakis
# 
3 adee02b8 Giorgos Verigakis
# Redistribution and use in source and binary forms, with or
4 adee02b8 Giorgos Verigakis
# without modification, are permitted provided that the following
5 adee02b8 Giorgos Verigakis
# conditions are met:
6 adee02b8 Giorgos Verigakis
# 
7 adee02b8 Giorgos Verigakis
#   1. Redistributions of source code must retain the above
8 adee02b8 Giorgos Verigakis
#      copyright notice, this list of conditions and the following
9 adee02b8 Giorgos Verigakis
#      disclaimer.
10 adee02b8 Giorgos Verigakis
# 
11 adee02b8 Giorgos Verigakis
#   2. Redistributions in binary form must reproduce the above
12 adee02b8 Giorgos Verigakis
#      copyright notice, this list of conditions and the following
13 adee02b8 Giorgos Verigakis
#      disclaimer in the documentation and/or other materials
14 adee02b8 Giorgos Verigakis
#      provided with the distribution.
15 adee02b8 Giorgos Verigakis
# 
16 adee02b8 Giorgos Verigakis
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
17 adee02b8 Giorgos Verigakis
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 adee02b8 Giorgos Verigakis
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 adee02b8 Giorgos Verigakis
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
20 adee02b8 Giorgos Verigakis
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 adee02b8 Giorgos Verigakis
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 adee02b8 Giorgos Verigakis
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23 adee02b8 Giorgos Verigakis
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24 adee02b8 Giorgos Verigakis
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 adee02b8 Giorgos Verigakis
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26 adee02b8 Giorgos Verigakis
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 adee02b8 Giorgos Verigakis
# POSSIBILITY OF SUCH DAMAGE.
28 adee02b8 Giorgos Verigakis
# 
29 adee02b8 Giorgos Verigakis
# The views and conclusions contained in the software and
30 adee02b8 Giorgos Verigakis
# documentation are those of the authors and should not be
31 adee02b8 Giorgos Verigakis
# interpreted as representing official policies, either expressed
32 adee02b8 Giorgos Verigakis
# or implied, of GRNET S.A.
33 7e2f9d4b Giorgos Verigakis
34 ccd0d474 Giorgos Verigakis
from django.conf import settings
35 d8e50a39 Giorgos Verigakis
from django.conf.urls.defaults import patterns
36 7e2f9d4b Giorgos Verigakis
from django.http import HttpResponse
37 7e2f9d4b Giorgos Verigakis
from django.template.loader import render_to_string
38 29a59bc1 Giorgos Verigakis
from django.utils import simplejson as json
39 7e2f9d4b Giorgos Verigakis
40 ccd0d474 Giorgos Verigakis
from synnefo.api import faults, util
41 0971fa71 Markos Gogoulos
from synnefo.api.actions import server_actions
42 d8e50a39 Giorgos Verigakis
from synnefo.api.common import method_not_allowed
43 529178b1 Giorgos Verigakis
from synnefo.db.models import VirtualMachine, VirtualMachineMetadata
44 529178b1 Giorgos Verigakis
from synnefo.logic.backend import create_instance, delete_instance
45 d8e50a39 Giorgos Verigakis
from synnefo.logic.utils import get_rsapi_state
46 55b7ee4f Georgios Gousios
from synnefo.logic import log
47 529178b1 Giorgos Verigakis
from synnefo.util.rapi import GanetiApiError
48 7e2f9d4b Giorgos Verigakis
49 55b7ee4f Georgios Gousios
_log = log.get_logger("synnefo.api")
50 7e2f9d4b Giorgos Verigakis
51 7e2f9d4b Giorgos Verigakis
urlpatterns = patterns('synnefo.api.servers',
52 7e2f9d4b Giorgos Verigakis
    (r'^(?:/|.json|.xml)?$', 'demux'),
53 7e2f9d4b Giorgos Verigakis
    (r'^/detail(?:.json|.xml)?$', 'list_servers', {'detail': True}),
54 7e2f9d4b Giorgos Verigakis
    (r'^/(\d+)(?:.json|.xml)?$', 'server_demux'),
55 b016b476 Giorgos Verigakis
    (r'^/(\d+)/action(?:.json|.xml)?$', 'server_action'),
56 b016b476 Giorgos Verigakis
    (r'^/(\d+)/ips(?:.json|.xml)?$', 'list_addresses'),
57 b016b476 Giorgos Verigakis
    (r'^/(\d+)/ips/(.+?)(?:.json|.xml)?$', 'list_addresses_by_network'),
58 d8e50a39 Giorgos Verigakis
    (r'^/(\d+)/meta(?:.json|.xml)?$', 'metadata_demux'),
59 d8e50a39 Giorgos Verigakis
    (r'^/(\d+)/meta/(.+?)(?:.json|.xml)?$', 'metadata_item_demux'),
60 c738c935 Giorgos Verigakis
    (r'^/(\d+)/stats(?:.json|.xml)?$', 'server_stats'),
61 7e2f9d4b Giorgos Verigakis
)
62 7e2f9d4b Giorgos Verigakis
63 7e2f9d4b Giorgos Verigakis
64 7e2f9d4b Giorgos Verigakis
def demux(request):
65 7e2f9d4b Giorgos Verigakis
    if request.method == 'GET':
66 7e2f9d4b Giorgos Verigakis
        return list_servers(request)
67 7e2f9d4b Giorgos Verigakis
    elif request.method == 'POST':
68 7e2f9d4b Giorgos Verigakis
        return create_server(request)
69 7e2f9d4b Giorgos Verigakis
    else:
70 d8e50a39 Giorgos Verigakis
        return method_not_allowed(request)
71 7e2f9d4b Giorgos Verigakis
72 7e2f9d4b Giorgos Verigakis
def server_demux(request, server_id):
73 7e2f9d4b Giorgos Verigakis
    if request.method == 'GET':
74 7e2f9d4b Giorgos Verigakis
        return get_server_details(request, server_id)
75 7e2f9d4b Giorgos Verigakis
    elif request.method == 'PUT':
76 7e2f9d4b Giorgos Verigakis
        return update_server_name(request, server_id)
77 7e2f9d4b Giorgos Verigakis
    elif request.method == 'DELETE':
78 7e2f9d4b Giorgos Verigakis
        return delete_server(request, server_id)
79 7e2f9d4b Giorgos Verigakis
    else:
80 d8e50a39 Giorgos Verigakis
        return method_not_allowed(request)
81 d8e50a39 Giorgos Verigakis
82 d8e50a39 Giorgos Verigakis
def metadata_demux(request, server_id):
83 d8e50a39 Giorgos Verigakis
    if request.method == 'GET':
84 d8e50a39 Giorgos Verigakis
        return list_metadata(request, server_id)
85 d8e50a39 Giorgos Verigakis
    elif request.method == 'POST':
86 d8e50a39 Giorgos Verigakis
        return update_metadata(request, server_id)
87 d8e50a39 Giorgos Verigakis
    else:
88 d8e50a39 Giorgos Verigakis
        return method_not_allowed(request)
89 d8e50a39 Giorgos Verigakis
90 d8e50a39 Giorgos Verigakis
def metadata_item_demux(request, server_id, key):
91 d8e50a39 Giorgos Verigakis
    if request.method == 'GET':
92 d8e50a39 Giorgos Verigakis
        return get_metadata_item(request, server_id, key)
93 d8e50a39 Giorgos Verigakis
    elif request.method == 'PUT':
94 d8e50a39 Giorgos Verigakis
        return create_metadata_item(request, server_id, key)
95 d8e50a39 Giorgos Verigakis
    elif request.method == 'DELETE':
96 d8e50a39 Giorgos Verigakis
        return delete_metadata_item(request, server_id, key)
97 d8e50a39 Giorgos Verigakis
    else:
98 d8e50a39 Giorgos Verigakis
        return method_not_allowed(request)
99 7e2f9d4b Giorgos Verigakis
100 c36934a7 Giorgos Verigakis
101 d44c236b Giorgos Verigakis
def nic_to_dict(nic):
102 207b70d5 Giorgos Verigakis
    network = nic.network
103 207b70d5 Giorgos Verigakis
    network_id = str(network.id) if not network.public else 'public'
104 207b70d5 Giorgos Verigakis
    d = {'id': network_id, 'name': network.name, 'mac': nic.mac}
105 207b70d5 Giorgos Verigakis
    if nic.firewall_profile:
106 207b70d5 Giorgos Verigakis
        d['firewallProfile'] = nic.firewall_profile
107 d44c236b Giorgos Verigakis
    if nic.ipv4 or nic.ipv6:
108 797e88b3 Giorgos Verigakis
        d['values'] = []
109 797e88b3 Giorgos Verigakis
        if nic.ipv4:
110 797e88b3 Giorgos Verigakis
            d['values'].append({'version': 4, 'addr': nic.ipv4})
111 797e88b3 Giorgos Verigakis
        if nic.ipv6:
112 797e88b3 Giorgos Verigakis
            d['values'].append({'version': 6, 'addr': nic.ipv6})
113 d44c236b Giorgos Verigakis
    return d
114 b016b476 Giorgos Verigakis
115 d8e50a39 Giorgos Verigakis
def metadata_to_dict(vm):
116 d8e50a39 Giorgos Verigakis
    vm_meta = vm.virtualmachinemetadata_set.all()
117 d8e50a39 Giorgos Verigakis
    return dict((meta.meta_key, meta.meta_value) for meta in vm_meta)
118 d8e50a39 Giorgos Verigakis
119 d8e50a39 Giorgos Verigakis
def vm_to_dict(vm, detail=False):
120 d8e50a39 Giorgos Verigakis
    d = dict(id=vm.id, name=vm.name)
121 7e2f9d4b Giorgos Verigakis
    if detail:
122 d8e50a39 Giorgos Verigakis
        d['status'] = get_rsapi_state(vm)
123 d8e50a39 Giorgos Verigakis
        d['progress'] = 100 if get_rsapi_state(vm) == 'ACTIVE' else 0
124 d8e50a39 Giorgos Verigakis
        d['hostId'] = vm.hostid
125 b36f78fa Giorgos Verigakis
        d['updated'] = util.isoformat(vm.updated)
126 b36f78fa Giorgos Verigakis
        d['created'] = util.isoformat(vm.created)
127 d8e50a39 Giorgos Verigakis
        d['flavorRef'] = vm.flavor.id
128 d8e50a39 Giorgos Verigakis
        d['imageRef'] = vm.sourceimage.id
129 aa197ee4 Vangelis Koukis
130 d8e50a39 Giorgos Verigakis
        metadata = metadata_to_dict(vm)
131 7e2f9d4b Giorgos Verigakis
        if metadata:
132 b9a77976 Giorgos Verigakis
            d['metadata'] = {'values': metadata}
133 aa197ee4 Vangelis Koukis
134 d44c236b Giorgos Verigakis
        addresses = [nic_to_dict(nic) for nic in vm.nics.all()]
135 207b70d5 Giorgos Verigakis
        if addresses:
136 207b70d5 Giorgos Verigakis
            d['addresses'] = {'values': addresses}
137 7e2f9d4b Giorgos Verigakis
    return d
138 7e2f9d4b Giorgos Verigakis
139 d8e50a39 Giorgos Verigakis
140 d8e50a39 Giorgos Verigakis
def render_server(request, server, status=200):
141 d8e50a39 Giorgos Verigakis
    if request.serialization == 'xml':
142 b36f78fa Giorgos Verigakis
        data = render_to_string('server.xml', {
143 b36f78fa Giorgos Verigakis
            'server': server,
144 b36f78fa Giorgos Verigakis
            'is_root': True})
145 7e2f9d4b Giorgos Verigakis
    else:
146 d8e50a39 Giorgos Verigakis
        data = json.dumps({'server': server})
147 c36934a7 Giorgos Verigakis
    return HttpResponse(data, status=status)
148 aa197ee4 Vangelis Koukis
149 7e2f9d4b Giorgos Verigakis
150 b36f78fa Giorgos Verigakis
@util.api_method('GET')
151 7e2f9d4b Giorgos Verigakis
def list_servers(request, detail=False):
152 7e2f9d4b Giorgos Verigakis
    # Normal Response Codes: 200, 203
153 7e2f9d4b Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
154 7e2f9d4b Giorgos Verigakis
    #                       serviceUnavailable (503),
155 7e2f9d4b Giorgos Verigakis
    #                       unauthorized (401),
156 7e2f9d4b Giorgos Verigakis
    #                       badRequest (400),
157 7e2f9d4b Giorgos Verigakis
    #                       overLimit (413)
158 2987cd8a Giorgos Verigakis
    
159 2987cd8a Giorgos Verigakis
    user_vms = VirtualMachine.objects.filter(owner=request.user)
160 b36f78fa Giorgos Verigakis
    since = util.isoparse(request.GET.get('changes-since'))
161 2987cd8a Giorgos Verigakis
    
162 d8e50a39 Giorgos Verigakis
    if since:
163 2987cd8a Giorgos Verigakis
        user_vms = user_vms.filter(updated__gte=since)
164 d8e50a39 Giorgos Verigakis
        if not user_vms:
165 d8e50a39 Giorgos Verigakis
            return HttpResponse(status=304)
166 d8e50a39 Giorgos Verigakis
    else:
167 2987cd8a Giorgos Verigakis
        user_vms = user_vms.filter(deleted=False)
168 b36f78fa Giorgos Verigakis
    
169 d8e50a39 Giorgos Verigakis
    servers = [vm_to_dict(server, detail) for server in user_vms]
170 aa197ee4 Vangelis Koukis
171 d8e50a39 Giorgos Verigakis
    if request.serialization == 'xml':
172 b36f78fa Giorgos Verigakis
        data = render_to_string('list_servers.xml', {
173 b36f78fa Giorgos Verigakis
            'servers': servers,
174 b36f78fa Giorgos Verigakis
            'detail': detail})
175 7e2f9d4b Giorgos Verigakis
    else:
176 c36934a7 Giorgos Verigakis
        data = json.dumps({'servers': {'values': servers}})
177 aa197ee4 Vangelis Koukis
178 c36934a7 Giorgos Verigakis
    return HttpResponse(data, status=200)
179 7e2f9d4b Giorgos Verigakis
180 b36f78fa Giorgos Verigakis
@util.api_method('POST')
181 7e2f9d4b Giorgos Verigakis
def create_server(request):
182 7e2f9d4b Giorgos Verigakis
    # Normal Response Code: 202
183 7e2f9d4b Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
184 7e2f9d4b Giorgos Verigakis
    #                       serviceUnavailable (503),
185 7e2f9d4b Giorgos Verigakis
    #                       unauthorized (401),
186 7e2f9d4b Giorgos Verigakis
    #                       badMediaType(415),
187 7e2f9d4b Giorgos Verigakis
    #                       itemNotFound (404),
188 7e2f9d4b Giorgos Verigakis
    #                       badRequest (400),
189 7e2f9d4b Giorgos Verigakis
    #                       serverCapacityUnavailable (503),
190 7e2f9d4b Giorgos Verigakis
    #                       overLimit (413)
191 aa197ee4 Vangelis Koukis
192 b36f78fa Giorgos Verigakis
    req = util.get_request_dict(request)
193 d44c236b Giorgos Verigakis
    owner = request.user
194 d44c236b Giorgos Verigakis
    
195 7e2f9d4b Giorgos Verigakis
    try:
196 7e2f9d4b Giorgos Verigakis
        server = req['server']
197 7e2f9d4b Giorgos Verigakis
        name = server['name']
198 bc855ce7 Giorgos Verigakis
        metadata = server.get('metadata', {})
199 bc855ce7 Giorgos Verigakis
        assert isinstance(metadata, dict)
200 529178b1 Giorgos Verigakis
        image_id = server['imageRef']
201 529178b1 Giorgos Verigakis
        flavor_id = server['flavorRef']
202 bc855ce7 Giorgos Verigakis
    except (KeyError, AssertionError):
203 ccd0d474 Giorgos Verigakis
        raise faults.BadRequest("Malformed request")
204 d44c236b Giorgos Verigakis
    
205 b36f78fa Giorgos Verigakis
    image = util.get_image(image_id, owner)
206 b36f78fa Giorgos Verigakis
    flavor = util.get_flavor(flavor_id)
207 b36f78fa Giorgos Verigakis
    password = util.random_password()
208 d44c236b Giorgos Verigakis
    
209 ccd0d474 Giorgos Verigakis
    count = VirtualMachine.objects.filter(owner=owner, deleted=False).count()
210 ccd0d474 Giorgos Verigakis
    if count >= settings.MAX_VMS_PER_USER:
211 ccd0d474 Giorgos Verigakis
        raise faults.OverLimit("Maximum number of servers reached")
212 ccd0d474 Giorgos Verigakis
    
213 d44c236b Giorgos Verigakis
    # We must save the VM instance now, so that it gets a valid vm.backend_id.
214 b36f78fa Giorgos Verigakis
    vm = VirtualMachine.objects.create(
215 b36f78fa Giorgos Verigakis
        name=name,
216 b36f78fa Giorgos Verigakis
        owner=owner,
217 b36f78fa Giorgos Verigakis
        sourceimage=image,
218 b36f78fa Giorgos Verigakis
        flavor=flavor)
219 d44c236b Giorgos Verigakis
    
220 1c03e74e Vangelis Koukis
    try:
221 1ef58e5b Constantinos Venetsanopoulos
        create_instance(vm, flavor, image, password)
222 4f598167 Giorgos Verigakis
    except GanetiApiError:
223 1c03e74e Vangelis Koukis
        vm.delete()
224 ccd0d474 Giorgos Verigakis
        raise faults.ServiceUnavailable("Could not create server")
225 aa197ee4 Vangelis Koukis
226 bc855ce7 Giorgos Verigakis
    for key, val in metadata.items():
227 b36f78fa Giorgos Verigakis
        VirtualMachineMetadata.objects.create(
228 b36f78fa Giorgos Verigakis
            meta_key=key,
229 b36f78fa Giorgos Verigakis
            meta_value=val,
230 b36f78fa Giorgos Verigakis
            vm=vm)
231 b36f78fa Giorgos Verigakis
    
232 55b7ee4f Georgios Gousios
    _log.info('created vm with %s cpus, %s ram and %s storage',
233 529178b1 Giorgos Verigakis
                    flavor.cpu, flavor.ram, flavor.disk)
234 aa197ee4 Vangelis Koukis
235 d8e50a39 Giorgos Verigakis
    server = vm_to_dict(vm, detail=True)
236 d8e50a39 Giorgos Verigakis
    server['status'] = 'BUILD'
237 529178b1 Giorgos Verigakis
    server['adminPass'] = password
238 d8e50a39 Giorgos Verigakis
    return render_server(request, server, status=202)
239 7e2f9d4b Giorgos Verigakis
240 b36f78fa Giorgos Verigakis
@util.api_method('GET')
241 7e2f9d4b Giorgos Verigakis
def get_server_details(request, server_id):
242 c36934a7 Giorgos Verigakis
    # Normal Response Codes: 200, 203
243 c36934a7 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
244 c36934a7 Giorgos Verigakis
    #                       serviceUnavailable (503),
245 c36934a7 Giorgos Verigakis
    #                       unauthorized (401),
246 c36934a7 Giorgos Verigakis
    #                       badRequest (400),
247 c36934a7 Giorgos Verigakis
    #                       itemNotFound (404),
248 c36934a7 Giorgos Verigakis
    #                       overLimit (413)
249 aa197ee4 Vangelis Koukis
250 b36f78fa Giorgos Verigakis
    vm = util.get_vm(server_id, request.user)
251 d8e50a39 Giorgos Verigakis
    server = vm_to_dict(vm, detail=True)
252 d8e50a39 Giorgos Verigakis
    return render_server(request, server)
253 7e2f9d4b Giorgos Verigakis
254 b36f78fa Giorgos Verigakis
@util.api_method('PUT')
255 c36934a7 Giorgos Verigakis
def update_server_name(request, server_id):
256 c36934a7 Giorgos Verigakis
    # Normal Response Code: 204
257 c36934a7 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
258 c36934a7 Giorgos Verigakis
    #                       serviceUnavailable (503),
259 c36934a7 Giorgos Verigakis
    #                       unauthorized (401),
260 c36934a7 Giorgos Verigakis
    #                       badRequest (400),
261 c36934a7 Giorgos Verigakis
    #                       badMediaType(415),
262 c36934a7 Giorgos Verigakis
    #                       itemNotFound (404),
263 c36934a7 Giorgos Verigakis
    #                       buildInProgress (409),
264 c36934a7 Giorgos Verigakis
    #                       overLimit (413)
265 aa197ee4 Vangelis Koukis
266 b36f78fa Giorgos Verigakis
    req = util.get_request_dict(request)
267 aa197ee4 Vangelis Koukis
268 7e2f9d4b Giorgos Verigakis
    try:
269 7e2f9d4b Giorgos Verigakis
        name = req['server']['name']
270 529178b1 Giorgos Verigakis
    except (TypeError, KeyError):
271 ccd0d474 Giorgos Verigakis
        raise faults.BadRequest("Malformed request")
272 aa197ee4 Vangelis Koukis
273 b36f78fa Giorgos Verigakis
    vm = util.get_vm(server_id, request.user)
274 d8e50a39 Giorgos Verigakis
    vm.name = name
275 d8e50a39 Giorgos Verigakis
    vm.save()
276 aa197ee4 Vangelis Koukis
277 7e2f9d4b Giorgos Verigakis
    return HttpResponse(status=204)
278 7e2f9d4b Giorgos Verigakis
279 b36f78fa Giorgos Verigakis
@util.api_method('DELETE')
280 7e2f9d4b Giorgos Verigakis
def delete_server(request, server_id):
281 c36934a7 Giorgos Verigakis
    # Normal Response Codes: 204
282 c36934a7 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
283 c36934a7 Giorgos Verigakis
    #                       serviceUnavailable (503),
284 c36934a7 Giorgos Verigakis
    #                       unauthorized (401),
285 c36934a7 Giorgos Verigakis
    #                       itemNotFound (404),
286 c36934a7 Giorgos Verigakis
    #                       unauthorized (401),
287 c36934a7 Giorgos Verigakis
    #                       buildInProgress (409),
288 c36934a7 Giorgos Verigakis
    #                       overLimit (413)
289 aa197ee4 Vangelis Koukis
290 b36f78fa Giorgos Verigakis
    vm = util.get_vm(server_id, request.user)
291 529178b1 Giorgos Verigakis
    delete_instance(vm)
292 7e2f9d4b Giorgos Verigakis
    return HttpResponse(status=204)
293 b016b476 Giorgos Verigakis
294 b36f78fa Giorgos Verigakis
@util.api_method('POST')
295 b016b476 Giorgos Verigakis
def server_action(request, server_id):
296 b36f78fa Giorgos Verigakis
    vm = util.get_vm(server_id, request.user)
297 b36f78fa Giorgos Verigakis
    req = util.get_request_dict(request)
298 b016b476 Giorgos Verigakis
    if len(req) != 1:
299 ccd0d474 Giorgos Verigakis
        raise faults.BadRequest("Malformed request")
300 aa197ee4 Vangelis Koukis
301 b016b476 Giorgos Verigakis
    key = req.keys()[0]
302 d8e50a39 Giorgos Verigakis
    val = req[key]
303 aa197ee4 Vangelis Koukis
304 d8e50a39 Giorgos Verigakis
    try:
305 d8e50a39 Giorgos Verigakis
        assert isinstance(val, dict)
306 20a51b1e Giorgos Verigakis
        return server_actions[key](request, vm, req[key])
307 d8e50a39 Giorgos Verigakis
    except KeyError:
308 ccd0d474 Giorgos Verigakis
        raise faults.BadRequest("Unknown action")
309 d8e50a39 Giorgos Verigakis
    except AssertionError:
310 ccd0d474 Giorgos Verigakis
        raise faults.BadRequest("Invalid argument")
311 b016b476 Giorgos Verigakis
312 b36f78fa Giorgos Verigakis
@util.api_method('GET')
313 b016b476 Giorgos Verigakis
def list_addresses(request, server_id):
314 b016b476 Giorgos Verigakis
    # Normal Response Codes: 200, 203
315 b016b476 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
316 b016b476 Giorgos Verigakis
    #                       serviceUnavailable (503),
317 b016b476 Giorgos Verigakis
    #                       unauthorized (401),
318 b016b476 Giorgos Verigakis
    #                       badRequest (400),
319 b016b476 Giorgos Verigakis
    #                       overLimit (413)
320 aa197ee4 Vangelis Koukis
321 b36f78fa Giorgos Verigakis
    vm = util.get_vm(server_id, request.user)
322 d44c236b Giorgos Verigakis
    addresses = [nic_to_dict(nic) for nic in vm.nics.all()]
323 d44c236b Giorgos Verigakis
    
324 d8e50a39 Giorgos Verigakis
    if request.serialization == 'xml':
325 b016b476 Giorgos Verigakis
        data = render_to_string('list_addresses.xml', {'addresses': addresses})
326 b016b476 Giorgos Verigakis
    else:
327 b016b476 Giorgos Verigakis
        data = json.dumps({'addresses': {'values': addresses}})
328 aa197ee4 Vangelis Koukis
329 b016b476 Giorgos Verigakis
    return HttpResponse(data, status=200)
330 b016b476 Giorgos Verigakis
331 b36f78fa Giorgos Verigakis
@util.api_method('GET')
332 b016b476 Giorgos Verigakis
def list_addresses_by_network(request, server_id, network_id):
333 b016b476 Giorgos Verigakis
    # Normal Response Codes: 200, 203
334 b016b476 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
335 b016b476 Giorgos Verigakis
    #                       serviceUnavailable (503),
336 b016b476 Giorgos Verigakis
    #                       unauthorized (401),
337 b016b476 Giorgos Verigakis
    #                       badRequest (400),
338 b016b476 Giorgos Verigakis
    #                       itemNotFound (404),
339 b016b476 Giorgos Verigakis
    #                       overLimit (413)
340 d44c236b Giorgos Verigakis
    
341 d44c236b Giorgos Verigakis
    owner = request.user
342 b36f78fa Giorgos Verigakis
    machine = util.get_vm(server_id, owner)
343 b36f78fa Giorgos Verigakis
    network = util.get_network(network_id, owner)
344 b36f78fa Giorgos Verigakis
    nic = util.get_nic(machine, network)
345 d44c236b Giorgos Verigakis
    address = nic_to_dict(nic)
346 d44c236b Giorgos Verigakis
    
347 d8e50a39 Giorgos Verigakis
    if request.serialization == 'xml':
348 b016b476 Giorgos Verigakis
        data = render_to_string('address.xml', {'address': address})
349 b016b476 Giorgos Verigakis
    else:
350 b016b476 Giorgos Verigakis
        data = json.dumps({'network': address})
351 aa197ee4 Vangelis Koukis
352 b016b476 Giorgos Verigakis
    return HttpResponse(data, status=200)
353 d8e50a39 Giorgos Verigakis
354 b36f78fa Giorgos Verigakis
@util.api_method('GET')
355 d8e50a39 Giorgos Verigakis
def list_metadata(request, server_id):
356 d8e50a39 Giorgos Verigakis
    # Normal Response Codes: 200, 203
357 d8e50a39 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
358 d8e50a39 Giorgos Verigakis
    #                       serviceUnavailable (503),
359 d8e50a39 Giorgos Verigakis
    #                       unauthorized (401),
360 d8e50a39 Giorgos Verigakis
    #                       badRequest (400),
361 d8e50a39 Giorgos Verigakis
    #                       overLimit (413)
362 d8e50a39 Giorgos Verigakis
363 b36f78fa Giorgos Verigakis
    vm = util.get_vm(server_id, request.user)
364 d8e50a39 Giorgos Verigakis
    metadata = metadata_to_dict(vm)
365 b36f78fa Giorgos Verigakis
    return util.render_metadata(request, metadata, use_values=True, status=200)
366 d8e50a39 Giorgos Verigakis
367 b36f78fa Giorgos Verigakis
@util.api_method('POST')
368 d8e50a39 Giorgos Verigakis
def update_metadata(request, server_id):
369 d8e50a39 Giorgos Verigakis
    # Normal Response Code: 201
370 d8e50a39 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
371 d8e50a39 Giorgos Verigakis
    #                       serviceUnavailable (503),
372 d8e50a39 Giorgos Verigakis
    #                       unauthorized (401),
373 d8e50a39 Giorgos Verigakis
    #                       badRequest (400),
374 d8e50a39 Giorgos Verigakis
    #                       buildInProgress (409),
375 d8e50a39 Giorgos Verigakis
    #                       badMediaType(415),
376 d8e50a39 Giorgos Verigakis
    #                       overLimit (413)
377 d8e50a39 Giorgos Verigakis
378 b36f78fa Giorgos Verigakis
    vm = util.get_vm(server_id, request.user)
379 b36f78fa Giorgos Verigakis
    req = util.get_request_dict(request)
380 d8e50a39 Giorgos Verigakis
    try:
381 d8e50a39 Giorgos Verigakis
        metadata = req['metadata']
382 d8e50a39 Giorgos Verigakis
        assert isinstance(metadata, dict)
383 d8e50a39 Giorgos Verigakis
    except (KeyError, AssertionError):
384 ccd0d474 Giorgos Verigakis
        raise faults.BadRequest("Malformed request")
385 aa197ee4 Vangelis Koukis
386 d8e50a39 Giorgos Verigakis
    updated = {}
387 aa197ee4 Vangelis Koukis
388 d8e50a39 Giorgos Verigakis
    for key, val in metadata.items():
389 d8e50a39 Giorgos Verigakis
        try:
390 d8e50a39 Giorgos Verigakis
            meta = VirtualMachineMetadata.objects.get(meta_key=key, vm=vm)
391 d8e50a39 Giorgos Verigakis
            meta.meta_value = val
392 d8e50a39 Giorgos Verigakis
            meta.save()
393 d8e50a39 Giorgos Verigakis
            updated[key] = val
394 d8e50a39 Giorgos Verigakis
        except VirtualMachineMetadata.DoesNotExist:
395 d8e50a39 Giorgos Verigakis
            pass    # Ignore non-existent metadata
396 5509b599 Giorgos Verigakis
    
397 5509b599 Giorgos Verigakis
    if updated:
398 5509b599 Giorgos Verigakis
        vm.save()
399 5509b599 Giorgos Verigakis
    
400 b36f78fa Giorgos Verigakis
    return util.render_metadata(request, updated, status=201)
401 d8e50a39 Giorgos Verigakis
402 b36f78fa Giorgos Verigakis
@util.api_method('GET')
403 d8e50a39 Giorgos Verigakis
def get_metadata_item(request, server_id, key):
404 d8e50a39 Giorgos Verigakis
    # Normal Response Codes: 200, 203
405 d8e50a39 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
406 d8e50a39 Giorgos Verigakis
    #                       serviceUnavailable (503),
407 d8e50a39 Giorgos Verigakis
    #                       unauthorized (401),
408 d8e50a39 Giorgos Verigakis
    #                       itemNotFound (404),
409 d8e50a39 Giorgos Verigakis
    #                       badRequest (400),
410 d8e50a39 Giorgos Verigakis
    #                       overLimit (413)
411 aa197ee4 Vangelis Koukis
412 b36f78fa Giorgos Verigakis
    vm = util.get_vm(server_id, request.user)
413 b36f78fa Giorgos Verigakis
    meta = util.get_vm_meta(vm, key)
414 b36f78fa Giorgos Verigakis
    return util.render_meta(request, meta, status=200)
415 d8e50a39 Giorgos Verigakis
416 b36f78fa Giorgos Verigakis
@util.api_method('PUT')
417 d8e50a39 Giorgos Verigakis
def create_metadata_item(request, server_id, key):
418 d8e50a39 Giorgos Verigakis
    # Normal Response Code: 201
419 d8e50a39 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
420 d8e50a39 Giorgos Verigakis
    #                       serviceUnavailable (503),
421 d8e50a39 Giorgos Verigakis
    #                       unauthorized (401),
422 d8e50a39 Giorgos Verigakis
    #                       itemNotFound (404),
423 d8e50a39 Giorgos Verigakis
    #                       badRequest (400),
424 d8e50a39 Giorgos Verigakis
    #                       buildInProgress (409),
425 d8e50a39 Giorgos Verigakis
    #                       badMediaType(415),
426 d8e50a39 Giorgos Verigakis
    #                       overLimit (413)
427 d8e50a39 Giorgos Verigakis
428 b36f78fa Giorgos Verigakis
    vm = util.get_vm(server_id, request.user)
429 b36f78fa Giorgos Verigakis
    req = util.get_request_dict(request)
430 d8e50a39 Giorgos Verigakis
    try:
431 d8e50a39 Giorgos Verigakis
        metadict = req['meta']
432 d8e50a39 Giorgos Verigakis
        assert isinstance(metadict, dict)
433 d8e50a39 Giorgos Verigakis
        assert len(metadict) == 1
434 d8e50a39 Giorgos Verigakis
        assert key in metadict
435 d8e50a39 Giorgos Verigakis
    except (KeyError, AssertionError):
436 ccd0d474 Giorgos Verigakis
        raise faults.BadRequest("Malformed request")
437 b36f78fa Giorgos Verigakis
    
438 b36f78fa Giorgos Verigakis
    meta, created = VirtualMachineMetadata.objects.get_or_create(
439 b36f78fa Giorgos Verigakis
        meta_key=key,
440 b36f78fa Giorgos Verigakis
        vm=vm)
441 b36f78fa Giorgos Verigakis
    
442 d8e50a39 Giorgos Verigakis
    meta.meta_value = metadict[key]
443 d8e50a39 Giorgos Verigakis
    meta.save()
444 5509b599 Giorgos Verigakis
    vm.save()
445 b36f78fa Giorgos Verigakis
    return util.render_meta(request, meta, status=201)
446 d8e50a39 Giorgos Verigakis
447 b36f78fa Giorgos Verigakis
@util.api_method('DELETE')
448 d8e50a39 Giorgos Verigakis
def delete_metadata_item(request, server_id, key):
449 d8e50a39 Giorgos Verigakis
    # Normal Response Code: 204
450 d8e50a39 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
451 d8e50a39 Giorgos Verigakis
    #                       serviceUnavailable (503),
452 d8e50a39 Giorgos Verigakis
    #                       unauthorized (401),
453 d8e50a39 Giorgos Verigakis
    #                       itemNotFound (404),
454 d8e50a39 Giorgos Verigakis
    #                       badRequest (400),
455 d8e50a39 Giorgos Verigakis
    #                       buildInProgress (409),
456 d8e50a39 Giorgos Verigakis
    #                       badMediaType(415),
457 d8e50a39 Giorgos Verigakis
    #                       overLimit (413),
458 aa197ee4 Vangelis Koukis
459 b36f78fa Giorgos Verigakis
    vm = util.get_vm(server_id, request.user)
460 b36f78fa Giorgos Verigakis
    meta = util.get_vm_meta(vm, key)
461 d8e50a39 Giorgos Verigakis
    meta.delete()
462 5509b599 Giorgos Verigakis
    vm.save()
463 d8e50a39 Giorgos Verigakis
    return HttpResponse(status=204)
464 c738c935 Giorgos Verigakis
465 c738c935 Giorgos Verigakis
@util.api_method('GET')
466 c738c935 Giorgos Verigakis
def server_stats(request, server_id):
467 c738c935 Giorgos Verigakis
    # Normal Response Codes: 200
468 c738c935 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
469 c738c935 Giorgos Verigakis
    #                       serviceUnavailable (503),
470 c738c935 Giorgos Verigakis
    #                       unauthorized (401),
471 c738c935 Giorgos Verigakis
    #                       badRequest (400),
472 c738c935 Giorgos Verigakis
    #                       itemNotFound (404),
473 c738c935 Giorgos Verigakis
    #                       overLimit (413)
474 c738c935 Giorgos Verigakis
    
475 c738c935 Giorgos Verigakis
    vm = util.get_vm(server_id, request.user)
476 5391d6b5 Giorgos Verigakis
    #secret = util.encrypt(vm.backend_id)
477 5391d6b5 Giorgos Verigakis
    secret = vm.backend_id      # XXX disable backend id encryption
478 c738c935 Giorgos Verigakis
    
479 c738c935 Giorgos Verigakis
    stats = {
480 c738c935 Giorgos Verigakis
        'serverRef': vm.id,
481 c738c935 Giorgos Verigakis
        'refresh': settings.STATS_REFRESH_PERIOD,
482 5391d6b5 Giorgos Verigakis
        'cpuBar': settings.CPU_BAR_GRAPH_URL % secret,
483 5391d6b5 Giorgos Verigakis
        'cpuTimeSeries': settings.CPU_TIMESERIES_GRAPH_URL % secret,
484 5391d6b5 Giorgos Verigakis
        'netBar': settings.NET_BAR_GRAPH_URL % secret,
485 5391d6b5 Giorgos Verigakis
        'netTimeSeries': settings.NET_TIMESERIES_GRAPH_URL % secret}
486 c738c935 Giorgos Verigakis
    
487 c738c935 Giorgos Verigakis
    if request.serialization == 'xml':
488 c738c935 Giorgos Verigakis
        data = render_to_string('server_stats.xml', stats)
489 c738c935 Giorgos Verigakis
    else:
490 c738c935 Giorgos Verigakis
        data = json.dumps({'stats': stats})
491 c738c935 Giorgos Verigakis
492 c738c935 Giorgos Verigakis
    return HttpResponse(data, status=200)