Statistics
| Branch: | Tag: | Revision:

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

History | View | Annotate | Download (8.4 kB)

1
# Copyright 2011-2014 GRNET S.A. All rights reserved.
2
#
3
# Redistribution and use in source and binary forms, with or
4
# without modification, are permitted provided that the following
5
# conditions are met:
6
#
7
#   1. Redistributions of source code must retain the above
8
#      copyright notice, this list of conditions and the following
9
#      disclaimer.
10
#
11
#   2. Redistributions in binary form must reproduce the above
12
#      copyright notice, this list of conditions and the following
13
#      disclaimer in the documentation and/or other materials
14
#      provided with the distribution.
15
#
16
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
17
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
20
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27
# POSSIBILITY OF SUCH DAMAGE.
28
#
29
# The views and conclusions contained in the software and
30
# documentation are those of the authors and should not be
31
# interpreted as representing official policies, either expressed
32
# or implied, of GRNET S.A.
33

    
34
from django.conf import settings
35
from django.conf.urls import patterns
36
from django.http import HttpResponse
37
from django.utils import simplejson as json
38
from django.db import transaction
39
from django.db.models import Q
40
from django.template.loader import render_to_string
41

    
42
from snf_django.lib import api
43
from snf_django.lib.api import utils
44

    
45
from synnefo.api import util
46
from synnefo.db.models import Network
47
from synnefo.logic import networks
48

    
49
from logging import getLogger
50

    
51
log = getLogger(__name__)
52

    
53
urlpatterns = patterns(
54
    'synnefo.api.networks',
55
    (r'^(?:/|.json|.xml)?$', 'demux'),
56
    (r'^/detail(?:.json|.xml)?$', 'list_networks', {'detail': True}),
57
    (r'^/(\w+)(?:/|.json|.xml)?$', 'network_demux'),
58
    (r'^/(\w+)/action(?:/|.json|.xml)?$', 'network_action_demux'),
59
)
60

    
61

    
62
def demux(request):
63
    if request.method == 'GET':
64
        return list_networks(request)
65
    elif request.method == 'POST':
66
        return create_network(request)
67
    else:
68
        return api.api_method_not_allowed(request,
69
                                          allowed_methods=['GET', 'POST'])
70

    
71

    
72
def network_demux(request, network_id):
73

    
74
    if request.method == 'GET':
75
        return get_network_details(request, network_id)
76
    elif request.method == 'DELETE':
77
        return delete_network(request, network_id)
78
    elif request.method == 'PUT':
79
        return update_network(request, network_id)
80
    else:
81
        return api.api_method_not_allowed(request,
82
                                          allowed_methods=['GET',
83
                                                           'PUT',
84
                                                           'DELETE'])
85

    
86

    
87
@api.api_method(http_method='POST', user_required=True, logger=log)
88
def network_action_demux(request, network_id):
89
    req = utils.get_request_dict(request)
90
    network = util.get_network(network_id, request.user_uniq, for_update=True)
91
    action = req.keys()[0]
92
    try:
93
        f = NETWORK_ACTIONS[action]
94
    except KeyError:
95
        raise faults.BadRequest("Action %s not supported." % action)
96
    action_args = req[action]
97
    if not isinstance(action_args, dict):
98
        raise faults.BadRequest("Invalid argument.")
99

    
100
    return f(request, network, action_args)
101

    
102

    
103
@api.api_method(http_method='GET', user_required=True, logger=log)
104
def list_networks(request, detail=True):
105
    log.debug('list_networks detail=%s', detail)
106

    
107
    user_networks = Network.objects.filter(Q(userid=request.user_uniq) |
108
                                           Q(public=True))\
109
                                   .order_by('id')
110

    
111
    user_networks = api.utils.filter_modified_since(request,
112
                                                    objects=user_networks)
113

    
114
    network_dicts = [network_to_dict(network, detail)
115
                     for network in user_networks]
116

    
117
    if request.serialization == 'xml':
118
        data = render_to_string('list_networks.xml', {
119
            "networks": network_dicts})
120
    else:
121
        data = json.dumps({'networks': network_dicts})
122

    
123
    return HttpResponse(data, status=200)
