Statistics
| Branch: | Tag: | Revision:

root / snf-cyclades-app / synnefo / api / networks.py @ 5a6cee09

History | View | Annotate | Download (8.7 kB)

1 a96e84cf Christos Stavrakakis
# Copyright 2011-2013 GRNET S.A. All rights reserved.
2 a96e84cf Christos Stavrakakis
#
3 a96e84cf Christos Stavrakakis
# Redistribution and use in source and binary forms, with or
4 a96e84cf Christos Stavrakakis
# without modification, are permitted provided that the following
5 a96e84cf Christos Stavrakakis
# conditions are met:
6 a96e84cf Christos Stavrakakis
#
7 a96e84cf Christos Stavrakakis
#   1. Redistributions of source code must retain the above
8 a96e84cf Christos Stavrakakis
#      copyright notice, this list of conditions and the following
9 a96e84cf Christos Stavrakakis
#      disclaimer.
10 a96e84cf Christos Stavrakakis
#
11 a96e84cf Christos Stavrakakis
#   2. Redistributions in binary form must reproduce the above
12 a96e84cf Christos Stavrakakis
#      copyright notice, this list of conditions and the following
13 a96e84cf Christos Stavrakakis
#      disclaimer in the documentation and/or other materials
14 a96e84cf Christos Stavrakakis
#      provided with the distribution.
15 a96e84cf Christos Stavrakakis
#
16 a96e84cf Christos Stavrakakis
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
17 a96e84cf Christos Stavrakakis
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 a96e84cf Christos Stavrakakis
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 a96e84cf Christos Stavrakakis
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
20 a96e84cf Christos Stavrakakis
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 a96e84cf Christos Stavrakakis
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 a96e84cf Christos Stavrakakis
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23 a96e84cf Christos Stavrakakis
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24 a96e84cf Christos Stavrakakis
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 a96e84cf Christos Stavrakakis
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26 a96e84cf Christos Stavrakakis
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 a96e84cf Christos Stavrakakis
# POSSIBILITY OF SUCH DAMAGE.
28 a96e84cf Christos Stavrakakis
#
29 a96e84cf Christos Stavrakakis
# The views and conclusions contained in the software and
30 a96e84cf Christos Stavrakakis
# documentation are those of the authors and should not be
31 a96e84cf Christos Stavrakakis
# interpreted as representing official policies, either expressed
32 a96e84cf Christos Stavrakakis
# or implied, of GRNET S.A.
33 a96e84cf Christos Stavrakakis
34 ce55f211 Kostas Papadimitriou
from django.conf import settings
35 6b256427 Christos Stavrakakis
from django.conf.urls import patterns
36 0269afd6 Giorgos Verigakis
from django.http import HttpResponse
37 0269afd6 Giorgos Verigakis
from django.utils import simplejson as json
38 0baa1e3d Buildbot
from django.db import transaction
39 0baa1e3d Buildbot
from django.db.models import Q
40 0baa1e3d Buildbot
from django.template.loader import render_to_string
41 a96e84cf Christos Stavrakakis
42 a96e84cf Christos Stavrakakis
from snf_django.lib import api
43 99667854 Giorgos Korfiatis
from snf_django.lib.api import utils
44 a96e84cf Christos Stavrakakis
45 5061546f Christos Stavrakakis
from synnefo.api import util
46 03992c72 Christos Stavrakakis
from synnefo.db.models import Network
47 a96e84cf Christos Stavrakakis
from synnefo.logic import networks
48 9e98ba3c Giorgos Verigakis
49 b3fd98ae Christos Stavrakakis
from logging import getLogger
50 0baa1e3d Buildbot
51 b3fd98ae Christos Stavrakakis
log = getLogger(__name__)
52 b36f78fa Giorgos Verigakis
53 e440e835 Christos Stavrakakis
urlpatterns = patterns(
54 e440e835 Christos Stavrakakis
    'synnefo.api.networks',
55 95a213d4 Christos Stavrakakis
    (r'^(?:/|.json|.xml)?$', 'demux'),
56 a96e84cf Christos Stavrakakis
    (r'^/detail(?:.json|.xml)?$', 'list_networks', {'detail': True}),
57 99667854 Giorgos Korfiatis
    (r'^/(\w+)(?:/|.json|.xml)?$', 'network_demux'),
58 99667854 Giorgos Korfiatis
    (r'^/(\w+)/action(?:/|.json|.xml)?$', 'network_action_demux'),
59 99667854 Giorgos Korfiatis
)
60 95a213d4 Christos Stavrakakis
61 0269afd6 Giorgos Verigakis
62 0269afd6 Giorgos Verigakis
def demux(request):
63 0269afd6 Giorgos Verigakis
    if request.method == 'GET':
