Skip to content

Commit 552f127

Browse files
committed
(PUP-10942) Don't leak environment state when creating a new instance
If an enviroment was expired and a new instance of the environment created, it was possible for the new instance to see the cached modulepath from the old instance. This only could happen if the old environment was created via the `Cached#list` or `Cached#get_conf` method, but not `Cached#get`. The reason is in the `get` case the entry is cached, so settings are correctly cleared when the environment is removed from the cache. It also makes `list` and `get` behave consistently with respect to expired environments.
1 parent b9ea3c5 commit 552f127

File tree

3 files changed

+69
-2
lines changed

3 files changed

+69
-2
lines changed

lib/puppet/environments.rb

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,10 @@ def get_conf(name)
225225
private
226226

227227
def create_environment(name)
228+
# interpolated modulepaths may be cached from prior environment
229+
# instances, eg prior to a code deploy
230+
Puppet.settings.clear_environment_settings(name)
231+
228232
env_symbol = name.intern
229233
setting_values = Puppet.settings.values(env_symbol, Puppet.settings.preferred_run_mode)
230234
env = Puppet::Node::Environment.create(
@@ -350,6 +354,9 @@ def initialize(loader)
350354

351355
# @!macro loader_list
352356
def list
357+
# Evict all that have expired, in the same way as `get`
358+
clear_all_expired
359+
353360
@loader.list
354361
end
355362

lib/puppet/settings/environment_conf.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ def self.load_from(path_to_env, global_module_path)
2929
section = config.sections[:main]
3030
rescue Errno::ENOENT
3131
# environment.conf is an optional file
32+
Puppet.debug { "Path to #{path_to_env} does not exist, using default environment.conf" }
3233
end
3334

3435
new(path_to_env, section, global_module_path)

spec/unit/environments_spec.rb

Lines changed: 61 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
module PuppetEnvironments
88
describe Puppet::Environments do
99
include Matchers::Include
10+
include PuppetSpec::Files
1011

1112
FS = Puppet::FileSystem
1213

@@ -436,6 +437,56 @@ module PuppetEnvironments
436437
end
437438
end
438439
end
440+
441+
it "'get' should see module directories added after 'list', but before 'clear_all'" do
442+
base_dir = tmpdir("environments")
443+
envdir = File.join(base_dir, "a_race")
444+
Puppet::FileSystem.mkpath(envdir)
445+
446+
default_dir = File.join(envdir, "modules")
447+
site_dir = File.join(envdir, "site")
448+
449+
loader = Puppet::Environments::Cached.new(Puppet::Environments::Directories.new(base_dir, []))
450+
Puppet.override(:environments => loader) do
451+
loader.list
452+
453+
expect(Puppet.settings.value(:modulepath, :a_race)).to eq(default_dir)
454+
455+
File.write(File.join(envdir, "environment.conf"), <<-END)
456+
modulepath=site#{File::PATH_SEPARATOR}$basemodulepath
457+
environment_timeout=unlimited
458+
END
459+
Puppet::FileSystem.mkpath(site_dir)
460+
loader.clear_all
461+
462+
expect(loader.get(:a_race).modulepath.first).to eq(site_dir)
463+
end
464+
end
465+
466+
it "'get' should see module directories added after 'get_conf', but before 'clear_all'" do
467+
base_dir = tmpdir("environments")
468+
envdir = File.join(base_dir, "a_race")
469+
Puppet::FileSystem.mkpath(envdir)
470+
471+
default_dir = File.join(envdir, "modules")
472+
site_dir = File.join(envdir, "site")
473+
474+
loader = Puppet::Environments::Cached.new(Puppet::Environments::Directories.new(base_dir, []))
475+
Puppet.override(:environments => loader) do
476+
loader.get_conf(:a_race).modulepath
477+
478+
expect(Puppet.settings.value(:modulepath, :a_race)).to eq(default_dir)
479+
480+
File.write(File.join(envdir, "environment.conf"), <<-END)
481+
modulepath=site#{File::PATH_SEPARATOR}$basemodulepath
482+
environment_timeout=unlimited
483+
END
484+
Puppet::FileSystem.mkpath(site_dir)
485+
loader.clear_all
486+
487+
expect(loader.get(:a_race).modulepath.first).to eq(site_dir)
488+
end
489+
end
439490
end
440491
end
441492

@@ -647,8 +698,6 @@ module PuppetEnvironments
647698
end
648699

649700
it "evicts an expired environment" do
650-
service = ReplayExpirationService.new
651-
652701
expect(service).to receive(:expired?).and_return(true)
653702

654703
with_environment_loaded(service) do |cached|
@@ -703,6 +752,16 @@ module PuppetEnvironments
703752
expect(service.created_envs).to eq([:an_environment, :an_environment])
704753
expect(service.evicted_envs).to eq([:an_environment])
705754
end
755+
756+
it "evicts expired environments when listing" do
757+
expect(service).to receive(:expired?).with(:an_environment).and_return(true)
758+
759+
with_environment_loaded(service) do |cached|
760+
cached.list
761+
end
762+
763+
expect(service.evicted_envs).to eq([:an_environment])
764+
end
706765
end
707766

708767
it "gets an environment.conf" do

0 commit comments

Comments
 (0)