Statistics
| Branch: | Tag: | Revision:

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

History | View | Annotate | Download (10.5 kB)

1 6ef51e9f Giorgos Verigakis
# Copyright 2011-2012 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 adee02b8 Giorgos Verigakis
34 2035039b Giorgos Verigakis
from logging import getLogger
35 2035039b Giorgos Verigakis
36 0269afd6 Giorgos Verigakis
from django.conf.urls.defaults import patterns
37 ce55f211 Kostas Papadimitriou
from django.conf import settings
38 d44c236b Giorgos Verigakis
from django.db.models import Q
39 4dba0480 Christos Stavrakakis
from django.db import transaction
40 0269afd6 Giorgos Verigakis
from django.http import HttpResponse
41 69d6d7dd Giorgos Verigakis
from django.template.loader import render_to_string
42 0269afd6 Giorgos Verigakis
from django.utils import simplejson as json
43 0269afd6 Giorgos Verigakis
44 5061546f Christos Stavrakakis
from synnefo.api import util
45 b36f78fa Giorgos Verigakis
from synnefo.api.actions import network_actions
46 b36f78fa Giorgos Verigakis
from synnefo.api.common import method_not_allowed
47 6dd70a5c Christos Stavrakakis
from synnefo.api.faults import (BadRequest, Unauthorized,
48 6eed1ede Christos Stavrakakis
                                NetworkInUse, OverLimit)
49 03992c72 Christos Stavrakakis
from synnefo.db.models import Network
50 03992c72 Christos Stavrakakis
from synnefo.db.pools import EmptyPool
51 b36f78fa Giorgos Verigakis
from synnefo.logic import backend
52 9e98ba3c Giorgos Verigakis
53 9e98ba3c Giorgos Verigakis
54 9e98ba3c Giorgos Verigakis
log = getLogger('synnefo.api')
55 b36f78fa Giorgos Verigakis
56 0269afd6 Giorgos Verigakis
urlpatterns = patterns('synnefo.api.networks',
57 0269afd6 Giorgos Verigakis
    (r'^(?:/|.json|.xml)?$', 'demux'),
58 0269afd6 Giorgos Verigakis
    (r'^/detail(?:.json|.xml)?$', 'list_networks', {'detail': True}),
59 f4fe8796 Giorgos Verigakis
    (r'^/(\w+)(?:.json|.xml)?$', 'network_demux'),
60 f4fe8796 Giorgos Verigakis
    (r'^/(\w+)/action(?:.json|.xml)?$', 'network_action'),
61 0269afd6 Giorgos Verigakis
)
62 0269afd6 Giorgos Verigakis
63 0269afd6 Giorgos Verigakis
64 0269afd6 Giorgos Verigakis
def demux(request):
65 0269afd6 Giorgos Verigakis
    if request.method == 'GET':
66 0269afd6 Giorgos Verigakis
        return list_networks(request)
67 0269afd6 Giorgos Verigakis
    elif request.method == 'POST':
68 0269afd6 Giorgos Verigakis
        return create_network(request)
69 0269afd6 Giorgos Verigakis
    else:
70 0269afd6 Giorgos Verigakis
        return method_not_allowed(request)
71 0269afd6 Giorgos Verigakis
72 6ef51e9f Giorgos Verigakis
73 b19653d1 Giorgos Verigakis
def network_demux(request, network_id):
74 0269afd6 Giorgos Verigakis
    if request.method == 'GET':
75 b19653d1 Giorgos Verigakis
        return get_network_details(request, network_id)
76 0269afd6 Giorgos Verigakis
    elif request.method == 'PUT':
77 b19653d1 Giorgos Verigakis
        return update_network_name(request, network_id)
78 0269afd6 Giorgos Verigakis
    elif request.method == 'DELETE':
79 b19653d1 Giorgos Verigakis
        return delete_network(request, network_id)
80 0269afd6 Giorgos Verigakis
    else:
81 0269afd6 Giorgos Verigakis
        return method_not_allowed(request)
