Statistics
| Branch: | Tag: | Revision:

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

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