Statistics
| Branch: | Tag: | Revision:

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

History | View | Annotate | Download (23.6 kB)

1 6ef51e9f Giorgos Verigakis
# Copyright 2011-2012 GRNET S.A. All rights reserved.
2 ce55f211 Kostas Papadimitriou
#
3 adee02b8 Giorgos Verigakis
# Redistribution and use in source and binary forms, with or
4 adee02b8 Giorgos Verigakis
# without modification, are permitted provided that the following
5 adee02b8 Giorgos Verigakis
# conditions are met:
6 ce55f211 Kostas Papadimitriou
#
7 adee02b8 Giorgos Verigakis
#   1. Redistributions of source code must retain the above
8 adee02b8 Giorgos Verigakis
#      copyright notice, this list of conditions and the following
9 adee02b8 Giorgos Verigakis
#      disclaimer.
10 ce55f211 Kostas Papadimitriou
#
11 adee02b8 Giorgos Verigakis
#   2. Redistributions in binary form must reproduce the above
12 adee02b8 Giorgos Verigakis
#      copyright notice, this list of conditions and the following
13 adee02b8 Giorgos Verigakis
#      disclaimer in the documentation and/or other materials
14 adee02b8 Giorgos Verigakis
#      provided with the distribution.
15 ce55f211 Kostas Papadimitriou
#
16 adee02b8 Giorgos Verigakis
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
17 adee02b8 Giorgos Verigakis
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 adee02b8 Giorgos Verigakis
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 adee02b8 Giorgos Verigakis
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
20 adee02b8 Giorgos Verigakis
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 adee02b8 Giorgos Verigakis
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 adee02b8 Giorgos Verigakis
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23 adee02b8 Giorgos Verigakis
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24 adee02b8 Giorgos Verigakis
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 adee02b8 Giorgos Verigakis
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26 adee02b8 Giorgos Verigakis
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 adee02b8 Giorgos Verigakis
# POSSIBILITY OF SUCH DAMAGE.
28 ce55f211 Kostas Papadimitriou
#
29 adee02b8 Giorgos Verigakis
# The views and conclusions contained in the software and
30 adee02b8 Giorgos Verigakis
# documentation are those of the authors and should not be
31 adee02b8 Giorgos Verigakis
# interpreted as representing official policies, either expressed
32 adee02b8 Giorgos Verigakis
# or implied, of GRNET S.A.
33 7e2f9d4b Giorgos Verigakis
34 fc443bcd Giorgos Verigakis
from base64 import b64decode
35 fc443bcd Giorgos Verigakis
36 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 4b8e03e5 Christos Stavrakakis
    try:
309 77f45438 Christos Stavrakakis
        # Issue commission
310 77f45438 Christos Stavrakakis
        serial = quotas.issue_vm_commission(user_id, flavor)
311 77f45438 Christos Stavrakakis
        serials.append(serial)
312 77f45438 Christos Stavrakakis
        # Make the commission accepted, since in the end of this
313 77f45438 Christos Stavrakakis
        # transaction the VM will have been created in the DB.
314 77f45438 Christos Stavrakakis
        serial.accepted = True
315 77f45438 Christos Stavrakakis
        serial.save()
316 77f45438 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 77f45438 Christos Stavrakakis
            action="CREATE",
326 77f45438 Christos Stavrakakis
            serial=serial)
327 0c37a721 Christos Stavrakakis
328 79b7dbb7 Christos Stavrakakis
        password = util.random_password()
329 79b7dbb7 Christos Stavrakakis
330 2a599282 Christos Stavrakakis
        disk_template, provider = util.get_flavor_provider(flavor)
331 2a599282 Christos Stavrakakis
        if provider:
332 2a599282 Christos Stavrakakis
            flavor.disk_template = disk_template
333 2a599282 Christos Stavrakakis
            flavor.disk_provider = provider
334 2a599282 Christos Stavrakakis
            flavor.disk_origin = None
335 79b7dbb7 Christos Stavrakakis
            if provider == 'vlmc':
336 2a599282 Christos Stavrakakis
                flavor.disk_origin = image['backend_id']
