Statistics
| Branch: | Tag: | Revision:

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

History | View | Annotate | Download (24.2 kB)

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