Statistics
| Branch: | Tag: | Revision:

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

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 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 ce55f211 Kostas Papadimitriou
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 ce55f211 Kostas Papadimitriou
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 b36f78fa Giorgos Verigakis
    req = util.get_request_dict(request)
198 9e98ba3c Giorgos Verigakis
    log.debug('create_server %s', req)
199 ce55f211 Kostas Papadimitriou
200 7e2f9d4b Giorgos Verigakis
    try:
201 7e2f9d4b Giorgos Verigakis
        server = req['server']
202 7e2f9d4b Giorgos Verigakis
        name = server['name']
203 bc855ce7 Giorgos Verigakis
        metadata = server.get('metadata', {})
204 bc855ce7 Giorgos Verigakis
        assert isinstance(metadata, dict)
205 529178b1 Giorgos Verigakis
        image_id = server['imageRef']
206 529178b1 Giorgos Verigakis
        flavor_id = server['flavorRef']
207 0419e0c1 Giorgos Verigakis
        personality = server.get('personality', [])
208 2b1db26f Giorgos Verigakis
        assert isinstance(personality, list)
209 bc855ce7 Giorgos Verigakis
    except (KeyError, AssertionError):
210 ccd0d474 Giorgos Verigakis
        raise faults.BadRequest("Malformed request")
211 ce55f211 Kostas Papadimitriou
212 fc443bcd Giorgos Verigakis
    if len(personality) > settings.MAX_PERSONALITY:
213 fc443bcd Giorgos Verigakis
        raise faults.OverLimit("Maximum number of personalities exceeded")
214 ce55f211 Kostas Papadimitriou
215 fc443bcd Giorgos Verigakis
    for p in personality:
216 22a3918c Giorgos Verigakis
        # Verify that personalities are well-formed
217 fc443bcd Giorgos Verigakis
        try:
218 fc443bcd Giorgos Verigakis
            assert isinstance(p, dict)
219 22a3918c Giorgos Verigakis
            keys = set(p.keys())
220 22a3918c Giorgos Verigakis
            allowed = set(['contents', 'group', 'mode', 'owner', 'path'])
221 22a3918c Giorgos Verigakis
            assert keys.issubset(allowed)
222 fc443bcd Giorgos Verigakis
            contents = p['contents']
223 fc443bcd Giorgos Verigakis
            if len(contents) > settings.MAX_PERSONALITY_SIZE:
224 fc443bcd Giorgos Verigakis
                # No need to decode if contents already exceed limit
225 fc443bcd Giorgos Verigakis
                raise faults.OverLimit("Maximum size of personality exceeded")
226 fc443bcd Giorgos Verigakis
            if len(b64decode(contents)) > settings.MAX_PERSONALITY_SIZE:
227 fc443bcd Giorgos Verigakis
                raise faults.OverLimit("Maximum size of personality exceeded")
228 fc443bcd Giorgos Verigakis
        except AssertionError:
229 fc443bcd Giorgos Verigakis
            raise faults.BadRequest("Malformed personality in request")
230 ce55f211 Kostas Papadimitriou
231 3a9b3cde Giorgos Verigakis
    image = {}
232 4b3b8688 Giorgos Verigakis
    img = util.get_image(image_id, request.user_uniq)
233 6ef51e9f Giorgos Verigakis
    properties = img.get('properties', {})
234 6ef51e9f Giorgos Verigakis
    image['backend_id'] = img['location']
235 6ef51e9f Giorgos Verigakis
    image['format'] = img['disk_format']
236 6ef51e9f Giorgos Verigakis
    image['metadata'] = dict((key.upper(), val) \
237 6ef51e9f Giorgos Verigakis
                             for key, val in properties.items())
238 ce55f211 Kostas Papadimitriou
239 b36f78fa Giorgos Verigakis
    flavor = util.get_flavor(flavor_id)
240 b36f78fa Giorgos Verigakis
    password = util.random_password()
241 ce55f211 Kostas Papadimitriou
242 4b3b8688 Giorgos Verigakis
    count = VirtualMachine.objects.filter(userid=request.user_uniq,
243 6ef51e9f Giorgos Verigakis
                                          deleted=False).count()
