Statistics
| Branch: | Tag: | Revision:

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

History | View | Annotate | Download (29.1 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 816d7588 Christos Stavrakakis
44 bd40abfa Christos Stavrakakis
from synnefo.api import util
45 41a7fae7 Christos Stavrakakis
from synnefo.db.models import (VirtualMachine, VirtualMachineMetadata)
46 41a7fae7 Christos Stavrakakis
from synnefo.logic import servers, utils as logic_utils
47 9e98ba3c Giorgos Verigakis
48 bf5c82dc Christos Stavrakakis
from logging import getLogger
49 b3fd98ae Christos Stavrakakis
log = getLogger(__name__)
50 7e2f9d4b Giorgos Verigakis
51 e440e835 Christos Stavrakakis
urlpatterns = patterns(
52 e440e835 Christos Stavrakakis
    'synnefo.api.servers',
53 7e2f9d4b Giorgos Verigakis
    (r'^(?:/|.json|.xml)?$', 'demux'),
54 7e2f9d4b Giorgos Verigakis
    (r'^/detail(?:.json|.xml)?$', 'list_servers', {'detail': True}),
55 7e2f9d4b Giorgos Verigakis
    (r'^/(\d+)(?:.json|.xml)?$', 'server_demux'),
56 41a7fae7 Christos Stavrakakis
    (r'^/(\d+)/action(?:.json|.xml)?$', 'demux_server_action'),
57 b016b476 Giorgos Verigakis
    (r'^/(\d+)/ips(?:.json|.xml)?$', 'list_addresses'),
58 b016b476 Giorgos Verigakis
    (r'^/(\d+)/ips/(.+?)(?:.json|.xml)?$', 'list_addresses_by_network'),
59 8a992938 Christos Stavrakakis
    (r'^/(\d+)/metadata(?:.json|.xml)?$', 'metadata_demux'),
60 8a992938 Christos Stavrakakis
    (r'^/(\d+)/metadata/(.+?)(?:.json|.xml)?$', 'metadata_item_demux'),
61 c738c935 Giorgos Verigakis
    (r'^/(\d+)/stats(?:.json|.xml)?$', 'server_stats'),
62 85a634e6 Kostas Papadimitriou
    (r'^/(\d+)/diagnostics(?:.json)?$', 'get_server_diagnostics'),
63 7e2f9d4b Giorgos Verigakis
)
64 7e2f9d4b Giorgos Verigakis
65 7e2f9d4b Giorgos Verigakis
66 7e2f9d4b Giorgos Verigakis
def demux(request):
67 7e2f9d4b Giorgos Verigakis
    if request.method == 'GET':
68 7e2f9d4b Giorgos Verigakis
        return list_servers(request)
69 7e2f9d4b Giorgos Verigakis
    elif request.method == 'POST':
70 7e2f9d4b Giorgos Verigakis
        return create_server(request)
71 7e2f9d4b Giorgos Verigakis
    else:
72 c0720b78 Kostas Papadimitriou
        return api.api_method_not_allowed(request)
73 7e2f9d4b Giorgos Verigakis
74 55cd40be Vangelis Koukis
75 7e2f9d4b Giorgos Verigakis
def server_demux(request, server_id):
76 7e2f9d4b Giorgos Verigakis
    if request.method == 'GET':
77 7e2f9d4b Giorgos Verigakis
        return get_server_details(request, server_id)
78 7e2f9d4b Giorgos Verigakis
    elif request.method == 'PUT':
79 7e2f9d4b Giorgos Verigakis
        return update_server_name(request, server_id)
80 7e2f9d4b Giorgos Verigakis
    elif request.method == 'DELETE':
81 7e2f9d4b Giorgos Verigakis
        return delete_server(request, server_id)
82 7e2f9d4b Giorgos Verigakis
    else:
83 c0720b78 Kostas Papadimitriou
        return api.api_method_not_allowed(request)
84 d8e50a39 Giorgos Verigakis
85 55cd40be Vangelis Koukis
86 d8e50a39 Giorgos Verigakis
def metadata_demux(request, server_id):
87 d8e50a39 Giorgos Verigakis
    if request.method == 'GET':
88 d8e50a39 Giorgos Verigakis
        return list_metadata(request, server_id)
89 d8e50a39 Giorgos Verigakis
    elif request.method == 'POST':
90 d8e50a39 Giorgos Verigakis
        return update_metadata(request, server_id)
91 d8e50a39 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_item_demux(request, server_id, key):
96 d8e50a39 Giorgos Verigakis
    if request.method == 'GET':
97 d8e50a39 Giorgos Verigakis
        return get_metadata_item(request, server_id, key)
98 d8e50a39 Giorgos Verigakis
    elif request.method == 'PUT':
99 d8e50a39 Giorgos Verigakis
        return create_metadata_item(request, server_id, key)
100 d8e50a39 Giorgos Verigakis
    elif request.method == 'DELETE':
101 d8e50a39 Giorgos Verigakis
        return delete_metadata_item(request, server_id, key)
102 d8e50a39 Giorgos Verigakis
    else:
103 c0720b78 Kostas Papadimitriou
        return api.api_method_not_allowed(request)
104 7e2f9d4b Giorgos Verigakis
105 08b079e2 Stavros Sachtouris
106 7fede91e Christos Stavrakakis
def nic_to_dict(nic):
107 78c165cf Christos Stavrakakis
    ip_type = "floating" if nic.is_floating_ip else "fixed"
108 7fede91e Christos Stavrakakis
    d = {'id': util.construct_nic_id(nic),
109 7fede91e Christos Stavrakakis
         'network_id': str(nic.network.id),
110 7fede91e Christos Stavrakakis
         'mac_address': nic.mac,
111 8d325d4b Christos Stavrakakis
         'ipv4': nic.ipv4,
112 8d325d4b Christos Stavrakakis
         'ipv6': nic.ipv6,
113 78c165cf Christos Stavrakakis
         'OS-EXT-IPS:type': ip_type}
114 47c66641 Dimitris Aragiorgis
115 207b70d5 Giorgos Verigakis
    if nic.firewall_profile:
116 207b70d5 Giorgos Verigakis
        d['firewallProfile'] = nic.firewall_profile
117 d44c236b Giorgos Verigakis
    return d
118 b016b476 Giorgos Verigakis
119 55cd40be Vangelis Koukis
120 78c165cf Christos Stavrakakis
def attachments_to_addresses(attachments):
121 1f638a85 Christos Stavrakakis
    addresses = {}
122 78c165cf Christos Stavrakakis
    for nic in attachments:
123 1f638a85 Christos Stavrakakis
        net_nics = []
124 f8352d29 Christos Stavrakakis
        net_nics.append({"version": 4,
125 78c165cf Christos Stavrakakis
                         "addr": nic["ipv4"],
126 78c165cf Christos Stavrakakis
                         "OS-EXT-IPS:type": nic["OS-EXT-IPS:type"]})
127 78c165cf Christos Stavrakakis
        if nic["ipv6"]:
128 f8352d29 Christos Stavrakakis
            net_nics.append({"version": 6,
129 78c165cf Christos Stavrakakis
                             "addr": nic["ipv6"],
130 78c165cf Christos Stavrakakis
                             "OS-EXT-IPS:type": nic["OS-EXT-IPS:type"]})
131 78c165cf Christos Stavrakakis
        addresses[nic["network_id"]] = net_nics
132 1f638a85 Christos Stavrakakis
    return addresses
133 1f638a85 Christos Stavrakakis
134 1f638a85 Christos Stavrakakis
135 d8e50a39 Giorgos Verigakis
def vm_to_dict(vm, detail=False):
136 d8e50a39 Giorgos Verigakis
    d = dict(id=vm.id, name=vm.name)
137 1b696c26 Christos Stavrakakis
    d['links'] = util.vm_to_links(vm.id)
138 7e2f9d4b Giorgos Verigakis
    if detail:
139 936e0be3 Christos Stavrakakis
        d['user_id'] = vm.userid
140 936e0be3 Christos Stavrakakis
        d['tenant_id'] = vm.userid
141 41a7fae7 Christos Stavrakakis
        d['status'] = logic_utils.get_rsapi_state(vm)
142 41a7fae7 Christos Stavrakakis
        d['SNF:task_state'] = logic_utils.get_task_state(vm)
143 41a7fae7 Christos Stavrakakis
        d['progress'] = 100 if d['status'] == 'ACTIVE' else vm.buildpercentage
144 d8e50a39 Giorgos Verigakis
        d['hostId'] = vm.hostid
145 b3fd98ae Christos Stavrakakis
        d['updated'] = utils.isoformat(vm.updated)
146 b3fd98ae Christos Stavrakakis
        d['created'] = utils.isoformat(vm.created)
147 1b696c26 Christos Stavrakakis
        d['flavor'] = {"id": vm.flavor.id,
148 1b696c26 Christos Stavrakakis
                       "links": util.flavor_to_links(vm.flavor.id)}
149 1b696c26 Christos Stavrakakis
        d['image'] = {"id": vm.imageid,
150 1b696c26 Christos Stavrakakis
                      "links": util.image_to_links(vm.imageid)}
151 e221ade2 Christos Stavrakakis
        d['suspended'] = vm.suspended
152 ce55f211 Kostas Papadimitriou
153 7cc3c7d9 Giorgos Verigakis
        metadata = dict((m.meta_key, m.meta_value) for m in vm.metadata.all())
154 1b696c26 Christos Stavrakakis
        d['metadata'] = metadata
155 aa197ee4 Vangelis Koukis
156 939d71dd Christos Stavrakakis
        vm_nics = vm.nics.filter(state="ACTIVE").order_by("index")
157 939d71dd Christos Stavrakakis
        attachments = map(nic_to_dict, vm_nics)
158 5029ff36 Christos Stavrakakis
        d['attachments'] = attachments
159 78c165cf Christos Stavrakakis
        d['addresses'] = attachments_to_addresses(attachments)
160 85a634e6 Kostas Papadimitriou
161 85a634e6 Kostas Papadimitriou
        # include the latest vm diagnostic, if set
162 85a634e6 Kostas Papadimitriou
        diagnostic = vm.get_last_diagnostic()
163 85a634e6 Kostas Papadimitriou
        if diagnostic:
164 85a634e6 Kostas Papadimitriou
            d['diagnostics'] = diagnostics_to_dict([diagnostic])
165 1b696c26 Christos Stavrakakis
        else:
166 1b696c26 Christos Stavrakakis
            d['diagnostics'] = []
167 f8352d29 Christos Stavrakakis
        # Fixed
168 f8352d29 Christos Stavrakakis
        d["security_groups"] = [{"name": "default"}]
169 f8352d29 Christos Stavrakakis
        d["key_name"] = None
170 f8352d29 Christos Stavrakakis
        d["config_drive"] = ""
171 f8352d29 Christos Stavrakakis
        d["accessIPv4"] = ""
172 f8352d29 Christos Stavrakakis
        d["accessIPv6"] = ""
173 85a634e6 Kostas Papadimitriou
174 7e2f9d4b Giorgos Verigakis
    return d
175 7e2f9d4b Giorgos Verigakis
176 d8e50a39 Giorgos Verigakis
177 85a634e6 Kostas Papadimitriou
def diagnostics_to_dict(diagnostics):
178 85a634e6 Kostas Papadimitriou
    """
179 85a634e6 Kostas Papadimitriou
    Extract api data from diagnostics QuerySet.
180 85a634e6 Kostas Papadimitriou
    """
181 85a634e6 Kostas Papadimitriou
    entries = list()
182 85a634e6 Kostas Papadimitriou
183 85a634e6 Kostas Papadimitriou
    for diagnostic in diagnostics:
184 85a634e6 Kostas Papadimitriou
        # format source date if set
185 85a634e6 Kostas Papadimitriou
        formatted_source_date = None
186 85a634e6 Kostas Papadimitriou
        if diagnostic.source_date:
187 b3fd98ae Christos Stavrakakis
            formatted_source_date = utils.isoformat(diagnostic.source_date)
188 85a634e6 Kostas Papadimitriou
189 85a634e6 Kostas Papadimitriou
        entry = {
190 85a634e6 Kostas Papadimitriou
            'source': diagnostic.source,
191 b3fd98ae Christos Stavrakakis
            'created': utils.isoformat(diagnostic.created),
192 85a634e6 Kostas Papadimitriou
            'message': diagnostic.message,
193 85a634e6 Kostas Papadimitriou
            'details': diagnostic.details,
194 85a634e6 Kostas Papadimitriou
            'level': diagnostic.level,
195 85a634e6 Kostas Papadimitriou
        }
196 85a634e6 Kostas Papadimitriou
197 85a634e6 Kostas Papadimitriou
        if formatted_source_date:
198 85a634e6 Kostas Papadimitriou
            entry['source_date'] = formatted_source_date
199 85a634e6 Kostas Papadimitriou
200 85a634e6 Kostas Papadimitriou
        entries.append(entry)
201 85a634e6 Kostas Papadimitriou
202 85a634e6 Kostas Papadimitriou
    return entries
203 85a634e6 Kostas Papadimitriou
204 85a634e6 Kostas Papadimitriou
205 d8e50a39 Giorgos Verigakis
def render_server(request, server, status=200):
206 d8e50a39 Giorgos Verigakis
    if request.serialization == 'xml':
207 b36f78fa Giorgos Verigakis
        data = render_to_string('server.xml', {
208 b36f78fa Giorgos Verigakis
            'server': server,
209 b36f78fa Giorgos Verigakis
            'is_root': True})
210 7e2f9d4b Giorgos Verigakis
    else:
211 d8e50a39 Giorgos Verigakis
        data = json.dumps({'server': server})
212 c36934a7 Giorgos Verigakis
    return HttpResponse(data, status=status)
213 aa197ee4 Vangelis Koukis
214 7e2f9d4b Giorgos Verigakis
215 85a634e6 Kostas Papadimitriou
def render_diagnostics(request, diagnostics_dict, status=200):
216 85a634e6 Kostas Papadimitriou
    """
217 85a634e6 Kostas Papadimitriou
    Render diagnostics dictionary to json response.
218 85a634e6 Kostas Papadimitriou
    """
219 85a634e6 Kostas Papadimitriou
    return HttpResponse(json.dumps(diagnostics_dict), status=status)
220 85a634e6 Kostas Papadimitriou
221 85a634e6 Kostas Papadimitriou
222 b3fd98ae Christos Stavrakakis
@api.api_method(http_method='GET', user_required=True, logger=log)
223 85a634e6 Kostas Papadimitriou
def get_server_diagnostics(request, server_id):
224 85a634e6 Kostas Papadimitriou
    """
225 85a634e6 Kostas Papadimitriou
    Virtual machine diagnostics api view.
226 85a634e6 Kostas Papadimitriou
    """
227 85a634e6 Kostas Papadimitriou
    log.debug('server_diagnostics %s', server_id)
228 85a634e6 Kostas Papadimitriou
    vm = util.get_vm(server_id, request.user_uniq)
229 85a634e6 Kostas Papadimitriou
    diagnostics = diagnostics_to_dict(vm.diagnostics.all())
230 85a634e6 Kostas Papadimitriou
    return render_diagnostics(request, diagnostics)
231 85a634e6 Kostas Papadimitriou
232 85a634e6 Kostas Papadimitriou
233 b3fd98ae Christos Stavrakakis
@api.api_method(http_method='GET', user_required=True, logger=log)
234 7e2f9d4b Giorgos Verigakis
def list_servers(request, detail=False):
235 7e2f9d4b Giorgos Verigakis
    # Normal Response Codes: 200, 203
236 7e2f9d4b Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
237 7e2f9d4b Giorgos Verigakis
    #                       serviceUnavailable (503),
238 7e2f9d4b Giorgos Verigakis
    #                       unauthorized (401),
239 7e2f9d4b Giorgos Verigakis
    #                       badRequest (400),
240 7e2f9d4b Giorgos Verigakis
    #                       overLimit (413)
241 ce55f211 Kostas Papadimitriou
242 0c37a721 Christos Stavrakakis
    log.debug('list_servers detail=%s', detail)
243 e524ed5f Kostas Papadimitriou
    user_vms = VirtualMachine.objects.filter(userid=request.user_uniq)
244 ce55f211 Kostas Papadimitriou
245 b6bc4afa Christos Stavrakakis
    user_vms = utils.filter_modified_since(request, objects=user_vms)
246 ce55f211 Kostas Papadimitriou
247 41a7fae7 Christos Stavrakakis
    servers_dict = [vm_to_dict(server, detail)
248 41a7fae7 Christos Stavrakakis
                    for server in user_vms.order_by('id')]
249 aa197ee4 Vangelis Koukis
250 d8e50a39 Giorgos Verigakis
    if request.serialization == 'xml':
251 b36f78fa Giorgos Verigakis
        data = render_to_string('list_servers.xml', {
252 41a7fae7 Christos Stavrakakis
            'servers': servers_dict,
253 b36f78fa Giorgos Verigakis
            'detail': detail})
254 7e2f9d4b Giorgos Verigakis
    else:
255 41a7fae7 Christos Stavrakakis
        data = json.dumps({'servers': servers_dict})
256 aa197ee4 Vangelis Koukis
257 c36934a7 Giorgos Verigakis
    return HttpResponse(data, status=200)
258 7e2f9d4b Giorgos Verigakis
259 55cd40be Vangelis Koukis
260 b3fd98ae Christos Stavrakakis
@api.api_method(http_method='POST', user_required=True, logger=log)
261 2509ce17 Christos Stavrakakis
def create_server(request):
262 7e2f9d4b Giorgos Verigakis
    # Normal Response Code: 202
263 7e2f9d4b Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
264 7e2f9d4b Giorgos Verigakis
    #                       serviceUnavailable (503),
265 7e2f9d4b Giorgos Verigakis
    #                       unauthorized (401),
266 7e2f9d4b Giorgos Verigakis
    #                       badMediaType(415),
267 7e2f9d4b Giorgos Verigakis
    #                       itemNotFound (404),
268 7e2f9d4b Giorgos Verigakis
    #                       badRequest (400),
269 7e2f9d4b Giorgos Verigakis
    #                       serverCapacityUnavailable (503),
270 7e2f9d4b Giorgos Verigakis
    #                       overLimit (413)
271 bcd80cd9 Christos Stavrakakis
    req = utils.get_request_dict(request)
272 bcd80cd9 Christos Stavrakakis
    log.info('create_server %s', req)
273 bcd80cd9 Christos Stavrakakis
    user_id = request.user_uniq
274 bcd80cd9 Christos Stavrakakis
275 7e2f9d4b Giorgos Verigakis
    try:
276 bcd80cd9 Christos Stavrakakis
        server = req['server']
277 bcd80cd9 Christos Stavrakakis
        name = server['name']
278 bcd80cd9 Christos Stavrakakis
        metadata = server.get('metadata', {})
279 bcd80cd9 Christos Stavrakakis
        assert isinstance(metadata, dict)
280 bcd80cd9 Christos Stavrakakis
        image_id = server['imageRef']
281 bcd80cd9 Christos Stavrakakis
        flavor_id = server['flavorRef']
282 bcd80cd9 Christos Stavrakakis
        personality = server.get('personality', [])
283 bcd80cd9 Christos Stavrakakis
        assert isinstance(personality, list)
284 cb66110b Christos Stavrakakis
        private_networks = server.get("networks", [])
285 cb66110b Christos Stavrakakis
        assert isinstance(private_networks, list)
286 816d7588 Christos Stavrakakis
        floating_ips = server.get("floating_ips", [])
287 816d7588 Christos Stavrakakis
        assert isinstance(floating_ips, 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 cb66110b Christos Stavrakakis
                        metadata=metadata, personality=personality,
302 816d7588 Christos Stavrakakis
                        private_networks=private_networks,
303 816d7588 Christos Stavrakakis
                        floating_ips=floating_ips)
304 bcd80cd9 Christos Stavrakakis
305 bcd80cd9 Christos Stavrakakis
    server = vm_to_dict(vm, detail=True)
306 bcd80cd9 Christos Stavrakakis
    server['status'] = 'BUILD'
307 bcd80cd9 Christos Stavrakakis
    server['adminPass'] = password
308 bcd80cd9 Christos Stavrakakis
309 bcd80cd9 Christos Stavrakakis
    response = render_server(request, server, status=202)
310 4b8e03e5 Christos Stavrakakis
311 bcd80cd9 Christos Stavrakakis
    return response
312 bcd80cd9 Christos Stavrakakis
313 bcd80cd9 Christos Stavrakakis
314 b3fd98ae Christos Stavrakakis
@api.api_method(http_method='GET', user_required=True, logger=log)
315 7e2f9d4b Giorgos Verigakis
def get_server_details(request, server_id):
316 c36934a7 Giorgos Verigakis
    # Normal Response Codes: 200, 203
317 c36934a7 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
318 c36934a7 Giorgos Verigakis
    #                       serviceUnavailable (503),
319 c36934a7 Giorgos Verigakis
    #                       unauthorized (401),
320 c36934a7 Giorgos Verigakis
    #                       badRequest (400),
321 c36934a7 Giorgos Verigakis
    #                       itemNotFound (404),
322 c36934a7 Giorgos Verigakis
    #                       overLimit (413)
323 ce55f211 Kostas Papadimitriou
324 0c37a721 Christos Stavrakakis
    log.debug('get_server_details %s', server_id)
325 4b3b8688 Giorgos Verigakis
    vm = util.get_vm(server_id, request.user_uniq)
326 d8e50a39 Giorgos Verigakis
    server = vm_to_dict(vm, detail=True)
327 d8e50a39 Giorgos Verigakis
    return render_server(request, server)
328 7e2f9d4b Giorgos Verigakis
329 55cd40be Vangelis Koukis
330 b3fd98ae Christos Stavrakakis
@api.api_method(http_method='PUT', user_required=True, logger=log)
331 c36934a7 Giorgos Verigakis
def update_server_name(request, server_id):
332 c36934a7 Giorgos Verigakis
    # Normal Response Code: 204
333 c36934a7 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
334 c36934a7 Giorgos Verigakis
    #                       serviceUnavailable (503),
335 c36934a7 Giorgos Verigakis
    #                       unauthorized (401),
336 c36934a7 Giorgos Verigakis
    #                       badRequest (400),
337 c36934a7 Giorgos Verigakis
    #                       badMediaType(415),
338 c36934a7 Giorgos Verigakis
    #                       itemNotFound (404),
339 c36934a7 Giorgos Verigakis
    #                       buildInProgress (409),
340 c36934a7 Giorgos Verigakis
    #                       overLimit (413)
341 aa197ee4 Vangelis Koukis
342 b3fd98ae Christos Stavrakakis
    req = utils.get_request_dict(request)
343 bf5c82dc Christos Stavrakakis
    log.info('update_server_name %s %s', server_id, req)
344 ce55f211 Kostas Papadimitriou
345 7e2f9d4b Giorgos Verigakis
    try:
346 7e2f9d4b Giorgos Verigakis
        name = req['server']['name']
347 529178b1 Giorgos Verigakis
    except (TypeError, KeyError):
348 ccd0d474 Giorgos Verigakis
        raise faults.BadRequest("Malformed request")
349 aa197ee4 Vangelis Koukis
350 7f2dbcad Christos Stavrakakis
    vm = util.get_vm(server_id, request.user_uniq, for_update=True,
351 7f2dbcad Christos Stavrakakis
                     non_suspended=True)
352 d8e50a39 Giorgos Verigakis
    vm.name = name
353 d8e50a39 Giorgos Verigakis
    vm.save()
354 aa197ee4 Vangelis Koukis
355 7e2f9d4b Giorgos Verigakis
    return HttpResponse(status=204)
356 7e2f9d4b Giorgos Verigakis
357 55cd40be Vangelis Koukis
358 b3fd98ae Christos Stavrakakis
@api.api_method(http_method='DELETE', user_required=True, logger=log)
359 7e2f9d4b Giorgos Verigakis
def delete_server(request, server_id):
360 c36934a7 Giorgos Verigakis
    # Normal Response Codes: 204
361 c36934a7 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
362 c36934a7 Giorgos Verigakis
    #                       serviceUnavailable (503),
363 c36934a7 Giorgos Verigakis
    #                       unauthorized (401),
364 c36934a7 Giorgos Verigakis
    #                       itemNotFound (404),
365 c36934a7 Giorgos Verigakis
    #                       unauthorized (401),
366 c36934a7 Giorgos Verigakis
    #                       buildInProgress (409),
367 c36934a7 Giorgos Verigakis
    #                       overLimit (413)
368 ce55f211 Kostas Papadimitriou
369 bf5c82dc Christos Stavrakakis
    log.info('delete_server %s', server_id)
370 7f2dbcad Christos Stavrakakis
    vm = util.get_vm(server_id, request.user_uniq, for_update=True,
371 7f2dbcad Christos Stavrakakis
                     non_suspended=True)
372 41a7fae7 Christos Stavrakakis
    vm = servers.destroy(vm)
373 7e2f9d4b Giorgos Verigakis
    return HttpResponse(status=204)
374 b016b476 Giorgos Verigakis
375 55cd40be Vangelis Koukis
376 04a95cf3 Kostas Papadimitriou
# additional server actions
377 04a95cf3 Kostas Papadimitriou
ARBITRARY_ACTIONS = ['console', 'firewallProfile']
378 04a95cf3 Kostas Papadimitriou
379 e440e835 Christos Stavrakakis
380 7f2dbcad Christos Stavrakakis
def key_to_action(key):
381 7f2dbcad Christos Stavrakakis
    """Map HTTP request key to a VM Action"""
382 7f2dbcad Christos Stavrakakis
    if key == "shutdown":
383 7f2dbcad Christos Stavrakakis
        return "STOP"
384 7f2dbcad Christos Stavrakakis
    if key == "delete":
385 7f2dbcad Christos Stavrakakis
        return "DESTROY"
386 b7f21824 Kostas Papadimitriou
    if key in ARBITRARY_ACTIONS:
387 7f2dbcad Christos Stavrakakis
        return None
388 7f2dbcad Christos Stavrakakis
    else:
389 7f2dbcad Christos Stavrakakis
        return key.upper()
390 7f2dbcad Christos Stavrakakis
391 7f2dbcad Christos Stavrakakis
392 41a7fae7 Christos Stavrakakis
@api.api_method(http_method='POST', user_required=True, logger=log)
393 41a7fae7 Christos Stavrakakis
@transaction.commit_on_success
394 41a7fae7 Christos Stavrakakis
def demux_server_action(request, server_id):
395 41a7fae7 Christos Stavrakakis
    req = utils.get_request_dict(request)
396 41a7fae7 Christos Stavrakakis
    log.debug('server_action %s %s', server_id, req)
397 7f2dbcad Christos Stavrakakis
398 41a7fae7 Christos Stavrakakis
    if len(req) != 1:
399 41a7fae7 Christos Stavrakakis
        raise faults.BadRequest("Malformed request")
400 41a7fae7 Christos Stavrakakis
401 41a7fae7 Christos Stavrakakis
    # Do not allow any action on deleted or suspended VMs
402 41a7fae7 Christos Stavrakakis
    vm = util.get_vm(server_id, request.user_uniq, for_update=True,
403 41a7fae7 Christos Stavrakakis
                     non_deleted=True, non_suspended=True)
404 7f2dbcad Christos Stavrakakis
405 ece5581b Christos Stavrakakis
    action = req.keys()[0]
406 7f2dbcad Christos Stavrakakis
407 41a7fae7 Christos Stavrakakis
    if key_to_action(action) not in [x[0] for x in VirtualMachine.ACTIONS]:
408 41a7fae7 Christos Stavrakakis
        if action not in ARBITRARY_ACTIONS:
409 41a7fae7 Christos Stavrakakis
            raise faults.BadRequest("Action %s not supported" % action)
410 41a7fae7 Christos Stavrakakis
    action_args = req[action]
411 7f2dbcad Christos Stavrakakis
412 41a7fae7 Christos Stavrakakis
    if not isinstance(action_args, dict):
413 41a7fae7 Christos Stavrakakis
        raise faults.BadRequest("Invalid argument")
414 7f2dbcad Christos Stavrakakis
415 41a7fae7 Christos Stavrakakis
    return server_actions[action](request, vm, action_args)
416 7f2dbcad Christos Stavrakakis
417 7f2dbcad Christos Stavrakakis
418 b3fd98ae Christos Stavrakakis
@api.api_method(http_method='GET', user_required=True, logger=log)
419 b016b476 Giorgos Verigakis
def list_addresses(request, server_id):
420 b016b476 Giorgos Verigakis
    # Normal Response Codes: 200, 203
421 b016b476 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
422 b016b476 Giorgos Verigakis
    #                       serviceUnavailable (503),
423 b016b476 Giorgos Verigakis
    #                       unauthorized (401),
424 b016b476 Giorgos Verigakis
    #                       badRequest (400),
425 b016b476 Giorgos Verigakis
    #                       overLimit (413)
426 ce55f211 Kostas Papadimitriou
427 0c37a721 Christos Stavrakakis
    log.debug('list_addresses %s', server_id)
428 4b3b8688 Giorgos Verigakis
    vm = util.get_vm(server_id, request.user_uniq)
429 1f638a85 Christos Stavrakakis
    attachments = [nic_to_dict(nic) for nic in vm.nics.all()]
430 78c165cf Christos Stavrakakis
    addresses = attachments_to_addresses(attachments)
431 ce55f211 Kostas Papadimitriou
432 d8e50a39 Giorgos Verigakis
    if request.serialization == 'xml':
433 b016b476 Giorgos Verigakis
        data = render_to_string('list_addresses.xml', {'addresses': addresses})
434 b016b476 Giorgos Verigakis
    else:
435 1f638a85 Christos Stavrakakis
        data = json.dumps({'addresses': addresses, 'attachments': attachments})
436 aa197ee4 Vangelis Koukis
437 b016b476 Giorgos Verigakis
    return HttpResponse(data, status=200)
438 b016b476 Giorgos Verigakis
439 55cd40be Vangelis Koukis
440 b3fd98ae Christos Stavrakakis
@api.api_method(http_method='GET', user_required=True, logger=log)
441 b016b476 Giorgos Verigakis
def list_addresses_by_network(request, server_id, network_id):
442 b016b476 Giorgos Verigakis
    # Normal Response Codes: 200, 203
443 b016b476 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
444 b016b476 Giorgos Verigakis
    #                       serviceUnavailable (503),
445 b016b476 Giorgos Verigakis
    #                       unauthorized (401),
446 b016b476 Giorgos Verigakis
    #                       badRequest (400),
447 b016b476 Giorgos Verigakis
    #                       itemNotFound (404),
448 b016b476 Giorgos Verigakis
    #                       overLimit (413)
449 ce55f211 Kostas Papadimitriou
450 0c37a721 Christos Stavrakakis
    log.debug('list_addresses_by_network %s %s', server_id, network_id)
451 4b3b8688 Giorgos Verigakis
    machine = util.get_vm(server_id, request.user_uniq)
452 4b3b8688 Giorgos Verigakis
    network = util.get_network(network_id, request.user_uniq)
453 1f638a85 Christos Stavrakakis
    nics = machine.nics.filter(network=network).all()
454 78c165cf Christos Stavrakakis
    addresses = attachments_to_addresses(map(nic_to_dict, nics))
455 ce55f211 Kostas Papadimitriou
456 d8e50a39 Giorgos Verigakis
    if request.serialization == 'xml':
457 1f638a85 Christos Stavrakakis
        data = render_to_string('address.xml', {'addresses': addresses})
458 b016b476 Giorgos Verigakis
    else:
459 1f638a85 Christos Stavrakakis
        data = json.dumps({'network': addresses})
460 aa197ee4 Vangelis Koukis
461 b016b476 Giorgos Verigakis
    return HttpResponse(data, status=200)
462 d8e50a39 Giorgos Verigakis
463 55cd40be Vangelis Koukis
464 b3fd98ae Christos Stavrakakis
@api.api_method(http_method='GET', user_required=True, logger=log)
465 d8e50a39 Giorgos Verigakis
def list_metadata(request, server_id):
466 d8e50a39 Giorgos Verigakis
    # Normal Response Codes: 200, 203
467 d8e50a39 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
468 d8e50a39 Giorgos Verigakis
    #                       serviceUnavailable (503),
469 d8e50a39 Giorgos Verigakis
    #                       unauthorized (401),
470 d8e50a39 Giorgos Verigakis
    #                       badRequest (400),
471 d8e50a39 Giorgos Verigakis
    #                       overLimit (413)
472 ce55f211 Kostas Papadimitriou
473 0c37a721 Christos Stavrakakis
    log.debug('list_server_metadata %s', server_id)
474 4b3b8688 Giorgos Verigakis
    vm = util.get_vm(server_id, request.user_uniq)
475 7cc3c7d9 Giorgos Verigakis
    metadata = dict((m.meta_key, m.meta_value) for m in vm.metadata.all())
476 5029ff36 Christos Stavrakakis
    return util.render_metadata(request, metadata, use_values=False,
477 5029ff36 Christos Stavrakakis
                                status=200)
478 d8e50a39 Giorgos Verigakis
479 55cd40be Vangelis Koukis
480 b3fd98ae Christos Stavrakakis
@api.api_method(http_method='POST', user_required=True, logger=log)
481 d8e50a39 Giorgos Verigakis
def update_metadata(request, server_id):
482 d8e50a39 Giorgos Verigakis
    # Normal Response Code: 201
483 d8e50a39 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
484 d8e50a39 Giorgos Verigakis
    #                       serviceUnavailable (503),
485 d8e50a39 Giorgos Verigakis
    #                       unauthorized (401),
486 d8e50a39 Giorgos Verigakis
    #                       badRequest (400),
487 d8e50a39 Giorgos Verigakis
    #                       buildInProgress (409),
488 d8e50a39 Giorgos Verigakis
    #                       badMediaType(415),
489 d8e50a39 Giorgos Verigakis
    #                       overLimit (413)
490 ce55f211 Kostas Papadimitriou
491 b3fd98ae Christos Stavrakakis
    req = utils.get_request_dict(request)
492 bf5c82dc Christos Stavrakakis
    log.info('update_server_metadata %s %s', server_id, req)
493 e221ade2 Christos Stavrakakis
    vm = util.get_vm(server_id, request.user_uniq, non_suspended=True)
494 d8e50a39 Giorgos Verigakis
    try:
495 d8e50a39 Giorgos Verigakis
        metadata = req['metadata']
496 d8e50a39 Giorgos Verigakis
        assert isinstance(metadata, dict)
497 d8e50a39 Giorgos Verigakis
    except (KeyError, AssertionError):
498 ccd0d474 Giorgos Verigakis
        raise faults.BadRequest("Malformed request")
499 ce55f211 Kostas Papadimitriou
500 7cc3c7d9 Giorgos Verigakis
    for key, val in metadata.items():
501 7cc3c7d9 Giorgos Verigakis
        meta, created = vm.metadata.get_or_create(meta_key=key)
502 7cc3c7d9 Giorgos Verigakis
        meta.meta_value = val
503 7cc3c7d9 Giorgos Verigakis
        meta.save()
504 ce55f211 Kostas Papadimitriou
505 7cc3c7d9 Giorgos Verigakis
    vm.save()
506 7cc3c7d9 Giorgos Verigakis
    vm_meta = dict((m.meta_key, m.meta_value) for m in vm.metadata.all())
507 7cc3c7d9 Giorgos Verigakis
    return util.render_metadata(request, vm_meta, status=201)
508 d8e50a39 Giorgos Verigakis
509 55cd40be Vangelis Koukis
510 b3fd98ae Christos Stavrakakis
@api.api_method(http_method='GET', user_required=True, logger=log)
511 d8e50a39 Giorgos Verigakis
def get_metadata_item(request, server_id, key):
512 d8e50a39 Giorgos Verigakis
    # Normal Response Codes: 200, 203
513 d8e50a39 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
514 d8e50a39 Giorgos Verigakis
    #                       serviceUnavailable (503),
515 d8e50a39 Giorgos Verigakis
    #                       unauthorized (401),
516 d8e50a39 Giorgos Verigakis
    #                       itemNotFound (404),
517 d8e50a39 Giorgos Verigakis
    #                       badRequest (400),
518 d8e50a39 Giorgos Verigakis
    #                       overLimit (413)
519 ce55f211 Kostas Papadimitriou
520 0c37a721 Christos Stavrakakis
    log.debug('get_server_metadata_item %s %s', server_id, key)
521 4b3b8688 Giorgos Verigakis
    vm = util.get_vm(server_id, request.user_uniq)
522 b36f78fa Giorgos Verigakis
    meta = util.get_vm_meta(vm, key)
523 62b894c0 Giorgos Verigakis
    d = {meta.meta_key: meta.meta_value}
524 62b894c0 Giorgos Verigakis
    return util.render_meta(request, d, status=200)
525 d8e50a39 Giorgos Verigakis
526 55cd40be Vangelis Koukis
527 b3fd98ae Christos Stavrakakis
@api.api_method(http_method='PUT', user_required=True, logger=log)
528 4dba0480 Christos Stavrakakis
@transaction.commit_on_success
529 d8e50a39 Giorgos Verigakis
def create_metadata_item(request, server_id, key):
530 d8e50a39 Giorgos Verigakis
    # Normal Response Code: 201
531 d8e50a39 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
532 d8e50a39 Giorgos Verigakis
    #                       serviceUnavailable (503),
533 d8e50a39 Giorgos Verigakis
    #                       unauthorized (401),
534 d8e50a39 Giorgos Verigakis
    #                       itemNotFound (404),
535 d8e50a39 Giorgos Verigakis
    #                       badRequest (400),
536 d8e50a39 Giorgos Verigakis
    #                       buildInProgress (409),
537 d8e50a39 Giorgos Verigakis
    #                       badMediaType(415),
538 d8e50a39 Giorgos Verigakis
    #                       overLimit (413)
539 ce55f211 Kostas Papadimitriou
540 b3fd98ae Christos Stavrakakis
    req = utils.get_request_dict(request)
541 bf5c82dc Christos Stavrakakis
    log.info('create_server_metadata_item %s %s %s', server_id, key, req)
542 e221ade2 Christos Stavrakakis
    vm = util.get_vm(server_id, request.user_uniq, non_suspended=True)
543 d8e50a39 Giorgos Verigakis
    try:
544 d8e50a39 Giorgos Verigakis
        metadict = req['meta']
545 d8e50a39 Giorgos Verigakis
        assert isinstance(metadict, dict)
546 d8e50a39 Giorgos Verigakis
        assert len(metadict) == 1
547 d8e50a39 Giorgos Verigakis
        assert key in metadict
548 d8e50a39 Giorgos Verigakis
    except (KeyError, AssertionError):
549 ccd0d474 Giorgos Verigakis
        raise faults.BadRequest("Malformed request")
550 ce55f211 Kostas Papadimitriou
551 b36f78fa Giorgos Verigakis
    meta, created = VirtualMachineMetadata.objects.get_or_create(
552 b36f78fa Giorgos Verigakis
        meta_key=key,
553 b36f78fa Giorgos Verigakis
        vm=vm)
554 ce55f211 Kostas Papadimitriou
555 d8e50a39 Giorgos Verigakis
    meta.meta_value = metadict[key]
556 d8e50a39 Giorgos Verigakis
    meta.save()
557 5509b599 Giorgos Verigakis
    vm.save()
558 62b894c0 Giorgos Verigakis
    d = {meta.meta_key: meta.meta_value}
559 62b894c0 Giorgos Verigakis
    return util.render_meta(request, d, status=201)
560 d8e50a39 Giorgos Verigakis
561 55cd40be Vangelis Koukis
562 b3fd98ae Christos Stavrakakis
@api.api_method(http_method='DELETE', user_required=True, logger=log)
563 4dba0480 Christos Stavrakakis
@transaction.commit_on_success
564 d8e50a39 Giorgos Verigakis
def delete_metadata_item(request, server_id, key):
565 d8e50a39 Giorgos Verigakis
    # Normal Response Code: 204
566 d8e50a39 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
567 d8e50a39 Giorgos Verigakis
    #                       serviceUnavailable (503),
568 d8e50a39 Giorgos Verigakis
    #                       unauthorized (401),
569 d8e50a39 Giorgos Verigakis
    #                       itemNotFound (404),
570 d8e50a39 Giorgos Verigakis
    #                       badRequest (400),
571 d8e50a39 Giorgos Verigakis
    #                       buildInProgress (409),
572 d8e50a39 Giorgos Verigakis
    #                       badMediaType(415),
573 d8e50a39 Giorgos Verigakis
    #                       overLimit (413),
574 ce55f211 Kostas Papadimitriou
575 bf5c82dc Christos Stavrakakis
    log.info('delete_server_metadata_item %s %s', server_id, key)
576 e221ade2 Christos Stavrakakis
    vm = util.get_vm(server_id, request.user_uniq, non_suspended=True)
577 b36f78fa Giorgos Verigakis
    meta = util.get_vm_meta(vm, key)
578 d8e50a39 Giorgos Verigakis
    meta.delete()
579 5509b599 Giorgos Verigakis
    vm.save()
580 d8e50a39 Giorgos Verigakis
    return HttpResponse(status=204)
581 c738c935 Giorgos Verigakis
582 55cd40be Vangelis Koukis
583 b3fd98ae Christos Stavrakakis
@api.api_method(http_method='GET', user_required=True, logger=log)
584 c738c935 Giorgos Verigakis
def server_stats(request, server_id):
585 c738c935 Giorgos Verigakis
    # Normal Response Codes: 200
586 c738c935 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
587 c738c935 Giorgos Verigakis
    #                       serviceUnavailable (503),
588 c738c935 Giorgos Verigakis
    #                       unauthorized (401),
589 c738c935 Giorgos Verigakis
    #                       badRequest (400),
590 c738c935 Giorgos Verigakis
    #                       itemNotFound (404),
591 c738c935 Giorgos Verigakis
    #                       overLimit (413)
592 ce55f211 Kostas Papadimitriou
593 0c37a721 Christos Stavrakakis
    log.debug('server_stats %s', server_id)
594 4b3b8688 Giorgos Verigakis
    vm = util.get_vm(server_id, request.user_uniq)
595 924d8085 Christos Stavrakakis
    #secret = util.encrypt(vm.backend_vm_id)
596 924d8085 Christos Stavrakakis
    secret = vm.backend_vm_id      # XXX disable backend id encryption
597 ce55f211 Kostas Papadimitriou
598 c738c935 Giorgos Verigakis
    stats = {
599 c738c935 Giorgos Verigakis
        'serverRef': vm.id,
600 c738c935 Giorgos Verigakis
        'refresh': settings.STATS_REFRESH_PERIOD,
601 5391d6b5 Giorgos Verigakis
        'cpuBar': settings.CPU_BAR_GRAPH_URL % secret,
602 5391d6b5 Giorgos Verigakis
        'cpuTimeSeries': settings.CPU_TIMESERIES_GRAPH_URL % secret,
603 5391d6b5 Giorgos Verigakis
        'netBar': settings.NET_BAR_GRAPH_URL % secret,
604 5391d6b5 Giorgos Verigakis
        'netTimeSeries': settings.NET_TIMESERIES_GRAPH_URL % secret}
605 ce55f211 Kostas Papadimitriou
606 c738c935 Giorgos Verigakis
    if request.serialization == 'xml':
607 c738c935 Giorgos Verigakis
        data = render_to_string('server_stats.xml', stats)
608 c738c935 Giorgos Verigakis
    else:
609 c738c935 Giorgos Verigakis
        data = json.dumps({'stats': stats})
610 c738c935 Giorgos Verigakis
611 c738c935 Giorgos Verigakis
    return HttpResponse(data, status=200)
612 41a7fae7 Christos Stavrakakis
613 41a7fae7 Christos Stavrakakis
614 41a7fae7 Christos Stavrakakis
# ACTIONS
615 41a7fae7 Christos Stavrakakis
616 41a7fae7 Christos Stavrakakis
617 41a7fae7 Christos Stavrakakis
server_actions = {}
618 41a7fae7 Christos Stavrakakis
network_actions = {}
619 41a7fae7 Christos Stavrakakis
620 41a7fae7 Christos Stavrakakis
621 41a7fae7 Christos Stavrakakis
def server_action(name):
622 41a7fae7 Christos Stavrakakis
    '''Decorator for functions implementing server actions.
623 41a7fae7 Christos Stavrakakis
    `name` is the key in the dict passed by the client.
624 41a7fae7 Christos Stavrakakis
    '''
625 41a7fae7 Christos Stavrakakis
626 41a7fae7 Christos Stavrakakis
    def decorator(func):
627 41a7fae7 Christos Stavrakakis
        server_actions[name] = func
628 41a7fae7 Christos Stavrakakis
        return func
629 41a7fae7 Christos Stavrakakis
    return decorator
630 41a7fae7 Christos Stavrakakis
631 41a7fae7 Christos Stavrakakis
632 41a7fae7 Christos Stavrakakis
def network_action(name):
633 41a7fae7 Christos Stavrakakis
    '''Decorator for functions implementing network actions.
634 41a7fae7 Christos Stavrakakis
    `name` is the key in the dict passed by the client.
635 41a7fae7 Christos Stavrakakis
    '''
636 41a7fae7 Christos Stavrakakis
637 41a7fae7 Christos Stavrakakis
    def decorator(func):
638 41a7fae7 Christos Stavrakakis
        network_actions[name] = func
639 41a7fae7 Christos Stavrakakis
        return func
640 41a7fae7 Christos Stavrakakis
    return decorator
641 41a7fae7 Christos Stavrakakis
642 41a7fae7 Christos Stavrakakis
643 41a7fae7 Christos Stavrakakis
@server_action('start')
644 41a7fae7 Christos Stavrakakis
def start(request, vm, args):
645 41a7fae7 Christos Stavrakakis
    # Normal Response Code: 202
646 41a7fae7 Christos Stavrakakis
    # Error Response Codes: serviceUnavailable (503),
647 41a7fae7 Christos Stavrakakis
    #                       itemNotFound (404)
648 41a7fae7 Christos Stavrakakis
    vm = servers.start(vm)
649 41a7fae7 Christos Stavrakakis
    return HttpResponse(status=202)
650 41a7fae7 Christos Stavrakakis
651 41a7fae7 Christos Stavrakakis
652 41a7fae7 Christos Stavrakakis
@server_action('shutdown')
653 41a7fae7 Christos Stavrakakis
def shutdown(request, vm, args):
654 41a7fae7 Christos Stavrakakis
    # Normal Response Code: 202
655 41a7fae7 Christos Stavrakakis
    # Error Response Codes: serviceUnavailable (503),
656 41a7fae7 Christos Stavrakakis
    #                       itemNotFound (404)
657 41a7fae7 Christos Stavrakakis
    vm = servers.stop(vm)
658 41a7fae7 Christos Stavrakakis
    return HttpResponse(status=202)
659 41a7fae7 Christos Stavrakakis
660 41a7fae7 Christos Stavrakakis
661 41a7fae7 Christos Stavrakakis
@server_action('reboot')
662 41a7fae7 Christos Stavrakakis
def reboot(request, vm, args):
663 41a7fae7 Christos Stavrakakis
    # Normal Response Code: 202
664 41a7fae7 Christos Stavrakakis
    # Error Response Codes: computeFault (400, 500),
665 41a7fae7 Christos Stavrakakis
    #                       serviceUnavailable (503),
666 41a7fae7 Christos Stavrakakis
    #                       unauthorized (401),
667 41a7fae7 Christos Stavrakakis
    #                       badRequest (400),
668 41a7fae7 Christos Stavrakakis
    #                       badMediaType(415),
669 41a7fae7 Christos Stavrakakis
    #                       itemNotFound (404),
670 41a7fae7 Christos Stavrakakis
    #                       buildInProgress (409),
671 41a7fae7 Christos Stavrakakis
    #                       overLimit (413)
672 41a7fae7 Christos Stavrakakis
673 41a7fae7 Christos Stavrakakis
    reboot_type = args.get("type")
674 41a7fae7 Christos Stavrakakis
    if reboot_type is None:
675 41a7fae7 Christos Stavrakakis
        raise faults.BadRequest("Missing 'type' attribute.")
676 41a7fae7 Christos Stavrakakis
    elif reboot_type not in ["SOFT", "HARD"]:
677 41a7fae7 Christos Stavrakakis
        raise faults.BadRequest("Invalid 'type' attribute.")
678 41a7fae7 Christos Stavrakakis
    vm = servers.reboot(vm, reboot_type=reboot_type)
679 41a7fae7 Christos Stavrakakis
    return HttpResponse(status=202)
680 41a7fae7 Christos Stavrakakis
681 41a7fae7 Christos Stavrakakis
682 41a7fae7 Christos Stavrakakis
@server_action('firewallProfile')
683 41a7fae7 Christos Stavrakakis
def set_firewall_profile(request, vm, args):
684 41a7fae7 Christos Stavrakakis
    # Normal Response Code: 200
685 41a7fae7 Christos Stavrakakis
    # Error Response Codes: computeFault (400, 500),
686 41a7fae7 Christos Stavrakakis
    #                       serviceUnavailable (503),
687 41a7fae7 Christos Stavrakakis
    #                       unauthorized (401),
688 41a7fae7 Christos Stavrakakis
    #                       badRequest (400),
689 41a7fae7 Christos Stavrakakis
    #                       badMediaType(415),
690 41a7fae7 Christos Stavrakakis
    #                       itemNotFound (404),
691 41a7fae7 Christos Stavrakakis
    #                       buildInProgress (409),
692 41a7fae7 Christos Stavrakakis
    #                       overLimit (413)
693 41a7fae7 Christos Stavrakakis
    profile = args.get("profile")
694 41a7fae7 Christos Stavrakakis
    if profile is None:
695 41a7fae7 Christos Stavrakakis
        raise faults.BadRequest("Missing 'profile' attribute")
696 b2791a77 Christos Stavrakakis
    index = args.get("index", 0)
697 b2791a77 Christos Stavrakakis
    servers.set_firewall_profile(vm, profile=profile, index=index)
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 f8675683 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 f8675683 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)