From 743fb4223c3825899d1340353036a013f756373b Mon Sep 17 00:00:00 2001 From: Riccardo Magliocchetti Date: Wed, 18 Dec 2024 15:14:54 +0100 Subject: [PATCH 1/3] opentelemetry-sdk-extension-aws: make ec2 resource detector silent when loaded outside AWS Assume that if we fail to get the token quickly we are not on AWS. --- .../sdk/extension/aws/resource/ec2.py | 28 ++++++++++++++----- .../tests/resource/test_ec2.py | 11 ++++++++ 2 files changed, 32 insertions(+), 7 deletions(-) diff --git a/sdk-extension/opentelemetry-sdk-extension-aws/src/opentelemetry/sdk/extension/aws/resource/ec2.py b/sdk-extension/opentelemetry-sdk-extension-aws/src/opentelemetry/sdk/extension/aws/resource/ec2.py index b0cfeeb312..b10ada8089 100644 --- a/sdk-extension/opentelemetry-sdk-extension-aws/src/opentelemetry/sdk/extension/aws/resource/ec2.py +++ b/sdk-extension/opentelemetry-sdk-extension-aws/src/opentelemetry/sdk/extension/aws/resource/ec2.py @@ -14,6 +14,7 @@ import json import logging +from urllib.error import URLError from urllib.request import Request, urlopen from opentelemetry.sdk.resources import Resource, ResourceDetector @@ -27,39 +28,47 @@ _AWS_METADATA_TOKEN_HEADER = "X-aws-ec2-metadata-token" _GET_METHOD = "GET" +_AWS_METADATA_HOST = "169.254.169.254" -def _aws_http_request(method, path, headers): +def _aws_http_request(method, path, headers, timeout=None): + if timeout is None: + timeout = 5 with urlopen( Request( - "http://169.254.169.254" + path, headers=headers, method=method + "http://" + _AWS_METADATA_HOST + path, + headers=headers, + method=method, ), - timeout=5, + timeout=timeout, ) as response: return response.read().decode("utf-8") -def _get_token(): +def _get_token(timeout=None): return _aws_http_request( "PUT", "/latest/api/token", {"X-aws-ec2-metadata-token-ttl-seconds": "60"}, + timeout, ) -def _get_identity(token): +def _get_identity(token, timeout=None): return _aws_http_request( _GET_METHOD, "/latest/dynamic/instance-identity/document", {_AWS_METADATA_TOKEN_HEADER: token}, + timeout, ) -def _get_host(token): +def _get_host(token, timeout=None): return _aws_http_request( _GET_METHOD, "/latest/meta-data/hostname", {_AWS_METADATA_TOKEN_HEADER: token}, + timeout, ) @@ -72,7 +81,12 @@ class AwsEc2ResourceDetector(ResourceDetector): def detect(self) -> "Resource": try: - token = _get_token() + # If can't get a token quick assume we are not on ec2 + try: + token = _get_token(timeout=1) + except URLError: + return Resource.get_empty() + identity_dict = json.loads(_get_identity(token)) hostname = _get_host(token) diff --git a/sdk-extension/opentelemetry-sdk-extension-aws/tests/resource/test_ec2.py b/sdk-extension/opentelemetry-sdk-extension-aws/tests/resource/test_ec2.py index 300f963ac5..70034849a2 100644 --- a/sdk-extension/opentelemetry-sdk-extension-aws/tests/resource/test_ec2.py +++ b/sdk-extension/opentelemetry-sdk-extension-aws/tests/resource/test_ec2.py @@ -15,6 +15,7 @@ import unittest from collections import OrderedDict from unittest.mock import patch +from urllib.error import URLError from opentelemetry.sdk.extension.aws.resource.ec2 import ( # pylint: disable=no-name-in-module AwsEc2ResourceDetector, @@ -73,3 +74,13 @@ def test_simple_create( self.assertDictEqual( actual.attributes.copy(), OrderedDict(MockEc2ResourceAttributes) ) + + @patch( + "opentelemetry.sdk.extension.aws.resource.ec2._get_token", + side_effect=URLError("Something went wrong"), + ) + def test_empty_resource_if_token_returns_an_url_error( + self, mock_get_token + ): + actual = AwsEc2ResourceDetector().detect() + self.assertDictEqual(actual.attributes.copy(), OrderedDict()) From 0eba358e9adc63bd49236d64fd9970e23754c68a Mon Sep 17 00:00:00 2001 From: Riccardo Magliocchetti Date: Thu, 19 Dec 2024 10:25:48 +0100 Subject: [PATCH 2/3] Add changelog --- sdk-extension/opentelemetry-sdk-extension-aws/CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sdk-extension/opentelemetry-sdk-extension-aws/CHANGELOG.md b/sdk-extension/opentelemetry-sdk-extension-aws/CHANGELOG.md index c1c8286894..25201d51d1 100644 --- a/sdk-extension/opentelemetry-sdk-extension-aws/CHANGELOG.md +++ b/sdk-extension/opentelemetry-sdk-extension-aws/CHANGELOG.md @@ -7,6 +7,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased +- Make ec2 resource detector silent when loaded outside AWS + ([#3120](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3120)) - Make ecs and beanstalk resource detector silent when loaded outside AWS ([#3076](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3076)) - Make EKS resource detector don't warn when not running in EKS From 1462091d0c0897c2e33dd3832085d529fdf56807 Mon Sep 17 00:00:00 2001 From: Riccardo Magliocchetti Date: Mon, 23 Dec 2024 10:37:23 +0100 Subject: [PATCH 3/3] Keep a debug log in case we are not able to get the token --- .../opentelemetry/sdk/extension/aws/resource/ec2.py | 7 ++++++- .../tests/resource/test_ec2.py | 11 ++++++++++- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/sdk-extension/opentelemetry-sdk-extension-aws/src/opentelemetry/sdk/extension/aws/resource/ec2.py b/sdk-extension/opentelemetry-sdk-extension-aws/src/opentelemetry/sdk/extension/aws/resource/ec2.py index b10ada8089..cc497264f5 100644 --- a/sdk-extension/opentelemetry-sdk-extension-aws/src/opentelemetry/sdk/extension/aws/resource/ec2.py +++ b/sdk-extension/opentelemetry-sdk-extension-aws/src/opentelemetry/sdk/extension/aws/resource/ec2.py @@ -84,7 +84,12 @@ def detect(self) -> "Resource": # If can't get a token quick assume we are not on ec2 try: token = _get_token(timeout=1) - except URLError: + except URLError as exception: + logger.debug( + "%s failed to get token: %s", + self.__class__.__name__, + exception, + ) return Resource.get_empty() identity_dict = json.loads(_get_identity(token)) diff --git a/sdk-extension/opentelemetry-sdk-extension-aws/tests/resource/test_ec2.py b/sdk-extension/opentelemetry-sdk-extension-aws/tests/resource/test_ec2.py index 70034849a2..88815ed55b 100644 --- a/sdk-extension/opentelemetry-sdk-extension-aws/tests/resource/test_ec2.py +++ b/sdk-extension/opentelemetry-sdk-extension-aws/tests/resource/test_ec2.py @@ -82,5 +82,14 @@ def test_simple_create( def test_empty_resource_if_token_returns_an_url_error( self, mock_get_token ): - actual = AwsEc2ResourceDetector().detect() + with self.assertLogs( + "opentelemetry.sdk.extension.aws.resource.ec2", level="DEBUG" + ) as logger: + actual = AwsEc2ResourceDetector().detect() + self.assertEqual( + logger.output, + [ + "DEBUG:opentelemetry.sdk.extension.aws.resource.ec2:AwsEc2ResourceDetector failed to get token: " + ], + ) self.assertDictEqual(actual.attributes.copy(), OrderedDict())