Statistics
| Branch: | Tag: | Revision:

root / snf-cyclades-app / synnefo / api / floating_ips.py @ 1fb3293d

History | View | Annotate | Download (9.6 kB)

1 59183afc Christos Stavrakakis
# Copyright 2013 GRNET S.A. All rights reserved.
2 59183afc Christos Stavrakakis
#
3 59183afc Christos Stavrakakis
# Redistribution and use in source and binary forms, with or
4 59183afc Christos Stavrakakis
# without modification, are permitted provided that the following
5 59183afc Christos Stavrakakis
# conditions are met:
6 59183afc Christos Stavrakakis
#
7 59183afc Christos Stavrakakis
#   1. Redistributions of source code must retain the above
8 59183afc Christos Stavrakakis
#      copyright notice, this list of conditions and the following
9 59183afc Christos Stavrakakis
#      disclaimer.
10 59183afc Christos Stavrakakis
#
11 59183afc Christos Stavrakakis
#   2. Redistributions in binary form must reproduce the above
12 59183afc Christos Stavrakakis
#      copyright notice, this list of conditions and the following
13 59183afc Christos Stavrakakis
#      disclaimer in the documentation and/or other materials
14 59183afc Christos Stavrakakis
#      provided with the distribution.
15 59183afc Christos Stavrakakis
#
16 59183afc Christos Stavrakakis
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
17 59183afc Christos Stavrakakis
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 59183afc Christos Stavrakakis
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 59183afc Christos Stavrakakis
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
20 59183afc Christos Stavrakakis
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 59183afc Christos Stavrakakis
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 59183afc Christos Stavrakakis
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23 59183afc Christos Stavrakakis
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24 59183afc Christos Stavrakakis
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 59183afc Christos Stavrakakis
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26 59183afc Christos Stavrakakis
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 59183afc Christos Stavrakakis
# POSSIBILITY OF SUCH DAMAGE.
28 59183afc Christos Stavrakakis
#
29 59183afc Christos Stavrakakis
# The views and conclusions contained in the software and
30 59183afc Christos Stavrakakis
# documentation are those of the authors and should not be
31 59183afc Christos Stavrakakis
# interpreted as representing official policies, either expressed
32 59183afc Christos Stavrakakis
# or implied, of GRNET S.A.
33 59183afc Christos Stavrakakis
34 59183afc Christos Stavrakakis
from django.conf.urls.defaults import patterns
35 59183afc Christos Stavrakakis
from django.db import transaction
36 59183afc Christos Stavrakakis
from django.http import HttpResponse
37 59183afc Christos Stavrakakis
from django.utils import simplejson as json
38 59183afc Christos Stavrakakis
39 59183afc Christos Stavrakakis
from snf_django.lib import api
40 59183afc Christos Stavrakakis
from snf_django.lib.api import faults, utils
41 59183afc Christos Stavrakakis
from synnefo.api import util
42 59183afc Christos Stavrakakis
from synnefo import quotas
43 fde2c1f7 Christos Stavrakakis
from synnefo.db.models import Network, IPAddress
44 59183afc Christos Stavrakakis
45 59183afc Christos Stavrakakis
from logging import getLogger
46 59183afc Christos Stavrakakis
log = getLogger(__name__)
47 59183afc Christos Stavrakakis
48 e4f484da Marios Kogias
'''
49 7d368e73 Christos Stavrakakis
ips_urlpatterns = patterns(
50 59183afc Christos Stavrakakis
    'synnefo.api.floating_ips',
51 59183afc Christos Stavrakakis
    (r'^(?:/|.json|.xml)?$', 'demux'),
52 59183afc Christos Stavrakakis
    (r'^/(\w+)(?:.json|.xml)?$', 'floating_ip_demux'),
53 59183afc Christos Stavrakakis
)
54 59183afc Christos Stavrakakis

55 7d368e73 Christos Stavrakakis
pools_urlpatterns = patterns(
56 7d368e73 Christos Stavrakakis
    "synnefo.api.floating_ips",
57 7d368e73 Christos Stavrakakis
    (r'^(?:/|.json|.xml)?$', 'list_floating_ip_pools'),
58 7d368e73 Christos Stavrakakis
)
59 e4f484da Marios Kogias
'''
60 e4f484da Marios Kogias
61 e4f484da Marios Kogias
ips_urlpatterns = patterns(
62 e4f484da Marios Kogias
    'synnefo.api.floating_ips',
63 e4f484da Marios Kogias
    (r'^(?:/|.json|.xml)?$', 'demux'),
64 e4f484da Marios Kogias
    (r'^/detail(?:.json|.xml)?$', 'list_floating_ips', {'detail': True}),
65 e4f484da Marios Kogias
    (r'^/(\w+)(?:/|.json|.xml)?$', 'floating_ip_demux'))
