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