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
525 def delete(self
, id, flavorid
):
527 Removes the given flavor.
528 Does not really remove anything from the machine, just fakes an OK.
530 LOG
.debug("API CALL: %s GET" % str(self
.__class
__.__name
__))
531 return Response("{}", status
=204, mimetype
="application/json")
534 class NovaListImages(Resource
):
535 def __init__(self
, api
):
540 Creates a list of all usable images.
542 :param id: tenant id, used for the 'href' link
544 :return: Returns a flask response with a list of available images.
545 :rtype: :class:`flask.response`
547 LOG
.debug("API CALL: %s GET" % str(self
.__class
__.__name
__))
550 resp
['images'] = list()
551 for image
in self
.api
.compute
.images
.values():
554 f
['name'] = str(image
.name
).replace(":latest", "")
555 f
['links'] = [{'href': "http://%s:%d/v2.1/%s/images/%s" % (self
.api
.ip
,
559 resp
['images'].append(f
)
560 response
= Response(json
.dumps(resp
), status
=200, mimetype
="application/json")
561 response
.headers
['Access-Control-Allow-Origin'] = '*'
564 except Exception as ex
:
565 LOG
.exception(u
"%s: Could not retrieve the list of images." % __name__
)
566 return ex
.message
, 500
569 class NovaListImagesDetails(Resource
):
570 def __init__(self
, api
):
575 As List Images but with additional metadata.
577 :param id: tenant id, used for the 'href' link
579 :return: Returns a flask response with a list of images and their metadata.
580 :rtype: :class:`flask.response`
582 LOG
.debug("API CALL: %s GET" % str(self
.__class
__.__name
__))
585 resp
['images'] = list()
586 for image
in self
.api
.compute
.images
.values():
587 # use the class dict. it should work fine
588 # but use a copy so we don't modifiy the original
589 f
= image
.__dict
__.copy()
590 # add additional expected stuff stay openstack compatible
591 f
['name'] = str(image
.name
).replace(":latest", "")
592 f
['links'] = [{'href': "http://%s:%d/v2.1/%s/images/%s" % (self
.api
.ip
,
597 "architecture": "x86_64",
598 "auto_disk_config": "True",
599 "kernel_id": "nokernel",
600 "ramdisk_id": "nokernel"
602 resp
['images'].append(f
)
604 response
= Response(json
.dumps(resp
), status
=200, mimetype
="application/json")
605 response
.headers
['Access-Control-Allow-Origin'] = '*'
608 except Exception as ex
:
609 LOG
.exception(u
"%s: Could not retrieve the list of images." % __name__
)
610 return ex
.message
, 500
613 class NovaListImageById(Resource
):
614 def __init__(self
, api
):
617 def get(self
, id, imageid
):
619 Gets an image by id from the emulator with openstack nova compliant return values.
621 :param id: tenantid, we ignore this most of the time
623 :param imageid: id of the image. If it is 1 the dummy CREATE-IMAGE is returned
624 :type imageid: ``str``
625 :return: Returns a flask response with the information about one image.
626 :rtype: :class:`flask.response`
628 LOG
.debug("API CALL: %s GET" % str(self
.__class
__.__name
__))
631 i
= resp
['image'] = dict()
632 for image
in self
.api
.compute
.images
.values():
633 if image
.id == imageid
or image
.name
== imageid
:
635 i
['name'] = image
.name
637 return Response(json
.dumps(resp
), status
=200, mimetype
="application/json")
639 response
= Response("Image with id or name %s does not exists." % imageid
, status
=404)
640 response
.headers
['Access-Control-Allow-Origin'] = '*'
643 except Exception as ex
:
644 LOG
.exception(u
"%s: Could not retrieve image with id %s." % (__name__
, imageid
))
645 return ex
.message
, 500
647 def delete(self
, id, imageid
):
649 Removes the given image.
650 Does not really remove anything from the machine, just fakes an OK.
652 LOG
.debug("API CALL: %s GET" % str(self
.__class
__.__name
__))
653 return Response("{}", status
=204, mimetype
="application/json")
656 class NovaShowServerDetails(Resource
):
657 def __init__(self
, api
):
660 def get(self
, id, serverid
):
662 Returns detailed information about the specified server.
664 :param id: tenant id, used for the 'href' link
666 :param serverid: Specifies the requested server.
667 :type serverid: ``str``
668 :return: Returns a flask response with details about the server.
669 :rtype: :class:`flask.response`
671 LOG
.debug("API CALL: %s GET" % str(self
.__class
__.__name
__))
673 server
= self
.api
.compute
.find_server_by_name_or_id(serverid
)
675 return Response("Server with id or name %s does not exists." % serverid
, status
=404)
676 s
= server
.create_server_dict()
677 s
['links'] = [{'href': "http://%s:%d/v2.1/%s/servers/%s" % (self
.api
.ip
,
682 flavor
= self
.api
.compute
.flavors
[server
.flavor
]
687 "href": "http://%s:%d/v2.1/%s/flavors/%s" % (self
.api
.ip
,
695 image
= self
.api
.compute
.images
[server
.image
]
700 "href": "http://%s:%d/v2.1/%s/images/%s" % (self
.api
.ip
,
709 response
= Response(json
.dumps({'server': s
}), status
=200, mimetype
="application/json")
710 response
.headers
['Access-Control-Allow-Origin'] = '*'
713 except Exception as ex
:
714 LOG
.exception(u
"%s: Could not retrieve the server details." % __name__
)
715 return ex
.message
, 500
717 def delete(self
, id, serverid
):
719 Delete a server instance.
721 :param id: tenant id, we ignore this most of the time
723 :param serverid: The UUID of the server
724 :type serverid: ``str``
725 :return: Returns 200 if everything is fine.
726 :rtype: :class:`flask.response`
728 LOG
.debug("API CALL: %s POST" % str(self
.__class
__.__name
__))
730 server
= self
.api
.compute
.find_server_by_name_or_id(serverid
)
732 return Response('Could not find server.', status
=404, mimetype
="application/json")
734 self
.api
.compute
.stop_compute(server
)
736 response
= Response('Server deleted.', status
=204, mimetype
="application/json")
737 response
.headers
['Access-Control-Allow-Origin'] = '*'
740 except Exception as ex
:
741 LOG
.exception(u
"%s: Could not create the server." % __name__
)
742 return ex
.message
, 500
745 class NovaInterfaceToServer(Resource
):
746 def __init__(self
, api
):
749 def post(self
, id, serverid
):
751 Add an interface to the specified server.
753 :param id: tenant id, we ignore this most of the time
755 :param serverid: Specifies the server.
756 :type serverid: ``str``
757 :return: Returns a flask response with information about the attached interface.
758 :rtype: :class:`flask.response`
760 LOG
.debug("API CALL: %s GET" % str(self
.__class
__.__name
__))
762 server
= self
.api
.compute
.find_server_by_name_or_id(serverid
)
764 return Response("Server with id or name %s does not exists." % serverid
, status
=404)
766 if server
.emulator_compute
is None:
767 LOG
.error("The targeted container does not exist.")
768 return Response("The targeted container of %s does not exist." % serverid
, status
=404)
769 data
= json
.loads(request
.data
).get("interfaceAttachment")
771 port
= data
.get("port_id", None)
772 net
= data
.get("net_id", None)
773 dc
= self
.api
.compute
.dc
774 network_dict
= dict()
777 if net
is not None and port
is not None:
778 port
= self
.api
.compute
.find_port_by_name_or_id(port
)
779 network
= self
.api
.compute
.find_network_by_name_or_id(net
)
780 network_dict
['id'] = port
.intf_name
781 network_dict
['ip'] = port
.ip_address
782 network_dict
[network_dict
['id']] = network
.name
783 elif net
is not None:
784 network
= self
.api
.compute
.find_network_by_name_or_id(net
)
786 return Response("Network with id or name %s does not exists." % net
, status
=404)
787 port
= self
.api
.compute
.create_port("port:cp%s:fl:%s" %
788 (len(self
.api
.compute
.ports
), str(uuid
.uuid4())))
790 port
.net_name
= network
.name
791 port
.ip_address
= network
.get_new_ip_address(port
.name
)
792 network_dict
['id'] = port
.intf_name
793 network_dict
['ip'] = port
.ip_address
794 network_dict
[network_dict
['id']] = network
.name
795 elif port
is not None:
796 port
= self
.api
.compute
.find_port_by_name_or_id(port
)
797 network_dict
['id'] = port
.intf_name
798 network_dict
['ip'] = port
.ip_address
799 network
= self
.api
.compute
.find_network_by_name_or_id(port
.net_name
)
800 network_dict
[network_dict
['id']] = network
.name
802 raise Exception("You can only attach interfaces by port or network at the moment")
804 if network
== self
.api
.manage
.floating_network
:
805 dc
.net
.addLink(server
.emulator_compute
, self
.api
.manage
.floating_switch
,
806 params1
=network_dict
, cls
=Link
, intfName1
=port
.intf_name
)
808 dc
.net
.addLink(server
.emulator_compute
, dc
.switch
,
809 params1
=network_dict
, cls
=Link
, intfName1
=port
.intf_name
)
810 resp
["port_state"] = "ACTIVE"
811 resp
["port_id"] = port
.id
812 resp
["net_id"] = self
.api
.compute
.find_network_by_name_or_id(port
.net_name
).id
813 resp
["mac_addr"] = port
.mac_address
814 resp
["fixed_ips"] = list()
816 fixed_ips
["ip_address"] = port
.ip_address
817 fixed_ips
["subnet_id"] = network
.subnet_name
818 resp
["fixed_ips"].append(fixed_ips
)
819 response
= Response(json
.dumps({"interfaceAttachment": resp
}), status
=202, mimetype
="application/json")
820 response
.headers
['Access-Control-Allow-Origin'] = '*'
823 except Exception as ex
:
824 LOG
.exception(u
"%s: Could not add interface to the server." % __name__
)
825 return ex
.message
, 500
828 class NovaShowAndDeleteInterfaceAtServer(Resource
):
829 def __init__(self
, api
):
832 def delete(self
, id, serverid
, port_id
):
834 Deletes an existing interface.
836 :param id: tenant id, we ignore this most of the time
838 :param serverid: Specifies the server, where the interface will be deleted.
839 :type serverid: ``str``
840 :param port_id: Specifies the port of the interface.
841 :type port_id: ``str``
842 :return: Returns a flask response with 202 if everything worked out. Otherwise it will return 404 and an
844 :rtype: :class:`flask.response`
846 LOG
.debug("API CALL: %s GET" % str(self
.__class
__.__name
__))
848 server
= self
.api
.compute
.find_server_by_name_or_id(serverid
)
850 return Response("Server with id or name %s does not exists." % serverid
, status
=404)
851 port
= self
.api
.compute
.find_port_by_name_or_id(port_id
)
853 return Response("Port with id or name %s does not exists." % port_id
, status
=404)
855 for link
in self
.api
.compute
.dc
.net
.links
:
856 if str(link
.intf1
) == port
.intf_name
and \
857 str(link
.intf1
.ip
) == port
.ip_address
.split('/')[0]:
858 self
.api
.compute
.dc
.net
.removeLink(link
)
861 response
= Response("", status
=202, mimetype
="application/json")
862 response
.headers
['Access-Control-Allow-Origin'] = '*'
865 except Exception as ex
:
866 LOG
.exception(u
"%s: Could not detach interface from the server." % __name__
)
867 return ex
.message
, 500
870 class NovaLimits(Resource
):
871 def __init__(self
, api
):
876 Returns the resource limits of the emulated cloud.
877 https://developer.openstack.org/api-ref/compute/?expanded=show-rate-and-absolute-limits-detail#limits-limits
879 TODO: For now we only return fixed limits, not based on the real deployment.
881 :param id: tenant id, used for the 'href' link
883 :return: Returns the resource limits.
884 :rtype: :class:`flask.response`
886 LOG
.debug("API CALL: %s GET" % str(self
.__class
__.__name
__))
891 "maxImageMeta": 12800,
892 "maxPersonality": 500,
893 "maxPersonalitySize": 1024000,
894 "maxSecurityGroupRules": 2000,
895 "maxSecurityGroups": 1000,
896 "maxServerMeta": 12800,
897 "maxTotalCores": 2000,
898 "maxTotalFloatingIps": 1000,
899 "maxTotalInstances": 1000,
900 "maxTotalKeypairs": 1000,
901 "maxTotalRAMSize": 5120000,
902 "maxServerGroups": 1000,
903 "maxServerGroupMembers": 1000,
905 "totalInstancesUsed": 0,
907 "totalSecurityGroupsUsed": 0,
908 "totalFloatingIpsUsed": 0,
909 "totalServerGroupsUsed": 0
914 response
= Response(json
.dumps(resp
), status
=200, mimetype
="application/json")
915 response
.headers
['Access-Control-Allow-Origin'] = '*'
918 except Exception as ex
:
919 LOG
.exception(u
"%s: Could not retrieve the list of images." % __name__
)
920 return ex
.message
, 500