Statistics
| Branch: | Tag: | Revision:

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

History | View | Annotate | Download (9.6 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 0269afd6 Giorgos Verigakis
from django.http import HttpResponse
40 69d6d7dd Giorgos Verigakis
from django.template.loader import render_to_string
41 0269afd6 Giorgos Verigakis
from django.utils import simplejson as json
42 0269afd6 Giorgos Verigakis
43 5061546f Christos Stavrakakis
from synnefo import settings
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 b36f78fa Giorgos Verigakis
from synnefo.api.faults import BadRequest, OverLimit, Unauthorized
48 5061546f Christos Stavrakakis
from synnefo.db.models import Network, BridgePool, MacPrefixPool
49 b36f78fa Giorgos Verigakis
from synnefo.logic import backend
50 9e98ba3c Giorgos Verigakis
51 9e98ba3c Giorgos Verigakis
52 9e98ba3c Giorgos Verigakis
log = getLogger('synnefo.api')
53 b36f78fa Giorgos Verigakis
54 0269afd6 Giorgos Verigakis
55 0269afd6 Giorgos Verigakis
urlpatterns = patterns('synnefo.api.networks',
56 0269afd6 Giorgos Verigakis
    (r'^(?:/|.json|.xml)?$', 'demux'),
57 0269afd6 Giorgos Verigakis
    (r'^/detail(?:.json|.xml)?$', 'list_networks', {'detail': True}),
58 f4fe8796 Giorgos Verigakis
    (r'^/(\w+)(?:.json|.xml)?$', 'network_demux'),
59 f4fe8796 Giorgos Verigakis
    (r'^/(\w+)/action(?:.json|.xml)?$', 'network_action'),
60 0269afd6 Giorgos Verigakis
)
61 0269afd6 Giorgos Verigakis
62 0269afd6 Giorgos Verigakis
63 0269afd6 Giorgos Verigakis
def demux(request):
64 0269afd6 Giorgos Verigakis
    if request.method == 'GET':
65 0269afd6 Giorgos Verigakis
        return list_networks(request)
66 0269afd6 Giorgos Verigakis
    elif request.method == 'POST':
67 0269afd6 Giorgos Verigakis
        return create_network(request)
68 0269afd6 Giorgos Verigakis
    else:
69 0269afd6 Giorgos Verigakis
        return method_not_allowed(request)
70 0269afd6 Giorgos Verigakis
71 6ef51e9f Giorgos Verigakis
72 b19653d1 Giorgos Verigakis
def network_demux(request, network_id):
73 0269afd6 Giorgos Verigakis
    if request.method == 'GET':
74 b19653d1 Giorgos Verigakis
        return get_network_details(request, network_id)
75 0269afd6 Giorgos Verigakis
    elif request.method == 'PUT':
76 b19653d1 Giorgos Verigakis
        return update_network_name(request, network_id)
77 0269afd6 Giorgos Verigakis
    elif request.method == 'DELETE':
78 b19653d1 Giorgos Verigakis
        return delete_network(request, network_id)
79 0269afd6 Giorgos Verigakis
    else:
80 0269afd6 Giorgos Verigakis
        return method_not_allowed(request)
81 0269afd6 Giorgos Verigakis
82 0269afd6 Giorgos Verigakis
83 6ef51e9f Giorgos Verigakis
def network_to_dict(network, user_id, detail=True):
84 207b70d5 Giorgos Verigakis
    network_id = str(network.id) if not network.public else 'public'
85 207b70d5 Giorgos Verigakis
    d = {'id': network_id, 'name': network.name}
86 0269afd6 Giorgos Verigakis
    if detail:
87 08b079e2 Stavros Sachtouris
        d['cidr'] = network.subnet
88 08b079e2 Stavros Sachtouris
        d['gateway'] = network.gateway
89 08b079e2 Stavros Sachtouris
        d['dhcp'] = network.dhcp
90 08b079e2 Stavros Sachtouris
        d['type'] = network.type
91 b36f78fa Giorgos Verigakis
        d['updated'] = util.isoformat(network.updated)
92 b36f78fa Giorgos Verigakis
        d['created'] = util.isoformat(network.created)
93 d44c236b Giorgos Verigakis
        d['status'] = network.state
94 08b079e2 Stavros Sachtouris
95 08b079e2 Stavros Sachtouris
        attachments = [util.construct_nic_id(nic) for nic in network.nics.filter(machine__userid= user_id)]
96 08b079e2 Stavros Sachtouris
        d['attachments'] = {'values':attachments}
97 0269afd6 Giorgos Verigakis
    return d
98 0269afd6 Giorgos Verigakis
99 6ef51e9f Giorgos Verigakis
100 0269afd6 Giorgos Verigakis
def render_network(request, networkdict, status=200):
101 0269afd6 Giorgos Verigakis
    if request.serialization == 'xml':
102 0269afd6 Giorgos Verigakis
        data = render_to_string('network.xml', {'network': networkdict})
103 0269afd6 Giorgos Verigakis
    else:
104 0269afd6 Giorgos Verigakis
        data = json.dumps({'network': networkdict})
105 0269afd6 Giorgos Verigakis
    return HttpResponse(data, status=status)
106 0269afd6 Giorgos Verigakis
107 0269afd6 Giorgos Verigakis
108 b36f78fa Giorgos Verigakis
@util.api_method('GET')
109 0269afd6 Giorgos Verigakis
def list_networks(request, detail=False):
110 0269afd6 Giorgos Verigakis
    # Normal Response Codes: 200, 203
111 0269afd6 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
112 0269afd6 Giorgos Verigakis
    #                       serviceUnavailable (503),
113 0269afd6 Giorgos Verigakis
    #                       unauthorized (401),
114 0269afd6 Giorgos Verigakis
    #                       badRequest (400),
115 0269afd6 Giorgos Verigakis
    #                       overLimit (413)
116 ce55f211 Kostas Papadimitriou
117 9e98ba3c Giorgos Verigakis
    log.debug('list_networks detail=%s', detail)
118 b36f78fa Giorgos Verigakis
    since = util.isoparse(request.GET.get('changes-since'))
119 6ef51e9f Giorgos Verigakis
    user_networks = Network.objects.filter(
120 4b3b8688 Giorgos Verigakis
                                Q(userid=request.user_uniq) | Q(public=True))
121 ce55f211 Kostas Papadimitriou
122 0269afd6 Giorgos Verigakis
    if since:
123 d44c236b Giorgos Verigakis
        user_networks = user_networks.filter(updated__gte=since)
124 0269afd6 Giorgos Verigakis
        if not user_networks:
125 0269afd6 Giorgos Verigakis
            return HttpResponse(status=304)
126 0269afd6 Giorgos Verigakis
    else:
127 5061546f Christos Stavrakakis
        user_networks = user_networks.filter(deleted=False)
128 ce55f211 Kostas Papadimitriou
129 4b3b8688 Giorgos Verigakis
    networks = [network_to_dict(network, request.user_uniq, detail)
130 73aed6bf Giorgos Verigakis
                for network in user_networks]
131 ce55f211 Kostas Papadimitriou
132 0269afd6 Giorgos Verigakis
    if request.serialization == 'xml':
133 b36f78fa Giorgos Verigakis
        data = render_to_string('list_networks.xml', {
134 b36f78fa Giorgos Verigakis
            'networks': networks,
135 b36f78fa Giorgos Verigakis
            'detail': detail})
136 0269afd6 Giorgos Verigakis
    else:
137 0269afd6 Giorgos Verigakis
        data = json.dumps({'networks': {'values': networks}})
138 aa197ee4 Vangelis Koukis
139 0269afd6 Giorgos Verigakis
    return HttpResponse(data, status=200)
140 0269afd6 Giorgos Verigakis
141 6ef51e9f Giorgos Verigakis
142 b36f78fa Giorgos Verigakis
@util.api_method('POST')
143 0269afd6 Giorgos Verigakis
def create_network(request):
144 0269afd6 Giorgos Verigakis
    # Normal Response Code: 202
145 0269afd6 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
146 0269afd6 Giorgos Verigakis
    #                       serviceUnavailable (503),
147 0269afd6 Giorgos Verigakis
    #                       unauthorized (401),
148 13b954b0 Giorgos Verigakis
    #                       badMediaType(415),
149 0269afd6 Giorgos Verigakis
    #                       badRequest (400),
150 0269afd6 Giorgos Verigakis
    #                       overLimit (413)
151 aa197ee4 Vangelis Koukis
152 b36f78fa Giorgos Verigakis
    req = util.get_request_dict(request)
153 9e98ba3c Giorgos Verigakis
    log.debug('create_network %s', req)
154 ce55f211 Kostas Papadimitriou
155 0269afd6 Giorgos Verigakis
    try:
156 0269afd6 Giorgos Verigakis
        d = req['network']
157 0269afd6 Giorgos Verigakis
        name = d['name']
158 5061546f Christos Stavrakakis
        # TODO: Fix this temp values:
159 5061546f Christos Stavrakakis
        subnet = d.get('subnet', '192.168.1.0/24')
160 5061546f Christos Stavrakakis
        gateway = d.get('gateway', None)
161 04fe9a86 Christos Stavrakakis
        type = d.get('type', 'PRIVATE_VLAN')
162 5061546f Christos Stavrakakis
        dhcp = d.get('dhcp', True)
163 0269afd6 Giorgos Verigakis
    except (KeyError, ValueError):
164 0269afd6 Giorgos Verigakis
        raise BadRequest('Malformed request.')
165 ce55f211 Kostas Papadimitriou
166 5061546f Christos Stavrakakis
    link = None
167 5061546f Christos Stavrakakis
    mac_prefix = None
168 5061546f Christos Stavrakakis
    if type == 'PUBLIC_ROUTED':
169 5061546f Christos Stavrakakis
        pass
170 5061546f Christos Stavrakakis
        # raise Exception (user can not create public)
171 5061546f Christos Stavrakakis
    if type == 'PRIVATE_FILTERED':
172 04fe9a86 Christos Stavrakakis
        link = settings.GANETI_PRIVATE_BRIDGE
173 5061546f Christos Stavrakakis
        mac_prefix = MacPrefixPool.get_available().value
174 5061546f Christos Stavrakakis
        state = 'PENDING'
175 04fe9a86 Christos Stavrakakis
    else: # PRIVATE_VLAN
176 04fe9a86 Christos Stavrakakis
        link = BridgePool.get_available().value
177 5061546f Christos Stavrakakis
        # Physical-Vlans are pre-provisioned
178 5061546f Christos Stavrakakis
        state = 'ACTIVE'
179 5061546f Christos Stavrakakis
180 5061546f Christos Stavrakakis
    network = Network.objects.create(
181 5061546f Christos Stavrakakis
            name=name,
182 5061546f Christos Stavrakakis
            userid=request.user_uniq,
183 5061546f Christos Stavrakakis
            subnet=subnet,
184 5061546f Christos Stavrakakis
            gateway=gateway,
185 5061546f Christos Stavrakakis
            dhcp=dhcp,
186 5061546f Christos Stavrakakis
            type=type,
187 5061546f Christos Stavrakakis
            link=link,
188 5061546f Christos Stavrakakis
            mac_prefix=mac_prefix,
189 5061546f Christos Stavrakakis
            state=state)
190 5061546f Christos Stavrakakis
191 5061546f Christos Stavrakakis
    network = backend.create_network(network)
192 5061546f Christos Stavrakakis
    if not network:
193 5061546f Christos Stavrakakis
        raise OverLimit('Network count limit exceeded for your account.')
194 ce55f211 Kostas Papadimitriou
195 4b3b8688 Giorgos Verigakis
    networkdict = network_to_dict(network, request.user_uniq)
196 0269afd6 Giorgos Verigakis
    return render_network(request, networkdict, status=202)
197 0269afd6 Giorgos Verigakis
198 6ef51e9f Giorgos Verigakis
199 b36f78fa Giorgos Verigakis
@util.api_method('GET')
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 9e98ba3c Giorgos Verigakis
    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 b36f78fa Giorgos Verigakis
@util.api_method('PUT')
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 13b954b0 Giorgos Verigakis
    #                       badMediaType(415),
223 13b954b0 Giorgos Verigakis
    #                       itemNotFound (404),
224 13b954b0 Giorgos Verigakis
    #                       overLimit (413)
225 aa197ee4 Vangelis Koukis
226 b36f78fa Giorgos Verigakis
    req = util.get_request_dict(request)
227 9e98ba3c Giorgos Verigakis
    log.debug('update_network_name %s', network_id)
228 ce55f211 Kostas Papadimitriou
229 0269afd6 Giorgos Verigakis
    try:
230 0269afd6 Giorgos Verigakis
        name = req['network']['name']
231 0269afd6 Giorgos Verigakis
    except (TypeError, KeyError):
232 0269afd6 Giorgos Verigakis
        raise BadRequest('Malformed request.')
233 0269afd6 Giorgos Verigakis
234 4b3b8688 Giorgos Verigakis
    net = util.get_network(network_id, request.user_uniq)
235 207b70d5 Giorgos Verigakis
    if net.public:
236 207b70d5 Giorgos Verigakis
        raise Unauthorized('Can not rename the public network.')
237 0269afd6 Giorgos Verigakis
    net.name = name
238 0269afd6 Giorgos Verigakis
    net.save()
239 0269afd6 Giorgos Verigakis
    return HttpResponse(status=204)
240 0269afd6 Giorgos Verigakis
241 6ef51e9f Giorgos Verigakis
242 b36f78fa Giorgos Verigakis
@util.api_method('DELETE')
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 13b954b0 Giorgos Verigakis
    #                       itemNotFound (404),
249 13b954b0 Giorgos Verigakis
    #                       unauthorized (401),
250 13b954b0 Giorgos Verigakis
    #                       overLimit (413)
251 ce55f211 Kostas Papadimitriou
252 9e98ba3c Giorgos Verigakis
    log.debug('delete_network %s', network_id)
253 4b3b8688 Giorgos Verigakis
    net = util.get_network(network_id, request.user_uniq)
254 207b70d5 Giorgos Verigakis
    if net.public:
255 207b70d5 Giorgos Verigakis
        raise Unauthorized('Can not delete the public network.')
256 5061546f Christos Stavrakakis
257 5061546f Christos Stavrakakis
    net.action = 'DESTROY'
258 5061546f Christos Stavrakakis
    net.save()
259 5061546f Christos Stavrakakis
260 64938cb0 Giorgos Verigakis
    backend.delete_network(net)
261 0269afd6 Giorgos Verigakis
    return HttpResponse(status=204)
262 0269afd6 Giorgos Verigakis
263 6ef51e9f Giorgos Verigakis
264 b36f78fa Giorgos Verigakis
@util.api_method('POST')
265 b19653d1 Giorgos Verigakis
def network_action(request, network_id):
266 9e98ba3c Giorgos Verigakis
    req = util.get_request_dict(request)
267 9e98ba3c Giorgos Verigakis
    log.debug('network_action %s %s', network_id, req)
268 9e98ba3c Giorgos Verigakis
    if len(req) != 1:
269 9e98ba3c Giorgos Verigakis
        raise 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 207b70d5 Giorgos Verigakis
        raise Unauthorized('Can not modify the public network.')
274 ce55f211 Kostas Papadimitriou
275 0269afd6 Giorgos Verigakis
    key = req.keys()[0]
276 0269afd6 Giorgos Verigakis
    val = req[key]
277 aa197ee4 Vangelis Koukis
278 0269afd6 Giorgos Verigakis
    try:
279 0269afd6 Giorgos Verigakis
        assert isinstance(val, dict)
280 0269afd6 Giorgos Verigakis
        return network_actions[key](request, net, req[key])
281 0269afd6 Giorgos Verigakis
    except KeyError:
282 0269afd6 Giorgos Verigakis
        raise BadRequest('Unknown action.')
283 0269afd6 Giorgos Verigakis
    except AssertionError:
284 0269afd6 Giorgos Verigakis
        raise BadRequest('Invalid argument.')