Merge "Add config use-internal-endpoints option."

This commit is contained in:
Zuul 2021-04-06 15:45:42 +00:00 committed by Gerrit Code Review
commit 71916888e5
9 changed files with 156 additions and 32 deletions

View File

@ -415,3 +415,10 @@ options:
description: |
If True, displays an Admin Password field on the Change Password form
to verify that it is indeed the admin logged-in who wants to change the password.
use-internal-endpoints:
type: boolean
default: False
description: |
Openstack mostly defaults to using public endpoints for internal
communication between services. If set to True this option will
configure services to use internal endpoints where possible.

View File

@ -23,8 +23,8 @@ from charmhelpers.core.hookenv import (
relation_get,
local_unit,
log,
WARNING,
ERROR,
WARNING,
)
from charmhelpers.core.strutils import bool_from_string
from charmhelpers.contrib.openstack import context
@ -90,8 +90,6 @@ class HorizonHAProxyContext(OSContextGenerator):
return ctxt
# NOTE: this is a stripped-down version of
# contrib.openstack.IdentityServiceContext
class IdentityServiceContext(OSContextGenerator):
interfaces = ['identity-service']
@ -126,6 +124,9 @@ class IdentityServiceContext(OSContextGenerator):
default_role = role
serv_host = rdata.get('service_host')
serv_host = format_ipv6_addr(serv_host) or serv_host
internal_host = rdata.get('internal_host')
internal_host = (format_ipv6_addr(internal_host)
or internal_host)
region = rdata.get('region')
local_ctxt = {
@ -136,6 +137,7 @@ class IdentityServiceContext(OSContextGenerator):
'api_version': rdata.get('api_version', '2'),
'default_role': default_role
}
# If using keystone v3 the context is incomplete without the
# admin domain id
if local_ctxt['api_version'] == '3':
@ -145,11 +147,41 @@ class IdentityServiceContext(OSContextGenerator):
if not context_complete(local_ctxt):
continue
# internal_* keys will be treated as optional, since the user
# could be upgrading the openstack-dashboard charm before
# keystone, so we add them to `local_ctxt` after calling
# `context_complete()`.
local_ctxt.update({
'internal_port': rdata.get('internal_port'),
'internal_host': internal_host,
'internal_protocol':
rdata.get('internal_protocol') or 'http',
})
# if the use configured the charm to use internal endpoints,
# but the keystone charm didn't provide the internal_host key
# in the relation we fallback to use the service_host.
if config("use-internal-endpoints") and internal_host:
log("Using internal endpoints to configure horizon")
local_ctxt["ks_protocol"] = local_ctxt["internal_protocol"]
local_ctxt["ks_host"] = local_ctxt["internal_host"]
local_ctxt["ks_port"] = local_ctxt["internal_port"]
else:
log("Using service host to configure horizon")
local_ctxt["ks_protocol"] = local_ctxt["service_protocol"]
local_ctxt["ks_host"] = local_ctxt["service_host"]
local_ctxt["ks_port"] = local_ctxt["service_port"]
# Update the service endpoint and title for each available
# region in order to support multi-region deployments
if region is not None:
endpoint = ("%(service_protocol)s://%(service_host)s"
":%(service_port)s/v2.0") % local_ctxt
if config("use-internal-endpoints") and internal_host:
endpoint = ("%(internal_protocol)s://%(internal_host)s"
":%(internal_port)s/v2.0") % local_ctxt
else:
endpoint = ("%(service_protocol)s://%(service_host)s"
":%(service_port)s/v2.0") % local_ctxt
for reg in region.split():
regions.add((endpoint, reg))

View File

@ -139,8 +139,8 @@ AVAILABLE_REGIONS = [
]
{% endif -%}
OPENSTACK_HOST = "{{ service_host }}"
OPENSTACK_KEYSTONE_URL = "{{ service_protocol }}://%s:{{ service_port }}/v2.0" % OPENSTACK_HOST
OPENSTACK_HOST = "{{ ks_host }}"
OPENSTACK_KEYSTONE_URL = "{{ ks_protocol }}://%s:{{ ks_port }}/v2.0" % OPENSTACK_HOST
OPENSTACK_KEYSTONE_DEFAULT_ROLE = "{{ default_role }}"
# Disable SSL certificate checks (useful for self-signed certificates):

