Statistics
| Branch: | Tag: | Revision:

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

History | View | Annotate | Download (26.4 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 bcd80cd9 Christos Stavrakakis
    if backend is None:
326 bcd80cd9 Christos Stavrakakis
        # Allocate backend to host the server. Commit after allocation to
327 bcd80cd9 Christos Stavrakakis
        # release the locks hold by the backend allocator.
328 fc443bcd Giorgos Verigakis
        try:
329 bcd80cd9 Christos Stavrakakis
            backend_allocator = BackendAllocator()
330 bcd80cd9 Christos Stavrakakis
            backend = backend_allocator.allocate(userid, flavor)
331 bcd80cd9 Christos Stavrakakis
            if backend is None:
332 bcd80cd9 Christos Stavrakakis
                log.error("No available backend for VM with flavor %s", flavor)
333 bcd80cd9 Christos Stavrakakis
                raise faults.ServiceUnavailable("No available backends")
334 bcd80cd9 Christos Stavrakakis
        except:
335 bcd80cd9 Christos Stavrakakis
            transaction.rollback()
336 bcd80cd9 Christos Stavrakakis
            raise
337 bcd80cd9 Christos Stavrakakis
        else:
338 bcd80cd9 Christos Stavrakakis
            transaction.commit()
339 ce55f211 Kostas Papadimitriou
340 482c6454 Christos Stavrakakis
    # Fix flavor for archipelago
341 482c6454 Christos Stavrakakis
    disk_template, provider = util.get_flavor_provider(flavor)
342 482c6454 Christos Stavrakakis
    if provider:
343 482c6454 Christos Stavrakakis
        flavor.disk_template = disk_template
344 482c6454 Christos Stavrakakis
        flavor.disk_provider = provider
345 b2222a7f Christos Stavrakakis
        flavor.disk_origin = image['checksum']
346 b2222a7f Christos Stavrakakis
        image['backend_id'] = 'null'
347 482c6454 Christos Stavrakakis
    else:
348 482c6454 Christos Stavrakakis
        flavor.disk_provider = None
349 b2222a7f Christos Stavrakakis
        flavor.disk_origin = None
350 482c6454 Christos Stavrakakis
351 4b8e03e5 Christos Stavrakakis
    try:
352 bcd80cd9 Christos Stavrakakis
        if network is None:
353 bcd80cd9 Christos Stavrakakis
            # Allocate IP from public network
354 bcd80cd9 Christos Stavrakakis
            (network, address) = util.get_public_ip(backend)
355 bcd80cd9 Christos Stavrakakis
            nic = {'ip': address, 'network': network.backend_id}
356 bcd80cd9 Christos Stavrakakis
        else:
357 bcd80cd9 Christos Stavrakakis
            address = util.get_network_free_address(network)
358 501053a1 Christos Stavrakakis
359 4b8e03e5 Christos Stavrakakis
        # We must save the VM instance now, so that it gets a valid
360 4b8e03e5 Christos Stavrakakis
        # vm.backend_vm_id.
361 4b8e03e5 Christos Stavrakakis
        vm = VirtualMachine.objects.create(
362 4b8e03e5 Christos Stavrakakis
            name=name,
363 4b8e03e5 Christos Stavrakakis
            backend=backend,
364 bcd80cd9 Christos Stavrakakis
            userid=userid,
365 bcd80cd9 Christos Stavrakakis
            imageid=image["id"],
366 7f2dbcad Christos Stavrakakis
            flavor=flavor,
367 2509ce17 Christos Stavrakakis
            action="CREATE")
368 0c37a721 Christos Stavrakakis
369 939d71dd Christos Stavrakakis
        # Create VM's public NIC. Do not wait notification form ganeti hooks to
370 939d71dd Christos Stavrakakis
        # create this NIC, because if the hooks never run (e.g. building error)
371 939d71dd Christos Stavrakakis
        # the VM's public IP address will never be released!
372 939d71dd Christos Stavrakakis
        NetworkInterface.objects.create(machine=vm, network=network, index=0,
373 fa8c2506 Christos Stavrakakis
                                        ipv4=address, state="BUILDING")
374 939d71dd Christos Stavrakakis
375 482c6454 Christos Stavrakakis
        log.info("Created entry in DB for VM '%s'", vm)
376 79b7dbb7 Christos Stavrakakis
377 a9e5e76a Kostas Papadimitriou
        # dispatch server created signal
378 a9e5e76a Kostas Papadimitriou
        server_created.send(sender=vm, created_vm_params={
379 2a599282 Christos Stavrakakis
            'img_id': image['backend_id'],
380 79b7dbb7 Christos Stavrakakis
            'img_passwd': password,
381 79b7dbb7 Christos Stavrakakis
            'img_format': str(image['format']),
382 97f9c50c root
            'img_personality': json.dumps(personality),
383 97f9c50c root
            'img_properties': json.dumps(image['metadata']),
384 a9e5e76a Kostas Papadimitriou
        })
385 027e437a Kostas Papadimitriou
386 482c6454 Christos Stavrakakis
        # Also we must create the VM metadata in the same transaction.
387 4b8e03e5 Christos Stavrakakis
        for key, val in metadata.items():
388 4b8e03e5 Christos Stavrakakis
            VirtualMachineMetadata.objects.create(
389 4b8e03e5 Christos Stavrakakis
                meta_key=key,
390 4b8e03e5 Christos Stavrakakis
                meta_value=val,
391 4b8e03e5 Christos Stavrakakis
                vm=vm)
392 2509ce17 Christos Stavrakakis
        # Issue commission to Quotaholder and accept it since at the end of
393 a5781130 Christos Stavrakakis
        # this transaction the VirtualMachine object will be created in the DB.
394 2509ce17 Christos Stavrakakis
        # Note: the following call does a commit!
395 2509ce17 Christos Stavrakakis
        quotas.issue_and_accept_commission(vm)
396 4b8e03e5 Christos Stavrakakis
    except:
397 4b8e03e5 Christos Stavrakakis
        transaction.rollback()
398 4b8e03e5 Christos Stavrakakis
        raise
399 4b8e03e5 Christos Stavrakakis
    else:
400 4b8e03e5 Christos Stavrakakis
        transaction.commit()
401 adc46059 Christos Stavrakakis
402 482c6454 Christos Stavrakakis
    try:
403 482c6454 Christos Stavrakakis
        jobID = create_instance(vm, nic, flavor, image)
404 482c6454 Christos Stavrakakis
        # At this point the job is enqueued in the Ganeti backend
405 482c6454 Christos Stavrakakis
        vm.backendjobid = jobID
406 482c6454 Christos Stavrakakis
        vm.save()
407 482c6454 Christos Stavrakakis
        transaction.commit()
408 482c6454 Christos Stavrakakis
        log.info("User %s created VM %s, NIC %s, Backend %s, JobID %s",
409 bcd80cd9 Christos Stavrakakis
                 userid, vm, nic, backend, str(jobID))
410 482c6454 Christos Stavrakakis
    except GanetiApiError as e:
411 7907af91 Christos Stavrakakis
        log.exception("Can not communicate to backend %s: %s.",
412 7907af91 Christos Stavrakakis
                      backend, e)
413 7907af91 Christos Stavrakakis
        # Failed while enqueuing OP_INSTANCE_CREATE to backend. Restore
414 7907af91 Christos Stavrakakis
        # already reserved quotas by issuing a negative commission
415 7907af91 Christos Stavrakakis
        vm.operstate = "ERROR"
416 7907af91 Christos Stavrakakis
        vm.backendlogmsg = "Can not communicate to backend."
417 7907af91 Christos Stavrakakis
        vm.deleted = True
418 7907af91 Christos Stavrakakis
        vm.save()
419 7907af91 Christos Stavrakakis
        quotas.issue_and_accept_commission(vm, delete=True)
420 482c6454 Christos Stavrakakis
        raise
421 482c6454 Christos Stavrakakis
    except:
422 482c6454 Christos Stavrakakis
        transaction.rollback()
423 482c6454 Christos Stavrakakis
        raise
424 482c6454 Christos Stavrakakis
425 bcd80cd9 Christos Stavrakakis
    return vm
426 7e2f9d4b Giorgos Verigakis
427 55cd40be Vangelis Koukis
428 b3fd98ae Christos Stavrakakis
@api.api_method(http_method='GET', user_required=True, logger=log)
429 7e2f9d4b Giorgos Verigakis
def get_server_details(request, server_id):
430 c36934a7 Giorgos Verigakis
    # Normal Response Codes: 200, 203
431 c36934a7 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
432 c36934a7 Giorgos Verigakis
    #                       serviceUnavailable (503),
433 c36934a7 Giorgos Verigakis
    #                       unauthorized (401),
434 c36934a7 Giorgos Verigakis
    #                       badRequest (400),
435 c36934a7 Giorgos Verigakis
    #                       itemNotFound (404),
436 c36934a7 Giorgos Verigakis
    #                       overLimit (413)
437 ce55f211 Kostas Papadimitriou
438 0c37a721 Christos Stavrakakis
    log.debug('get_server_details %s', server_id)
439 4b3b8688 Giorgos Verigakis
    vm = util.get_vm(server_id, request.user_uniq)
440 d8e50a39 Giorgos Verigakis
    server = vm_to_dict(vm, detail=True)
441 d8e50a39 Giorgos Verigakis
    return render_server(request, server)
442 7e2f9d4b Giorgos Verigakis
443 55cd40be Vangelis Koukis
444 b3fd98ae Christos Stavrakakis
@api.api_method(http_method='PUT', user_required=True, logger=log)
445 c36934a7 Giorgos Verigakis
def update_server_name(request, server_id):
446 c36934a7 Giorgos Verigakis
    # Normal Response Code: 204
447 c36934a7 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
448 c36934a7 Giorgos Verigakis
    #                       serviceUnavailable (503),
449 c36934a7 Giorgos Verigakis
    #                       unauthorized (401),
450 c36934a7 Giorgos Verigakis
    #                       badRequest (400),
451 c36934a7 Giorgos Verigakis
    #                       badMediaType(415),
452 c36934a7 Giorgos Verigakis
    #                       itemNotFound (404),
453 c36934a7 Giorgos Verigakis
    #                       buildInProgress (409),
454 c36934a7 Giorgos Verigakis
    #                       overLimit (413)
455 aa197ee4 Vangelis Koukis
456 b3fd98ae Christos Stavrakakis
    req = utils.get_request_dict(request)
457 bf5c82dc Christos Stavrakakis
    log.info('update_server_name %s %s', server_id, req)
458 ce55f211 Kostas Papadimitriou
459 7e2f9d4b Giorgos Verigakis
    try:
460 7e2f9d4b Giorgos Verigakis
        name = req['server']['name']
461 529178b1 Giorgos Verigakis
    except (TypeError, KeyError):
462 ccd0d474 Giorgos Verigakis
        raise faults.BadRequest("Malformed request")
463 aa197ee4 Vangelis Koukis
464 7f2dbcad Christos Stavrakakis
    vm = util.get_vm(server_id, request.user_uniq, for_update=True,
465 7f2dbcad Christos Stavrakakis
                     non_suspended=True)
466 d8e50a39 Giorgos Verigakis
    vm.name = name
467 d8e50a39 Giorgos Verigakis
    vm.save()
468 aa197ee4 Vangelis Koukis
469 7e2f9d4b Giorgos Verigakis
    return HttpResponse(status=204)
470 7e2f9d4b Giorgos Verigakis
471 55cd40be Vangelis Koukis
472 b3fd98ae Christos Stavrakakis
@api.api_method(http_method='DELETE', user_required=True, logger=log)
473 4dba0480 Christos Stavrakakis
@transaction.commit_on_success
474 7e2f9d4b Giorgos Verigakis
def delete_server(request, server_id):
475 c36934a7 Giorgos Verigakis
    # Normal Response Codes: 204
476 c36934a7 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
477 c36934a7 Giorgos Verigakis
    #                       serviceUnavailable (503),
478 c36934a7 Giorgos Verigakis
    #                       unauthorized (401),
479 c36934a7 Giorgos Verigakis
    #                       itemNotFound (404),
480 c36934a7 Giorgos Verigakis
    #                       unauthorized (401),
481 c36934a7 Giorgos Verigakis
    #                       buildInProgress (409),
482 c36934a7 Giorgos Verigakis
    #                       overLimit (413)
483 ce55f211 Kostas Papadimitriou
484 bf5c82dc Christos Stavrakakis
    log.info('delete_server %s', server_id)
485 7f2dbcad Christos Stavrakakis
    vm = util.get_vm(server_id, request.user_uniq, for_update=True,
486 7f2dbcad Christos Stavrakakis
                     non_suspended=True)
487 7f2dbcad Christos Stavrakakis
    start_action(vm, 'DESTROY')
488 529178b1 Giorgos Verigakis
    delete_instance(vm)
489 7e2f9d4b Giorgos Verigakis
    return HttpResponse(status=204)
490 b016b476 Giorgos Verigakis
491 55cd40be Vangelis Koukis
492 04a95cf3 Kostas Papadimitriou
# additional server actions
493 04a95cf3 Kostas Papadimitriou
ARBITRARY_ACTIONS = ['console', 'firewallProfile']
494 04a95cf3 Kostas Papadimitriou
495 e440e835 Christos Stavrakakis
496 b3fd98ae Christos Stavrakakis
@api.api_method(http_method='POST', user_required=True, logger=log)
497 b016b476 Giorgos Verigakis
def server_action(request, server_id):
498 b3fd98ae Christos Stavrakakis
    req = utils.get_request_dict(request)
499 0c37a721 Christos Stavrakakis
    log.debug('server_action %s %s', server_id, req)
500 e221ade2 Christos Stavrakakis
501 b016b476 Giorgos Verigakis
    if len(req) != 1:
502 ccd0d474 Giorgos Verigakis
        raise faults.BadRequest("Malformed request")
503 aa197ee4 Vangelis Koukis
504 e221ade2 Christos Stavrakakis
    # Do not allow any action on deleted or suspended VMs
505 7f2dbcad Christos Stavrakakis
    vm = util.get_vm(server_id, request.user_uniq, for_update=True,
506 7f2dbcad Christos Stavrakakis
                     non_deleted=True, non_suspended=True)
507 aa197ee4 Vangelis Koukis
508 d8e50a39 Giorgos Verigakis
    try:
509 e221ade2 Christos Stavrakakis
        key = req.keys()[0]
510 b7f21824 Kostas Papadimitriou
        if key not in ARBITRARY_ACTIONS:
511 7f2dbcad Christos Stavrakakis
            start_action(vm, key_to_action(key))
512 e221ade2 Christos Stavrakakis
        val = req[key]
513 d8e50a39 Giorgos Verigakis
        assert isinstance(val, dict)
514 e221ade2 Christos Stavrakakis
        return server_actions[key](request, vm, val)
515 d8e50a39 Giorgos Verigakis
    except KeyError:
516 ccd0d474 Giorgos Verigakis
        raise faults.BadRequest("Unknown action")
517 d8e50a39 Giorgos Verigakis
    except AssertionError:
518 ccd0d474 Giorgos Verigakis
        raise faults.BadRequest("Invalid argument")
519 b016b476 Giorgos Verigakis
520 55cd40be Vangelis Koukis
521 7f2dbcad Christos Stavrakakis
def key_to_action(key):
522 7f2dbcad Christos Stavrakakis
    """Map HTTP request key to a VM Action"""
523 7f2dbcad Christos Stavrakakis
    if key == "shutdown":
524 7f2dbcad Christos Stavrakakis
        return "STOP"
525 7f2dbcad Christos Stavrakakis
    if key == "delete":
526 7f2dbcad Christos Stavrakakis
        return "DESTROY"
527 b7f21824 Kostas Papadimitriou
    if key in ARBITRARY_ACTIONS:
528 7f2dbcad Christos Stavrakakis
        return None
529 7f2dbcad Christos Stavrakakis
    else:
530 7f2dbcad Christos Stavrakakis
        return key.upper()
531 7f2dbcad Christos Stavrakakis
532 7f2dbcad Christos Stavrakakis
533 7f2dbcad Christos Stavrakakis
def start_action(vm, action):
534 7f2dbcad Christos Stavrakakis
    log.debug("Applying action %s to VM %s", action, vm)
535 7f2dbcad Christos Stavrakakis
    if not action:
536 7f2dbcad Christos Stavrakakis
        return
537 7f2dbcad Christos Stavrakakis
538 7f2dbcad Christos Stavrakakis
    if not action in [x[0] for x in VirtualMachine.ACTIONS]:
539 7f2dbcad Christos Stavrakakis
        raise faults.ServiceUnavailable("Action %s not supported" % action)
540 7f2dbcad Christos Stavrakakis
541 7f2dbcad Christos Stavrakakis
    # No actions to deleted VMs
542 7f2dbcad Christos Stavrakakis
    if vm.deleted:
543 05d401cf Christos Stavrakakis
        raise faults.BadRequest("VirtualMachine has been deleted.")
544 7f2dbcad Christos Stavrakakis
545 7f2dbcad Christos Stavrakakis
    # No actions to machines being built. They may be destroyed, however.
546 7f2dbcad Christos Stavrakakis
    if vm.operstate == 'BUILD' and action != 'DESTROY':
547 05d401cf Christos Stavrakakis
        raise faults.BuildInProgress("Server is being build.")
548 7f2dbcad Christos Stavrakakis
549 7f2dbcad Christos Stavrakakis
    vm.action = action
550 7f2dbcad Christos Stavrakakis
    vm.backendjobid = None
551 7f2dbcad Christos Stavrakakis
    vm.backendopcode = None
552 7f2dbcad Christos Stavrakakis
    vm.backendjobstatus = None
553 7f2dbcad Christos Stavrakakis
    vm.backendlogmsg = None
554 7f2dbcad Christos Stavrakakis
555 7f2dbcad Christos Stavrakakis
    vm.save()
556 7f2dbcad Christos Stavrakakis
557 7f2dbcad Christos Stavrakakis
558 b3fd98ae Christos Stavrakakis
@api.api_method(http_method='GET', user_required=True, logger=log)
559 b016b476 Giorgos Verigakis
def list_addresses(request, server_id):
560 b016b476 Giorgos Verigakis
    # Normal Response Codes: 200, 203
561 b016b476 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
562 b016b476 Giorgos Verigakis
    #                       serviceUnavailable (503),
563 b016b476 Giorgos Verigakis
    #                       unauthorized (401),
564 b016b476 Giorgos Verigakis
    #                       badRequest (400),
565 b016b476 Giorgos Verigakis
    #                       overLimit (413)
566 ce55f211 Kostas Papadimitriou
567 0c37a721 Christos Stavrakakis
    log.debug('list_addresses %s', server_id)
568 4b3b8688 Giorgos Verigakis
    vm = util.get_vm(server_id, request.user_uniq)
569 1f638a85 Christos Stavrakakis
    attachments = [nic_to_dict(nic) for nic in vm.nics.all()]
570 1f638a85 Christos Stavrakakis
    addresses = nics_to_addresses(vm.nics.all())
571 ce55f211 Kostas Papadimitriou
572 d8e50a39 Giorgos Verigakis
    if request.serialization == 'xml':
573 b016b476 Giorgos Verigakis
        data = render_to_string('list_addresses.xml', {'addresses': addresses})
574 b016b476 Giorgos Verigakis
    else:
575 1f638a85 Christos Stavrakakis
        data = json.dumps({'addresses': addresses, 'attachments': attachments})
576 aa197ee4 Vangelis Koukis
577 b016b476 Giorgos Verigakis
    return HttpResponse(data, status=200)
578 b016b476 Giorgos Verigakis
579 55cd40be Vangelis Koukis
580 b3fd98ae Christos Stavrakakis
@api.api_method(http_method='GET', user_required=True, logger=log)
581 b016b476 Giorgos Verigakis
def list_addresses_by_network(request, server_id, network_id):
582 b016b476 Giorgos Verigakis
    # Normal Response Codes: 200, 203
583 b016b476 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
584 b016b476 Giorgos Verigakis
    #                       serviceUnavailable (503),
585 b016b476 Giorgos Verigakis
    #                       unauthorized (401),
586 b016b476 Giorgos Verigakis
    #                       badRequest (400),
587 b016b476 Giorgos Verigakis
    #                       itemNotFound (404),
588 b016b476 Giorgos Verigakis
    #                       overLimit (413)
589 ce55f211 Kostas Papadimitriou
590 0c37a721 Christos Stavrakakis
    log.debug('list_addresses_by_network %s %s', server_id, network_id)
591 4b3b8688 Giorgos Verigakis
    machine = util.get_vm(server_id, request.user_uniq)
592 4b3b8688 Giorgos Verigakis
    network = util.get_network(network_id, request.user_uniq)
593 1f638a85 Christos Stavrakakis
    nics = machine.nics.filter(network=network).all()
594 1f638a85 Christos Stavrakakis
    addresses = nics_to_addresses(nics)
595 ce55f211 Kostas Papadimitriou
596 d8e50a39 Giorgos Verigakis
    if request.serialization == 'xml':
597 1f638a85 Christos Stavrakakis
        data = render_to_string('address.xml', {'addresses': addresses})
598 b016b476 Giorgos Verigakis
    else:
599 1f638a85 Christos Stavrakakis
        data = json.dumps({'network': addresses})
600 aa197ee4 Vangelis Koukis
601 b016b476 Giorgos Verigakis
    return HttpResponse(data, status=200)
602 d8e50a39 Giorgos Verigakis
603 55cd40be Vangelis Koukis
604 b3fd98ae Christos Stavrakakis
@api.api_method(http_method='GET', user_required=True, logger=log)
605 d8e50a39 Giorgos Verigakis
def list_metadata(request, server_id):
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
    #                       badRequest (400),
611 d8e50a39 Giorgos Verigakis
    #                       overLimit (413)
612 ce55f211 Kostas Papadimitriou
613 0c37a721 Christos Stavrakakis
    log.debug('list_server_metadata %s', server_id)
614 4b3b8688 Giorgos Verigakis
    vm = util.get_vm(server_id, request.user_uniq)
615 7cc3c7d9 Giorgos Verigakis
    metadata = dict((m.meta_key, m.meta_value) for m in vm.metadata.all())
616 5029ff36 Christos Stavrakakis
    return util.render_metadata(request, metadata, use_values=False,
617 5029ff36 Christos Stavrakakis
                                status=200)
618 d8e50a39 Giorgos Verigakis
619 55cd40be Vangelis Koukis
620 b3fd98ae Christos Stavrakakis
@api.api_method(http_method='POST', user_required=True, logger=log)
621 d8e50a39 Giorgos Verigakis
def update_metadata(request, server_id):
622 d8e50a39 Giorgos Verigakis
    # Normal Response Code: 201
623 d8e50a39 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
624 d8e50a39 Giorgos Verigakis
    #                       serviceUnavailable (503),
625 d8e50a39 Giorgos Verigakis
    #                       unauthorized (401),
626 d8e50a39 Giorgos Verigakis
    #                       badRequest (400),
627 d8e50a39 Giorgos Verigakis
    #                       buildInProgress (409),
628 d8e50a39 Giorgos Verigakis
    #                       badMediaType(415),
629 d8e50a39 Giorgos Verigakis
    #                       overLimit (413)
630 ce55f211 Kostas Papadimitriou
631 b3fd98ae Christos Stavrakakis
    req = utils.get_request_dict(request)
632 bf5c82dc Christos Stavrakakis
    log.info('update_server_metadata %s %s', server_id, req)
633 e221ade2 Christos Stavrakakis
    vm = util.get_vm(server_id, request.user_uniq, non_suspended=True)
634 d8e50a39 Giorgos Verigakis
    try:
635 d8e50a39 Giorgos Verigakis
        metadata = req['metadata']
636 d8e50a39 Giorgos Verigakis
        assert isinstance(metadata, dict)
637 d8e50a39 Giorgos Verigakis
    except (KeyError, AssertionError):
638 ccd0d474 Giorgos Verigakis
        raise faults.BadRequest("Malformed request")
639 ce55f211 Kostas Papadimitriou
640 7cc3c7d9 Giorgos Verigakis
    for key, val in metadata.items():
641 7cc3c7d9 Giorgos Verigakis
        meta, created = vm.metadata.get_or_create(meta_key=key)
642 7cc3c7d9 Giorgos Verigakis
        meta.meta_value = val
643 7cc3c7d9 Giorgos Verigakis
        meta.save()
644 ce55f211 Kostas Papadimitriou
645 7cc3c7d9 Giorgos Verigakis
    vm.save()
646 7cc3c7d9 Giorgos Verigakis
    vm_meta = dict((m.meta_key, m.meta_value) for m in vm.metadata.all())
647 7cc3c7d9 Giorgos Verigakis
    return util.render_metadata(request, vm_meta, status=201)
648 d8e50a39 Giorgos Verigakis
649 55cd40be Vangelis Koukis
650 b3fd98ae Christos Stavrakakis
@api.api_method(http_method='GET', user_required=True, logger=log)
651 d8e50a39 Giorgos Verigakis
def get_metadata_item(request, server_id, key):
652 d8e50a39 Giorgos Verigakis
    # Normal Response Codes: 200, 203
653 d8e50a39 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
654 d8e50a39 Giorgos Verigakis
    #                       serviceUnavailable (503),
655 d8e50a39 Giorgos Verigakis
    #                       unauthorized (401),
656 d8e50a39 Giorgos Verigakis
    #                       itemNotFound (404),
657 d8e50a39 Giorgos Verigakis
    #                       badRequest (400),
658 d8e50a39 Giorgos Verigakis
    #                       overLimit (413)
659 ce55f211 Kostas Papadimitriou
660 0c37a721 Christos Stavrakakis
    log.debug('get_server_metadata_item %s %s', server_id, key)
661 4b3b8688 Giorgos Verigakis
    vm = util.get_vm(server_id, request.user_uniq)
662 b36f78fa Giorgos Verigakis
    meta = util.get_vm_meta(vm, key)
663 62b894c0 Giorgos Verigakis
    d = {meta.meta_key: meta.meta_value}
664 62b894c0 Giorgos Verigakis
    return util.render_meta(request, d, status=200)
665 d8e50a39 Giorgos Verigakis
666 55cd40be Vangelis Koukis
667 b3fd98ae Christos Stavrakakis
@api.api_method(http_method='PUT', user_required=True, logger=log)
668 4dba0480 Christos Stavrakakis
@transaction.commit_on_success
669 d8e50a39 Giorgos Verigakis
def create_metadata_item(request, server_id, key):
670 d8e50a39 Giorgos Verigakis
    # Normal Response Code: 201
671 d8e50a39 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
672 d8e50a39 Giorgos Verigakis
    #                       serviceUnavailable (503),
673 d8e50a39 Giorgos Verigakis
    #                       unauthorized (401),
674 d8e50a39 Giorgos Verigakis
    #                       itemNotFound (404),
675 d8e50a39 Giorgos Verigakis
    #                       badRequest (400),
676 d8e50a39 Giorgos Verigakis
    #                       buildInProgress (409),
677 d8e50a39 Giorgos Verigakis
    #                       badMediaType(415),
678 d8e50a39 Giorgos Verigakis
    #                       overLimit (413)
679 ce55f211 Kostas Papadimitriou
680 b3fd98ae Christos Stavrakakis
    req = utils.get_request_dict(request)
681 bf5c82dc Christos Stavrakakis
    log.info('create_server_metadata_item %s %s %s', server_id, key, req)
682 e221ade2 Christos Stavrakakis
    vm = util.get_vm(server_id, request.user_uniq, non_suspended=True)
683 d8e50a39 Giorgos Verigakis
    try:
684 d8e50a39 Giorgos Verigakis
        metadict = req['meta']
685 d8e50a39 Giorgos Verigakis
        assert isinstance(metadict, dict)
686 d8e50a39 Giorgos Verigakis
        assert len(metadict) == 1
687 d8e50a39 Giorgos Verigakis
        assert key in metadict
688 d8e50a39 Giorgos Verigakis
    except (KeyError, AssertionError):
689 ccd0d474 Giorgos Verigakis
        raise faults.BadRequest("Malformed request")
690 ce55f211 Kostas Papadimitriou
691 b36f78fa Giorgos Verigakis
    meta, created = VirtualMachineMetadata.objects.get_or_create(
692 b36f78fa Giorgos Verigakis
        meta_key=key,
693 b36f78fa Giorgos Verigakis
        vm=vm)
694 ce55f211 Kostas Papadimitriou
695 d8e50a39 Giorgos Verigakis
    meta.meta_value = metadict[key]
696 d8e50a39 Giorgos Verigakis
    meta.save()
697 5509b599 Giorgos Verigakis
    vm.save()
698 62b894c0 Giorgos Verigakis
    d = {meta.meta_key: meta.meta_value}
699 62b894c0 Giorgos Verigakis
    return util.render_meta(request, d, status=201)
700 d8e50a39 Giorgos Verigakis
701 55cd40be Vangelis Koukis
702 b3fd98ae Christos Stavrakakis
@api.api_method(http_method='DELETE', user_required=True, logger=log)
703 4dba0480 Christos Stavrakakis
@transaction.commit_on_success
704 d8e50a39 Giorgos Verigakis
def delete_metadata_item(request, server_id, key):
705 d8e50a39 Giorgos Verigakis
    # Normal Response Code: 204
706 d8e50a39 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
707 d8e50a39 Giorgos Verigakis
    #                       serviceUnavailable (503),
708 d8e50a39 Giorgos Verigakis
    #                       unauthorized (401),
709 d8e50a39 Giorgos Verigakis
    #                       itemNotFound (404),
710 d8e50a39 Giorgos Verigakis
    #                       badRequest (400),
711 d8e50a39 Giorgos Verigakis
    #                       buildInProgress (409),
712 d8e50a39 Giorgos Verigakis
    #                       badMediaType(415),
713 d8e50a39 Giorgos Verigakis
    #                       overLimit (413),
714 ce55f211 Kostas Papadimitriou
715 bf5c82dc Christos Stavrakakis
    log.info('delete_server_metadata_item %s %s', server_id, key)
716 e221ade2 Christos Stavrakakis
    vm = util.get_vm(server_id, request.user_uniq, non_suspended=True)
717 b36f78fa Giorgos Verigakis
    meta = util.get_vm_meta(vm, key)
718 d8e50a39 Giorgos Verigakis
    meta.delete()
719 5509b599 Giorgos Verigakis
    vm.save()
720 d8e50a39 Giorgos Verigakis
    return HttpResponse(status=204)
721 c738c935 Giorgos Verigakis
722 55cd40be Vangelis Koukis
723 b3fd98ae Christos Stavrakakis
@api.api_method(http_method='GET', user_required=True, logger=log)
724 c738c935 Giorgos Verigakis
def server_stats(request, server_id):
725 c738c935 Giorgos Verigakis
    # Normal Response Codes: 200
726 c738c935 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
727 c738c935 Giorgos Verigakis
    #                       serviceUnavailable (503),
728 c738c935 Giorgos Verigakis
    #                       unauthorized (401),
729 c738c935 Giorgos Verigakis
    #                       badRequest (400),
730 c738c935 Giorgos Verigakis
    #                       itemNotFound (404),
731 c738c935 Giorgos Verigakis
    #                       overLimit (413)
732 ce55f211 Kostas Papadimitriou
733 0c37a721 Christos Stavrakakis
    log.debug('server_stats %s', server_id)
734 4b3b8688 Giorgos Verigakis
    vm = util.get_vm(server_id, request.user_uniq)
735 924d8085 Christos Stavrakakis
    #secret = util.encrypt(vm.backend_vm_id)
736 924d8085 Christos Stavrakakis
    secret = vm.backend_vm_id      # XXX disable backend id encryption
737 ce55f211 Kostas Papadimitriou
738 c738c935 Giorgos Verigakis
    stats = {
739 c738c935 Giorgos Verigakis
        'serverRef': vm.id,
740 c738c935 Giorgos Verigakis
        'refresh': settings.STATS_REFRESH_PERIOD,
741 5391d6b5 Giorgos Verigakis
        'cpuBar': settings.CPU_BAR_GRAPH_URL % secret,
742 5391d6b5 Giorgos Verigakis
        'cpuTimeSeries': settings.CPU_TIMESERIES_GRAPH_URL % secret,
743 5391d6b5 Giorgos Verigakis
        'netBar': settings.NET_BAR_GRAPH_URL % secret,
744 5391d6b5 Giorgos Verigakis
        'netTimeSeries': settings.NET_TIMESERIES_GRAPH_URL % secret}
745 ce55f211 Kostas Papadimitriou
746 c738c935 Giorgos Verigakis
    if request.serialization == 'xml':
747 c738c935 Giorgos Verigakis
        data = render_to_string('server_stats.xml', stats)
748 c738c935 Giorgos Verigakis
    else:
749 c738c935 Giorgos Verigakis
        data = json.dumps({'stats': stats})
750 c738c935 Giorgos Verigakis
751 c738c935 Giorgos Verigakis
    return HttpResponse(data, status=200)