Statistics
| Branch: | Tag: | Revision:

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

History | View | Annotate | Download (25.4 kB)

1 b3fd98ae Christos Stavrakakis
# Copyright 2011-2013 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 07b73be0 Kostas Papadimitriou
from django import dispatch
35 ccd0d474 Giorgos Verigakis
from django.conf import settings
36 d8e50a39 Giorgos Verigakis
from django.conf.urls.defaults import patterns
37 4dba0480 Christos Stavrakakis
from django.db import transaction
38 7e2f9d4b Giorgos Verigakis
from django.http import HttpResponse
39 7e2f9d4b Giorgos Verigakis
from django.template.loader import render_to_string
40 29a59bc1 Giorgos Verigakis
from django.utils import simplejson as json
41 7e2f9d4b Giorgos Verigakis
42 b3fd98ae Christos Stavrakakis
from snf_django.lib import api
43 b3fd98ae Christos Stavrakakis
from snf_django.lib.api import faults, utils
44 bd40abfa Christos Stavrakakis
from synnefo.api import util
45 0971fa71 Markos Gogoulos
from synnefo.api.actions import server_actions
46 939d71dd Christos Stavrakakis
from synnefo.db.models import (VirtualMachine, VirtualMachineMetadata,
47 939d71dd Christos Stavrakakis
                               NetworkInterface)
48 529178b1 Giorgos Verigakis
from synnefo.logic.backend import create_instance, delete_instance
49 d8e50a39 Giorgos Verigakis
from synnefo.logic.utils import get_rsapi_state
50 ec0b5e5b Christos Stavrakakis
from synnefo.logic.rapi import GanetiApiError
51 cc7c0f44 Christos Stavrakakis
from synnefo.logic.backend_allocator import BackendAllocator
52 77f45438 Christos Stavrakakis
from synnefo import quotas
53 cc7c0f44 Christos Stavrakakis
54 07b73be0 Kostas Papadimitriou
# server creation signal
55 07b73be0 Kostas Papadimitriou
server_created = dispatch.Signal(providing_args=["created_vm_params"])
56 9e98ba3c Giorgos Verigakis
57 bf5c82dc Christos Stavrakakis
from logging import getLogger
58 b3fd98ae Christos Stavrakakis
log = getLogger(__name__)
59 7e2f9d4b Giorgos Verigakis
60 e440e835 Christos Stavrakakis
urlpatterns = patterns(
61 e440e835 Christos Stavrakakis
    'synnefo.api.servers',
62 7e2f9d4b Giorgos Verigakis
    (r'^(?:/|.json|.xml)?$', 'demux'),
63 7e2f9d4b Giorgos Verigakis
    (r'^/detail(?:.json|.xml)?$', 'list_servers', {'detail': True}),
64 7e2f9d4b Giorgos Verigakis
    (r'^/(\d+)(?:.json|.xml)?$', 'server_demux'),
65 b016b476 Giorgos Verigakis
    (r'^/(\d+)/action(?:.json|.xml)?$', 'server_action'),
66 b016b476 Giorgos Verigakis
    (r'^/(\d+)/ips(?:.json|.xml)?$', 'list_addresses'),
67 b016b476 Giorgos Verigakis
    (r'^/(\d+)/ips/(.+?)(?:.json|.xml)?$', 'list_addresses_by_network'),
68 8a992938 Christos Stavrakakis
    (r'^/(\d+)/metadata(?:.json|.xml)?$', 'metadata_demux'),
69 8a992938 Christos Stavrakakis
    (r'^/(\d+)/metadata/(.+?)(?:.json|.xml)?$', 'metadata_item_demux'),
70 c738c935 Giorgos Verigakis
    (r'^/(\d+)/stats(?:.json|.xml)?$', 'server_stats'),
71 85a634e6 Kostas Papadimitriou
    (r'^/(\d+)/diagnostics(?:.json)?$', 'get_server_diagnostics'),
72 7e2f9d4b Giorgos Verigakis
)
73 7e2f9d4b Giorgos Verigakis
74 7e2f9d4b Giorgos Verigakis
75 7e2f9d4b Giorgos Verigakis
def demux(request):
76 7e2f9d4b Giorgos Verigakis
    if request.method == 'GET':
77 7e2f9d4b Giorgos Verigakis
        return list_servers(request)
78 7e2f9d4b Giorgos Verigakis
    elif request.method == 'POST':
79 7e2f9d4b Giorgos Verigakis
        return create_server(request)
80 7e2f9d4b Giorgos Verigakis
    else:
81 b3fd98ae Christos Stavrakakis
        return api.method_not_allowed(request)
82 7e2f9d4b Giorgos Verigakis
83 55cd40be Vangelis Koukis
84 7e2f9d4b Giorgos Verigakis
def server_demux(request, server_id):
85 7e2f9d4b Giorgos Verigakis
    if request.method == 'GET':
86 7e2f9d4b Giorgos Verigakis
        return get_server_details(request, server_id)
87 7e2f9d4b Giorgos Verigakis
    elif request.method == 'PUT':
88 7e2f9d4b Giorgos Verigakis
        return update_server_name(request, server_id)
89 7e2f9d4b Giorgos Verigakis
    elif request.method == 'DELETE':
90 7e2f9d4b Giorgos Verigakis
        return delete_server(request, server_id)
91 7e2f9d4b Giorgos Verigakis
    else:
92 b3fd98ae Christos Stavrakakis
        return api.method_not_allowed(request)
93 d8e50a39 Giorgos Verigakis
94 55cd40be Vangelis Koukis
95 d8e50a39 Giorgos Verigakis
def metadata_demux(request, server_id):
96 d8e50a39 Giorgos Verigakis
    if request.method == 'GET':
97 d8e50a39 Giorgos Verigakis
        return list_metadata(request, server_id)
98 d8e50a39 Giorgos Verigakis
    elif request.method == 'POST':
99 d8e50a39 Giorgos Verigakis
        return update_metadata(request, server_id)
100 d8e50a39 Giorgos Verigakis
    else:
101 b3fd98ae Christos Stavrakakis
        return api.method_not_allowed(request)
102 d8e50a39 Giorgos Verigakis
103 55cd40be Vangelis Koukis
104 d8e50a39 Giorgos Verigakis
def metadata_item_demux(request, server_id, key):
105 d8e50a39 Giorgos Verigakis
    if request.method == 'GET':
106 d8e50a39 Giorgos Verigakis
        return get_metadata_item(request, server_id, key)
107 d8e50a39 Giorgos Verigakis
    elif request.method == 'PUT':
108 d8e50a39 Giorgos Verigakis
        return create_metadata_item(request, server_id, key)
109 d8e50a39 Giorgos Verigakis
    elif request.method == 'DELETE':
110 d8e50a39 Giorgos Verigakis
        return delete_metadata_item(request, server_id, key)
111 d8e50a39 Giorgos Verigakis
    else:
112 b3fd98ae Christos Stavrakakis
        return api.method_not_allowed(request)
