From 9a941eeb36f2fbde7e08de94f6d372914d4c7b2d Mon Sep 17 00:00:00 2001 From: Lucy Wyman Date: Mon, 11 Oct 2021 07:26:10 -0700 Subject: [PATCH] (hack) Unset GEM_PATH and GEM_HOME when running local tasks In PE we use the Ruby interpreter shipped with the Puppet Agent to run the ace server. The ace server is responsible for executing remote tasks. Remote tasks will often use the puppet library, and run in ACE using the local transport. Now that puppet has moved to using require_relative there is a bug whereby a new combination of code is loaded between the Puppet gem and the Puppet code shipped with the agent (because we set GEM_HOME and GEM_PATH when we start the service). As a workaround, this commit uses the `BOLT_ORIG` environment variable mechanism in Bolt to configure the Ruby environment that the task itself will run in (and not the ruby code that's *running* the task). ACE can unset the GEM_PATH and GEM_HOME environment variable so that `Gem.specifications` in the Puppet autoloader is empty, and loads from the `$LOAD_PATH` first (which can be added to using the `RUBYLIB` environment variable). Then, ACE uses `BOLT_ORIG_RUBYLIB` to append the Gem load paths to the LOAD_PATH so that the dependencies are still available. This is *very* much a hack, but this problem is also somewhat limited in scope. --- agentless-catalog-executor.gemspec | 2 +- lib/ace/transport_app.rb | 11 +++++++++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/agentless-catalog-executor.gemspec b/agentless-catalog-executor.gemspec index e564e2c..860b131 100644 --- a/agentless-catalog-executor.gemspec +++ b/agentless-catalog-executor.gemspec @@ -28,7 +28,7 @@ Gem::Specification.new do |spec| spec.add_dependency "hocon", ">= 1.2.5" spec.add_dependency "json-schema", ">= 2.8.0" spec.add_dependency "puma", ">= 3.12.0" - spec.add_dependency "puppet", ">= 6.23", "< 8.0.0" + spec.add_dependency "puppet", ">= 6.17.0" spec.add_dependency "rack", ">= 2.0.5" spec.add_dependency "rails-auth", ">= 2.1.4" spec.add_dependency "sinatra", ">= 2.0.4" diff --git a/lib/ace/transport_app.rb b/lib/ace/transport_app.rb index 814f724..57d706d 100644 --- a/lib/ace/transport_app.rb +++ b/lib/ace/transport_app.rb @@ -221,6 +221,9 @@ def self.trusted_facts(certname) validate_schema(@schemas["run_task"], body) inventory = Bolt::Inventory.empty + local_data = { 'name' => 'localhost', + 'config' => { 'transport' => 'local', 'local' => { 'bundled-ruby' => false } } } + local_target = Bolt::Target.from_hash(local_data, inventory) target_data = { 'name' => body['target']['host'] || body['target']['name'] || 'remote', 'config' => { @@ -228,7 +231,7 @@ def self.trusted_facts(certname) 'remote' => body['target'] } } - target = [Bolt::Target.from_hash(target_data, inventory)] + target = [Bolt::Target.from_hash(target_data, local_target.inventory)] rescue ACE::Error => e return [400, error_result(e).to_json] rescue JSON::ParserError => e @@ -251,8 +254,12 @@ def self.trusted_facts(certname) parameters = body['parameters'] || {} - # Since this will only be on one node we can just return the first result + # Unset gem specifications so that LOAD_PATH is loaded first, then + # append gem paths to the LOAD_PATH so they are still loaded. This is + # limited to the task run environment itself. + ENV['BOLT_ORIG_RUBYLIB'] = $LOAD_PATH.clone.concat(Gem.path).join(":") results = @executor.run_task(target, task, parameters) + # Since this will only be on one node we can just return the first result result = results.first # Unwrap _sensitive output (orchestrator will handle obfuscating it from the result) if result.value.is_a?(Hash) && result.value.key?('_sensitive')