Statistics
| Branch: | Tag: | Revision:

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

History | View | Annotate | Download (29.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 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 d328a525 Christos Stavrakakis
        d["SNF:fqdn"] = get_server_fqdn(vm)
174 85a634e6 Kostas Papadimitriou
175 7e2f9d4b Giorgos Verigakis
    return d
176 7e2f9d4b Giorgos Verigakis
177 d8e50a39 Giorgos Verigakis
178 d328a525 Christos Stavrakakis
def get_server_fqdn(vm):
179 d328a525 Christos Stavrakakis
    fqdn_setting = settings.CYCLADES_SERVERS_FQDN
180 d328a525 Christos Stavrakakis
    if fqdn_setting is None:
181 d328a525 Christos Stavrakakis
        public_nics = vm.nics.filter(network__public=True, state="ACTIVE")
182 d328a525 Christos Stavrakakis
        # Return the first public IPv4 address if exists
183 d328a525 Christos Stavrakakis
        ipv4_nics = public_nics.exclude(ipv4=None)
184 d328a525 Christos Stavrakakis
        if ipv4_nics:
185 d328a525 Christos Stavrakakis
            return ipv4_nics[0].ipv4
186 d328a525 Christos Stavrakakis
        # Else return the first public IPv6 address if exists
187 d328a525 Christos Stavrakakis
        ipv6_nics = public_nics.exclude(ipv6=None)
188 d328a525 Christos Stavrakakis
        if ipv6_nics:
189 d328a525 Christos Stavrakakis
            return ipv6_nics[0].ipv6
190 d328a525 Christos Stavrakakis
        return ""
191 d328a525 Christos Stavrakakis
    elif isinstance(fqdn_setting, basestring):
192 d328a525 Christos Stavrakakis
        return fqdn_setting % {"id": vm.id}
193 d328a525 Christos Stavrakakis
    else:
194 d328a525 Christos Stavrakakis
        msg = ("Invalid setting: CYCLADES_SERVERS_FQDN."
195 d328a525 Christos Stavrakakis
               " Value must be a string.")
196 d328a525 Christos Stavrakakis
        raise faults.InternalServerError(msg)
197 d328a525 Christos Stavrakakis
198 d328a525 Christos Stavrakakis
199 85a634e6 Kostas Papadimitriou
def diagnostics_to_dict(diagnostics):
200 85a634e6 Kostas Papadimitriou
    """
201 85a634e6 Kostas Papadimitriou
    Extract api data from diagnostics QuerySet.
202 85a634e6 Kostas Papadimitriou
    """
203 85a634e6 Kostas Papadimitriou
    entries = list()
204 85a634e6 Kostas Papadimitriou
205 85a634e6 Kostas Papadimitriou
    for diagnostic in diagnostics:
206 85a634e6 Kostas Papadimitriou
        # format source date if set
207 85a634e6 Kostas Papadimitriou
        formatted_source_date = None
208 85a634e6 Kostas Papadimitriou
        if diagnostic.source_date:
209 b3fd98ae Christos Stavrakakis
            formatted_source_date = utils.isoformat(diagnostic.source_date)
210 85a634e6 Kostas Papadimitriou
211 85a634e6 Kostas Papadimitriou
        entry = {
212 85a634e6 Kostas Papadimitriou
            'source': diagnostic.source,
213 b3fd98ae Christos Stavrakakis
            'created': utils.isoformat(diagnostic.created),
214 85a634e6 Kostas Papadimitriou
            'message': diagnostic.message,
215 85a634e6 Kostas Papadimitriou
            'details': diagnostic.details,
216 85a634e6 Kostas Papadimitriou
            'level': diagnostic.level,
217 85a634e6 Kostas Papadimitriou
        }
218 85a634e6 Kostas Papadimitriou
219 85a634e6 Kostas Papadimitriou
        if formatted_source_date:
220 85a634e6 Kostas Papadimitriou
            entry['source_date'] = formatted_source_date
221 85a634e6 Kostas Papadimitriou
222 85a634e6 Kostas Papadimitriou
        entries.append(entry)
223 85a634e6 Kostas Papadimitriou
224 85a634e6 Kostas Papadimitriou
    return entries
225 85a634e6 Kostas Papadimitriou
226 85a634e6 Kostas Papadimitriou
227 d8e50a39 Giorgos Verigakis
def render_server(request, server, status=200):
228 d8e50a39 Giorgos Verigakis
    if request.serialization == 'xml':
229 b36f78fa Giorgos Verigakis
        data = render_to_string('server.xml', {
230 b36f78fa Giorgos Verigakis
            'server': server,
231 b36f78fa Giorgos Verigakis
            'is_root': True})
232 7e2f9d4b Giorgos Verigakis
    else:
233 d8e50a39 Giorgos Verigakis
        data = json.dumps({'server': server})
234 c36934a7 Giorgos Verigakis
    return HttpResponse(data, status=status)
235 aa197ee4 Vangelis Koukis
236 7e2f9d4b Giorgos Verigakis
237 85a634e6 Kostas Papadimitriou
def render_diagnostics(request, diagnostics_dict, status=200):
238 85a634e6 Kostas Papadimitriou
    """
239 85a634e6 Kostas Papadimitriou
    Render diagnostics dictionary to json response.
240 85a634e6 Kostas Papadimitriou
    """
241 85a634e6 Kostas Papadimitriou
    return HttpResponse(json.dumps(diagnostics_dict), status=status)
242 85a634e6 Kostas Papadimitriou
243 85a634e6 Kostas Papadimitriou
244 b3fd98ae Christos Stavrakakis
@api.api_method(http_method='GET', user_required=True, logger=log)
245 85a634e6 Kostas Papadimitriou
def get_server_diagnostics(request, server_id):
246 85a634e6 Kostas Papadimitriou
    """
247 85a634e6 Kostas Papadimitriou
    Virtual machine diagnostics api view.
248 85a634e6 Kostas Papadimitriou
    """
249 85a634e6 Kostas Papadimitriou
    log.debug('server_diagnostics %s', server_id)
250 85a634e6 Kostas Papadimitriou
    vm = util.get_vm(server_id, request.user_uniq)
251 85a634e6 Kostas Papadimitriou
    diagnostics = diagnostics_to_dict(vm.diagnostics.all())
252 85a634e6 Kostas Papadimitriou
    return render_diagnostics(request, diagnostics)
253 85a634e6 Kostas Papadimitriou
254 85a634e6 Kostas Papadimitriou
255 b3fd98ae Christos Stavrakakis
@api.api_method(http_method='GET', user_required=True, logger=log)
256 7e2f9d4b Giorgos Verigakis
def list_servers(request, detail=False):
257 7e2f9d4b Giorgos Verigakis
    # Normal Response Codes: 200, 203
258 7e2f9d4b Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
259 7e2f9d4b Giorgos Verigakis
    #                       serviceUnavailable (503),
260 7e2f9d4b Giorgos Verigakis
    #                       unauthorized (401),
261 7e2f9d4b Giorgos Verigakis
    #                       badRequest (400),
262 7e2f9d4b Giorgos Verigakis
    #                       overLimit (413)
263 ce55f211 Kostas Papadimitriou
264 0c37a721 Christos Stavrakakis
    log.debug('list_servers detail=%s', detail)
265 e524ed5f Kostas Papadimitriou
    user_vms = VirtualMachine.objects.filter(userid=request.user_uniq)
266 ce55f211 Kostas Papadimitriou
267 b6bc4afa Christos Stavrakakis
    user_vms = utils.filter_modified_since(request, objects=user_vms)
268 ce55f211 Kostas Papadimitriou
269 41a7fae7 Christos Stavrakakis
    servers_dict = [vm_to_dict(server, detail)
270 41a7fae7 Christos Stavrakakis
                    for server in user_vms.order_by('id')]
271 aa197ee4 Vangelis Koukis
272 d8e50a39 Giorgos Verigakis
    if request.serialization == 'xml':
273 b36f78fa Giorgos Verigakis
        data = render_to_string('list_servers.xml', {
274 41a7fae7 Christos Stavrakakis
            'servers': servers_dict,
275 b36f78fa Giorgos Verigakis
            'detail': detail})
276 7e2f9d4b Giorgos Verigakis
    else:
277 41a7fae7 Christos Stavrakakis
        data = json.dumps({'servers': servers_dict})
278 aa197ee4 Vangelis Koukis
279 c36934a7 Giorgos Verigakis
    return HttpResponse(data, status=200)
280 7e2f9d4b Giorgos Verigakis
281 55cd40be Vangelis Koukis
282 b3fd98ae Christos Stavrakakis
@api.api_method(http_method='POST', user_required=True, logger=log)
283 2509ce17 Christos Stavrakakis
def create_server(request):
284 7e2f9d4b Giorgos Verigakis
    # Normal Response Code: 202
285 7e2f9d4b Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
286 7e2f9d4b Giorgos Verigakis
    #                       serviceUnavailable (503),
287 7e2f9d4b Giorgos Verigakis
    #                       unauthorized (401),
288 7e2f9d4b Giorgos Verigakis
    #                       badMediaType(415),
289 7e2f9d4b Giorgos Verigakis
    #                       itemNotFound (404),
290 7e2f9d4b Giorgos Verigakis
    #                       badRequest (400),
291 7e2f9d4b Giorgos Verigakis
    #                       serverCapacityUnavailable (503),
292 7e2f9d4b Giorgos Verigakis
    #                       overLimit (413)
293 bcd80cd9 Christos Stavrakakis
    req = utils.get_request_dict(request)
294 bcd80cd9 Christos Stavrakakis
    log.info('create_server %s', req)
295 bcd80cd9 Christos Stavrakakis
    user_id = request.user_uniq
296 bcd80cd9 Christos Stavrakakis
297 7e2f9d4b Giorgos Verigakis
    try:
298 bcd80cd9 Christos Stavrakakis
        server = req['server']
299 bcd80cd9 Christos Stavrakakis
        name = server['name']
300 bcd80cd9 Christos Stavrakakis
        metadata = server.get('metadata', {})
301 bcd80cd9 Christos Stavrakakis
        assert isinstance(metadata, dict)
302 bcd80cd9 Christos Stavrakakis
        image_id = server['imageRef']
303 bcd80cd9 Christos Stavrakakis
        flavor_id = server['flavorRef']
304 bcd80cd9 Christos Stavrakakis
        personality = server.get('personality', [])
305 bcd80cd9 Christos Stavrakakis
        assert isinstance(personality, list)
306 cb66110b Christos Stavrakakis
        private_networks = server.get("networks", [])
307 cb66110b Christos Stavrakakis
        assert isinstance(private_networks, list)
308 816d7588 Christos Stavrakakis
        floating_ips = server.get("floating_ips", [])
309 816d7588 Christos Stavrakakis
        assert isinstance(floating_ips, list)
310 bcd80cd9 Christos Stavrakakis
    except (KeyError, AssertionError):
311 bcd80cd9 Christos Stavrakakis
        raise faults.BadRequest("Malformed request")
312 bcd80cd9 Christos Stavrakakis
313 bcd80cd9 Christos Stavrakakis
    # Verify that personalities are well-formed
314 bcd80cd9 Christos Stavrakakis
    util.verify_personality(personality)
315 bcd80cd9 Christos Stavrakakis
    # Get image information
316 bcd80cd9 Christos Stavrakakis
    image = util.get_image_dict(image_id, user_id)
317 bcd80cd9 Christos Stavrakakis
    # Get flavor (ensure it is active)
318 bcd80cd9 Christos Stavrakakis
    flavor = util.get_flavor(flavor_id, include_deleted=False)
319 bcd80cd9 Christos Stavrakakis
    # Generate password
320 bcd80cd9 Christos Stavrakakis
    password = util.random_password()
321 bcd80cd9 Christos Stavrakakis
322 41a7fae7 Christos Stavrakakis
    vm = servers.create(user_id, name, password, flavor, image,
323 cb66110b Christos Stavrakakis
                        metadata=metadata, personality=personality,
324 816d7588 Christos Stavrakakis
                        private_networks=private_networks,
325 816d7588 Christos Stavrakakis
                        floating_ips=floating_ips)
326 bcd80cd9 Christos Stavrakakis
327 bcd80cd9 Christos Stavrakakis
    server = vm_to_dict(vm, detail=True)
328 bcd80cd9 Christos Stavrakakis
    server['status'] = 'BUILD'
329 bcd80cd9 Christos Stavrakakis
    server['adminPass'] = password
330 bcd80cd9 Christos Stavrakakis
331 bcd80cd9 Christos Stavrakakis
    response = render_server(request, server, status=202)
332 4b8e03e5 Christos Stavrakakis
333 bcd80cd9 Christos Stavrakakis
    return response
334 bcd80cd9 Christos Stavrakakis
335 bcd80cd9 Christos Stavrakakis
336 b3fd98ae Christos Stavrakakis
@api.api_method(http_method='GET', user_required=True, logger=log)
337 7e2f9d4b Giorgos Verigakis
def get_server_details(request, server_id):
338 c36934a7 Giorgos Verigakis
    # Normal Response Codes: 200, 203
339 c36934a7 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
340 c36934a7 Giorgos Verigakis
    #                       serviceUnavailable (503),
341 c36934a7 Giorgos Verigakis
    #                       unauthorized (401),
342 c36934a7 Giorgos Verigakis
    #                       badRequest (400),
343 c36934a7 Giorgos Verigakis
    #                       itemNotFound (404),
344 c36934a7 Giorgos Verigakis
    #                       overLimit (413)
345 ce55f211 Kostas Papadimitriou
346 0c37a721 Christos Stavrakakis
    log.debug('get_server_details %s', server_id)
347 4b3b8688 Giorgos Verigakis
    vm = util.get_vm(server_id, request.user_uniq)
348 d8e50a39 Giorgos Verigakis
    server = vm_to_dict(vm, detail=True)
349 d8e50a39 Giorgos Verigakis
    return render_server(request, server)
350 7e2f9d4b Giorgos Verigakis
351 55cd40be Vangelis Koukis
352 b3fd98ae Christos Stavrakakis
@api.api_method(http_method='PUT', user_required=True, logger=log)
353 c36934a7 Giorgos Verigakis
def update_server_name(request, server_id):
354 c36934a7 Giorgos Verigakis
    # Normal Response Code: 204
355 c36934a7 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
356 c36934a7 Giorgos Verigakis
    #                       serviceUnavailable (503),
357 c36934a7 Giorgos Verigakis
    #                       unauthorized (401),
358 c36934a7 Giorgos Verigakis
    #                       badRequest (400),
359 c36934a7 Giorgos Verigakis
    #                       badMediaType(415),
360 c36934a7 Giorgos Verigakis
    #                       itemNotFound (404),
361 c36934a7 Giorgos Verigakis
    #                       buildInProgress (409),
362 c36934a7 Giorgos Verigakis
    #                       overLimit (413)
363 aa197ee4 Vangelis Koukis
364 b3fd98ae Christos Stavrakakis
    req = utils.get_request_dict(request)
365 bf5c82dc Christos Stavrakakis
    log.info('update_server_name %s %s', server_id, req)
366 ce55f211 Kostas Papadimitriou
367 7e2f9d4b Giorgos Verigakis
    try:
368 7e2f9d4b Giorgos Verigakis
        name = req['server']['name']
369 529178b1 Giorgos Verigakis
    except (TypeError, KeyError):
370 ccd0d474 Giorgos Verigakis
        raise faults.BadRequest("Malformed request")
371 aa197ee4 Vangelis Koukis
372 7f2dbcad Christos Stavrakakis
    vm = util.get_vm(server_id, request.user_uniq, for_update=True,
373 7f2dbcad Christos Stavrakakis
                     non_suspended=True)
374 d8e50a39 Giorgos Verigakis
    vm.name = name
375 d8e50a39 Giorgos Verigakis
    vm.save()
376 aa197ee4 Vangelis Koukis
377 7e2f9d4b Giorgos Verigakis
    return HttpResponse(status=204)
378 7e2f9d4b Giorgos Verigakis
379 55cd40be Vangelis Koukis
380 b3fd98ae Christos Stavrakakis
@api.api_method(http_method='DELETE', user_required=True, logger=log)
381 7e2f9d4b Giorgos Verigakis
def delete_server(request, server_id):
382 c36934a7 Giorgos Verigakis
    # Normal Response Codes: 204
383 c36934a7 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
384 c36934a7 Giorgos Verigakis
    #                       serviceUnavailable (503),
385 c36934a7 Giorgos Verigakis
    #                       unauthorized (401),
386 c36934a7 Giorgos Verigakis
    #                       itemNotFound (404),
387 c36934a7 Giorgos Verigakis
    #                       unauthorized (401),
388 c36934a7 Giorgos Verigakis
    #                       buildInProgress (409),
389 c36934a7 Giorgos Verigakis
    #                       overLimit (413)
390 ce55f211 Kostas Papadimitriou
391 bf5c82dc Christos Stavrakakis
    log.info('delete_server %s', server_id)
392 7f2dbcad Christos Stavrakakis
    vm = util.get_vm(server_id, request.user_uniq, for_update=True,
393 7f2dbcad Christos Stavrakakis
                     non_suspended=True)
394 41a7fae7 Christos Stavrakakis
    vm = servers.destroy(vm)
395 7e2f9d4b Giorgos Verigakis
    return HttpResponse(status=204)
396 b016b476 Giorgos Verigakis
397 55cd40be Vangelis Koukis
398 04a95cf3 Kostas Papadimitriou
# additional server actions
399 04a95cf3 Kostas Papadimitriou
ARBITRARY_ACTIONS = ['console', 'firewallProfile']
400 04a95cf3 Kostas Papadimitriou
401 e440e835 Christos Stavrakakis
402 7f2dbcad Christos Stavrakakis
def key_to_action(key):
403 7f2dbcad Christos Stavrakakis
    """Map HTTP request key to a VM Action"""
404 7f2dbcad Christos Stavrakakis
    if key == "shutdown":
405 7f2dbcad Christos Stavrakakis
        return "STOP"
406 7f2dbcad Christos Stavrakakis
    if key == "delete":
407 7f2dbcad Christos Stavrakakis
        return "DESTROY"
408 b7f21824 Kostas Papadimitriou
    if key in ARBITRARY_ACTIONS:
409 7f2dbcad Christos Stavrakakis
        return None
410 7f2dbcad Christos Stavrakakis
    else:
411 7f2dbcad Christos Stavrakakis
        return key.upper()
412 7f2dbcad Christos Stavrakakis
413 7f2dbcad Christos Stavrakakis
414 41a7fae7 Christos Stavrakakis
@api.api_method(http_method='POST', user_required=True, logger=log)
415 41a7fae7 Christos Stavrakakis
@transaction.commit_on_success
416 41a7fae7 Christos Stavrakakis
def demux_server_action(request, server_id):
417 41a7fae7 Christos Stavrakakis
    req = utils.get_request_dict(request)
418 41a7fae7 Christos Stavrakakis
    log.debug('server_action %s %s', server_id, req)
419 7f2dbcad Christos Stavrakakis
420 41a7fae7 Christos Stavrakakis
    if len(req) != 1:
421 41a7fae7 Christos Stavrakakis
        raise faults.BadRequest("Malformed request")
422 41a7fae7 Christos Stavrakakis
423 41a7fae7 Christos Stavrakakis
    # Do not allow any action on deleted or suspended VMs
424 41a7fae7 Christos Stavrakakis
    vm = util.get_vm(server_id, request.user_uniq, for_update=True,
425 41a7fae7 Christos Stavrakakis
                     non_deleted=True, non_suspended=True)
426 7f2dbcad Christos Stavrakakis
427 ece5581b Christos Stavrakakis
    action = req.keys()[0]
428 7f2dbcad Christos Stavrakakis
429 41a7fae7 Christos Stavrakakis
    if key_to_action(action) not in [x[0] for x in VirtualMachine.ACTIONS]:
430 41a7fae7 Christos Stavrakakis
        if action not in ARBITRARY_ACTIONS:
431 41a7fae7 Christos Stavrakakis
            raise faults.BadRequest("Action %s not supported" % action)
432 41a7fae7 Christos Stavrakakis
    action_args = req[action]
433 7f2dbcad Christos Stavrakakis
434 41a7fae7 Christos Stavrakakis
    if not isinstance(action_args, dict):
435 41a7fae7 Christos Stavrakakis
        raise faults.BadRequest("Invalid argument")
436 7f2dbcad Christos Stavrakakis
437 41a7fae7 Christos Stavrakakis
    return server_actions[action](request, vm, action_args)
438 7f2dbcad Christos Stavrakakis
439 7f2dbcad Christos Stavrakakis
440 b3fd98ae Christos Stavrakakis
@api.api_method(http_method='GET', user_required=True, logger=log)
441 b016b476 Giorgos Verigakis
def list_addresses(request, server_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
    #                       overLimit (413)
448 ce55f211 Kostas Papadimitriou
449 0c37a721 Christos Stavrakakis
    log.debug('list_addresses %s', server_id)
450 4b3b8688 Giorgos Verigakis
    vm = util.get_vm(server_id, request.user_uniq)
451 1f638a85 Christos Stavrakakis
    attachments = [nic_to_dict(nic) for nic in vm.nics.all()]
452 78c165cf Christos Stavrakakis
    addresses = attachments_to_addresses(attachments)
453 ce55f211 Kostas Papadimitriou
454 d8e50a39 Giorgos Verigakis
    if request.serialization == 'xml':
455 b016b476 Giorgos Verigakis
        data = render_to_string('list_addresses.xml', {'addresses': addresses})
456 b016b476 Giorgos Verigakis
    else:
457 1f638a85 Christos Stavrakakis
        data = json.dumps({'addresses': addresses, 'attachments': attachments})
458 aa197ee4 Vangelis Koukis
459 b016b476 Giorgos Verigakis
    return HttpResponse(data, status=200)
460 b016b476 Giorgos Verigakis
461 55cd40be Vangelis Koukis
462 b3fd98ae Christos Stavrakakis
@api.api_method(http_method='GET', user_required=True, logger=log)
463 b016b476 Giorgos Verigakis
def list_addresses_by_network(request, server_id, network_id):
464 b016b476 Giorgos Verigakis
    # Normal Response Codes: 200, 203
465 b016b476 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
466 b016b476 Giorgos Verigakis
    #                       serviceUnavailable (503),
467 b016b476 Giorgos Verigakis
    #                       unauthorized (401),
468 b016b476 Giorgos Verigakis
    #                       badRequest (400),
469 b016b476 Giorgos Verigakis
    #                       itemNotFound (404),
470 b016b476 Giorgos Verigakis
    #                       overLimit (413)
471 ce55f211 Kostas Papadimitriou
472 0c37a721 Christos Stavrakakis
    log.debug('list_addresses_by_network %s %s', server_id, network_id)
473 4b3b8688 Giorgos Verigakis
    machine = util.get_vm(server_id, request.user_uniq)
474 4b3b8688 Giorgos Verigakis
    network = util.get_network(network_id, request.user_uniq)
475 1f638a85 Christos Stavrakakis
    nics = machine.nics.filter(network=network).all()
476 78c165cf Christos Stavrakakis
    addresses = attachments_to_addresses(map(nic_to_dict, nics))
477 ce55f211 Kostas Papadimitriou
478 d8e50a39 Giorgos Verigakis
    if request.serialization == 'xml':
479 1f638a85 Christos Stavrakakis
        data = render_to_string('address.xml', {'addresses': addresses})
480 b016b476 Giorgos Verigakis
    else:
481 1f638a85 Christos Stavrakakis
        data = json.dumps({'network': addresses})
482 aa197ee4 Vangelis Koukis
483 b016b476 Giorgos Verigakis
    return HttpResponse(data, status=200)
484 d8e50a39 Giorgos Verigakis
485 55cd40be Vangelis Koukis
486 b3fd98ae Christos Stavrakakis
@api.api_method(http_method='GET', user_required=True, logger=log)
487 d8e50a39 Giorgos Verigakis
def list_metadata(request, server_id):
488 d8e50a39 Giorgos Verigakis
    # Normal Response Codes: 200, 203
489 d8e50a39 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
490 d8e50a39 Giorgos Verigakis
    #                       serviceUnavailable (503),
491 d8e50a39 Giorgos Verigakis
    #                       unauthorized (401),
492 d8e50a39 Giorgos Verigakis
    #                       badRequest (400),
493 d8e50a39 Giorgos Verigakis
    #                       overLimit (413)
494 ce55f211 Kostas Papadimitriou
495 0c37a721 Christos Stavrakakis
    log.debug('list_server_metadata %s', server_id)
496 4b3b8688 Giorgos Verigakis
    vm = util.get_vm(server_id, request.user_uniq)
497 7cc3c7d9 Giorgos Verigakis
    metadata = dict((m.meta_key, m.meta_value) for m in vm.metadata.all())
498 5029ff36 Christos Stavrakakis
    return util.render_metadata(request, metadata, use_values=False,
499 5029ff36 Christos Stavrakakis
                                status=200)
500 d8e50a39 Giorgos Verigakis
501 55cd40be Vangelis Koukis
502 b3fd98ae Christos Stavrakakis
@api.api_method(http_method='POST', user_required=True, logger=log)
503 d8e50a39 Giorgos Verigakis
def update_metadata(request, server_id):
504 d8e50a39 Giorgos Verigakis
    # Normal Response Code: 201
505 d8e50a39 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
506 d8e50a39 Giorgos Verigakis
    #                       serviceUnavailable (503),
507 d8e50a39 Giorgos Verigakis
    #                       unauthorized (401),
508 d8e50a39 Giorgos Verigakis
    #                       badRequest (400),
509 d8e50a39 Giorgos Verigakis
    #                       buildInProgress (409),
510 d8e50a39 Giorgos Verigakis
    #                       badMediaType(415),
511 d8e50a39 Giorgos Verigakis
    #                       overLimit (413)
512 ce55f211 Kostas Papadimitriou
513 b3fd98ae Christos Stavrakakis
    req = utils.get_request_dict(request)
514 bf5c82dc Christos Stavrakakis
    log.info('update_server_metadata %s %s', server_id, req)
515 e221ade2 Christos Stavrakakis
    vm = util.get_vm(server_id, request.user_uniq, non_suspended=True)
516 d8e50a39 Giorgos Verigakis
    try:
517 d8e50a39 Giorgos Verigakis
        metadata = req['metadata']
518 d8e50a39 Giorgos Verigakis
        assert isinstance(metadata, dict)
519 d8e50a39 Giorgos Verigakis
    except (KeyError, AssertionError):
520 ccd0d474 Giorgos Verigakis
        raise faults.BadRequest("Malformed request")
521 ce55f211 Kostas Papadimitriou
522 7cc3c7d9 Giorgos Verigakis
    for key, val in metadata.items():
523 7cc3c7d9 Giorgos Verigakis
        meta, created = vm.metadata.get_or_create(meta_key=key)
524 7cc3c7d9 Giorgos Verigakis
        meta.meta_value = val
525 7cc3c7d9 Giorgos Verigakis
        meta.save()
526 ce55f211 Kostas Papadimitriou
527 7cc3c7d9 Giorgos Verigakis
    vm.save()
528 7cc3c7d9 Giorgos Verigakis
    vm_meta = dict((m.meta_key, m.meta_value) for m in vm.metadata.all())
529 7cc3c7d9 Giorgos Verigakis
    return util.render_metadata(request, vm_meta, status=201)
530 d8e50a39 Giorgos Verigakis
531 55cd40be Vangelis Koukis
532 b3fd98ae Christos Stavrakakis
@api.api_method(http_method='GET', user_required=True, logger=log)
533 d8e50a39 Giorgos Verigakis
def get_metadata_item(request, server_id, key):
534 d8e50a39 Giorgos Verigakis
    # Normal Response Codes: 200, 203
535 d8e50a39 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
536 d8e50a39 Giorgos Verigakis
    #                       serviceUnavailable (503),
537 d8e50a39 Giorgos Verigakis
    #                       unauthorized (401),
538 d8e50a39 Giorgos Verigakis
    #                       itemNotFound (404),
539 d8e50a39 Giorgos Verigakis
    #                       badRequest (400),
540 d8e50a39 Giorgos Verigakis
    #                       overLimit (413)
541 ce55f211 Kostas Papadimitriou
542 0c37a721 Christos Stavrakakis
    log.debug('get_server_metadata_item %s %s', server_id, key)
543 4b3b8688 Giorgos Verigakis
    vm = util.get_vm(server_id, request.user_uniq)
544 b36f78fa Giorgos Verigakis
    meta = util.get_vm_meta(vm, key)
545 62b894c0 Giorgos Verigakis
    d = {meta.meta_key: meta.meta_value}
546 62b894c0 Giorgos Verigakis
    return util.render_meta(request, d, status=200)
547 d8e50a39 Giorgos Verigakis
548 55cd40be Vangelis Koukis
549 b3fd98ae Christos Stavrakakis
@api.api_method(http_method='PUT', user_required=True, logger=log)
550 4dba0480 Christos Stavrakakis
@transaction.commit_on_success
551 d8e50a39 Giorgos Verigakis
def create_metadata_item(request, server_id, key):
552 d8e50a39 Giorgos Verigakis
    # Normal Response Code: 201
553 d8e50a39 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
554 d8e50a39 Giorgos Verigakis
    #                       serviceUnavailable (503),
555 d8e50a39 Giorgos Verigakis
    #                       unauthorized (401),
556 d8e50a39 Giorgos Verigakis
    #                       itemNotFound (404),
557 d8e50a39 Giorgos Verigakis
    #                       badRequest (400),
558 d8e50a39 Giorgos Verigakis
    #                       buildInProgress (409),
559 d8e50a39 Giorgos Verigakis
    #                       badMediaType(415),
560 d8e50a39 Giorgos Verigakis
    #                       overLimit (413)
561 ce55f211 Kostas Papadimitriou
562 b3fd98ae Christos Stavrakakis
    req = utils.get_request_dict(request)
563 bf5c82dc Christos Stavrakakis
    log.info('create_server_metadata_item %s %s %s', server_id, key, req)
564 e221ade2 Christos Stavrakakis
    vm = util.get_vm(server_id, request.user_uniq, non_suspended=True)
565 d8e50a39 Giorgos Verigakis
    try:
566 d8e50a39 Giorgos Verigakis
        metadict = req['meta']
567 d8e50a39 Giorgos Verigakis
        assert isinstance(metadict, dict)
568 d8e50a39 Giorgos Verigakis
        assert len(metadict) == 1
569 d8e50a39 Giorgos Verigakis
        assert key in metadict
570 d8e50a39 Giorgos Verigakis
    except (KeyError, AssertionError):
571 ccd0d474 Giorgos Verigakis
        raise faults.BadRequest("Malformed request")
572 ce55f211 Kostas Papadimitriou
573 b36f78fa Giorgos Verigakis
    meta, created = VirtualMachineMetadata.objects.get_or_create(
574 b36f78fa Giorgos Verigakis
        meta_key=key,
575 b36f78fa Giorgos Verigakis
        vm=vm)
576 ce55f211 Kostas Papadimitriou
577 d8e50a39 Giorgos Verigakis
    meta.meta_value = metadict[key]
578 d8e50a39 Giorgos Verigakis
    meta.save()
579 5509b599 Giorgos Verigakis
    vm.save()
580 62b894c0 Giorgos Verigakis
    d = {meta.meta_key: meta.meta_value}
581 62b894c0 Giorgos Verigakis
    return util.render_meta(request, d, status=201)
582 d8e50a39 Giorgos Verigakis
583 55cd40be Vangelis Koukis
584 b3fd98ae Christos Stavrakakis
@api.api_method(http_method='DELETE', user_required=True, logger=log)
585 4dba0480 Christos Stavrakakis
@transaction.commit_on_success
586 d8e50a39 Giorgos Verigakis
def delete_metadata_item(request, server_id, key):
587 d8e50a39 Giorgos Verigakis
    # Normal Response Code: 204
588 d8e50a39 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
589 d8e50a39 Giorgos Verigakis
    #                       serviceUnavailable (503),
590 d8e50a39 Giorgos Verigakis
    #                       unauthorized (401),
591 d8e50a39 Giorgos Verigakis
    #                       itemNotFound (404),
592 d8e50a39 Giorgos Verigakis
    #                       badRequest (400),
593 d8e50a39 Giorgos Verigakis
    #                       buildInProgress (409),
594 d8e50a39 Giorgos Verigakis
    #                       badMediaType(415),
595 d8e50a39 Giorgos Verigakis
    #                       overLimit (413),
596 ce55f211 Kostas Papadimitriou
597 bf5c82dc Christos Stavrakakis
    log.info('delete_server_metadata_item %s %s', server_id, key)
598 e221ade2 Christos Stavrakakis
    vm = util.get_vm(server_id, request.user_uniq, non_suspended=True)
599 b36f78fa Giorgos Verigakis
    meta = util.get_vm_meta(vm, key)
600 d8e50a39 Giorgos Verigakis
    meta.delete()
601 5509b599 Giorgos Verigakis
    vm.save()
602 d8e50a39 Giorgos Verigakis
    return HttpResponse(status=204)
603 c738c935 Giorgos Verigakis
604 55cd40be Vangelis Koukis
605 b3fd98ae Christos Stavrakakis
@api.api_method(http_method='GET', user_required=True, logger=log)
606 c738c935 Giorgos Verigakis
def server_stats(request, server_id):
607 c738c935 Giorgos Verigakis
    # Normal Response Codes: 200
608 c738c935 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
609 c738c935 Giorgos Verigakis
    #                       serviceUnavailable (503),
610 c738c935 Giorgos Verigakis
    #                       unauthorized (401),
611 c738c935 Giorgos Verigakis
    #                       badRequest (400),
612 c738c935 Giorgos Verigakis
    #                       itemNotFound (404),
613 c738c935 Giorgos Verigakis
    #                       overLimit (413)
614 ce55f211 Kostas Papadimitriou
615 0c37a721 Christos Stavrakakis
    log.debug('server_stats %s', server_id)
616 4b3b8688 Giorgos Verigakis
    vm = util.get_vm(server_id, request.user_uniq)
617 924d8085 Christos Stavrakakis
    #secret = util.encrypt(vm.backend_vm_id)
618 924d8085 Christos Stavrakakis
    secret = vm.backend_vm_id      # XXX disable backend id encryption
619 ce55f211 Kostas Papadimitriou
620 c738c935 Giorgos Verigakis
    stats = {
621 c738c935 Giorgos Verigakis
        'serverRef': vm.id,
622 c738c935 Giorgos Verigakis
        'refresh': settings.STATS_REFRESH_PERIOD,
623 5391d6b5 Giorgos Verigakis
        'cpuBar': settings.CPU_BAR_GRAPH_URL % secret,
624 5391d6b5 Giorgos Verigakis
        'cpuTimeSeries': settings.CPU_TIMESERIES_GRAPH_URL % secret,
625 5391d6b5 Giorgos Verigakis
        'netBar': settings.NET_BAR_GRAPH_URL % secret,
626 5391d6b5 Giorgos Verigakis
        'netTimeSeries': settings.NET_TIMESERIES_GRAPH_URL % secret}
627 ce55f211 Kostas Papadimitriou
628 c738c935 Giorgos Verigakis
    if request.serialization == 'xml':
629 c738c935 Giorgos Verigakis
        data = render_to_string('server_stats.xml', stats)
630 c738c935 Giorgos Verigakis
    else:
631 c738c935 Giorgos Verigakis
        data = json.dumps({'stats': stats})
632 c738c935 Giorgos Verigakis
633 c738c935 Giorgos Verigakis
    return HttpResponse(data, status=200)
634 41a7fae7 Christos Stavrakakis
635 41a7fae7 Christos Stavrakakis
636 41a7fae7 Christos Stavrakakis
# ACTIONS
637 41a7fae7 Christos Stavrakakis
638 41a7fae7 Christos Stavrakakis
639 41a7fae7 Christos Stavrakakis
server_actions = {}
640 41a7fae7 Christos Stavrakakis
network_actions = {}
641 41a7fae7 Christos Stavrakakis
642 41a7fae7 Christos Stavrakakis
643 41a7fae7 Christos Stavrakakis
def server_action(name):
644 41a7fae7 Christos Stavrakakis
    '''Decorator for functions implementing server actions.
645 41a7fae7 Christos Stavrakakis
    `name` is the key in the dict passed by the client.
646 41a7fae7 Christos Stavrakakis
    '''
647 41a7fae7 Christos Stavrakakis
648 41a7fae7 Christos Stavrakakis
    def decorator(func):
649 41a7fae7 Christos Stavrakakis
        server_actions[name] = func
650 41a7fae7 Christos Stavrakakis
        return func
651 41a7fae7 Christos Stavrakakis
    return decorator
652 41a7fae7 Christos Stavrakakis
653 41a7fae7 Christos Stavrakakis
654 41a7fae7 Christos Stavrakakis
def network_action(name):
655 41a7fae7 Christos Stavrakakis
    '''Decorator for functions implementing network actions.
656 41a7fae7 Christos Stavrakakis
    `name` is the key in the dict passed by the client.
657 41a7fae7 Christos Stavrakakis
    '''
658 41a7fae7 Christos Stavrakakis
659 41a7fae7 Christos Stavrakakis
    def decorator(func):
660 41a7fae7 Christos Stavrakakis
        network_actions[name] = func
661 41a7fae7 Christos Stavrakakis
        return func
662 41a7fae7 Christos Stavrakakis
    return decorator
663 41a7fae7 Christos Stavrakakis
664 41a7fae7 Christos Stavrakakis
665 41a7fae7 Christos Stavrakakis
@server_action('start')
666 41a7fae7 Christos Stavrakakis
def start(request, vm, args):
667 41a7fae7 Christos Stavrakakis
    # Normal Response Code: 202
668 41a7fae7 Christos Stavrakakis
    # Error Response Codes: serviceUnavailable (503),
669 41a7fae7 Christos Stavrakakis
    #                       itemNotFound (404)
670 41a7fae7 Christos Stavrakakis
    vm = servers.start(vm)
671 41a7fae7 Christos Stavrakakis
    return HttpResponse(status=202)
672 41a7fae7 Christos Stavrakakis
673 41a7fae7 Christos Stavrakakis
674 41a7fae7 Christos Stavrakakis
@server_action('shutdown')
675 41a7fae7 Christos Stavrakakis
def shutdown(request, vm, args):
676 41a7fae7 Christos Stavrakakis
    # Normal Response Code: 202
677 41a7fae7 Christos Stavrakakis
    # Error Response Codes: serviceUnavailable (503),
678 41a7fae7 Christos Stavrakakis
    #                       itemNotFound (404)
679 41a7fae7 Christos Stavrakakis
    vm = servers.stop(vm)
680 41a7fae7 Christos Stavrakakis
    return HttpResponse(status=202)
681 41a7fae7 Christos Stavrakakis
682 41a7fae7 Christos Stavrakakis
683 41a7fae7 Christos Stavrakakis
@server_action('reboot')
684 41a7fae7 Christos Stavrakakis
def reboot(request, vm, args):
685 41a7fae7 Christos Stavrakakis
    # Normal Response Code: 202
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
695 41a7fae7 Christos Stavrakakis
    reboot_type = args.get("type")
696 41a7fae7 Christos Stavrakakis
    if reboot_type is None:
697 41a7fae7 Christos Stavrakakis
        raise faults.BadRequest("Missing 'type' attribute.")
698 41a7fae7 Christos Stavrakakis
    elif reboot_type not in ["SOFT", "HARD"]:
699 41a7fae7 Christos Stavrakakis
        raise faults.BadRequest("Invalid 'type' attribute.")
700 41a7fae7 Christos Stavrakakis
    vm = servers.reboot(vm, reboot_type=reboot_type)
701 41a7fae7 Christos Stavrakakis
    return HttpResponse(status=202)
702 41a7fae7 Christos Stavrakakis
703 41a7fae7 Christos Stavrakakis
704 41a7fae7 Christos Stavrakakis
@server_action('firewallProfile')
705 41a7fae7 Christos Stavrakakis
def set_firewall_profile(request, vm, args):
706 41a7fae7 Christos Stavrakakis
    # Normal Response Code: 200
707 41a7fae7 Christos Stavrakakis
    # Error Response Codes: computeFault (400, 500),
708 41a7fae7 Christos Stavrakakis
    #                       serviceUnavailable (503),
709 41a7fae7 Christos Stavrakakis
    #                       unauthorized (401),
710 41a7fae7 Christos Stavrakakis
    #                       badRequest (400),
711 41a7fae7 Christos Stavrakakis
    #                       badMediaType(415),
712 41a7fae7 Christos Stavrakakis
    #                       itemNotFound (404),
713 41a7fae7 Christos Stavrakakis
    #                       buildInProgress (409),
714 41a7fae7 Christos Stavrakakis
    #                       overLimit (413)
715 41a7fae7 Christos Stavrakakis
    profile = args.get("profile")
716 41a7fae7 Christos Stavrakakis
    if profile is None:
717 41a7fae7 Christos Stavrakakis
        raise faults.BadRequest("Missing 'profile' attribute")
718 b2791a77 Christos Stavrakakis
    index = args.get("index", 0)
719 b2791a77 Christos Stavrakakis
    servers.set_firewall_profile(vm, profile=profile, index=index)
720 41a7fae7 Christos Stavrakakis
    return HttpResponse(status=202)
721 41a7fae7 Christos Stavrakakis
722 41a7fae7 Christos Stavrakakis
723 41a7fae7 Christos Stavrakakis
@server_action('resize')
724 41a7fae7 Christos Stavrakakis
def resize(request, vm, args):
725 41a7fae7 Christos Stavrakakis
    # Normal Response Code: 202
726 41a7fae7 Christos Stavrakakis
    # Error Response Codes: computeFault (400, 500),
727 41a7fae7 Christos Stavrakakis
    #                       serviceUnavailable (503),
728 41a7fae7 Christos Stavrakakis
    #                       unauthorized (401),
729 41a7fae7 Christos Stavrakakis
    #                       badRequest (400),
730 41a7fae7 Christos Stavrakakis
    #                       badMediaType(415),
731 41a7fae7 Christos Stavrakakis
    #                       itemNotFound (404),
732 41a7fae7 Christos Stavrakakis
    #                       buildInProgress (409),
733 41a7fae7 Christos Stavrakakis
    #                       serverCapacityUnavailable (503),
734 41a7fae7 Christos Stavrakakis
    #                       overLimit (413),
735 41a7fae7 Christos Stavrakakis
    #                       resizeNotAllowed (403)
736 41a7fae7 Christos Stavrakakis
    flavorRef = args.get("flavorRef")
737 41a7fae7 Christos Stavrakakis
    if flavorRef is None:
738 41a7fae7 Christos Stavrakakis
        raise faults.BadRequest("Missing 'flavorRef' attribute.")
739 41a7fae7 Christos Stavrakakis
    flavor = util.get_flavor(flavor_id=flavorRef, include_deleted=False)
740 41a7fae7 Christos Stavrakakis
    servers.resize(vm, flavor=flavor)
741 41a7fae7 Christos Stavrakakis
    return HttpResponse(status=202)
742 41a7fae7 Christos Stavrakakis
743 41a7fae7 Christos Stavrakakis
744 41a7fae7 Christos Stavrakakis
@server_action('console')
745 41a7fae7 Christos Stavrakakis
def get_console(request, vm, args):
746 41a7fae7 Christos Stavrakakis
    # Normal Response Code: 200
747 41a7fae7 Christos Stavrakakis
    # Error Response Codes: computeFault (400, 500),
748 41a7fae7 Christos Stavrakakis
    #                       serviceUnavailable (503),
749 41a7fae7 Christos Stavrakakis
    #                       unauthorized (401),
750 41a7fae7 Christos Stavrakakis
    #                       badRequest (400),
751 41a7fae7 Christos Stavrakakis
    #                       badMediaType(415),
752 41a7fae7 Christos Stavrakakis
    #                       itemNotFound (404),
753 41a7fae7 Christos Stavrakakis
    #                       buildInProgress (409),
754 41a7fae7 Christos Stavrakakis
    #                       overLimit (413)
755 41a7fae7 Christos Stavrakakis
756 41a7fae7 Christos Stavrakakis
    log.info("Get console  VM %s: %s", vm, args)
757 41a7fae7 Christos Stavrakakis
758 41a7fae7 Christos Stavrakakis
    console_type = args.get("type")
759 41a7fae7 Christos Stavrakakis
    if console_type is None:
760 41a7fae7 Christos Stavrakakis
        raise faults.BadRequest("No console 'type' specified.")
761 41a7fae7 Christos Stavrakakis
    elif console_type != "vnc":
762 41a7fae7 Christos Stavrakakis
        raise faults.BadRequest("Console 'type' can only be 'vnc'.")
763 41a7fae7 Christos Stavrakakis
    console_info = servers.console(vm, console_type)
764 41a7fae7 Christos Stavrakakis
765 41a7fae7 Christos Stavrakakis
    if request.serialization == 'xml':
766 41a7fae7 Christos Stavrakakis
        mimetype = 'application/xml'
767 41a7fae7 Christos Stavrakakis
        data = render_to_string('console.xml', {'console': console_info})
768 41a7fae7 Christos Stavrakakis
    else:
769 41a7fae7 Christos Stavrakakis
        mimetype = 'application/json'
770 41a7fae7 Christos Stavrakakis
        data = json.dumps({'console': console_info})
771 41a7fae7 Christos Stavrakakis
772 41a7fae7 Christos Stavrakakis
    return HttpResponse(data, mimetype=mimetype, status=200)
773 41a7fae7 Christos Stavrakakis
774 41a7fae7 Christos Stavrakakis
775 41a7fae7 Christos Stavrakakis
@server_action('changePassword')
776 41a7fae7 Christos Stavrakakis
def change_password(request, vm, args):
777 41a7fae7 Christos Stavrakakis
    raise faults.NotImplemented('Changing password is not supported.')
778 41a7fae7 Christos Stavrakakis
779 41a7fae7 Christos Stavrakakis
780 41a7fae7 Christos Stavrakakis
@server_action('rebuild')
781 41a7fae7 Christos Stavrakakis
def rebuild(request, vm, args):
782 41a7fae7 Christos Stavrakakis
    raise faults.NotImplemented('Rebuild not supported.')
783 41a7fae7 Christos Stavrakakis
784 41a7fae7 Christos Stavrakakis
785 41a7fae7 Christos Stavrakakis
@server_action('confirmResize')
786 41a7fae7 Christos Stavrakakis
def confirm_resize(request, vm, args):
787 41a7fae7 Christos Stavrakakis
    raise faults.NotImplemented('Resize not supported.')
788 41a7fae7 Christos Stavrakakis
789 41a7fae7 Christos Stavrakakis
790 41a7fae7 Christos Stavrakakis
@server_action('revertResize')
791 41a7fae7 Christos Stavrakakis
def revert_resize(request, vm, args):
792 41a7fae7 Christos Stavrakakis
    raise faults.NotImplemented('Resize not supported.')
793 41a7fae7 Christos Stavrakakis
794 41a7fae7 Christos Stavrakakis
795 41a7fae7 Christos Stavrakakis
@network_action('add')
796 41a7fae7 Christos Stavrakakis
@transaction.commit_on_success
797 41a7fae7 Christos Stavrakakis
def add(request, net, args):
798 41a7fae7 Christos Stavrakakis
    # Normal Response Code: 202
799 41a7fae7 Christos Stavrakakis
    # Error Response Codes: computeFault (400, 500),
800 41a7fae7 Christos Stavrakakis
    #                       serviceUnavailable (503),
801 41a7fae7 Christos Stavrakakis
    #                       unauthorized (401),
802 41a7fae7 Christos Stavrakakis
    #                       badRequest (400),
803 41a7fae7 Christos Stavrakakis
    #                       buildInProgress (409),
804 41a7fae7 Christos Stavrakakis
    #                       badMediaType(415),
805 41a7fae7 Christos Stavrakakis
    #                       itemNotFound (404),
806 41a7fae7 Christos Stavrakakis
    #                       overLimit (413)
807 41a7fae7 Christos Stavrakakis
    server_id = args.get('serverRef', None)
808 41a7fae7 Christos Stavrakakis
    if not server_id:
809 41a7fae7 Christos Stavrakakis
        raise faults.BadRequest('Malformed Request.')
810 41a7fae7 Christos Stavrakakis
811 41a7fae7 Christos Stavrakakis
    vm = util.get_vm(server_id, request.user_uniq, non_suspended=True)
812 41a7fae7 Christos Stavrakakis
    servers.connect(vm, network=net)
813 41a7fae7 Christos Stavrakakis
    return HttpResponse(status=202)
814 41a7fae7 Christos Stavrakakis
815 41a7fae7 Christos Stavrakakis
816 41a7fae7 Christos Stavrakakis
@network_action('remove')
817 41a7fae7 Christos Stavrakakis
@transaction.commit_on_success
818 41a7fae7 Christos Stavrakakis
def remove(request, net, args):
819 41a7fae7 Christos Stavrakakis
    # Normal Response Code: 202
820 41a7fae7 Christos Stavrakakis
    # Error Response Codes: computeFault (400, 500),
821 41a7fae7 Christos Stavrakakis
    #                       serviceUnavailable (503),
822 41a7fae7 Christos Stavrakakis
    #                       unauthorized (401),
823 41a7fae7 Christos Stavrakakis
    #                       badRequest (400),
824 41a7fae7 Christos Stavrakakis
    #                       badMediaType(415),
825 41a7fae7 Christos Stavrakakis
    #                       itemNotFound (404),
826 41a7fae7 Christos Stavrakakis
    #                       overLimit (413)
827 41a7fae7 Christos Stavrakakis
828 41a7fae7 Christos Stavrakakis
    attachment = args.get("attachment")
829 41a7fae7 Christos Stavrakakis
    if attachment is None:
830 41a7fae7 Christos Stavrakakis
        raise faults.BadRequest("Missing 'attachment' attribute.")
831 41a7fae7 Christos Stavrakakis
    try:
832 41a7fae7 Christos Stavrakakis
        # attachment string: nic-<vm-id>-<nic-index>
833 41a7fae7 Christos Stavrakakis
        _, server_id, nic_index = attachment.split("-", 2)
834 41a7fae7 Christos Stavrakakis
        server_id = int(server_id)
835 41a7fae7 Christos Stavrakakis
        nic_index = int(nic_index)
836 41a7fae7 Christos Stavrakakis
    except (ValueError, TypeError):
837 41a7fae7 Christos Stavrakakis
        raise faults.BadRequest("Invalid 'attachment' attribute.")
838 41a7fae7 Christos Stavrakakis
839 41a7fae7 Christos Stavrakakis
    vm = util.get_vm(server_id, request.user_uniq, non_suspended=True)
840 41a7fae7 Christos Stavrakakis
    servers.disconnect(vm, nic_index=nic_index)
841 41a7fae7 Christos Stavrakakis
842 41a7fae7 Christos Stavrakakis
    return HttpResponse(status=202)
843 9ba6bb95 Christos Stavrakakis
844 9ba6bb95 Christos Stavrakakis
845 f8675683 Christos Stavrakakis
@server_action("addFloatingIp")
846 9ba6bb95 Christos Stavrakakis
def add_floating_ip(request, vm, args):
847 9ba6bb95 Christos Stavrakakis
    address = args.get("address")
848 9ba6bb95 Christos Stavrakakis
    if address is None:
849 9ba6bb95 Christos Stavrakakis
        raise faults.BadRequest("Missing 'address' attribute")
850 9ba6bb95 Christos Stavrakakis
851 9ba6bb95 Christos Stavrakakis
    servers.add_floating_ip(vm, address)
852 9ba6bb95 Christos Stavrakakis
    return HttpResponse(status=202)
853 9ba6bb95 Christos Stavrakakis
854 9ba6bb95 Christos Stavrakakis
855 f8675683 Christos Stavrakakis
@server_action("removeFloatingIp")
856 9ba6bb95 Christos Stavrakakis
def remove_floating_ip(request, vm, args):
857 9ba6bb95 Christos Stavrakakis
    address = args.get("address")
858 9ba6bb95 Christos Stavrakakis
    if address is None:
859 9ba6bb95 Christos Stavrakakis
        raise faults.BadRequest("Missing 'address' attribute")
860 9ba6bb95 Christos Stavrakakis
861 9ba6bb95 Christos Stavrakakis
    servers.remove_floating_ip(vm, address)
862 9ba6bb95 Christos Stavrakakis
    return HttpResponse(status=202)