Statistics
| Branch: | Tag: | Revision:

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

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 92d2d1ce Christos Stavrakakis
from synnefo.db import query as db_query
47 41a7fae7 Christos Stavrakakis
from synnefo.db.models import (VirtualMachine, VirtualMachineMetadata)
48 41a7fae7 Christos Stavrakakis
from synnefo.logic import servers, utils as logic_utils
49 9e98ba3c Giorgos Verigakis
50 bf5c82dc Christos Stavrakakis
from logging import getLogger
51 b3fd98ae Christos Stavrakakis
log = getLogger(__name__)
52 7e2f9d4b Giorgos Verigakis
53 e440e835 Christos Stavrakakis
urlpatterns = patterns(
54 e440e835 Christos Stavrakakis
    'synnefo.api.servers',
55 7e2f9d4b Giorgos Verigakis
    (r'^(?:/|.json|.xml)?$', 'demux'),
56 7e2f9d4b Giorgos Verigakis
    (r'^/detail(?:.json|.xml)?$', 'list_servers', {'detail': True}),
57 7e2f9d4b Giorgos Verigakis
    (r'^/(\d+)(?:.json|.xml)?$', 'server_demux'),
58 41a7fae7 Christos Stavrakakis
    (r'^/(\d+)/action(?:.json|.xml)?$', 'demux_server_action'),
59 b016b476 Giorgos Verigakis
    (r'^/(\d+)/ips(?:.json|.xml)?$', 'list_addresses'),
60 b016b476 Giorgos Verigakis
    (r'^/(\d+)/ips/(.+?)(?:.json|.xml)?$', 'list_addresses_by_network'),
61 8a992938 Christos Stavrakakis
    (r'^/(\d+)/metadata(?:.json|.xml)?$', 'metadata_demux'),
62 8a992938 Christos Stavrakakis
    (r'^/(\d+)/metadata/(.+?)(?:.json|.xml)?$', 'metadata_item_demux'),
63 c738c935 Giorgos Verigakis
    (r'^/(\d+)/stats(?:.json|.xml)?$', 'server_stats'),
64 85a634e6 Kostas Papadimitriou
    (r'^/(\d+)/diagnostics(?:.json)?$', 'get_server_diagnostics'),
65 7e2f9d4b Giorgos Verigakis
)
66 7e2f9d4b Giorgos Verigakis
67 7e2f9d4b Giorgos Verigakis
68 7e2f9d4b Giorgos Verigakis
def demux(request):
69 7e2f9d4b Giorgos Verigakis
    if request.method == 'GET':
70 7e2f9d4b Giorgos Verigakis
        return list_servers(request)
71 7e2f9d4b Giorgos Verigakis
    elif request.method == 'POST':
72 7e2f9d4b Giorgos Verigakis
        return create_server(request)
73 7e2f9d4b Giorgos Verigakis
    else:
74 c0720b78 Kostas Papadimitriou
        return api.api_method_not_allowed(request)
75 7e2f9d4b Giorgos Verigakis
76 55cd40be Vangelis Koukis
77 7e2f9d4b Giorgos Verigakis
def server_demux(request, server_id):
78 7e2f9d4b Giorgos Verigakis
    if request.method == 'GET':
79 7e2f9d4b Giorgos Verigakis
        return get_server_details(request, server_id)
80 7e2f9d4b Giorgos Verigakis
    elif request.method == 'PUT':
81 7e2f9d4b Giorgos Verigakis
        return update_server_name(request, server_id)
82 7e2f9d4b Giorgos Verigakis
    elif request.method == 'DELETE':
83 7e2f9d4b Giorgos Verigakis
        return delete_server(request, server_id)
84 7e2f9d4b Giorgos Verigakis
    else:
85 c0720b78 Kostas Papadimitriou
        return api.api_method_not_allowed(request)
86 d8e50a39 Giorgos Verigakis
87 55cd40be Vangelis Koukis
88 d8e50a39 Giorgos Verigakis
def metadata_demux(request, server_id):
89 d8e50a39 Giorgos Verigakis
    if request.method == 'GET':
90 d8e50a39 Giorgos Verigakis
        return list_metadata(request, server_id)
91 d8e50a39 Giorgos Verigakis
    elif request.method == 'POST':
92 d8e50a39 Giorgos Verigakis
        return update_metadata(request, server_id)
93 d8e50a39 Giorgos Verigakis
    else:
94 c0720b78 Kostas Papadimitriou
        return api.api_method_not_allowed(request)
95 d8e50a39 Giorgos Verigakis
96 55cd40be Vangelis Koukis
97 d8e50a39 Giorgos Verigakis
def metadata_item_demux(request, server_id, key):
98 d8e50a39 Giorgos Verigakis
    if request.method == 'GET':
99 d8e50a39 Giorgos Verigakis
        return get_metadata_item(request, server_id, key)
100 d8e50a39 Giorgos Verigakis
    elif request.method == 'PUT':
101 d8e50a39 Giorgos Verigakis
        return create_metadata_item(request, server_id, key)
