Statistics
| Branch: | Tag: | Revision:

root / snf-cyclades-app / synnefo / api / servers.py @ bb54871d

History | View | Annotate | Download (19.3 kB)

1 6ef51e9f Giorgos Verigakis
# Copyright 2011-2012 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 fc443bcd Giorgos Verigakis
from base64 import b64decode
35 2035039b Giorgos Verigakis
from logging import getLogger
36 fc443bcd Giorgos Verigakis
37 ccd0d474 Giorgos Verigakis
from django.conf import settings
38 d8e50a39 Giorgos Verigakis
from django.conf.urls.defaults import patterns
39 7e2f9d4b Giorgos Verigakis
from django.http import HttpResponse
40 7e2f9d4b Giorgos Verigakis
from django.template.loader import render_to_string
41 29a59bc1 Giorgos Verigakis
from django.utils import simplejson as json
42 7e2f9d4b Giorgos Verigakis
43 ccd0d474 Giorgos Verigakis
from synnefo.api import faults, util
44 0971fa71 Markos Gogoulos
from synnefo.api.actions import server_actions
45 d8e50a39 Giorgos Verigakis
from synnefo.api.common import method_not_allowed
46 529178b1 Giorgos Verigakis
from synnefo.db.models import VirtualMachine, VirtualMachineMetadata
47 529178b1 Giorgos Verigakis
from synnefo.logic.backend import create_instance, delete_instance
48 d8e50a39 Giorgos Verigakis
from synnefo.logic.utils import get_rsapi_state
49 529178b1 Giorgos Verigakis
from synnefo.util.rapi import GanetiApiError
50 7e2f9d4b Giorgos Verigakis
51 9e98ba3c Giorgos Verigakis
52 9e98ba3c Giorgos Verigakis
log = getLogger('synnefo.api')
53 7e2f9d4b Giorgos Verigakis
54 7e2f9d4b Giorgos Verigakis
urlpatterns = patterns('synnefo.api.servers',
55 7e2f9d4b Giorgos Verigakis
    (r'^(?:/|.json|.xml)?$', 'demux'),
56 7e2f9d4b Giorgos Verigakis
    (r'^/detail(?:.json|.xml)?$', 'list_servers', {'detail': True}),
57 7e2f9d4b Giorgos Verigakis
    (r'^/(\d+)(?:.json|.xml)?$', 'server_demux'),
58 b016b476 Giorgos Verigakis
    (r'^/(\d+)/action(?:.json|.xml)?$', 'server_action'),
59 b016b476 Giorgos Verigakis
    (r'^/(\d+)/ips(?:.json|.xml)?$', 'list_addresses'),
60 b016b476 Giorgos Verigakis
    (r'^/(\d+)/ips/(.+?)(?:.json|.xml)?$', 'list_addresses_by_network'),
61 d8e50a39 Giorgos Verigakis
    (r'^/(\d+)/meta(?:.json|.xml)?$', 'metadata_demux'),
62 d8e50a39 Giorgos Verigakis
    (r'^/(\d+)/meta/(.+?)(?:.json|.xml)?$', 'metadata_item_demux'),
63 c738c935 Giorgos Verigakis
    (r'^/(\d+)/stats(?:.json|.xml)?$', 'server_stats'),
64 7e2f9d4b Giorgos Verigakis
)
65 7e2f9d4b Giorgos Verigakis
66 7e2f9d4b Giorgos Verigakis
67 7e2f9d4b Giorgos Verigakis
def demux(request):
68 7e2f9d4b Giorgos Verigakis
    if request.method == 'GET':
69 7e2f9d4b Giorgos Verigakis
        return list_servers(request)
70 7e2f9d4b Giorgos Verigakis
    elif request.method == 'POST':
71 7e2f9d4b Giorgos Verigakis
        return create_server(request)
72 7e2f9d4b Giorgos Verigakis
    else:
73 d8e50a39 Giorgos Verigakis
        return method_not_allowed(request)
74 7e2f9d4b Giorgos Verigakis
75 55cd40be Vangelis Koukis
76 7e2f9d4b Giorgos Verigakis
def server_demux(request, server_id):
77 7e2f9d4b Giorgos Verigakis
    if request.method == 'GET':
78 7e2f9d4b Giorgos Verigakis
        return get_server_details(request, server_id)
79 7e2f9d4b Giorgos Verigakis
    elif request.method == 'PUT':
80 7e2f9d4b Giorgos Verigakis
        return update_server_name(request, server_id)
81 7e2f9d4b Giorgos Verigakis
    elif request.method == 'DELETE':
82 7e2f9d4b Giorgos Verigakis
        return delete_server(request, server_id)
83 7e2f9d4b Giorgos Verigakis
    else:
84 d8e50a39 Giorgos Verigakis
        return method_not_allowed(request)
85 d8e50a39 Giorgos Verigakis
86 55cd40be Vangelis Koukis
87 d8e50a39 Giorgos Verigakis
def metadata_demux(request, server_id):
88 d8e50a39 Giorgos Verigakis
    if request.method == 'GET':
89 d8e50a39 Giorgos Verigakis
        return list_metadata(request, server_id)
