blob: b15fed08bfb4696980e80bad512e898d0ff7e045 [file] [log] [blame]
peustermc89ba382016-07-08 13:46:32 +02001"""
2Copyright (c) 2015 SONATA-NFV
3ALL RIGHTS RESERVED.
4
5Licensed under the Apache License, Version 2.0 (the "License");
6you may not use this file except in compliance with the License.
7You may obtain a copy of the License at
8
9 http://www.apache.org/licenses/LICENSE-2.0
10
11Unless required by applicable law or agreed to in writing, software
12distributed under the License is distributed on an "AS IS" BASIS,
13WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14See the License for the specific language governing permissions and
15limitations under the License.
16
17Neither the name of the SONATA-NFV [, ANY ADDITIONAL AFFILIATION]
18nor the names of its contributors may be used to endorse or promote
19products derived from this software without specific prior written
20permission.
21
22This work has been performed in the framework of the SONATA project,
23funded by the European Commission under Grant number 671517 through
24the Horizon 2020 and 5G-PPP programmes. The authors would like to
25acknowledge the contributions of their colleagues of the SONATA
26partner consortium (www.sonata-nfv.eu).
27"""
28
peusterm43485a22016-03-14 11:18:37 +010029import time
peusterm3055e702016-04-16 16:48:12 +020030import os
peustermc1305232016-05-11 16:14:22 +020031import unittest
peusterm5c6475c2016-03-13 12:54:11 +010032from emuvim.test.base import SimpleTestTopology
peusterma41f7862016-04-27 11:01:24 +020033from emuvim.dcemulator.resourcemodel import BaseResourceModel, ResourceFlavor, NotEnoughResourcesAvailable, ResourceModelRegistrar
peusterm8687cb72016-04-28 20:32:36 +020034from emuvim.dcemulator.resourcemodel.upb.simple import UpbSimpleCloudDcRM, UpbOverprovisioningCloudDcRM, UpbDummyRM
peusterma41f7862016-04-27 11:01:24 +020035
peusterm5c6475c2016-03-13 12:54:11 +010036
37
38class testResourceModel(SimpleTestTopology):
peustermbdcf2d22016-03-25 12:14:15 +010039 """
40 Test the general resource model API and functionality.
41 """
peusterm5c6475c2016-03-13 12:54:11 +010042
43 def testBaseResourceModelApi(self):
peustermbdcf2d22016-03-25 12:14:15 +010044 """
45 Tast bare API without real resource madel.
46 :return:
47 """
peusterm43485a22016-03-14 11:18:37 +010048 r = BaseResourceModel()
49 # check if default flavors are there
peustermbdcf2d22016-03-25 12:14:15 +010050 self.assertTrue(len(r._flavors) == 5)
peusterm43485a22016-03-14 11:18:37 +010051 # check addFlavor functionality
52 f = ResourceFlavor("test", {"testmetric": 42})
53 r.addFlavour(f)
peustermbdcf2d22016-03-25 12:14:15 +010054 self.assertTrue("test" in r._flavors)
55 self.assertTrue(r._flavors.get("test").get("testmetric") == 42)
peusterm5c6475c2016-03-13 12:54:11 +010056
57 def testAddRmToDc(self):
peustermbdcf2d22016-03-25 12:14:15 +010058 """
59 Test is allocate/free is called when a RM is added to a DC.
60 :return:
61 """
peusterm5c6475c2016-03-13 12:54:11 +010062 # create network
63 self.createNet(nswitches=0, ndatacenter=1, nhosts=2, ndockers=0)
64 # setup links
65 self.net.addLink(self.dc[0], self.h[0])
66 self.net.addLink(self.h[1], self.dc[0])
67 # add resource model
68 r = BaseResourceModel()
69 self.dc[0].assignResourceModel(r)
70 # start Mininet network
71 self.startNet()
72 # check number of running nodes
peusterm5877ea22016-05-11 13:44:59 +020073 self.assertTrue(len(self.getContainernetContainers()) == 0)
peustermbdcf2d22016-03-25 12:14:15 +010074 self.assertTrue(len(self.net.hosts) == 2)
75 self.assertTrue(len(self.net.switches) == 1)
peusterm5c6475c2016-03-13 12:54:11 +010076 # check resource model and resource model registrar
peustermbdcf2d22016-03-25 12:14:15 +010077 self.assertTrue(self.dc[0]._resource_model is not None)
78 self.assertTrue(len(self.net.rm_registrar.resource_models) == 1)
peusterm43485a22016-03-14 11:18:37 +010079
80 # check if alloc was called during startCompute
peustermd18559d2016-04-16 04:59:23 +020081 self.assertTrue(len(r._allocated_compute_instances) == 0)
peusterm43485a22016-03-14 11:18:37 +010082 self.dc[0].startCompute("tc1")
83 time.sleep(1)
peustermd18559d2016-04-16 04:59:23 +020084 self.assertTrue(len(r._allocated_compute_instances) == 1)
peusterm43485a22016-03-14 11:18:37 +010085 # check if free was called during stopCompute
86 self.dc[0].stopCompute("tc1")
peustermd18559d2016-04-16 04:59:23 +020087 self.assertTrue(len(r._allocated_compute_instances) == 0)
peusterm5c6475c2016-03-13 12:54:11 +010088 # check connectivity by using ping
peustermbdcf2d22016-03-25 12:14:15 +010089 self.assertTrue(self.net.ping([self.h[0], self.h[1]]) <= 0.0)
peusterm5c6475c2016-03-13 12:54:11 +010090 # stop Mininet network
91 self.stopNet()
peusterm279565d2016-03-19 10:36:52 +010092
93
peustermd18559d2016-04-16 04:59:23 +020094def createDummyContainerObject(name, flavor):
95
96 class DummyContainer(object):
97
98 def __init__(self):
99 self.cpu_period = -1
100 self.cpu_quota = -1
101 self.mem_limit = -1
102 self.memswap_limit = -1
103
104 def updateCpuLimit(self, cpu_period, cpu_quota):
105 self.cpu_period = cpu_period
106 self.cpu_quota = cpu_quota
107
108 def updateMemoryLimit(self, mem_limit):
109 self.mem_limit = mem_limit
110
111 d = DummyContainer()
112 d.name = name
113 d.flavor_name = flavor
114 return d
115
116
117
118
peusterm279565d2016-03-19 10:36:52 +0100119class testUpbSimpleCloudDcRM(SimpleTestTopology):
120 """
121 Test the UpbSimpleCloudDc resource model.
122 """
peustermbdcf2d22016-03-25 12:14:15 +0100123
peusterm72fc3732016-04-26 19:48:43 +0200124 def testAllocationComputations(self):
peustermbdcf2d22016-03-25 12:14:15 +0100125 """
126 Test the allocation procedures and correct calculations.
127 :return:
128 """
peusterm279565d2016-03-19 10:36:52 +0100129 # config
130 E_CPU = 1.0
131 MAX_CU = 100
peusterm972a9f02016-03-25 14:58:05 +0100132 E_MEM = 512
133 MAX_MU = 2048
peusterm279565d2016-03-19 10:36:52 +0100134 # create dummy resource model environment
peusterm972a9f02016-03-25 14:58:05 +0100135 reg = ResourceModelRegistrar(dc_emulation_max_cpu=E_CPU, dc_emulation_max_mem=E_MEM)
136 rm = UpbSimpleCloudDcRM(max_cu=MAX_CU, max_mu=MAX_MU)
peusterm279565d2016-03-19 10:36:52 +0100137 reg.register("test_dc", rm)
138
peustermd18559d2016-04-16 04:59:23 +0200139 c1 = createDummyContainerObject("c1", flavor="tiny")
140 rm.allocate(c1) # calculate allocation
141 self.assertEqual(float(c1.cpu_quota) / c1.cpu_period, E_CPU / MAX_CU * 0.5) # validate compute result
142 self.assertEqual(float(c1.mem_limit/1024/1024), float(E_MEM) / MAX_MU * 32) # validate memory result
peusterm279565d2016-03-19 10:36:52 +0100143
peustermd18559d2016-04-16 04:59:23 +0200144 c2 = createDummyContainerObject("c2", flavor="small")
145 rm.allocate(c2) # calculate allocation
146 self.assertEqual(float(c2.cpu_quota) / c2.cpu_period, E_CPU / MAX_CU * 1) # validate compute result
147 self.assertEqual(float(c2.mem_limit/1024/1024), float(E_MEM) / MAX_MU * 128) # validate memory result
peusterm279565d2016-03-19 10:36:52 +0100148
peustermd18559d2016-04-16 04:59:23 +0200149 c3 = createDummyContainerObject("c3", flavor="medium")
peusterm72fc3732016-04-26 19:48:43 +0200150 rm.allocate(c3) # calculate allocation
peustermd18559d2016-04-16 04:59:23 +0200151 self.assertEqual(float(c3.cpu_quota) / c3.cpu_period, E_CPU / MAX_CU * 4) # validate compute result
152 self.assertEqual(float(c3.mem_limit/1024/1024), float(E_MEM) / MAX_MU * 256) # validate memory result
peusterm279565d2016-03-19 10:36:52 +0100153
peustermd18559d2016-04-16 04:59:23 +0200154 c4 = createDummyContainerObject("c4", flavor="large")
155 rm.allocate(c4) # calculate allocation
156 self.assertEqual(float(c4.cpu_quota) / c4.cpu_period, E_CPU / MAX_CU * 8) # validate compute result
157 self.assertEqual(float(c4.mem_limit/1024/1024), float(E_MEM) / MAX_MU * 512) # validate memory result
158
peustermd18559d2016-04-16 04:59:23 +0200159 c5 = createDummyContainerObject("c5", flavor="xlarge")
160 rm.allocate(c5) # calculate allocation
161 self.assertEqual(float(c5.cpu_quota) / c5.cpu_period, E_CPU / MAX_CU * 16) # validate compute result
162 self.assertEqual(float(c5.mem_limit/1024/1024), float(E_MEM) / MAX_MU * 1024) # validate memory result
163
peusterm279565d2016-03-19 10:36:52 +0100164
peusterm972a9f02016-03-25 14:58:05 +0100165 def testAllocationCpuLimit(self):
166 """
167 Test CPU allocation limit
168 :return:
169 """
170 # config
171 E_CPU = 1.0
peusterm60bf8b82016-04-06 14:12:35 +0200172 MAX_CU = 40
peusterm972a9f02016-03-25 14:58:05 +0100173 E_MEM = 512
174 MAX_MU = 4096
175 # create dummy resource model environment
176 reg = ResourceModelRegistrar(dc_emulation_max_cpu=E_CPU, dc_emulation_max_mem=E_MEM)
177 rm = UpbSimpleCloudDcRM(max_cu=MAX_CU, max_mu=MAX_MU)
178 reg.register("test_dc", rm)
179
peusterm279565d2016-03-19 10:36:52 +0100180 # test over provisioning exeption
181 exception = False
182 try:
peustermd18559d2016-04-16 04:59:23 +0200183 c6 = createDummyContainerObject("c6", flavor="xlarge")
184 c7 = createDummyContainerObject("c7", flavor="xlarge")
185 c8 = createDummyContainerObject("c8", flavor="xlarge")
186 c9 = createDummyContainerObject("c9", flavor="xlarge")
187 rm.allocate(c6) # calculate allocation
188 rm.allocate(c7) # calculate allocation
189 rm.allocate(c8) # calculate allocation
190 rm.allocate(c9) # calculate allocation
peusterma41f7862016-04-27 11:01:24 +0200191 except NotEnoughResourcesAvailable as e:
peusterm972a9f02016-03-25 14:58:05 +0100192 self.assertIn("Not enough compute", e.message)
193 exception = True
194 self.assertTrue(exception)
195
196 def testAllocationMemLimit(self):
197 """
198 Test MEM allocation limit
199 :return:
200 """
201 # config
202 E_CPU = 1.0
203 MAX_CU = 500
204 E_MEM = 512
205 MAX_MU = 2048
206 # create dummy resource model environment
207 reg = ResourceModelRegistrar(dc_emulation_max_cpu=E_CPU, dc_emulation_max_mem=E_MEM)
208 rm = UpbSimpleCloudDcRM(max_cu=MAX_CU, max_mu=MAX_MU)
209 reg.register("test_dc", rm)
210
211 # test over provisioning exeption
212 exception = False
213 try:
peustermd18559d2016-04-16 04:59:23 +0200214 c6 = createDummyContainerObject("c6", flavor="xlarge")
215 c7 = createDummyContainerObject("c7", flavor="xlarge")
216 c8 = createDummyContainerObject("c8", flavor="xlarge")
217 rm.allocate(c6) # calculate allocation
218 rm.allocate(c7) # calculate allocation
219 rm.allocate(c8) # calculate allocation
peusterma41f7862016-04-27 11:01:24 +0200220 except NotEnoughResourcesAvailable as e:
peusterm972a9f02016-03-25 14:58:05 +0100221 self.assertIn("Not enough memory", e.message)
peusterm279565d2016-03-19 10:36:52 +0100222 exception = True
peustermbdcf2d22016-03-25 12:14:15 +0100223 self.assertTrue(exception)
peusterm279565d2016-03-19 10:36:52 +0100224
225 def testFree(self):
peustermbdcf2d22016-03-25 12:14:15 +0100226 """
227 Test the free procedure.
228 :return:
229 """
peusterm279565d2016-03-19 10:36:52 +0100230 # config
231 E_CPU = 1.0
232 MAX_CU = 100
233 # create dummy resource model environment
peusterm972a9f02016-03-25 14:58:05 +0100234 reg = ResourceModelRegistrar(dc_emulation_max_cpu=1.0, dc_emulation_max_mem=512)
peusterm279565d2016-03-19 10:36:52 +0100235 rm = UpbSimpleCloudDcRM(max_cu=100, max_mu=100)
236 reg.register("test_dc", rm)
peustermd18559d2016-04-16 04:59:23 +0200237 c1 = createDummyContainerObject("c6", flavor="tiny")
238 rm.allocate(c1) # calculate allocation
peusterm60bf8b82016-04-06 14:12:35 +0200239 self.assertTrue(rm.dc_alloc_cu == 0.5)
peustermd18559d2016-04-16 04:59:23 +0200240 rm.free(c1)
peustermbdcf2d22016-03-25 12:14:15 +0100241 self.assertTrue(rm.dc_alloc_cu == 0)
242
peustermc1305232016-05-11 16:14:22 +0200243 @unittest.skipIf(os.environ.get("SON_EMU_IN_DOCKER") is not None,
244 "skipping test when running inside Docker container")
peustermbdcf2d22016-03-25 12:14:15 +0100245 def testInRealTopo(self):
246 """
peusterm5877ea22016-05-11 13:44:59 +0200247 Start a real container and check if limitations are really passed down to Conteinernet.
peustermbdcf2d22016-03-25 12:14:15 +0100248 :return:
249 """
250 # create network
251 self.createNet(nswitches=0, ndatacenter=1, nhosts=2, ndockers=0)
252 # setup links
253 self.net.addLink(self.dc[0], self.h[0])
254 self.net.addLink(self.h[1], self.dc[0])
255 # add resource model
256 r = UpbSimpleCloudDcRM(max_cu=100, max_mu=100)
257 self.dc[0].assignResourceModel(r)
258 # start Mininet network
259 self.startNet()
260 # check number of running nodes
peusterm5877ea22016-05-11 13:44:59 +0200261 self.assertTrue(len(self.getContainernetContainers()) == 0)
peustermbdcf2d22016-03-25 12:14:15 +0100262 self.assertTrue(len(self.net.hosts) == 2)
263 self.assertTrue(len(self.net.switches) == 1)
264 # check resource model and resource model registrar
265 self.assertTrue(self.dc[0]._resource_model is not None)
266 self.assertTrue(len(self.net.rm_registrar.resource_models) == 1)
267
268 # check if alloc was called during startCompute
peustermd18559d2016-04-16 04:59:23 +0200269 self.assertTrue(len(r._allocated_compute_instances) == 0)
peustermbdcf2d22016-03-25 12:14:15 +0100270 tc1 = self.dc[0].startCompute("tc1", flavor_name="tiny")
271 time.sleep(1)
peustermd18559d2016-04-16 04:59:23 +0200272 self.assertTrue(len(r._allocated_compute_instances) == 1)
peustermbdcf2d22016-03-25 12:14:15 +0100273
274 # check if there is a real limitation set for containers cgroup
peusterm9349c872016-04-16 06:36:42 +0200275 # deactivated for now, seems not to work in docker-in-docker setup used in CI
peusterm3055e702016-04-16 16:48:12 +0200276 self.assertEqual(float(tc1.cpu_quota)/tc1.cpu_period, 0.005)
peustermbdcf2d22016-03-25 12:14:15 +0100277
278 # check if free was called during stopCompute
279 self.dc[0].stopCompute("tc1")
peustermd18559d2016-04-16 04:59:23 +0200280 self.assertTrue(len(r._allocated_compute_instances) == 0)
peustermbdcf2d22016-03-25 12:14:15 +0100281 # check connectivity by using ping
282 self.assertTrue(self.net.ping([self.h[0], self.h[1]]) <= 0.0)
283 # stop Mininet network
284 self.stopNet()
peusterm279565d2016-03-19 10:36:52 +0100285
286
peusterm72fc3732016-04-26 19:48:43 +0200287class testUpbOverprovisioningCloudDcRM(SimpleTestTopology):
288 """
289 Test the UpbOverprovisioningCloudDc resource model.
290 """
291
292 def testAllocationComputations(self):
293 """
294 Test the allocation procedures and correct calculations.
295 :return:
296 """
297 # config
298 E_CPU = 1.0
299 MAX_CU = 3
300 E_MEM = 512
301 MAX_MU = 2048
302 # create dummy resource model environment
303 reg = ResourceModelRegistrar(dc_emulation_max_cpu=E_CPU, dc_emulation_max_mem=E_MEM)
304 rm = UpbOverprovisioningCloudDcRM(max_cu=MAX_CU, max_mu=MAX_MU)
305 reg.register("test_dc", rm)
306
307 c1 = createDummyContainerObject("c1", flavor="small")
308 rm.allocate(c1) # calculate allocation
309 self.assertAlmostEqual(float(c1.cpu_quota) / c1.cpu_period, E_CPU / MAX_CU * 1.0, places=5)
310 self.assertAlmostEqual(float(c1.mem_limit/1024/1024), float(E_MEM) / MAX_MU * 128)
311 self.assertAlmostEqual(rm.cpu_op_factor, 1.0)
312
313 c2 = createDummyContainerObject("c2", flavor="small")
314 rm.allocate(c2) # calculate allocation
315 self.assertAlmostEqual(float(c2.cpu_quota) / c2.cpu_period, E_CPU / MAX_CU * 1.0, places=5)
316 self.assertAlmostEqual(float(c2.mem_limit/1024/1024), float(E_MEM) / MAX_MU * 128)
317 self.assertAlmostEqual(rm.cpu_op_factor, 1.0)
318
319 c3 = createDummyContainerObject("c3", flavor="small")
320 rm.allocate(c3) # calculate allocation
321 self.assertAlmostEqual(float(c3.cpu_quota) / c3.cpu_period, E_CPU / MAX_CU * 1.0, places=5)
322 self.assertAlmostEqual(float(c3.mem_limit/1024/1024), float(E_MEM) / MAX_MU * 128)
323 self.assertAlmostEqual(rm.cpu_op_factor, 1.0)
324
325 # from this container onwards, we should go to over provisioning mode:
326 c4 = createDummyContainerObject("c4", flavor="small")
327 rm.allocate(c4) # calculate allocation
328 self.assertAlmostEqual(float(c4.cpu_quota) / c4.cpu_period, E_CPU / MAX_CU * (float(3) / 4), places=5)
329 self.assertAlmostEqual(float(c4.mem_limit/1024/1024), float(E_MEM) / MAX_MU * 128, places=5)
330 self.assertAlmostEqual(rm.cpu_op_factor, 0.75)
331
332 c5 = createDummyContainerObject("c5", flavor="small")
333 rm.allocate(c5) # calculate allocation
334 self.assertAlmostEqual(float(c5.cpu_quota) / c5.cpu_period, E_CPU / MAX_CU * (float(3) / 5), places=5)
335 self.assertAlmostEqual(float(c5.mem_limit/1024/1024), float(E_MEM) / MAX_MU * 128)
336 self.assertAlmostEqual(rm.cpu_op_factor, 0.6)
337
338
peusterm8687cb72016-04-28 20:32:36 +0200339class testUpbDummyRM(SimpleTestTopology):
340 """
341 Test the UpbDummyRM resource model.
342 """
343
344 def testAllocationComputations(self):
345 """
346 Test the allocation procedures and correct calculations.
347 :return:
348 """
349 # config
350 E_CPU = 1.0
351 MAX_CU = 3
352 E_MEM = 512
353 MAX_MU = 2048
354 # create dummy resource model environment
355 reg = ResourceModelRegistrar(dc_emulation_max_cpu=E_CPU, dc_emulation_max_mem=E_MEM)
356 rm = UpbDummyRM(max_cu=MAX_CU, max_mu=MAX_MU)
357 reg.register("test_dc", rm)
358
359 c1 = createDummyContainerObject("c1", flavor="small")
360 rm.allocate(c1) # calculate allocation
361 self.assertEqual(len(rm._allocated_compute_instances), 1)
362
363 c2 = createDummyContainerObject("c2", flavor="small")
364 rm.allocate(c2) # calculate allocation
365 self.assertEqual(len(rm._allocated_compute_instances), 2)
peusterm279565d2016-03-19 10:36:52 +0100366