Merge branch 'demo-mano-integration' of github.com:mpeuster/son-emu into demo-mano...
[osm/vim-emu.git] / src / emuvim / api / openstack / openstack_dummies / neutron_dummy_api.py
1 from flask_restful import Resource
2 from flask import request, Response
3 from emuvim.api.openstack.openstack_dummies.base_openstack_dummy import BaseOpenstackDummy
4 from datetime import datetime
5 import neutron_sfc_dummy_api as SFC
6 import logging
7 import json
8 import uuid
9 import copy
10
11 LOG = logging.getLogger("api.openstack.neutron")
12
13
14 class NeutronDummyApi(BaseOpenstackDummy):
15 def __init__(self, ip, port, compute):
16 super(NeutronDummyApi, self).__init__(ip, port)
17 self.compute = compute
18
19 self.api.add_resource(NeutronListAPIVersions, "/")
20 self.api.add_resource(Shutdown, "/shutdown")
21 self.api.add_resource(NeutronShowAPIv2Details, "/v2.0")
22 self.api.add_resource(NeutronListNetworks, "/v2.0/networks.json", "/v2.0/networks",
23 resource_class_kwargs={'api': self})
24 self.api.add_resource(NeutronShowNetwork, "/v2.0/networks/<network_id>.json", "/v2.0/networks/<network_id>",
25 resource_class_kwargs={'api': self})
26 self.api.add_resource(NeutronCreateNetwork, "/v2.0/networks.json", "/v2.0/networks",
27 resource_class_kwargs={'api': self})
28 self.api.add_resource(NeutronUpdateNetwork, "/v2.0/networks/<network_id>.json", "/v2.0/networks/<network_id>",
29 resource_class_kwargs={'api': self})
30 self.api.add_resource(NeutronDeleteNetwork, "/v2.0/networks/<network_id>.json", "/v2.0/networks/<network_id>",
31 resource_class_kwargs={'api': self})
32 self.api.add_resource(NeutronListSubnets, "/v2.0/subnets.json", "/v2.0/subnets",
33 resource_class_kwargs={'api': self})
34 self.api.add_resource(NeutronShowSubnet, "/v2.0/subnets/<subnet_id>.json", "/v2.0/subnets/<subnet_id>",
35 resource_class_kwargs={'api': self})
36 self.api.add_resource(NeutronCreateSubnet, "/v2.0/subnets.json", "/v2.0/subnets",
37 resource_class_kwargs={'api': self})
38 self.api.add_resource(NeutronUpdateSubnet, "/v2.0/subnets/<subnet_id>.json", "/v2.0/subnets/<subnet_id>",
39 resource_class_kwargs={'api': self})
40 self.api.add_resource(NeutronDeleteSubnet, "/v2.0/subnets/<subnet_id>.json", "/v2.0/subnets/<subnet_id>",
41 resource_class_kwargs={'api': self})
42 self.api.add_resource(NeutronListPorts, "/v2.0/ports.json", "/v2.0/ports",
43 resource_class_kwargs={'api': self})
44 self.api.add_resource(NeutronShowPort, "/v2.0/ports/<port_id>.json", "/v2.0/ports/<port_id>",
45 resource_class_kwargs={'api': self})
46 self.api.add_resource(NeutronCreatePort, "/v2.0/ports.json", "/v2.0/ports",
47 resource_class_kwargs={'api': self})
48 self.api.add_resource(NeutronUpdatePort, "/v2.0/ports/<port_id>.json", "/v2.0/ports/<port_id>",
49 resource_class_kwargs={'api': self})
50 self.api.add_resource(NeutronDeletePort, "/v2.0/ports/<port_id>.json", "/v2.0/ports/<port_id>",
51 resource_class_kwargs={'api': self})
52 self.api.add_resource(NeutronAddFloatingIp, "/v2.0/floatingips.json", "/v2.0/floatingips",
53 resource_class_kwargs={'api': self})
54
55 # Service Function Chaining (SFC) API
56 self.api.add_resource(SFC.PortPairsCreate, "/v2.0/sfc/port_pairs.json", "/v2.0/sfc/port_pairs",
57 resource_class_kwargs={'api': self})
58 self.api.add_resource(SFC.PortPairsUpdate, "/v2.0/sfc/port_pairs/<pair_id>.json",
59 "/v2.0/sfc/port_pairs/<pair_id>",
60 resource_class_kwargs={'api': self})
61 self.api.add_resource(SFC.PortPairsDelete, "/v2.0/sfc/port_pairs/<pair_id>.json",
62 "/v2.0/sfc/port_pairs/<pair_id>",
63 resource_class_kwargs={'api': self})
64 self.api.add_resource(SFC.PortPairsList, "/v2.0/sfc/port_pairs.json", "/v2.0/sfc/port_pairs",
65 resource_class_kwargs={'api': self})
66 self.api.add_resource(SFC.PortPairsShow, "/v2.0/sfc/port_pairs/<pair_id>.json",
67 "/v2.0/sfc/port_pairs/<pair_id>",
68 resource_class_kwargs={'api': self})
69
70 self.api.add_resource(SFC.PortPairGroupCreate, "/v2.0/sfc/port_pair_groups.json", "/v2.0/sfc/port_pair_groups",
71 resource_class_kwargs={'api': self})
72 self.api.add_resource(SFC.PortPairGroupUpdate, "/v2.0/sfc/port_pair_groups/<group_id>.json",
73 "/v2.0/sfc/port_pair_groups/<group_id>",
74 resource_class_kwargs={'api': self})
75 self.api.add_resource(SFC.PortPairGroupDelete, "/v2.0/sfc/port_pair_groups/<group_id>.json",
76 "/v2.0/sfc/port_pair_groups/<group_id>",
77 resource_class_kwargs={'api': self})
78 self.api.add_resource(SFC.PortPairGroupList, "/v2.0/sfc/port_pair_groups.json", "/v2.0/sfc/port_pair_groups",
79 resource_class_kwargs={'api': self})
80 self.api.add_resource(SFC.PortPairGroupShow, "/v2.0/sfc/port_pair_groups/<group_id>.json",
81 "/v2.0/sfc/port_pair_groups/<group_id>",
82 resource_class_kwargs={'api': self})
83
84 self.api.add_resource(SFC.FlowClassifierCreate, "/v2.0/sfc/flow_classifiers.json", "/v2.0/sfc/flow_classifiers",
85 resource_class_kwargs={'api': self})
86 self.api.add_resource(SFC.FlowClassifierUpdate, "/v2.0/sfc/flow_classifiers/<flow_classifier_id>.json",
87 "/v2.0/sfc/flow_classifiers/<flow_classifier_id>",
88 resource_class_kwargs={'api': self})
89 self.api.add_resource(SFC.FlowClassifierDelete, "/v2.0/sfc/flow_classifiers/<flow_classifier_id>.json",
90 "/v2.0/sfc/flow_classifiers/<flow_classifier_id>",
91 resource_class_kwargs={'api': self})
92 self.api.add_resource(SFC.FlowClassifierList, "/v2.0/sfc/flow_classifiers.json", "/v2.0/sfc/flow_classifiers",
93 resource_class_kwargs={'api': self})
94 self.api.add_resource(SFC.FlowClassifierShow, "/v2.0/sfc/flow_classifiers/<flow_classifier_id>.json",
95 "/v2.0/sfc/flow_classifiers/<flow_classifier_id>",
96 resource_class_kwargs={'api': self})
97
98 self.api.add_resource(SFC.PortChainCreate, "/v2.0/sfc/port_chains.json", "/v2.0/sfc/port_chains",
99 resource_class_kwargs={'api': self})
100 self.api.add_resource(SFC.PortChainUpdate, "/v2.0/sfc/port_chains/<chain_id>.json",
101 "/v2.0/sfc/port_chains/<chain_id>",
102 resource_class_kwargs={'api': self})
103 self.api.add_resource(SFC.PortChainDelete, "/v2.0/sfc/port_chains/<chain_id>.json",
104 "/v2.0/sfc/port_chains/<chain_id>",
105 resource_class_kwargs={'api': self})
106 self.api.add_resource(SFC.PortChainList, "/v2.0/sfc/port_chains.json", "/v2.0/sfc/port_chains",
107 resource_class_kwargs={'api': self})
108 self.api.add_resource(SFC.PortChainShow, "/v2.0/sfc/port_chains/<chain_id>.json",
109 "/v2.0/sfc/port_chains/<chain_id>",
110 resource_class_kwargs={'api': self})
111
112 def _start_flask(self):
113 LOG.info("Starting %s endpoint @ http://%s:%d" % (__name__, self.ip, self.port))
114 if self.app is not None:
115 self.app.before_request(self.dump_playbook)
116 self.app.run(self.ip, self.port, debug=True, use_reloader=False)
117
118
119 class Shutdown(Resource):
120 def get(self):
121 LOG.debug(("%s is beeing shut down") % (__name__))
122 func = request.environ.get('werkzeug.server.shutdown')
123 if func is None:
124 raise RuntimeError('Not running with the Werkzeug Server')
125 func()
126
127
128 class NeutronListAPIVersions(Resource):
129 def get(self):
130 """
131 Lists API versions.
132
133 :return: Returns a json with API versions.
134 :rtype: :class:`flask.response`
135 """
136 LOG.debug("API CALL: Neutron - List API Versions")
137 resp = dict()
138 resp['versions'] = dict()
139
140 versions = [{
141 "status": "CURRENT",
142 "id": "v2.0",
143 "links": [
144 {
145 "href": request.url_root + '/v2.0',
146 "rel": "self"
147 }
148 ]
149 }]
150 resp['versions'] = versions
151
152 return Response(json.dumps(resp), status=200, mimetype='application/json')
153
154
155 class NeutronShowAPIv2Details(Resource):
156 def get(self):
157 """
158 Returns API details.
159
160 :return: Returns a json with API details.
161 :rtype: :class:`flask.response`
162 """
163 LOG.debug("API CALL: %s GET" % str(self.__class__.__name__))
164 resp = dict()
165
166 resp['resources'] = dict()
167 resp['resources'] = [{
168 "links": [
169 {
170 "href": request.url_root + 'v2.0/subnets',
171 "rel": "self"
172 }
173 ],
174 "name": "subnet",
175 "collection": "subnets"
176 },
177 {
178 "links": [
179 {
180 "href": request.url_root + 'v2.0/networks',
181 "rel": "self"
182 }
183 ],
184 "name": "network",
185 "collection": "networks"
186 },
187 {
188 "links": [
189 {
190 "href": request.url_root + 'v2.0/ports',
191 "rel": "self"
192 }
193 ],
194 "name": "ports",
195 "collection": "ports"
196 }
197 ]
198
199 return Response(json.dumps(resp), status=200, mimetype='application/json')
200
201
202 class NeutronListNetworks(Resource):
203 def __init__(self, api):
204 self.api = api
205
206 def get(self):
207 """
208 Lists all networks, used in son-emu. If a 'name' or one or more 'id's are specified, it will only list the
209 network with the name, or the networks specified via id.
210
211 :return: Returns a json response, starting with 'networks' as root node.
212 :rtype: :class:`flask.response`
213 """
214 LOG.debug("API CALL: %s GET" % str(self.__class__.__name__))
215 try:
216 if request.args.get('name'):
217 tmp_network = NeutronShowNetwork(self.api)
218 return tmp_network.get_network(request.args.get('name'), True)
219 id_list = request.args.getlist('id')
220 if len(id_list) == 1:
221 tmp_network = NeutronShowNetwork(self.api)
222 return tmp_network.get_network(request.args.get('id'), True)
223
224 network_list = list()
225 network_dict = dict()
226
227 if len(id_list) == 0:
228 for net in self.api.compute.nets.values():
229 tmp_network_dict = net.create_network_dict()
230 if tmp_network_dict not in network_list:
231 network_list.append(tmp_network_dict)
232 else:
233 for net in self.api.compute.nets.values():
234 if net.id in id_list:
235 tmp_network_dict = net.create_network_dict()
236 if tmp_network_dict not in network_list:
237 network_list.append(tmp_network_dict)
238
239 network_dict["networks"] = network_list
240
241 return Response(json.dumps(network_dict), status=200, mimetype='application/json')
242
243 except Exception as ex:
244 LOG.exception("Neutron: List networks exception.")
245 return Response(ex.message, status=500, mimetype='application/json')
246
247
248 class NeutronShowNetwork(Resource):
249 def __init__(self, api):
250 self.api = api
251
252 def get(self, network_id):
253 """
254 Returns the network, specified via 'network_id'.
255
256 :param network_id: The unique ID string of the network.
257 :type network_id: ``str``
258 :return: Returns a json response, starting with 'network' as root node and one network description.
259 :rtype: :class:`flask.response`
260 """
261 LOG.debug("API CALL: %s GET" % str(self.__class__.__name__))
262 return self.get_network(network_id, False)
263
264 def get_network(self, network_name_or_id, as_list):
265 """
266 Returns one network description of the network, specified via 'network_name_or_id'.
267
268 :param network_name_or_id: The indicator string, which specifies the requested network.
269 :type network_name_or_id: ``str``
270 :param as_list: Determines if the network description should start with the root node 'network' or 'networks'.
271 :type as_list: ``bool``
272 :return: Returns a json response, with one network description.
273 :rtype: :class:`flask.response`
274 """
275 try:
276 net = self.api.compute.find_network_by_name_or_id(network_name_or_id)
277 if net is None:
278 return Response(u'Network not found.\n', status=404, mimetype='application/json')
279
280 tmp_network_dict = net.create_network_dict()
281 tmp_dict = dict()
282 if as_list:
283 tmp_dict["networks"] = [tmp_network_dict]
284 else:
285 tmp_dict["network"] = tmp_network_dict
286
287 return Response(json.dumps(tmp_dict), status=200, mimetype='application/json')
288
289
290 except Exception as ex:
291 logging.exception("Neutron: Show network exception.")
292 return Response(ex.message, status=500, mimetype='application/json')
293
294
295 class NeutronCreateNetwork(Resource):
296 def __init__(self, api):
297 self.api = api
298
299 def post(self):
300 """
301 Creates a network with the name, specified within the request under ['network']['name'].
302
303 :return: * 400, if the network already exists.
304 * 500, if any exception occurred while creation.
305 * 201, if everything worked out.
306 :rtype: :class:`flask.response`
307 """
308 LOG.debug("API CALL: %s POST" % str(self.__class__.__name__))
309 try:
310 network_dict = json.loads(request.data)
311 name = network_dict['network']['name']
312 net = self.api.compute.find_network_by_name_or_id(name)
313 if net is not None:
314 return Response('Network already exists.\n', status=400, mimetype='application/json')
315
316 net = self.api.compute.create_network(name)
317 return Response(json.dumps({"network": net.create_network_dict()}), status=201, mimetype='application/json')
318 except Exception as ex:
319 LOG.exception("Neutron: Create network excepiton.")
320 return Response(ex.message, status=500, mimetype='application/json')
321
322
323 class NeutronUpdateNetwork(Resource):
324 def __init__(self, api):
325 self.api = api
326
327 def put(self, network_id): # TODO currently only the name will be changed
328 """
329 Updates the existing network with the given parameters.
330
331 :param network_id: The indicator string, which specifies the requested network.
332 :type network_id: ``str``
333 :return: * 404, if the network could not be found.
334 * 500, if any exception occurred while updating the network.
335 * 200, if everything worked out.
336 :rtype: :class:`flask.response`
337 """
338 LOG.debug("API CALL: %s PUT" % str(self.__class__.__name__))
339 try:
340 if network_id in self.api.compute.nets:
341 net = self.api.compute.nets[network_id]
342 network_dict = json.loads(request.data)
343 old_net = copy.copy(net)
344
345 if "status" in network_dict["network"]:
346 net.status = network_dict["network"]["status"]
347 if "subnets" in network_dict["network"]:
348 pass # tmp_network_dict["subnets"] = None
349 if "name" in network_dict["network"] and net.name != network_dict["network"]["name"]:
350 net.name = network_dict["network"]["name"]
351 if "admin_state_up" in network_dict["network"]:
352 pass # tmp_network_dict["admin_state_up"] = True
353 if "tenant_id" in network_dict["network"]:
354 pass # tmp_network_dict["tenant_id"] = "c1210485b2424d48804aad5d39c61b8f"
355 if "shared" in network_dict["network"]:
356 pass # tmp_network_dict["shared"] = False
357
358 return Response(json.dumps(network_dict), status=200, mimetype='application/json')
359
360 return Response('Network not found.\n', status=404, mimetype='application/json')
361
362 except Exception as ex:
363 LOG.exception("Neutron: Show networks exception.")
364 return Response(ex.message, status=500, mimetype='application/json')
365
366
367 class NeutronDeleteNetwork(Resource):
368 def __init__(self, api):
369 self.api = api
370
371 def delete(self, network_id):
372 """
373 Deletes the specified network and all its subnets.
374
375 :param network_id: The indicator string, which specifies the requested network.
376 :type network_id: ``str``
377 :return: * 404, if the network or the subnet could not be removed.
378 * 500, if any exception occurred while deletion.
379 * 204, if everything worked out.
380 :rtype: :class:`flask.response`
381 """
382 LOG.debug("API CALL: %s DELETE" % str(self.__class__.__name__))
383 try:
384 if network_id not in self.api.compute.nets:
385 return Response('Could not find network. (' + network_id + ')\n',
386 status=404, mimetype='application/json')
387
388 net = self.api.compute.nets[network_id]
389 delete_subnet = NeutronDeleteSubnet(self.api)
390 resp = delete_subnet.delete(net.subnet_id)
391
392 if not '204' in resp.status and not '404' in resp.status:
393 return resp
394
395 self.api.compute.delete_network(network_id)
396
397 return Response('Network ' + str(network_id) + ' deleted.\n', status=204, mimetype='application/json')
398 except Exception as ex:
399 LOG.exception("Neutron: Delete network exception.")
400 return Response(ex.message, status=500, mimetype='application/json')
401
402
403 class NeutronListSubnets(Resource):
404 def __init__(self, api):
405 self.api = api
406
407 def get(self):
408 """
409 Lists all subnets, used in son-emu. If a 'name' or one or more 'id's are specified, it will only list the
410 subnet with the name, or the subnets specified via id.
411
412 :return: Returns a json response, starting with 'subnets' as root node.
413 :rtype: :class:`flask.response`
414 """
415 LOG.debug("API CALL: %s GET" % str(self.__class__.__name__))
416 try:
417 if request.args.get('name'):
418 show_subnet = NeutronShowSubnet(self.api)
419 return show_subnet.get_subnet(request.args.get('name'), True)
420 id_list = request.args.getlist('id')
421 if len(id_list) == 1:
422 show_subnet = NeutronShowSubnet(self.api)
423 return show_subnet.get_subnet(id_list[0], True)
424
425 subnet_list = list()
426 subnet_dict = dict()
427
428 if len(id_list) == 0:
429 for net in self.api.compute.nets.values():
430 if net.subnet_id is not None:
431 tmp_subnet_dict = net.create_subnet_dict()
432 subnet_list.append(tmp_subnet_dict)
433 else:
434 for net in self.api.compute.nets.values():
435 if net.subnet_id in id_list:
436 tmp_subnet_dict = net.create_subnet_dict()
437 subnet_list.append(tmp_subnet_dict)
438
439 subnet_dict["subnets"] = subnet_list
440
441 return Response(json.dumps(subnet_dict), status=200, mimetype='application/json')
442
443 except Exception as ex:
444 LOG.exception("Neutron: List subnets exception.")
445 return Response(ex.message, status=500, mimetype='application/json')
446
447
448 class NeutronShowSubnet(Resource):
449 def __init__(self, api):
450 self.api = api
451
452 def get(self, subnet_id):
453 """
454 Returns the subnet, specified via 'subnet_id'.
455
456 :param subnet_id: The unique ID string of the subnet.
457 :type subnet_id: ``str``
458 :return: Returns a json response, starting with 'subnet' as root node and one subnet description.
459 :rtype: :class:`flask.response`
460 """
461 LOG.debug("API CALL: %s GET" % str(self.__class__.__name__))
462 return self.get_subnet(subnet_id, False)
463
464 def get_subnet(self, subnet_name_or_id, as_list):
465 """
466 Returns one subnet description of the subnet, specified via 'subnet_name_or_id'.
467
468 :param subnet_name_or_id: The indicator string, which specifies the requested subnet.
469 :type subnet_name_or_id: ``str``
470 :param as_list: Determines if the subnet description should start with the root node 'subnet' or 'subnets'.
471 :type as_list: ``bool``
472 :return: Returns a json response, with one subnet description.
473 :rtype: :class:`flask.response`
474 """
475 try:
476 for net in self.api.compute.nets.values():
477 if net.subnet_id == subnet_name_or_id or net.subnet_name == subnet_name_or_id:
478 tmp_subnet_dict = net.create_subnet_dict()
479 tmp_dict = dict()
480 if as_list:
481 tmp_dict["subnets"] = [tmp_subnet_dict]
482 else:
483 tmp_dict["subnet"] = tmp_subnet_dict
484 return Response(json.dumps(tmp_dict), status=200, mimetype='application/json')
485
486 return Response('Subnet not found. (' + subnet_name_or_id + ')\n', status=404, mimetype='application/json')
487
488 except Exception as ex:
489 LOG.exception("Neutron: Show subnet exception.")
490 return Response(ex.message, status=500, mimetype='application/json')
491
492
493 class NeutronCreateSubnet(Resource):
494 def __init__(self, api):
495 self.api = api
496
497 def post(self):
498 """
499 Creates a subnet with the name, specified within the request under ['subnet']['name'].
500
501 :return: * 400, if the 'CIDR' format is wrong or it does not exist.
502 * 404, if the network was not found.
503 * 409, if the corresponding network already has one subnet.
504 * 500, if any exception occurred while creation and
505 * 201, if everything worked out.
506 :rtype: :class:`flask.response`
507 """
508 LOG.debug("API CALL: %s POST" % str(self.__class__.__name__))
509 try:
510 subnet_dict = json.loads(request.data)
511 net = self.api.compute.find_network_by_name_or_id(subnet_dict['subnet']['network_id'])
512
513 if net is None:
514 return Response('Could not find network.\n', status=404, mimetype='application/json')
515
516 net.subnet_name = subnet_dict["subnet"].get('name', str(net.name) + '-sub')
517 if net.subnet_id is not None:
518 return Response('Only one subnet per network is supported\n', status=409, mimetype='application/json')
519
520 if "id" in subnet_dict["subnet"]:
521 net.subnet_id = subnet_dict["subnet"]["id"]
522 else:
523 net.subnet_id = str(uuid.uuid4())
524 import emuvim.api.openstack.ip_handler as IP
525 net.set_cidr(IP.get_new_cidr(net.subnet_id))
526
527 if "tenant_id" in subnet_dict["subnet"]:
528 pass
529 if "allocation_pools" in subnet_dict["subnet"]:
530 pass
531 if "gateway_ip" in subnet_dict["subnet"]:
532 net.gateway_ip = subnet_dict["subnet"]["gateway_ip"]
533 if "ip_version" in subnet_dict["subnet"]:
534 pass
535 if "enable_dhcp" in subnet_dict["subnet"]:
536 pass
537
538 return Response(json.dumps({'subnet': net.create_subnet_dict()}), status=201, mimetype='application/json')
539
540 except Exception as ex:
541 LOG.exception("Neutron: Create network excepiton.")
542 return Response(ex.message, status=500, mimetype='application/json')
543
544
545 class NeutronUpdateSubnet(Resource):
546 def __init__(self, api):
547 self.api = api
548
549 def put(self, subnet_id):
550 """
551 Updates the existing subnet with the given parameters.
552
553 :param subnet_id: The indicator string, which specifies the requested subnet.
554 :type subnet_id: ``str``
555 :return: * 404, if the network could not be found.
556 * 500, if any exception occurred while updating the network.
557 * 200, if everything worked out.
558 :rtype: :class:`flask.response`
559 """
560 LOG.debug("API CALL: %s PUT" % str(self.__class__.__name__))
561 try:
562 for net in self.api.compute.nets.values():
563 if net.subnet_id == subnet_id:
564 subnet_dict = json.loads(request.data)
565
566 if "name" in subnet_dict["subnet"]:
567 net.subnet_name = subnet_dict["subnet"]["name"]
568 if "network_id" in subnet_dict["subnet"]:
569 net.id = subnet_dict["subnet"]["network_id"]
570 if "tenant_id" in subnet_dict["subnet"]:
571 pass
572 if "allocation_pools" in subnet_dict["subnet"]:
573 pass
574 if "gateway_ip" in subnet_dict["subnet"]:
575 net.gateway_ip = subnet_dict["subnet"]["gateway_ip"]
576 if "ip_version" in subnet_dict["subnet"]:
577 pass
578 if "cidr" in subnet_dict["subnet"]:
579 net.set_cidr(subnet_dict["subnet"]["cidr"])
580 if "id" in subnet_dict["subnet"]:
581 net.subnet_id = subnet_dict["subnet"]["id"]
582 if "enable_dhcp" in subnet_dict["subnet"]:
583 pass
584
585 net.subnet_update_time = str(datetime.now())
586 tmp_dict = {'subnet': net.create_subnet_dict()}
587 return Response(json.dumps(tmp_dict), status=200, mimetype='application/json')
588
589 return Response('Network not found.\n', status=404, mimetype='application/json')
590
591 except Exception as ex:
592 LOG.exception("Neutron: Show networks exception.")
593 return Response(ex.message, status=500, mimetype='application/json')
594
595
596 class NeutronDeleteSubnet(Resource):
597 def __init__(self, api):
598 self.api = api
599
600 def delete(self, subnet_id):
601 """
602 Deletes the specified subnet.
603
604 :param subnet_id: The indicator string, which specifies the requested subnet.
605 :type subnet_id: ``str``
606 :return: * 404, if the subnet could not be removed.
607 * 500, if any exception occurred while deletion.
608 * 204, if everything worked out.
609 :rtype: :class:`flask.response`
610 """
611 LOG.debug("API CALL: %s DELETE" % str(self.__class__.__name__))
612 try:
613 for net in self.api.compute.nets.values():
614 if net.subnet_id == subnet_id:
615 for server in self.api.compute.computeUnits.values():
616 for port_name in server.port_names:
617 port = self.api.compute.find_port_by_name_or_id(port_name)
618 if port.net_name == net.name:
619 port.ip_address = None
620 self.api.compute.dc.net.removeLink(
621 link=None,
622 node1=self.api.compute.dc.containers[server.name],
623 node2=self.api.compute.dc.switch)
624 port.net_name = None
625
626 net.delete_subnet()
627
628 return Response('Subnet ' + str(subnet_id) + ' deleted.\n',
629 status=204, mimetype='application/json')
630
631 return Response('Could not find subnet.', status=404, mimetype='application/json')
632 except Exception as ex:
633 LOG.exception("Neutron: Delete subnet exception.")
634 return Response(ex.message, status=500, mimetype='application/json')
635
636
637 class NeutronListPorts(Resource):
638 def __init__(self, api):
639 self.api = api
640
641 def get(self):
642 """
643 Lists all ports, used in son-emu. If a 'name' or one or more 'id's are specified, it will only list the
644 port with the name, or the ports specified via id.
645
646 :return: Returns a json response, starting with 'ports' as root node.
647 :rtype: :class:`flask.response`
648 """
649 LOG.debug("API CALL: %s GET" % str(self.__class__.__name__))
650 try:
651 if request.args.get('name'):
652 show_port = NeutronShowPort(self.api)
653 return show_port.get_port(request.args.get('name'), True)
654 id_list = request.args.getlist('id')
655 if len(id_list) == 1:
656 show_port = NeutronShowPort(self.api)
657 return show_port.get_port(request.args.get('id'), True)
658
659 port_list = list()
660 port_dict = dict()
661
662 if len(id_list) == 0:
663 for port in self.api.compute.ports.values():
664 tmp_port_dict = port.create_port_dict(self.api.compute)
665 port_list.append(tmp_port_dict)
666 else:
667 for port in self.api.compute.ports.values():
668 if port.id in id_list:
669 tmp_port_dict = port.create_port_dict(self.api.compute)
670 port_list.append(tmp_port_dict)
671
672 port_dict["ports"] = port_list
673
674 return Response(json.dumps(port_dict), status=200, mimetype='application/json')
675
676 except Exception as ex:
677 LOG.exception("Neutron: List ports exception.")
678 return Response(ex.message, status=500, mimetype='application/json')
679
680
681 class NeutronShowPort(Resource):
682 def __init__(self, api):
683 self.api = api
684
685 def get(self, port_id):
686 """
687 Returns the port, specified via 'port_id'.
688
689 :param port_id: The unique ID string of the network.
690 :type port_id: ``str``
691 :return: Returns a json response, starting with 'port' as root node and one network description.
692 :rtype: :class:`flask.response`
693 """
694 LOG.debug("API CALL: %s GET" % str(self.__class__.__name__))
695 return self.get_port(port_id, False)
696
697 def get_port(self, port_name_or_id, as_list):
698 """
699 Returns one network description of the port, specified via 'port_name_or_id'.
700
701 :param port_name_or_id: The indicator string, which specifies the requested port.
702 :type port_name_or_id: ``str``
703 :param as_list: Determines if the port description should start with the root node 'port' or 'ports'.
704 :type as_list: ``bool``
705 :return: Returns a json response, with one port description.
706 :rtype: :class:`flask.response`
707 """
708 try:
709 port = self.api.compute.find_port_by_name_or_id(port_name_or_id)
710 if port is None:
711 return Response('Port not found. (' + port_name_or_id + ')\n', status=404, mimetype='application/json')
712 tmp_port_dict = port.create_port_dict(self.api.compute)
713 tmp_dict = dict()
714 if as_list:
715 tmp_dict["ports"] = [tmp_port_dict]
716 else:
717 tmp_dict["port"] = tmp_port_dict
718 return Response(json.dumps(tmp_dict), status=200, mimetype='application/json')
719 except Exception as ex:
720 LOG.exception("Neutron: Show port exception.")
721 return Response(ex.message, status=500, mimetype='application/json')
722
723
724 class NeutronCreatePort(Resource):
725 def __init__(self, api):
726 self.api = api
727
728 def post(self):
729 """
730 Creates a port with the name, specified within the request under ['port']['name'].
731
732 :return: * 404, if the network could not be found.
733 * 500, if any exception occurred while creation and
734 * 201, if everything worked out.
735 :rtype: :class:`flask.response`
736 """
737 LOG.debug("API CALL: %s POST" % str(self.__class__.__name__))
738 try:
739 port_dict = json.loads(request.data)
740 net_id = port_dict['port']['network_id']
741
742 if net_id not in self.api.compute.nets:
743 return Response('Could not find network.\n', status=404, mimetype='application/json')
744
745 net = self.api.compute.nets[net_id]
746 if 'name' in port_dict['port']:
747 name = port_dict['port']['name']
748 else:
749 num_ports = len(self.api.compute.ports)
750 name = "port:cp%s:man:%s" % (num_ports, str(uuid.uuid4()))
751
752 if self.api.compute.find_port_by_name_or_id(name):
753 return Response("Port with name %s already exists.\n" % name, status=500, mimetype='application/json')
754
755 port = self.api.compute.create_port(name)
756
757 port.net_name = net.name
758 port.ip_address = net.get_new_ip_address(name)
759
760 if "admin_state_up" in port_dict["port"]:
761 pass
762 if "device_id" in port_dict["port"]:
763 pass
764 if "device_owner" in port_dict["port"]:
765 pass
766 if "fixed_ips" in port_dict["port"]:
767 pass
768 if "mac_address" in port_dict["port"]:
769 port.mac_address = port_dict["port"]["mac_address"]
770 if "status" in port_dict["port"]:
771 pass
772 if "tenant_id" in port_dict["port"]:
773 pass
774
775 # add the port to a stack if the specified network is a stack network
776 for stack in self.api.compute.stacks.values():
777 for net in stack.nets.values():
778 if net.id == net_id:
779 stack.ports[name] = port
780
781 return Response(json.dumps({'port': port.create_port_dict(self.api.compute)}), status=201,
782 mimetype='application/json')
783 except Exception as ex:
784 LOG.exception("Neutron: Show port exception.")
785 return Response(ex.message, status=500, mimetype='application/json')
786
787
788 class NeutronUpdatePort(Resource):
789 def __init__(self, api):
790 self.api = api
791
792 def put(self, port_id):
793 """
794 Updates the existing port with the given parameters.
795
796 :param network_id: The indicator string, which specifies the requested port.
797 :type network_id: ``str``
798 :return: * 404, if the network could not be found.
799 * 500, if any exception occurred while updating the network.
800 * 200, if everything worked out.
801 :rtype: :class:`flask.response`
802 """
803 LOG.debug("API CALL: %s PUT" % str(self.__class__.__name__))
804 try:
805 port_dict = json.loads(request.data)
806 port = self.api.compute.find_port_by_name_or_id(port_id)
807 if port is None:
808 return Response("Port with id %s does not exists.\n" % port_id, status=404, mimetype='application/json')
809 old_port = copy.copy(port)
810
811 stack = None
812 for s in self.api.compute.stacks.values():
813 for port in s.ports.values():
814 if port.id == port_id:
815 stack = s
816 if "admin_state_up" in port_dict["port"]:
817 pass
818 if "device_id" in port_dict["port"]:
819 pass
820 if "device_owner" in port_dict["port"]:
821 pass
822 if "fixed_ips" in port_dict["port"]:
823 pass
824 if "id" in port_dict["port"]:
825 port.id = port_dict["port"]["id"]
826 if "mac_address" in port_dict["port"]:
827 port.mac_address = port_dict["port"]["mac_address"]
828 if "name" in port_dict["port"] and port_dict["port"]["name"] != port.name:
829 port.set_name(port_dict["port"]["name"])
830 if stack is not None:
831 if port.net_name in stack.nets:
832 stack.nets[port.net_name].update_port_name_for_ip_address(port.ip_address, port.name)
833 stack.ports[port.name] = stack.ports[old_port.name]
834 del stack.ports[old_port.name]
835 if "network_id" in port_dict["port"]:
836 pass
837 if "status" in port_dict["port"]:
838 pass
839 if "tenant_id" in port_dict["port"]:
840 pass
841
842 return Response(json.dumps({'port': port.create_port_dict(self.api.compute)}), status=200,
843 mimetype='application/json')
844 except Exception as ex:
845 LOG.exception("Neutron: Update port exception.")
846 return Response(ex.message, status=500, mimetype='application/json')
847
848
849 class NeutronDeletePort(Resource):
850 def __init__(self, api):
851 self.api = api
852
853 def delete(self, port_id):
854 """
855 Deletes the specified port.
856
857 :param port_id: The indicator string, which specifies the requested port.
858 :type port_id: ``str``
859 :return: * 404, if the port could not be found.
860 * 500, if any exception occurred while deletion.
861 * 204, if everything worked out.
862 :rtype: :class:`flask.response`
863 """
864 LOG.debug("API CALL: %s DELETE" % str(self.__class__.__name__))
865 try:
866 port = self.api.compute.find_port_by_name_or_id(port_id)
867 if port is None:
868 return Response("Port with id %s does not exists.\n" % port_id, status=404)
869 stack = None
870 for s in self.api.compute.stacks.values():
871 for p in s.ports.values():
872 if p.id == port_id:
873 stack = s
874 if stack is not None:
875 if port.net_name in stack.nets:
876 stack.nets[port.net_name].withdraw_ip_address(port.ip_address)
877 for server in stack.servers.values():
878 try:
879 server.port_names.remove(port.name)
880 except ValueError:
881 pass
882
883 # delete the port
884 self.api.compute.delete_port(port.id)
885
886 return Response('Port ' + port_id + ' deleted.\n', status=204, mimetype='application/json')
887
888 except Exception as ex:
889 LOG.exception("Neutron: Delete port exception.")
890 return Response(ex.message, status=500, mimetype='application/json')
891
892
893 class NeutronAddFloatingIp(Resource):
894 def __init__(self, api):
895 self.api = api
896
897 def get(self):
898 """
899 Added a quick and dirty fake for the OSM integration. Returns a list of
900 floating IPs. Has nothing to do with the setup inside the emulator.
901 But its enough to make the OSM driver happy.
902 @PG Sandman: Feel free to improve this and let it do something meaningful.
903 """
904 resp = dict()
905 resp["floatingips"] = list()
906 # create a list of floting IP definitions and return it
907 for i in range(100, 110):
908 ip = dict()
909 ip["router_id"] = "router_id"
910 ip["description"] = "hardcoded in api"
911 ip["created_at"] = "router_id"
912 ip["updated_at"] = "router_id"
913 ip["revision_number"] = 1
914 ip["tenant_id"] = "tenant_id"
915 ip["project_id"] = "project_id"
916 ip["floating_network_id"] = str(i)
917 ip["status"] = "ACTIVE"
918 ip["id"] = str(i)
919 ip["port_id"] = "port_id"
920 ip["floating_ip_address"] = "172.0.0.%d" % i
921 ip["fixed_ip_address"] = "10.0.0.%d" % i
922 resp["floatingips"].append(ip)
923 return Response(json.dumps(resp), status=200, mimetype='application/json')
924
925 def post(self):
926 """
927 Adds a floating IP to neutron.
928
929 :return: Returns a floating network description.
930 :rtype: :class:`flask.response`
931 """
932 LOG.debug("API CALL: %s POST" % str(self.__class__.__name__))
933 try:
934 # Fiddle with floating_network !
935 req = json.loads(request.data)
936
937 network_id = req["floatingip"]["floating_network_id"]
938 net = self.api.compute.find_network_by_name_or_id(network_id)
939 if net != self.api.manage.floating_network:
940 return Response("You have to specify the existing floating network\n",
941 status=400, mimetype='application/json')
942
943 port_id = req["floatingip"].get("port_id", None)
944 port = self.api.compute.find_port_by_name_or_id(port_id)
945 if port is not None:
946 if port.net_name != self.api.manage.floating_network.name:
947 return Response("You have to specify a port in the floating network\n",
948 status=400, mimetype='application/json')
949
950 if port.floating_ip is not None:
951 return Response("We allow only one floating ip per port\n", status=400, mimetype='application/json')
952 else:
953 num_ports = len(self.api.compute.ports)
954 name = "port:cp%s:fl:%s" % (num_ports, str(uuid.uuid4()))
955 port = self.api.compute.create_port(name)
956 port.net_name = net.name
957 port.ip_address = net.get_new_ip_address(name)
958
959 port.floating_ip = port.ip_address
960
961 response = dict()
962 resp = response["floatingip"] = dict()
963
964 resp["floating_network_id"] = net.id
965 resp["status"] = "ACTIVE"
966 resp["id"] = net.id
967 resp["port_id"] = port.id
968 resp["floating_ip_address"] = port.floating_ip
969 resp["fixed_ip_address"] = port.floating_ip
970
971 return Response(json.dumps(response), status=200, mimetype='application/json')
972 except Exception as ex:
973 LOG.exception("Neutron: Create FloatingIP exception %s.", ex)
974 return Response(ex.message, status=500, mimetype='application/json')