[gnuoy, r=hopem]

Set admin password in identity-admin relation regardless of how it was generated
This commit is contained in:
Liam Young 2015-01-16 11:41:03 +00:00
commit c1d1565048
4 changed files with 95 additions and 33 deletions

View File

@ -45,6 +45,7 @@ from keystone_utils import (
determine_packages, determine_packages,
do_openstack_upgrade, do_openstack_upgrade,
ensure_initial_admin, ensure_initial_admin,
get_admin_passwd,
migrate_database, migrate_database,
save_script_rc, save_script_rc,
synchronize_ca, synchronize_ca,
@ -55,7 +56,6 @@ from keystone_utils import (
CLUSTER_RES, CLUSTER_RES,
KEYSTONE_CONF, KEYSTONE_CONF,
SSH_USER, SSH_USER,
STORED_PASSWD,
setup_ipv6, setup_ipv6,
send_notifications, send_notifications,
) )
@ -71,12 +71,16 @@ from charmhelpers.contrib.peerstorage import (
peer_retrieve_by_prefix, peer_retrieve_by_prefix,
peer_echo, peer_echo,
) )
from charmhelpers.contrib.openstack.ip import (
ADMIN,
resolve_address,
)
from charmhelpers.contrib.network.ip import ( from charmhelpers.contrib.network.ip import (
get_iface_for_address, get_iface_for_address,
get_netmask_for_address, get_netmask_for_address,
get_address_in_network, get_address_in_network,
get_ipv6_addr, get_ipv6_addr,
is_ipv6 is_ipv6,
) )
from charmhelpers.contrib.openstack.context import ADDRESS_TYPES from charmhelpers.contrib.openstack.context import ADDRESS_TYPES
@ -127,7 +131,10 @@ def config_changed():
identity_changed(relation_id=r_id, identity_changed(relation_id=r_id,
remote_unit=unit) remote_unit=unit)
[cluster_joined(rid) for rid in relation_ids('cluster')] for rid in relation_ids('identity-admin'):
admin_relation_changed(rid)
for rid in relation_ids('cluster'):
cluster_joined(rid)
@hooks.hook('shared-db-relation-joined') @hooks.hook('shared-db-relation-joined')
@ -172,7 +179,6 @@ def db_changed():
# units acl entry has been added. So, if the db supports passing # units acl entry has been added. So, if the db supports passing
# a list of permitted units then check if we're in the list. # a list of permitted units then check if we're in the list.
allowed_units = relation_get('allowed_units') allowed_units = relation_get('allowed_units')
print "allowed_units:" + str(allowed_units)
if allowed_units and local_unit() not in allowed_units.split(): if allowed_units and local_unit() not in allowed_units.split():
log('Allowed_units list provided and this unit not present') log('Allowed_units list provided and this unit not present')
return return
@ -273,6 +279,8 @@ def cluster_changed():
for unit in relation_list(r_id): for unit in relation_list(r_id):
identity_changed(relation_id=r_id, identity_changed(relation_id=r_id,
remote_unit=unit) remote_unit=unit)
for rid in relation_ids('identity-admin'):
admin_relation_changed(rid)
@hooks.hook('ha-relation-joined') @hooks.hook('ha-relation-joined')
@ -344,19 +352,17 @@ def ha_changed():
@hooks.hook('identity-admin-relation-changed') @hooks.hook('identity-admin-relation-changed')
def admin_relation_changed(): def admin_relation_changed(relation_id=None):
# TODO: fixup # TODO: fixup
relation_data = { relation_data = {
'service_hostname': unit_get('private-address'), 'service_hostname': resolve_address(ADMIN),
'service_port': config('service-port'), 'service_port': config('service-port'),
'service_username': config('admin-user'), 'service_username': config('admin-user'),
'service_tenant_name': config('admin-role'), 'service_tenant_name': config('admin-role'),
'service_region': config('region'), 'service_region': config('region'),
} }
if os.path.isfile(STORED_PASSWD): relation_data['service_password'] = get_admin_passwd()
with open(STORED_PASSWD) as f: relation_set(relation_id=relation_id, **relation_data)
relation_data['service_password'] = f.readline().strip('\n')
relation_set(**relation_data)
def configure_https(): def configure_https():

View File

