Statistics
| Branch: | Tag: | Revision:

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

History | View | Annotate | Download (10.6 kB)

1 ff5edb80 Giorgos Korfiatis
# Copyright 2013-2014 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 0292883e Christos Stavrakakis
from synnefo.logic import ips
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 99667854 Giorgos Korfiatis
    (r'^/(\w+)(?:/|.json|.xml)?$', 'floating_ip_demux'),
66 99667854 Giorgos Korfiatis
    (r'^/(\w+)/action(?:.json|.xml)?$', 'floating_ip_action_demux'),
67 99667854 Giorgos Korfiatis
)
68 7d368e73 Christos Stavrakakis
69 59183afc Christos Stavrakakis
70 59183afc Christos Stavrakakis
def demux(request):
71 59183afc Christos Stavrakakis
    if request.method == 'GET':
72 59183afc Christos Stavrakakis
        return list_floating_ips(request)
73 59183afc Christos Stavrakakis
    elif request.method == 'POST':
74 59183afc Christos Stavrakakis
        return allocate_floating_ip(request)
75 59183afc Christos Stavrakakis
    else:
76 2aba7764 Sofia Papagiannaki
        return api.api_method_not_allowed(request,
77 2aba7764 Sofia Papagiannaki
                                          allowed_methods=['GET', 'POST'])
78 59183afc Christos Stavrakakis
79 59183afc Christos Stavrakakis
80 59183afc Christos Stavrakakis
def floating_ip_demux(request, floating_ip_id):
81 59183afc Christos Stavrakakis
    if request.method == 'GET':
82 59183afc Christos Stavrakakis
        return get_floating_ip(request, floating_ip_id)
83 59183afc Christos Stavrakakis
    elif request.method == 'DELETE':
84 59183afc Christos Stavrakakis
        return release_floating_ip(request, floating_ip_id)
85 e4f484da Marios Kogias
    elif request.method == 'PUT':
86 e4f484da Marios Kogias
        return update_floating_ip(request, floating_ip_id)
87 59183afc Christos Stavrakakis
    else:
88 2aba7764 Sofia Papagiannaki
        return api.api_method_not_allowed(request,
89 2aba7764 Sofia Papagiannaki
                                          allowed_methods=['GET', 'DELETE'])
90 59183afc Christos Stavrakakis
91 59183afc Christos Stavrakakis
92 99667854 Giorgos Korfiatis
@api.api_method(http_method='POST', user_required=True, logger=log,
93 99667854 Giorgos Korfiatis
                serializations=["json"])
94 99667854 Giorgos Korfiatis
def floating_ip_action_demux(request, floating_ip_id):
95 99667854 Giorgos Korfiatis
    userid = request.user_uniq
96 99667854 Giorgos Korfiatis
    req = utils.get_request_dict(request)
97 99667854 Giorgos Korfiatis
    log.debug('floating_ip_action %s %s', floating_ip_id, req)
98 99667854 Giorgos Korfiatis
    if len(req) != 1:
99 99667854 Giorgos Korfiatis
        raise faults.BadRequest('Malformed request.')
100 99667854 Giorgos Korfiatis
    floating_ip = util.get_floating_ip_by_id(userid,
101 99667854 Giorgos Korfiatis
                                             floating_ip_id,
102 99667854 Giorgos Korfiatis
                                             for_update=True)
103 99667854 Giorgos Korfiatis
    action = req.keys()[0]
104 99667854 Giorgos Korfiatis
    try:
105 99667854 Giorgos Korfiatis
        f = FLOATING_IP_ACTIONS[action]
106 99667854 Giorgos Korfiatis
    except KeyError:
107 99667854 Giorgos Korfiatis
        raise faults.BadRequest("Action %s not supported." % action)
108 99667854 Giorgos Korfiatis
    action_args = req[action]
109 99667854 Giorgos Korfiatis
    if not isinstance(action_args, dict):
110 99667854 Giorgos Korfiatis
        raise faults.BadRequest("Invalid argument.")
111 99667854 Giorgos Korfiatis
112 99667854 Giorgos Korfiatis
    return f(request, floating_ip, action_args)
113 99667854 Giorgos Korfiatis
114 99667854 Giorgos Korfiatis
115 59183afc Christos Stavrakakis
def ip_to_dict(floating_ip):
116 fde2c1f7 Christos Stavrakakis
    machine_id = None
117 e4f484da Marios Kogias
    port_id = None
118 fde2c1f7 Christos Stavrakakis
    if floating_ip.nic is not None:
