Skip to content

Commit

Permalink
Expose s3 environment variables to hook execution
Browse files Browse the repository at this point in the history
This patch exposes the bucket name, key, version,
and etag of the bundle if we are running an s3 deployment.
  • Loading branch information
jcbhl authored and mwjones-aws committed Sep 15, 2022
1 parent 6ce81f9 commit 6a3e34a
Show file tree
Hide file tree
Showing 4 changed files with 68 additions and 18 deletions.
25 changes: 24 additions & 1 deletion lib/instance_agent/plugins/codedeploy/command_executor.rb
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,30 @@ def create_hook_executor(lifecycle_event, deployment_spec)
:deployment_root_dir => deployment_root_dir(deployment_spec),
:last_successful_deployment_dir => last_successful_deployment_dir(deployment_spec.deployment_group_id),
:most_recent_deployment_dir => most_recent_deployment_dir(deployment_spec.deployment_group_id),
:app_spec_path => deployment_spec.app_spec_path)
:app_spec_path => deployment_spec.app_spec_path,
:revision_envs => get_revision_envs(deployment_spec))
end

private
def get_revision_envs(deployment_spec)
case deployment_spec.revision_source
when 'S3'
return get_s3_envs(deployment_spec)
when 'GitHub', 'Local File', 'Local Directory'
return {}
else
raise "Unknown revision type '#{deployment_spec.revision_source}'"
end
end

private
def get_s3_envs(deployment_spec)
return {
"BUNDLE_BUCKET" => deployment_spec.bucket,
"BUNDLE_KEY" => deployment_spec.key,
"BUNDLE_VERSION" => deployment_spec.version,
"BUNDLE_ETAG" => deployment_spec.etag
}
end

private
Expand Down
1 change: 1 addition & 0 deletions lib/instance_agent/plugins/codedeploy/hook_executor.rb
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ def initialize(arguments = {})
'APPLICATION_NAME' => @application_name,
'DEPLOYMENT_GROUP_NAME' => @deployment_group_name,
'DEPLOYMENT_GROUP_ID' => @deployment_group_id}
@child_envs.merge!(arguments[:revision_envs]) if arguments[:revision_envs]
end

def is_noop?
Expand Down
15 changes: 13 additions & 2 deletions test/instance_agent/plugins/codedeploy/command_executor_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,15 @@ def generate_signed_message_for(map)
return spec
end

def s3_env_vars()
return {
"BUNDLE_BUCKET" => @s3Revision["Bucket"],
"BUNDLE_KEY" => @s3Revision["Key"],
"BUNDLE_VERSION" => @s3Revision["Version"],
"BUNDLE_ETAG" => @s3Revision["Etag"]
}
end

context 'The CodeDeploy Plugin Command Executor' do
setup do
@test_hook_mapping = { "BeforeBlockTraffic"=>["BeforeBlockTraffic"],
Expand Down Expand Up @@ -711,7 +720,8 @@ def generate_signed_message_for(map)
:deployment_root_dir => @deployment_root_dir,
:last_successful_deployment_dir => nil,
:most_recent_deployment_dir => nil,
:app_spec_path => 'appspec.yml'}
:app_spec_path => 'appspec.yml',
:revision_envs => s3_env_vars()}
@mock_hook_executor = mock
end

Expand Down Expand Up @@ -906,7 +916,8 @@ def generate_signed_message_for(map)
:deployment_type => @deployment_type,
:last_successful_deployment_dir => nil,
:most_recent_deployment_dir => nil,
:app_spec_path => 'appspec.yml'}
:app_spec_path => 'appspec.yml',
:revision_envs => s3_env_vars()}
@hook_executor_constructor_hash_1 = hook_executor_constructor_hash.merge({:lifecycle_event => "lifecycle_event_1"})
@hook_executor_constructor_hash_2 = hook_executor_constructor_hash.merge({:lifecycle_event => "lifecycle_event_2"})
@mock_hook_executor = mock
Expand Down
45 changes: 30 additions & 15 deletions test/instance_agent/plugins/codedeploy/hook_executor_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ class HookExecutorTest < InstanceAgentTestCase