90 d8e50a39 Giorgos Verigakis
    elif request.method == 'POST':
91 d8e50a39 Giorgos Verigakis
        return update_metadata(request, server_id)
92 d8e50a39 Giorgos Verigakis
    else:
93 d8e50a39 Giorgos Verigakis
        return method_not_allowed(request)
94 d8e50a39 Giorgos Verigakis
95 55cd40be Vangelis Koukis
96 d8e50a39 Giorgos Verigakis
def metadata_item_demux(request, server_id, key):
97 d8e50a39 Giorgos Verigakis
    if request.method == 'GET':
98 d8e50a39 Giorgos Verigakis
        return get_metadata_item(request, server_id, key)
99 d8e50a39 Giorgos Verigakis
    elif request.method == 'PUT':
100 d8e50a39 Giorgos Verigakis
        return create_metadata_item(request, server_id, key)
101 d8e50a39 Giorgos Verigakis
    elif request.method == 'DELETE':
102 d8e50a39 Giorgos Verigakis
        return delete_metadata_item(request, server_id, key)
103 d8e50a39 Giorgos Verigakis
    else:
104 d8e50a39 Giorgos Verigakis
        return method_not_allowed(request)
105 7e2f9d4b Giorgos Verigakis
106 c36934a7 Giorgos Verigakis
107 d44c236b Giorgos Verigakis
def nic_to_dict(nic):
108 207b70d5 Giorgos Verigakis
    network = nic.network
109 207b70d5 Giorgos Verigakis
    network_id = str(network.id) if not network.public else 'public'
110 207b70d5 Giorgos Verigakis
    d = {'id': network_id, 'name': network.name, 'mac': nic.mac}
111 207b70d5 Giorgos Verigakis
    if nic.firewall_profile:
112 207b70d5 Giorgos Verigakis
        d['firewallProfile'] = nic.firewall_profile
113 d44c236b Giorgos Verigakis
    if nic.ipv4 or nic.ipv6:
114 797e88b3 Giorgos Verigakis
        d['values'] = []
115 797e88b3 Giorgos Verigakis
        if nic.ipv4:
116 797e88b3 Giorgos Verigakis
            d['values'].append({'version': 4, 'addr': nic.ipv4})
117 797e88b3 Giorgos Verigakis
        if nic.ipv6:
118 797e88b3 Giorgos Verigakis
            d['values'].append({'version': 6, 'addr': nic.ipv6})
119 d44c236b Giorgos Verigakis
    return d
120 b016b476 Giorgos Verigakis
121 55cd40be Vangelis Koukis
122 d8e50a39 Giorgos Verigakis
def vm_to_dict(vm, detail=False):
123 d8e50a39 Giorgos Verigakis
    d = dict(id=vm.id, name=vm.name)
124 7e2f9d4b Giorgos Verigakis
    if detail:
125 d8e50a39 Giorgos Verigakis
        d['status'] = get_rsapi_state(vm)
126 19da4325 Vangelis Koukis
        d['progress'] = 100 if get_rsapi_state(vm) == 'ACTIVE' \
127 19da4325 Vangelis Koukis
                        else vm.buildpercentage
128 d8e50a39 Giorgos Verigakis
        d['hostId'] = vm.hostid
129 b36f78fa Giorgos Verigakis
        d['updated'] = util.isoformat(vm.updated)
130 b36f78fa Giorgos Verigakis
        d['created'] = util.isoformat(vm.created)
131 d8e50a39 Giorgos Verigakis
        d['flavorRef'] = vm.flavor.id
132 936afb7b Giorgos Verigakis
        d['imageRef'] = vm.imageid
133 7cc3c7d9 Giorgos Verigakis
        
134 7cc3c7d9 Giorgos Verigakis
        metadata = dict((m.meta_key, m.meta_value) for m in vm.metadata.all())
135 7e2f9d4b Giorgos Verigakis
        if metadata:
136 b9a77976 Giorgos Verigakis
            d['metadata'] = {'values': metadata}
137 aa197ee4 Vangelis Koukis
138 d44c236b Giorgos Verigakis
        addresses = [nic_to_dict(nic) for nic in vm.nics.all()]
139 207b70d5 Giorgos Verigakis
        if addresses:
140 207b70d5 Giorgos Verigakis
            d['addresses'] = {'values': addresses}
141 7e2f9d4b Giorgos Verigakis
    return d
142 7e2f9d4b Giorgos Verigakis
143 d8e50a39 Giorgos Verigakis
144 d8e50a39 Giorgos Verigakis
def render_server(request, server, status=200):
145 d8e50a39 Giorgos Verigakis
    if request.serialization == 'xml':
146 b36f78fa Giorgos Verigakis
        data = render_to_string('server.xml', {
147 b36f78fa Giorgos Verigakis
            'server': server,
148 b36f78fa Giorgos Verigakis
            'is_root': True})
149 7e2f9d4b Giorgos Verigakis
    else:
150 d8e50a39 Giorgos Verigakis
        data = json.dumps({'server': server})
151 c36934a7 Giorgos Verigakis
    return HttpResponse(data, status=status)
