Statistics
| Branch: | Tag: | Revision:

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

History | View | Annotate | Download (32.6 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 b3a43976 Christos Stavrakakis
def nic_to_attachments(nic):
108 b3a43976 Christos Stavrakakis
    """Convert a NIC object to 'attachments attribute.
109 b3a43976 Christos Stavrakakis

110 b3a43976 Christos Stavrakakis
    Convert a NIC object to match the format of 'attachments' attribute of the
111 b3a43976 Christos Stavrakakis
    response to the /servers API call.
112 b3a43976 Christos Stavrakakis

113 b3a43976 Christos Stavrakakis
    NOTE: The 'ips' of the NIC object have been prefetched in order to avoid DB
114 b3a43976 Christos Stavrakakis
    queries. No subsequent queries for 'ips' (like filtering) should be
115 b3a43976 Christos Stavrakakis
    performed because this will return in a new DB query.
116 b3a43976 Christos Stavrakakis

117 b3a43976 Christos Stavrakakis
    """
118 c988fcca Christos Stavrakakis
    d = {'id': nic.id,
119 b3a43976 Christos Stavrakakis
         'network_id': str(nic.network_id),
120 7fede91e Christos Stavrakakis
         'mac_address': nic.mac,
121 92d2d1ce Christos Stavrakakis
         'ipv4': '',
122 92d2d1ce Christos Stavrakakis
         'ipv6': ''}
123 47c66641 Dimitris Aragiorgis
124 207b70d5 Giorgos Verigakis
    if nic.firewall_profile:
125 207b70d5 Giorgos Verigakis
        d['firewallProfile'] = nic.firewall_profile
126 b3a43976 Christos Stavrakakis
127 b3a43976 Christos Stavrakakis
    for ip in nic.ips.all():
128 b3a43976 Christos Stavrakakis
        if not ip.deleted:
129 b3a43976 Christos Stavrakakis
            ip_type = "floating" if ip.floating_ip else "fixed"
130 b3a43976 Christos Stavrakakis
            if ip.ipversion == 4:
131 b3a43976 Christos Stavrakakis
                d["ipv4"] = ip.address
132 b3a43976 Christos Stavrakakis
                d["OS-EXT-IPS:type"] = ip_type
133 b3a43976 Christos Stavrakakis
            else:
134 b3a43976 Christos Stavrakakis
                d["ipv6"] = ip.address
135 b3a43976 Christos Stavrakakis
                d["OS-EXT-IPS:type"] = ip_type
136 d44c236b Giorgos Verigakis
    return d
137 b016b476 Giorgos Verigakis
138 55cd40be Vangelis Koukis
139 78c165cf Christos Stavrakakis
def attachments_to_addresses(attachments):
140 b3a43976 Christos Stavrakakis
    """Convert 'attachments' attribute to 'addresses'.
141 b3a43976 Christos Stavrakakis

142 b3a43976 Christos Stavrakakis
    Convert a a list of 'attachments' attribute to a list of 'addresses'
143 b3a43976 Christos Stavrakakis
    attribute, as expected in the response to /servers API call.
144 b3a43976 Christos Stavrakakis

145 b3a43976 Christos Stavrakakis
    """
146 1f638a85 Christos Stavrakakis
    addresses = {}
147 78c165cf Christos Stavrakakis
    for nic in attachments:
148 b3a43976 Christos Stavrakakis
        net_addrs = []
149 92d2d1ce Christos Stavrakakis
        if nic["ipv4"]:
150 b3a43976 Christos Stavrakakis
            net_addrs.append({"version": 4,
151 b3a43976 Christos Stavrakakis
                              "addr": nic["ipv4"],
152 b3a43976 Christos Stavrakakis
                              "OS-EXT-IPS:type": nic["OS-EXT-IPS:type"]})
153 78c165cf Christos Stavrakakis
        if nic["ipv6"]:
154 b3a43976 Christos Stavrakakis
            net_addrs.append({"version": 6,
155 b3a43976 Christos Stavrakakis
                              "addr": nic["ipv6"],
156 b3a43976 Christos Stavrakakis
                              "OS-EXT-IPS:type": nic["OS-EXT-IPS:type"]})
157 b3a43976 Christos Stavrakakis
        addresses[nic["network_id"]] = net_addrs
158 1f638a85 Christos Stavrakakis
    return addresses
159 1f638a85 Christos Stavrakakis
160 1f638a85 Christos Stavrakakis
161 d8e50a39 Giorgos Verigakis
def vm_to_dict(vm, detail=False):
162 d8e50a39 Giorgos Verigakis
    d = dict(id=vm.id, name=vm.name)
163 1b696c26 Christos Stavrakakis
    d['links'] = util.vm_to_links(vm.id)
164 7e2f9d4b Giorgos Verigakis
    if detail:
165 936e0be3 Christos Stavrakakis
        d['user_id'] = vm.userid
166 936e0be3 Christos Stavrakakis
        d['tenant_id'] = vm.userid
167 41a7fae7 Christos Stavrakakis
        d['status'] = logic_utils.get_rsapi_state(vm)
168 41a7fae7 Christos Stavrakakis
        d['SNF:task_state'] = logic_utils.get_task_state(vm)
169 41a7fae7 Christos Stavrakakis
        d['progress'] = 100 if d['status'] == 'ACTIVE' else vm.buildpercentage
170 d8e50a39 Giorgos Verigakis
        d['hostId'] = vm.hostid
171 b3fd98ae Christos Stavrakakis
        d['updated'] = utils.isoformat(vm.updated)
172 b3fd98ae Christos Stavrakakis
        d['created'] = utils.isoformat(vm.created)
173 1b696c26 Christos Stavrakakis
        d['flavor'] = {"id": vm.flavor.id,
174 1b696c26 Christos Stavrakakis
                       "links": util.flavor_to_links(vm.flavor.id)}
175 1b696c26 Christos Stavrakakis
        d['image'] = {"id": vm.imageid,
176 1b696c26 Christos Stavrakakis
                      "links": util.image_to_links(vm.imageid)}
177 e221ade2 Christos Stavrakakis
        d['suspended'] = vm.suspended
178 ce55f211 Kostas Papadimitriou
179 7cc3c7d9 Giorgos Verigakis
        metadata = dict((m.meta_key, m.meta_value) for m in vm.metadata.all())
180 1b696c26 Christos Stavrakakis
        d['metadata'] = metadata
181 aa197ee4 Vangelis Koukis
182 b3a43976 Christos Stavrakakis
        nics = vm.nics.all()
183 b3a43976 Christos Stavrakakis
        active_nics = filter(lambda nic: nic.state == "ACTIVE", nics)
184 b3a43976 Christos Stavrakakis
        active_nics.sort(key=lambda nic: nic.id)
185 b3a43976 Christos Stavrakakis
        attachments = map(nic_to_attachments, active_nics)
186 5029ff36 Christos Stavrakakis
        d['attachments'] = attachments
187 78c165cf Christos Stavrakakis
        d['addresses'] = attachments_to_addresses(attachments)
188 85a634e6 Kostas Papadimitriou
189 85a634e6 Kostas Papadimitriou
        # include the latest vm diagnostic, if set
190 85a634e6 Kostas Papadimitriou
        diagnostic = vm.get_last_diagnostic()
191 85a634e6 Kostas Papadimitriou
        if diagnostic:
192 85a634e6 Kostas Papadimitriou
            d['diagnostics'] = diagnostics_to_dict([diagnostic])
193 1b696c26 Christos Stavrakakis
        else:
194 1b696c26 Christos Stavrakakis
            d['diagnostics'] = []
195 f8352d29 Christos Stavrakakis
        # Fixed
196 f8352d29 Christos Stavrakakis
        d["security_groups"] = [{"name": "default"}]
197 f8352d29 Christos Stavrakakis
        d["key_name"] = None
198 f8352d29 Christos Stavrakakis
        d["config_drive"] = ""
199 f8352d29 Christos Stavrakakis
        d["accessIPv4"] = ""
200 f8352d29 Christos Stavrakakis
        d["accessIPv6"] = ""
201 b3a43976 Christos Stavrakakis
        fqdn = get_server_fqdn(vm, active_nics)
202 2522e489 Christos Stavrakakis
        d["SNF:fqdn"] = fqdn
203 b3a43976 Christos Stavrakakis
        d["SNF:port_forwarding"] = get_server_port_forwarding(vm, active_nics,
204 b3a43976 Christos Stavrakakis
                                                              fqdn)
205 7e2f9d4b Giorgos Verigakis
    return d
206 7e2f9d4b Giorgos Verigakis
207 d8e50a39 Giorgos Verigakis
208 b3a43976 Christos Stavrakakis
def get_server_public_ip(vm_nics, version=4):
209 b3a43976 Christos Stavrakakis
    """Get the first public IP address of a server.
210 b3a43976 Christos Stavrakakis

211 b3a43976 Christos Stavrakakis
    NOTE: 'vm_nics' objects have prefetched the ips
212 b3a43976 Christos Stavrakakis
    """
213 b3a43976 Christos Stavrakakis
    for version in [4, 6]:
214 b3a43976 Christos Stavrakakis
        for nic in vm_nics:
215 b3a43976 Christos Stavrakakis
            for ip in nic.ips.all():
216 b3a43976 Christos Stavrakakis
                if ip.ipversion == version and ip.public:
217 b3a43976 Christos Stavrakakis
                    return ip
218 b3a43976 Christos Stavrakakis
    return None
219 b3a43976 Christos Stavrakakis
220 b3a43976 Christos Stavrakakis
221 b3a43976 Christos Stavrakakis
def get_server_fqdn(vm, vm_nics):
222 b3a43976 Christos Stavrakakis
    public_ip = get_server_public_ip(vm_nics)
223 b3a43976 Christos Stavrakakis
    if public_ip is None:
224 b3a43976 Christos Stavrakakis
        return ""
225 b3a43976 Christos Stavrakakis
226 d328a525 Christos Stavrakakis
    fqdn_setting = settings.CYCLADES_SERVERS_FQDN
227 d328a525 Christos Stavrakakis
    if fqdn_setting is None:
228 b3a43976 Christos Stavrakakis
        return public_ip.address
229 d328a525 Christos Stavrakakis
    elif isinstance(fqdn_setting, basestring):
230 d328a525 Christos Stavrakakis
        return fqdn_setting % {"id": vm.id}
231 d328a525 Christos Stavrakakis
    else:
232 d328a525 Christos Stavrakakis
        msg = ("Invalid setting: CYCLADES_SERVERS_FQDN."
233 d328a525 Christos Stavrakakis
               " Value must be a string.")
234 d328a525 Christos Stavrakakis
        raise faults.InternalServerError(msg)
235 d328a525 Christos Stavrakakis
236 d328a525 Christos Stavrakakis
237 b3a43976 Christos Stavrakakis
def get_server_port_forwarding(vm, vm_nics, fqdn):
238 2522e489 Christos Stavrakakis
    """Create API 'port_forwarding' attribute from corresponding setting.
239 2522e489 Christos Stavrakakis

240 2522e489 Christos Stavrakakis
    Create the 'port_forwarding' API vm attribute based on the corresponding
241 2522e489 Christos Stavrakakis
    setting (CYCLADES_PORT_FORWARDING), which can be either a tuple
242 2522e489 Christos Stavrakakis
    of the form (host, port) or a callable object returning such tuple. In
243 2522e489 Christos Stavrakakis
    case of callable object, must be called with the following arguments:
244 2522e489 Christos Stavrakakis
    * ip_address
245 2522e489 Christos Stavrakakis
    * server_id
246 2522e489 Christos Stavrakakis
    * fqdn
247 2522e489 Christos Stavrakakis
    * owner UUID
248 2522e489 Christos Stavrakakis

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