Statistics
| Branch: | Tag: | Revision:

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

History | View | Annotate | Download (7.8 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 fde2c1f7 Christos Stavrakakis
from synnefo.db import pools
45 59183afc Christos Stavrakakis
46 59183afc Christos Stavrakakis
47 59183afc Christos Stavrakakis
from logging import getLogger
48 59183afc Christos Stavrakakis
log = getLogger(__name__)
49 59183afc Christos Stavrakakis
50 7d368e73 Christos Stavrakakis
ips_urlpatterns = patterns(
51 59183afc Christos Stavrakakis
    'synnefo.api.floating_ips',
52 59183afc Christos Stavrakakis
    (r'^(?:/|.json|.xml)?$', 'demux'),
53 59183afc Christos Stavrakakis
    (r'^/(\w+)(?:.json|.xml)?$', 'floating_ip_demux'),
54 59183afc Christos Stavrakakis
)
55 59183afc Christos Stavrakakis
56 7d368e73 Christos Stavrakakis
pools_urlpatterns = patterns(
57 7d368e73 Christos Stavrakakis
    "synnefo.api.floating_ips",
58 7d368e73 Christos Stavrakakis
    (r'^(?:/|.json|.xml)?$', 'list_floating_ip_pools'),
59 7d368e73 Christos Stavrakakis
)
60 7d368e73 Christos Stavrakakis
61 59183afc Christos Stavrakakis
62 59183afc Christos Stavrakakis
def demux(request):
63 59183afc Christos Stavrakakis
    if request.method == 'GET':
64 59183afc Christos Stavrakakis
        return list_floating_ips(request)
65 59183afc Christos Stavrakakis
    elif request.method == 'POST':
66 59183afc Christos Stavrakakis
        return allocate_floating_ip(request)
67 59183afc Christos Stavrakakis
    else:
68 20a626e7 Giorgos Korfiatis
        return api.api_method_not_allowed(request)
69 59183afc Christos Stavrakakis
70 59183afc Christos Stavrakakis
71 59183afc Christos Stavrakakis
def floating_ip_demux(request, floating_ip_id):
72 59183afc Christos Stavrakakis
    if request.method == 'GET':
73 59183afc Christos Stavrakakis
        return get_floating_ip(request, floating_ip_id)
74 59183afc Christos Stavrakakis
    elif request.method == 'DELETE':
75 59183afc Christos Stavrakakis
        return release_floating_ip(request, floating_ip_id)
76 59183afc Christos Stavrakakis
    else:
77 20a626e7 Giorgos Korfiatis
        return api.api_method_not_allowed(request)
78 59183afc Christos Stavrakakis
79 59183afc Christos Stavrakakis
80 59183afc Christos Stavrakakis
def ip_to_dict(floating_ip):
81 fde2c1f7 Christos Stavrakakis
    machine_id = None
82 fde2c1f7 Christos Stavrakakis
    if floating_ip.nic is not None:
83 fde2c1f7 Christos Stavrakakis
        machine_id = floating_ip.nic.machine_id
84 59183afc Christos Stavrakakis
    return {"fixed_ip": None,
85 59183afc Christos Stavrakakis
            "id": str(floating_ip.id),
86 59183afc Christos Stavrakakis
            "instance_id": str(machine_id) if machine_id else None,
87 fde2c1f7 Christos Stavrakakis
            "ip": floating_ip.address,
88 59183afc Christos Stavrakakis
            "pool": str(floating_ip.network_id)}
89 59183afc Christos Stavrakakis
90 59183afc Christos Stavrakakis
91 1cbe2522 Christos Stavrakakis
@api.api_method(http_method="GET", user_required=True, logger=log,
92 1cbe2522 Christos Stavrakakis
                serializations=["json"])
93 59183afc Christos Stavrakakis
def list_floating_ips(request):
94 59183afc Christos Stavrakakis
    """Return user reserved floating IPs"""
95 59183afc Christos Stavrakakis
    log.debug("list_floating_ips")
96 59183afc Christos Stavrakakis
97 59183afc Christos Stavrakakis
    userid = request.user_uniq
98 fde2c1f7 Christos Stavrakakis
    floating_ips = IPAddress.objects.filter(userid=userid, deleted=False,
99 fde2c1f7 Christos Stavrakakis
                                            floating_ip=True).order_by("id")\
100 fde2c1f7 Christos Stavrakakis
                                    .select_related("nic")
101 b6bc4afa Christos Stavrakakis
    floating_ips = utils.filter_modified_since(request, objects=floating_ips)
102 59183afc Christos Stavrakakis
103 59183afc Christos Stavrakakis
    floating_ips = map(ip_to_dict, floating_ips)
104 59183afc Christos Stavrakakis
105 59183afc Christos Stavrakakis
    request.serialization = "json"
106 59183afc Christos Stavrakakis
    data = json.dumps({"floating_ips": floating_ips})
107 59183afc Christos Stavrakakis
108 59183afc Christos Stavrakakis
    return HttpResponse(data, status=200)
109 59183afc Christos Stavrakakis
110 59183afc Christos Stavrakakis
111 1cbe2522 Christos Stavrakakis
@api.api_method(http_method="GET", user_required=True, logger=log,
112 1cbe2522 Christos Stavrakakis
                serializations=["json"])
113 59183afc Christos Stavrakakis
def get_floating_ip(request, floating_ip_id):
114 59183afc Christos Stavrakakis
    """Return information for a floating IP."""
115 59183afc Christos Stavrakakis
    userid = request.user_uniq
116 fde2c1f7 Christos Stavrakakis
    floating_ip = util.get_floating_ip_by_id(userid, floating_ip_id)
117 59183afc Christos Stavrakakis
    request.serialization = "json"
118 59183afc Christos Stavrakakis
    data = json.dumps({"floating_ip": ip_to_dict(floating_ip)})
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='POST', user_required=True, logger=log,
123 1cbe2522 Christos Stavrakakis
                serializations=["json"])
