Statistics
| Branch: | Tag: | Revision:

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

History | View | Annotate | Download (10.5 kB)

1 ece5581b Christos Stavrakakis
# Copyright 2011-2013 GRNET S.A. All rights reserved.
2 ce55f211 Kostas Papadimitriou
#
3 adee02b8 Giorgos Verigakis
# Redistribution and use in source and binary forms, with or
4 adee02b8 Giorgos Verigakis
# without modification, are permitted provided that the following
5 adee02b8 Giorgos Verigakis
# conditions are met:
6 ce55f211 Kostas Papadimitriou
#
7 adee02b8 Giorgos Verigakis
#   1. Redistributions of source code must retain the above
8 adee02b8 Giorgos Verigakis
#      copyright notice, this list of conditions and the following
9 adee02b8 Giorgos Verigakis
#      disclaimer.
10 ce55f211 Kostas Papadimitriou
#
11 adee02b8 Giorgos Verigakis
#   2. Redistributions in binary form must reproduce the above
12 adee02b8 Giorgos Verigakis
#      copyright notice, this list of conditions and the following
13 adee02b8 Giorgos Verigakis
#      disclaimer in the documentation and/or other materials
14 adee02b8 Giorgos Verigakis
#      provided with the distribution.
15 ce55f211 Kostas Papadimitriou
#
16 adee02b8 Giorgos Verigakis
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
17 adee02b8 Giorgos Verigakis
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 adee02b8 Giorgos Verigakis
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 adee02b8 Giorgos Verigakis
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
20 adee02b8 Giorgos Verigakis
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 adee02b8 Giorgos Verigakis
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 adee02b8 Giorgos Verigakis
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23 adee02b8 Giorgos Verigakis
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24 adee02b8 Giorgos Verigakis
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 adee02b8 Giorgos Verigakis
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26 adee02b8 Giorgos Verigakis
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 adee02b8 Giorgos Verigakis
# POSSIBILITY OF SUCH DAMAGE.
28 ce55f211 Kostas Papadimitriou
#
29 adee02b8 Giorgos Verigakis
# The views and conclusions contained in the software and
30 adee02b8 Giorgos Verigakis
# documentation are those of the authors and should not be
31 adee02b8 Giorgos Verigakis
# interpreted as representing official policies, either expressed
32 adee02b8 Giorgos Verigakis
# or implied, of GRNET S.A.
33 ce55f211 Kostas Papadimitriou
from django.conf import settings
34 b3fd98ae Christos Stavrakakis
from django.conf.urls.defaults import patterns
35 b3fd98ae Christos Stavrakakis
from django.db.models import Q
36 0269afd6 Giorgos Verigakis
from django.http import HttpResponse
37 69d6d7dd Giorgos Verigakis
from django.template.loader import render_to_string
38 0269afd6 Giorgos Verigakis
from django.utils import simplejson as json
39 0269afd6 Giorgos Verigakis
40 b3fd98ae Christos Stavrakakis
from snf_django.lib import api
41 b3fd98ae Christos Stavrakakis
from snf_django.lib.api import faults, utils
42 5061546f Christos Stavrakakis
from synnefo.api import util
43 41a7fae7 Christos Stavrakakis
from synnefo.api.servers import network_actions
44 03992c72 Christos Stavrakakis
from synnefo.db.models import Network
45 ece5581b Christos Stavrakakis
from synnefo.logic import networks
46 9e98ba3c Giorgos Verigakis
47 9e98ba3c Giorgos Verigakis
48 b3fd98ae Christos Stavrakakis
from logging import getLogger
49 b3fd98ae Christos Stavrakakis
log = getLogger(__name__)
50 b36f78fa Giorgos Verigakis
51 e440e835 Christos Stavrakakis
urlpatterns = patterns(
52 e440e835 Christos Stavrakakis
    'synnefo.api.networks',
53 0269afd6 Giorgos Verigakis
    (r'^(?:/|.json|.xml)?$', 'demux'),
54 0269afd6 Giorgos Verigakis
    (r'^/detail(?:.json|.xml)?$', 'list_networks', {'detail': True}),
55 f4fe8796 Giorgos Verigakis
    (r'^/(\w+)(?:.json|.xml)?$', 'network_demux'),
56 ece5581b Christos Stavrakakis
    (r'^/(\w+)/action(?:.json|.xml)?$', 'demux_network_action'),
57 0269afd6 Giorgos Verigakis
)
58 0269afd6 Giorgos Verigakis
59 0269afd6 Giorgos Verigakis
60 0269afd6 Giorgos Verigakis
def demux(request):
61 0269afd6 Giorgos Verigakis
    if request.method == 'GET':