113 7e2f9d4b Giorgos Verigakis
114 08b079e2 Stavros Sachtouris
115 7fede91e Christos Stavrakakis
def nic_to_dict(nic):
116 7fede91e Christos Stavrakakis
    d = {'id': util.construct_nic_id(nic),
117 7fede91e Christos Stavrakakis
         'network_id': str(nic.network.id),
118 7fede91e Christos Stavrakakis
         'mac_address': nic.mac,
119 7fede91e Christos Stavrakakis
         'ipv4': nic.ipv4 if nic.ipv4 else None,
120 7fede91e Christos Stavrakakis
         'ipv6': nic.ipv6 if nic.ipv6 else None}
121 47c66641 Dimitris Aragiorgis
122 207b70d5 Giorgos Verigakis
    if nic.firewall_profile:
123 207b70d5 Giorgos Verigakis
        d['firewallProfile'] = nic.firewall_profile
124 d44c236b Giorgos Verigakis
    return d
125 b016b476 Giorgos Verigakis
126 55cd40be Vangelis Koukis
127 d8e50a39 Giorgos Verigakis
def vm_to_dict(vm, detail=False):
128 d8e50a39 Giorgos Verigakis
    d = dict(id=vm.id, name=vm.name)
129 7e2f9d4b Giorgos Verigakis
    if detail:
130 d8e50a39 Giorgos Verigakis
        d['status'] = get_rsapi_state(vm)
131 19da4325 Vangelis Koukis
        d['progress'] = 100 if get_rsapi_state(vm) == 'ACTIVE' \
132 e440e835 Christos Stavrakakis
            else vm.buildpercentage
133 d8e50a39 Giorgos Verigakis
        d['hostId'] = vm.hostid
134 b3fd98ae Christos Stavrakakis
        d['updated'] = utils.isoformat(vm.updated)
135 b3fd98ae Christos Stavrakakis
        d['created'] = utils.isoformat(vm.created)
136 e13aeb09 Christos Stavrakakis
        d['flavor'] = vm.flavor.id
137 e13aeb09 Christos Stavrakakis
        d['image'] = vm.imageid
138 e221ade2 Christos Stavrakakis
        d['suspended'] = vm.suspended
139 ce55f211 Kostas Papadimitriou
140 7cc3c7d9 Giorgos Verigakis
        metadata = dict((m.meta_key, m.meta_value) for m in vm.metadata.all())
141 7e2f9d4b Giorgos Verigakis
        if metadata:
142 5029ff36 Christos Stavrakakis
            d['metadata'] = metadata
143 aa197ee4 Vangelis Koukis
144 939d71dd Christos Stavrakakis
        vm_nics = vm.nics.filter(state="ACTIVE").order_by("index")
145 939d71dd Christos Stavrakakis
        attachments = map(nic_to_dict, vm_nics)
146 5029ff36 Christos Stavrakakis
        d['attachments'] = attachments
147 85a634e6 Kostas Papadimitriou
148 85a634e6 Kostas Papadimitriou
        # include the latest vm diagnostic, if set
149 85a634e6 Kostas Papadimitriou
        diagnostic = vm.get_last_diagnostic()
150 85a634e6 Kostas Papadimitriou
        if diagnostic:
151 85a634e6 Kostas Papadimitriou
            d['diagnostics'] = diagnostics_to_dict([diagnostic])
152 85a634e6 Kostas Papadimitriou
153 7e2f9d4b Giorgos Verigakis
    return d
154 7e2f9d4b Giorgos Verigakis
155 d8e50a39 Giorgos Verigakis
156 85a634e6 Kostas Papadimitriou
def diagnostics_to_dict(diagnostics):
157 85a634e6 Kostas Papadimitriou
    """
158 85a634e6 Kostas Papadimitriou
    Extract api data from diagnostics QuerySet.
159 85a634e6 Kostas Papadimitriou
    """
160 85a634e6 Kostas Papadimitriou
    entries = list()
161 85a634e6 Kostas Papadimitriou
162 85a634e6 Kostas Papadimitriou
    for diagnostic in diagnostics:
163 85a634e6 Kostas Papadimitriou
        # format source date if set
164 85a634e6 Kostas Papadimitriou
        formatted_source_date = None
165 85a634e6 Kostas Papadimitriou
        if diagnostic.source_date:
166 b3fd98ae Christos Stavrakakis
            formatted_source_date = utils.isoformat(diagnostic.source_date)
167 85a634e6 Kostas Papadimitriou
168 85a634e6 Kostas Papadimitriou
        entry = {
169 85a634e6 Kostas Papadimitriou
            'source': diagnostic.source,
170 b3fd98ae Christos Stavrakakis
            'created': utils.isoformat(diagnostic.created),
171 85a634e6 Kostas Papadimitriou
            'message': diagnostic.message,
172 85a634e6 Kostas Papadimitriou
            'details': diagnostic.details,
173 85a634e6 Kostas Papadimitriou
            'level': diagnostic.level,
174 85a634e6 Kostas Papadimitriou
        }
175 85a634e6 Kostas Papadimitriou
176 85a634e6 Kostas Papadimitriou
        if formatted_source_date:
177 85a634e6 Kostas Papadimitriou
            entry['source_date'] = formatted_source_date
178 85a634e6 Kostas Papadimitriou
179 85a634e6 Kostas Papadimitriou
        entries.append(entry)
180 85a634e6 Kostas Papadimitriou
181 85a634e6 Kostas Papadimitriou
    return entries
182 85a634e6 Kostas Papadimitriou
183 85a634e6 Kostas Papadimitriou
184 d8e50a39 Giorgos Verigakis
def render_server(request, server, status=200):
185 d8e50a39 Giorgos Verigakis
    if request.serialization == 'xml':
186 b36f78fa Giorgos Verigakis
        data = render_to_string('server.xml', {
187 b36f78fa Giorgos Verigakis
            'server': server,
188 b36f78fa Giorgos Verigakis
            'is_root': True})
189 7e2f9d4b Giorgos Verigakis
    else:
190 d8e50a39 Giorgos Verigakis
        data = json.dumps({'server': server})
191 c36934a7 Giorgos Verigakis
    return HttpResponse(data, status=status)
192 aa197ee4 Vangelis Koukis
193 7e2f9d4b Giorgos Verigakis
194 85a634e6 Kostas Papadimitriou
def render_diagnostics(request, diagnostics_dict, status=200):
195 85a634e6 Kostas Papadimitriou
    """
196 85a634e6 Kostas Papadimitriou
    Render diagnostics dictionary to json response.
197 85a634e6 Kostas Papadimitriou
    """
198 85a634e6 Kostas Papadimitriou
    return HttpResponse(json.dumps(diagnostics_dict), status=status)
