From 2d2e950e8f94a4bd9355f746913ecd37c3526b45 Mon Sep 17 00:00:00 2001
From: James Page <james.page@ubuntu.com>
Date: Mon, 29 Jun 2015 12:33:36 +0100
Subject: [PATCH] Fixup upgrades to ensure that only the leader attempts to
 migrate the database

---
 hooks/neutron_api_utils.py           |  3 +-
 unit_tests/test_neutron_api_utils.py | 43 ++++++++++++++++++++++++++++
 2 files changed, 45 insertions(+), 1 deletion(-)

diff --git a/hooks/neutron_api_utils.py b/hooks/neutron_api_utils.py
index 9f3724aa..8feef030 100644
--- a/hooks/neutron_api_utils.py
+++ b/hooks/neutron_api_utils.py
@@ -48,6 +48,7 @@ from charmhelpers.core.host import (
 )
 
 from charmhelpers.core.templating import render
+from charmhelpers.contrib.hahelpers.cluster import is_elected_leader
 
 import neutron_api_context
 
@@ -292,7 +293,7 @@ def do_openstack_upgrade(configs):
     # set CONFIGS to load templates from new release
     configs.set_release(openstack_release=new_os_rel)
     # Before kilo it's nova-cloud-controllers job
-    if new_os_rel >= 'kilo':
+    if is_elected_leader(CLUSTER_RES) and new_os_rel >= 'kilo':
         stamp_neutron_database(cur_os_rel)
         migrate_neutron_database()
 
diff --git a/unit_tests/test_neutron_api_utils.py b/unit_tests/test_neutron_api_utils.py
index 7de08226..f92bf27c 100644
--- a/unit_tests/test_neutron_api_utils.py
+++ b/unit_tests/test_neutron_api_utils.py
@@ -33,6 +33,7 @@ TO_PATCH = [
     'os_release',
     'pip_install',
     'subprocess',
+    'is_elected_leader',
 ]
 
 openstack_origin_git = \
@@ -190,6 +191,7 @@ class TestNeutronAPIUtils(CharmTestCase):
     def test_do_openstack_upgrade_juno(self, git_requested,
                                        stamp_neutron_db, migrate_neutron_db):
         git_requested.return_value = False
+        self.is_elected_leader.return_value = True
         self.config.side_effect = self.test_config.get
         self.test_config.set('openstack-origin', 'cloud:trusty-juno')
         self.os_release.return_value = 'icehouse'
@@ -227,6 +229,7 @@ class TestNeutronAPIUtils(CharmTestCase):
                                        stamp_neutron_db, migrate_neutron_db,
                                        gsrc):
         git_requested.return_value = False
+        self.is_elected_leader.return_value = True
         self.os_release.return_value = 'juno'
         self.config.side_effect = self.test_config.get
         self.test_config.set('openstack-origin', 'cloud:trusty-kilo')
@@ -256,6 +259,46 @@ class TestNeutronAPIUtils(CharmTestCase):
         stamp_neutron_db.assert_called_with('juno')
         migrate_neutron_db.assert_called_with()
 
+    @patch.object(charmhelpers.contrib.openstack.utils,
+                  'get_os_codename_install_source')
+    @patch.object(nutils, 'migrate_neutron_database')
+    @patch.object(nutils, 'stamp_neutron_database')
+    @patch.object(nutils, 'git_install_requested')
+    def test_do_openstack_upgrade_kilo_notleader(self, git_requested,
+                                                 stamp_neutron_db,
+                                                 migrate_neutron_db,
+                                                 gsrc):
+        git_requested.return_value = False
+        self.is_elected_leader.return_value = False
+        self.os_release.return_value = 'juno'
+        self.config.side_effect = self.test_config.get
+        self.test_config.set('openstack-origin', 'cloud:trusty-kilo')
+        gsrc.return_value = 'kilo'
+        self.get_os_codename_install_source.return_value = 'kilo'
+        configs = MagicMock()
+        nutils.do_openstack_upgrade(configs)
+        self.os_release.assert_called_with('neutron-server')
+        self.log.assert_called()
+        self.configure_installation_source.assert_called_with(
+            'cloud:trusty-kilo'
+        )
+        self.apt_update.assert_called_with(fatal=True)
+        dpkg_opts = [
+            '--option', 'Dpkg::Options::=--force-confnew',
+            '--option', 'Dpkg::Options::=--force-confdef',
+        ]
+        self.apt_upgrade.assert_called_with(options=dpkg_opts,
+                                            fatal=True,
+                                            dist=True)
+        pkgs = nutils.determine_packages()
+        pkgs.sort()
+        self.apt_install.assert_called_with(packages=pkgs,
+                                            options=dpkg_opts,
+                                            fatal=True)
+        configs.set_release.assert_called_with(openstack_release='kilo')
+        self.assertFalse(stamp_neutron_db.called)
+        self.assertFalse(migrate_neutron_db.called)
+
     @patch.object(ncontext, 'IdentityServiceContext')
     @patch('neutronclient.v2_0.client.Client')
     def test_get_neutron_client(self, nclient, IdentityServiceContext):