floating_ips.py 9.17 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
# Copyright 2013 GRNET S.A. All rights reserved.
#
# Redistribution and use in source and binary forms, with or
# without modification, are permitted provided that the following
# conditions are met:
#
#   1. Redistributions of source code must retain the above
#      copyright notice, this list of conditions and the following
#      disclaimer.
#
#   2. Redistributions in binary form must reproduce the above
#      copyright notice, this list of conditions and the following
#      disclaimer in the documentation and/or other materials
#      provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
# The views and conclusions contained in the software and
# documentation are those of the authors and should not be
# interpreted as representing official policies, either expressed
# or implied, of GRNET S.A.

from django.conf.urls.defaults import patterns
from django.db import transaction
from django.http import HttpResponse
from django.utils import simplejson as json

from snf_django.lib import api
from snf_django.lib.api import faults, utils
from synnefo.api import util
Christos Stavrakakis's avatar
Christos Stavrakakis committed
42
from synnefo.logic import ips
43
from synnefo.db.models import Network, IPAddress
44
45
46
47

from logging import getLogger
log = getLogger(__name__)

48
'''
49
ips_urlpatterns = patterns(
50
51
52
53
54
    'synnefo.api.floating_ips',
    (r'^(?:/|.json|.xml)?$', 'demux'),
    (r'^/(\w+)(?:.json|.xml)?$', 'floating_ip_demux'),
)

55
56
57
58
pools_urlpatterns = patterns(
    "synnefo.api.floating_ips",
    (r'^(?:/|.json|.xml)?$', 'list_floating_ip_pools'),
)
59
60
61
62
63
64
65
'''

ips_urlpatterns = patterns(
    'synnefo.api.floating_ips',
    (r'^(?:/|.json|.xml)?$', 'demux'),
    (r'^/detail(?:.json|.xml)?$', 'list_floating_ips', {'detail': True}),
    (r'^/(\w+)(?:/|.json|.xml)?$', 'floating_ip_demux'))
66

67
68
69
70
71
72
73

def demux(request):
    if request.method == 'GET':
        return list_floating_ips(request)
    elif request.method == 'POST':
        return allocate_floating_ip(request)
    else:
74
75
        return api.api_method_not_allowed(request,
                                          allowed_methods=['GET', 'POST'])
76
77
78
79
80
81
82


def floating_ip_demux(request, floating_ip_id):
    if request.method == 'GET':
        return get_floating_ip(request, floating_ip_id)
    elif request.method == 'DELETE':
        return release_floating_ip(request, floating_ip_id)
83
84
    elif request.method == 'PUT':
        return update_floating_ip(request, floating_ip_id)
85
    else:
86
87
        return api.api_method_not_allowed(request,
                                          allowed_methods=['GET', 'DELETE'])
88
89
90


def ip_to_dict(floating_ip):
91
    machine_id = None
92
    port_id = None
93
94
    if floating_ip.nic is not None:
        machine_id = floating_ip.nic.machine_id
95
96
        port_id = floating_ip.nic.id
    return {"fixed_ip_address": None,
97
98
            "id": str(floating_ip.id),
            "instance_id": str(machine_id) if machine_id else None,
99
            "floating_ip_address": floating_ip.address,
100
            "port_id": str(port_id) if port_id else None,
101
102
            "floating_network_id": str(floating_ip.network_id),
            "deleted": floating_ip.deleted}
103
104


105
106
@api.api_method(http_method="GET", user_required=True, logger=log,
                serializations=["json"])
107
108
109
110
111
def list_floating_ips(request):
    """Return user reserved floating IPs"""
    log.debug("list_floating_ips")

    userid = request.user_uniq
112
113
114
    floating_ips = IPAddress.objects.filter(userid=userid, deleted=False,
                                            floating_ip=True).order_by("id")\
                                    .select_related("nic")
115
    floating_ips = utils.filter_modified_since(request, objects=floating_ips)
116
117
118
119

    floating_ips = map(ip_to_dict, floating_ips)

    request.serialization = "json"
120
    data = json.dumps({"floatingips": floating_ips})
121
122
123
124

    return HttpResponse(data, status=200)


125
126
@api.api_method(http_method="GET", user_required=True, logger=log,
                serializations=["json"])
127
128
129
def get_floating_ip(request, floating_ip_id):
    """Return information for a floating IP."""
    userid = request.user_uniq
130
    floating_ip = util.get_floating_ip_by_id(userid, floating_ip_id)
131
    request.serialization = "json"
132
    data = json.dumps({"floatingip": ip_to_dict(floating_ip)})
133
134
135
    return HttpResponse(data, status=200)