62 0269afd6 Giorgos Verigakis
        return list_networks(request)
63 0269afd6 Giorgos Verigakis
    elif request.method == 'POST':
64 0269afd6 Giorgos Verigakis
        return create_network(request)
65 0269afd6 Giorgos Verigakis
    else:
66 c0720b78 Kostas Papadimitriou
        return api.api_method_not_allowed(request)
67 0269afd6 Giorgos Verigakis
68 6ef51e9f Giorgos Verigakis
69 b19653d1 Giorgos Verigakis
def network_demux(request, network_id):
70 0269afd6 Giorgos Verigakis
    if request.method == 'GET':
71 b19653d1 Giorgos Verigakis
        return get_network_details(request, network_id)
72 0269afd6 Giorgos Verigakis
    elif request.method == 'PUT':
73 b19653d1 Giorgos Verigakis
        return update_network_name(request, network_id)
74 0269afd6 Giorgos Verigakis
    elif request.method == 'DELETE':
75 b19653d1 Giorgos Verigakis
        return delete_network(request, network_id)
76 0269afd6 Giorgos Verigakis
    else:
77 c0720b78 Kostas Papadimitriou
        return api.api_method_not_allowed(request)
78 0269afd6 Giorgos Verigakis
79 0269afd6 Giorgos Verigakis
80 6ef51e9f Giorgos Verigakis
def network_to_dict(network, user_id, detail=True):
81 7fede91e Christos Stavrakakis
    d = {'id': str(network.id), 'name': network.name}
82 1b696c26 Christos Stavrakakis
    d['links'] = util.network_to_links(network.id)
83 0269afd6 Giorgos Verigakis
    if detail:
84 936e0be3 Christos Stavrakakis
        d['user_id'] = network.userid
85 936e0be3 Christos Stavrakakis
        d['tenant_id'] = network.userid
86 08b079e2 Stavros Sachtouris
        d['cidr'] = network.subnet
87 cc3f266e Christos Stavrakakis
        d['cidr6'] = network.subnet6
88 08b079e2 Stavros Sachtouris
        d['gateway'] = network.gateway
89 cc3f266e Christos Stavrakakis
        d['gateway6'] = network.gateway6
90 08b079e2 Stavros Sachtouris
        d['dhcp'] = network.dhcp
91 b7d38981 Dimitris Aragiorgis
        d['type'] = network.flavor
92 b3fd98ae Christos Stavrakakis
        d['updated'] = utils.isoformat(network.updated)
93 b3fd98ae Christos Stavrakakis
        d['created'] = utils.isoformat(network.created)
94 d44c236b Giorgos Verigakis
        d['status'] = network.state
95 7fede91e Christos Stavrakakis
        d['public'] = network.public
96 08b079e2 Stavros Sachtouris
97 7fede91e Christos Stavrakakis
        attachments = [util.construct_nic_id(nic)
98 e440e835 Christos Stavrakakis
                       for nic in network.nics.filter(machine__userid=user_id)
99 939d71dd Christos Stavrakakis
                                              .filter(state="ACTIVE")
100 cd2b0bf5 Christos Stavrakakis
                                              .order_by('machine')]
101 5029ff36 Christos Stavrakakis
        d['attachments'] = attachments
102 0269afd6 Giorgos Verigakis
    return d
103 0269afd6 Giorgos Verigakis
104 6ef51e9f Giorgos Verigakis
105 0269afd6 Giorgos Verigakis
def render_network(request, networkdict, status=200):
106 0269afd6 Giorgos Verigakis
    if request.serialization == 'xml':
107 0269afd6 Giorgos Verigakis
        data = render_to_string('network.xml', {'network': networkdict})
108 0269afd6 Giorgos Verigakis
    else:
109 0269afd6 Giorgos Verigakis
        data = json.dumps({'network': networkdict})
110 0269afd6 Giorgos Verigakis
    return HttpResponse(data, status=status)
111 0269afd6 Giorgos Verigakis
112 0269afd6 Giorgos Verigakis
113 b3fd98ae Christos Stavrakakis
@api.api_method(http_method='GET', user_required=True, logger=log)
114 0269afd6 Giorgos Verigakis
def list_networks(request, detail=False):
115 0269afd6 Giorgos Verigakis
    # Normal Response Codes: 200, 203