199 85a634e6 Kostas Papadimitriou
200 85a634e6 Kostas Papadimitriou
201 b3fd98ae Christos Stavrakakis
@api.api_method(http_method='GET', user_required=True, logger=log)
202 85a634e6 Kostas Papadimitriou
def get_server_diagnostics(request, server_id):
203 85a634e6 Kostas Papadimitriou
    """
204 85a634e6 Kostas Papadimitriou
    Virtual machine diagnostics api view.
205 85a634e6 Kostas Papadimitriou
    """
206 85a634e6 Kostas Papadimitriou
    log.debug('server_diagnostics %s', server_id)
207 85a634e6 Kostas Papadimitriou
    vm = util.get_vm(server_id, request.user_uniq)
208 85a634e6 Kostas Papadimitriou
    diagnostics = diagnostics_to_dict(vm.diagnostics.all())
209 85a634e6 Kostas Papadimitriou
    return render_diagnostics(request, diagnostics)
210 85a634e6 Kostas Papadimitriou
211 85a634e6 Kostas Papadimitriou
212 b3fd98ae Christos Stavrakakis
@api.api_method(http_method='GET', user_required=True, logger=log)
213 7e2f9d4b Giorgos Verigakis
def list_servers(request, detail=False):
214 7e2f9d4b Giorgos Verigakis
    # Normal Response Codes: 200, 203
215 7e2f9d4b Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
216 7e2f9d4b Giorgos Verigakis
    #                       serviceUnavailable (503),
217 7e2f9d4b Giorgos Verigakis
    #                       unauthorized (401),
218 7e2f9d4b Giorgos Verigakis
    #                       badRequest (400),
219 7e2f9d4b Giorgos Verigakis
    #                       overLimit (413)
220 ce55f211 Kostas Papadimitriou
221 0c37a721 Christos Stavrakakis
    log.debug('list_servers detail=%s', detail)
222 e524ed5f Kostas Papadimitriou
    user_vms = VirtualMachine.objects.filter(userid=request.user_uniq)
223 ce55f211 Kostas Papadimitriou
224 b3fd98ae Christos Stavrakakis
    since = utils.isoparse(request.GET.get('changes-since'))
225 85a634e6 Kostas Papadimitriou
226 d8e50a39 Giorgos Verigakis
    if since:
227 2987cd8a Giorgos Verigakis
        user_vms = user_vms.filter(updated__gte=since)
228 d8e50a39 Giorgos Verigakis
        if not user_vms:
229 d8e50a39 Giorgos Verigakis
            return HttpResponse(status=304)
230 e524ed5f Kostas Papadimitriou
    else:
231 1d7c75e4 Kostas Papadimitriou
        user_vms = user_vms.filter(deleted=False)
232 ce55f211 Kostas Papadimitriou
233 e440e835 Christos Stavrakakis
    servers = [vm_to_dict(server, detail)
234 cd2b0bf5 Christos Stavrakakis
               for server in user_vms.order_by('id')]
235 aa197ee4 Vangelis Koukis
236 d8e50a39 Giorgos Verigakis
    if request.serialization == 'xml':
237 b36f78fa Giorgos Verigakis
        data = render_to_string('list_servers.xml', {
238 b36f78fa Giorgos Verigakis
            'servers': servers,
239 b36f78fa Giorgos Verigakis
            'detail': detail})
240 7e2f9d4b Giorgos Verigakis
    else:
241 5029ff36 Christos Stavrakakis
        data = json.dumps({'servers': servers})
242 aa197ee4 Vangelis Koukis
243 c36934a7 Giorgos Verigakis
    return HttpResponse(data, status=200)
244 7e2f9d4b Giorgos Verigakis
245 55cd40be Vangelis Koukis
246 b3fd98ae Christos Stavrakakis
@api.api_method(http_method='POST', user_required=True, logger=log)
247 2509ce17 Christos Stavrakakis
def create_server(request):
248 7e2f9d4b Giorgos Verigakis
    # Normal Response Code: 202
249 7e2f9d4b Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
250 7e2f9d4b Giorgos Verigakis
    #                       serviceUnavailable (503),
251 7e2f9d4b Giorgos Verigakis
    #                       unauthorized (401),
252 7e2f9d4b Giorgos Verigakis
    #                       badMediaType(415),
253 7e2f9d4b Giorgos Verigakis
    #                       itemNotFound (404),
254 7e2f9d4b Giorgos Verigakis
    #                       badRequest (400),
255 7e2f9d4b Giorgos Verigakis
    #                       serverCapacityUnavailable (503),
256 7e2f9d4b Giorgos Verigakis
    #                       overLimit (413)
257 bcd80cd9 Christos Stavrakakis
    req = utils.get_request_dict(request)
258 bcd80cd9 Christos Stavrakakis
    log.info('create_server %s', req)
259 bcd80cd9 Christos Stavrakakis
    user_id = request.user_uniq
260 bcd80cd9 Christos Stavrakakis
261 7e2f9d4b Giorgos Verigakis
    try:
262 bcd80cd9 Christos Stavrakakis
        server = req['server']
263 bcd80cd9 Christos Stavrakakis
        name = server['name']
264 bcd80cd9 Christos Stavrakakis
        metadata = server.get('metadata', {})
265 bcd80cd9 Christos Stavrakakis
        assert isinstance(metadata, dict)
266 bcd80cd9 Christos Stavrakakis
        image_id = server['imageRef']
267 bcd80cd9 Christos Stavrakakis
        flavor_id = server['flavorRef']
268 bcd80cd9 Christos Stavrakakis
        personality = server.get('personality', [])
269 bcd80cd9 Christos Stavrakakis
        assert isinstance(personality, list)
270 bcd80cd9 Christos Stavrakakis
    except (KeyError, AssertionError):
271 bcd80cd9 Christos Stavrakakis
        raise faults.BadRequest("Malformed request")
272 bcd80cd9 Christos Stavrakakis
273 bcd80cd9 Christos Stavrakakis
    # Verify that personalities are well-formed
274 bcd80cd9 Christos Stavrakakis
    util.verify_personality(personality)
275 bcd80cd9 Christos Stavrakakis
    # Get image information
276 bcd80cd9 Christos Stavrakakis
    image = util.get_image_dict(image_id, user_id)
277 bcd80cd9 Christos Stavrakakis
    # Get flavor (ensure it is active)
278 bcd80cd9 Christos Stavrakakis
    flavor = util.get_flavor(flavor_id, include_deleted=False)
279 bcd80cd9 Christos Stavrakakis
    # Generate password
280 bcd80cd9 Christos Stavrakakis
    password = util.random_password()
281 bcd80cd9 Christos Stavrakakis
282 bcd80cd9 Christos Stavrakakis
    vm = do_create_server(user_id, name, password, flavor, image,
283 bcd80cd9 Christos Stavrakakis
                          metadata=metadata, personality=personality)
284 bcd80cd9 Christos Stavrakakis
285 bcd80cd9 Christos Stavrakakis
    server = vm_to_dict(vm, detail=True)
286 bcd80cd9 Christos Stavrakakis
    server['status'] = 'BUILD'
