Action managed upgrades

This commit is contained in:
David Ames 2015-09-21 16:06:54 -07:00
parent 9ace8eaa41
commit 468f3ae945
8 changed files with 116 additions and 10 deletions

View File

@ -1,2 +1,4 @@
git-reinstall: git-reinstall:
description: Reinstall nova-cloud-controller from the openstack-origin-git repositories. description: Reinstall nova-cloud-controller from the openstack-origin-git repositories.
openstack-upgrade:
description: Perform openstack upgrades. Config option action-managed-upgrade must be set to True.

1
actions/openstack-upgrade Symbolic link
View File

@ -0,0 +1 @@
openstack_upgrade.py

42
actions/openstack_upgrade.py Executable file
View File

@ -0,0 +1,42 @@
#!/usr/bin/python
import sys
sys.path.append('hooks/')
from charmhelpers.contrib.openstack.utils import (
do_action_openstack_upgrade,
)
from charmhelpers.core.hookenv import (
relation_ids,
)
from nova_cc_hooks import neutron_api_relation_joined
from nova_cc_utils import (
do_openstack_upgrade,
register_configs
)
from nova_cc_hooks import config_changed
CONFIGS = register_configs()
def openstack_upgrade():
"""Upgrade packages to config-set Openstack version.
If the charm was installed from source we cannot upgrade it.
For backwards compatibility a config flag must be set for this
code to run, otherwise a full service level upgrade will fire
on config-changed."""
if (do_action_openstack_upgrade('nova-common',
do_openstack_upgrade,
CONFIGS)):
[neutron_api_relation_joined(rid=rid, remote_restart=True)
for rid in relation_ids('neutron-api')]
config_changed()
if __name__ == '__main__':
openstack_upgrade()

View File

@ -395,3 +395,13 @@ options:
If memcached is being used to store the tokens, then it's recommended to If memcached is being used to store the tokens, then it's recommended to
change this configuration to False. change this configuration to False.
action-managed-upgrade:
type: boolean
default: False
description: |
If True enables openstack upgrades for this charm via juju actions.
You will still need to set openstack-origin to the new repository but
instead of an upgrade running automatically across all units, it will
wait for you to execute the openstack-upgrade action for this charm on
each unit. If False it will revert to existing behavior of upgrading
all units on config change.

View File

@ -25,6 +25,7 @@ import sys
import re import re
import six import six
import traceback
import yaml import yaml
from charmhelpers.contrib.network import ip from charmhelpers.contrib.network import ip
@ -34,6 +35,8 @@ from charmhelpers.core import (
) )
from charmhelpers.core.hookenv import ( from charmhelpers.core.hookenv import (
action_fail,
action_set,
config, config,
log as juju_log, log as juju_log,
charm_dir, charm_dir,
@ -114,6 +117,7 @@ SWIFT_CODENAMES = OrderedDict([
('2.2.1', 'kilo'), ('2.2.1', 'kilo'),
('2.2.2', 'kilo'), ('2.2.2', 'kilo'),
('2.3.0', 'liberty'), ('2.3.0', 'liberty'),
('2.4.0', 'liberty'),
]) ])
# >= Liberty version->codename mapping # >= Liberty version->codename mapping
@ -142,6 +146,9 @@ PACKAGE_CODENAMES = {
'glance-common': OrderedDict([ 'glance-common': OrderedDict([
('11.0.0', 'liberty'), ('11.0.0', 'liberty'),
]), ]),
'openstack-dashboard': OrderedDict([
('8.0.0', 'liberty'),
]),
} }
DEFAULT_LOOPBACK_SIZE = '5G' DEFAULT_LOOPBACK_SIZE = '5G'
@ -745,3 +752,47 @@ def git_yaml_value(projects_yaml, key):
return projects[key] return projects[key]
return None return None
def do_action_openstack_upgrade(package, upgrade_callback, configs):
"""Perform action-managed OpenStack upgrade.
Upgrades packages to the configured openstack-origin version and sets
the corresponding action status as a result.
If the charm was installed from source we cannot upgrade it.
For backwards compatibility a config flag (action-managed-upgrade) must
be set for this code to run, otherwise a full service level upgrade will
fire on config-changed.
@param package: package name for determining if upgrade available
@param upgrade_callback: function callback to charm's upgrade function
@param configs: templating object derived from OSConfigRenderer class
@return: True if upgrade successful; False if upgrade failed or skipped
"""
ret = False
if git_install_requested():
action_set({'outcome': 'installed from source, skipped upgrade.'})
else:
if openstack_upgrade_available(package):
if config('action-managed-upgrade'):
juju_log('Upgrading OpenStack release')
try:
upgrade_callback(configs=configs)
action_set({'outcome': 'success, upgrade completed.'})
ret = True
except:
action_set({'outcome': 'upgrade failed, see traceback.'})
action_set({'traceback': traceback.format_exc()})
action_fail('do_openstack_upgrade resulted in an '
'unexpected error')
else:
action_set({'outcome': 'action-managed-upgrade config is '
'False, skipped upgrade.'})
else:
action_set({'outcome': 'no upgrade available.'})
return ret

