Statistics
| Branch: | Tag: | Revision:

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

History | View | Annotate | Download (8.9 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 9115d567 Christos Stavrakakis
from synnefo.db.models import Network, FloatingIP
44 59183afc Christos Stavrakakis
45 59183afc Christos Stavrakakis
46 59183afc Christos Stavrakakis
from logging import getLogger
47 59183afc Christos Stavrakakis
log = getLogger(__name__)
48 59183afc Christos Stavrakakis
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 7d368e73 Christos Stavrakakis
60 59183afc Christos Stavrakakis
61 59183afc Christos Stavrakakis
def demux(request):
62 59183afc Christos Stavrakakis
    if request.method == 'GET':
63 59183afc Christos Stavrakakis
        return list_floating_ips(request)
64 59183afc Christos Stavrakakis
    elif request.method == 'POST':
65 59183afc Christos Stavrakakis
        return allocate_floating_ip(request)
66 59183afc Christos Stavrakakis
    else:
67 59183afc Christos Stavrakakis
        return api.method_not_allowed(request)
68 59183afc Christos Stavrakakis
69 59183afc Christos Stavrakakis
70 59183afc Christos Stavrakakis
def floating_ip_demux(request, floating_ip_id):
71 59183afc Christos Stavrakakis
    if request.method == 'GET':
72 59183afc Christos Stavrakakis
        return get_floating_ip(request, floating_ip_id)
73 59183afc Christos Stavrakakis
    elif request.method == 'DELETE':
74 59183afc Christos Stavrakakis
        return release_floating_ip(request, floating_ip_id)
75 59183afc Christos Stavrakakis
    else:
76 59183afc Christos Stavrakakis
        return api.method_not_allowed(request)
77 59183afc Christos Stavrakakis
78 59183afc Christos Stavrakakis
79 59183afc Christos Stavrakakis
def ip_to_dict(floating_ip):
80 59183afc Christos Stavrakakis
    machine_id = floating_ip.machine_id
81 59183afc Christos Stavrakakis
    return {"fixed_ip": None,
82 59183afc Christos Stavrakakis
            "id": str(floating_ip.id),
83 59183afc Christos Stavrakakis
            "instance_id": str(machine_id) if machine_id else None,
84 59183afc Christos Stavrakakis
            "ip": floating_ip.ipv4,
85 59183afc Christos Stavrakakis
            "pool": str(floating_ip.network_id)}
86 59183afc Christos Stavrakakis
87 59183afc Christos Stavrakakis
88 59183afc Christos Stavrakakis
@api.api_method(http_method="GET", user_required=True, logger=log)
89 59183afc Christos Stavrakakis
def list_floating_ips(request):
90 59183afc Christos Stavrakakis
    """Return user reserved floating IPs"""
91 59183afc Christos Stavrakakis
    log.debug("list_floating_ips")
92 59183afc Christos Stavrakakis
93 59183afc Christos Stavrakakis
    userid = request.user_uniq
94 59183afc Christos Stavrakakis
    floating_ips = FloatingIP.objects.filter(userid=userid, deleted=False)\
95 59183afc Christos Stavrakakis
                                     .order_by("id")
96 59183afc Christos Stavrakakis
97 59183afc Christos Stavrakakis
    floating_ips = map(ip_to_dict, floating_ips)
98 59183afc Christos Stavrakakis
99 59183afc Christos Stavrakakis
    request.serialization = "json"
100 59183afc Christos Stavrakakis
    data = json.dumps({"floating_ips": floating_ips})
101 59183afc Christos Stavrakakis
102 59183afc Christos Stavrakakis
    return HttpResponse(data, status=200)
103 59183afc Christos Stavrakakis
104 59183afc Christos Stavrakakis
105 59183afc Christos Stavrakakis
@api.api_method(http_method="GET", user_required=True, logger=log)
106 59183afc Christos Stavrakakis
def get_floating_ip(request, floating_ip_id):
107 59183afc Christos Stavrakakis
    """Return information for a floating IP."""
108 59183afc Christos Stavrakakis
    userid = request.user_uniq
109 59183afc Christos Stavrakakis
    try:
110 59183afc Christos Stavrakakis
        floating_ip = FloatingIP.objects.get(id=floating_ip_id,
111 59183afc Christos Stavrakakis
                                             deleted=False,
112 59183afc Christos Stavrakakis
                                             userid=userid)
113 59183afc Christos Stavrakakis
    except FloatingIP.DoesNotExist:
114 59183afc Christos Stavrakakis
        raise faults.ItemNotFound("Floating IP '%s' does not exist" %
115 59183afc Christos Stavrakakis
                                  floating_ip_id)
116 59183afc Christos Stavrakakis
    request.serialization = "json"
117 59183afc Christos Stavrakakis
    data = json.dumps({"floating_ip": ip_to_dict(floating_ip)})
118 59183afc Christos Stavrakakis
    return HttpResponse(data, status=200)
119 59183afc Christos Stavrakakis
120 59183afc Christos Stavrakakis
121 59183afc Christos Stavrakakis
@api.api_method(http_method='POST', user_required=True, logger=log)
122 59183afc Christos Stavrakakis
@transaction.commit_manually
123 59183afc Christos Stavrakakis
def allocate_floating_ip(request):
124 59183afc Christos Stavrakakis
    """Allocate a floating IP."""
125 59183afc Christos Stavrakakis
    req = utils.get_request_dict(request)
126 59183afc Christos Stavrakakis
    log.info('allocate_floating_ip %s', req)
127 59183afc Christos Stavrakakis
128 59183afc Christos Stavrakakis
    userid = request.user_uniq
129 9e8be4fb Christos Stavrakakis
    pool = req.get("pool", None)
130 a3d99af0 Christos Stavrakakis
    address = req.get("address", None)
131 a3d99af0 Christos Stavrakakis
    machine = None
132 9115d567 Christos Stavrakakis
    net_objects = Network.objects.select_for_update()\
133 9115d567 Christos Stavrakakis
                                 .filter(public=True, floating_ip_pool=True,
134 9115d567 Christos Stavrakakis
                                         deleted=False)
135 59183afc Christos Stavrakakis
    try:
136 9e8be4fb Christos Stavrakakis
        if pool is None:
137 9e8be4fb Christos Stavrakakis
            # User did not specified a pool. Choose a random public IP
138 9e8be4fb Christos Stavrakakis
            network, address = util.allocate_public_ip(net_objects)
139 a3d99af0 Christos Stavrakakis
        else:
140 9e8be4fb Christos Stavrakakis
            try:
141 9115d567 Christos Stavrakakis
                network = Network.objects.select_for_update()\
142 9115d567 Christos Stavrakakis
                                         .get(id=pool, public=True,
143 9115d567 Christos Stavrakakis
                                              deleted=False,
144 9115d567 Christos Stavrakakis
                                              floating_ip_pool=True)
145 9115d567 Christos Stavrakakis
146 f8675683 Christos Stavrakakis
            except Network.DoesNotExist:
147 9e8be4fb Christos Stavrakakis
                raise faults.ItemNotFound("Pool '%s' does not exist." % pool)
148 9e8be4fb Christos Stavrakakis
            if address is None:
149 9e8be4fb Christos Stavrakakis
                # User did not specified an IP address. Choose a random one
150 9e8be4fb Christos Stavrakakis
                # Gets X-Lock on IP pool
151 9e8be4fb Christos Stavrakakis
                address = util.get_network_free_address(network)
152 9e8be4fb Christos Stavrakakis
            else:
153 9e8be4fb Christos Stavrakakis
                # User specified an IP address. Check that it is not a used
154 9e8be4fb Christos Stavrakakis
                # floating IP
155 9e8be4fb Christos Stavrakakis
                if FloatingIP.objects.filter(network=network,
156 9e8be4fb Christos Stavrakakis
                                             deleted=False,
157 9e8be4fb Christos Stavrakakis
                                             ipv4=address).exists():
158 9e8be4fb Christos Stavrakakis
                    msg = "Floating IP '%s' is reserved" % address
159 a3d99af0 Christos Stavrakakis
                    raise faults.Conflict(msg)
160 9e8be4fb Christos Stavrakakis
                pool = network.get_pool()  # Gets X-Lock
161 9e8be4fb Christos Stavrakakis
                # Check address belongs to pool
162 9e8be4fb Christos Stavrakakis
                if not pool.contains(address):
163 9e8be4fb Christos Stavrakakis
                    raise faults.BadRequest("Invalid address")
164 9e8be4fb Christos Stavrakakis
                if pool.is_available(address):
165 9e8be4fb Christos Stavrakakis
                    pool.reserve(address)
166 9e8be4fb Christos Stavrakakis
                    pool.save()
167 9e8be4fb Christos Stavrakakis
                # If address is not available, check that it belongs to the
168 9e8be4fb Christos Stavrakakis
                # same user
169 9e8be4fb Christos Stavrakakis
                elif not network.nics.filter(ipv4=address,
170 9e8be4fb Christos Stavrakakis
                                            machine__userid=userid).exists():
171 9e8be4fb Christos Stavrakakis
                        msg = "Address '%s' is already in use" % address
172 9e8be4fb Christos Stavrakakis
                        raise faults.Conflict(msg)
173 59183afc Christos Stavrakakis
        floating_ip = FloatingIP.objects.create(ipv4=address, network=network,
174 a3d99af0 Christos Stavrakakis
                                                userid=userid, machine=machine)
175 59183afc Christos Stavrakakis
        quotas.issue_and_accept_commission(floating_ip)
176 59183afc Christos Stavrakakis
    except:
177 59183afc Christos Stavrakakis
        transaction.rollback()
178 59183afc Christos Stavrakakis
        raise
179 59183afc Christos Stavrakakis
    else:
180 59183afc Christos Stavrakakis
        transaction.commit()
181 59183afc Christos Stavrakakis
182 59183afc Christos Stavrakakis
    log.info("User '%s' allocated floating IP '%s", userid, floating_ip)
183 59183afc Christos Stavrakakis
184 59183afc Christos Stavrakakis
    request.serialization = "json"
185 59183afc Christos Stavrakakis
    data = json.dumps({"floating_ip": ip_to_dict(floating_ip)})
186 59183afc Christos Stavrakakis
    return HttpResponse(data, status=200)
187 59183afc Christos Stavrakakis
188 59183afc Christos Stavrakakis
189 59183afc Christos Stavrakakis
@api.api_method(http_method='DELETE', user_required=True, logger=log)
190 59183afc Christos Stavrakakis
@transaction.commit_on_success
191 59183afc Christos Stavrakakis
def release_floating_ip(request, floating_ip_id):
192 59183afc Christos Stavrakakis
    """Release a floating IP."""
193 59183afc Christos Stavrakakis
    userid = request.user_uniq
194 59183afc Christos Stavrakakis
    log.info("release_floating_ip '%s'. User '%s'.", floating_ip_id, userid)
195 59183afc Christos Stavrakakis
    try:
196 59183afc Christos Stavrakakis
        floating_ip = FloatingIP.objects.select_for_update()\
197 59183afc Christos Stavrakakis
                                        .get(id=floating_ip_id,
198 59183afc Christos Stavrakakis
                                             deleted=False,
199 59183afc Christos Stavrakakis
                                             userid=userid)
200 59183afc Christos Stavrakakis
    except FloatingIP.DoesNotExist:
201 59183afc Christos Stavrakakis
        raise faults.ItemNotFound("Floating IP '%s' does not exist" %
202 59183afc Christos Stavrakakis
                                  floating_ip_id)
203 59183afc Christos Stavrakakis
204 72dea98f Christos Stavrakakis
    # Since we have got an exlusively lock in floating IP, and since
205 72dea98f Christos Stavrakakis
    # to remove a floating IP you need the same lock, the in_use() query
206 72dea98f Christos Stavrakakis
    # is safe
207 59183afc Christos Stavrakakis
    if floating_ip.in_use():
208 59183afc Christos Stavrakakis
        msg = "Floating IP '%s' is used" % floating_ip.id
209 59183afc Christos Stavrakakis
        raise faults.Conflict(message=msg)
210 59183afc Christos Stavrakakis
211 59183afc Christos Stavrakakis
    try:
212 59183afc Christos Stavrakakis
        floating_ip.network.release_address(floating_ip.ipv4)
213 59183afc Christos Stavrakakis
        floating_ip.deleted = True
214 59183afc Christos Stavrakakis
        quotas.issue_and_accept_commission(floating_ip, delete=True)
215 59183afc Christos Stavrakakis
    except:
216 59183afc Christos Stavrakakis
        transaction.rollback()
217 59183afc Christos Stavrakakis
        raise
218 59183afc Christos Stavrakakis
    else:
219 59183afc Christos Stavrakakis
        floating_ip.delete()
220 59183afc Christos Stavrakakis
        transaction.commit()
221 59183afc Christos Stavrakakis
222 59183afc Christos Stavrakakis
    log.info("User '%s' released IP '%s", userid, floating_ip)
223 59183afc Christos Stavrakakis
224 59183afc Christos Stavrakakis
    return HttpResponse(status=204)
225 7d368e73 Christos Stavrakakis
226 7d368e73 Christos Stavrakakis
227 7d368e73 Christos Stavrakakis
@api.api_method(http_method='GET', user_required=True, logger=log)
228 7d368e73 Christos Stavrakakis
def list_floating_ip_pools(request):
229 9115d567 Christos Stavrakakis
    networks = Network.objects.filter(public=True, deleted=False,
230 9115d567 Christos Stavrakakis
                                      floating_ip_pool=True)
231 7d368e73 Christos Stavrakakis
    pools = [{"name": str(net.id)} for net in networks]
232 7d368e73 Christos Stavrakakis
    request.serialization = "json"
233 7d368e73 Christos Stavrakakis
    data = json.dumps({"floating_ip_pools": pools})
234 7d368e73 Christos Stavrakakis
    request.serialization = "json"
235 7d368e73 Christos Stavrakakis
    return HttpResponse(data, status=200)