287 bcd80cd9 Christos Stavrakakis
    server['adminPass'] = password
288 bcd80cd9 Christos Stavrakakis
289 bcd80cd9 Christos Stavrakakis
    response = render_server(request, server, status=202)
290 4b8e03e5 Christos Stavrakakis
291 bcd80cd9 Christos Stavrakakis
    return response
292 bcd80cd9 Christos Stavrakakis
293 bcd80cd9 Christos Stavrakakis
294 bcd80cd9 Christos Stavrakakis
@transaction.commit_manually
295 bcd80cd9 Christos Stavrakakis
def do_create_server(userid, name, password, flavor, image, metadata={},
296 bcd80cd9 Christos Stavrakakis
                  personality=[], network=None, backend=None):
297 bcd80cd9 Christos Stavrakakis
    if backend is None:
298 bcd80cd9 Christos Stavrakakis
        # Allocate backend to host the server. Commit after allocation to
299 bcd80cd9 Christos Stavrakakis
        # release the locks hold by the backend allocator.
300 fc443bcd Giorgos Verigakis
        try:
301 bcd80cd9 Christos Stavrakakis
            backend_allocator = BackendAllocator()
302 bcd80cd9 Christos Stavrakakis
            backend = backend_allocator.allocate(userid, flavor)
303 bcd80cd9 Christos Stavrakakis
            if backend is None:
304 bcd80cd9 Christos Stavrakakis
                log.error("No available backend for VM with flavor %s", flavor)
305 bcd80cd9 Christos Stavrakakis
                raise faults.ServiceUnavailable("No available backends")
306 bcd80cd9 Christos Stavrakakis
        except:
307 bcd80cd9 Christos Stavrakakis
            transaction.rollback()
308 bcd80cd9 Christos Stavrakakis
            raise
309 bcd80cd9 Christos Stavrakakis
        else:
310 bcd80cd9 Christos Stavrakakis
            transaction.commit()
311 ce55f211 Kostas Papadimitriou
312 482c6454 Christos Stavrakakis
    # Fix flavor for archipelago
313 482c6454 Christos Stavrakakis
    disk_template, provider = util.get_flavor_provider(flavor)
314 482c6454 Christos Stavrakakis
    if provider:
315 482c6454 Christos Stavrakakis
        flavor.disk_template = disk_template
316 482c6454 Christos Stavrakakis
        flavor.disk_provider = provider
317 482c6454 Christos Stavrakakis
        flavor.disk_origin = None
318 482c6454 Christos Stavrakakis
        if provider == 'vlmc':
319 482c6454 Christos Stavrakakis
            flavor.disk_origin = image['checksum']
320 482c6454 Christos Stavrakakis
            image['backend_id'] = 'null'
321 482c6454 Christos Stavrakakis
    else:
322 482c6454 Christos Stavrakakis
        flavor.disk_provider = None
323 482c6454 Christos Stavrakakis
324 4b8e03e5 Christos Stavrakakis
    try:
325 bcd80cd9 Christos Stavrakakis
        if network is None:
326 bcd80cd9 Christos Stavrakakis
            # Allocate IP from public network
327 bcd80cd9 Christos Stavrakakis
            (network, address) = util.get_public_ip(backend)
328 bcd80cd9 Christos Stavrakakis
            nic = {'ip': address, 'network': network.backend_id}
329 bcd80cd9 Christos Stavrakakis
        else:
330 bcd80cd9 Christos Stavrakakis
            address = util.get_network_free_address(network)
331 501053a1 Christos Stavrakakis
332 4b8e03e5 Christos Stavrakakis
        # We must save the VM instance now, so that it gets a valid
333 4b8e03e5 Christos Stavrakakis
        # vm.backend_vm_id.
334 4b8e03e5 Christos Stavrakakis
        vm = VirtualMachine.objects.create(
335 4b8e03e5 Christos Stavrakakis
            name=name,
336 4b8e03e5 Christos Stavrakakis
            backend=backend,
337 bcd80cd9 Christos Stavrakakis
            userid=userid,
338 bcd80cd9 Christos Stavrakakis
            imageid=image["id"],
339 7f2dbcad Christos Stavrakakis
            flavor=flavor,
340 2509ce17 Christos Stavrakakis
            action="CREATE")
341 0c37a721 Christos Stavrakakis
342 939d71dd Christos Stavrakakis
        # Create VM's public NIC. Do not wait notification form ganeti hooks to
343 939d71dd Christos Stavrakakis
        # create this NIC, because if the hooks never run (e.g. building error)
344 939d71dd Christos Stavrakakis
        # the VM's public IP address will never be released!
345 939d71dd Christos Stavrakakis
        NetworkInterface.objects.create(machine=vm, network=network, index=0,
346 fa8c2506 Christos Stavrakakis
                                        ipv4=address, state="BUILDING")
347 939d71dd Christos Stavrakakis
348 482c6454 Christos Stavrakakis
        log.info("Created entry in DB for VM '%s'", vm)
349 79b7dbb7 Christos Stavrakakis
350 a9e5e76a Kostas Papadimitriou
        # dispatch server created signal
351 a9e5e76a Kostas Papadimitriou
        server_created.send(sender=vm, created_vm_params={
352 2a599282 Christos Stavrakakis
            'img_id': image['backend_id'],
353 79b7dbb7 Christos Stavrakakis
            'img_passwd': password,
354 79b7dbb7 Christos Stavrakakis
            'img_format': str(image['format']),
355 97f9c50c root
            'img_personality': json.dumps(personality),
356 97f9c50c root
            'img_properties': json.dumps(image['metadata']),
357 a9e5e76a Kostas Papadimitriou
        })
358 027e437a Kostas Papadimitriou
359 482c6454 Christos Stavrakakis
        # Also we must create the VM metadata in the same transaction.
360 4b8e03e5 Christos Stavrakakis
        for key, val in metadata.items():
361 4b8e03e5 Christos Stavrakakis
            VirtualMachineMetadata.objects.create(
362 4b8e03e5 Christos Stavrakakis
                meta_key=key,
363 4b8e03e5 Christos Stavrakakis
                meta_value=val,
364 4b8e03e5 Christos Stavrakakis
                vm=vm)
365 2509ce17 Christos Stavrakakis
        # Issue commission to Quotaholder and accept it since at the end of
366 a5781130 Christos Stavrakakis
        # this transaction the VirtualMachine object will be created in the DB.
367 2509ce17 Christos Stavrakakis
        # Note: the following call does a commit!
368 2509ce17 Christos Stavrakakis
        quotas.issue_and_accept_commission(vm)
369 4b8e03e5 Christos Stavrakakis
    except:
370 4b8e03e5 Christos Stavrakakis
        transaction.rollback()
371 4b8e03e5 Christos Stavrakakis
        raise
372 4b8e03e5 Christos Stavrakakis
    else:
373 4b8e03e5 Christos Stavrakakis
        transaction.commit()