337 2a599282 Christos Stavrakakis
                image['backend_id'] = 'null'
338 006c6249 Christos Stavrakakis
        else:
339 006c6249 Christos Stavrakakis
            flavor.disk_provider = None
340 79b7dbb7 Christos Stavrakakis
341 a9e5e76a Kostas Papadimitriou
        # dispatch server created signal
342 a9e5e76a Kostas Papadimitriou
        server_created.send(sender=vm, created_vm_params={
343 2a599282 Christos Stavrakakis
            'img_id': image['backend_id'],
344 79b7dbb7 Christos Stavrakakis
            'img_passwd': password,
345 79b7dbb7 Christos Stavrakakis
            'img_format': str(image['format']),
346 97f9c50c root
            'img_personality': json.dumps(personality),
347 97f9c50c root
            'img_properties': json.dumps(image['metadata']),
348 a9e5e76a Kostas Papadimitriou
        })
349 027e437a Kostas Papadimitriou
350 4b8e03e5 Christos Stavrakakis
        try:
351 79b7dbb7 Christos Stavrakakis
            jobID = create_instance(vm, nic, flavor, image)
352 4b8e03e5 Christos Stavrakakis
        except GanetiApiError:
353 4b8e03e5 Christos Stavrakakis
            vm.delete()
354 4b8e03e5 Christos Stavrakakis
            raise
355 4161cb41 Christos Stavrakakis
356 4b8e03e5 Christos Stavrakakis
        log.info("User %s created VM %s, NIC %s, Backend %s, JobID %s",
357 dca7553e Christos Stavrakakis
                user_id, vm, nic, backend, str(jobID))
358 ce55f211 Kostas Papadimitriou
359 4b8e03e5 Christos Stavrakakis
        vm.backendjobid = jobID
360 4b8e03e5 Christos Stavrakakis
        vm.save()
361 4b8e03e5 Christos Stavrakakis
362 4b8e03e5 Christos Stavrakakis
        for key, val in metadata.items():
363 4b8e03e5 Christos Stavrakakis
            VirtualMachineMetadata.objects.create(
364 4b8e03e5 Christos Stavrakakis
                meta_key=key,
365 4b8e03e5 Christos Stavrakakis
                meta_value=val,
366 4b8e03e5 Christos Stavrakakis
                vm=vm)
367 4b8e03e5 Christos Stavrakakis
368 4b8e03e5 Christos Stavrakakis
        server = vm_to_dict(vm, detail=True)
369 4b8e03e5 Christos Stavrakakis
        server['status'] = 'BUILD'
370 4b8e03e5 Christos Stavrakakis
        server['adminPass'] = password
371 adc46059 Christos Stavrakakis
372 4b8e03e5 Christos Stavrakakis
        respsone = render_server(request, server, status=202)
373 4b8e03e5 Christos Stavrakakis
    except:
374 4b8e03e5 Christos Stavrakakis
        transaction.rollback()
375 4b8e03e5 Christos Stavrakakis
        raise
376 4b8e03e5 Christos Stavrakakis
    else:
377 4b8e03e5 Christos Stavrakakis
        transaction.commit()
378 adc46059 Christos Stavrakakis
379 adc46059 Christos Stavrakakis
    return respsone
380 7e2f9d4b Giorgos Verigakis
381 55cd40be Vangelis Koukis
382 b36f78fa Giorgos Verigakis
@util.api_method('GET')
383 7e2f9d4b Giorgos Verigakis
def get_server_details(request, server_id):
384 c36934a7 Giorgos Verigakis
    # Normal Response Codes: 200, 203
385 c36934a7 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
386 c36934a7 Giorgos Verigakis
    #                       serviceUnavailable (503),
387 c36934a7 Giorgos Verigakis
    #                       unauthorized (401),
388 c36934a7 Giorgos Verigakis
    #                       badRequest (400),
389 c36934a7 Giorgos Verigakis
    #                       itemNotFound (404),
390 c36934a7 Giorgos Verigakis
    #                       overLimit (413)
391 ce55f211 Kostas Papadimitriou
392 0c37a721 Christos Stavrakakis
    log.debug('get_server_details %s', server_id)