152 aa197ee4 Vangelis Koukis
153 7e2f9d4b Giorgos Verigakis
154 b36f78fa Giorgos Verigakis
@util.api_method('GET')
155 7e2f9d4b Giorgos Verigakis
def list_servers(request, detail=False):
156 7e2f9d4b Giorgos Verigakis
    # Normal Response Codes: 200, 203
157 7e2f9d4b Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
158 7e2f9d4b Giorgos Verigakis
    #                       serviceUnavailable (503),
159 7e2f9d4b Giorgos Verigakis
    #                       unauthorized (401),
160 7e2f9d4b Giorgos Verigakis
    #                       badRequest (400),
161 7e2f9d4b Giorgos Verigakis
    #                       overLimit (413)
162 2987cd8a Giorgos Verigakis
    
163 9e98ba3c Giorgos Verigakis
    log.debug('list_servers detail=%s', detail)
164 4b3b8688 Giorgos Verigakis
    user_vms = VirtualMachine.objects.filter(userid=request.user_uniq)
165 b36f78fa Giorgos Verigakis
    since = util.isoparse(request.GET.get('changes-since'))
166 2987cd8a Giorgos Verigakis
    
167 d8e50a39 Giorgos Verigakis
    if since:
168 2987cd8a Giorgos Verigakis
        user_vms = user_vms.filter(updated__gte=since)
169 d8e50a39 Giorgos Verigakis
        if not user_vms:
170 d8e50a39 Giorgos Verigakis
            return HttpResponse(status=304)
171 d8e50a39 Giorgos Verigakis
    else:
172 2987cd8a Giorgos Verigakis
        user_vms = user_vms.filter(deleted=False)
173 b36f78fa Giorgos Verigakis
    
174 d8e50a39 Giorgos Verigakis
    servers = [vm_to_dict(server, detail) for server in user_vms]
175 aa197ee4 Vangelis Koukis
176 d8e50a39 Giorgos Verigakis
    if request.serialization == 'xml':
177 b36f78fa Giorgos Verigakis
        data = render_to_string('list_servers.xml', {
178 b36f78fa Giorgos Verigakis
            'servers': servers,
179 b36f78fa Giorgos Verigakis
            'detail': detail})
180 7e2f9d4b Giorgos Verigakis
    else:
181 c36934a7 Giorgos Verigakis
        data = json.dumps({'servers': {'values': servers}})
182 aa197ee4 Vangelis Koukis
183 c36934a7 Giorgos Verigakis
    return HttpResponse(data, status=200)
184 7e2f9d4b Giorgos Verigakis
185 55cd40be Vangelis Koukis
186 b36f78fa Giorgos Verigakis
@util.api_method('POST')
187 7e2f9d4b Giorgos Verigakis
def create_server(request):
188 7e2f9d4b Giorgos Verigakis
    # Normal Response Code: 202
189 7e2f9d4b Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
190 7e2f9d4b Giorgos Verigakis
    #                       serviceUnavailable (503),
191 7e2f9d4b Giorgos Verigakis
    #                       unauthorized (401),
192 7e2f9d4b Giorgos Verigakis
    #                       badMediaType(415),
193 7e2f9d4b Giorgos Verigakis
    #                       itemNotFound (404),
194 7e2f9d4b Giorgos Verigakis
    #                       badRequest (400),
195 7e2f9d4b Giorgos Verigakis
    #                       serverCapacityUnavailable (503),
196 7e2f9d4b Giorgos Verigakis
    #                       overLimit (413)
197 aa197ee4 Vangelis Koukis
198 b36f78fa Giorgos Verigakis
    req = util.get_request_dict(request)
199 9e98ba3c Giorgos Verigakis
    log.debug('create_server %s', req)
200 d44c236b Giorgos Verigakis
    
201 7e2f9d4b Giorgos Verigakis
    try:
202 7e2f9d4b Giorgos Verigakis
        server = req['server']
203 7e2f9d4b Giorgos Verigakis
        name = server['name']
204 bc855ce7 Giorgos Verigakis
        metadata = server.get('metadata', {})
205 bc855ce7 Giorgos Verigakis
        assert isinstance(metadata, dict)
206 529178b1 Giorgos Verigakis
        image_id = server['imageRef']
207 529178b1 Giorgos Verigakis
        flavor_id = server['flavorRef']
208 0419e0c1 Giorgos Verigakis
        personality = server.get('personality', [])
209 2b1db26f Giorgos Verigakis
        assert isinstance(personality, list)
210 bc855ce7 Giorgos Verigakis
    except (KeyError, AssertionError):
211 ccd0d474 Giorgos Verigakis
        raise faults.BadRequest("Malformed request")
212 d44c236b Giorgos Verigakis
    
213 fc443bcd Giorgos Verigakis
    if len(personality) > settings.MAX_PERSONALITY:
214 fc443bcd Giorgos Verigakis
        raise faults.OverLimit("Maximum number of personalities exceeded")
215 fc443bcd Giorgos Verigakis
    
216 fc443bcd Giorgos Verigakis
    for p in personality:
217 22a3918c Giorgos Verigakis
        # Verify that personalities are well-formed
218 fc443bcd Giorgos Verigakis
        try:
219 fc443bcd Giorgos Verigakis
            assert isinstance(p, dict)
220 22a3918c Giorgos Verigakis
            keys = set(p.keys())
221 22a3918c Giorgos Verigakis
            allowed = set(['contents', 'group', 'mode', 'owner', 'path'])
222 22a3918c Giorgos Verigakis
            assert keys.issubset(allowed)
223 fc443bcd Giorgos Verigakis
            contents = p['contents']
224 fc443bcd Giorgos Verigakis
            if len(contents) > settings.MAX_PERSONALITY_SIZE:
225 fc443bcd Giorgos Verigakis
                # No need to decode if contents already exceed limit
226 fc443bcd Giorgos Verigakis
                raise faults.OverLimit("Maximum size of personality exceeded")
227 fc443bcd Giorgos Verigakis
            if len(b64decode(contents)) > settings.MAX_PERSONALITY_SIZE:
228 fc443bcd Giorgos Verigakis
                raise faults.OverLimit("Maximum size of personality exceeded")
229 fc443bcd Giorgos Verigakis
        except AssertionError:
230 fc443bcd Giorgos Verigakis
            raise faults.BadRequest("Malformed personality in request")
231 fc443bcd Giorgos Verigakis
    
232 3a9b3cde Giorgos Verigakis
    image = {}
233 4b3b8688 Giorgos Verigakis
    img = util.get_image(image_id, request.user_uniq)
234 6ef51e9f Giorgos Verigakis
    properties = img.get('properties', {})
235 6ef51e9f Giorgos Verigakis
    image['backend_id'] = img['location']
236 6ef51e9f Giorgos Verigakis
    image['format'] = img['disk_format']
237 6ef51e9f Giorgos Verigakis
    image['metadata'] = dict((key.upper(), val) \
238 6ef51e9f Giorgos Verigakis
                             for key, val in properties.items())
239 3a9b3cde Giorgos Verigakis
    
240 b36f78fa Giorgos Verigakis
    flavor = util.get_flavor(flavor_id)
241 b36f78fa Giorgos Verigakis
    password = util.random_password()
242 d44c236b Giorgos Verigakis
    
243 4b3b8688 Giorgos Verigakis
    count = VirtualMachine.objects.filter(userid=request.user_uniq,
244 6ef51e9f Giorgos Verigakis
                                          deleted=False).count()
245 ccd0d474 Giorgos Verigakis
    if count >= settings.MAX_VMS_PER_USER:
246 856804af Vangelis Koukis
        raise faults.OverLimit("Server count limit exceeded for your account.")
247 ccd0d474 Giorgos Verigakis
    
248 d44c236b Giorgos Verigakis
    # We must save the VM instance now, so that it gets a valid vm.backend_id.
249 b36f78fa Giorgos Verigakis
    vm = VirtualMachine.objects.create(
250 b36f78fa Giorgos Verigakis
        name=name,
251 4b3b8688 Giorgos Verigakis
        userid=request.user_uniq,
252 3a9b3cde Giorgos Verigakis
        imageid=image_id,
253 b36f78fa Giorgos Verigakis
        flavor=flavor)
254 d44c236b Giorgos Verigakis
    
255 1c03e74e Vangelis Koukis
    try:
256 2b1db26f Giorgos Verigakis
        create_instance(vm, flavor, image, password, personality)
257 4f598167 Giorgos Verigakis
    except GanetiApiError:
258 1c03e74e Vangelis Koukis
        vm.delete()
259 510d53b5 Vangelis Koukis
        raise
260 aa197ee4 Vangelis Koukis
261 bc855ce7 Giorgos Verigakis
    for key, val in metadata.items():
262 b36f78fa Giorgos Verigakis
        VirtualMachineMetadata.objects.create(
263 b36f78fa Giorgos Verigakis
            meta_key=key,
264 b36f78fa Giorgos Verigakis
            meta_value=val,
265 b36f78fa Giorgos Verigakis
            vm=vm)
266 b36f78fa Giorgos Verigakis
    
267 6ef51e9f Giorgos Verigakis
    log.info('User %s created vm with %s cpus, %s ram and %s storage',
268 4b3b8688 Giorgos Verigakis
             request.user_uniq, flavor.cpu, flavor.ram, flavor.disk)
269 9e98ba3c Giorgos Verigakis
    
270 d8e50a39 Giorgos Verigakis
    server = vm_to_dict(vm, detail=True)
271 d8e50a39 Giorgos Verigakis
    server['status'] = 'BUILD'
272 529178b1 Giorgos Verigakis
    server['adminPass'] = password
273 d8e50a39 Giorgos Verigakis
    return render_server(request, server, status=202)
274 7e2f9d4b Giorgos Verigakis
275 55cd40be Vangelis Koukis
276 b36f78fa Giorgos Verigakis
@util.api_method('GET')
277 7e2f9d4b Giorgos Verigakis
def get_server_details(request, server_id):
278 c36934a7 Giorgos Verigakis
    # Normal Response Codes: 200, 203
279 c36934a7 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
280 c36934a7 Giorgos Verigakis
    #                       serviceUnavailable (503),