374 adc46059 Christos Stavrakakis
375 482c6454 Christos Stavrakakis
    try:
376 482c6454 Christos Stavrakakis
        jobID = create_instance(vm, nic, flavor, image)
377 482c6454 Christos Stavrakakis
        # At this point the job is enqueued in the Ganeti backend
378 482c6454 Christos Stavrakakis
        vm.backendjobid = jobID
379 482c6454 Christos Stavrakakis
        vm.save()
380 482c6454 Christos Stavrakakis
        transaction.commit()
381 482c6454 Christos Stavrakakis
        log.info("User %s created VM %s, NIC %s, Backend %s, JobID %s",
382 bcd80cd9 Christos Stavrakakis
                 userid, vm, nic, backend, str(jobID))
383 482c6454 Christos Stavrakakis
    except GanetiApiError as e:
384 7907af91 Christos Stavrakakis
        log.exception("Can not communicate to backend %s: %s.",
385 7907af91 Christos Stavrakakis
                      backend, e)
386 7907af91 Christos Stavrakakis
        # Failed while enqueuing OP_INSTANCE_CREATE to backend. Restore
387 7907af91 Christos Stavrakakis
        # already reserved quotas by issuing a negative commission
388 7907af91 Christos Stavrakakis
        vm.operstate = "ERROR"
389 7907af91 Christos Stavrakakis
        vm.backendlogmsg = "Can not communicate to backend."
390 7907af91 Christos Stavrakakis
        vm.deleted = True
391 7907af91 Christos Stavrakakis
        vm.save()
392 7907af91 Christos Stavrakakis
        quotas.issue_and_accept_commission(vm, delete=True)
393 482c6454 Christos Stavrakakis
        raise
394 482c6454 Christos Stavrakakis
    except:
395 482c6454 Christos Stavrakakis
        transaction.rollback()
396 482c6454 Christos Stavrakakis
        raise
397 482c6454 Christos Stavrakakis
398 bcd80cd9 Christos Stavrakakis
    return vm
399 7e2f9d4b Giorgos Verigakis
400 55cd40be Vangelis Koukis
401 b3fd98ae Christos Stavrakakis
@api.api_method(http_method='GET', user_required=True, logger=log)
402 7e2f9d4b Giorgos Verigakis
def get_server_details(request, server_id):
403 c36934a7 Giorgos Verigakis
    # Normal Response Codes: 200, 203
404 c36934a7 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
405 c36934a7 Giorgos Verigakis
    #                       serviceUnavailable (503),
406 c36934a7 Giorgos Verigakis
    #                       unauthorized (401),
407 c36934a7 Giorgos Verigakis
    #                       badRequest (400),
408 c36934a7 Giorgos Verigakis
    #                       itemNotFound (404),
409 c36934a7 Giorgos Verigakis
    #                       overLimit (413)
410 ce55f211 Kostas Papadimitriou
411 0c37a721 Christos Stavrakakis
    log.debug('get_server_details %s', server_id)
412 4b3b8688 Giorgos Verigakis
    vm = util.get_vm(server_id, request.user_uniq)
413 d8e50a39 Giorgos Verigakis
    server = vm_to_dict(vm, detail=True)
414 d8e50a39 Giorgos Verigakis
    return render_server(request, server)
415 7e2f9d4b Giorgos Verigakis
416 55cd40be Vangelis Koukis
417 b3fd98ae Christos Stavrakakis
@api.api_method(http_method='PUT', user_required=True, logger=log)
418 c36934a7 Giorgos Verigakis
def update_server_name(request, server_id):
419 c36934a7 Giorgos Verigakis
    # Normal Response Code: 204
420 c36934a7 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
421 c36934a7 Giorgos Verigakis
    #                       serviceUnavailable (503),
422 c36934a7 Giorgos Verigakis
    #                       unauthorized (401),
423 c36934a7 Giorgos Verigakis
    #                       badRequest (400),
424 c36934a7 Giorgos Verigakis
    #                       badMediaType(415),
425 c36934a7 Giorgos Verigakis
    #                       itemNotFound (404),
426 c36934a7 Giorgos Verigakis
    #                       buildInProgress (409),
427 c36934a7 Giorgos Verigakis
    #                       overLimit (413)
428 aa197ee4 Vangelis Koukis
429 b3fd98ae Christos Stavrakakis
    req = utils.get_request_dict(request)
430 bf5c82dc Christos Stavrakakis
    log.info('update_server_name %s %s', server_id, req)
431 ce55f211 Kostas Papadimitriou
432 7e2f9d4b Giorgos Verigakis
    try:
433 7e2f9d4b Giorgos Verigakis
        name = req['server']['name']
434 529178b1 Giorgos Verigakis
    except (TypeError, KeyError):
435 ccd0d474 Giorgos Verigakis
        raise faults.BadRequest("Malformed request")
436 aa197ee4 Vangelis Koukis
437 7f2dbcad Christos Stavrakakis
    vm = util.get_vm(server_id, request.user_uniq, for_update=True,
438 7f2dbcad Christos Stavrakakis
                     non_suspended=True)
439 d8e50a39 Giorgos Verigakis
    vm.name = name
440 d8e50a39 Giorgos Verigakis
    vm.save()
441 aa197ee4 Vangelis Koukis
442 7e2f9d4b Giorgos Verigakis
    return HttpResponse(status=204)
443 7e2f9d4b Giorgos Verigakis
444 55cd40be Vangelis Koukis
445 b3fd98ae Christos Stavrakakis
@api.api_method(http_method='DELETE', user_required=True, logger=log)
446 4dba0480 Christos Stavrakakis
@transaction.commit_on_success
447 7e2f9d4b Giorgos Verigakis
def delete_server(request, server_id):
448 c36934a7 Giorgos Verigakis
    # Normal Response Codes: 204
449 c36934a7 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
450 c36934a7 Giorgos Verigakis
    #                       serviceUnavailable (503),
451 c36934a7 Giorgos Verigakis
    #                       unauthorized (401),
452 c36934a7 Giorgos Verigakis
    #                       itemNotFound (404),
453 c36934a7 Giorgos Verigakis
    #                       unauthorized (401),
454 c36934a7 Giorgos Verigakis
    #                       buildInProgress (409),
455 c36934a7 Giorgos Verigakis
    #                       overLimit (413)
456 ce55f211 Kostas Papadimitriou
457 bf5c82dc Christos Stavrakakis
    log.info('delete_server %s', server_id)
458 7f2dbcad Christos Stavrakakis
    vm = util.get_vm(server_id, request.user_uniq, for_update=True,
459 7f2dbcad Christos Stavrakakis
                     non_suspended=True)
460 7f2dbcad Christos Stavrakakis
    start_action(vm, 'DESTROY')
461 529178b1 Giorgos Verigakis
    delete_instance(vm)
462 7e2f9d4b Giorgos Verigakis
    return HttpResponse(status=204)
