Common: Refactor aws_metadata to improve readablility

This commit is contained in:
Mike Salvatore 2022-05-05 15:14:47 -04:00
parent d977d19d9f
commit 07f57a83ad
1 changed files with 47 additions and 30 deletions

View File

@ -1,6 +1,7 @@
import json import json
import logging import logging
import re import re
from typing import Optional, Tuple
import requests import requests
@ -13,42 +14,54 @@ logger = logging.getLogger(__name__)
AWS_TIMEOUT = 2 AWS_TIMEOUT = 2
def fetch_aws_instance_metadata(): class UnknownAWSInstanceIDError(Exception):
"""Raised if the AWS Instance ID could not be determined"""
def fetch_aws_instance_metadata() -> Tuple[Optional[str], Optional[str], Optional[str]]:
instance_id = None instance_id = None
region = None region = None
account_id = None account_id = None
try: try:
response = requests.get( instance_id = _fetch_aws_instance_id()
AWS_LATEST_METADATA_URI_PREFIX + "meta-data/instance-id", region = _fetch_aws_region()
timeout=AWS_TIMEOUT, account_id = _fetch_account_id()
) except (
if not response: requests.RequestException,
return (None, None, None) IOError,
json.decoder.JSONDecodeError,
instance_id = response.text UnknownAWSInstanceIDError,
) as err:
region = _parse_region(
requests.get(
AWS_LATEST_METADATA_URI_PREFIX + "meta-data/placement/availability-zone",
timeout=AWS_TIMEOUT,
).text
)
account_id = _extract_account_id(
requests.get(
AWS_LATEST_METADATA_URI_PREFIX + "dynamic/instance-identity/document",
timeout=AWS_TIMEOUT,
).text
)
except (requests.RequestException, IOError, json.decoder.JSONDecodeError) as err:
logger.debug(f"Failed init of AWSInstance while getting metadata: {err}") logger.debug(f"Failed init of AWSInstance while getting metadata: {err}")
return (None, None, None) return (None, None, None)
return (instance_id, region, account_id) return (instance_id, region, account_id)
def _parse_region(region_url_response): def _fetch_aws_instance_id() -> Optional[str]:
url = AWS_LATEST_METADATA_URI_PREFIX + "meta-data/instance-id"
response = requests.get(
url,
timeout=AWS_TIMEOUT,
)
if not response:
raise UnknownAWSInstanceIDError(f"Failed fetch the AWS Instance ID from {url}")
return response.text
def _fetch_aws_region() -> Optional[str]:
return _parse_region(
requests.get(
AWS_LATEST_METADATA_URI_PREFIX + "meta-data/placement/availability-zone",
timeout=AWS_TIMEOUT,
).text
)
def _parse_region(region_url_response: str) -> Optional[str]:
# For a list of regions, see: # For a list of regions, see:
# https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/Concepts # https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/Concepts
# .RegionsAndAvailabilityZones.html # .RegionsAndAvailabilityZones.html
@ -61,14 +74,18 @@ def _parse_region(region_url_response):
return None return None
def _extract_account_id(instance_identity_document_response): def _fetch_account_id() -> str:
""" """
Extracts the account id from the dynamic/instance-identity/document metadata path. Fetches and extracts the account id from the dynamic/instance-identity/document metadata path.
Based on https://forums.aws.amazon.com/message.jspa?messageID=409028 which has a few more Based on https://forums.aws.amazon.com/message.jspa?messageID=409028 which has a few more
solutions, solutions, in case Amazon break this mechanism.
in case Amazon break this mechanism.
:param instance_identity_document_response: json returned via the web page :param instance_identity_document_response: json returned via the web page
../dynamic/instance-identity/document ../dynamic/instance-identity/document
:return: The account id :return: The account id
""" """
return json.loads(instance_identity_document_response)[ACCOUNT_ID_KEY] instance_identity_document = requests.get(
AWS_LATEST_METADATA_URI_PREFIX + "dynamic/instance-identity/document",
timeout=AWS_TIMEOUT,
).text
return json.loads(instance_identity_document)[ACCOUNT_ID_KEY]