244 ce55f211 Kostas Papadimitriou
245 ce55f211 Kostas Papadimitriou
    # get user limit
246 ce55f211 Kostas Papadimitriou
    vms_limit_for_user = \
247 ce55f211 Kostas Papadimitriou
        settings.VMS_USER_QUOTA.get(request.user_uniq,
248 ce55f211 Kostas Papadimitriou
                settings.MAX_VMS_PER_USER)
249 ce55f211 Kostas Papadimitriou
250 ce55f211 Kostas Papadimitriou
    if count >= vms_limit_for_user:
251 856804af Vangelis Koukis
        raise faults.OverLimit("Server count limit exceeded for your account.")
252 ce55f211 Kostas Papadimitriou
253 cc7c0f44 Christos Stavrakakis
    backend_allocator = BackendAllocator()
254 cc7c0f44 Christos Stavrakakis
    backend = backend_allocator.allocate(flavor)
255 cc7c0f44 Christos Stavrakakis
    if backend is None:
256 cc7c0f44 Christos Stavrakakis
        raise Exception
257 cc7c0f44 Christos Stavrakakis
258 cc7c0f44 Christos Stavrakakis
    # We must save the VM instance now, so that it gets a valid
259 cc7c0f44 Christos Stavrakakis
    # vm.backend_vm_id.
260 b36f78fa Giorgos Verigakis
    vm = VirtualMachine.objects.create(
261 b36f78fa Giorgos Verigakis
        name=name,
262 f5b4f2a3 Christos Stavrakakis
        backend=backend,
263 4b3b8688 Giorgos Verigakis
        userid=request.user_uniq,
264 3a9b3cde Giorgos Verigakis
        imageid=image_id,
265 b36f78fa Giorgos Verigakis
        flavor=flavor)
266 ce55f211 Kostas Papadimitriou
267 1c03e74e Vangelis Koukis
    try:
268 4161cb41 Christos Stavrakakis
        jobID = create_instance(vm, flavor, image, password, personality)
269 4f598167 Giorgos Verigakis
    except GanetiApiError:
270 1c03e74e Vangelis Koukis
        vm.delete()
271 510d53b5 Vangelis Koukis
        raise
272 aa197ee4 Vangelis Koukis
273 4161cb41 Christos Stavrakakis
    vm.backendjobid = jobID
274 4161cb41 Christos Stavrakakis
    vm.save()
275 4161cb41 Christos Stavrakakis
276 bc855ce7 Giorgos Verigakis
    for key, val in metadata.items():
277 b36f78fa Giorgos Verigakis
        VirtualMachineMetadata.objects.create(
278 b36f78fa Giorgos Verigakis
            meta_key=key,
279 b36f78fa Giorgos Verigakis
            meta_value=val,
280 b36f78fa Giorgos Verigakis
            vm=vm)
281 ce55f211 Kostas Papadimitriou
282 6ef51e9f Giorgos Verigakis
    log.info('User %s created vm with %s cpus, %s ram and %s storage',
283 4b3b8688 Giorgos Verigakis
             request.user_uniq, flavor.cpu, flavor.ram, flavor.disk)
284 ce55f211 Kostas Papadimitriou
285 d8e50a39 Giorgos Verigakis
    server = vm_to_dict(vm, detail=True)
286 d8e50a39 Giorgos Verigakis
    server['status'] = 'BUILD'
287 529178b1 Giorgos Verigakis
    server['adminPass'] = password
288 d8e50a39 Giorgos Verigakis
    return render_server(request, server, status=202)
289 7e2f9d4b Giorgos Verigakis
290 55cd40be Vangelis Koukis
291 b36f78fa Giorgos Verigakis
@util.api_method('GET')
292 7e2f9d4b Giorgos Verigakis
def get_server_details(request, server_id):
293 c36934a7 Giorgos Verigakis
    # Normal Response Codes: 200, 203
294 c36934a7 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
295 c36934a7 Giorgos Verigakis
    #                       serviceUnavailable (503),
296 c36934a7 Giorgos Verigakis
    #                       unauthorized (401),