119 fde2c1f7 Christos Stavrakakis
        machine_id = floating_ip.nic.machine_id
120 e4f484da Marios Kogias
        port_id = floating_ip.nic.id
121 e4f484da Marios Kogias
    return {"fixed_ip_address": None,
122 59183afc Christos Stavrakakis
            "id": str(floating_ip.id),
123 59183afc Christos Stavrakakis
            "instance_id": str(machine_id) if machine_id else None,
124 e4f484da Marios Kogias
            "floating_ip_address": floating_ip.address,
125 03d430b5 Christos Stavrakakis
            "port_id": str(port_id) if port_id else None,
126 7219c7a3 Christos Stavrakakis
            "floating_network_id": str(floating_ip.network_id),
127 02353a1a Giorgos Korfiatis
            "user_id": floating_ip.userid,
128 02353a1a Giorgos Korfiatis
            "tenant_id": floating_ip.project,
129 7219c7a3 Christos Stavrakakis
            "deleted": floating_ip.deleted}
130 59183afc Christos Stavrakakis
131 59183afc Christos Stavrakakis
132 1cbe2522 Christos Stavrakakis
@api.api_method(http_method="GET", user_required=True, logger=log,
133 1cbe2522 Christos Stavrakakis
                serializations=["json"])
134 59183afc Christos Stavrakakis
def list_floating_ips(request):
135 59183afc Christos Stavrakakis
    """Return user reserved floating IPs"""
136 59183afc Christos Stavrakakis
    log.debug("list_floating_ips")
137 59183afc Christos Stavrakakis
138 59183afc Christos Stavrakakis
    userid = request.user_uniq
139 fde2c1f7 Christos Stavrakakis
    floating_ips = IPAddress.objects.filter(userid=userid, deleted=False,
140 fde2c1f7 Christos Stavrakakis
                                            floating_ip=True).order_by("id")\
141 fde2c1f7 Christos Stavrakakis
                                    .select_related("nic")
142 b6bc4afa Christos Stavrakakis
    floating_ips = utils.filter_modified_since(request, objects=floating_ips)
143 59183afc Christos Stavrakakis
144 59183afc Christos Stavrakakis
    floating_ips = map(ip_to_dict, floating_ips)
145 59183afc Christos Stavrakakis
146 59183afc Christos Stavrakakis
    request.serialization = "json"
147 53b0ea25 Christos Stavrakakis
    data = json.dumps({"floatingips": floating_ips})
148 59183afc Christos Stavrakakis
149 59183afc Christos Stavrakakis
    return HttpResponse(data, status=200)
150 59183afc Christos Stavrakakis
151 59183afc Christos Stavrakakis
152 1cbe2522 Christos Stavrakakis
@api.api_method(http_method="GET", user_required=True, logger=log,
153 1cbe2522 Christos Stavrakakis
                serializations=["json"])
154 59183afc Christos Stavrakakis
def get_floating_ip(request, floating_ip_id):
155 59183afc Christos Stavrakakis
    """Return information for a floating IP."""
156 59183afc Christos Stavrakakis
    userid = request.user_uniq
157 fde2c1f7 Christos Stavrakakis
    floating_ip = util.get_floating_ip_by_id(userid, floating_ip_id)
158 59183afc Christos Stavrakakis
    request.serialization = "json"
159 53b0ea25 Christos Stavrakakis
    data = json.dumps({"floatingip": ip_to_dict(floating_ip)})
160 59183afc Christos Stavrakakis
    return HttpResponse(data, status=200)
161 59183afc Christos Stavrakakis
162 59183afc Christos Stavrakakis
163 1cbe2522 Christos Stavrakakis
@api.api_method(http_method='POST', user_required=True, logger=log,
164 1cbe2522 Christos Stavrakakis
                serializations=["json"])
165 fde2c1f7 Christos Stavrakakis
@transaction.commit_on_success
166 59183afc Christos Stavrakakis
def allocate_floating_ip(request):
167 59183afc Christos Stavrakakis
    """Allocate a floating IP."""
168 59183afc Christos Stavrakakis
    req = utils.get_request_dict(request)
169 e4f484da Marios Kogias
    floating_ip_dict = api.utils.get_attribute(req, "floatingip",
170 14402edc Christos Stavrakakis
                                               required=True, attr_type=dict)
171 59183afc Christos Stavrakakis
    log.info('allocate_floating_ip %s', req)
172 59183afc Christos Stavrakakis
173 59183afc Christos Stavrakakis
    userid = request.user_uniq
