Skip to content

Commit

Permalink
fix ecr
Browse files Browse the repository at this point in the history
  • Loading branch information
morga471 committed Apr 3, 2025
1 parent 6f72395 commit c11dc9b
Show file tree
Hide file tree
Showing 6 changed files with 277 additions and 79 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -503,7 +503,8 @@ def get_account_list() -> List[Dict[str, str]]:
_session_cache[cache_key] = {"accounts": accounts, "timestamp": time.time()}

return accounts
except Exception:
except Exception as e:
logger.warning(f"Failed to get accounts from Organizations API: {str(e)}")
# Fall back to profiles
accounts = _get_accounts_from_profiles()

Expand All @@ -522,11 +523,26 @@ def get_organization_accounts() -> List[Dict[str, str]]:
List of dictionaries with account information
"""
try:
accounts = _get_accounts_from_profiles()
# Use Organizations API to get accounts
session = boto3.Session()
org_client = session.client("organizations")
accounts = []

# Use pagination to get all accounts
paginator = org_client.get_paginator("list_accounts")
for page in paginator.paginate():
for account in page["Accounts"]:
if account["Status"] == "ACTIVE":
accounts.append(
{"account_id": account["Id"], "account_name": account["Name"]}
)

logger.info(f"Found {len(accounts)} accounts in Organizations API")
return accounts
except Exception as e:
logger.error(f"Error getting accounts from profiles: {str(e)}")
return []
logger.error(f"Error getting accounts from Organizations API: {str(e)}")
logger.info("Falling back to accounts from profiles")
return _get_accounts_from_profiles()


def _get_accounts_from_profiles() -> List[Dict[str, str]]:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,11 +73,18 @@ def process_accounts(
exclude_regions = exclude_regions or []
stats = stats or initialize_stats()

# Get account list - either from profiles or Organizations API
# Get account list from the organization you're currently authenticated with
accounts = self._get_accounts()

# Pre-filter accounts that we can authenticate with
valid_accounts = self._pre_validate_accounts(accounts)

# Log summary of accounts
logger.info(f"Found {len(accounts)} accounts to process")
logger.info(f"Found {len(valid_accounts)} accessible accounts to process")
if len(accounts) > len(valid_accounts):
logger.info(
f"Skipped {len(accounts) - len(valid_accounts)} inaccessible accounts"
)
if exclude_accounts:
logger.info(f"Excluding {len(exclude_accounts)} accounts")

Expand All @@ -87,7 +94,7 @@ def process_accounts(
) as executor:
# Create futures for each account
futures = []
for account in accounts:
for account in valid_accounts:
account_id = account.get("account_id")
if account_id in exclude_accounts:
stats["accounts_skipped"] += 1
Expand Down Expand Up @@ -132,13 +139,42 @@ def process_accounts(
logger.warning("Account processing interrupted by user")
raise

def _pre_validate_accounts(
self, accounts: List[Dict[str, str]]
) -> List[Dict[str, str]]:
"""
Pre-validate which accounts we can actually authenticate with.
Args:
accounts: List of account dictionaries with account_id and account_name
Returns:
List of accounts we can authenticate with
"""
valid_accounts = []
for account in accounts:
account_id = account.get("account_id")
try:
# Try to get credentials without actually making any API calls
credentials = get_credentials(account_id, self.profile_name)
if credentials:
valid_accounts.append(account)
else:
logger.debug(
f"No credentials available for account {account_id}, skipping"
)
except Exception as e:
logger.debug(f"Cannot authenticate with account {account_id}: {str(e)}")

return valid_accounts

def _get_accounts(self) -> List[Dict[str, str]]:
"""Get list of accounts from profiles or Organizations API."""
"""Get list of accounts from the current organization only."""
# Always use the Organizations API by default to get accounts from current org
# Only use profiles if explicitly requested (which should be rare)
if self.use_profiles:
logger.info("Using AWS SSO profiles for account discovery")
return (
get_organization_accounts()
) # Changed from get_accounts_from_profiles
return get_organization_accounts()
else:
logger.info("Using AWS Organizations API for account discovery")
return get_account_list()
Expand Down Expand Up @@ -368,15 +404,24 @@ def _process_resources(
exclusion_tag = self.config.get("exclusion_tag", "DoNotStop")
emr_tag = self.config.get("emr_tag", "aws:elasticmapreduce:job-flow-id")
ec2_instances = resources.get("ec2_instances", [])

# Fixed: Safely check for EKS tag prefixes in instance tags
eks_managed = sum(
1
for i in ec2_instances
if any(tag.startswith(eks_tag) for tag in i.get("tags", {}))
if any(
isinstance(tag_key, str) and tag_key.startswith(eks_tag)
for tag_key in i.get("tags", {})
)
)

# Fixed: Safely check for EMR tags in instance tags
emr_managed = sum(1 for i in ec2_instances if emr_tag in i.get("tags", {}))

excluded_ec2 = sum(
1 for i in ec2_instances if exclusion_tag in i.get("tags", {})
)

# Update resource counts
stats["ec2_found"] += len(ec2_instances)
stats["ec2_skipped"] += excluded_ec2
Expand Down Expand Up @@ -415,18 +460,26 @@ def _log_resource_counts(
for i in resources.get("ec2_instances", [])
if self.config.get("exclusion_tag") in i.get("tags", {})
)

eks_tag = self.config.get("eks_tag", "kubernetes.io/cluster/")
emr_tag = self.config.get("emr_tag", "aws:elasticmapreduce:job-flow-id")

# Fixed: Safely check for EKS tag prefixes in instance tags
eks_managed = sum(
1
for i in resources.get("ec2_instances", [])
if any(tag.startswith(eks_tag) for tag in i.get("tags", {}))
if any(
isinstance(tag_key, str) and tag_key.startswith(eks_tag)
for tag_key in i.get("tags", {})
)
)

emr_managed = sum(
1
for i in resources.get("ec2_instances", [])
if emr_tag in i.get("tags", {})
)

logger.info(
f"Account {account_id} - Found {total_ec2} EC2 instances ({excluded_ec2} explicitly excluded, {eks_managed} EKS-managed, {emr_managed} EMR-managed)"
)
Expand All @@ -451,7 +504,7 @@ def _create_resource_managers(
# We're using a default region here just for manager initialization
# Each method in the manager will use the appropriate region for the operation
default_region = self._get_default_regions(credentials)[0]

return {
"ec2": EC2Manager(account_id, default_region),
"rds": RDSManager(account_id, default_region),
Expand Down
Loading

0 comments on commit c11dc9b

Please sign in to comment.