297 c36934a7 Giorgos Verigakis
    #                       badRequest (400),
298 c36934a7 Giorgos Verigakis
    #                       itemNotFound (404),
299 c36934a7 Giorgos Verigakis
    #                       overLimit (413)
300 ce55f211 Kostas Papadimitriou
301 9e98ba3c Giorgos Verigakis
    log.debug('get_server_details %s', server_id)
302 4b3b8688 Giorgos Verigakis
    vm = util.get_vm(server_id, request.user_uniq)
303 d8e50a39 Giorgos Verigakis
    server = vm_to_dict(vm, detail=True)
304 d8e50a39 Giorgos Verigakis
    return render_server(request, server)
305 7e2f9d4b Giorgos Verigakis
306 55cd40be Vangelis Koukis
307 b36f78fa Giorgos Verigakis
@util.api_method('PUT')
308 c36934a7 Giorgos Verigakis
def update_server_name(request, server_id):
309 c36934a7 Giorgos Verigakis
    # Normal Response Code: 204
310 c36934a7 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
311 c36934a7 Giorgos Verigakis
    #                       serviceUnavailable (503),
312 c36934a7 Giorgos Verigakis
    #                       unauthorized (401),
313 c36934a7 Giorgos Verigakis
    #                       badRequest (400),
314 c36934a7 Giorgos Verigakis
    #                       badMediaType(415),
315 c36934a7 Giorgos Verigakis
    #                       itemNotFound (404),
316 c36934a7 Giorgos Verigakis
    #                       buildInProgress (409),
317 c36934a7 Giorgos Verigakis
    #                       overLimit (413)
318 aa197ee4 Vangelis Koukis
319 b36f78fa Giorgos Verigakis
    req = util.get_request_dict(request)
320 9e98ba3c Giorgos Verigakis
    log.debug('update_server_name %s %s', server_id, req)
321 ce55f211 Kostas Papadimitriou
322 7e2f9d4b Giorgos Verigakis
    try:
323 7e2f9d4b Giorgos Verigakis
        name = req['server']['name']
324 529178b1 Giorgos Verigakis
    except (TypeError, KeyError):
325 ccd0d474 Giorgos Verigakis
        raise faults.BadRequest("Malformed request")
326 aa197ee4 Vangelis Koukis
327 4b3b8688 Giorgos Verigakis
    vm = util.get_vm(server_id, request.user_uniq)
328 d8e50a39 Giorgos Verigakis
    vm.name = name
329 d8e50a39 Giorgos Verigakis
    vm.save()
330 aa197ee4 Vangelis Koukis
331 7e2f9d4b Giorgos Verigakis
    return HttpResponse(status=204)
332 7e2f9d4b Giorgos Verigakis
333 55cd40be Vangelis Koukis
334 b36f78fa Giorgos Verigakis
@util.api_method('DELETE')
335 7e2f9d4b Giorgos Verigakis
def delete_server(request, server_id):
336 c36934a7 Giorgos Verigakis
    # Normal Response Codes: 204
337 c36934a7 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
338 c36934a7 Giorgos Verigakis
    #                       serviceUnavailable (503),
339 c36934a7 Giorgos Verigakis
    #                       unauthorized (401),
340 c36934a7 Giorgos Verigakis
    #                       itemNotFound (404),
341 c36934a7 Giorgos Verigakis
    #                       unauthorized (401),
342 c36934a7 Giorgos Verigakis
    #                       buildInProgress (409),
343 c36934a7 Giorgos Verigakis
    #                       overLimit (413)
344 ce55f211 Kostas Papadimitriou
345 9e98ba3c Giorgos Verigakis
    log.debug('delete_server %s', server_id)
346 4b3b8688 Giorgos Verigakis
    vm = util.get_vm(server_id, request.user_uniq)
347 529178b1 Giorgos Verigakis
    delete_instance(vm)
348 7e2f9d4b Giorgos Verigakis
    return HttpResponse(status=204)
