Statistics
| Branch: | Tag: | Revision:

root / api / networks.py @ f4fe8796

History | View | Annotate | Download (7.9 kB)

1
# Copyright 2011 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.urls.defaults import patterns
35
from django.db.models import Q
36
from django.http import HttpResponse
37
from django.template.loader import render_to_string
38
from django.utils import simplejson as json
39

    
40
from synnefo.api import util
41
from synnefo.api.actions import network_actions
42
from synnefo.api.common import method_not_allowed
43
from synnefo.api.faults import BadRequest, OverLimit, Unauthorized
44
from synnefo.db.models import Network
45
from synnefo.logic import backend
46

    
47

    
48
urlpatterns = patterns('synnefo.api.networks',
49
    (r'^(?:/|.json|.xml)?$', 'demux'),
50
    (r'^/detail(?:.json|.xml)?$', 'list_networks', {'detail': True}),
51
    (r'^/(\w+)(?:.json|.xml)?$', 'network_demux'),
52
    (r'^/(\w+)/action(?:.json|.xml)?$', 'network_action'),
53
)
54

    
55

    
56
def demux(request):
57
    if request.method == 'GET':
58
        return list_networks(request)
59
    elif request.method == 'POST':
60
        return create_network(request)
61
    else:
62
        return method_not_allowed(request)
63

    
64
def network_demux(request, network_id):
65
    if request.method == 'GET':
66
        return get_network_details(request, network_id)
67
    elif request.method == 'PUT':
68
        return update_network_name(request, network_id)
69
    elif request.method == 'DELETE':
70
        return delete_network(request, network_id)
71
    else:
72
        return method_not_allowed(request)
73

    
74

    
75
def network_to_dict(network, detail=True):
76
    network_id = str(network.id) if not network.public else 'public'
77
    d = {'id': network_id, 'name': network.name}
78
    if detail:
79
        d['updated'] = util.isoformat(network.updated)
80
        d['created'] = util.isoformat(network.created)
81
        d['servers'] = {'values': [vm.id for vm in network.machines.all()]}
82
        d['status'] = network.state
83
    return d
84

    
85
def render_network(request, networkdict, status=200):
86
    if request.serialization == 'xml':
87
        data = render_to_string('network.xml', {'network': networkdict})
88
    else:
89
        data = json.dumps({'network': networkdict})
90
    return HttpResponse(data, status=status)
91

    
92

    
93
@util.api_method('GET')
94
def list_networks(request, detail=False):
95
    # Normal Response Codes: 200, 203
96
    # Error Response Codes: computeFault (400, 500),
97
    #                       serviceUnavailable (503),
98
    #                       unauthorized (401),
99
    #                       badRequest (400),
100
    #                       overLimit (413)
101
    
102
    owner = request.user
103
    since = util.isoparse(request.GET.get('changes-since'))
104
    user_networks = Network.objects.filter(Q(owner=owner) | Q(public=True))
105
    
106
    if since:
107
        user_networks = user_networks.filter(updated__gte=since)
108
        if not user_networks:
109
            return HttpResponse(status=304)
110
    else:
111
        user_networks = user_networks.filter(state='ACTIVE')
112
    
113
    networks = [network_to_dict(network, detail) for network in user_networks]
114

    
115
    if request.serialization == 'xml':
116
        data = render_to_string('list_networks.xml', {
117
            'networks': networks,
118
            'detail': detail})
119
    else:
120
        data = json.dumps({'networks': {'values': networks}})
121

    
122
    return HttpResponse(data, status=200)
123

    
124
@util.api_method('POST')
125
def create_network(request):
126
    # Normal Response Code: 202
127
    # Error Response Codes: computeFault (400, 500),
128
    #                       serviceUnavailable (503),
129
    #                       unauthorized (401),
130
    #                       badMediaType(415),
131
    #                       badRequest (400),
132
    #                       overLimit (413)
133

    
134
    req = util.get_request_dict(request)
135

    
136
    try:
137
        d = req['network']
138
        name = d['name']
139
    except (KeyError, ValueError):
140
        raise BadRequest('Malformed request.')
141
    
142
    network = backend.create_network(name, request.user)
143
    if not network:
144
        raise OverLimit('Maximum number of networks reached.')
145
    
146
    networkdict = network_to_dict(network)
147
    return render_network(request, networkdict, status=202)
148

    
149
@util.api_method('GET')
150
def get_network_details(request, network_id):
151
    # Normal Response Codes: 200, 203
152
    # Error Response Codes: computeFault (400, 500),
153
    #                       serviceUnavailable (503),
154
    #                       unauthorized (401),
155
    #                       badRequest (400),
156
    #                       itemNotFound (404),
157
    #                       overLimit (413)
158

    
159
    net = util.get_network(network_id, request.user)
160
    netdict = network_to_dict(net)
161
    return render_network(request, netdict)
162

    
163
@util.api_method('PUT')
164
def update_network_name(request, network_id):
165
    # Normal Response Code: 204
166
    # Error Response Codes: computeFault (400, 500),
167
    #                       serviceUnavailable (503),
168
    #                       unauthorized (401),
169
    #                       badRequest (400),
170
    #                       badMediaType(415),
171
    #                       itemNotFound (404),
172
    #                       overLimit (413)
173

    
174
    req = util.get_request_dict(request)
175

    
176
    try:
177
        name = req['network']['name']
178
    except (TypeError, KeyError):
179
        raise BadRequest('Malformed request.')
180

    
181
    net = util.get_network(network_id, request.user)
182
    if net.public:
183
        raise Unauthorized('Can not rename the public network.')
184
    net.name = name
185
    net.save()
186
    return HttpResponse(status=204)
187

    
188
@util.api_method('DELETE')
189
def delete_network(request, network_id):
190
    # Normal Response Code: 204
191
    # Error Response Codes: computeFault (400, 500),
192
    #                       serviceUnavailable (503),
193
    #                       unauthorized (401),
194
    #                       itemNotFound (404),
195
    #                       unauthorized (401),
196
    #                       overLimit (413)
197
    
198
    net = util.get_network(network_id, request.user)
199
    if net.public:
200
        raise Unauthorized('Can not delete the public network.')
201
    backend.delete_network(net)
202
    return HttpResponse(status=204)
203

    
204
@util.api_method('POST')
205
def network_action(request, network_id):
206
    net = util.get_network(network_id, request.user)
207
    if net.public:
208
        raise Unauthorized('Can not modify the public network.')
209
    
210
    req = util.get_request_dict(request)
211
    if len(req) != 1:
212
        raise BadRequest('Malformed request.')
213

    
214
    key = req.keys()[0]
215
    val = req[key]
216

    
217
    try:
218
        assert isinstance(val, dict)
219
        return network_actions[key](request, net, req[key])
220
    except KeyError:
221
        raise BadRequest('Unknown action.')
222
    except AssertionError:
223
        raise BadRequest('Invalid argument.')