66 7d368e73 Christos Stavrakakis
67 59183afc Christos Stavrakakis
68 59183afc Christos Stavrakakis
def demux(request):
69 59183afc Christos Stavrakakis
    if request.method == 'GET':
70 59183afc Christos Stavrakakis
        return list_floating_ips(request)
71 59183afc Christos Stavrakakis
    elif request.method == 'POST':
72 59183afc Christos Stavrakakis
        return allocate_floating_ip(request)
73 59183afc Christos Stavrakakis
    else:
74 20a626e7 Giorgos Korfiatis
        return api.api_method_not_allowed(request)
75 59183afc Christos Stavrakakis
76 59183afc Christos Stavrakakis
77 59183afc Christos Stavrakakis
def floating_ip_demux(request, floating_ip_id):
78 59183afc Christos Stavrakakis
    if request.method == 'GET':
79 59183afc Christos Stavrakakis
        return get_floating_ip(request, floating_ip_id)
80 59183afc Christos Stavrakakis
    elif request.method == 'DELETE':
81 59183afc Christos Stavrakakis
        return release_floating_ip(request, floating_ip_id)
82 e4f484da Marios Kogias
    elif request.method == 'PUT':
83 e4f484da Marios Kogias
        return update_floating_ip(request, floating_ip_id)
84 59183afc Christos Stavrakakis
    else:
85 20a626e7 Giorgos Korfiatis
        return api.api_method_not_allowed(request)
86 59183afc Christos Stavrakakis
87 59183afc Christos Stavrakakis
88 59183afc Christos Stavrakakis
def ip_to_dict(floating_ip):
89 fde2c1f7 Christos Stavrakakis
    machine_id = None
90 e4f484da Marios Kogias
    port_id = None
91 fde2c1f7 Christos Stavrakakis
    if floating_ip.nic is not None:
92 fde2c1f7 Christos Stavrakakis
        machine_id = floating_ip.nic.machine_id
93 e4f484da Marios Kogias
        port_id = floating_ip.nic.id
94 e4f484da Marios Kogias
    return {"fixed_ip_address": None,
95 59183afc Christos Stavrakakis
            "id": str(floating_ip.id),
96 59183afc Christos Stavrakakis
            "instance_id": str(machine_id) if machine_id else None,
97 e4f484da Marios Kogias
            "floating_ip_address": floating_ip.address,
98 e4f484da Marios Kogias
            "port_id": str(floating_ip.nic.id) if port_id else None,
99 e4f484da Marios Kogias
            "floating_network_id": str(floating_ip.network_id)}
100 59183afc Christos Stavrakakis
101 59183afc Christos Stavrakakis
102 1cbe2522 Christos Stavrakakis
@api.api_method(http_method="GET", user_required=True, logger=log,
103 1cbe2522 Christos Stavrakakis
                serializations=["json"])
104 59183afc Christos Stavrakakis
def list_floating_ips(request):
105 59183afc Christos Stavrakakis
    """Return user reserved floating IPs"""
106 59183afc Christos Stavrakakis
    log.debug("list_floating_ips")
107 59183afc Christos Stavrakakis
108 59183afc Christos Stavrakakis
    userid = request.user_uniq
109 fde2c1f7 Christos Stavrakakis
    floating_ips = IPAddress.objects.filter(userid=userid, deleted=False,
110 fde2c1f7 Christos Stavrakakis
                                            floating_ip=True).order_by("id")\
