First part of Containernet re-integration
[osm/vim-emu.git] / src / emuvim / test / test_resourcemodel.py
1 import time
2 import os
3 from emuvim.test.base import SimpleTestTopology
4 from emuvim.dcemulator.resourcemodel import BaseResourceModel, ResourceFlavor, NotEnoughResourcesAvailable, ResourceModelRegistrar
5 from emuvim.dcemulator.resourcemodel.upb.simple import UpbSimpleCloudDcRM, UpbOverprovisioningCloudDcRM, UpbDummyRM
6
7
8
9 class testResourceModel(SimpleTestTopology):
10 """
11 Test the general resource model API and functionality.
12 """
13
14 def testBaseResourceModelApi(self):
15 """
16 Tast bare API without real resource madel.
17 :return:
18 """
19 r = BaseResourceModel()
20 # check if default flavors are there
21 self.assertTrue(len(r._flavors) == 5)
22 # check addFlavor functionality
23 f = ResourceFlavor("test", {"testmetric": 42})
24 r.addFlavour(f)
25 self.assertTrue("test" in r._flavors)
26 self.assertTrue(r._flavors.get("test").get("testmetric") == 42)
27
28 def testAddRmToDc(self):
29 """
30 Test is allocate/free is called when a RM is added to a DC.
31 :return:
32 """
33 # create network
34 self.createNet(nswitches=0, ndatacenter=1, nhosts=2, ndockers=0)
35 # setup links
36 self.net.addLink(self.dc[0], self.h[0])
37 self.net.addLink(self.h[1], self.dc[0])
38 # add resource model
39 r = BaseResourceModel()
40 self.dc[0].assignResourceModel(r)
41 # start Mininet network
42 self.startNet()
43 # check number of running nodes
44 self.assertTrue(len(self.getContainernetContainers()) == 0)
45 self.assertTrue(len(self.net.hosts) == 2)
46 self.assertTrue(len(self.net.switches) == 1)
47 # check resource model and resource model registrar
48 self.assertTrue(self.dc[0]._resource_model is not None)
49 self.assertTrue(len(self.net.rm_registrar.resource_models) == 1)
50
51 # check if alloc was called during startCompute
52 self.assertTrue(len(r._allocated_compute_instances) == 0)
53 self.dc[0].startCompute("tc1")
54 time.sleep(1)
55 self.assertTrue(len(r._allocated_compute_instances) == 1)
56 # check if free was called during stopCompute
57 self.dc[0].stopCompute("tc1")
58 self.assertTrue(len(r._allocated_compute_instances) == 0)
59 # check connectivity by using ping
60 self.assertTrue(self.net.ping([self.h[0], self.h[1]]) <= 0.0)
61 # stop Mininet network
62 self.stopNet()
63
64
65 def createDummyContainerObject(name, flavor):
66
67 class DummyContainer(object):
68
69 def __init__(self):
70 self.cpu_period = -1
71 self.cpu_quota = -1
72 self.mem_limit = -1
73 self.memswap_limit = -1
74
75 def updateCpuLimit(self, cpu_period, cpu_quota):
76 self.cpu_period = cpu_period
77 self.cpu_quota = cpu_quota
78
79 def updateMemoryLimit(self, mem_limit):
80 self.mem_limit = mem_limit
81
82 d = DummyContainer()
83 d.name = name
84 d.flavor_name = flavor
85 return d
86
87
88
89
90 class testUpbSimpleCloudDcRM(SimpleTestTopology):
91 """
92 Test the UpbSimpleCloudDc resource model.
93 """
94
95 def testAllocationComputations(self):
96 """
97 Test the allocation procedures and correct calculations.
98 :return:
99 """
100 # config
101 E_CPU = 1.0
102 MAX_CU = 100
103 E_MEM = 512
104 MAX_MU = 2048
105 # create dummy resource model environment
106 reg = ResourceModelRegistrar(dc_emulation_max_cpu=E_CPU, dc_emulation_max_mem=E_MEM)
107 rm = UpbSimpleCloudDcRM(max_cu=MAX_CU, max_mu=MAX_MU)
108 reg.register("test_dc", rm)
109
110 c1 = createDummyContainerObject("c1", flavor="tiny")
111 rm.allocate(c1) # calculate allocation
112 self.assertEqual(float(c1.cpu_quota) / c1.cpu_period, E_CPU / MAX_CU * 0.5) # validate compute result
113 self.assertEqual(float(c1.mem_limit/1024/1024), float(E_MEM) / MAX_MU * 32) # validate memory result
114
115 c2 = createDummyContainerObject("c2", flavor="small")
116 rm.allocate(c2) # calculate allocation
117 self.assertEqual(float(c2.cpu_quota) / c2.cpu_period, E_CPU / MAX_CU * 1) # validate compute result
118 self.assertEqual(float(c2.mem_limit/1024/1024), float(E_MEM) / MAX_MU * 128) # validate memory result
119
120 c3 = createDummyContainerObject("c3", flavor="medium")
121 rm.allocate(c3) # calculate allocation
122 self.assertEqual(float(c3.cpu_quota) / c3.cpu_period, E_CPU / MAX_CU * 4) # validate compute result
123 self.assertEqual(float(c3.mem_limit/1024/1024), float(E_MEM) / MAX_MU * 256) # validate memory result
124
125 c4 = createDummyContainerObject("c4", flavor="large")
126 rm.allocate(c4) # calculate allocation
127 self.assertEqual(float(c4.cpu_quota) / c4.cpu_period, E_CPU / MAX_CU * 8) # validate compute result
128 self.assertEqual(float(c4.mem_limit/1024/1024), float(E_MEM) / MAX_MU * 512) # validate memory result
129
130 c5 = createDummyContainerObject("c5", flavor="xlarge")
131 rm.allocate(c5) # calculate allocation
132 self.assertEqual(float(c5.cpu_quota) / c5.cpu_period, E_CPU / MAX_CU * 16) # validate compute result
133 self.assertEqual(float(c5.mem_limit/1024/1024), float(E_MEM) / MAX_MU * 1024) # validate memory result
134
135
136 def testAllocationCpuLimit(self):
137 """
138 Test CPU allocation limit
139 :return:
140 """
141 # config
142 E_CPU = 1.0
143 MAX_CU = 40
144 E_MEM = 512
145 MAX_MU = 4096
146 # create dummy resource model environment
147 reg = ResourceModelRegistrar(dc_emulation_max_cpu=E_CPU, dc_emulation_max_mem=E_MEM)
148 rm = UpbSimpleCloudDcRM(max_cu=MAX_CU, max_mu=MAX_MU)
149 reg.register("test_dc", rm)
150
151 # test over provisioning exeption
152 exception = False
153 try:
154 c6 = createDummyContainerObject("c6", flavor="xlarge")
155 c7 = createDummyContainerObject("c7", flavor="xlarge")
156 c8 = createDummyContainerObject("c8", flavor="xlarge")
157 c9 = createDummyContainerObject("c9", flavor="xlarge")
158 rm.allocate(c6) # calculate allocation
159 rm.allocate(c7) # calculate allocation
160 rm.allocate(c8) # calculate allocation
161 rm.allocate(c9) # calculate allocation
162 except NotEnoughResourcesAvailable as e:
163 self.assertIn("Not enough compute", e.message)
164 exception = True
165 self.assertTrue(exception)
166
167 def testAllocationMemLimit(self):
168 """
169 Test MEM allocation limit
170 :return:
171 """
172 # config
173 E_CPU = 1.0
174 MAX_CU = 500
175 E_MEM = 512
176 MAX_MU = 2048
177 # create dummy resource model environment
178 reg = ResourceModelRegistrar(dc_emulation_max_cpu=E_CPU, dc_emulation_max_mem=E_MEM)
179 rm = UpbSimpleCloudDcRM(max_cu=MAX_CU, max_mu=MAX_MU)
180 reg.register("test_dc", rm)
181
182 # test over provisioning exeption
183 exception = False
184 try:
185 c6 = createDummyContainerObject("c6", flavor="xlarge")
186 c7 = createDummyContainerObject("c7", flavor="xlarge")
187 c8 = createDummyContainerObject("c8", flavor="xlarge")
188 rm.allocate(c6) # calculate allocation
189 rm.allocate(c7) # calculate allocation
190 rm.allocate(c8) # calculate allocation
191 except NotEnoughResourcesAvailable as e:
192 self.assertIn("Not enough memory", e.message)
193 exception = True
194 self.assertTrue(exception)
195
196 def testFree(self):
197 """
198 Test the free procedure.
199 :return:
200 """
201 # config
202 E_CPU = 1.0
203 MAX_CU = 100
204 # create dummy resource model environment
205 reg = ResourceModelRegistrar(dc_emulation_max_cpu=1.0, dc_emulation_max_mem=512)
206 rm = UpbSimpleCloudDcRM(max_cu=100, max_mu=100)
207 reg.register("test_dc", rm)
208 c1 = createDummyContainerObject("c6", flavor="tiny")
209 rm.allocate(c1) # calculate allocation
210 self.assertTrue(rm.dc_alloc_cu == 0.5)
211 rm.free(c1)
212 self.assertTrue(rm.dc_alloc_cu == 0)
213
214 def testInRealTopo(self):
215 """
216 Start a real container and check if limitations are really passed down to Conteinernet.
217 :return:
218 """
219 # ATTENTION: This test should only be executed if emu runs not inside a Docker container,
220 # because it manipulates cgroups.
221 if os.environ.get("SON_EMU_IN_DOCKER") is not None:
222 return
223 # create network
224 self.createNet(nswitches=0, ndatacenter=1, nhosts=2, ndockers=0)
225 # setup links
226 self.net.addLink(self.dc[0], self.h[0])
227 self.net.addLink(self.h[1], self.dc[0])
228 # add resource model
229 r = UpbSimpleCloudDcRM(max_cu=100, max_mu=100)
230 self.dc[0].assignResourceModel(r)
231 # start Mininet network
232 self.startNet()
233 # check number of running nodes
234 self.assertTrue(len(self.getContainernetContainers()) == 0)
235 self.assertTrue(len(self.net.hosts) == 2)
236 self.assertTrue(len(self.net.switches) == 1)
237 # check resource model and resource model registrar
238 self.assertTrue(self.dc[0]._resource_model is not None)
239 self.assertTrue(len(self.net.rm_registrar.resource_models) == 1)
240
241 # check if alloc was called during startCompute
242 self.assertTrue(len(r._allocated_compute_instances) == 0)
243 tc1 = self.dc[0].startCompute("tc1", flavor_name="tiny")
244 time.sleep(1)
245 self.assertTrue(len(r._allocated_compute_instances) == 1)
246
247 # check if there is a real limitation set for containers cgroup
248 # deactivated for now, seems not to work in docker-in-docker setup used in CI
249 self.assertEqual(float(tc1.cpu_quota)/tc1.cpu_period, 0.005)
250
251 # check if free was called during stopCompute
252 self.dc[0].stopCompute("tc1")
253 self.assertTrue(len(r._allocated_compute_instances) == 0)
254 # check connectivity by using ping
255 self.assertTrue(self.net.ping([self.h[0], self.h[1]]) <= 0.0)
256 # stop Mininet network
257 self.stopNet()
258
259
260 class testUpbOverprovisioningCloudDcRM(SimpleTestTopology):
261 """
262 Test the UpbOverprovisioningCloudDc resource model.
263 """
264
265 def testAllocationComputations(self):
266 """
267 Test the allocation procedures and correct calculations.
268 :return:
269 """
270 # config
271 E_CPU = 1.0
272 MAX_CU = 3
273 E_MEM = 512
274 MAX_MU = 2048
275 # create dummy resource model environment
276 reg = ResourceModelRegistrar(dc_emulation_max_cpu=E_CPU, dc_emulation_max_mem=E_MEM)
277 rm = UpbOverprovisioningCloudDcRM(max_cu=MAX_CU, max_mu=MAX_MU)
278 reg.register("test_dc", rm)
279
280 c1 = createDummyContainerObject("c1", flavor="small")
281 rm.allocate(c1) # calculate allocation
282 self.assertAlmostEqual(float(c1.cpu_quota) / c1.cpu_period, E_CPU / MAX_CU * 1.0, places=5)
283 self.assertAlmostEqual(float(c1.mem_limit/1024/1024), float(E_MEM) / MAX_MU * 128)
284 self.assertAlmostEqual(rm.cpu_op_factor, 1.0)
285
286 c2 = createDummyContainerObject("c2", flavor="small")
287 rm.allocate(c2) # calculate allocation
288 self.assertAlmostEqual(float(c2.cpu_quota) / c2.cpu_period, E_CPU / MAX_CU * 1.0, places=5)
289 self.assertAlmostEqual(float(c2.mem_limit/1024/1024), float(E_MEM) / MAX_MU * 128)
290 self.assertAlmostEqual(rm.cpu_op_factor, 1.0)
291
292 c3 = createDummyContainerObject("c3", flavor="small")
293 rm.allocate(c3) # calculate allocation
294 self.assertAlmostEqual(float(c3.cpu_quota) / c3.cpu_period, E_CPU / MAX_CU * 1.0, places=5)
295 self.assertAlmostEqual(float(c3.mem_limit/1024/1024), float(E_MEM) / MAX_MU * 128)
296 self.assertAlmostEqual(rm.cpu_op_factor, 1.0)
297
298 # from this container onwards, we should go to over provisioning mode:
299 c4 = createDummyContainerObject("c4", flavor="small")
300 rm.allocate(c4) # calculate allocation
301 self.assertAlmostEqual(float(c4.cpu_quota) / c4.cpu_period, E_CPU / MAX_CU * (float(3) / 4), places=5)
302 self.assertAlmostEqual(float(c4.mem_limit/1024/1024), float(E_MEM) / MAX_MU * 128, places=5)
303 self.assertAlmostEqual(rm.cpu_op_factor, 0.75)
304
305 c5 = createDummyContainerObject("c5", flavor="small")
306 rm.allocate(c5) # calculate allocation
307 self.assertAlmostEqual(float(c5.cpu_quota) / c5.cpu_period, E_CPU / MAX_CU * (float(3) / 5), places=5)
308 self.assertAlmostEqual(float(c5.mem_limit/1024/1024), float(E_MEM) / MAX_MU * 128)
309 self.assertAlmostEqual(rm.cpu_op_factor, 0.6)
310
311
312 class testUpbDummyRM(SimpleTestTopology):
313 """
314 Test the UpbDummyRM resource model.
315 """
316
317 def testAllocationComputations(self):
318 """
319 Test the allocation procedures and correct calculations.
320 :return:
321 """
322 # config
323 E_CPU = 1.0
324 MAX_CU = 3
325 E_MEM = 512
326 MAX_MU = 2048
327 # create dummy resource model environment
328 reg = ResourceModelRegistrar(dc_emulation_max_cpu=E_CPU, dc_emulation_max_mem=E_MEM)
329 rm = UpbDummyRM(max_cu=MAX_CU, max_mu=MAX_MU)
330 reg.register("test_dc", rm)
331
332 c1 = createDummyContainerObject("c1", flavor="small")
333 rm.allocate(c1) # calculate allocation
334 self.assertEqual(len(rm._allocated_compute_instances), 1)
335
336 c2 = createDummyContainerObject("c2", flavor="small")
337 rm.allocate(c2) # calculate allocation
338 self.assertEqual(len(rm._allocated_compute_instances), 2)
339