393 4b3b8688 Giorgos Verigakis
    vm = util.get_vm(server_id, request.user_uniq)
394 d8e50a39 Giorgos Verigakis
    server = vm_to_dict(vm, detail=True)
395 d8e50a39 Giorgos Verigakis
    return render_server(request, server)
396 7e2f9d4b Giorgos Verigakis
397 55cd40be Vangelis Koukis
398 b36f78fa Giorgos Verigakis
@util.api_method('PUT')
399 c36934a7 Giorgos Verigakis
def update_server_name(request, server_id):
400 c36934a7 Giorgos Verigakis
    # Normal Response Code: 204
401 c36934a7 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
402 c36934a7 Giorgos Verigakis
    #                       serviceUnavailable (503),
403 c36934a7 Giorgos Verigakis
    #                       unauthorized (401),
404 c36934a7 Giorgos Verigakis
    #                       badRequest (400),
405 c36934a7 Giorgos Verigakis
    #                       badMediaType(415),
406 c36934a7 Giorgos Verigakis
    #                       itemNotFound (404),
407 c36934a7 Giorgos Verigakis
    #                       buildInProgress (409),
408 c36934a7 Giorgos Verigakis
    #                       overLimit (413)
409 aa197ee4 Vangelis Koukis
410 b36f78fa Giorgos Verigakis
    req = util.get_request_dict(request)
411 bf5c82dc Christos Stavrakakis
    log.info('update_server_name %s %s', server_id, req)
412 ce55f211 Kostas Papadimitriou
413 7e2f9d4b Giorgos Verigakis
    try:
414 7e2f9d4b Giorgos Verigakis
        name = req['server']['name']
415 529178b1 Giorgos Verigakis
    except (TypeError, KeyError):
416 ccd0d474 Giorgos Verigakis
        raise faults.BadRequest("Malformed request")
417 aa197ee4 Vangelis Koukis
418 7f2dbcad Christos Stavrakakis
    vm = util.get_vm(server_id, request.user_uniq, for_update=True,
419 7f2dbcad Christos Stavrakakis
                     non_suspended=True)
420 d8e50a39 Giorgos Verigakis
    vm.name = name
421 d8e50a39 Giorgos Verigakis
    vm.save()
422 aa197ee4 Vangelis Koukis
423 7e2f9d4b Giorgos Verigakis
    return HttpResponse(status=204)
424 7e2f9d4b Giorgos Verigakis
425 55cd40be Vangelis Koukis
426 b36f78fa Giorgos Verigakis
@util.api_method('DELETE')
427 4dba0480 Christos Stavrakakis
@transaction.commit_on_success
428 7e2f9d4b Giorgos Verigakis
def delete_server(request, server_id):
429 c36934a7 Giorgos Verigakis
    # Normal Response Codes: 204
430 c36934a7 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
431 c36934a7 Giorgos Verigakis
    #                       serviceUnavailable (503),
432 c36934a7 Giorgos Verigakis
    #                       unauthorized (401),
433 c36934a7 Giorgos Verigakis
    #                       itemNotFound (404),
434 c36934a7 Giorgos Verigakis
    #                       unauthorized (401),
435 c36934a7 Giorgos Verigakis
    #                       buildInProgress (409),
436 c36934a7 Giorgos Verigakis
    #                       overLimit (413)
437 ce55f211 Kostas Papadimitriou
438 bf5c82dc Christos Stavrakakis
    log.info('delete_server %s', server_id)
439 7f2dbcad Christos Stavrakakis
    vm = util.get_vm(server_id, request.user_uniq, for_update=True,
440 7f2dbcad Christos Stavrakakis
                     non_suspended=True)
441 7f2dbcad Christos Stavrakakis
    start_action(vm, 'DESTROY')
442 529178b1 Giorgos Verigakis
    delete_instance(vm)
443 7e2f9d4b Giorgos Verigakis
    return HttpResponse(status=204)
