root / snf-cyclades-app / synnefo / neutron / network_views.py @ 5cf968ab
History | View | Annotate | Download (8.6 kB)
1 |
from django.http import HttpResponse |
---|---|
2 |
from django.utils import simplejson as json |
3 |
from django.db import transaction |
4 |
from django.db.models import Q |
5 |
from synnefo.db.pools import EmptyPool |
6 |
from synnefo.db.utils import validate_mac |
7 |
from django.conf import settings |
8 |
from snf_django.lib import api |
9 |
from snf_django.lib.api import utils |
10 |
from synnefo.logic import backend |
11 |
from django.template.loader import render_to_string |
12 |
from synnefo.api import util |
13 |
from models import Network |
14 |
|
15 |
from logging import getLogger |
16 |
|
17 |
from synnefo import quotas |
18 |
|
19 |
|
20 |
log = getLogger(__name__) |
21 |
|
22 |
|
23 |
def demux(request): |
24 |
if request.method == 'GET': |
25 |
#return HttpResponse("in network get")
|
26 |
return list_networks(request)
|
27 |
elif request.method == 'POST': |
28 |
return create_network(request)
|
29 |
#return HttpResponse("in network post")
|
30 |
else:
|
31 |
return api.api_method_not_allowed(request)
|
32 |
|
33 |
|
34 |
def network_demux(request, offset): |
35 |
|
36 |
if request.method == 'GET': |
37 |
return get_network(request, offset)
|
38 |
#return HttpResponse("in network det get")
|
39 |
elif request.method == 'DELETE': |
40 |
return delete_network(request, offset)
|
41 |
#return HttpResponse("in network det delete")
|
42 |
elif request.method == 'PUT': |
43 |
return update_network(request, offset)
|
44 |
#return HttpResponse("in network det put")
|
45 |
else:
|
46 |
return api.api_method_not_allowed(request)
|
47 |
|
48 |
|
49 |
@api.api_method(http_method='GET', user_required=True, logger=log) |
50 |
def list_networks(request, detail=False): |
51 |
log.debug('list_networks detail=%s', detail)
|
52 |
|
53 |
user_networks = Network.objects.filter( |
54 |
Q(userid=request.user_uniq) | Q(public=True))
|
55 |
|
56 |
user_networks = utils.filter_modified_since(request, objects=user_networks) |
57 |
|
58 |
networks = [network_to_dict(network, detail) |
59 |
for network in user_networks.order_by('id')] |
60 |
|
61 |
if request.serialization == 'xml': |
62 |
data = render_to_string('list_networks.xml', {
|
63 |
"networks": networks})
|
64 |
else:
|
65 |
data = json.dumps({'networks': networks})
|
66 |
|
67 |
return HttpResponse(data, status=200) |
68 |
|
69 |
|
70 |
@api.api_method(http_method='POST', user_required=True, logger=log) |
71 |
@transaction.commit_manually
|
72 |
def create_network(request): |
73 |
'''
|
74 |
This operation does not require a rest body. If specified, the body might
|
75 |
include one or more of the following attributes:
|
76 |
|
77 |
name: a string specifying a symbolic name for the network, which is not
|
78 |
required to be unique;
|
79 |
|
80 |
admin_state_up: a bool value specifying the administrative status of
|
81 |
the network;
|
82 |
|
83 |
2 more attirbutes for administrative users (not supported)
|
84 |
'''
|
85 |
try:
|
86 |
user_id = request.user_uniq |
87 |
if request.raw_post_data:
|
88 |
req = utils.get_request_dict(request) |
89 |
log.info('create_network %s', req)
|
90 |
try:
|
91 |
d = req['network']
|
92 |
name = d['name']
|
93 |
except KeyError: |
94 |
raise api.faults.BadRequest("Malformed request") |
95 |
|
96 |
flavor = d.get("type", None) |
97 |
if flavor is None: |
98 |
#raise faults.BadRequest("Missing request parameter 'type'")
|
99 |
# set default flavor
|
100 |
#FIX ME!!!
|
101 |
flavor = "MAC_FILTERED"
|
102 |
log.info("not found flavor")
|
103 |
elif flavor not in Network.FLAVORS.keys(): |
104 |
raise api.faults.BadRequest("Invalid network type '%s'" |
105 |
% flavor) |
106 |
log.info("found flavor 1")
|
107 |
elif flavor not in settings.API_ENABLED_NETWORK_FLAVORS: |
108 |
log.info("found flavor2")
|
109 |
msg = "Can not create network of type '%s'"
|
110 |
raise api.faults.Forbidden(msg % flavor)
|
111 |
# Get and validate flavor. Flavors are still exposed
|
112 |
#as 'type' in the API.
|
113 |
else:
|
114 |
name = ""
|
115 |
flavor = "MAC_FILTERED" # this is the default FIX ME |
116 |
|
117 |
try:
|
118 |
#mode, link, mac_prefix, tags = util.values_from_flavor(flavor)
|
119 |
|
120 |
#validate_mac(mac_prefix + "0:00:00:00")
|
121 |
network = Network.objects.create( |
122 |
name=name, |
123 |
userid=user_id, |
124 |
flavor=flavor, |
125 |
#mode=mode,
|
126 |
#link=link,
|
127 |
#mac_prefix=mac_prefix,
|
128 |
#tags=tags,
|
129 |
action='CREATE',
|
130 |
state='ACTIVE')
|
131 |
except EmptyPool:
|
132 |
msg = "Failed to allocate resources for network of type: %s"
|
133 |
log.error(msg, flavor) |
134 |
raise api.faults.ServiceUnavailable("Failed to allocate network\ |
135 |
resources")
|
136 |
|
137 |
# Issue commission to Quotaholder and accept it since at the end of
|
138 |
# this transaction the Network object will be created in the DB.
|
139 |
# Note: the following call does a commit!
|
140 |
#quotas.issue_and_accept_commission(network)
|
141 |
# COME BACK....
|
142 |
|
143 |
except:
|
144 |
transaction.rollback() |
145 |
log.info("roll")
|
146 |
raise
|
147 |
else:
|
148 |
transaction.commit() |
149 |
log.info("commit")
|
150 |
networkdict = network_to_dict(network) |
151 |
response = render_network(request, networkdict, status=201)
|
152 |
|
153 |
return response
|
154 |
|
155 |
|
156 |
@api.api_method(http_method='GET', user_required=True, logger=log) |
157 |
def get_network(request, network_id): |
158 |
log.debug('get_network_details %s', network_id)
|
159 |
net = get_network_fromdb(network_id, request.user_uniq) |
160 |
|
161 |
#needs discussion
|
162 |
if net.deleted:
|
163 |
raise api.faults.BadRequest("Network has been deleted.") |
164 |
else:
|
165 |
netdict = network_to_dict(net) |
166 |
return render_network(request, netdict)
|
167 |
|
168 |
|
169 |
@api.api_method(http_method='DELETE', user_required=True, logger=log) |
170 |
@transaction.commit_on_success
|
171 |
def delete_network(request, network_id): |
172 |
log.info('delete_network %s', network_id)
|
173 |
net = get_network_fromdb(network_id, request.user_uniq, for_update=True)
|
174 |
|
175 |
log.info(net.name) |
176 |
if net.public:
|
177 |
raise api.faults.Forbidden('Can not delete the public network.') |
178 |
|
179 |
if net.deleted:
|
180 |
raise api.faults.BadRequest("Network has been deleted.") |
181 |
|
182 |
if net.machines.all(): # Nics attached on network |
183 |
#raise api.faults.NetworkInUse('Machines are connected to network.')
|
184 |
return HttpResponse("Network in use", status=409) |
185 |
|
186 |
net.action = 'DESTROY'
|
187 |
net.save() |
188 |
'''
|
189 |
skip the backend part...
|
190 |
backend_networks = net.backend_networks.exclude(operstate="DELETED")
|
191 |
for bnet in backend_networks:
|
192 |
backend.delete_network(net, bnet.backend)
|
193 |
if not backend_networks:
|
194 |
backend.update_network_state(net)
|
195 |
'''
|
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 and admin_state_up
|
208 |
'''
|
209 |
net = get_network_fromdb(network_id, request.user_uniq, for_update=True)
|
210 |
info = utils.get_request_dict(request) |
211 |
|
212 |
updatable = set(["name", "admin_state_up"]) |
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['admin_state_up'] = "true" |
240 |
subnet_cidr = [s.id for s in network.subnet_set.all()] |
241 |
d['subnets'] = subnet_cidr
|
242 |
return d
|
243 |
|
244 |
|
245 |
def render_network(request, networkdict, status=200): |
246 |
if request.serialization == 'xml': |
247 |
data = render_to_string('network.xml', {'network': networkdict}) |
248 |
else:
|
249 |
data = json.dumps({'network': networkdict})
|
250 |
return HttpResponse(data, status=status)
|
251 |
|
252 |
|
253 |
def get_network_fromdb(network_id, user_id, for_update=False): |
254 |
"""
|
255 |
Return a Network instance or raise ItemNotFound.
|
256 |
This is the same as util.get_network
|
257 |
"""
|
258 |
try:
|
259 |
network_id = int(network_id)
|
260 |
objects = Network.objects |
261 |
if for_update:
|
262 |
objects = objects.select_for_update() |
263 |
return objects.get(Q(userid=user_id) | Q(public=True), id=network_id) |
264 |
except (ValueError, Network.DoesNotExist): |
265 |
raise api.faults.ItemNotFound('Network not found.') |