Fix Keystone v3 auth for swift-proxy

No need for refresh of proxy-server.conf template for Mitaka. Update
template for Kilo and later to make use of domain_name and project_name
parameters instead of domain_id and project_id parameters.

The current template sets up auth to user in default domain
but project in service domain. This does not work with service
domain layout.

Do not request configured operator_roles roles from Keystone. From
which roles swift-proxy should accept requests are still configured
in proxy-server.conf, but requesting and setting up these roles for
the s3_swift user in Keystone is incorrect behaviour.

Register required relation data for identity-service immediatelly when
relation to 'identity-service' exists. Do not postpone registration
until context is complete which may cause the swift-proxy unit marking
itself ready while still being in a unconfigured state.

Add tests to verify configuration and operation of swift-proxy when
using Keystone v3 auth.

Change-Id: I8bf182a9256f96af50e4cc37505d9c0ca3d62e47
Closes-Bug: 1646765
This commit is contained in:
Frode Nordahl 2016-12-02 12:08:04 +01:00
parent c4cd0699c7
commit 7c24ae8128
6 changed files with 94 additions and 20 deletions

View File

@ -194,7 +194,6 @@ def keystone_joined(relid=None):
public_url = ('%s:%s/v1/AUTH_$(tenant_id)s' %
(canonical_url(CONFIGS, PUBLIC), port))
region = config('region')
roles = config('operator-roles')
s3_public_url = ('%s:%s' %
(canonical_url(CONFIGS, PUBLIC), port))
@ -202,7 +201,7 @@ def keystone_joined(relid=None):
(canonical_url(CONFIGS, INTERNAL), port))
s3_admin_url = '%s:%s' % (canonical_url(CONFIGS, ADMIN), port)
relation_set(requested_roles=roles, relation_id=relid,
relation_set(relation_id=relid,
region=None, public_url=None,
internal_url=None, admin_url=None, service=None,
swift_service='swift', swift_region=region,

View File

@ -14,7 +14,6 @@ from charmhelpers.core.hookenv import (
from charmhelpers.contrib.openstack.context import (
OSContextGenerator,
ApacheSSLContext as SSLContext,
context_complete,
IdentityServiceContext,
)
from charmhelpers.contrib.hahelpers.cluster import (
@ -183,8 +182,11 @@ class SwiftIdentityContext(OSContextGenerator):
'admin_domain_id', unit, relid)
ks_auth['service_tenant_id'] = relation_get(
'service_tenant_id', unit, relid)
if context_complete(ks_auth):
ctxt.update(ks_auth)
ks_auth['admin_domain_name'] = relation_get(
'service_domain', unit, relid)
ks_auth['admin_tenant_name'] = relation_get(
'service_tenant', unit, relid)
ctxt.update(ks_auth)
if config('prefer-ipv6'):
for key in ['keystone_host', 'service_host']:

View File

@ -87,9 +87,9 @@ auth_plugin = password
auth_url = {{ auth_protocol }}://{{ keystone_host }}:{{ auth_port }}
username = {{ service_user }}
password = {{ service_password }}
user_domain_name = default
project_id = {{ service_tenant_id }}
project_domain_id = {{ admin_domain_id }}
project_domain_name = {{ admin_domain_name }}
user_domain_name = {{ admin_domain_name }}
project_name = {{ admin_tenant_name }}
{% else -%}
admin_tenant_name = {{ service_tenant }}
admin_user = {{ service_user }}

View File

@ -14,6 +14,7 @@
import amulet
import swiftclient
import time
from charmhelpers.contrib.openstack.amulet.deployment import (
OpenStackAmuletDeployment
@ -275,7 +276,6 @@ class SwiftProxyBasicDeployment(OpenStackAmuletDeployment):
's3_internal_url': u.valid_url,
's3_admin_url': u.valid_url,
'private-address': u.valid_ip,
'requested_roles': 'Member,Admin',
}
ret = u.validate_relation_data(unit, relation, expected)
@ -386,9 +386,10 @@ class SwiftProxyBasicDeployment(OpenStackAmuletDeployment):
message = "swift config error: {}".format(ret)
amulet.raise_status(amulet.FAIL, msg=message)
def test_302_proxy_server_config(self):
def test_302_proxy_server_config(self, auth_api_version='2.0'):
"""Verify the data in the proxy-server config file."""
u.log.debug('Checking swift proxy-server config...')
u.log.debug("Checking swift proxy-server config auth_api_version={}..."
"".format(auth_api_version))
unit = self.swift_proxy_sentry
conf = '/etc/swift/proxy-server.conf'
keystone_relation = self.keystone_sentry.relation(
@ -453,26 +454,45 @@ class SwiftProxyBasicDeployment(OpenStackAmuletDeployment):
auth_protocol,
auth_host,
keystone_relation['service_port']),
'admin_tenant_name': keystone_relation['service_tenant'],
'admin_user': keystone_relation['service_username'],
'admin_password': keystone_relation['service_password'],
'delay_auth_decision': 'true',
'signing_dir': '/var/cache/swift',
'cache': 'swift.cache'
},
'filter:swift3': {'use': 'egg:swift3#swift3'}
}
if auth_api_version == '2.0':
expected['filter:authtoken'].update({
'admin_tenant_name': keystone_relation['service_tenant'],
'admin_user': keystone_relation['service_username'],
'admin_password': keystone_relation['service_password'],
})
if self._get_openstack_release() >= self.trusty_kilo:
# Kilo and later
expected['filter:authtoken'].update({
'paste.filter_factory': 'keystonemiddleware.auth_token:'
'filter_factory',
'identity_uri': '{}://{}:{}'.format(
auth_protocol,
auth_host,
keystone_relation['auth_port']),
})
if auth_api_version == '3':
expected['filter:authtoken'].update({
'auth_url': '{}://{}:{}'.format(
auth_protocol,
auth_host,
keystone_relation['auth_port']),
'auth_plugin': 'password',
'username': keystone_relation['service_username'],
'password': keystone_relation['service_password'],
'project_domain_name': keystone_relation['service_domain'],
'user_domain_name': keystone_relation['service_domain'],
'project_name': keystone_relation['service_tenant'],
})
else:
expected['filter:authtoken'].update({
'identity_uri': '{}://{}:{}'.format(
auth_protocol,
auth_host,
keystone_relation['auth_port']),
})
expected['filter:s3token'] = {
# No section commonality with J and earlier
'paste.filter_factory': 'keystonemiddleware.s3_token'
@ -553,6 +573,58 @@ class SwiftProxyBasicDeployment(OpenStackAmuletDeployment):
u.delete_resource(self.glance.images, img_id, msg="glance image")
u.log.info('OK')
def _set_auth_api_version(self, api_version, retry_count=5):
"""Change Keystone preferred-api-version, wait for: propagation to
relation data, update of service configuration file and restart of
services on swift-proxy unit."""
configs = {'keystone': {'preferred-api-version': api_version}}
super(SwiftProxyBasicDeployment, self)._configure_services(configs)
mtime = u.get_sentry_time(self.swift_proxy_sentry)
for i in range(retry_count, -1, -1):
ks_gl_rel = self.keystone_sentry.relation(
'identity-service', 'glance:identity-service')
ks_sw_rel = self.keystone_sentry.relation(
'identity-service', 'swift-proxy:identity-service')
if not (ks_gl_rel['api_version'] == api_version and
ks_sw_rel['api_version'] == api_version):
u.log.info("change of api_version not propagated yet "
"retries left: '%d' "
"glance:identity-service api_version: '%s' "
"swift-proxy:identity-service api_version: '%s' "
% (i,
ks_gl_rel['api_version'],
ks_sw_rel['api_version']))
u.log.info("sleeping %d seconds..." % i)
time.sleep(i)
elif not u.validate_service_config_changed(
self.swift_proxy_sentry,
mtime,
'swift-proxy-server',
'/etc/swift/proxy-server.conf',
sleep_time=i):
msg = "swift-proxy-server didn't restart after change of "\
"api_version"
amulet.raise_status(amulet.FAIL, msg=msg)
else:
return True
return False
def test_keystone_v3(self):
"""Verify that the service is configured and operates correctly when
using Keystone v3 auth."""
os_release = self._get_openstack_release_string()
if os_release < 'kilo':
u.log.info('Skipping test, {} < kilo'.format(os_release))
return
u.log.info('Checking that service is configured and operate correctly '
'when using Keystine v3 auth...')
if not self._set_auth_api_version('3'):
msg = "Unable to set auth_api_version to '3'"
amulet.raise_status(amulet.FAIL, msg=msg)
return
self.test_302_proxy_server_config(auth_api_version='3')
self.test_400_swift_backed_image_create()
def test_900_restart_on_config_change(self):
"""Verify that the specified services are restarted when the config
is changed."""

View File

@ -81,6 +81,7 @@ class SwiftIdentityContextTest(unittest.TestCase):
'auth_port': '5000',
'service_username': 'svcuser',
'service_password': 'svcpasswd',
'service_domain': 'service_domain',
'service_tenant': 'svctenant',
'service_port': 'svcport',
'admin_token': 'token',
@ -97,6 +98,8 @@ class SwiftIdentityContextTest(unittest.TestCase):
self.assertEqual(ctxt()['api_version'], '3')
self.assertEqual(ctxt()['admin_domain_id'], 'admin_dom_id')
self.assertEqual(ctxt()['service_tenant_id'], 'svc_tenant_id')
self.assertEqual(ctxt()['admin_domain_name'], 'service_domain')
self.assertEqual(ctxt()['admin_tenant_name'], 'svctenant')
class SwiftContextTestCase(unittest.TestCase):

View File

@ -106,7 +106,6 @@ class SwiftHooksTestCase(unittest.TestCase):
public_url=None,
region=None,
relation_id=None,
requested_roles='Operator,Monitor',
s3_admin_url='http://swift-proxy:1234',
s3_internal_url='http://swift-proxy:1234',
s3_public_url='http://swift-proxy:1234',
@ -163,7 +162,6 @@ class SwiftHooksTestCase(unittest.TestCase):
public_url=None,
region=None,
relation_id=None,
requested_roles='Operator,Monitor',
s3_admin_url='http://swift-proxy:1234',
s3_internal_url='http://swift-proxy:1234',
s3_public_url='http://public.example.com:1234',