From 5020264ab9a5f33da30a569eff6bb06516f7159c Mon Sep 17 00:00:00 2001 From: Claire McQuin Date: Tue, 27 May 2014 10:30:28 -0700 Subject: set ENV vars for http proxies --- lib/chef/application.rb | 67 ++++++++++++++++++++ lib/chef/application/apply.rb | 1 + lib/chef/application/windows_service.rb | 1 + spec/unit/application_spec.rb | 105 ++++++++++++++++++++++++++++++++ 4 files changed, 174 insertions(+) diff --git a/lib/chef/application.rb b/lib/chef/application.rb index 12e1546627..04ebbba25a 100644 --- a/lib/chef/application.rb +++ b/lib/chef/application.rb @@ -44,6 +44,7 @@ class Chef::Application def reconfigure configure_chef configure_logging + configure_environment_variables end # Get this party started @@ -165,6 +166,14 @@ class Chef::Application end end + # Configure and set any environment variables according to the config. + def configure_environment_variables + configure_http_proxy + configure_https_proxy + configure_ftp_proxy + configure_no_proxy + end + # Called prior to starting the application, by the run method def setup_application raise Chef::Exceptions::Application, "#{self.to_s}: you must override setup_application" @@ -242,6 +251,64 @@ class Chef::Application Chef::Application.fatal!("Aborting due to error in '#{config_file_path}'", 2) end + # Set ENV['HTTP_PROXY'] + def configure_http_proxy + env['HTTP_PROXY'] = configure_proxy("http") if Chef::Config[:http_proxy] + end + + # Set ENV['HTTPS_PROXY'] + def configure_https_proxy + env['HTTPS_PROXY'] = configure_proxy("https") if Chef::Config[:https_proxy] + end + + # Set ENV['FTP_PROXY'] + def configure_ftp_proxy + env['FTP_PROXY'] = configure_proxy("ftp") if Chef::Config[:ftp_proxy] + end + + # Set ENV['NO_PROXY'] + def configure_no_proxy + env['NO_PROXY'] = Chef::Config[:no_proxy] if Chef::Config[:no_proxy] + end + + # Builds a proxy according to http/https format. Examples: + # http://username:password@hostname:port + # https://username@hostname:port + # ftp://hostname:port + # with, when scheme = "http", + # hostname:port given via config[:http_proxy] + # username given via config[:http_proxy_user] + # password given via config[:http_proxy_pass] + def configure_proxy(scheme) + proxy = Chef::Config["#{scheme}_proxy"].split("#{scheme}://") + proxy.shift if proxy[0].empty? + proxy = URI.escape(proxy[0]) + + full_proxy = "#{scheme}://" + if Chef::Config["#{scheme}_proxy_user"] + full_proxy << encode_uri_full(Chef::Config["#{scheme}_proxy_user"]) + if Chef::Config["#{scheme}_proxy_pass"] + full_proxy << ":#{encode_uri_full(Chef::Config["#{scheme}_proxy_pass"])}" + end + full_proxy << "@" + end + + full_proxy << proxy + return full_proxy + end + + # URI doesn't encode/escape reserved characters from the percent encoding set. + # For strings such as proxy user and proxy password we need these reserved characters + # to be escaped, or else the fully proxy might not be interpreted correctly. + def encode_uri_full(uri_str) + URI.escape(uri_str, "!#$&'()*+,/:;=?@[]") + end + + # This is a hook for testing + def env + ENV + end + class << self def debug_stacktrace(e) message = "#{e.class}: #{e}\n#{e.backtrace.join("\n")}" diff --git a/lib/chef/application/apply.rb b/lib/chef/application/apply.rb index dfec31c51e..983b35d5b7 100644 --- a/lib/chef/application/apply.rb +++ b/lib/chef/application/apply.rb @@ -88,6 +88,7 @@ class Chef::Application::Apply < Chef::Application parse_options Chef::Config.merge!(config) configure_logging + configure_environment_variables end def read_recipe_file(file_name) diff --git a/lib/chef/application/windows_service.rb b/lib/chef/application/windows_service.rb index bea5e9fcdc..2f81256a63 100644 --- a/lib/chef/application/windows_service.rb +++ b/lib/chef/application/windows_service.rb @@ -211,6 +211,7 @@ class Chef def reconfigure(startup_parameters=[]) configure_chef startup_parameters configure_logging + configure_environment_variables Chef::Config[:chef_server_url] = config[:chef_server_url] if config.has_key? :chef_server_url unless Chef::Config[:exception_handlers].any? {|h| Chef::Handler::ErrorReport === h} diff --git a/spec/unit/application_spec.rb b/spec/unit/application_spec.rb index c73ebb2e21..efde6d6690 100644 --- a/spec/unit/application_spec.rb +++ b/spec/unit/application_spec.rb @@ -39,6 +39,7 @@ describe Chef::Application do @app = Chef::Application.new @app.stub(:configure_chef).and_return(true) @app.stub(:configure_logging).and_return(true) + @app.stub(:configure_environment_variables).and_return(true) end it "should configure chef" do @@ -51,6 +52,10 @@ describe Chef::Application do @app.reconfigure end + it "should configure environment variables" do + @app.should_receive(:configure_environment_variables).and_return(true) + @app.reconfigure + end end describe Chef::Application do @@ -235,6 +240,106 @@ describe Chef::Application do end end + describe "when configuring environment variables" do + def configure_environment_variables_stubs + @app.stub(:configure_http_proxy).and_return(true) + @app.stub(:configure_https_proxy).and_return(true) + @app.stub(:configure_ftp_proxy).and_return(true) + @app.stub(:configure_no_proxy).and_return(true) + end + + it "should configure ENV['HTTP_PROXY']" do + configure_environment_variables_stubs + @app.should_receive(:configure_http_proxy) + @app.configure_environment_variables + end + + it "should configure ENV['HTTPS_PROXY']" do + configure_environment_variables_stubs + @app.should_receive(:configure_https_proxy) + @app.configure_environment_variables + end + + it "should configure ENV['FTP_PROXY']" do + configure_environment_variables_stubs + @app.should_receive(:configure_ftp_proxy) + @app.configure_environment_variables + end + + it "should configure ENV['NO_PROXY']" do + configure_environment_variables_stubs + @app.should_receive(:configure_no_proxy) + @app.configure_environment_variables + end + + describe "when configuring ENV['HTTP_PROXY']" do + before do + @env = {} + @app.stub(:env).and_return(@env) + + @app.stub(:configure_https_proxy).and_return(true) + @app.stub(:configure_ftp_proxy).and_return(true) + @app.stub(:configure_no_proxy).and_return(true) + end + + describe "when Chef::Config[:http_proxy] is not set" do + before do + Chef::Config[:http_proxy] = nil + end + + it "should not set ENV['HTTP_PROXY']" do + @app.configure_environment_variables + @env.should == {} + end + end + + describe "when Chef::Config[:http_proxy] is set" do + before do + Chef::Config[:http_proxy] = "http://hostname:port" + end + + it "should set ENV['HTTP_PROXY'] to http://hostname:port" do + @app.configure_environment_variables + @env['HTTP_PROXY'].should == "http://hostname:port" + end + + describe "when Chef::Config[:http_proxy_user] is set" do + before do + Chef::Config[:http_proxy_user] = "username" + end + + it "should set ENV['HTTP_PROXY'] to http://username@hostname.port" do + @app.configure_environment_variables + @env['HTTP_PROXY'].should == "http://username@hostname:port" + end + + describe "when Chef::Config[:http_proxy_pass] is set" do + before do + Chef::Config[:http_proxy_pass] = "password" + end + + it "should set ENV['HTTP_PROXY'] to http://username:password@hostname:port" do + @app.configure_environment_variables + @env['HTTP_PROXY'].should == "http://username:password@hostname:port" + end + end + end + + describe "when Chef::Config[:http_proxy_pass] is set (but not Chef::Config[:http_proxy_user])" do + before do + Chef::Config[:http_proxy_user] = nil + Chef::Config[:http_proxy_pass] = "password" + end + + it "should set ENV['HTTP_PROXY'] to http://hostname:port" do + @app.configure_environment_variables + @env['HTTP_PROXY'].should == "http://hostname:port" + end + end + end + end + end + describe "class method: fatal!" do before do STDERR.stub(:puts).with("FATAL: blah").and_return(true) -- cgit v1.2.1