diff --git a/lib/stack_master/commands/drift.rb b/lib/stack_master/commands/drift.rb index 812f9e0f..3ed5a26c 100644 --- a/lib/stack_master/commands/drift.rb +++ b/lib/stack_master/commands/drift.rb @@ -19,9 +19,13 @@ def perform stack_drift_status_color(drift_results.stack_drift_status)) return if drift_results.stack_drift_status == 'IN_SYNC' - failed - resp = cf.describe_stack_resource_drifts(stack_name: stack_name) + actionable_drifts = resp.stack_resource_drifts.reject do |drift| + ignore_resource_types.include?(drift.resource_type) + end + + failed unless actionable_drifts.empty? + resp.stack_resource_drifts.each do |drift| display_drift(drift) end @@ -108,7 +112,7 @@ def puts(string) end extend Forwardable - def_delegators :@stack_definition, :stack_name, :region + def_delegators :@stack_definition, :stack_name, :region, :ignore_resource_types def_delegators :StackMaster, :colorize SLEEP_SECONDS = 1 diff --git a/lib/stack_master/stack_definition.rb b/lib/stack_master/stack_definition.rb index ef750186..0fe9f38a 100644 --- a/lib/stack_master/stack_definition.rb +++ b/lib/stack_master/stack_definition.rb @@ -19,7 +19,8 @@ class StackDefinition :compiler_options, :parameters_dir, :parameters, - :parameter_files + :parameter_files, + :ignore_resource_types attr_reader :compiler @@ -41,6 +42,7 @@ def initialize(attributes = {}) @allowed_accounts = Array(@allowed_accounts) @parameters ||= {} @parameter_files ||= [] + @ignore_resource_types ||= [] end def ==(other) diff --git a/spec/stack_master/commands/drift_spec.rb b/spec/stack_master/commands/drift_spec.rb index a6e25b2a..60183dfc 100644 --- a/spec/stack_master/commands/drift_spec.rb +++ b/spec/stack_master/commands/drift_spec.rb @@ -2,7 +2,8 @@ let(:cf) { instance_double(Aws::CloudFormation::Client) } let(:config) { instance_double(StackMaster::Config) } let(:options) { Commander::Command::Options.new } - let(:stack_definition) { instance_double(StackMaster::StackDefinition, stack_name: 'myapp', region: 'us-east-1') } + let(:ignore_resource_types) { [] } + let(:stack_definition) { instance_double(StackMaster::StackDefinition, stack_name: 'myapp', region: 'us-east-1', ignore_resource_types: ignore_resource_types) } subject(:drift) { described_class.new(config, stack_definition, options) } let(:stack_drift_detection_id) { 123 } @@ -118,6 +119,59 @@ end end + context 'when all drifted resources are in the ignore list' do + let(:stack_drift_status) { 'DRIFTED' } + let(:ignore_resource_types) { ['AWS::ElastiCache::ParameterGroup'] } + let(:stack_resource_drifts) do + [ + Aws::CloudFormation::Types::StackResourceDrift.new( + stack_resource_drift_status: 'MODIFIED', + resource_type: 'AWS::ElastiCache::ParameterGroup', + logical_resource_id: 'CacheParams', + physical_resource_id: 'params-1', + property_differences: [] + ) + ] + end + + it 'exits with success' do + drift.perform + expect(drift).to be_success + end + + it 'still displays the drift for visibility' do + expect { drift.perform }.to output(/MODIFIED AWS::ElastiCache::ParameterGroup CacheParams params-1/).to_stdout + end + end + + context 'when only some drifted resources are in the ignore list' do + let(:stack_drift_status) { 'DRIFTED' } + let(:ignore_resource_types) { ['AWS::ElastiCache::ParameterGroup'] } + let(:stack_resource_drifts) do + [ + Aws::CloudFormation::Types::StackResourceDrift.new( + stack_resource_drift_status: 'MODIFIED', + resource_type: 'AWS::ElastiCache::ParameterGroup', + logical_resource_id: 'CacheParams', + physical_resource_id: 'params-1', + property_differences: [] + ), + Aws::CloudFormation::Types::StackResourceDrift.new( + stack_resource_drift_status: 'MODIFIED', + resource_type: 'AWS::EC2::SecurityGroup', + logical_resource_id: 'SecurityGroup', + physical_resource_id: 'sg-123456', + property_differences: [property_difference] + ) + ] + end + + it 'exits with failure' do + drift.perform + expect(drift).not_to be_success + end + end + context "when stack drift detection doesn't complete" do before do describe_stack_drift_detection_status_response.detection_status = 'UNKNOWN'