|
| 1 | +#!/bin/env python3 |
| 2 | +import argparse |
| 3 | +import os |
| 4 | + |
| 5 | +import boto3 |
| 6 | +from tqdm import tqdm |
| 7 | + |
| 8 | + |
| 9 | +""" |
| 10 | +This script expects a file txt with one AWS instance id per line, passed as --filename. |
| 11 | +It will go through those instances, and kill them if they are running |
| 12 | +To be used in case of runner issues or security concerns to quickly kill a subset of runners. |
| 13 | +Note this will stop and fail tests that are currently running. |
| 14 | +Use --dryrun to just list the instances without killing them |
| 15 | +
|
| 16 | +Make sure credentials are set in ~/.aws/credentials or as env variables |
| 17 | +""" |
| 18 | + |
| 19 | + |
| 20 | +def main(filename, region="us-east-1", dryrun=False): |
| 21 | + ec2 = boto3.client("ec2", region_name=region) |
| 22 | + |
| 23 | + with open(filename, "r") as f: |
| 24 | + instance_ids = [line.strip() for line in f.readlines()] |
| 25 | + |
| 26 | + print( |
| 27 | + f"Found {len(instance_ids)} instances in {filename} - region {region} - dryrun {dryrun}" |
| 28 | + ) |
| 29 | + |
| 30 | + non_existent_instances = [] |
| 31 | + running_instances = [] |
| 32 | + not_running_instances = [] |
| 33 | + |
| 34 | + pbar = tqdm(instance_ids, desc="Listing instances") |
| 35 | + for instance_id in pbar: |
| 36 | + try: |
| 37 | + response = ec2.describe_instances(InstanceIds=[instance_id]) |
| 38 | + status = response["Reservations"][0]["Instances"][0]["State"]["Name"] |
| 39 | + if status == "running": |
| 40 | + running_instances.append(instance_id) |
| 41 | + if not dryrun: |
| 42 | + ec2.terminate_instances(InstanceIds=[instance_id]) |
| 43 | + else: |
| 44 | + not_running_instances.append(instance_id) |
| 45 | + except Exception as e: |
| 46 | + non_existent_instances.append(instance_id) |
| 47 | + pbar.set_postfix( |
| 48 | + { |
| 49 | + "Non-existent": len(non_existent_instances), |
| 50 | + "Running": len(running_instances), |
| 51 | + "Not running": len(not_running_instances), |
| 52 | + } |
| 53 | + ) |
| 54 | + print("\nTerminated instances:") |
| 55 | + for instance_id in running_instances: |
| 56 | + print(instance_id) |
| 57 | + print("\nExisted but not running:") |
| 58 | + for instance_id in not_running_instances: |
| 59 | + print(instance_id) |
| 60 | + print("\nNon-existent instances:") |
| 61 | + for instance_id in non_existent_instances: |
| 62 | + print(instance_id) |
| 63 | + |
| 64 | + |
| 65 | +if __name__ == "__main__": |
| 66 | + parser = argparse.ArgumentParser(description="Terminate EC2 instances") |
| 67 | + parser.add_argument( |
| 68 | + "--filename", required=True, help="File containing instance IDs" |
| 69 | + ) |
| 70 | + parser.add_argument( |
| 71 | + "--dryrun", |
| 72 | + action="store_true", |
| 73 | + help="Dry run mode (do not actually terminate instances)", |
| 74 | + ) |
| 75 | + parser.add_argument( |
| 76 | + "--region", help="region to query ec2 instances from", default="us-east-1" |
| 77 | + ) |
| 78 | + args = parser.parse_args() |
| 79 | + main(filename=args.filename, region=args.region, dryrun=args.dryrun) |
0 commit comments