174 47c27955 Giorgos Korfiatis
    project = floating_ip_dict.get("project", None)
175 e4f484da Marios Kogias
176 e4f484da Marios Kogias
    # the network_pool is a mandatory field
177 4edfc376 Christos Stavrakakis
    network_id = api.utils.get_attribute(floating_ip_dict,
178 4edfc376 Christos Stavrakakis
                                         "floating_network_id",
179 14402edc Christos Stavrakakis
                                         required=False,
180 14402edc Christos Stavrakakis
                                         attr_type=(basestring, int))
181 4edfc376 Christos Stavrakakis
    if network_id is None:
182 47c27955 Giorgos Korfiatis
        floating_ip = ips.create_floating_ip(userid, project=project)
183 4edfc376 Christos Stavrakakis
    else:
184 4edfc376 Christos Stavrakakis
        try:
185 4edfc376 Christos Stavrakakis
            network_id = int(network_id)
186 4edfc376 Christos Stavrakakis
        except ValueError:
187 4edfc376 Christos Stavrakakis
            raise faults.BadRequest("Invalid networkd ID.")
188 4edfc376 Christos Stavrakakis
189 4edfc376 Christos Stavrakakis
        network = util.get_network(network_id, userid, for_update=True,
190 4edfc376 Christos Stavrakakis
                                   non_deleted=True)
191 4edfc376 Christos Stavrakakis
        address = api.utils.get_attribute(floating_ip_dict,
192 4edfc376 Christos Stavrakakis
                                          "floating_ip_address",
193 14402edc Christos Stavrakakis
                                          required=False,
194 14402edc Christos Stavrakakis
                                          attr_type=basestring)
195 47c27955 Giorgos Korfiatis
        floating_ip = ips.create_floating_ip(userid, network, address,
196 47c27955 Giorgos Korfiatis
                                             project=project)
197 fde2c1f7 Christos Stavrakakis
198 fde2c1f7 Christos Stavrakakis
    log.info("User '%s' allocated floating IP '%s'", userid, floating_ip)
199 59183afc Christos Stavrakakis
    request.serialization = "json"
200 53b0ea25 Christos Stavrakakis
    data = json.dumps({"floatingip": ip_to_dict(floating_ip)})
201 59183afc Christos Stavrakakis
    return HttpResponse(data, status=200)
202 59183afc Christos Stavrakakis
203 59183afc Christos Stavrakakis
204 1cbe2522 Christos Stavrakakis
@api.api_method(http_method='DELETE', user_required=True, logger=log,
205 1cbe2522 Christos Stavrakakis
                serializations=["json"])
206 59183afc Christos Stavrakakis
@transaction.commit_on_success
207 59183afc Christos Stavrakakis
def release_floating_ip(request, floating_ip_id):
208 59183afc Christos Stavrakakis
    """Release a floating IP."""
209 59183afc Christos Stavrakakis
    userid = request.user_uniq
210 59183afc Christos Stavrakakis
    log.info("release_floating_ip '%s'. User '%s'.", floating_ip_id, userid)
211 fde2c1f7 Christos Stavrakakis
212 fde2c1f7 Christos Stavrakakis
    floating_ip = util.get_floating_ip_by_id(userid, floating_ip_id,
213 fde2c1f7 Christos Stavrakakis
                                             for_update=True)
214 0292883e Christos Stavrakakis
    ips.delete_floating_ip(floating_ip)
215 59183afc Christos Stavrakakis
    log.info("User '%s' released IP '%s", userid, floating_ip)
216 59183afc Christos Stavrakakis
217 59183afc Christos Stavrakakis
    return HttpResponse(status=204)
218 7d368e73 Christos Stavrakakis
219 7d368e73 Christos Stavrakakis
220 e4f484da Marios Kogias
@api.api_method(http_method='PUT', user_required=True, logger=log,
221 e4f484da Marios Kogias
                serializations=["json"])
222 e4f484da Marios Kogias
@transaction.commit_on_success
223 e4f484da Marios Kogias
def update_floating_ip(request, floating_ip_id):
224 e4f484da Marios Kogias
    """Update a floating IP."""
225 1fb3293d Christos Stavrakakis
    raise faults.NotImplemented("Updating a floating IP is not supported.")
226 d610698e Christos Stavrakakis
    #userid = request.user_uniq
227 d610698e Christos Stavrakakis
    #log.info("update_floating_ip '%s'. User '%s'.", floating_ip_id, userid)
228 d610698e Christos Stavrakakis
229 d610698e Christos Stavrakakis
    #req = utils.get_request_dict(request)