349 b016b476 Giorgos Verigakis
350 55cd40be Vangelis Koukis
351 b36f78fa Giorgos Verigakis
@util.api_method('POST')
352 b016b476 Giorgos Verigakis
def server_action(request, server_id):
353 b36f78fa Giorgos Verigakis
    req = util.get_request_dict(request)
354 9e98ba3c Giorgos Verigakis
    log.debug('server_action %s %s', server_id, req)
355 4b3b8688 Giorgos Verigakis
    vm = util.get_vm(server_id, request.user_uniq)
356 b016b476 Giorgos Verigakis
    if len(req) != 1:
357 ccd0d474 Giorgos Verigakis
        raise faults.BadRequest("Malformed request")
358 aa197ee4 Vangelis Koukis
359 b016b476 Giorgos Verigakis
    key = req.keys()[0]
360 d8e50a39 Giorgos Verigakis
    val = req[key]
361 aa197ee4 Vangelis Koukis
362 d8e50a39 Giorgos Verigakis
    try:
363 d8e50a39 Giorgos Verigakis
        assert isinstance(val, dict)
364 20a51b1e Giorgos Verigakis
        return server_actions[key](request, vm, req[key])
365 d8e50a39 Giorgos Verigakis
    except KeyError:
366 ccd0d474 Giorgos Verigakis
        raise faults.BadRequest("Unknown action")
367 d8e50a39 Giorgos Verigakis
    except AssertionError:
368 ccd0d474 Giorgos Verigakis
        raise faults.BadRequest("Invalid argument")
369 b016b476 Giorgos Verigakis
370 55cd40be Vangelis Koukis
371 b36f78fa Giorgos Verigakis
@util.api_method('GET')
372 b016b476 Giorgos Verigakis
def list_addresses(request, server_id):
373 b016b476 Giorgos Verigakis
    # Normal Response Codes: 200, 203
374 b016b476 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
375 b016b476 Giorgos Verigakis
    #                       serviceUnavailable (503),
376 b016b476 Giorgos Verigakis
    #                       unauthorized (401),
377 b016b476 Giorgos Verigakis
    #                       badRequest (400),
378 b016b476 Giorgos Verigakis
    #                       overLimit (413)
379 ce55f211 Kostas Papadimitriou
380 9e98ba3c Giorgos Verigakis
    log.debug('list_addresses %s', server_id)
381 4b3b8688 Giorgos Verigakis
    vm = util.get_vm(server_id, request.user_uniq)
382 d44c236b Giorgos Verigakis
    addresses = [nic_to_dict(nic) for nic in vm.nics.all()]
383 ce55f211 Kostas Papadimitriou
384 d8e50a39 Giorgos Verigakis
    if request.serialization == 'xml':
385 b016b476 Giorgos Verigakis
        data = render_to_string('list_addresses.xml', {'addresses': addresses})
386 b016b476 Giorgos Verigakis
    else:
387 b016b476 Giorgos Verigakis
        data = json.dumps({'addresses': {'values': addresses}})
388 aa197ee4 Vangelis Koukis
389 b016b476 Giorgos Verigakis
    return HttpResponse(data, status=200)
390 b016b476 Giorgos Verigakis
391 55cd40be Vangelis Koukis
392 b36f78fa Giorgos Verigakis
@util.api_method('GET')
393 b016b476 Giorgos Verigakis
def list_addresses_by_network(request, server_id, network_id):
394 b016b476 Giorgos Verigakis
    # Normal Response Codes: 200, 203
395 b016b476 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
396 b016b476 Giorgos Verigakis
    #                       serviceUnavailable (503),
397 b016b476 Giorgos Verigakis
    #                       unauthorized (401),
398 b016b476 Giorgos Verigakis
    #                       badRequest (400),
399 b016b476 Giorgos Verigakis
    #                       itemNotFound (404),
400 b016b476 Giorgos Verigakis
    #                       overLimit (413)
401 ce55f211 Kostas Papadimitriou
402 9e98ba3c Giorgos Verigakis
    log.debug('list_addresses_by_network %s %s', server_id, network_id)
403 4b3b8688 Giorgos Verigakis
    machine = util.get_vm(server_id, request.user_uniq)