111 fde2c1f7 Christos Stavrakakis
                                    .select_related("nic")
112 b6bc4afa Christos Stavrakakis
    floating_ips = utils.filter_modified_since(request, objects=floating_ips)
113 59183afc Christos Stavrakakis
114 59183afc Christos Stavrakakis
    floating_ips = map(ip_to_dict, floating_ips)
115 59183afc Christos Stavrakakis
116 59183afc Christos Stavrakakis
    request.serialization = "json"
117 53b0ea25 Christos Stavrakakis
    data = json.dumps({"floatingips": floating_ips})
118 59183afc Christos Stavrakakis
119 59183afc Christos Stavrakakis
    return HttpResponse(data, status=200)
120 59183afc Christos Stavrakakis
121 59183afc Christos Stavrakakis
122 1cbe2522 Christos Stavrakakis
@api.api_method(http_method="GET", user_required=True, logger=log,
123 1cbe2522 Christos Stavrakakis
                serializations=["json"])
124 59183afc Christos Stavrakakis
def get_floating_ip(request, floating_ip_id):
125 59183afc Christos Stavrakakis
    """Return information for a floating IP."""
126 59183afc Christos Stavrakakis
    userid = request.user_uniq
127 fde2c1f7 Christos Stavrakakis
    floating_ip = util.get_floating_ip_by_id(userid, floating_ip_id)
128 59183afc Christos Stavrakakis
    request.serialization = "json"
129 53b0ea25 Christos Stavrakakis
    data = json.dumps({"floatingip": ip_to_dict(floating_ip)})
130 59183afc Christos Stavrakakis
    return HttpResponse(data, status=200)
131 59183afc Christos Stavrakakis
132 59183afc Christos Stavrakakis
133 1cbe2522 Christos Stavrakakis
@api.api_method(http_method='POST', user_required=True, logger=log,
134 1cbe2522 Christos Stavrakakis
                serializations=["json"])
135 fde2c1f7 Christos Stavrakakis
@transaction.commit_on_success
136 59183afc Christos Stavrakakis
def allocate_floating_ip(request):
137 59183afc Christos Stavrakakis
    """Allocate a floating IP."""
138 59183afc Christos Stavrakakis
    req = utils.get_request_dict(request)
139 e4f484da Marios Kogias
    floating_ip_dict = api.utils.get_attribute(req, "floatingip",
140 e4f484da Marios Kogias
                                               required=True)
141 59183afc Christos Stavrakakis
    log.info('allocate_floating_ip %s', req)
142 59183afc Christos Stavrakakis
143 59183afc Christos Stavrakakis
    userid = request.user_uniq
144 e4f484da Marios Kogias
145 e4f484da Marios Kogias
    # the network_pool is a mandatory field
146 e4f484da Marios Kogias
    network_pool = api.utils.get_attribute(floating_ip_dict,
147 e4f484da Marios Kogias
                                           "floating_network_id",
148 e4f484da Marios Kogias
                                           required=True)
149 e4f484da Marios Kogias
    address = api.utils.get_attribute(floating_ip_dict, "floating_ip_address",
150 e4f484da Marios Kogias
                                      required=False)
151 e4f484da Marios Kogias
152 e4f484da Marios Kogias
    try:
153 e4f484da Marios Kogias
        network_id = int(network_pool)
154 e4f484da Marios Kogias
    except ValueError:
155 e4f484da Marios Kogias
        raise faults.BadRequest("Invalid networkd ID.")
156 e4f484da Marios Kogias
    network = util.get_network(network_id, userid, for_update=True,
157 e4f484da Marios Kogias
                               non_deleted=True)
158 d610698e Christos Stavrakakis
159 e4f484da Marios Kogias
    if not network.floating_ip_pool:
160 e4f484da Marios Kogias
        # Check that it is a floating IP pool
161 e4f484da Marios Kogias
        raise faults.ItemNotFound("Floating IP pool %s does not exist." %
162 e4f484da Marios Kogias
                                  network_id)