64 0269afd6 Giorgos Verigakis
        return list_networks(request)
65 0269afd6 Giorgos Verigakis
    elif request.method == 'POST':
66 0269afd6 Giorgos Verigakis
        return create_network(request)
67 0269afd6 Giorgos Verigakis
    else:
68 2aba7764 Sofia Papagiannaki
        return api.api_method_not_allowed(request,
69 2aba7764 Sofia Papagiannaki
                                          allowed_methods=['GET', 'POST'])
70 0269afd6 Giorgos Verigakis
71 6ef51e9f Giorgos Verigakis
72 a96e84cf Christos Stavrakakis
def network_demux(request, network_id):
73 0baa1e3d Buildbot
74 0269afd6 Giorgos Verigakis
    if request.method == 'GET':
75 a96e84cf Christos Stavrakakis
        return get_network_details(request, network_id)
76 0269afd6 Giorgos Verigakis
    elif request.method == 'DELETE':
77 a96e84cf Christos Stavrakakis
        return delete_network(request, network_id)
78 0baa1e3d Buildbot
    elif request.method == 'PUT':
79 a96e84cf Christos Stavrakakis
        return update_network(request, network_id)
80 0269afd6 Giorgos Verigakis
    else:
81 2aba7764 Sofia Papagiannaki
        return api.api_method_not_allowed(request,
82 2aba7764 Sofia Papagiannaki
                                          allowed_methods=['GET',
83 2aba7764 Sofia Papagiannaki
                                                           'PUT',
84 2aba7764 Sofia Papagiannaki
                                                           'DELETE'])
85 0269afd6 Giorgos Verigakis
86 0269afd6 Giorgos Verigakis
87 99667854 Giorgos Korfiatis
@api.api_method(http_method='POST', user_required=True, logger=log)
88 99667854 Giorgos Korfiatis
def network_action_demux(request, network_id):
89 5a6cee09 Christos Stavrakakis
    req = utils.get_json_body(request)
90 99667854 Giorgos Korfiatis
    network = util.get_network(network_id, request.user_uniq, for_update=True)
91 99667854 Giorgos Korfiatis
    action = req.keys()[0]
92 99667854 Giorgos Korfiatis
    try:
93 99667854 Giorgos Korfiatis
        f = NETWORK_ACTIONS[action]
94 99667854 Giorgos Korfiatis
    except KeyError:
95 99667854 Giorgos Korfiatis
        raise faults.BadRequest("Action %s not supported." % action)
96 99667854 Giorgos Korfiatis
    action_args = req[action]
97 99667854 Giorgos Korfiatis
    if not isinstance(action_args, dict):
98 99667854 Giorgos Korfiatis
        raise faults.BadRequest("Invalid argument.")
99 99667854 Giorgos Korfiatis
100 99667854 Giorgos Korfiatis
    return f(request, network, action_args)
101 99667854 Giorgos Korfiatis
102 99667854 Giorgos Korfiatis
103 b3fd98ae Christos Stavrakakis
@api.api_method(http_method='GET', user_required=True, logger=log)
104 bf58eed3 Dionysis Grigoropoulos
def list_networks(request, detail=True):
105 0c37a721 Christos Stavrakakis
    log.debug('list_networks detail=%s', detail)
106 0baa1e3d Buildbot
107 a96e84cf Christos Stavrakakis
    user_networks = Network.objects.filter(Q(userid=request.user_uniq) |
108 a96e84cf Christos Stavrakakis
                                           Q(public=True))\
109 883c1f94 Christos Stavrakakis
                                   .order_by('id')
110 883c1f94 Christos Stavrakakis
    if detail:
111 883c1f94 Christos Stavrakakis
        user_networks = user_networks.prefetch_related("subnets")
112 0baa1e3d Buildbot
113 a96e84cf Christos Stavrakakis
    user_networks = api.utils.filter_modified_since(request,
114 a96e84cf Christos Stavrakakis
                                                    objects=user_networks)
115 ce55f211 Kostas Papadimitriou
116 a96e84cf Christos Stavrakakis
    network_dicts = [network_to_dict(network, detail)
117 883c1f94 Christos Stavrakakis
                     for network in user_networks]
118 ce55f211 Kostas Papadimitriou
119 0269afd6 Giorgos Verigakis
    if request.serialization == 'xml':
120 b36f78fa Giorgos Verigakis
        data = render_to_string('list_networks.xml', {
121 a96e84cf Christos Stavrakakis
            "networks": network_dicts})