444 b016b476 Giorgos Verigakis
445 55cd40be Vangelis Koukis
446 04a95cf3 Kostas Papadimitriou
# additional server actions
447 04a95cf3 Kostas Papadimitriou
ARBITRARY_ACTIONS = ['console', 'firewallProfile']
448 04a95cf3 Kostas Papadimitriou
449 b36f78fa Giorgos Verigakis
@util.api_method('POST')
450 b016b476 Giorgos Verigakis
def server_action(request, server_id):
451 b36f78fa Giorgos Verigakis
    req = util.get_request_dict(request)
452 0c37a721 Christos Stavrakakis
    log.debug('server_action %s %s', server_id, req)
453 e221ade2 Christos Stavrakakis
454 b7f21824 Kostas Papadimitriou
455 b016b476 Giorgos Verigakis
    if len(req) != 1:
456 ccd0d474 Giorgos Verigakis
        raise faults.BadRequest("Malformed request")
457 aa197ee4 Vangelis Koukis
458 e221ade2 Christos Stavrakakis
    # Do not allow any action on deleted or suspended VMs
459 7f2dbcad Christos Stavrakakis
    vm = util.get_vm(server_id, request.user_uniq, for_update=True,
460 7f2dbcad Christos Stavrakakis
                     non_deleted=True, non_suspended=True)
461 aa197ee4 Vangelis Koukis
462 d8e50a39 Giorgos Verigakis
    try:
463 e221ade2 Christos Stavrakakis
        key = req.keys()[0]
464 b7f21824 Kostas Papadimitriou
        if key not in ARBITRARY_ACTIONS:
465 7f2dbcad Christos Stavrakakis
            start_action(vm, key_to_action(key))
466 e221ade2 Christos Stavrakakis
        val = req[key]
467 d8e50a39 Giorgos Verigakis
        assert isinstance(val, dict)
468 e221ade2 Christos Stavrakakis
        return server_actions[key](request, vm, val)
469 d8e50a39 Giorgos Verigakis
    except KeyError:
470 ccd0d474 Giorgos Verigakis
        raise faults.BadRequest("Unknown action")
471 d8e50a39 Giorgos Verigakis
    except AssertionError:
472 ccd0d474 Giorgos Verigakis
        raise faults.BadRequest("Invalid argument")
473 b016b476 Giorgos Verigakis
474 55cd40be Vangelis Koukis
475 7f2dbcad Christos Stavrakakis
def key_to_action(key):
476 7f2dbcad Christos Stavrakakis
    """Map HTTP request key to a VM Action"""
477 7f2dbcad Christos Stavrakakis
    if key == "shutdown":
478 7f2dbcad Christos Stavrakakis
        return "STOP"
479 7f2dbcad Christos Stavrakakis
    if key == "delete":
480 7f2dbcad Christos Stavrakakis
        return "DESTROY"
481 b7f21824 Kostas Papadimitriou
    if key in ARBITRARY_ACTIONS:
482 7f2dbcad Christos Stavrakakis
        return None
483 7f2dbcad Christos Stavrakakis
    else:
484 7f2dbcad Christos Stavrakakis
        return key.upper()
485 7f2dbcad Christos Stavrakakis
486 7f2dbcad Christos Stavrakakis
487 7f2dbcad Christos Stavrakakis
def start_action(vm, action):
488 7f2dbcad Christos Stavrakakis
    log.debug("Applying action %s to VM %s", action, vm)
489 7f2dbcad Christos Stavrakakis
    if not action:
490 7f2dbcad Christos Stavrakakis
        return
491 7f2dbcad Christos Stavrakakis
492 7f2dbcad Christos Stavrakakis
    if not action in [x[0] for x in VirtualMachine.ACTIONS]:
493 7f2dbcad Christos Stavrakakis
        raise faults.ServiceUnavailable("Action %s not supported" % action)
494 7f2dbcad Christos Stavrakakis
495 7f2dbcad Christos Stavrakakis
    # No actions to deleted VMs
496 7f2dbcad Christos Stavrakakis
    if vm.deleted:
497 7f2dbcad Christos Stavrakakis
        raise VirtualMachine.DeletedError
498 7f2dbcad Christos Stavrakakis
499 7f2dbcad Christos Stavrakakis
    # No actions to machines being built. They may be destroyed, however.