116 0269afd6 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
117 0269afd6 Giorgos Verigakis
    #                       serviceUnavailable (503),
118 0269afd6 Giorgos Verigakis
    #                       unauthorized (401),
119 0269afd6 Giorgos Verigakis
    #                       badRequest (400),
120 0269afd6 Giorgos Verigakis
    #                       overLimit (413)
121 ce55f211 Kostas Papadimitriou
122 0c37a721 Christos Stavrakakis
    log.debug('list_networks detail=%s', detail)
123 b3fd98ae Christos Stavrakakis
    since = utils.isoparse(request.GET.get('changes-since'))
124 8b2515a9 Christos Stavrakakis
    user_networks = Network.objects.filter(Q(userid=request.user_uniq) |
125 3878553d Kostas Papadimitriou
                                           Q(public=True))
126 ce55f211 Kostas Papadimitriou
127 0269afd6 Giorgos Verigakis
    if since:
128 d44c236b Giorgos Verigakis
        user_networks = user_networks.filter(updated__gte=since)
129 0269afd6 Giorgos Verigakis
        if not user_networks:
130 0269afd6 Giorgos Verigakis
            return HttpResponse(status=304)
131 3878553d Kostas Papadimitriou
    else:
132 3878553d Kostas Papadimitriou
        user_networks = user_networks.filter(deleted=False)
133 ce55f211 Kostas Papadimitriou
134 ece5581b Christos Stavrakakis
    networks_dict = [network_to_dict(network, request.user_uniq, detail)
135 ece5581b Christos Stavrakakis
                     for network in user_networks.order_by('id')]
136 ce55f211 Kostas Papadimitriou
137 0269afd6 Giorgos Verigakis
    if request.serialization == 'xml':
138 b36f78fa Giorgos Verigakis
        data = render_to_string('list_networks.xml', {
139 ece5581b Christos Stavrakakis
            'networks': networks_dict,
140 b36f78fa Giorgos Verigakis
            'detail': detail})
141 0269afd6 Giorgos Verigakis
    else:
142 ece5581b Christos Stavrakakis
        data = json.dumps({'networks': networks_dict})
143 aa197ee4 Vangelis Koukis
144 0269afd6 Giorgos Verigakis
    return HttpResponse(data, status=200)
145 0269afd6 Giorgos Verigakis
146 6ef51e9f Giorgos Verigakis
147 b3fd98ae Christos Stavrakakis
@api.api_method(http_method='POST', user_required=True, logger=log)
148 2509ce17 Christos Stavrakakis
def create_network(request):
149 0269afd6 Giorgos Verigakis
    # Normal Response Code: 202
150 0269afd6 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
151 0269afd6 Giorgos Verigakis
    #                       serviceUnavailable (503),
152 0269afd6 Giorgos Verigakis
    #                       unauthorized (401),
153 13b954b0 Giorgos Verigakis
    #                       badMediaType(415),
154 0269afd6 Giorgos Verigakis
    #                       badRequest (400),
155 17c2ed57 Christos Stavrakakis
    #                       forbidden (403)
156 0269afd6 Giorgos Verigakis
    #                       overLimit (413)
157 aa197ee4 Vangelis Koukis
158 ece5581b Christos Stavrakakis
    req = utils.get_request_dict(request)
159 ece5581b Christos Stavrakakis
    log.info('create_network %s', req)
160 ece5581b Christos Stavrakakis
    user_id = request.user_uniq
161 3165f027 Christos Stavrakakis
    try:
162 ece5581b Christos Stavrakakis
        d = req['network']
163 ece5581b Christos Stavrakakis
        name = d['name']
164 ece5581b Christos Stavrakakis
    except KeyError:
165 ece5581b Christos Stavrakakis
        raise faults.BadRequest("Malformed request")
166 ece5581b Christos Stavrakakis
167 ece5581b Christos Stavrakakis
    # Get and validate flavor. Flavors are still exposed as 'type' in the
168 ece5581b Christos Stavrakakis
    # API.
169 ece5581b Christos Stavrakakis
    flavor = d.get("type", None)
170 ece5581b Christos Stavrakakis
    if flavor is None:
171 ece5581b Christos Stavrakakis
        raise faults.BadRequest("Missing request parameter 'type'")
172 ece5581b Christos Stavrakakis
    elif flavor not in Network.FLAVORS.keys():