122 0269afd6 Giorgos Verigakis
    else:
123 a96e84cf Christos Stavrakakis
        data = json.dumps({'networks': network_dicts})
124 aa197ee4 Vangelis Koukis
125 0269afd6 Giorgos Verigakis
    return HttpResponse(data, status=200)
126 0269afd6 Giorgos Verigakis
127 6ef51e9f Giorgos Verigakis
128 b3fd98ae Christos Stavrakakis
@api.api_method(http_method='POST', user_required=True, logger=log)
129 2509ce17 Christos Stavrakakis
def create_network(request):
130 a96e84cf Christos Stavrakakis
    userid = request.user_uniq
131 5a6cee09 Christos Stavrakakis
    req = api.utils.get_json_body(request)
132 a96e84cf Christos Stavrakakis
    log.info('create_network %s', req)
133 a96e84cf Christos Stavrakakis
134 3d870b05 Dionysis Grigoropoulos
    network_dict = api.utils.get_attribute(req, "network",
135 3d870b05 Dionysis Grigoropoulos
                                           attr_type=dict)
136 3d870b05 Dionysis Grigoropoulos
    flavor = api.utils.get_attribute(network_dict, "type",
137 3d870b05 Dionysis Grigoropoulos
                                     attr_type=basestring)
138 a96e84cf Christos Stavrakakis
139 a96e84cf Christos Stavrakakis
    if flavor not in Network.FLAVORS.keys():
140 a96e84cf Christos Stavrakakis
        raise api.faults.BadRequest("Invalid network type '%s'" % flavor)
141 a96e84cf Christos Stavrakakis
    if flavor not in settings.API_ENABLED_NETWORK_FLAVORS:
142 8d5795b4 Christos Stavrakakis
        raise api.faults.Forbidden("Cannot create network of type '%s'." %
143 a96e84cf Christos Stavrakakis
                                   flavor)
144 a96e84cf Christos Stavrakakis
145 3d870b05 Dionysis Grigoropoulos
    name = api.utils.get_attribute(network_dict, "name", attr_type=basestring,
146 3d870b05 Dionysis Grigoropoulos
                                   required=False)
147 a96e84cf Christos Stavrakakis
    if name is None:
148 a96e84cf Christos Stavrakakis
        name = ""
149 a96e84cf Christos Stavrakakis
150 47c27955 Giorgos Korfiatis
    project = network_dict.get('project', None)
151 a96e84cf Christos Stavrakakis
    network = networks.create(userid=userid, name=name, flavor=flavor,
152 47c27955 Giorgos Korfiatis
                              public=False, project=project)
153 a96e84cf Christos Stavrakakis
    networkdict = network_to_dict(network, detail=True)
154 0baa1e3d Buildbot
    response = render_network(request, networkdict, status=201)
155 77f45438 Christos Stavrakakis
156 77f45438 Christos Stavrakakis
    return response
157 0269afd6 Giorgos Verigakis
158 6ef51e9f Giorgos Verigakis
159 b3fd98ae Christos Stavrakakis
@api.api_method(http_method='GET', user_required=True, logger=log)
160 a96e84cf Christos Stavrakakis
def get_network_details(request, network_id):
161 0c37a721 Christos Stavrakakis
    log.debug('get_network_details %s', network_id)
162 a96e84cf Christos Stavrakakis
    network = util.get_network(network_id, request.user_uniq)
163 a96e84cf Christos Stavrakakis
    return render_network(request, network_to_dict(network, detail=True))
164 6ef51e9f Giorgos Verigakis
165 a96e84cf Christos Stavrakakis
166 a96e84cf Christos Stavrakakis
@api.api_method(http_method='PUT', user_required=True, logger=log)
167 a96e84cf Christos Stavrakakis
def update_network(request, network_id):
168 5a6cee09 Christos Stavrakakis
    info = api.utils.get_json_body(request)
169 a96e84cf Christos Stavrakakis
170 3d870b05 Dionysis Grigoropoulos
    network = api.utils.get_attribute(info, "network", attr_type=dict,
171 3d870b05 Dionysis Grigoropoulos
                                      required=True)
172 3d870b05 Dionysis Grigoropoulos
    new_name = api.utils.get_attribute(network, "name", attr_type=basestring)
173 a96e84cf Christos Stavrakakis
174 a96e84cf Christos Stavrakakis
    network = util.get_network(network_id, request.user_uniq, for_update=True)
175 a96e84cf Christos Stavrakakis
    if network.public:
176 8d5795b4 Christos Stavrakakis
        raise api.faults.Forbidden("Cannot rename the public network.")
