Merge "Add config for extra regions"
This commit is contained in:
commit
f433c3fb90
16
config.yaml
16
config.yaml
|
@ -512,3 +512,19 @@ options:
|
||||||
this option sets True as the default value, which is consistent with the
|
this option sets True as the default value, which is consistent with the
|
||||||
default value 'WSGISocketRotation On' in Apache. This option should be
|
default value 'WSGISocketRotation On' in Apache. This option should be
|
||||||
used with caution. Please read the Apache doc page for more information.
|
used with caution. Please read the Apache doc page for more information.
|
||||||
|
extra-regions:
|
||||||
|
type: string
|
||||||
|
default: "{}"
|
||||||
|
description: |
|
||||||
|
Define extra regions to register in the region selector.
|
||||||
|
Only use this if it's not possible to integrate the keystone unit with juju.
|
||||||
|
It must be a json dictionary where the keys are region names,
|
||||||
|
and the values are keystone endpoint urls.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
{
|
||||||
|
"cluster2": "https://cluster2.example.com/identity/v3",
|
||||||
|
"another cluster": "https://another.example.com/identity/v3"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
|
|
||||||
import functools
|
import functools
|
||||||
import json
|
import json
|
||||||
|
from typing import Set, Tuple
|
||||||
|
|
||||||
from charmhelpers.core.hookenv import (
|
from charmhelpers.core.hookenv import (
|
||||||
config,
|
config,
|
||||||
|
@ -55,6 +56,25 @@ SSL_CERT_FILE = '/etc/apache2/ssl/horizon/cert_dashboard'
|
||||||
SSL_KEY_FILE = '/etc/apache2/ssl/horizon/key_dashboard'
|
SSL_KEY_FILE = '/etc/apache2/ssl/horizon/key_dashboard'
|
||||||
|
|
||||||
|
|
||||||
|
def get_extra_regions() -> Set[Tuple[str, str]]:
|
||||||
|
"""
|
||||||
|
Get extra regions from config, as a set of (name, url) tuples
|
||||||
|
|
||||||
|
Raises ValueError if parsing fails.
|
||||||
|
"""
|
||||||
|
extra_regions = set()
|
||||||
|
try:
|
||||||
|
extra_regions_config = json.loads(config("extra-regions"))
|
||||||
|
for title, endpoint in extra_regions_config.items():
|
||||||
|
if isinstance(title, str) and isinstance(endpoint, str):
|
||||||
|
extra_regions.add((endpoint, title))
|
||||||
|
else:
|
||||||
|
raise ValueError("keys and values must be strings")
|
||||||
|
except Exception as e:
|
||||||
|
raise ValueError(f"failed parsing extra-regions config: {e!r}")
|
||||||
|
return extra_regions
|
||||||
|
|
||||||
|
|
||||||
class HorizonHAProxyContext(OSContextGenerator):
|
class HorizonHAProxyContext(OSContextGenerator):
|
||||||
def __call__(self):
|
def __call__(self):
|
||||||
'''
|
'''
|
||||||
|
@ -203,6 +223,14 @@ class IdentityServiceContext(OSContextGenerator):
|
||||||
if len(ctxt) == 0:
|
if len(ctxt) == 0:
|
||||||
ctxt = local_ctxt
|
ctxt = local_ctxt
|
||||||
|
|
||||||
|
try:
|
||||||
|
regions.update(get_extra_regions())
|
||||||
|
except ValueError as e:
|
||||||
|
log(
|
||||||
|
f"Ignoring 'extra-regions' config, it is invalid. Err: {e}",
|
||||||
|
WARNING
|
||||||
|
)
|
||||||
|
|
||||||
if len(regions) > 1:
|
if len(regions) > 1:
|
||||||
avail_regions = map(lambda r: {'endpoint': r[0], 'title': r[1]},
|
avail_regions = map(lambda r: {'endpoint': r[0], 'title': r[1]},
|
||||||
regions)
|
regions)
|
||||||
|
|
|
@ -114,6 +114,8 @@ from hooks.horizon_utils import (
|
||||||
update_plugin_packages_in_kv,
|
update_plugin_packages_in_kv,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
from hooks.horizon_contexts import get_extra_regions
|
||||||
|
|
||||||
|
|
||||||
hooks = Hooks()
|
hooks = Hooks()
|
||||||
# Note that CONFIGS is now set up via resolve_CONFIGS so that it is not a
|
# Note that CONFIGS is now set up via resolve_CONFIGS so that it is not a
|
||||||
|
@ -227,6 +229,12 @@ def config_changed():
|
||||||
application_dashboard_relation_changed()
|
application_dashboard_relation_changed()
|
||||||
dashboard_relation_changed()
|
dashboard_relation_changed()
|
||||||
|
|
||||||
|
# Provide a message to the user if extra regions config is invalid
|
||||||
|
try:
|
||||||
|
get_extra_regions()
|
||||||
|
except ValueError:
|
||||||
|
status_set("blocked", "Invalid 'extra-regions' config value")
|
||||||
|
|
||||||
|
|
||||||
@hooks.hook('identity-service-relation-joined')
|
@hooks.hook('identity-service-relation-joined')
|
||||||
def keystone_joined(rel_id=None):
|
def keystone_joined(rel_id=None):
|
||||||
|
|
|
@ -1071,6 +1071,68 @@ class TestHorizonContexts(CharmTestCase):
|
||||||
{'endpoint': 'http://foo:5000/v2.0',
|
{'endpoint': 'http://foo:5000/v2.0',
|
||||||
'title': 'regionTwo'}]})
|
'title': 'regionTwo'}]})
|
||||||
|
|
||||||
|
@patch("hooks.horizon_contexts.format_ipv6_addr")
|
||||||
|
def test_IdentityServiceContext_multi_region_with_extra(
|
||||||
|
self, mock_format_ipv6_addr
|
||||||
|
):
|
||||||
|
mock_format_ipv6_addr.side_effect = lambda x: x
|
||||||
|
self.relation_ids.return_value = ['foo']
|
||||||
|
self.related_units.return_value = ['bar', 'baz']
|
||||||
|
self.relation_get.side_effect = self.test_relation.get
|
||||||
|
self.test_relation.set({'service_host': 'foo', 'service_port': 5000,
|
||||||
|
'internal_host': 'bar', 'internal_port': 5001,
|
||||||
|
'region': 'regionOne regionTwo'})
|
||||||
|
self.test_config.set(
|
||||||
|
'extra-regions', '{"regionThree": "http://example.com/v3"}'
|
||||||
|
)
|
||||||
|
self.maxDiff = None
|
||||||
|
self.context_complete.return_value = True
|
||||||
|
self.assertEqual(
|
||||||
|
with_regions_sorted(horizon_contexts.IdentityServiceContext()),
|
||||||
|
{'service_host': 'foo', 'service_port': 5000,
|
||||||
|
'service_protocol': 'http', 'api_version': '2',
|
||||||
|
'internal_host': 'bar', 'internal_port': 5001,
|
||||||
|
'internal_protocol': 'http',
|
||||||
|
'ks_host': 'foo', 'ks_port': 5000,
|
||||||
|
'ks_protocol': 'http',
|
||||||
|
'ks_endpoint_path': 'v2.0',
|
||||||
|
'default_role': 'member',
|
||||||
|
'regions': [{'endpoint': 'http://foo:5000/v2.0',
|
||||||
|
'title': 'regionOne'},
|
||||||
|
{'endpoint': 'http://example.com/v3',
|
||||||
|
'title': 'regionThree'},
|
||||||
|
{'endpoint': 'http://foo:5000/v2.0',
|
||||||
|
'title': 'regionTwo'}]})
|
||||||
|
|
||||||
|
@patch("hooks.horizon_contexts.format_ipv6_addr")
|
||||||
|
def test_IdentityServiceContext_multi_region_with_invalid_extra_regions(
|
||||||
|
self, mock_format_ipv6_addr
|
||||||
|
):
|
||||||
|
mock_format_ipv6_addr.side_effect = lambda x: x
|
||||||
|
self.relation_ids.return_value = ['foo']
|
||||||
|
self.related_units.return_value = ['bar', 'baz']
|
||||||
|
self.relation_get.side_effect = self.test_relation.get
|
||||||
|
self.test_relation.set({'service_host': 'foo', 'service_port': 5000,
|
||||||
|
'internal_host': 'bar', 'internal_port': 5001,
|
||||||
|
'region': 'regionOne regionTwo'})
|
||||||
|
self.test_config.set('extra-regions', '{{{{')
|
||||||
|
self.maxDiff = None
|
||||||
|
self.context_complete.return_value = True
|
||||||
|
self.assertEqual(
|
||||||
|
with_regions_sorted(horizon_contexts.IdentityServiceContext()),
|
||||||
|
{'service_host': 'foo', 'service_port': 5000,
|
||||||
|
'service_protocol': 'http', 'api_version': '2',
|
||||||
|
'internal_host': 'bar', 'internal_port': 5001,
|
||||||
|
'internal_protocol': 'http',
|
||||||
|
'ks_host': 'foo', 'ks_port': 5000,
|
||||||
|
'ks_protocol': 'http',
|
||||||
|
'ks_endpoint_path': 'v2.0',
|
||||||
|
'default_role': 'member',
|
||||||
|
'regions': [{'endpoint': 'http://foo:5000/v2.0',
|
||||||
|
'title': 'regionOne'},
|
||||||
|
{'endpoint': 'http://foo:5000/v2.0',
|
||||||
|
'title': 'regionTwo'}]})
|
||||||
|
|
||||||
@patch("hooks.horizon_contexts.format_ipv6_addr")
|
@patch("hooks.horizon_contexts.format_ipv6_addr")
|
||||||
def test_IdentityServiceContext_multi_region_v3(self,
|
def test_IdentityServiceContext_multi_region_v3(self,
|
||||||
mock_format_ipv6_addr):
|
mock_format_ipv6_addr):
|
||||||
|
|
|
@ -266,6 +266,7 @@ class TestHorizonHooks(CharmTestCase):
|
||||||
'action-managed-upgrade': False,
|
'action-managed-upgrade': False,
|
||||||
'webroot': '/horizon',
|
'webroot': '/horizon',
|
||||||
'site-name': 'local',
|
'site-name': 'local',
|
||||||
|
'extra-regions': '{}',
|
||||||
}[key]
|
}[key]
|
||||||
self.config.side_effect = config_side_effect
|
self.config.side_effect = config_side_effect
|
||||||
_is_leader.return_value = True
|
_is_leader.return_value = True
|
||||||
|
@ -283,6 +284,88 @@ class TestHorizonHooks(CharmTestCase):
|
||||||
self.open_port.assert_has_calls([call(80), call(443)])
|
self.open_port.assert_has_calls([call(80), call(443)])
|
||||||
self.assertTrue(_custom_theme.called)
|
self.assertTrue(_custom_theme.called)
|
||||||
|
|
||||||
|
@patch('hooks.horizon_contexts.config')
|
||||||
|
@patch('hooks.horizon_hooks.check_custom_theme')
|
||||||
|
@patch('hooks.horizon_hooks.keystone_joined')
|
||||||
|
@patch('hooks.horizon_hooks.is_leader')
|
||||||
|
@patch('os.environ.get')
|
||||||
|
def test_config_changed_invalid_extra_regions(
|
||||||
|
self, _environ_get, _is_leader, _joined, _custom_theme, _config
|
||||||
|
):
|
||||||
|
self.relation_ids.side_effect = lambda _: []
|
||||||
|
self.config.side_effect = _config.side_effect = lambda key: {
|
||||||
|
'ssl_key': 'somekey',
|
||||||
|
'enforce-ssl': True,
|
||||||
|
'dns-ha': True,
|
||||||
|
'os-public-hostname': 'dashboard.intranet.test',
|
||||||
|
'prefer-ipv6': False,
|
||||||
|
'action-managed-upgrade': False,
|
||||||
|
'webroot': '/horizon',
|
||||||
|
'site-name': 'local',
|
||||||
|
'extra-regions': '{',
|
||||||
|
}[key]
|
||||||
|
_is_leader.return_value = True
|
||||||
|
_environ_get.return_value = ''
|
||||||
|
self.openstack_upgrade_available.return_value = False
|
||||||
|
self._call_hook('config-changed')
|
||||||
|
self.status_set.assert_has_calls([
|
||||||
|
call("blocked", "Invalid 'extra-regions' config value")
|
||||||
|
])
|
||||||
|
|
||||||
|
@patch('hooks.horizon_contexts.config')
|
||||||
|
@patch('hooks.horizon_hooks.check_custom_theme')
|
||||||
|
@patch('hooks.horizon_hooks.keystone_joined')
|
||||||
|
@patch('hooks.horizon_hooks.is_leader')
|
||||||
|
@patch('os.environ.get')
|
||||||
|
def test_config_changed_invalid_extra_regions2(
|
||||||
|
self, _environ_get, _is_leader, _joined, _custom_theme, _config
|
||||||
|
):
|
||||||
|
self.relation_ids.side_effect = lambda _: []
|
||||||
|
self.config.side_effect = _config.side_effect = lambda key: {
|
||||||
|
'ssl_key': 'somekey',
|
||||||
|
'enforce-ssl': True,
|
||||||
|
'dns-ha': True,
|
||||||
|
'os-public-hostname': 'dashboard.intranet.test',
|
||||||
|
'prefer-ipv6': False,
|
||||||
|
'action-managed-upgrade': False,
|
||||||
|
'webroot': '/horizon',
|
||||||
|
'site-name': 'local',
|
||||||
|
'extra-regions': '{"test": 2}',
|
||||||
|
}[key]
|
||||||
|
_is_leader.return_value = True
|
||||||
|
_environ_get.return_value = ''
|
||||||
|
self.openstack_upgrade_available.return_value = False
|
||||||
|
self._call_hook('config-changed')
|
||||||
|
self.status_set.assert_has_calls([
|
||||||
|
call("blocked", "Invalid 'extra-regions' config value")
|
||||||
|
])
|
||||||
|
|
||||||
|
@patch('hooks.horizon_contexts.config')
|
||||||
|
@patch('hooks.horizon_hooks.check_custom_theme')
|
||||||
|
@patch('hooks.horizon_hooks.keystone_joined')
|
||||||
|
@patch('hooks.horizon_hooks.is_leader')
|
||||||
|
@patch('os.environ.get')
|
||||||
|
def test_config_changed_valid_extra_regions(
|
||||||
|
self, _environ_get, _is_leader, _joined, _custom_theme, _config
|
||||||
|
):
|
||||||
|
self.relation_ids.side_effect = lambda _: []
|
||||||
|
self.config.side_effect = _config.side_effect = lambda key: {
|
||||||
|
'ssl_key': 'somekey',
|
||||||
|
'enforce-ssl': True,
|
||||||
|
'dns-ha': True,
|
||||||
|
'os-public-hostname': 'dashboard.intranet.test',
|
||||||
|
'prefer-ipv6': False,
|
||||||
|
'action-managed-upgrade': False,
|
||||||
|
'webroot': '/horizon',
|
||||||
|
'site-name': 'local',
|
||||||
|
'extra-regions': '{"test": "http://example.com/v3"}',
|
||||||
|
}[key]
|
||||||
|
_is_leader.return_value = True
|
||||||
|
_environ_get.return_value = ''
|
||||||
|
self.openstack_upgrade_available.return_value = False
|
||||||
|
self._call_hook('config-changed')
|
||||||
|
self.status_set.assert_not_called()
|
||||||
|
|
||||||
@patch('hooks.horizon_hooks.check_custom_theme')
|
@patch('hooks.horizon_hooks.check_custom_theme')
|
||||||
@patch('hooks.horizon_hooks.is_leader')
|
@patch('hooks.horizon_hooks.is_leader')
|
||||||
def test_config_changed_do_upgrade(self, _is_leader, _custom_theme):
|
def test_config_changed_do_upgrade(self, _is_leader, _custom_theme):
|
||||||
|
|
Loading…
Reference in New Issue