Statistics
| Branch: | Tag: | Revision:

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

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