Statistics
| Branch: | Tag: | Revision:

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

History | View | Annotate | Download (28.9 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 ccd0d474 Giorgos Verigakis
from django.conf import settings
35 d8e50a39 Giorgos Verigakis
from django.conf.urls.defaults import patterns
36 4dba0480 Christos Stavrakakis
from django.db import transaction
37 7e2f9d4b Giorgos Verigakis
from django.http import HttpResponse
38 7e2f9d4b Giorgos Verigakis
from django.template.loader import render_to_string
39 29a59bc1 Giorgos Verigakis
from django.utils import simplejson as json
40 7e2f9d4b Giorgos Verigakis
41 b3fd98ae Christos Stavrakakis
from snf_django.lib import api
42 b3fd98ae Christos Stavrakakis
from snf_django.lib.api import faults, utils
43 bd40abfa Christos Stavrakakis
from synnefo.api import util
44 41a7fae7 Christos Stavrakakis
from synnefo.db.models import (VirtualMachine, VirtualMachineMetadata)
45 41a7fae7 Christos Stavrakakis
from synnefo.logic import servers, utils as logic_utils
46 9e98ba3c Giorgos Verigakis
47 bf5c82dc Christos Stavrakakis
from logging import getLogger
48 b3fd98ae Christos Stavrakakis
log = getLogger(__name__)
49 7e2f9d4b Giorgos Verigakis
50 e440e835 Christos Stavrakakis
urlpatterns = patterns(
51 e440e835 Christos Stavrakakis
    'synnefo.api.servers',
52 7e2f9d4b Giorgos Verigakis
    (r'^(?:/|.json|.xml)?$', 'demux'),
53 7e2f9d4b Giorgos Verigakis
    (r'^/detail(?:.json|.xml)?$', 'list_servers', {'detail': True}),
54 7e2f9d4b Giorgos Verigakis
    (r'^/(\d+)(?:.json|.xml)?$', 'server_demux'),
55 41a7fae7 Christos Stavrakakis
    (r'^/(\d+)/action(?:.json|.xml)?$', 'demux_server_action'),
56 b016b476 Giorgos Verigakis
    (r'^/(\d+)/ips(?:.json|.xml)?$', 'list_addresses'),
57 b016b476 Giorgos Verigakis
    (r'^/(\d+)/ips/(.+?)(?:.json|.xml)?$', 'list_addresses_by_network'),
58 8a992938 Christos Stavrakakis
    (r'^/(\d+)/metadata(?:.json|.xml)?$', 'metadata_demux'),
59 8a992938 Christos Stavrakakis
    (r'^/(\d+)/metadata/(.+?)(?:.json|.xml)?$', 'metadata_item_demux'),
60 c738c935 Giorgos Verigakis
    (r'^/(\d+)/stats(?:.json|.xml)?$', 'server_stats'),
61 85a634e6 Kostas Papadimitriou
    (r'^/(\d+)/diagnostics(?:.json)?$', 'get_server_diagnostics'),
62 7e2f9d4b Giorgos Verigakis
)
63 7e2f9d4b Giorgos Verigakis
64 7e2f9d4b Giorgos Verigakis
65 7e2f9d4b Giorgos Verigakis
def demux(request):
66 7e2f9d4b Giorgos Verigakis
    if request.method == 'GET':
67 7e2f9d4b Giorgos Verigakis
        return list_servers(request)
68 7e2f9d4b Giorgos Verigakis
    elif request.method == 'POST':
69 7e2f9d4b Giorgos Verigakis
        return create_server(request)
70 7e2f9d4b Giorgos Verigakis
    else:
71 c0720b78 Kostas Papadimitriou
        return api.api_method_not_allowed(request)
72 7e2f9d4b Giorgos Verigakis
73 55cd40be Vangelis Koukis
74 7e2f9d4b Giorgos Verigakis
def server_demux(request, server_id):
75 7e2f9d4b Giorgos Verigakis
    if request.method == 'GET':
76 7e2f9d4b Giorgos Verigakis
        return get_server_details(request, server_id)
77 7e2f9d4b Giorgos Verigakis
    elif request.method == 'PUT':
78 7e2f9d4b Giorgos Verigakis
        return update_server_name(request, server_id)
79 7e2f9d4b Giorgos Verigakis
    elif request.method == 'DELETE':
80 7e2f9d4b Giorgos Verigakis
        return delete_server(request, server_id)
81 7e2f9d4b Giorgos Verigakis
    else:
82 c0720b78 Kostas Papadimitriou
        return api.api_method_not_allowed(request)
83 d8e50a39 Giorgos Verigakis
84 55cd40be Vangelis Koukis
85 d8e50a39 Giorgos Verigakis
def metadata_demux(request, server_id):
86 d8e50a39 Giorgos Verigakis
    if request.method == 'GET':
87 d8e50a39 Giorgos Verigakis
        return list_metadata(request, server_id)
88 d8e50a39 Giorgos Verigakis
    elif request.method == 'POST':
89 d8e50a39 Giorgos Verigakis
        return update_metadata(request, server_id)
90 d8e50a39 Giorgos Verigakis
    else:
91 c0720b78 Kostas Papadimitriou
        return api.api_method_not_allowed(request)
92 d8e50a39 Giorgos Verigakis
93 55cd40be Vangelis Koukis
94 d8e50a39 Giorgos Verigakis
def metadata_item_demux(request, server_id, key):
95 d8e50a39 Giorgos Verigakis
    if request.method == 'GET':
96 d8e50a39 Giorgos Verigakis
        return get_metadata_item(request, server_id, key)
97 d8e50a39 Giorgos Verigakis
    elif request.method == 'PUT':
98 d8e50a39 Giorgos Verigakis
        return create_metadata_item(request, server_id, key)
99 d8e50a39 Giorgos Verigakis
    elif request.method == 'DELETE':
100 d8e50a39 Giorgos Verigakis
        return delete_metadata_item(request, server_id, key)
101 d8e50a39 Giorgos Verigakis
    else:
102 c0720b78 Kostas Papadimitriou
        return api.api_method_not_allowed(request)
103 7e2f9d4b Giorgos Verigakis
104 08b079e2 Stavros Sachtouris
105 7fede91e Christos Stavrakakis
def nic_to_dict(nic):
106 7fede91e Christos Stavrakakis
    d = {'id': util.construct_nic_id(nic),
107 7fede91e Christos Stavrakakis
         'network_id': str(nic.network.id),
108 7fede91e Christos Stavrakakis
         'mac_address': nic.mac,
109 7fede91e Christos Stavrakakis
         'ipv4': nic.ipv4 if nic.ipv4 else None,
110 7fede91e Christos Stavrakakis
         'ipv6': nic.ipv6 if nic.ipv6 else None}
111 47c66641 Dimitris Aragiorgis
112 207b70d5 Giorgos Verigakis
    if nic.firewall_profile:
113 207b70d5 Giorgos Verigakis
        d['firewallProfile'] = nic.firewall_profile
114 d44c236b Giorgos Verigakis
    return d
115 b016b476 Giorgos Verigakis
116 55cd40be Vangelis Koukis
117 1f638a85 Christos Stavrakakis
def nics_to_addresses(nics):
118 1f638a85 Christos Stavrakakis
    addresses = {}
119 1f638a85 Christos Stavrakakis
    for nic in nics:
120 1f638a85 Christos Stavrakakis
        net_nics = []
121 f8352d29 Christos Stavrakakis
        net_nics.append({"version": 4,
122 f8352d29 Christos Stavrakakis
                         "addr": nic.ipv4,
123 f8352d29 Christos Stavrakakis
                         "OS-EXT-IPS:type": "fixed"})
124 1f638a85 Christos Stavrakakis
        if nic.ipv6:
125 f8352d29 Christos Stavrakakis
            net_nics.append({"version": 6,
126 f8352d29 Christos Stavrakakis
                             "addr": nic.ipv6,
127 f8352d29 Christos Stavrakakis
                             "OS-EXT-IPS:type": "fixed"})
128 1f638a85 Christos Stavrakakis
        addresses[nic.network.id] = net_nics
129 1f638a85 Christos Stavrakakis
    return addresses
130 1f638a85 Christos Stavrakakis
131 1f638a85 Christos Stavrakakis
132 d8e50a39 Giorgos Verigakis
def vm_to_dict(vm, detail=False):
133 d8e50a39 Giorgos Verigakis
    d = dict(id=vm.id, name=vm.name)
134 1b696c26 Christos Stavrakakis
    d['links'] = util.vm_to_links(vm.id)
135 7e2f9d4b Giorgos Verigakis
    if detail:
136 936e0be3 Christos Stavrakakis
        d['user_id'] = vm.userid
137 936e0be3 Christos Stavrakakis
        d['tenant_id'] = vm.userid
138 41a7fae7 Christos Stavrakakis
        d['status'] = logic_utils.get_rsapi_state(vm)
139 41a7fae7 Christos Stavrakakis
        d['SNF:task_state'] = logic_utils.get_task_state(vm)
140 41a7fae7 Christos Stavrakakis
        d['progress'] = 100 if d['status'] == 'ACTIVE' else vm.buildpercentage
141 d8e50a39 Giorgos Verigakis
        d['hostId'] = vm.hostid
142 b3fd98ae Christos Stavrakakis
        d['updated'] = utils.isoformat(vm.updated)
143 b3fd98ae Christos Stavrakakis
        d['created'] = utils.isoformat(vm.created)
144 1b696c26 Christos Stavrakakis
        d['flavor'] = {"id": vm.flavor.id,
145 1b696c26 Christos Stavrakakis
                       "links": util.flavor_to_links(vm.flavor.id)}
146 1b696c26 Christos Stavrakakis
        d['image'] = {"id": vm.imageid,
147 1b696c26 Christos Stavrakakis
                      "links": util.image_to_links(vm.imageid)}
148 e221ade2 Christos Stavrakakis
        d['suspended'] = vm.suspended
149 ce55f211 Kostas Papadimitriou
150 7cc3c7d9 Giorgos Verigakis
        metadata = dict((m.meta_key, m.meta_value) for m in vm.metadata.all())
151 1b696c26 Christos Stavrakakis
        d['metadata'] = metadata
152 aa197ee4 Vangelis Koukis
153 939d71dd Christos Stavrakakis
        vm_nics = vm.nics.filter(state="ACTIVE").order_by("index")
154 939d71dd Christos Stavrakakis
        attachments = map(nic_to_dict, vm_nics)
155 5029ff36 Christos Stavrakakis
        d['attachments'] = attachments
156 1f638a85 Christos Stavrakakis
        d['addresses'] = nics_to_addresses(vm_nics)
157 85a634e6 Kostas Papadimitriou
158 85a634e6 Kostas Papadimitriou
        # include the latest vm diagnostic, if set
159 85a634e6 Kostas Papadimitriou
        diagnostic = vm.get_last_diagnostic()
160 85a634e6 Kostas Papadimitriou
        if diagnostic:
161 85a634e6 Kostas Papadimitriou
            d['diagnostics'] = diagnostics_to_dict([diagnostic])
162 1b696c26 Christos Stavrakakis
        else:
163 1b696c26 Christos Stavrakakis
            d['diagnostics'] = []
164 f8352d29 Christos Stavrakakis
        # Fixed
165 f8352d29 Christos Stavrakakis
        d["security_groups"] = [{"name": "default"}]
166 f8352d29 Christos Stavrakakis
        d["key_name"] = None
167 f8352d29 Christos Stavrakakis
        d["config_drive"] = ""
168 f8352d29 Christos Stavrakakis
        d["accessIPv4"] = ""
169 f8352d29 Christos Stavrakakis
        d["accessIPv6"] = ""
170 85a634e6 Kostas Papadimitriou
171 7e2f9d4b Giorgos Verigakis
    return d
172 7e2f9d4b Giorgos Verigakis
173 d8e50a39 Giorgos Verigakis
174 85a634e6 Kostas Papadimitriou
def diagnostics_to_dict(diagnostics):
175 85a634e6 Kostas Papadimitriou
    """
176 85a634e6 Kostas Papadimitriou
    Extract api data from diagnostics QuerySet.
177 85a634e6 Kostas Papadimitriou
    """
178 85a634e6 Kostas Papadimitriou
    entries = list()
179 85a634e6 Kostas Papadimitriou
180 85a634e6 Kostas Papadimitriou
    for diagnostic in diagnostics:
181 85a634e6 Kostas Papadimitriou
        # format source date if set
182 85a634e6 Kostas Papadimitriou
        formatted_source_date = None
183 85a634e6 Kostas Papadimitriou
        if diagnostic.source_date:
184 b3fd98ae Christos Stavrakakis
            formatted_source_date = utils.isoformat(diagnostic.source_date)
185 85a634e6 Kostas Papadimitriou
186 85a634e6 Kostas Papadimitriou
        entry = {
187 85a634e6 Kostas Papadimitriou
            'source': diagnostic.source,
188 b3fd98ae Christos Stavrakakis
            'created': utils.isoformat(diagnostic.created),
189 85a634e6 Kostas Papadimitriou
            'message': diagnostic.message,
190 85a634e6 Kostas Papadimitriou
            'details': diagnostic.details,
191 85a634e6 Kostas Papadimitriou
            'level': diagnostic.level,
192 85a634e6 Kostas Papadimitriou
        }
193 85a634e6 Kostas Papadimitriou
194 85a634e6 Kostas Papadimitriou
        if formatted_source_date:
195 85a634e6 Kostas Papadimitriou
            entry['source_date'] = formatted_source_date
196 85a634e6 Kostas Papadimitriou
197 85a634e6 Kostas Papadimitriou
        entries.append(entry)
198 85a634e6 Kostas Papadimitriou
199 85a634e6 Kostas Papadimitriou
    return entries
200 85a634e6 Kostas Papadimitriou
201 85a634e6 Kostas Papadimitriou
202 d8e50a39 Giorgos Verigakis
def render_server(request, server, status=200):
203 d8e50a39 Giorgos Verigakis
    if request.serialization == 'xml':
204 b36f78fa Giorgos Verigakis
        data = render_to_string('server.xml', {
205 b36f78fa Giorgos Verigakis
            'server': server,
206 b36f78fa Giorgos Verigakis
            'is_root': True})
207 7e2f9d4b Giorgos Verigakis
    else:
208 d8e50a39 Giorgos Verigakis
        data = json.dumps({'server': server})
209 c36934a7 Giorgos Verigakis
    return HttpResponse(data, status=status)
210 aa197ee4 Vangelis Koukis
211 7e2f9d4b Giorgos Verigakis
212 85a634e6 Kostas Papadimitriou
def render_diagnostics(request, diagnostics_dict, status=200):
213 85a634e6 Kostas Papadimitriou
    """
214 85a634e6 Kostas Papadimitriou
    Render diagnostics dictionary to json response.
215 85a634e6 Kostas Papadimitriou
    """
216 85a634e6 Kostas Papadimitriou
    return HttpResponse(json.dumps(diagnostics_dict), status=status)
217 85a634e6 Kostas Papadimitriou
218 85a634e6 Kostas Papadimitriou
219 b3fd98ae Christos Stavrakakis
@api.api_method(http_method='GET', user_required=True, logger=log)
220 85a634e6 Kostas Papadimitriou
def get_server_diagnostics(request, server_id):
221 85a634e6 Kostas Papadimitriou
    """
222 85a634e6 Kostas Papadimitriou
    Virtual machine diagnostics api view.
223 85a634e6 Kostas Papadimitriou
    """
224 85a634e6 Kostas Papadimitriou
    log.debug('server_diagnostics %s', server_id)
225 85a634e6 Kostas Papadimitriou
    vm = util.get_vm(server_id, request.user_uniq)
226 85a634e6 Kostas Papadimitriou
    diagnostics = diagnostics_to_dict(vm.diagnostics.all())
227 85a634e6 Kostas Papadimitriou
    return render_diagnostics(request, diagnostics)
228 85a634e6 Kostas Papadimitriou
229 85a634e6 Kostas Papadimitriou
230 b3fd98ae Christos Stavrakakis
@api.api_method(http_method='GET', user_required=True, logger=log)
231 7e2f9d4b Giorgos Verigakis
def list_servers(request, detail=False):
232 7e2f9d4b Giorgos Verigakis
    # Normal Response Codes: 200, 203
233 7e2f9d4b Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
234 7e2f9d4b Giorgos Verigakis
    #                       serviceUnavailable (503),
235 7e2f9d4b Giorgos Verigakis
    #                       unauthorized (401),
236 7e2f9d4b Giorgos Verigakis
    #                       badRequest (400),
237 7e2f9d4b Giorgos Verigakis
    #                       overLimit (413)
238 ce55f211 Kostas Papadimitriou
239 0c37a721 Christos Stavrakakis
    log.debug('list_servers detail=%s', detail)
240 e524ed5f Kostas Papadimitriou
    user_vms = VirtualMachine.objects.filter(userid=request.user_uniq)
241 ce55f211 Kostas Papadimitriou
242 b3fd98ae Christos Stavrakakis
    since = utils.isoparse(request.GET.get('changes-since'))
243 85a634e6 Kostas Papadimitriou
244 d8e50a39 Giorgos Verigakis
    if since:
245 2987cd8a Giorgos Verigakis
        user_vms = user_vms.filter(updated__gte=since)
246 d8e50a39 Giorgos Verigakis
        if not user_vms:
247 d8e50a39 Giorgos Verigakis
            return HttpResponse(status=304)
248 e524ed5f Kostas Papadimitriou
    else:
249 1d7c75e4 Kostas Papadimitriou
        user_vms = user_vms.filter(deleted=False)
250 ce55f211 Kostas Papadimitriou
251 41a7fae7 Christos Stavrakakis
    servers_dict = [vm_to_dict(server, detail)
252 41a7fae7 Christos Stavrakakis
                    for server in user_vms.order_by('id')]
253 aa197ee4 Vangelis Koukis
254 d8e50a39 Giorgos Verigakis
    if request.serialization == 'xml':
255 b36f78fa Giorgos Verigakis
        data = render_to_string('list_servers.xml', {
256 41a7fae7 Christos Stavrakakis
            'servers': servers_dict,
257 b36f78fa Giorgos Verigakis
            'detail': detail})
258 7e2f9d4b Giorgos Verigakis
    else:
259 41a7fae7 Christos Stavrakakis
        data = json.dumps({'servers': servers_dict})
260 aa197ee4 Vangelis Koukis
261 c36934a7 Giorgos Verigakis
    return HttpResponse(data, status=200)
262 7e2f9d4b Giorgos Verigakis
263 55cd40be Vangelis Koukis
264 b3fd98ae Christos Stavrakakis
@api.api_method(http_method='POST', user_required=True, logger=log)
265 2509ce17 Christos Stavrakakis
def create_server(request):
266 7e2f9d4b Giorgos Verigakis
    # Normal Response Code: 202
267 7e2f9d4b Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
268 7e2f9d4b Giorgos Verigakis
    #                       serviceUnavailable (503),
269 7e2f9d4b Giorgos Verigakis
    #                       unauthorized (401),
270 7e2f9d4b Giorgos Verigakis
    #                       badMediaType(415),
271 7e2f9d4b Giorgos Verigakis
    #                       itemNotFound (404),
272 7e2f9d4b Giorgos Verigakis
    #                       badRequest (400),
273 7e2f9d4b Giorgos Verigakis
    #                       serverCapacityUnavailable (503),
274 7e2f9d4b Giorgos Verigakis
    #                       overLimit (413)
275 bcd80cd9 Christos Stavrakakis
    req = utils.get_request_dict(request)
276 bcd80cd9 Christos Stavrakakis
    log.info('create_server %s', req)
277 bcd80cd9 Christos Stavrakakis
    user_id = request.user_uniq
278 bcd80cd9 Christos Stavrakakis
279 7e2f9d4b Giorgos Verigakis
    try:
280 bcd80cd9 Christos Stavrakakis
        server = req['server']
281 bcd80cd9 Christos Stavrakakis
        name = server['name']
282 bcd80cd9 Christos Stavrakakis
        metadata = server.get('metadata', {})
283 bcd80cd9 Christos Stavrakakis
        assert isinstance(metadata, dict)
284 bcd80cd9 Christos Stavrakakis
        image_id = server['imageRef']
285 bcd80cd9 Christos Stavrakakis
        flavor_id = server['flavorRef']
286 bcd80cd9 Christos Stavrakakis
        personality = server.get('personality', [])
287 bcd80cd9 Christos Stavrakakis
        assert isinstance(personality, list)
288 bcd80cd9 Christos Stavrakakis
    except (KeyError, AssertionError):
289 bcd80cd9 Christos Stavrakakis
        raise faults.BadRequest("Malformed request")
290 bcd80cd9 Christos Stavrakakis
291 bcd80cd9 Christos Stavrakakis
    # Verify that personalities are well-formed
292 bcd80cd9 Christos Stavrakakis
    util.verify_personality(personality)
293 bcd80cd9 Christos Stavrakakis
    # Get image information
294 bcd80cd9 Christos Stavrakakis
    image = util.get_image_dict(image_id, user_id)
295 bcd80cd9 Christos Stavrakakis
    # Get flavor (ensure it is active)
296 bcd80cd9 Christos Stavrakakis
    flavor = util.get_flavor(flavor_id, include_deleted=False)
297 bcd80cd9 Christos Stavrakakis
    # Generate password
298 bcd80cd9 Christos Stavrakakis
    password = util.random_password()
299 bcd80cd9 Christos Stavrakakis
300 41a7fae7 Christos Stavrakakis
    vm = servers.create(user_id, name, password, flavor, image,
301 41a7fae7 Christos Stavrakakis
                        metadata=metadata, personality=personality)
302 bcd80cd9 Christos Stavrakakis
303 bcd80cd9 Christos Stavrakakis
    server = vm_to_dict(vm, detail=True)
304 bcd80cd9 Christos Stavrakakis
    server['status'] = 'BUILD'
305 bcd80cd9 Christos Stavrakakis
    server['adminPass'] = password
306 bcd80cd9 Christos Stavrakakis
307 bcd80cd9 Christos Stavrakakis
    response = render_server(request, server, status=202)
308 4b8e03e5 Christos Stavrakakis
309 bcd80cd9 Christos Stavrakakis
    return response
310 bcd80cd9 Christos Stavrakakis
311 bcd80cd9 Christos Stavrakakis
312 b3fd98ae Christos Stavrakakis
@api.api_method(http_method='GET', user_required=True, logger=log)
313 7e2f9d4b Giorgos Verigakis
def get_server_details(request, server_id):
314 c36934a7 Giorgos Verigakis
    # Normal Response Codes: 200, 203
315 c36934a7 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
316 c36934a7 Giorgos Verigakis
    #                       serviceUnavailable (503),
317 c36934a7 Giorgos Verigakis
    #                       unauthorized (401),
318 c36934a7 Giorgos Verigakis
    #                       badRequest (400),
319 c36934a7 Giorgos Verigakis
    #                       itemNotFound (404),
320 c36934a7 Giorgos Verigakis
    #                       overLimit (413)
321 ce55f211 Kostas Papadimitriou
322 0c37a721 Christos Stavrakakis
    log.debug('get_server_details %s', server_id)
323 4b3b8688 Giorgos Verigakis
    vm = util.get_vm(server_id, request.user_uniq)
324 d8e50a39 Giorgos Verigakis
    server = vm_to_dict(vm, detail=True)
325 d8e50a39 Giorgos Verigakis
    return render_server(request, server)
326 7e2f9d4b Giorgos Verigakis
327 55cd40be Vangelis Koukis
328 b3fd98ae Christos Stavrakakis
@api.api_method(http_method='PUT', user_required=True, logger=log)
329 c36934a7 Giorgos Verigakis
def update_server_name(request, server_id):
330 c36934a7 Giorgos Verigakis
    # Normal Response Code: 204
331 c36934a7 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
332 c36934a7 Giorgos Verigakis
    #                       serviceUnavailable (503),
333 c36934a7 Giorgos Verigakis
    #                       unauthorized (401),
334 c36934a7 Giorgos Verigakis
    #                       badRequest (400),
335 c36934a7 Giorgos Verigakis
    #                       badMediaType(415),
336 c36934a7 Giorgos Verigakis
    #                       itemNotFound (404),
337 c36934a7 Giorgos Verigakis
    #                       buildInProgress (409),
338 c36934a7 Giorgos Verigakis
    #                       overLimit (413)
339 aa197ee4 Vangelis Koukis
340 b3fd98ae Christos Stavrakakis
    req = utils.get_request_dict(request)
341 bf5c82dc Christos Stavrakakis
    log.info('update_server_name %s %s', server_id, req)
342 ce55f211 Kostas Papadimitriou
343 7e2f9d4b Giorgos Verigakis
    try:
344 7e2f9d4b Giorgos Verigakis
        name = req['server']['name']
345 529178b1 Giorgos Verigakis
    except (TypeError, KeyError):
346 ccd0d474 Giorgos Verigakis
        raise faults.BadRequest("Malformed request")
347 aa197ee4 Vangelis Koukis
348 7f2dbcad Christos Stavrakakis
    vm = util.get_vm(server_id, request.user_uniq, for_update=True,
349 7f2dbcad Christos Stavrakakis
                     non_suspended=True)
350 d8e50a39 Giorgos Verigakis
    vm.name = name
351 d8e50a39 Giorgos Verigakis
    vm.save()
352 aa197ee4 Vangelis Koukis
353 7e2f9d4b Giorgos Verigakis
    return HttpResponse(status=204)
354 7e2f9d4b Giorgos Verigakis
355 55cd40be Vangelis Koukis
356 b3fd98ae Christos Stavrakakis
@api.api_method(http_method='DELETE', user_required=True, logger=log)
357 7e2f9d4b Giorgos Verigakis
def delete_server(request, server_id):
358 c36934a7 Giorgos Verigakis
    # Normal Response Codes: 204
359 c36934a7 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
360 c36934a7 Giorgos Verigakis
    #                       serviceUnavailable (503),
361 c36934a7 Giorgos Verigakis
    #                       unauthorized (401),
362 c36934a7 Giorgos Verigakis
    #                       itemNotFound (404),
363 c36934a7 Giorgos Verigakis
    #                       unauthorized (401),
364 c36934a7 Giorgos Verigakis
    #                       buildInProgress (409),
365 c36934a7 Giorgos Verigakis
    #                       overLimit (413)
366 ce55f211 Kostas Papadimitriou
367 bf5c82dc Christos Stavrakakis
    log.info('delete_server %s', server_id)
368 7f2dbcad Christos Stavrakakis
    vm = util.get_vm(server_id, request.user_uniq, for_update=True,
369 7f2dbcad Christos Stavrakakis
                     non_suspended=True)
370 41a7fae7 Christos Stavrakakis
    vm = servers.destroy(vm)
371 7e2f9d4b Giorgos Verigakis
    return HttpResponse(status=204)
372 b016b476 Giorgos Verigakis
373 55cd40be Vangelis Koukis
374 04a95cf3 Kostas Papadimitriou
# additional server actions
375 04a95cf3 Kostas Papadimitriou
ARBITRARY_ACTIONS = ['console', 'firewallProfile']
376 04a95cf3 Kostas Papadimitriou
377 e440e835 Christos Stavrakakis
378 7f2dbcad Christos Stavrakakis
def key_to_action(key):
379 7f2dbcad Christos Stavrakakis
    """Map HTTP request key to a VM Action"""
380 7f2dbcad Christos Stavrakakis
    if key == "shutdown":
381 7f2dbcad Christos Stavrakakis
        return "STOP"
382 7f2dbcad Christos Stavrakakis
    if key == "delete":
383 7f2dbcad Christos Stavrakakis
        return "DESTROY"
384 b7f21824 Kostas Papadimitriou
    if key in ARBITRARY_ACTIONS:
385 7f2dbcad Christos Stavrakakis
        return None
386 7f2dbcad Christos Stavrakakis
    else:
387 7f2dbcad Christos Stavrakakis
        return key.upper()
388 7f2dbcad Christos Stavrakakis
389 7f2dbcad Christos Stavrakakis
390 41a7fae7 Christos Stavrakakis
@api.api_method(http_method='POST', user_required=True, logger=log)
391 41a7fae7 Christos Stavrakakis
@transaction.commit_on_success
392 41a7fae7 Christos Stavrakakis
def demux_server_action(request, server_id):
393 41a7fae7 Christos Stavrakakis
    req = utils.get_request_dict(request)
394 41a7fae7 Christos Stavrakakis
    log.debug('server_action %s %s', server_id, req)
395 7f2dbcad Christos Stavrakakis
396 41a7fae7 Christos Stavrakakis
    if len(req) != 1:
397 41a7fae7 Christos Stavrakakis
        raise faults.BadRequest("Malformed request")
398 41a7fae7 Christos Stavrakakis
399 41a7fae7 Christos Stavrakakis
    # Do not allow any action on deleted or suspended VMs
400 41a7fae7 Christos Stavrakakis
    vm = util.get_vm(server_id, request.user_uniq, for_update=True,
401 41a7fae7 Christos Stavrakakis
                     non_deleted=True, non_suspended=True)
402 7f2dbcad Christos Stavrakakis
403 41a7fae7 Christos Stavrakakis
    try:
404 41a7fae7 Christos Stavrakakis
        action = req.keys()[0]
405 41a7fae7 Christos Stavrakakis
    except KeyError:
406 41a7fae7 Christos Stavrakakis
        raise faults.BadRequest("Unknown action")
407 7f2dbcad Christos Stavrakakis
408 41a7fae7 Christos Stavrakakis
    if key_to_action(action) not in [x[0] for x in VirtualMachine.ACTIONS]:
409 41a7fae7 Christos Stavrakakis
        if action not in ARBITRARY_ACTIONS:
410 41a7fae7 Christos Stavrakakis
            raise faults.BadRequest("Action %s not supported" % action)
411 41a7fae7 Christos Stavrakakis
    action_args = req[action]
412 7f2dbcad Christos Stavrakakis
413 41a7fae7 Christos Stavrakakis
    if not isinstance(action_args, dict):
414 41a7fae7 Christos Stavrakakis
        raise faults.BadRequest("Invalid argument")
415 7f2dbcad Christos Stavrakakis
416 41a7fae7 Christos Stavrakakis
    return server_actions[action](request, vm, action_args)
417 7f2dbcad Christos Stavrakakis
418 7f2dbcad Christos Stavrakakis
419 b3fd98ae Christos Stavrakakis
@api.api_method(http_method='GET', user_required=True, logger=log)
420 b016b476 Giorgos Verigakis
def list_addresses(request, server_id):
421 b016b476 Giorgos Verigakis
    # Normal Response Codes: 200, 203
422 b016b476 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
423 b016b476 Giorgos Verigakis
    #                       serviceUnavailable (503),
424 b016b476 Giorgos Verigakis
    #                       unauthorized (401),
425 b016b476 Giorgos Verigakis
    #                       badRequest (400),
426 b016b476 Giorgos Verigakis
    #                       overLimit (413)
427 ce55f211 Kostas Papadimitriou
428 0c37a721 Christos Stavrakakis
    log.debug('list_addresses %s', server_id)
429 4b3b8688 Giorgos Verigakis
    vm = util.get_vm(server_id, request.user_uniq)
430 1f638a85 Christos Stavrakakis
    attachments = [nic_to_dict(nic) for nic in vm.nics.all()]
431 1f638a85 Christos Stavrakakis
    addresses = nics_to_addresses(vm.nics.all())
432 ce55f211 Kostas Papadimitriou
433 d8e50a39 Giorgos Verigakis
    if request.serialization == 'xml':
434 b016b476 Giorgos Verigakis
        data = render_to_string('list_addresses.xml', {'addresses': addresses})
435 b016b476 Giorgos Verigakis
    else:
436 1f638a85 Christos Stavrakakis
        data = json.dumps({'addresses': addresses, 'attachments': attachments})
437 aa197ee4 Vangelis Koukis
438 b016b476 Giorgos Verigakis
    return HttpResponse(data, status=200)
439 b016b476 Giorgos Verigakis
440 55cd40be Vangelis Koukis
441 b3fd98ae Christos Stavrakakis
@api.api_method(http_method='GET', user_required=True, logger=log)
442 b016b476 Giorgos Verigakis
def list_addresses_by_network(request, server_id, network_id):
443 b016b476 Giorgos Verigakis
    # Normal Response Codes: 200, 203
444 b016b476 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
445 b016b476 Giorgos Verigakis
    #                       serviceUnavailable (503),
446 b016b476 Giorgos Verigakis
    #                       unauthorized (401),
447 b016b476 Giorgos Verigakis
    #                       badRequest (400),
448 b016b476 Giorgos Verigakis
    #                       itemNotFound (404),
449 b016b476 Giorgos Verigakis
    #                       overLimit (413)
450 ce55f211 Kostas Papadimitriou
451 0c37a721 Christos Stavrakakis
    log.debug('list_addresses_by_network %s %s', server_id, network_id)
452 4b3b8688 Giorgos Verigakis
    machine = util.get_vm(server_id, request.user_uniq)
453 4b3b8688 Giorgos Verigakis
    network = util.get_network(network_id, request.user_uniq)
454 1f638a85 Christos Stavrakakis
    nics = machine.nics.filter(network=network).all()
455 1f638a85 Christos Stavrakakis
    addresses = nics_to_addresses(nics)
456 ce55f211 Kostas Papadimitriou
457 d8e50a39 Giorgos Verigakis
    if request.serialization == 'xml':
458 1f638a85 Christos Stavrakakis
        data = render_to_string('address.xml', {'addresses': addresses})
459 b016b476 Giorgos Verigakis
    else:
460 1f638a85 Christos Stavrakakis
        data = json.dumps({'network': addresses})
461 aa197ee4 Vangelis Koukis
462 b016b476 Giorgos Verigakis
    return HttpResponse(data, status=200)
463 d8e50a39 Giorgos Verigakis
464 55cd40be Vangelis Koukis
465 b3fd98ae Christos Stavrakakis
@api.api_method(http_method='GET', user_required=True, logger=log)
466 d8e50a39 Giorgos Verigakis
def list_metadata(request, server_id):
467 d8e50a39 Giorgos Verigakis
    # Normal Response Codes: 200, 203
468 d8e50a39 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
469 d8e50a39 Giorgos Verigakis
    #                       serviceUnavailable (503),
470 d8e50a39 Giorgos Verigakis
    #                       unauthorized (401),
471 d8e50a39 Giorgos Verigakis
    #                       badRequest (400),
472 d8e50a39 Giorgos Verigakis
    #                       overLimit (413)
473 ce55f211 Kostas Papadimitriou
474 0c37a721 Christos Stavrakakis
    log.debug('list_server_metadata %s', server_id)
475 4b3b8688 Giorgos Verigakis
    vm = util.get_vm(server_id, request.user_uniq)
476 7cc3c7d9 Giorgos Verigakis
    metadata = dict((m.meta_key, m.meta_value) for m in vm.metadata.all())
477 5029ff36 Christos Stavrakakis
    return util.render_metadata(request, metadata, use_values=False,
478 5029ff36 Christos Stavrakakis
                                status=200)
479 d8e50a39 Giorgos Verigakis
480 55cd40be Vangelis Koukis
481 b3fd98ae Christos Stavrakakis
@api.api_method(http_method='POST', user_required=True, logger=log)
482 d8e50a39 Giorgos Verigakis
def update_metadata(request, server_id):
483 d8e50a39 Giorgos Verigakis
    # Normal Response Code: 201
484 d8e50a39 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
485 d8e50a39 Giorgos Verigakis
    #                       serviceUnavailable (503),
486 d8e50a39 Giorgos Verigakis
    #                       unauthorized (401),
487 d8e50a39 Giorgos Verigakis
    #                       badRequest (400),
488 d8e50a39 Giorgos Verigakis
    #                       buildInProgress (409),
489 d8e50a39 Giorgos Verigakis
    #                       badMediaType(415),
490 d8e50a39 Giorgos Verigakis
    #                       overLimit (413)
491 ce55f211 Kostas Papadimitriou
492 b3fd98ae Christos Stavrakakis
    req = utils.get_request_dict(request)
493 bf5c82dc Christos Stavrakakis
    log.info('update_server_metadata %s %s', server_id, req)
494 e221ade2 Christos Stavrakakis
    vm = util.get_vm(server_id, request.user_uniq, non_suspended=True)
495 d8e50a39 Giorgos Verigakis
    try:
496 d8e50a39 Giorgos Verigakis
        metadata = req['metadata']
497 d8e50a39 Giorgos Verigakis
        assert isinstance(metadata, dict)
498 d8e50a39 Giorgos Verigakis
    except (KeyError, AssertionError):
499 ccd0d474 Giorgos Verigakis
        raise faults.BadRequest("Malformed request")
500 ce55f211 Kostas Papadimitriou
501 7cc3c7d9 Giorgos Verigakis
    for key, val in metadata.items():
502 7cc3c7d9 Giorgos Verigakis
        meta, created = vm.metadata.get_or_create(meta_key=key)
503 7cc3c7d9 Giorgos Verigakis
        meta.meta_value = val
504 7cc3c7d9 Giorgos Verigakis
        meta.save()
505 ce55f211 Kostas Papadimitriou
506 7cc3c7d9 Giorgos Verigakis
    vm.save()
507 7cc3c7d9 Giorgos Verigakis
    vm_meta = dict((m.meta_key, m.meta_value) for m in vm.metadata.all())
508 7cc3c7d9 Giorgos Verigakis
    return util.render_metadata(request, vm_meta, status=201)
509 d8e50a39 Giorgos Verigakis
510 55cd40be Vangelis Koukis
511 b3fd98ae Christos Stavrakakis
@api.api_method(http_method='GET', user_required=True, logger=log)
512 d8e50a39 Giorgos Verigakis
def get_metadata_item(request, server_id, key):
513 d8e50a39 Giorgos Verigakis
    # Normal Response Codes: 200, 203
514 d8e50a39 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
515 d8e50a39 Giorgos Verigakis
    #                       serviceUnavailable (503),
516 d8e50a39 Giorgos Verigakis
    #                       unauthorized (401),
517 d8e50a39 Giorgos Verigakis
    #                       itemNotFound (404),
518 d8e50a39 Giorgos Verigakis
    #                       badRequest (400),
519 d8e50a39 Giorgos Verigakis
    #                       overLimit (413)
520 ce55f211 Kostas Papadimitriou
521 0c37a721 Christos Stavrakakis
    log.debug('get_server_metadata_item %s %s', server_id, key)
522 4b3b8688 Giorgos Verigakis
    vm = util.get_vm(server_id, request.user_uniq)
523 b36f78fa Giorgos Verigakis
    meta = util.get_vm_meta(vm, key)
524 62b894c0 Giorgos Verigakis
    d = {meta.meta_key: meta.meta_value}
525 62b894c0 Giorgos Verigakis
    return util.render_meta(request, d, status=200)
526 d8e50a39 Giorgos Verigakis
527 55cd40be Vangelis Koukis
528 b3fd98ae Christos Stavrakakis
@api.api_method(http_method='PUT', user_required=True, logger=log)
529 4dba0480 Christos Stavrakakis
@transaction.commit_on_success
530 d8e50a39 Giorgos Verigakis
def create_metadata_item(request, server_id, key):
531 d8e50a39 Giorgos Verigakis
    # Normal Response Code: 201
532 d8e50a39 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
533 d8e50a39 Giorgos Verigakis
    #                       serviceUnavailable (503),
534 d8e50a39 Giorgos Verigakis
    #                       unauthorized (401),
535 d8e50a39 Giorgos Verigakis
    #                       itemNotFound (404),
536 d8e50a39 Giorgos Verigakis
    #                       badRequest (400),
537 d8e50a39 Giorgos Verigakis
    #                       buildInProgress (409),
538 d8e50a39 Giorgos Verigakis
    #                       badMediaType(415),
539 d8e50a39 Giorgos Verigakis
    #                       overLimit (413)
540 ce55f211 Kostas Papadimitriou
541 b3fd98ae Christos Stavrakakis
    req = utils.get_request_dict(request)
542 bf5c82dc Christos Stavrakakis
    log.info('create_server_metadata_item %s %s %s', server_id, key, req)
543 e221ade2 Christos Stavrakakis
    vm = util.get_vm(server_id, request.user_uniq, non_suspended=True)
544 d8e50a39 Giorgos Verigakis
    try:
545 d8e50a39 Giorgos Verigakis
        metadict = req['meta']
546 d8e50a39 Giorgos Verigakis
        assert isinstance(metadict, dict)
547 d8e50a39 Giorgos Verigakis
        assert len(metadict) == 1
548 d8e50a39 Giorgos Verigakis
        assert key in metadict
549 d8e50a39 Giorgos Verigakis
    except (KeyError, AssertionError):
550 ccd0d474 Giorgos Verigakis
        raise faults.BadRequest("Malformed request")
551 ce55f211 Kostas Papadimitriou
552 b36f78fa Giorgos Verigakis
    meta, created = VirtualMachineMetadata.objects.get_or_create(
553 b36f78fa Giorgos Verigakis
        meta_key=key,
554 b36f78fa Giorgos Verigakis
        vm=vm)
555 ce55f211 Kostas Papadimitriou
556 d8e50a39 Giorgos Verigakis
    meta.meta_value = metadict[key]
557 d8e50a39 Giorgos Verigakis
    meta.save()
558 5509b599 Giorgos Verigakis
    vm.save()
559 62b894c0 Giorgos Verigakis
    d = {meta.meta_key: meta.meta_value}
560 62b894c0 Giorgos Verigakis
    return util.render_meta(request, d, status=201)
561 d8e50a39 Giorgos Verigakis
562 55cd40be Vangelis Koukis
563 b3fd98ae Christos Stavrakakis
@api.api_method(http_method='DELETE', user_required=True, logger=log)
564 4dba0480 Christos Stavrakakis
@transaction.commit_on_success
565 d8e50a39 Giorgos Verigakis
def delete_metadata_item(request, server_id, key):
566 d8e50a39 Giorgos Verigakis
    # Normal Response Code: 204
567 d8e50a39 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
568 d8e50a39 Giorgos Verigakis
    #                       serviceUnavailable (503),
569 d8e50a39 Giorgos Verigakis
    #                       unauthorized (401),
570 d8e50a39 Giorgos Verigakis
    #                       itemNotFound (404),
571 d8e50a39 Giorgos Verigakis
    #                       badRequest (400),
572 d8e50a39 Giorgos Verigakis
    #                       buildInProgress (409),
573 d8e50a39 Giorgos Verigakis
    #                       badMediaType(415),
574 d8e50a39 Giorgos Verigakis
    #                       overLimit (413),
575 ce55f211 Kostas Papadimitriou
576 bf5c82dc Christos Stavrakakis
    log.info('delete_server_metadata_item %s %s', server_id, key)
577 e221ade2 Christos Stavrakakis
    vm = util.get_vm(server_id, request.user_uniq, non_suspended=True)
578 b36f78fa Giorgos Verigakis
    meta = util.get_vm_meta(vm, key)
579 d8e50a39 Giorgos Verigakis
    meta.delete()
580 5509b599 Giorgos Verigakis
    vm.save()
581 d8e50a39 Giorgos Verigakis
    return HttpResponse(status=204)
582 c738c935 Giorgos Verigakis
583 55cd40be Vangelis Koukis
584 b3fd98ae Christos Stavrakakis
@api.api_method(http_method='GET', user_required=True, logger=log)
585 c738c935 Giorgos Verigakis
def server_stats(request, server_id):
586 c738c935 Giorgos Verigakis
    # Normal Response Codes: 200
587 c738c935 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
588 c738c935 Giorgos Verigakis
    #                       serviceUnavailable (503),
589 c738c935 Giorgos Verigakis
    #                       unauthorized (401),
590 c738c935 Giorgos Verigakis
    #                       badRequest (400),
591 c738c935 Giorgos Verigakis
    #                       itemNotFound (404),
592 c738c935 Giorgos Verigakis
    #                       overLimit (413)
593 ce55f211 Kostas Papadimitriou
594 0c37a721 Christos Stavrakakis
    log.debug('server_stats %s', server_id)
595 4b3b8688 Giorgos Verigakis
    vm = util.get_vm(server_id, request.user_uniq)
596 924d8085 Christos Stavrakakis
    #secret = util.encrypt(vm.backend_vm_id)
597 924d8085 Christos Stavrakakis
    secret = vm.backend_vm_id      # XXX disable backend id encryption
598 ce55f211 Kostas Papadimitriou
599 c738c935 Giorgos Verigakis
    stats = {
600 c738c935 Giorgos Verigakis
        'serverRef': vm.id,
601 c738c935 Giorgos Verigakis
        'refresh': settings.STATS_REFRESH_PERIOD,
602 5391d6b5 Giorgos Verigakis
        'cpuBar': settings.CPU_BAR_GRAPH_URL % secret,
603 5391d6b5 Giorgos Verigakis
        'cpuTimeSeries': settings.CPU_TIMESERIES_GRAPH_URL % secret,
604 5391d6b5 Giorgos Verigakis
        'netBar': settings.NET_BAR_GRAPH_URL % secret,
605 5391d6b5 Giorgos Verigakis
        'netTimeSeries': settings.NET_TIMESERIES_GRAPH_URL % secret}
606 ce55f211 Kostas Papadimitriou
607 c738c935 Giorgos Verigakis
    if request.serialization == 'xml':
608 c738c935 Giorgos Verigakis
        data = render_to_string('server_stats.xml', stats)
609 c738c935 Giorgos Verigakis
    else:
610 c738c935 Giorgos Verigakis
        data = json.dumps({'stats': stats})
611 c738c935 Giorgos Verigakis
612 c738c935 Giorgos Verigakis
    return HttpResponse(data, status=200)
613 41a7fae7 Christos Stavrakakis
614 41a7fae7 Christos Stavrakakis
615 41a7fae7 Christos Stavrakakis
# ACTIONS
616 41a7fae7 Christos Stavrakakis
617 41a7fae7 Christos Stavrakakis
618 41a7fae7 Christos Stavrakakis
server_actions = {}
619 41a7fae7 Christos Stavrakakis
network_actions = {}
620 41a7fae7 Christos Stavrakakis
621 41a7fae7 Christos Stavrakakis
622 41a7fae7 Christos Stavrakakis
def server_action(name):
623 41a7fae7 Christos Stavrakakis
    '''Decorator for functions implementing server actions.
624 41a7fae7 Christos Stavrakakis
    `name` is the key in the dict passed by the client.
625 41a7fae7 Christos Stavrakakis
    '''
626 41a7fae7 Christos Stavrakakis
627 41a7fae7 Christos Stavrakakis
    def decorator(func):
628 41a7fae7 Christos Stavrakakis
        server_actions[name] = func
629 41a7fae7 Christos Stavrakakis
        return func
630 41a7fae7 Christos Stavrakakis
    return decorator
631 41a7fae7 Christos Stavrakakis
632 41a7fae7 Christos Stavrakakis
633 41a7fae7 Christos Stavrakakis
def network_action(name):
634 41a7fae7 Christos Stavrakakis
    '''Decorator for functions implementing network actions.
635 41a7fae7 Christos Stavrakakis
    `name` is the key in the dict passed by the client.
636 41a7fae7 Christos Stavrakakis
    '''
637 41a7fae7 Christos Stavrakakis
638 41a7fae7 Christos Stavrakakis
    def decorator(func):
639 41a7fae7 Christos Stavrakakis
        network_actions[name] = func
640 41a7fae7 Christos Stavrakakis
        return func
641 41a7fae7 Christos Stavrakakis
    return decorator
642 41a7fae7 Christos Stavrakakis
643 41a7fae7 Christos Stavrakakis
644 41a7fae7 Christos Stavrakakis
@server_action('start')
645 41a7fae7 Christos Stavrakakis
def start(request, vm, args):
646 41a7fae7 Christos Stavrakakis
    # Normal Response Code: 202
647 41a7fae7 Christos Stavrakakis
    # Error Response Codes: serviceUnavailable (503),
648 41a7fae7 Christos Stavrakakis
    #                       itemNotFound (404)
649 41a7fae7 Christos Stavrakakis
    vm = servers.start(vm)
650 41a7fae7 Christos Stavrakakis
    return HttpResponse(status=202)
651 41a7fae7 Christos Stavrakakis
652 41a7fae7 Christos Stavrakakis
653 41a7fae7 Christos Stavrakakis
@server_action('shutdown')
654 41a7fae7 Christos Stavrakakis
def shutdown(request, vm, args):
655 41a7fae7 Christos Stavrakakis
    # Normal Response Code: 202
656 41a7fae7 Christos Stavrakakis
    # Error Response Codes: serviceUnavailable (503),
657 41a7fae7 Christos Stavrakakis
    #                       itemNotFound (404)
658 41a7fae7 Christos Stavrakakis
    vm = servers.stop(vm)
659 41a7fae7 Christos Stavrakakis
    return HttpResponse(status=202)
660 41a7fae7 Christos Stavrakakis
661 41a7fae7 Christos Stavrakakis
662 41a7fae7 Christos Stavrakakis
@server_action('reboot')
663 41a7fae7 Christos Stavrakakis
def reboot(request, vm, args):
664 41a7fae7 Christos Stavrakakis
    # Normal Response Code: 202
665 41a7fae7 Christos Stavrakakis
    # Error Response Codes: computeFault (400, 500),
666 41a7fae7 Christos Stavrakakis
    #                       serviceUnavailable (503),
667 41a7fae7 Christos Stavrakakis
    #                       unauthorized (401),
668 41a7fae7 Christos Stavrakakis
    #                       badRequest (400),
669 41a7fae7 Christos Stavrakakis
    #                       badMediaType(415),
670 41a7fae7 Christos Stavrakakis
    #                       itemNotFound (404),
671 41a7fae7 Christos Stavrakakis
    #                       buildInProgress (409),
672 41a7fae7 Christos Stavrakakis
    #                       overLimit (413)
673 41a7fae7 Christos Stavrakakis
674 41a7fae7 Christos Stavrakakis
    reboot_type = args.get("type")
675 41a7fae7 Christos Stavrakakis
    if reboot_type is None:
676 41a7fae7 Christos Stavrakakis
        raise faults.BadRequest("Missing 'type' attribute.")
677 41a7fae7 Christos Stavrakakis
    elif reboot_type not in ["SOFT", "HARD"]:
678 41a7fae7 Christos Stavrakakis
        raise faults.BadRequest("Invalid 'type' attribute.")
679 41a7fae7 Christos Stavrakakis
    vm = servers.reboot(vm, reboot_type=reboot_type)
680 41a7fae7 Christos Stavrakakis
    return HttpResponse(status=202)
681 41a7fae7 Christos Stavrakakis
682 41a7fae7 Christos Stavrakakis
683 41a7fae7 Christos Stavrakakis
@server_action('firewallProfile')
684 41a7fae7 Christos Stavrakakis
def set_firewall_profile(request, vm, args):
685 41a7fae7 Christos Stavrakakis
    # Normal Response Code: 200
686 41a7fae7 Christos Stavrakakis
    # Error Response Codes: computeFault (400, 500),
687 41a7fae7 Christos Stavrakakis
    #                       serviceUnavailable (503),
688 41a7fae7 Christos Stavrakakis
    #                       unauthorized (401),
689 41a7fae7 Christos Stavrakakis
    #                       badRequest (400),
690 41a7fae7 Christos Stavrakakis
    #                       badMediaType(415),
691 41a7fae7 Christos Stavrakakis
    #                       itemNotFound (404),
692 41a7fae7 Christos Stavrakakis
    #                       buildInProgress (409),
693 41a7fae7 Christos Stavrakakis
    #                       overLimit (413)
694 41a7fae7 Christos Stavrakakis
    profile = args.get("profile")
695 41a7fae7 Christos Stavrakakis
    if profile is None:
696 41a7fae7 Christos Stavrakakis
        raise faults.BadRequest("Missing 'profile' attribute")
697 41a7fae7 Christos Stavrakakis
    servers.set_firewall_profile(vm, profile=profile)
698 41a7fae7 Christos Stavrakakis
    return HttpResponse(status=202)
699 41a7fae7 Christos Stavrakakis
700 41a7fae7 Christos Stavrakakis
701 41a7fae7 Christos Stavrakakis
@server_action('resize')
702 41a7fae7 Christos Stavrakakis
def resize(request, vm, args):
703 41a7fae7 Christos Stavrakakis
    # Normal Response Code: 202
704 41a7fae7 Christos Stavrakakis
    # Error Response Codes: computeFault (400, 500),
705 41a7fae7 Christos Stavrakakis
    #                       serviceUnavailable (503),
706 41a7fae7 Christos Stavrakakis
    #                       unauthorized (401),
707 41a7fae7 Christos Stavrakakis
    #                       badRequest (400),
708 41a7fae7 Christos Stavrakakis
    #                       badMediaType(415),
709 41a7fae7 Christos Stavrakakis
    #                       itemNotFound (404),
710 41a7fae7 Christos Stavrakakis
    #                       buildInProgress (409),
711 41a7fae7 Christos Stavrakakis
    #                       serverCapacityUnavailable (503),
712 41a7fae7 Christos Stavrakakis
    #                       overLimit (413),
713 41a7fae7 Christos Stavrakakis
    #                       resizeNotAllowed (403)
714 41a7fae7 Christos Stavrakakis
    flavorRef = args.get("flavorRef")
715 41a7fae7 Christos Stavrakakis
    if flavorRef is None:
716 41a7fae7 Christos Stavrakakis
        raise faults.BadRequest("Missing 'flavorRef' attribute.")
717 41a7fae7 Christos Stavrakakis
    flavor = util.get_flavor(flavor_id=flavorRef, include_deleted=False)
718 41a7fae7 Christos Stavrakakis
    servers.resize(vm, flavor=flavor)
719 41a7fae7 Christos Stavrakakis
    return HttpResponse(status=202)
720 41a7fae7 Christos Stavrakakis
721 41a7fae7 Christos Stavrakakis
722 41a7fae7 Christos Stavrakakis
@server_action('console')
723 41a7fae7 Christos Stavrakakis
def get_console(request, vm, args):
724 41a7fae7 Christos Stavrakakis
    # Normal Response Code: 200
725 41a7fae7 Christos Stavrakakis
    # Error Response Codes: computeFault (400, 500),
726 41a7fae7 Christos Stavrakakis
    #                       serviceUnavailable (503),
727 41a7fae7 Christos Stavrakakis
    #                       unauthorized (401),
728 41a7fae7 Christos Stavrakakis
    #                       badRequest (400),
729 41a7fae7 Christos Stavrakakis
    #                       badMediaType(415),
730 41a7fae7 Christos Stavrakakis
    #                       itemNotFound (404),
731 41a7fae7 Christos Stavrakakis
    #                       buildInProgress (409),
732 41a7fae7 Christos Stavrakakis
    #                       overLimit (413)
733 41a7fae7 Christos Stavrakakis
734 41a7fae7 Christos Stavrakakis
    log.info("Get console  VM %s: %s", vm, args)
735 41a7fae7 Christos Stavrakakis
736 41a7fae7 Christos Stavrakakis
    console_type = args.get("type")
737 41a7fae7 Christos Stavrakakis
    if console_type is None:
738 41a7fae7 Christos Stavrakakis
        raise faults.BadRequest("No console 'type' specified.")
739 41a7fae7 Christos Stavrakakis
    elif console_type != "vnc":
740 41a7fae7 Christos Stavrakakis
        raise faults.BadRequest("Console 'type' can only be 'vnc'.")
741 41a7fae7 Christos Stavrakakis
    console_info = servers.console(vm, console_type)
742 41a7fae7 Christos Stavrakakis
743 41a7fae7 Christos Stavrakakis
    if request.serialization == 'xml':
744 41a7fae7 Christos Stavrakakis
        mimetype = 'application/xml'
745 41a7fae7 Christos Stavrakakis
        data = render_to_string('console.xml', {'console': console_info})
746 41a7fae7 Christos Stavrakakis
    else:
747 41a7fae7 Christos Stavrakakis
        mimetype = 'application/json'
748 41a7fae7 Christos Stavrakakis
        data = json.dumps({'console': console_info})
749 41a7fae7 Christos Stavrakakis
750 41a7fae7 Christos Stavrakakis
    return HttpResponse(data, mimetype=mimetype, status=200)
751 41a7fae7 Christos Stavrakakis
752 41a7fae7 Christos Stavrakakis
753 41a7fae7 Christos Stavrakakis
@server_action('changePassword')
754 41a7fae7 Christos Stavrakakis
def change_password(request, vm, args):
755 41a7fae7 Christos Stavrakakis
    raise faults.NotImplemented('Changing password is not supported.')
756 41a7fae7 Christos Stavrakakis
757 41a7fae7 Christos Stavrakakis
758 41a7fae7 Christos Stavrakakis
@server_action('rebuild')
759 41a7fae7 Christos Stavrakakis
def rebuild(request, vm, args):
760 41a7fae7 Christos Stavrakakis
    raise faults.NotImplemented('Rebuild not supported.')
761 41a7fae7 Christos Stavrakakis
762 41a7fae7 Christos Stavrakakis
763 41a7fae7 Christos Stavrakakis
@server_action('confirmResize')
764 41a7fae7 Christos Stavrakakis
def confirm_resize(request, vm, args):
765 41a7fae7 Christos Stavrakakis
    raise faults.NotImplemented('Resize not supported.')
766 41a7fae7 Christos Stavrakakis
767 41a7fae7 Christos Stavrakakis
768 41a7fae7 Christos Stavrakakis
@server_action('revertResize')
769 41a7fae7 Christos Stavrakakis
def revert_resize(request, vm, args):
770 41a7fae7 Christos Stavrakakis
    raise faults.NotImplemented('Resize not supported.')
771 41a7fae7 Christos Stavrakakis
772 41a7fae7 Christos Stavrakakis
773 41a7fae7 Christos Stavrakakis
@network_action('add')
774 41a7fae7 Christos Stavrakakis
@transaction.commit_on_success
775 41a7fae7 Christos Stavrakakis
def add(request, net, args):
776 41a7fae7 Christos Stavrakakis
    # Normal Response Code: 202
777 41a7fae7 Christos Stavrakakis
    # Error Response Codes: computeFault (400, 500),
778 41a7fae7 Christos Stavrakakis
    #                       serviceUnavailable (503),
779 41a7fae7 Christos Stavrakakis
    #                       unauthorized (401),
780 41a7fae7 Christos Stavrakakis
    #                       badRequest (400),
781 41a7fae7 Christos Stavrakakis
    #                       buildInProgress (409),
782 41a7fae7 Christos Stavrakakis
    #                       badMediaType(415),
783 41a7fae7 Christos Stavrakakis
    #                       itemNotFound (404),
784 41a7fae7 Christos Stavrakakis
    #                       overLimit (413)
785 41a7fae7 Christos Stavrakakis
    server_id = args.get('serverRef', None)
786 41a7fae7 Christos Stavrakakis
    if not server_id:
787 41a7fae7 Christos Stavrakakis
        raise faults.BadRequest('Malformed Request.')
788 41a7fae7 Christos Stavrakakis
789 41a7fae7 Christos Stavrakakis
    vm = util.get_vm(server_id, request.user_uniq, non_suspended=True)
790 41a7fae7 Christos Stavrakakis
    servers.connect(vm, network=net)
791 41a7fae7 Christos Stavrakakis
    return HttpResponse(status=202)
792 41a7fae7 Christos Stavrakakis
793 41a7fae7 Christos Stavrakakis
794 41a7fae7 Christos Stavrakakis
@network_action('remove')
795 41a7fae7 Christos Stavrakakis
@transaction.commit_on_success
796 41a7fae7 Christos Stavrakakis
def remove(request, net, args):
797 41a7fae7 Christos Stavrakakis
    # Normal Response Code: 202
798 41a7fae7 Christos Stavrakakis
    # Error Response Codes: computeFault (400, 500),
799 41a7fae7 Christos Stavrakakis
    #                       serviceUnavailable (503),
800 41a7fae7 Christos Stavrakakis
    #                       unauthorized (401),
801 41a7fae7 Christos Stavrakakis
    #                       badRequest (400),
802 41a7fae7 Christos Stavrakakis
    #                       badMediaType(415),
803 41a7fae7 Christos Stavrakakis
    #                       itemNotFound (404),
804 41a7fae7 Christos Stavrakakis
    #                       overLimit (413)
805 41a7fae7 Christos Stavrakakis
806 41a7fae7 Christos Stavrakakis
    attachment = args.get("attachment")
807 41a7fae7 Christos Stavrakakis
    if attachment is None:
808 41a7fae7 Christos Stavrakakis
        raise faults.BadRequest("Missing 'attachment' attribute.")
809 41a7fae7 Christos Stavrakakis
    try:
810 41a7fae7 Christos Stavrakakis
        # attachment string: nic-<vm-id>-<nic-index>
811 41a7fae7 Christos Stavrakakis
        _, server_id, nic_index = attachment.split("-", 2)
812 41a7fae7 Christos Stavrakakis
        server_id = int(server_id)
813 41a7fae7 Christos Stavrakakis
        nic_index = int(nic_index)
814 41a7fae7 Christos Stavrakakis
    except (ValueError, TypeError):
815 41a7fae7 Christos Stavrakakis
        raise faults.BadRequest("Invalid 'attachment' attribute.")
816 41a7fae7 Christos Stavrakakis
817 41a7fae7 Christos Stavrakakis
    vm = util.get_vm(server_id, request.user_uniq, non_suspended=True)
818 41a7fae7 Christos Stavrakakis
    servers.disconnect(vm, nic_index=nic_index)
819 41a7fae7 Christos Stavrakakis
820 41a7fae7 Christos Stavrakakis
    return HttpResponse(status=202)
821 9ba6bb95 Christos Stavrakakis
822 9ba6bb95 Christos Stavrakakis
823 9ba6bb95 Christos Stavrakakis
@server_action("addfloatingip")
824 9ba6bb95 Christos Stavrakakis
def add_floating_ip(request, vm, args):
825 9ba6bb95 Christos Stavrakakis
    address = args.get("address")
826 9ba6bb95 Christos Stavrakakis
    if address is None:
827 9ba6bb95 Christos Stavrakakis
        raise faults.BadRequest("Missing 'address' attribute")
828 9ba6bb95 Christos Stavrakakis
829 9ba6bb95 Christos Stavrakakis
    servers.add_floating_ip(vm, address)
830 9ba6bb95 Christos Stavrakakis
    return HttpResponse(status=202)
831 9ba6bb95 Christos Stavrakakis
832 9ba6bb95 Christos Stavrakakis
833 9ba6bb95 Christos Stavrakakis
@server_action("removefloatingip")
834 9ba6bb95 Christos Stavrakakis
def remove_floating_ip(request, vm, args):
835 9ba6bb95 Christos Stavrakakis
    address = args.get("address")
836 9ba6bb95 Christos Stavrakakis
    if address is None:
837 9ba6bb95 Christos Stavrakakis
        raise faults.BadRequest("Missing 'address' attribute")
838 9ba6bb95 Christos Stavrakakis
839 9ba6bb95 Christos Stavrakakis
    servers.remove_floating_ip(vm, address)
840 9ba6bb95 Christos Stavrakakis
    return HttpResponse(status=202)