-
Notifications
You must be signed in to change notification settings - Fork 8
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
17 changed files
with
913 additions
and
822 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,92 @@ | ||
| # AWS Resource Management | ||
| # Makefile for development, testing, and execution | ||
|
|
||
| .PHONY: help setup install-dev code-check run-dry-run run-stop run-start \ | ||
| run-stop-ec2 run-start-ec2 clean all | ||
|
|
||
| # Variables | ||
| SCRIPT_DIR = $(shell pwd) | ||
| MODULE_PATH = $(SCRIPT_DIR)/aws_resource_management.py | ||
| LOG_FILE = aws_resource_management.log | ||
|
|
||
| # Default target | ||
| help: | ||
| @echo "AWS Resource Management Tool Makefile" | ||
| @echo "" | ||
| @echo "Available targets:" | ||
| @echo " help - Show this help message" | ||
| @echo " setup - Set up the development environment" | ||
| @echo " install-dev - Install development dependencies" | ||
| @echo " code-check - Basic code checks (uses 'python -m py_compile')" | ||
| @echo " run-dry-run - Run the tool in dry-run mode (no changes)" | ||
| @echo " run-stop - Run the tool to stop all resources" | ||
| @echo " run-start - Run the tool to start all resources" | ||
| @echo " run-stop-ec2 - Run the tool to stop EC2 instances only" | ||
| @echo " run-start-ec2 - Run the tool to start EC2 instances only" | ||
| @echo " clean - Remove temporary and generated files" | ||
| @echo " all - Run code-check" | ||
|
|
||
| # Setup the development environment | ||
| setup: install-dev | ||
|
|
||
| # Install development dependencies | ||
| install-dev: | ||
| pip install boto3 | ||
|
|
||
| # Basic code check - no external tools needed | ||
| code-check: | ||
| @echo "Checking Python files for syntax errors..." | ||
| @if [ -f $(MODULE_PATH) ]; then \ | ||
| python -m py_compile $(MODULE_PATH) && echo "No syntax errors found in main script."; \ | ||
| else \ | ||
| echo "Warning: Main script $(MODULE_PATH) not found."; \ | ||
| fi | ||
| @if [ -d aws_resource_management ]; then \ | ||
| find aws_resource_management -name "*.py" -type f -exec python -m py_compile {} \; && \ | ||
| echo "No syntax errors found in module files."; \ | ||
| else \ | ||
| echo "Note: aws_resource_management directory not found. Skipping module checks."; \ | ||
| fi | ||
|
|
||
| # Run basic test verification | ||
| test: | ||
| @echo "Basic verification:" | ||
| @if [ -f $(MODULE_PATH) ]; then \ | ||
| echo "Main script exists."; \ | ||
| else \ | ||
| echo "Main script $(MODULE_PATH) not found."; \ | ||
| fi | ||
| @echo "For full testing, install pytest: pip install pytest pytest-mock" | ||
|
|
||
| # Run the tool in dry-run mode | ||
| run-dry-run: | ||
| python $(MODULE_PATH) --dry-run | ||
|
|
||
| # Run the tool to stop all resources | ||
| run-stop: | ||
| python $(MODULE_PATH) --action stop | ||
|
|
||
| # Run the tool to start all resources | ||
| run-start: | ||
| python $(MODULE_PATH) --action start | ||
|
|
||
| # Run the tool to stop EC2 instances only | ||
| run-stop-ec2: | ||
| python $(MODULE_PATH) --action stop --exclude-resources rds eks emr | ||
|
|
||
| # Run the tool to start EC2 instances only | ||
| run-start-ec2: | ||
| python $(MODULE_PATH) --action start --exclude-resources rds eks emr | ||
|
|
||
| # Clean up temporary files | ||
| clean: | ||
| rm -f $(LOG_FILE) | ||
| find . -name "__pycache__" -type d -exec rm -rf {} + | ||
| find . -name "*.pyc" -delete | ||
| find . -name "*.pyo" -delete | ||
| find . -name "*.pyd" -delete | ||
| find . -name ".pytest_cache" -type d -exec rm -rf {} + | ||
| @echo "Cleaned up temporary files." | ||
|
|
||
| # Run all development tasks | ||
| all: clean setup code-check test run-dry-run |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| """ | ||
| AWS Resource Management package. | ||
| Provides tools for managing AWS resources across multiple accounts. | ||
| """ | ||
|
|
||
| __version__ = "1.0.0" |
Binary file added
BIN
+1.48 KB
...app/python-tools/gfl-resource-actions/__pycache__/aws_resource_management.cpython-311.pyc
Binary file not shown.
Binary file added
BIN
+6.9 KB
local-app/python-tools/gfl-resource-actions/__pycache__/main.cpython-311.pyc
Binary file not shown.
51 changes: 51 additions & 0 deletions
51
local-app/python-tools/gfl-resource-actions/aws_resource_management.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,51 @@ | ||
| #!/usr/bin/env python3 | ||
| """ | ||
| Runner script for AWS Resource Management. | ||
| Acts as a wrapper for the main.py script. | ||
| """ | ||
|
|
||
| import sys | ||
| import os | ||
| import tempfile | ||
| import subprocess | ||
|
|
||
| if __name__ == "__main__": | ||
| # Get the current script directory | ||
| script_dir = os.path.dirname(os.path.abspath(__file__)) | ||
|
|
||
| # Path to main.py | ||
| main_path = os.path.join(script_dir, "main.py") | ||
|
|
||
| # Check if the main script exists | ||
| if not os.path.exists(main_path): | ||
| print(f"Error: Main script not found at {main_path}") | ||
| sys.exit(1) | ||
|
|
||
| # Create a temporary version of main.py with absolute imports | ||
| with open(main_path, "r") as f: | ||
| content = f.read() | ||
|
|
||
| # Replace relative imports with absolute imports | ||
| content = content.replace("from . import config", "import config") | ||
| content = content.replace("from .logging_utils", "from logging_utils") | ||
| content = content.replace("from .aws_utils", "from aws_utils") | ||
| content = content.replace("from .discovery", "from discovery") | ||
| content = content.replace("from .managers", "from managers") | ||
|
|
||
| # Write to temporary file | ||
| temp_file = tempfile.NamedTemporaryFile(suffix=".py", delete=False) | ||
| temp_file.write(content.encode('utf-8')) | ||
| temp_file.close() | ||
|
|
||
| try: | ||
| # Execute the temporary file with the current script directory in PYTHONPATH | ||
| cmd = [sys.executable, temp_file.name] + sys.argv[1:] | ||
| env = os.environ.copy() | ||
| env['PYTHONPATH'] = script_dir + os.pathsep + env.get('PYTHONPATH', '') | ||
|
|
||
| # Run the command and exit with its return code | ||
| result = subprocess.run(cmd, env=env) | ||
| sys.exit(result.returncode) | ||
| finally: | ||
| # Clean up the temporary file | ||
| os.unlink(temp_file.name) |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,27 @@ | ||
| """ | ||
| Configuration settings for AWS Resource Management. | ||
| """ | ||
|
|
||
| # Role name to assume in member accounts | ||
| ASSUME_ROLE_NAME = "OrganizationAccountAccessRole" | ||
|
|
||
| # Default node group sizes for EKS when starting | ||
| DEFAULT_NG_MIN_SIZE = 1 | ||
| DEFAULT_NG_DESIRED_SIZE = 1 | ||
|
|
||
| # Tag keys for storing node group sizes | ||
| TAG_KEY_ORIGINAL_MIN_SIZE = "managed-by:resource-management:original-min-size" | ||
| TAG_KEY_ORIGINAL_DESIRED_SIZE = "managed-by:resource-management:original-desired-size" | ||
|
|
||
| # Exclusion tag - resources with this tag will be excluded from management | ||
| EXCLUSION_TAG = "gfl_exclude" | ||
|
|
||
| # Service-specific tags that indicate managed EC2 instances | ||
| EKS_TAG = "eks:cluster-name" | ||
| EMR_TAG = "aws:elasticmapreduce:job-flow-id" | ||
|
|
||
| # Tag for tracking stop action | ||
| STOP_TAG = "gfl_stop" | ||
|
|
||
| # Log file name | ||
| LOG_FILE = "aws_resource_management.log" |
133 changes: 133 additions & 0 deletions
133
local-app/python-tools/gfl-resource-actions/discovery/discovery.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,133 @@ | ||
| """ | ||
| Resource discovery functions for AWS resources. | ||
| """ | ||
| from . import config | ||
| from .aws_utils import create_boto3_client | ||
| from .logging_utils import setup_logging | ||
|
|
||
| logger = setup_logging() | ||
|
|
||
| def get_ec2_instances(credentials, region): | ||
| """Get EC2 instances in a region.""" | ||
| try: | ||
| ec2_client = create_boto3_client('ec2', credentials, region) | ||
| instances = [] | ||
|
|
||
| response = ec2_client.describe_instances() | ||
| for reservation in response.get('Reservations', []): | ||
| for instance in reservation.get('Instances', []): | ||
| # Capture tags for exclusion check | ||
| tags = {tag['Key']: tag['Value'] for tag in instance.get('Tags', [])} | ||
|
|
||
| instances.append({ | ||
| "id": instance['InstanceId'], | ||
| "state": instance['State']['Name'], | ||
| "region": region, | ||
| "tags": tags | ||
| }) | ||
|
|
||
| # Handle pagination | ||
| while 'NextToken' in response: | ||
| response = ec2_client.describe_instances(NextToken=response['NextToken']) | ||
| for reservation in response.get('Reservations', []): | ||
| for instance in reservation.get('Instances', []): | ||
| # Capture tags for exclusion check | ||
| tags = {tag['Key']: tag['Value'] for tag in instance.get('Tags', [])} | ||
|
|
||
| instances.append({ | ||
| "id": instance['InstanceId'], | ||
| "state": instance['State']['Name'], | ||
| "region": region, | ||
| "tags": tags | ||
| }) | ||
|
|
||
| return instances | ||
| except Exception as e: | ||
| logger.error(f"Error getting EC2 instances in region {region}: {e}") | ||
| return [] | ||
|
|
||
| def get_rds_instances(credentials, region): | ||
| """Get RDS instances in a region.""" | ||
| try: | ||
| rds_client = create_boto3_client('rds', credentials, region) | ||
| instances = [] | ||
|
|
||
| response = rds_client.describe_db_instances() | ||
| for instance in response.get('DBInstances', []): | ||
| # Capture tags for exclusion check | ||
| tags = {} | ||
| try: | ||
| tag_list = rds_client.list_tags_for_resource( | ||
| ResourceName=instance['DBInstanceArn'] | ||
| ).get('TagList', []) | ||
| tags = {tag['Key']: tag['Value'] for tag in tag_list} | ||
| except Exception as tag_e: | ||
| logger.warning(f"Error getting tags for RDS instance {instance['DBInstanceIdentifier']}: {tag_e}") | ||
|
|
||
| instances.append({ | ||
| "id": instance['DBInstanceIdentifier'], | ||
| "status": instance['DBInstanceStatus'], | ||
| "region": region, | ||
| "tags": tags | ||
| }) | ||
|
|
||
| # Handle pagination | ||
| while 'Marker' in response: | ||
| response = rds_client.describe_db_instances(Marker=response['Marker']) | ||
| for instance in response.get('DBInstances', []): | ||
| # Capture tags for exclusion check | ||
| tags = {} | ||
| try: | ||
| tag_list = rds_client.list_tags_for_resource( | ||
| ResourceName=instance['DBInstanceArn'] | ||
| ).get('TagList', []) | ||
| tags = {tag['Key']: tag['Value'] for tag in tag_list} | ||
| except Exception as tag_e: | ||
| logger.warning(f"Error getting tags for RDS instance {instance['DBInstanceIdentifier']}: {tag_e}") | ||
|
|
||
| instances.append({ | ||
| "id": instance['DBInstanceIdentifier'], | ||
| "status": instance['DBInstanceStatus'], | ||
| "region": region, | ||
| "tags": tags | ||
| }) | ||
|
|
||
| return instances | ||
| except Exception as e: | ||
| logger.error(f"Error getting RDS instances in region {region}: {e}") | ||
| return [] | ||
|
|
||
| # Similarly implement get_eks_clusters() and get_emr_clusters()... | ||
|
|
||
| def get_account_resources(credentials, regions, exclude_resources=None): | ||
| """Get all resources from an account across specified regions.""" | ||
| if exclude_resources is None: | ||
| exclude_resources = [] | ||
|
|
||
| resources = { | ||
| "ec2_instances": [], | ||
| "rds_instances": [], | ||
| "eks_clusters": [], | ||
| "emr_clusters": [] | ||
| } | ||
|
|
||
| for region in regions: | ||
| # Get EC2 instances | ||
| if "ec2" not in exclude_resources: | ||
| resources["ec2_instances"].extend(get_ec2_instances(credentials, region)) | ||
|
|
||
| # Get RDS instances | ||
| if "rds" not in exclude_resources: | ||
| resources["rds_instances"].extend(get_rds_instances(credentials, region)) | ||
|
|
||
| # Get EKS clusters | ||
| if "eks" not in exclude_resources: | ||
| # Implementation would go here | ||
| pass | ||
|
|
||
| # Get EMR clusters | ||
| if "emr" not in exclude_resources: | ||
| # Implementation would go here | ||
| pass | ||
|
|
||
| return resources |
Oops, something went wrong.