summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJames E. Blair <jeblair@redhat.com>2018-11-29 08:33:24 -0800
committerJames E. Blair <jeblair@redhat.com>2018-11-29 14:26:11 -0800
commit854f638e358e59b64aeeebb346a6551636fd3c1f (patch)
tree49d0ae6c7ace192a0f984cce465251dad014b7bf
parent40162102a757621a23fbada8c3bbf22ebf94ee67 (diff)
Support relative priority of node requests
The launcher now processes node requests in relative priority order. This relies on the new node request cache because the relative priority field may be updated at any time by the requestor. Needed-By: https://review.openstack.org/615356 Change-Id: If893c34c6652b9649bfb6f1d9f7b942c549c98b4
Notes
Notes (review): Code-Review+2: James E. Blair <corvus@inaugust.com> Workflow+1: James E. Blair <corvus@inaugust.com> Verified+2: Zuul Submitted-by: Zuul Submitted-at: Fri, 30 Nov 2018 01:58:40 +0000 Reviewed-on: https://review.openstack.org/620954 Project: openstack-infra/nodepool Branch: refs/heads/master
-rwxr-xr-xnodepool/launcher.py12
-rw-r--r--nodepool/tests/unit/test_launcher.py30
-rwxr-xr-xnodepool/zk.py6
3 files changed, 45 insertions, 3 deletions
diff --git a/nodepool/launcher.py b/nodepool/launcher.py
index 192651f..3d90fcf 100755
--- a/nodepool/launcher.py
+++ b/nodepool/launcher.py
@@ -164,7 +164,15 @@ class PoolWorker(threading.Thread):
164 if provider.max_concurrency == 0: 164 if provider.max_concurrency == 0:
165 return 165 return
166 166
167 for req_id in self.zk.getNodeRequests(): 167 # Sort requests by queue priority, then, for all requests at
168 # the same priority, use the relative_priority field to
169 # further sort, then finally, the submission order.
170 requests = list(self.zk.nodeRequestIterator())
171 requests.sort(key=lambda r: (r.id.split('-')[0],
172 r.relative_priority,
173 r.id.split('-')[1]))
174
175 for req in requests:
168 if self.paused_handler: 176 if self.paused_handler:
169 return 177 return
170 178
@@ -182,7 +190,7 @@ class PoolWorker(threading.Thread):
182 active_threads, provider.max_concurrency) 190 active_threads, provider.max_concurrency)
183 return 191 return
184 192
185 req = self.zk.getNodeRequest(req_id) 193 req = self.zk.getNodeRequest(req.id)
186 if not req: 194 if not req:
187 continue 195 continue
188 196
diff --git a/nodepool/tests/unit/test_launcher.py b/nodepool/tests/unit/test_launcher.py
index 4b12ff2..4bb116a 100644
--- a/nodepool/tests/unit/test_launcher.py
+++ b/nodepool/tests/unit/test_launcher.py
@@ -1792,3 +1792,33 @@ class TestLauncher(tests.DBTestCase):
1792 1792
1793 req3 = self.waitForNodeRequest(req3) 1793 req3 = self.waitForNodeRequest(req3)
1794 self.assertEqual(req3.state, zk.FAILED) 1794 self.assertEqual(req3.state, zk.FAILED)
1795
1796 def test_request_order(self):
1797 """Test that requests are handled in sorted order"""
1798 configfile = self.setup_config('node_no_min_ready.yaml')
1799 self.useBuilder(configfile)
1800 image = self.waitForImage('fake-provider', 'fake-image')
1801 self.assertEqual(image.username, 'zuul')
1802
1803 req1 = zk.NodeRequest()
1804 req1.state = zk.REQUESTED
1805 req1.node_types.append('fake-label')
1806 req1.relative_priority = 2
1807 self.zk.storeNodeRequest(req1)
1808
1809 req2 = zk.NodeRequest()
1810 req2.state = zk.REQUESTED
1811 req2.node_types.append('fake-label')
1812 req2.relative_priority = 1
1813 self.zk.storeNodeRequest(req2)
1814
1815 pool = self.useNodepool(configfile, watermark_sleep=1)
1816 pool.start()
1817
1818 req2 = self.waitForNodeRequest(req2)
1819 self.assertEqual(req2.state, zk.FULFILLED)
1820 req1 = self.waitForNodeRequest(req1)
1821 self.assertEqual(req1.state, zk.FULFILLED)
1822
1823 self.assertTrue(req2.id > req1.id)
1824 self.assertTrue(req2.state_time < req1.state_time)
diff --git a/nodepool/zk.py b/nodepool/zk.py
index 0bcd190..caa984f 100755
--- a/nodepool/zk.py
+++ b/nodepool/zk.py
@@ -433,6 +433,7 @@ class NodeRequest(BaseModel):
433 self.nodes = [] 433 self.nodes = []
434 self.reuse = True 434 self.reuse = True
435 self.requestor = None 435 self.requestor = None
436 self.relative_priority = 0
436 437
437 def __repr__(self): 438 def __repr__(self):
438 d = self.toDict() 439 d = self.toDict()
@@ -447,7 +448,8 @@ class NodeRequest(BaseModel):
447 self.node_types == other.node_types and 448 self.node_types == other.node_types and
448 self.nodes == other.nodes and 449 self.nodes == other.nodes and
449 self.reuse == other.reuse and 450 self.reuse == other.reuse and
450 self.requestor == other.requestor) 451 self.requestor == other.requestor and
452 self.relative_priority == other.relative_priority)
451 else: 453 else:
452 return False 454 return False
453 455
@@ -461,6 +463,7 @@ class NodeRequest(BaseModel):
461 d['nodes'] = self.nodes 463 d['nodes'] = self.nodes
462 d['reuse'] = self.reuse 464 d['reuse'] = self.reuse
463 d['requestor'] = self.requestor 465 d['requestor'] = self.requestor
466 d['relative_priority'] = self.relative_priority
464 return d 467 return d
465 468
466 @staticmethod 469 @staticmethod
@@ -485,6 +488,7 @@ class NodeRequest(BaseModel):
485 self.nodes = d.get('nodes', []) 488 self.nodes = d.get('nodes', [])
486 self.reuse = d.get('reuse', True) 489 self.reuse = d.get('reuse', True)
487 self.requestor = d.get('requestor') 490 self.requestor = d.get('requestor')
491 self.relative_priority = d.get('relative_priority', 0)
488 492
489 493
490class Node(BaseModel): 494class Node(BaseModel):