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