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
12 LOG
= logging
.getLogger("api.openstack.neutron")
15 class NeutronDummyApi(BaseOpenstackDummy
):
16 def __init__(self
, ip
, port
, compute
):
17 super(NeutronDummyApi
, self
).__init
__(ip
, port
)
18 self
.compute
= compute
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
})
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
})
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
})
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
})
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
})
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)
120 class Shutdown(Resource
):
122 LOG
.debug(("%s is beeing shut down") % (__name__
))
123 func
= request
.environ
.get('werkzeug.server.shutdown')
125 raise RuntimeError('Not running with the Werkzeug Server')
129 class NeutronListAPIVersions(Resource
):
134 :return: Returns a json with API versions.
135 :rtype: :class:`flask.response`
137 LOG
.debug("API CALL: Neutron - List API Versions")
139 resp
['versions'] = dict()
146 "href": request
.url_root
+ '/v2.0',
151 resp
['versions'] = versions
153 return Response(json
.dumps(resp
), status
=200, mimetype
='application/json')
156 class NeutronShowAPIv2Details(Resource
):
161 :return: Returns a json with API details.
162 :rtype: :class:`flask.response`
164 LOG
.debug("API CALL: %s GET" % str(self
.__class
__.__name
__))
167 resp
['resources'] = dict()
168 resp
['resources'] = [{
171 "href": request
.url_root
+ 'v2.0/subnets',
176 "collection": "subnets"
181 "href": request
.url_root
+ 'v2.0/networks',
186 "collection": "networks"
191 "href": request
.url_root
+ 'v2.0/ports',
196 "collection": "ports"
200 return Response(json
.dumps(resp
), status
=200, mimetype
='application/json')
203 class NeutronListNetworks(Resource
):
204 def __init__(self
, api
):
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.
212 :return: Returns a json response, starting with 'networks' as root node.
213 :rtype: :class:`flask.response`
215 LOG
.debug("API CALL: %s GET" % str(self
.__class
__.__name
__))
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)
225 network_list
= list()
226 network_dict
= dict()
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
)
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
)
240 network_dict
["networks"] = network_list
242 return Response(json
.dumps(network_dict
), status
=200, mimetype
='application/json')
244 except Exception as ex
:
245 LOG
.exception("Neutron: List networks exception.")
246 return Response(ex
.message
, status
=500, mimetype
='application/json')
249 class NeutronShowNetwork(Resource
):
250 def __init__(self
, api
):
253 def get(self
, network_id
):
255 Returns the network, specified via 'network_id'.
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`
262 LOG
.debug("API CALL: %s GET" % str(self
.__class
__.__name
__))
263 return self
.get_network(network_id
, False)
265 def get_network(self
, network_name_or_id
, as_list
):
267 Returns one network description of the network, specified via 'network_name_or_id'.
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`
277 net
= self
.api
.compute
.find_network_by_name_or_id(network_name_or_id
)
279 return Response(u
'Network not found.\n', status
=404, mimetype
='application/json')
281 tmp_network_dict
= net
.create_network_dict()
284 tmp_dict
["networks"] = [tmp_network_dict
]
286 tmp_dict
["network"] = tmp_network_dict
288 return Response(json
.dumps(tmp_dict
), status
=200, mimetype
='application/json')
291 except Exception as ex
:
292 logging
.exception("Neutron: Show network exception.")
293 return Response(ex
.message
, status
=500, mimetype
='application/json')
296 class NeutronCreateNetwork(Resource
):
297 def __init__(self
, api
):
302 Creates a network with the name, specified within the request under ['network']['name'].
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`
309 LOG
.debug("API CALL: %s POST" % str(self
.__class
__.__name
__))
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
)
315 return Response('Network already exists.\n', status
=400, mimetype
='application/json')
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')
324 class NeutronUpdateNetwork(Resource
):
325 def __init__(self
, api
):
328 def put(self
, network_id
): # TODO currently only the name will be changed
330 Updates the existing network with the given parameters.
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`
339 LOG
.debug("API CALL: %s PUT" % str(self
.__class
__.__name
__))
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
)
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
359 return Response(json
.dumps(network_dict
), status
=200, mimetype
='application/json')
361 return Response('Network not found.\n', status
=404, mimetype
='application/json')
363 except Exception as ex
:
364 LOG
.exception("Neutron: Show networks exception.")
365 return Response(ex
.message
, status
=500, mimetype
='application/json')
368 class NeutronDeleteNetwork(Resource
):
369 def __init__(self
, api
):
372 def delete(self
, network_id
):
374 Deletes the specified network and all its subnets.
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`
383 LOG
.debug("API CALL: %s DELETE" % str(self
.__class
__.__name
__))
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')
389 net
= self
.api
.compute
.nets
[network_id
]
390 delete_subnet
= NeutronDeleteSubnet(self
.api
)
391 resp
= delete_subnet
.delete(net
.subnet_id
)
393 if not '204' in resp
.status
and not '404' in resp
.status
:
396 self
.api
.compute
.delete_network(network_id
)
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')
404 class NeutronListSubnets(Resource
):
405 def __init__(self
, api
):
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.
413 :return: Returns a json response, starting with 'subnets' as root node.
414 :rtype: :class:`flask.response`
416 LOG
.debug("API CALL: %s GET" % str(self
.__class
__.__name
__))
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)
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
)
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
)
440 subnet_dict
["subnets"] = subnet_list
442 return Response(json
.dumps(subnet_dict
), status
=200, mimetype
='application/json')
444 except Exception as ex
:
445 LOG
.exception("Neutron: List subnets exception.")
446 return Response(ex
.message
, status
=500, mimetype
='application/json')
449 class NeutronShowSubnet(Resource
):
450 def __init__(self
, api
):
453 def get(self
, subnet_id
):
455 Returns the subnet, specified via 'subnet_id'.
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`
462 LOG
.debug("API CALL: %s GET" % str(self
.__class
__.__name
__))
463 return self
.get_subnet(subnet_id
, False)
465 def get_subnet(self
, subnet_name_or_id
, as_list
):
467 Returns one subnet description of the subnet, specified via 'subnet_name_or_id'.
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`
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()
482 tmp_dict
["subnets"] = [tmp_subnet_dict
]
484 tmp_dict
["subnet"] = tmp_subnet_dict
485 return Response(json
.dumps(tmp_dict
), status
=200, mimetype
='application/json')
487 return Response('Subnet not found. (' + subnet_name_or_id
+ ')\n', status
=404, mimetype
='application/json')
489 except Exception as ex
:
490 LOG
.exception("Neutron: Show subnet exception.")
491 return Response(ex
.message
, status
=500, mimetype
='application/json')
494 class NeutronCreateSubnet(Resource
):
495 def __init__(self
, api
):
500 Creates a subnet with the name, specified within the request under ['subnet']['name'].
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`
509 LOG
.debug("API CALL: %s POST" % str(self
.__class
__.__name
__))
511 subnet_dict
= json
.loads(request
.data
)
512 net
= self
.api
.compute
.find_network_by_name_or_id(subnet_dict
['subnet']['network_id'])
515 return Response('Could not find network.\n', status
=404, mimetype
='application/json')
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')
521 if "id" in subnet_dict
["subnet"]:
522 net
.subnet_id
= subnet_dict
["subnet"]["id"]
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
))
528 if "tenant_id" in subnet_dict
["subnet"]:
530 if "allocation_pools" in subnet_dict
["subnet"]:
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"]:
536 if "enable_dhcp" in subnet_dict
["subnet"]:
539 return Response(json
.dumps({'subnet': net
.create_subnet_dict()}), status
=201, mimetype
='application/json')
541 except Exception as ex
:
542 LOG
.exception("Neutron: Create network excepiton.")
543 return Response(ex
.message
, status
=500, mimetype
='application/json')
546 class NeutronUpdateSubnet(Resource
):
547 def __init__(self
, api
):
550 def put(self
, subnet_id
):
552 Updates the existing subnet with the given parameters.
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`
561 LOG
.debug("API CALL: %s PUT" % str(self
.__class
__.__name
__))
563 for net
in self
.api
.compute
.nets
.values():
564 if net
.subnet_id
== subnet_id
:
565 subnet_dict
= json
.loads(request
.data
)
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"]:
573 if "allocation_pools" in subnet_dict
["subnet"]:
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"]:
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"]:
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')
590 return Response('Network not found.\n', status
=404, mimetype
='application/json')
592 except Exception as ex
:
593 LOG
.exception("Neutron: Show networks exception.")
594 return Response(ex
.message
, status
=500, mimetype
='application/json')
597 class NeutronDeleteSubnet(Resource
):
598 def __init__(self
, api
):
601 def delete(self
, subnet_id
):
603 Deletes the specified subnet.
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`
612 LOG
.debug("API CALL: %s DELETE" % str(self
.__class
__.__name
__))
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(
623 node1
=self
.api
.compute
.dc
.containers
[server
.name
],
624 node2
=self
.api
.compute
.dc
.switch
)
629 return Response('Subnet ' + str(subnet_id
) + ' deleted.\n',
630 status
=204, mimetype
='application/json')
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')
638 class NeutronListPorts(Resource
):
639 def __init__(self
, api
):
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.
647 :return: Returns a json response, starting with 'ports' as root node.
648 :rtype: :class:`flask.response`
650 LOG
.debug("API CALL: %s GET" % str(self
.__class
__.__name
__))
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)
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
)
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
)
673 port_dict
["ports"] = port_list
675 return Response(json
.dumps(port_dict
), status
=200, mimetype
='application/json')
677 except Exception as ex
:
678 LOG
.exception("Neutron: List ports exception.")
679 return Response(ex
.message
, status
=500, mimetype
='application/json')
682 class NeutronShowPort(Resource
):
683 def __init__(self
, api
):
686 def get(self
, port_id
):
688 Returns the port, specified via 'port_id'.
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`
695 LOG
.debug("API CALL: %s GET" % str(self
.__class
__.__name
__))
696 return self
.get_port(port_id
, False)
698 def get_port(self
, port_name_or_id
, as_list
):
700 Returns one network description of the port, specified via 'port_name_or_id'.
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`
710 port
= self
.api
.compute
.find_port_by_name_or_id(port_name_or_id
)
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
)
716 tmp_dict
["ports"] = [tmp_port_dict
]
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')
725 class NeutronCreatePort(Resource
):
726 def __init__(self
, api
):
731 Creates a port with the name, specified within the request under ['port']['name'].
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`
738 LOG
.debug("API CALL: %s POST" % str(self
.__class
__.__name
__))
740 port_dict
= json
.loads(request
.data
)
741 net_id
= port_dict
['port']['network_id']
743 if net_id
not in self
.api
.compute
.nets
:
744 return Response('Could not find network.\n', status
=404, mimetype
='application/json')
746 net
= self
.api
.compute
.nets
[net_id
]
747 if 'name' in port_dict
['port']:
748 name
= port_dict
['port']['name']
750 num_ports
= len(self
.api
.compute
.ports
)
751 name
= "port:cp%s:man:%s" % (num_ports
, str(uuid
.uuid4()))
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')
756 port
= self
.api
.compute
.create_port(name
)
758 port
.net_name
= net
.name
759 port
.ip_address
= net
.get_new_ip_address(name
)
761 if "admin_state_up" in port_dict
["port"]:
763 if "device_id" in port_dict
["port"]:
765 if "device_owner" in port_dict
["port"]:
767 if "fixed_ips" in port_dict
["port"]:
769 if "mac_address" in port_dict
["port"]:
770 port
.mac_address
= port_dict
["port"]["mac_address"]
771 if "status" in port_dict
["port"]:
773 if "tenant_id" in port_dict
["port"]:
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():
780 stack
.ports
[name
] = port
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')
789 class NeutronUpdatePort(Resource
):
790 def __init__(self
, api
):
793 def put(self
, port_id
):
795 Updates the existing port with the given parameters.
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`
804 LOG
.debug("API CALL: %s PUT" % str(self
.__class
__.__name
__))
806 port_dict
= json
.loads(request
.data
)
807 port
= self
.api
.compute
.find_port_by_name_or_id(port_id
)
809 return Response("Port with id %s does not exists.\n" % port_id
, status
=404, mimetype
='application/json')
810 old_port
= copy
.copy(port
)
813 for s
in self
.api
.compute
.stacks
.values():
814 for port
in s
.ports
.values():
815 if port
.id == port_id
:
817 if "admin_state_up" in port_dict
["port"]:
819 if "device_id" in port_dict
["port"]:
821 if "device_owner" in port_dict
["port"]:
823 if "fixed_ips" in port_dict
["port"]:
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"]:
838 if "status" in port_dict
["port"]:
840 if "tenant_id" in port_dict
["port"]:
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')
850 class NeutronDeletePort(Resource
):
851 def __init__(self
, api
):
854 def delete(self
, port_id
):
856 Deletes the specified port.
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`
865 LOG
.debug("API CALL: %s DELETE" % str(self
.__class
__.__name
__))
867 port
= self
.api
.compute
.find_port_by_name_or_id(port_id
)
869 return Response("Port with id %s does not exists.\n" % port_id
, status
=404)
871 for s
in self
.api
.compute
.stacks
.values():
872 for p
in s
.ports
.values():
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():
880 server
.port_names
.remove(port
.name
)
885 self
.api
.compute
.delete_port(port
.id)
887 return Response('Port ' + port_id
+ ' deleted.\n', status
=204, mimetype
='application/json')
889 except Exception as ex
:
890 LOG
.exception("Neutron: Delete port exception.")
891 return Response(ex
.message
, status
=500, mimetype
='application/json')
894 class NeutronAddFloatingIp(Resource
):
895 def __init__(self
, api
):
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.
906 resp
["floatingips"] = list()
907 # create a list of floting IP definitions and return it
908 for i
in range(100, 110):
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"
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')
928 Adds a floating IP to neutron.
930 :return: Returns a floating network description.
931 :rtype: :class:`flask.response`
933 LOG
.debug("API CALL: %s POST" % str(self
.__class
__.__name
__))
935 # Fiddle with floating_network !
936 req
= json
.loads(request
.data
)
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')
944 port_id
= req
["floatingip"].get("port_id", None)
945 port
= self
.api
.compute
.find_port_by_name_or_id(port_id
)
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')
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')
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
)
960 port
.floating_ip
= port
.ip_address
963 resp
= response
["floatingip"] = dict()
965 resp
["floating_network_id"] = net
.id
966 resp
["status"] = "ACTIVE"
968 resp
["port_id"] = port
.id
969 resp
["floating_ip_address"] = port
.floating_ip
970 resp
["fixed_ip_address"] = port
.floating_ip
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')