diff --git a/lib/puppet/provider/keystone.rb b/lib/puppet/provider/keystone.rb index a79d2e715..e132610b2 100644 --- a/lib/puppet/provider/keystone.rb +++ b/lib/puppet/provider/keystone.rb @@ -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) diff --git a/lib/puppet/provider/keystone_user/keystone.rb b/lib/puppet/provider/keystone_user/keystone.rb index 170bbd6c5..8f37787fc 100644 --- a/lib/puppet/provider/keystone_user/keystone.rb +++ b/lib/puppet/provider/keystone_user/keystone.rb @@ -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] diff --git a/lib/puppet/type/keystone_user.rb b/lib/puppet/type/keystone_user.rb index 345a6226d..0ee46e5e4 100644 --- a/lib/puppet/type/keystone_user.rb +++ b/lib/puppet/type/keystone_user.rb @@ -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 diff --git a/spec/unit/provider/keystone_spec.rb b/spec/unit/provider/keystone_spec.rb index 790810767..2b7be430c 100644 --- a/spec/unit/provider/keystone_spec.rb +++ b/spec/unit/provider/keystone_spec.rb @@ -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'] diff --git a/spec/unit/provider/keystone_user/keystone_spec.rb b/spec/unit/provider/keystone_user/keystone_spec.rb new file mode 100644 index 000000000..f5957e9b5 --- /dev/null +++ b/spec/unit/provider/keystone_user/keystone_spec.rb @@ -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 +