Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
cloud
charms
Federated Keystone
Commits
2d25e81b
Commit
2d25e81b
authored
May 14, 2018
by
Zuul
Committed by
Gerrit Code Review
May 14, 2018
Browse files
Merge "add support for Federated IDentity (FID) and WebSSO"
parents
dc5ccac4
6f3751cc
Changes
18
Hide whitespace changes
Inline
Side-by-side
hooks/keystone-fid-service-provider-relation-broken
0 → 120000
View file @
2d25e81b
keystone_hooks.py
\ No newline at end of file
hooks/keystone-fid-service-provider-relation-changed
0 → 120000
View file @
2d25e81b
keystone_hooks.py
\ No newline at end of file
hooks/keystone-fid-service-provider-relation-departed
0 → 120000
View file @
2d25e81b
keystone_hooks.py
\ No newline at end of file
hooks/keystone-fid-service-provider-relation-joined
0 → 120000
View file @
2d25e81b
keystone_hooks.py
\ No newline at end of file
hooks/keystone_context.py
View file @
2d25e81b
...
...
@@ -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
hooks/keystone_hooks.py
View file @
2d25e81b
...
...
@@ -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_servic
e
,
restart_keyston
e
,
)
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
)
...
...
hooks/keystone_utils.py
View file @
2d25e81b
...
...
@@ -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
())
hooks/websso-trusted-dashboard-relation-broken
0 → 120000
View file @
2d25e81b
keystone_hooks.py
\ No newline at end of file
hooks/websso-trusted-dashboard-relation-changed
0 → 120000
View file @
2d25e81b
keystone_hooks.py
\ No newline at end of file
hooks/websso-trusted-dashboard-relation-departed
0 → 120000
View file @
2d25e81b
keystone_hooks.py
\ No newline at end of file
hooks/websso-trusted-dashboard-relation-joined
0 → 120000
View file @
2d25e81b
keystone_hooks.py
\ No newline at end of file
metadata.yaml
View file @
2d25e81b
...
...
@@ -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
templates/ocata/keystone.conf
View file @
2d25e81b
...
...
@@ -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"
%}
templates/openstack_https_frontend.conf
0 → 100644
View file @
2d25e81b
{%
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
-%}
templates/parts/section-federation
0 → 100644
View file @
2d25e81b
{% 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 -%}
templates/wsgi-openstack-api.conf
0 → 100644
View file @
2d25e81b
# 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
-%}
unit_tests/test_keystone_contexts.py
View file @
2d25e81b
...
...
@@ -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
(