Statistics
| Branch: | Tag: | Revision:

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

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