136
137
@api.api_method(http_method='POST', user_required=True, logger=log,
                serializations=["json"])
138
@transaction.commit_on_success
139
140
141
def allocate_floating_ip(request):
    """Allocate a floating IP."""
    req = utils.get_request_dict(request)
142
    floating_ip_dict = api.utils.get_attribute(req, "floatingip",
143
                                               required=True, attr_type=dict)
144
    userid = request.user_uniq
145
146
    log.info('allocate_floating_ip user: %s request: %s', userid, req)

147
148

    # the network_pool is a mandatory field
149
150
    network_id = api.utils.get_attribute(floating_ip_dict,
                                         "floating_network_id",
151
152
                                         required=False,
                                         attr_type=(basestring, int))
153
    if network_id is None:
Christos Stavrakakis's avatar
Christos Stavrakakis committed
154
        floating_ip = ips.create_floating_ip(userid)
155
156
157
158
159
160
161
162
163
164
    else:
        try:
            network_id = int(network_id)
        except ValueError:
            raise faults.BadRequest("Invalid networkd ID.")

        network = util.get_network(network_id, userid, for_update=True,
                                   non_deleted=True)
        address = api.utils.get_attribute(floating_ip_dict,
                                          "floating_ip_address",
165
166
                                          required=False,
                                          attr_type=basestring)
Christos Stavrakakis's avatar
Christos Stavrakakis committed
167
        floating_ip = ips.create_floating_ip(userid, network, address)
168
169

    log.info("User '%s' allocated floating IP '%s'", userid, floating_ip)
170
    request.serialization = "json"
171
    data = json.dumps({"floatingip": ip_to_dict(floating_ip)})
172
173
174
    return HttpResponse(data, status=200)


175
176
@api.api_method(http_method='DELETE', user_required=True, logger=log,
                serializations=["json"])
177
178
179
180
181
@transaction.commit_on_success
def release_floating_ip(request, floating_ip_id):
    """Release a floating IP."""
    userid = request.user_uniq
    log.info("release_floating_ip '%s'. User '%s'.", floating_ip_id, userid)
182
183
184

    floating_ip = util.get_floating_ip_by_id(userid, floating_ip_id,
                                             for_update=True)
Christos Stavrakakis's avatar
Christos Stavrakakis committed
185
    ips.delete_floating_ip(floating_ip)
186
187
188
    log.info("User '%s' released IP '%s", userid, floating_ip)

    return HttpResponse(status=204)
189
190


191
192
193
194
195
@api.api_method(http_method='PUT', user_required=True, logger=log,
                serializations=["json"])
@transaction.commit_on_success
def update_floating_ip(request, floating_ip_id):
    """Update a floating IP."""
Christos Stavrakakis's avatar
Christos Stavrakakis committed
196
    raise faults.NotImplemented("Updating a floating IP is not supported.")
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
    #userid = request.user_uniq
    #log.info("update_floating_ip '%s'. User '%s'.", floating_ip_id, userid)

    #req = utils.get_request_dict(request)
    #info = api.utils.get_attribute(req, "floatingip", required=True)

    #device_id = api.utils.get_attribute(info, "device_id", required=False)

    #floating_ip = util.get_floating_ip_by_id(userid, floating_ip_id,
    #                                         for_update=True)
    #if device_id:
    #    # attach
    #    vm = util.get_vm(device_id, userid)
    #    nic, floating_ip = servers.create_nic(vm, ipaddress=floating_ip)
    #    backend.connect_to_network(vm, nic)
    #else:
    #    # dettach
    #    nic = floating_ip.nic
    #    if not nic:
    #        raise faults.BadRequest("The floating IP is not associated\
    #                                with any device")
    #    vm = nic.machine
    #    servers.disconnect(vm, nic)
    #return HttpResponse(status=202)
221
222


223
# Floating IP pools
224
225
@api.api_method(http_method='GET', user_required=True, logger=log,
                serializations=["json"])
226
def list_floating_ip_pools(request):
227
228
    networks = Network.objects.filter(public=True, floating_ip_pool=True,
                                      deleted=False)
229
    networks = utils.filter_modified_since(request, objects=networks)
230
    floating_ip_pools = map(network_to_floating_ip_pool, networks)
231
    request.serialization = "json"
232
    data = json.dumps({"floating_ip_pools": floating_ip_pools})
233
234
    request.serialization = "json"
    return HttpResponse(data, status=200)
235
236
237
238
239
240
241


def network_to_floating_ip_pool(network):
    """Convert a 'Network' object to a floating IP pool dict."""
    total, free = network.ip_count()
    return {"name": str(network.id),
            "size": total,
242
243
            "free": free,
            "deleted": network.deleted}