281 c36934a7 Giorgos Verigakis
    #                       unauthorized (401),
282 c36934a7 Giorgos Verigakis
    #                       badRequest (400),
283 c36934a7 Giorgos Verigakis
    #                       itemNotFound (404),
284 c36934a7 Giorgos Verigakis
    #                       overLimit (413)
285 9e98ba3c Giorgos Verigakis
    
286 9e98ba3c Giorgos Verigakis
    log.debug('get_server_details %s', server_id)
287 4b3b8688 Giorgos Verigakis
    vm = util.get_vm(server_id, request.user_uniq)
288 d8e50a39 Giorgos Verigakis
    server = vm_to_dict(vm, detail=True)
289 d8e50a39 Giorgos Verigakis
    return render_server(request, server)
290 7e2f9d4b Giorgos Verigakis
291 55cd40be Vangelis Koukis
292 b36f78fa Giorgos Verigakis
@util.api_method('PUT')
293 c36934a7 Giorgos Verigakis
def update_server_name(request, server_id):
294 c36934a7 Giorgos Verigakis
    # Normal Response Code: 204
295 c36934a7 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
296 c36934a7 Giorgos Verigakis
    #                       serviceUnavailable (503),
297 c36934a7 Giorgos Verigakis
    #                       unauthorized (401),
298 c36934a7 Giorgos Verigakis
    #                       badRequest (400),
299 c36934a7 Giorgos Verigakis
    #                       badMediaType(415),
300 c36934a7 Giorgos Verigakis
    #                       itemNotFound (404),
301 c36934a7 Giorgos Verigakis
    #                       buildInProgress (409),
302 c36934a7 Giorgos Verigakis
    #                       overLimit (413)
303 aa197ee4 Vangelis Koukis
304 b36f78fa Giorgos Verigakis
    req = util.get_request_dict(request)
305 9e98ba3c Giorgos Verigakis
    log.debug('update_server_name %s %s', server_id, req)
306 9e98ba3c Giorgos Verigakis
    
307 7e2f9d4b Giorgos Verigakis
    try:
308 7e2f9d4b Giorgos Verigakis
        name = req['server']['name']
309 529178b1 Giorgos Verigakis
    except (TypeError, KeyError):
310 ccd0d474 Giorgos Verigakis
        raise faults.BadRequest("Malformed request")
311 aa197ee4 Vangelis Koukis
312 4b3b8688 Giorgos Verigakis
    vm = util.get_vm(server_id, request.user_uniq)
313 d8e50a39 Giorgos Verigakis
    vm.name = name
314 d8e50a39 Giorgos Verigakis
    vm.save()
315 aa197ee4 Vangelis Koukis
316 7e2f9d4b Giorgos Verigakis
    return HttpResponse(status=204)
317 7e2f9d4b Giorgos Verigakis
318 55cd40be Vangelis Koukis
319 b36f78fa Giorgos Verigakis
@util.api_method('DELETE')
320 7e2f9d4b Giorgos Verigakis
def delete_server(request, server_id):
321 c36934a7 Giorgos Verigakis
    # Normal Response Codes: 204
322 c36934a7 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
323 c36934a7 Giorgos Verigakis
    #                       serviceUnavailable (503),
324 c36934a7 Giorgos Verigakis
    #                       unauthorized (401),
325 c36934a7 Giorgos Verigakis
    #                       itemNotFound (404),
326 c36934a7 Giorgos Verigakis
    #                       unauthorized (401),
327 c36934a7 Giorgos Verigakis
    #                       buildInProgress (409),
328 c36934a7 Giorgos Verigakis
    #                       overLimit (413)
329 9e98ba3c Giorgos Verigakis
    
330 9e98ba3c Giorgos Verigakis
    log.debug('delete_server %s', server_id)
331 4b3b8688 Giorgos Verigakis
    vm = util.get_vm(server_id, request.user_uniq)
332 529178b1 Giorgos Verigakis
    delete_instance(vm)
333 7e2f9d4b Giorgos Verigakis
    return HttpResponse(status=204)
334 b016b476 Giorgos Verigakis
335 55cd40be Vangelis Koukis
336 b36f78fa Giorgos Verigakis
@util.api_method('POST')
337 b016b476 Giorgos Verigakis
def server_action(request, server_id):
338 b36f78fa Giorgos Verigakis
    req = util.get_request_dict(request)
339 9e98ba3c Giorgos Verigakis
    log.debug('server_action %s %s', server_id, req)
340 4b3b8688 Giorgos Verigakis
    vm = util.get_vm(server_id, request.user_uniq)
341 b016b476 Giorgos Verigakis
    if len(req) != 1:
342 ccd0d474 Giorgos Verigakis
        raise faults.BadRequest("Malformed request")
343 aa197ee4 Vangelis Koukis
344 b016b476 Giorgos Verigakis
    key = req.keys()[0]
345 d8e50a39 Giorgos Verigakis
    val = req[key]
346 aa197ee4 Vangelis Koukis
347 d8e50a39 Giorgos Verigakis
    try:
348 d8e50a39 Giorgos Verigakis
        assert isinstance(val, dict)