102 d8e50a39 Giorgos Verigakis
    elif request.method == 'DELETE':
103 d8e50a39 Giorgos Verigakis
        return delete_metadata_item(request, server_id, key)
104 d8e50a39 Giorgos Verigakis
    else:
105 c0720b78 Kostas Papadimitriou
        return api.api_method_not_allowed(request)
106 7e2f9d4b Giorgos Verigakis
107 08b079e2 Stavros Sachtouris
108 7fede91e Christos Stavrakakis
def nic_to_dict(nic):
109 c988fcca Christos Stavrakakis
    d = {'id': nic.id,
110 7fede91e Christos Stavrakakis
         'network_id': str(nic.network.id),
111 7fede91e Christos Stavrakakis
         'mac_address': nic.mac,
112 92d2d1ce Christos Stavrakakis
         'ipv4': '',
113 92d2d1ce Christos Stavrakakis
         'ipv6': ''}
114 92d2d1ce Christos Stavrakakis
    for ip in nic.ips.filter(deleted=False).select_related("subnet"):
115 92d2d1ce Christos Stavrakakis
        ip_type = "floating" if ip.floating_ip else "fixed"
116 92d2d1ce Christos Stavrakakis
        if ip.subnet.ipversion == 4:
117 92d2d1ce Christos Stavrakakis
            d["ipv4"] = ip.address
118 92d2d1ce Christos Stavrakakis
            d["OS-EXT-IPS:type"] = ip_type
119 92d2d1ce Christos Stavrakakis
        else:
120 92d2d1ce Christos Stavrakakis
            d["ipv6"] = ip.address
121 92d2d1ce Christos Stavrakakis
            d["OS-EXT-IPS:type"] = ip_type
122 47c66641 Dimitris Aragiorgis
123 207b70d5 Giorgos Verigakis
    if nic.firewall_profile:
124 207b70d5 Giorgos Verigakis
        d['firewallProfile'] = nic.firewall_profile
125 d44c236b Giorgos Verigakis
    return d
126 b016b476 Giorgos Verigakis
127 55cd40be Vangelis Koukis
128 78c165cf Christos Stavrakakis
def attachments_to_addresses(attachments):
129 1f638a85 Christos Stavrakakis
    addresses = {}
130 78c165cf Christos Stavrakakis
    for nic in attachments:
131 1f638a85 Christos Stavrakakis
        net_nics = []
132 92d2d1ce Christos Stavrakakis
        if nic["ipv4"]:
133 92d2d1ce Christos Stavrakakis
            net_nics.append({"version": 4,
134 92d2d1ce Christos Stavrakakis
                             "addr": nic["ipv4"],
135 92d2d1ce Christos Stavrakakis
                             "OS-EXT-IPS:type": nic["OS-EXT-IPS:type"]})
136 78c165cf Christos Stavrakakis
        if nic["ipv6"]:
137 f8352d29 Christos Stavrakakis
            net_nics.append({"version": 6,
138 78c165cf Christos Stavrakakis
                             "addr": nic["ipv6"],
139 78c165cf Christos Stavrakakis
                             "OS-EXT-IPS:type": nic["OS-EXT-IPS:type"]})
140 78c165cf Christos Stavrakakis
        addresses[nic["network_id"]] = net_nics
141 1f638a85 Christos Stavrakakis
    return addresses
142 1f638a85 Christos Stavrakakis
143 1f638a85 Christos Stavrakakis
144 d8e50a39 Giorgos Verigakis
def vm_to_dict(vm, detail=False):
145 d8e50a39 Giorgos Verigakis
    d = dict(id=vm.id, name=vm.name)
146 1b696c26 Christos Stavrakakis
    d['links'] = util.vm_to_links(vm.id)
147 7e2f9d4b Giorgos Verigakis
    if detail:
148 936e0be3 Christos Stavrakakis
        d['user_id'] = vm.userid
149 936e0be3 Christos Stavrakakis
        d['tenant_id'] = vm.userid
150 41a7fae7 Christos Stavrakakis
        d['status'] = logic_utils.get_rsapi_state(vm)
151 41a7fae7 Christos Stavrakakis
        d['SNF:task_state'] = logic_utils.get_task_state(vm)
152 41a7fae7 Christos Stavrakakis
        d['progress'] = 100 if d['status'] == 'ACTIVE' else vm.buildpercentage
153 d8e50a39 Giorgos Verigakis
        d['hostId'] = vm.hostid
154 b3fd98ae Christos Stavrakakis
        d['updated'] = utils.isoformat(vm.updated)
155 b3fd98ae Christos Stavrakakis
        d['created'] = utils.isoformat(vm.created)
156 1b696c26 Christos Stavrakakis
        d['flavor'] = {"id": vm.flavor.id,
157 1b696c26 Christos Stavrakakis
                       "links": util.flavor_to_links(vm.flavor.id)}
158 1b696c26 Christos Stavrakakis
        d['image'] = {"id": vm.imageid,
159 1b696c26 Christos Stavrakakis
                      "links": util.image_to_links(vm.imageid)}
