1 from flask_restful
import Resource
2 from flask
import request
, Response
3 from emuvim
.api
.openstack
.openstack_dummies
.base_openstack_dummy
import BaseOpenstackDummy
4 from datetime
import datetime
5 import neutron_sfc_dummy_api
as SFC
11 LOG
= logging
.getLogger("api.openstack.neutron")
14 class NeutronDummyApi(BaseOpenstackDummy
):
15 def __init__(self
, ip
, port
, compute
):
16 super(NeutronDummyApi
, self
).__init
__(ip
, port
)
17 self
.compute
= compute
19 self
.api
.add_resource(NeutronListAPIVersions
, "/")
20 self
.api
.add_resource(Shutdown
, "/shutdown")
21 self
.api
.add_resource(NeutronShowAPIv2Details
, "/v2.0")
22 self
.api
.add_resource(NeutronListNetworks
, "/v2.0/networks.json", "/v2.0/networks",
23 resource_class_kwargs
={'api': self
})
24 self
.api
.add_resource(NeutronShowNetwork
, "/v2.0/networks/<network_id>.json", "/v2.0/networks/<network_id>",
25 resource_class_kwargs
={'api': self
})
26 self
.api
.add_resource(NeutronCreateNetwork
, "/v2.0/networks.json", "/v2.0/networks",
27 resource_class_kwargs
={'api': self
})
28 self
.api
.add_resource(NeutronUpdateNetwork
, "/v2.0/networks/<network_id>.json", "/v2.0/networks/<network_id>",
29 resource_class_kwargs
={'api': self
})
30 self
.api
.add_resource(NeutronDeleteNetwork
, "/v2.0/networks/<network_id>.json", "/v2.0/networks/<network_id>",
31 resource_class_kwargs
={'api': self
})
32 self
.api
.add_resource(NeutronListSubnets
, "/v2.0/subnets.json", "/v2.0/subnets",
33 resource_class_kwargs
={'api': self
})
34 self
.api
.add_resource(NeutronShowSubnet
, "/v2.0/subnets/<subnet_id>.json", "/v2.0/subnets/<subnet_id>",
35 resource_class_kwargs
={'api': self
})
36 self
.api
.add_resource(NeutronCreateSubnet
, "/v2.0/subnets.json", "/v2.0/subnets",
37 resource_class_kwargs
={'api': self
})
38 self
.api
.add_resource(NeutronUpdateSubnet
, "/v2.0/subnets/<subnet_id>.json", "/v2.0/subnets/<subnet_id>",
39 resource_class_kwargs
={'api': self
})
40 self
.api
.add_resource(NeutronDeleteSubnet
, "/v2.0/subnets/<subnet_id>.json", "/v2.0/subnets/<subnet_id>",
41 resource_class_kwargs
={'api': self
})
42 self
.api
.add_resource(NeutronListPorts
, "/v2.0/ports.json", "/v2.0/ports",
43 resource_class_kwargs
={'api': self
})
44 self
.api
.add_resource(NeutronShowPort
, "/v2.0/ports/<port_id>.json", "/v2.0/ports/<port_id>",
45 resource_class_kwargs
={'api': self
})
46 self
.api
.add_resource(NeutronCreatePort
, "/v2.0/ports.json", "/v2.0/ports",
47 resource_class_kwargs
={'api': self
})
48 self
.api
.add_resource(NeutronUpdatePort
, "/v2.0/ports/<port_id>.json", "/v2.0/ports/<port_id>",
49 resource_class_kwargs
={'api': self
})
50 self
.api
.add_resource(NeutronDeletePort
, "/v2.0/ports/<port_id>.json", "/v2.0/ports/<port_id>",
51 resource_class_kwargs
={'api': self
})
52 self
.api
.add_resource(NeutronAddFloatingIp
, "/v2.0/floatingips.json", "/v2.0/floatingips",
53 resource_class_kwargs
={'api': self
})
55 # Service Function Chaining (SFC) API
56 self
.api
.add_resource(SFC
.PortPairsCreate
, "/v2.0/sfc/port_pairs.json", "/v2.0/sfc/port_pairs",
57 resource_class_kwargs
={'api': self
})
58 self
.api
.add_resource(SFC
.PortPairsUpdate
, "/v2.0/sfc/port_pairs/<pair_id>.json",
59 "/v2.0/sfc/port_pairs/<pair_id>",
60 resource_class_kwargs
={'api': self
})
61 self
.api
.add_resource(SFC
.PortPairsDelete
, "/v2.0/sfc/port_pairs/<pair_id>.json",
62 "/v2.0/sfc/port_pairs/<pair_id>",
63 resource_class_kwargs
={'api': self
})
64 self
.api
.add_resource(SFC
.PortPairsList
, "/v2.0/sfc/port_pairs.json", "/v2.0/sfc/port_pairs",
65 resource_class_kwargs
={'api': self
})
66 self
.api
.add_resource(SFC
.PortPairsShow
, "/v2.0/sfc/port_pairs/<pair_id>.json",
67 "/v2.0/sfc/port_pairs/<pair_id>",
68 resource_class_kwargs
={'api': self
})
70 self
.api
.add_resource(SFC
.PortPairGroupCreate
, "/v2.0/sfc/port_pair_groups.json", "/v2.0/sfc/port_pair_groups",
71 resource_class_kwargs
={'api': self
})
72 self
.api
.add_resource(SFC
.PortPairGroupUpdate
, "/v2.0/sfc/port_pair_groups/<group_id>.json",
73 "/v2.0/sfc/port_pair_groups/<group_id>",
74 resource_class_kwargs
={'api': self
})
75 self
.api
.add_resource(SFC
.PortPairGroupDelete
, "/v2.0/sfc/port_pair_groups/<group_id>.json",
76 "/v2.0/sfc/port_pair_groups/<group_id>",
77 resource_class_kwargs
={'api': self
})
78 self
.api
.add_resource(SFC
.PortPairGroupList
, "/v2.0/sfc/port_pair_groups.json", "/v2.0/sfc/port_pair_groups",
79 resource_class_kwargs
={'api': self
})
80 self
.api
.add_resource(SFC
.PortPairGroupShow
, "/v2.0/sfc/port_pair_groups/<group_id>.json",
81 "/v2.0/sfc/port_pair_groups/<group_id>",
82 resource_class_kwargs
={'api': self
})
84 self
.api
.add_resource(SFC
.FlowClassifierCreate
, "/v2.0/sfc/flow_classifiers.json", "/v2.0/sfc/flow_classifiers",
85 resource_class_kwargs
={'api': self
})
86 self
.api
.add_resource(SFC
.FlowClassifierUpdate
, "/v2.0/sfc/flow_classifiers/<flow_classifier_id>.json",
87 "/v2.0/sfc/flow_classifiers/<flow_classifier_id>",
88 resource_class_kwargs
={'api': self
})
89 self
.api
.add_resource(SFC
.FlowClassifierDelete
, "/v2.0/sfc/flow_classifiers/<flow_classifier_id>.json",
90 "/v2.0/sfc/flow_classifiers/<flow_classifier_id>",
91 resource_class_kwargs
={'api': self
})
92 self
.api
.add_resource(SFC
.FlowClassifierList
, "/v2.0/sfc/flow_classifiers.json", "/v2.0/sfc/flow_classifiers",
93 resource_class_kwargs
={'api': self
})
94 self
.api
.add_resource(SFC
.FlowClassifierShow
, "/v2.0/sfc/flow_classifiers/<flow_classifier_id>.json",
95 "/v2.0/sfc/flow_classifiers/<flow_classifier_id>",
96 resource_class_kwargs
={'api': self
})
98 self
.api
.add_resource(SFC
.PortChainCreate
, "/v2.0/sfc/port_chains.json", "/v2.0/sfc/port_chains",
99 resource_class_kwargs
={'api': self
})
100 self
.api
.add_resource(SFC
.PortChainUpdate
, "/v2.0/sfc/port_chains/<chain_id>.json",
101 "/v2.0/sfc/port_chains/<chain_id>",
102 resource_class_kwargs
={'api': self
})
103 self
.api
.add_resource(SFC
.PortChainDelete
, "/v2.0/sfc/port_chains/<chain_id>.json",
104 "/v2.0/sfc/port_chains/<chain_id>",
105 resource_class_kwargs
={'api': self
})
106 self
.api
.add_resource(SFC
.PortChainList
, "/v2.0/sfc/port_chains.json", "/v2.0/sfc/port_chains",
107 resource_class_kwargs
={'api': self
})
108 self
.api
.add_resource(SFC
.PortChainShow
, "/v2.0/sfc/port_chains/<chain_id>.json",
109 "/v2.0/sfc/port_chains/<chain_id>",
110 resource_class_kwargs
={'api': self
})
112 def _start_flask(self
):
113 LOG
.info("Starting %s endpoint @ http://%s:%d" % (__name__
, self
.ip
, self
.port
))
114 if self
.app
is not None:
115 self
.app
.before_request(self
.dump_playbook
)
116 self
.app
.run(self
.ip
, self
.port
, debug
=True, use_reloader
=False)
119 class Shutdown(Resource
):
121 LOG
.debug(("%s is beeing shut down") % (__name__
))
122 func
= request
.environ
.get('werkzeug.server.shutdown')
124 raise RuntimeError('Not running with the Werkzeug Server')
128 class NeutronListAPIVersions(Resource
):
133 :return: Returns a json with API versions.
134 :rtype: :class:`flask.response`
136 LOG
.debug("API CALL: Neutron - List API Versions")
138 resp
['versions'] = dict()
145 "href": request
.url_root
+ '/v2.0',
150 resp
['versions'] = versions
152 return Response(json
.dumps(resp
), status
=200, mimetype
='application/json')
155 class NeutronShowAPIv2Details(Resource
):
160 :return: Returns a json with API details.
161 :rtype: :class:`flask.response`
163 LOG
.debug("API CALL: %s GET" % str(self
.__class
__.__name
__))
166 resp
['resources'] = dict()
167 resp
['resources'] = [{
170 "href": request
.url_root
+ 'v2.0/subnets',
175 "collection": "subnets"
180 "href": request
.url_root
+ 'v2.0/networks',
185 "collection": "networks"
190 "href": request
.url_root
+ 'v2.0/ports',
195 "collection": "ports"
199 return Response(json
.dumps(resp
), status
=200, mimetype
='application/json')
202 class NeutronListNetworks(Resource
):
203 def __init__(self
, api
):
208 Lists all networks, used in son-emu. If a 'name' or one or more 'id's are specified, it will only list the
209 network with the name, or the networks specified via id.
211 :return: Returns a json response, starting with 'networks' as root node.
212 :rtype: :class:`flask.response`
214 LOG
.debug("API CALL: %s GET" % str(self
.__class
__.__name
__))
216 if request
.args
.get('name'):
217 tmp_network
= NeutronShowNetwork(self
.api
)
218 return tmp_network
.get_network(request
.args
.get('name'), True)
219 id_list
= request
.args
.getlist('id')
220 if len(id_list
) == 1:
221 tmp_network
= NeutronShowNetwork(self
.api
)
222 return tmp_network
.get_network(request
.args
.get('id'), True)
224 network_list
= list()
225 network_dict
= dict()
227 if len(id_list
) == 0:
228 for net
in self
.api
.compute
.nets
.values():
229 tmp_network_dict
= net
.create_network_dict()
230 if tmp_network_dict
not in network_list
:
231 network_list
.append(tmp_network_dict
)
233 for net
in self
.api
.compute
.nets
.values():
234 if net
.id in id_list
:
235 tmp_network_dict
= net
.create_network_dict()
236 if tmp_network_dict
not in network_list
:
237 network_list
.append(tmp_network_dict
)
239 network_dict
["networks"] = network_list
241 return Response(json
.dumps(network_dict
), status
=200, mimetype
='application/json')
243 except Exception as ex
:
244 LOG
.exception("Neutron: List networks exception.")
245 return Response(ex
.message
, status
=500, mimetype
='application/json')
248 class NeutronShowNetwork(Resource
):
249 def __init__(self
, api
):
252 def get(self
, network_id
):
254 Returns the network, specified via 'network_id'.
256 :param network_id: The unique ID string of the network.
257 :type network_id: ``str``
258 :return: Returns a json response, starting with 'network' as root node and one network description.
259 :rtype: :class:`flask.response`
261 LOG
.debug("API CALL: %s GET" % str(self
.__class
__.__name
__))
262 return self
.get_network(network_id
, False)
264 def get_network(self
, network_name_or_id
, as_list
):
266 Returns one network description of the network, specified via 'network_name_or_id'.
268 :param network_name_or_id: The indicator string, which specifies the requested network.
269 :type network_name_or_id: ``str``
270 :param as_list: Determines if the network description should start with the root node 'network' or 'networks'.
271 :type as_list: ``bool``
272 :return: Returns a json response, with one network description.
273 :rtype: :class:`flask.response`
276 net
= self
.api
.compute
.find_network_by_name_or_id(network_name_or_id
)
278 return Response(u
'Network not found.\n', status
=404, mimetype
='application/json')
280 tmp_network_dict
= net
.create_network_dict()
283 tmp_dict
["networks"] = [tmp_network_dict
]
285 tmp_dict
["network"] = tmp_network_dict
287 return Response(json
.dumps(tmp_dict
), status
=200, mimetype
='application/json')
290 except Exception as ex
:
291 logging
.exception("Neutron: Show network exception.")
292 return Response(ex
.message
, status
=500, mimetype
='application/json')
295 class NeutronCreateNetwork(Resource
):
296 def __init__(self
, api
):
301 Creates a network with the name, specified within the request under ['network']['name'].
303 :return: * 400, if the network already exists.
304 * 500, if any exception occurred while creation.
305 * 201, if everything worked out.
306 :rtype: :class:`flask.response`
308 LOG
.debug("API CALL: %s POST" % str(self
.__class
__.__name
__))
310 network_dict
= json
.loads(request
.data
)
311 name
= network_dict
['network']['name']
312 net
= self
.api
.compute
.find_network_by_name_or_id(name
)
314 return Response('Network already exists.\n', status
=400, mimetype
='application/json')
316 net
= self
.api
.compute
.create_network(name
)
317 return Response(json
.dumps({"network": net
.create_network_dict()}), status
=201, mimetype
='application/json')
318 except Exception as ex
:
319 LOG
.exception("Neutron: Create network excepiton.")
320 return Response(ex
.message
, status
=500, mimetype
='application/json')
323 class NeutronUpdateNetwork(Resource
):
324 def __init__(self
, api
):
327 def put(self
, network_id
): # TODO currently only the name will be changed
329 Updates the existing network with the given parameters.
331 :param network_id: The indicator string, which specifies the requested network.
332 :type network_id: ``str``
333 :return: * 404, if the network could not be found.
334 * 500, if any exception occurred while updating the network.
335 * 200, if everything worked out.
336 :rtype: :class:`flask.response`
338 LOG
.debug("API CALL: %s PUT" % str(self
.__class
__.__name
__))
340 if network_id
in self
.api
.compute
.nets
:
341 net
= self
.api
.compute
.nets
[network_id
]
342 network_dict
= json
.loads(request
.data
)
343 old_net
= copy
.copy(net
)
345 if "status" in network_dict
["network"]:
346 net
.status
= network_dict
["network"]["status"]
347 if "subnets" in network_dict
["network"]:
348 pass # tmp_network_dict["subnets"] = None
349 if "name" in network_dict
["network"] and net
.name
!= network_dict
["network"]["name"]:
350 net
.name
= network_dict
["network"]["name"]
351 if "admin_state_up" in network_dict
["network"]:
352 pass # tmp_network_dict["admin_state_up"] = True
353 if "tenant_id" in network_dict
["network"]:
354 pass # tmp_network_dict["tenant_id"] = "c1210485b2424d48804aad5d39c61b8f"
355 if "shared" in network_dict
["network"]:
356 pass # tmp_network_dict["shared"] = False
358 return Response(json
.dumps(network_dict
), status
=200, mimetype
='application/json')
360 return Response('Network not found.\n', status
=404, mimetype
='application/json')
362 except Exception as ex
:
363 LOG
.exception("Neutron: Show networks exception.")
364 return Response(ex
.message
, status
=500, mimetype
='application/json')
367 class NeutronDeleteNetwork(Resource
):
368 def __init__(self
, api
):
371 def delete(self
, network_id
):
373 Deletes the specified network and all its subnets.
375 :param network_id: The indicator string, which specifies the requested network.
376 :type network_id: ``str``
377 :return: * 404, if the network or the subnet could not be removed.
378 * 500, if any exception occurred while deletion.
379 * 204, if everything worked out.
380 :rtype: :class:`flask.response`
382 LOG
.debug("API CALL: %s DELETE" % str(self
.__class
__.__name
__))
384 if network_id
not in self
.api
.compute
.nets
:
385 return Response('Could not find network. (' + network_id
+ ')\n',
386 status
=404, mimetype
='application/json')
388 net
= self
.api
.compute
.nets
[network_id
]
389 delete_subnet
= NeutronDeleteSubnet(self
.api
)
390 resp
= delete_subnet
.delete(net
.subnet_id
)
392 if not '204' in resp
.status
and not '404' in resp
.status
:
395 self
.api
.compute
.delete_network(network_id
)
397 return Response('Network ' + str(network_id
) + ' deleted.\n', status
=204, mimetype
='application/json')
398 except Exception as ex
:
399 LOG
.exception("Neutron: Delete network exception.")
400 return Response(ex
.message
, status
=500, mimetype
='application/json')
403 class NeutronListSubnets(Resource
):
404 def __init__(self
, api
):
409 Lists all subnets, used in son-emu. If a 'name' or one or more 'id's are specified, it will only list the
410 subnet with the name, or the subnets specified via id.
412 :return: Returns a json response, starting with 'subnets' as root node.
413 :rtype: :class:`flask.response`
415 LOG
.debug("API CALL: %s GET" % str(self
.__class
__.__name
__))
417 if request
.args
.get('name'):
418 show_subnet
= NeutronShowSubnet(self
.api
)
419 return show_subnet
.get_subnet(request
.args
.get('name'), True)
420 id_list
= request
.args
.getlist('id')
421 if len(id_list
) == 1:
422 show_subnet
= NeutronShowSubnet(self
.api
)
423 return show_subnet
.get_subnet(id_list
[0], True)
428 if len(id_list
) == 0:
429 for net
in self
.api
.compute
.nets
.values():
430 if net
.subnet_id
is not None:
431 tmp_subnet_dict
= net
.create_subnet_dict()
432 subnet_list
.append(tmp_subnet_dict
)
434 for net
in self
.api
.compute
.nets
.values():
435 if net
.subnet_id
in id_list
:
436 tmp_subnet_dict
= net
.create_subnet_dict()
437 subnet_list
.append(tmp_subnet_dict
)
439 subnet_dict
["subnets"] = subnet_list
441 return Response(json
.dumps(subnet_dict
), status
=200, mimetype
='application/json')
443 except Exception as ex
:
444 LOG
.exception("Neutron: List subnets exception.")
445 return Response(ex
.message
, status
=500, mimetype
='application/json')
448 class NeutronShowSubnet(Resource
):
449 def __init__(self
, api
):
452 def get(self
, subnet_id
):
454 Returns the subnet, specified via 'subnet_id'.
456 :param subnet_id: The unique ID string of the subnet.
457 :type subnet_id: ``str``
458 :return: Returns a json response, starting with 'subnet' as root node and one subnet description.
459 :rtype: :class:`flask.response`
461 LOG
.debug("API CALL: %s GET" % str(self
.__class
__.__name
__))
462 return self
.get_subnet(subnet_id
, False)
464 def get_subnet(self
, subnet_name_or_id
, as_list
):
466 Returns one subnet description of the subnet, specified via 'subnet_name_or_id'.
468 :param subnet_name_or_id: The indicator string, which specifies the requested subnet.
469 :type subnet_name_or_id: ``str``
470 :param as_list: Determines if the subnet description should start with the root node 'subnet' or 'subnets'.
471 :type as_list: ``bool``
472 :return: Returns a json response, with one subnet description.
473 :rtype: :class:`flask.response`
476 for net
in self
.api
.compute
.nets
.values():
477 if net
.subnet_id
== subnet_name_or_id
or net
.subnet_name
== subnet_name_or_id
:
478 tmp_subnet_dict
= net
.create_subnet_dict()
481 tmp_dict
["subnets"] = [tmp_subnet_dict
]
483 tmp_dict
["subnet"] = tmp_subnet_dict
484 return Response(json
.dumps(tmp_dict
), status
=200, mimetype
='application/json')
486 return Response('Subnet not found. (' + subnet_name_or_id
+ ')\n', status
=404, mimetype
='application/json')
488 except Exception as ex
:
489 LOG
.exception("Neutron: Show subnet exception.")
490 return Response(ex
.message
, status
=500, mimetype
='application/json')
493 class NeutronCreateSubnet(Resource
):
494 def __init__(self
, api
):
499 Creates a subnet with the name, specified within the request under ['subnet']['name'].
501 :return: * 400, if the 'CIDR' format is wrong or it does not exist.
502 * 404, if the network was not found.
503 * 409, if the corresponding network already has one subnet.
504 * 500, if any exception occurred while creation and
505 * 201, if everything worked out.
506 :rtype: :class:`flask.response`
508 LOG
.debug("API CALL: %s POST" % str(self
.__class
__.__name
__))
510 subnet_dict
= json
.loads(request
.data
)
511 net
= self
.api
.compute
.find_network_by_name_or_id(subnet_dict
['subnet']['network_id'])
514 return Response('Could not find network.\n', status
=404, mimetype
='application/json')
516 net
.subnet_name
= subnet_dict
["subnet"].get('name', str(net
.name
) + '-sub')
517 if net
.subnet_id
is not None:
518 return Response('Only one subnet per network is supported\n', status
=409, mimetype
='application/json')
520 if "id" in subnet_dict
["subnet"]:
521 net
.subnet_id
= subnet_dict
["subnet"]["id"]
523 net
.subnet_id
= str(uuid
.uuid4())
524 import emuvim
.api
.openstack
.ip_handler
as IP
525 net
.set_cidr(IP
.get_new_cidr(net
.subnet_id
))
527 if "tenant_id" in subnet_dict
["subnet"]:
529 if "allocation_pools" in subnet_dict
["subnet"]:
531 if "gateway_ip" in subnet_dict
["subnet"]:
532 net
.gateway_ip
= subnet_dict
["subnet"]["gateway_ip"]
533 if "ip_version" in subnet_dict
["subnet"]:
535 if "enable_dhcp" in subnet_dict
["subnet"]:
538 return Response(json
.dumps({'subnet': net
.create_subnet_dict()}), status
=201, mimetype
='application/json')
540 except Exception as ex
:
541 LOG
.exception("Neutron: Create network excepiton.")
542 return Response(ex
.message
, status
=500, mimetype
='application/json')
545 class NeutronUpdateSubnet(Resource
):
546 def __init__(self
, api
):
549 def put(self
, subnet_id
):
551 Updates the existing subnet with the given parameters.
553 :param subnet_id: The indicator string, which specifies the requested subnet.
554 :type subnet_id: ``str``
555 :return: * 404, if the network could not be found.
556 * 500, if any exception occurred while updating the network.
557 * 200, if everything worked out.
558 :rtype: :class:`flask.response`
560 LOG
.debug("API CALL: %s PUT" % str(self
.__class
__.__name
__))
562 for net
in self
.api
.compute
.nets
.values():
563 if net
.subnet_id
== subnet_id
:
564 subnet_dict
= json
.loads(request
.data
)
566 if "name" in subnet_dict
["subnet"]:
567 net
.subnet_name
= subnet_dict
["subnet"]["name"]
568 if "network_id" in subnet_dict
["subnet"]:
569 net
.id = subnet_dict
["subnet"]["network_id"]
570 if "tenant_id" in subnet_dict
["subnet"]:
572 if "allocation_pools" in subnet_dict
["subnet"]:
574 if "gateway_ip" in subnet_dict
["subnet"]:
575 net
.gateway_ip
= subnet_dict
["subnet"]["gateway_ip"]
576 if "ip_version" in subnet_dict
["subnet"]:
578 if "cidr" in subnet_dict
["subnet"]:
579 net
.set_cidr(subnet_dict
["subnet"]["cidr"])
580 if "id" in subnet_dict
["subnet"]:
581 net
.subnet_id
= subnet_dict
["subnet"]["id"]
582 if "enable_dhcp" in subnet_dict
["subnet"]:
585 net
.subnet_update_time
= str(datetime
.now())
586 tmp_dict
= {'subnet': net
.create_subnet_dict()}
587 return Response(json
.dumps(tmp_dict
), status
=200, mimetype
='application/json')
589 return Response('Network not found.\n', status
=404, mimetype
='application/json')
591 except Exception as ex
:
592 LOG
.exception("Neutron: Show networks exception.")
593 return Response(ex
.message
, status
=500, mimetype
='application/json')
596 class NeutronDeleteSubnet(Resource
):
597 def __init__(self
, api
):
600 def delete(self
, subnet_id
):
602 Deletes the specified subnet.
604 :param subnet_id: The indicator string, which specifies the requested subnet.
605 :type subnet_id: ``str``
606 :return: * 404, if the subnet could not be removed.
607 * 500, if any exception occurred while deletion.
608 * 204, if everything worked out.
609 :rtype: :class:`flask.response`
611 LOG
.debug("API CALL: %s DELETE" % str(self
.__class
__.__name
__))
613 for net
in self
.api
.compute
.nets
.values():
614 if net
.subnet_id
== subnet_id
:
615 for server
in self
.api
.compute
.computeUnits
.values():
616 for port_name
in server
.port_names
:
617 port
= self
.api
.compute
.find_port_by_name_or_id(port_name
)
618 if port
.net_name
== net
.name
:
619 port
.ip_address
= None
620 self
.api
.compute
.dc
.net
.removeLink(
622 node1
=self
.api
.compute
.dc
.containers
[server
.name
],
623 node2
=self
.api
.compute
.dc
.switch
)
628 return Response('Subnet ' + str(subnet_id
) + ' deleted.\n',
629 status
=204, mimetype
='application/json')
631 return Response('Could not find subnet.', status
=404, mimetype
='application/json')
632 except Exception as ex
:
633 LOG
.exception("Neutron: Delete subnet exception.")
634 return Response(ex
.message
, status
=500, mimetype
='application/json')
637 class NeutronListPorts(Resource
):
638 def __init__(self
, api
):
643 Lists all ports, used in son-emu. If a 'name' or one or more 'id's are specified, it will only list the
644 port with the name, or the ports specified via id.
646 :return: Returns a json response, starting with 'ports' as root node.
647 :rtype: :class:`flask.response`
649 LOG
.debug("API CALL: %s GET" % str(self
.__class
__.__name
__))
651 if request
.args
.get('name'):
652 show_port
= NeutronShowPort(self
.api
)
653 return show_port
.get_port(request
.args
.get('name'), True)
654 id_list
= request
.args
.getlist('id')
655 if len(id_list
) == 1:
656 show_port
= NeutronShowPort(self
.api
)
657 return show_port
.get_port(request
.args
.get('id'), True)
662 if len(id_list
) == 0:
663 for port
in self
.api
.compute
.ports
.values():
664 tmp_port_dict
= port
.create_port_dict(self
.api
.compute
)
665 port_list
.append(tmp_port_dict
)
667 for port
in self
.api
.compute
.ports
.values():
668 if port
.id in id_list
:
669 tmp_port_dict
= port
.create_port_dict(self
.api
.compute
)
670 port_list
.append(tmp_port_dict
)
672 port_dict
["ports"] = port_list
674 return Response(json
.dumps(port_dict
), status
=200, mimetype
='application/json')
676 except Exception as ex
:
677 LOG
.exception("Neutron: List ports exception.")
678 return Response(ex
.message
, status
=500, mimetype
='application/json')
681 class NeutronShowPort(Resource
):
682 def __init__(self
, api
):
685 def get(self
, port_id
):
687 Returns the port, specified via 'port_id'.
689 :param port_id: The unique ID string of the network.
690 :type port_id: ``str``
691 :return: Returns a json response, starting with 'port' as root node and one network description.
692 :rtype: :class:`flask.response`
694 LOG
.debug("API CALL: %s GET" % str(self
.__class
__.__name
__))
695 return self
.get_port(port_id
, False)
697 def get_port(self
, port_name_or_id
, as_list
):
699 Returns one network description of the port, specified via 'port_name_or_id'.
701 :param port_name_or_id: The indicator string, which specifies the requested port.
702 :type port_name_or_id: ``str``
703 :param as_list: Determines if the port description should start with the root node 'port' or 'ports'.
704 :type as_list: ``bool``
705 :return: Returns a json response, with one port description.
706 :rtype: :class:`flask.response`
709 port
= self
.api
.compute
.find_port_by_name_or_id(port_name_or_id
)
711 return Response('Port not found. (' + port_name_or_id
+ ')\n', status
=404, mimetype
='application/json')
712 tmp_port_dict
= port
.create_port_dict(self
.api
.compute
)
715 tmp_dict
["ports"] = [tmp_port_dict
]
717 tmp_dict
["port"] = tmp_port_dict
718 return Response(json
.dumps(tmp_dict
), status
=200, mimetype
='application/json')
719 except Exception as ex
:
720 LOG
.exception("Neutron: Show port exception.")
721 return Response(ex
.message
, status
=500, mimetype
='application/json')
724 class NeutronCreatePort(Resource
):
725 def __init__(self
, api
):
730 Creates a port with the name, specified within the request under ['port']['name'].
732 :return: * 404, if the network could not be found.
733 * 500, if any exception occurred while creation and
734 * 201, if everything worked out.
735 :rtype: :class:`flask.response`
737 LOG
.debug("API CALL: %s POST" % str(self
.__class
__.__name
__))
739 port_dict
= json
.loads(request
.data
)
740 net_id
= port_dict
['port']['network_id']
742 if net_id
not in self
.api
.compute
.nets
:
743 return Response('Could not find network.\n', status
=404, mimetype
='application/json')
745 net
= self
.api
.compute
.nets
[net_id
]
746 if 'name' in port_dict
['port']:
747 name
= port_dict
['port']['name']
749 num_ports
= len(self
.api
.compute
.ports
)
750 name
= "port:cp%s:man:%s" % (num_ports
, str(uuid
.uuid4()))
752 if self
.api
.compute
.find_port_by_name_or_id(name
):
753 return Response("Port with name %s already exists.\n" % name
, status
=500, mimetype
='application/json')
755 port
= self
.api
.compute
.create_port(name
)
757 port
.net_name
= net
.name
758 port
.ip_address
= net
.get_new_ip_address(name
)
760 if "admin_state_up" in port_dict
["port"]:
762 if "device_id" in port_dict
["port"]:
764 if "device_owner" in port_dict
["port"]:
766 if "fixed_ips" in port_dict
["port"]:
768 if "mac_address" in port_dict
["port"]:
769 port
.mac_address
= port_dict
["port"]["mac_address"]
770 if "status" in port_dict
["port"]:
772 if "tenant_id" in port_dict
["port"]:
775 # add the port to a stack if the specified network is a stack network
776 for stack
in self
.api
.compute
.stacks
.values():
777 for net
in stack
.nets
.values():
779 stack
.ports
[name
] = port
781 return Response(json
.dumps({'port': port
.create_port_dict(self
.api
.compute
)}), status
=201,
782 mimetype
='application/json')
783 except Exception as ex
:
784 LOG
.exception("Neutron: Show port exception.")
785 return Response(ex
.message
, status
=500, mimetype
='application/json')
788 class NeutronUpdatePort(Resource
):
789 def __init__(self
, api
):
792 def put(self
, port_id
):
794 Updates the existing port with the given parameters.
796 :param network_id: The indicator string, which specifies the requested port.
797 :type network_id: ``str``
798 :return: * 404, if the network could not be found.
799 * 500, if any exception occurred while updating the network.
800 * 200, if everything worked out.
801 :rtype: :class:`flask.response`
803 LOG
.debug("API CALL: %s PUT" % str(self
.__class
__.__name
__))
805 port_dict
= json
.loads(request
.data
)
806 port
= self
.api
.compute
.find_port_by_name_or_id(port_id
)
808 return Response("Port with id %s does not exists.\n" % port_id
, status
=404, mimetype
='application/json')
809 old_port
= copy
.copy(port
)
812 for s
in self
.api
.compute
.stacks
.values():
813 for port
in s
.ports
.values():
814 if port
.id == port_id
:
816 if "admin_state_up" in port_dict
["port"]:
818 if "device_id" in port_dict
["port"]:
820 if "device_owner" in port_dict
["port"]:
822 if "fixed_ips" in port_dict
["port"]:
824 if "id" in port_dict
["port"]:
825 port
.id = port_dict
["port"]["id"]
826 if "mac_address" in port_dict
["port"]:
827 port
.mac_address
= port_dict
["port"]["mac_address"]
828 if "name" in port_dict
["port"] and port_dict
["port"]["name"] != port
.name
:
829 port
.set_name(port_dict
["port"]["name"])
830 if stack
is not None:
831 if port
.net_name
in stack
.nets
:
832 stack
.nets
[port
.net_name
].update_port_name_for_ip_address(port
.ip_address
, port
.name
)
833 stack
.ports
[port
.name
] = stack
.ports
[old_port
.name
]
834 del stack
.ports
[old_port
.name
]
835 if "network_id" in port_dict
["port"]:
837 if "status" in port_dict
["port"]:
839 if "tenant_id" in port_dict
["port"]:
842 return Response(json
.dumps({'port': port
.create_port_dict(self
.api
.compute
)}), status
=200,
843 mimetype
='application/json')
844 except Exception as ex
:
845 LOG
.exception("Neutron: Update port exception.")
846 return Response(ex
.message
, status
=500, mimetype
='application/json')
849 class NeutronDeletePort(Resource
):
850 def __init__(self
, api
):
853 def delete(self
, port_id
):
855 Deletes the specified port.
857 :param port_id: The indicator string, which specifies the requested port.
858 :type port_id: ``str``
859 :return: * 404, if the port could not be found.
860 * 500, if any exception occurred while deletion.
861 * 204, if everything worked out.
862 :rtype: :class:`flask.response`
864 LOG
.debug("API CALL: %s DELETE" % str(self
.__class
__.__name
__))
866 port
= self
.api
.compute
.find_port_by_name_or_id(port_id
)
868 return Response("Port with id %s does not exists.\n" % port_id
, status
=404)
870 for s
in self
.api
.compute
.stacks
.values():
871 for p
in s
.ports
.values():
874 if stack
is not None:
875 if port
.net_name
in stack
.nets
:
876 stack
.nets
[port
.net_name
].withdraw_ip_address(port
.ip_address
)
877 for server
in stack
.servers
.values():
879 server
.port_names
.remove(port
.name
)
884 self
.api
.compute
.delete_port(port
.id)
886 return Response('Port ' + port_id
+ ' deleted.\n', status
=204, mimetype
='application/json')
888 except Exception as ex
:
889 LOG
.exception("Neutron: Delete port exception.")
890 return Response(ex
.message
, status
=500, mimetype
='application/json')
893 class NeutronAddFloatingIp(Resource
):
894 def __init__(self
, api
):
899 Added a quick and dirty fake for the OSM integration. Returns a list of
900 floating IPs. Has nothing to do with the setup inside the emulator.
901 But its enough to make the OSM driver happy.
902 @PG Sandman: Feel free to improve this and let it do something meaningful.
905 resp
["floatingips"] = list()
906 # create a list of floting IP definitions and return it
907 for i
in range(100, 110):
909 ip
["router_id"] = "router_id"
910 ip
["description"] = "hardcoded in api"
911 ip
["created_at"] = "router_id"
912 ip
["updated_at"] = "router_id"
913 ip
["revision_number"] = 1
914 ip
["tenant_id"] = "tenant_id"
915 ip
["project_id"] = "project_id"
916 ip
["floating_network_id"] = str(i
)
917 ip
["status"] = "ACTIVE"
919 ip
["port_id"] = "port_id"
920 ip
["floating_ip_address"] = "172.0.0.%d" % i
921 ip
["fixed_ip_address"] = "10.0.0.%d" % i
922 resp
["floatingips"].append(ip
)
923 return Response(json
.dumps(resp
), status
=200, mimetype
='application/json')
927 Adds a floating IP to neutron.
929 :return: Returns a floating network description.
930 :rtype: :class:`flask.response`
932 LOG
.debug("API CALL: %s POST" % str(self
.__class
__.__name
__))
934 # Fiddle with floating_network !
935 req
= json
.loads(request
.data
)
937 network_id
= req
["floatingip"]["floating_network_id"]
938 net
= self
.api
.compute
.find_network_by_name_or_id(network_id
)
939 if net
!= self
.api
.manage
.floating_network
:
940 return Response("You have to specify the existing floating network\n",
941 status
=400, mimetype
='application/json')
943 port_id
= req
["floatingip"].get("port_id", None)
944 port
= self
.api
.compute
.find_port_by_name_or_id(port_id
)
946 if port
.net_name
!= self
.api
.manage
.floating_network
.name
:
947 return Response("You have to specify a port in the floating network\n",
948 status
=400, mimetype
='application/json')
950 if port
.floating_ip
is not None:
951 return Response("We allow only one floating ip per port\n", status
=400, mimetype
='application/json')
953 num_ports
= len(self
.api
.compute
.ports
)
954 name
= "port:cp%s:fl:%s" % (num_ports
, str(uuid
.uuid4()))
955 port
= self
.api
.compute
.create_port(name
)
956 port
.net_name
= net
.name
957 port
.ip_address
= net
.get_new_ip_address(name
)
959 port
.floating_ip
= port
.ip_address
962 resp
= response
["floatingip"] = dict()
964 resp
["floating_network_id"] = net
.id
965 resp
["status"] = "ACTIVE"
967 resp
["port_id"] = port
.id
968 resp
["floating_ip_address"] = port
.floating_ip
969 resp
["fixed_ip_address"] = port
.floating_ip
971 return Response(json
.dumps(response
), status
=200, mimetype
='application/json')
972 except Exception as ex
:
973 LOG
.exception("Neutron: Create FloatingIP exception %s.", ex
)
974 return Response(ex
.message
, status
=500, mimetype
='application/json')