blob: c0cf0c45733aa5e322043d198e48f8bda12f3cdd [file] [log] [blame]
peusterm72f09882018-05-15 17:10:27 +02001# Copyright (c) 2015 SONATA-NFV and Paderborn University
2# ALL RIGHTS RESERVED.
3#
4# Licensed under the Apache License, Version 2.0 (the "License");
5# you may not use this file except in compliance with the License.
6# You may obtain a copy of the License at
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS,
12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13# See the License for the specific language governing permissions and
14# limitations under the License.
15#
16# Neither the name of the SONATA-NFV, Paderborn University
17# nor the names of its contributors may be used to endorse or promote
18# products derived from this software without specific prior written
19# permission.
20#
21# This work has been performed in the framework of the SONATA project,
22# funded by the European Commission under Grant number 671517 through
23# the Horizon 2020 and 5G-PPP programmes. The authors would like to
24# acknowledge the contributions of their colleagues of the SONATA
25# partner consortium (www.sonata-nfv.eu).
peusterm43485a22016-03-14 11:18:37 +010026import time
peusterm3055e702016-04-16 16:48:12 +020027import os
peustermc1305232016-05-11 16:14:22 +020028import unittest
peusterm5c6475c2016-03-13 12:54:11 +010029from emuvim.test.base import SimpleTestTopology
peusterma41f7862016-04-27 11:01:24 +020030from emuvim.dcemulator.resourcemodel import BaseResourceModel, ResourceFlavor, NotEnoughResourcesAvailable, ResourceModelRegistrar
peusterm8687cb72016-04-28 20:32:36 +020031from emuvim.dcemulator.resourcemodel.upb.simple import UpbSimpleCloudDcRM, UpbOverprovisioningCloudDcRM, UpbDummyRM
peusterma41f7862016-04-27 11:01:24 +020032
peusterm5c6475c2016-03-13 12:54:11 +010033
peusterm5c6475c2016-03-13 12:54:11 +010034class testResourceModel(SimpleTestTopology):
peustermbdcf2d22016-03-25 12:14:15 +010035 """
36 Test the general resource model API and functionality.
37 """
peusterm5c6475c2016-03-13 12:54:11 +010038
39 def testBaseResourceModelApi(self):
peustermbdcf2d22016-03-25 12:14:15 +010040 """
41 Tast bare API without real resource madel.
42 :return:
43 """
peusterm43485a22016-03-14 11:18:37 +010044 r = BaseResourceModel()
45 # check if default flavors are there
peustermbdcf2d22016-03-25 12:14:15 +010046 self.assertTrue(len(r._flavors) == 5)
peusterm43485a22016-03-14 11:18:37 +010047 # check addFlavor functionality
48 f = ResourceFlavor("test", {"testmetric": 42})
49 r.addFlavour(f)
peustermbdcf2d22016-03-25 12:14:15 +010050 self.assertTrue("test" in r._flavors)
51 self.assertTrue(r._flavors.get("test").get("testmetric") == 42)
peusterm5c6475c2016-03-13 12:54:11 +010052
53 def testAddRmToDc(self):
peustermbdcf2d22016-03-25 12:14:15 +010054 """
55 Test is allocate/free is called when a RM is added to a DC.
56 :return:
57 """
peusterm5c6475c2016-03-13 12:54:11 +010058 # create network
59 self.createNet(nswitches=0, ndatacenter=1, nhosts=2, ndockers=0)
60 # setup links
61 self.net.addLink(self.dc[0], self.h[0])
62 self.net.addLink(self.h[1], self.dc[0])
63 # add resource model
64 r = BaseResourceModel()
65 self.dc[0].assignResourceModel(r)
66 # start Mininet network
67 self.startNet()
68 # check number of running nodes
peusterm5877ea22016-05-11 13:44:59 +020069 self.assertTrue(len(self.getContainernetContainers()) == 0)
peustermbdcf2d22016-03-25 12:14:15 +010070 self.assertTrue(len(self.net.hosts) == 2)
71 self.assertTrue(len(self.net.switches) == 1)
peusterm5c6475c2016-03-13 12:54:11 +010072 # check resource model and resource model registrar
peustermbdcf2d22016-03-25 12:14:15 +010073 self.assertTrue(self.dc[0]._resource_model is not None)
74 self.assertTrue(len(self.net.rm_registrar.resource_models) == 1)
peusterm43485a22016-03-14 11:18:37 +010075
76 # check if alloc was called during startCompute
peustermd18559d2016-04-16 04:59:23 +020077 self.assertTrue(len(r._allocated_compute_instances) == 0)
peusterm43485a22016-03-14 11:18:37 +010078 self.dc[0].startCompute("tc1")
79 time.sleep(1)
peustermd18559d2016-04-16 04:59:23 +020080 self.assertTrue(len(r._allocated_compute_instances) == 1)
peusterm43485a22016-03-14 11:18:37 +010081 # check if free was called during stopCompute
82 self.dc[0].stopCompute("tc1")
peustermd18559d2016-04-16 04:59:23 +020083 self.assertTrue(len(r._allocated_compute_instances) == 0)
peusterm5c6475c2016-03-13 12:54:11 +010084 # check connectivity by using ping
peustermbdcf2d22016-03-25 12:14:15 +010085 self.assertTrue(self.net.ping([self.h[0], self.h[1]]) <= 0.0)
peusterm5c6475c2016-03-13 12:54:11 +010086 # stop Mininet network
87 self.stopNet()
peusterm279565d2016-03-19 10:36:52 +010088
89
peustermd18559d2016-04-16 04:59:23 +020090def createDummyContainerObject(name, flavor):
91
92 class DummyContainer(object):
93
94 def __init__(self):
stevenvanrossem33d76892017-02-13 00:13:37 +010095 # take defaukt values from son-emu
stevenvanrossemb2a29bf2017-02-14 14:27:44 +010096 self.resources = dict(
peusterm72f09882018-05-15 17:10:27 +020097 cpu_period=-1,
98 cpu_quota=-1,
99 mem_limit=-1,
100 memswap_limit=-1
stevenvanrossemb2a29bf2017-02-14 14:27:44 +0100101 )
peusterm72f09882018-05-15 17:10:27 +0200102 # self.cpu_period = self.resources['cpu_period']
103 # self.cpu_quota = self.resources['cpu_quota']
104 # self.mem_limit = self.resources['mem_limit']
105 # self.memswap_limit = self.resources['memswap_limit']
peustermd18559d2016-04-16 04:59:23 +0200106
107 def updateCpuLimit(self, cpu_period, cpu_quota):
stevenvanrossemb2a29bf2017-02-14 14:27:44 +0100108 self.resources['cpu_period'] = cpu_period
109 self.resources['cpu_quota'] = cpu_quota
peustermd18559d2016-04-16 04:59:23 +0200110
111 def updateMemoryLimit(self, mem_limit):
stevenvanrossemb2a29bf2017-02-14 14:27:44 +0100112 self.resources['mem_limit'] = mem_limit
peustermd18559d2016-04-16 04:59:23 +0200113
114 d = DummyContainer()
115 d.name = name
116 d.flavor_name = flavor
117 return d
118
119
peusterm279565d2016-03-19 10:36:52 +0100120class testUpbSimpleCloudDcRM(SimpleTestTopology):
121 """
122 Test the UpbSimpleCloudDc resource model.
123 """
peustermbdcf2d22016-03-25 12:14:15 +0100124
peusterm72fc3732016-04-26 19:48:43 +0200125 def testAllocationComputations(self):
peustermbdcf2d22016-03-25 12:14:15 +0100126 """
127 Test the allocation procedures and correct calculations.
128 :return:
129 """
peusterm279565d2016-03-19 10:36:52 +0100130 # config
131 E_CPU = 1.0
132 MAX_CU = 100
peusterm972a9f02016-03-25 14:58:05 +0100133 E_MEM = 512
134 MAX_MU = 2048
peusterm279565d2016-03-19 10:36:52 +0100135 # create dummy resource model environment
peusterm72f09882018-05-15 17:10:27 +0200136 reg = ResourceModelRegistrar(
137 dc_emulation_max_cpu=E_CPU, dc_emulation_max_mem=E_MEM)
peusterm972a9f02016-03-25 14:58:05 +0100138 rm = UpbSimpleCloudDcRM(max_cu=MAX_CU, max_mu=MAX_MU)
peusterm279565d2016-03-19 10:36:52 +0100139 reg.register("test_dc", rm)
140
peustermd18559d2016-04-16 04:59:23 +0200141 c1 = createDummyContainerObject("c1", flavor="tiny")
142 rm.allocate(c1) # calculate allocation
peusterm72f09882018-05-15 17:10:27 +0200143 # validate compute result
144 self.assertEqual(float(
145 c1.resources['cpu_quota']) / c1.resources['cpu_period'], E_CPU / MAX_CU * 0.5)
146 # validate memory result
147 self.assertEqual(
148 float(c1.resources['mem_limit'] / 1024 / 1024), float(E_MEM) / MAX_MU * 32)
peusterm279565d2016-03-19 10:36:52 +0100149
peustermd18559d2016-04-16 04:59:23 +0200150 c2 = createDummyContainerObject("c2", flavor="small")
151 rm.allocate(c2) # calculate allocation
peusterm72f09882018-05-15 17:10:27 +0200152 # validate compute result
153 self.assertEqual(float(
154 c2.resources['cpu_quota']) / c2.resources['cpu_period'], E_CPU / MAX_CU * 1)
155 # validate memory result
156 self.assertEqual(
157 float(c2.resources['mem_limit'] / 1024 / 1024), float(E_MEM) / MAX_MU * 128)
peusterm279565d2016-03-19 10:36:52 +0100158
peustermd18559d2016-04-16 04:59:23 +0200159 c3 = createDummyContainerObject("c3", flavor="medium")
peusterm72fc3732016-04-26 19:48:43 +0200160 rm.allocate(c3) # calculate allocation
peusterm72f09882018-05-15 17:10:27 +0200161 # validate compute result
162 self.assertEqual(float(
163 c3.resources['cpu_quota']) / c3.resources['cpu_period'], E_CPU / MAX_CU * 4)
164 # validate memory result
165 self.assertEqual(
166 float(c3.resources['mem_limit'] / 1024 / 1024), float(E_MEM) / MAX_MU * 256)
peusterm279565d2016-03-19 10:36:52 +0100167
peustermd18559d2016-04-16 04:59:23 +0200168 c4 = createDummyContainerObject("c4", flavor="large")
169 rm.allocate(c4) # calculate allocation
peusterm72f09882018-05-15 17:10:27 +0200170 # validate compute result
171 self.assertEqual(float(
172 c4.resources['cpu_quota']) / c4.resources['cpu_period'], E_CPU / MAX_CU * 8)
173 # validate memory result
174 self.assertEqual(
175 float(c4.resources['mem_limit'] / 1024 / 1024), float(E_MEM) / MAX_MU * 512)
peustermd18559d2016-04-16 04:59:23 +0200176
peustermd18559d2016-04-16 04:59:23 +0200177 c5 = createDummyContainerObject("c5", flavor="xlarge")
178 rm.allocate(c5) # calculate allocation
peusterm72f09882018-05-15 17:10:27 +0200179 # validate compute result
180 self.assertEqual(float(
181 c5.resources['cpu_quota']) / c5.resources['cpu_period'], E_CPU / MAX_CU * 16)
182 # validate memory result
183 self.assertEqual(
184 float(c5.resources['mem_limit'] / 1024 / 1024), float(E_MEM) / MAX_MU * 1024)
peusterm279565d2016-03-19 10:36:52 +0100185
peusterm972a9f02016-03-25 14:58:05 +0100186 def testAllocationCpuLimit(self):
187 """
188 Test CPU allocation limit
189 :return:
190 """
191 # config
192 E_CPU = 1.0
peusterm60bf8b82016-04-06 14:12:35 +0200193 MAX_CU = 40
peusterm972a9f02016-03-25 14:58:05 +0100194 E_MEM = 512
195 MAX_MU = 4096
196 # create dummy resource model environment
peusterm72f09882018-05-15 17:10:27 +0200197 reg = ResourceModelRegistrar(
198 dc_emulation_max_cpu=E_CPU, dc_emulation_max_mem=E_MEM)
peusterm972a9f02016-03-25 14:58:05 +0100199 rm = UpbSimpleCloudDcRM(max_cu=MAX_CU, max_mu=MAX_MU)
200 reg.register("test_dc", rm)
201
peusterm279565d2016-03-19 10:36:52 +0100202 # test over provisioning exeption
203 exception = False
204 try:
peustermd18559d2016-04-16 04:59:23 +0200205 c6 = createDummyContainerObject("c6", flavor="xlarge")
206 c7 = createDummyContainerObject("c7", flavor="xlarge")
207 c8 = createDummyContainerObject("c8", flavor="xlarge")
208 c9 = createDummyContainerObject("c9", flavor="xlarge")
209 rm.allocate(c6) # calculate allocation
210 rm.allocate(c7) # calculate allocation
211 rm.allocate(c8) # calculate allocation
212 rm.allocate(c9) # calculate allocation
peusterma41f7862016-04-27 11:01:24 +0200213 except NotEnoughResourcesAvailable as e:
peusterm972a9f02016-03-25 14:58:05 +0100214 self.assertIn("Not enough compute", e.message)
215 exception = True
216 self.assertTrue(exception)
217
218 def testAllocationMemLimit(self):
219 """
220 Test MEM allocation limit
221 :return:
222 """
223 # config
224 E_CPU = 1.0
225 MAX_CU = 500
226 E_MEM = 512
227 MAX_MU = 2048
228 # create dummy resource model environment
peusterm72f09882018-05-15 17:10:27 +0200229 reg = ResourceModelRegistrar(
230 dc_emulation_max_cpu=E_CPU, dc_emulation_max_mem=E_MEM)
peusterm972a9f02016-03-25 14:58:05 +0100231 rm = UpbSimpleCloudDcRM(max_cu=MAX_CU, max_mu=MAX_MU)
232 reg.register("test_dc", rm)
233
234 # test over provisioning exeption
235 exception = False
236 try:
peustermd18559d2016-04-16 04:59:23 +0200237 c6 = createDummyContainerObject("c6", flavor="xlarge")
238 c7 = createDummyContainerObject("c7", flavor="xlarge")
239 c8 = createDummyContainerObject("c8", flavor="xlarge")
240 rm.allocate(c6) # calculate allocation
241 rm.allocate(c7) # calculate allocation
242 rm.allocate(c8) # calculate allocation
peusterma41f7862016-04-27 11:01:24 +0200243 except NotEnoughResourcesAvailable as e:
peusterm972a9f02016-03-25 14:58:05 +0100244 self.assertIn("Not enough memory", e.message)
peusterm279565d2016-03-19 10:36:52 +0100245 exception = True
peustermbdcf2d22016-03-25 12:14:15 +0100246 self.assertTrue(exception)
peusterm279565d2016-03-19 10:36:52 +0100247
248 def testFree(self):
peustermbdcf2d22016-03-25 12:14:15 +0100249 """
250 Test the free procedure.
251 :return:
252 """
peusterm279565d2016-03-19 10:36:52 +0100253 # create dummy resource model environment
peusterm72f09882018-05-15 17:10:27 +0200254 reg = ResourceModelRegistrar(
255 dc_emulation_max_cpu=1.0, dc_emulation_max_mem=512)
peusterm279565d2016-03-19 10:36:52 +0100256 rm = UpbSimpleCloudDcRM(max_cu=100, max_mu=100)
257 reg.register("test_dc", rm)
peustermd18559d2016-04-16 04:59:23 +0200258 c1 = createDummyContainerObject("c6", flavor="tiny")
259 rm.allocate(c1) # calculate allocation
peusterm60bf8b82016-04-06 14:12:35 +0200260 self.assertTrue(rm.dc_alloc_cu == 0.5)
peustermd18559d2016-04-16 04:59:23 +0200261 rm.free(c1)
peustermbdcf2d22016-03-25 12:14:15 +0100262 self.assertTrue(rm.dc_alloc_cu == 0)
263
peustermc1305232016-05-11 16:14:22 +0200264 @unittest.skipIf(os.environ.get("SON_EMU_IN_DOCKER") is not None,
265 "skipping test when running inside Docker container")
peustermbdcf2d22016-03-25 12:14:15 +0100266 def testInRealTopo(self):
267 """
peusterm5877ea22016-05-11 13:44:59 +0200268 Start a real container and check if limitations are really passed down to Conteinernet.
peustermbdcf2d22016-03-25 12:14:15 +0100269 :return:
270 """
271 # create network
272 self.createNet(nswitches=0, ndatacenter=1, nhosts=2, ndockers=0)
273 # setup links
274 self.net.addLink(self.dc[0], self.h[0])
275 self.net.addLink(self.h[1], self.dc[0])
276 # add resource model
277 r = UpbSimpleCloudDcRM(max_cu=100, max_mu=100)
278 self.dc[0].assignResourceModel(r)
279 # start Mininet network
280 self.startNet()
281 # check number of running nodes
peusterm5877ea22016-05-11 13:44:59 +0200282 self.assertTrue(len(self.getContainernetContainers()) == 0)
peustermbdcf2d22016-03-25 12:14:15 +0100283 self.assertTrue(len(self.net.hosts) == 2)
284 self.assertTrue(len(self.net.switches) == 1)
285 # check resource model and resource model registrar
286 self.assertTrue(self.dc[0]._resource_model is not None)
287 self.assertTrue(len(self.net.rm_registrar.resource_models) == 1)
288
289 # check if alloc was called during startCompute
peustermd18559d2016-04-16 04:59:23 +0200290 self.assertTrue(len(r._allocated_compute_instances) == 0)
peustermbdcf2d22016-03-25 12:14:15 +0100291 tc1 = self.dc[0].startCompute("tc1", flavor_name="tiny")
292 time.sleep(1)
peustermd18559d2016-04-16 04:59:23 +0200293 self.assertTrue(len(r._allocated_compute_instances) == 1)
peustermbdcf2d22016-03-25 12:14:15 +0100294
295 # check if there is a real limitation set for containers cgroup
peusterm72f09882018-05-15 17:10:27 +0200296 # deactivated for now, seems not to work in docker-in-docker setup used
297 # in CI
298 self.assertEqual(
299 float(tc1.resources['cpu_quota']) / tc1.resources['cpu_period'], 0.005)
peustermbdcf2d22016-03-25 12:14:15 +0100300
301 # check if free was called during stopCompute
302 self.dc[0].stopCompute("tc1")
peustermd18559d2016-04-16 04:59:23 +0200303 self.assertTrue(len(r._allocated_compute_instances) == 0)
peustermbdcf2d22016-03-25 12:14:15 +0100304 # check connectivity by using ping
305 self.assertTrue(self.net.ping([self.h[0], self.h[1]]) <= 0.0)
306 # stop Mininet network
307 self.stopNet()
peusterm279565d2016-03-19 10:36:52 +0100308
309
peusterm72fc3732016-04-26 19:48:43 +0200310class testUpbOverprovisioningCloudDcRM(SimpleTestTopology):
311 """
312 Test the UpbOverprovisioningCloudDc resource model.
313 """
314
315 def testAllocationComputations(self):
316 """
317 Test the allocation procedures and correct calculations.
318 :return:
319 """
320 # config
321 E_CPU = 1.0
322 MAX_CU = 3
323 E_MEM = 512
324 MAX_MU = 2048
325 # create dummy resource model environment
peusterm72f09882018-05-15 17:10:27 +0200326 reg = ResourceModelRegistrar(
327 dc_emulation_max_cpu=E_CPU, dc_emulation_max_mem=E_MEM)
peusterm72fc3732016-04-26 19:48:43 +0200328 rm = UpbOverprovisioningCloudDcRM(max_cu=MAX_CU, max_mu=MAX_MU)
329 reg.register("test_dc", rm)
330
331 c1 = createDummyContainerObject("c1", flavor="small")
332 rm.allocate(c1) # calculate allocation
peusterm72f09882018-05-15 17:10:27 +0200333 self.assertAlmostEqual(float(
334 c1.resources['cpu_quota']) / c1.resources['cpu_period'], E_CPU / MAX_CU * 1.0, places=5)
335 self.assertAlmostEqual(
336 float(c1.resources['mem_limit'] / 1024 / 1024), float(E_MEM) / MAX_MU * 128)
peusterm72fc3732016-04-26 19:48:43 +0200337 self.assertAlmostEqual(rm.cpu_op_factor, 1.0)
338
339 c2 = createDummyContainerObject("c2", flavor="small")
340 rm.allocate(c2) # calculate allocation
peusterm72f09882018-05-15 17:10:27 +0200341 self.assertAlmostEqual(float(
342 c2.resources['cpu_quota']) / c2.resources['cpu_period'], E_CPU / MAX_CU * 1.0, places=5)
343 self.assertAlmostEqual(
344 float(c2.resources['mem_limit'] / 1024 / 1024), float(E_MEM) / MAX_MU * 128)
peusterm72fc3732016-04-26 19:48:43 +0200345 self.assertAlmostEqual(rm.cpu_op_factor, 1.0)
346
347 c3 = createDummyContainerObject("c3", flavor="small")
348 rm.allocate(c3) # calculate allocation
peusterm72f09882018-05-15 17:10:27 +0200349 self.assertAlmostEqual(float(
350 c3.resources['cpu_quota']) / c3.resources['cpu_period'], E_CPU / MAX_CU * 1.0, places=5)
351 self.assertAlmostEqual(
352 float(c3.resources['mem_limit'] / 1024 / 1024), float(E_MEM) / MAX_MU * 128)
peusterm72fc3732016-04-26 19:48:43 +0200353 self.assertAlmostEqual(rm.cpu_op_factor, 1.0)
354
355 # from this container onwards, we should go to over provisioning mode:
356 c4 = createDummyContainerObject("c4", flavor="small")
357 rm.allocate(c4) # calculate allocation
peusterm72f09882018-05-15 17:10:27 +0200358 self.assertAlmostEqual(float(
359 c4.resources['cpu_quota']) / c4.resources['cpu_period'], E_CPU / MAX_CU * (float(3) / 4), places=5)
360 self.assertAlmostEqual(float(
361 c4.resources['mem_limit'] / 1024 / 1024), float(E_MEM) / MAX_MU * 128, places=5)
peusterm72fc3732016-04-26 19:48:43 +0200362 self.assertAlmostEqual(rm.cpu_op_factor, 0.75)
363
364 c5 = createDummyContainerObject("c5", flavor="small")
365 rm.allocate(c5) # calculate allocation
peusterm72f09882018-05-15 17:10:27 +0200366 self.assertAlmostEqual(float(
367 c5.resources['cpu_quota']) / c5.resources['cpu_period'], E_CPU / MAX_CU * (float(3) / 5), places=5)
368 self.assertAlmostEqual(
369 float(c5.resources['mem_limit'] / 1024 / 1024), float(E_MEM) / MAX_MU * 128)
peusterm72fc3732016-04-26 19:48:43 +0200370 self.assertAlmostEqual(rm.cpu_op_factor, 0.6)
371
372
peusterm8687cb72016-04-28 20:32:36 +0200373class testUpbDummyRM(SimpleTestTopology):
374 """
375 Test the UpbDummyRM resource model.
376 """
377
378 def testAllocationComputations(self):
379 """
380 Test the allocation procedures and correct calculations.
381 :return:
382 """
383 # config
384 E_CPU = 1.0
385 MAX_CU = 3
386 E_MEM = 512
387 MAX_MU = 2048
388 # create dummy resource model environment
peusterm72f09882018-05-15 17:10:27 +0200389 reg = ResourceModelRegistrar(
390 dc_emulation_max_cpu=E_CPU, dc_emulation_max_mem=E_MEM)
peusterm8687cb72016-04-28 20:32:36 +0200391 rm = UpbDummyRM(max_cu=MAX_CU, max_mu=MAX_MU)
392 reg.register("test_dc", rm)
393
394 c1 = createDummyContainerObject("c1", flavor="small")
395 rm.allocate(c1) # calculate allocation
396 self.assertEqual(len(rm._allocated_compute_instances), 1)
397
398 c2 = createDummyContainerObject("c2", flavor="small")
399 rm.allocate(c2) # calculate allocation
400 self.assertEqual(len(rm._allocated_compute_instances), 2)