def _construct_cell(): """Constructs a test cell.""" cell = scheduler.Cell('top') rack1 = scheduler.Bucket('rack:rack1', traits=0, level='rack') rack2 = scheduler.Bucket('rack:rack2', traits=0, level='rack') cell.add_node(rack1) cell.add_node(rack2) srv1 = scheduler.Server('srv1', [10, 20, 30], traits=3, valid_until=1000) srv2 = scheduler.Server('srv2', [10, 20, 30], traits=7, valid_until=2000) srv3 = scheduler.Server('srv3', [10, 20, 30], traits=0, valid_until=3000) srv4 = scheduler.Server('srv4', [10, 20, 30], traits=0, valid_until=4000) rack1.add_node(srv1) rack1.add_node(srv2) rack2.add_node(srv3) rack2.add_node(srv4) tenant1 = scheduler.Allocation() tenant2 = scheduler.Allocation() tenant3 = scheduler.Allocation() alloc1 = scheduler.Allocation([10, 10, 10], rank=100, traits=0) alloc2 = scheduler.Allocation([10, 10, 10], rank=100, traits=3) cell.partitions[None].allocation.add_sub_alloc('t1', tenant1) cell.partitions[None].allocation.add_sub_alloc('t2', tenant2) tenant1.add_sub_alloc('t3', tenant3) tenant2.add_sub_alloc('a1', alloc1) tenant3.add_sub_alloc('a2', alloc2) return cell
def test_utilization(self): """Test utilization calculation.""" alloc = scheduler.Allocation([10, 10]) alloc.add(scheduler.Application('app1', 100, [1, 1], 'app1')) alloc.add(scheduler.Application('app2', 100, [2, 2], 'app1')) alloc.add(scheduler.Application('app3', 100, [3, 3], 'app1')) # First element is rank. util_q = list(alloc.utilization_queue([20, 20])) self.assertEqual(100, util_q[0][0]) self.assertEqual(100, util_q[1][0]) self.assertEqual(100, util_q[2][0]) # Second elememt is utilization. self.assertEqual(-9. / (10. + 20), util_q[0][1]) self.assertEqual(-7. / (10. + 20), util_q[1][1]) self.assertEqual(-4. / (10. + 20), util_q[2][1]) # Applications are sorted by priority. alloc = scheduler.Allocation([10, 10]) alloc.add(scheduler.Application('app1', 10, [1, 1], 'app1')) alloc.add(scheduler.Application('app2', 50, [2, 2], 'app1')) alloc.add(scheduler.Application('app3', 100, [3, 3], 'app1')) util_q = list(alloc.utilization_queue([20., 20.])) self.assertEqual(-7. / (10. + 20), util_q[0][1]) self.assertEqual(-5. / (10. + 20), util_q[1][1]) self.assertEqual(-4. / (10. + 20), util_q[2][1])
def test_sub_allocs(self): """Test utilization calculation with sub-allocs.""" alloc = scheduler.Allocation([3, 3]) self.assertEqual(3, alloc.total_reserved()[0]) alloc.add(scheduler.Application('1', 3, [2, 2], 'app1')) alloc.add(scheduler.Application('2', 2, [1, 1], 'app1')) alloc.add(scheduler.Application('3', 1, [3, 3], 'app1')) queue = list(alloc.utilization_queue([20., 20.])) sub_alloc_a = scheduler.Allocation([5, 5]) alloc.add_sub_alloc('a1/a', sub_alloc_a) self.assertEqual(8, alloc.total_reserved()[0]) sub_alloc_a.add(scheduler.Application('1a', 3, [2, 2], 'app1')) sub_alloc_a.add(scheduler.Application('2a', 2, [3, 3], 'app1')) sub_alloc_a.add(scheduler.Application('3a', 1, [5, 5], 'app1')) queue = list(alloc.utilization_queue([20., 20.])) _rank, util, _pending, _order, app = queue[0] self.assertEqual('1a', app.name) self.assertEqual((2 - (5 + 3)) / (20. + (5 + 3)), util) sub_alloc_b = scheduler.Allocation([10, 10]) alloc.add_sub_alloc('a1/b', sub_alloc_b) sub_alloc_b.add(scheduler.Application('1b', 3, [2, 2], 'app1')) sub_alloc_b.add(scheduler.Application('2b', 2, [3, 3], 'app1')) sub_alloc_b.add(scheduler.Application('3b', 1, [5, 5], 'app1')) queue = list(alloc.utilization_queue([20., 20.])) self.assertEqual(9, len(queue)) self.assertEqual(18, alloc.total_reserved()[0]) # For each sub-alloc (and self) the least utilized app is 1. # The sub_allloc_b is largest, so utilization smallest, 1b will be # first. _rank, util, _pending, _order, app = queue[0] self.assertEqual('1b', app.name) self.assertEqual((2. - 18) / (20. + 18), util) # Add prio 0 app to each, make sure they all end up last. alloc.add(scheduler.Application('1-zero', 0, [2, 2], 'app1')) sub_alloc_b.add(scheduler.Application('b-zero', 0, [5, 5], 'app1')) sub_alloc_a.add(scheduler.Application('a-zero', 0, [5, 5], 'app1')) queue = list(alloc.utilization_queue([20., 20.])) self.assertIn('1-zero', [item[-1].name for item in queue[-3:]]) self.assertIn('a-zero', [item[-1].name for item in queue[-3:]]) self.assertIn('b-zero', [item[-1].name for item in queue[-3:]]) # Check that utilization of prio 0 apps is always max float. self.assertEqual( [float('inf')] * 3, [util for (_rank, util, _pending, _order, _app) in queue[-3:]] # noqa: F812,E501 )
def test_zerovector(self): """Test updating allocation with allocation vector containing 0's""" alloc = scheduler.Allocation(None) alloc.update([1, 0], None) self.assertEqual(1.0, alloc.reserved[0]) self.assertEqual(0, alloc.reserved[1])
def _construct_cell(empty=False): """Constructs a test cell.""" cell = scheduler.Cell('top') if empty: return cell rack1 = scheduler.Bucket('rack:rack1', traits=0, level='rack') rack2 = scheduler.Bucket('rack:rack2', traits=0, level='rack') cell.add_node(rack1) cell.add_node(rack2) srv1 = scheduler.Server('srv1', [10, 20, 30], traits=1, valid_until=1000, label='part') srv2 = scheduler.Server('srv2', [10, 20, 30], traits=3, valid_until=2000, label='part') srv3 = scheduler.Server('srv3', [10, 20, 30], traits=0, valid_until=3000, label='_default') srv4 = scheduler.Server('srv4', [10, 20, 30], traits=0, valid_until=4000, label='_default') rack1.add_node(srv1) rack1.add_node(srv2) rack2.add_node(srv3) rack2.add_node(srv4) tenant1 = scheduler.Allocation() cell.partitions['_default'].allocation.add_sub_alloc('t1', tenant1) tenant11 = scheduler.Allocation() tenant1.add_sub_alloc('t11', tenant11) alloc1 = scheduler.Allocation([10, 10, 10], rank=100, traits=0) tenant11.add_sub_alloc('a1', alloc1) tenant2 = scheduler.Allocation() cell.partitions['part'].allocation.add_sub_alloc('t2', tenant2) alloc2 = scheduler.Allocation([10, 10, 10], rank=100, traits=3) tenant2.add_sub_alloc('a2', alloc2) return cell
def test_duplicate(self): """Checks behavior when adding duplicate app.""" alloc = scheduler.Allocation(None) alloc.add(scheduler.Application('app1', 0, [1, 1], 'app1')) self.assertEqual( 1, len(list(alloc.utilization_queue(np.array([5., 5.]))))) alloc.add(scheduler.Application('app1', 0, [1, 1], 'app1')) self.assertEqual( 1, len(list(alloc.utilization_queue(np.array([5., 5.])))))
def _construct_cell(): """Constructs a test cell.""" cell = scheduler.Cell('top') rack1 = scheduler.Bucket('rack:rack1', features=[], level='rack') rack2 = scheduler.Bucket('rack:rack2', features=[], level='rack') cell.add_node(rack1) cell.add_node(rack2) srv1 = scheduler.Server('srv1', [10, 20, 30], features=['aaa', 'bbb'], valid_until=1000) srv2 = scheduler.Server('srv2', [10, 20, 30], features=['ccc'], valid_until=2000) srv3 = scheduler.Server('srv3', [10, 20, 30], features=[], valid_until=3000) srv4 = scheduler.Server('srv4', [10, 20, 30], features=[], valid_until=4000) rack1.add_node(srv1) rack1.add_node(srv2) rack2.add_node(srv3) rack2.add_node(srv4) tenant1 = scheduler.Allocation() tenant2 = scheduler.Allocation() tenant3 = scheduler.Allocation() alloc1 = scheduler.Allocation([10, 10, 10], rank=100, features=[]) alloc2 = scheduler.Allocation([10, 10, 10], rank=100, features=['aaa']) cell.allocation.add_sub_alloc('t1', tenant1) cell.allocation.add_sub_alloc('t2', tenant2) tenant1.add_sub_alloc('t3', tenant3) tenant2.add_sub_alloc('a1', alloc1) tenant3.add_sub_alloc('a2', alloc2) return cell
def test_running_order(self): """Test apps are ordered by status (running first) for same prio.""" alloc = scheduler.Allocation([10, 10]) alloc.add(scheduler.Application('app1', 5, [1, 1], 'app1')) alloc.add(scheduler.Application('app2', 5, [2, 2], 'app1')) alloc.add(scheduler.Application('app3', 5, [3, 3], 'app1')) queue = list(alloc.utilization_queue([20., 20.])) self.assertEqual(alloc.apps['app1'], queue[0][-1]) alloc.apps['app2'].server = 'abc' queue = list(alloc.utilization_queue([20., 20.])) self.assertEqual(alloc.apps['app2'], queue[0][-1])
def test_utilization_max(self): """Tests max utilization cap on the allocation.""" alloc = scheduler.Allocation([3, 3]) alloc.add(scheduler.Application('app1', 1, [1, 1], 'app1')) alloc.add(scheduler.Application('app2', 1, [2, 2], 'app1')) alloc.add(scheduler.Application('app3', 1, [3, 3], 'app1')) self.assertEqual(3, len(list(alloc.utilization_queue([20., 20.])))) # Now set max_utilization to 1 alloc.max_utilization = 1 # XXX(boysson: Broken test. Needs upgrade to V3 # XXX: # XXX: self.assertEqual( # XXX: 2, # XXX: len(list(alloc.utilization_queue([20., 20.]))) # XXX: ) alloc.set_max_utilization(None) self.assertEqual(3, len(list(alloc.utilization_queue([20., 20.]))))
def test_app_trait_placement(self): """Tests placement of app with traits.""" top = scheduler.Bucket('top', traits=_traits2int(['top'])) left = scheduler.Bucket('left', traits=_traits2int(['left'])) right = scheduler.Bucket('right', traits=_traits2int(['right'])) srv_a = scheduler.Server('a', [10, 10], traits=_traits2int(['a', '0']), valid_until=500) srv_b = scheduler.Server('b', [10, 10], traits=_traits2int(['b', '0']), valid_until=500) srv_y = scheduler.Server('y', [10, 10], traits=_traits2int(['y', '1']), valid_until=500) srv_z = scheduler.Server('z', [10, 10], traits=_traits2int(['z', '1']), valid_until=500) top.add_node(left) top.add_node(right) left.add_node(srv_a) left.add_node(srv_b) right.add_node(srv_y) right.add_node(srv_z) alloc_a = scheduler.Allocation(traits=_traits2int(['a'])) apps_a = app_list(10, 'app_a', 50, [2, 2]) for app in apps_a: alloc_a.add(app) # srv_a is the only one with trait 'a'. self.assertTrue(top.put(apps_a[0])) self.assertTrue(top.put(apps_a[1])) self.assertIn(apps_a[0].name, srv_a.apps) self.assertIn(apps_a[1].name, srv_a.apps) alloc_0 = scheduler.Allocation(traits=_traits2int(['0'])) apps_0 = app_list(10, 'app_0', 50, [2, 2]) for app in apps_0: alloc_0.add(app) # '0' trait - two servers, will spread by default. self.assertTrue(top.put(apps_0[0])) self.assertTrue(top.put(apps_0[1])) self.assertIn(apps_0[0].name, srv_a.apps) self.assertIn(apps_0[1].name, srv_b.apps) # Prev implementation propagated traits from parent to children, # so "right" trait propagated to leaf servers. # # This behavior is removed, so placing app with "right" trait will # fail. # # alloc_r1 = scheduler.Allocation(traits=_traits2int(['right', '1'])) # apps_r1 = app_list(10, 'app_r1', 50, [2, 2]) # for app in apps_r1: # alloc_r1.add(app) # self.assertTrue(top.put(apps_r1[0])) # self.assertTrue(top.put(apps_r1[1])) # self.assertIn(apps_r1[0].name, srv_y.apps) # self.assertIn(apps_r1[1].name, srv_z.apps) apps_nothing = app_list(10, 'apps_nothing', 50, [1, 1]) # All nodes fit. Spead first between buckets, then between nodes. # top # left right # a b y z self.assertTrue(top.put(apps_nothing[0])) self.assertTrue(top.put(apps_nothing[1])) self.assertTrue( (apps_nothing[0].server in ['a', 'b'] and apps_nothing[1].server in ['y', 'z']) or (apps_nothing[0].server in ['y', 'z'] and apps_nothing[1].server in ['a', 'b'])) self.assertTrue(top.put(apps_nothing[2])) self.assertTrue(top.put(apps_nothing[3])) self.assertTrue( (apps_nothing[2].server in ['a', 'b'] and apps_nothing[3].server in ['y', 'z']) or (apps_nothing[2].server in ['y', 'z'] and apps_nothing[3].server in ['a', 'b']))
def test_utilization_no_reservation(self): """Checks that any utilization without reservation is VERY large.""" alloc = scheduler.Allocation(None) alloc.add(scheduler.Application('app1', 1, [1., 1.], 'app1')) queue = list(alloc.utilization_queue(np.array([10., 10.]))) self.assertEqual(1. / (10), queue[0][1])
def test_app_feature_placement(self): """Tests placement of app with features.""" top = scheduler.Bucket('top', features=['top']) left = scheduler.Bucket('left', features=['left']) right = scheduler.Bucket('right', features=['right']) srv_a = scheduler.Server('a', [10, 10], features=['a', '0'], valid_until=500) srv_b = scheduler.Server('b', [10, 10], features=['b', '0'], valid_until=500) srv_y = scheduler.Server('y', [10, 10], features=['y', '1'], valid_until=500) srv_z = scheduler.Server('z', [10, 10], features=['z', '1'], valid_until=500) top.add_node(left) top.add_node(right) left.add_node(srv_a) left.add_node(srv_b) right.add_node(srv_y) right.add_node(srv_z) alloc_a = scheduler.Allocation(features=['a']) apps_a = app_list(10, 'app_a', 50, [2, 2]) for app in apps_a: alloc_a.add(app) # srv_a is the only one with feature 'a'. self.assertTrue(top.put(apps_a[0])) self.assertTrue(top.put(apps_a[1])) self.assertIn(apps_a[0].name, srv_a.apps) self.assertIn(apps_a[1].name, srv_a.apps) alloc_0 = scheduler.Allocation(features=['0']) apps_0 = app_list(10, 'app_0', 50, [2, 2]) for app in apps_0: alloc_0.add(app) # '0' feature - two servers, will spread by default. self.assertTrue(top.put(apps_0[0])) self.assertTrue(top.put(apps_0[1])) self.assertIn(apps_0[0].name, srv_a.apps) self.assertIn(apps_0[1].name, srv_b.apps) alloc_r1 = scheduler.Allocation(features=['right', '1']) apps_r1 = app_list(10, 'app_r1', 50, [2, 2]) for app in apps_r1: alloc_r1.add(app) self.assertTrue(top.put(apps_r1[0])) self.assertTrue(top.put(apps_r1[1])) self.assertIn(apps_r1[0].name, srv_y.apps) self.assertIn(apps_r1[1].name, srv_z.apps) apps_nothing = app_list(10, 'apps_nothing', 50, [1, 1]) self.assertTrue(top.put(apps_nothing[0])) self.assertTrue(top.put(apps_nothing[1])) self.assertTrue(top.put(apps_nothing[2])) self.assertTrue(top.put(apps_nothing[3])) # All nodes fit. Spead first between buckets, then between nodes. # top # left right # a b y z self.assertIn(apps_nothing[0].name, srv_a.apps) self.assertIn(apps_nothing[1].name, srv_y.apps) self.assertIn(apps_nothing[2].name, srv_b.apps) self.assertIn(apps_nothing[3].name, srv_z.apps)