View File

@ -161,8 +161,8 @@ AVAILABLE_REGIONS = [
]
{% endif -%}
OPENSTACK_HOST = "{{ service_host }}"
OPENSTACK_KEYSTONE_URL = "{{ service_protocol }}://%s:{{ service_port }}/v2.0" % OPENSTACK_HOST
OPENSTACK_HOST = "{{ ks_host }}"
OPENSTACK_KEYSTONE_URL = "{{ ks_protocol }}://%s:{{ ks_port }}/v2.0" % OPENSTACK_HOST
OPENSTACK_KEYSTONE_DEFAULT_ROLE = "{{ default_role }}"
# Enables keystone web single-sign-on if set to True.
#WEBSSO_ENABLED = False

View File

@ -202,15 +202,15 @@ AVAILABLE_REGIONS = [
]
{% endif -%}
OPENSTACK_HOST = "{{ service_host }}"
OPENSTACK_HOST = "{{ ks_host }}"
OPENSTACK_KEYSTONE_DEFAULT_ROLE = "{{ default_role }}"
{% if api_version == "3" -%}
OPENSTACK_KEYSTONE_URL = "{{ service_protocol }}://%s:{{ service_port }}/v3" % OPENSTACK_HOST
OPENSTACK_KEYSTONE_URL = "{{ ks_protocol }}://%s:{{ ks_port }}/v3" % OPENSTACK_HOST
OPENSTACK_API_VERSIONS = { "identity": 3, }
OPENSTACK_KEYSTONE_MULTIDOMAIN_SUPPORT = {{ multi_domain }}
OPENSTACK_KEYSTONE_DEFAULT_DOMAIN = "{{ default_domain or admin_domain_id }}"
{% else -%}
OPENSTACK_KEYSTONE_URL = "{{ service_protocol }}://%s:{{ service_port }}/v2.0" % OPENSTACK_HOST
OPENSTACK_KEYSTONE_URL = "{{ ks_protocol }}://%s:{{ ks_port }}/v2.0" % OPENSTACK_HOST
{% endif -%}

View File

@ -202,15 +202,15 @@ AVAILABLE_REGIONS = [
]
{% endif -%}
OPENSTACK_HOST = "{{ service_host }}"
OPENSTACK_HOST = "{{ ks_host }}"
OPENSTACK_KEYSTONE_DEFAULT_ROLE = "{{ default_role }}"
{% if api_version == "3" -%}
OPENSTACK_KEYSTONE_URL = "{{ service_protocol }}://%s:{{ service_port }}/v3" % OPENSTACK_HOST
OPENSTACK_KEYSTONE_URL = "{{ ks_protocol }}://%s:{{ ks_port }}/v3" % OPENSTACK_HOST
OPENSTACK_API_VERSIONS = { "identity": 3, }
OPENSTACK_KEYSTONE_MULTIDOMAIN_SUPPORT = {{ multi_domain }}
OPENSTACK_KEYSTONE_DEFAULT_DOMAIN = "{{ default_domain or admin_domain_id }}"
{% else -%}
OPENSTACK_KEYSTONE_URL = "{{ service_protocol }}://%s:{{ service_port }}/v2.0" % OPENSTACK_HOST
OPENSTACK_KEYSTONE_URL = "{{ ks_protocol }}://%s:{{ ks_port }}/v2.0" % OPENSTACK_HOST
{% endif -%}

View File

@ -203,15 +203,15 @@ AVAILABLE_REGIONS = [
]
{% endif -%}
OPENSTACK_HOST = "{{ service_host }}"
OPENSTACK_HOST = "{{ ks_host }}"
OPENSTACK_KEYSTONE_DEFAULT_ROLE = "{{ default_role }}"
{% if api_version == "3" -%}
OPENSTACK_KEYSTONE_URL = "{{ service_protocol }}://%s:{{ service_port }}/v3" % OPENSTACK_HOST
OPENSTACK_KEYSTONE_URL = "{{ ks_protocol }}://%s:{{ ks_port }}/v3" % OPENSTACK_HOST
OPENSTACK_API_VERSIONS = { "identity": 3, }
OPENSTACK_KEYSTONE_MULTIDOMAIN_SUPPORT = {{ multi_domain }}
OPENSTACK_KEYSTONE_DEFAULT_DOMAIN = "{{ default_domain or admin_domain_id }}"
{% else -%}
OPENSTACK_KEYSTONE_URL = "{{ service_protocol }}://%s:{{ service_port }}/v2.0" % OPENSTACK_HOST
OPENSTACK_KEYSTONE_URL = "{{ ks_protocol }}://%s:{{ ks_port }}/v2.0" % OPENSTACK_HOST
{% endif -%}

