Add extra-repositories config option

Add an extra-repositories config option to nova-compute in order to
allow configuring additional apt repositories. This is useful when some
packages are not available in the distro or cloud archive.

Change-Id: Ie3b76ff3bc07b83e416c80fab1da2560d48df498
This commit is contained in:
Billy Olsen 2022-03-31 15:14:07 -07:00
parent 71567080b3
commit 330086cb71
3 changed files with 107 additions and 1 deletions

View File

@ -38,6 +38,18 @@ options:
NOTE: updating this setting to a source that is known to provide
a later version of OpenStack will trigger a software upgrade.
.
extra-repositories:
type: string
default:
description: |
Additional apt repositories to configure as installation sources for apt.
The acceptable format of this option are those values accepted by the
`add-apt-repository` command. Multiple repositories can be provided by
separating the entries with a comma. Examples include:
ppa:user/repository
deb http://myserver/path/to/repo stable main
ppa:userA/repository1, ppa:userB/repository2
action-managed-upgrade:
type: boolean
default: False

View File

@ -33,6 +33,7 @@ from charmhelpers.core.hookenv import (
local_unit,
log,
DEBUG,
INFO,
relation_ids,
remote_service_name,
related_units,
@ -56,6 +57,7 @@ from charmhelpers.core.host import (
mkdir,
)
from charmhelpers.fetch import (
add_source,
apt_install,
apt_purge,
apt_update,
@ -68,6 +70,7 @@ from charmhelpers.contrib.openstack.utils import (
CompareOpenStackReleases,
configure_installation_source,
is_unit_paused_set,
get_source_and_pgp_key,
openstack_upgrade_available,
os_release,
pausable_restart_on_change as restart_on_change,
@ -158,6 +161,7 @@ def install():
status_set('maintenance', 'Executing pre-install')
execd_preinstall()
configure_installation_source(config('openstack-origin'))
configure_extra_repositories(config('extra-repositories'))
status_set('maintenance', 'Installing apt packages')
apt_update()
@ -174,6 +178,36 @@ def install():
install_vaultlocker()
def configure_extra_repositories(extra_repositories):
"""Configures extra repositories to be added to the deployment.
Evaluates the config option 'extra-repositories' and configures the
additional installation sources as appropriate.
:param extra_repositories: extra repositories to install
:type extra_repositories: str
:raises: SourceConfigError if there is an error with the extra repositories
"""
if not extra_repositories:
log('No additional repositories to configure.', level=DEBUG)
return
for repo in extra_repositories.split(','):
if not repo:
continue
repo = repo.strip()
log('Configuring additional repository: "{}"'.format(repo),
level=DEBUG)
source, key = get_source_and_pgp_key(repo)
# Note: the add_source should fail and will result in the hook failing
# which is better to correct at this point if there is a
# configuration error rather than believing the repository to be
# configured.
add_source(source, key, fail_invalid=True)
@hooks.hook('config-changed')
@restart_on_change(restart_map())
@harden()
@ -190,6 +224,11 @@ def config_changed():
status_set('maintenance', 'configuring ipv6')
assert_charm_supports_ipv6()
if config('extra-repositories'):
log('Configuring extra repositories', level=INFO)
configure_extra_repositories(config('extra-repositories'))
apt_update()
if (migration_enabled() and
config('migration-auth-type') not in MIGRATION_AUTH_TYPES):
message = ("Invalid migration-auth-type")

View File

@ -49,6 +49,7 @@ TO_PATCH = [
'related_units',
'remote_service_name',
# charmhelpers.core.host
'add_source',
'apt_install',
'apt_purge',
'apt_update',
@ -118,15 +119,17 @@ class NovaComputeRelationsTests(CharmTestCase):
self.get_relation_ip.return_value = '10.0.0.50'
self.is_container.return_value = False
@patch.object(hooks, 'configure_extra_repositories')
@patch.object(hooks, 'kv')
@patch.object(hooks, 'os_release')
def test_install_hook(self, _os_release, _kv):
def test_install_hook(self, _os_release, _kv, _configure_extra_repos):
repo = 'cloud:precise-grizzly'
self.test_config.set('openstack-origin', repo)
self.determine_packages.return_value = ['foo', 'bar']
_os_release.return_value = 'rocky'
hooks.install()
self.configure_installation_source.assert_called_with(repo)
_configure_extra_repos.assert_called_with(None)
self.assertTrue(self.apt_update.called)
self.apt_install.assert_called_with(['foo', 'bar'], fatal=True)
self.assertTrue(self.execd_preinstall.called)
@ -137,6 +140,58 @@ class NovaComputeRelationsTests(CharmTestCase):
kv.set.assert_called_once_with(hooks.USE_FQDN_KEY, True)
kv.flush.assert_called_once_with()
def test_configure_extra_repositories(self):
"""Tests configuring of extra repositories"""
# Validate that invalid strings do not attempt to add sources
for repo in [None, '']:
hooks.configure_extra_repositories(repo)
self.add_source.assert_not_called()
# Validate that a single source is added
self.add_source.reset_mock()
hooks.configure_extra_repositories('ppa:user/repo')
self.add_source.assert_called_with('ppa:user/repo', None,
fail_invalid=True)
# Validate that multiple sources are added
self.add_source.reset_mock()
repositories = 'ppa:user1/repo2, ppa:user2/repo1'
hooks.configure_extra_repositories(repositories)
self.add_source.assert_has_calls([
call('ppa:user1/repo2', None, fail_invalid=True),
call('ppa:user2/repo1', None, fail_invalid=True),
])
# Validate that multiple source types and empty string
self.add_source.reset_mock()
repositories = (
'deb http://myserver/path/to/repo stable main|ABCDEFG,'
'ppa:team/foo,'
)
hooks.configure_extra_repositories(repositories)
self.add_source.assert_has_calls([
call('deb http://myserver/path/to/repo stable main', 'ABCDEFG',
fail_invalid=True),
call('ppa:team/foo', None, fail_invalid=True),
])
# Validate an error raises an error
self.add_source.reset_mock()
self.add_source.side_effect = Exception('Fail')
self.assertRaises(Exception, hooks.configure_extra_repositories,
'malformed')
@patch.object(hooks, 'configure_extra_repositories')
@patch.object(hooks, 'ceph_changed')
@patch.object(hooks, 'neutron_plugin_joined')
def test_config_changed_with_extra_repositories(
self, neutron_plugin_joined, ceph_changed,
configure_extra_repositories):
self.test_config.set('extra-repositories', 'ppa:someuser/repo')
hooks.config_changed()
configure_extra_repositories.assert_called_with('ppa:someuser/repo')
self.apt_update.assert_called()
@patch.object(hooks, 'ceph_changed')
@patch.object(hooks, 'neutron_plugin_joined')
def test_config_changed_with_upgrade(self, neutron_plugin_joined,