From 861f35b038431f64dbc29c64a230461efa41b60e Mon Sep 17 00:00:00 2001
From: shenxindi <shenxindi@cmss.chinamobile.com>
Date: Wed, 8 Apr 2020 16:07:29 +0800
Subject: [PATCH] Release reservation when stoping the ironic-conductor service

If a conductor hostname is changed while reservations are
issued to a conductor with one hostname, such as 'hostname'
and then the process is restarted with 'new_hostname', then the
queries would not match the node and effectively the nodes
would become inaccessible until the reservation is cleared.

This patch clears the reservation when stoping the
ironic-conductor service to avoid the nodes becoming inaccessible.

Ref to: https://review.opendev.org/#/c/711765/

Change-Id: Id31cd30564ff26df0bbe4976ffe3f268b0dd3d7b
---
 ironic/conductor/base_manager.py                      |  2 ++
 ironic/tests/unit/conductor/test_base_manager.py      | 11 +++++++++++
 ...eservation-on-conductor-stop-6ebbcdf92da57ca6.yaml |  6 ++++++
 3 files changed, 19 insertions(+)
 create mode 100644 releasenotes/notes/release-reservation-on-conductor-stop-6ebbcdf92da57ca6.yaml

diff --git a/ironic/conductor/base_manager.py b/ironic/conductor/base_manager.py
index 8ef568d830..6f071246a2 100644
--- a/ironic/conductor/base_manager.py
+++ b/ironic/conductor/base_manager.py
@@ -296,6 +296,8 @@ class BaseConductorManager(object):
             return
         self._shutdown = True
         self._keepalive_evt.set()
+        # clear all locks held by this conductor before deregistering
+        self.dbapi.clear_node_reservations_for_conductor(self.host)
         if deregister:
             try:
                 # Inform the cluster that this conductor is shutting down.
diff --git a/ironic/tests/unit/conductor/test_base_manager.py b/ironic/tests/unit/conductor/test_base_manager.py
index f8ba77c3fa..49cacbff5b 100644
--- a/ironic/tests/unit/conductor/test_base_manager.py
+++ b/ironic/tests/unit/conductor/test_base_manager.py
@@ -64,6 +64,17 @@ class StartStopTestCase(mgr_utils.ServiceSetUpMixin, db_base.DbTestCase):
         node.refresh()
         self.assertIsNone(node.reservation)
 
+    def test_stop_clears_conductor_locks(self):
+        node = obj_utils.create_test_node(self.context,
+                                          reservation=self.hostname)
+        node.save()
+        self._start_service()
+        res = objects.Conductor.get_by_hostname(self.context, self.hostname)
+        self.assertEqual(self.hostname, res['hostname'])
+        self.service.del_host()
+        node.refresh()
+        self.assertIsNone(node.reservation)
+
     def test_stop_unregisters_conductor(self):
         self._start_service()
         res = objects.Conductor.get_by_hostname(self.context, self.hostname)
diff --git a/releasenotes/notes/release-reservation-on-conductor-stop-6ebbcdf92da57ca6.yaml b/releasenotes/notes/release-reservation-on-conductor-stop-6ebbcdf92da57ca6.yaml
new file mode 100644
index 0000000000..1d583a88cb
--- /dev/null
+++ b/releasenotes/notes/release-reservation-on-conductor-stop-6ebbcdf92da57ca6.yaml
@@ -0,0 +1,6 @@
+---
+fixes:
+  - |
+    Fixes an issue where a node may be locked from changes if a conductor's
+    hostname case is changed before restarting the conductor service. clean
+    up the reservation once the conductor stopped.