update cpu_bw resource parameter
[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.cpu_period = -1
101 self.cpu_quota = -1
102 # self.mem_limit = -1
103 # self.memswap_limit = -1
104
105 def updateCpuLimit(self, cpu_period, cpu_quota):
106 self.cpu_period = cpu_period
107 self.cpu_quota = cpu_quota
108
109 def updateMemoryLimit(self, mem_limit):
110 self.mem_limit = mem_limit
111
112 d = DummyContainer()
113 d.name = name
114 d.flavor_name = flavor
115 return d
116
117
118
119
120 class testUpbSimpleCloudDcRM(SimpleTestTopology):
121 """
122 Test the UpbSimpleCloudDc resource model.
123 """
124
125 def testAllocationComputations(self):
126 """
127 Test the allocation procedures and correct calculations.
128 :return:
129 """
130 # config
131 E_CPU = 1.0
132 MAX_CU = 100
133 E_MEM = 512
134 MAX_MU = 2048
135 # create dummy resource model environment
136 reg = ResourceModelRegistrar(dc_emulation_max_cpu=E_CPU, dc_emulation_max_mem=E_MEM)
137 rm = UpbSimpleCloudDcRM(max_cu=MAX_CU, max_mu=MAX_MU)
138 reg.register("test_dc", rm)
139
140 c1 = createDummyContainerObject("c1", flavor="tiny")
141 rm.allocate(c1) # calculate allocation
142 self.assertEqual(float(c1.cpu_quota) / c1.cpu_period, E_CPU / MAX_CU * 0.5) # validate compute result
143 self.assertEqual(float(c1.mem_limit/1024/1024), float(E_MEM) / MAX_MU * 32) # validate memory result
144
145 c2 = createDummyContainerObject("c2", flavor="small")
146 rm.allocate(c2) # calculate allocation
147 self.assertEqual(float(c2.cpu_quota) / c2.cpu_period, E_CPU / MAX_CU * 1) # validate compute result
148 self.assertEqual(float(c2.mem_limit/1024/1024), float(E_MEM) / MAX_MU * 128) # validate memory result
149
150 c3 = createDummyContainerObject("c3", flavor="medium")
151 rm.allocate(c3) # calculate allocation
152 self.assertEqual(float(c3.cpu_quota) / c3.cpu_period, E_CPU / MAX_CU * 4) # validate compute result
153 self.assertEqual(float(c3.mem_limit/1024/1024), float(E_MEM) / MAX_MU * 256) # validate memory result
154
155 c4 = createDummyContainerObject("c4", flavor="large")
156 rm.allocate(c4) # calculate allocation
157 self.assertEqual(float(c4.cpu_quota) / c4.cpu_period, E_CPU / MAX_CU * 8) # validate compute result
158 self.assertEqual(float(c4.mem_limit/1024/1024), float(E_MEM) / MAX_MU * 512) # validate memory result
159
160 c5 = createDummyContainerObject("c5", flavor="xlarge")
161 rm.allocate(c5) # calculate allocation
162 self.assertEqual(float(c5.cpu_quota) / c5.cpu_period, E_CPU / MAX_CU * 16) # validate compute result
163 self.assertEqual(float(c5.mem_limit/1024/1024), float(E_MEM) / MAX_MU * 1024) # validate memory result
164
165
166 def testAllocationCpuLimit(self):
167 """
168 Test CPU allocation limit
169 :return:
170 """
171 # config
172 E_CPU = 1.0
173 MAX_CU = 40
174 E_MEM = 512
175 MAX_MU = 4096
176 # create dummy resource model environment
177 reg = ResourceModelRegistrar(dc_emulation_max_cpu=E_CPU, dc_emulation_max_mem=E_MEM)
178 rm = UpbSimpleCloudDcRM(max_cu=MAX_CU, max_mu=MAX_MU)
179 reg.register("test_dc", rm)
180
181 # test over provisioning exeption
182 exception = False
183 try:
184 c6 = createDummyContainerObject("c6", flavor="xlarge")
185 c7 = createDummyContainerObject("c7", flavor="xlarge")
186 c8 = createDummyContainerObject("c8", flavor="xlarge")
187 c9 = createDummyContainerObject("c9", flavor="xlarge")
188 rm.allocate(c6) # calculate allocation
189 rm.allocate(c7) # calculate allocation
190 rm.allocate(c8) # calculate allocation
191 rm.allocate(c9) # calculate allocation
192 except NotEnoughResourcesAvailable as e:
193 self.assertIn("Not enough compute", e.message)
194 exception = True
195 self.assertTrue(exception)
196
197 def testAllocationMemLimit(self):
198 """
199 Test MEM allocation limit
200 :return:
201 """
202 # config
203 E_CPU = 1.0
204 MAX_CU = 500
205 E_MEM = 512
206 MAX_MU = 2048
207 # create dummy resource model environment
208 reg = ResourceModelRegistrar(dc_emulation_max_cpu=E_CPU, dc_emulation_max_mem=E_MEM)
209 rm = UpbSimpleCloudDcRM(max_cu=MAX_CU, max_mu=MAX_MU)
210 reg.register("test_dc", rm)
211
212 # test over provisioning exeption
213 exception = False
214 try:
215 c6 = createDummyContainerObject("c6", flavor="xlarge")
216 c7 = createDummyContainerObject("c7", flavor="xlarge")
217 c8 = createDummyContainerObject("c8", flavor="xlarge")
218 rm.allocate(c6) # calculate allocation
219 rm.allocate(c7) # calculate allocation
220 rm.allocate(c8) # calculate allocation
221 except NotEnoughResourcesAvailable as e:
222 self.assertIn("Not enough memory", e.message)
223 exception = True
224 self.assertTrue(exception)
225
226 def testFree(self):
227 """
228 Test the free procedure.
229 :return:
230 """
231 # config
232 E_CPU = 1.0
233 MAX_CU = 100
234 # create dummy resource model environment
235 reg = ResourceModelRegistrar(dc_emulation_max_cpu=1.0, dc_emulation_max_mem=512)
236 rm = UpbSimpleCloudDcRM(max_cu=100, max_mu=100)
237 reg.register("test_dc", rm)
238 c1 = createDummyContainerObject("c6", flavor="tiny")
239 rm.allocate(c1) # calculate allocation
240 self.assertTrue(rm.dc_alloc_cu == 0.5)
241 rm.free(c1)
242 self.assertTrue(rm.dc_alloc_cu == 0)
243
244 @unittest.skipIf(os.environ.get("SON_EMU_IN_DOCKER") is not None,
245 "skipping test when running inside Docker container")
246 def testInRealTopo(self):
247 """
248 Start a real container and check if limitations are really passed down to Conteinernet.
249 :return:
250 """
251 # create network
252 self.createNet(nswitches=0, ndatacenter=1, nhosts=2, ndockers=0)
253 # setup links
254 self.net.addLink(self.dc[0], self.h[0])
255 self.net.addLink(self.h[1], self.dc[0])
256 # add resource model
257 r = UpbSimpleCloudDcRM(max_cu=100, max_mu=100)
258 self.dc[0].assignResourceModel(r)
259 # start Mininet network
260 self.startNet()
261 # check number of running nodes
262 self.assertTrue(len(self.getContainernetContainers()) == 0)
263 self.assertTrue(len(self.net.hosts) == 2)
264 self.assertTrue(len(self.net.switches) == 1)
265 # check resource model and resource model registrar
266 self.assertTrue(self.dc[0]._resource_model is not None)
267 self.assertTrue(len(self.net.rm_registrar.resource_models) == 1)
268
269 # check if alloc was called during startCompute
270 self.assertTrue(len(r._allocated_compute_instances) == 0)
271 tc1 = self.dc[0].startCompute("tc1", flavor_name="tiny")
272 time.sleep(1)
273 self.assertTrue(len(r._allocated_compute_instances) == 1)
274
275 # check if there is a real limitation set for containers cgroup
276 # deactivated for now, seems not to work in docker-in-docker setup used in CI
277 self.assertEqual(float(tc1.cpu_quota)/tc1.cpu_period, 0.005)
278
279 # check if free was called during stopCompute
280 self.dc[0].stopCompute("tc1")
281 self.assertTrue(len(r._allocated_compute_instances) == 0)
282 # check connectivity by using ping
283 self.assertTrue(self.net.ping([self.h[0], self.h[1]]) <= 0.0)
284 # stop Mininet network
285 self.stopNet()
286
287
288 class testUpbOverprovisioningCloudDcRM(SimpleTestTopology):
289 """
290 Test the UpbOverprovisioningCloudDc resource model.
291 """
292
293 def testAllocationComputations(self):
294 """
295 Test the allocation procedures and correct calculations.
296 :return:
297 """
298 # config
299 E_CPU = 1.0
300 MAX_CU = 3
301 E_MEM = 512
302 MAX_MU = 2048
303 # create dummy resource model environment
304 reg = ResourceModelRegistrar(dc_emulation_max_cpu=E_CPU, dc_emulation_max_mem=E_MEM)
305 rm = UpbOverprovisioningCloudDcRM(max_cu=MAX_CU, max_mu=MAX_MU)
306 reg.register("test_dc", rm)
307
308 c1 = createDummyContainerObject("c1", flavor="small")
309 rm.allocate(c1) # calculate allocation
310 self.assertAlmostEqual(float(c1.cpu_quota) / c1.cpu_period, E_CPU / MAX_CU * 1.0, places=5)
311 self.assertAlmostEqual(float(c1.mem_limit/1024/1024), float(E_MEM) / MAX_MU * 128)
312 self.assertAlmostEqual(rm.cpu_op_factor, 1.0)
313
314 c2 = createDummyContainerObject("c2", flavor="small")
315 rm.allocate(c2) # calculate allocation
316 self.assertAlmostEqual(float(c2.cpu_quota) / c2.cpu_period, E_CPU / MAX_CU * 1.0, places=5)
317 self.assertAlmostEqual(float(c2.mem_limit/1024/1024), float(E_MEM) / MAX_MU * 128)
318 self.assertAlmostEqual(rm.cpu_op_factor, 1.0)
319
320 c3 = createDummyContainerObject("c3", flavor="small")
321 rm.allocate(c3) # calculate allocation
322 self.assertAlmostEqual(float(c3.cpu_quota) / c3.cpu_period, E_CPU / MAX_CU * 1.0, places=5)
323 self.assertAlmostEqual(float(c3.mem_limit/1024/1024), float(E_MEM) / MAX_MU * 128)
324 self.assertAlmostEqual(rm.cpu_op_factor, 1.0)
325
326 # from this container onwards, we should go to over provisioning mode:
327 c4 = createDummyContainerObject("c4", flavor="small")
328 rm.allocate(c4) # calculate allocation
329 self.assertAlmostEqual(float(c4.cpu_quota) / c4.cpu_period, E_CPU / MAX_CU * (float(3) / 4), places=5)
330 self.assertAlmostEqual(float(c4.mem_limit/1024/1024), float(E_MEM) / MAX_MU * 128, places=5)
331 self.assertAlmostEqual(rm.cpu_op_factor, 0.75)
332
333 c5 = createDummyContainerObject("c5", flavor="small")
334 rm.allocate(c5) # calculate allocation
335 self.assertAlmostEqual(float(c5.cpu_quota) / c5.cpu_period, E_CPU / MAX_CU * (float(3) / 5), places=5)
336 self.assertAlmostEqual(float(c5.mem_limit/1024/1024), float(E_MEM) / MAX_MU * 128)
337 self.assertAlmostEqual(rm.cpu_op_factor, 0.6)
338
339
340 class testUpbDummyRM(SimpleTestTopology):
341 """
342 Test the UpbDummyRM resource model.
343 """
344
345 def testAllocationComputations(self):
346 """
347 Test the allocation procedures and correct calculations.
348 :return:
349 """
350 # config
351 E_CPU = 1.0
352 MAX_CU = 3
353 E_MEM = 512
354 MAX_MU = 2048
355 # create dummy resource model environment
356 reg = ResourceModelRegistrar(dc_emulation_max_cpu=E_CPU, dc_emulation_max_mem=E_MEM)
357 rm = UpbDummyRM(max_cu=MAX_CU, max_mu=MAX_MU)
358 reg.register("test_dc", rm)
359
360 c1 = createDummyContainerObject("c1", flavor="small")
361 rm.allocate(c1) # calculate allocation
362 self.assertEqual(len(rm._allocated_compute_instances), 1)
363
364 c2 = createDummyContainerObject("c2", flavor="small")
365 rm.allocate(c2) # calculate allocation
366 self.assertEqual(len(rm._allocated_compute_instances), 2)
367