Statistics
| Branch: | Tag: | Revision:

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

History | View | Annotate | Download (19.4 kB)

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