Get a list of All Detached AWS EC2 Instances from an ASG

This task involves identifying AWS EC2 instances that are not currently associated with any Auto Scaling Groups (ASGs).

Note: region_name = None, fetches the results from all regions.

import boto3 from botocore.exceptions import NoCredentialsError, PartialCredentialsError, BotoCoreError, ClientError creds = _get_creds(cred_label)['creds'] access_key = creds['username'] secret_key = creds['password'] def list_all_regions(): ec2 = boto3.client('ec2', aws_access_key_id=access_key, aws_secret_access_key=secret_key, region_name='us-east-1') return [region['RegionName'] for region in ec2.describe_regions()['Regions']] def list_detached_ec2_instances(region=None): regions = [region] if region else list_all_regions() detached_instances = [] for region in regions: try: ec2_client = boto3.client('ec2', aws_access_key_id=access_key, aws_secret_access_key=secret_key, region_name=region) asg_client = boto3.client('autoscaling', aws_access_key_id=access_key, aws_secret_access_key=secret_key, region_name=region) except (NoCredentialsError, PartialCredentialsError, BotoCoreError) as e: print(f"Failed for {region}: {str(e)}") continue try: all_instances = [] paginator = ec2_client.get_paginator('describe_instances') for page in paginator.paginate(): for reservation in page['Reservations']: for instance in reservation['Instances']: all_instances.append(instance['InstanceId']) # Get all instance IDs in Auto Scaling Groups asg_instances = [] paginator = asg_client.get_paginator('describe_auto_scaling_instances') for page in paginator.paginate(): for asg_instance in page['AutoScalingInstances']: asg_instances.append(asg_instance['InstanceId']) # Determine detached instances by finding instances not in any ASG detached_instances_ids = set(all_instances) - set(asg_instances) # Fetch details for detached instances if detached_instances_ids: for instance_id in detached_instances_ids: response = ec2_client.describe_instances(InstanceIds=[instance_id]) for reservation in response['Reservations']: for instance in reservation['Instances']: detached_instances.append({ 'InstanceId': instance['InstanceId'], 'InstanceType': instance['InstanceType'], 'LaunchTime': instance['LaunchTime'], 'State': instance['State']['Name'], 'Region': region }) except ClientError as e: print(f"Failed for {region}: {e}") return detached_instances def display_detached_instance_details(data): # Check if any data is present if not data: print("No detached instances found.") return # Initialize the table with the desired structure and headers table = context.newtable() table.title = "Detached EC2 Instance Details" table.num_cols = 5 # Number of columns according to headers table.num_rows = 1 # Starts with one row for headers table.has_header_row = True # Define header names based on the new structure headers = ["Instance ID", "Instance Type", "Launch Time", "State", "Region"] # Set headers in the first row for col_num, header in enumerate(headers): table.setval(0, col_num, header) # Sort the instance data by launch time for better organization data.sort(key=lambda x: x["LaunchTime"], reverse=True) # Populate the table with instance data for row_num, instance in enumerate(data, start=1): # Starting from the second row table.num_rows += 1 # Add a row for each instance values = [ instance["InstanceId"], instance["InstanceType"], instance["LaunchTime"].strftime('%Y-%m-%d %H:%M:%S'), # Format the datetime instance["State"], instance["Region"] ] for col_num, value in enumerate(values): table.setval(row_num, col_num, value) # Example usage #region_name = None # Set this to a specific region or None to check all regions detached_instances = list_detached_ec2_instances(region_name) display_detached_instance_details(detached_instances)
copied