aboutsummaryrefslogtreecommitdiff
path: root/.venv/lib/python3.12/site-packages/opentelemetry/resource/detector/azure/vm.py
blob: 211228294993ab222503df00d20d68c4f8ec6733 (about) (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
# Copyright The OpenTelemetry Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from json import loads
from logging import getLogger
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,
    CloudProviderValues,
    ResourceAttributes,
)

from ._constants import (
    _AZURE_VM_METADATA_ENDPOINT,
    _AZURE_VM_SCALE_SET_NAME_ATTRIBUTE,
    _AZURE_VM_SKU_ATTRIBUTE,
    _EXPECTED_AZURE_AMS_ATTRIBUTES,
)
from ._utils import _can_ignore_vm_detect

_logger = getLogger(__name__)


class AzureVMResourceDetector(ResourceDetector):
    # pylint: disable=no-self-use
    def detect(self) -> "Resource":
        attributes = {}
        if not _can_ignore_vm_detect():
            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] = _get_attribute_from_metadata(
                    metadata_json, attribute_key
                )
            detach(token)
        return Resource(attributes)


def _get_azure_vm_metadata():
    request = Request(_AZURE_VM_METADATA_ENDPOINT)
    request.add_header("Metadata", "True")
    try:
        # VM metadata service should not take more than 200ms on success case
        with urlopen(request, timeout=0.2) 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(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