124 fde2c1f7 Christos Stavrakakis
@transaction.commit_on_success
125 59183afc Christos Stavrakakis
def allocate_floating_ip(request):
126 59183afc Christos Stavrakakis
    """Allocate a floating IP."""
127 59183afc Christos Stavrakakis
    req = utils.get_request_dict(request)
128 59183afc Christos Stavrakakis
    log.info('allocate_floating_ip %s', req)
129 59183afc Christos Stavrakakis
130 59183afc Christos Stavrakakis
    userid = request.user_uniq
131 9e8be4fb Christos Stavrakakis
    pool = req.get("pool", None)
132 a3d99af0 Christos Stavrakakis
    address = req.get("address", None)
133 59183afc Christos Stavrakakis
134 fde2c1f7 Christos Stavrakakis
    if pool is None:
135 fde2c1f7 Christos Stavrakakis
        # User did not specified a pool. Choose a random public IP
136 fde2c1f7 Christos Stavrakakis
        try:
137 fde2c1f7 Christos Stavrakakis
            floating_ip = util.allocate_public_ip(userid=userid,
138 fde2c1f7 Christos Stavrakakis
                                                  floating_ip=True)
139 fde2c1f7 Christos Stavrakakis
        except pools.EmptyPool:
140 fde2c1f7 Christos Stavrakakis
            raise faults.Conflict("No more IP addresses available.")
141 fde2c1f7 Christos Stavrakakis
    else:
142 fde2c1f7 Christos Stavrakakis
        try:
143 fde2c1f7 Christos Stavrakakis
            network_id = int(pool)
144 fde2c1f7 Christos Stavrakakis
        except ValueError:
145 fde2c1f7 Christos Stavrakakis
            raise faults.BadRequest("Invalid pool ID.")
146 fde2c1f7 Christos Stavrakakis
        network = util.get_network(network_id, userid, for_update=True,
147 fde2c1f7 Christos Stavrakakis
                                   non_deleted=True)
148 fde2c1f7 Christos Stavrakakis
        if not network.floating_ip_pool:
149 fde2c1f7 Christos Stavrakakis
            # Check that it is a floating IP pool
150 fde2c1f7 Christos Stavrakakis
            raise faults.ItemNotFound("Floating IP pool %s does not exist." %
151 fde2c1f7 Christos Stavrakakis
                                      network_id)
152 fde2c1f7 Christos Stavrakakis
        floating_ip = util.allocate_ip(network, userid, address=address,
153 fde2c1f7 Christos Stavrakakis
                                       floating_ip=True)
154 fde2c1f7 Christos Stavrakakis
155 fde2c1f7 Christos Stavrakakis
    quotas.issue_and_accept_commission(floating_ip)
156 fde2c1f7 Christos Stavrakakis
    transaction.commit()
157 fde2c1f7 Christos Stavrakakis
158 fde2c1f7 Christos Stavrakakis
    log.info("User '%s' allocated floating IP '%s'", userid, floating_ip)
159 59183afc Christos Stavrakakis
160 59183afc Christos Stavrakakis
    request.serialization = "json"
161 59183afc Christos Stavrakakis
    data = json.dumps({"floating_ip": ip_to_dict(floating_ip)})
