root / snf-cyclades-app / synnefo / api / networks.py @ 95a213d4
History | View | Annotate | Download (7.9 kB)
1 |
from django.conf import settings |
---|---|
2 |
from django.conf.urls import patterns |
3 |
|
4 |
from django.http import HttpResponse |
5 |
from django.utils import simplejson as json |
6 |
from django.db import transaction |
7 |
from django.db.models import Q |
8 |
from synnefo.db.pools import EmptyPool |
9 |
from synnefo.db.utils import validate_mac |
10 |
from django.conf import settings |
11 |
from snf_django.lib import api |
12 |
from snf_django.lib.api import utils |
13 |
from synnefo.logic import backend |
14 |
from django.template.loader import render_to_string |
15 |
from synnefo.api import util |
16 |
from synnefo.db.models import Network |
17 |
|
18 |
from logging import getLogger |
19 |
|
20 |
from synnefo import quotas |
21 |
|
22 |
log = getLogger(__name__) |
23 |
|
24 |
urlpatterns = patterns( |
25 |
'synnefo.api.networks',
|
26 |
(r'^(?:/|.json|.xml)?$', 'demux'), |
27 |
(r'^/(\w+)(?:/|.json|.xml)?$', 'network_demux')) |
28 |
|
29 |
|
30 |
def demux(request): |
31 |
if request.method == 'GET': |
32 |
#return HttpResponse("in network get")
|
33 |
return list_networks(request)
|
34 |
elif request.method == 'POST': |
35 |
return create_network(request)
|
36 |
#return HttpResponse("in network post")
|
37 |
else:
|
38 |
return api.api_method_not_allowed(request)
|
39 |
|
40 |
|
41 |
def network_demux(request, offset): |
42 |
|
43 |
if request.method == 'GET': |
44 |
return get_network(request, offset)
|
45 |
#return HttpResponse("in network det get")
|
46 |
elif request.method == 'DELETE': |
47 |
return delete_network(request, offset)
|
48 |
#return HttpResponse("in network det delete")
|
49 |
elif request.method == 'PUT': |
50 |
return update_network(request, offset)
|
51 |
#return HttpResponse("in network det put")
|
52 |
else:
|
53 |
return api.api_method_not_allowed(request)
|
54 |
|
55 |
|
56 |
@api.api_method(http_method='GET', user_required=True, logger=log) |
57 |
def list_networks(request, detail=False): |
58 |
log.debug('list_networks detail=%s', detail)
|
59 |
|
60 |
user_networks = Network.objects.filter( |
61 |
Q(userid=request.user_uniq) | Q(public=True))
|
62 |
|
63 |
user_networks = utils.filter_modified_since(request, objects=user_networks) |
64 |
|
65 |
networks = [network_to_dict(network, detail) |
66 |
for network in user_networks.order_by('id')] |
67 |
|
68 |
if request.serialization == 'xml': |
69 |
data = render_to_string('list_networks.xml', {
|
70 |
"networks": networks})
|
71 |
else:
|
72 |
data = json.dumps({'networks': networks})
|
73 |
|
74 |
return HttpResponse(data, status=200) |
75 |
|
76 |
|
77 |
@api.api_method(http_method='POST', user_required=True, logger=log) |
78 |
@transaction.commit_manually
|
79 |
def create_network(request): |
80 |
try:
|
81 |
user_id = request.user_uniq |
82 |
req = utils.get_request_dict(request) |
83 |
log.info('create_network %s', req)
|
84 |
try:
|
85 |
d = req['network']
|
86 |
except KeyError: |
87 |
raise api.faults.BadRequest("Malformed request") |
88 |
|
89 |
try:
|
90 |
flavor = d['type']
|
91 |
except KeyError: |
92 |
raise api.faults.BadRequest("Missing request parameter 'type'") |
93 |
|
94 |
if flavor not in Network.FLAVORS.keys(): |
95 |
raise api.faults.BadRequest("Invalid network type '%s'" |
96 |
% flavor) |
97 |
if flavor not in settings.API_ENABLED_NETWORK_FLAVORS: |
98 |
msg = "Can not create network of type '%s'"
|
99 |
raise api.faults.Forbidden(msg % flavor)
|
100 |
|
101 |
try:
|
102 |
name = d['name']
|
103 |
except KeyError: |
104 |
name = ""
|
105 |
|
106 |
try:
|
107 |
#mode, link, mac_prefix, tags = util.values_from_flavor(flavor)
|
108 |
|
109 |
#validate_mac(mac_prefix + "0:00:00:00")
|
110 |
network = Network.objects.create( |
111 |
name=name, |
112 |
userid=user_id, |
113 |
flavor=flavor, |
114 |
#mode=mode,
|
115 |
#link=link,
|
116 |
#mac_prefix=mac_prefix,
|
117 |
#tags=tags,
|
118 |
action='CREATE',
|
119 |
state='ACTIVE')
|
120 |
except EmptyPool:
|
121 |
msg = "Failed to allocate resources for network of type: %s"
|
122 |
log.error(msg, flavor) |
123 |
raise api.faults.ServiceUnavailable("Failed to allocate network\ |
124 |
resources")
|
125 |
|
126 |
# Issue commission to Quotaholder and accept it since at the end of
|
127 |
# this transaction the Network object will be created in the DB.
|
128 |
# Note: the following call does a commit!
|
129 |
#quotas.issue_and_accept_commission(network)
|
130 |
# COME BACK....
|
131 |
|
132 |
except:
|
133 |
transaction.rollback() |
134 |
log.info("roll")
|
135 |
raise
|
136 |
else:
|
137 |
transaction.commit() |
138 |
log.info("commit")
|
139 |
networkdict = network_to_dict(network) |
140 |
response = render_network(request, networkdict, status=201)
|
141 |
|
142 |
return response
|
143 |
|
144 |
|
145 |
@api.api_method(http_method='GET', user_required=True, logger=log) |
146 |
def get_network(request, network_id): |
147 |
log.debug('get_network_details %s', network_id)
|
148 |
net = util.get_network(network_id, request.user_uniq) |
149 |
|
150 |
#needs discussion
|
151 |
if net.deleted:
|
152 |
raise api.faults.BadRequest("Network has been deleted.") |
153 |
else:
|
154 |
netdict = network_to_dict(net) |
155 |
return render_network(request, netdict)
|
156 |
|
157 |
|
158 |
@api.api_method(http_method='DELETE', user_required=True, logger=log) |
159 |
@transaction.commit_on_success
|
160 |
def delete_network(request, network_id): |
161 |
log.info('delete_network %s', network_id)
|
162 |
net = util.get_network(network_id, request.user_uniq, for_update=True)
|
163 |
|
164 |
log.info(net.name) |
165 |
if net.public:
|
166 |
raise api.faults.Forbidden('Can not delete the public network.') |
167 |
|
168 |
if net.deleted:
|
169 |
raise api.faults.BadRequest("Network has been deleted.") |
170 |
|
171 |
if net.machines.all(): # Nics attached on network |
172 |
#raise api.faults.NetworkInUse('Machines are connected to network.')
|
173 |
#edit to return with 409
|
174 |
return HttpResponse("Network in use", status=409) |
175 |
|
176 |
#check if there are any floating ips reserved
|
177 |
#if net.floating_ips.all():
|
178 |
# #raise api.faults.NetworkInUse('Machines are connected to network.')
|
179 |
# #edit to return with 409
|
180 |
# return HttpResponse("Network in use", status=409)
|
181 |
|
182 |
net.action = 'DESTROY'
|
183 |
'''
|
184 |
skip the backend part...
|
185 |
backend_networks = net.backend_networks.exclude(operstate="DELETED")
|
186 |
for bnet in backend_networks:
|
187 |
backend.delete_network(net, bnet.backend)
|
188 |
if not backend_networks:
|
189 |
backend.update_network_state(net)
|
190 |
'''
|
191 |
|
192 |
#delete all the subnets
|
193 |
|
194 |
for s in net.subnets.all(): |
195 |
s.deleted = True
|
196 |
|
197 |
#the following has to leave when fix the backend thing
|
198 |
net.deleted = True
|
199 |
net.save() |
200 |
|
201 |
return HttpResponse(status=204) |
202 |
|
203 |
|
204 |
@api.api_method(http_method='PUT', user_required=True, logger=log) |
205 |
def update_network(request, network_id): |
206 |
'''
|
207 |
You can update only name
|
208 |
'''
|
209 |
net = util.get_network(network_id, request.user_uniq, for_update=True)
|
210 |
info = utils.get_request_dict(request) |
211 |
|
212 |
updatable = set(["name"]) |
213 |
try:
|
214 |
new_vals = info["network"]
|
215 |
except KeyError: |
216 |
raise api.faults.BadRequest("Malformed request") |
217 |
|
218 |
for key, val in new_vals.iteritems(): |
219 |
if key in updatable: |
220 |
setattr(net, key, val)
|
221 |
else:
|
222 |
raise api.faults.BadRequest("Wrong field update") |
223 |
net.save() |
224 |
netdict = network_to_dict(net) |
225 |
return render_network(request, netdict, 200) |
226 |
|
227 |
|
228 |
def network_to_dict(network, detail=True): |
229 |
d = {'id': str(network.id), 'name': network.name} |
230 |
d['links'] = util.network_to_links(network.id)
|
231 |
if detail:
|
232 |
d['user_id'] = network.userid
|
233 |
d['tenant_id'] = network.userid
|
234 |
d['type'] = network.flavor
|
235 |
d['updated'] = utils.isoformat(network.updated)
|
236 |
d['created'] = utils.isoformat(network.created)
|
237 |
d['status'] = network.state
|
238 |
d['public'] = network.public
|
239 |
d['external_router'] = network.external_router
|
240 |
d['external_router'] = network.external_router
|
241 |
d['admin_state_up'] = True |
242 |
subnet_cidr = [s.id for s in network.subnets.all()] |
243 |
d['subnets'] = subnet_cidr
|
244 |
return d
|
245 |
|
246 |
|
247 |
def render_network(request, networkdict, status=200): |
248 |
if request.serialization == 'xml': |
249 |
data = render_to_string('network.xml', {'network': networkdict}) |
250 |
else:
|
251 |
data = json.dumps({'network': networkdict})
|
252 |
return HttpResponse(data, status=status)
|