diff --git a/tests/test_nodepool.py b/tests/test_nodepool.py index 3019f08e47..677ae739e1 100644 --- a/tests/test_nodepool.py +++ b/tests/test_nodepool.py @@ -83,6 +83,12 @@ class TestNodepool(BaseTestCase): for node in nodeset.getNodes(): self.assertEqual(node.state, 'in-use') + # Return the nodes + self.nodepool.returnNodeset(nodeset) + for node in nodeset.getNodes(): + self.assertIsNone(node.lock) + self.assertEqual(node.state, 'used') + def test_node_request_disconnect(self): # Test that node requests are re-submitted after disconnect diff --git a/zuul/manager/__init__.py b/zuul/manager/__init__.py index d1e12c5640..f5a35cdb85 100644 --- a/zuul/manager/__init__.py +++ b/zuul/manager/__init__.py @@ -599,6 +599,13 @@ class PipelineManager(object): self.sched.mutex.release(item, build.job) self.log.debug("Item %s status is now:\n %s" % (item, item.formatStatus())) + + try: + nodeset = build.build_set.getJobNodeSet(build.job.name) + self.nodepool.returnNodeset(nodeset) + except Exception: + self.log.exception("Unable to return nodeset %s" % (nodeset,)) + return True def onMergeCompleted(self, event): diff --git a/zuul/nodepool.py b/zuul/nodepool.py index eceac0ba05..11b02b6e27 100644 --- a/zuul/nodepool.py +++ b/zuul/nodepool.py @@ -45,8 +45,14 @@ class Nodepool(object): node.state = 'in-use' self.sched.zk.storeNode(node) - def returnNodes(self, nodes, used=True): - pass + def returnNodeset(self, nodeset): + for node in nodeset.getNodes(): + if node.lock is None: + raise Exception("Node %s is not locked" % (node,)) + if node.state == 'in-use': + node.state = 'used' + self.sched.zk.storeNode(node) + self._unlockNodes(nodeset.getNodes()) def unlockNodeset(self, nodeset): self._unlockNodes(nodeset.getNodes()) diff --git a/zuul/scheduler.py b/zuul/scheduler.py index 270e055f2d..4a0a9eb88f 100644 --- a/zuul/scheduler.py +++ b/zuul/scheduler.py @@ -810,12 +810,13 @@ class Scheduler(threading.Thread): if build_set is not build_set.item.current_build_set: self.log.warning("Build set %s is not current" % (build_set,)) - self.nodepool.returnNodes(request.nodes, used=False) + self.nodepool.returnNodeset(request.nodeset) return pipeline = build_set.item.pipeline if not pipeline: self.log.warning("Build set %s is not associated with a pipeline" % (build_set,)) + self.nodepool.returnNodeset(request.nodeset) return pipeline.manager.onNodesProvisioned(event)