500 7f2dbcad Christos Stavrakakis
    if vm.operstate == 'BUILD' and action != 'DESTROY':
501 7f2dbcad Christos Stavrakakis
        raise VirtualMachine.BuildingError
502 7f2dbcad Christos Stavrakakis
503 7f2dbcad Christos Stavrakakis
    vm.action = action
504 7f2dbcad Christos Stavrakakis
    vm.backendjobid = None
505 7f2dbcad Christos Stavrakakis
    vm.backendopcode = None
506 7f2dbcad Christos Stavrakakis
    vm.backendjobstatus = None
507 7f2dbcad Christos Stavrakakis
    vm.backendlogmsg = None
508 7f2dbcad Christos Stavrakakis
509 7f2dbcad Christos Stavrakakis
    vm.save()
510 7f2dbcad Christos Stavrakakis
511 7f2dbcad Christos Stavrakakis
512 b36f78fa Giorgos Verigakis
@util.api_method('GET')
513 b016b476 Giorgos Verigakis
def list_addresses(request, server_id):
514 b016b476 Giorgos Verigakis
    # Normal Response Codes: 200, 203
515 b016b476 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
516 b016b476 Giorgos Verigakis
    #                       serviceUnavailable (503),
517 b016b476 Giorgos Verigakis
    #                       unauthorized (401),
518 b016b476 Giorgos Verigakis
    #                       badRequest (400),
519 b016b476 Giorgos Verigakis
    #                       overLimit (413)
520 ce55f211 Kostas Papadimitriou
521 0c37a721 Christos Stavrakakis
    log.debug('list_addresses %s', server_id)
522 4b3b8688 Giorgos Verigakis
    vm = util.get_vm(server_id, request.user_uniq)
523 d44c236b Giorgos Verigakis
    addresses = [nic_to_dict(nic) for nic in vm.nics.all()]
524 ce55f211 Kostas Papadimitriou
525 d8e50a39 Giorgos Verigakis
    if request.serialization == 'xml':
526 b016b476 Giorgos Verigakis
        data = render_to_string('list_addresses.xml', {'addresses': addresses})
527 b016b476 Giorgos Verigakis
    else:
528 b016b476 Giorgos Verigakis
        data = json.dumps({'addresses': {'values': addresses}})
529 aa197ee4 Vangelis Koukis
530 b016b476 Giorgos Verigakis
    return HttpResponse(data, status=200)
531 b016b476 Giorgos Verigakis
532 55cd40be Vangelis Koukis
533 b36f78fa Giorgos Verigakis
@util.api_method('GET')
534 b016b476 Giorgos Verigakis
def list_addresses_by_network(request, server_id, network_id):
535 b016b476 Giorgos Verigakis
    # Normal Response Codes: 200, 203
536 b016b476 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
537 b016b476 Giorgos Verigakis
    #                       serviceUnavailable (503),
538 b016b476 Giorgos Verigakis
    #                       unauthorized (401),
539 b016b476 Giorgos Verigakis
    #                       badRequest (400),
540 b016b476 Giorgos Verigakis
    #                       itemNotFound (404),
541 b016b476 Giorgos Verigakis
    #                       overLimit (413)
542 ce55f211 Kostas Papadimitriou
543 0c37a721 Christos Stavrakakis
    log.debug('list_addresses_by_network %s %s', server_id, network_id)
544 4b3b8688 Giorgos Verigakis
    machine = util.get_vm(server_id, request.user_uniq)
545 4b3b8688 Giorgos Verigakis
    network = util.get_network(network_id, request.user_uniq)
546 b36f78fa Giorgos Verigakis
    nic = util.get_nic(machine, network)
547 d44c236b Giorgos Verigakis
    address = nic_to_dict(nic)
548 ce55f211 Kostas Papadimitriou
549 d8e50a39 Giorgos Verigakis
    if request.serialization == 'xml':
550 b016b476 Giorgos Verigakis
        data = render_to_string('address.xml', {'address': address})
551 b016b476 Giorgos Verigakis
    else:
552 b016b476 Giorgos Verigakis
        data = json.dumps({'network': address})
553 aa197ee4 Vangelis Koukis
554 b016b476 Giorgos Verigakis
    return HttpResponse(data, status=200)
555 d8e50a39 Giorgos Verigakis
556 55cd40be Vangelis Koukis
557 b36f78fa Giorgos Verigakis
@util.api_method('GET')
558 d8e50a39 Giorgos Verigakis
def list_metadata(request, server_id):
559 d8e50a39 Giorgos Verigakis
    # Normal Response Codes: 200, 203
560 d8e50a39 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
561 d8e50a39 Giorgos Verigakis
    #                       serviceUnavailable (503),
562 d8e50a39 Giorgos Verigakis
    #                       unauthorized (401),
563 d8e50a39 Giorgos Verigakis
    #                       badRequest (400),
564 d8e50a39 Giorgos Verigakis
    #                       overLimit (413)
565 ce55f211 Kostas Papadimitriou
566 0c37a721 Christos Stavrakakis
    log.debug('list_server_metadata %s', server_id)
567 4b3b8688 Giorgos Verigakis
    vm = util.get_vm(server_id, request.user_uniq)
568 7cc3c7d9 Giorgos Verigakis
    metadata = dict((m.meta_key, m.meta_value) for m in vm.metadata.all())
569 b36f78fa Giorgos Verigakis
    return util.render_metadata(request, metadata, use_values=True, status=200)
570 d8e50a39 Giorgos Verigakis
571 55cd40be Vangelis Koukis
572 b36f78fa Giorgos Verigakis
@util.api_method('POST')
573 d8e50a39 Giorgos Verigakis
def update_metadata(request, server_id):
574 d8e50a39 Giorgos Verigakis
    # Normal Response Code: 201
575 d8e50a39 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
576 d8e50a39 Giorgos Verigakis
    #                       serviceUnavailable (503),
577 d8e50a39 Giorgos Verigakis
    #                       unauthorized (401),
578 d8e50a39 Giorgos Verigakis
    #                       badRequest (400),
579 d8e50a39 Giorgos Verigakis
    #                       buildInProgress (409),
580 d8e50a39 Giorgos Verigakis
    #                       badMediaType(415),
581 d8e50a39 Giorgos Verigakis
    #                       overLimit (413)
582 ce55f211 Kostas Papadimitriou
583 b36f78fa Giorgos Verigakis
    req = util.get_request_dict(request)
584 bf5c82dc Christos Stavrakakis
    log.info('update_server_metadata %s %s', server_id, req)
585 e221ade2 Christos Stavrakakis
    vm = util.get_vm(server_id, request.user_uniq, non_suspended=True)
586 d8e50a39 Giorgos Verigakis
    try:
587 d8e50a39 Giorgos Verigakis
        metadata = req['metadata']
588 d8e50a39 Giorgos Verigakis
        assert isinstance(metadata, dict)
589 d8e50a39 Giorgos Verigakis
    except (KeyError, AssertionError):
590 ccd0d474 Giorgos Verigakis
        raise faults.BadRequest("Malformed request")
591 ce55f211 Kostas Papadimitriou
592 7cc3c7d9 Giorgos Verigakis
    for key, val in metadata.items():
593 7cc3c7d9 Giorgos Verigakis
        meta, created = vm.metadata.get_or_create(meta_key=key)
594 7cc3c7d9 Giorgos Verigakis
        meta.meta_value = val
595 7cc3c7d9 Giorgos Verigakis
        meta.save()
596 ce55f211 Kostas Papadimitriou
597 7cc3c7d9 Giorgos Verigakis
    vm.save()
598 7cc3c7d9 Giorgos Verigakis
    vm_meta = dict((m.meta_key, m.meta_value) for m in vm.metadata.all())
599 7cc3c7d9 Giorgos Verigakis
    return util.render_metadata(request, vm_meta, status=201)
600 d8e50a39 Giorgos Verigakis
601 55cd40be Vangelis Koukis
602 b36f78fa Giorgos Verigakis
@util.api_method('GET')
603 d8e50a39 Giorgos Verigakis
def get_metadata_item(request, server_id, key):
604 d8e50a39 Giorgos Verigakis
    # Normal Response Codes: 200, 203