163 d610698e Christos Stavrakakis
164 d610698e Christos Stavrakakis
    # Allocate the floating IP
165 e4f484da Marios Kogias
    floating_ip = util.allocate_ip(network, userid, address=address,
166 e4f484da Marios Kogias
                                   floating_ip=True)
167 d610698e Christos Stavrakakis
    # Issue commission (quotas)
168 fde2c1f7 Christos Stavrakakis
    quotas.issue_and_accept_commission(floating_ip)
169 fde2c1f7 Christos Stavrakakis
    transaction.commit()
170 fde2c1f7 Christos Stavrakakis
171 fde2c1f7 Christos Stavrakakis
    log.info("User '%s' allocated floating IP '%s'", userid, floating_ip)
172 59183afc Christos Stavrakakis
173 59183afc Christos Stavrakakis
    request.serialization = "json"
174 53b0ea25 Christos Stavrakakis
    data = json.dumps({"floatingip": ip_to_dict(floating_ip)})
175 59183afc Christos Stavrakakis
    return HttpResponse(data, status=200)
176 59183afc Christos Stavrakakis
177 59183afc Christos Stavrakakis
178 1cbe2522 Christos Stavrakakis
@api.api_method(http_method='DELETE', user_required=True, logger=log,
179 1cbe2522 Christos Stavrakakis
                serializations=["json"])
180 59183afc Christos Stavrakakis
@transaction.commit_on_success
181 59183afc Christos Stavrakakis
def release_floating_ip(request, floating_ip_id):
182 59183afc Christos Stavrakakis
    """Release a floating IP."""
183 59183afc Christos Stavrakakis
    userid = request.user_uniq
184 59183afc Christos Stavrakakis
    log.info("release_floating_ip '%s'. User '%s'.", floating_ip_id, userid)
185 fde2c1f7 Christos Stavrakakis
186 fde2c1f7 Christos Stavrakakis
    floating_ip = util.get_floating_ip_by_id(userid, floating_ip_id,
187 fde2c1f7 Christos Stavrakakis
                                             for_update=True)
188 fde2c1f7 Christos Stavrakakis
    if floating_ip.nic:
189 fde2c1f7 Christos Stavrakakis
        # This is safe, you also need for_update to attach floating IP to
190 fde2c1f7 Christos Stavrakakis
        # instance.
191 fde2c1f7 Christos Stavrakakis
        msg = "Floating IP '%s' is attached to instance." % floating_ip.id
192 fde2c1f7 Christos Stavrakakis
        raise faults.Conflict(msg)
193 fde2c1f7 Christos Stavrakakis
194 fde2c1f7 Christos Stavrakakis
    # Return the address of the floating IP back to pool
195 fde2c1f7 Christos Stavrakakis
    floating_ip.release_address()
196 fde2c1f7 Christos Stavrakakis
    # And mark the floating IP as deleted
197 fde2c1f7 Christos Stavrakakis
    floating_ip.deleted = True
198 fde2c1f7 Christos Stavrakakis
    floating_ip.save()
199 fde2c1f7 Christos Stavrakakis
    # Release quota for floating IP
200 fde2c1f7 Christos Stavrakakis
    quotas.issue_and_accept_commission(floating_ip, delete=True)
201 fde2c1f7 Christos Stavrakakis
    transaction.commit()
202 fde2c1f7 Christos Stavrakakis
    # Delete the floating IP from DB
203 fde2c1f7 Christos Stavrakakis
    floating_ip.delete()
204 59183afc Christos Stavrakakis
205 59183afc Christos Stavrakakis
    log.info("User '%s' released IP '%s", userid, floating_ip)
206 59183afc Christos Stavrakakis
207 59183afc Christos Stavrakakis
    return HttpResponse(status=204)
208 7d368e73 Christos Stavrakakis
209 7d368e73 Christos Stavrakakis
210 e4f484da Marios Kogias
@api.api_method(http_method='PUT', user_required=True, logger=log,
211 e4f484da Marios Kogias
                serializations=["json"])
