Merge "add support for Federated IDentity (FID) and WebSSO"
This commit is contained in:
commit
2d25e81bbd
|
@ -0,0 +1 @@
|
|||
keystone_hooks.py
|
|
@ -0,0 +1 @@
|
|||
keystone_hooks.py
|
|
@ -0,0 +1 @@
|
|||
keystone_hooks.py
|
|
@ -0,0 +1 @@
|
|||
keystone_hooks.py
|
|
@ -14,6 +14,7 @@
|
|||
|
||||
import hashlib
|
||||
import os
|
||||
import json
|
||||
|
||||
from base64 import b64decode
|
||||
|
||||
|
@ -39,6 +40,9 @@ from charmhelpers.core.hookenv import (
|
|||
leader_get,
|
||||
DEBUG,
|
||||
INFO,
|
||||
related_units,
|
||||
relation_ids,
|
||||
relation_get,
|
||||
)
|
||||
|
||||
from charmhelpers.core.strutils import (
|
||||
|
@ -405,3 +409,46 @@ class TokenFlushContext(context.OSContextGenerator):
|
|||
'token_flush': is_elected_leader(DC_RESOURCE_NAME)
|
||||
}
|
||||
return ctxt
|
||||
|
||||
|
||||
class KeystoneFIDServiceProviderContext(context.OSContextGenerator):
|
||||
interfaces = ['keystone-fid-service-provider']
|
||||
|
||||
def __call__(self):
|
||||
fid_sp_keys = ['protocol-name', 'remote-id-attribute']
|
||||
fid_sps = []
|
||||
for rid in relation_ids("keystone-fid-service-provider"):
|
||||
for unit in related_units(rid):
|
||||
rdata = relation_get(unit=unit, rid=rid)
|
||||
if set(rdata).issuperset(set(fid_sp_keys)):
|
||||
fid_sps.append({
|
||||
k: json.loads(v) for k, v in rdata.items()
|
||||
if k in fid_sp_keys
|
||||
})
|
||||
# populate the context with data from one or more
|
||||
# service providers
|
||||
ctxt = ({'fid_sps': fid_sps}
|
||||
if fid_sps else {})
|
||||
return ctxt
|
||||
|
||||
|
||||
class WebSSOTrustedDashboardContext(context.OSContextGenerator):
|
||||
interfaces = ['websso-trusted-dashboard']
|
||||
|
||||
def __call__(self):
|
||||
trusted_dashboard_keys = ['scheme', 'hostname', 'path']
|
||||
trusted_dashboards = set()
|
||||
for rid in relation_ids("websso-trusted-dashboard"):
|
||||
for unit in related_units(rid):
|
||||
rdata = relation_get(unit=unit, rid=rid)
|
||||
if set(rdata).issuperset(set(trusted_dashboard_keys)):
|
||||
scheme = rdata.get('scheme')
|
||||
hostname = rdata.get('hostname')
|
||||
path = rdata.get('path')
|
||||
url = '{}{}{}'.format(scheme, hostname, path)
|
||||
trusted_dashboards.add(url)
|
||||
# populate the context with data from one or more
|
||||
# service providers
|
||||
ctxt = ({'trusted_dashboards': trusted_dashboards}
|
||||
if trusted_dashboards else {})
|
||||
return ctxt
|
||||
|
|
|
@ -40,6 +40,7 @@ from charmhelpers.core.hookenv import (
|
|||
status_set,
|
||||
open_port,
|
||||
is_leader,
|
||||
relation_id,
|
||||
)
|
||||
|
||||
from charmhelpers.core.host import (
|
||||
|
@ -121,7 +122,7 @@ from keystone_utils import (
|
|||
ADMIN_DOMAIN,
|
||||
ADMIN_PROJECT,
|
||||
create_or_show_domain,
|
||||
keystone_service,
|
||||
restart_keystone,
|
||||
)
|
||||
|
||||
from charmhelpers.contrib.hahelpers.cluster import (
|
||||
|
@ -272,6 +273,7 @@ def config_changed_postupgrade():
|
|||
|
||||
update_all_identity_relation_units()
|
||||
update_all_domain_backends()
|
||||
update_all_fid_backends()
|
||||
|
||||
# Ensure sync request is sent out (needed for any/all ssl change)
|
||||
send_ssl_sync_request()
|
||||
|
@ -381,6 +383,17 @@ def update_all_domain_backends():
|
|||
domain_backend_changed(relation_id=rid, unit=unit)
|
||||
|
||||
|
||||
def update_all_fid_backends():
|
||||
if CompareOpenStackReleases(os_release('keystone-common')) < 'ocata':
|
||||
log('Ignoring keystone-fid-service-provider relation as it is'
|
||||
' not supported on releases older than Ocata')
|
||||
return
|
||||
"""If there are any config changes, e.g. for domain or service port
|
||||
make sure to update those for all relation-level buckets"""
|
||||
for rid in relation_ids('keystone-fid-service-provider'):
|
||||
update_keystone_fid_service_provider(relation_id=rid)
|
||||
|
||||
|
||||
def leader_init_db_if_ready(use_current_context=False):
|
||||
""" Initialise the keystone db if it is ready and mark it as initialised.
|
||||
|
||||
|
@ -784,11 +797,7 @@ def domain_backend_changed(relation_id=None, unit=None):
|
|||
domain_nonce_key = 'domain-restart-nonce-{}'.format(domain_name)
|
||||
db = unitdata.kv()
|
||||
if restart_nonce != db.get(domain_nonce_key):
|
||||
if not is_unit_paused_set():
|
||||
if snap_install_requested():
|
||||
service_restart('snap.keystone.*')
|
||||
else:
|
||||
service_restart(keystone_service())
|
||||
restart_keystone()
|
||||
db.set(domain_nonce_key, restart_nonce)
|
||||
db.flush()
|
||||
|
||||
|
@ -869,6 +878,80 @@ def update_nrpe_config():
|
|||
nrpe_setup.write()
|
||||
|
||||
|
||||
@hooks.hook('keystone-fid-service-provider-relation-joined',
|
||||
'keystone-fid-service-provider-relation-changed')
|
||||
def keystone_fid_service_provider_changed():
|
||||
if get_api_version() < 3:
|
||||
log('Identity federation is only supported with keystone v3')
|
||||
return
|
||||
if CompareOpenStackReleases(os_release('keystone-common')) < 'ocata':
|
||||
log('Ignoring keystone-fid-service-provider relation as it is'
|
||||
' not supported on releases older than Ocata')
|
||||
return
|
||||
# for the join case a keystone public-facing hostname and service
|
||||
# port need to be set
|
||||
update_keystone_fid_service_provider(relation_id=relation_id())
|
||||
|
||||
# handle relation data updates (if any), e.g. remote_id_attribute
|
||||
# and a restart will be handled via a nonce, not restart_on_change
|
||||
CONFIGS.write(KEYSTONE_CONF)
|
||||
|
||||
# The relation is container-scoped so this keystone unit's unitdata
|
||||
# will only contain a nonce of a single fid subordinate for a given
|
||||
# fid backend (relation id)
|
||||
restart_nonce = relation_get('restart-nonce')
|
||||
if restart_nonce:
|
||||
nonce = json.loads(restart_nonce)
|
||||
# multiplex by relation id for multiple federated identity
|
||||
# provider charms
|
||||
fid_nonce_key = 'fid-restart-nonce-{}'.format(relation_id())
|
||||
db = unitdata.kv()
|
||||
if restart_nonce != db.get(fid_nonce_key):
|
||||
restart_keystone()
|
||||
db.set(fid_nonce_key, nonce)
|
||||
db.flush()
|
||||
|
||||
|
||||
@hooks.hook('keystone-fid-service-provider-relation-broken')
|
||||
def keystone_fid_service_provider_broken():
|
||||
if CompareOpenStackReleases(os_release('keystone-common')) < 'ocata':
|
||||
log('Ignoring keystone-fid-service-provider relation as it is'
|
||||
' not supported on releases older than Ocata')
|
||||
return
|
||||
|
||||
restart_keystone()
|
||||
|
||||
|
||||
@hooks.hook('websso-trusted-dashboard-relation-joined',
|
||||
'websso-trusted-dashboard-relation-changed',
|
||||
'websso-trusted-dashboard-relation-broken')
|
||||
@restart_on_change(restart_map(), restart_functions=restart_function_map())
|
||||
def websso_trusted_dashboard_changed():
|
||||
if get_api_version() < 3:
|
||||
log('WebSSO is only supported with keystone v3')
|
||||
return
|
||||
if CompareOpenStackReleases(os_release('keystone-common')) < 'ocata':
|
||||
log('Ignoring WebSSO relation as it is not supported on'
|
||||
' releases older than Ocata')
|
||||
return
|
||||
CONFIGS.write(KEYSTONE_CONF)
|
||||
|
||||
|
||||
def update_keystone_fid_service_provider(relation_id=None):
|
||||
tls_enabled = (config('ssl_cert') is not None and
|
||||
config('ssl_key') is not None)
|
||||
# reactive endpoints implementation on the other side, hence
|
||||
# json-encoded values
|
||||
fid_settings = {
|
||||
'hostname': json.dumps(config('os-public-hostname')),
|
||||
'port': json.dumps(config('service-port')),
|
||||
'tls-enabled': json.dumps(tls_enabled),
|
||||
}
|
||||
|
||||
relation_set(relation_id=relation_id,
|
||||
relation_settings=fid_settings)
|
||||
|
||||
|
||||
def main():
|
||||
try:
|
||||
hooks.execute(sys.argv)
|
||||
|
|
|
@ -72,6 +72,7 @@ from charmhelpers.contrib.openstack.utils import (
|
|||
install_os_snaps,
|
||||
get_snaps_install_info_from_origin,
|
||||
enable_memcache,
|
||||
is_unit_paused_set,
|
||||
)
|
||||
|
||||
from charmhelpers.core.strutils import (
|
||||
|
@ -245,7 +246,9 @@ BASE_RESOURCE_MAP = OrderedDict([
|
|||
keystone_context.HAProxyContext(),
|
||||
context.BindHostContext(),
|
||||
context.WorkerConfigContext(),
|
||||
context.MemcacheContext(package='keystone')],
|
||||
context.MemcacheContext(package='keystone'),
|
||||
keystone_context.KeystoneFIDServiceProviderContext(),
|
||||
keystone_context.WebSSOTrustedDashboardContext()],
|
||||
}),
|
||||
(KEYSTONE_LOGGER_CONF, {
|
||||
'contexts': [keystone_context.KeystoneLoggingContext()],
|
||||
|
@ -2574,3 +2577,11 @@ def post_snap_install():
|
|||
if os.path.exists(PASTE_SRC):
|
||||
log("Perfoming post snap install tasks", INFO)
|
||||
shutil.copy(PASTE_SRC, PASTE_DST)
|
||||
|
||||
|
||||
def restart_keystone():
|
||||
if not is_unit_paused_set():
|
||||
if snap_install_requested():
|
||||
service_restart('snap.keystone.*')
|
||||
else:
|
||||
service_restart(keystone_service())
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
keystone_hooks.py
|
|
@ -0,0 +1 @@
|
|||
keystone_hooks.py
|
|
@ -0,0 +1 @@
|
|||
keystone_hooks.py
|
|
@ -0,0 +1 @@
|
|||
keystone_hooks.py
|
|
@ -39,6 +39,11 @@ requires:
|
|||
domain-backend:
|
||||
interface: keystone-domain-backend
|
||||
scope: container
|
||||
keystone-fid-service-provider:
|
||||
interface: keystone-fid-service-provider
|
||||
scope: container
|
||||
websso-trusted-dashboard:
|
||||
interface: websso-trusted-dashboard
|
||||
peers:
|
||||
cluster:
|
||||
interface: keystone-ha
|
||||
|
|
|
@ -67,7 +67,7 @@ driver = {{ assignment_backend }}
|
|||
[oauth1]
|
||||
|
||||
[auth]
|
||||
methods = external,password,token,oauth1
|
||||
methods = external,password,token,oauth1,mapped,openid
|
||||
password = keystone.auth.plugins.password.Password
|
||||
token = keystone.auth.plugins.token.Token
|
||||
oauth1 = keystone.auth.plugins.oauth1.OAuth
|
||||
|
@ -115,3 +115,5 @@ group_allow_delete = False
|
|||
admin_project_domain_name = {{ admin_domain_name }}
|
||||
admin_project_name = admin
|
||||
{% endif -%}
|
||||
|
||||
{% include "parts/section-federation" %}
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
{% if endpoints -%}
|
||||
{% for ext_port in ext_ports -%}
|
||||
Listen {{ ext_port }}
|
||||
{% endfor -%}
|
||||
{% for address, endpoint, ext, int in endpoints -%}
|
||||
<VirtualHost {{ address }}:{{ ext }}>
|
||||
ServerName {{ endpoint }}
|
||||
SSLEngine on
|
||||
SSLProtocol +TLSv1 +TLSv1.1 +TLSv1.2
|
||||
SSLCipherSuite HIGH:!RC4:!MD5:!aNULL:!eNULL:!EXP:!LOW:!MEDIUM
|
||||
SSLCertificateFile /etc/apache2/ssl/{{ namespace }}/cert_{{ endpoint }}
|
||||
# See LP 1484489 - this is to support <= 2.4.7 and >= 2.4.8
|
||||
SSLCertificateChainFile /etc/apache2/ssl/{{ namespace }}/cert_{{ endpoint }}
|
||||
SSLCertificateKeyFile /etc/apache2/ssl/{{ namespace }}/key_{{ endpoint }}
|
||||
ProxyPass / http://localhost:{{ int }}/
|
||||
ProxyPassReverse / http://localhost:{{ int }}/
|
||||
ProxyPreserveHost on
|
||||
RequestHeader set X-Forwarded-Proto "https"
|
||||
IncludeOptional /etc/apache2/mellon*/sp-location*.conf
|
||||
</VirtualHost>
|
||||
{% endfor -%}
|
||||
<Proxy *>
|
||||
Order deny,allow
|
||||
Allow from all
|
||||
</Proxy>
|
||||
<Location />
|
||||
Order allow,deny
|
||||
Allow from all
|
||||
</Location>
|
||||
{% endif -%}
|
|
@ -0,0 +1,10 @@
|
|||
{% if trusted_dashboards %}
|
||||
[federation]
|
||||
{% for dashboard_url in trusted_dashboards -%}
|
||||
trusted_dashboard = {{ dashboard_url }}
|
||||
{% endfor -%}
|
||||
{% endif %}
|
||||
{% for sp in fid_sps -%}
|
||||
[{{ sp['protocol-name'] }}]
|
||||
remote_id_attribute = {{ sp['remote-id-attribute'] }}
|
||||
{% endfor -%}
|
|
@ -0,0 +1,94 @@
|
|||
# Configuration file maintained by Juju. Local changes may be overwritten.
|
||||
|
||||
{% if port -%}
|
||||
Listen {{ port }}
|
||||
{% endif -%}
|
||||
|
||||
{% if admin_port -%}
|
||||
Listen {{ admin_port }}
|
||||
{% endif -%}
|
||||
|
||||
{% if public_port -%}
|
||||
Listen {{ public_port }}
|
||||
{% endif -%}
|
||||
|
||||
{% if port -%}
|
||||
<VirtualHost *:{{ port }}>
|
||||
WSGIDaemonProcess {{ service_name }} processes={{ processes }} threads={{ threads }} user={{ service_name }} group={{ service_name }} \
|
||||
display-name=%{GROUP}
|
||||
WSGIProcessGroup {{ service_name }}
|
||||
WSGIScriptAlias / {{ script }}
|
||||
WSGIApplicationGroup %{GLOBAL}
|
||||
WSGIPassAuthorization On
|
||||
<IfVersion >= 2.4>
|
||||
ErrorLogFormat "%{cu}t %M"
|
||||
</IfVersion>
|
||||
ErrorLog /var/log/apache2/{{ service_name }}_error.log
|
||||
CustomLog /var/log/apache2/{{ service_name }}_access.log combined
|
||||
|
||||
<Directory /usr/bin>
|
||||
<IfVersion >= 2.4>
|
||||
Require all granted
|
||||
</IfVersion>
|
||||
<IfVersion < 2.4>
|
||||
Order allow,deny
|
||||
Allow from all
|
||||
</IfVersion>
|
||||
</Directory>
|
||||
IncludeOptional /etc/apache2/mellon*/sp-location*.conf
|
||||
</VirtualHost>
|
||||
{% endif -%}
|
||||
|
||||
{% if admin_port -%}
|
||||
<VirtualHost *:{{ admin_port }}>
|
||||
WSGIDaemonProcess {{ service_name }}-admin processes={{ admin_processes }} threads={{ threads }} user={{ service_name }} group={{ service_name }} \
|
||||
display-name=%{GROUP}
|
||||
WSGIProcessGroup {{ service_name }}-admin
|
||||
WSGIScriptAlias / {{ admin_script }}
|
||||
WSGIApplicationGroup %{GLOBAL}
|
||||
WSGIPassAuthorization On
|
||||
<IfVersion >= 2.4>
|
||||
ErrorLogFormat "%{cu}t %M"
|
||||
</IfVersion>
|
||||
ErrorLog /var/log/apache2/{{ service_name }}_error.log
|
||||
CustomLog /var/log/apache2/{{ service_name }}_access.log combined
|
||||
|
||||
<Directory /usr/bin>
|
||||
<IfVersion >= 2.4>
|
||||
Require all granted
|
||||
</IfVersion>
|
||||
<IfVersion < 2.4>
|
||||
Order allow,deny
|
||||
Allow from all
|
||||
</IfVersion>
|
||||
</Directory>
|
||||
IncludeOptional /etc/apache2/mellon*/sp-location*.conf
|
||||
</VirtualHost>
|
||||
{% endif -%}
|
||||
|
||||
{% if public_port -%}
|
||||
<VirtualHost *:{{ public_port }}>
|
||||
WSGIDaemonProcess {{ service_name }}-public processes={{ public_processes }} threads={{ threads }} user={{ service_name }} group={{ service_name }} \
|
||||
display-name=%{GROUP}
|
||||
WSGIProcessGroup {{ service_name }}-public
|
||||
WSGIScriptAlias / {{ public_script }}
|
||||
WSGIApplicationGroup %{GLOBAL}
|
||||
WSGIPassAuthorization On
|
||||
<IfVersion >= 2.4>
|
||||
ErrorLogFormat "%{cu}t %M"
|
||||
</IfVersion>
|
||||
ErrorLog /var/log/apache2/{{ service_name }}_error.log
|
||||
CustomLog /var/log/apache2/{{ service_name }}_access.log combined
|
||||
|
||||
<Directory /usr/bin>
|
||||
<IfVersion >= 2.4>
|
||||
Require all granted
|
||||
</IfVersion>
|
||||
<IfVersion < 2.4>
|
||||
Order allow,deny
|
||||
Allow from all
|
||||
</IfVersion>
|
||||
</Directory>
|
||||
IncludeOptional /etc/apache2/mellon*/sp-location*.conf
|
||||
</VirtualHost>
|
||||
{% endif -%}
|
|
@ -217,3 +217,204 @@ class TestKeystoneContexts(CharmTestCase):
|
|||
|
||||
mock_is_elected_leader.return_value = True
|
||||
self.assertEqual({'token_flush': True}, ctxt())
|
||||
|
||||
@patch.object(context, 'relation_ids')
|
||||
@patch.object(context, 'related_units')
|
||||
@patch.object(context, 'relation_get')
|
||||
def test_keystone_fid_service_provider_rdata(
|
||||
self, mock_relation_get, mock_related_units,
|
||||
mock_relation_ids):
|
||||
os.environ['JUJU_UNIT_NAME'] = 'keystone'
|
||||
|
||||
def relation_ids_side_effect(rname):
|
||||
return {
|
||||
'keystone-fid-service-provider': {
|
||||
'keystone-fid-service-provider:0',
|
||||
'keystone-fid-service-provider:1',
|
||||
'keystone-fid-service-provider:2'
|
||||
}
|
||||
}[rname]
|
||||
|
||||
mock_relation_ids.side_effect = relation_ids_side_effect
|
||||
|
||||
def related_units_side_effect(rid):
|
||||
return {
|
||||
'keystone-fid-service-provider:0': ['sp-mellon/0'],
|
||||
'keystone-fid-service-provider:1': ['sp-shib/0'],
|
||||
'keystone-fid-service-provider:2': ['sp-oidc/0'],
|
||||
}[rid]
|
||||
mock_related_units.side_effect = related_units_side_effect
|
||||
|
||||
def relation_get_side_effect(unit, rid):
|
||||
# one unit only as the relation is container-scoped
|
||||
return {
|
||||
"keystone-fid-service-provider:0": {
|
||||
"sp-mellon/0": {
|
||||
"ingress-address": '10.0.0.10',
|
||||
"protocol-name": '"saml2"',
|
||||
"remote-id-attribute": '"MELLON_IDP"',
|
||||
},
|
||||
},
|
||||
"keystone-fid-service-provider:1": {
|
||||
"sp-shib/0": {
|
||||
"ingress-address": '10.0.0.10',
|
||||
"protocol-name": '"mapped"',
|
||||
"remote-id-attribute": '"Shib-Identity-Provider"',
|
||||
},
|
||||
},
|
||||
"keystone-fid-service-provider:2": {
|
||||
"sp-oidc/0": {
|
||||
"ingress-address": '10.0.0.10',
|
||||
"protocol-name": '"oidc"',
|
||||
"remote-id-attribute": '"HTTP_OIDC_ISS"',
|
||||
},
|
||||
},
|
||||
}[rid][unit]
|
||||
|
||||
mock_relation_get.side_effect = relation_get_side_effect
|
||||
ctxt = context.KeystoneFIDServiceProviderContext()
|
||||
|
||||
self.maxDiff = None
|
||||
self.assertItemsEqual(
|
||||
ctxt(),
|
||||
{
|
||||
"fid_sps": [
|
||||
{
|
||||
"protocol-name": "saml2",
|
||||
"remote-id-attribute": "MELLON_IDP",
|
||||
},
|
||||
{
|
||||
"protocol-name": "mapped",
|
||||
"remote-id-attribute": "Shib-Identity-Provider",
|
||||
},
|
||||
{
|
||||
"protocol-name": "oidc",
|
||||
"remote-id-attribute": "HTTP_OIDC_ISS",
|
||||
},
|
||||
]
|
||||
}
|
||||
)
|
||||
|
||||
@patch.object(context, 'relation_ids')
|
||||
def test_keystone_fid_service_provider_empty(
|
||||
self, mock_relation_ids):
|
||||
os.environ['JUJU_UNIT_NAME'] = 'keystone'
|
||||
|
||||
def relation_ids_side_effect(rname):
|
||||
return {
|
||||
'keystone-fid-service-provider': {}
|
||||
}[rname]
|
||||
|
||||
mock_relation_ids.side_effect = relation_ids_side_effect
|
||||
ctxt = context.KeystoneFIDServiceProviderContext()
|
||||
|
||||
self.maxDiff = None
|
||||
self.assertItemsEqual(ctxt(), {})
|
||||
|
||||
@patch.object(context, 'relation_ids')
|
||||
@patch.object(context, 'related_units')
|
||||
@patch.object(context, 'relation_get')
|
||||
def test_websso_trusted_dashboard_urls_generated(
|
||||
self, mock_relation_get, mock_related_units,
|
||||
mock_relation_ids):
|
||||
os.environ['JUJU_UNIT_NAME'] = 'keystone'
|
||||
|
||||
def relation_ids_side_effect(rname):
|
||||
return {
|
||||
'websso-trusted-dashboard': {
|
||||
'websso-trusted-dashboard:0',
|
||||
'websso-trusted-dashboard:1',
|
||||
'websso-trusted-dashboard:2'
|
||||
}
|
||||
}[rname]
|
||||
|
||||
mock_relation_ids.side_effect = relation_ids_side_effect
|
||||
|
||||
def related_units_side_effect(rid):
|
||||
return {
|
||||
'websso-trusted-dashboard:0': ['dashboard-blue/0',
|
||||
'dashboard-blue/1'],
|
||||
'websso-trusted-dashboard:1': ['dashboard-red/0',
|
||||
'dashboard-red/1'],
|
||||
'websso-trusted-dashboard:2': ['dashboard-green/0',
|
||||
'dashboard-green/1']
|
||||
}[rid]
|
||||
mock_related_units.side_effect = related_units_side_effect
|
||||
|
||||
def relation_get_side_effect(unit, rid):
|
||||
return {
|
||||
"websso-trusted-dashboard:0": {
|
||||
"dashboard-blue/0": { # dns-ha
|
||||
"ingress-address": '10.0.0.10',
|
||||
"scheme": "https://",
|
||||
"hostname": "horizon.intranet.test",
|
||||
"path": "/auth/websso/",
|
||||
},
|
||||
"dashboard-blue/1": { # dns-ha
|
||||
"ingress-address": '10.0.0.11',
|
||||
"scheme": "https://",
|
||||
"hostname": "horizon.intranet.test",
|
||||
"path": "/auth/websso/",
|
||||
},
|
||||
},
|
||||
"websso-trusted-dashboard:1": {
|
||||
"dashboard-red/0": { # vip
|
||||
"ingress-address": '10.0.0.12',
|
||||
"scheme": "https://",
|
||||
"hostname": "10.0.0.100",
|
||||
"path": "/auth/websso/",
|
||||
},
|
||||
"dashboard-red/1": { # vip
|
||||
"ingress-address": '10.0.0.13',
|
||||
"scheme": "https://",
|
||||
"hostname": "10.0.0.100",
|
||||
"path": "/auth/websso/",
|
||||
},
|
||||
},
|
||||
"websso-trusted-dashboard:2": {
|
||||
"dashboard-green/0": { # vip-less, dns-ha-less
|
||||
"ingress-address": '10.0.0.14',
|
||||
"scheme": "http://",
|
||||
"hostname": "10.0.0.14",
|
||||
"path": "/auth/websso/",
|
||||
},
|
||||
"dashboard-green/1": {
|
||||
"ingress-address": '10.0.0.15',
|
||||
"scheme": "http://",
|
||||
"hostname": "10.0.0.15",
|
||||
"path": "/auth/websso/",
|
||||
},
|
||||
},
|
||||
}[rid][unit]
|
||||
|
||||
mock_relation_get.side_effect = relation_get_side_effect
|
||||
ctxt = context.WebSSOTrustedDashboardContext()
|
||||
|
||||
self.maxDiff = None
|
||||
self.assertEqual(
|
||||
ctxt(),
|
||||
{
|
||||
'trusted_dashboards': set([
|
||||
'https://horizon.intranet.test/auth/websso/',
|
||||
'https://10.0.0.100/auth/websso/',
|
||||
'http://10.0.0.14/auth/websso/',
|
||||
'http://10.0.0.15/auth/websso/',
|
||||
])
|
||||
}
|
||||
)
|
||||
|
||||
@patch.object(context, 'relation_ids')
|
||||
def test_websso_trusted_dashboard_empty(
|
||||
self, mock_relation_ids):
|
||||
os.environ['JUJU_UNIT_NAME'] = 'keystone'
|
||||
|
||||
def relation_ids_side_effect(rname):
|
||||
return {
|
||||
'websso-trusted-dashboard': {}
|
||||
}[rname]
|
||||
|
||||
mock_relation_ids.side_effect = relation_ids_side_effect
|
||||
ctxt = context.WebSSOTrustedDashboardContext()
|
||||
|
||||
self.maxDiff = None
|
||||
self.assertItemsEqual(ctxt(), {})
|
||||
|
|
|
@ -93,7 +93,6 @@ TO_PATCH = [
|
|||
'update_nrpe_config',
|
||||
'ensure_ssl_dirs',
|
||||
'is_db_ready',
|
||||
'keystone_service',
|
||||
'create_or_show_domain',
|
||||
'get_api_version',
|
||||
# other
|
||||
|
@ -441,6 +440,7 @@ class KeystoneRelationTests(CharmTestCase):
|
|||
self.assertTrue(update.called)
|
||||
self.assertTrue(mock_update_domains.called)
|
||||
|
||||
@patch.object(hooks, 'os_release')
|
||||
@patch.object(hooks, 'run_in_apache')
|
||||
@patch.object(hooks, 'initialise_pki')
|
||||
@patch.object(hooks, 'is_db_initialised')
|
||||
|
@ -460,7 +460,9 @@ class KeystoneRelationTests(CharmTestCase):
|
|||
ensure_ssl_dir,
|
||||
mock_db_init,
|
||||
mock_initialise_pki,
|
||||
mock_run_in_apache):
|
||||
mock_run_in_apache,
|
||||
os_release):
|
||||
os_release.return_value = 'ocata'
|
||||
self.enable_memcache.return_value = False
|
||||
mock_run_in_apache.return_value = False
|
||||
ensure_ssl_cert.return_value = False
|
||||
|
@ -1087,9 +1089,14 @@ class KeystoneRelationTests(CharmTestCase):
|
|||
|
||||
@patch.object(hooks, 'is_unit_paused_set')
|
||||
@patch.object(hooks, 'is_db_initialised')
|
||||
@patch.object(utils, 'run_in_apache')
|
||||
@patch.object(utils, 'service_restart')
|
||||
def test_domain_backend_changed_complete(self,
|
||||
service_restart,
|
||||
run_in_apache,
|
||||
is_db_initialised,
|
||||
is_unit_paused_set):
|
||||
run_in_apache.return_value = True
|
||||
self.get_api_version.return_value = 3
|
||||
self.relation_get.side_effect = ['mydomain', 'nonce2']
|
||||
self.is_leader.return_value = True
|
||||
|
@ -1099,7 +1106,6 @@ class KeystoneRelationTests(CharmTestCase):
|
|||
mock_kv.get.return_value = None
|
||||
self.unitdata.kv.return_value = mock_kv
|
||||
is_unit_paused_set.return_value = False
|
||||
self.keystone_service.return_value = 'apache2'
|
||||
|
||||
hooks.domain_backend_changed()
|
||||
|
||||
|
@ -1113,16 +1119,21 @@ class KeystoneRelationTests(CharmTestCase):
|
|||
rid=None),
|
||||
])
|
||||
self.create_or_show_domain.assert_called_with('mydomain')
|
||||
self.service_restart.assert_called_with('apache2')
|
||||
service_restart.assert_called_with('apache2')
|
||||
mock_kv.set.assert_called_with('domain-restart-nonce-mydomain',
|
||||
'nonce2')
|
||||
self.assertTrue(mock_kv.flush.called)
|
||||
|
||||
@patch.object(hooks, 'is_unit_paused_set')
|
||||
@patch.object(hooks, 'is_db_initialised')
|
||||
@patch.object(utils, 'run_in_apache')
|
||||
@patch.object(utils, 'service_restart')
|
||||
def test_domain_backend_changed_complete_follower(self,
|
||||
service_restart,
|
||||
run_in_apache,
|
||||
is_db_initialised,
|
||||
is_unit_paused_set):
|
||||
run_in_apache.return_value = True
|
||||
self.get_api_version.return_value = 3
|
||||
self.relation_get.side_effect = ['mydomain', 'nonce2']
|
||||
self.is_leader.return_value = False
|
||||
|
@ -1132,7 +1143,6 @@ class KeystoneRelationTests(CharmTestCase):
|
|||
mock_kv.get.return_value = None
|
||||
self.unitdata.kv.return_value = mock_kv
|
||||
is_unit_paused_set.return_value = False
|
||||
self.keystone_service.return_value = 'apache2'
|
||||
|
||||
hooks.domain_backend_changed()
|
||||
|
||||
|
@ -1147,7 +1157,84 @@ class KeystoneRelationTests(CharmTestCase):
|
|||
])
|
||||
# Only lead unit will create the domain
|
||||
self.assertFalse(self.create_or_show_domain.called)
|
||||
self.service_restart.assert_called_with('apache2')
|
||||
service_restart.assert_called_with('apache2')
|
||||
mock_kv.set.assert_called_with('domain-restart-nonce-mydomain',
|
||||
'nonce2')
|
||||
self.assertTrue(mock_kv.flush.called)
|
||||
|
||||
@patch.object(hooks, 'os_release')
|
||||
@patch.object(hooks, 'relation_id')
|
||||
@patch.object(hooks, 'is_unit_paused_set')
|
||||
@patch.object(hooks, 'is_db_initialised')
|
||||
@patch.object(utils, 'run_in_apache')
|
||||
@patch.object(utils, 'service_restart')
|
||||
def test_fid_service_provider_changed_complete(
|
||||
self,
|
||||
service_restart,
|
||||
run_in_apache,
|
||||
is_db_initialised,
|
||||
is_unit_paused_set,
|
||||
relation_id, os_release):
|
||||
os_release.return_value = 'ocata'
|
||||
rel = 'keystone-fid-service-provider:0'
|
||||
relation_id.return_value = rel
|
||||
run_in_apache.return_value = True
|
||||
self.get_api_version.return_value = 3
|
||||
self.relation_get.side_effect = ['"nonce2"']
|
||||
self.is_leader.return_value = True
|
||||
self.is_db_ready.return_value = True
|
||||
is_db_initialised.return_value = True
|
||||
mock_kv = MagicMock()
|
||||
mock_kv.get.return_value = None
|
||||
self.unitdata.kv.return_value = mock_kv
|
||||
is_unit_paused_set.return_value = False
|
||||
|
||||
hooks.keystone_fid_service_provider_changed()
|
||||
|
||||
self.assertTrue(self.get_api_version.called)
|
||||
self.relation_get.assert_has_calls([
|
||||
call('restart-nonce'),
|
||||
])
|
||||
service_restart.assert_called_with('apache2')
|
||||
mock_kv.set.assert_called_with(
|
||||
'fid-restart-nonce-{}'.format(rel), 'nonce2')
|
||||
self.assertTrue(mock_kv.flush.called)
|
||||
|
||||
@patch.object(hooks, 'os_release')
|
||||
@patch.object(hooks, 'relation_id')
|
||||
@patch.object(hooks, 'is_unit_paused_set')
|
||||
@patch.object(hooks, 'is_db_initialised')
|
||||
@patch.object(utils, 'run_in_apache')
|
||||
@patch.object(utils, 'service_restart')
|
||||
def test_fid_service_provider_changed_complete_follower(
|
||||
self,
|
||||
service_restart,
|
||||
run_in_apache,
|
||||
is_db_initialised,
|
||||
is_unit_paused_set,
|
||||
relation_id, os_release):
|
||||
os_release.return_value = 'ocata'
|
||||
rel = 'keystone-fid-service-provider:0'
|
||||
relation_id.return_value = rel
|
||||
run_in_apache.return_value = True
|
||||
self.get_api_version.return_value = 3
|
||||
self.relation_get.side_effect = ['"nonce2"']
|
||||
self.is_leader.return_value = False
|
||||
self.is_db_ready.return_value = True
|
||||
is_db_initialised.return_value = True
|
||||
mock_kv = MagicMock()
|
||||
mock_kv.get.return_value = None
|
||||
self.unitdata.kv.return_value = mock_kv
|
||||
is_unit_paused_set.return_value = False
|
||||
|
||||
hooks.keystone_fid_service_provider_changed()
|
||||
|
||||
self.assertTrue(self.get_api_version.called)
|
||||
self.relation_get.assert_has_calls([
|
||||
call('restart-nonce'),
|
||||
])
|
||||
service_restart.assert_called_with('apache2')
|
||||
mock_kv.set.assert_called_with(
|
||||
'fid-restart-nonce-{}'.format(rel),
|
||||
'nonce2')
|
||||
self.assertTrue(mock_kv.flush.called)
|
||||
|
|
Loading…
Reference in New Issue