605 d8e50a39 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
606 d8e50a39 Giorgos Verigakis
    #                       serviceUnavailable (503),
607 d8e50a39 Giorgos Verigakis
    #                       unauthorized (401),
608 d8e50a39 Giorgos Verigakis
    #                       itemNotFound (404),
609 d8e50a39 Giorgos Verigakis
    #                       badRequest (400),
610 d8e50a39 Giorgos Verigakis
    #                       overLimit (413)
611 ce55f211 Kostas Papadimitriou
612 0c37a721 Christos Stavrakakis
    log.debug('get_server_metadata_item %s %s', server_id, key)
613 4b3b8688 Giorgos Verigakis
    vm = util.get_vm(server_id, request.user_uniq)
614 b36f78fa Giorgos Verigakis
    meta = util.get_vm_meta(vm, key)
615 62b894c0 Giorgos Verigakis
    d = {meta.meta_key: meta.meta_value}
616 62b894c0 Giorgos Verigakis
    return util.render_meta(request, d, status=200)
617 d8e50a39 Giorgos Verigakis
618 55cd40be Vangelis Koukis
619 b36f78fa Giorgos Verigakis
@util.api_method('PUT')
620 4dba0480 Christos Stavrakakis
@transaction.commit_on_success
621 d8e50a39 Giorgos Verigakis
def create_metadata_item(request, server_id, key):
622 d8e50a39 Giorgos Verigakis
    # Normal Response Code: 201
623 d8e50a39 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
624 d8e50a39 Giorgos Verigakis
    #                       serviceUnavailable (503),
625 d8e50a39 Giorgos Verigakis
    #                       unauthorized (401),
626 d8e50a39 Giorgos Verigakis
    #                       itemNotFound (404),
627 d8e50a39 Giorgos Verigakis
    #                       badRequest (400),
628 d8e50a39 Giorgos Verigakis
    #                       buildInProgress (409),
629 d8e50a39 Giorgos Verigakis
    #                       badMediaType(415),
630 d8e50a39 Giorgos Verigakis
    #                       overLimit (413)
631 ce55f211 Kostas Papadimitriou
632 b36f78fa Giorgos Verigakis
    req = util.get_request_dict(request)
633 bf5c82dc Christos Stavrakakis
    log.info('create_server_metadata_item %s %s %s', server_id, key, req)
634 e221ade2 Christos Stavrakakis
    vm = util.get_vm(server_id, request.user_uniq, non_suspended=True)
635 d8e50a39 Giorgos Verigakis
    try:
636 d8e50a39 Giorgos Verigakis
        metadict = req['meta']
637 d8e50a39 Giorgos Verigakis
        assert isinstance(metadict, dict)
638 d8e50a39 Giorgos Verigakis
        assert len(metadict) == 1
639 d8e50a39 Giorgos Verigakis
        assert key in metadict
640 d8e50a39 Giorgos Verigakis
    except (KeyError, AssertionError):
641 ccd0d474 Giorgos Verigakis
        raise faults.BadRequest("Malformed request")
642 ce55f211 Kostas Papadimitriou
643 b36f78fa Giorgos Verigakis
    meta, created = VirtualMachineMetadata.objects.get_or_create(
644 b36f78fa Giorgos Verigakis
        meta_key=key,
645 b36f78fa Giorgos Verigakis
        vm=vm)
646 ce55f211 Kostas Papadimitriou
647 d8e50a39 Giorgos Verigakis
    meta.meta_value = metadict[key]
648 d8e50a39 Giorgos Verigakis
    meta.save()
649 5509b599 Giorgos Verigakis
    vm.save()
650 62b894c0 Giorgos Verigakis
    d = {meta.meta_key: meta.meta_value}
651 62b894c0 Giorgos Verigakis
    return util.render_meta(request, d, status=201)