177 a96e84cf Christos Stavrakakis
    network = networks.rename(network, new_name)
178 a96e84cf Christos Stavrakakis
    return render_network(request, network_to_dict(network), 200)
179 0269afd6 Giorgos Verigakis
180 6ef51e9f Giorgos Verigakis
181 b3fd98ae Christos Stavrakakis
@api.api_method(http_method='DELETE', user_required=True, logger=log)
182 0baa1e3d Buildbot
@transaction.commit_on_success
183 b19653d1 Giorgos Verigakis
def delete_network(request, network_id):
184 bf5c82dc Christos Stavrakakis
    log.info('delete_network %s', network_id)
185 a96e84cf Christos Stavrakakis
    network = util.get_network(network_id, request.user_uniq, for_update=True)
186 a96e84cf Christos Stavrakakis
    if network.public:
187 8d5795b4 Christos Stavrakakis
        raise api.faults.Forbidden("Cannot delete the public network.")
188 a96e84cf Christos Stavrakakis
    networks.delete(network)
189 ece5581b Christos Stavrakakis
    return HttpResponse(status=204)
190 5061546f Christos Stavrakakis
191 5061546f Christos Stavrakakis
192 0baa1e3d Buildbot
def network_to_dict(network, detail=True):
193 0baa1e3d Buildbot
    d = {'id': str(network.id), 'name': network.name}
194 0baa1e3d Buildbot
    d['links'] = util.network_to_links(network.id)
195 0baa1e3d Buildbot
    if detail:
196 883c1f94 Christos Stavrakakis
        # Loop over subnets. Do not perform any extra query because of prefetch
197 883c1f94 Christos Stavrakakis
        # related!
198 883c1f94 Christos Stavrakakis
        subnet_ids = []
199 883c1f94 Christos Stavrakakis
        for subnet in network.subnets.all():
200 aff81af3 Christos Stavrakakis
            subnet_ids.append(subnet.id)
201 883c1f94 Christos Stavrakakis
202 8f335041 Christos Stavrakakis
        state = "SNF:DRAINED" if network.drained else network.state
203 0baa1e3d Buildbot
        d['user_id'] = network.userid
204 70c51e5d Giorgos Korfiatis
        d['tenant_id'] = network.project
205 0baa1e3d Buildbot
        d['type'] = network.flavor
206 a96e84cf Christos Stavrakakis
        d['updated'] = api.utils.isoformat(network.updated)
207 a96e84cf Christos Stavrakakis
        d['created'] = api.utils.isoformat(network.created)
208 8f335041 Christos Stavrakakis
        d['status'] = state
209 0baa1e3d Buildbot
        d['public'] = network.public
210 64209939 Christos Stavrakakis
        d['router:external'] = network.external_router
211 0baa1e3d Buildbot
        d['admin_state_up'] = True
212 883c1f94 Christos Stavrakakis
        d['subnets'] = subnet_ids
213 7421d45e Christos Stavrakakis
        d['SNF:floating_ip_pool'] = network.floating_ip_pool
214 6faf3c78 Dionysis Grigoropoulos
        d['deleted'] = network.deleted
215 0baa1e3d Buildbot
    return d
216 0baa1e3d Buildbot
217 0baa1e3d Buildbot
218 99667854 Giorgos Korfiatis
@transaction.commit_on_success
219 99667854 Giorgos Korfiatis
def reassign_network(request, network, args):
220 99667854 Giorgos Korfiatis
    project = args.get("project")
221 99667854 Giorgos Korfiatis
    if project is None:
222 99667854 Giorgos Korfiatis
        raise faults.BadRequest("Missing 'project' attribute.")
223 99667854 Giorgos Korfiatis
    networks.reassign(network, project)
224 99667854 Giorgos Korfiatis
    return HttpResponse(status=200)
225 99667854 Giorgos Korfiatis
226 99667854 Giorgos Korfiatis
227 99667854 Giorgos Korfiatis
NETWORK_ACTIONS = {
228 99667854 Giorgos Korfiatis
    "reassign": reassign_network,
229 99667854 Giorgos Korfiatis
}
230 99667854 Giorgos Korfiatis
231 99667854 Giorgos Korfiatis
232 0baa1e3d Buildbot
def render_network(request, networkdict, status=200):
233 0baa1e3d Buildbot
    if request.serialization == 'xml':
234 0baa1e3d Buildbot
        data = render_to_string('network.xml', {'network': networkdict})
235 0baa1e3d Buildbot
    else:
236 0baa1e3d Buildbot
        data = json.dumps({'network': networkdict})
237 0baa1e3d Buildbot
    return HttpResponse(data, status=status)