404 4b3b8688 Giorgos Verigakis
    network = util.get_network(network_id, request.user_uniq)
405 b36f78fa Giorgos Verigakis
    nic = util.get_nic(machine, network)
406 d44c236b Giorgos Verigakis
    address = nic_to_dict(nic)
407 ce55f211 Kostas Papadimitriou
408 d8e50a39 Giorgos Verigakis
    if request.serialization == 'xml':
409 b016b476 Giorgos Verigakis
        data = render_to_string('address.xml', {'address': address})
410 b016b476 Giorgos Verigakis
    else:
411 b016b476 Giorgos Verigakis
        data = json.dumps({'network': address})
412 aa197ee4 Vangelis Koukis
413 b016b476 Giorgos Verigakis
    return HttpResponse(data, status=200)
414 d8e50a39 Giorgos Verigakis
415 55cd40be Vangelis Koukis
416 b36f78fa Giorgos Verigakis
@util.api_method('GET')
417 d8e50a39 Giorgos Verigakis
def list_metadata(request, server_id):
418 d8e50a39 Giorgos Verigakis
    # Normal Response Codes: 200, 203
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
    #                       overLimit (413)
424 ce55f211 Kostas Papadimitriou
425 9e98ba3c Giorgos Verigakis
    log.debug('list_server_metadata %s', server_id)
426 4b3b8688 Giorgos Verigakis
    vm = util.get_vm(server_id, request.user_uniq)
427 7cc3c7d9 Giorgos Verigakis
    metadata = dict((m.meta_key, m.meta_value) for m in vm.metadata.all())
428 b36f78fa Giorgos Verigakis
    return util.render_metadata(request, metadata, use_values=True, status=200)
429 d8e50a39 Giorgos Verigakis
430 55cd40be Vangelis Koukis
431 b36f78fa Giorgos Verigakis
@util.api_method('POST')
432 d8e50a39 Giorgos Verigakis
def update_metadata(request, server_id):
433 d8e50a39 Giorgos Verigakis
    # Normal Response Code: 201
434 d8e50a39 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
435 d8e50a39 Giorgos Verigakis
    #                       serviceUnavailable (503),
436 d8e50a39 Giorgos Verigakis
    #                       unauthorized (401),
437 d8e50a39 Giorgos Verigakis
    #                       badRequest (400),
438 d8e50a39 Giorgos Verigakis
    #                       buildInProgress (409),
439 d8e50a39 Giorgos Verigakis
    #                       badMediaType(415),
440 d8e50a39 Giorgos Verigakis
    #                       overLimit (413)
441 ce55f211 Kostas Papadimitriou
442 b36f78fa Giorgos Verigakis
    req = util.get_request_dict(request)
443 9e98ba3c Giorgos Verigakis
    log.debug('update_server_metadata %s %s', server_id, req)
444 4b3b8688 Giorgos Verigakis
    vm = util.get_vm(server_id, request.user_uniq)
445 d8e50a39 Giorgos Verigakis
    try:
446 d8e50a39 Giorgos Verigakis
        metadata = req['metadata']
447 d8e50a39 Giorgos Verigakis
        assert isinstance(metadata, dict)
448 d8e50a39 Giorgos Verigakis
    except (KeyError, AssertionError):
449 ccd0d474 Giorgos Verigakis
        raise faults.BadRequest("Malformed request")
450 ce55f211 Kostas Papadimitriou
451 7cc3c7d9 Giorgos Verigakis
    for key, val in metadata.items():
452 7cc3c7d9 Giorgos Verigakis
        meta, created = vm.metadata.get_or_create(meta_key=key)
453 7cc3c7d9 Giorgos Verigakis
        meta.meta_value = val
454 7cc3c7d9 Giorgos Verigakis
        meta.save()
455 ce55f211 Kostas Papadimitriou
456 7cc3c7d9 Giorgos Verigakis
    vm.save()
457 7cc3c7d9 Giorgos Verigakis
    vm_meta = dict((m.meta_key, m.meta_value) for m in vm.metadata.all())
458 7cc3c7d9 Giorgos Verigakis
    return util.render_metadata(request, vm_meta, status=201)
