Merge next branch

This commit is contained in:
Corey Bryant 2015-04-01 15:15:49 +00:00
commit 4d99449780
6 changed files with 161 additions and 42 deletions

View File

@ -78,10 +78,10 @@ options:
default: 'Admin'
type: string
description: 'Admin role to be associated with admin and service users'
token-expiry:
default: "2017-02-05T00:00"
type: string
description: "Expiration date of generated admin tokens"
token-expiration:
default: 3600
type: int
description: "Amount of time a token should remain valid (in seconds)."
service-tenant:
default: "services"
type: string

View File

@ -202,6 +202,7 @@ class KeystoneContext(context.OSContextGenerator):
ctxt['debug'] = debug and bool_from_string(debug)
verbose = config('verbose')
ctxt['verbose'] = verbose and bool_from_string(verbose)
ctxt['token_expiration'] = config('token-expiration')
ctxt['identity_backend'] = config('identity-backend')
ctxt['assignment_backend'] = config('assignment-backend')

View File

@ -472,12 +472,14 @@ def create_service_entry(service_name, service_type, service_desc, owner=None):
token=get_admin_token())
for service in [s._info for s in manager.api.services.list()]:
if service['name'] == service_name:
log("Service entry for '%s' already exists." % service_name)
log("Service entry for '%s' already exists." % service_name,
level=DEBUG)
return
manager.api.services.create(name=service_name,
service_type=service_type,
description=service_desc)
log("Created new service entry '%s'" % service_name)
log("Created new service entry '%s'" % service_name, level=DEBUG)
def create_endpoint_template(region, service, publicurl, adminurl,
@ -510,7 +512,8 @@ def create_endpoint_template(region, service, publicurl, adminurl,
publicurl=publicurl,
adminurl=adminurl,
internalurl=internalurl)
log("Created new endpoint template for '%s' in '%s'" % (region, service))
log("Created new endpoint template for '%s' in '%s'" % (region, service),
level=DEBUG)
def create_tenant(name):
@ -522,9 +525,21 @@ def create_tenant(name):
if not tenants or name not in [t['name'] for t in tenants]:
manager.api.tenants.create(tenant_name=name,
description='Created by Juju')
log("Created new tenant: %s" % name)
log("Created new tenant: %s" % name, level=DEBUG)
return
log("Tenant '%s' already exists." % name)
log("Tenant '%s' already exists." % name, level=DEBUG)
def user_exists(name):
import manager
manager = manager.KeystoneManager(endpoint=get_local_endpoint(),
token=get_admin_token())
users = [u._info for u in manager.api.users.list()]
if not users or name not in [u['name'] for u in users]:
return False
return True
def create_user(name, password, tenant):
@ -532,18 +547,20 @@ def create_user(name, password, tenant):
import manager
manager = manager.KeystoneManager(endpoint=get_local_endpoint(),
token=get_admin_token())
users = [u._info for u in manager.api.users.list()]
if not users or name not in [u['name'] for u in users]:
tenant_id = manager.resolve_tenant_id(tenant)
if not tenant_id:
error_out('Could not resolve tenant_id for tenant %s' % tenant)
manager.api.users.create(name=name,
password=password,
email='juju@localhost',
tenant_id=tenant_id)
log("Created new user '%s' tenant: %s" % (name, tenant_id))
if user_exists(name):
log("A user named '%s' already exists" % name, level=DEBUG)
return
log("A user named '%s' already exists" % name)
tenant_id = manager.resolve_tenant_id(tenant)
if not tenant_id:
error_out('Could not resolve tenant_id for tenant %s' % tenant)
manager.api.users.create(name=name,
password=password,
email='juju@localhost',
tenant_id=tenant_id)
log("Created new user '%s' tenant: %s" % (name, tenant_id),
level=DEBUG)
def create_role(name, user=None, tenant=None):
@ -554,9 +571,9 @@ def create_role(name, user=None, tenant=None):
roles = [r._info for r in manager.api.roles.list()]
if not roles or name not in [r['name'] for r in roles]:
manager.api.roles.create(name=name)
log("Created new role '%s'" % name)
log("Created new role '%s'" % name, level=DEBUG)
else:
log("A role named '%s' already exists" % name)
log("A role named '%s' already exists" % name, level=DEBUG)
if not user and not tenant:
return
@ -590,10 +607,10 @@ def grant_role(user, role, tenant):
role=role_id,
tenant=tenant_id)
log("Granted user '%s' role '%s' on tenant '%s'" %
(user, role, tenant))
(user, role, tenant), level=DEBUG)
else:
log("User '%s' already has role '%s' on tenant '%s'" %
(user, role, tenant))
(user, role, tenant), level=DEBUG)
def store_admin_passwd(passwd):
@ -663,10 +680,9 @@ def ensure_initial_admin(config):
'ldap' and config('ldap-readonly')):
passwd = get_admin_passwd()
if passwd:
create_user(config('admin-user'), passwd, tenant='admin')
update_user_password(config('admin-user'), passwd)
create_role(config('admin-role'), config('admin-user'),
'admin')
create_user_credentials(config('admin-user'), 'admin', passwd,
new_roles=[config('admin-role')])
create_service_entry("keystone", "identity",
"Keystone Identity Service")
@ -1260,6 +1276,50 @@ def relation_list(rid):
return result
def create_user_credentials(user, tenant, passwd, new_roles=None, grants=None):
"""Create user credentials.
Optionally adds role grants to user and/or creates new roles.
"""
log("Creating service credentials for '%s'" % user, level=DEBUG)
if user_exists(user):
log("User '%s' already exists - updating password" % (user),
level=DEBUG)
update_user_password(user, passwd)
else:
create_user(user, passwd, tenant)
if grants:
for role in grants:
grant_role(user, role, tenant)
else:
log("No role grants requested for user '%s'" % (user), level=DEBUG)
if new_roles:
# Allow the remote service to request creation of any additional roles.
# Currently used by Swift and Ceilometer.
for role in new_roles:
log("Creating requested role '%s'" % role, level=DEBUG)
create_role(role, user, tenant)
return passwd
def create_service_credentials(user, new_roles=None):
"""Create credentials for service with given username.
Services are given a user under config('service-tenant') and are given the
config('admin-role') role. Tenant is assumed to already exist,
"""
tenant = config('service-tenant')
if not tenant:
raise Exception("No service tenant provided in config")
return create_user_credentials(user, tenant, get_service_password(user),
new_roles=new_roles,
grants=[config('admin-role')])
def add_service_to_keystone(relation_id=None, remote_unit=None):
import manager
manager = manager.KeystoneManager(endpoint=get_local_endpoint(),
@ -1390,18 +1450,9 @@ def add_service_to_keystone(relation_id=None, remote_unit=None):
return
token = get_admin_token()
log("Creating service credentials for '%s'" % service_username)
service_password = get_service_password(service_username)
create_user(service_username, service_password, config('service-tenant'))
grant_role(service_username, config('admin-role'),
config('service-tenant'))
# Allow the remote service to request creation of any additional roles.
# Currently used by Swift and Ceilometer.
for role in get_requested_roles(settings):
log("Creating requested role: %s" % role)
create_role(role, service_username, config('service-tenant'))
roles = get_requested_roles(settings)
service_password = create_service_credentials(service_username,
new_roles=roles)
# As of https://review.openstack.org/#change,4675, all nodes hosting
# an endpoint(s) needs a service username and password assigned to

View File

@ -49,7 +49,8 @@ provider = keystone.token.providers.pki.Provider
provider = keystone.token.providers.pkiz.Provider
{% else -%}
provider = keystone.token.providers.uuid.Provider
{% endif %}
{% endif -%}
expiration = {{ token_expiration }}
{% include "parts/section-signing" %}

View File

@ -45,7 +45,16 @@ driver = keystone.catalog.backends.sql.Catalog
[token]
driver = keystone.token.persistence.backends.sql.Token
{% if token_provider == 'pki' -%}
provider = keystone.token.providers.pki.Provider
{% elif token_provider == 'pkiz' -%}
provider = keystone.token.providers.pkiz.Provider
{% else -%}
provider = keystone.token.providers.uuid.Provider
{% endif -%}
expiration = {{ token_expiration }}
{% include "parts/section-signing" %}
[cache]

View File

@ -303,6 +303,63 @@ class TestKeystoneUtils(CharmTestCase):
adminurl='10.0.0.2',
internalurl='192.168.1.2')
@patch.object(utils, 'user_exists')
@patch.object(utils, 'grant_role')
@patch.object(utils, 'create_role')
@patch.object(utils, 'create_user')
def test_create_user_credentials_no_roles(self, mock_create_user,
mock_create_role,
mock_grant_role,
mock_user_exists):
mock_user_exists.return_value = False
utils.create_user_credentials('userA', 'tenantA', 'passA')
mock_create_user.assert_has_calls([call('userA', 'passA', 'tenantA')])
mock_create_role.assert_has_calls([])
mock_grant_role.assert_has_calls([])
@patch.object(utils, 'user_exists')
@patch.object(utils, 'grant_role')
@patch.object(utils, 'create_role')
@patch.object(utils, 'create_user')
def test_create_user_credentials(self, mock_create_user, mock_create_role,
mock_grant_role, mock_user_exists):
mock_user_exists.return_value = False
utils.create_user_credentials('userA', 'tenantA', 'passA',
grants=['roleA'], new_roles=['roleB'])
mock_create_user.assert_has_calls([call('userA', 'passA', 'tenantA')])
mock_create_role.assert_has_calls([call('roleB', 'userA', 'tenantA')])
mock_grant_role.assert_has_calls([call('userA', 'roleA', 'tenantA')])
@patch.object(utils, 'update_user_password')
@patch.object(utils, 'user_exists')
@patch.object(utils, 'grant_role')
@patch.object(utils, 'create_role')
@patch.object(utils, 'create_user')
def test_create_user_credentials_user_exists(self, mock_create_user,
mock_create_role,
mock_grant_role,
mock_user_exists,
mock_update_user_password):
mock_user_exists.return_value = True
utils.create_user_credentials('userA', 'tenantA', 'passA',
grants=['roleA'], new_roles=['roleB'])
mock_create_user.assert_has_calls([])
mock_create_role.assert_has_calls([call('roleB', 'userA', 'tenantA')])
mock_grant_role.assert_has_calls([call('userA', 'roleA', 'tenantA')])
mock_update_user_password.assert_has_calls([call('userA', 'passA')])
@patch.object(utils, 'get_service_password')
@patch.object(utils, 'create_user_credentials')
def test_create_service_credentials(self, mock_create_user_credentials,
mock_get_service_password):
mock_get_service_password.return_value = 'passA'
cfg = {'service-tenant': 'tenantA', 'admin-role': 'Admin'}
self.config.side_effect = lambda key: cfg.get(key, None)
calls = [call('serviceA', 'tenantA', 'passA', grants=['Admin'],
new_roles=None)]
utils.create_service_credentials('serviceA')
mock_create_user_credentials.assert_has_calls(calls)
def test_ensure_valid_service_incorrect(self):
utils.ensure_valid_service('fakeservice')
self.log.assert_called_with("Invalid service requested: 'fakeservice'")