@ -41,6 +41,7 @@ import charmhelpers.contrib.unison as unison
from charmhelpers.core.hookenv import ( from charmhelpers.core.hookenv import (
config, config,
is_relation_made,
log, log,
local_unit, local_unit,
relation_get, relation_get,
@ -484,6 +485,42 @@ def grant_role(user, role, tenant):
(user, role, tenant)) (user, role, tenant))
def store_admin_passwd(passwd):
with open(STORED_PASSWD, 'w+') as fd:
fd.writelines("%s\n" % passwd)
def get_admin_passwd():
passwd = config("admin-password")
if passwd and passwd.lower() != "none":
return passwd
if eligible_leader(CLUSTER_RES):
if os.path.isfile(STORED_PASSWD):
log("Loading stored passwd from %s" % STORED_PASSWD, level=INFO)
with open(STORED_PASSWD, 'r') as fd:
passwd = fd.readline().strip('\n')
if not passwd:
log("Generating new passwd for user: %s" %
config("admin-user"))
cmd = ['pwgen', '-c', '16', '1']
passwd = str(subprocess.check_output(cmd)).strip()
store_admin_passwd(passwd)
if is_relation_made("cluster"):
peer_store("admin_passwd", passwd)
return passwd
if is_relation_made("cluster"):
passwd = peer_retrieve('admin_passwd')
if passwd:
store_admin_passwd(passwd)
return passwd
def ensure_initial_admin(config): def ensure_initial_admin(config):
""" Ensures the minimum admin stuff exists in whatever database we're """ Ensures the minimum admin stuff exists in whatever database we're
using. using.
@ -496,21 +533,10 @@ def ensure_initial_admin(config):
""" """
create_tenant("admin") create_tenant("admin")
create_tenant(config("service-tenant")) create_tenant(config("service-tenant"))
passwd = ""
if config("admin-password") != "None":
passwd = config("admin-password")
elif os.path.isfile(STORED_PASSWD):
log("Loading stored passwd from %s" % STORED_PASSWD)
passwd = open(STORED_PASSWD, 'r').readline().strip('\n')
if passwd == "":
log("Generating new passwd for user: %s" %
config("admin-user"))
cmd = ['pwgen', '-c', '16', '1']
passwd = str(subprocess.check_output(cmd)).strip()
open(STORED_PASSWD, 'w+').writelines("%s\n" % passwd)
# User is managed by ldap backend when using ldap identity # User is managed by ldap backend when using ldap identity
if not (config('identity-backend') == 'ldap' and config('ldap-readonly')): if not (config('identity-backend') == 'ldap' and config('ldap-readonly')):
passwd = get_admin_passwd()
if passwd:
create_user(config('admin-user'), passwd, tenant='admin') create_user(config('admin-user'), passwd, tenant='admin')
update_user_password(config('admin-user'), passwd) update_user_password(config('admin-user'), passwd)
create_role(config('admin-role'), config('admin-user'), 'admin') create_role(config('admin-role'), config('admin-user'), 'admin')

View File

