Skip to content

Commit f2866d1

Browse files
committed
(maint) Compare Environment#name in compiler
During catalog compilation, after loading the requested environment we load the node and server specified environment. Previously, We would then compare the Environment objects to determine if the requested environment matched the server specified environment. However, if the environment cache is flushed between those two environments being loaded they could be different object instances representing the same desired environment. Environment objects define a `==` method but require the name and modulepath to be the same. If we are running with versioned environment dirs those modulepaths may be different (ie different versions of the same environment). To resolve this race condition we now check the environment names (Environment#name canoncalizes to symbols to avoid symbol/string mismatch). The catalog already uses the server specified environment which, if we are running with versioned environment dirs and have different versions of the same environment, will be the most up to date version of the environment.
1 parent 4d7ebae commit f2866d1

File tree

2 files changed

+29
-4
lines changed

2 files changed

+29
-4
lines changed

lib/puppet/indirector/catalog/compiler.rb

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -53,12 +53,20 @@ def find(request)
5353
node.trusted_data = Puppet.lookup(:trusted_information) { Puppet::Context::TrustedInformation.local(node) }.to_h
5454

5555
if node.environment
56-
# If the requested environment doesn't match the server specified environment,
57-
# as determined by the node terminus, and the request wants us to check for an
56+
# If the requested environment name doesn't match the server specified environment
57+
# name, as determined by the node terminus, and the request wants us to check for an
5858
# environment mismatch, then return an empty catalog with the server-specified
5959
# enviroment.
60-
if request.remote? && request.options[:check_environment] && node.environment != request.environment
61-
return Puppet::Resource::Catalog.new(node.name, node.environment)
60+
if request.remote? && request.options[:check_environment]
61+
# The "environment" may be same while environment objects differ. This
62+
# is most likely because the environment cache was flushed between the request
63+
# processing and node lookup. Environment overrides `==` but requires the
64+
# name and modulepath to be the same. When using versioned environment dirs the
65+
# same "environment" can have different modulepaths so simply compare names here.
66+
if node.environment.name != request.environment.name
67+
Puppet.warning _("Requested environment '%{request_env}' did not match server specified environment '%{server_env}'") % {request_env: request.environment.name, server_env: node.environment.name}
68+
return Puppet::Resource::Catalog.new(node.name, node.environment)
69+
end
6270
end
6371

6472
node.environment.with_text_domain do

spec/unit/indirector/catalog/compiler_spec.rb

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -271,6 +271,23 @@ def set_facts(fact_hash)
271271
expect(catalog).to have_resource('Stage[main]')
272272
end
273273

274+
# versioned environment directories can cause this
275+
it 'allows environments with the same name but mismatched modulepaths' do
276+
envs = Puppet.lookup(:environments)
277+
env_server = envs.get!(:env_server)
278+
v1_env = env_server.override_with({ modulepath: ['/code-v1/env-v1/'] })
279+
v2_env = env_server.override_with({ modulepath: ['/code-v2/env-v2/'] })
280+
281+
@request.options[:check_environment] = "true"
282+
@request.environment = v1_env
283+
node.environment = v2_env
284+
285+
catalog = compiler.find(@request)
286+
287+
expect(catalog.environment).to eq('env_server')
288+
expect(catalog).to have_resource('Stage[main]')
289+
end
290+
274291
it 'returns an empty catalog if asked to check the environment and they are mismatched' do
275292
@request.options[:check_environment] = "true"
276293
catalog = compiler.find(@request)

0 commit comments

Comments
 (0)