From 85a2578a53fe859039c6fff3f451d0814500b1ae Mon Sep 17 00:00:00 2001 From: Sathish Date: Thu, 20 Jan 2022 11:22:38 +0530 Subject: [PATCH 1/3] support in-memory cache ! Signed-off-by: Sathish --- libraries/aws_backend.rb | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/libraries/aws_backend.rb b/libraries/aws_backend.rb index ec84ba33b..be402028a 100644 --- a/libraries/aws_backend.rb +++ b/libraries/aws_backend.rb @@ -78,6 +78,11 @@ def initialize(params) def aws_client(klass) # TODO: make this a dict with keys of klass.to_s.to_sym such that we can send different args per client in cases such as EC2 instance that use multiple different clients + + # @client_args[:stub_data][:client] ||= klass if @client_args[:stub_data].present? + if @client_args && @client_args[:resource_data] && !@client_args[:resource_data].empty? + return AwsMockResource.new(@client_args[:resource_data]) + end return @cache[klass.to_s.to_sym] ||= klass.new(@client_args) if @client_args @cache[klass.to_s.to_sym] ||= klass.new end @@ -328,6 +333,19 @@ def waf_client end end + +class AwsMockResource + def initialize(opts) + @opts = opts + end + + private + attr_reader :opts + def method_missing(symbol, *args) + [opts[:resource_data]] + end +end + # Base class for AWS resources # class AwsResourceBase < Inspec.resource(1) @@ -351,6 +369,13 @@ def initialize(opts) client_args[:client_args][:retry_limit] = opts[:aws_retry_limit] if opts[:aws_retry_limit] client_args[:client_args][:retry_backoff] = "lambda { |c| sleep(#{opts[:aws_retry_backoff]}) }" if opts[:aws_retry_backoff] # this catches the stub_data true option for unit testing - and others that could be useful for consumers + if @opts.key?(:resource_data) + @opts[:resource_data] = @opts[:resource_data].to_h + end + if @opts[:resource_data] && !@opts[:resource_data].empty? + client_args[:client_args][:stub_responses] = true + client_args[:client_args][:resource_data] = @opts[:resource_data] + end client_args[:client_args].update(opts[:client_args]) if opts[:client_args] end @aws = AwsConnection.new(client_args) @@ -386,7 +411,7 @@ def validate_parameters(allow: [], required: nil, require_any_of: nil) # rubocop allow += require_any_of end - allow += %i(client_args stub_data aws_region aws_endpoint aws_retry_limit aws_retry_backoff) + allow += %i(client_args stub_data aws_region aws_endpoint aws_retry_limit aws_retry_backoff resource_data) raise ArgumentError, 'Scalar arguments not supported' unless defined?(@opts.keys) raise ArgumentError, 'Unexpected arguments found' unless @opts.keys.all? { |a| allow.include?(a) } raise ArgumentError, 'Provided parameter should not be empty' unless @opts.values.all? do |a| From 5d2fdd685571adf16b76fc146287c25addd36a51 Mon Sep 17 00:00:00 2001 From: Sathish Date: Thu, 20 Jan 2022 11:22:53 +0530 Subject: [PATCH 2/3] a random example!! Signed-off-by: Sathish --- libraries/aws_ec2_instance.rb | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/libraries/aws_ec2_instance.rb b/libraries/aws_ec2_instance.rb index 596b8a276..7a710a5db 100644 --- a/libraries/aws_ec2_instance.rb +++ b/libraries/aws_ec2_instance.rb @@ -23,7 +23,8 @@ def initialize(opts = {}) super(opts) validate_parameters(require_any_of: %i(instance_id name)) - if opts[:instance_id] && !opts[:instance_id].empty? # Use instance_id, if provided + if !opts[:resource_data] + if opts[:instance_id] && !opts[:instance_id].empty? # Use instance_id, if provided if !opts[:instance_id].is_a?(String) || opts[:instance_id] !~ /(^i-[0-9a-f]{8})|(^i-[0-9a-f]{17})$/ raise ArgumentError, "#{@__resource_name__}: `instance_id` must be a string in the format of 'i-' followed by 8 or 17 hexadecimal characters." end @@ -34,10 +35,11 @@ def initialize(opts = {}) instance_arguments = { filters: [{ name: 'tag:Name', values: [opts[:name]] }] } else raise ArgumentError, "#{@__resource_name__}: either instance_id or name must be provided." + end end catch_aws_errors do - resp = @aws.compute_client.describe_instances(instance_arguments) + resp = opts[:resource_data] || @aws.compute_client.describe_instances(instance_arguments) if resp.reservations.first.nil? || resp.reservations.first.instances.first.nil? empty_response_warn return From 738951ea7f262cf32230d475bcb61edb2cd9e332 Mon Sep 17 00:00:00 2001 From: Soumyodeep Karmakar Date: Fri, 11 Feb 2022 18:10:28 +0530 Subject: [PATCH 3/3] lint errors fixed Signed-off-by: Soumyodeep Karmakar --- libraries/aws_backend.rb | 5 +++-- libraries/aws_ec2_instance.rb | 20 ++++++++++---------- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/libraries/aws_backend.rb b/libraries/aws_backend.rb index be402028a..827a3a9fa 100644 --- a/libraries/aws_backend.rb +++ b/libraries/aws_backend.rb @@ -333,15 +333,16 @@ def waf_client end end - class AwsMockResource def initialize(opts) @opts = opts end private + attr_reader :opts - def method_missing(symbol, *args) + + def method_missing(_symbol, *_args) [opts[:resource_data]] end end diff --git a/libraries/aws_ec2_instance.rb b/libraries/aws_ec2_instance.rb index 7a710a5db..06d7af894 100644 --- a/libraries/aws_ec2_instance.rb +++ b/libraries/aws_ec2_instance.rb @@ -25,16 +25,16 @@ def initialize(opts = {}) if !opts[:resource_data] if opts[:instance_id] && !opts[:instance_id].empty? # Use instance_id, if provided - if !opts[:instance_id].is_a?(String) || opts[:instance_id] !~ /(^i-[0-9a-f]{8})|(^i-[0-9a-f]{17})$/ - raise ArgumentError, "#{@__resource_name__}: `instance_id` must be a string in the format of 'i-' followed by 8 or 17 hexadecimal characters." - end - @display_name = opts[:instance_id] - instance_arguments = { instance_ids: [opts[:instance_id]] } - elsif opts[:name] && !opts[:name].empty? # Otherwise use name, if provided - @display_name = opts[:name] - instance_arguments = { filters: [{ name: 'tag:Name', values: [opts[:name]] }] } - else - raise ArgumentError, "#{@__resource_name__}: either instance_id or name must be provided." + if !opts[:instance_id].is_a?(String) || opts[:instance_id] !~ /(^i-[0-9a-f]{8})|(^i-[0-9a-f]{17})$/ + raise ArgumentError, "#{@__resource_name__}: `instance_id` must be a string in the format of 'i-' followed by 8 or 17 hexadecimal characters." + end + @display_name = opts[:instance_id] + instance_arguments = { instance_ids: [opts[:instance_id]] } + elsif opts[:name] && !opts[:name].empty? # Otherwise use name, if provided + @display_name = opts[:name] + instance_arguments = { filters: [{ name: 'tag:Name', values: [opts[:name]] }] } + else + raise ArgumentError, "#{@__resource_name__}: either instance_id or name must be provided." end end