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