1 from flask_restful
import Resource
2 from flask
import Response
, request
3 from emuvim
.api
.openstack
.openstack_dummies
.base_openstack_dummy
import BaseOpenstackDummy
7 from mininet
.link
import Link
10 LOG
= logging
.getLogger("api.openstack.nova")
13 class NovaDummyApi(BaseOpenstackDummy
):
14 def __init__(self
, in_ip
, in_port
, compute
):
15 super(NovaDummyApi
, self
).__init
__(in_ip
, in_port
)
16 self
.compute
= compute
18 self
.api
.add_resource(NovaVersionsList
, "/",
19 resource_class_kwargs
={'api': self
})
20 self
.api
.add_resource(Shutdown
, "/shutdown")
21 self
.api
.add_resource(NovaVersionShow
, "/v2.1/<id>",
22 resource_class_kwargs
={'api': self
})
23 self
.api
.add_resource(NovaListServersApi
, "/v2.1/<id>/servers",
24 resource_class_kwargs
={'api': self
})
25 self
.api
.add_resource(NovaListServersAndPortsApi
, "/v2.1/<id>/servers/andPorts",
26 resource_class_kwargs
={'api': self
})
27 self
.api
.add_resource(NovaListServersDetailed
, "/v2.1/<id>/servers/detail",
28 resource_class_kwargs
={'api': self
})
29 self
.api
.add_resource(NovaShowServerDetails
, "/v2.1/<id>/servers/<serverid>",
30 resource_class_kwargs
={'api': self
})
31 self
.api
.add_resource(NovaInterfaceToServer
, "/v2.1/<id>/servers/<serverid>/os-interface",
32 resource_class_kwargs
={'api': self
})
33 self
.api
.add_resource(NovaShowAndDeleteInterfaceAtServer
, "/v2.1/<id>/servers/<serverid>/os-interface/<port_id>",
34 resource_class_kwargs
={'api': self
})
35 self
.api
.add_resource(NovaListFlavors
, "/v2.1/<id>/flavors", "/v2/<id>/flavors",
36 resource_class_kwargs
={'api': self
})
37 self
.api
.add_resource(NovaListFlavorsDetails
, "/v2.1/<id>/flavors/detail", "/v2/<id>/flavors/detail",
38 resource_class_kwargs
={'api': self
})
39 self
.api
.add_resource(NovaListFlavorById
, "/v2.1/<id>/flavors/<flavorid>", "/v2/<id>/flavors/<flavorid>",
40 resource_class_kwargs
={'api': self
})
41 self
.api
.add_resource(NovaListImages
, "/v2.1/<id>/images",
42 resource_class_kwargs
={'api': self
})
43 self
.api
.add_resource(NovaListImagesDetails
, "/v2.1/<id>/images/detail",
44 resource_class_kwargs
={'api': self
})
45 self
.api
.add_resource(NovaListImageById
, "/v2.1/<id>/images/<imageid>",
46 resource_class_kwargs
={'api': self
})
47 self
.api
.add_resource(NovaLimits
, "/v2.1/<id>/limits",
48 resource_class_kwargs
={'api': self
})
50 def _start_flask(self
):
51 LOG
.info("Starting %s endpoint @ http://%s:%d" % ("NovaDummyApi", self
.ip
, self
.port
))
52 # add some flavors for good measure
53 self
.compute
.add_flavor('m1.tiny', 1, 512, "MB", 1, "GB")
54 self
.compute
.add_flavor('m1.nano', 1, 64, "MB", 0, "GB")
55 self
.compute
.add_flavor('m1.micro', 1, 128, "MB", 0, "GB")
56 self
.compute
.add_flavor('m1.small', 1, 1024, "MB", 2, "GB")
57 if self
.app
is not None:
58 self
.app
.before_request(self
.dump_playbook
)
59 self
.app
.run(self
.ip
, self
.port
, debug
=True, use_reloader
=False)
62 class Shutdown(Resource
):
64 A get request to /shutdown will shut down this endpoint.
68 LOG
.debug(("%s is beeing shut doen") % (__name__
))
69 func
= request
.environ
.get('werkzeug.server.shutdown')
71 raise RuntimeError('Not running with the Werkzeug Server')
75 class NovaVersionsList(Resource
):
76 def __init__(self
, api
):
83 :return: Returns a json with API versions.
84 :rtype: :class:`flask.response`
86 LOG
.debug("API CALL: %s GET" % str(self
.__class
__.__name
__))
95 "href": "http://%s:%d/v2.1/",
101 "min_version": "2.1",
102 "updated": "2013-07-23T11:33:21Z"
106 """ % (self
.api
.ip
, self
.api
.port
)
108 response
= Response(resp
, status
=200, mimetype
="application/json")
109 response
.headers
['Access-Control-Allow-Origin'] = '*'
112 except Exception as ex
:
113 LOG
.exception(u
"%s: Could not show list of versions." % __name__
)
114 return ex
.message
, 500
117 class NovaVersionShow(Resource
):
118 def __init__(self
, api
):
127 :return: Returns a json with API details.
128 :rtype: :class:`flask.response`
130 LOG
.debug("API CALL: %s GET" % str(self
.__class
__.__name
__))
139 "href": "http://%s:%d/v2.1/",
143 "href": "http://docs.openstack.org/",
144 "rel": "describedby",
150 "base": "application/json",
151 "type": "application/vnd.openstack.compute+json;version=2.1"
156 "min_version": "2.1",
157 "updated": "2013-07-23T11:33:21Z"
160 """ % (self
.api
.ip
, self
.api
.port
)
162 response
= Response(resp
, status
=200, mimetype
="application/json")
163 response
.headers
['Access-Control-Allow-Origin'] = '*'
166 except Exception as ex
:
167 LOG
.exception(u
"%s: Could not show list of versions." % __name__
)
168 return ex
.message
, 500
171 class NovaListServersApi(Resource
):
172 def __init__(self
, api
):
177 Creates a list with all running servers and their detailed information.
179 :param id: Used to create a individual link to quarry further information.
181 :return: Returns a json response with a dictionary that contains the server information.
182 :rtype: :class:`flask.response`
184 LOG
.debug("API CALL: %s GET" % str(self
.__class
__.__name
__))
188 resp
['servers'] = list()
189 for server
in self
.api
.compute
.computeUnits
.values():
190 s
= server
.create_server_dict(self
.api
.compute
)
191 s
['links'] = [{'href': "http://%s:%d/v2.1/%s/servers/%s" % (self
.api
.ip
,
196 resp
['servers'].append(s
)
198 response
= Response(json
.dumps(resp
), status
=200, mimetype
="application/json")
199 response
.headers
['Access-Control-Allow-Origin'] = '*'
202 except Exception as ex
:
203 LOG
.exception(u
"%s: Could not retrieve the list of servers." % __name__
)
204 return ex
.message
, 500
208 Creates a server instance.
210 :param id: tenant id, we ignore this most of the time
212 :return: Returns a flask response, with detailed information about the just created server.
213 :rtype: :class:`flask.response`
215 LOG
.debug("API CALL: %s POST" % str(self
.__class
__.__name
__))
217 server_dict
= json
.loads(request
.data
)['server']
218 networks
= server_dict
.get('networks', None)
219 name
= str(self
.api
.compute
.dc
.label
) + "_man_" + server_dict
["name"][0:12]
221 if self
.api
.compute
.find_server_by_name_or_id(name
) is not None:
222 return Response("Server with name %s already exists." % name
, status
=409)
223 # TODO: not finished!
226 server
= self
.api
.compute
.create_server(name
)
227 server
.full_name
= str(self
.api
.compute
.dc
.label
) + "_man_" + server_dict
["name"]
228 server
.template_name
= server_dict
["name"]
230 for flavor
in self
.api
.compute
.flavors
.values():
231 if flavor
.id == server_dict
.get('flavorRef', ''):
232 server
.flavor
= flavor
.name
233 for image
in self
.api
.compute
.images
.values():
234 if image
.id in server_dict
['imageRef']:
235 server
.image
= image
.name
237 if networks
is not None:
239 port
= self
.api
.compute
.find_port_by_name_or_id(net
.get('port', ""))
241 server
.port_names
.append(port
.name
)
243 return Response("Currently only networking by port is supported.", status
=400)
245 self
.api
.compute
._start
_compute
(server
)
247 response
= NovaShowServerDetails(self
.api
).get(id, server
.id)
248 response
.headers
['Access-Control-Allow-Origin'] = '*'
251 except Exception as ex
:
252 LOG
.exception(u
"%s: Could not create the server." % __name__
)
253 return ex
.message
, 500
256 class NovaListServersAndPortsApi(Resource
):
257 def __init__(self
, api
):
262 Creates a list with all running servers and their detailed information. This function also presents all
263 port information of each server.
265 :param id: Used to create a individual link to quarry further information.
267 :return: Returns a json response with a dictionary that contains the server information.
268 :rtype: :class:`flask.response`
270 LOG
.debug("API CALL: %s GET" % str(self
.__class
__.__name
__))
274 resp
['servers'] = list()
275 for server
in self
.api
.compute
.computeUnits
.values():
276 s
= server
.create_server_dict(self
.api
.compute
)
277 s
['links'] = [{'href': "http://%s:%d/v2.1/%s/servers/%s" % (self
.api
.ip
,
283 for port_name
in server
.port_names
:
284 port
= self
.api
.compute
.find_port_by_name_or_id(port_name
)
288 tmp
= port
.create_port_dict(self
.api
.compute
)
289 tmp
['intf_name'] = port
.intf_name
290 s
['ports'].append(tmp
)
292 resp
['servers'].append(s
)
294 response
= Response(json
.dumps(resp
), status
=200, mimetype
="application/json")
295 response
.headers
['Access-Control-Allow-Origin'] = '*'
298 except Exception as ex
:
299 LOG
.exception(u
"%s: Could not retrieve the list of servers." % __name__
)
300 return ex
.message
, 500
303 class NovaListServersDetailed(Resource
):
304 def __init__(self
, api
):
309 As List Servers, it lists all running servers and their details but furthermore it also states the
310 used flavor and the server image.
312 :param id: tenant id, used for the 'href' link.
314 :return: Returns a flask response, with detailed information aboit the servers and their flavor and image.
315 :rtype: :class:`flask.response`
317 LOG
.debug("API CALL: %s GET" % str(self
.__class
__.__name
__))
320 resp
= {"servers": list()}
321 for server
in self
.api
.compute
.computeUnits
.values():
322 s
= server
.create_server_dict(self
.api
.compute
)
323 s
['links'] = [{'href': "http://%s:%d/v2.1/%s/servers/%s" % (self
.api
.ip
,
327 flavor
= self
.api
.compute
.flavors
[server
.flavor
]
332 "href": "http://%s:%d/v2.1/%s/flavors/%s" % (self
.api
.ip
,
340 image
= self
.api
.compute
.images
[server
.image
]
345 "href": "http://%s:%d/v2.1/%s/images/%s" % (self
.api
.ip
,
354 resp
['servers'].append(s
)
356 response
= Response(json
.dumps(resp
), status
=200, mimetype
="application/json")
357 response
.headers
['Access-Control-Allow-Origin'] = '*'
360 except Exception as ex
:
361 LOG
.exception(u
"%s: Could not retrieve the list of servers." % __name__
)
362 return ex
.message
, 500
365 class NovaListFlavors(Resource
):
366 def __init__(self
, api
):
371 Lists all available flavors.
373 :param id: tenant id, used for the 'href' link
375 :return: Returns a flask response with a list of all flavors.
376 :rtype: :class:`flask.response`
378 LOG
.debug("API CALL: %s GET" % str(self
.__class
__.__name
__))
381 resp
['flavors'] = list()
382 for flavor
in self
.api
.compute
.flavors
.values():
383 f
= flavor
.__dict
__.copy()
385 f
['name'] = flavor
.name
386 f
['links'] = [{'href': "http://%s:%d/v2.1/%s/flavors/%s" % (self
.api
.ip
,
390 resp
['flavors'].append(f
)
392 response
= Response(json
.dumps(resp
), status
=200, mimetype
="application/json")
393 response
.headers
['Access-Control-Allow-Origin'] = '*'
396 except Exception as ex
:
397 LOG
.exception(u
"%s: Could not retrieve the list of servers." % __name__
)
398 return ex
.message
, 500
401 LOG
.debug("API CALL: %s POST" % str(self
.__class
__.__name
__))
402 data
= json
.loads(request
.data
).get("flavor")
403 LOG
.warning("Create Flavor: %s" % str(data
))
404 # add to internal dict
405 f
= self
.api
.compute
.add_flavor(
408 data
.get("ram"), "MB",
409 data
.get("disk"), "GB")
410 # create response based on incoming data
412 data
["links"] = [{'href': "http://%s:%d/v2.1/%s/flavors/%s" % (self
.api
.ip
,
416 resp
= {"flavor": data
}
417 return Response(json
.dumps(resp
), status
=200, mimetype
="application/json")
420 class NovaListFlavorsDetails(Resource
):
421 def __init__(self
, api
):
426 Lists all flavors with additional information like ram and disk space.
428 :param id: tenant id, used for the 'href' link
430 :return: Returns a flask response with a list of all flavors with additional information.
431 :rtype: :class:`flask.response`
433 LOG
.debug("API CALL: %s GET" % str(self
.__class
__.__name
__))
436 resp
['flavors'] = list()
437 for flavor
in self
.api
.compute
.flavors
.values():
438 # use the class dict. it should work fine
439 # but use a copy so we don't modifiy the original
440 f
= flavor
.__dict
__.copy()
441 # add additional expected stuff stay openstack compatible
442 f
['links'] = [{'href': "http://%s:%d/v2.1/%s/flavors/%s" % (self
.api
.ip
,
446 f
['OS-FLV-DISABLED:disabled'] = False
447 f
['OS-FLV-EXT-DATA:ephemeral'] = 0
448 f
['os-flavor-access:is_public'] = True
449 f
['ram'] = flavor
.memory
450 f
['vcpus'] = flavor
.cpu
452 f
['disk'] = flavor
.storage
453 f
['rxtx_factor'] = 1.0
454 resp
['flavors'].append(f
)
456 response
= Response(json
.dumps(resp
), status
=200, mimetype
="application/json")
457 response
.headers
['Access-Control-Allow-Origin'] = '*'
460 except Exception as ex
:
461 LOG
.exception(u
"%s: Could not retrieve the list of servers." % __name__
)
462 return ex
.message
, 500
465 LOG
.debug("API CALL: %s POST" % str(self
.__class
__.__name
__))
466 data
= json
.loads(request
.data
).get("flavor")
467 LOG
.warning("Create Flavor: %s" % str(data
))
468 # add to internal dict
469 f
= self
.api
.compute
.add_flavor(
472 data
.get("ram"), "MB",
473 data
.get("disk"), "GB")
474 # create response based on incoming data
476 data
["links"] = [{'href': "http://%s:%d/v2.1/%s/flavors/%s" % (self
.api
.ip
,
480 resp
= {"flavor": data
}
481 return Response(json
.dumps(resp
), status
=200, mimetype
="application/json")
484 class NovaListFlavorById(Resource
):
485 def __init__(self
, api
):
488 def get(self
, id, flavorid
):
490 Returns details about one flavor.
492 :param id: tenant id, used for the 'href' link
494 :param flavorid: Represents the flavor.
495 :type flavorid: ``str``
496 :return: Returns a flask response with detailed information about the flavor.
497 :rtype: :class:`flask.response`
499 LOG
.debug("API CALL: %s GET" % str(self
.__class
__.__name
__))
502 resp
['flavor'] = dict()
503 flavor
= self
.api
.compute
.flavors
.get(flavorid
, None)
505 for f
in self
.api
.compute
.flavors
.values():
509 resp
['flavor']['id'] = flavor
.id
510 resp
['flavor']['name'] = flavor
.name
511 resp
['flavor']['links'] = [{'href': "http://%s:%d/v2.1/%s/flavors/%s" % (self
.api
.ip
,
515 response
= Response(json
.dumps(resp
), status
=200, mimetype
="application/json")
516 response
.headers
['Access-Control-Allow-Origin'] = '*'
519 except Exception as ex
:
520 LOG
.exception(u
"%s: Could not retrieve flavor with id %s" % (__name__
, flavorid
))
521 return ex
.message
, 500
523 def delete(self
, id, flavorid
):
525 Removes the given flavor.
526 Does not really remove anything from the machine, just fakes an OK.
528 LOG
.debug("API CALL: %s GET" % str(self
.__class
__.__name
__))
529 return Response("{}", status
=204, mimetype
="application/json")
532 class NovaListImages(Resource
):
533 def __init__(self
, api
):
538 Creates a list of all usable images.
540 :param id: tenant id, used for the 'href' link
542 :return: Returns a flask response with a list of available images.
543 :rtype: :class:`flask.response`
545 LOG
.debug("API CALL: %s GET" % str(self
.__class
__.__name
__))
548 resp
['images'] = list()
549 for image
in self
.api
.compute
.images
.values():
552 f
['name'] = str(image
.name
).replace(":latest", "")
553 f
['links'] = [{'href': "http://%s:%d/v2.1/%s/images/%s" % (self
.api
.ip
,
557 resp
['images'].append(f
)
558 response
= Response(json
.dumps(resp
), status
=200, mimetype
="application/json")
559 response
.headers
['Access-Control-Allow-Origin'] = '*'
562 except Exception as ex
:
563 LOG
.exception(u
"%s: Could not retrieve the list of images." % __name__
)
564 return ex
.message
, 500
567 class NovaListImagesDetails(Resource
):
568 def __init__(self
, api
):
573 As List Images but with additional metadata.
575 :param id: tenant id, used for the 'href' link
577 :return: Returns a flask response with a list of images and their metadata.
578 :rtype: :class:`flask.response`
580 LOG
.debug("API CALL: %s GET" % str(self
.__class
__.__name
__))
583 resp
['images'] = list()
584 for image
in self
.api
.compute
.images
.values():
585 # use the class dict. it should work fine
586 # but use a copy so we don't modifiy the original
587 f
= image
.__dict
__.copy()
588 # add additional expected stuff stay openstack compatible
589 f
['name'] = str(image
.name
).replace(":latest", "")
590 f
['links'] = [{'href': "http://%s:%d/v2.1/%s/images/%s" % (self
.api
.ip
,
595 "architecture": "x86_64",
596 "auto_disk_config": "True",
597 "kernel_id": "nokernel",
598 "ramdisk_id": "nokernel"
600 resp
['images'].append(f
)
602 response
= Response(json
.dumps(resp
), status
=200, mimetype
="application/json")
603 response
.headers
['Access-Control-Allow-Origin'] = '*'
606 except Exception as ex
:
607 LOG
.exception(u
"%s: Could not retrieve the list of images." % __name__
)
608 return ex
.message
, 500
611 class NovaListImageById(Resource
):
612 def __init__(self
, api
):
615 def get(self
, id, imageid
):
617 Gets an image by id from the emulator with openstack nova compliant return values.
619 :param id: tenantid, we ignore this most of the time
621 :param imageid: id of the image. If it is 1 the dummy CREATE-IMAGE is returned
622 :type imageid: ``str``
623 :return: Returns a flask response with the information about one image.
624 :rtype: :class:`flask.response`
626 LOG
.debug("API CALL: %s GET" % str(self
.__class
__.__name
__))
629 i
= resp
['image'] = dict()
630 for image
in self
.api
.compute
.images
.values():
631 if image
.id == imageid
or image
.name
== imageid
:
633 i
['name'] = image
.name
635 return Response(json
.dumps(resp
), status
=200, mimetype
="application/json")
637 response
= Response("Image with id or name %s does not exists." % imageid
, status
=404)
638 response
.headers
['Access-Control-Allow-Origin'] = '*'
641 except Exception as ex
:
642 LOG
.exception(u
"%s: Could not retrieve image with id %s." % (__name__
, imageid
))
643 return ex
.message
, 500
645 def delete(self
, id, imageid
):
647 Removes the given image.
648 Does not really remove anything from the machine, just fakes an OK.
650 LOG
.debug("API CALL: %s GET" % str(self
.__class
__.__name
__))
651 return Response("{}", status
=204, mimetype
="application/json")
654 class NovaShowServerDetails(Resource
):
655 def __init__(self
, api
):
658 def get(self
, id, serverid
):
660 Returns detailed information about the specified server.
662 :param id: tenant id, used for the 'href' link
664 :param serverid: Specifies the requested server.
665 :type serverid: ``str``
666 :return: Returns a flask response with details about the server.
667 :rtype: :class:`flask.response`
669 LOG
.debug("API CALL: %s GET" % str(self
.__class
__.__name
__))
671 server
= self
.api
.compute
.find_server_by_name_or_id(serverid
)
673 return Response("Server with id or name %s does not exists." % serverid
, status
=404)
674 s
= server
.create_server_dict()
675 s
['links'] = [{'href': "http://%s:%d/v2.1/%s/servers/%s" % (self
.api
.ip
,
680 flavor
= self
.api
.compute
.flavors
[server
.flavor
]
685 "href": "http://%s:%d/v2.1/%s/flavors/%s" % (self
.api
.ip
,
693 image
= self
.api
.compute
.images
[server
.image
]
698 "href": "http://%s:%d/v2.1/%s/images/%s" % (self
.api
.ip
,
707 response
= Response(json
.dumps({'server': s
}), status
=200, mimetype
="application/json")
708 response
.headers
['Access-Control-Allow-Origin'] = '*'
711 except Exception as ex
:
712 LOG
.exception(u
"%s: Could not retrieve the server details." % __name__
)
713 return ex
.message
, 500
715 def delete(self
, id, serverid
):
717 Delete a server instance.
719 :param id: tenant id, we ignore this most of the time
721 :param serverid: The UUID of the server
722 :type serverid: ``str``
723 :return: Returns 200 if everything is fine.
724 :rtype: :class:`flask.response`
726 LOG
.debug("API CALL: %s POST" % str(self
.__class
__.__name
__))
728 server
= self
.api
.compute
.find_server_by_name_or_id(serverid
)
730 return Response('Could not find server.', status
=404, mimetype
="application/json")
732 self
.api
.compute
.stop_compute(server
)
734 response
= Response('Server deleted.', status
=204, mimetype
="application/json")
735 response
.headers
['Access-Control-Allow-Origin'] = '*'
738 except Exception as ex
:
739 LOG
.exception(u
"%s: Could not create the server." % __name__
)
740 return ex
.message
, 500
743 class NovaInterfaceToServer(Resource
):
744 def __init__(self
, api
):
747 def post(self
, id, serverid
):
749 Add an interface to the specified server.
751 :param id: tenant id, we ignore this most of the time
753 :param serverid: Specifies the server.
754 :type serverid: ``str``
755 :return: Returns a flask response with information about the attached interface.
756 :rtype: :class:`flask.response`
758 LOG
.debug("API CALL: %s GET" % str(self
.__class
__.__name
__))
760 server
= self
.api
.compute
.find_server_by_name_or_id(serverid
)
762 return Response("Server with id or name %s does not exists." % serverid
, status
=404)
764 if server
.emulator_compute
is None:
765 LOG
.error("The targeted container does not exist.")
766 return Response("The targeted container of %s does not exist." % serverid
, status
=404)
767 data
= json
.loads(request
.data
).get("interfaceAttachment")
769 port
= data
.get("port_id", None)
770 net
= data
.get("net_id", None)
771 dc
= self
.api
.compute
.dc
772 network_dict
= dict()
775 if net
is not None and port
is not None:
776 port
= self
.api
.compute
.find_port_by_name_or_id(port
)
777 network
= self
.api
.compute
.find_network_by_name_or_id(net
)
778 network_dict
['id'] = port
.intf_name
779 network_dict
['ip'] = port
.ip_address
780 network_dict
[network_dict
['id']] = network
.name
781 elif net
is not None:
782 network
= self
.api
.compute
.find_network_by_name_or_id(net
)
784 return Response("Network with id or name %s does not exists." % net
, status
=404)
785 port
= self
.api
.compute
.create_port("port:cp%s:fl:%s" %
786 (len(self
.api
.compute
.ports
), str(uuid
.uuid4())))
788 port
.net_name
= network
.name
789 port
.ip_address
= network
.get_new_ip_address(port
.name
)
790 network_dict
['id'] = port
.intf_name
791 network_dict
['ip'] = port
.ip_address
792 network_dict
[network_dict
['id']] = network
.name
793 elif port
is not None:
794 port
= self
.api
.compute
.find_port_by_name_or_id(port
)
795 network_dict
['id'] = port
.intf_name
796 network_dict
['ip'] = port
.ip_address
797 network
= self
.api
.compute
.find_network_by_name_or_id(port
.net_name
)
798 network_dict
[network_dict
['id']] = network
.name
800 raise Exception("You can only attach interfaces by port or network at the moment")
802 if network
== self
.api
.manage
.floating_network
:
803 dc
.net
.addLink(server
.emulator_compute
, self
.api
.manage
.floating_switch
,
804 params1
=network_dict
, cls
=Link
, intfName1
=port
.intf_name
)
806 dc
.net
.addLink(server
.emulator_compute
, dc
.switch
,
807 params1
=network_dict
, cls
=Link
, intfName1
=port
.intf_name
)
808 resp
["port_state"] = "ACTIVE"
809 resp
["port_id"] = port
.id
810 resp
["net_id"] = self
.api
.compute
.find_network_by_name_or_id(port
.net_name
).id
811 resp
["mac_addr"] = port
.mac_address
812 resp
["fixed_ips"] = list()
814 fixed_ips
["ip_address"] = port
.ip_address
815 fixed_ips
["subnet_id"] = network
.subnet_name
816 resp
["fixed_ips"].append(fixed_ips
)
817 response
= Response(json
.dumps({"interfaceAttachment": resp
}), status
=202, mimetype
="application/json")
818 response
.headers
['Access-Control-Allow-Origin'] = '*'
821 except Exception as ex
:
822 LOG
.exception(u
"%s: Could not add interface to the server." % __name__
)
823 return ex
.message
, 500
826 class NovaShowAndDeleteInterfaceAtServer(Resource
):
827 def __init__(self
, api
):
830 def delete(self
, id, serverid
, port_id
):
832 Deletes an existing interface.
834 :param id: tenant id, we ignore this most of the time
836 :param serverid: Specifies the server, where the interface will be deleted.
837 :type serverid: ``str``
838 :param port_id: Specifies the port of the interface.
839 :type port_id: ``str``
840 :return: Returns a flask response with 202 if everything worked out. Otherwise it will return 404 and an
842 :rtype: :class:`flask.response`
844 LOG
.debug("API CALL: %s GET" % str(self
.__class
__.__name
__))
846 server
= self
.api
.compute
.find_server_by_name_or_id(serverid
)
848 return Response("Server with id or name %s does not exists." % serverid
, status
=404)
849 port
= self
.api
.compute
.find_port_by_name_or_id(port_id
)
851 return Response("Port with id or name %s does not exists." % port_id
, status
=404)
853 for link
in self
.api
.compute
.dc
.net
.links
:
854 if str(link
.intf1
) == port
.intf_name
and \
855 str(link
.intf1
.ip
) == port
.ip_address
.split('/')[0]:
856 self
.api
.compute
.dc
.net
.removeLink(link
)
859 response
= Response("", status
=202, mimetype
="application/json")
860 response
.headers
['Access-Control-Allow-Origin'] = '*'
863 except Exception as ex
:
864 LOG
.exception(u
"%s: Could not detach interface from the server." % __name__
)
865 return ex
.message
, 500
868 class NovaLimits(Resource
):
869 def __init__(self
, api
):
874 Returns the resource limits of the emulated cloud.
875 https://developer.openstack.org/api-ref/compute/?expanded=show-rate-and-absolute-limits-detail#limits-limits
877 TODO: For now we only return fixed limits, not based on the real deployment.
879 :param id: tenant id, used for the 'href' link
881 :return: Returns the resource limits.
882 :rtype: :class:`flask.response`
884 LOG
.debug("API CALL: %s GET" % str(self
.__class
__.__name
__))
889 "maxImageMeta": 12800,
890 "maxPersonality": 500,
891 "maxPersonalitySize": 1024000,
892 "maxSecurityGroupRules": 2000,
893 "maxSecurityGroups": 1000,
894 "maxServerMeta": 12800,
895 "maxTotalCores": 2000,
896 "maxTotalFloatingIps": 1000,
897 "maxTotalInstances": 1000,
898 "maxTotalKeypairs": 1000,
899 "maxTotalRAMSize": 5120000,
900 "maxServerGroups": 1000,
901 "maxServerGroupMembers": 1000,
903 "totalInstancesUsed": 0,
905 "totalSecurityGroupsUsed": 0,
906 "totalFloatingIpsUsed": 0,
907 "totalServerGroupsUsed": 0
912 response
= Response(json
.dumps(resp
), status
=200, mimetype
="application/json")
913 response
.headers
['Access-Control-Allow-Origin'] = '*'
916 except Exception as ex
:
917 LOG
.exception(u
"%s: Could not retrieve the list of images." % __name__
)
918 return ex
.message
, 500