Ensure crgw works with Keystone v3
The URLs for SSL certificates are different and the v2 client functions do not work. This change fixes these issues. Add missing config.yaml options. Change-Id: Ia4c7b508e70f690493b098c6fb07d24a340bc2a6 Closes-Bug: #1708464
This commit is contained in:
parent
2226518612
commit
a1444c4b2f
46
config.yaml
46
config.yaml
|
@ -275,3 +275,49 @@ options:
|
|||
description: |
|
||||
A comma-separated list of nagios servicegroups. If left empty,
|
||||
the nagios_context will be used as the servicegroup
|
||||
# HAProxy Parameters
|
||||
haproxy-server-timeout:
|
||||
type: int
|
||||
default:
|
||||
description: |
|
||||
Server timeout configuration in ms for haproxy, used in HA
|
||||
configurations. If not provided, default value of 30000ms is used.
|
||||
haproxy-client-timeout:
|
||||
type: int
|
||||
default:
|
||||
description: |
|
||||
Client timeout configuration in ms for haproxy, used in HA
|
||||
configurations. If not provided, default value of 30000ms is used.
|
||||
haproxy-queue-timeout:
|
||||
type: int
|
||||
default:
|
||||
description: |
|
||||
Queue timeout configuration in ms for haproxy, used in HA
|
||||
configurations. If not provided, default value of 5000ms is used.
|
||||
haproxy-connect-timeout:
|
||||
type: int
|
||||
default:
|
||||
description: |
|
||||
Connect timeout configuration in ms for haproxy, used in HA
|
||||
configurations. If not provided, default value of 5000ms is used.
|
||||
|
||||
# External SSL Parameters
|
||||
ssl_cert:
|
||||
type: string
|
||||
default:
|
||||
description: |
|
||||
SSL certificate to install and use for API ports. Setting this value
|
||||
and ssl_key will enable reverse proxying, point Glance's entry in the
|
||||
Keystone catalog to use https, and override any certificate and key
|
||||
issued by Keystone (if it is configured to do so).
|
||||
ssl_key:
|
||||
type: string
|
||||
default:
|
||||
description: SSL key to use with certificate specified as ssl_cert.
|
||||
ssl_ca:
|
||||
type: string
|
||||
default:
|
||||
description: |
|
||||
SSL CA to use with the certificate and key provided - this is only
|
||||
required if you are providing a privately signed ssl_cert and ssl_key.
|
||||
|
||||
|
|
|
@ -25,6 +25,7 @@ import ceph_radosgw_context
|
|||
from charmhelpers.core.hookenv import (
|
||||
log,
|
||||
DEBUG,
|
||||
ERROR,
|
||||
INFO,
|
||||
relation_get,
|
||||
relation_ids,
|
||||
|
@ -72,6 +73,7 @@ from charmhelpers.fetch import (
|
|||
try:
|
||||
import keystoneclient
|
||||
from keystoneclient.v2_0 import client
|
||||
from keystoneclient.v3 import client as client_v3
|
||||
try:
|
||||
# Kilo and newer
|
||||
from keystoneclient.exceptions import (
|
||||
|
@ -362,25 +364,32 @@ def defer_if_unavailable(modules):
|
|||
def get_ks_cert(ksclient, auth_endpoint, cert_type):
|
||||
"""Get certificate from keystone.
|
||||
|
||||
:param admin_token: Keystone admin token
|
||||
:param ksclient: Keystone client
|
||||
:param auth_endpoint: Keystone auth endpoint url
|
||||
:param certs_path: Path to local certs store
|
||||
:returns: certificate
|
||||
"""
|
||||
if ksclient.version == 'v3':
|
||||
if cert_type == 'signing':
|
||||
cert_type = 'certificates'
|
||||
request = ("{}OS-SIMPLE-CERT/{}"
|
||||
"".format(auth_endpoint, cert_type))
|
||||
else:
|
||||
request = "{}/certificates/{}".format(auth_endpoint, cert_type)
|
||||
|
||||
try:
|
||||
try:
|
||||
# Kilo and newer
|
||||
if cert_type == 'ca':
|
||||
cert = ksclient.certificates.get_ca_certificate()
|
||||
elif cert_type == 'signing':
|
||||
elif cert_type in ['signing', 'certificates']:
|
||||
cert = ksclient.certificates.get_signing_certificate()
|
||||
else:
|
||||
raise KSCertSetupException("Invalid cert type "
|
||||
"'{}'".format(cert_type))
|
||||
except AttributeError:
|
||||
# Juno and older
|
||||
cert = requests.request('GET', "{}/certificates/{}".
|
||||
format(auth_endpoint, cert_type)).text
|
||||
# Keystone v3 or Juno and older
|
||||
cert = requests.request('GET', request).text
|
||||
except (ConnectionRefused, requests.exceptions.ConnectionError,
|
||||
Forbidden, InternalServerError):
|
||||
raise KSCertSetupException("Error connecting to keystone")
|
||||
|
@ -389,17 +398,15 @@ def get_ks_cert(ksclient, auth_endpoint, cert_type):
|
|||
|
||||
|
||||
@defer_if_unavailable(['keystoneclient'])
|
||||
def get_ks_ca_cert(admin_token, auth_endpoint, certs_path):
|
||||
def get_ks_ca_cert(ksclient, auth_endpoint, certs_path):
|
||||
""""Get and store keystone CA certificate.
|
||||
|
||||
:param admin_token: Keystone admin token
|
||||
:param ksclient: Keystone client
|
||||
:param auth_endpoint: Keystone auth endpoint url
|
||||
:param certs_path: Path to local certs store
|
||||
:returns: None
|
||||
"""
|
||||
|
||||
ksclient = keystoneclient.httpclient.HTTPClient(token=admin_token,
|
||||
endpoint=auth_endpoint)
|
||||
ca_cert = get_ks_cert(ksclient, auth_endpoint, 'ca')
|
||||
if ca_cert:
|
||||
try:
|
||||
|
@ -424,15 +431,14 @@ def get_ks_ca_cert(admin_token, auth_endpoint, certs_path):
|
|||
|
||||
|
||||
@defer_if_unavailable(['keystoneclient'])
|
||||
def get_ks_signing_cert(admin_token, auth_endpoint, certs_path):
|
||||
def get_ks_signing_cert(ksclient, auth_endpoint, certs_path):
|
||||
""""Get and store keystone signing certificate.
|
||||
|
||||
:param admin_token: Keystone admin token
|
||||
:param ksclient: Keystone client
|
||||
:param auth_endpoint: Keystone auth endpoint url
|
||||
:param certs_path: Path to local certs store
|
||||
:returns: None
|
||||
"""
|
||||
ksclient = client.Client(token=admin_token, endpoint=auth_endpoint)
|
||||
signing_cert = get_ks_cert(ksclient, auth_endpoint, 'signing')
|
||||
if signing_cert:
|
||||
try:
|
||||
|
@ -474,8 +480,32 @@ def setup_keystone_certs(CONFIGS):
|
|||
log("Missing relation settings - deferring cert setup",
|
||||
level=DEBUG)
|
||||
return
|
||||
|
||||
ksclient = get_keystone_client_from_relation()
|
||||
if not ksclient:
|
||||
log("Failed to get keystoneclient", level=ERROR)
|
||||
return
|
||||
|
||||
auth_endpoint = ksclient.auth_endpoint
|
||||
|
||||
try:
|
||||
get_ks_ca_cert(ksclient, auth_endpoint, certs_path)
|
||||
get_ks_signing_cert(ksclient, auth_endpoint, certs_path)
|
||||
except KSCertSetupException as e:
|
||||
log("Keystone certs setup incomplete - {}".format(e), level=INFO)
|
||||
|
||||
|
||||
# TODO: Move to charmhelpers
|
||||
# TODO: Make it session aware
|
||||
def get_keystone_client_from_relation(relation_type='identity-service'):
|
||||
""" Get keystone client from relation data
|
||||
|
||||
:param relation_type: Relation to keystone
|
||||
:returns: Keystone client
|
||||
"""
|
||||
|
||||
rdata = {}
|
||||
for relid in relation_ids('identity-service'):
|
||||
for relid in relation_ids(relation_type):
|
||||
for unit in related_units(relid):
|
||||
rdata = relation_get(unit=unit, rid=relid)
|
||||
if rdata:
|
||||
|
@ -488,16 +518,21 @@ def setup_keystone_certs(CONFIGS):
|
|||
if is_ipv6(settings.get('auth_host')):
|
||||
settings['auth_host'] = format_ipv6_addr(settings.get('auth_host'))
|
||||
|
||||
api_version = rdata.get('api_version')
|
||||
auth_endpoint = format_endpoint(auth_protocol,
|
||||
settings['auth_host'],
|
||||
settings['auth_port'],
|
||||
settings['api_version'])
|
||||
|
||||
try:
|
||||
get_ks_ca_cert(settings['admin_token'], auth_endpoint, certs_path)
|
||||
get_ks_signing_cert(settings['admin_token'], auth_endpoint, certs_path)
|
||||
except KSCertSetupException as e:
|
||||
log("Keystone certs setup incomplete - {}".format(e), level=INFO)
|
||||
if api_version and '3' in api_version:
|
||||
ksclient = client_v3.Client(token=settings['admin_token'],
|
||||
endpoint=auth_endpoint)
|
||||
else:
|
||||
ksclient = client.Client(token=settings['admin_token'],
|
||||
endpoint=auth_endpoint)
|
||||
# Add simple way to retrieve keystone auth endpoint
|
||||
ksclient.auth_endpoint = auth_endpoint
|
||||
return ksclient
|
||||
|
||||
|
||||
def disable_unused_apache_sites():
|
||||
|
|
|
@ -89,38 +89,67 @@ class CephRadosGWUtilTests(CharmTestCase):
|
|||
# ports=None whilst port checks are disabled.
|
||||
f.assert_called_once_with('assessor', services='s1', ports=None)
|
||||
|
||||
@patch.object(utils, 'related_units')
|
||||
@patch.object(utils, 'relation_ids')
|
||||
@patch.dict('sys.modules', {'requests': MagicMock(),
|
||||
'keystoneclient': MagicMock(),
|
||||
'httpclient': MagicMock()})
|
||||
@patch.object(utils, 'get_keystone_client_from_relation')
|
||||
@patch.object(utils, 'is_ipv6', lambda addr: False)
|
||||
@patch.object(utils, 'get_ks_signing_cert')
|
||||
@patch.object(utils, 'get_ks_ca_cert')
|
||||
@patch.object(utils, 'relation_get')
|
||||
@patch.object(utils, 'mkdir')
|
||||
def test_setup_keystone_certs(self, mock_mkdir, mock_relation_get,
|
||||
def test_setup_keystone_certs(self, mock_mkdir,
|
||||
mock_get_ks_ca_cert,
|
||||
mock_get_ks_signing_cert,
|
||||
mock_relation_ids, mock_related_units):
|
||||
mock_get_keystone_client):
|
||||
auth_host = 'foo/bar'
|
||||
auth_port = 80
|
||||
auth_url = 'http://%s:%s/v2.0' % (auth_host, auth_port)
|
||||
mock_ksclient = MagicMock()
|
||||
mock_ksclient.auth_endpoint = auth_url
|
||||
mock_get_keystone_client.return_value = mock_ksclient
|
||||
|
||||
configs = MagicMock()
|
||||
configs.complete_contexts.return_value = ['identity-service']
|
||||
|
||||
utils.setup_keystone_certs(configs)
|
||||
mock_get_ks_signing_cert.assert_has_calls([call(mock_ksclient,
|
||||
auth_url,
|
||||
'/var/lib/ceph/nss')])
|
||||
mock_get_ks_ca_cert.assert_has_calls([call(mock_ksclient, auth_url,
|
||||
'/var/lib/ceph/nss')])
|
||||
|
||||
@patch.object(utils, 'client_v3')
|
||||
@patch.object(utils, 'client')
|
||||
@patch.object(utils, 'related_units')
|
||||
@patch.object(utils, 'relation_ids')
|
||||
@patch.object(utils, 'is_ipv6', lambda addr: False)
|
||||
@patch.object(utils, 'relation_get')
|
||||
def test_get_keystone_client_from_relation(self, mock_relation_get,
|
||||
mock_relation_ids,
|
||||
mock_related_units,
|
||||
mock_client,
|
||||
mock_client_v3):
|
||||
auth_host = 'foo/bar'
|
||||
auth_port = 80
|
||||
admin_token = '666'
|
||||
auth_url = 'http://%s:%s/v2.0' % (auth_host, auth_port)
|
||||
self.format_endpoint.return_value = auth_url
|
||||
configs = MagicMock()
|
||||
configs.complete_contexts.return_value = ['identity-service']
|
||||
mock_relation_ids.return_value = ['identity-service:5']
|
||||
mock_related_units.return_value = ['keystone/1']
|
||||
mock_relation_get.return_value = {'auth_host': auth_host,
|
||||
'auth_port': auth_port,
|
||||
'admin_token': admin_token,
|
||||
'api_version': '2'}
|
||||
utils.setup_keystone_certs(configs)
|
||||
mock_get_ks_signing_cert.assert_has_calls([call(admin_token, auth_url,
|
||||
'/var/lib/ceph/nss')])
|
||||
mock_get_ks_ca_cert.assert_has_calls([call(admin_token, auth_url,
|
||||
'/var/lib/ceph/nss')])
|
||||
rel_data = {'auth_host': auth_host,
|
||||
'auth_port': auth_port,
|
||||
'admin_token': admin_token,
|
||||
'api_version': '2'}
|
||||
|
||||
mock_relation_get.return_value = rel_data
|
||||
utils.get_keystone_client_from_relation()
|
||||
mock_client.Client.assert_called_with(endpoint=auth_url,
|
||||
token=admin_token)
|
||||
|
||||
auth_url = 'http://%s:%s/v3' % (auth_host, auth_port)
|
||||
self.format_endpoint.return_value = auth_url
|
||||
rel_data['api_version'] = '3'
|
||||
mock_relation_get.return_value = rel_data
|
||||
utils.get_keystone_client_from_relation()
|
||||
mock_client_v3.Client.assert_called_with(endpoint=auth_url,
|
||||
token=admin_token)
|
||||
|
||||
@patch.object(utils, 'get_ks_cert')
|
||||
@patch.object(utils.subprocess, 'Popen')
|
||||
|
|
Loading…
Reference in New Issue