162 59183afc Christos Stavrakakis
    return HttpResponse(data, status=200)
163 59183afc Christos Stavrakakis
164 59183afc Christos Stavrakakis
165 1cbe2522 Christos Stavrakakis
@api.api_method(http_method='DELETE', user_required=True, logger=log,
166 1cbe2522 Christos Stavrakakis
                serializations=["json"])
167 59183afc Christos Stavrakakis
@transaction.commit_on_success
168 59183afc Christos Stavrakakis
def release_floating_ip(request, floating_ip_id):
169 59183afc Christos Stavrakakis
    """Release a floating IP."""
170 59183afc Christos Stavrakakis
    userid = request.user_uniq
171 59183afc Christos Stavrakakis
    log.info("release_floating_ip '%s'. User '%s'.", floating_ip_id, userid)
172 fde2c1f7 Christos Stavrakakis
173 fde2c1f7 Christos Stavrakakis
    floating_ip = util.get_floating_ip_by_id(userid, floating_ip_id,
174 fde2c1f7 Christos Stavrakakis
                                             for_update=True)
175 fde2c1f7 Christos Stavrakakis
    if floating_ip.nic:
176 fde2c1f7 Christos Stavrakakis
        # This is safe, you also need for_update to attach floating IP to
177 fde2c1f7 Christos Stavrakakis
        # instance.
178 fde2c1f7 Christos Stavrakakis
        msg = "Floating IP '%s' is attached to instance." % floating_ip.id
179 fde2c1f7 Christos Stavrakakis
        raise faults.Conflict(msg)
180 fde2c1f7 Christos Stavrakakis
181 fde2c1f7 Christos Stavrakakis
    # Return the address of the floating IP back to pool
182 fde2c1f7 Christos Stavrakakis
    floating_ip.release_address()
183 fde2c1f7 Christos Stavrakakis
    # And mark the floating IP as deleted
184 fde2c1f7 Christos Stavrakakis
    floating_ip.deleted = True
185 fde2c1f7 Christos Stavrakakis
    floating_ip.save()
186 fde2c1f7 Christos Stavrakakis
    # Release quota for floating IP
187 fde2c1f7 Christos Stavrakakis
    quotas.issue_and_accept_commission(floating_ip, delete=True)
188 fde2c1f7 Christos Stavrakakis
    transaction.commit()
189 fde2c1f7 Christos Stavrakakis
    # Delete the floating IP from DB
190 fde2c1f7 Christos Stavrakakis
    floating_ip.delete()
191 59183afc Christos Stavrakakis
192 59183afc Christos Stavrakakis
    log.info("User '%s' released IP '%s", userid, floating_ip)
193 59183afc Christos Stavrakakis
194 59183afc Christos Stavrakakis
    return HttpResponse(status=204)
195 7d368e73 Christos Stavrakakis
196 7d368e73 Christos Stavrakakis
197 fde2c1f7 Christos Stavrakakis
# Floating IP pools
198 1cbe2522 Christos Stavrakakis
@api.api_method(http_method='GET', user_required=True, logger=log,
199 1cbe2522 Christos Stavrakakis
                serializations=["json"])
200 7d368e73 Christos Stavrakakis
def list_floating_ip_pools(request):
201 fde2c1f7 Christos Stavrakakis
    networks = Network.objects.filter(public=True, floating_ip_pool=True,
202 fde2c1f7 Christos Stavrakakis
                                      deleted=False)
203 b6bc4afa Christos Stavrakakis
    networks = utils.filter_modified_since(request, objects=networks)
204 fde2c1f7 Christos Stavrakakis
    pools = map(network_to_floating_ip_pool, networks)
205 7d368e73 Christos Stavrakakis
    request.serialization = "json"
206 7d368e73 Christos Stavrakakis
    data = json.dumps({"floating_ip_pools": pools})
207 7d368e73 Christos Stavrakakis
    request.serialization = "json"
208 7d368e73 Christos Stavrakakis
    return HttpResponse(data, status=200)
209 fde2c1f7 Christos Stavrakakis
210 fde2c1f7 Christos Stavrakakis
211 fde2c1f7 Christos Stavrakakis
def network_to_floating_ip_pool(network):
212 fde2c1f7 Christos Stavrakakis
    """Convert a 'Network' object to a floating IP pool dict."""
213 fde2c1f7 Christos Stavrakakis
    total, free = network.ip_count()
214 fde2c1f7 Christos Stavrakakis
    return {"name": str(network.id),
215 fde2c1f7 Christos Stavrakakis
            "size": total,
216 fde2c1f7 Christos Stavrakakis
            "free": free}