1 from flask_restful
import Resource
2 from flask
import Response
, request
3 from emuvim
.api
.openstack
.openstack_dummies
.base_openstack_dummy
import BaseOpenstackDummy
4 from emuvim
.api
.openstack
.helper
import get_host
8 from mininet
.link
import Link
11 LOG
= logging
.getLogger("api.openstack.nova")
14 class NovaDummyApi(BaseOpenstackDummy
):
15 def __init__(self
, in_ip
, in_port
, compute
):
16 super(NovaDummyApi
, self
).__init
__(in_ip
, in_port
)
17 self
.compute
= compute
19 self
.api
.add_resource(NovaVersionsList
, "/",
20 resource_class_kwargs
={'api': self
})
21 self
.api
.add_resource(Shutdown
, "/shutdown")
22 self
.api
.add_resource(NovaVersionShow
, "/v2.1/<id>",
23 resource_class_kwargs
={'api': self
})
24 self
.api
.add_resource(NovaListServersApi
, "/v2.1/<id>/servers",
25 resource_class_kwargs
={'api': self
})
26 self
.api
.add_resource(NovaListServersAndPortsApi
, "/v2.1/<id>/servers/andPorts",
27 resource_class_kwargs
={'api': self
})
28 self
.api
.add_resource(NovaListServersDetailed
, "/v2.1/<id>/servers/detail",
29 resource_class_kwargs
={'api': self
})
30 self
.api
.add_resource(NovaShowServerDetails
, "/v2.1/<id>/servers/<serverid>",
31 resource_class_kwargs
={'api': self
})
32 self
.api
.add_resource(NovaInterfaceToServer
, "/v2.1/<id>/servers/<serverid>/os-interface",
33 resource_class_kwargs
={'api': self
})
34 self
.api
.add_resource(NovaShowAndDeleteInterfaceAtServer
, "/v2.1/<id>/servers/<serverid>/os-interface/<port_id>",
35 resource_class_kwargs
={'api': self
})
36 self
.api
.add_resource(NovaListFlavors
, "/v2.1/<id>/flavors", "/v2/<id>/flavors",
37 resource_class_kwargs
={'api': self
})
38 self
.api
.add_resource(NovaListFlavorsDetails
, "/v2.1/<id>/flavors/detail", "/v2/<id>/flavors/detail",
39 resource_class_kwargs
={'api': self
})
40 self
.api
.add_resource(NovaListFlavorById
, "/v2.1/<id>/flavors/<flavorid>", "/v2/<id>/flavors/<flavorid>",
41 resource_class_kwargs
={'api': self
})
42 self
.api
.add_resource(NovaListImages
, "/v2.1/<id>/images",
43 resource_class_kwargs
={'api': self
})
44 self
.api
.add_resource(NovaListImagesDetails
, "/v2.1/<id>/images/detail",
45 resource_class_kwargs
={'api': self
})
46 self
.api
.add_resource(NovaListImageById
, "/v2.1/<id>/images/<imageid>",
47 resource_class_kwargs
={'api': self
})
48 self
.api
.add_resource(NovaLimits
, "/v2.1/<id>/limits",
49 resource_class_kwargs
={'api': self
})
51 def _start_flask(self
):
52 LOG
.info("Starting %s endpoint @ http://%s:%d" % ("NovaDummyApi", self
.ip
, self
.port
))
53 # add some flavors for good measure
54 self
.compute
.add_flavor('m1.tiny', 1, 512, "MB", 1, "GB")
55 self
.compute
.add_flavor('m1.nano', 1, 64, "MB", 0, "GB")
56 self
.compute
.add_flavor('m1.micro', 1, 128, "MB", 0, "GB")
57 self
.compute
.add_flavor('m1.small', 1, 1024, "MB", 2, "GB")
58 if self
.app
is not None:
59 self
.app
.before_request(self
.dump_playbook
)
60 self
.app
.run(self
.ip
, self
.port
, debug
=True, use_reloader
=False)
63 class Shutdown(Resource
):
65 A get request to /shutdown will shut down this endpoint.
69 LOG
.debug(("%s is beeing shut doen") % (__name__
))
70 func
= request
.environ
.get('werkzeug.server.shutdown')
72 raise RuntimeError('Not running with the Werkzeug Server')
76 class NovaVersionsList(Resource
):
77 def __init__(self
, api
):
84 :return: Returns a json with API versions.
85 :rtype: :class:`flask.response`
87 LOG
.debug("API CALL: %s GET" % str(self
.__class
__.__name
__))
96 "href": "http://%s:%d/v2.1/",
102 "min_version": "2.1",
103 "updated": "2013-07-23T11:33:21Z"
107 """ % (get_host(request
), self
.api
.port
)
109 response
= Response(resp
, status
=200, mimetype
="application/json")
110 response
.headers
['Access-Control-Allow-Origin'] = '*'
113 except Exception as ex
:
114 LOG
.exception(u
"%s: Could not show list of versions." % __name__
)
115 return ex
.message
, 500
118 class NovaVersionShow(Resource
):
119 def __init__(self
, api
):
128 :return: Returns a json with API details.
129 :rtype: :class:`flask.response`
131 LOG
.debug("API CALL: %s GET" % str(self
.__class
__.__name
__))
140 "href": "http://%s:%d/v2.1/",
144 "href": "http://docs.openstack.org/",
145 "rel": "describedby",
151 "base": "application/json",
152 "type": "application/vnd.openstack.compute+json;version=2.1"
157 "min_version": "2.1",
158 "updated": "2013-07-23T11:33:21Z"
161 """ % (get_host(request
), self
.api
.port
)
163 response
= Response(resp
, status
=200, mimetype
="application/json")
164 response
.headers
['Access-Control-Allow-Origin'] = '*'
167 except Exception as ex
:
168 LOG
.exception(u
"%s: Could not show list of versions." % __name__
)
169 return ex
.message
, 500
172 class NovaListServersApi(Resource
):
173 def __init__(self
, api
):
178 Creates a list with all running servers and their detailed information.
180 :param id: Used to create a individual link to quarry further information.
182 :return: Returns a json response with a dictionary that contains the server information.
183 :rtype: :class:`flask.response`
185 LOG
.debug("API CALL: %s GET" % str(self
.__class
__.__name
__))
189 resp
['servers'] = list()
190 for server
in self
.api
.compute
.computeUnits
.values():
191 s
= server
.create_server_dict(self
.api
.compute
)
192 s
['links'] = [{'href': "http://%s:%d/v2.1/%s/servers/%s" % (get_host(request
),
197 resp
['servers'].append(s
)
199 response
= Response(json
.dumps(resp
), status
=200, mimetype
="application/json")
200 response
.headers
['Access-Control-Allow-Origin'] = '*'
203 except Exception as ex
:
204 LOG
.exception(u
"%s: Could not retrieve the list of servers." % __name__
)
205 return ex
.message
, 500
209 Creates a server instance.
211 :param id: tenant id, we ignore this most of the time
213 :return: Returns a flask response, with detailed information about the just created server.
214 :rtype: :class:`flask.response`
216 LOG
.debug("API CALL: %s POST" % str(self
.__class
__.__name
__))
218 server_dict
= json
.loads(request
.data
)['server']
219 networks
= server_dict
.get('networks', None)
220 name
= str(self
.api
.compute
.dc
.label
) + "_man_" + server_dict
["name"][0:12]
222 if self
.api
.compute
.find_server_by_name_or_id(name
) is not None:
223 return Response("Server with name %s already exists." % name
, status
=409)
224 # TODO: not finished!
227 server
= self
.api
.compute
.create_server(name
)
228 server
.full_name
= str(self
.api
.compute
.dc
.label
) + "_man_" + server_dict
["name"]
229 server
.template_name
= server_dict
["name"]
230 if "metadata" in server_dict
:
231 server
.properties
= server_dict
["metadata"]
233 for flavor
in self
.api
.compute
.flavors
.values():
234 if flavor
.id == server_dict
.get('flavorRef', ''):
235 server
.flavor
= flavor
.name
236 for image
in self
.api
.compute
.images
.values():
237 if image
.id in server_dict
['imageRef']:
238 server
.image
= image
.name
240 if networks
is not None:
242 port
= self
.api
.compute
.find_port_by_name_or_id(net
.get('port', ""))
244 server
.port_names
.append(port
.name
)
246 return Response("Currently only networking by port is supported.", status
=400)
248 self
.api
.compute
._start
_compute
(server
)
250 response
= NovaShowServerDetails(self
.api
).get(id, server
.id)
251 response
.headers
['Access-Control-Allow-Origin'] = '*'
254 except Exception as ex
:
255 LOG
.exception(u
"%s: Could not create the server." % __name__
)
256 return ex
.message
, 500
259 class NovaListServersAndPortsApi(Resource
):
260 def __init__(self
, api
):
265 Creates a list with all running servers and their detailed information. This function also presents all
266 port information of each server.
268 :param id: Used to create a individual link to quarry further information.
270 :return: Returns a json response with a dictionary that contains the server information.
271 :rtype: :class:`flask.response`
273 LOG
.debug("API CALL: %s GET" % str(self
.__class
__.__name
__))
277 resp
['servers'] = list()
278 for server
in self
.api
.compute
.computeUnits
.values():
279 s
= server
.create_server_dict(self
.api
.compute
)
280 s
['links'] = [{'href': "http://%s:%d/v2.1/%s/servers/%s" % (get_host(request
),
286 for port_name
in server
.port_names
:
287 port
= self
.api
.compute
.find_port_by_name_or_id(port_name
)
291 tmp
= port
.create_port_dict(self
.api
.compute
)
292 tmp
['intf_name'] = port
.intf_name
293 s
['ports'].append(tmp
)
295 resp
['servers'].append(s
)
297 response
= Response(json
.dumps(resp
), status
=200, mimetype
="application/json")
298 response
.headers
['Access-Control-Allow-Origin'] = '*'
301 except Exception as ex
:
302 LOG
.exception(u
"%s: Could not retrieve the list of servers." % __name__
)
303 return ex
.message
, 500
306 class NovaListServersDetailed(Resource
):
307 def __init__(self
, api
):
312 As List Servers, it lists all running servers and their details but furthermore it also states the
313 used flavor and the server image.
315 :param id: tenant id, used for the 'href' link.
317 :return: Returns a flask response, with detailed information aboit the servers and their flavor and image.
318 :rtype: :class:`flask.response`
320 LOG
.debug("API CALL: %s GET" % str(self
.__class
__.__name
__))
323 resp
= {"servers": list()}
324 for server
in self
.api
.compute
.computeUnits
.values():
325 s
= server
.create_server_dict(self
.api
.compute
)
326 s
['links'] = [{'href': "http://%s:%d/v2.1/%s/servers/%s" % (get_host(request
),
330 flavor
= self
.api
.compute
.flavors
[server
.flavor
]
335 "href": "http://%s:%d/v2.1/%s/flavors/%s" % (get_host(request
),
343 image
= self
.api
.compute
.images
[server
.image
]
348 "href": "http://%s:%d/v2.1/%s/images/%s" % (get_host(request
),
357 resp
['servers'].append(s
)
359 response
= Response(json
.dumps(resp
), status
=200, mimetype
="application/json")
360 response
.headers
['Access-Control-Allow-Origin'] = '*'
363 except Exception as ex
:
364 LOG
.exception(u
"%s: Could not retrieve the list of servers." % __name__
)
365 return ex
.message
, 500
368 class NovaListFlavors(Resource
):
369 def __init__(self
, api
):
374 Lists all available flavors.
376 :param id: tenant id, used for the 'href' link
378 :return: Returns a flask response with a list of all flavors.
379 :rtype: :class:`flask.response`
381 LOG
.debug("API CALL: %s GET" % str(self
.__class
__.__name
__))
384 resp
['flavors'] = list()
385 for flavor
in self
.api
.compute
.flavors
.values():
386 f
= flavor
.__dict
__.copy()
388 f
['name'] = flavor
.name
389 f
['links'] = [{'href': "http://%s:%d/v2.1/%s/flavors/%s" % (get_host(request
),
393 resp
['flavors'].append(f
)
395 response
= Response(json
.dumps(resp
), status
=200, mimetype
="application/json")
396 response
.headers
['Access-Control-Allow-Origin'] = '*'
399 except Exception as ex
:
400 LOG
.exception(u
"%s: Could not retrieve the list of servers." % __name__
)
401 return ex
.message
, 500
404 LOG
.debug("API CALL: %s POST" % str(self
.__class
__.__name
__))
405 data
= json
.loads(request
.data
).get("flavor")
406 LOG
.warning("Create Flavor: %s" % str(data
))
407 # add to internal dict
408 f
= self
.api
.compute
.add_flavor(
411 data
.get("ram"), "MB",
412 data
.get("disk"), "GB")
413 # create response based on incoming data
415 data
["links"] = [{'href': "http://%s:%d/v2.1/%s/flavors/%s" % (get_host(request
),
419 resp
= {"flavor": data
}
420 return Response(json
.dumps(resp
), status
=200, mimetype
="application/json")
423 class NovaListFlavorsDetails(Resource
):
424 def __init__(self
, api
):
429 Lists all flavors with additional information like ram and disk space.
431 :param id: tenant id, used for the 'href' link
433 :return: Returns a flask response with a list of all flavors with additional information.
434 :rtype: :class:`flask.response`
436 LOG
.debug("API CALL: %s GET" % str(self
.__class
__.__name
__))
439 resp
['flavors'] = list()
440 for flavor
in self
.api
.compute
.flavors
.values():
441 # use the class dict. it should work fine
442 # but use a copy so we don't modifiy the original
443 f
= flavor
.__dict
__.copy()
444 # add additional expected stuff stay openstack compatible
445 f
['links'] = [{'href': "http://%s:%d/v2.1/%s/flavors/%s" % (get_host(request
),
449 f
['OS-FLV-DISABLED:disabled'] = False
450 f
['OS-FLV-EXT-DATA:ephemeral'] = 0
451 f
['os-flavor-access:is_public'] = True
452 f
['ram'] = flavor
.memory
453 f
['vcpus'] = flavor
.cpu
455 f
['disk'] = flavor
.storage
456 f
['rxtx_factor'] = 1.0
457 resp
['flavors'].append(f
)
459 response
= Response(json
.dumps(resp
), status
=200, mimetype
="application/json")
460 response
.headers
['Access-Control-Allow-Origin'] = '*'
463 except Exception as ex
:
464 LOG
.exception(u
"%s: Could not retrieve the list of servers." % __name__
)
465 return ex
.message
, 500
468 LOG
.debug("API CALL: %s POST" % str(self
.__class
__.__name
__))
469 data
= json
.loads(request
.data
).get("flavor")
470 LOG
.warning("Create Flavor: %s" % str(data
))
471 # add to internal dict
472 f
= self
.api
.compute
.add_flavor(
475 data
.get("ram"), "MB",
476 data
.get("disk"), "GB")
477 # create response based on incoming data
479 data
["links"] = [{'href': "http://%s:%d/v2.1/%s/flavors/%s" % (get_host(request
),
483 resp
= {"flavor": data
}
484 return Response(json
.dumps(resp
), status
=200, mimetype
="application/json")
487 class NovaListFlavorById(Resource
):
488 def __init__(self
, api
):
491 def get(self
, id, flavorid
):
493 Returns details about one flavor.
495 :param id: tenant id, used for the 'href' link
497 :param flavorid: Represents the flavor.
498 :type flavorid: ``str``
499 :return: Returns a flask response with detailed information about the flavor.
500 :rtype: :class:`flask.response`
502 LOG
.debug("API CALL: %s GET" % str(self
.__class
__.__name
__))
505 resp
['flavor'] = dict()
506 flavor
= self
.api
.compute
.flavors
.get(flavorid
, None)
508 for f
in self
.api
.compute
.flavors
.values():
512 resp
['flavor']['id'] = flavor
.id
513 resp
['flavor']['name'] = flavor
.name
514 resp
['flavor']['links'] = [{'href': "http://%s:%d/v2.1/%s/flavors/%s" % (get_host(request
),
518 response
= Response(json
.dumps(resp
), status
=200, mimetype
="application/json")
519 response
.headers
['Access-Control-Allow-Origin'] = '*'
522 except Exception as ex
:
523 LOG
.exception(u
"%s: Could not retrieve flavor with id %s" % (__name__
, flavorid
))
524 return ex
.message
, 500
526 def delete(self
, id, flavorid
):
528 Removes the given flavor.
529 Does not really remove anything from the machine, just fakes an OK.
531 LOG
.debug("API CALL: %s GET" % str(self
.__class
__.__name
__))
532 return Response("{}", status
=204, mimetype
="application/json")
535 class NovaListImages(Resource
):
536 def __init__(self
, api
):
541 Creates a list of all usable images.
543 :param id: tenant id, used for the 'href' link
545 :return: Returns a flask response with a list of available images.
546 :rtype: :class:`flask.response`
548 LOG
.debug("API CALL: %s GET" % str(self
.__class
__.__name
__))
551 resp
['images'] = list()
552 for image
in self
.api
.compute
.images
.values():
555 f
['name'] = str(image
.name
).replace(":latest", "")
556 f
['links'] = [{'href': "http://%s:%d/v2.1/%s/images/%s" % (get_host(request
),
560 resp
['images'].append(f
)
561 response
= Response(json
.dumps(resp
), status
=200, mimetype
="application/json")
562 response
.headers
['Access-Control-Allow-Origin'] = '*'
565 except Exception as ex
:
566 LOG
.exception(u
"%s: Could not retrieve the list of images." % __name__
)
567 return ex
.message
, 500
570 class NovaListImagesDetails(Resource
):
571 def __init__(self
, api
):
576 As List Images but with additional metadata.
578 :param id: tenant id, used for the 'href' link
580 :return: Returns a flask response with a list of images and their metadata.
581 :rtype: :class:`flask.response`
583 LOG
.debug("API CALL: %s GET" % str(self
.__class
__.__name
__))
586 resp
['images'] = list()
587 for image
in self
.api
.compute
.images
.values():
588 # use the class dict. it should work fine
589 # but use a copy so we don't modifiy the original
590 f
= image
.__dict
__.copy()
591 # add additional expected stuff stay openstack compatible
592 f
['name'] = str(image
.name
).replace(":latest", "")
593 f
['links'] = [{'href': "http://%s:%d/v2.1/%s/images/%s" % (get_host(request
),
598 "architecture": "x86_64",
599 "auto_disk_config": "True",
600 "kernel_id": "nokernel",
601 "ramdisk_id": "nokernel"
603 resp
['images'].append(f
)
605 response
= Response(json
.dumps(resp
), status
=200, mimetype
="application/json")
606 response
.headers
['Access-Control-Allow-Origin'] = '*'
609 except Exception as ex
:
610 LOG
.exception(u
"%s: Could not retrieve the list of images." % __name__
)
611 return ex
.message
, 500
614 class NovaListImageById(Resource
):
615 def __init__(self
, api
):
618 def get(self
, id, imageid
):
620 Gets an image by id from the emulator with openstack nova compliant return values.
622 :param id: tenantid, we ignore this most of the time
624 :param imageid: id of the image. If it is 1 the dummy CREATE-IMAGE is returned
625 :type imageid: ``str``
626 :return: Returns a flask response with the information about one image.
627 :rtype: :class:`flask.response`
629 LOG
.debug("API CALL: %s GET" % str(self
.__class
__.__name
__))
632 i
= resp
['image'] = dict()
633 for image
in self
.api
.compute
.images
.values():
634 if image
.id == imageid
or image
.name
== imageid
:
636 i
['name'] = image
.name
638 return Response(json
.dumps(resp
), status
=200, mimetype
="application/json")
640 response
= Response("Image with id or name %s does not exists." % imageid
, status
=404)
641 response
.headers
['Access-Control-Allow-Origin'] = '*'
644 except Exception as ex
:
645 LOG
.exception(u
"%s: Could not retrieve image with id %s." % (__name__
, imageid
))
646 return ex
.message
, 500
648 def delete(self
, id, imageid
):
650 Removes the given image.
651 Does not really remove anything from the machine, just fakes an OK.
653 LOG
.debug("API CALL: %s GET" % str(self
.__class
__.__name
__))
654 return Response("{}", status
=204, mimetype
="application/json")
657 class NovaShowServerDetails(Resource
):
658 def __init__(self
, api
):
661 def get(self
, id, serverid
):
663 Returns detailed information about the specified server.
665 :param id: tenant id, used for the 'href' link
667 :param serverid: Specifies the requested server.
668 :type serverid: ``str``
669 :return: Returns a flask response with details about the server.
670 :rtype: :class:`flask.response`
672 LOG
.debug("API CALL: %s GET" % str(self
.__class
__.__name
__))
674 server
= self
.api
.compute
.find_server_by_name_or_id(serverid
)
676 return Response("Server with id or name %s does not exists." % serverid
, status
=404)
677 s
= server
.create_server_dict()
678 s
['links'] = [{'href': "http://%s:%d/v2.1/%s/servers/%s" % (get_host(request
),
683 flavor
= self
.api
.compute
.flavors
[server
.flavor
]
688 "href": "http://%s:%d/v2.1/%s/flavors/%s" % (get_host(request
),
696 image
= self
.api
.compute
.images
[server
.image
]
701 "href": "http://%s:%d/v2.1/%s/images/%s" % (get_host(request
),
710 response
= Response(json
.dumps({'server': s
}), status
=200, mimetype
="application/json")
711 response
.headers
['Access-Control-Allow-Origin'] = '*'
714 except Exception as ex
:
715 LOG
.exception(u
"%s: Could not retrieve the server details." % __name__
)
716 return ex
.message
, 500
718 def delete(self
, id, serverid
):
720 Delete a server instance.
722 :param id: tenant id, we ignore this most of the time
724 :param serverid: The UUID of the server
725 :type serverid: ``str``
726 :return: Returns 200 if everything is fine.
727 :rtype: :class:`flask.response`
729 LOG
.debug("API CALL: %s POST" % str(self
.__class
__.__name
__))
731 server
= self
.api
.compute
.find_server_by_name_or_id(serverid
)
733 return Response('Could not find server.', status
=404, mimetype
="application/json")
735 self
.api
.compute
.stop_compute(server
)
737 response
= Response('Server deleted.', status
=204, mimetype
="application/json")
738 response
.headers
['Access-Control-Allow-Origin'] = '*'
741 except Exception as ex
:
742 LOG
.exception(u
"%s: Could not create the server." % __name__
)
743 return ex
.message
, 500
746 class NovaInterfaceToServer(Resource
):
747 def __init__(self
, api
):
750 def post(self
, id, serverid
):
752 Add an interface to the specified server.
754 :param id: tenant id, we ignore this most of the time
756 :param serverid: Specifies the server.
757 :type serverid: ``str``
758 :return: Returns a flask response with information about the attached interface.
759 :rtype: :class:`flask.response`
761 LOG
.debug("API CALL: %s GET" % str(self
.__class
__.__name
__))
763 server
= self
.api
.compute
.find_server_by_name_or_id(serverid
)
765 return Response("Server with id or name %s does not exists." % serverid
, status
=404)
767 if server
.emulator_compute
is None:
768 LOG
.error("The targeted container does not exist.")
769 return Response("The targeted container of %s does not exist." % serverid
, status
=404)
770 data
= json
.loads(request
.data
).get("interfaceAttachment")
772 port
= data
.get("port_id", None)
773 net
= data
.get("net_id", None)
774 dc
= self
.api
.compute
.dc
775 network_dict
= dict()
778 if net
is not None and port
is not None:
779 port
= self
.api
.compute
.find_port_by_name_or_id(port
)
780 network
= self
.api
.compute
.find_network_by_name_or_id(net
)
781 network_dict
['id'] = port
.intf_name
782 network_dict
['ip'] = port
.ip_address
783 network_dict
[network_dict
['id']] = network
.name
784 elif net
is not None:
785 network
= self
.api
.compute
.find_network_by_name_or_id(net
)
787 return Response("Network with id or name %s does not exists." % net
, status
=404)
788 port
= self
.api
.compute
.create_port("port:cp%s:fl:%s" %
789 (len(self
.api
.compute
.ports
), str(uuid
.uuid4())))
791 port
.net_name
= network
.name
792 port
.ip_address
= network
.get_new_ip_address(port
.name
)
793 network_dict
['id'] = port
.intf_name
794 network_dict
['ip'] = port
.ip_address
795 network_dict
[network_dict
['id']] = network
.name
796 elif port
is not None:
797 port
= self
.api
.compute
.find_port_by_name_or_id(port
)
798 network_dict
['id'] = port
.intf_name
799 network_dict
['ip'] = port
.ip_address
800 network
= self
.api
.compute
.find_network_by_name_or_id(port
.net_name
)
801 network_dict
[network_dict
['id']] = network
.name
803 raise Exception("You can only attach interfaces by port or network at the moment")
805 if network
== self
.api
.manage
.floating_network
:
806 dc
.net
.addLink(server
.emulator_compute
, self
.api
.manage
.floating_switch
,
807 params1
=network_dict
, cls
=Link
, intfName1
=port
.intf_name
)
809 dc
.net
.addLink(server
.emulator_compute
, dc
.switch
,
810 params1
=network_dict
, cls
=Link
, intfName1
=port
.intf_name
)
811 resp
["port_state"] = "ACTIVE"
812 resp
["port_id"] = port
.id
813 resp
["net_id"] = self
.api
.compute
.find_network_by_name_or_id(port
.net_name
).id
814 resp
["mac_addr"] = port
.mac_address
815 resp
["fixed_ips"] = list()
817 fixed_ips
["ip_address"] = port
.ip_address
818 fixed_ips
["subnet_id"] = network
.subnet_name
819 resp
["fixed_ips"].append(fixed_ips
)
820 response
= Response(json
.dumps({"interfaceAttachment": resp
}), status
=202, mimetype
="application/json")
821 response
.headers
['Access-Control-Allow-Origin'] = '*'
824 except Exception as ex
:
825 LOG
.exception(u
"%s: Could not add interface to the server." % __name__
)
826 return ex
.message
, 500
829 class NovaShowAndDeleteInterfaceAtServer(Resource
):
830 def __init__(self
, api
):
833 def delete(self
, id, serverid
, port_id
):
835 Deletes an existing interface.
837 :param id: tenant id, we ignore this most of the time
839 :param serverid: Specifies the server, where the interface will be deleted.
840 :type serverid: ``str``
841 :param port_id: Specifies the port of the interface.
842 :type port_id: ``str``
843 :return: Returns a flask response with 202 if everything worked out. Otherwise it will return 404 and an
845 :rtype: :class:`flask.response`
847 LOG
.debug("API CALL: %s GET" % str(self
.__class
__.__name
__))
849 server
= self
.api
.compute
.find_server_by_name_or_id(serverid
)
851 return Response("Server with id or name %s does not exists." % serverid
, status
=404)
852 port
= self
.api
.compute
.find_port_by_name_or_id(port_id
)
854 return Response("Port with id or name %s does not exists." % port_id
, status
=404)
856 for link
in self
.api
.compute
.dc
.net
.links
:
857 if str(link
.intf1
) == port
.intf_name
and \
858 str(link
.intf1
.ip
) == port
.ip_address
.split('/')[0]:
859 self
.api
.compute
.dc
.net
.removeLink(link
)
862 response
= Response("", status
=202, mimetype
="application/json")
863 response
.headers
['Access-Control-Allow-Origin'] = '*'
866 except Exception as ex
:
867 LOG
.exception(u
"%s: Could not detach interface from the server." % __name__
)
868 return ex
.message
, 500
871 class NovaLimits(Resource
):
872 def __init__(self
, api
):
877 Returns the resource limits of the emulated cloud.
878 https://developer.openstack.org/api-ref/compute/?expanded=show-rate-and-absolute-limits-detail#limits-limits
880 TODO: For now we only return fixed limits, not based on the real deployment.
882 :param id: tenant id, used for the 'href' link
884 :return: Returns the resource limits.
885 :rtype: :class:`flask.response`
887 LOG
.debug("API CALL: %s GET" % str(self
.__class
__.__name
__))
892 "maxImageMeta": 12800,
893 "maxPersonality": 500,
894 "maxPersonalitySize": 1024000,
895 "maxSecurityGroupRules": 2000,
896 "maxSecurityGroups": 1000,
897 "maxServerMeta": 12800,
898 "maxTotalCores": 2000,
899 "maxTotalFloatingIps": 1000,
900 "maxTotalInstances": 1000,
901 "maxTotalKeypairs": 1000,
902 "maxTotalRAMSize": 5120000,
903 "maxServerGroups": 1000,
904 "maxServerGroupMembers": 1000,
906 "totalInstancesUsed": 0,
908 "totalSecurityGroupsUsed": 0,
909 "totalFloatingIpsUsed": 0,
910 "totalServerGroupsUsed": 0
915 response
= Response(json
.dumps(resp
), status
=200, mimetype
="application/json")
916 response
.headers
['Access-Control-Allow-Origin'] = '*'
919 except Exception as ex
:
920 LOG
.exception(u
"%s: Could not retrieve the list of images." % __name__
)
921 return ex
.message
, 500