463 b016b476 Giorgos Verigakis
464 55cd40be Vangelis Koukis
465 04a95cf3 Kostas Papadimitriou
# additional server actions
466 04a95cf3 Kostas Papadimitriou
ARBITRARY_ACTIONS = ['console', 'firewallProfile']
467 04a95cf3 Kostas Papadimitriou
468 e440e835 Christos Stavrakakis
469 b3fd98ae Christos Stavrakakis
@api.api_method(http_method='POST', user_required=True, logger=log)
470 b016b476 Giorgos Verigakis
def server_action(request, server_id):
471 b3fd98ae Christos Stavrakakis
    req = utils.get_request_dict(request)
472 0c37a721 Christos Stavrakakis
    log.debug('server_action %s %s', server_id, req)
473 e221ade2 Christos Stavrakakis
474 b016b476 Giorgos Verigakis
    if len(req) != 1:
475 ccd0d474 Giorgos Verigakis
        raise faults.BadRequest("Malformed request")
476 aa197ee4 Vangelis Koukis
477 e221ade2 Christos Stavrakakis
    # Do not allow any action on deleted or suspended VMs
478 7f2dbcad Christos Stavrakakis
    vm = util.get_vm(server_id, request.user_uniq, for_update=True,
479 7f2dbcad Christos Stavrakakis
                     non_deleted=True, non_suspended=True)
480 aa197ee4 Vangelis Koukis
481 d8e50a39 Giorgos Verigakis
    try:
482 e221ade2 Christos Stavrakakis
        key = req.keys()[0]
483 b7f21824 Kostas Papadimitriou
        if key not in ARBITRARY_ACTIONS:
484 7f2dbcad Christos Stavrakakis
            start_action(vm, key_to_action(key))
485 e221ade2 Christos Stavrakakis
        val = req[key]
486 d8e50a39 Giorgos Verigakis
        assert isinstance(val, dict)
487 e221ade2 Christos Stavrakakis
        return server_actions[key](request, vm, val)
488 d8e50a39 Giorgos Verigakis
    except KeyError:
489 ccd0d474 Giorgos Verigakis
        raise faults.BadRequest("Unknown action")
490 d8e50a39 Giorgos Verigakis
    except AssertionError:
491 ccd0d474 Giorgos Verigakis
        raise faults.BadRequest("Invalid argument")
492 b016b476 Giorgos Verigakis
493 55cd40be Vangelis Koukis
494 7f2dbcad Christos Stavrakakis
def key_to_action(key):
495 7f2dbcad Christos Stavrakakis
    """Map HTTP request key to a VM Action"""
496 7f2dbcad Christos Stavrakakis
    if key == "shutdown":
497 7f2dbcad Christos Stavrakakis
        return "STOP"
498 7f2dbcad Christos Stavrakakis
    if key == "delete":
499 7f2dbcad Christos Stavrakakis
        return "DESTROY"
500 b7f21824 Kostas Papadimitriou
    if key in ARBITRARY_ACTIONS:
501 7f2dbcad Christos Stavrakakis
        return None
502 7f2dbcad Christos Stavrakakis
    else:
503 7f2dbcad Christos Stavrakakis
        return key.upper()
504 7f2dbcad Christos Stavrakakis
505 7f2dbcad Christos Stavrakakis
506 7f2dbcad Christos Stavrakakis
def start_action(vm, action):
507 7f2dbcad Christos Stavrakakis
    log.debug("Applying action %s to VM %s", action, vm)
508 7f2dbcad Christos Stavrakakis
    if not action:
509 7f2dbcad Christos Stavrakakis
        return
510 7f2dbcad Christos Stavrakakis
511 7f2dbcad Christos Stavrakakis
    if not action in [x[0] for x in VirtualMachine.ACTIONS]:
512 7f2dbcad Christos Stavrakakis
        raise faults.ServiceUnavailable("Action %s not supported" % action)
513 7f2dbcad Christos Stavrakakis
514 7f2dbcad Christos Stavrakakis
    # No actions to deleted VMs
515 7f2dbcad Christos Stavrakakis
    if vm.deleted:
516 05d401cf Christos Stavrakakis
        raise faults.BadRequest("VirtualMachine has been deleted.")
517 7f2dbcad Christos Stavrakakis
518 7f2dbcad Christos Stavrakakis
    # No actions to machines being built. They may be destroyed, however.
519 7f2dbcad Christos Stavrakakis
    if vm.operstate == 'BUILD' and action != 'DESTROY':
520 05d401cf Christos Stavrakakis
        raise faults.BuildInProgress("Server is being build.")
521 7f2dbcad Christos Stavrakakis
522 7f2dbcad Christos Stavrakakis
    vm.action = action
523 7f2dbcad Christos Stavrakakis
    vm.backendjobid = None
524 7f2dbcad Christos Stavrakakis
    vm.backendopcode = None
525 7f2dbcad Christos Stavrakakis
    vm.backendjobstatus = None
526 7f2dbcad Christos Stavrakakis
    vm.backendlogmsg = None
527 7f2dbcad Christos Stavrakakis
528 7f2dbcad Christos Stavrakakis
    vm.save()
529 7f2dbcad Christos Stavrakakis
530 7f2dbcad Christos Stavrakakis
531 b3fd98ae Christos Stavrakakis
@api.api_method(http_method='GET', user_required=True, logger=log)
532 b016b476 Giorgos Verigakis
def list_addresses(request, server_id):
533 b016b476 Giorgos Verigakis
    # Normal Response Codes: 200, 203
534 b016b476 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
535 b016b476 Giorgos Verigakis
    #                       serviceUnavailable (503),
536 b016b476 Giorgos Verigakis
    #                       unauthorized (401),
537 b016b476 Giorgos Verigakis
    #                       badRequest (400),
538 b016b476 Giorgos Verigakis
    #                       overLimit (413)
539 ce55f211 Kostas Papadimitriou
540 0c37a721 Christos Stavrakakis
    log.debug('list_addresses %s', server_id)
541 4b3b8688 Giorgos Verigakis
    vm = util.get_vm(server_id, request.user_uniq)
542 d44c236b Giorgos Verigakis
    addresses = [nic_to_dict(nic) for nic in vm.nics.all()]
543 ce55f211 Kostas Papadimitriou
544 d8e50a39 Giorgos Verigakis
    if request.serialization == 'xml':
545 b016b476 Giorgos Verigakis
        data = render_to_string('list_addresses.xml', {'addresses': addresses})
546 b016b476 Giorgos Verigakis
    else:
547 5029ff36 Christos Stavrakakis
        data = json.dumps({'addresses': addresses})
548 aa197ee4 Vangelis Koukis
549 b016b476 Giorgos Verigakis
    return HttpResponse(data, status=200)
550 b016b476 Giorgos Verigakis
551 55cd40be Vangelis Koukis
552 b3fd98ae Christos Stavrakakis
@api.api_method(http_method='GET', user_required=True, logger=log)
553 b016b476 Giorgos Verigakis
def list_addresses_by_network(request, server_id, network_id):
554 b016b476 Giorgos Verigakis
    # Normal Response Codes: 200, 203