459 d8e50a39 Giorgos Verigakis
460 55cd40be Vangelis Koukis
461 b36f78fa Giorgos Verigakis
@util.api_method('GET')
462 d8e50a39 Giorgos Verigakis
def get_metadata_item(request, server_id, key):
463 d8e50a39 Giorgos Verigakis
    # Normal Response Codes: 200, 203
464 d8e50a39 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
465 d8e50a39 Giorgos Verigakis
    #                       serviceUnavailable (503),
466 d8e50a39 Giorgos Verigakis
    #                       unauthorized (401),
467 d8e50a39 Giorgos Verigakis
    #                       itemNotFound (404),
468 d8e50a39 Giorgos Verigakis
    #                       badRequest (400),
469 d8e50a39 Giorgos Verigakis
    #                       overLimit (413)
470 ce55f211 Kostas Papadimitriou
471 9e98ba3c Giorgos Verigakis
    log.debug('get_server_metadata_item %s %s', server_id, key)
472 4b3b8688 Giorgos Verigakis
    vm = util.get_vm(server_id, request.user_uniq)
473 b36f78fa Giorgos Verigakis
    meta = util.get_vm_meta(vm, key)
474 62b894c0 Giorgos Verigakis
    d = {meta.meta_key: meta.meta_value}
475 62b894c0 Giorgos Verigakis
    return util.render_meta(request, d, status=200)
476 d8e50a39 Giorgos Verigakis
477 55cd40be Vangelis Koukis
478 b36f78fa Giorgos Verigakis
@util.api_method('PUT')
479 d8e50a39 Giorgos Verigakis
def create_metadata_item(request, server_id, key):
480 d8e50a39 Giorgos Verigakis
    # Normal Response Code: 201
481 d8e50a39 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
482 d8e50a39 Giorgos Verigakis
    #                       serviceUnavailable (503),
483 d8e50a39 Giorgos Verigakis
    #                       unauthorized (401),
484 d8e50a39 Giorgos Verigakis
    #                       itemNotFound (404),
485 d8e50a39 Giorgos Verigakis
    #                       badRequest (400),
486 d8e50a39 Giorgos Verigakis
    #                       buildInProgress (409),
487 d8e50a39 Giorgos Verigakis
    #                       badMediaType(415),
488 d8e50a39 Giorgos Verigakis
    #                       overLimit (413)
489 ce55f211 Kostas Papadimitriou
490 b36f78fa Giorgos Verigakis
    req = util.get_request_dict(request)
491 9e98ba3c Giorgos Verigakis
    log.debug('create_server_metadata_item %s %s %s', server_id, key, req)
492 4b3b8688 Giorgos Verigakis
    vm = util.get_vm(server_id, request.user_uniq)
493 d8e50a39 Giorgos Verigakis
    try:
494 d8e50a39 Giorgos Verigakis
        metadict = req['meta']
495 d8e50a39 Giorgos Verigakis
        assert isinstance(metadict, dict)
496 d8e50a39 Giorgos Verigakis
        assert len(metadict) == 1
497 d8e50a39 Giorgos Verigakis
        assert key in metadict
498 d8e50a39 Giorgos Verigakis
    except (KeyError, AssertionError):
499 ccd0d474 Giorgos Verigakis
        raise faults.BadRequest("Malformed request")
500 ce55f211 Kostas Papadimitriou
501 b36f78fa Giorgos Verigakis
    meta, created = VirtualMachineMetadata.objects.get_or_create(
502 b36f78fa Giorgos Verigakis
        meta_key=key,
503 b36f78fa Giorgos Verigakis
        vm=vm)
504 ce55f211 Kostas Papadimitriou
505 d8e50a39 Giorgos Verigakis
    meta.meta_value = metadict[key]
506 d8e50a39 Giorgos Verigakis
    meta.save()
507 5509b599 Giorgos Verigakis
    vm.save()
508 62b894c0 Giorgos Verigakis
    d = {meta.meta_key: meta.meta_value}
509 62b894c0 Giorgos Verigakis
    return util.render_meta(request, d, status=201)
