From 45c32abcdf72bc4f25f67bb25fb128d8ed547725 Mon Sep 17 00:00:00 2001 From: Daniel Barranquero <74871504+danibarranqueroo@users.noreply.github.com> Date: Tue, 15 Oct 2024 21:36:48 +0200 Subject: [PATCH] feat(autoscaling): add new check `autoscaling_group_multiple_instance_types` (#5325) Co-authored-by: Sergio --- .../__init__.py | 0 ...roup_multiple_instance_types.metadata.json | 32 ++ ...toscaling_group_multiple_instance_types.py | 34 ++ .../autoscaling/autoscaling_service.py | 14 + ...ling_group_multiple_instance_types_test.py | 418 ++++++++++++++++++ .../autoscaling/autoscaling_service_test.py | 111 +++++ 6 files changed, 609 insertions(+) create mode 100644 prowler/providers/aws/services/autoscaling/autoscaling_group_multiple_instance_types/__init__.py create mode 100644 prowler/providers/aws/services/autoscaling/autoscaling_group_multiple_instance_types/autoscaling_group_multiple_instance_types.metadata.json create mode 100644 prowler/providers/aws/services/autoscaling/autoscaling_group_multiple_instance_types/autoscaling_group_multiple_instance_types.py create mode 100644 tests/providers/aws/services/autoscaling/autoscaling_group_multiple_instance_types/autoscaling_group_multiple_instance_types_test.py diff --git a/prowler/providers/aws/services/autoscaling/autoscaling_group_multiple_instance_types/__init__.py b/prowler/providers/aws/services/autoscaling/autoscaling_group_multiple_instance_types/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/prowler/providers/aws/services/autoscaling/autoscaling_group_multiple_instance_types/autoscaling_group_multiple_instance_types.metadata.json b/prowler/providers/aws/services/autoscaling/autoscaling_group_multiple_instance_types/autoscaling_group_multiple_instance_types.metadata.json new file mode 100644 index 0000000000..7604051326 --- /dev/null +++ b/prowler/providers/aws/services/autoscaling/autoscaling_group_multiple_instance_types/autoscaling_group_multiple_instance_types.metadata.json @@ -0,0 +1,32 @@ +{ + "Provider": "aws", + "CheckID": "autoscaling_group_multiple_instance_types", + "CheckTitle": "EC2 Auto Scaling Group should use multiple instance types in multiple Availability Zones.", + "CheckType": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "ServiceName": "autoscaling", + "SubServiceName": "", + "ResourceIdTemplate": "arn:partition:autoscaling:region:account-id:autoScalingGroupName/resource-name", + "Severity": "medium", + "ResourceType": "AwsAutoScalingAutoScalingGroup", + "Description": "This control checks whether an Amazon EC2 Auto Scaling group uses multiple instance types in all the Availability Zones, meaning that there should be multiple Availability Zones with multiple instances on each one. The control fails if the Auto Scaling group has only one instance type defined.", + "Risk": "Using only one instance type in an Auto Scaling group reduces the flexibility to launch new instances when there is insufficient capacity for that specific type, potentially affecting the availability of the application.", + "RelatedUrl": "https://docs.aws.amazon.com/autoscaling/ec2/userguide/ec2-auto-scaling-mixed-instances-groups.html", + "Remediation": { + "Code": { + "CLI": "aws autoscaling create-auto-scaling-group --mixed-instances-policy ...", + "NativeIaC": "", + "Other": "https://docs.aws.amazon.com/securityhub/latest/userguide/autoscaling-controls.html#autoscaling-6", + "Terraform": "" + }, + "Recommendation": { + "Text": "Configure your EC2 Auto Scaling group to use multiple instance types across multiple Availability Zones.", + "Url": "https://www.trendmicro.com/cloudoneconformity/knowledge-base/aws/AutoScaling/asg-multiple-instance-type-az.html" + } + }, + "Categories": [], + "DependsOn": [], + "RelatedTo": [], + "Notes": "" +} diff --git a/prowler/providers/aws/services/autoscaling/autoscaling_group_multiple_instance_types/autoscaling_group_multiple_instance_types.py b/prowler/providers/aws/services/autoscaling/autoscaling_group_multiple_instance_types/autoscaling_group_multiple_instance_types.py new file mode 100644 index 0000000000..5dd8bae2a5 --- /dev/null +++ b/prowler/providers/aws/services/autoscaling/autoscaling_group_multiple_instance_types/autoscaling_group_multiple_instance_types.py @@ -0,0 +1,34 @@ +from prowler.lib.check.models import Check, Check_Report_AWS +from prowler.providers.aws.services.autoscaling.autoscaling_client import ( + autoscaling_client, +) + + +class autoscaling_group_multiple_instance_types(Check): + def execute(self): + findings = [] + for group in autoscaling_client.groups: + report = Check_Report_AWS(self.metadata()) + report.region = group.region + report.resource_id = group.name + report.resource_arn = group.arn + report.resource_tags = group.tags + report.status = "FAIL" + report.status_extended = f"Autoscaling group {group.name} does not have multiple instance types in multiple Availability Zones." + + failing_azs = [] + + for az, types in group.az_instance_types.items(): + if len(types) < 2: + failing_azs.append(az) + + if not failing_azs and len(group.az_instance_types) > 1: + report.status = "PASS" + report.status_extended = f"Autoscaling group {group.name} has multiple instance types in each of its Availability Zones." + elif failing_azs: + azs_str = ", ".join(failing_azs) + report.status_extended = f"Autoscaling group {group.name} has only one or no instance types in Availability Zone(s): {azs_str}." + + findings.append(report) + + return findings diff --git a/prowler/providers/aws/services/autoscaling/autoscaling_service.py b/prowler/providers/aws/services/autoscaling/autoscaling_service.py index 0dbc2cd2a3..b207b89d2a 100644 --- a/prowler/providers/aws/services/autoscaling/autoscaling_service.py +++ b/prowler/providers/aws/services/autoscaling/autoscaling_service.py @@ -66,6 +66,16 @@ class AutoScaling(AWSService): self.audit_resources, ) ): + instance_types = [] + az_instance_types = {} + for instance in group.get("Instances", []): + az = instance["AvailabilityZone"] + instance_type = instance["InstanceType"] + instance_types.append(instance_type) + if az not in az_instance_types: + az_instance_types[az] = set() + az_instance_types[az].add(instance_type) + self.groups.append( Group( arn=group.get("AutoScalingGroupARN"), @@ -73,6 +83,8 @@ class AutoScaling(AWSService): region=regional_client.region, availability_zones=group.get("AvailabilityZones"), tags=group.get("Tags"), + instance_types=instance_types, + az_instance_types=az_instance_types, launch_template=group.get("LaunchTemplate", {}), mixed_instances_policy_launch_template=group.get( "MixedInstancesPolicy", {} @@ -154,6 +166,8 @@ class Group(BaseModel): region: str availability_zones: list tags: list = [] + instance_types: list = [] + az_instance_types: dict = {} launch_template: dict = {} mixed_instances_policy_launch_template: dict = {} health_check_type: str diff --git a/tests/providers/aws/services/autoscaling/autoscaling_group_multiple_instance_types/autoscaling_group_multiple_instance_types_test.py b/tests/providers/aws/services/autoscaling/autoscaling_group_multiple_instance_types/autoscaling_group_multiple_instance_types_test.py new file mode 100644 index 0000000000..9dc2a24976 --- /dev/null +++ b/tests/providers/aws/services/autoscaling/autoscaling_group_multiple_instance_types/autoscaling_group_multiple_instance_types_test.py @@ -0,0 +1,418 @@ +from unittest import mock + +import botocore +from boto3 import client +from moto import mock_aws + +from tests.providers.aws.utils import AWS_REGION_US_EAST_1, set_mocked_aws_provider + +make_api_call = botocore.client.BaseClient._make_api_call + + +def mock_make_api_call_multi_az(self, operation_name, kwarg): + if operation_name == "DescribeAutoScalingGroups": + return { + "AutoScalingGroups": [ + { + "AutoScalingGroupName": "my-autoscaling-group", + "AutoScalingGroupARN": "arn:aws:autoscaling:us-east-1:123456789012:autoScalingGroup:uuid:autoScalingGroupName/my-autoscaling-group", + "AvailabilityZones": ["us-east-1a", "us-east-1b"], + "Tags": [], + "Instances": [ + { + "InstanceId": "i-0b9f1f3a0e1e3e0f4", + "InstanceType": "t2.micro", + "AvailabilityZone": "us-east-1a", + }, + { + "InstanceId": "i-0b9f1f3a0e1e3e0f5", + "InstanceType": "t3.large", + "AvailabilityZone": "us-east-1b", + }, + ], + } + ] + } + return make_api_call(self, operation_name, kwarg) + + +def mock_make_api_call_single_az(self, operation_name, kwarg): + if operation_name == "DescribeAutoScalingGroups": + return { + "AutoScalingGroups": [ + { + "AutoScalingGroupName": "my-autoscaling-group", + "AutoScalingGroupARN": "arn:aws:autoscaling:us-east-1:123456789012:autoScalingGroup:uuid:autoScalingGroupName/my-autoscaling-group", + "AvailabilityZones": ["us-east-1a"], + "Tags": [], + "Instances": [ + { + "InstanceId": "i-0b9f1f3a0e1e3e0f4", + "InstanceType": "t2.micro", + "AvailabilityZone": "us-east-1a", + }, + { + "InstanceId": "i-0b9f1f3a0e1e3e0f5", + "InstanceType": "t3.large", + "AvailabilityZone": "us-east-1a", + }, + ], + } + ] + } + return make_api_call(self, operation_name, kwarg) + + +def mock_make_api_call(self, operation_name, kwarg): + if operation_name == "DescribeAutoScalingGroups": + return { + "AutoScalingGroups": [ + { + "AutoScalingGroupName": "my-autoscaling-group", + "AutoScalingGroupARN": "arn:aws:autoscaling:us-east-1:123456789012:autoScalingGroup:uuid:autoScalingGroupName/my-autoscaling-group", + "AvailabilityZones": ["us-east-1a", "us-east-1b"], + "Tags": [], + "Instances": [ + { + "InstanceId": "i-0b9f1f3a0e1e3e0f4", + "InstanceType": "t2.micro", + "AvailabilityZone": "us-east-1a", + }, + { + "InstanceId": "i-0b9f1f3a0e1e3e0f5", + "InstanceType": "t3.large", + "AvailabilityZone": "us-east-1a", + }, + { + "InstanceId": "i-0b9f1f3a0e1e3e0f6", + "InstanceType": "t2.micro", + "AvailabilityZone": "us-east-1b", + }, + { + "InstanceId": "i-0b9f1f3a0e1e3e0f7", + "InstanceType": "t3.large", + "AvailabilityZone": "us-east-1b", + }, + ], + } + ] + } + return make_api_call(self, operation_name, kwarg) + + +class Test_autoscaling_group_multiple_instance_types: + @mock_aws + def test_no_autoscaling(self): + autoscaling_client = client("autoscaling", region_name=AWS_REGION_US_EAST_1) + autoscaling_client.groups = [] + + from prowler.providers.aws.services.autoscaling.autoscaling_service import ( + AutoScaling, + ) + + aws_provider = set_mocked_aws_provider([AWS_REGION_US_EAST_1]) + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=aws_provider, + ), mock.patch( + "prowler.providers.aws.services.autoscaling.autoscaling_group_multiple_instance_types.autoscaling_group_multiple_instance_types.autoscaling_client", + new=AutoScaling(aws_provider), + ): + # Test Check + from prowler.providers.aws.services.autoscaling.autoscaling_group_multiple_instance_types.autoscaling_group_multiple_instance_types import ( + autoscaling_group_multiple_instance_types, + ) + + check = autoscaling_group_multiple_instance_types() + result = check.execute() + + assert len(result) == 0 + + @mock_aws + def test_groups_with_multi_az_one_or_less_instances(self): + autoscaling_client = client("autoscaling", region_name=AWS_REGION_US_EAST_1) + autoscaling_client.create_launch_configuration( + LaunchConfigurationName="test", + ImageId="ami-12c6146b", + InstanceType="t1.micro", + KeyName="the_keys", + SecurityGroups=["default", "default2"], + ) + autoscaling_group_name = "my-autoscaling-group" + autoscaling_client.create_auto_scaling_group( + AutoScalingGroupName=autoscaling_group_name, + LaunchConfigurationName="test", + MinSize=0, + MaxSize=0, + DesiredCapacity=0, + AvailabilityZones=["us-east-1a", "us-east-1b"], + ) + + autoscaling_group_arn = autoscaling_client.describe_auto_scaling_groups( + AutoScalingGroupNames=[autoscaling_group_name] + )["AutoScalingGroups"][0]["AutoScalingGroupARN"] + + from prowler.providers.aws.services.autoscaling.autoscaling_service import ( + AutoScaling, + ) + + aws_provider = set_mocked_aws_provider([AWS_REGION_US_EAST_1]) + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=aws_provider, + ), mock.patch( + "prowler.providers.aws.services.autoscaling.autoscaling_group_multiple_instance_types.autoscaling_group_multiple_instance_types.autoscaling_client", + new=AutoScaling(aws_provider), + ): + # Test Check + from prowler.providers.aws.services.autoscaling.autoscaling_group_multiple_instance_types.autoscaling_group_multiple_instance_types import ( + autoscaling_group_multiple_instance_types, + ) + + check = autoscaling_group_multiple_instance_types() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "FAIL" + assert ( + result[0].status_extended + == f"Autoscaling group {autoscaling_group_name} does not have multiple instance types in multiple Availability Zones." + ) + assert result[0].resource_id == autoscaling_group_name + assert result[0].resource_arn == autoscaling_group_arn + assert result[0].region == AWS_REGION_US_EAST_1 + assert result[0].resource_tags == [] + + @mock_aws + def test_groups_with_single_az_one_or_less_instances(self): + autoscaling_client = client("autoscaling", region_name=AWS_REGION_US_EAST_1) + autoscaling_client.create_launch_configuration( + LaunchConfigurationName="test", + ImageId="ami-12c6146b", + InstanceType="t1.micro", + KeyName="the_keys", + SecurityGroups=["default", "default2"], + ) + autoscaling_group_name = "my-autoscaling-group" + autoscaling_client.create_auto_scaling_group( + AutoScalingGroupName=autoscaling_group_name, + LaunchConfigurationName="test", + MinSize=0, + MaxSize=0, + DesiredCapacity=0, + AvailabilityZones=["us-east-1a"], + ) + + autoscaling_group_arn = autoscaling_client.describe_auto_scaling_groups( + AutoScalingGroupNames=[autoscaling_group_name] + )["AutoScalingGroups"][0]["AutoScalingGroupARN"] + + from prowler.providers.aws.services.autoscaling.autoscaling_service import ( + AutoScaling, + ) + + aws_provider = set_mocked_aws_provider([AWS_REGION_US_EAST_1]) + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=aws_provider, + ), mock.patch( + "prowler.providers.aws.services.autoscaling.autoscaling_group_multiple_instance_types.autoscaling_group_multiple_instance_types.autoscaling_client", + new=AutoScaling(aws_provider), + ): + # Test Check + from prowler.providers.aws.services.autoscaling.autoscaling_group_multiple_instance_types.autoscaling_group_multiple_instance_types import ( + autoscaling_group_multiple_instance_types, + ) + + check = autoscaling_group_multiple_instance_types() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "FAIL" + assert ( + result[0].status_extended + == f"Autoscaling group {autoscaling_group_name} does not have multiple instance types in multiple Availability Zones." + ) + assert result[0].resource_id == autoscaling_group_name + assert result[0].resource_tags == [] + assert result[0].resource_arn == autoscaling_group_arn + + @mock_aws + def test_groups_with_multi_az_multi_instances_but_not_in_each_az(self): + with mock.patch( + "botocore.client.BaseClient._make_api_call", new=mock_make_api_call_multi_az + ): + autoscaling_client = client("autoscaling", region_name=AWS_REGION_US_EAST_1) + autoscaling_client.create_launch_configuration( + LaunchConfigurationName="test", + ImageId="ami-12c6146b", + InstanceType="t1.micro", + KeyName="the_keys", + SecurityGroups=["default", "default2"], + ) + autoscaling_group_name = "my-autoscaling-group" + autoscaling_client.create_auto_scaling_group( + AutoScalingGroupName=autoscaling_group_name, + LaunchConfigurationName="test", + MinSize=0, + MaxSize=0, + DesiredCapacity=0, + AvailabilityZones=["us-east-1a", "us-east-1b"], + ) + + autoscaling_group_arn = autoscaling_client.describe_auto_scaling_groups( + AutoScalingGroupNames=[autoscaling_group_name] + )["AutoScalingGroups"][0]["AutoScalingGroupARN"] + + from prowler.providers.aws.services.autoscaling.autoscaling_service import ( + AutoScaling, + ) + + aws_provider = set_mocked_aws_provider([AWS_REGION_US_EAST_1]) + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=aws_provider, + ), mock.patch( + "prowler.providers.aws.services.autoscaling.autoscaling_group_multiple_instance_types.autoscaling_group_multiple_instance_types.autoscaling_client", + new=AutoScaling(aws_provider), + ): + # Test Check + from prowler.providers.aws.services.autoscaling.autoscaling_group_multiple_instance_types.autoscaling_group_multiple_instance_types import ( + autoscaling_group_multiple_instance_types, + ) + + check = autoscaling_group_multiple_instance_types() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "FAIL" + assert ( + result[0].status_extended + == f"Autoscaling group {autoscaling_group_name} has only one or no instance types in Availability Zone(s): us-east-1a, us-east-1b." + ) + assert result[0].resource_id == autoscaling_group_name + assert result[0].resource_arn == autoscaling_group_arn + assert result[0].region == AWS_REGION_US_EAST_1 + assert result[0].resource_tags == [] + + @mock_aws + def test_groups_with_single_az_multi_instances(self): + with mock.patch( + "botocore.client.BaseClient._make_api_call", + new=mock_make_api_call_single_az, + ): + autoscaling_client = client("autoscaling", region_name=AWS_REGION_US_EAST_1) + autoscaling_client.create_launch_configuration( + LaunchConfigurationName="test", + ImageId="ami-12c6146b", + InstanceType="t1.micro", + KeyName="the_keys", + SecurityGroups=["default", "default2"], + ) + autoscaling_group_name = "my-autoscaling-group" + autoscaling_client.create_auto_scaling_group( + AutoScalingGroupName=autoscaling_group_name, + LaunchConfigurationName="test", + MinSize=0, + MaxSize=0, + DesiredCapacity=0, + AvailabilityZones=["us-east-1a"], + ) + + autoscaling_group_arn = autoscaling_client.describe_auto_scaling_groups( + AutoScalingGroupNames=[autoscaling_group_name] + )["AutoScalingGroups"][0]["AutoScalingGroupARN"] + + from prowler.providers.aws.services.autoscaling.autoscaling_service import ( + AutoScaling, + ) + + aws_provider = set_mocked_aws_provider([AWS_REGION_US_EAST_1]) + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=aws_provider, + ), mock.patch( + "prowler.providers.aws.services.autoscaling.autoscaling_group_multiple_instance_types.autoscaling_group_multiple_instance_types.autoscaling_client", + new=AutoScaling(aws_provider), + ): + # Test Check + from prowler.providers.aws.services.autoscaling.autoscaling_group_multiple_instance_types.autoscaling_group_multiple_instance_types import ( + autoscaling_group_multiple_instance_types, + ) + + check = autoscaling_group_multiple_instance_types() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "FAIL" + assert ( + result[0].status_extended + == f"Autoscaling group {autoscaling_group_name} does not have multiple instance types in multiple Availability Zones." + ) + assert result[0].resource_id == autoscaling_group_name + assert result[0].resource_tags == [] + assert result[0].resource_arn == autoscaling_group_arn + + @mock_aws + def test_groups_with_multi_az_multi_instances_in_each_one(self): + with mock.patch( + "botocore.client.BaseClient._make_api_call", new=mock_make_api_call + ): + autoscaling_client = client("autoscaling", region_name=AWS_REGION_US_EAST_1) + autoscaling_client.create_launch_configuration( + LaunchConfigurationName="test", + ImageId="ami-12c6146b", + InstanceType="t1.micro", + KeyName="the_keys", + SecurityGroups=["default", "default2"], + ) + autoscaling_group_name = "my-autoscaling-group" + autoscaling_client.create_auto_scaling_group( + AutoScalingGroupName=autoscaling_group_name, + LaunchConfigurationName="test", + MinSize=0, + MaxSize=0, + DesiredCapacity=0, + AvailabilityZones=["us-east-1a", "us-east-1b"], + ) + + autoscaling_group_arn = autoscaling_client.describe_auto_scaling_groups( + AutoScalingGroupNames=[autoscaling_group_name] + )["AutoScalingGroups"][0]["AutoScalingGroupARN"] + + from prowler.providers.aws.services.autoscaling.autoscaling_service import ( + AutoScaling, + ) + + aws_provider = set_mocked_aws_provider([AWS_REGION_US_EAST_1]) + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=aws_provider, + ), mock.patch( + "prowler.providers.aws.services.autoscaling.autoscaling_group_multiple_instance_types.autoscaling_group_multiple_instance_types.autoscaling_client", + new=AutoScaling(aws_provider), + ): + # Test Check + from prowler.providers.aws.services.autoscaling.autoscaling_group_multiple_instance_types.autoscaling_group_multiple_instance_types import ( + autoscaling_group_multiple_instance_types, + ) + + check = autoscaling_group_multiple_instance_types() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "PASS" + assert ( + result[0].status_extended + == f"Autoscaling group {autoscaling_group_name} has multiple instance types in each of its Availability Zones." + ) + assert result[0].resource_id == autoscaling_group_name + assert result[0].resource_arn == autoscaling_group_arn + assert result[0].region == AWS_REGION_US_EAST_1 + assert result[0].resource_tags == [] diff --git a/tests/providers/aws/services/autoscaling/autoscaling_service_test.py b/tests/providers/aws/services/autoscaling/autoscaling_service_test.py index 57ebc1a7fb..dcbd208842 100644 --- a/tests/providers/aws/services/autoscaling/autoscaling_service_test.py +++ b/tests/providers/aws/services/autoscaling/autoscaling_service_test.py @@ -1,5 +1,7 @@ from base64 import b64decode +import botocore +import mock from boto3 import client from moto import mock_aws @@ -14,6 +16,53 @@ from tests.providers.aws.utils import ( set_mocked_aws_provider, ) +make_api_call = botocore.client.BaseClient._make_api_call + + +def mock_make_api_call(self, operation_name, kwarg): + if operation_name == "DescribeAutoScalingGroups": + return { + "AutoScalingGroups": [ + { + "AutoScalingGroupName": "my-autoscaling-group", + "AutoScalingGroupARN": "arn:aws:autoscaling:us-east-1:123456789012:autoScalingGroup:uuid:autoScalingGroupName/my-autoscaling-group", + "AvailabilityZones": ["us-east-1a", "us-east-1b"], + "Tags": [ + { + "Key": "tag_test", + "PropagateAtLaunch": False, + "ResourceId": "my-autoscaling-group", + "ResourceType": "auto-scaling-group", + "Value": "value_test", + } + ], + "Instances": [ + { + "InstanceId": "i-0b9f1f3a0e1e3e0f4", + "InstanceType": "t2.micro", + "AvailabilityZone": "us-east-1a", + }, + { + "InstanceId": "i-0b9f1f3a0e1e3e0f5", + "InstanceType": "t3.large", + "AvailabilityZone": "us-east-1a", + }, + { + "InstanceId": "i-0b9f1f3a0e1e3e0f6", + "InstanceType": "t2.micro", + "AvailabilityZone": "us-east-1b", + }, + { + "InstanceId": "i-0b9f1f3a0e1e3e0f7", + "InstanceType": "t3.large", + "AvailabilityZone": "us-east-1b", + }, + ], + } + ] + } + return make_api_call(self, operation_name, kwarg) + class Test_AutoScaling_Service: # Test AutoScaling Service @@ -105,6 +154,68 @@ class Test_AutoScaling_Service: assert launch_configurations[arn_tester2].http_tokens == "required" assert launch_configurations[arn_tester2].http_endpoint == "enabled" + # Test Describe Auto Scaling Groups With Botocore + @mock_aws + def test_describe_auto_scaling_groups_with_attached_instances(self): + with mock.patch( + "botocore.client.BaseClient._make_api_call", new=mock_make_api_call + ): + # Generate AutoScaling Client + autoscaling_client = client("autoscaling", region_name=AWS_REGION_US_EAST_1) + autoscaling_client.create_launch_configuration( + LaunchConfigurationName="test", + ImageId="ami-12c6146b", + InstanceType="t1.micro", + KeyName="the_keys", + SecurityGroups=["default", "default2"], + ) + autoscaling_client.create_auto_scaling_group( + AutoScalingGroupName="my-autoscaling-group", + LaunchConfigurationName="test", + MinSize=0, + MaxSize=0, + DesiredCapacity=0, + AvailabilityZones=["us-east-1a", "us-east-1b"], + Tags=[ + { + "Key": "tag_test", + "Value": "value_test", + }, + ], + ) + + # AutoScaling client for this test class + aws_provider = set_mocked_aws_provider([AWS_REGION_US_EAST_1]) + autoscaling = AutoScaling(aws_provider) + assert len(autoscaling.groups) == 1 + # create_auto_scaling_group doesn't return the ARN, can't check it + # assert autoscaling.groups[0].arn == + assert autoscaling.groups[0].name == "my-autoscaling-group" + assert autoscaling.groups[0].region == AWS_REGION_US_EAST_1 + assert autoscaling.groups[0].availability_zones == [ + "us-east-1a", + "us-east-1b", + ] + assert autoscaling.groups[0].tags == [ + { + "Key": "tag_test", + "PropagateAtLaunch": False, + "ResourceId": "my-autoscaling-group", + "ResourceType": "auto-scaling-group", + "Value": "value_test", + } + ] + assert autoscaling.groups[0].instance_types == [ + "t2.micro", + "t3.large", + "t2.micro", + "t3.large", + ] + assert autoscaling.groups[0].az_instance_types == { + "us-east-1a": {"t2.micro", "t3.large"}, + "us-east-1b": {"t2.micro", "t3.large"}, + } + # Test Describe Auto Scaling Groups @mock_aws def test_describe_auto_scaling_groups(self):