Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

IndentityServiceContext app data fixes #746

Merged
merged 2 commits into from Nov 3, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
74 changes: 43 additions & 31 deletions charmhelpers/contrib/openstack/context.py
Expand Up @@ -469,66 +469,78 @@ def __call__(self):
# forwards compat with application data
# bag driven approach to relation.
_adata = relation_get(rid=rid, app=remote_service_name(rid))
adata = {}
# if no app data bag presented - fallback
# to legacy unit based relation data
rdata = relation_get(rid=rid, unit=unit)
if _adata:
# New app data bag uses - instead of _
# in key names - remap for compat with
# existing relation data keys
for key, value in _adata.items():
if key == 'api-version':
rdata[key.replace('-', '_')] = value.strip('v')
adata[key.replace('-', '_')] = value.strip('v')
else:
rdata[key.replace('-', '_')] = value
adata[key.replace('-', '_')] = value
# Re-map some keys for backwards compatibility
for target, source in self._forward_compat_remaps.items():
rdata[target] = _adata.get(source)
else:
# No app data bag presented - fallback
# to legacy unit based relation data
rdata = relation_get(rid=rid, unit=unit)
serv_host = rdata.get('service_host')
adata[target] = _adata.get(source)
# Now preferentially get data from the app data bag, but if
# it's not available, get it from the legacy based relation
# data.

def _resolve(key):
return adata.get(key) or rdata.get(key)

serv_host = _resolve('service_host')
serv_host = format_ipv6_addr(serv_host) or serv_host
auth_host = rdata.get('auth_host')
auth_host = _resolve('auth_host')
auth_host = format_ipv6_addr(auth_host) or auth_host
int_host = rdata.get('internal_host')
int_host = _resolve('internal_host',)
int_host = format_ipv6_addr(int_host) or int_host
svc_protocol = rdata.get('service_protocol') or 'http'
auth_protocol = rdata.get('auth_protocol') or 'http'
int_protocol = rdata.get('internal_protocol') or 'http'
api_version = rdata.get('api_version') or '2.0'
ctxt.update({'service_port': rdata.get('service_port'),
svc_protocol = _resolve('service_protocol') or 'http'
auth_protocol = _resolve('auth_protocol') or 'http'
int_protocol = _resolve('internal_protocol') or 'http'
api_version = _resolve('api_version') or '2.0'
ctxt.update({'service_port': _resolve('service_port'),
'service_host': serv_host,
'auth_host': auth_host,
'auth_port': rdata.get('auth_port'),
'auth_port': _resolve('auth_port'),
'internal_host': int_host,
'internal_port': rdata.get('internal_port'),
'admin_tenant_name': rdata.get('service_tenant'),
'admin_user': rdata.get('service_username'),
'admin_password': rdata.get('service_password'),
'internal_port': _resolve('internal_port'),
'admin_tenant_name': _resolve('service_tenant'),
'admin_user': _resolve('service_username'),
'admin_password': _resolve('service_password'),
'service_protocol': svc_protocol,
'auth_protocol': auth_protocol,
'internal_protocol': int_protocol,
'api_version': api_version})

if rdata.get('service_type'):
ctxt['service_type'] = rdata.get('service_type')
service_type = _resolve('service_type')
if service_type:
ctxt['service_type'] = service_type

if float(api_version) > 2:
ctxt.update({
'admin_domain_name': rdata.get('service_domain'),
'service_project_id': rdata.get('service_tenant_id'),
'service_domain_id': rdata.get('service_domain_id')})
'admin_domain_name': _resolve('service_domain'),
'service_project_id': _resolve('service_tenant_id'),
'service_domain_id': _resolve('service_domain_id')})

# NOTE:
# keystone-k8s operator presents full URLS
# for all three endpoints - public and internal are
# externally addressable for machine based charm
if 'public_auth_url' in rdata:
public_auth_url = _resolve('public_auth_url')
# if 'public_auth_url' in rdata:
if public_auth_url:
ctxt.update({
'public_auth_url': rdata.get('public_auth_url'),
'public_auth_url': public_auth_url,
})
if 'internal_auth_url' in rdata:
internal_auth_url = _resolve('internal_auth_url')
# if 'internal_auth_url' in rdata:
if internal_auth_url:
ctxt.update({
'internal_auth_url': rdata.get('internal_auth_url'),
'internal_auth_url': internal_auth_url,
})

# we keep all veriables in ctxt for compatibility and
Expand All @@ -543,8 +555,8 @@ def __call__(self):
# NOTE(jamespage) this is required for >= icehouse
# so a missing value just indicates keystone needs
# upgrading
ctxt['admin_tenant_id'] = rdata.get('service_tenant_id')
ctxt['admin_domain_id'] = rdata.get('service_domain_id')
ctxt['admin_tenant_id'] = _resolve('service_tenant_id')
ctxt['admin_domain_id'] = _resolve('service_domain_id')
return ctxt

return {}
Expand Down
41 changes: 41 additions & 0 deletions tests/contrib/openstack/test_os_contexts.py
Expand Up @@ -1262,6 +1262,47 @@ def test_identity_service_app_context_with_data_http(self, *args):
result.pop('keystone_authtoken')
self.assertEquals(result, expected)

@patch.object(context, 'filter_installed_packages', return_value=[])
@patch.object(context, 'os_release', return_value='rocky')
def test_identity_service_app_context_with_app_data_nones(self, *args):
'''Test identity-service context for forwards compatibility'''
# This verifies that if there are None values in the app data that
# would override non-None values in the relation data, that the
# relation data keys are used.
app_data = IDENTITY_SERVICE_RELATION_APP_HTTP.copy()
app_data['service-user-name'] = None
app_data['service-host'] = None
relation = FakeRelation(app_data=app_data,
relation_data=IDENTITY_SERVICE_RELATION_HTTPS)
self.relation_get.side_effect = relation.get
identity_service = context.IdentityServiceContext()
result = identity_service()
expected = {
'admin_password': 'foo',
'admin_domain_name': 'admin_domain',
'admin_tenant_name': 'services',
'admin_tenant_id': 'svc-proj-id',
'admin_domain_id': 'svc-dom-id',
'service_project_id': 'svc-proj-id',
'service_domain_id': 'svc-dom-id',
'admin_user': 'adam', # comes from the relation data
'auth_host': 'keystoneadmin.local',
'auth_port': '5000',
'auth_protocol': 'http',
'service_host': 'keystonehost.local', # comes from relation data
'service_port': '5000',
'service_protocol': 'http',
'service_type': 'volume',
'internal_host': 'keystoneinternal.local',
'internal_port': '5000',
'internal_protocol': 'http',
'api_version': '3',
'public_auth_url': 'http://keystonepublic.local:80/keystone',
'internal_auth_url': 'http://keystoneinternal.local:80/keystone',
}
result.pop('keystone_authtoken')
self.assertEquals(result, expected)

@patch.object(context, 'filter_installed_packages', return_value=[])
@patch.object(context, 'os_release', return_value='rocky')
def test_identity_service_context_with_data_versioned(self, *args):
Expand Down