View File

@ -203,15 +203,15 @@ AVAILABLE_REGIONS = [
]
{% endif -%}
OPENSTACK_HOST = "{{ service_host }}"
OPENSTACK_HOST = "{{ ks_host }}"
OPENSTACK_KEYSTONE_DEFAULT_ROLE = "{{ default_role }}"
{% if api_version == "3" -%}
OPENSTACK_KEYSTONE_URL = "{{ service_protocol }}://%s:{{ service_port }}/v3" % OPENSTACK_HOST
OPENSTACK_KEYSTONE_URL = "{{ ks_protocol }}://%s:{{ ks_port }}/v3" % OPENSTACK_HOST
OPENSTACK_API_VERSIONS = { "identity": 3, }
OPENSTACK_KEYSTONE_MULTIDOMAIN_SUPPORT = {{ multi_domain }}
OPENSTACK_KEYSTONE_DEFAULT_DOMAIN = "{{ default_domain or admin_domain_id }}"
{% else -%}
OPENSTACK_KEYSTONE_URL = "{{ service_protocol }}://%s:{{ service_port }}/v2.0" % OPENSTACK_HOST
OPENSTACK_KEYSTONE_URL = "{{ ks_protocol }}://%s:{{ ks_port }}/v2.0" % OPENSTACK_HOST
{% endif -%}

View File