173 ece5581b Christos Stavrakakis
        raise faults.BadRequest("Invalid network type '%s'" % flavor)
174 ece5581b Christos Stavrakakis
    elif flavor not in settings.API_ENABLED_NETWORK_FLAVORS:
175 99af08a4 Christos Stavrakakis
            raise faults.Forbidden("Can not create network of type '%s'" %
176 99af08a4 Christos Stavrakakis
                                   flavor)
177 ece5581b Christos Stavrakakis
    public = d.get("public", False)
178 ece5581b Christos Stavrakakis
    if public:
179 ece5581b Christos Stavrakakis
        raise faults.Forbidden("Can not create a public network.")
180 4e1133ab Christos Stavrakakis
181 ece5581b Christos Stavrakakis
    dhcp = d.get('dhcp', True)
182 ece5581b Christos Stavrakakis
183 ece5581b Christos Stavrakakis
    # Get and validate network parameters
184 ece5581b Christos Stavrakakis
    subnet = d.get('cidr', '192.168.1.0/24')
185 ece5581b Christos Stavrakakis
    subnet6 = d.get('cidr6', None)
186 ece5581b Christos Stavrakakis
    gateway = d.get('gateway', None)
187 ece5581b Christos Stavrakakis
    gateway6 = d.get('gateway6', None)
188 ece5581b Christos Stavrakakis
189 ece5581b Christos Stavrakakis
    network = networks.create(user_id=user_id, name=name, flavor=flavor,
190 ece5581b Christos Stavrakakis
                              subnet=subnet, gateway=gateway, subnet6=subnet6,
191 ece5581b Christos Stavrakakis
                              gateway6=gateway6, dhcp=dhcp, public=False)
192 7cfbbf32 Christos Stavrakakis
193 4b3b8688 Giorgos Verigakis
    networkdict = network_to_dict(network, request.user_uniq)
194 77f45438 Christos Stavrakakis
    response = render_network(request, networkdict, status=202)
195 77f45438 Christos Stavrakakis
196 77f45438 Christos Stavrakakis
    return response
197 0269afd6 Giorgos Verigakis
198 6ef51e9f Giorgos Verigakis
199 b3fd98ae Christos Stavrakakis
@api.api_method(http_method='GET', user_required=True, logger=log)
200 b19653d1 Giorgos Verigakis
def get_network_details(request, network_id):
201 0269afd6 Giorgos Verigakis
    # Normal Response Codes: 200, 203
202 13b954b0 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
203 13b954b0 Giorgos Verigakis
    #                       serviceUnavailable (503),
204 13b954b0 Giorgos Verigakis
    #                       unauthorized (401),
205 13b954b0 Giorgos Verigakis
    #                       badRequest (400),
206 13b954b0 Giorgos Verigakis
    #                       itemNotFound (404),
207 13b954b0 Giorgos Verigakis
    #                       overLimit (413)
208 ce55f211 Kostas Papadimitriou
209 0c37a721 Christos Stavrakakis
    log.debug('get_network_details %s', network_id)
210 4b3b8688 Giorgos Verigakis
    net = util.get_network(network_id, request.user_uniq)
211 4b3b8688 Giorgos Verigakis
    netdict = network_to_dict(net, request.user_uniq)
212 0269afd6 Giorgos Verigakis
    return render_network(request, netdict)
213 0269afd6 Giorgos Verigakis
214 6ef51e9f Giorgos Verigakis
215 b3fd98ae Christos Stavrakakis
@api.api_method(http_method='PUT', user_required=True, logger=log)
216 b19653d1 Giorgos Verigakis
def update_network_name(request, network_id):
217 0269afd6 Giorgos Verigakis
    # Normal Response Code: 204
218 13b954b0 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
219 13b954b0 Giorgos Verigakis
    #                       serviceUnavailable (503),
220 13b954b0 Giorgos Verigakis
    #                       unauthorized (401),
221 13b954b0 Giorgos Verigakis
    #                       badRequest (400),
222 17c2ed57 Christos Stavrakakis
    #                       forbidden (403)
223 13b954b0 Giorgos Verigakis
    #                       badMediaType(415),
224 13b954b0 Giorgos Verigakis
    #                       itemNotFound (404),
225 13b954b0 Giorgos Verigakis
    #                       overLimit (413)
226 aa197ee4 Vangelis Koukis
227 b3fd98ae Christos Stavrakakis
    req = utils.get_request_dict(request)