include InstanceAgent::Plugins::CodeDeployPlugin

def create_full_hook_executor
def create_hook_executor(map = {})
HookExecutor.new ({:lifecycle_event => @lifecycle_event,
:application_name => @application_name,
:deployment_id => @deployment_id,
Expand All @@ -17,7 +17,8 @@ def create_full_hook_executor
:deployment_root_dir => @deployment_root_dir,
:last_successful_deployment_dir => @last_successful_deployment_dir,
:most_recent_deployment_dir => @most_recent_deployment_dir,
:app_spec_path => @app_spec_path})
:app_spec_path => @app_spec_path}
.merge(map))
end

context "testing hook executor" do
Expand Down Expand Up @@ -91,13 +92,13 @@ def create_full_hook_executor
should "fail if app spec not found" do
File.stubs(:exists?).with(){|value| value.is_a?(String) && value.end_with?("/app_spec")}.returns(false)
assert_raised_with_message("The CodeDeploy agent did not find an AppSpec file within the unpacked revision directory at revision-relative path \"app_spec\". The revision was unpacked to directory \"deployment/root/dir/deployment-archive\", and the AppSpec file was expected but not found at path \"deployment/root/dir/deployment-archive/app_spec\". Consult the AWS CodeDeploy Appspec documentation for more information at http://docs.aws.amazon.com/codedeploy/latest/userguide/reference-appspec-file.html", RuntimeError)do
@hook_executor = create_full_hook_executor
@hook_executor = create_hook_executor
end
end

should "parse an app spec from the current deployments directory" do
File.expects(:read).with(File.join(@deployment_root_dir, 'deployment-archive', @app_spec_path))
@hook_executor = create_full_hook_executor
@hook_executor = create_hook_executor
end

context "hook is before download bundle" do
Expand All @@ -107,7 +108,7 @@ def create_full_hook_executor

should "parse an app spec from the last successful deployment's directory" do
File.expects(:read).with(File.join(@last_successful_deployment_dir, 'deployment-archive', @app_spec_path))
@hook_executor = create_full_hook_executor
@hook_executor = create_hook_executor
end
end

Expand All @@ -118,7 +119,7 @@ def create_full_hook_executor

should "parse an app spec from the last successful deployment's directory" do
File.expects(:read).with(File.join(@last_successful_deployment_dir, 'deployment-archive', @app_spec_path))
@hook_executor = create_full_hook_executor
@hook_executor = create_hook_executor
end
end

Expand All @@ -131,7 +132,7 @@ def create_full_hook_executor

should "parse an app spec from the most recent deployment's directory" do
File.expects(:read).with(File.join(@most_recent_deployment_dir, 'deployment-archive', @app_spec_path))
@hook_executor = create_full_hook_executor
@hook_executor = create_hook_executor
end
end
end
Expand All @@ -152,7 +153,7 @@ def create_full_hook_executor
setup do
@app_spec = {"version" => 0.0, "os" => "linux", "hooks" => {}}
YAML.stubs(:load).returns(@app_spec)
@hook_executor = create_full_hook_executor
@hook_executor = create_hook_executor
end

should "do nothing" do
Expand All @@ -169,7 +170,7 @@ def create_full_hook_executor
@app_spec = {"version" => 0.0, "os" => "linux", "hooks" => {'ValidateService'=>[{'location'=>'test'}]}}
YAML.stubs(:load).returns(@app_spec)
@script_location = File.join(@deployment_root_dir, 'deployment-archive', 'test')
@hook_executor = create_full_hook_executor
@hook_executor = create_hook_executor
end

should "not be a noop" do
Expand Down Expand Up @@ -241,11 +242,25 @@ def create_full_hook_executor
InstanceAgent::ThreadJoiner.stubs(:new).returns(@thread_joiner)
end

context "extra child environment variables are added" do
setup do
revision_envs = {"TEST_ENVIRONMENT_VARIABLE" => "ONE", "ANOTHER_ENV_VARIABLE" => "TWO"}
@child_env.merge!(revision_envs)
@hook_executor = create_hook_executor(:revision_envs => revision_envs)
end