230 d610698e Christos Stavrakakis
    #info = api.utils.get_attribute(req, "floatingip", required=True)
231 d610698e Christos Stavrakakis
232 d610698e Christos Stavrakakis
    #device_id = api.utils.get_attribute(info, "device_id", required=False)
233 d610698e Christos Stavrakakis
234 d610698e Christos Stavrakakis
    #floating_ip = util.get_floating_ip_by_id(userid, floating_ip_id,
235 d610698e Christos Stavrakakis
    #                                         for_update=True)
236 d610698e Christos Stavrakakis
    #if device_id:
237 d610698e Christos Stavrakakis
    #    # attach
238 d610698e Christos Stavrakakis
    #    vm = util.get_vm(device_id, userid)
239 d610698e Christos Stavrakakis
    #    nic, floating_ip = servers.create_nic(vm, ipaddress=floating_ip)
240 d610698e Christos Stavrakakis
    #    backend.connect_to_network(vm, nic)
241 d610698e Christos Stavrakakis
    #else:
242 d610698e Christos Stavrakakis
    #    # dettach
243 d610698e Christos Stavrakakis
    #    nic = floating_ip.nic
244 d610698e Christos Stavrakakis
    #    if not nic:
245 d610698e Christos Stavrakakis
    #        raise faults.BadRequest("The floating IP is not associated\
246 d610698e Christos Stavrakakis
    #                                with any device")
247 d610698e Christos Stavrakakis
    #    vm = nic.machine
248 d610698e Christos Stavrakakis
    #    servers.disconnect(vm, nic)
249 d610698e Christos Stavrakakis
    #return HttpResponse(status=202)
250 e4f484da Marios Kogias
251 e4f484da Marios Kogias
252 fde2c1f7 Christos Stavrakakis
# Floating IP pools
253 1cbe2522 Christos Stavrakakis
@api.api_method(http_method='GET', user_required=True, logger=log,
254 1cbe2522 Christos Stavrakakis
                serializations=["json"])
255 7d368e73 Christos Stavrakakis
def list_floating_ip_pools(request):
256 fde2c1f7 Christos Stavrakakis
    networks = Network.objects.filter(public=True, floating_ip_pool=True,
257 fde2c1f7 Christos Stavrakakis
                                      deleted=False)
258 b6bc4afa Christos Stavrakakis
    networks = utils.filter_modified_since(request, objects=networks)
259 d610698e Christos Stavrakakis
    floating_ip_pools = map(network_to_floating_ip_pool, networks)
260 7d368e73 Christos Stavrakakis
    request.serialization = "json"
261 d610698e Christos Stavrakakis
    data = json.dumps({"floating_ip_pools": floating_ip_pools})
262 7d368e73 Christos Stavrakakis
    request.serialization = "json"
263 7d368e73 Christos Stavrakakis
    return HttpResponse(data, status=200)
264 fde2c1f7 Christos Stavrakakis
265 fde2c1f7 Christos Stavrakakis
266 99667854 Giorgos Korfiatis
@transaction.commit_on_success
267 99667854 Giorgos Korfiatis
def reassign(request, floating_ip, args):
268 99667854 Giorgos Korfiatis
    project = args.get("project")
269 99667854 Giorgos Korfiatis
    if project is None:
270 99667854 Giorgos Korfiatis
        raise faults.BadRequest("Missing 'project' attribute.")
271 99667854 Giorgos Korfiatis
    ips.reassign_floating_ip(floating_ip, project)
272 99667854 Giorgos Korfiatis
    return HttpResponse(status=200)
273 99667854 Giorgos Korfiatis
274 99667854 Giorgos Korfiatis
275 99667854 Giorgos Korfiatis
FLOATING_IP_ACTIONS = {
276 99667854 Giorgos Korfiatis
    "reassign": reassign,
277 99667854 Giorgos Korfiatis
}
278 99667854 Giorgos Korfiatis
279 99667854 Giorgos Korfiatis
280 fde2c1f7 Christos Stavrakakis
def network_to_floating_ip_pool(network):
281 fde2c1f7 Christos Stavrakakis
    """Convert a 'Network' object to a floating IP pool dict."""
282 fde2c1f7 Christos Stavrakakis
    total, free = network.ip_count()
283 fde2c1f7 Christos Stavrakakis
    return {"name": str(network.id),
284 fde2c1f7 Christos Stavrakakis
            "size": total,
285 7219c7a3 Christos Stavrakakis
            "free": free,
286 7219c7a3 Christos Stavrakakis
            "deleted": network.deleted}