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