82 0269afd6 Giorgos Verigakis
83 0269afd6 Giorgos Verigakis
84 6ef51e9f Giorgos Verigakis
def network_to_dict(network, user_id, detail=True):
85 7fede91e Christos Stavrakakis
    d = {'id': str(network.id), 'name': network.name}
86 0269afd6 Giorgos Verigakis
    if detail:
87 08b079e2 Stavros Sachtouris
        d['cidr'] = network.subnet
88 cc3f266e Christos Stavrakakis
        d['cidr6'] = network.subnet6
89 08b079e2 Stavros Sachtouris
        d['gateway'] = network.gateway
90 cc3f266e Christos Stavrakakis
        d['gateway6'] = network.gateway6
91 08b079e2 Stavros Sachtouris
        d['dhcp'] = network.dhcp
92 08b079e2 Stavros Sachtouris
        d['type'] = network.type
93 b36f78fa Giorgos Verigakis
        d['updated'] = util.isoformat(network.updated)
94 b36f78fa Giorgos Verigakis
        d['created'] = util.isoformat(network.created)
95 d44c236b Giorgos Verigakis
        d['status'] = network.state
96 7fede91e Christos Stavrakakis
        d['public'] = network.public
97 08b079e2 Stavros Sachtouris
98 7fede91e Christos Stavrakakis
        attachments = [util.construct_nic_id(nic)
99 7fede91e Christos Stavrakakis
                       for nic in network.nics.filter(machine__userid=user_id)]
100 7fede91e Christos Stavrakakis
        d['attachments'] = {'values': attachments}
101 0269afd6 Giorgos Verigakis
    return d
102 0269afd6 Giorgos Verigakis
103 6ef51e9f Giorgos Verigakis
104 0269afd6 Giorgos Verigakis
def render_network(request, networkdict, status=200):
105 0269afd6 Giorgos Verigakis
    if request.serialization == 'xml':
106 0269afd6 Giorgos Verigakis
        data = render_to_string('network.xml', {'network': networkdict})
107 0269afd6 Giorgos Verigakis
    else:
108 0269afd6 Giorgos Verigakis
        data = json.dumps({'network': networkdict})
109 0269afd6 Giorgos Verigakis
    return HttpResponse(data, status=status)
110 0269afd6 Giorgos Verigakis
111 0269afd6 Giorgos Verigakis
112 b36f78fa Giorgos Verigakis
@util.api_method('GET')
113 0269afd6 Giorgos Verigakis
def list_networks(request, detail=False):
114 0269afd6 Giorgos Verigakis
    # Normal Response Codes: 200, 203
115 0269afd6 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
116 0269afd6 Giorgos Verigakis
    #                       serviceUnavailable (503),
117 0269afd6 Giorgos Verigakis
    #                       unauthorized (401),
118 0269afd6 Giorgos Verigakis
    #                       badRequest (400),
119 0269afd6 Giorgos Verigakis
    #                       overLimit (413)
120 ce55f211 Kostas Papadimitriou
121 9e98ba3c Giorgos Verigakis
    log.debug('list_networks detail=%s', detail)
122 b36f78fa Giorgos Verigakis
    since = util.isoparse(request.GET.get('changes-since'))
123 8b2515a9 Christos Stavrakakis
    user_networks = Network.objects.filter(Q(userid=request.user_uniq) |
124 3878553d Kostas Papadimitriou
                                           Q(public=True))
125 ce55f211 Kostas Papadimitriou
126 0269afd6 Giorgos Verigakis
    if since:
127 d44c236b Giorgos Verigakis
        user_networks = user_networks.filter(updated__gte=since)
128 0269afd6 Giorgos Verigakis
        if not user_networks:
129 0269afd6 Giorgos Verigakis
            return HttpResponse(status=304)
130 3878553d Kostas Papadimitriou
    else:
131 3878553d Kostas Papadimitriou
        user_networks = user_networks.filter(deleted=False)
132 ce55f211 Kostas Papadimitriou
133 4b3b8688 Giorgos Verigakis
    networks = [network_to_dict(network, request.user_uniq, detail)
134 73aed6bf Giorgos Verigakis
                for network in user_networks]
135 ce55f211 Kostas Papadimitriou
136 0269afd6 Giorgos Verigakis
    if request.serialization == 'xml':