555 b016b476 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
556 b016b476 Giorgos Verigakis
    #                       serviceUnavailable (503),
557 b016b476 Giorgos Verigakis
    #                       unauthorized (401),
558 b016b476 Giorgos Verigakis
    #                       badRequest (400),
559 b016b476 Giorgos Verigakis
    #                       itemNotFound (404),
560 b016b476 Giorgos Verigakis
    #                       overLimit (413)
561 ce55f211 Kostas Papadimitriou
562 0c37a721 Christos Stavrakakis
    log.debug('list_addresses_by_network %s %s', server_id, network_id)
563 4b3b8688 Giorgos Verigakis
    machine = util.get_vm(server_id, request.user_uniq)
564 4b3b8688 Giorgos Verigakis
    network = util.get_network(network_id, request.user_uniq)
565 b36f78fa Giorgos Verigakis
    nic = util.get_nic(machine, network)
566 d44c236b Giorgos Verigakis
    address = nic_to_dict(nic)
567 ce55f211 Kostas Papadimitriou
568 d8e50a39 Giorgos Verigakis
    if request.serialization == 'xml':
569 b016b476 Giorgos Verigakis
        data = render_to_string('address.xml', {'address': address})
570 b016b476 Giorgos Verigakis
    else:
571 b016b476 Giorgos Verigakis
        data = json.dumps({'network': address})
572 aa197ee4 Vangelis Koukis
573 b016b476 Giorgos Verigakis
    return HttpResponse(data, status=200)
574 d8e50a39 Giorgos Verigakis
575 55cd40be Vangelis Koukis
576 b3fd98ae Christos Stavrakakis
@api.api_method(http_method='GET', user_required=True, logger=log)
577 d8e50a39 Giorgos Verigakis
def list_metadata(request, server_id):
578 d8e50a39 Giorgos Verigakis
    # Normal Response Codes: 200, 203
579 d8e50a39 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
580 d8e50a39 Giorgos Verigakis
    #                       serviceUnavailable (503),
581 d8e50a39 Giorgos Verigakis
    #                       unauthorized (401),
582 d8e50a39 Giorgos Verigakis
    #                       badRequest (400),
583 d8e50a39 Giorgos Verigakis
    #                       overLimit (413)
584 ce55f211 Kostas Papadimitriou
585 0c37a721 Christos Stavrakakis
    log.debug('list_server_metadata %s', server_id)
586 4b3b8688 Giorgos Verigakis
    vm = util.get_vm(server_id, request.user_uniq)
587 7cc3c7d9 Giorgos Verigakis
    metadata = dict((m.meta_key, m.meta_value) for m in vm.metadata.all())
588 5029ff36 Christos Stavrakakis
    return util.render_metadata(request, metadata, use_values=False,
589 5029ff36 Christos Stavrakakis
                                status=200)
590 d8e50a39 Giorgos Verigakis
591 55cd40be Vangelis Koukis
592 b3fd98ae Christos Stavrakakis
@api.api_method(http_method='POST', user_required=True, logger=log)
593 d8e50a39 Giorgos Verigakis
def update_metadata(request, server_id):
594 d8e50a39 Giorgos Verigakis
    # Normal Response Code: 201
595 d8e50a39 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
596 d8e50a39 Giorgos Verigakis
    #                       serviceUnavailable (503),
597 d8e50a39 Giorgos Verigakis
    #                       unauthorized (401),
598 d8e50a39 Giorgos Verigakis
    #                       badRequest (400),
599 d8e50a39 Giorgos Verigakis
    #                       buildInProgress (409),
600 d8e50a39 Giorgos Verigakis
    #                       badMediaType(415),
601 d8e50a39 Giorgos Verigakis
    #                       overLimit (413)
602 ce55f211 Kostas Papadimitriou
603 b3fd98ae Christos Stavrakakis
    req = utils.get_request_dict(request)
604 bf5c82dc Christos Stavrakakis
    log.info('update_server_metadata %s %s', server_id, req)
605 e221ade2 Christos Stavrakakis
    vm = util.get_vm(server_id, request.user_uniq, non_suspended=True)
606 d8e50a39 Giorgos Verigakis
    try:
607 d8e50a39 Giorgos Verigakis
        metadata = req['metadata']
608 d8e50a39 Giorgos Verigakis
        assert isinstance(metadata, dict)
609 d8e50a39 Giorgos Verigakis
    except (KeyError, AssertionError):
610 ccd0d474 Giorgos Verigakis
        raise faults.BadRequest("Malformed request")
611 ce55f211 Kostas Papadimitriou
612 7cc3c7d9 Giorgos Verigakis
    for key, val in metadata.items():
613 7cc3c7d9 Giorgos Verigakis
        meta, created = vm.metadata.get_or_create(meta_key=key)
614 7cc3c7d9 Giorgos Verigakis
        meta.meta_value = val
615 7cc3c7d9 Giorgos Verigakis
        meta.save()
616 ce55f211 Kostas Papadimitriou
617 7cc3c7d9 Giorgos Verigakis
    vm.save()
618 7cc3c7d9 Giorgos Verigakis
    vm_meta = dict((m.meta_key, m.meta_value) for m in vm.metadata.all())
619 7cc3c7d9 Giorgos Verigakis
    return util.render_metadata(request, vm_meta, status=201)
620 d8e50a39 Giorgos Verigakis
621 55cd40be Vangelis Koukis
622 b3fd98ae Christos Stavrakakis
@api.api_method(http_method='GET', user_required=True, logger=log)
623 d8e50a39 Giorgos Verigakis
def get_metadata_item(request, server_id, key):
624 d8e50a39 Giorgos Verigakis
    # Normal Response Codes: 200, 203
625 d8e50a39 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
626 d8e50a39 Giorgos Verigakis
    #                       serviceUnavailable (503),
627 d8e50a39 Giorgos Verigakis
    #                       unauthorized (401),
628 d8e50a39 Giorgos Verigakis
    #                       itemNotFound (404),
629 d8e50a39 Giorgos Verigakis
    #                       badRequest (400),
630 d8e50a39 Giorgos Verigakis
    #                       overLimit (413)
631 ce55f211 Kostas Papadimitriou
632 0c37a721 Christos Stavrakakis
    log.debug('get_server_metadata_item %s %s', server_id, key)
633 4b3b8688 Giorgos Verigakis
    vm = util.get_vm(server_id, request.user_uniq)
634 b36f78fa Giorgos Verigakis
    meta = util.get_vm_meta(vm, key)
635 62b894c0 Giorgos Verigakis
    d = {meta.meta_key: meta.meta_value}
636 62b894c0 Giorgos Verigakis
    return util.render_meta(request, d, status=200)
