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"]
229 if "metadata" in server_dict
:
230 server
.properties
= server_dict
["metadata"]
232 for flavor
in self
.api
.compute
.flavors
.values():
233 if flavor
.id == server_dict
.get('flavorRef', ''):
234 server
.flavor
= flavor
.name
235 for image
in self
.api
.compute
.images
.values():
236 if image
.id in server_dict
['imageRef']:
237 server
.image
= image
.name
239 if networks
is not None:
241 port
= self
.api
.compute
.find_port_by_name_or_id(net
.get('port', ""))
243 server
.port_names
.append(port
.name
)
245 return Response("Currently only networking by port is supported.", status
=400)
247 self
.api
.compute
._start
_compute
(server
)
249 response
= NovaShowServerDetails(self
.api
).get(id, server
.id)
250 response
.headers
['Access-Control-Allow-Origin'] = '*'
253 except Exception as ex
:
254 LOG
.exception(u
"%s: Could not create the server." % __name__
)
255 return ex
.message
, 500
258 class NovaListServersAndPortsApi(Resource
):
259 def __init__(self
, api
):
264 Creates a list with all running servers and their detailed information. This function also presents all
265 port information of each server.
267 :param id: Used to create a individual link to quarry further information.
269 :return: Returns a json response with a dictionary that contains the server information.
270 :rtype: :class:`flask.response`
272 LOG
.debug("API CALL: %s GET" % str(self
.__class
__.__name
__))
276 resp
['servers'] = list()
277 for server
in self
.api
.compute
.computeUnits
.values():
278 s
= server
.create_server_dict(self
.api
.compute
)
279 s
['links'] = [{'href': "http://%s:%d/v2.1/%s/servers/%s" % (self
.api
.ip
,
285 for port_name
in server
.port_names
:
286 port
= self
.api
.compute
.find_port_by_name_or_id(port_name
)
290 tmp
= port
.create_port_dict(self
.api
.compute
)
291 tmp
['intf_name'] = port
.intf_name
292 s
['ports'].append(tmp
)
294 resp
['servers'].append(s
)
296 response
= Response(json
.dumps(resp
), status
=200, mimetype
="application/json")
297 response
.headers
['Access-Control-Allow-Origin'] = '*'
300 except Exception as ex
:
301 LOG
.exception(u
"%s: Could not retrieve the list of servers." % __name__
)
302 return ex
.message
, 500
305 class NovaListServersDetailed(Resource
):
306 def __init__(self
, api
):
311 As List Servers, it lists all running servers and their details but furthermore it also states the
312 used flavor and the server image.
314 :param id: tenant id, used for the 'href' link.
316 :return: Returns a flask response, with detailed information aboit the servers and their flavor and image.
317 :rtype: :class:`flask.response`
319 LOG
.debug("API CALL: %s GET" % str(self
.__class
__.__name
__))
322 resp
= {"servers": list()}
323 for server
in self
.api
.compute
.computeUnits
.values():
324 s
= server
.create_server_dict(self
.api
.compute
)
325 s
['links'] = [{'href': "http://%s:%d/v2.1/%s/servers/%s" % (self
.api
.ip
,
329 flavor
= self
.api
.compute
.flavors
[server
.flavor
]
334 "href": "http://%s:%d/v2.1/%s/flavors/%s" % (self
.api
.ip
,
342 image
= self
.api
.compute
.images
[server
.image
]
347 "href": "http://%s:%d/v2.1/%s/images/%s" % (self
.api
.ip
,
356 resp
['servers'].append(s
)
358 response
= Response(json
.dumps(resp
), status
=200, mimetype
="application/json")
359 response
.headers
['Access-Control-Allow-Origin'] = '*'
362 except Exception as ex
:
363 LOG
.exception(u
"%s: Could not retrieve the list of servers." % __name__
)
364 return ex
.message
, 500
367 class NovaListFlavors(Resource
):
368 def __init__(self
, api
):
373 Lists all available flavors.
375 :param id: tenant id, used for the 'href' link
377 :return: Returns a flask response with a list of all flavors.
378 :rtype: :class:`flask.response`
380 LOG
.debug("API CALL: %s GET" % str(self
.__class
__.__name
__))
383 resp
['flavors'] = list()
384 for flavor
in self
.api
.compute
.flavors
.values():
385 f
= flavor
.__dict
__.copy()
387 f
['name'] = flavor
.name
388 f
['links'] = [{'href': "http://%s:%d/v2.1/%s/flavors/%s" % (self
.api
.ip
,
392 resp
['flavors'].append(f
)
394 response
= Response(json
.dumps(resp
), status
=200, mimetype
="application/json")
395 response
.headers
['Access-Control-Allow-Origin'] = '*'
398 except Exception as ex
:
399 LOG
.exception(u
"%s: Could not retrieve the list of servers." % __name__
)
400 return ex
.message
, 500
403 LOG
.debug("API CALL: %s POST" % str(self
.__class
__.__name
__))
404 data
= json
.loads(request
.data
).get("flavor")
405 LOG
.warning("Create Flavor: %s" % str(data
))
406 # add to internal dict
407 f
= self
.api
.compute
.add_flavor(
410 data
.get("ram"), "MB",
411 data
.get("disk"), "GB")
412 # create response based on incoming data
414 data
["links"] = [{'href': "http://%s:%d/v2.1/%s/flavors/%s" % (self
.api
.ip
,
418 resp
= {"flavor": data
}
419 return Response(json
.dumps(resp
), status
=200, mimetype
="application/json")
422 class NovaListFlavorsDetails(Resource
):
423 def __init__(self
, api
):
428 Lists all flavors with additional information like ram and disk space.
430 :param id: tenant id, used for the 'href' link
432 :return: Returns a flask response with a list of all flavors with additional information.
433 :rtype: :class:`flask.response`
435 LOG
.debug("API CALL: %s GET" % str(self
.__class
__.__name
__))
438 resp
['flavors'] = list()
439 for flavor
in self
.api
.compute
.flavors
.values():
440 # use the class dict. it should work fine
441 # but use a copy so we don't modifiy the original
442 f
= flavor
.__dict
__.copy()
443 # add additional expected stuff stay openstack compatible
444 f
['links'] = [{'href': "http://%s:%d/v2.1/%s/flavors/%s" % (self
.api
.ip
,
448 f
['OS-FLV-DISABLED:disabled'] = False
449 f
['OS-FLV-EXT-DATA:ephemeral'] = 0
450 f
['os-flavor-access:is_public'] = True
451 f
['ram'] = flavor
.memory
452 f
['vcpus'] = flavor
.cpu
454 f
['disk'] = flavor
.storage
455 f
['rxtx_factor'] = 1.0
456 resp
['flavors'].append(f
)
458 response
= Response(json
.dumps(resp
), status
=200, mimetype
="application/json")
459 response
.headers
['Access-Control-Allow-Origin'] = '*'
462 except Exception as ex
:
463 LOG
.exception(u
"%s: Could not retrieve the list of servers." % __name__
)
464 return ex
.message
, 500
467 LOG
.debug("API CALL: %s POST" % str(self
.__class
__.__name
__))
468 data
= json
.loads(request
.data
).get("flavor")
469 LOG
.warning("Create Flavor: %s" % str(data
))
470 # add to internal dict
471 f
= self
.api
.compute
.add_flavor(
474 data
.get("ram"), "MB",
475 data
.get("disk"), "GB")
476 # create response based on incoming data
478 data
["links"] = [{'href': "http://%s:%d/v2.1/%s/flavors/%s" % (self
.api
.ip
,
482 resp
= {"flavor": data
}
483 return Response(json
.dumps(resp
), status
=200, mimetype
="application/json")
486 class NovaListFlavorById(Resource
):
487 def __init__(self
, api
):
490 def get(self
, id, flavorid
):
492 Returns details about one flavor.
494 :param id: tenant id, used for the 'href' link
496 :param flavorid: Represents the flavor.
497 :type flavorid: ``str``
498 :return: Returns a flask response with detailed information about the flavor.
499 :rtype: :class:`flask.response`
501 LOG
.debug("API CALL: %s GET" % str(self
.__class
__.__name
__))
504 resp
['flavor'] = dict()
505 flavor
= self
.api
.compute
.flavors
.get(flavorid
, None)
507 for f
in self
.api
.compute
.flavors
.values():
511 resp
['flavor']['id'] = flavor
.id
512 resp
['flavor']['name'] = flavor
.name
513 resp
['flavor']['links'] = [{'href': "http://%s:%d/v2.1/%s/flavors/%s" % (self
.api
.ip
,
517 response
= Response(json
.dumps(resp
), status
=200, mimetype
="application/json")
518 response
.headers
['Access-Control-Allow-Origin'] = '*'
521 except Exception as ex
:
522 LOG
.exception(u
"%s: Could not retrieve flavor with id %s" % (__name__
, flavorid
))
523 return ex
.message
, 500
526 class NovaListImages(Resource
):
527 def __init__(self
, api
):
532 Creates a list of all usable images.
534 :param id: tenant id, used for the 'href' link
536 :return: Returns a flask response with a list of available images.
537 :rtype: :class:`flask.response`
539 LOG
.debug("API CALL: %s GET" % str(self
.__class
__.__name
__))
542 resp
['images'] = list()
543 for image
in self
.api
.compute
.images
.values():
546 f
['name'] = str(image
.name
).replace(":latest", "")
547 f
['links'] = [{'href': "http://%s:%d/v2.1/%s/images/%s" % (self
.api
.ip
,
551 resp
['images'].append(f
)
552 response
= Response(json
.dumps(resp
), status
=200, mimetype
="application/json")
553 response
.headers
['Access-Control-Allow-Origin'] = '*'
556 except Exception as ex
:
557 LOG
.exception(u
"%s: Could not retrieve the list of images." % __name__
)
558 return ex
.message
, 500
561 class NovaListImagesDetails(Resource
):
562 def __init__(self
, api
):
567 As List Images but with additional metadata.
569 :param id: tenant id, used for the 'href' link
571 :return: Returns a flask response with a list of images and their metadata.
572 :rtype: :class:`flask.response`
574 LOG
.debug("API CALL: %s GET" % str(self
.__class
__.__name
__))
577 resp
['images'] = list()
578 for image
in self
.api
.compute
.images
.values():
579 # use the class dict. it should work fine
580 # but use a copy so we don't modifiy the original
581 f
= image
.__dict
__.copy()
582 # add additional expected stuff stay openstack compatible
583 f
['name'] = str(image
.name
).replace(":latest", "")
584 f
['links'] = [{'href': "http://%s:%d/v2.1/%s/images/%s" % (self
.api
.ip
,
589 "architecture": "x86_64",
590 "auto_disk_config": "True",
591 "kernel_id": "nokernel",
592 "ramdisk_id": "nokernel"
594 resp
['images'].append(f
)
596 response
= Response(json
.dumps(resp
), status
=200, mimetype
="application/json")
597 response
.headers
['Access-Control-Allow-Origin'] = '*'
600 except Exception as ex
:
601 LOG
.exception(u
"%s: Could not retrieve the list of images." % __name__
)
602 return ex
.message
, 500
605 class NovaListImageById(Resource
):
606 def __init__(self
, api
):
609 def get(self
, id, imageid
):
611 Gets an image by id from the emulator with openstack nova compliant return values.
613 :param id: tenantid, we ignore this most of the time
615 :param imageid: id of the image. If it is 1 the dummy CREATE-IMAGE is returned
616 :type imageid: ``str``
617 :return: Returns a flask response with the information about one image.
618 :rtype: :class:`flask.response`
620 LOG
.debug("API CALL: %s GET" % str(self
.__class
__.__name
__))
623 i
= resp
['image'] = dict()
624 for image
in self
.api
.compute
.images
.values():
625 if image
.id == imageid
or image
.name
== imageid
:
627 i
['name'] = image
.name
629 return Response(json
.dumps(resp
), status
=200, mimetype
="application/json")
631 response
= Response("Image with id or name %s does not exists." % imageid
, status
=404)
632 response
.headers
['Access-Control-Allow-Origin'] = '*'
635 except Exception as ex
:
636 LOG
.exception(u
"%s: Could not retrieve image with id %s." % (__name__
, imageid
))
637 return ex
.message
, 500
640 class NovaShowServerDetails(Resource
):
641 def __init__(self
, api
):
644 def get(self
, id, serverid
):
646 Returns detailed information about the specified server.
648 :param id: tenant id, used for the 'href' link
650 :param serverid: Specifies the requested server.
651 :type serverid: ``str``
652 :return: Returns a flask response with details about the server.
653 :rtype: :class:`flask.response`
655 LOG
.debug("API CALL: %s GET" % str(self
.__class
__.__name
__))
657 server
= self
.api
.compute
.find_server_by_name_or_id(serverid
)
659 return Response("Server with id or name %s does not exists." % serverid
, status
=404)
660 s
= server
.create_server_dict()
661 s
['links'] = [{'href': "http://%s:%d/v2.1/%s/servers/%s" % (self
.api
.ip
,
666 flavor
= self
.api
.compute
.flavors
[server
.flavor
]
671 "href": "http://%s:%d/v2.1/%s/flavors/%s" % (self
.api
.ip
,
679 image
= self
.api
.compute
.images
[server
.image
]
684 "href": "http://%s:%d/v2.1/%s/images/%s" % (self
.api
.ip
,
693 response
= Response(json
.dumps({'server': s
}), status
=200, mimetype
="application/json")
694 response
.headers
['Access-Control-Allow-Origin'] = '*'
697 except Exception as ex
:
698 LOG
.exception(u
"%s: Could not retrieve the server details." % __name__
)
699 return ex
.message
, 500
701 def delete(self
, id, serverid
):
703 Delete a server instance.
705 :param id: tenant id, we ignore this most of the time
707 :param serverid: The UUID of the server
708 :type serverid: ``str``
709 :return: Returns 200 if everything is fine.
710 :rtype: :class:`flask.response`
712 LOG
.debug("API CALL: %s POST" % str(self
.__class
__.__name
__))
714 server
= self
.api
.compute
.find_server_by_name_or_id(serverid
)
716 return Response('Could not find server.', status
=404, mimetype
="application/json")
718 self
.api
.compute
.stop_compute(server
)
720 response
= Response('Server deleted.', status
=204, mimetype
="application/json")
721 response
.headers
['Access-Control-Allow-Origin'] = '*'
724 except Exception as ex
:
725 LOG
.exception(u
"%s: Could not create the server." % __name__
)
726 return ex
.message
, 500
729 class NovaInterfaceToServer(Resource
):
730 def __init__(self
, api
):
733 def post(self
, id, serverid
):
735 Add an interface to the specified server.
737 :param id: tenant id, we ignore this most of the time
739 :param serverid: Specifies the server.
740 :type serverid: ``str``
741 :return: Returns a flask response with information about the attached interface.
742 :rtype: :class:`flask.response`
744 LOG
.debug("API CALL: %s GET" % str(self
.__class
__.__name
__))
746 server
= self
.api
.compute
.find_server_by_name_or_id(serverid
)
748 return Response("Server with id or name %s does not exists." % serverid
, status
=404)
750 if server
.emulator_compute
is None:
751 LOG
.error("The targeted container does not exist.")
752 return Response("The targeted container of %s does not exist." % serverid
, status
=404)
753 data
= json
.loads(request
.data
).get("interfaceAttachment")
755 port
= data
.get("port_id", None)
756 net
= data
.get("net_id", None)
757 dc
= self
.api
.compute
.dc
758 network_dict
= dict()
761 if net
is not None and port
is not None:
762 port
= self
.api
.compute
.find_port_by_name_or_id(port
)
763 network
= self
.api
.compute
.find_network_by_name_or_id(net
)
764 network_dict
['id'] = port
.intf_name
765 network_dict
['ip'] = port
.ip_address
766 network_dict
[network_dict
['id']] = network
.name
767 elif net
is not None:
768 network
= self
.api
.compute
.find_network_by_name_or_id(net
)
770 return Response("Network with id or name %s does not exists." % net
, status
=404)
771 port
= self
.api
.compute
.create_port("port:cp%s:fl:%s" %
772 (len(self
.api
.compute
.ports
), str(uuid
.uuid4())))
774 port
.net_name
= network
.name
775 port
.ip_address
= network
.get_new_ip_address(port
.name
)
776 network_dict
['id'] = port
.intf_name
777 network_dict
['ip'] = port
.ip_address
778 network_dict
[network_dict
['id']] = network
.name
779 elif port
is not None:
780 port
= self
.api
.compute
.find_port_by_name_or_id(port
)
781 network_dict
['id'] = port
.intf_name
782 network_dict
['ip'] = port
.ip_address
783 network
= self
.api
.compute
.find_network_by_name_or_id(port
.net_name
)
784 network_dict
[network_dict
['id']] = network
.name
786 raise Exception("You can only attach interfaces by port or network at the moment")
788 if network
== self
.api
.manage
.floating_network
:
789 dc
.net
.addLink(server
.emulator_compute
, self
.api
.manage
.floating_switch
,
790 params1
=network_dict
, cls
=Link
, intfName1
=port
.intf_name
)
792 dc
.net
.addLink(server
.emulator_compute
, dc
.switch
,
793 params1
=network_dict
, cls
=Link
, intfName1
=port
.intf_name
)
794 resp
["port_state"] = "ACTIVE"
795 resp
["port_id"] = port
.id
796 resp
["net_id"] = self
.api
.compute
.find_network_by_name_or_id(port
.net_name
).id
797 resp
["mac_addr"] = port
.mac_address
798 resp
["fixed_ips"] = list()
800 fixed_ips
["ip_address"] = port
.ip_address
801 fixed_ips
["subnet_id"] = network
.subnet_name
802 resp
["fixed_ips"].append(fixed_ips
)
803 response
= Response(json
.dumps({"interfaceAttachment": resp
}), status
=202, mimetype
="application/json")
804 response
.headers
['Access-Control-Allow-Origin'] = '*'
807 except Exception as ex
:
808 LOG
.exception(u
"%s: Could not add interface to the server." % __name__
)
809 return ex
.message
, 500
812 class NovaShowAndDeleteInterfaceAtServer(Resource
):
813 def __init__(self
, api
):
816 def delete(self
, id, serverid
, port_id
):
818 Deletes an existing interface.
820 :param id: tenant id, we ignore this most of the time
822 :param serverid: Specifies the server, where the interface will be deleted.
823 :type serverid: ``str``
824 :param port_id: Specifies the port of the interface.
825 :type port_id: ``str``
826 :return: Returns a flask response with 202 if everything worked out. Otherwise it will return 404 and an
828 :rtype: :class:`flask.response`
830 LOG
.debug("API CALL: %s GET" % str(self
.__class
__.__name
__))
832 server
= self
.api
.compute
.find_server_by_name_or_id(serverid
)
834 return Response("Server with id or name %s does not exists." % serverid
, status
=404)
835 port
= self
.api
.compute
.find_port_by_name_or_id(port_id
)
837 return Response("Port with id or name %s does not exists." % port_id
, status
=404)
839 for link
in self
.api
.compute
.dc
.net
.links
:
840 if str(link
.intf1
) == port
.intf_name
and \
841 str(link
.intf1
.ip
) == port
.ip_address
.split('/')[0]:
842 self
.api
.compute
.dc
.net
.removeLink(link
)
845 response
= Response("", status
=202, mimetype
="application/json")
846 response
.headers
['Access-Control-Allow-Origin'] = '*'
849 except Exception as ex
:
850 LOG
.exception(u
"%s: Could not detach interface from the server." % __name__
)
851 return ex
.message
, 500
854 class NovaLimits(Resource
):
855 def __init__(self
, api
):
860 Returns the resource limits of the emulated cloud.
861 https://developer.openstack.org/api-ref/compute/?expanded=show-rate-and-absolute-limits-detail#limits-limits
863 TODO: For now we only return fixed limits, not based on the real deployment.
865 :param id: tenant id, used for the 'href' link
867 :return: Returns the resource limits.
868 :rtype: :class:`flask.response`
870 LOG
.debug("API CALL: %s GET" % str(self
.__class
__.__name
__))
875 "maxImageMeta": 12800,
876 "maxPersonality": 500,
877 "maxPersonalitySize": 1024000,
878 "maxSecurityGroupRules": 2000,
879 "maxSecurityGroups": 1000,
880 "maxServerMeta": 12800,
881 "maxTotalCores": 2000,
882 "maxTotalFloatingIps": 1000,
883 "maxTotalInstances": 1000,
884 "maxTotalKeypairs": 1000,
885 "maxTotalRAMSize": 5120000,
886 "maxServerGroups": 1000,
887 "maxServerGroupMembers": 1000,
889 "totalInstancesUsed": 0,
891 "totalSecurityGroupsUsed": 0,
892 "totalFloatingIpsUsed": 0,
893 "totalServerGroupsUsed": 0
898 response
= Response(json
.dumps(resp
), status
=200, mimetype
="application/json")
899 response
.headers
['Access-Control-Allow-Origin'] = '*'
902 except Exception as ex
:
903 LOG
.exception(u
"%s: Could not retrieve the list of images." % __name__
)
904 return ex
.message
, 500