Statistics
| Branch: | Tag: | Revision:

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

History | View | Annotate | Download (8.1 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 a3d99af0 Christos Stavrakakis
from synnefo.db.models import Network, FloatingIP, NetworkInterface
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 59183afc Christos Stavrakakis
    try:
130 59183afc Christos Stavrakakis
        pool = req['pool']
131 59183afc Christos Stavrakakis
    except KeyError:
132 59183afc Christos Stavrakakis
        raise faults.BadRequest("Malformed request. Missing"
133 59183afc Christos Stavrakakis
                                " 'pool' attribute")
134 59183afc Christos Stavrakakis
135 59183afc Christos Stavrakakis
    try:
136 e57893cd Christos Stavrakakis
        objects = Network.objects.select_for_update()
137 e57893cd Christos Stavrakakis
        network = objects.get(id=pool, public=True, deleted=False)
138 59183afc Christos Stavrakakis
    except Network.DoesNotExist:
139 59183afc Christos Stavrakakis
        raise faults.ItemNotFound("Pool '%s' does not exist." % pool)
140 59183afc Christos Stavrakakis
141 a3d99af0 Christos Stavrakakis
    address = req.get("address", None)
142 a3d99af0 Christos Stavrakakis
    machine = None
143 59183afc Christos Stavrakakis
    try:
144 a3d99af0 Christos Stavrakakis
        if address is None:
145 a3d99af0 Christos Stavrakakis
            address = util.get_network_free_address(network)  # Get X-Lock
146 a3d99af0 Christos Stavrakakis
        else:
147 a3d99af0 Christos Stavrakakis
            if FloatingIP.objects.filter(network=network,
148 72dea98f Christos Stavrakakis
                                         deleted=False,
149 a3d99af0 Christos Stavrakakis
                                         ipv4=address).exists():
150 a3d99af0 Christos Stavrakakis
                msg = "Floating IP '%s' is reserved" % address
151 a3d99af0 Christos Stavrakakis
                raise faults.Conflict(msg)
152 a3d99af0 Christos Stavrakakis
            pool = network.get_pool()  # Gets X-Lock
153 a3d99af0 Christos Stavrakakis
            if not pool.contains(address):
154 a3d99af0 Christos Stavrakakis
                raise faults.BadRequest("Invalid address")
155 a3d99af0 Christos Stavrakakis
            if not pool.is_available(address):
156 a3d99af0 Christos Stavrakakis
                try:
157 a3d99af0 Christos Stavrakakis
                    network.nics.get(ipv4=address,
158 a3d99af0 Christos Stavrakakis
                                     machine__userid=userid)
159 a3d99af0 Christos Stavrakakis
                except NetworkInterface.DoesNotExist:
160 a3d99af0 Christos Stavrakakis
                    msg = "Address '%s' is already in use" % address
161 a3d99af0 Christos Stavrakakis
                    raise faults.Conflict(msg)
162 a3d99af0 Christos Stavrakakis
            pool.reserve(address)
163 a3d99af0 Christos Stavrakakis
            pool.save()
164 59183afc Christos Stavrakakis
        floating_ip = FloatingIP.objects.create(ipv4=address, network=network,
165 a3d99af0 Christos Stavrakakis
                                                userid=userid, machine=machine)
166 59183afc Christos Stavrakakis
        quotas.issue_and_accept_commission(floating_ip)
167 59183afc Christos Stavrakakis
    except:
168 59183afc Christos Stavrakakis
        transaction.rollback()
169 59183afc Christos Stavrakakis
        raise
170 59183afc Christos Stavrakakis
    else:
171 59183afc Christos Stavrakakis
        transaction.commit()
172 59183afc Christos Stavrakakis
173 59183afc Christos Stavrakakis
    log.info("User '%s' allocated floating IP '%s", userid, floating_ip)
174 59183afc Christos Stavrakakis
175 59183afc Christos Stavrakakis
    request.serialization = "json"
176 59183afc Christos Stavrakakis
    data = json.dumps({"floating_ip": ip_to_dict(floating_ip)})
177 59183afc Christos Stavrakakis
    return HttpResponse(data, status=200)
178 59183afc Christos Stavrakakis
179 59183afc Christos Stavrakakis
180 59183afc Christos Stavrakakis
@api.api_method(http_method='DELETE', user_required=True, logger=log)
181 59183afc Christos Stavrakakis
@transaction.commit_on_success
182 59183afc Christos Stavrakakis
def release_floating_ip(request, floating_ip_id):
183 59183afc Christos Stavrakakis
    """Release a floating IP."""
184 59183afc Christos Stavrakakis
    userid = request.user_uniq
185 59183afc Christos Stavrakakis
    log.info("release_floating_ip '%s'. User '%s'.", floating_ip_id, userid)
186 59183afc Christos Stavrakakis
    try:
187 59183afc Christos Stavrakakis
        floating_ip = FloatingIP.objects.select_for_update()\
188 59183afc Christos Stavrakakis
                                        .get(id=floating_ip_id,
189 59183afc Christos Stavrakakis
                                             deleted=False,
190 59183afc Christos Stavrakakis
                                             userid=userid)
191 59183afc Christos Stavrakakis
    except FloatingIP.DoesNotExist:
192 59183afc Christos Stavrakakis
        raise faults.ItemNotFound("Floating IP '%s' does not exist" %
193 59183afc Christos Stavrakakis
                                  floating_ip_id)
194 59183afc Christos Stavrakakis
195 72dea98f Christos Stavrakakis
    # Since we have got an exlusively lock in floating IP, and since
196 72dea98f Christos Stavrakakis
    # to remove a floating IP you need the same lock, the in_use() query
197 72dea98f Christos Stavrakakis
    # is safe
198 59183afc Christos Stavrakakis
    if floating_ip.in_use():
199 59183afc Christos Stavrakakis
        msg = "Floating IP '%s' is used" % floating_ip.id
200 59183afc Christos Stavrakakis
        raise faults.Conflict(message=msg)
201 59183afc Christos Stavrakakis
202 59183afc Christos Stavrakakis
    try:
203 59183afc Christos Stavrakakis
        floating_ip.network.release_address(floating_ip.ipv4)
204 59183afc Christos Stavrakakis
        floating_ip.deleted = True
205 59183afc Christos Stavrakakis
        quotas.issue_and_accept_commission(floating_ip, delete=True)
206 59183afc Christos Stavrakakis
    except:
207 59183afc Christos Stavrakakis
        transaction.rollback()
208 59183afc Christos Stavrakakis
        raise
209 59183afc Christos Stavrakakis
    else:
210 59183afc Christos Stavrakakis
        floating_ip.delete()
211 59183afc Christos Stavrakakis
        transaction.commit()
212 59183afc Christos Stavrakakis
213 59183afc Christos Stavrakakis
    log.info("User '%s' released IP '%s", userid, floating_ip)
214 59183afc Christos Stavrakakis
215 59183afc Christos Stavrakakis
    return HttpResponse(status=204)
216 7d368e73 Christos Stavrakakis
217 7d368e73 Christos Stavrakakis
218 7d368e73 Christos Stavrakakis
@api.api_method(http_method='GET', user_required=True, logger=log)
219 7d368e73 Christos Stavrakakis
def list_floating_ip_pools(request):
220 7d368e73 Christos Stavrakakis
    networks = Network.objects.filter(public=True, deleted=False)
221 7d368e73 Christos Stavrakakis
    pools = [{"name": str(net.id)} for net in networks]
222 7d368e73 Christos Stavrakakis
    request.serialization = "json"
223 7d368e73 Christos Stavrakakis
    data = json.dumps({"floating_ip_pools": pools})
224 7d368e73 Christos Stavrakakis
    request.serialization = "json"
225 7d368e73 Christos Stavrakakis
    return HttpResponse(data, status=200)