Statistics
| Branch: | Tag: | Revision:

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

History | View | Annotate | Download (26.2 kB)

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