212 e4f484da Marios Kogias
@transaction.commit_on_success
213 e4f484da Marios Kogias
def update_floating_ip(request, floating_ip_id):
214 e4f484da Marios Kogias
    """Update a floating IP."""
215 1fb3293d Christos Stavrakakis
    raise faults.NotImplemented("Updating a floating IP is not supported.")
216 d610698e Christos Stavrakakis
    #userid = request.user_uniq
217 d610698e Christos Stavrakakis
    #log.info("update_floating_ip '%s'. User '%s'.", floating_ip_id, userid)
218 d610698e Christos Stavrakakis
219 d610698e Christos Stavrakakis
    #req = utils.get_request_dict(request)
220 d610698e Christos Stavrakakis
    #info = api.utils.get_attribute(req, "floatingip", required=True)
221 d610698e Christos Stavrakakis
222 d610698e Christos Stavrakakis
    #device_id = api.utils.get_attribute(info, "device_id", required=False)
223 d610698e Christos Stavrakakis
224 d610698e Christos Stavrakakis
    #floating_ip = util.get_floating_ip_by_id(userid, floating_ip_id,
225 d610698e Christos Stavrakakis
    #                                         for_update=True)
226 d610698e Christos Stavrakakis
    #if device_id:
227 d610698e Christos Stavrakakis
    #    # attach
228 d610698e Christos Stavrakakis
    #    vm = util.get_vm(device_id, userid)
229 d610698e Christos Stavrakakis
    #    nic, floating_ip = servers.create_nic(vm, ipaddress=floating_ip)
230 d610698e Christos Stavrakakis
    #    backend.connect_to_network(vm, nic)
231 d610698e Christos Stavrakakis
    #else:
232 d610698e Christos Stavrakakis
    #    # dettach
233 d610698e Christos Stavrakakis
    #    nic = floating_ip.nic
234 d610698e Christos Stavrakakis
    #    if not nic:
235 d610698e Christos Stavrakakis
    #        raise faults.BadRequest("The floating IP is not associated\
236 d610698e Christos Stavrakakis
    #                                with any device")
237 d610698e Christos Stavrakakis
    #    vm = nic.machine
238 d610698e Christos Stavrakakis
    #    servers.disconnect(vm, nic)
239 d610698e Christos Stavrakakis
    #return HttpResponse(status=202)
240 e4f484da Marios Kogias
241 e4f484da Marios Kogias
242 fde2c1f7 Christos Stavrakakis
# Floating IP pools
243 1cbe2522 Christos Stavrakakis
@api.api_method(http_method='GET', user_required=True, logger=log,
244 1cbe2522 Christos Stavrakakis
                serializations=["json"])
245 7d368e73 Christos Stavrakakis
def list_floating_ip_pools(request):
246 fde2c1f7 Christos Stavrakakis
    networks = Network.objects.filter(public=True, floating_ip_pool=True,
247 fde2c1f7 Christos Stavrakakis
                                      deleted=False)
248 b6bc4afa Christos Stavrakakis
    networks = utils.filter_modified_since(request, objects=networks)
249 d610698e Christos Stavrakakis
    floating_ip_pools = map(network_to_floating_ip_pool, networks)
250 7d368e73 Christos Stavrakakis
    request.serialization = "json"
251 d610698e Christos Stavrakakis
    data = json.dumps({"floating_ip_pools": floating_ip_pools})
252 7d368e73 Christos Stavrakakis
    request.serialization = "json"
253 7d368e73 Christos Stavrakakis
    return HttpResponse(data, status=200)
254 fde2c1f7 Christos Stavrakakis
255 fde2c1f7 Christos Stavrakakis
256 fde2c1f7 Christos Stavrakakis
def network_to_floating_ip_pool(network):
257 fde2c1f7 Christos Stavrakakis
    """Convert a 'Network' object to a floating IP pool dict."""
258 fde2c1f7 Christos Stavrakakis
    total, free = network.ip_count()
259 fde2c1f7 Christos Stavrakakis
    return {"name": str(network.id),
260 fde2c1f7 Christos Stavrakakis
            "size": total,
261 fde2c1f7 Christos Stavrakakis
            "free": free}