Fix: Crashbug that was caused by an import of an
[osm/vim-emu.git] / src / emuvim / test / unittests / test_resourcemodel.py
1 """
2 Copyright (c) 2015 SONATA-NFV
3 ALL RIGHTS RESERVED.
4
5 Licensed under the Apache License, Version 2.0 (the "License");
6 you may not use this file except in compliance with the License.
7 You may obtain a copy of the License at
8
9 http://www.apache.org/licenses/LICENSE-2.0
10
11 Unless required by applicable law or agreed to in writing, software
12 distributed under the License is distributed on an "AS IS" BASIS,
13 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 See the License for the specific language governing permissions and
15 limitations under the License.
16
17 Neither the name of the SONATA-NFV [, ANY ADDITIONAL AFFILIATION]
18 nor the names of its contributors may be used to endorse or promote
19 products derived from this software without specific prior written
20 permission.
21
22 This work has been performed in the framework of the SONATA project,
23 funded by the European Commission under Grant number 671517 through
24 the Horizon 2020 and 5G-PPP programmes. The authors would like to
25 acknowledge the contributions of their colleagues of the SONATA
26 partner consortium (www.sonata-nfv.eu).
27 """
28
29 import time
30 import os
31 import unittest
32 from emuvim.test.base import SimpleTestTopology
33 from emuvim.dcemulator.resourcemodel import BaseResourceModel, ResourceFlavor, NotEnoughResourcesAvailable, ResourceModelRegistrar
34 from emuvim.dcemulator.resourcemodel.upb.simple import UpbSimpleCloudDcRM, UpbOverprovisioningCloudDcRM, UpbDummyRM
35
36
37
38 class testResourceModel(SimpleTestTopology):
39 """
40 Test the general resource model API and functionality.
41 """
42
43 def testBaseResourceModelApi(self):
44 """
45 Tast bare API without real resource madel.
46 :return:
47 """
48 r = BaseResourceModel()
49 # check if default flavors are there
50 self.assertTrue(len(r._flavors) == 5)
51 # check addFlavor functionality
52 f = ResourceFlavor("test", {"testmetric": 42})
53 r.addFlavour(f)
54 self.assertTrue("test" in r._flavors)
55 self.assertTrue(r._flavors.get("test").get("testmetric") == 42)
56
57 def testAddRmToDc(self):
58 """
59 Test is allocate/free is called when a RM is added to a DC.
60 :return:
61 """
62 # 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
73 self.assertTrue(len(self.getContainernetContainers()) == 0)
74 self.assertTrue(len(self.net.hosts) == 2)
75 self.assertTrue(len(self.net.switches) == 1)
76 # check resource model and resource model registrar
77 self.assertTrue(self.dc[0]._resource_model is not None)
78 self.assertTrue(len(self.net.rm_registrar.resource_models) == 1)
79
80 # check if alloc was called during startCompute
81 self.assertTrue(len(r._allocated_compute_instances) == 0)
82 self.dc[0].startCompute("tc1")
83 time.sleep(1)
84 self.assertTrue(len(r._allocated_compute_instances) == 1)
85 # check if free was called during stopCompute
86 self.dc[0].stopCompute("tc1")
87 self.assertTrue(len(r._allocated_compute_instances) == 0)
88 # check connectivity by using ping
89 self.assertTrue(self.net.ping([self.h[0], self.h[1]]) <= 0.0)
90 # stop Mininet network
91 self.stopNet()
92
93
94 def createDummyContainerObject(name, flavor):
95
96 class DummyContainer(object):
97
98 def __init__(self):
99 # take defaukt values from son-emu
100 self.resources = dict(
101 cpu_period = -1,
102 cpu_quota = -1,
103 mem_limit = -1,
104 memswap_limit = -1
105 )
106 #self.cpu_period = self.resources['cpu_period']
107 #self.cpu_quota = self.resources['cpu_quota']
108 #self.mem_limit = self.resources['mem_limit']
109 #self.memswap_limit = self.resources['memswap_limit']
110
111 def updateCpuLimit(self, cpu_period, cpu_quota):
112 self.resources['cpu_period'] = cpu_period
113 self.resources['cpu_quota'] = cpu_quota
114
115 def updateMemoryLimit(self, mem_limit):
116 self.resources['mem_limit'] = mem_limit
117
118 d = DummyContainer()
119 d.name = name
120 d.flavor_name = flavor
121 return d
122
123
124
125
126 class testUpbSimpleCloudDcRM(SimpleTestTopology):
127 """
128 Test the UpbSimpleCloudDc resource model.
129 """
130
131 def testAllocationComputations(self):
132 """
133 Test the allocation procedures and correct calculations.
134 :return:
135 """
136 # config
137 E_CPU = 1.0
138 MAX_CU = 100
139 E_MEM = 512
140 MAX_MU = 2048
141 # create dummy resource model environment
142 reg = ResourceModelRegistrar(dc_emulation_max_cpu=E_CPU, dc_emulation_max_mem=E_MEM)
143 rm = UpbSimpleCloudDcRM(max_cu=MAX_CU, max_mu=MAX_MU)
144 reg.register("test_dc", rm)
145
146 c1 = createDummyContainerObject("c1", flavor="tiny")
147 rm.allocate(c1) # calculate allocation
148 self.assertEqual(float(c1.resources['cpu_quota']) / c1.resources['cpu_period'], E_CPU / MAX_CU * 0.5) # validate compute result
149 self.assertEqual(float(c1.resources['mem_limit']/1024/1024), float(E_MEM) / MAX_MU * 32) # validate memory result
150
151 c2 = createDummyContainerObject("c2", flavor="small")
152 rm.allocate(c2) # calculate allocation
153 self.assertEqual(float(c2.resources['cpu_quota']) / c2.resources['cpu_period'], E_CPU / MAX_CU * 1) # validate compute result
154 self.assertEqual(float(c2.resources['mem_limit']/1024/1024), float(E_MEM) / MAX_MU * 128) # validate memory result
155
156 c3 = createDummyContainerObject("c3", flavor="medium")
157 rm.allocate(c3) # calculate allocation
158 self.assertEqual(float(c3.resources['cpu_quota']) / c3.resources['cpu_period'], E_CPU / MAX_CU * 4) # validate compute result
159 self.assertEqual(float(c3.resources['mem_limit']/1024/1024), float(E_MEM) / MAX_MU * 256) # validate memory result
160
161 c4 = createDummyContainerObject("c4", flavor="large")
162 rm.allocate(c4) # calculate allocation
163 self.assertEqual(float(c4.resources['cpu_quota']) / c4.resources['cpu_period'], E_CPU / MAX_CU * 8) # validate compute result
164 self.assertEqual(float(c4.resources['mem_limit']/1024/1024), float(E_MEM) / MAX_MU * 512) # validate memory result
165
166 c5 = createDummyContainerObject("c5", flavor="xlarge")
167 rm.allocate(c5) # calculate allocation
168 self.assertEqual(float(c5.resources['cpu_quota']) / c5.resources['cpu_period'], E_CPU / MAX_CU * 16) # validate compute result
169 self.assertEqual(float(c5.resources['mem_limit']/1024/1024), float(E_MEM) / MAX_MU * 1024) # validate memory result
170
171
172 def testAllocationCpuLimit(self):
173 """
174 Test CPU allocation limit
175 :return:
176 """
177 # config
178 E_CPU = 1.0
179 MAX_CU = 40
180 E_MEM = 512
181 MAX_MU = 4096
182 # create dummy resource model environment
183 reg = ResourceModelRegistrar(dc_emulation_max_cpu=E_CPU, dc_emulation_max_mem=E_MEM)
184 rm = UpbSimpleCloudDcRM(max_cu=MAX_CU, max_mu=MAX_MU)
185 reg.register("test_dc", rm)
186
187 # test over provisioning exeption
188 exception = False
189 try:
190 c6 = createDummyContainerObject("c6", flavor="xlarge")
191 c7 = createDummyContainerObject("c7", flavor="xlarge")
192 c8 = createDummyContainerObject("c8", flavor="xlarge")
193 c9 = createDummyContainerObject("c9", flavor="xlarge")
194 rm.allocate(c6) # calculate allocation
195 rm.allocate(c7) # calculate allocation
196 rm.allocate(c8) # calculate allocation
197 rm.allocate(c9) # calculate allocation
198 except NotEnoughResourcesAvailable as e:
199 self.assertIn("Not enough compute", e.message)
200 exception = True
201 self.assertTrue(exception)
202
203 def testAllocationMemLimit(self):
204 """
205 Test MEM allocation limit
206 :return:
207 """
208 # config
209 E_CPU = 1.0
210 MAX_CU = 500
211 E_MEM = 512
212 MAX_MU = 2048
213 # create dummy resource model environment
214 reg = ResourceModelRegistrar(dc_emulation_max_cpu=E_CPU, dc_emulation_max_mem=E_MEM)
215 rm = UpbSimpleCloudDcRM(max_cu=MAX_CU, max_mu=MAX_MU)
216 reg.register("test_dc", rm)
217
218 # test over provisioning exeption
219 exception = False
220 try:
221 c6 = createDummyContainerObject("c6", flavor="xlarge")
222 c7 = createDummyContainerObject("c7", flavor="xlarge")
223 c8 = createDummyContainerObject("c8", flavor="xlarge")
224 rm.allocate(c6) # calculate allocation
225 rm.allocate(c7) # calculate allocation
226 rm.allocate(c8) # calculate allocation
227 except NotEnoughResourcesAvailable as e:
228 self.assertIn("Not enough memory", e.message)
229 exception = True
230 self.assertTrue(exception)
231
232 def testFree(self):
233 """
234 Test the free procedure.
235 :return:
236 """
237 # config
238 E_CPU = 1.0
239 MAX_CU = 100
240 # create dummy resource model environment
241 reg = ResourceModelRegistrar(dc_emulation_max_cpu=1.0, dc_emulation_max_mem=512)
242 rm = UpbSimpleCloudDcRM(max_cu=100, max_mu=100)
243 reg.register("test_dc", rm)
244 c1 = createDummyContainerObject("c6", flavor="tiny")
245 rm.allocate(c1) # calculate allocation
246 self.assertTrue(rm.dc_alloc_cu == 0.5)
247 rm.free(c1)
248 self.assertTrue(rm.dc_alloc_cu == 0)
249
250 @unittest.skipIf(os.environ.get("SON_EMU_IN_DOCKER") is not None,
251 "skipping test when running inside Docker container")
252 def testInRealTopo(self):
253 """
254 Start a real container and check if limitations are really passed down to Conteinernet.
255 :return:
256 """
257 # create network
258 self.createNet(nswitches=0, ndatacenter=1, nhosts=2, ndockers=0)
259 # setup links
260 self.net.addLink(self.dc[0], self.h[0])
261 self.net.addLink(self.h[1], self.dc[0])
262 # add resource model
263 r = UpbSimpleCloudDcRM(max_cu=100, max_mu=100)
264 self.dc[0].assignResourceModel(r)
265 # start Mininet network
266 self.startNet()
267 # check number of running nodes
268 self.assertTrue(len(self.getContainernetContainers()) == 0)
269 self.assertTrue(len(self.net.hosts) == 2)
270 self.assertTrue(len(self.net.switches) == 1)
271 # check resource model and resource model registrar
272 self.assertTrue(self.dc[0]._resource_model is not None)
273 self.assertTrue(len(self.net.rm_registrar.resource_models) == 1)
274
275 # check if alloc was called during startCompute
276 self.assertTrue(len(r._allocated_compute_instances) == 0)
277 tc1 = self.dc[0].startCompute("tc1", flavor_name="tiny")
278 time.sleep(1)
279 self.assertTrue(len(r._allocated_compute_instances) == 1)
280
281 # check if there is a real limitation set for containers cgroup
282 # deactivated for now, seems not to work in docker-in-docker setup used in CI
283 self.assertEqual(float(tc1.resources['cpu_quota'])/tc1.resources['cpu_period'], 0.005)
284
285 # check if free was called during stopCompute
286 self.dc[0].stopCompute("tc1")
287 self.assertTrue(len(r._allocated_compute_instances) == 0)
288 # check connectivity by using ping
289 self.assertTrue(self.net.ping([self.h[0], self.h[1]]) <= 0.0)
290 # stop Mininet network
291 self.stopNet()
292
293
294 class testUpbOverprovisioningCloudDcRM(SimpleTestTopology):
295 """
296 Test the UpbOverprovisioningCloudDc resource model.
297 """
298
299 def testAllocationComputations(self):
300 """
301 Test the allocation procedures and correct calculations.
302 :return:
303 """
304 # config
305 E_CPU = 1.0
306 MAX_CU = 3
307 E_MEM = 512
308 MAX_MU = 2048
309 # create dummy resource model environment
310 reg = ResourceModelRegistrar(dc_emulation_max_cpu=E_CPU, dc_emulation_max_mem=E_MEM)
311 rm = UpbOverprovisioningCloudDcRM(max_cu=MAX_CU, max_mu=MAX_MU)
312 reg.register("test_dc", rm)
313
314 c1 = createDummyContainerObject("c1", flavor="small")
315 rm.allocate(c1) # calculate allocation
316 self.assertAlmostEqual(float(c1.resources['cpu_quota']) / c1.resources['cpu_period'], E_CPU / MAX_CU * 1.0, places=5)
317 self.assertAlmostEqual(float(c1.resources['mem_limit']/1024/1024), float(E_MEM) / MAX_MU * 128)
318 self.assertAlmostEqual(rm.cpu_op_factor, 1.0)
319
320 c2 = createDummyContainerObject("c2", flavor="small")
321 rm.allocate(c2) # calculate allocation
322 self.assertAlmostEqual(float(c2.resources['cpu_quota']) / c2.resources['cpu_period'], E_CPU / MAX_CU * 1.0, places=5)
323 self.assertAlmostEqual(float(c2.resources['mem_limit']/1024/1024), float(E_MEM) / MAX_MU * 128)
324 self.assertAlmostEqual(rm.cpu_op_factor, 1.0)
325
326 c3 = createDummyContainerObject("c3", flavor="small")
327 rm.allocate(c3) # calculate allocation
328 self.assertAlmostEqual(float(c3.resources['cpu_quota']) / c3.resources['cpu_period'], E_CPU / MAX_CU * 1.0, places=5)
329 self.assertAlmostEqual(float(c3.resources['mem_limit']/1024/1024), float(E_MEM) / MAX_MU * 128)
330 self.assertAlmostEqual(rm.cpu_op_factor, 1.0)
331
332 # from this container onwards, we should go to over provisioning mode:
333 c4 = createDummyContainerObject("c4", flavor="small")
334 rm.allocate(c4) # calculate allocation
335 self.assertAlmostEqual(float(c4.resources['cpu_quota']) / c4.resources['cpu_period'], E_CPU / MAX_CU * (float(3) / 4), places=5)
336 self.assertAlmostEqual(float(c4.resources['mem_limit']/1024/1024), float(E_MEM) / MAX_MU * 128, places=5)
337 self.assertAlmostEqual(rm.cpu_op_factor, 0.75)
338
339 c5 = createDummyContainerObject("c5", flavor="small")
340 rm.allocate(c5) # calculate allocation
341 self.assertAlmostEqual(float(c5.resources['cpu_quota']) / c5.resources['cpu_period'], E_CPU / MAX_CU * (float(3) / 5), places=5)
342 self.assertAlmostEqual(float(c5.resources['mem_limit']/1024/1024), float(E_MEM) / MAX_MU * 128)
343 self.assertAlmostEqual(rm.cpu_op_factor, 0.6)
344
345
346 class testUpbDummyRM(SimpleTestTopology):
347 """
348 Test the UpbDummyRM resource model.
349 """
350
351 def testAllocationComputations(self):
352 """
353 Test the allocation procedures and correct calculations.
354 :return:
355 """
356 # config
357 E_CPU = 1.0
358 MAX_CU = 3
359 E_MEM = 512
360 MAX_MU = 2048
361 # create dummy resource model environment
362 reg = ResourceModelRegistrar(dc_emulation_max_cpu=E_CPU, dc_emulation_max_mem=E_MEM)
363 rm = UpbDummyRM(max_cu=MAX_CU, max_mu=MAX_MU)
364 reg.register("test_dc", rm)
365
366 c1 = createDummyContainerObject("c1", flavor="small")
367 rm.allocate(c1) # calculate allocation
368 self.assertEqual(len(rm._allocated_compute_instances), 1)
369
370 c2 = createDummyContainerObject("c2", flavor="small")
371 rm.allocate(c2) # calculate allocation
372 self.assertEqual(len(rm._allocated_compute_instances), 2)
373