349 20a51b1e Giorgos Verigakis
        return server_actions[key](request, vm, req[key])
350 d8e50a39 Giorgos Verigakis
    except KeyError:
351 ccd0d474 Giorgos Verigakis
        raise faults.BadRequest("Unknown action")
352 d8e50a39 Giorgos Verigakis
    except AssertionError:
353 ccd0d474 Giorgos Verigakis
        raise faults.BadRequest("Invalid argument")
354 b016b476 Giorgos Verigakis
355 55cd40be Vangelis Koukis
356 b36f78fa Giorgos Verigakis
@util.api_method('GET')
357 b016b476 Giorgos Verigakis
def list_addresses(request, server_id):
358 b016b476 Giorgos Verigakis
    # Normal Response Codes: 200, 203
359 b016b476 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
360 b016b476 Giorgos Verigakis
    #                       serviceUnavailable (503),
361 b016b476 Giorgos Verigakis
    #                       unauthorized (401),
362 b016b476 Giorgos Verigakis
    #                       badRequest (400),
363 b016b476 Giorgos Verigakis
    #                       overLimit (413)
364 9e98ba3c Giorgos Verigakis
    
365 9e98ba3c Giorgos Verigakis
    log.debug('list_addresses %s', server_id)
366 4b3b8688 Giorgos Verigakis
    vm = util.get_vm(server_id, request.user_uniq)
367 d44c236b Giorgos Verigakis
    addresses = [nic_to_dict(nic) for nic in vm.nics.all()]
368 d44c236b Giorgos Verigakis
    
369 d8e50a39 Giorgos Verigakis
    if request.serialization == 'xml':
370 b016b476 Giorgos Verigakis
        data = render_to_string('list_addresses.xml', {'addresses': addresses})
371 b016b476 Giorgos Verigakis
    else:
372 b016b476 Giorgos Verigakis
        data = json.dumps({'addresses': {'values': addresses}})
373 aa197ee4 Vangelis Koukis
374 b016b476 Giorgos Verigakis
    return HttpResponse(data, status=200)
375 b016b476 Giorgos Verigakis
376 55cd40be Vangelis Koukis
377 b36f78fa Giorgos Verigakis
@util.api_method('GET')
378 b016b476 Giorgos Verigakis
def list_addresses_by_network(request, server_id, network_id):
379 b016b476 Giorgos Verigakis
    # Normal Response Codes: 200, 203
380 b016b476 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
381 b016b476 Giorgos Verigakis
    #                       serviceUnavailable (503),
382 b016b476 Giorgos Verigakis
    #                       unauthorized (401),
383 b016b476 Giorgos Verigakis
    #                       badRequest (400),
384 b016b476 Giorgos Verigakis
    #                       itemNotFound (404),
385 b016b476 Giorgos Verigakis
    #                       overLimit (413)
386 d44c236b Giorgos Verigakis
    
387 9e98ba3c Giorgos Verigakis
    log.debug('list_addresses_by_network %s %s', server_id, network_id)
388 4b3b8688 Giorgos Verigakis
    machine = util.get_vm(server_id, request.user_uniq)
389 4b3b8688 Giorgos Verigakis
    network = util.get_network(network_id, request.user_uniq)
390 b36f78fa Giorgos Verigakis
    nic = util.get_nic(machine, network)
391 d44c236b Giorgos Verigakis
    address = nic_to_dict(nic)
392 d44c236b Giorgos Verigakis
    
393 d8e50a39 Giorgos Verigakis
    if request.serialization == 'xml':
394 b016b476 Giorgos Verigakis
        data = render_to_string('address.xml', {'address': address})
395 b016b476 Giorgos Verigakis
    else:
396 b016b476 Giorgos Verigakis
        data = json.dumps({'network': address})
397 aa197ee4 Vangelis Koukis
398 b016b476 Giorgos Verigakis
    return HttpResponse(data, status=200)
399 d8e50a39 Giorgos Verigakis
400 55cd40be Vangelis Koukis
401 b36f78fa Giorgos Verigakis
@util.api_method('GET')
402 d8e50a39 Giorgos Verigakis
def list_metadata(request, server_id):
403 d8e50a39 Giorgos Verigakis
    # Normal Response Codes: 200, 203
404 d8e50a39 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
405 d8e50a39 Giorgos Verigakis
    #                       serviceUnavailable (503),
406 d8e50a39 Giorgos Verigakis
    #                       unauthorized (401),
407 d8e50a39 Giorgos Verigakis
    #                       badRequest (400),
408 d8e50a39 Giorgos Verigakis
    #                       overLimit (413)
409 9e98ba3c Giorgos Verigakis
    
410 9e98ba3c Giorgos Verigakis
    log.debug('list_server_metadata %s', server_id)
411 4b3b8688 Giorgos Verigakis
    vm = util.get_vm(server_id, request.user_uniq)
412 7cc3c7d9 Giorgos Verigakis
    metadata = dict((m.meta_key, m.meta_value) for m in vm.metadata.all())
413 b36f78fa Giorgos Verigakis
    return util.render_metadata(request, metadata, use_values=True, status=200)