View File

@ -182,9 +182,9 @@ def config_changed():
if git_install_requested(): if git_install_requested():
if config_value_changed('openstack-origin-git'): if config_value_changed('openstack-origin-git'):
git_install(config('openstack-origin-git')) git_install(config('openstack-origin-git'))
else: elif not config('action-managed-upgrade'):
if openstack_upgrade_available('nova-common'): if openstack_upgrade_available('nova-common'):
CONFIGS = do_openstack_upgrade() CONFIGS = do_openstack_upgrade(CONFIGS)
[neutron_api_relation_joined(rid=rid, remote_restart=True) [neutron_api_relation_joined(rid=rid, remote_restart=True)
for rid in relation_ids('neutron-api')] for rid in relation_ids('neutron-api')]
save_script_rc() save_script_rc()

View File

@ -624,7 +624,7 @@ def _do_openstack_upgrade(new_src):
return configs return configs
def do_openstack_upgrade(): def do_openstack_upgrade(configs):
new_src = config('openstack-origin') new_src = config('openstack-origin')
if new_src[:6] != 'cloud:': if new_src[:6] != 'cloud:':
raise ValueError("Unable to perform upgrade to %s" % new_src) raise ValueError("Unable to perform upgrade to %s" % new_src)

View File

@ -647,7 +647,7 @@ class NovaCCUtilsTests(CharmTestCase):
'icehouse'] 'icehouse']
self.is_elected_leader.return_value = True self.is_elected_leader.return_value = True
self.relation_ids.return_value = [] self.relation_ids.return_value = []
utils.do_openstack_upgrade() utils.do_openstack_upgrade(self.register_configs())
expected = [call(['stamp', 'grizzly']), call(['upgrade', 'head']), expected = [call(['stamp', 'grizzly']), call(['upgrade', 'head']),
call(['stamp', 'havana']), call(['upgrade', 'head'])] call(['stamp', 'havana']), call(['upgrade', 'head'])]
self.assertEquals(self.neutron_db_manage.call_args_list, expected) self.assertEquals(self.neutron_db_manage.call_args_list, expected)
@ -655,7 +655,7 @@ class NovaCCUtilsTests(CharmTestCase):
self.apt_upgrade.assert_called_with(options=DPKG_OPTS, fatal=True, self.apt_upgrade.assert_called_with(options=DPKG_OPTS, fatal=True,
dist=True) dist=True)
self.apt_install.assert_called_with(determine_packages(), fatal=True) self.apt_install.assert_called_with(determine_packages(), fatal=True)
expected = [call(release='havana'), call(release='icehouse')] expected = [call(), call(release='havana'), call(release='icehouse')]
self.assertEquals(self.register_configs.call_args_list, expected) self.assertEquals(self.register_configs.call_args_list, expected)
self.assertEquals(self.ml2_migration.call_count, 1) self.assertEquals(self.ml2_migration.call_count, 1)
self.assertTrue(migrate_nova_database.call_count, 2) self.assertTrue(migrate_nova_database.call_count, 2)
@ -673,7 +673,7 @@ class NovaCCUtilsTests(CharmTestCase):
self.get_os_codename_install_source.return_value = 'icehouse' self.get_os_codename_install_source.return_value = 'icehouse'
self.is_elected_leader.return_value = True self.is_elected_leader.return_value = True
self.relation_ids.return_value = [] self.relation_ids.return_value = []
utils.do_openstack_upgrade() utils.do_openstack_upgrade(self.register_configs())
self.neutron_db_manage.assert_called_with(['upgrade', 'head']) self.neutron_db_manage.assert_called_with(['upgrade', 'head'])
self.apt_update.assert_called_with(fatal=True) self.apt_update.assert_called_with(fatal=True)
self.apt_upgrade.assert_called_with(options=DPKG_OPTS, fatal=True, self.apt_upgrade.assert_called_with(options=DPKG_OPTS, fatal=True,
@ -696,7 +696,7 @@ class NovaCCUtilsTests(CharmTestCase):
self.get_os_codename_install_source.return_value = 'juno' self.get_os_codename_install_source.return_value = 'juno'
self.is_elected_leader.return_value = True self.is_elected_leader.return_value = True
self.relation_ids.return_value = [] self.relation_ids.return_value = []
utils.do_openstack_upgrade() utils.do_openstack_upgrade(self.register_configs())
neutron_db_calls = [call(['stamp', 'icehouse']), neutron_db_calls = [call(['stamp', 'icehouse']),
call(['upgrade', 'head'])] call(['upgrade', 'head'])]
self.neutron_db_manage.assert_has_calls(neutron_db_calls, self.neutron_db_manage.assert_has_calls(neutron_db_calls,
@ -722,7 +722,7 @@ class NovaCCUtilsTests(CharmTestCase):
self.get_os_codename_install_source.return_value = 'kilo' self.get_os_codename_install_source.return_value = 'kilo'
self.is_elected_leader.return_value = True self.is_elected_leader.return_value = True
self.relation_ids.return_value = [] self.relation_ids.return_value = []
utils.do_openstack_upgrade() utils.do_openstack_upgrade(self.register_configs())
self.assertEquals(self.neutron_db_manage.call_count, 0) self.assertEquals(self.neutron_db_manage.call_count, 0)
self.apt_update.assert_called_with(fatal=True) self.apt_update.assert_called_with(fatal=True)
self.apt_upgrade.assert_called_with(options=DPKG_OPTS, fatal=True, self.apt_upgrade.assert_called_with(options=DPKG_OPTS, fatal=True,
@ -741,7 +741,7 @@ class NovaCCUtilsTests(CharmTestCase):
_file.read = MagicMock() _file.read = MagicMock()
_file.readline.return_value = ("deb url" _file.readline.return_value = ("deb url"
" precise-updates/grizzly main") " precise-updates/grizzly main")
utils.do_openstack_upgrade() utils.do_openstack_upgrade(self.register_configs())
expected = [call('cloud:precise-havana'), expected = [call('cloud:precise-havana'),
call('cloud:precise-icehouse')] call('cloud:precise-icehouse')]
self.assertEquals(_do_openstack_upgrade.call_args_list, expected) self.assertEquals(_do_openstack_upgrade.call_args_list, expected)
@ -754,7 +754,7 @@ class NovaCCUtilsTests(CharmTestCase):
with patch_open() as (_open, _file): with patch_open() as (_open, _file):
_file.read = MagicMock() _file.read = MagicMock()
_file.readline.return_value = "deb url precise-updates/havana main" _file.readline.return_value = "deb url precise-updates/havana main"
utils.do_openstack_upgrade() utils.do_openstack_upgrade(self.register_configs())
expected = [call('cloud:precise-icehouse')] expected = [call('cloud:precise-icehouse')]
self.assertEquals(_do_openstack_upgrade.call_args_list, expected) self.assertEquals(_do_openstack_upgrade.call_args_list, expected)