Manage updates to keystone user password with keystone_user
Fix bug 1170380 o Test if the current password works and if not reset it allowing users to reset passwords with puppet o Also move admin token from command line of keystone command in favour of using a env variable o Note : this will break folsom support Change-Id: I4bae9cad767cdd141ae76343298f7ac43c2a1f90
This commit is contained in:
@@ -53,13 +53,33 @@ class Puppet::Provider::Keystone < Puppet::Provider
|
||||
@keystone_file = nil
|
||||
end
|
||||
|
||||
# the path to withenv changes between versions of puppet, so redefining this function here,
|
||||
# Run some code with a specific environment. Resets the environment at the end of the code.
|
||||
def self.withenv(hash, &block)
|
||||
saved = ENV.to_hash
|
||||
hash.each do |name, val|
|
||||
ENV[name.to_s] = val
|
||||
end
|
||||
block.call
|
||||
ensure
|
||||
ENV.clear
|
||||
saved.each do |name, val|
|
||||
ENV[name] = val
|
||||
end
|
||||
end
|
||||
|
||||
def self.auth_keystone(*args)
|
||||
authenv = {:OS_SERVICE_TOKEN => admin_token}
|
||||
begin
|
||||
remove_warnings(keystone('--token', admin_token, '--endpoint', admin_endpoint, args))
|
||||
withenv authenv do
|
||||
remove_warnings(keystone('--endpoint', admin_endpoint, args))
|
||||
end
|
||||
rescue Exception => e
|
||||
if (e.message =~ /\[Errno 111\] Connection refused/) or (e.message =~ /\(HTTP 400\)/)
|
||||
sleep 10
|
||||
remove_warnings(keystone('--token', admin_token, '--endpoint', admin_endpoint, args))
|
||||
sleep 10
|
||||
withenv authenv do
|
||||
remove_warnings(keystone('--endpoint', admin_endpoint, args))
|
||||
end
|
||||
else
|
||||
raise(e)
|
||||
end
|
||||
@@ -70,6 +90,29 @@ class Puppet::Provider::Keystone < Puppet::Provider
|
||||
self.class.auth_keystone(args)
|
||||
end
|
||||
|
||||
def self.creds_keystone(name, tenant, password, *args)
|
||||
authenv = {:OS_USERNAME => name, :OS_TENANT_NAME => tenant, :OS_PASSWORD => password}
|
||||
begin
|
||||
withenv authenv do
|
||||
remove_warnings(keystone('--os-auth-url', admin_endpoint, args))
|
||||
end
|
||||
rescue Exception => e
|
||||
if (e.message =~ /\[Errno 111\] Connection refused/) or (e.message =~ /\(HTTP 400\)/)
|
||||
sleep 10
|
||||
withenv authenv do
|
||||
remove_warnings(keystone('--os-auth-url', admin_endpoint, args))
|
||||
end
|
||||
else
|
||||
raise(e)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def creds_keystone(name, tenant, password, *args)
|
||||
self.class.creds_keystone(name, tenant, password, args)
|
||||
end
|
||||
|
||||
|
||||
private
|
||||
|
||||
def self.list_keystone_objects(type, number_columns, *args)
|
||||
|
||||
@@ -80,20 +80,23 @@ Puppet::Type.type(:keystone_user).provide(
|
||||
)
|
||||
end
|
||||
|
||||
# def password
|
||||
# Puppet.warning("Cannot retrieve password")
|
||||
# user_hash[resource[:name]][:password]
|
||||
# end
|
||||
#
|
||||
# def password=(value)
|
||||
# Puppet.warning('Cannot update password')
|
||||
# # user-password-update does not support the ability know what the
|
||||
# # current value is
|
||||
# #auth_keystone(
|
||||
# # 'user-password-update',
|
||||
# # '--pass', value,
|
||||
# # user_hash[resource[:name]][:id]
|
||||
# end
|
||||
def password
|
||||
# if we don't know a password we can't test it
|
||||
return nil if resource[:password] == nil
|
||||
# we can't get the value of the password but we can test to see if the one we know
|
||||
# about works, if it doesn't then return nil, causing it to be reset
|
||||
begin
|
||||
token_out = creds_keystone(resource[:name], resource[:tenant], resource[:password], "token-get")
|
||||
rescue Exception => e
|
||||
return nil if e.message =~ /Not Authorized/
|
||||
raise e
|
||||
end
|
||||
return resource[:password]
|
||||
end
|
||||
|
||||
def password=(value)
|
||||
auth_keystone('user-password-update', '--pass', value, user_hash[resource[:name]][:id])
|
||||
end
|
||||
|
||||
def tenant
|
||||
user_hash[resource[:name]][:tenant]
|
||||
|
||||
@@ -24,8 +24,23 @@ Puppet::Type.newtype(:keystone_user) do
|
||||
end
|
||||
end
|
||||
|
||||
newparam(:password) do
|
||||
newproperty(:password) do
|
||||
newvalues(/\S+/)
|
||||
def change_to_s(currentvalue, newvalue)
|
||||
if currentvalue == :absent
|
||||
return "created password"
|
||||
else
|
||||
return "changed password"
|
||||
end
|
||||
end
|
||||
|
||||
def is_to_s( currentvalue )
|
||||
return '[old password redacted]'
|
||||
end
|
||||
|
||||
def should_to_s( newvalue )
|
||||
return '[new password redacted]'
|
||||
end
|
||||
end
|
||||
|
||||
newproperty(:tenant) do
|
||||
|
||||
@@ -81,7 +81,7 @@ describe Puppet::Provider::Keystone do
|
||||
Puppet::Util::IniConfig::File.expects(:new).returns(mock)
|
||||
mock.expects(:read).with('/etc/keystone/keystone.conf')
|
||||
klass.expects(:sleep).with(10).returns(nil)
|
||||
klass.expects(:keystone).twice.with('--token', 'foo', '--endpoint', 'http://127.0.0.1:35357/v2.0/', ['test_retries']).raises(Exception, valid_message).then.returns('')
|
||||
klass.expects(:keystone).twice.with('--endpoint', 'http://127.0.0.1:35357/v2.0/', ['test_retries']).raises(Exception, valid_message).then.returns('')
|
||||
klass.auth_keystone('test_retries')
|
||||
end
|
||||
end
|
||||
@@ -97,8 +97,6 @@ describe Puppet::Provider::Keystone do
|
||||
klass.expects(
|
||||
:keystone
|
||||
).with(
|
||||
'--token',
|
||||
'foo',
|
||||
'--endpoint',
|
||||
'http://127.0.0.1:35357/v2.0/',
|
||||
['test_retries']
|
||||
|
||||
44
spec/unit/provider/keystone_user/keystone_spec.rb
Normal file
44
spec/unit/provider/keystone_user/keystone_spec.rb
Normal file
@@ -0,0 +1,44 @@
|
||||
require 'puppet'
|
||||
require 'spec_helper'
|
||||
require 'puppet/provider/keystone_user/keystone'
|
||||
|
||||
provider_class = Puppet::Type.type(:keystone_user).provider(:keystone)
|
||||
|
||||
describe provider_class do
|
||||
|
||||
describe 'when updating a user' do
|
||||
let :resource do
|
||||
Puppet::Type::Keystone_user.new(
|
||||
{
|
||||
:name => 'foo',
|
||||
:ensure => 'present',
|
||||
:enabled => 'True',
|
||||
:tenant => 'foo2',
|
||||
:email => 'foo@foo.com',
|
||||
:password => 'passwd'
|
||||
}
|
||||
)
|
||||
end
|
||||
|
||||
let :provider do
|
||||
provider_class.new(resource)
|
||||
end
|
||||
|
||||
before :each do
|
||||
provider_class.expects(:build_user_hash).returns(
|
||||
'foo' => {:id => 'id', :name => 'foo', :tenant => 'foo2', :password => 'passwd'}
|
||||
)
|
||||
end
|
||||
|
||||
after :each do
|
||||
# reset global state
|
||||
provider_class.prefetch(nil)
|
||||
end
|
||||
|
||||
it 'should call user-password-update to change password' do
|
||||
provider.expects(:auth_keystone).with('user-password-update', '--pass', 'newpassword', 'id')
|
||||
provider.password=('newpassword')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user