414 d8e50a39 Giorgos Verigakis
415 55cd40be Vangelis Koukis
416 b36f78fa Giorgos Verigakis
@util.api_method('POST')
417 d8e50a39 Giorgos Verigakis
def update_metadata(request, server_id):
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
    #                       badRequest (400),
423 d8e50a39 Giorgos Verigakis
    #                       buildInProgress (409),
424 d8e50a39 Giorgos Verigakis
    #                       badMediaType(415),
425 d8e50a39 Giorgos Verigakis
    #                       overLimit (413)
426 9e98ba3c Giorgos Verigakis
    
427 b36f78fa Giorgos Verigakis
    req = util.get_request_dict(request)
428 9e98ba3c Giorgos Verigakis
    log.debug('update_server_metadata %s %s', server_id, req)
429 4b3b8688 Giorgos Verigakis
    vm = util.get_vm(server_id, request.user_uniq)
430 d8e50a39 Giorgos Verigakis
    try:
431 d8e50a39 Giorgos Verigakis
        metadata = req['metadata']
432 d8e50a39 Giorgos Verigakis
        assert isinstance(metadata, dict)
433 d8e50a39 Giorgos Verigakis
    except (KeyError, AssertionError):
434 ccd0d474 Giorgos Verigakis
        raise faults.BadRequest("Malformed request")
435 5509b599 Giorgos Verigakis
    
436 7cc3c7d9 Giorgos Verigakis
    for key, val in metadata.items():
437 7cc3c7d9 Giorgos Verigakis
        meta, created = vm.metadata.get_or_create(meta_key=key)
438 7cc3c7d9 Giorgos Verigakis
        meta.meta_value = val
439 7cc3c7d9 Giorgos Verigakis
        meta.save()
440 5509b599 Giorgos Verigakis
    
441 7cc3c7d9 Giorgos Verigakis
    vm.save()
442 7cc3c7d9 Giorgos Verigakis
    vm_meta = dict((m.meta_key, m.meta_value) for m in vm.metadata.all())
443 7cc3c7d9 Giorgos Verigakis
    return util.render_metadata(request, vm_meta, status=201)
444 d8e50a39 Giorgos Verigakis
445 55cd40be Vangelis Koukis
446 b36f78fa Giorgos Verigakis
@util.api_method('GET')
447 d8e50a39 Giorgos Verigakis
def get_metadata_item(request, server_id, key):
448 d8e50a39 Giorgos Verigakis
    # Normal Response Codes: 200, 203
449 d8e50a39 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
450 d8e50a39 Giorgos Verigakis
    #                       serviceUnavailable (503),
451 d8e50a39 Giorgos Verigakis
    #                       unauthorized (401),
452 d8e50a39 Giorgos Verigakis
    #                       itemNotFound (404),
453 d8e50a39 Giorgos Verigakis
    #                       badRequest (400),
454 d8e50a39 Giorgos Verigakis
    #                       overLimit (413)
455 9e98ba3c Giorgos Verigakis
    
456 9e98ba3c Giorgos Verigakis
    log.debug('get_server_metadata_item %s %s', server_id, key)
457 4b3b8688 Giorgos Verigakis
    vm = util.get_vm(server_id, request.user_uniq)
458 b36f78fa Giorgos Verigakis
    meta = util.get_vm_meta(vm, key)
459 62b894c0 Giorgos Verigakis
    d = {meta.meta_key: meta.meta_value}
460 62b894c0 Giorgos Verigakis
    return util.render_meta(request, d, status=200)
461 d8e50a39 Giorgos Verigakis
462 55cd40be Vangelis Koukis
463 b36f78fa Giorgos Verigakis
@util.api_method('PUT')
464 d8e50a39 Giorgos Verigakis
def create_metadata_item(request, server_id, key):
465 d8e50a39 Giorgos Verigakis
    # Normal Response Code: 201
466 d8e50a39 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
467 d8e50a39 Giorgos Verigakis
    #                       serviceUnavailable (503),
468 d8e50a39 Giorgos Verigakis
    #                       unauthorized (401),
469 d8e50a39 Giorgos Verigakis
    #                       itemNotFound (404),
470 d8e50a39 Giorgos Verigakis
    #                       badRequest (400),
471 d8e50a39 Giorgos Verigakis
    #                       buildInProgress (409),
472 d8e50a39 Giorgos Verigakis
    #                       badMediaType(415),
473 d8e50a39 Giorgos Verigakis
    #                       overLimit (413)
474 9e98ba3c Giorgos Verigakis
    
475 b36f78fa Giorgos Verigakis
    req = util.get_request_dict(request)
476 9e98ba3c Giorgos Verigakis
    log.debug('create_server_metadata_item %s %s %s', server_id, key, req)
477 4b3b8688 Giorgos Verigakis
    vm = util.get_vm(server_id, request.user_uniq)
478 d8e50a39 Giorgos Verigakis
    try:
479 d8e50a39 Giorgos Verigakis
        metadict = req['meta']
480 d8e50a39 Giorgos Verigakis
        assert isinstance(metadict, dict)
481 d8e50a39 Giorgos Verigakis
        assert len(metadict) == 1
