Statistics
| Branch: | Tag: | Revision:

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

History | View | Annotate | Download (33.3 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 2aba7764 Sofia Papagiannaki
        return api.api_method_not_allowed(request,
74 2aba7764 Sofia Papagiannaki
                                          allowed_methods=['GET', 'POST'])
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 2aba7764 Sofia Papagiannaki
        return api.api_method_not_allowed(request,
86 2aba7764 Sofia Papagiannaki
                                          allowed_methods=['GET',
87 2aba7764 Sofia Papagiannaki
                                                           'PUT',
88 2aba7764 Sofia Papagiannaki
                                                           'DELETE'])
89 d8e50a39 Giorgos Verigakis
90 55cd40be Vangelis Koukis
91 d8e50a39 Giorgos Verigakis
def metadata_demux(request, server_id):
92 d8e50a39 Giorgos Verigakis
    if request.method == 'GET':
93 d8e50a39 Giorgos Verigakis
        return list_metadata(request, server_id)
94 d8e50a39 Giorgos Verigakis
    elif request.method == 'POST':
95 d8e50a39 Giorgos Verigakis
        return update_metadata(request, server_id)
96 d8e50a39 Giorgos Verigakis
    else:
97 2aba7764 Sofia Papagiannaki
        return api.api_method_not_allowed(request,
98 2aba7764 Sofia Papagiannaki
                                          allowed_methods=['GET', 'POST'])
99 d8e50a39 Giorgos Verigakis
100 55cd40be Vangelis Koukis
101 d8e50a39 Giorgos Verigakis
def metadata_item_demux(request, server_id, key):
102 d8e50a39 Giorgos Verigakis
    if request.method == 'GET':
103 d8e50a39 Giorgos Verigakis
        return get_metadata_item(request, server_id, key)
104 d8e50a39 Giorgos Verigakis
    elif request.method == 'PUT':
105 d8e50a39 Giorgos Verigakis
        return create_metadata_item(request, server_id, key)
106 d8e50a39 Giorgos Verigakis
    elif request.method == 'DELETE':
107 d8e50a39 Giorgos Verigakis
        return delete_metadata_item(request, server_id, key)
108 d8e50a39 Giorgos Verigakis
    else:
109 2aba7764 Sofia Papagiannaki
        return api.api_method_not_allowed(request,
110 2aba7764 Sofia Papagiannaki
                                          allowed_methods=['GET',
111 2aba7764 Sofia Papagiannaki
                                                           'PUT',
112 2aba7764 Sofia Papagiannaki
                                                           'DELETE'])
113 7e2f9d4b Giorgos Verigakis
114 08b079e2 Stavros Sachtouris
115 b3a43976 Christos Stavrakakis
def nic_to_attachments(nic):
116 b3a43976 Christos Stavrakakis
    """Convert a NIC object to 'attachments attribute.
117 b3a43976 Christos Stavrakakis

118 b3a43976 Christos Stavrakakis
    Convert a NIC object to match the format of 'attachments' attribute of the
119 b3a43976 Christos Stavrakakis
    response to the /servers API call.
120 b3a43976 Christos Stavrakakis

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

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

150 b3a43976 Christos Stavrakakis
    Convert a a list of 'attachments' attribute to a list of 'addresses'
151 b3a43976 Christos Stavrakakis
    attribute, as expected in the response to /servers API call.
152 b3a43976 Christos Stavrakakis

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

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

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

252 b3a43976 Christos Stavrakakis
    NOTE: 'vm_nics' objects have prefetched the ips
253 2522e489 Christos Stavrakakis
    """
254 2522e489 Christos Stavrakakis
    port_forwarding = {}
255 b3a43976 Christos Stavrakakis
    public_ip = get_server_public_ip(vm_nics)
256 b3a43976 Christos Stavrakakis
    if public_ip is None:
257 b3a43976 Christos Stavrakakis
        return port_forwarding
258 2522e489 Christos Stavrakakis
    for dport, to_dest in settings.CYCLADES_PORT_FORWARDING.items():
259 2522e489 Christos Stavrakakis
        if hasattr(to_dest, "__call__"):
260 b3a43976 Christos Stavrakakis
            to_dest = to_dest(public_ip.address, vm.id, fqdn, vm.userid)
261 2522e489 Christos Stavrakakis
        msg = ("Invalid setting: CYCLADES_PORT_FOWARDING."
262 2522e489 Christos Stavrakakis
               " Value must be a tuple of two elements (host, port).")
263 2522e489 Christos Stavrakakis
        if not isinstance(to_dest, tuple) or len(to_dest) != 2:
264 2522e489 Christos Stavrakakis
                raise faults.InternalServerError(msg)
265 2522e489 Christos Stavrakakis
        else:
266 2522e489 Christos Stavrakakis
            try:
267 2522e489 Christos Stavrakakis
                host, port = to_dest
268 2522e489 Christos Stavrakakis
            except (TypeError, ValueError):
269 2522e489 Christos Stavrakakis
                raise faults.InternalServerError(msg)
270 2522e489 Christos Stavrakakis
271 2522e489 Christos Stavrakakis
        port_forwarding[dport] = {"host": host, "port": str(port)}
272 2522e489 Christos Stavrakakis
    return port_forwarding
273 2522e489 Christos Stavrakakis
274 2522e489 Christos Stavrakakis
275 85a634e6 Kostas Papadimitriou
def diagnostics_to_dict(diagnostics):
276 85a634e6 Kostas Papadimitriou
    """
277 85a634e6 Kostas Papadimitriou
    Extract api data from diagnostics QuerySet.
278 85a634e6 Kostas Papadimitriou
    """
279 85a634e6 Kostas Papadimitriou
    entries = list()
280 85a634e6 Kostas Papadimitriou
281 85a634e6 Kostas Papadimitriou
    for diagnostic in diagnostics:
282 85a634e6 Kostas Papadimitriou
        # format source date if set
283 85a634e6 Kostas Papadimitriou
        formatted_source_date = None
284 85a634e6 Kostas Papadimitriou
        if diagnostic.source_date:
285 b3fd98ae Christos Stavrakakis
            formatted_source_date = utils.isoformat(diagnostic.source_date)
286 85a634e6 Kostas Papadimitriou
287 85a634e6 Kostas Papadimitriou
        entry = {
288 85a634e6 Kostas Papadimitriou
            'source': diagnostic.source,
289 b3fd98ae Christos Stavrakakis
            'created': utils.isoformat(diagnostic.created),
290 85a634e6 Kostas Papadimitriou
            'message': diagnostic.message,
291 85a634e6 Kostas Papadimitriou
            'details': diagnostic.details,
292 85a634e6 Kostas Papadimitriou
            'level': diagnostic.level,
293 85a634e6 Kostas Papadimitriou
        }
294 85a634e6 Kostas Papadimitriou
295 85a634e6 Kostas Papadimitriou
        if formatted_source_date:
296 85a634e6 Kostas Papadimitriou
            entry['source_date'] = formatted_source_date
297 85a634e6 Kostas Papadimitriou
298 85a634e6 Kostas Papadimitriou
        entries.append(entry)
299 85a634e6 Kostas Papadimitriou
300 85a634e6 Kostas Papadimitriou
    return entries
301 85a634e6 Kostas Papadimitriou
302 85a634e6 Kostas Papadimitriou
303 d8e50a39 Giorgos Verigakis
def render_server(request, server, status=200):
304 d8e50a39 Giorgos Verigakis
    if request.serialization == 'xml':
305 b36f78fa Giorgos Verigakis
        data = render_to_string('server.xml', {
306 b36f78fa Giorgos Verigakis
            'server': server,
307 b36f78fa Giorgos Verigakis
            'is_root': True})
308 7e2f9d4b Giorgos Verigakis
    else:
309 d8e50a39 Giorgos Verigakis
        data = json.dumps({'server': server})
310 c36934a7 Giorgos Verigakis
    return HttpResponse(data, status=status)
311 aa197ee4 Vangelis Koukis
312 7e2f9d4b Giorgos Verigakis
313 85a634e6 Kostas Papadimitriou
def render_diagnostics(request, diagnostics_dict, status=200):
314 85a634e6 Kostas Papadimitriou
    """
315 85a634e6 Kostas Papadimitriou
    Render diagnostics dictionary to json response.
316 85a634e6 Kostas Papadimitriou
    """
317 85a634e6 Kostas Papadimitriou
    return HttpResponse(json.dumps(diagnostics_dict), status=status)
318 85a634e6 Kostas Papadimitriou
319 85a634e6 Kostas Papadimitriou
320 b3fd98ae Christos Stavrakakis
@api.api_method(http_method='GET', user_required=True, logger=log)
321 85a634e6 Kostas Papadimitriou
def get_server_diagnostics(request, server_id):
322 85a634e6 Kostas Papadimitriou
    """
323 85a634e6 Kostas Papadimitriou
    Virtual machine diagnostics api view.
324 85a634e6 Kostas Papadimitriou
    """
325 85a634e6 Kostas Papadimitriou
    log.debug('server_diagnostics %s', server_id)
326 85a634e6 Kostas Papadimitriou
    vm = util.get_vm(server_id, request.user_uniq)
327 85a634e6 Kostas Papadimitriou
    diagnostics = diagnostics_to_dict(vm.diagnostics.all())
328 85a634e6 Kostas Papadimitriou
    return render_diagnostics(request, diagnostics)
329 85a634e6 Kostas Papadimitriou
330 85a634e6 Kostas Papadimitriou
331 b3fd98ae Christos Stavrakakis
@api.api_method(http_method='GET', user_required=True, logger=log)
332 7e2f9d4b Giorgos Verigakis
def list_servers(request, detail=False):
333 7e2f9d4b Giorgos Verigakis
    # Normal Response Codes: 200, 203
334 7e2f9d4b Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
335 7e2f9d4b Giorgos Verigakis
    #                       serviceUnavailable (503),
336 7e2f9d4b Giorgos Verigakis
    #                       unauthorized (401),
337 7e2f9d4b Giorgos Verigakis
    #                       badRequest (400),
338 7e2f9d4b Giorgos Verigakis
    #                       overLimit (413)
339 ce55f211 Kostas Papadimitriou
340 0c37a721 Christos Stavrakakis
    log.debug('list_servers detail=%s', detail)
341 e524ed5f Kostas Papadimitriou
    user_vms = VirtualMachine.objects.filter(userid=request.user_uniq)
342 b3a43976 Christos Stavrakakis
    if detail:
343 b3a43976 Christos Stavrakakis
        user_vms = user_vms.prefetch_related("nics__ips")
344 ce55f211 Kostas Papadimitriou
345 b6bc4afa Christos Stavrakakis
    user_vms = utils.filter_modified_since(request, objects=user_vms)
346 ce55f211 Kostas Papadimitriou
347 41a7fae7 Christos Stavrakakis
    servers_dict = [vm_to_dict(server, detail)
348 41a7fae7 Christos Stavrakakis
                    for server in user_vms.order_by('id')]
349 aa197ee4 Vangelis Koukis
350 d8e50a39 Giorgos Verigakis
    if request.serialization == 'xml':
351 b36f78fa Giorgos Verigakis
        data = render_to_string('list_servers.xml', {
352 41a7fae7 Christos Stavrakakis
            'servers': servers_dict,
353 b36f78fa Giorgos Verigakis
            'detail': detail})
354 7e2f9d4b Giorgos Verigakis
    else:
355 41a7fae7 Christos Stavrakakis
        data = json.dumps({'servers': servers_dict})
356 aa197ee4 Vangelis Koukis
357 c36934a7 Giorgos Verigakis
    return HttpResponse(data, status=200)
358 7e2f9d4b Giorgos Verigakis
359 55cd40be Vangelis Koukis
360 b3fd98ae Christos Stavrakakis
@api.api_method(http_method='POST', user_required=True, logger=log)
361 2509ce17 Christos Stavrakakis
def create_server(request):
362 7e2f9d4b Giorgos Verigakis
    # Normal Response Code: 202
363 7e2f9d4b Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
364 7e2f9d4b Giorgos Verigakis
    #                       serviceUnavailable (503),
365 7e2f9d4b Giorgos Verigakis
    #                       unauthorized (401),
366 7e2f9d4b Giorgos Verigakis
    #                       badMediaType(415),
367 7e2f9d4b Giorgos Verigakis
    #                       itemNotFound (404),
368 7e2f9d4b Giorgos Verigakis
    #                       badRequest (400),
369 7e2f9d4b Giorgos Verigakis
    #                       serverCapacityUnavailable (503),
370 7e2f9d4b Giorgos Verigakis
    #                       overLimit (413)
371 bcd80cd9 Christos Stavrakakis
    req = utils.get_request_dict(request)
372 bcd80cd9 Christos Stavrakakis
    log.info('create_server %s', req)
373 bcd80cd9 Christos Stavrakakis
    user_id = request.user_uniq
374 bcd80cd9 Christos Stavrakakis
375 7e2f9d4b Giorgos Verigakis
    try:
376 bcd80cd9 Christos Stavrakakis
        server = req['server']
377 bcd80cd9 Christos Stavrakakis
        name = server['name']
378 bcd80cd9 Christos Stavrakakis
        metadata = server.get('metadata', {})
379 bcd80cd9 Christos Stavrakakis
        assert isinstance(metadata, dict)
380 bcd80cd9 Christos Stavrakakis
        image_id = server['imageRef']
381 bcd80cd9 Christos Stavrakakis
        flavor_id = server['flavorRef']
382 bcd80cd9 Christos Stavrakakis
        personality = server.get('personality', [])
383 bcd80cd9 Christos Stavrakakis
        assert isinstance(personality, list)
384 3aecadc8 Christos Stavrakakis
        networks = server.get("networks")
385 3aecadc8 Christos Stavrakakis
        if networks is not None:
386 3aecadc8 Christos Stavrakakis
            assert isinstance(networks, list)
387 bcd80cd9 Christos Stavrakakis
    except (KeyError, AssertionError):
388 bcd80cd9 Christos Stavrakakis
        raise faults.BadRequest("Malformed request")
389 bcd80cd9 Christos Stavrakakis
390 bcd80cd9 Christos Stavrakakis
    # Verify that personalities are well-formed
391 bcd80cd9 Christos Stavrakakis
    util.verify_personality(personality)
392 bcd80cd9 Christos Stavrakakis
    # Get image information
393 bcd80cd9 Christos Stavrakakis
    image = util.get_image_dict(image_id, user_id)
394 bcd80cd9 Christos Stavrakakis
    # Get flavor (ensure it is active)
395 bcd80cd9 Christos Stavrakakis
    flavor = util.get_flavor(flavor_id, include_deleted=False)
396 bcd80cd9 Christos Stavrakakis
    # Generate password
397 bcd80cd9 Christos Stavrakakis
    password = util.random_password()
398 bcd80cd9 Christos Stavrakakis
399 41a7fae7 Christos Stavrakakis
    vm = servers.create(user_id, name, password, flavor, image,
400 cb66110b Christos Stavrakakis
                        metadata=metadata, personality=personality,
401 d2c3c533 Christos Stavrakakis
                        networks=networks)
402 bcd80cd9 Christos Stavrakakis
403 bcd80cd9 Christos Stavrakakis
    server = vm_to_dict(vm, detail=True)
404 bcd80cd9 Christos Stavrakakis
    server['status'] = 'BUILD'
405 bcd80cd9 Christos Stavrakakis
    server['adminPass'] = password
406 bcd80cd9 Christos Stavrakakis
407 bcd80cd9 Christos Stavrakakis
    response = render_server(request, server, status=202)
408 4b8e03e5 Christos Stavrakakis
409 bcd80cd9 Christos Stavrakakis
    return response
410 bcd80cd9 Christos Stavrakakis
411 bcd80cd9 Christos Stavrakakis
412 b3fd98ae Christos Stavrakakis
@api.api_method(http_method='GET', user_required=True, logger=log)
413 7e2f9d4b Giorgos Verigakis
def get_server_details(request, server_id):
414 c36934a7 Giorgos Verigakis
    # Normal Response Codes: 200, 203
415 c36934a7 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
416 c36934a7 Giorgos Verigakis
    #                       serviceUnavailable (503),
417 c36934a7 Giorgos Verigakis
    #                       unauthorized (401),
418 c36934a7 Giorgos Verigakis
    #                       badRequest (400),
419 c36934a7 Giorgos Verigakis
    #                       itemNotFound (404),
420 c36934a7 Giorgos Verigakis
    #                       overLimit (413)
421 ce55f211 Kostas Papadimitriou
422 0c37a721 Christos Stavrakakis
    log.debug('get_server_details %s', server_id)
423 b3a43976 Christos Stavrakakis
    vm = util.get_vm(server_id, request.user_uniq,
424 b3a43976 Christos Stavrakakis
                     prefetch_related="nics__ips")
425 d8e50a39 Giorgos Verigakis
    server = vm_to_dict(vm, detail=True)
426 d8e50a39 Giorgos Verigakis
    return render_server(request, server)
427 7e2f9d4b Giorgos Verigakis
428 55cd40be Vangelis Koukis
429 b3fd98ae Christos Stavrakakis
@api.api_method(http_method='PUT', user_required=True, logger=log)
430 874383a4 Christos Stavrakakis
@transaction.commit_on_success
431 c36934a7 Giorgos Verigakis
def update_server_name(request, server_id):
432 c36934a7 Giorgos Verigakis
    # Normal Response Code: 204
433 c36934a7 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
434 c36934a7 Giorgos Verigakis
    #                       serviceUnavailable (503),
435 c36934a7 Giorgos Verigakis
    #                       unauthorized (401),
436 c36934a7 Giorgos Verigakis
    #                       badRequest (400),
437 c36934a7 Giorgos Verigakis
    #                       badMediaType(415),
438 c36934a7 Giorgos Verigakis
    #                       itemNotFound (404),
439 c36934a7 Giorgos Verigakis
    #                       buildInProgress (409),
440 c36934a7 Giorgos Verigakis
    #                       overLimit (413)
441 aa197ee4 Vangelis Koukis
442 b3fd98ae Christos Stavrakakis
    req = utils.get_request_dict(request)
443 bf5c82dc Christos Stavrakakis
    log.info('update_server_name %s %s', server_id, req)
444 ce55f211 Kostas Papadimitriou
445 7e2f9d4b Giorgos Verigakis
    try:
446 7e2f9d4b Giorgos Verigakis
        name = req['server']['name']
447 529178b1 Giorgos Verigakis
    except (TypeError, KeyError):
448 ccd0d474 Giorgos Verigakis
        raise faults.BadRequest("Malformed request")
449 aa197ee4 Vangelis Koukis
450 7f2dbcad Christos Stavrakakis
    vm = util.get_vm(server_id, request.user_uniq, for_update=True,
451 7f2dbcad Christos Stavrakakis
                     non_suspended=True)
452 a52cc1b4 Christos Stavrakakis
453 a52cc1b4 Christos Stavrakakis
    servers.rename(vm, new_name=name)
454 aa197ee4 Vangelis Koukis
455 7e2f9d4b Giorgos Verigakis
    return HttpResponse(status=204)
456 7e2f9d4b Giorgos Verigakis
457 55cd40be Vangelis Koukis
458 b3fd98ae Christos Stavrakakis
@api.api_method(http_method='DELETE', user_required=True, logger=log)
459 7e2f9d4b Giorgos Verigakis
def delete_server(request, server_id):
460 c36934a7 Giorgos Verigakis
    # Normal Response Codes: 204
461 c36934a7 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
462 c36934a7 Giorgos Verigakis
    #                       serviceUnavailable (503),
463 c36934a7 Giorgos Verigakis
    #                       unauthorized (401),
464 c36934a7 Giorgos Verigakis
    #                       itemNotFound (404),
465 c36934a7 Giorgos Verigakis
    #                       unauthorized (401),
466 c36934a7 Giorgos Verigakis
    #                       buildInProgress (409),
467 c36934a7 Giorgos Verigakis
    #                       overLimit (413)
468 ce55f211 Kostas Papadimitriou
469 bf5c82dc Christos Stavrakakis
    log.info('delete_server %s', server_id)
470 7f2dbcad Christos Stavrakakis
    vm = util.get_vm(server_id, request.user_uniq, for_update=True,
471 7f2dbcad Christos Stavrakakis
                     non_suspended=True)
472 41a7fae7 Christos Stavrakakis
    vm = servers.destroy(vm)
473 7e2f9d4b Giorgos Verigakis
    return HttpResponse(status=204)
474 b016b476 Giorgos Verigakis
475 55cd40be Vangelis Koukis
476 04a95cf3 Kostas Papadimitriou
# additional server actions
477 04a95cf3 Kostas Papadimitriou
ARBITRARY_ACTIONS = ['console', 'firewallProfile']
478 04a95cf3 Kostas Papadimitriou
479 e440e835 Christos Stavrakakis
480 7f2dbcad Christos Stavrakakis
def key_to_action(key):
481 7f2dbcad Christos Stavrakakis
    """Map HTTP request key to a VM Action"""
482 7f2dbcad Christos Stavrakakis
    if key == "shutdown":
483 7f2dbcad Christos Stavrakakis
        return "STOP"
484 7f2dbcad Christos Stavrakakis
    if key == "delete":
485 7f2dbcad Christos Stavrakakis
        return "DESTROY"
486 b7f21824 Kostas Papadimitriou
    if key in ARBITRARY_ACTIONS:
487 7f2dbcad Christos Stavrakakis
        return None
488 7f2dbcad Christos Stavrakakis
    else:
489 7f2dbcad Christos Stavrakakis
        return key.upper()
490 7f2dbcad Christos Stavrakakis
491 7f2dbcad Christos Stavrakakis
492 41a7fae7 Christos Stavrakakis
@api.api_method(http_method='POST', user_required=True, logger=log)
493 41a7fae7 Christos Stavrakakis
@transaction.commit_on_success
494 41a7fae7 Christos Stavrakakis
def demux_server_action(request, server_id):
495 41a7fae7 Christos Stavrakakis
    req = utils.get_request_dict(request)
496 41a7fae7 Christos Stavrakakis
    log.debug('server_action %s %s', server_id, req)
497 7f2dbcad Christos Stavrakakis
498 41a7fae7 Christos Stavrakakis
    if len(req) != 1:
499 41a7fae7 Christos Stavrakakis
        raise faults.BadRequest("Malformed request")
500 41a7fae7 Christos Stavrakakis
501 41a7fae7 Christos Stavrakakis
    # Do not allow any action on deleted or suspended VMs
502 41a7fae7 Christos Stavrakakis
    vm = util.get_vm(server_id, request.user_uniq, for_update=True,
503 41a7fae7 Christos Stavrakakis
                     non_deleted=True, non_suspended=True)
504 7f2dbcad Christos Stavrakakis
505 ece5581b Christos Stavrakakis
    action = req.keys()[0]
506 7f2dbcad Christos Stavrakakis
507 41a7fae7 Christos Stavrakakis
    if key_to_action(action) not in [x[0] for x in VirtualMachine.ACTIONS]:
508 41a7fae7 Christos Stavrakakis
        if action not in ARBITRARY_ACTIONS:
509 41a7fae7 Christos Stavrakakis
            raise faults.BadRequest("Action %s not supported" % action)
510 41a7fae7 Christos Stavrakakis
    action_args = req[action]
511 7f2dbcad Christos Stavrakakis
512 41a7fae7 Christos Stavrakakis
    if not isinstance(action_args, dict):
513 41a7fae7 Christos Stavrakakis
        raise faults.BadRequest("Invalid argument")
514 7f2dbcad Christos Stavrakakis
515 41a7fae7 Christos Stavrakakis
    return server_actions[action](request, vm, action_args)
516 7f2dbcad Christos Stavrakakis
517 7f2dbcad Christos Stavrakakis
518 b3fd98ae Christos Stavrakakis
@api.api_method(http_method='GET', user_required=True, logger=log)
519 b016b476 Giorgos Verigakis
def list_addresses(request, server_id):
520 b016b476 Giorgos Verigakis
    # Normal Response Codes: 200, 203
521 b016b476 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
522 b016b476 Giorgos Verigakis
    #                       serviceUnavailable (503),
523 b016b476 Giorgos Verigakis
    #                       unauthorized (401),
524 b016b476 Giorgos Verigakis
    #                       badRequest (400),
525 b016b476 Giorgos Verigakis
    #                       overLimit (413)
526 ce55f211 Kostas Papadimitriou
527 0c37a721 Christos Stavrakakis
    log.debug('list_addresses %s', server_id)
528 b3a43976 Christos Stavrakakis
    vm = util.get_vm(server_id, request.user_uniq, prefetch_related="nic__ips")
529 b3a43976 Christos Stavrakakis
    attachments = [nic_to_attachments(nic)
530 b3a43976 Christos Stavrakakis
                   for nic in vm.nics.filter(state="ACTIVE")]
531 78c165cf Christos Stavrakakis
    addresses = attachments_to_addresses(attachments)
532 ce55f211 Kostas Papadimitriou
533 d8e50a39 Giorgos Verigakis
    if request.serialization == 'xml':
534 b016b476 Giorgos Verigakis
        data = render_to_string('list_addresses.xml', {'addresses': addresses})
535 b016b476 Giorgos Verigakis
    else:
536 1f638a85 Christos Stavrakakis
        data = json.dumps({'addresses': addresses, 'attachments': attachments})
537 aa197ee4 Vangelis Koukis
538 b016b476 Giorgos Verigakis
    return HttpResponse(data, status=200)
539 b016b476 Giorgos Verigakis
540 55cd40be Vangelis Koukis
541 b3fd98ae Christos Stavrakakis
@api.api_method(http_method='GET', user_required=True, logger=log)
542 b016b476 Giorgos Verigakis
def list_addresses_by_network(request, server_id, network_id):
543 b016b476 Giorgos Verigakis
    # Normal Response Codes: 200, 203
544 b016b476 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
545 b016b476 Giorgos Verigakis
    #                       serviceUnavailable (503),
546 b016b476 Giorgos Verigakis
    #                       unauthorized (401),
547 b016b476 Giorgos Verigakis
    #                       badRequest (400),
548 b016b476 Giorgos Verigakis
    #                       itemNotFound (404),
549 b016b476 Giorgos Verigakis
    #                       overLimit (413)
550 ce55f211 Kostas Papadimitriou
551 0c37a721 Christos Stavrakakis
    log.debug('list_addresses_by_network %s %s', server_id, network_id)
552 4b3b8688 Giorgos Verigakis
    machine = util.get_vm(server_id, request.user_uniq)
553 4b3b8688 Giorgos Verigakis
    network = util.get_network(network_id, request.user_uniq)
554 7c714455 Christos Stavrakakis
    nics = machine.nics.filter(network=network, state="ACTIVE")
555 b3a43976 Christos Stavrakakis
    addresses = attachments_to_addresses(map(nic_to_attachments, nics))
556 ce55f211 Kostas Papadimitriou
557 d8e50a39 Giorgos Verigakis
    if request.serialization == 'xml':
558 1f638a85 Christos Stavrakakis
        data = render_to_string('address.xml', {'addresses': addresses})
559 b016b476 Giorgos Verigakis
    else:
560 1f638a85 Christos Stavrakakis
        data = json.dumps({'network': addresses})
561 aa197ee4 Vangelis Koukis
562 b016b476 Giorgos Verigakis
    return HttpResponse(data, status=200)
563 d8e50a39 Giorgos Verigakis
564 55cd40be Vangelis Koukis
565 b3fd98ae Christos Stavrakakis
@api.api_method(http_method='GET', user_required=True, logger=log)
566 d8e50a39 Giorgos Verigakis
def list_metadata(request, server_id):
567 d8e50a39 Giorgos Verigakis
    # Normal Response Codes: 200, 203
568 d8e50a39 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
569 d8e50a39 Giorgos Verigakis
    #                       serviceUnavailable (503),
570 d8e50a39 Giorgos Verigakis
    #                       unauthorized (401),
571 d8e50a39 Giorgos Verigakis
    #                       badRequest (400),
572 d8e50a39 Giorgos Verigakis
    #                       overLimit (413)
573 ce55f211 Kostas Papadimitriou
574 0c37a721 Christos Stavrakakis
    log.debug('list_server_metadata %s', server_id)
575 4b3b8688 Giorgos Verigakis
    vm = util.get_vm(server_id, request.user_uniq)
576 7cc3c7d9 Giorgos Verigakis
    metadata = dict((m.meta_key, m.meta_value) for m in vm.metadata.all())
577 5029ff36 Christos Stavrakakis
    return util.render_metadata(request, metadata, use_values=False,
578 5029ff36 Christos Stavrakakis
                                status=200)
579 d8e50a39 Giorgos Verigakis
580 55cd40be Vangelis Koukis
581 b3fd98ae Christos Stavrakakis
@api.api_method(http_method='POST', user_required=True, logger=log)
582 874383a4 Christos Stavrakakis
@transaction.commit_on_success
583 d8e50a39 Giorgos Verigakis
def update_metadata(request, server_id):
584 d8e50a39 Giorgos Verigakis
    # Normal Response Code: 201
585 d8e50a39 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
586 d8e50a39 Giorgos Verigakis
    #                       serviceUnavailable (503),
587 d8e50a39 Giorgos Verigakis
    #                       unauthorized (401),
588 d8e50a39 Giorgos Verigakis
    #                       badRequest (400),
589 d8e50a39 Giorgos Verigakis
    #                       buildInProgress (409),
590 d8e50a39 Giorgos Verigakis
    #                       badMediaType(415),
591 d8e50a39 Giorgos Verigakis
    #                       overLimit (413)
592 ce55f211 Kostas Papadimitriou
593 b3fd98ae Christos Stavrakakis
    req = utils.get_request_dict(request)
594 bf5c82dc Christos Stavrakakis
    log.info('update_server_metadata %s %s', server_id, req)
595 e221ade2 Christos Stavrakakis
    vm = util.get_vm(server_id, request.user_uniq, non_suspended=True)
596 d8e50a39 Giorgos Verigakis
    try:
597 d8e50a39 Giorgos Verigakis
        metadata = req['metadata']
598 d8e50a39 Giorgos Verigakis
        assert isinstance(metadata, dict)
599 d8e50a39 Giorgos Verigakis
    except (KeyError, AssertionError):
600 ccd0d474 Giorgos Verigakis
        raise faults.BadRequest("Malformed request")
601 ce55f211 Kostas Papadimitriou
602 7cc3c7d9 Giorgos Verigakis
    for key, val in metadata.items():
603 7cc3c7d9 Giorgos Verigakis
        meta, created = vm.metadata.get_or_create(meta_key=key)
604 7cc3c7d9 Giorgos Verigakis
        meta.meta_value = val
605 7cc3c7d9 Giorgos Verigakis
        meta.save()
606 ce55f211 Kostas Papadimitriou
607 7cc3c7d9 Giorgos Verigakis
    vm.save()
608 7cc3c7d9 Giorgos Verigakis
    vm_meta = dict((m.meta_key, m.meta_value) for m in vm.metadata.all())
609 7cc3c7d9 Giorgos Verigakis
    return util.render_metadata(request, vm_meta, status=201)
610 d8e50a39 Giorgos Verigakis
611 55cd40be Vangelis Koukis
612 b3fd98ae Christos Stavrakakis
@api.api_method(http_method='GET', user_required=True, logger=log)
613 d8e50a39 Giorgos Verigakis
def get_metadata_item(request, server_id, key):
614 d8e50a39 Giorgos Verigakis
    # Normal Response Codes: 200, 203
615 d8e50a39 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
616 d8e50a39 Giorgos Verigakis
    #                       serviceUnavailable (503),
617 d8e50a39 Giorgos Verigakis
    #                       unauthorized (401),
618 d8e50a39 Giorgos Verigakis
    #                       itemNotFound (404),
619 d8e50a39 Giorgos Verigakis
    #                       badRequest (400),
620 d8e50a39 Giorgos Verigakis
    #                       overLimit (413)
621 ce55f211 Kostas Papadimitriou
622 0c37a721 Christos Stavrakakis
    log.debug('get_server_metadata_item %s %s', server_id, key)
623 4b3b8688 Giorgos Verigakis
    vm = util.get_vm(server_id, request.user_uniq)
624 b36f78fa Giorgos Verigakis
    meta = util.get_vm_meta(vm, key)
625 62b894c0 Giorgos Verigakis
    d = {meta.meta_key: meta.meta_value}
626 62b894c0 Giorgos Verigakis
    return util.render_meta(request, d, status=200)
627 d8e50a39 Giorgos Verigakis
628 55cd40be Vangelis Koukis
629 b3fd98ae Christos Stavrakakis
@api.api_method(http_method='PUT', user_required=True, logger=log)
630 4dba0480 Christos Stavrakakis
@transaction.commit_on_success
631 d8e50a39 Giorgos Verigakis
def create_metadata_item(request, server_id, key):
632 d8e50a39 Giorgos Verigakis
    # Normal Response Code: 201
633 d8e50a39 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
634 d8e50a39 Giorgos Verigakis
    #                       serviceUnavailable (503),
635 d8e50a39 Giorgos Verigakis
    #                       unauthorized (401),
636 d8e50a39 Giorgos Verigakis
    #                       itemNotFound (404),
637 d8e50a39 Giorgos Verigakis
    #                       badRequest (400),
638 d8e50a39 Giorgos Verigakis
    #                       buildInProgress (409),
639 d8e50a39 Giorgos Verigakis
    #                       badMediaType(415),
640 d8e50a39 Giorgos Verigakis
    #                       overLimit (413)
641 ce55f211 Kostas Papadimitriou
642 b3fd98ae Christos Stavrakakis
    req = utils.get_request_dict(request)
643 bf5c82dc Christos Stavrakakis
    log.info('create_server_metadata_item %s %s %s', server_id, key, req)
644 e221ade2 Christos Stavrakakis
    vm = util.get_vm(server_id, request.user_uniq, non_suspended=True)
645 d8e50a39 Giorgos Verigakis
    try:
646 d8e50a39 Giorgos Verigakis
        metadict = req['meta']
647 d8e50a39 Giorgos Verigakis
        assert isinstance(metadict, dict)
648 d8e50a39 Giorgos Verigakis
        assert len(metadict) == 1
649 d8e50a39 Giorgos Verigakis
        assert key in metadict
650 d8e50a39 Giorgos Verigakis
    except (KeyError, AssertionError):
651 ccd0d474 Giorgos Verigakis
        raise faults.BadRequest("Malformed request")
652 ce55f211 Kostas Papadimitriou
653 b36f78fa Giorgos Verigakis
    meta, created = VirtualMachineMetadata.objects.get_or_create(
654 b36f78fa Giorgos Verigakis
        meta_key=key,
655 b36f78fa Giorgos Verigakis
        vm=vm)
656 ce55f211 Kostas Papadimitriou
657 d8e50a39 Giorgos Verigakis
    meta.meta_value = metadict[key]
658 d8e50a39 Giorgos Verigakis
    meta.save()
659 5509b599 Giorgos Verigakis
    vm.save()
660 62b894c0 Giorgos Verigakis
    d = {meta.meta_key: meta.meta_value}
661 62b894c0 Giorgos Verigakis
    return util.render_meta(request, d, status=201)
662 d8e50a39 Giorgos Verigakis
663 55cd40be Vangelis Koukis
664 b3fd98ae Christos Stavrakakis
@api.api_method(http_method='DELETE', user_required=True, logger=log)
665 4dba0480 Christos Stavrakakis
@transaction.commit_on_success
666 d8e50a39 Giorgos Verigakis
def delete_metadata_item(request, server_id, key):
667 d8e50a39 Giorgos Verigakis
    # Normal Response Code: 204
668 d8e50a39 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
669 d8e50a39 Giorgos Verigakis
    #                       serviceUnavailable (503),
670 d8e50a39 Giorgos Verigakis
    #                       unauthorized (401),
671 d8e50a39 Giorgos Verigakis
    #                       itemNotFound (404),
672 d8e50a39 Giorgos Verigakis
    #                       badRequest (400),
673 d8e50a39 Giorgos Verigakis
    #                       buildInProgress (409),
674 d8e50a39 Giorgos Verigakis
    #                       badMediaType(415),
675 d8e50a39 Giorgos Verigakis
    #                       overLimit (413),
676 ce55f211 Kostas Papadimitriou
677 bf5c82dc Christos Stavrakakis
    log.info('delete_server_metadata_item %s %s', server_id, key)
678 e221ade2 Christos Stavrakakis
    vm = util.get_vm(server_id, request.user_uniq, non_suspended=True)
679 b36f78fa Giorgos Verigakis
    meta = util.get_vm_meta(vm, key)
680 d8e50a39 Giorgos Verigakis
    meta.delete()
681 5509b599 Giorgos Verigakis
    vm.save()
682 d8e50a39 Giorgos Verigakis
    return HttpResponse(status=204)
683 c738c935 Giorgos Verigakis
684 55cd40be Vangelis Koukis
685 b3fd98ae Christos Stavrakakis
@api.api_method(http_method='GET', user_required=True, logger=log)
686 c738c935 Giorgos Verigakis
def server_stats(request, server_id):
687 c738c935 Giorgos Verigakis
    # Normal Response Codes: 200
688 c738c935 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
689 c738c935 Giorgos Verigakis
    #                       serviceUnavailable (503),
690 c738c935 Giorgos Verigakis
    #                       unauthorized (401),
691 c738c935 Giorgos Verigakis
    #                       badRequest (400),
692 c738c935 Giorgos Verigakis
    #                       itemNotFound (404),
693 c738c935 Giorgos Verigakis
    #                       overLimit (413)
694 ce55f211 Kostas Papadimitriou
695 0c37a721 Christos Stavrakakis
    log.debug('server_stats %s', server_id)
696 4b3b8688 Giorgos Verigakis
    vm = util.get_vm(server_id, request.user_uniq)
697 bd16bf3e Stratos Psomadakis
    secret = util.stats_encrypt(vm.backend_vm_id)
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 fae6e5f0 Christos Stavrakakis
    userid = vm.userid
932 fae6e5f0 Christos Stavrakakis
    floating_ip = util.get_floating_ip_by_address(userid, address,
933 fae6e5f0 Christos Stavrakakis
                                                  for_update=True)
934 fae6e5f0 Christos Stavrakakis
    servers.create_port(userid, floating_ip.network, machine=vm,
935 fae6e5f0 Christos Stavrakakis
                        user_ipaddress=floating_ip)
936 9ba6bb95 Christos Stavrakakis
    return HttpResponse(status=202)
937 9ba6bb95 Christos Stavrakakis
938 9ba6bb95 Christos Stavrakakis
939 f8675683 Christos Stavrakakis
@server_action("removeFloatingIp")
940 9ba6bb95 Christos Stavrakakis
def remove_floating_ip(request, vm, args):
941 9ba6bb95 Christos Stavrakakis
    address = args.get("address")
942 9ba6bb95 Christos Stavrakakis
    if address is None:
943 9ba6bb95 Christos Stavrakakis
        raise faults.BadRequest("Missing 'address' attribute")
944 fae6e5f0 Christos Stavrakakis
    floating_ip = util.get_floating_ip_by_address(vm.userid, address,
945 fae6e5f0 Christos Stavrakakis
                                                  for_update=True)
946 fae6e5f0 Christos Stavrakakis
    if floating_ip.nic is None:
947 fae6e5f0 Christos Stavrakakis
        raise faults.BadRequest("Floating IP %s not attached to instance"
948 fae6e5f0 Christos Stavrakakis
                                % address)
949 fae6e5f0 Christos Stavrakakis
    servers.delete_port(floating_ip.nic)
950 9ba6bb95 Christos Stavrakakis
    return HttpResponse(status=202)