137 b36f78fa Giorgos Verigakis
        data = render_to_string('list_networks.xml', {
138 b36f78fa Giorgos Verigakis
            'networks': networks,
139 b36f78fa Giorgos Verigakis
            'detail': detail})
140 0269afd6 Giorgos Verigakis
    else:
141 0269afd6 Giorgos Verigakis
        data = json.dumps({'networks': {'values': networks}})
142 aa197ee4 Vangelis Koukis
143 0269afd6 Giorgos Verigakis
    return HttpResponse(data, status=200)
144 0269afd6 Giorgos Verigakis
145 6ef51e9f Giorgos Verigakis
146 b36f78fa Giorgos Verigakis
@util.api_method('POST')
147 4dba0480 Christos Stavrakakis
@transaction.commit_on_success
148 0269afd6 Giorgos Verigakis
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 0269afd6 Giorgos Verigakis
    #                       overLimit (413)
156 aa197ee4 Vangelis Koukis
157 b36f78fa Giorgos Verigakis
    req = util.get_request_dict(request)
158 9e98ba3c Giorgos Verigakis
    log.debug('create_network %s', req)
159 ce55f211 Kostas Papadimitriou
160 0269afd6 Giorgos Verigakis
    try:
161 0269afd6 Giorgos Verigakis
        d = req['network']
162 0269afd6 Giorgos Verigakis
        name = d['name']
163 5061546f Christos Stavrakakis
        # TODO: Fix this temp values:
164 b9a0b3d5 Stavros Sachtouris
        subnet = d.get('cidr', '192.168.1.0/24')
165 cc3f266e Christos Stavrakakis
        subnet6 = d.get('cidr6', None)
166 5061546f Christos Stavrakakis
        gateway = d.get('gateway', None)
167 cc3f266e Christos Stavrakakis
        gateway6 = d.get('gateway6', None)
168 af6a3bc5 Christos Stavrakakis
        net_type = d.get('type', 'PRIVATE_MAC_FILTERED')
169 5061546f Christos Stavrakakis
        dhcp = d.get('dhcp', True)
170 0269afd6 Giorgos Verigakis
    except (KeyError, ValueError):
171 0269afd6 Giorgos Verigakis
        raise BadRequest('Malformed request.')
172 ce55f211 Kostas Papadimitriou
173 af6a3bc5 Christos Stavrakakis
    if net_type == 'PUBLIC_ROUTED':
174 87994836 Christos Stavrakakis
        raise Unauthorized('Can not create a public network.')
175 87994836 Christos Stavrakakis
176 f91dee69 Christos Stavrakakis
    user_networks = len(Network.objects.filter(userid=request.user_uniq,
177 f91dee69 Christos Stavrakakis
                                               deleted=False))
178 f91dee69 Christos Stavrakakis
    if user_networks == settings.MAX_NETWORKS_PER_USER:
179 f4a66897 Christos Stavrakakis
        raise OverLimit('Network count limit exceeded for your account.')
180 f4a66897 Christos Stavrakakis
181 6eed1ede Christos Stavrakakis
    cidr_block = int(subnet.split('/')[1])
182 b14725eb Christos Stavrakakis
    if not util.validate_network_size(cidr_block):
183 b14725eb Christos Stavrakakis
        raise OverLimit("Unsupported network size.")
184 6dd70a5c Christos Stavrakakis
185 3165f027 Christos Stavrakakis
    try:
186 af6a3bc5 Christos Stavrakakis
        link, mac_prefix = util.net_resources(net_type)
187 3165f027 Christos Stavrakakis
        if not link:
188 3165f027 Christos Stavrakakis
            raise Exception("Can not create network. No connectivity link.")
