Statistics
| Branch: | Tag: | Revision:

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

History | View | Annotate | Download (31.5 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 6b256427 Christos Stavrakakis
from django.conf.urls import patterns
36 a6b17d33 Christos Stavrakakis
37 4dba0480 Christos Stavrakakis
from django.db import transaction
38 7e2f9d4b Giorgos Verigakis
from django.http import HttpResponse
39 7e2f9d4b Giorgos Verigakis
from django.template.loader import render_to_string
40 29a59bc1 Giorgos Verigakis
from django.utils import simplejson as json
41 7e2f9d4b Giorgos Verigakis
42 b3fd98ae Christos Stavrakakis
from snf_django.lib import api
43 b3fd98ae Christos Stavrakakis
from snf_django.lib.api import faults, utils
44 816d7588 Christos Stavrakakis
45 bd40abfa Christos Stavrakakis
from synnefo.api import util
46 41a7fae7 Christos Stavrakakis
from synnefo.db.models import (VirtualMachine, VirtualMachineMetadata)
47 41a7fae7 Christos Stavrakakis
from synnefo.logic import servers, utils as logic_utils
48 9e98ba3c Giorgos Verigakis
49 bf5c82dc Christos Stavrakakis
from logging import getLogger
50 b3fd98ae Christos Stavrakakis
log = getLogger(__name__)
51 7e2f9d4b Giorgos Verigakis
52 e440e835 Christos Stavrakakis
urlpatterns = patterns(
53 e440e835 Christos Stavrakakis
    'synnefo.api.servers',
54 7e2f9d4b Giorgos Verigakis
    (r'^(?:/|.json|.xml)?$', 'demux'),
55 7e2f9d4b Giorgos Verigakis
    (r'^/detail(?:.json|.xml)?$', 'list_servers', {'detail': True}),
56 7e2f9d4b Giorgos Verigakis
    (r'^/(\d+)(?:.json|.xml)?$', 'server_demux'),
57 41a7fae7 Christos Stavrakakis
    (r'^/(\d+)/action(?:.json|.xml)?$', 'demux_server_action'),
58 b016b476 Giorgos Verigakis
    (r'^/(\d+)/ips(?:.json|.xml)?$', 'list_addresses'),
59 b016b476 Giorgos Verigakis
    (r'^/(\d+)/ips/(.+?)(?:.json|.xml)?$', 'list_addresses_by_network'),
60 8a992938 Christos Stavrakakis
    (r'^/(\d+)/metadata(?:.json|.xml)?$', 'metadata_demux'),
61 8a992938 Christos Stavrakakis
    (r'^/(\d+)/metadata/(.+?)(?:.json|.xml)?$', 'metadata_item_demux'),
62 c738c935 Giorgos Verigakis
    (r'^/(\d+)/stats(?:.json|.xml)?$', 'server_stats'),
63 85a634e6 Kostas Papadimitriou
    (r'^/(\d+)/diagnostics(?:.json)?$', 'get_server_diagnostics'),
64 7e2f9d4b Giorgos Verigakis
)
65 7e2f9d4b Giorgos Verigakis
66 7e2f9d4b Giorgos Verigakis
67 7e2f9d4b Giorgos Verigakis
def demux(request):
68 7e2f9d4b Giorgos Verigakis
    if request.method == 'GET':
69 7e2f9d4b Giorgos Verigakis
        return list_servers(request)
70 7e2f9d4b Giorgos Verigakis
    elif request.method == 'POST':
71 7e2f9d4b Giorgos Verigakis
        return create_server(request)
72 7e2f9d4b Giorgos Verigakis
    else:
73 c0720b78 Kostas Papadimitriou
        return api.api_method_not_allowed(request)
74 7e2f9d4b Giorgos Verigakis
75 55cd40be Vangelis Koukis
76 7e2f9d4b Giorgos Verigakis
def server_demux(request, server_id):
77 7e2f9d4b Giorgos Verigakis
    if request.method == 'GET':
78 7e2f9d4b Giorgos Verigakis
        return get_server_details(request, server_id)
79 7e2f9d4b Giorgos Verigakis
    elif request.method == 'PUT':
80 7e2f9d4b Giorgos Verigakis
        return update_server_name(request, server_id)
81 7e2f9d4b Giorgos Verigakis
    elif request.method == 'DELETE':
82 7e2f9d4b Giorgos Verigakis
        return delete_server(request, server_id)
83 7e2f9d4b Giorgos Verigakis
    else:
84 c0720b78 Kostas Papadimitriou
        return api.api_method_not_allowed(request)
85 d8e50a39 Giorgos Verigakis
86 55cd40be Vangelis Koukis
87 d8e50a39 Giorgos Verigakis
def metadata_demux(request, server_id):
88 d8e50a39 Giorgos Verigakis
    if request.method == 'GET':
89 d8e50a39 Giorgos Verigakis
        return list_metadata(request, server_id)
90 d8e50a39 Giorgos Verigakis
    elif request.method == 'POST':
91 d8e50a39 Giorgos Verigakis
        return update_metadata(request, server_id)
92 d8e50a39 Giorgos Verigakis
    else:
93 c0720b78 Kostas Papadimitriou
        return api.api_method_not_allowed(request)
94 d8e50a39 Giorgos Verigakis
95 55cd40be Vangelis Koukis
96 d8e50a39 Giorgos Verigakis
def metadata_item_demux(request, server_id, key):
97 d8e50a39 Giorgos Verigakis
    if request.method == 'GET':
98 d8e50a39 Giorgos Verigakis
        return get_metadata_item(request, server_id, key)
99 d8e50a39 Giorgos Verigakis
    elif request.method == 'PUT':
100 d8e50a39 Giorgos Verigakis
        return create_metadata_item(request, server_id, key)
101 d8e50a39 Giorgos Verigakis
    elif request.method == 'DELETE':
102 d8e50a39 Giorgos Verigakis
        return delete_metadata_item(request, server_id, key)
103 d8e50a39 Giorgos Verigakis
    else:
104 c0720b78 Kostas Papadimitriou
        return api.api_method_not_allowed(request)
105 7e2f9d4b Giorgos Verigakis
106 08b079e2 Stavros Sachtouris
107 7fede91e Christos Stavrakakis
def nic_to_dict(nic):
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 443315d6 Christos Stavrakakis
         'OS-EXT-IPS:type': nic.ip_type.lower()}
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 7c714455 Christos Stavrakakis
        vm_nics = vm.nics.filter(state="ACTIVE").order_by("id")
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 2522e489 Christos Stavrakakis
        fqdn = get_server_fqdn(vm)
