Statistics
| Branch: | Tag: | Revision:

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

History | View | Annotate | Download (10.3 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 8b2515a9 Christos Stavrakakis
    user_networks = Network.objects.filter(Q(userid=request.user_uniq) |
124 3878553d Kostas Papadimitriou
                                           Q(public=True))
125 b6bc4afa Christos Stavrakakis
    user_networks = utils.filter_modified_since(request, objects=user_networks)
126 ce55f211 Kostas Papadimitriou
127 ece5581b Christos Stavrakakis
    networks_dict = [network_to_dict(network, request.user_uniq, detail)
128 ece5581b Christos Stavrakakis
                     for network in user_networks.order_by('id')]
129 ce55f211 Kostas Papadimitriou
130 0269afd6 Giorgos Verigakis
    if request.serialization == 'xml':
131 b36f78fa Giorgos Verigakis
        data = render_to_string('list_networks.xml', {
132 ece5581b Christos Stavrakakis
            'networks': networks_dict,
133 b36f78fa Giorgos Verigakis
            'detail': detail})
134 0269afd6 Giorgos Verigakis
    else:
135 ece5581b Christos Stavrakakis
        data = json.dumps({'networks': networks_dict})
136 aa197ee4 Vangelis Koukis
137 0269afd6 Giorgos Verigakis
    return HttpResponse(data, status=200)
138 0269afd6 Giorgos Verigakis
139 6ef51e9f Giorgos Verigakis
140 b3fd98ae Christos Stavrakakis
@api.api_method(http_method='POST', user_required=True, logger=log)
141 2509ce17 Christos Stavrakakis
def create_network(request):
142 0269afd6 Giorgos Verigakis
    # Normal Response Code: 202
143 0269afd6 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
144 0269afd6 Giorgos Verigakis
    #                       serviceUnavailable (503),
145 0269afd6 Giorgos Verigakis
    #                       unauthorized (401),
146 13b954b0 Giorgos Verigakis
    #                       badMediaType(415),
147 0269afd6 Giorgos Verigakis
    #                       badRequest (400),
148 17c2ed57 Christos Stavrakakis
    #                       forbidden (403)
149 0269afd6 Giorgos Verigakis
    #                       overLimit (413)
150 aa197ee4 Vangelis Koukis
151 ece5581b Christos Stavrakakis
    req = utils.get_request_dict(request)
152 ece5581b Christos Stavrakakis
    log.info('create_network %s', req)
153 ece5581b Christos Stavrakakis
    user_id = request.user_uniq
154 3165f027 Christos Stavrakakis
    try:
155 ece5581b Christos Stavrakakis
        d = req['network']
156 ece5581b Christos Stavrakakis
        name = d['name']
157 ece5581b Christos Stavrakakis
    except KeyError:
158 ece5581b Christos Stavrakakis
        raise faults.BadRequest("Malformed request")
159 ece5581b Christos Stavrakakis
160 ece5581b Christos Stavrakakis
    # Get and validate flavor. Flavors are still exposed as 'type' in the
161 ece5581b Christos Stavrakakis
    # API.
162 ece5581b Christos Stavrakakis
    flavor = d.get("type", None)
163 ece5581b Christos Stavrakakis
    if flavor is None:
164 ece5581b Christos Stavrakakis
        raise faults.BadRequest("Missing request parameter 'type'")
165 ece5581b Christos Stavrakakis
    elif flavor not in Network.FLAVORS.keys():
166 ece5581b Christos Stavrakakis
        raise faults.BadRequest("Invalid network type '%s'" % flavor)
167 ece5581b Christos Stavrakakis
    elif flavor not in settings.API_ENABLED_NETWORK_FLAVORS:
168 99af08a4 Christos Stavrakakis
            raise faults.Forbidden("Can not create network of type '%s'" %
169 99af08a4 Christos Stavrakakis
                                   flavor)
170 ece5581b Christos Stavrakakis
    public = d.get("public", False)
171 ece5581b Christos Stavrakakis
    if public:
172 ece5581b Christos Stavrakakis
        raise faults.Forbidden("Can not create a public network.")
173 4e1133ab Christos Stavrakakis
174 ece5581b Christos Stavrakakis
    dhcp = d.get('dhcp', True)
175 ece5581b Christos Stavrakakis
176 ece5581b Christos Stavrakakis
    # Get and validate network parameters
177 ece5581b Christos Stavrakakis
    subnet = d.get('cidr', '192.168.1.0/24')
178 ece5581b Christos Stavrakakis
    subnet6 = d.get('cidr6', None)
179 ece5581b Christos Stavrakakis
    gateway = d.get('gateway', None)
180 ece5581b Christos Stavrakakis
    gateway6 = d.get('gateway6', None)
181 ece5581b Christos Stavrakakis
182 ece5581b Christos Stavrakakis
    network = networks.create(user_id=user_id, name=name, flavor=flavor,
183 ece5581b Christos Stavrakakis
                              subnet=subnet, gateway=gateway, subnet6=subnet6,
184 ece5581b Christos Stavrakakis
                              gateway6=gateway6, dhcp=dhcp, public=False)
185 7cfbbf32 Christos Stavrakakis
186 4b3b8688 Giorgos Verigakis
    networkdict = network_to_dict(network, request.user_uniq)
187 77f45438 Christos Stavrakakis
    response = render_network(request, networkdict, status=202)
188 77f45438 Christos Stavrakakis
189 77f45438 Christos Stavrakakis
    return response
190 0269afd6 Giorgos Verigakis
191 6ef51e9f Giorgos Verigakis
192 b3fd98ae Christos Stavrakakis
@api.api_method(http_method='GET', user_required=True, logger=log)
193 b19653d1 Giorgos Verigakis
def get_network_details(request, network_id):
194 0269afd6 Giorgos Verigakis
    # Normal Response Codes: 200, 203
195 13b954b0 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
196 13b954b0 Giorgos Verigakis
    #                       serviceUnavailable (503),
197 13b954b0 Giorgos Verigakis
    #                       unauthorized (401),
198 13b954b0 Giorgos Verigakis
    #                       badRequest (400),
199 13b954b0 Giorgos Verigakis
    #                       itemNotFound (404),
200 13b954b0 Giorgos Verigakis
    #                       overLimit (413)
201 ce55f211 Kostas Papadimitriou
202 0c37a721 Christos Stavrakakis
    log.debug('get_network_details %s', network_id)
203 4b3b8688 Giorgos Verigakis
    net = util.get_network(network_id, request.user_uniq)
204 4b3b8688 Giorgos Verigakis
    netdict = network_to_dict(net, request.user_uniq)
205 0269afd6 Giorgos Verigakis
    return render_network(request, netdict)
206 0269afd6 Giorgos Verigakis
207 6ef51e9f Giorgos Verigakis
208 b3fd98ae Christos Stavrakakis
@api.api_method(http_method='PUT', user_required=True, logger=log)
209 b19653d1 Giorgos Verigakis
def update_network_name(request, network_id):
210 0269afd6 Giorgos Verigakis
    # Normal Response Code: 204
211 13b954b0 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
212 13b954b0 Giorgos Verigakis
    #                       serviceUnavailable (503),
213 13b954b0 Giorgos Verigakis
    #                       unauthorized (401),
214 13b954b0 Giorgos Verigakis
    #                       badRequest (400),
215 17c2ed57 Christos Stavrakakis
    #                       forbidden (403)
216 13b954b0 Giorgos Verigakis
    #                       badMediaType(415),
217 13b954b0 Giorgos Verigakis
    #                       itemNotFound (404),
218 13b954b0 Giorgos Verigakis
    #                       overLimit (413)
219 aa197ee4 Vangelis Koukis
220 b3fd98ae Christos Stavrakakis
    req = utils.get_request_dict(request)
221 bf5c82dc Christos Stavrakakis
    log.info('update_network_name %s', network_id)
222 ce55f211 Kostas Papadimitriou
223 0269afd6 Giorgos Verigakis
    try:
224 0269afd6 Giorgos Verigakis
        name = req['network']['name']
225 0269afd6 Giorgos Verigakis
    except (TypeError, KeyError):
226 bd40abfa Christos Stavrakakis
        raise faults.BadRequest('Malformed request.')
227 0269afd6 Giorgos Verigakis
228 ece5581b Christos Stavrakakis
    network = util.get_network(network_id, request.user_uniq)
229 ece5581b Christos Stavrakakis
    if network.public:
230 bd40abfa Christos Stavrakakis
        raise faults.Forbidden('Can not rename the public network.')
231 ece5581b Christos Stavrakakis
    network = networks.rename(network, name)
232 0269afd6 Giorgos Verigakis
    return HttpResponse(status=204)
233 0269afd6 Giorgos Verigakis
234 6ef51e9f Giorgos Verigakis
235 b3fd98ae Christos Stavrakakis
@api.api_method(http_method='DELETE', user_required=True, logger=log)
236 b19653d1 Giorgos Verigakis
def delete_network(request, network_id):
237 0269afd6 Giorgos Verigakis
    # Normal Response Code: 204
238 13b954b0 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
239 13b954b0 Giorgos Verigakis
    #                       serviceUnavailable (503),
240 13b954b0 Giorgos Verigakis
    #                       unauthorized (401),
241 17c2ed57 Christos Stavrakakis
    #                       forbidden (403)
242 13b954b0 Giorgos Verigakis
    #                       itemNotFound (404),
243 13b954b0 Giorgos Verigakis
    #                       overLimit (413)
244 ce55f211 Kostas Papadimitriou
245 bf5c82dc Christos Stavrakakis
    log.info('delete_network %s', network_id)
246 ece5581b Christos Stavrakakis
    network = util.get_network(network_id, request.user_uniq, for_update=True)
247 ece5581b Christos Stavrakakis
    if network.public:
248 bd40abfa Christos Stavrakakis
        raise faults.Forbidden('Can not delete the public network.')
249 ece5581b Christos Stavrakakis
    networks.delete(network)
250 ece5581b Christos Stavrakakis
    return HttpResponse(status=204)
251 5061546f Christos Stavrakakis
252 5061546f Christos Stavrakakis
253 ece5581b Christos Stavrakakis
def key_to_action(action):
254 ece5581b Christos Stavrakakis
    return action.upper()
255 0269afd6 Giorgos Verigakis
256 6ef51e9f Giorgos Verigakis
257 b3fd98ae Christos Stavrakakis
@api.api_method(http_method='POST', user_required=True, logger=log)
258 ece5581b Christos Stavrakakis
def demux_network_action(request, network_id):
259 b3fd98ae Christos Stavrakakis
    req = utils.get_request_dict(request)
260 0c37a721 Christos Stavrakakis
    log.debug('network_action %s %s', network_id, req)
261 9e98ba3c Giorgos Verigakis
    if len(req) != 1:
262 bd40abfa Christos Stavrakakis
        raise faults.BadRequest('Malformed request.')
263 ce55f211 Kostas Papadimitriou
264 4b3b8688 Giorgos Verigakis
    net = util.get_network(network_id, request.user_uniq)
265 207b70d5 Giorgos Verigakis
    if net.public:
266 bd40abfa Christos Stavrakakis
        raise faults.Forbidden('Can not modify the public network.')
267 22a9959d Christos Stavrakakis
    if net.deleted:
268 05d401cf Christos Stavrakakis
        raise faults.BadRequest("Network has been deleted.")
269 ce55f211 Kostas Papadimitriou
270 ece5581b Christos Stavrakakis
    action = req.keys()[0]
271 ece5581b Christos Stavrakakis
    if key_to_action(action) not in [x[0] for x in Network.ACTIONS]:
272 ece5581b Christos Stavrakakis
        raise faults.BadRequest("Action %s not supported." % action)
273 ece5581b Christos Stavrakakis
    action_args = req[action]
274 ece5581b Christos Stavrakakis
    if not isinstance(action_args, dict):
275 ece5581b Christos Stavrakakis
        raise faults.BadRequest("Invalid argument.")
276 ece5581b Christos Stavrakakis
    return network_actions[action](request, net, action_args)