Statistics
| Branch: | Tag: | Revision:

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

History | View | Annotate | Download (24 kB)

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