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
524 class NovaListImages(Resource
):
525 def __init__(self
, api
):
530 Creates a list of all usable images.
532 :param id: tenant id, used for the 'href' link
534 :return: Returns a flask response with a list of available images.
535 :rtype: :class:`flask.response`
537 LOG
.debug("API CALL: %s GET" % str(self
.__class
__.__name
__))
540 resp
['images'] = list()
541 for image
in self
.api
.compute
.images
.values():
544 f
['name'] = str(image
.name
).replace(":latest", "")
545 f
['links'] = [{'href': "http://%s:%d/v2.1/%s/images/%s" % (self
.api
.ip
,
549 resp
['images'].append(f
)
550 response
= Response(json
.dumps(resp
), status
=200, mimetype
="application/json")
551 response
.headers
['Access-Control-Allow-Origin'] = '*'
554 except Exception as ex
:
555 LOG
.exception(u
"%s: Could not retrieve the list of images." % __name__
)
556 return ex
.message
, 500
559 class NovaListImagesDetails(Resource
):
560 def __init__(self
, api
):
565 As List Images but with additional metadata.
567 :param id: tenant id, used for the 'href' link
569 :return: Returns a flask response with a list of images and their metadata.
570 :rtype: :class:`flask.response`
572 LOG
.debug("API CALL: %s GET" % str(self
.__class
__.__name
__))
575 resp
['images'] = list()
576 for image
in self
.api
.compute
.images
.values():
577 # use the class dict. it should work fine
578 # but use a copy so we don't modifiy the original
579 f
= image
.__dict
__.copy()
580 # add additional expected stuff stay openstack compatible
581 f
['name'] = str(image
.name
).replace(":latest", "")
582 f
['links'] = [{'href': "http://%s:%d/v2.1/%s/images/%s" % (self
.api
.ip
,
587 "architecture": "x86_64",
588 "auto_disk_config": "True",
589 "kernel_id": "nokernel",
590 "ramdisk_id": "nokernel"
592 resp
['images'].append(f
)
594 response
= Response(json
.dumps(resp
), status
=200, mimetype
="application/json")
595 response
.headers
['Access-Control-Allow-Origin'] = '*'
598 except Exception as ex
:
599 LOG
.exception(u
"%s: Could not retrieve the list of images." % __name__
)
600 return ex
.message
, 500
603 class NovaListImageById(Resource
):
604 def __init__(self
, api
):
607 def get(self
, id, imageid
):
609 Gets an image by id from the emulator with openstack nova compliant return values.
611 :param id: tenantid, we ignore this most of the time
613 :param imageid: id of the image. If it is 1 the dummy CREATE-IMAGE is returned
614 :type imageid: ``str``
615 :return: Returns a flask response with the information about one image.
616 :rtype: :class:`flask.response`
618 LOG
.debug("API CALL: %s GET" % str(self
.__class
__.__name
__))
621 i
= resp
['image'] = dict()
622 for image
in self
.api
.compute
.images
.values():
623 if image
.id == imageid
or image
.name
== imageid
:
625 i
['name'] = image
.name
627 return Response(json
.dumps(resp
), status
=200, mimetype
="application/json")
629 response
= Response("Image with id or name %s does not exists." % imageid
, status
=404)
630 response
.headers
['Access-Control-Allow-Origin'] = '*'
633 except Exception as ex
:
634 LOG
.exception(u
"%s: Could not retrieve image with id %s." % (__name__
, imageid
))
635 return ex
.message
, 500
638 class NovaShowServerDetails(Resource
):
639 def __init__(self
, api
):
642 def get(self
, id, serverid
):
644 Returns detailed information about the specified server.
646 :param id: tenant id, used for the 'href' link
648 :param serverid: Specifies the requested server.
649 :type serverid: ``str``
650 :return: Returns a flask response with details about the server.
651 :rtype: :class:`flask.response`
653 LOG
.debug("API CALL: %s GET" % str(self
.__class
__.__name
__))
655 server
= self
.api
.compute
.find_server_by_name_or_id(serverid
)
657 return Response("Server with id or name %s does not exists." % serverid
, status
=404)
658 s
= server
.create_server_dict()
659 s
['links'] = [{'href': "http://%s:%d/v2.1/%s/servers/%s" % (self
.api
.ip
,
664 flavor
= self
.api
.compute
.flavors
[server
.flavor
]
669 "href": "http://%s:%d/v2.1/%s/flavors/%s" % (self
.api
.ip
,
677 image
= self
.api
.compute
.images
[server
.image
]
682 "href": "http://%s:%d/v2.1/%s/images/%s" % (self
.api
.ip
,
691 response
= Response(json
.dumps({'server': s
}), status
=200, mimetype
="application/json")
692 response
.headers
['Access-Control-Allow-Origin'] = '*'
695 except Exception as ex
:
696 LOG
.exception(u
"%s: Could not retrieve the server details." % __name__
)
697 return ex
.message
, 500
699 def delete(self
, id, serverid
):
701 Delete a server instance.
703 :param id: tenant id, we ignore this most of the time
705 :param serverid: The UUID of the server
706 :type serverid: ``str``
707 :return: Returns 200 if everything is fine.
708 :rtype: :class:`flask.response`
710 LOG
.debug("API CALL: %s POST" % str(self
.__class
__.__name
__))
712 server
= self
.api
.compute
.find_server_by_name_or_id(serverid
)
714 return Response('Could not find server.', status
=404, mimetype
="application/json")
716 self
.api
.compute
.stop_compute(server
)
718 response
= Response('Server deleted.', status
=204, mimetype
="application/json")
719 response
.headers
['Access-Control-Allow-Origin'] = '*'
722 except Exception as ex
:
723 LOG
.exception(u
"%s: Could not create the server." % __name__
)
724 return ex
.message
, 500
727 class NovaInterfaceToServer(Resource
):
728 def __init__(self
, api
):
731 def post(self
, id, serverid
):
733 Add an interface to the specified server.
735 :param id: tenant id, we ignore this most of the time
737 :param serverid: Specifies the server.
738 :type serverid: ``str``
739 :return: Returns a flask response with information about the attached interface.
740 :rtype: :class:`flask.response`
742 LOG
.debug("API CALL: %s GET" % str(self
.__class
__.__name
__))
744 server
= self
.api
.compute
.find_server_by_name_or_id(serverid
)
746 return Response("Server with id or name %s does not exists." % serverid
, status
=404)
748 if server
.emulator_compute
is None:
749 LOG
.error("The targeted container does not exist.")
750 return Response("The targeted container of %s does not exist." % serverid
, status
=404)
751 data
= json
.loads(request
.data
).get("interfaceAttachment")
753 port
= data
.get("port_id", None)
754 net
= data
.get("net_id", None)
755 dc
= self
.api
.compute
.dc
756 network_dict
= dict()
759 if net
is not None and port
is not None:
760 port
= self
.api
.compute
.find_port_by_name_or_id(port
)
761 network
= self
.api
.compute
.find_network_by_name_or_id(net
)
762 network_dict
['id'] = port
.intf_name
763 network_dict
['ip'] = port
.ip_address
764 network_dict
[network_dict
['id']] = network
.name
765 elif net
is not None:
766 network
= self
.api
.compute
.find_network_by_name_or_id(net
)
768 return Response("Network with id or name %s does not exists." % net
, status
=404)
769 port
= self
.api
.compute
.create_port("port:cp%s:fl:%s" %
770 (len(self
.api
.compute
.ports
), str(uuid
.uuid4())))
772 port
.net_name
= network
.name
773 port
.ip_address
= network
.get_new_ip_address(port
.name
)
774 network_dict
['id'] = port
.intf_name
775 network_dict
['ip'] = port
.ip_address
776 network_dict
[network_dict
['id']] = network
.name
777 elif port
is not None:
778 port
= self
.api
.compute
.find_port_by_name_or_id(port
)
779 network_dict
['id'] = port
.intf_name
780 network_dict
['ip'] = port
.ip_address
781 network
= self
.api
.compute
.find_network_by_name_or_id(port
.net_name
)
782 network_dict
[network_dict
['id']] = network
.name
784 raise Exception("You can only attach interfaces by port or network at the moment")
786 if network
== self
.api
.manage
.floating_network
:
787 dc
.net
.addLink(server
.emulator_compute
, self
.api
.manage
.floating_switch
,
788 params1
=network_dict
, cls
=Link
, intfName1
=port
.intf_name
)
790 dc
.net
.addLink(server
.emulator_compute
, dc
.switch
,
791 params1
=network_dict
, cls
=Link
, intfName1
=port
.intf_name
)
792 resp
["port_state"] = "ACTIVE"
793 resp
["port_id"] = port
.id
794 resp
["net_id"] = self
.api
.compute
.find_network_by_name_or_id(port
.net_name
).id
795 resp
["mac_addr"] = port
.mac_address
796 resp
["fixed_ips"] = list()
798 fixed_ips
["ip_address"] = port
.ip_address
799 fixed_ips
["subnet_id"] = network
.subnet_name
800 resp
["fixed_ips"].append(fixed_ips
)
801 response
= Response(json
.dumps({"interfaceAttachment": resp
}), status
=202, mimetype
="application/json")
802 response
.headers
['Access-Control-Allow-Origin'] = '*'
805 except Exception as ex
:
806 LOG
.exception(u
"%s: Could not add interface to the server." % __name__
)
807 return ex
.message
, 500
810 class NovaShowAndDeleteInterfaceAtServer(Resource
):
811 def __init__(self
, api
):
814 def delete(self
, id, serverid
, port_id
):
816 Deletes an existing interface.
818 :param id: tenant id, we ignore this most of the time
820 :param serverid: Specifies the server, where the interface will be deleted.
821 :type serverid: ``str``
822 :param port_id: Specifies the port of the interface.
823 :type port_id: ``str``
824 :return: Returns a flask response with 202 if everything worked out. Otherwise it will return 404 and an
826 :rtype: :class:`flask.response`
828 LOG
.debug("API CALL: %s GET" % str(self
.__class
__.__name
__))
830 server
= self
.api
.compute
.find_server_by_name_or_id(serverid
)
832 return Response("Server with id or name %s does not exists." % serverid
, status
=404)
833 port
= self
.api
.compute
.find_port_by_name_or_id(port_id
)
835 return Response("Port with id or name %s does not exists." % port_id
, status
=404)
837 for link
in self
.api
.compute
.dc
.net
.links
:
838 if str(link
.intf1
) == port
.intf_name
and \
839 str(link
.intf1
.ip
) == port
.ip_address
.split('/')[0]:
840 self
.api
.compute
.dc
.net
.removeLink(link
)
843 response
= Response("", status
=202, mimetype
="application/json")
844 response
.headers
['Access-Control-Allow-Origin'] = '*'
847 except Exception as ex
:
848 LOG
.exception(u
"%s: Could not detach interface from the server." % __name__
)
849 return ex
.message
, 500
852 class NovaLimits(Resource
):
853 def __init__(self
, api
):
858 Returns the resource limits of the emulated cloud.
859 https://developer.openstack.org/api-ref/compute/?expanded=show-rate-and-absolute-limits-detail#limits-limits
861 TODO: For now we only return fixed limits, not based on the real deployment.
863 :param id: tenant id, used for the 'href' link
865 :return: Returns the resource limits.
866 :rtype: :class:`flask.response`
868 LOG
.debug("API CALL: %s GET" % str(self
.__class
__.__name
__))
873 "maxImageMeta": 12800,
874 "maxPersonality": 500,
875 "maxPersonalitySize": 1024000,
876 "maxSecurityGroupRules": 2000,
877 "maxSecurityGroups": 1000,
878 "maxServerMeta": 12800,
879 "maxTotalCores": 2000,
880 "maxTotalFloatingIps": 1000,
881 "maxTotalInstances": 1000,
882 "maxTotalKeypairs": 1000,
883 "maxTotalRAMSize": 5120000,
884 "maxServerGroups": 1000,
885 "maxServerGroupMembers": 1000,
887 "totalInstancesUsed": 0,
889 "totalSecurityGroupsUsed": 0,
890 "totalFloatingIpsUsed": 0,
891 "totalServerGroupsUsed": 0
896 response
= Response(json
.dumps(resp
), status
=200, mimetype
="application/json")
897 response
.headers
['Access-Control-Allow-Origin'] = '*'
900 except Exception as ex
:
901 LOG
.exception(u
"%s: Could not retrieve the list of images." % __name__
)
902 return ex
.message
, 500