637 d8e50a39 Giorgos Verigakis
638 55cd40be Vangelis Koukis
639 b3fd98ae Christos Stavrakakis
@api.api_method(http_method='PUT', user_required=True, logger=log)
640 4dba0480 Christos Stavrakakis
@transaction.commit_on_success
641 d8e50a39 Giorgos Verigakis
def create_metadata_item(request, server_id, key):
642 d8e50a39 Giorgos Verigakis
    # Normal Response Code: 201
643 d8e50a39 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
644 d8e50a39 Giorgos Verigakis
    #                       serviceUnavailable (503),
645 d8e50a39 Giorgos Verigakis
    #                       unauthorized (401),
646 d8e50a39 Giorgos Verigakis
    #                       itemNotFound (404),
647 d8e50a39 Giorgos Verigakis
    #                       badRequest (400),
648 d8e50a39 Giorgos Verigakis
    #                       buildInProgress (409),
649 d8e50a39 Giorgos Verigakis
    #                       badMediaType(415),
650 d8e50a39 Giorgos Verigakis
    #                       overLimit (413)
651 ce55f211 Kostas Papadimitriou
652 b3fd98ae Christos Stavrakakis
    req = utils.get_request_dict(request)
653 bf5c82dc Christos Stavrakakis
    log.info('create_server_metadata_item %s %s %s', server_id, key, req)
654 e221ade2 Christos Stavrakakis
    vm = util.get_vm(server_id, request.user_uniq, non_suspended=True)
655 d8e50a39 Giorgos Verigakis
    try:
656 d8e50a39 Giorgos Verigakis
        metadict = req['meta']
657 d8e50a39 Giorgos Verigakis
        assert isinstance(metadict, dict)
658 d8e50a39 Giorgos Verigakis
        assert len(metadict) == 1
659 d8e50a39 Giorgos Verigakis
        assert key in metadict
660 d8e50a39 Giorgos Verigakis
    except (KeyError, AssertionError):
661 ccd0d474 Giorgos Verigakis
        raise faults.BadRequest("Malformed request")
662 ce55f211 Kostas Papadimitriou
663 b36f78fa Giorgos Verigakis
    meta, created = VirtualMachineMetadata.objects.get_or_create(
664 b36f78fa Giorgos Verigakis
        meta_key=key,
665 b36f78fa Giorgos Verigakis
        vm=vm)
666 ce55f211 Kostas Papadimitriou
667 d8e50a39 Giorgos Verigakis
    meta.meta_value = metadict[key]
668 d8e50a39 Giorgos Verigakis
    meta.save()
669 5509b599 Giorgos Verigakis
    vm.save()
670 62b894c0 Giorgos Verigakis
    d = {meta.meta_key: meta.meta_value}
671 62b894c0 Giorgos Verigakis
    return util.render_meta(request, d, status=201)
672 d8e50a39 Giorgos Verigakis
673 55cd40be Vangelis Koukis
674 b3fd98ae Christos Stavrakakis
@api.api_method(http_method='DELETE', user_required=True, logger=log)
675 4dba0480 Christos Stavrakakis
@transaction.commit_on_success
676 d8e50a39 Giorgos Verigakis
def delete_metadata_item(request, server_id, key):
677 d8e50a39 Giorgos Verigakis
    # Normal Response Code: 204
678 d8e50a39 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
679 d8e50a39 Giorgos Verigakis
    #                       serviceUnavailable (503),
680 d8e50a39 Giorgos Verigakis
    #                       unauthorized (401),
681 d8e50a39 Giorgos Verigakis
    #                       itemNotFound (404),
682 d8e50a39 Giorgos Verigakis
    #                       badRequest (400),
683 d8e50a39 Giorgos Verigakis
    #                       buildInProgress (409),
684 d8e50a39 Giorgos Verigakis
    #                       badMediaType(415),
685 d8e50a39 Giorgos Verigakis
    #                       overLimit (413),
686 ce55f211 Kostas Papadimitriou
687 bf5c82dc Christos Stavrakakis
    log.info('delete_server_metadata_item %s %s', server_id, key)
688 e221ade2 Christos Stavrakakis
    vm = util.get_vm(server_id, request.user_uniq, non_suspended=True)
689 b36f78fa Giorgos Verigakis
    meta = util.get_vm_meta(vm, key)
690 d8e50a39 Giorgos Verigakis
    meta.delete()
691 5509b599 Giorgos Verigakis
    vm.save()
692 d8e50a39 Giorgos Verigakis
    return HttpResponse(status=204)
693 c738c935 Giorgos Verigakis
694 55cd40be Vangelis Koukis
695 b3fd98ae Christos Stavrakakis
@api.api_method(http_method='GET', user_required=True, logger=log)
696 c738c935 Giorgos Verigakis
def server_stats(request, server_id):
697 c738c935 Giorgos Verigakis
    # Normal Response Codes: 200
698 c738c935 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
699 c738c935 Giorgos Verigakis
    #                       serviceUnavailable (503),
700 c738c935 Giorgos Verigakis
    #                       unauthorized (401),
701 c738c935 Giorgos Verigakis
    #                       badRequest (400),
702 c738c935 Giorgos Verigakis
    #                       itemNotFound (404),
703 c738c935 Giorgos Verigakis
    #                       overLimit (413)
704 ce55f211 Kostas Papadimitriou
705 0c37a721 Christos Stavrakakis
    log.debug('server_stats %s', server_id)
706 4b3b8688 Giorgos Verigakis
    vm = util.get_vm(server_id, request.user_uniq)
707 924d8085 Christos Stavrakakis
    #secret = util.encrypt(vm.backend_vm_id)
708 924d8085 Christos Stavrakakis
    secret = vm.backend_vm_id      # XXX disable backend id encryption
709 ce55f211 Kostas Papadimitriou
710 c738c935 Giorgos Verigakis
    stats = {
711 c738c935 Giorgos Verigakis
        'serverRef': vm.id,
712 c738c935 Giorgos Verigakis
        'refresh': settings.STATS_REFRESH_PERIOD,
713 5391d6b5 Giorgos Verigakis
        'cpuBar': settings.CPU_BAR_GRAPH_URL % secret,
714 5391d6b5 Giorgos Verigakis
        'cpuTimeSeries': settings.CPU_TIMESERIES_GRAPH_URL % secret,
715 5391d6b5 Giorgos Verigakis
        'netBar': settings.NET_BAR_GRAPH_URL % secret,
716 5391d6b5 Giorgos Verigakis
        'netTimeSeries': settings.NET_TIMESERIES_GRAPH_URL % secret}
717 ce55f211 Kostas Papadimitriou
718 c738c935 Giorgos Verigakis
    if request.serialization == 'xml':
719 c738c935 Giorgos Verigakis
        data = render_to_string('server_stats.xml', stats)
720 c738c935 Giorgos Verigakis
    else:
721 c738c935 Giorgos Verigakis
        data = json.dumps({'stats': stats})
722 c738c935 Giorgos Verigakis
723 c738c935 Giorgos Verigakis
    return HttpResponse(data, status=200)