124

    
125

    
126
@api.api_method(http_method='POST', user_required=True, logger=log)
127
def create_network(request):
128
    userid = request.user_uniq
129
    req = api.utils.get_request_dict(request)
130
    log.info('create_network %s', req)
131

    
132
    network_dict = api.utils.get_attribute(req, "network",
133
                                           attr_type=dict)
134
    flavor = api.utils.get_attribute(network_dict, "type",
135
                                     attr_type=basestring)
136

    
137
    if flavor not in Network.FLAVORS.keys():
138
        raise api.faults.BadRequest("Invalid network type '%s'" % flavor)
139
    if flavor not in settings.API_ENABLED_NETWORK_FLAVORS:
140
        raise api.faults.Forbidden("Cannot create network of type '%s'." %
141
                                   flavor)
142

    
143
    name = api.utils.get_attribute(network_dict, "name", attr_type=basestring,
144
                                   required=False)
145
    if name is None:
146
        name = ""
147

    
148
    project = network_dict.get('project', None)
149
    network = networks.create(userid=userid, name=name, flavor=flavor,
150
                              public=False, project=project)
151
    networkdict = network_to_dict(network, detail=True)
152
    response = render_network(request, networkdict, status=201)
153

    
154
    return response
155

    
156

    
157
@api.api_method(http_method='GET', user_required=True, logger=log)
158
def get_network_details(request, network_id):
159
    log.debug('get_network_details %s', network_id)
160
    network = util.get_network(network_id, request.user_uniq)
161
    return render_network(request, network_to_dict(network, detail=True))
162

    
163

    
164
@api.api_method(http_method='PUT', user_required=True, logger=log)
165
def update_network(request, network_id):
166
    info = api.utils.get_request_dict(request)
167

    
168
    network = api.utils.get_attribute(info, "network", attr_type=dict,
169
                                      required=True)
170
    new_name = api.utils.get_attribute(network, "name", attr_type=basestring)
171

    
172
    network = util.get_network(network_id, request.user_uniq, for_update=True)
173
    if network.public:
174
        raise api.faults.Forbidden("Cannot rename the public network.")
175
    network = networks.rename(network, new_name)
176
    return render_network(request, network_to_dict(network), 200)
177

    
178

    
179
@api.api_method(http_method='DELETE', user_required=True, logger=log)
180
@transaction.commit_on_success
181
def delete_network(request, network_id):
182
    log.info('delete_network %s', network_id)
183
    network = util.get_network(network_id, request.user_uniq, for_update=True)
184
    if network.public:
185
        raise api.faults.Forbidden("Cannot delete the public network.")
186
    networks.delete(network)
187
    return HttpResponse(status=204)
188

    
189

    
190
def network_to_dict(network, detail=True):
191
    d = {'id': str(network.id), 'name': network.name}
192
    d['links'] = util.network_to_links(network.id)
193
    if detail:
194
        state = "SNF:DRAINED" if network.drained else network.state
195
        d['user_id'] = network.userid
196
        d['tenant_id'] = network.project
197
        d['type'] = network.flavor
198
        d['updated'] = api.utils.isoformat(network.updated)
199
        d['created'] = api.utils.isoformat(network.created)
200
        d['status'] = state
201
        d['public'] = network.public
202
        d['router:external'] = network.external_router
203
        d['admin_state_up'] = True
204
        d['subnets'] = network.subnet_ids
205
        d['SNF:floating_ip_pool'] = network.floating_ip_pool
206
        d['deleted'] = network.deleted
207
    return d
208

    
209

    
210
@transaction.commit_on_success
211
def reassign_network(request, network, args):
212
    project = args.get("project")
213
    if project is None:
214
        raise api.faults.BadRequest("Missing 'project' attribute.")
215
    networks.reassign(network, project)
216
    return HttpResponse(status=200)
217

    
218

    
219
NETWORK_ACTIONS = {
220
    "reassign": reassign_network,
221
}
222

    
223

    
224
def render_network(request, networkdict, status=200):
225
    if request.serialization == 'xml':
226
        data = render_to_string('network.xml', {'network': networkdict})
227
    else:
228
        data = json.dumps({'network': networkdict})
229
    return HttpResponse(data, status=status)