blob: 4a21feeabc8e30b6ff43f946464501e905f96efd [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):
stevenvanrossem33d76892017-02-13 00:13:37 +010099 # take defaukt values from son-emu
stevenvanrossemb2a29bf2017-02-14 14:27:44 +0100100 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']
peustermd18559d2016-04-16 04:59:23 +0200110
111 def updateCpuLimit(self, cpu_period, cpu_quota):
stevenvanrossemb2a29bf2017-02-14 14:27:44 +0100112 self.resources['cpu_period'] = cpu_period
113 self.resources['cpu_quota'] = cpu_quota
peustermd18559d2016-04-16 04:59:23 +0200114
115 def updateMemoryLimit(self, mem_limit):
stevenvanrossemb2a29bf2017-02-14 14:27:44 +0100116 self.resources['mem_limit'] = mem_limit
peustermd18559d2016-04-16 04:59:23 +0200117
118 d = DummyContainer()
119 d.name = name
120 d.flavor_name = flavor
121 return d
122
123
124
125
peusterm279565d2016-03-19 10:36:52 +0100126class testUpbSimpleCloudDcRM(SimpleTestTopology):
127 """
128 Test the UpbSimpleCloudDc resource model.
129 """
peustermbdcf2d22016-03-25 12:14:15 +0100130
peusterm72fc3732016-04-26 19:48:43 +0200131 def testAllocationComputations(self):
peustermbdcf2d22016-03-25 12:14:15 +0100132 """
133 Test the allocation procedures and correct calculations.
134 :return:
135 """
peusterm279565d2016-03-19 10:36:52 +0100136 # config
137 E_CPU = 1.0
138 MAX_CU = 100
peusterm972a9f02016-03-25 14:58:05 +0100139 E_MEM = 512
140 MAX_MU = 2048
peusterm279565d2016-03-19 10:36:52 +0100141 # create dummy resource model environment
peusterm972a9f02016-03-25 14:58:05 +0100142 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)
peusterm279565d2016-03-19 10:36:52 +0100144 reg.register("test_dc", rm)
145
peustermd18559d2016-04-16 04:59:23 +0200146 c1 = createDummyContainerObject("c1", flavor="tiny")
147 rm.allocate(c1) # calculate allocation
stevenvanrossemb2a29bf2017-02-14 14:27:44 +0100148 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
peusterm279565d2016-03-19 10:36:52 +0100150
peustermd18559d2016-04-16 04:59:23 +0200151 c2 = createDummyContainerObject("c2", flavor="small")
152 rm.allocate(c2) # calculate allocation
stevenvanrossemb2a29bf2017-02-14 14:27:44 +0100153 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
peusterm279565d2016-03-19 10:36:52 +0100155
peustermd18559d2016-04-16 04:59:23 +0200156 c3 = createDummyContainerObject("c3", flavor="medium")
peusterm72fc3732016-04-26 19:48:43 +0200157 rm.allocate(c3) # calculate allocation
stevenvanrossemb2a29bf2017-02-14 14:27:44 +0100158 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
peusterm279565d2016-03-19 10:36:52 +0100160
peustermd18559d2016-04-16 04:59:23 +0200161 c4 = createDummyContainerObject("c4", flavor="large")
162 rm.allocate(c4) # calculate allocation
stevenvanrossemb2a29bf2017-02-14 14:27:44 +0100163 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
peustermd18559d2016-04-16 04:59:23 +0200165
peustermd18559d2016-04-16 04:59:23 +0200166 c5 = createDummyContainerObject("c5", flavor="xlarge")
167 rm.allocate(c5) # calculate allocation
stevenvanrossemb2a29bf2017-02-14 14:27:44 +0100168 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
peustermd18559d2016-04-16 04:59:23 +0200170
peusterm279565d2016-03-19 10:36:52 +0100171
peusterm972a9f02016-03-25 14:58:05 +0100172 def testAllocationCpuLimit(self):
173 """
174 Test CPU allocation limit
175 :return:
176 """
177 # config
178 E_CPU = 1.0
peusterm60bf8b82016-04-06 14:12:35 +0200179 MAX_CU = 40
peusterm972a9f02016-03-25 14:58:05 +0100180 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
peusterm279565d2016-03-19 10:36:52 +0100187 # test over provisioning exeption
188 exception = False
189 try:
peustermd18559d2016-04-16 04:59:23 +0200190 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
peusterma41f7862016-04-27 11:01:24 +0200198 except NotEnoughResourcesAvailable as e:
peusterm972a9f02016-03-25 14:58:05 +0100199 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:
peustermd18559d2016-04-16 04:59:23 +0200221 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
peusterma41f7862016-04-27 11:01:24 +0200227 except NotEnoughResourcesAvailable as e:
peusterm972a9f02016-03-25 14:58:05 +0100228 self.assertIn("Not enough memory", e.message)
peusterm279565d2016-03-19 10:36:52 +0100229 exception = True
peustermbdcf2d22016-03-25 12:14:15 +0100230 self.assertTrue(exception)
peusterm279565d2016-03-19 10:36:52 +0100231
232 def testFree(self):
peustermbdcf2d22016-03-25 12:14:15 +0100233 """
234 Test the free procedure.
235 :return:
236 """
peusterm279565d2016-03-19 10:36:52 +0100237 # config
238 E_CPU = 1.0
239 MAX_CU = 100
240 # create dummy resource model environment
peusterm972a9f02016-03-25 14:58:05 +0100241 reg = ResourceModelRegistrar(dc_emulation_max_cpu=1.0, dc_emulation_max_mem=512)
peusterm279565d2016-03-19 10:36:52 +0100242 rm = UpbSimpleCloudDcRM(max_cu=100, max_mu=100)
243 reg.register("test_dc", rm)
peustermd18559d2016-04-16 04:59:23 +0200244 c1 = createDummyContainerObject("c6", flavor="tiny")
245 rm.allocate(c1) # calculate allocation
peusterm60bf8b82016-04-06 14:12:35 +0200246 self.assertTrue(rm.dc_alloc_cu == 0.5)
peustermd18559d2016-04-16 04:59:23 +0200247 rm.free(c1)
peustermbdcf2d22016-03-25 12:14:15 +0100248 self.assertTrue(rm.dc_alloc_cu == 0)
249
peustermc1305232016-05-11 16:14:22 +0200250 @unittest.skipIf(os.environ.get("SON_EMU_IN_DOCKER") is not None,
251 "skipping test when running inside Docker container")
peustermbdcf2d22016-03-25 12:14:15 +0100252 def testInRealTopo(self):
253 """
peusterm5877ea22016-05-11 13:44:59 +0200254 Start a real container and check if limitations are really passed down to Conteinernet.
peustermbdcf2d22016-03-25 12:14:15 +0100255 :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
peusterm5877ea22016-05-11 13:44:59 +0200268 self.assertTrue(len(self.getContainernetContainers()) == 0)
peustermbdcf2d22016-03-25 12:14:15 +0100269 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
peustermd18559d2016-04-16 04:59:23 +0200276 self.assertTrue(len(r._allocated_compute_instances) == 0)
peustermbdcf2d22016-03-25 12:14:15 +0100277 tc1 = self.dc[0].startCompute("tc1", flavor_name="tiny")
278 time.sleep(1)
peustermd18559d2016-04-16 04:59:23 +0200279 self.assertTrue(len(r._allocated_compute_instances) == 1)
peustermbdcf2d22016-03-25 12:14:15 +0100280
281 # check if there is a real limitation set for containers cgroup
peusterm9349c872016-04-16 06:36:42 +0200282 # deactivated for now, seems not to work in docker-in-docker setup used in CI
stevenvanrossemb2a29bf2017-02-14 14:27:44 +0100283 self.assertEqual(float(tc1.resources['cpu_quota'])/tc1.resources['cpu_period'], 0.005)
peustermbdcf2d22016-03-25 12:14:15 +0100284
285 # check if free was called during stopCompute
286 self.dc[0].stopCompute("tc1")
peustermd18559d2016-04-16 04:59:23 +0200287 self.assertTrue(len(r._allocated_compute_instances) == 0)
peustermbdcf2d22016-03-25 12:14:15 +0100288 # 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()
peusterm279565d2016-03-19 10:36:52 +0100292
293
peusterm72fc3732016-04-26 19:48:43 +0200294class 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
stevenvanrossemb2a29bf2017-02-14 14:27:44 +0100316 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)
peusterm72fc3732016-04-26 19:48:43 +0200318 self.assertAlmostEqual(rm.cpu_op_factor, 1.0)
319
320 c2 = createDummyContainerObject("c2", flavor="small")
321 rm.allocate(c2) # calculate allocation
stevenvanrossemb2a29bf2017-02-14 14:27:44 +0100322 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)
peusterm72fc3732016-04-26 19:48:43 +0200324 self.assertAlmostEqual(rm.cpu_op_factor, 1.0)
325
326 c3 = createDummyContainerObject("c3", flavor="small")
327 rm.allocate(c3) # calculate allocation
stevenvanrossemb2a29bf2017-02-14 14:27:44 +0100328 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)
peusterm72fc3732016-04-26 19:48:43 +0200330 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
stevenvanrossemb2a29bf2017-02-14 14:27:44 +0100335 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)
peusterm72fc3732016-04-26 19:48:43 +0200337 self.assertAlmostEqual(rm.cpu_op_factor, 0.75)
338
339 c5 = createDummyContainerObject("c5", flavor="small")
340 rm.allocate(c5) # calculate allocation
stevenvanrossemb2a29bf2017-02-14 14:27:44 +0100341 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)
peusterm72fc3732016-04-26 19:48:43 +0200343 self.assertAlmostEqual(rm.cpu_op_factor, 0.6)
344
345
peusterm8687cb72016-04-28 20:32:36 +0200346class 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)
peusterm279565d2016-03-19 10:36:52 +0100373