482 d8e50a39 Giorgos Verigakis
        assert key in metadict
483 d8e50a39 Giorgos Verigakis
    except (KeyError, AssertionError):
484 ccd0d474 Giorgos Verigakis
        raise faults.BadRequest("Malformed request")
485 b36f78fa Giorgos Verigakis
    
486 b36f78fa Giorgos Verigakis
    meta, created = VirtualMachineMetadata.objects.get_or_create(
487 b36f78fa Giorgos Verigakis
        meta_key=key,
488 b36f78fa Giorgos Verigakis
        vm=vm)
489 b36f78fa Giorgos Verigakis
    
490 d8e50a39 Giorgos Verigakis
    meta.meta_value = metadict[key]
491 d8e50a39 Giorgos Verigakis
    meta.save()
492 5509b599 Giorgos Verigakis
    vm.save()
493 62b894c0 Giorgos Verigakis
    d = {meta.meta_key: meta.meta_value}
494 62b894c0 Giorgos Verigakis
    return util.render_meta(request, d, status=201)
495 d8e50a39 Giorgos Verigakis
496 55cd40be Vangelis Koukis
497 b36f78fa Giorgos Verigakis
@util.api_method('DELETE')
498 d8e50a39 Giorgos Verigakis
def delete_metadata_item(request, server_id, key):
499 d8e50a39 Giorgos Verigakis
    # Normal Response Code: 204
500 d8e50a39 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
501 d8e50a39 Giorgos Verigakis
    #                       serviceUnavailable (503),
502 d8e50a39 Giorgos Verigakis
    #                       unauthorized (401),
503 d8e50a39 Giorgos Verigakis
    #                       itemNotFound (404),
504 d8e50a39 Giorgos Verigakis
    #                       badRequest (400),
505 d8e50a39 Giorgos Verigakis
    #                       buildInProgress (409),
506 d8e50a39 Giorgos Verigakis
    #                       badMediaType(415),
507 d8e50a39 Giorgos Verigakis
    #                       overLimit (413),
508 9e98ba3c Giorgos Verigakis
    
509 9e98ba3c Giorgos Verigakis
    log.debug('delete_server_metadata_item %s %s', server_id, key)
510 4b3b8688 Giorgos Verigakis
    vm = util.get_vm(server_id, request.user_uniq)
511 b36f78fa Giorgos Verigakis
    meta = util.get_vm_meta(vm, key)
512 d8e50a39 Giorgos Verigakis
    meta.delete()
513 5509b599 Giorgos Verigakis
    vm.save()
514 d8e50a39 Giorgos Verigakis
    return HttpResponse(status=204)
515 c738c935 Giorgos Verigakis
516 55cd40be Vangelis Koukis
517 c738c935 Giorgos Verigakis
@util.api_method('GET')
518 c738c935 Giorgos Verigakis
def server_stats(request, server_id):
519 c738c935 Giorgos Verigakis
    # Normal Response Codes: 200
520 c738c935 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
521 c738c935 Giorgos Verigakis
    #                       serviceUnavailable (503),
522 c738c935 Giorgos Verigakis
    #                       unauthorized (401),
523 c738c935 Giorgos Verigakis
    #                       badRequest (400),
524 c738c935 Giorgos Verigakis
    #                       itemNotFound (404),
525 c738c935 Giorgos Verigakis
    #                       overLimit (413)
526 c738c935 Giorgos Verigakis
    
527 9e98ba3c Giorgos Verigakis
    log.debug('server_stats %s', server_id)
528 4b3b8688 Giorgos Verigakis
    vm = util.get_vm(server_id, request.user_uniq)
529 5391d6b5 Giorgos Verigakis
    #secret = util.encrypt(vm.backend_id)
530 5391d6b5 Giorgos Verigakis
    secret = vm.backend_id      # XXX disable backend id encryption
531 c738c935 Giorgos Verigakis
    
532 c738c935 Giorgos Verigakis
    stats = {
533 c738c935 Giorgos Verigakis
        'serverRef': vm.id,
534 c738c935 Giorgos Verigakis
        'refresh': settings.STATS_REFRESH_PERIOD,
535 5391d6b5 Giorgos Verigakis
        'cpuBar': settings.CPU_BAR_GRAPH_URL % secret,
536 5391d6b5 Giorgos Verigakis
        'cpuTimeSeries': settings.CPU_TIMESERIES_GRAPH_URL % secret,
537 5391d6b5 Giorgos Verigakis
        'netBar': settings.NET_BAR_GRAPH_URL % secret,
538 5391d6b5 Giorgos Verigakis
        'netTimeSeries': settings.NET_TIMESERIES_GRAPH_URL % secret}
539 c738c935 Giorgos Verigakis
    
540 c738c935 Giorgos Verigakis
    if request.serialization == 'xml':
541 c738c935 Giorgos Verigakis
        data = render_to_string('server_stats.xml', stats)
542 c738c935 Giorgos Verigakis
    else:
543 c738c935 Giorgos Verigakis
        data = json.dumps({'stats': stats})
544 c738c935 Giorgos Verigakis
545 c738c935 Giorgos Verigakis
    return HttpResponse(data, status=200)