should "call popen with the environment variables" do
Open3.stubs(:popen3).with(@child_env, @script_location, :pgroup => true).yields([@mock_pipe,@mock_pipe,@mock_pipe,@wait_thr])
@value.stubs(:exitstatus).returns(0)
@hook_executor.execute()
end
end

context 'scripts fail for unknown reason' do
setup do
@app_spec = { "version" => 0.0, "os" => "linux", "hooks" => {'ValidateService'=> [{"location"=>"test", "timeout"=>"30"}]}}
YAML.stubs(:load).returns(@app_spec)
@hook_executor = create_full_hook_executor
@hook_executor = create_hook_executor
@popen_error = Errno::ENOENT
Open3.stubs(:popen3).with(@child_env, @script_location, :pgroup => true).raises(@popen_error, 'su')
end
Expand All @@ -262,7 +277,7 @@ def create_full_hook_executor
setup do
@app_spec = { "version" => 0.0, "os" => "linux", "hooks" => {'ValidateService'=> [{"location"=>"test", "timeout"=>"30"}]}}
YAML.stubs(:load).returns(@app_spec)
@hook_executor = create_full_hook_executor
@hook_executor = create_hook_executor
@thread_joiner.expects(:joinOrFail).with(@wait_thr).yields
InstanceAgent::ThreadJoiner.expects(:new).with(30).returns(@thread_joiner)
@wait_thr.stubs(:pid).returns(1234)
Expand Down Expand Up @@ -307,7 +322,7 @@ def create_full_hook_executor
Open3.stubs(:popen3).with(@child_env, @script_location, :pgroup => true).yields([@mock_pipe,@mock_pipe,@mock_pipe,@wait_thr])
@app_spec = {"version" => 0.0, "os" => "linux", "hooks" => {'ValidateService'=>[{'location'=>'test', 'timeout'=>"#{timeout}"}]}}
YAML.stubs(:load).returns(@app_spec)
@hook_executor = create_full_hook_executor
@hook_executor = create_hook_executor
end

context "STDOUT left open" do
Expand Down Expand Up @@ -341,7 +356,7 @@ def create_full_hook_executor
setup do
@app_spec = { "version" => 0.0, "os" => "linux", "hooks" => {'ValidateService'=> [{"location"=>"test", "runas"=>"user"}]}}
YAML.stubs(:load).returns(@app_spec)
@hook_executor = create_full_hook_executor
@hook_executor = create_hook_executor
mock_pipe = mock
Open3.stubs(:popen3).with(@child_env, 'su user -c ' + @script_location, :pgroup => true).yields([@mock_pipe,@mock_pipe,@mock_pipe,@wait_thr])
end
Expand Down Expand Up @@ -374,7 +389,7 @@ def create_full_hook_executor
setup do
@app_spec = { "version" => 0.0, "os" => "linux", "hooks" => {'ValidateService'=> [{"location"=>"test"}]}}
YAML.stubs(:load).returns(@app_spec)
@hook_executor = create_full_hook_executor
@hook_executor = create_hook_executor
Open3.stubs(:popen3).with(@child_env, @script_location, :pgroup => true).yields([@mock_pipe,@mock_pipe,@mock_pipe,@wait_thr])
end

Expand Down Expand Up @@ -406,7 +421,7 @@ def create_full_hook_executor
setup do
@app_spec = { "version" => 0.0, "os" => "linux", "hooks" => {'ValidateService'=> [{"location"=>"test"}]}}
YAML.stubs(:load).returns(@app_spec)
@hook_executor = create_full_hook_executor
@hook_executor = create_hook_executor
Open3.stubs(:popen3).with(@child_env, @script_location, {}).yields([@mock_pipe,@mock_pipe,@mock_pipe,@wait_thr])
InstanceAgent::LinuxUtil.stubs(:supports_process_groups?).returns(false)
end
Expand Down

0 comments on commit 6a3e34a

Please sign in to comment.