174 2522e489 Christos Stavrakakis
        d["SNF:fqdn"] = fqdn
175 2522e489 Christos Stavrakakis
        d["SNF:port_forwarding"] = get_server_port_forwarding(vm, fqdn)
176 85a634e6 Kostas Papadimitriou
177 7e2f9d4b Giorgos Verigakis
    return d
178 7e2f9d4b Giorgos Verigakis
179 d8e50a39 Giorgos Verigakis
180 d328a525 Christos Stavrakakis
def get_server_fqdn(vm):
181 d328a525 Christos Stavrakakis
    fqdn_setting = settings.CYCLADES_SERVERS_FQDN
182 d328a525 Christos Stavrakakis
    if fqdn_setting is None:
183 d328a525 Christos Stavrakakis
        public_nics = vm.nics.filter(network__public=True, state="ACTIVE")
184 d328a525 Christos Stavrakakis
        # Return the first public IPv4 address if exists
185 d328a525 Christos Stavrakakis
        ipv4_nics = public_nics.exclude(ipv4=None)
186 d328a525 Christos Stavrakakis
        if ipv4_nics:
187 d328a525 Christos Stavrakakis
            return ipv4_nics[0].ipv4
188 d328a525 Christos Stavrakakis
        # Else return the first public IPv6 address if exists
189 d328a525 Christos Stavrakakis
        ipv6_nics = public_nics.exclude(ipv6=None)
190 d328a525 Christos Stavrakakis
        if ipv6_nics:
191 d328a525 Christos Stavrakakis
            return ipv6_nics[0].ipv6
192 d328a525 Christos Stavrakakis
        return ""
193 d328a525 Christos Stavrakakis
    elif isinstance(fqdn_setting, basestring):
194 d328a525 Christos Stavrakakis
        return fqdn_setting % {"id": vm.id}
195 d328a525 Christos Stavrakakis
    else:
196 d328a525 Christos Stavrakakis
        msg = ("Invalid setting: CYCLADES_SERVERS_FQDN."
197 d328a525 Christos Stavrakakis
               " Value must be a string.")
198 d328a525 Christos Stavrakakis
        raise faults.InternalServerError(msg)
199 d328a525 Christos Stavrakakis
200 d328a525 Christos Stavrakakis
201 2522e489 Christos Stavrakakis
def get_server_port_forwarding(vm, fqdn):
202 2522e489 Christos Stavrakakis
    """Create API 'port_forwarding' attribute from corresponding setting.
203 2522e489 Christos Stavrakakis

204 2522e489 Christos Stavrakakis
    Create the 'port_forwarding' API vm attribute based on the corresponding
205 2522e489 Christos Stavrakakis
    setting (CYCLADES_PORT_FORWARDING), which can be either a tuple
206 2522e489 Christos Stavrakakis
    of the form (host, port) or a callable object returning such tuple. In
207 2522e489 Christos Stavrakakis
    case of callable object, must be called with the following arguments:
208 2522e489 Christos Stavrakakis
    * ip_address
209 2522e489 Christos Stavrakakis
    * server_id
210 2522e489 Christos Stavrakakis
    * fqdn
211 2522e489 Christos Stavrakakis
    * owner UUID
212 2522e489 Christos Stavrakakis

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