228 bf5c82dc Christos Stavrakakis
    log.info('update_network_name %s', network_id)
229 ce55f211 Kostas Papadimitriou
230 0269afd6 Giorgos Verigakis
    try:
231 0269afd6 Giorgos Verigakis
        name = req['network']['name']
232 0269afd6 Giorgos Verigakis
    except (TypeError, KeyError):
233 bd40abfa Christos Stavrakakis
        raise faults.BadRequest('Malformed request.')
234 0269afd6 Giorgos Verigakis
235 ece5581b Christos Stavrakakis
    network = util.get_network(network_id, request.user_uniq)
236 ece5581b Christos Stavrakakis
    if network.public:
237 bd40abfa Christos Stavrakakis
        raise faults.Forbidden('Can not rename the public network.')
238 ece5581b Christos Stavrakakis
    network = networks.rename(network, name)
239 0269afd6 Giorgos Verigakis
    return HttpResponse(status=204)
240 0269afd6 Giorgos Verigakis
241 6ef51e9f Giorgos Verigakis
242 b3fd98ae Christos Stavrakakis
@api.api_method(http_method='DELETE', user_required=True, logger=log)
243 b19653d1 Giorgos Verigakis
def delete_network(request, network_id):
244 0269afd6 Giorgos Verigakis
    # Normal Response Code: 204
245 13b954b0 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
246 13b954b0 Giorgos Verigakis
    #                       serviceUnavailable (503),
247 13b954b0 Giorgos Verigakis
    #                       unauthorized (401),
248 17c2ed57 Christos Stavrakakis
    #                       forbidden (403)
249 13b954b0 Giorgos Verigakis
    #                       itemNotFound (404),
250 13b954b0 Giorgos Verigakis
    #                       overLimit (413)
251 ce55f211 Kostas Papadimitriou
252 bf5c82dc Christos Stavrakakis
    log.info('delete_network %s', network_id)
253 ece5581b Christos Stavrakakis
    network = util.get_network(network_id, request.user_uniq, for_update=True)
254 ece5581b Christos Stavrakakis
    if network.public:
255 bd40abfa Christos Stavrakakis
        raise faults.Forbidden('Can not delete the public network.')
256 ece5581b Christos Stavrakakis
    networks.delete(network)
257 ece5581b Christos Stavrakakis
    return HttpResponse(status=204)
258 5061546f Christos Stavrakakis
259 5061546f Christos Stavrakakis
260 ece5581b Christos Stavrakakis
def key_to_action(action):
261 ece5581b Christos Stavrakakis
    return action.upper()
262 0269afd6 Giorgos Verigakis
263 6ef51e9f Giorgos Verigakis
264 b3fd98ae Christos Stavrakakis
@api.api_method(http_method='POST', user_required=True, logger=log)
265 ece5581b Christos Stavrakakis
def demux_network_action(request, network_id):
266 b3fd98ae Christos Stavrakakis
    req = utils.get_request_dict(request)
267 0c37a721 Christos Stavrakakis
    log.debug('network_action %s %s', network_id, req)
268 9e98ba3c Giorgos Verigakis
    if len(req) != 1:
269 bd40abfa Christos Stavrakakis
        raise faults.BadRequest('Malformed request.')
270 ce55f211 Kostas Papadimitriou
271 4b3b8688 Giorgos Verigakis
    net = util.get_network(network_id, request.user_uniq)
272 207b70d5 Giorgos Verigakis
    if net.public:
273 bd40abfa Christos Stavrakakis
        raise faults.Forbidden('Can not modify the public network.')
274 22a9959d Christos Stavrakakis
    if net.deleted:
275 05d401cf Christos Stavrakakis
        raise faults.BadRequest("Network has been deleted.")
276 ce55f211 Kostas Papadimitriou
277 ece5581b Christos Stavrakakis
    action = req.keys()[0]
278 ece5581b Christos Stavrakakis
    if key_to_action(action) not in [x[0] for x in Network.ACTIONS]:
279 ece5581b Christos Stavrakakis
        raise faults.BadRequest("Action %s not supported." % action)
280 ece5581b Christos Stavrakakis
    action_args = req[action]
281 ece5581b Christos Stavrakakis
    if not isinstance(action_args, dict):
282 ece5581b Christos Stavrakakis
        raise faults.BadRequest("Invalid argument.")
283 ece5581b Christos Stavrakakis
    return network_actions[action](request, net, action_args)