Skip to content

Fix azure vm resource detector tests/Suppress instrumentation for urllib call #2178

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Feb 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## Unreleased

- Drop uspport for 3.7
- Drop support for 3.7
([#2151](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2151))
- `opentelemetry-resource-detector-azure` Added 10s timeout to VM Resource Detector
([#2119](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2119))
Expand All @@ -17,6 +17,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
([#2132](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2132))
- `opentelemetry-resource-detector-azure` Changed timeout to 4 seconds due to [timeout bug](https://github.com/open-telemetry/opentelemetry-python/issues/3644)
([#2136](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2136))
- `opentelemetry-resource-detector-azure` Suppress instrumentation for `urllib` call
([#2178](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2178))

## Version 1.22.0/0.43b0 (2023-12-14)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,12 @@
from urllib.error import URLError
from urllib.request import Request, urlopen

from opentelemetry.context import (
_SUPPRESS_INSTRUMENTATION_KEY,
attach,
detach,
set_value,
)
from opentelemetry.sdk.resources import Resource, ResourceDetector
from opentelemetry.semconv.resource import (
CloudPlatformValues,
Expand Down Expand Up @@ -49,64 +55,60 @@ class AzureVMResourceDetector(ResourceDetector):
# pylint: disable=no-self-use
def detect(self) -> "Resource":
attributes = {}
metadata_json = (
_AzureVMMetadataServiceRequestor().get_azure_vm_metadata()
)
token = attach(set_value(_SUPPRESS_INSTRUMENTATION_KEY, True))
metadata_json = _get_azure_vm_metadata()
if not metadata_json:
return Resource(attributes)
for attribute_key in EXPECTED_AZURE_AMS_ATTRIBUTES:
attributes[
attribute_key
] = _AzureVMMetadataServiceRequestor().get_attribute_from_metadata(
attributes[attribute_key] = _get_attribute_from_metadata(
metadata_json, attribute_key
)
detach(token)
return Resource(attributes)


class _AzureVMMetadataServiceRequestor:
def get_azure_vm_metadata(self): # pylint: disable=no-self-use
request = Request(_AZURE_VM_METADATA_ENDPOINT)
request.add_header("Metadata", "True")
try:
# TODO: Changed to 4s to fit into OTel SDK's 5 second timeout.
# Lengthen or allow user input if issue is resolved.
# See https://github.com/open-telemetry/opentelemetry-python/issues/3644
with urlopen(request, timeout=4) as response:
return loads(response.read())
except URLError:
# Not on Azure VM
return None
except Exception as e: # pylint: disable=broad-except,invalid-name
_logger.exception("Failed to receive Azure VM metadata: %s", e)
return None
def _get_azure_vm_metadata():
request = Request(_AZURE_VM_METADATA_ENDPOINT)
request.add_header("Metadata", "True")
try:
# TODO: Changed to 4s to fit into OTel SDK's 5 second timeout.
# Lengthen or allow user input if issue is resolved.
# See https://github.com/open-telemetry/opentelemetry-python/issues/3644
with urlopen(request, timeout=4) as response:
return loads(response.read())
except URLError:
# Not on Azure VM
return None
except Exception as e: # pylint: disable=broad-except,invalid-name
_logger.exception("Failed to receive Azure VM metadata: %s", e)
return None


def get_attribute_from_metadata(
self, metadata_json, attribute_key
): # pylint: disable=no-self-use
ams_value = ""
if attribute_key == _AZURE_VM_SCALE_SET_NAME_ATTRIBUTE:
ams_value = metadata_json["vmScaleSetName"]
elif attribute_key == _AZURE_VM_SKU_ATTRIBUTE:
ams_value = metadata_json["sku"]
elif attribute_key == ResourceAttributes.CLOUD_PLATFORM:
ams_value = CloudPlatformValues.AZURE_VM.value
elif attribute_key == ResourceAttributes.CLOUD_PROVIDER:
ams_value = CloudProviderValues.AZURE.value
elif attribute_key == ResourceAttributes.CLOUD_REGION:
ams_value = metadata_json["location"]
elif attribute_key == ResourceAttributes.CLOUD_RESOURCE_ID:
ams_value = metadata_json["resourceId"]
elif attribute_key in (
ResourceAttributes.HOST_ID,
ResourceAttributes.SERVICE_INSTANCE_ID,
):
ams_value = metadata_json["vmId"]
elif attribute_key == ResourceAttributes.HOST_NAME:
ams_value = metadata_json["name"]
elif attribute_key == ResourceAttributes.HOST_TYPE:
ams_value = metadata_json["vmSize"]
elif attribute_key == ResourceAttributes.OS_TYPE:
ams_value = metadata_json["osType"]
elif attribute_key == ResourceAttributes.OS_VERSION:
ams_value = metadata_json["version"]
return ams_value
def _get_attribute_from_metadata(metadata_json, attribute_key):
ams_value = ""
if attribute_key == _AZURE_VM_SCALE_SET_NAME_ATTRIBUTE:
ams_value = metadata_json["vmScaleSetName"]
elif attribute_key == _AZURE_VM_SKU_ATTRIBUTE:
ams_value = metadata_json["sku"]
elif attribute_key == ResourceAttributes.CLOUD_PLATFORM:
ams_value = CloudPlatformValues.AZURE_VM.value
elif attribute_key == ResourceAttributes.CLOUD_PROVIDER:
ams_value = CloudProviderValues.AZURE.value
elif attribute_key == ResourceAttributes.CLOUD_REGION:
ams_value = metadata_json["location"]
elif attribute_key == ResourceAttributes.CLOUD_RESOURCE_ID:
ams_value = metadata_json["resourceId"]
elif attribute_key in (
ResourceAttributes.HOST_ID,
ResourceAttributes.SERVICE_INSTANCE_ID,
):
ams_value = metadata_json["vmId"]
elif attribute_key == ResourceAttributes.HOST_NAME:
ams_value = metadata_json["name"]
elif attribute_key == ResourceAttributes.HOST_TYPE:
ams_value = metadata_json["vmSize"]
elif attribute_key == ResourceAttributes.OS_TYPE:
ams_value = metadata_json["osType"]
elif attribute_key == ResourceAttributes.OS_VERSION:
ams_value = metadata_json["version"]
return ams_value
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
import unittest
from unittest.mock import Mock, patch
from unittest.mock import patch

# pylint: disable=no-name-in-module
from opentelemetry.resource.detector.azure.vm import AzureVMResourceDetector
Expand Down Expand Up @@ -363,18 +363,18 @@
class TestAzureVMResourceDetector(unittest.TestCase):
@patch("opentelemetry.resource.detector.azure.vm.urlopen")
def test_linux(self, mock_urlopen):
mock_response = Mock()
mock_urlopen.return_value = mock_response
mock_response.read.return_value = LINUX_JSON
mock_urlopen.return_value.__enter__.return_value.read.return_value = (
LINUX_JSON
)
attributes = AzureVMResourceDetector().detect().attributes
for attribute_key, attribute_value in LINUX_ATTRIBUTES.items():
self.assertEqual(attributes[attribute_key], attribute_value)

@patch("opentelemetry.resource.detector.azure.vm.urlopen")
def test_windows(self, mock_urlopen):
mock_response = Mock()
mock_urlopen.return_value = mock_response
mock_response.read.return_value = WINDOWS_JSON
mock_urlopen.return_value.__enter__.return_value.read.return_value = (
WINDOWS_JSON
)
attributes = AzureVMResourceDetector().detect().attributes
for attribute_key, attribute_value in LINUX_ATTRIBUTES.items():
for attribute_key, attribute_value in WINDOWS_ATTRIBUTES.items():
self.assertEqual(attributes[attribute_key], attribute_value)