510 d8e50a39 Giorgos Verigakis
511 55cd40be Vangelis Koukis
512 b36f78fa Giorgos Verigakis
@util.api_method('DELETE')
513 d8e50a39 Giorgos Verigakis
def delete_metadata_item(request, server_id, key):
514 d8e50a39 Giorgos Verigakis
    # Normal Response Code: 204
515 d8e50a39 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
516 d8e50a39 Giorgos Verigakis
    #                       serviceUnavailable (503),
517 d8e50a39 Giorgos Verigakis
    #                       unauthorized (401),
518 d8e50a39 Giorgos Verigakis
    #                       itemNotFound (404),
519 d8e50a39 Giorgos Verigakis
    #                       badRequest (400),
520 d8e50a39 Giorgos Verigakis
    #                       buildInProgress (409),
521 d8e50a39 Giorgos Verigakis
    #                       badMediaType(415),
522 d8e50a39 Giorgos Verigakis
    #                       overLimit (413),
523 ce55f211 Kostas Papadimitriou
524 9e98ba3c Giorgos Verigakis
    log.debug('delete_server_metadata_item %s %s', server_id, key)
525 4b3b8688 Giorgos Verigakis
    vm = util.get_vm(server_id, request.user_uniq)
526 b36f78fa Giorgos Verigakis
    meta = util.get_vm_meta(vm, key)
527 d8e50a39 Giorgos Verigakis
    meta.delete()
528 5509b599 Giorgos Verigakis
    vm.save()
529 d8e50a39 Giorgos Verigakis
    return HttpResponse(status=204)
530 c738c935 Giorgos Verigakis
531 55cd40be Vangelis Koukis
532 c738c935 Giorgos Verigakis
@util.api_method('GET')
533 c738c935 Giorgos Verigakis
def server_stats(request, server_id):
534 c738c935 Giorgos Verigakis
    # Normal Response Codes: 200
535 c738c935 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
536 c738c935 Giorgos Verigakis
    #                       serviceUnavailable (503),
537 c738c935 Giorgos Verigakis
    #                       unauthorized (401),
538 c738c935 Giorgos Verigakis
    #                       badRequest (400),
539 c738c935 Giorgos Verigakis
    #                       itemNotFound (404),
540 c738c935 Giorgos Verigakis
    #                       overLimit (413)
541 ce55f211 Kostas Papadimitriou
542 9e98ba3c Giorgos Verigakis
    log.debug('server_stats %s', server_id)
543 4b3b8688 Giorgos Verigakis
    vm = util.get_vm(server_id, request.user_uniq)
544 924d8085 Christos Stavrakakis
    #secret = util.encrypt(vm.backend_vm_id)
545 924d8085 Christos Stavrakakis
    secret = vm.backend_vm_id      # XXX disable backend id encryption
546 ce55f211 Kostas Papadimitriou
547 c738c935 Giorgos Verigakis
    stats = {
548 c738c935 Giorgos Verigakis
        'serverRef': vm.id,
549 c738c935 Giorgos Verigakis
        'refresh': settings.STATS_REFRESH_PERIOD,
550 5391d6b5 Giorgos Verigakis
        'cpuBar': settings.CPU_BAR_GRAPH_URL % secret,
551 5391d6b5 Giorgos Verigakis
        'cpuTimeSeries': settings.CPU_TIMESERIES_GRAPH_URL % secret,
552 5391d6b5 Giorgos Verigakis
        'netBar': settings.NET_BAR_GRAPH_URL % secret,
553 5391d6b5 Giorgos Verigakis
        'netTimeSeries': settings.NET_TIMESERIES_GRAPH_URL % secret}
554 ce55f211 Kostas Papadimitriou
555 c738c935 Giorgos Verigakis
    if request.serialization == 'xml':
556 c738c935 Giorgos Verigakis
        data = render_to_string('server_stats.xml', stats)
557 c738c935 Giorgos Verigakis
    else:
558 c738c935 Giorgos Verigakis
        data = json.dumps({'stats': stats})
559 c738c935 Giorgos Verigakis
560 c738c935 Giorgos Verigakis
    return HttpResponse(data, status=200)