Replace Puppet::Util::withenv with custom version

... that filters out OS_* environment variables
from the existing copied ENV and then set the
passed environment variables to ENV and yield
to the openstack CLI call.

This has been a problem for a very long this
where if you source OS_* environment in your
shell and try to run Puppet the openstack CLI
calls executed by the Puppet modules will
pick up these environment variables causing
side effects such as `openstack token issue`
commands failing to test password for keystone_user
resources causing a `openstack uset set` command
even though the password has not changed.

Conflicts:
	spec/unit/provider/openstack_spec.rb

Change-Id: Ic4f9d7f7e8faf5ba5caaade49f10789aa8dba864
Signed-off-by: Tobias Urdin <tobias.urdin@binero.com>
(cherry picked from commit 864f02dda6)
(cherry picked from commit 2e85937d75)
(cherry picked from commit 12557ed183)
This commit is contained in:
Tobias Urdin
2025-11-06 16:53:24 +01:00
committed by Takashi Kajinami
parent 0b584c8a46
commit 98e64c6dad
3 changed files with 66 additions and 2 deletions

View File

@@ -78,6 +78,23 @@ class Puppet::Provider::Openstack < Puppet::Provider
rc
end
# Copy of Puppet::Util::withenv but that filters out
# env variables starting with OS_ from the existing
# environment.
#
# @param hash [Hash] Hash of environment variables
def self.os_withenv(hash)
saved = ENV.to_hash
begin
cleaned_env = ENV.to_hash.reject { |k, _| k.start_with?('OS_') }
ENV.replace(cleaned_env)
ENV.merge!(hash.transform_keys(&:to_s))
yield
ensure
ENV.replace(saved)
end
end
# Returns an array of hashes, where the keys are the downcased CSV headers
# with underscores instead of spaces
#
@@ -87,7 +104,7 @@ class Puppet::Provider::Openstack < Puppet::Provider
env = credentials ? credentials.to_env : {}
no_retry = options[:no_retry_exception_msgs]
Puppet::Util.withenv(env) do
os_withenv(env) do
rv = nil
end_time = current_time + request_timeout
start_time = current_time

View File

@@ -0,0 +1,6 @@
---
fixes:
- |
The ``Puppet::Provider::Openstack.request`` now filters out all external
``OS_*`` environment variables to prevent collisions with environment
variables in the shell where Puppet is running.

View File

@@ -80,7 +80,7 @@ name="test"
end
it 'uses provided credentials' do
expect(Puppet::Util).to receive(:withenv).with(credentials.to_env)
expect(provider.class).to receive(:os_withenv).with(credentials.to_env)
Puppet::Provider::Openstack.request('project', 'list', ['--long'], credentials)
end
@@ -210,4 +210,45 @@ name="test"
end
end
end
describe '#os_withenv' do
around do |example|
@original_env = ENV.to_hash
example.run
ENV.replace(@original_env)
end
it 'removes environment variables starting with OS_' do
ENV['OS_FOO'] = 'should be removed'
ENV['OTHER'] = 'should stay'
Puppet::Provider::Openstack.os_withenv({}) do
expect(ENV.key?('OS_FOO')).to be false
expect(ENV['OTHER']).to eq('should stay')
end
end
it 'merges the given environment variables' do
Puppet::Provider::Openstack.os_withenv({'MY_VAR' => '123'}) do
expect(ENV['MY_VAR']).to eq('123')
end
end
it 'restores the original environment after the block' do
original = ENV.to_hash
Puppet::Provider::Openstack.os_withenv({'TEMP_VAR' => 'test'}) do
ENV['INSIDE_BLOCK'] = 'yep'
end
expect(ENV.key?('TEMP_VAR')).to be false
expect(ENV.key?('INSIDE_BLOCK')).to be false
expect(ENV.to_hash).to eq(original)
end
it 'handles string and symbol keys in the input hash' do
Puppet::Provider::Openstack.os_withenv({:FOO => 'bar'}) do
expect(ENV['FOO']).to eq('bar')
end
end
end
end