@ -235,6 +235,7 @@ class KeystoneRelationTests(CharmTestCase):
relation_id='identity-service:0', relation_id='identity-service:0',
remote_unit='unit/0') remote_unit='unit/0')
@patch.object(hooks, 'admin_relation_changed')
@patch.object(hooks, 'cluster_joined') @patch.object(hooks, 'cluster_joined')
@patch.object(unison, 'ensure_user') @patch.object(unison, 'ensure_user')
@patch.object(unison, 'get_homedir') @patch.object(unison, 'get_homedir')
@ -243,10 +244,11 @@ class KeystoneRelationTests(CharmTestCase):
@patch.object(hooks, 'configure_https') @patch.object(hooks, 'configure_https')
def test_config_changed_no_openstack_upgrade_leader( def test_config_changed_no_openstack_upgrade_leader(
self, configure_https, identity_changed, self, configure_https, identity_changed,
configs, get_homedir, ensure_user, cluster_joined): configs, get_homedir, ensure_user, cluster_joined,
admin_relation_changed):
self.openstack_upgrade_available.return_value = False self.openstack_upgrade_available.return_value = False
self.eligible_leader.return_value = True self.eligible_leader.return_value = True
self.relation_ids.return_value = ['identity-service:0'] self.relation_ids.return_value = ['dummyid:0']
self.relation_list.return_value = ['unit/0'] self.relation_list.return_value = ['unit/0']
hooks.config_changed() hooks.config_changed()
@ -262,8 +264,9 @@ class KeystoneRelationTests(CharmTestCase):
self.log.assert_called_with( self.log.assert_called_with(
'Firing identity_changed hook for all related services.') 'Firing identity_changed hook for all related services.')
identity_changed.assert_called_with( identity_changed.assert_called_with(
relation_id='identity-service:0', relation_id='dummyid:0',
remote_unit='unit/0') remote_unit='unit/0')
admin_relation_changed.assert_called_with('dummyid:0')
@patch.object(hooks, 'cluster_joined') @patch.object(hooks, 'cluster_joined')
@patch.object(unison, 'ensure_user') @patch.object(unison, 'ensure_user')
@ -289,6 +292,7 @@ class KeystoneRelationTests(CharmTestCase):
self.assertFalse(self.ensure_initial_admin.called) self.assertFalse(self.ensure_initial_admin.called)
self.assertFalse(identity_changed.called) self.assertFalse(identity_changed.called)
@patch.object(hooks, 'admin_relation_changed')
@patch.object(hooks, 'cluster_joined') @patch.object(hooks, 'cluster_joined')
@patch.object(unison, 'ensure_user') @patch.object(unison, 'ensure_user')
@patch.object(unison, 'get_homedir') @patch.object(unison, 'get_homedir')
@ -297,10 +301,11 @@ class KeystoneRelationTests(CharmTestCase):
@patch.object(hooks, 'configure_https') @patch.object(hooks, 'configure_https')
def test_config_changed_with_openstack_upgrade( def test_config_changed_with_openstack_upgrade(
self, configure_https, identity_changed, self, configure_https, identity_changed,
configs, get_homedir, ensure_user, cluster_joined): configs, get_homedir, ensure_user, cluster_joined,
admin_relation_changed):
self.openstack_upgrade_available.return_value = True self.openstack_upgrade_available.return_value = True
self.eligible_leader.return_value = True self.eligible_leader.return_value = True
self.relation_ids.return_value = ['identity-service:0'] self.relation_ids.return_value = ['dummyid:0']
self.relation_list.return_value = ['unit/0'] self.relation_list.return_value = ['unit/0']
hooks.config_changed() hooks.config_changed()
@ -318,8 +323,9 @@ class KeystoneRelationTests(CharmTestCase):
self.log.assert_called_with( self.log.assert_called_with(
'Firing identity_changed hook for all related services.') 'Firing identity_changed hook for all related services.')
identity_changed.assert_called_with( identity_changed.assert_called_with(
relation_id='identity-service:0', relation_id='dummyid:0',
remote_unit='unit/0') remote_unit='unit/0')
admin_relation_changed.assert_called_with('dummyid:0')
@patch.object(hooks, 'hashlib') @patch.object(hooks, 'hashlib')
@patch.object(hooks, 'send_notifications') @patch.object(hooks, 'send_notifications')

View File

@ -1,4 +1,4 @@
from mock import patch, call, MagicMock from mock import patch, call, MagicMock, Mock
from test_utils import CharmTestCase from test_utils import CharmTestCase
import os import os
import manager import manager
@ -35,6 +35,8 @@ TO_PATCH = [
'relation_get', 'relation_get',
'relation_set', 'relation_set',
'https', 'https',
'is_relation_made',
'peer_store',
# generic # generic
'apt_update', 'apt_update',
'apt_upgrade', 'apt_upgrade',
@ -323,3 +325,25 @@ class TestKeystoneUtils(CharmTestCase):
settings['trigger'] = '1234' settings['trigger'] = '1234'
mock_relation_set.assert_called_once_with(relation_id=relation_id, mock_relation_set.assert_called_once_with(relation_id=relation_id,
relation_settings=settings) relation_settings=settings)
def test_get_admin_passwd_pwd_set(self):
self.test_config.set('admin-password', 'supersecret')
self.assertEqual(utils.get_admin_passwd(), 'supersecret')
@patch('os.path.isfile')
def test_get_admin_passwd_pwd_file_load(self, isfile):
self.test_config.set('admin-password', '')
isfile.return_value = True
with patch('__builtin__.open') as mock_open:
mock_open.return_value.__enter__ = lambda s: s
mock_open.return_value.__exit__ = Mock()
mock_open.return_value.readline.return_value = 'supersecretfilepwd'
self.assertEqual(utils.get_admin_passwd(), 'supersecretfilepwd')
@patch.object(utils, 'store_admin_passwd')
@patch('os.path.isfile')
def test_get_admin_passwd_genpass(self, isfile, store_admin_passwd):
self.test_config.set('admin-password', '')
isfile.return_value = False
self.subprocess.check_output.return_value = 'supersecretgen'
self.assertEqual(utils.get_admin_passwd(), 'supersecretgen')