@ -684,43 +684,59 @@ class TestHorizonContexts(CharmTestCase):
@patch("hooks.horizon_contexts.format_ipv6_addr")
def test_IdentityServiceContext_data(self, mock_format_ipv6_addr):
mock_format_ipv6_addr.return_value = "foo"
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})
self.test_relation.set({'service_host': 'foo', 'service_port': 5000,
'internal_host': 'bar', 'internal_port': 5001})
self.test_config.set('use-internal-endpoints', False)
self.context_complete.return_value = True
self.assertEqual(horizon_contexts.IdentityServiceContext()(),
{'service_host': 'foo', 'service_port': 5000,
'internal_host': 'bar', 'internal_port': 5001,
'internal_protocol': 'http',
'ks_host': 'foo', 'ks_port': 5000,
'ks_protocol': 'http',
'default_role': 'member',
'api_version': '2', 'service_protocol': 'http'})
@patch("hooks.horizon_contexts.format_ipv6_addr")
def test_IdentityServiceContext_single_region(self, mock_format_ipv6_addr):
mock_format_ipv6_addr.return_value = "foo"
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'})
self.context_complete.return_value = True
self.assertEqual(horizon_contexts.IdentityServiceContext()(),
{'service_host': 'foo', 'service_port': 5000,
'internal_host': 'bar', 'internal_port': 5001,
'internal_protocol': 'http',
'ks_host': 'foo', 'ks_port': 5000,
'ks_protocol': 'http',
'default_role': 'member',
'api_version': '2', 'service_protocol': 'http'})
@patch("hooks.horizon_contexts.format_ipv6_addr")
def test_IdentityServiceContext_multi_region(self, mock_format_ipv6_addr):
mock_format_ipv6_addr.return_value = "foo"
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.context_complete.return_value = True
self.assertEqual(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',
'default_role': 'member',
'regions': [{'endpoint': 'http://foo:5000/v2.0',
'title': 'regionOne'},
@ -729,13 +745,15 @@ class TestHorizonContexts(CharmTestCase):
@patch("hooks.horizon_contexts.format_ipv6_addr")
def test_IdentityServiceContext_api3(self, mock_format_ipv6_addr):
mock_format_ipv6_addr.return_value = "foo"
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',
'api_version': '3',
'admin_domain_id': 'admindomainid'})
@ -743,6 +761,12 @@ class TestHorizonContexts(CharmTestCase):
self.assertEqual(horizon_contexts.IdentityServiceContext()(), {
'service_host': 'foo',
'service_port': 5000,
'internal_host': 'bar',
'internal_port': 5001,
'internal_protocol': 'http',
'ks_host': 'foo',
'ks_port': 5000,
'ks_protocol': 'http',
'api_version': '3',
'default_role': 'member',
'admin_domain_id': 'admindomainid',
@ -781,13 +805,16 @@ class TestHorizonContexts(CharmTestCase):
@patch("hooks.horizon_contexts.format_ipv6_addr")
def test_IdentityServiceContext_default_role(self, mock_format_ipv6_addr):
self.test_config.set('default-role', 'member')
mock_format_ipv6_addr.return_value = "foo"
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,
'internal_protocol': 'http',
'region': 'regionOne',
'api_version': '3',
'created_roles': 'Member',
@ -796,6 +823,12 @@ class TestHorizonContexts(CharmTestCase):
self.assertEqual(horizon_contexts.IdentityServiceContext()(), {
'service_host': 'foo',
'service_port': 5000,
'internal_host': 'bar',
'internal_port': 5001,
'internal_protocol': 'http',
'ks_host': 'foo',
'ks_port': 5000,
'ks_protocol': 'http',
'api_version': '3',
'default_role': 'Member',
'admin_domain_id': 'admindomainid',
@ -805,25 +838,77 @@ class TestHorizonContexts(CharmTestCase):
def test_IdentityServiceContext_default_role_fallback(self,
mock_ipv6_addr):
self.test_config.set('default-role', 'member')
mock_ipv6_addr.return_value = "foo"
mock_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,
'service_host': 'foo', 'service_port': 5000,
'internal_host': 'bar', 'internal_port': 5001,
'region': 'regionOne',
'api_version': '3',
'admin_domain_id': 'admindomainid'})
self.context_complete.return_value = True
self.assertEqual(horizon_contexts.IdentityServiceContext()(), {
'service_host': 'foo',
'service_port': 5000,
'service_host': 'foo', 'service_port': 5000,
'internal_host': 'bar', 'internal_port': 5001,
'internal_protocol': 'http',
'ks_host': 'foo', 'ks_port': 5000,
'ks_protocol': 'http',
'api_version': '3',
'default_role': 'member',
'admin_domain_id': 'admindomainid',
'service_protocol': 'http'})
@patch("hooks.horizon_contexts.format_ipv6_addr")
def test_IdentityServiceContext_use_internal_endpoints(self,
mock_format_ipv6):
mock_format_ipv6.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'})
self.test_config.set('use-internal-endpoints', True)
self.context_complete.return_value = True
self.maxDiff = None
self.assertEqual(horizon_contexts.IdentityServiceContext()(),
{'service_host': 'foo', 'service_port': 5000,
'service_protocol': 'http',
'internal_host': 'bar', 'internal_port': 5001,
'internal_protocol': 'http',
'ks_host': 'bar', 'ks_port': 5001,
'ks_protocol': 'http',
'api_version': '2',
'default_role': 'member'})
@patch("hooks.horizon_contexts.format_ipv6_addr")
def test_IdentityServiceContext_use_internal_endpoints_no_internal_host(
self, mock_format_ipv6):
mock_format_ipv6.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,
'region': 'regionOne regionTwo'})
self.test_config.set('use-internal-endpoints', True)
self.context_complete.return_value = True
self.maxDiff = None
self.assertEqual(horizon_contexts.IdentityServiceContext()(),
{'service_host': 'foo', 'service_port': 5000,
'service_protocol': 'http',
'internal_host': None, 'internal_port': None,
'internal_protocol': 'http',
'ks_host': 'foo', 'ks_port': 5000,
'ks_protocol': 'http',
'api_version': '2',
'default_role': 'member',
'regions': [{'endpoint': 'http://foo:5000/v2.0',
'title': 'regionOne'},
{'endpoint': 'http://foo:5000/v2.0',
'title': 'regionTwo'}]})
def test_HorizonHAProxyContext_no_cluster(self):
self.relation_ids.return_value = []
self.local_unit.return_value = 'openstack-dashboard/0'