652 d8e50a39 Giorgos Verigakis
653 55cd40be Vangelis Koukis
654 b36f78fa Giorgos Verigakis
@util.api_method('DELETE')
655 4dba0480 Christos Stavrakakis
@transaction.commit_on_success
656 d8e50a39 Giorgos Verigakis
def delete_metadata_item(request, server_id, key):
657 d8e50a39 Giorgos Verigakis
    # Normal Response Code: 204
658 d8e50a39 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
659 d8e50a39 Giorgos Verigakis
    #                       serviceUnavailable (503),
660 d8e50a39 Giorgos Verigakis
    #                       unauthorized (401),
661 d8e50a39 Giorgos Verigakis
    #                       itemNotFound (404),
662 d8e50a39 Giorgos Verigakis
    #                       badRequest (400),
663 d8e50a39 Giorgos Verigakis
    #                       buildInProgress (409),
664 d8e50a39 Giorgos Verigakis
    #                       badMediaType(415),
665 d8e50a39 Giorgos Verigakis
    #                       overLimit (413),
666 ce55f211 Kostas Papadimitriou
667 bf5c82dc Christos Stavrakakis
    log.info('delete_server_metadata_item %s %s', server_id, key)
668 e221ade2 Christos Stavrakakis
    vm = util.get_vm(server_id, request.user_uniq, non_suspended=True)
669 b36f78fa Giorgos Verigakis
    meta = util.get_vm_meta(vm, key)
670 d8e50a39 Giorgos Verigakis
    meta.delete()
671 5509b599 Giorgos Verigakis
    vm.save()
672 d8e50a39 Giorgos Verigakis
    return HttpResponse(status=204)
673 c738c935 Giorgos Verigakis
674 55cd40be Vangelis Koukis
675 c738c935 Giorgos Verigakis
@util.api_method('GET')
676 c738c935 Giorgos Verigakis
def server_stats(request, server_id):
677 c738c935 Giorgos Verigakis
    # Normal Response Codes: 200
678 c738c935 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
679 c738c935 Giorgos Verigakis
    #                       serviceUnavailable (503),
680 c738c935 Giorgos Verigakis
    #                       unauthorized (401),
681 c738c935 Giorgos Verigakis
    #                       badRequest (400),
682 c738c935 Giorgos Verigakis
    #                       itemNotFound (404),
683 c738c935 Giorgos Verigakis
    #                       overLimit (413)
684 ce55f211 Kostas Papadimitriou
685 0c37a721 Christos Stavrakakis
    log.debug('server_stats %s', server_id)
686 4b3b8688 Giorgos Verigakis
    vm = util.get_vm(server_id, request.user_uniq)
687 924d8085 Christos Stavrakakis
    #secret = util.encrypt(vm.backend_vm_id)
688 924d8085 Christos Stavrakakis
    secret = vm.backend_vm_id      # XXX disable backend id encryption
689 ce55f211 Kostas Papadimitriou
690 c738c935 Giorgos Verigakis
    stats = {
691 c738c935 Giorgos Verigakis
        'serverRef': vm.id,
692 c738c935 Giorgos Verigakis
        'refresh': settings.STATS_REFRESH_PERIOD,
693 5391d6b5 Giorgos Verigakis
        'cpuBar': settings.CPU_BAR_GRAPH_URL % secret,
694 5391d6b5 Giorgos Verigakis
        'cpuTimeSeries': settings.CPU_TIMESERIES_GRAPH_URL % secret,
695 5391d6b5 Giorgos Verigakis
        'netBar': settings.NET_BAR_GRAPH_URL % secret,
696 5391d6b5 Giorgos Verigakis
        'netTimeSeries': settings.NET_TIMESERIES_GRAPH_URL % secret}
697 ce55f211 Kostas Papadimitriou
698 c738c935 Giorgos Verigakis
    if request.serialization == 'xml':
699 c738c935 Giorgos Verigakis
        data = render_to_string('server_stats.xml', stats)
700 c738c935 Giorgos Verigakis
    else:
701 c738c935 Giorgos Verigakis
        data = json.dumps({'stats': stats})
702 c738c935 Giorgos Verigakis
703 c738c935 Giorgos Verigakis
    return HttpResponse(data, status=200)