189 3165f027 Christos Stavrakakis
190 3165f027 Christos Stavrakakis
        network = Network.objects.create(
191 3165f027 Christos Stavrakakis
                name=name,
192 3165f027 Christos Stavrakakis
                userid=request.user_uniq,
193 3165f027 Christos Stavrakakis
                subnet=subnet,
194 3165f027 Christos Stavrakakis
                subnet6=subnet6,
195 3165f027 Christos Stavrakakis
                gateway=gateway,
196 3165f027 Christos Stavrakakis
                gateway6=gateway6,
197 3165f027 Christos Stavrakakis
                dhcp=dhcp,
198 af6a3bc5 Christos Stavrakakis
                type=net_type,
199 3165f027 Christos Stavrakakis
                link=link,
200 af6a3bc5 Christos Stavrakakis
                mac_prefix=mac_prefix,
201 1cf6ac86 Christos Stavrakakis
                action='CREATE',
202 3165f027 Christos Stavrakakis
                state='PENDING')
203 03992c72 Christos Stavrakakis
    except EmptyPool:
204 3165f027 Christos Stavrakakis
        raise OverLimit('Network count limit exceeded.')
205 5061546f Christos Stavrakakis
206 7cfbbf32 Christos Stavrakakis
    # Create BackendNetwork entries for each Backend
207 7cfbbf32 Christos Stavrakakis
    network.create_backend_network()
208 7cfbbf32 Christos Stavrakakis
209 7cfbbf32 Christos Stavrakakis
    # Create the network in the actual backends
210 87994836 Christos Stavrakakis
    backend.create_network(network)
211 ce55f211 Kostas Papadimitriou
212 4b3b8688 Giorgos Verigakis
    networkdict = network_to_dict(network, request.user_uniq)
213 0269afd6 Giorgos Verigakis
    return render_network(request, networkdict, status=202)
214 0269afd6 Giorgos Verigakis
215 6ef51e9f Giorgos Verigakis
216 b36f78fa Giorgos Verigakis
@util.api_method('GET')
217 b19653d1 Giorgos Verigakis
def get_network_details(request, network_id):
218 0269afd6 Giorgos Verigakis
    # Normal Response Codes: 200, 203
219 13b954b0 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
220 13b954b0 Giorgos Verigakis
    #                       serviceUnavailable (503),
221 13b954b0 Giorgos Verigakis
    #                       unauthorized (401),
222 13b954b0 Giorgos Verigakis
    #                       badRequest (400),
223 13b954b0 Giorgos Verigakis
    #                       itemNotFound (404),
224 13b954b0 Giorgos Verigakis
    #                       overLimit (413)
225 ce55f211 Kostas Papadimitriou
226 9e98ba3c Giorgos Verigakis
    log.debug('get_network_details %s', network_id)
227 4b3b8688 Giorgos Verigakis
    net = util.get_network(network_id, request.user_uniq)
228 4b3b8688 Giorgos Verigakis
    netdict = network_to_dict(net, request.user_uniq)
229 0269afd6 Giorgos Verigakis
    return render_network(request, netdict)
230 0269afd6 Giorgos Verigakis
231 6ef51e9f Giorgos Verigakis
232 b36f78fa Giorgos Verigakis
@util.api_method('PUT')
233 b19653d1 Giorgos Verigakis
def update_network_name(request, network_id):
234 0269afd6 Giorgos Verigakis
    # Normal Response Code: 204
235 13b954b0 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
236 13b954b0 Giorgos Verigakis
    #                       serviceUnavailable (503),
237 13b954b0 Giorgos Verigakis
    #                       unauthorized (401),
238 13b954b0 Giorgos Verigakis
    #                       badRequest (400),
239 13b954b0 Giorgos Verigakis
    #                       badMediaType(415),
240 13b954b0 Giorgos Verigakis
    #                       itemNotFound (404),
241 13b954b0 Giorgos Verigakis
    #                       overLimit (413)
242 aa197ee4 Vangelis Koukis
243 b36f78fa Giorgos Verigakis
    req = util.get_request_dict(request)
244 9e98ba3c Giorgos Verigakis
    log.debug('update_network_name %s', network_id)
245 ce55f211 Kostas Papadimitriou
246 0269afd6 Giorgos Verigakis
    try:
247 0269afd6 Giorgos Verigakis
        name = req['network']['name']
248 0269afd6 Giorgos Verigakis
    except (TypeError, KeyError):
249 0269afd6 Giorgos Verigakis
        raise BadRequest('Malformed request.')
