From 6aa99fd970bf40477e54148e9e89c8bdbbae6254 Mon Sep 17 00:00:00 2001 From: Eric Hayes Date: Fri, 22 Jun 2018 13:31:01 -0700 Subject: [PATCH] Add support for using deployment spec values within appspec.yml file. These same values are also allowed to be used in the hook scripts: https://blogs.aws.amazon.com/application-management/post/Tx1PX2XMPLYPULD/Using-CodeDeploy-Environment-Variables --- .../application_specification.rb | 7 ++++++- .../plugins/codedeploy/command_executor.rb | 8 ++++++++ .../plugins/codedeploy/hook_executor.rb | 14 +++++++++++++- .../plugins/codedeploy/command_executor_test.rb | 6 +++--- 4 files changed, 30 insertions(+), 5 deletions(-) diff --git a/lib/instance_agent/plugins/codedeploy/application_specification/application_specification.rb b/lib/instance_agent/plugins/codedeploy/application_specification/application_specification.rb index 519b3ed9..5875bf4f 100644 --- a/lib/instance_agent/plugins/codedeploy/application_specification/application_specification.rb +++ b/lib/instance_agent/plugins/codedeploy/application_specification/application_specification.rb @@ -2,6 +2,8 @@ require 'instance_agent/plugins/codedeploy/application_specification/file_info' require 'instance_agent/plugins/codedeploy/application_specification/linux_permission_info' require 'instance_agent/plugins/codedeploy/application_specification/mode_info' +require 'ostruct' +require 'erb' module InstanceAgent module Plugins @@ -23,7 +25,10 @@ def initialize(yaml_hash, opts = {}) @permissions = parse_permissions(yaml_hash['permissions'] || []) end - def self.parse(app_spec_string) + def self.parse(app_spec_template_string, deployment_spec) + # make deployment_spec keys available to the yaml template + app_spec_string = ERB.new(app_spec_template_string || '').result(OpenStruct.new(deployment_spec).instance_eval { binding }) + new(YAML.load(app_spec_string)) end diff --git a/lib/instance_agent/plugins/codedeploy/command_executor.rb b/lib/instance_agent/plugins/codedeploy/command_executor.rb index 3d1a1def..e1d0e51b 100644 --- a/lib/instance_agent/plugins/codedeploy/command_executor.rb +++ b/lib/instance_agent/plugins/codedeploy/command_executor.rb @@ -199,6 +199,14 @@ def most_recent_deployment_dir(deployment_group) def default_app_spec(deployment_spec) default_app_spec_location = File.join(archive_root_dir(deployment_spec), app_spec_path) log(:debug, "Checking for app spec in #{default_app_spec_location}") + app_spec = ApplicationSpecification::ApplicationSpecification.parse(File.read(default_app_spec_location), { + :application_name => deployment_spec.application_name, + :deployment_id => deployment_spec.deployment_id, + :deployment_group_name => deployment_spec.deployment_group_name, + :deployment_group_id => deployment_spec.deployment_group_id, + :deployment_root_dir => deployment_root_dir(deployment_spec), + :last_successful_deployment_dir => last_successful_deployment_dir(deployment_spec.deployment_group_id) + }) validate_app_spec_hooks(ApplicationSpecification::ApplicationSpecification.parse(File.read(default_app_spec_location)), deployment_spec.all_possible_lifecycle_events) end diff --git a/lib/instance_agent/plugins/codedeploy/hook_executor.rb b/lib/instance_agent/plugins/codedeploy/hook_executor.rb index 6674b090..dbfd6f45 100644 --- a/lib/instance_agent/plugins/codedeploy/hook_executor.rb +++ b/lib/instance_agent/plugins/codedeploy/hook_executor.rb @@ -227,7 +227,19 @@ def parse_app_spec http://docs.aws.amazon.com/codedeploy/latest/userguide/reference-appspec-file.html MESSAGE end - @app_spec = InstanceAgent::Plugins::CodeDeployPlugin::ApplicationSpecification::ApplicationSpecification.parse(File.read(app_spec_location)) + @app_spec = InstanceAgent::Plugins::CodeDeployPlugin::ApplicationSpecification::ApplicationSpecification.parse(File.read(app_spec_location), deployment_spec) + end + + private + def deployment_spec + { + :application_name => @application_name, + :deployment_id => @deployment_id, + :deployment_group_name => @deployment_group_name, + :deployment_group_id => @deployment_group_id, + :deployment_root_dir => @current_deployment_root_dir, + :last_successful_deployment_dir => @last_successful_deployment_dir + } end private diff --git a/test/instance_agent/plugins/codedeploy/command_executor_test.rb b/test/instance_agent/plugins/codedeploy/command_executor_test.rb index fc10b105..c4cdabde 100644 --- a/test/instance_agent/plugins/codedeploy/command_executor_test.rb +++ b/test/instance_agent/plugins/codedeploy/command_executor_test.rb @@ -152,7 +152,7 @@ def generate_signed_message_for(map) stubs(:read). with("#@archive_root_dir/appspec.yml"). returns("APP SPEC") - ApplicationSpecification::ApplicationSpecification.stubs(:parse).with("APP SPEC").returns(@app_spec) + ApplicationSpecification::ApplicationSpecification.stubs(:parse).with("APP SPEC", {}).returns(@app_spec) end should "create an appropriate Installer" do @@ -201,7 +201,7 @@ def generate_signed_message_for(map) app_spec_hooks = {'UnknownHook' => nil} app_spec.expects(:hooks).returns(app_spec_hooks) File.stubs(:read).with("#@archive_root_dir/appspec.yml").returns("APP SPEC") - ApplicationSpecification::ApplicationSpecification.stubs(:parse).with("APP SPEC").returns(app_spec) + ApplicationSpecification::ApplicationSpecification.stubs(:parse).with("APP SPEC", {}).returns(app_spec) unknown_hooks = app_spec_hooks.merge(@test_hook_mapping) assert_raised_with_message("appspec.yml file contains unknown lifecycle events: #{unknown_hooks.keys}", ArgumentError) do @command_executor.execute_command(@command, deployment_spec) @@ -229,7 +229,7 @@ def generate_signed_message_for(map) app_spec_hooks = InstanceAgent::Plugins::CodeDeployPlugin::CommandPoller::DEFAULT_HOOK_MAPPING.merge({'ExampleLifecycleEvent' => nil, 'SecondLifecycleEvent' => nil}) app_spec.expects(:hooks).twice.returns(app_spec_hooks) File.stubs(:read).with("#@archive_root_dir/appspec.yml").returns("APP SPEC") - ApplicationSpecification::ApplicationSpecification.stubs(:parse).with("APP SPEC").returns(app_spec) + ApplicationSpecification::ApplicationSpecification.stubs(:parse).with("APP SPEC", {}).returns(app_spec) assert_raised_with_message("You specified a lifecycle event which is not a default one and doesn't exist in your appspec.yml file: CustomHookNotInAppspec", ArgumentError) do @command_executor.execute_command(@command, deployment_spec) end