160 e221ade2 Christos Stavrakakis
        d['suspended'] = vm.suspended
161 ce55f211 Kostas Papadimitriou
162 7cc3c7d9 Giorgos Verigakis
        metadata = dict((m.meta_key, m.meta_value) for m in vm.metadata.all())
163 1b696c26 Christos Stavrakakis
        d['metadata'] = metadata
164 aa197ee4 Vangelis Koukis
165 7c714455 Christos Stavrakakis
        vm_nics = vm.nics.filter(state="ACTIVE").order_by("id")
166 939d71dd Christos Stavrakakis
        attachments = map(nic_to_dict, vm_nics)
167 5029ff36 Christos Stavrakakis
        d['attachments'] = attachments
168 78c165cf Christos Stavrakakis
        d['addresses'] = attachments_to_addresses(attachments)
169 85a634e6 Kostas Papadimitriou
170 85a634e6 Kostas Papadimitriou
        # include the latest vm diagnostic, if set
171 85a634e6 Kostas Papadimitriou
        diagnostic = vm.get_last_diagnostic()
172 85a634e6 Kostas Papadimitriou
        if diagnostic:
173 85a634e6 Kostas Papadimitriou
            d['diagnostics'] = diagnostics_to_dict([diagnostic])
174 1b696c26 Christos Stavrakakis
        else:
175 1b696c26 Christos Stavrakakis
            d['diagnostics'] = []
176 f8352d29 Christos Stavrakakis
        # Fixed
177 f8352d29 Christos Stavrakakis
        d["security_groups"] = [{"name": "default"}]
178 f8352d29 Christos Stavrakakis
        d["key_name"] = None
179 f8352d29 Christos Stavrakakis
        d["config_drive"] = ""
180 f8352d29 Christos Stavrakakis
        d["accessIPv4"] = ""
181 f8352d29 Christos Stavrakakis
        d["accessIPv6"] = ""
182 2522e489 Christos Stavrakakis
        fqdn = get_server_fqdn(vm)
183 2522e489 Christos Stavrakakis
        d["SNF:fqdn"] = fqdn
184 2522e489 Christos Stavrakakis
        d["SNF:port_forwarding"] = get_server_port_forwarding(vm, fqdn)
185 85a634e6 Kostas Papadimitriou
186 7e2f9d4b Giorgos Verigakis
    return d
187 7e2f9d4b Giorgos Verigakis
188 d8e50a39 Giorgos Verigakis
189 d328a525 Christos Stavrakakis
def get_server_fqdn(vm):
190 d328a525 Christos Stavrakakis
    fqdn_setting = settings.CYCLADES_SERVERS_FQDN
191 d328a525 Christos Stavrakakis
    if fqdn_setting is None:
192 d328a525 Christos Stavrakakis
        # Return the first public IPv4 address if exists
193 92d2d1ce Christos Stavrakakis
        address = db_query.get_server_public_ip(server=vm, version=4)
194 92d2d1ce Christos Stavrakakis
        if address is None:
195 92d2d1ce Christos Stavrakakis
            # Else return the first public IPv6 address if exists
196 92d2d1ce Christos Stavrakakis
            address = db_query.get_server_public_ip(server=vm, version=6)
197 92d2d1ce Christos Stavrakakis
        if address is None:
198 92d2d1ce Christos Stavrakakis
            return ""
199 92d2d1ce Christos Stavrakakis
        else:
200 92d2d1ce Christos Stavrakakis
            return address
201 d328a525 Christos Stavrakakis
    elif isinstance(fqdn_setting, basestring):
202 d328a525 Christos Stavrakakis
        return fqdn_setting % {"id": vm.id}
203 d328a525 Christos Stavrakakis
    else:
204 d328a525 Christos Stavrakakis
        msg = ("Invalid setting: CYCLADES_SERVERS_FQDN."
205 d328a525 Christos Stavrakakis
               " Value must be a string.")
206 d328a525 Christos Stavrakakis
        raise faults.InternalServerError(msg)
207 d328a525 Christos Stavrakakis
208 d328a525 Christos Stavrakakis
209 2522e489 Christos Stavrakakis
def get_server_port_forwarding(vm, fqdn):
210 2522e489 Christos Stavrakakis
    """Create API 'port_forwarding' attribute from corresponding setting.
211 2522e489 Christos Stavrakakis

212 2522e489 Christos Stavrakakis
    Create the 'port_forwarding' API vm attribute based on the corresponding
213 2522e489 Christos Stavrakakis
    setting (CYCLADES_PORT_FORWARDING), which can be either a tuple
214 2522e489 Christos Stavrakakis
    of the form (host, port) or a callable object returning such tuple. In
215 2522e489 Christos Stavrakakis
    case of callable object, must be called with the following arguments:
216 2522e489 Christos Stavrakakis
    * ip_address
217 2522e489 Christos Stavrakakis
    * server_id
218 2522e489 Christos Stavrakakis
    * fqdn
219 2522e489 Christos Stavrakakis
    * owner UUID
220 2522e489 Christos Stavrakakis

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