250 0269afd6 Giorgos Verigakis
251 4b3b8688 Giorgos Verigakis
    net = util.get_network(network_id, request.user_uniq)
252 207b70d5 Giorgos Verigakis
    if net.public:
253 207b70d5 Giorgos Verigakis
        raise Unauthorized('Can not rename the public network.')
254 0269afd6 Giorgos Verigakis
    net.name = name
255 0269afd6 Giorgos Verigakis
    net.save()
256 0269afd6 Giorgos Verigakis
    return HttpResponse(status=204)
257 0269afd6 Giorgos Verigakis
258 6ef51e9f Giorgos Verigakis
259 b36f78fa Giorgos Verigakis
@util.api_method('DELETE')
260 4dba0480 Christos Stavrakakis
@transaction.commit_on_success
261 b19653d1 Giorgos Verigakis
def delete_network(request, network_id):
262 0269afd6 Giorgos Verigakis
    # Normal Response Code: 204
263 13b954b0 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
264 13b954b0 Giorgos Verigakis
    #                       serviceUnavailable (503),
265 13b954b0 Giorgos Verigakis
    #                       unauthorized (401),
266 13b954b0 Giorgos Verigakis
    #                       itemNotFound (404),
267 13b954b0 Giorgos Verigakis
    #                       unauthorized (401),
268 13b954b0 Giorgos Verigakis
    #                       overLimit (413)
269 ce55f211 Kostas Papadimitriou
270 9e98ba3c Giorgos Verigakis
    log.debug('delete_network %s', network_id)
271 d2e73c0c Christos Stavrakakis
    net = util.get_network(network_id, request.user_uniq, for_update=True)
272 207b70d5 Giorgos Verigakis
    if net.public:
273 207b70d5 Giorgos Verigakis
        raise Unauthorized('Can not delete the public network.')
274 5061546f Christos Stavrakakis
275 0196d9a3 Christos Stavrakakis
    if net.machines.all():  # Nics attached on network
276 0196d9a3 Christos Stavrakakis
        raise NetworkInUse('Machines are connected to network.')
277 0196d9a3 Christos Stavrakakis
278 5061546f Christos Stavrakakis
    net.action = 'DESTROY'
279 5061546f Christos Stavrakakis
    net.save()
280 5061546f Christos Stavrakakis
281 64938cb0 Giorgos Verigakis
    backend.delete_network(net)
282 0269afd6 Giorgos Verigakis
    return HttpResponse(status=204)
283 0269afd6 Giorgos Verigakis
284 6ef51e9f Giorgos Verigakis
285 b36f78fa Giorgos Verigakis
@util.api_method('POST')
286 b19653d1 Giorgos Verigakis
def network_action(request, network_id):
287 9e98ba3c Giorgos Verigakis
    req = util.get_request_dict(request)
288 9e98ba3c Giorgos Verigakis
    log.debug('network_action %s %s', network_id, req)
289 9e98ba3c Giorgos Verigakis
    if len(req) != 1:
290 9e98ba3c Giorgos Verigakis
        raise BadRequest('Malformed request.')
291 ce55f211 Kostas Papadimitriou
292 4b3b8688 Giorgos Verigakis
    net = util.get_network(network_id, request.user_uniq)
293 207b70d5 Giorgos Verigakis
    if net.public:
294 207b70d5 Giorgos Verigakis
        raise Unauthorized('Can not modify the public network.')
295 ce55f211 Kostas Papadimitriou
296 0269afd6 Giorgos Verigakis
    key = req.keys()[0]
297 0269afd6 Giorgos Verigakis
    val = req[key]
298 aa197ee4 Vangelis Koukis
299 0269afd6 Giorgos Verigakis
    try:
300 0269afd6 Giorgos Verigakis
        assert isinstance(val, dict)
301 0269afd6 Giorgos Verigakis
        return network_actions[key](request, net, req[key])
302 0269afd6 Giorgos Verigakis
    except KeyError:
303 0269afd6 Giorgos Verigakis
        raise BadRequest('Unknown action.')
304 0269afd6 Giorgos Verigakis
    except AssertionError:
305 0269afd6 Giorgos Verigakis
        raise BadRequest('Invalid argument.')