Skip to content

Commit

Permalink
a little cleanup
Browse files Browse the repository at this point in the history
  • Loading branch information
morga471 committed Mar 14, 2025
1 parent 9f06bad commit 407713c
Show file tree
Hide file tree
Showing 8 changed files with 139 additions and 28 deletions.
1 change: 1 addition & 0 deletions local-app/python-tools/gfl-resource-actions/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,4 @@

# Log file name
LOG_FILE = "aws_resource_management.log"
ACTION_CSV_FILE = 'resource_actions.csv'
3 changes: 2 additions & 1 deletion local-app/python-tools/gfl-resource-actions/logging_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
import sys
import csv
import datetime
from config import ACTION_CSV_FILE

from pathlib import Path

# Configure log formats
Expand All @@ -14,7 +16,6 @@

# Configure CSV logging
CSV_LOG_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'logs')
ACTION_CSV_FILE = 'resource_actions.csv'
CSV_FIELDS = ['timestamp', 'account_id', 'account_name', 'resource_type', 'resource_id', 'resource_name', 'action', 'region', 'status', 'details']

def setup_logging(name='resource_management', level=logging.INFO):
Expand Down
10 changes: 5 additions & 5 deletions local-app/python-tools/gfl-resource-actions/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -150,11 +150,11 @@ def process_account(account, credentials, regions, action, dry_run, exclude_reso
logger.info(f"Account {account['id']} - Found {len(resources.get('eks_clusters', []))} EKS clusters")
logger.info(f"Account {account['id']} - Found {len(resources.get('emr_clusters', []))} EMR clusters")

# Initialize resource managers
ec2_manager = EC2Manager(credentials, account['id'])
rds_manager = RDSManager(credentials, account['id'])
eks_manager = EKSManager(credentials, account['id'])
emr_manager = EMRManager(credentials, account['id'])
# Initialize resource managers with account name
ec2_manager = EC2Manager(credentials, account['id'], account['name'])
rds_manager = RDSManager(credentials, account['id'], account['name'])
eks_manager = EKSManager(credentials, account['id'], account['name'])
emr_manager = EMRManager(credentials, account['id'], account['name'])

# Helper function to safely process manager results
def safe_get_result(result, key):
Expand Down
91 changes: 69 additions & 22 deletions local-app/python-tools/gfl-resource-actions/managers/base.py
Original file line number Diff line number Diff line change
@@ -1,55 +1,102 @@
"""
Base resource manager class with common functionality for AWS resources.
Base resource manager class that provides common functionality.
"""
import datetime
from aws_utils import create_boto3_client_for_account, get_partition_for_region
import config
from aws_utils import create_boto3_client, get_partition_for_region
from logging_utils import setup_logging

logger = setup_logging()

class ResourceManager:
"""Base class for AWS resource managers."""
"""Base class for all resource managers."""

def __init__(self, credentials, account_id):
def __init__(self, credentials, account_id, account_name=None):
"""
Initialize resource manager.
Initialize resource manager with credentials.
Args:
credentials: AWS credentials dictionary
account_id: AWS account ID
account_id: AWS account ID
account_name: AWS account name (optional)
"""
self.credentials = credentials
self.account_id = account_id

self.account_name = account_name or account_id
self.resource_type = "generic"

def create_client(self, service, region):
"""Create a boto3 client for the resource service."""
return create_boto3_client(service, self.credentials, region)
"""Create a boto3 client for the specified service and region."""
if not self.credentials:
return None

return boto3.client(
service,
region_name=region,
aws_access_key_id=self.credentials['AccessKeyId'],
aws_secret_access_key=self.credentials['SecretAccessKey'],
aws_session_token=self.credentials['SessionToken']
)

def get_partition_for_region(self, region):
"""Get AWS partition for the specified region."""
return get_partition_for_region(region)

def get_timestamp(self):
"""Get ISO 8601 timestamp."""
return datetime.datetime.now().isoformat()
"""Get ISO 8601 timestamp for tagging."""
return datetime.datetime.utcnow().isoformat()

def log_action(self, resource_id, region, action, details="", dry_run=False, existing_schedule=None):
"""Log a resource action to CSV for audit trail."""
def should_exclude(self, resource):
"""Check if resource should be excluded based on tags."""
tags = resource.get("tags", {})
return config.EXCLUSION_TAG in tags

def log_action(self, resource_id, region, action, resource_name=None, details=None, dry_run=False, existing_schedule=None):
"""
Log an action performed on a resource.
Args:
resource_id: Resource identifier
region: AWS region
action: Action performed (stop, start, etc.)
resource_name: Optional resource name
details: Optional additional details
dry_run: Whether this was a dry run
existing_schedule: Existing schedule for the resource
"""
dry_run_prefix = "[DRY RUN] " if dry_run else ""

# Build a detailed log message
resource_desc = f"{resource_id}"
if resource_name:
resource_desc = f"{resource_name} ({resource_id})"

account_desc = f"account {self.account_id}"
if self.account_name and self.account_name != self.account_id:
account_desc = f"{self.account_name} ({self.account_id})"

action_desc = f"{action}ed" if action[-1] != 'e' else f"{action}d"

message = f"{dry_run_prefix}{self.resource_type.upper()} {resource_desc} {action_desc} in {account_desc} region {region}"

if details:
message += f" - {details}"

# Add schedule information if available
if existing_schedule:
message += f" (Schedule: {existing_schedule})"

log_action_to_csv(
account_id=self.account_id,
account_name=self.account_name,
resource_type=self.resource_type,
resource_id=resource_id,
resource_name=resource_id, # Using ID as name for simplicity
resource_name=resource_name or resource_id, # Use ID as name if not provided
action=action,
region=region,
status="simulated" if dry_run else "success",
details=details,
dry_run=dry_run,
existing_schedule=existing_schedule
)

def should_exclude(self, resource):
"""Check if resource should be excluded based on tags."""
return config.EXCLUSION_TAG in resource.get("tags", {})

def get_partition_for_region(self, region):
"""Get AWS partition for region."""
return get_partition_for_region(region)
logger.info(message)
5 changes: 5 additions & 0 deletions local-app/python-tools/gfl-resource-actions/managers/ec2.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@
class EC2Manager(base.ResourceManager):
"""Manager for EC2 instances."""

def __init__(self, credentials, account_id, account_name=None):
"""Initialize EC2 manager."""
super().__init__(credentials, account_id, account_name)
self.resource_type = "ec2_instance"

def should_exclude(self, instance):
"""Check if EC2 instance should be excluded based on tags."""
tags = instance.get("tags", {})
Expand Down
47 changes: 47 additions & 0 deletions local-app/python-tools/gfl-resource-actions/managers/eks.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,53 @@
class EKSManager(base.ResourceManager):
"""Manager for EKS clusters."""

def __init__(self, credentials, account_id, account_name=None):
"""Initialize EKS manager."""
super().__init__(credentials, account_id, account_name)
self.resource_type = "eks_cluster"

# Add stop method that delegates to scale_down
def stop(self, clusters, dry_run=False):
"""
Stop EKS clusters by scaling down their nodegroups.
Args:
clusters: List of EKS cluster dictionaries
dry_run: If True, only simulate the action
Returns:
dict: Summary of actions taken
"""
logger.info(f"Delegating EKS stop operation to scale_down for {len(clusters)} clusters")
self.scale_down(clusters, dry_run)

# Return a result dictionary that matches the expected interface
return {
"success": len(clusters),
"errors": 0
}

# Add start method that delegates to scale_up
def start(self, clusters, dry_run=False):
"""
Start EKS clusters by scaling up their nodegroups.
Args:
clusters: List of EKS cluster dictionaries
dry_run: If True, only simulate the action
Returns:
dict: Summary of actions taken
"""
logger.info(f"Delegating EKS start operation to scale_up for {len(clusters)} clusters")
self.scale_up(clusters, dry_run)

# Return a result dictionary that matches the expected interface
return {
"success": len(clusters),
"errors": 0
}

def scale_down(self, clusters, dry_run=False):
"""Scale down EKS clusters by setting node counts to 0."""
logger.info(f"Evaluating {len(clusters)} EKS clusters for scale down action")
Expand Down
5 changes: 5 additions & 0 deletions local-app/python-tools/gfl-resource-actions/managers/emr.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@
class EMRManager(base.ResourceManager):
"""Manager for EMR clusters."""

def __init__(self, credentials, account_id, account_name=None):
"""Initialize EMR manager."""
super().__init__(credentials, account_id, account_name)
self.resource_type = "emr_cluster"

def stop(self, clusters, dry_run=False):
"""
Stop EMR clusters gracefully.
Expand Down
5 changes: 5 additions & 0 deletions local-app/python-tools/gfl-resource-actions/managers/rds.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@
class RDSManager(base.ResourceManager):
"""Manager for RDS instances."""

def __init__(self, credentials, account_id, account_name=None):
"""Initialize RDS manager."""
super().__init__(credentials, account_id, account_name)
self.resource_type = "rds_instance"

def stop(self, instances, dry_run=False):
"""Stop available RDS instances."""
logger.info(f"Evaluating {len(instances)} RDS instances for stop action")
Expand Down

0 comments on commit 407713c

Please sign in to comment.