Improve upgrade process to include upgrade flag
Previously, the upgrade process for the undercloud has been to just rerun the install process. The problem is that this does not include anwyay to indicate that it's already been run if we need to trigger some different actions on subsequent runs. As part of the Newton to Ocata upgrade, we need to be able to run the cell v2 setup in a different order than on a traditional install. We need a way for the puppet scripts that ultimately get run to know if it's an upgrade or install action. This change adds the creation of an undercloud_upgrade fact that will be used when the upgrade process is run. Additionally a new script called instack-upgrade-undercloud has been created to be used when upgrade. The use of instack-install-undercloud will cause the install flow to be execuated, while the instack-upgrade-undercloud will set the fact to true to allow for the puppet scripts to use the upgrade flow. Change-Id: Ie3cb21e30334fe8ffc0a9d6e707b42269b64c9ec Related-Bug: #1649341 Related-Blueprint: undercloud-upgrade
This commit is contained in:
parent
c5f80ddfbf
commit
a661b6d5e1
|
@ -17,6 +17,7 @@ import io
|
|||
import json
|
||||
import os
|
||||
import subprocess
|
||||
import tempfile
|
||||
|
||||
import fixtures
|
||||
import mock
|
||||
|
@ -41,6 +42,7 @@ class BaseTestCase(base.BaseTestCase):
|
|||
|
||||
|
||||
class TestUndercloud(BaseTestCase):
|
||||
@mock.patch('instack_undercloud.undercloud._handle_upgrade_fact')
|
||||
@mock.patch('instack_undercloud.undercloud._configure_logging')
|
||||
@mock.patch('instack_undercloud.undercloud._validate_configuration')
|
||||
@mock.patch('instack_undercloud.undercloud._run_command')
|
||||
|
@ -53,7 +55,8 @@ class TestUndercloud(BaseTestCase):
|
|||
def test_install(self, mock_load_config, mock_generate_environment,
|
||||
mock_run_yum_update, mock_run_instack, mock_run_orc,
|
||||
mock_post_config, mock_run_command,
|
||||
mock_validate_configuration, mock_configure_logging):
|
||||
mock_validate_configuration, mock_configure_logging,
|
||||
mock_upgrade_fact):
|
||||
fake_env = mock.MagicMock()
|
||||
mock_generate_environment.return_value = fake_env
|
||||
undercloud.install('.')
|
||||
|
@ -63,6 +66,33 @@ class TestUndercloud(BaseTestCase):
|
|||
mock_run_orc.assert_called_with(fake_env)
|
||||
mock_run_command.assert_called_with(
|
||||
['sudo', 'rm', '-f', '/tmp/svc-map-services'], None, 'rm')
|
||||
mock_upgrade_fact.assert_called_with(False)
|
||||
|
||||
@mock.patch('instack_undercloud.undercloud._handle_upgrade_fact')
|
||||
@mock.patch('instack_undercloud.undercloud._configure_logging')
|
||||
@mock.patch('instack_undercloud.undercloud._validate_configuration')
|
||||
@mock.patch('instack_undercloud.undercloud._run_command')
|
||||
@mock.patch('instack_undercloud.undercloud._post_config')
|
||||
@mock.patch('instack_undercloud.undercloud._run_orc')
|
||||
@mock.patch('instack_undercloud.undercloud._run_yum_update')
|
||||
@mock.patch('instack_undercloud.undercloud._run_instack')
|
||||
@mock.patch('instack_undercloud.undercloud._generate_environment')
|
||||
@mock.patch('instack_undercloud.undercloud._load_config')
|
||||
def test_install_upgrade(self, mock_load_config, mock_generate_environment,
|
||||
mock_run_yum_update, mock_run_instack,
|
||||
mock_run_orc, mock_post_config, mock_run_command,
|
||||
mock_validate_configuration,
|
||||
mock_configure_logging, mock_upgrade_fact):
|
||||
fake_env = mock.MagicMock()
|
||||
mock_generate_environment.return_value = fake_env
|
||||
undercloud.install('.', upgrade=True)
|
||||
self.assertTrue(mock_validate_configuration.called)
|
||||
mock_generate_environment.assert_called_with('.')
|
||||
mock_run_instack.assert_called_with(fake_env)
|
||||
mock_run_orc.assert_called_with(fake_env)
|
||||
mock_run_command.assert_called_with(
|
||||
['sudo', 'rm', '-f', '/tmp/svc-map-services'], None, 'rm')
|
||||
mock_upgrade_fact.assert_called_with(True)
|
||||
|
||||
@mock.patch('instack_undercloud.undercloud._configure_logging')
|
||||
def test_install_exception(self, mock_configure_logging):
|
||||
|
@ -744,3 +774,64 @@ class TestPostConfig(base.BaseTestCase):
|
|||
mock_instance.flavors.list.return_value = mock_flavors
|
||||
undercloud._delete_default_flavors(mock_instance)
|
||||
mock_instance.flavors.delete.assert_called_once_with('8ar')
|
||||
|
||||
|
||||
class TestUpgradeFact(base.BaseTestCase):
|
||||
@mock.patch('instack_undercloud.undercloud._run_command')
|
||||
@mock.patch('os.path.dirname')
|
||||
@mock.patch('os.path.exists')
|
||||
@mock.patch.object(tempfile, 'mkstemp', return_value=(1, '/tmp/file'))
|
||||
def test_upgrade_fact(self, mock_mkstemp, mock_exists, mock_dirname,
|
||||
mock_run):
|
||||
fact_path = '/etc/facter/facts.d/undercloud_upgrade.txt'
|
||||
mock_dirname.return_value = '/etc/facter/facts.d'
|
||||
mock_exists.side_effect = [False, True]
|
||||
|
||||
with mock.patch('instack_undercloud.undercloud.open') as mock_open:
|
||||
undercloud._handle_upgrade_fact(True)
|
||||
mock_open.assert_called_with('/tmp/file', 'w')
|
||||
|
||||
run_calls = [
|
||||
mock.call(['sudo', 'mkdir', '-p', '/etc/facter/facts.d']),
|
||||
mock.call(['sudo', 'mv', '/tmp/file', fact_path]),
|
||||
mock.call(['sudo', 'chmod', '0644', fact_path])
|
||||
]
|
||||
mock_run.assert_has_calls(run_calls)
|
||||
self.assertEqual(mock_run.call_count, 3)
|
||||
|
||||
@mock.patch('instack_undercloud.undercloud._run_command')
|
||||
@mock.patch('os.path.dirname')
|
||||
@mock.patch('os.path.exists')
|
||||
@mock.patch.object(tempfile, 'mkstemp', return_value=(1, '/tmp/file'))
|
||||
def test_upgrade_fact_install(self, mock_mkstemp, mock_exists,
|
||||
mock_dirname, mock_run):
|
||||
mock_dirname.return_value = '/etc/facter/facts.d'
|
||||
mock_exists.return_value = False
|
||||
|
||||
with mock.patch('instack_undercloud.undercloud.open') as mock_open:
|
||||
undercloud._handle_upgrade_fact(False)
|
||||
mock_open.assert_not_called()
|
||||
|
||||
mock_run.assert_not_called()
|
||||
|
||||
@mock.patch('instack_undercloud.undercloud._run_command')
|
||||
@mock.patch('os.path.dirname')
|
||||
@mock.patch('os.path.exists')
|
||||
@mock.patch.object(tempfile, 'mkstemp', return_value=(1, '/tmp/file'))
|
||||
def test_upgrade_fact_upgrade_after_install(self, mock_mkstemp,
|
||||
mock_exists, mock_dirname,
|
||||
mock_run):
|
||||
fact_path = '/etc/facter/facts.d/undercloud_upgrade.txt'
|
||||
mock_dirname.return_value = '/etc/facter/facts.d'
|
||||
mock_exists.return_value = True
|
||||
|
||||
with mock.patch('instack_undercloud.undercloud.open') as open_m:
|
||||
undercloud._handle_upgrade_fact(True)
|
||||
open_m.assert_called_with('/tmp/file', 'w')
|
||||
|
||||
run_calls = [
|
||||
mock.call(['sudo', 'mv', '/tmp/file', fact_path]),
|
||||
mock.call(['sudo', 'chmod', '0644', fact_path])
|
||||
]
|
||||
mock_run.assert_has_calls(run_calls)
|
||||
self.assertEqual(mock_run.call_count, 2)
|
||||
|
|
|
@ -1232,7 +1232,36 @@ def _post_config(instack_env):
|
|||
_post_config_mistral(instack_env, mistral)
|
||||
|
||||
|
||||
def install(instack_root):
|
||||
def _handle_upgrade_fact(upgrade=False):
|
||||
"""Create an upgrade fact for use in puppet
|
||||
|
||||
Since we don't run different puppets depending on if it's an upgrade or
|
||||
not, we need to be able to pass a flag into puppet to let it know if
|
||||
we're doing an upgrade. This is helpful when trying to handle state
|
||||
transitions from an already installed undercloud. This function creates
|
||||
a static fact named undercloud_upgrade only after the install has occured.
|
||||
When invoked with upgrade=True, the $::undercloud_upgrade fact should
|
||||
be set to true.
|
||||
|
||||
:param upgrade: Boolean indicating if this is an upgrade action or not
|
||||
"""
|
||||
|
||||
fact_string = 'undercloud_upgrade={}'.format(upgrade)
|
||||
fact_path = '/etc/facter/facts.d/undercloud_upgrade.txt'
|
||||
if not os.path.exists(os.path.dirname(fact_path)) and upgrade:
|
||||
_run_command(['sudo', 'mkdir', '-p', os.path.dirname(fact_path)])
|
||||
|
||||
# We only need to ensure the fact is correct when we've already installed
|
||||
# the undercloud.
|
||||
if os.path.exists(os.path.dirname(fact_path)):
|
||||
tmp_fact = tempfile.mkstemp()[1]
|
||||
with open(tmp_fact, 'w') as f:
|
||||
f.write(fact_string.lower())
|
||||
_run_command(['sudo', 'mv', tmp_fact, fact_path])
|
||||
_run_command(['sudo', 'chmod', '0644', fact_path])
|
||||
|
||||
|
||||
def install(instack_root, upgrade=False):
|
||||
"""Install the undercloud
|
||||
|
||||
:param instack_root: The path containing the instack-undercloud elements
|
||||
|
@ -1248,6 +1277,7 @@ def install(instack_root):
|
|||
_generate_init_data(instack_env)
|
||||
if CONF.undercloud_update_packages:
|
||||
_run_yum_update(instack_env)
|
||||
_handle_upgrade_fact(upgrade)
|
||||
_run_instack(instack_env)
|
||||
_run_orc(instack_env)
|
||||
_post_config(instack_env)
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
#!/bin/bash
|
||||
|
||||
python -c "from instack_undercloud import undercloud; undercloud.install('$(dirname $0)/..', upgrade=True)"
|
Loading…
Reference in New Issue