-
Notifications
You must be signed in to change notification settings - Fork 112
[DevSetting] Add install_proxy_url which will allow ParallelCluster to set Proxy environment for Build Image installation #3157
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
95 changes: 95 additions & 0 deletions
95
cookbooks/aws-parallelcluster-shared/recipes/setup_proxy.rb
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,95 @@ | ||
| # frozen_string_literal: true | ||
|
|
||
| # | ||
| # Cookbook:: aws-parallelcluster | ||
| # Recipe:: setup_proxy | ||
| # | ||
| # Copyright:: 2026 Amazon.com, Inc. or its affiliates. All Rights Reserved. | ||
| # | ||
| # Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance with the | ||
| # License. A copy of the License is located at | ||
| # | ||
| # http://aws.amazon.com/apache2.0/ | ||
| # | ||
| # or in the "LICENSE.txt" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES | ||
| # OR CONDITIONS OF ANY KIND, express or implied. See the License for the specific language governing permissions and | ||
| # limitations under the License. | ||
|
|
||
| # This recipe configures proxy environment variables for build-image in isolated networks. | ||
| # | ||
| # It reads the proxy URL from node['cluster']['install_http_proxy_address'] (set via ExtraChefAttributes) | ||
| # and configures http_proxy/https_proxy ENV vars for the Chef run. This makes all subsequent | ||
| # Chef resources (remote_file, bash, execute, etc.) use the explicit proxy for HTTPS traffic | ||
| # instead of trying direct connections that would fail in an isolated network. | ||
| # | ||
| # The no_proxy list excludes S3 endpoints so downloads from S3 go through the VPC Gateway | ||
| # Endpoint directly, not through the proxy. | ||
| # | ||
| # Both leading-dot and bare-host entries are needed for each S3 endpoint: | ||
| # ".s3.{region}.amazonaws.com" — matches subdomains (virtual-hosted bucket URLs) | ||
| # e.g., mybucket.s3.us-east-1.amazonaws.com used by remote_file downloads | ||
| # "s3.{region}.amazonaws.com" — matches the exact host (path-style URLs) | ||
| # e.g., s3.us-east-1.amazonaws.com/mybucket/key used by aws s3 presign URLs; cfn-bootstrap | ||
| # # bucket uses https://s3.amazonaws.com/cloudformation-examples/... | ||
| # | ||
| # The global .s3.amazonaws.com endpoint does NOT work through the VPC Gateway Endpoint | ||
| # (SSL errors with FSx repos), so it is intentionally left out of no_proxy without the | ||
| # bare-host form and instead goes through the proxy. The proxy allowlist must include | ||
| # s3.amazonaws.com for this to work. | ||
| # | ||
| # IMDS (169.254.169.254) is excluded so instance metadata queries bypass the proxy. | ||
| # | ||
| # This recipe only runs when install_http_proxy_address is set — normal builds are unaffected. | ||
|
|
||
| ruby_block 'configure proxy from install_http_proxy_address' do | ||
| block do | ||
| proxy_url = node['cluster']['install_http_proxy_address'] | ||
|
|
||
| if proxy_url && !proxy_url.empty? | ||
| # Validate proxy URL format: must be http://host:port | ||
| unless proxy_url.match?(%r{^https?://[^/:]+:\d+/?$}) | ||
| raise "Invalid install_http_proxy_address '#{proxy_url}'. Expected format: http://host:port" | ||
| end | ||
|
|
||
| region = node['cluster']['region'] | ||
|
|
||
| # S3 endpoints bypass the proxy and use the VPC Gateway Endpoint. | ||
| # Includes regional (s3.{region}), dash-style (s3-{region}), global (s3.amazonaws.com), | ||
| # and dualstack (s3.dualstack.{region}) variants used by different AWS services and repos. | ||
| no_proxy = [ | ||
| "localhost", | ||
| "127.0.0.1", | ||
| "169.254.169.254", | ||
| ".s3.#{region}.amazonaws.com", | ||
| "s3.#{region}.amazonaws.com", | ||
| ".s3-#{region}.amazonaws.com", | ||
| "s3-#{region}.amazonaws.com", | ||
| ".s3.amazonaws.com", | ||
himani2411 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| ".s3.dualstack.#{region}.amazonaws.com", | ||
| "s3.dualstack.#{region}.amazonaws.com", | ||
himani2411 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| ].join(",") | ||
|
|
||
| Chef::Log.info("Configuring proxy: #{proxy_url}") | ||
|
|
||
| ENV['http_proxy'] = proxy_url | ||
| ENV['https_proxy'] = proxy_url | ||
| ENV['HTTP_PROXY'] = proxy_url | ||
| ENV['HTTPS_PROXY'] = proxy_url | ||
| ENV['no_proxy'] = no_proxy | ||
| ENV['NO_PROXY'] = no_proxy | ||
|
|
||
| # On Ubuntu, configure snapd to use the explicit proxy. snapd uses its own HTTP | ||
| # client and doesn't go through the transparent proxy (iptables REDIRECT). Without | ||
| # this, the Firefox transitional package's preinst runs `snap info firefox` via snapd, | ||
| # which times out, retries for 30 minutes holding the dpkg lock, and blocks all | ||
| # subsequent apt-get installs (e.g., DCV prerequisites). | ||
| if node['platform'] == 'ubuntu' && ::File.exist?('/run/snapd.socket') | ||
| Chef::Log.info("Configuring snapd proxy: #{proxy_url}") | ||
| shell_out!("snap", "set", "system", "proxy.http=#{proxy_url}") | ||
| shell_out!("snap", "set", "system", "proxy.https=#{proxy_url}") | ||
| end | ||
| else | ||
| Chef::Log.info("No install_http_proxy_address set, skipping proxy configuration") | ||
| end | ||
| end | ||
| end | ||
108 changes: 108 additions & 0 deletions
108
cookbooks/aws-parallelcluster-shared/spec/unit/recipes/setup_proxy_spec.rb
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,108 @@ | ||
| # frozen_string_literal: true | ||
|
|
||
| require 'spec_helper' | ||
|
|
||
| describe 'aws-parallelcluster-shared::setup_proxy' do | ||
| PROXY_URL = 'http://10.0.0.109:8888' | ||
| TEST_REGION = 'test-region-1' | ||
| RUBY_BLOCK_NAME = 'configure proxy from install_http_proxy_address' | ||
|
|
||
| for_all_oses do |platform, version| | ||
| context "on #{platform}#{version}" do | ||
| before(:each) do | ||
| # Clean proxy ENV vars between tests to prevent leakage | ||
| %w(http_proxy https_proxy HTTP_PROXY HTTPS_PROXY no_proxy NO_PROXY).each { |var| ENV.delete(var) } | ||
| allow(::File).to receive(:exist?).and_call_original | ||
| end | ||
|
|
||
| context 'when install_http_proxy_address is set with valid URL' do | ||
| cached(:chef_run) do | ||
| runner(platform: platform, version: version) do |node| | ||
| node.override['cluster'] = { 'install_http_proxy_address' => PROXY_URL, 'region' => TEST_REGION } | ||
| end.converge(described_recipe) | ||
| end | ||
|
|
||
| before(:each) do | ||
| allow_any_instance_of(Chef::Resource::RubyBlock).to receive(:shell_out!).and_return(true) | ||
| end | ||
|
|
||
| it 'configures proxy environment variables' do | ||
| expect(chef_run).to run_ruby_block(RUBY_BLOCK_NAME) | ||
| end | ||
|
|
||
| it 'sets proxy env vars in the ruby block' do | ||
| chef_run | ||
| chef_run.ruby_block(RUBY_BLOCK_NAME).block.call | ||
|
|
||
| %w(http_proxy https_proxy HTTP_PROXY HTTPS_PROXY).each do |var| | ||
| expect(ENV[var]).to eq(PROXY_URL) | ||
| end | ||
| expect(ENV['no_proxy']).to include(".s3.#{TEST_REGION}.amazonaws.com") | ||
| expect(ENV['no_proxy']).to include("s3.#{TEST_REGION}.amazonaws.com") | ||
| expect(ENV['no_proxy']).to include(".s3-#{TEST_REGION}.amazonaws.com") | ||
| expect(ENV['no_proxy']).to include('.s3.amazonaws.com') | ||
| expect(ENV['no_proxy']).to include(".s3.dualstack.#{TEST_REGION}.amazonaws.com") | ||
| expect(ENV['no_proxy']).to include('169.254.169.254') | ||
| expect(ENV['no_proxy']).to include('localhost') | ||
| end | ||
|
|
||
| # snapd proxy configuration tests | ||
| { true => 'exists', false => 'does not exist' }.each do |socket_exists, description| | ||
| context "when snapd socket #{description}" do | ||
| before(:each) do | ||
| allow(::File).to receive(:exist?).with('/run/snapd.socket').and_return(socket_exists) | ||
| end | ||
|
|
||
| if platform == 'ubuntu' && socket_exists | ||
| it 'configures snapd proxy' do | ||
| chef_run | ||
| expect_any_instance_of(Chef::Resource::RubyBlock).to receive(:shell_out!) | ||
| .with("snap", "set", "system", "proxy.http=#{PROXY_URL}") | ||
| expect_any_instance_of(Chef::Resource::RubyBlock).to receive(:shell_out!) | ||
| .with("snap", "set", "system", "proxy.https=#{PROXY_URL}") | ||
| chef_run.ruby_block(RUBY_BLOCK_NAME).block.call | ||
| end | ||
| else | ||
| it 'does not configure snapd proxy' do | ||
| chef_run | ||
| expect_any_instance_of(Chef::Resource::RubyBlock).not_to receive(:shell_out!) | ||
| chef_run.ruby_block(RUBY_BLOCK_NAME).block.call | ||
| end | ||
| end | ||
| end | ||
| end | ||
| end | ||
|
|
||
| { | ||
| nil => { description: 'not set', should_skip: true }, | ||
| '' => { description: 'empty string', should_skip: true }, | ||
| 'not-a-valid-url' => { description: 'invalid format', should_skip: false }, | ||
| 'http://10.0.0.109' => { description: 'missing port', should_skip: false }, | ||
| }.each do |proxy_value, test_actions| | ||
| context "when install_http_proxy_address is #{test_actions[:description]}" do | ||
| cached(:chef_run) do | ||
| runner(platform: platform, version: version) do |node| | ||
| attrs = { 'region' => TEST_REGION } | ||
| attrs['install_http_proxy_address'] = proxy_value unless proxy_value.nil? | ||
| node.override['cluster'] = attrs | ||
| end.converge(described_recipe) | ||
| end | ||
|
|
||
| if test_actions[:should_skip] | ||
| it 'does not configure proxy' do | ||
| chef_run | ||
| chef_run.ruby_block(RUBY_BLOCK_NAME).block.call | ||
| expect(ENV['http_proxy']).to be_nil | ||
| end | ||
| else | ||
| it 'raises an error' do | ||
| chef_run | ||
| expect { chef_run.ruby_block(RUBY_BLOCK_NAME).block.call } | ||
| .to raise_error(RuntimeError, /Invalid install_http_proxy_address/) | ||
| end | ||
| end | ||
| end | ||
| end | ||
| end | ||
| end | ||
| end |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.