From: stevenvanrossem Date: Wed, 16 Nov 2016 22:30:57 +0000 (+0100) Subject: cpu resource control via rest api + unittest including ELAN test X-Git-Tag: v3.1~45^2~31 X-Git-Url: https://osm.etsi.org/gitweb/?p=osm%2Fvim-emu.git;a=commitdiff_plain;h=b3f3417d353e5cb40f2f5f5348792f19feade624 cpu resource control via rest api + unittest including ELAN test --- diff --git a/Vagrantfile b/Vagrantfile old mode 100644 new mode 100755 diff --git a/setup-cli.py b/setup-cli.py old mode 100644 new mode 100755 diff --git a/src/emuvim/api/rest/compute.py b/src/emuvim/api/rest/compute.py index c3680a0..f0c8954 100755 --- a/src/emuvim/api/rest/compute.py +++ b/src/emuvim/api/rest/compute.py @@ -48,8 +48,13 @@ class Compute(Resource): """ global dcs - def put(self, dc_label, compute_name): + def put(self, dc_label, compute_name, resource=None, value=None): + # check if resource update + if resource and value: + c = self._update_resource(dc_label, compute_name, resource, value) + return c.getStatus(), 200 + # deploy new container # check if json data is a dict data = request.json if data is None: @@ -72,6 +77,20 @@ class Compute(Resource): logging.exception("API error.") return ex.message, 500 + def _update_resource(self, dc_label, compute_name, resource, value): + #check if container exists + d = dcs.get(dc_label).net.getNodeByName(compute_name) + if resource == 'cpu': + cpu_period = int(dcs.get(dc_label).net.cpu_period) + cpu_quota = int(cpu_period * float(value)) + #put default values back + if float(value) <= 0: + cpu_period = 100000 + cpu_quota = -1 + d.updateCpuLimit(cpu_period=cpu_period, cpu_quota=cpu_quota) + return d + + def get(self, dc_label, compute_name): logging.debug("API CALL: compute status") diff --git a/src/emuvim/api/rest/rest_api_endpoint.py b/src/emuvim/api/rest/rest_api_endpoint.py index e382f5a..a065e16 100755 --- a/src/emuvim/api/rest/rest_api_endpoint.py +++ b/src/emuvim/api/rest/rest_api_endpoint.py @@ -61,7 +61,9 @@ class RestApiEndpoint(object): # setup endpoints - self.api.add_resource(Compute, "/restapi/compute//") + self.api.add_resource(Compute, + "/restapi/compute//", + "/restapi/compute////") self.api.add_resource(ComputeList, "/restapi/compute", "/restapi/compute/") diff --git a/src/emuvim/dcemulator/net.py b/src/emuvim/dcemulator/net.py index 731331b..3b4dd54 100755 --- a/src/emuvim/dcemulator/net.py +++ b/src/emuvim/dcemulator/net.py @@ -47,6 +47,9 @@ from emuvim.dcemulator.resourcemodel import ResourceModelRegistrar LOG = logging.getLogger("dcemulator.net") LOG.setLevel(logging.DEBUG) +# default CPU period used for cpu percentage-based cfs values (microseconds) +CPU_PERIOD = 1000000 + class DCNetwork(Containernet): """ Wraps the original Mininet/Containernet class and provides @@ -56,7 +59,7 @@ class DCNetwork(Containernet): """ def __init__(self, controller=RemoteController, monitor=False, - enable_learning=False, # learning switch behavior of the default ovs switches icw Ryu controller can be turned off/on, neede for E-LAN functionality + enable_learning=False, # learning switch behavior of the default ovs switches icw Ryu controller can be turned off/on, needed for E-LAN functionality dc_emulation_max_cpu=1.0, # fraction of overall CPU time for emulation dc_emulation_max_mem=512, # emulation max mem in MB **kwargs): @@ -121,6 +124,7 @@ class DCNetwork(Containernet): # initialize resource model registrar self.rm_registrar = ResourceModelRegistrar( dc_emulation_max_cpu, dc_emulation_max_mem) + self.cpu_period = CPU_PERIOD def addDatacenter(self, label, metadata={}, resource_log_path=None): """ diff --git a/src/emuvim/dcemulator/node.py b/src/emuvim/dcemulator/node.py index 8219761..8e7a63a 100755 --- a/src/emuvim/dcemulator/node.py +++ b/src/emuvim/dcemulator/node.py @@ -38,7 +38,6 @@ LOG.setLevel(logging.DEBUG) DCDPID_BASE = 1000 # start of switch dpid's used for data center switches - class EmulatorCompute(Docker): """ Emulator specific compute node class. @@ -148,7 +147,7 @@ class Datacenter(object): def start(self): pass - def startCompute(self, name, image=None, command=None, network=None, flavor_name="tiny"): + def startCompute(self, name, image=None, command=None, network=None, flavor_name="tiny", **kwargs): """ Create a new container as compute resource and connect it to this data center. @@ -174,15 +173,28 @@ class Datacenter(object): if len(network) < 1: network.append({}) + # apply hard-set resource limits=0 + cpu_percentage = kwargs.get('cpu_percent') + if cpu_percentage: + cpu_period = self.net.cpu_period + cpu_quota = self.net.cpu_period * float(cpu_percentage) + else: + cpu_quota = None + cpu_period = None + # create the container d = self.net.addDocker( "%s" % (name), dimage=image, dcmd=command, datacenter=self, - flavor_name=flavor_name + flavor_name=flavor_name, + cpu_period = cpu_period, + cpu_quota = cpu_quota ) + + # apply resource limits to container if a resource model is defined if self._resource_model is not None: try: diff --git a/src/emuvim/test/unittests/test_sonata_dummy_gatekeeper.py b/src/emuvim/test/unittests/test_sonata_dummy_gatekeeper.py index 2e01d92..053fdb6 100755 --- a/src/emuvim/test/unittests/test_sonata_dummy_gatekeeper.py +++ b/src/emuvim/test/unittests/test_sonata_dummy_gatekeeper.py @@ -44,7 +44,7 @@ class testSonataDummyGatekeeper(SimpleTestTopology): # @unittest.skip("disabled") def test_GK_Api_start_service(self): # create network - self.createNet(nswitches=0, ndatacenter=2, nhosts=2, ndockers=0) + self.createNet(nswitches=0, ndatacenter=2, nhosts=2, ndockers=0, enable_learning=True) # setup links self.net.addLink(self.dc[0], self.h[0]) self.net.addLink(self.dc[0], self.dc[1]) @@ -87,10 +87,37 @@ class testSonataDummyGatekeeper(SimpleTestTopology): # check compute list result self.assertEqual(len(self.dc[0].listCompute()), 2) # check connectivity by using ping + ELAN_list=[] + for i in [0]: + for vnf in self.dc[i].listCompute(): + # check connection + p = self.net.ping([self.h[i], vnf]) + print p + self.assertTrue(p <= 0.0) + + # check E LAN connection + network_list = vnf.getNetworkStatus() + mgmt_ip = [intf['ip'] for intf in network_list if intf['intf_name'] == 'mgmt'] + self.assertTrue(len(mgmt_ip) > 0) + ip_address = mgmt_ip[0] + ELAN_list.append(ip_address) + print ip_address + + # check ELAN connection by ping over the mgmt network (needs to be configured as ELAN in the test service) for vnf in self.dc[0].listCompute(): - p = self.net.ping([self.h[0], vnf]) - print p -# self.assertTrue(p <= 50.0) + network_list = vnf.getNetworkStatus() + mgmt_ip = [intf['ip'] for intf in network_list if intf['intf_name'] == 'mgmt'] + self.assertTrue(len(mgmt_ip) > 0) + ip_address = mgmt_ip[0] + print ELAN_list + print ip_address + test_ip_list = list(ELAN_list) + test_ip_list.remove(ip_address) + for ip in test_ip_list: + p = self.net.ping([vnf],manualdestip=ip) + print p + self.assertTrue(p <= 0.0) + # stop Mininet network self.stopNet() initialize_GK()