Azure resource detectors (#1901)
This commit is contained in:
		
							parent
							
								
									9cd9de7f01
								
							
						
					
					
						commit
						9627f74a73
					
				|  | @ -14,6 +14,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 | |||
| - Fixed union typing error not compatible with Python 3.7 introduced in `opentelemetry-util-http`, fix tests introduced by patch related to sanitize method for wsgi | ||||
|   ([#1913](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1913)) | ||||
| 
 | ||||
| ### Added | ||||
| 
 | ||||
| - `opentelemetry-resource-detector-azure` Add resource detectors for Azure App Service and VM | ||||
|   ([#1901](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1901)) | ||||
| 
 | ||||
| ## Version 1.19.0/0.40b0 (2023-07-13) | ||||
| - `opentelemetry-instrumentation-asgi` Add `http.server.request.size` metric | ||||
|   ([#1867](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1867)) | ||||
|  |  | |||
|  | @ -0,0 +1,201 @@ | |||
|                                  Apache License | ||||
|                            Version 2.0, January 2004 | ||||
|                         http://www.apache.org/licenses/ | ||||
| 
 | ||||
|    TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION | ||||
| 
 | ||||
|    1. Definitions. | ||||
| 
 | ||||
|       "License" shall mean the terms and conditions for use, reproduction, | ||||
|       and distribution as defined by Sections 1 through 9 of this document. | ||||
| 
 | ||||
|       "Licensor" shall mean the copyright owner or entity authorized by | ||||
|       the copyright owner that is granting the License. | ||||
| 
 | ||||
|       "Legal Entity" shall mean the union of the acting entity and all | ||||
|       other entities that control, are controlled by, or are under common | ||||
|       control with that entity. For the purposes of this definition, | ||||
|       "control" means (i) the power, direct or indirect, to cause the | ||||
|       direction or management of such entity, whether by contract or | ||||
|       otherwise, or (ii) ownership of fifty percent (50%) or more of the | ||||
|       outstanding shares, or (iii) beneficial ownership of such entity. | ||||
| 
 | ||||
|       "You" (or "Your") shall mean an individual or Legal Entity | ||||
|       exercising permissions granted by this License. | ||||
| 
 | ||||
|       "Source" form shall mean the preferred form for making modifications, | ||||
|       including but not limited to software source code, documentation | ||||
|       source, and configuration files. | ||||
| 
 | ||||
|       "Object" form shall mean any form resulting from mechanical | ||||
|       transformation or translation of a Source form, including but | ||||
|       not limited to compiled object code, generated documentation, | ||||
|       and conversions to other media types. | ||||
| 
 | ||||
|       "Work" shall mean the work of authorship, whether in Source or | ||||
|       Object form, made available under the License, as indicated by a | ||||
|       copyright notice that is included in or attached to the work | ||||
|       (an example is provided in the Appendix below). | ||||
| 
 | ||||
|       "Derivative Works" shall mean any work, whether in Source or Object | ||||
|       form, that is based on (or derived from) the Work and for which the | ||||
|       editorial revisions, annotations, elaborations, or other modifications | ||||
|       represent, as a whole, an original work of authorship. For the purposes | ||||
|       of this License, Derivative Works shall not include works that remain | ||||
|       separable from, or merely link (or bind by name) to the interfaces of, | ||||
|       the Work and Derivative Works thereof. | ||||
| 
 | ||||
|       "Contribution" shall mean any work of authorship, including | ||||
|       the original version of the Work and any modifications or additions | ||||
|       to that Work or Derivative Works thereof, that is intentionally | ||||
|       submitted to Licensor for inclusion in the Work by the copyright owner | ||||
|       or by an individual or Legal Entity authorized to submit on behalf of | ||||
|       the copyright owner. For the purposes of this definition, "submitted" | ||||
|       means any form of electronic, verbal, or written communication sent | ||||
|       to the Licensor or its representatives, including but not limited to | ||||
|       communication on electronic mailing lists, source code control systems, | ||||
|       and issue tracking systems that are managed by, or on behalf of, the | ||||
|       Licensor for the purpose of discussing and improving the Work, but | ||||
|       excluding communication that is conspicuously marked or otherwise | ||||
|       designated in writing by the copyright owner as "Not a Contribution." | ||||
| 
 | ||||
|       "Contributor" shall mean Licensor and any individual or Legal Entity | ||||
|       on behalf of whom a Contribution has been received by Licensor and | ||||
|       subsequently incorporated within the Work. | ||||
| 
 | ||||
|    2. Grant of Copyright License. Subject to the terms and conditions of | ||||
|       this License, each Contributor hereby grants to You a perpetual, | ||||
|       worldwide, non-exclusive, no-charge, royalty-free, irrevocable | ||||
|       copyright license to reproduce, prepare Derivative Works of, | ||||
|       publicly display, publicly perform, sublicense, and distribute the | ||||
|       Work and such Derivative Works in Source or Object form. | ||||
| 
 | ||||
|    3. Grant of Patent License. Subject to the terms and conditions of | ||||
|       this License, each Contributor hereby grants to You a perpetual, | ||||
|       worldwide, non-exclusive, no-charge, royalty-free, irrevocable | ||||
|       (except as stated in this section) patent license to make, have made, | ||||
|       use, offer to sell, sell, import, and otherwise transfer the Work, | ||||
|       where such license applies only to those patent claims licensable | ||||
|       by such Contributor that are necessarily infringed by their | ||||
|       Contribution(s) alone or by combination of their Contribution(s) | ||||
|       with the Work to which such Contribution(s) was submitted. If You | ||||
|       institute patent litigation against any entity (including a | ||||
|       cross-claim or counterclaim in a lawsuit) alleging that the Work | ||||
|       or a Contribution incorporated within the Work constitutes direct | ||||
|       or contributory patent infringement, then any patent licenses | ||||
|       granted to You under this License for that Work shall terminate | ||||
|       as of the date such litigation is filed. | ||||
| 
 | ||||
|    4. Redistribution. You may reproduce and distribute copies of the | ||||
|       Work or Derivative Works thereof in any medium, with or without | ||||
|       modifications, and in Source or Object form, provided that You | ||||
|       meet the following conditions: | ||||
| 
 | ||||
|       (a) You must give any other recipients of the Work or | ||||
|           Derivative Works a copy of this License; and | ||||
| 
 | ||||
|       (b) You must cause any modified files to carry prominent notices | ||||
|           stating that You changed the files; and | ||||
| 
 | ||||
|       (c) You must retain, in the Source form of any Derivative Works | ||||
|           that You distribute, all copyright, patent, trademark, and | ||||
|           attribution notices from the Source form of the Work, | ||||
|           excluding those notices that do not pertain to any part of | ||||
|           the Derivative Works; and | ||||
| 
 | ||||
|       (d) If the Work includes a "NOTICE" text file as part of its | ||||
|           distribution, then any Derivative Works that You distribute must | ||||
|           include a readable copy of the attribution notices contained | ||||
|           within such NOTICE file, excluding those notices that do not | ||||
|           pertain to any part of the Derivative Works, in at least one | ||||
|           of the following places: within a NOTICE text file distributed | ||||
|           as part of the Derivative Works; within the Source form or | ||||
|           documentation, if provided along with the Derivative Works; or, | ||||
|           within a display generated by the Derivative Works, if and | ||||
|           wherever such third-party notices normally appear. The contents | ||||
|           of the NOTICE file are for informational purposes only and | ||||
|           do not modify the License. You may add Your own attribution | ||||
|           notices within Derivative Works that You distribute, alongside | ||||
|           or as an addendum to the NOTICE text from the Work, provided | ||||
|           that such additional attribution notices cannot be construed | ||||
|           as modifying the License. | ||||
| 
 | ||||
|       You may add Your own copyright statement to Your modifications and | ||||
|       may provide additional or different license terms and conditions | ||||
|       for use, reproduction, or distribution of Your modifications, or | ||||
|       for any such Derivative Works as a whole, provided Your use, | ||||
|       reproduction, and distribution of the Work otherwise complies with | ||||
|       the conditions stated in this License. | ||||
| 
 | ||||
|    5. Submission of Contributions. Unless You explicitly state otherwise, | ||||
|       any Contribution intentionally submitted for inclusion in the Work | ||||
|       by You to the Licensor shall be under the terms and conditions of | ||||
|       this License, without any additional terms or conditions. | ||||
|       Notwithstanding the above, nothing herein shall supersede or modify | ||||
|       the terms of any separate license agreement you may have executed | ||||
|       with Licensor regarding such Contributions. | ||||
| 
 | ||||
|    6. Trademarks. This License does not grant permission to use the trade | ||||
|       names, trademarks, service marks, or product names of the Licensor, | ||||
|       except as required for reasonable and customary use in describing the | ||||
|       origin of the Work and reproducing the content of the NOTICE file. | ||||
| 
 | ||||
|    7. Disclaimer of Warranty. Unless required by applicable law or | ||||
|       agreed to in writing, Licensor provides the Work (and each | ||||
|       Contributor provides its Contributions) on an "AS IS" BASIS, | ||||
|       WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or | ||||
|       implied, including, without limitation, any warranties or conditions | ||||
|       of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A | ||||
|       PARTICULAR PURPOSE. You are solely responsible for determining the | ||||
|       appropriateness of using or redistributing the Work and assume any | ||||
|       risks associated with Your exercise of permissions under this License. | ||||
| 
 | ||||
|    8. Limitation of Liability. In no event and under no legal theory, | ||||
|       whether in tort (including negligence), contract, or otherwise, | ||||
|       unless required by applicable law (such as deliberate and grossly | ||||
|       negligent acts) or agreed to in writing, shall any Contributor be | ||||
|       liable to You for damages, including any direct, indirect, special, | ||||
|       incidental, or consequential damages of any character arising as a | ||||
|       result of this License or out of the use or inability to use the | ||||
|       Work (including but not limited to damages for loss of goodwill, | ||||
|       work stoppage, computer failure or malfunction, or any and all | ||||
|       other commercial damages or losses), even if such Contributor | ||||
|       has been advised of the possibility of such damages. | ||||
| 
 | ||||
|    9. Accepting Warranty or Additional Liability. While redistributing | ||||
|       the Work or Derivative Works thereof, You may choose to offer, | ||||
|       and charge a fee for, acceptance of support, warranty, indemnity, | ||||
|       or other liability obligations and/or rights consistent with this | ||||
|       License. However, in accepting such obligations, You may act only | ||||
|       on Your own behalf and on Your sole responsibility, not on behalf | ||||
|       of any other Contributor, and only if You agree to indemnify, | ||||
|       defend, and hold each Contributor harmless for any liability | ||||
|       incurred by, or claims asserted against, such Contributor by reason | ||||
|       of your accepting any such warranty or additional liability. | ||||
| 
 | ||||
|    END OF TERMS AND CONDITIONS | ||||
| 
 | ||||
|    APPENDIX: How to apply the Apache License to your work. | ||||
| 
 | ||||
|       To apply the Apache License to your work, attach the following | ||||
|       boilerplate notice, with the fields enclosed by brackets "[]" | ||||
|       replaced with your own identifying information. (Don't include | ||||
|       the brackets!)  The text should be enclosed in the appropriate | ||||
|       comment syntax for the file format. We also recommend that a | ||||
|       file or class name and description of purpose be included on the | ||||
|       same "printed page" as the copyright notice for easier | ||||
|       identification within third-party archives. | ||||
| 
 | ||||
|    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. | ||||
|  | @ -0,0 +1,82 @@ | |||
| OpenTelemetry Resource detectors for Azure | ||||
| ========================================== | ||||
| 
 | ||||
| |pypi| | ||||
| 
 | ||||
| .. |pypi| image:: https://badge.fury.io/py/opentelemetry-resource-detector-azure.svg | ||||
|    :target: https://pypi.org/project/opentelemetry-resource-detector-azure/ | ||||
| 
 | ||||
| This library contains OpenTelemetry `Resource Detectors <https://opentelemetry.io/docs/specs/otel/resource/sdk/#detecting-resource-information-from-the-environment>`_ for the following Azure resources: | ||||
|  * `Azure App Service <https://azure.microsoft.com/en-us/products/app-service>`_ | ||||
|  * `Azure Virtual Machines <https://azure.microsoft.com/en-us/products/virtual-machines>`_ | ||||
| 
 | ||||
| Installation | ||||
| ------------ | ||||
| 
 | ||||
| :: | ||||
| 
 | ||||
|     pip install opentelemetry-resource-detector-azure | ||||
| 
 | ||||
| --------------------------- | ||||
| 
 | ||||
| Usage example for ``opentelemetry-resource-detector-azure`` | ||||
| 
 | ||||
| .. code-block:: python | ||||
| 
 | ||||
|     from opentelemetry import trace | ||||
|     from opentelemetry.sdk.trace import TracerProvider | ||||
|     from opentelemetry.resource.detector.azure.app_service import ( | ||||
|         AzureAppServiceResourceDetector, | ||||
|         AzureVMResourceDetector, | ||||
|     ) | ||||
|     from opentelemetry.resource.detector.azure.vm import ( | ||||
|         AzureVMResourceDetector, | ||||
|     ) | ||||
|     from opentelemetry.sdk.resources import get_aggregated_resources | ||||
| 
 | ||||
| 
 | ||||
|     trace.set_tracer_provider( | ||||
|         TracerProvider( | ||||
|             resource=get_aggregated_resources( | ||||
|                 [ | ||||
|                     AzureAppServiceResourceDetector(), | ||||
|                     AzureVMResourceDetector(), | ||||
|                 ] | ||||
|             ), | ||||
|         ) | ||||
|     ) | ||||
| 
 | ||||
| Mappings | ||||
| -------- | ||||
| 
 | ||||
| The Azure App Service Resource Detector sets the following Resource Attributes: | ||||
|  * ``service.name`` set to the value of the ``WEBSITE_SITE_NAME`` environment variable. | ||||
|  * ``cloud.platform`` set to ``azure_app_service``. | ||||
|  * ``cloud.provider`` set to ``azure``. | ||||
|  * ``cloud.resource_id`` set using the ``WEBSITE_RESOURCE_GROUP``, ``WEBSITE_OWNER_NAME``, and ``WEBSITE_SITE_NAME`` environment variables. | ||||
|  * ``cloud.region`` set to the value of the ``REGION_NAME`` environment variable. | ||||
|  * ``deployment.environment`` set to the value of the ``WEBSITE_SLOT_NAME`` environment variable. | ||||
|  * ``host.id`` set to the value of the ``WEBSITE_HOSTNAME`` environment variable. | ||||
|  * ``service.instance.id`` set to the value of the ``WEBSITE_INSTANCE_ID`` environment variable. | ||||
|  * ``azure.app.service.stamp`` set to the value of the ``WEBSITE_HOME_STAMPNAME`` environment variable. | ||||
| 
 | ||||
| The Azure VM Resource Detector sets the following Resource Attributes according to the response from the `Azure Metadata Service <https://learn.microsoft.com/en-us/azure/virtual-machines/instance-metadata-service?tabs=windows>`_: | ||||
|  * ``azure.vm.scaleset.name`` set to the value of the ``vmScaleSetName`` field. | ||||
|  * ``azure.vm.sku`` set to the value of the ``sku`` field. | ||||
|  * ``cloud.platform`` set to the value of the ``azure_vm``. | ||||
|  * ``cloud.provider`` set to the value of the ``azure``. | ||||
|  * ``cloud.region`` set to the value of the ``location`` field. | ||||
|  * ``cloud.resource_id`` set to the value of the ``resourceId`` field. | ||||
|  * ``host.id`` set to the value of the ``vmId`` field. | ||||
|  * ``host.name`` set to the value of the ``name`` field. | ||||
|  * ``host.type`` set to the value of the ``vmSize`` field. | ||||
|  * ``os.type`` set to the value of the ``osType`` field. | ||||
|  * ``os.version`` set to the value of the ``version`` field. | ||||
|  * ``service.instance.id`` set to the value of the ``vmId`` field. | ||||
| 
 | ||||
| For more information, see the `Semantic Conventions for Cloud Resource Attributes <https://opentelemetry.io/docs/specs/otel/resource/semantic_conventions/cloud/>`_. | ||||
| 
 | ||||
| References | ||||
| ---------- | ||||
| 
 | ||||
| * `OpenTelemetry Project <https://opentelemetry.io/>`_ | ||||
|  | @ -0,0 +1,51 @@ | |||
| [build-system] | ||||
| requires = ["hatchling"] | ||||
| build-backend = "hatchling.build" | ||||
| 
 | ||||
| [project] | ||||
| name = "opentelemetry-resource-detector-container" | ||||
| dynamic = ["version"] | ||||
| description = "Container Resource Detector for OpenTelemetry" | ||||
| readme = "README.rst" | ||||
| license = "Apache-2.0" | ||||
| requires-python = ">=3.7" | ||||
| authors = [ | ||||
|   { name = "OpenTelemetry Authors", email = "cncf-opentelemetry-contributors@lists.cncf.io" }, | ||||
| ] | ||||
| classifiers = [ | ||||
|   "Development Status :: 4 - Beta", | ||||
|   "Intended Audience :: Developers", | ||||
|   "License :: OSI Approved :: Apache Software License", | ||||
|   "Programming Language :: Python", | ||||
|   "Programming Language :: Python :: 3", | ||||
|   "Programming Language :: Python :: 3.7", | ||||
|   "Programming Language :: Python :: 3.8", | ||||
|   "Programming Language :: Python :: 3.9", | ||||
|   "Programming Language :: Python :: 3.10", | ||||
|   "Programming Language :: Python :: 3.11", | ||||
| ] | ||||
| dependencies = [ | ||||
|   "opentelemetry-sdk ~= 1.19", | ||||
| ] | ||||
| 
 | ||||
| [project.optional-dependencies] | ||||
| test = [] | ||||
| 
 | ||||
| [project.entry-points.opentelemetry_resource_detector] | ||||
| azure_app_service = "opentelemetry.resource.detector.azure.app_service:AzureAppServiceResourceDetector" | ||||
| azure_vm = "opentelemetry.resource.detector.azure.vm:AzureVMResourceDetector" | ||||
| 
 | ||||
| [project.urls] | ||||
| Homepage = "https://github.com/open-telemetry/opentelemetry-python-contrib/tree/main/resource/opentelemetry-resource-detector-azure" | ||||
| 
 | ||||
| [tool.hatch.version] | ||||
| path = "src/opentelemetry/resource/detector/azure/version.py" | ||||
| 
 | ||||
| [tool.hatch.build.targets.sdist] | ||||
| include = [ | ||||
|   "/src", | ||||
|   "/tests", | ||||
| ] | ||||
| 
 | ||||
| [tool.hatch.build.targets.wheel] | ||||
| packages = ["src/opentelemetry"] | ||||
|  | @ -0,0 +1,75 @@ | |||
| # 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 os import environ | ||||
| 
 | ||||
| from opentelemetry.sdk.resources import ResourceDetector, Resource | ||||
| from opentelemetry.semconv.resource import ResourceAttributes, CloudPlatformValues, CloudProviderValues | ||||
| 
 | ||||
| _AZURE_APP_SERVICE_STAMP_RESOURCE_ATTRIBUTE = "azure.app.service.stamp" | ||||
| # TODO: Remove once this resource attribute is no longer missing from SDK | ||||
| _CLOUD_RESOURCE_ID_RESOURCE_ATTRIBUTE = "cloud.resource_id" | ||||
| _REGION_NAME = "REGION_NAME" | ||||
| _WEBSITE_HOME_STAMPNAME = "WEBSITE_HOME_STAMPNAME" | ||||
| _WEBSITE_HOSTNAME = "WEBSITE_HOSTNAME" | ||||
| _WEBSITE_INSTANCE_ID = "WEBSITE_INSTANCE_ID" | ||||
| _WEBSITE_OWNER_NAME = "WEBSITE_OWNER_NAME" | ||||
| _WEBSITE_RESOURCE_GROUP = "WEBSITE_RESOURCE_GROUP" | ||||
| _WEBSITE_SITE_NAME = "WEBSITE_SITE_NAME" | ||||
| _WEBSITE_SLOT_NAME = "WEBSITE_SLOT_NAME" | ||||
| 
 | ||||
| 
 | ||||
| _APP_SERVICE_ATTRIBUTE_ENV_VARS = { | ||||
|     ResourceAttributes.CLOUD_REGION: _REGION_NAME, | ||||
|     ResourceAttributes.DEPLOYMENT_ENVIRONMENT: _WEBSITE_SLOT_NAME, | ||||
|     ResourceAttributes.HOST_ID: _WEBSITE_HOSTNAME, | ||||
|     ResourceAttributes.SERVICE_INSTANCE_ID: _WEBSITE_INSTANCE_ID, | ||||
|     _AZURE_APP_SERVICE_STAMP_RESOURCE_ATTRIBUTE: _WEBSITE_HOME_STAMPNAME, | ||||
| } | ||||
| 
 | ||||
| class AzureAppServiceResourceDetector(ResourceDetector): | ||||
|     def detect(self) -> Resource: | ||||
|         attributes = {} | ||||
|         website_site_name = environ.get(_WEBSITE_SITE_NAME) | ||||
|         if website_site_name: | ||||
|             attributes[ResourceAttributes.SERVICE_NAME] = website_site_name | ||||
|             attributes[ResourceAttributes.CLOUD_PROVIDER] = CloudProviderValues.AZURE.value | ||||
|             attributes[ResourceAttributes.CLOUD_PLATFORM] = CloudPlatformValues.AZURE_APP_SERVICE.value | ||||
| 
 | ||||
|             azure_resource_uri = _get_azure_resource_uri(website_site_name) | ||||
|             if azure_resource_uri: | ||||
|                 attributes[_CLOUD_RESOURCE_ID_RESOURCE_ATTRIBUTE] = azure_resource_uri | ||||
|             for (key, env_var) in _APP_SERVICE_ATTRIBUTE_ENV_VARS.items(): | ||||
|                 value = environ.get(env_var) | ||||
|                 if value: | ||||
|                     attributes[key] = value | ||||
| 
 | ||||
|         return Resource(attributes) | ||||
| 
 | ||||
| def _get_azure_resource_uri(website_site_name): | ||||
|     website_resource_group = environ.get(_WEBSITE_RESOURCE_GROUP) | ||||
|     website_owner_name = environ.get(_WEBSITE_OWNER_NAME) | ||||
| 
 | ||||
|     subscription_id = website_owner_name | ||||
|     if website_owner_name and '+' in website_owner_name: | ||||
|         subscription_id = website_owner_name[0:website_owner_name.index('+')] | ||||
| 
 | ||||
|     if not (website_resource_group and subscription_id): | ||||
|         return None | ||||
| 
 | ||||
|     return "/subscriptions/%s/resourceGroups/%s/providers/Microsoft.Web/sites/%s" % ( | ||||
|         subscription_id, | ||||
|         website_resource_group, | ||||
|         website_site_name, | ||||
|     ) | ||||
|  | @ -0,0 +1,15 @@ | |||
| # 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. | ||||
| 
 | ||||
| __version__ = "0.41b0.dev" | ||||
|  | @ -0,0 +1,97 @@ | |||
| # 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 os import environ | ||||
| from urllib.request import Request, urlopen | ||||
| from urllib.error import URLError | ||||
| 
 | ||||
| from opentelemetry.sdk.resources import ResourceDetector, Resource | ||||
| from opentelemetry.semconv.resource import ResourceAttributes, CloudPlatformValues, CloudProviderValues | ||||
| 
 | ||||
| 
 | ||||
| # TODO: Remove when cloud resource id is no longer missing in Resource Attributes | ||||
| _CLOUD_RESOURCE_ID_RESOURCE_ATTRIBUTE = "cloud.resource_id" | ||||
| _AZURE_VM_METADATA_ENDPOINT = "http://169.254.169.254/metadata/instance/compute?api-version=2021-12-13&format=json" | ||||
| _AZURE_VM_SCALE_SET_NAME_ATTRIBUTE = "azure.vm.scaleset.name" | ||||
| _AZURE_VM_SKU_ATTRIBUTE = "azure.vm.sku" | ||||
| _logger = getLogger(__name__) | ||||
| 
 | ||||
| EXPECTED_AZURE_AMS_ATTRIBUTES = [ | ||||
|     _AZURE_VM_SCALE_SET_NAME_ATTRIBUTE, | ||||
|     _AZURE_VM_SKU_ATTRIBUTE, | ||||
|     ResourceAttributes.CLOUD_PLATFORM, | ||||
|     ResourceAttributes.CLOUD_PROVIDER, | ||||
|     ResourceAttributes.CLOUD_REGION, | ||||
|     _CLOUD_RESOURCE_ID_RESOURCE_ATTRIBUTE, | ||||
|     ResourceAttributes.HOST_ID, | ||||
|     ResourceAttributes.HOST_NAME, | ||||
|     ResourceAttributes.HOST_TYPE, | ||||
|     ResourceAttributes.OS_TYPE, | ||||
|     ResourceAttributes.OS_VERSION, | ||||
|     ResourceAttributes.SERVICE_INSTANCE_ID, | ||||
| ] | ||||
| 
 | ||||
| class AzureVMResourceDetector(ResourceDetector): | ||||
|     # pylint: disable=no-self-use | ||||
|     def detect(self) -> "Resource": | ||||
|         attributes = {} | ||||
|         metadata_json = _AzureVMMetadataServiceRequestor().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(metadata_json, attribute_key) | ||||
|         return Resource(attributes) | ||||
| 
 | ||||
| class _AzureVMMetadataServiceRequestor: | ||||
|     def get_azure_vm_metadata(self): | ||||
|         request = Request(_AZURE_VM_METADATA_ENDPOINT) | ||||
|         request.add_header("Metadata", "True") | ||||
|         try: | ||||
|             response = urlopen(request).read() | ||||
|             return loads(response) | ||||
|         except URLError: | ||||
|             # Not on Azure VM | ||||
|             return None | ||||
|         except Exception as e: | ||||
|             _logger.exception("Failed to receive Azure VM metadata: %s", e) | ||||
|             return None | ||||
| 
 | ||||
|     def get_attribute_from_metadata(self, 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 == _CLOUD_RESOURCE_ID_RESOURCE_ATTRIBUTE: | ||||
|             ams_value = metadata_json["resourceId"] | ||||
|         elif attribute_key == ResourceAttributes.HOST_ID or \ | ||||
|             attribute_key == 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 | ||||
|  | @ -0,0 +1,13 @@ | |||
| # 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. | ||||
|  | @ -0,0 +1,116 @@ | |||
| # 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. | ||||
| import unittest | ||||
| from unittest.mock import patch | ||||
| 
 | ||||
| from opentelemetry.resource.detector.azure.app_service import ( | ||||
|     AzureAppServiceResourceDetector, | ||||
| ) | ||||
| 
 | ||||
| TEST_WEBSITE_SITE_NAME = "TEST_WEBSITE_SITE_NAME" | ||||
| TEST_REGION_NAME = "TEST_REGION_NAME" | ||||
| TEST_WEBSITE_SLOT_NAME = "TEST_WEBSITE_SLOT_NAME" | ||||
| TEST_WEBSITE_HOSTNAME = "TEST_WEBSITE_HOSTNAME" | ||||
| TEST_WEBSITE_INSTANCE_ID = "TEST_WEBSITE_INSTANCE_ID" | ||||
| TEST_WEBSITE_HOME_STAMPNAME = "TEST_WEBSITE_HOME_STAMPNAME" | ||||
| 
 | ||||
| TEST_WEBSITE_RESOURCE_GROUP = "TEST_WEBSITE_RESOURCE_GROUP" | ||||
| TEST_WEBSITE_OWNER_NAME = "TEST_WEBSITE_OWNER_NAME" | ||||
| 
 | ||||
| class TestAzureAppServiceResourceDetector(unittest.TestCase): | ||||
|     @patch.dict("os.environ", { | ||||
|         "WEBSITE_SITE_NAME": TEST_WEBSITE_SITE_NAME, | ||||
|         "REGION_NAME": TEST_REGION_NAME, | ||||
|         "WEBSITE_SLOT_NAME": TEST_WEBSITE_SLOT_NAME, | ||||
|         "WEBSITE_HOSTNAME": TEST_WEBSITE_HOSTNAME, | ||||
|         "WEBSITE_INSTANCE_ID": TEST_WEBSITE_INSTANCE_ID, | ||||
|         "WEBSITE_HOME_STAMPNAME": TEST_WEBSITE_HOME_STAMPNAME, | ||||
|         "WEBSITE_RESOURCE_GROUP": TEST_WEBSITE_RESOURCE_GROUP, | ||||
|         "WEBSITE_OWNER_NAME": TEST_WEBSITE_OWNER_NAME, | ||||
|     }, clear=True) | ||||
|     def test_on_app_service(self): | ||||
|         resource = AzureAppServiceResourceDetector().detect() | ||||
|         attributes = resource.attributes | ||||
|         self.assertEqual(attributes["service.name"], TEST_WEBSITE_SITE_NAME) | ||||
|         self.assertEqual(attributes["cloud.provider"], "azure") | ||||
|         self.assertEqual(attributes["cloud.platform"], "azure_app_service") | ||||
| 
 | ||||
|         self.assertEqual(attributes["cloud.resource_id"], \ | ||||
|             f"/subscriptions/{TEST_WEBSITE_OWNER_NAME}/resourceGroups/{TEST_WEBSITE_RESOURCE_GROUP}/providers/Microsoft.Web/sites/{TEST_WEBSITE_SITE_NAME}") | ||||
| 
 | ||||
|         self.assertEqual(attributes["cloud.region"], TEST_REGION_NAME) | ||||
|         self.assertEqual(attributes["deployment.environment"], TEST_WEBSITE_SLOT_NAME) | ||||
|         self.assertEqual(attributes["host.id"], TEST_WEBSITE_HOSTNAME) | ||||
|         self.assertEqual(attributes["service.instance.id"], TEST_WEBSITE_INSTANCE_ID) | ||||
|         self.assertEqual(attributes["azure.app.service.stamp"], TEST_WEBSITE_HOME_STAMPNAME) | ||||
| 
 | ||||
|     @patch.dict("os.environ", { | ||||
|         "WEBSITE_SITE_NAME": TEST_WEBSITE_SITE_NAME, | ||||
|         "REGION_NAME": TEST_REGION_NAME, | ||||
|         "WEBSITE_SLOT_NAME": TEST_WEBSITE_SLOT_NAME, | ||||
|         "WEBSITE_HOSTNAME": TEST_WEBSITE_HOSTNAME, | ||||
|         "WEBSITE_INSTANCE_ID": TEST_WEBSITE_INSTANCE_ID, | ||||
|         "WEBSITE_HOME_STAMPNAME": TEST_WEBSITE_HOME_STAMPNAME, | ||||
|         "WEBSITE_OWNER_NAME": TEST_WEBSITE_OWNER_NAME, | ||||
|     }, clear=True) | ||||
|     def test_on_app_service_no_resource_group(self): | ||||
|         resource = AzureAppServiceResourceDetector().detect() | ||||
|         attributes = resource.attributes | ||||
|         self.assertEqual(attributes["service.name"], TEST_WEBSITE_SITE_NAME) | ||||
|         self.assertEqual(attributes["cloud.provider"], "azure") | ||||
|         self.assertEqual(attributes["cloud.platform"], "azure_app_service") | ||||
| 
 | ||||
|         self.assertTrue("cloud.resource_id" not in attributes) | ||||
| 
 | ||||
|         self.assertEqual(attributes["cloud.region"], TEST_REGION_NAME) | ||||
|         self.assertEqual(attributes["deployment.environment"], TEST_WEBSITE_SLOT_NAME) | ||||
|         self.assertEqual(attributes["host.id"], TEST_WEBSITE_HOSTNAME) | ||||
|         self.assertEqual(attributes["service.instance.id"], TEST_WEBSITE_INSTANCE_ID) | ||||
|         self.assertEqual(attributes["azure.app.service.stamp"], TEST_WEBSITE_HOME_STAMPNAME) | ||||
| 
 | ||||
|     @patch.dict("os.environ", { | ||||
|         "WEBSITE_SITE_NAME": TEST_WEBSITE_SITE_NAME, | ||||
|         "REGION_NAME": TEST_REGION_NAME, | ||||
|         "WEBSITE_SLOT_NAME": TEST_WEBSITE_SLOT_NAME, | ||||
|         "WEBSITE_HOSTNAME": TEST_WEBSITE_HOSTNAME, | ||||
|         "WEBSITE_INSTANCE_ID": TEST_WEBSITE_INSTANCE_ID, | ||||
|         "WEBSITE_HOME_STAMPNAME": TEST_WEBSITE_HOME_STAMPNAME, | ||||
|         "WEBSITE_OWNER_NAME": TEST_WEBSITE_OWNER_NAME, | ||||
|     }, clear=True) | ||||
|     def test_on_app_service_no_owner(self): | ||||
|         resource = AzureAppServiceResourceDetector().detect() | ||||
|         attributes = resource.attributes | ||||
|         self.assertEqual(attributes["service.name"], TEST_WEBSITE_SITE_NAME) | ||||
|         self.assertEqual(attributes["cloud.provider"], "azure") | ||||
|         self.assertEqual(attributes["cloud.platform"], "azure_app_service") | ||||
| 
 | ||||
|         self.assertTrue("cloud.resource_id" not in attributes) | ||||
| 
 | ||||
|         self.assertEqual(attributes["cloud.region"], TEST_REGION_NAME) | ||||
|         self.assertEqual(attributes["deployment.environment"], TEST_WEBSITE_SLOT_NAME) | ||||
|         self.assertEqual(attributes["host.id"], TEST_WEBSITE_HOSTNAME) | ||||
|         self.assertEqual(attributes["service.instance.id"], TEST_WEBSITE_INSTANCE_ID) | ||||
|         self.assertEqual(attributes["azure.app.service.stamp"], TEST_WEBSITE_HOME_STAMPNAME) | ||||
| 
 | ||||
|     @patch.dict("os.environ", { | ||||
|         "REGION_NAME": TEST_REGION_NAME, | ||||
|         "WEBSITE_SLOT_NAME": TEST_WEBSITE_SLOT_NAME, | ||||
|         "WEBSITE_HOSTNAME": TEST_WEBSITE_HOSTNAME, | ||||
|         "WEBSITE_INSTANCE_ID": TEST_WEBSITE_INSTANCE_ID, | ||||
|         "WEBSITE_HOME_STAMPNAME": TEST_WEBSITE_HOME_STAMPNAME, | ||||
|         "WEBSITE_OWNER_NAME": TEST_WEBSITE_OWNER_NAME, | ||||
|     }, clear=True) | ||||
|     def test_off_app_service(self): | ||||
|         resource = AzureAppServiceResourceDetector().detect() | ||||
|         self.assertEqual(resource.attributes, {}) | ||||
|  | @ -0,0 +1,382 @@ | |||
| # 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. | ||||
| import unittest | ||||
| from unittest.mock import patch, Mock | ||||
| 
 | ||||
| from opentelemetry.semconv.resource import ResourceAttributes | ||||
| from opentelemetry.resource.detector.azure.vm import ( | ||||
|     AzureVMResourceDetector, | ||||
| ) | ||||
| 
 | ||||
| LINUX_JSON = """ | ||||
| { | ||||
|     "additionalCapabilities": { | ||||
|         "hibernationEnabled": "false" | ||||
|     }, | ||||
|     "azEnvironment": "AzurePublicCloud", | ||||
|     "customData": "", | ||||
|     "evictionPolicy": "", | ||||
|     "extendedLocation": { | ||||
|         "name": "", | ||||
|         "type": "" | ||||
|     }, | ||||
|     "host": { | ||||
|         "id": "" | ||||
|     }, | ||||
|     "hostGroup": { | ||||
|         "id": "" | ||||
|     }, | ||||
|     "isHostCompatibilityLayerVm": "true", | ||||
|     "licenseType": "", | ||||
|     "location": "westus", | ||||
|     "name": "examplevmname", | ||||
|     "offer": "0001-com-ubuntu-server-focal", | ||||
|     "osProfile": { | ||||
|         "adminUsername": "azureuser", | ||||
|         "computerName": "examplevmname", | ||||
|         "disablePasswordAuthentication": "true" | ||||
|     }, | ||||
|     "osType": "Linux", | ||||
|     "placementGroupId": "", | ||||
|     "plan": { | ||||
|         "name": "", | ||||
|         "product": "", | ||||
|         "publisher": "" | ||||
|     }, | ||||
|     "platformFaultDomain": "0", | ||||
|     "platformSubFaultDomain": "", | ||||
|     "platformUpdateDomain": "0", | ||||
|     "priority": "", | ||||
|     "provider": "Microsoft.Compute", | ||||
|     "publicKeys": [ | ||||
|         { | ||||
|             "keyData": "ssh-rsa 0", | ||||
|             "path": "/home/user/.ssh/authorized_keys0" | ||||
|         }, | ||||
|         { | ||||
|             "keyData": "ssh-rsa 1", | ||||
|             "path": "/home/user/.ssh/authorized_keys1" | ||||
|         } | ||||
|     ], | ||||
|     "publisher": "canonical", | ||||
|     "resourceGroupName": "macikgo-test-may-23", | ||||
|     "resourceId": "/subscriptions/xxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxx/resourceGroups/macikgo-test-may-23/providers/Microsoft.Compute/virtualMachines/examplevmname", | ||||
|     "securityProfile": { | ||||
|         "encryptionAtHost": "false", | ||||
|         "secureBootEnabled": "true", | ||||
|         "securityType": "TrustedLaunch", | ||||
|         "virtualTpmEnabled": "true" | ||||
|     }, | ||||
|     "sku": "20_04-lts-gen2", | ||||
|     "storageProfile": { | ||||
|         "dataDisks": [ | ||||
|             { | ||||
|                 "bytesPerSecondThrottle": "979202048", | ||||
|                 "caching": "None", | ||||
|                 "createOption": "Empty", | ||||
|                 "diskCapacityBytes": "274877906944", | ||||
|                 "diskSizeGB": "1024", | ||||
|                 "image": { | ||||
|                     "uri": "" | ||||
|                 }, | ||||
|                 "isSharedDisk": "false", | ||||
|                 "isUltraDisk": "true", | ||||
|                 "lun": "0", | ||||
|                 "managedDisk": { | ||||
|                     "id": "/subscriptions/xxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxx/resourceGroups/macikgo-test-may-23/providers/Microsoft.Compute/disks/exampledatadiskname", | ||||
|                     "storageAccountType": "StandardSSD_LRS" | ||||
|                 }, | ||||
|                 "name": "exampledatadiskname", | ||||
|                 "opsPerSecondThrottle": "65280", | ||||
|                 "vhd": { | ||||
|                     "uri": "" | ||||
|                 }, | ||||
|                 "writeAcceleratorEnabled": "false" | ||||
|             } | ||||
|         ], | ||||
|         "imageReference": { | ||||
|             "id": "", | ||||
|             "offer": "0001-com-ubuntu-server-focal", | ||||
|             "publisher": "canonical", | ||||
|             "sku": "20_04-lts-gen2", | ||||
|             "version": "latest" | ||||
|         }, | ||||
|         "osDisk": { | ||||
|             "caching": "ReadWrite", | ||||
|             "createOption": "FromImage", | ||||
|             "diffDiskSettings": { | ||||
|                 "option": "" | ||||
|             }, | ||||
|             "diskSizeGB": "30", | ||||
|             "encryptionSettings": { | ||||
|                 "enabled": "false", | ||||
|                 "diskEncryptionKey": { | ||||
|                     "sourceVault": { | ||||
|                         "id": "/subscriptions/test-source-guid/resourceGroups/testrg/providers/Microsoft.KeyVault/vaults/test-kv" | ||||
|                     }, | ||||
|                     "secretUrl": "https://test-disk.vault.azure.net/secrets/xxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxx/xxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxx" | ||||
|                 }, | ||||
|                 "keyEncryptionKey": { | ||||
|                     "sourceVault": { | ||||
|                         "id": "/subscriptions/test-key-guid/resourceGroups/testrg/providers/Microsoft.KeyVault/vaults/test-kv" | ||||
|                     }, | ||||
|                     "keyUrl": "https://test-key.vault.azure.net/secrets/xxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxx/xxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxx" | ||||
|                 } | ||||
|             }, | ||||
|             "image": { | ||||
|                 "uri": "" | ||||
|             }, | ||||
|             "managedDisk": { | ||||
|                 "id": "/subscriptions/xxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxx/resourceGroups/macikgo-test-may-23/providers/Microsoft.Compute/disks/exampleosdiskname", | ||||
|                 "storageAccountType": "StandardSSD_LRS" | ||||
|             }, | ||||
|             "name": "exampledatadiskname", | ||||
|             "osType": "Linux", | ||||
|             "vhd": { | ||||
|                 "uri": "" | ||||
|             }, | ||||
|             "writeAcceleratorEnabled": "false" | ||||
|         }, | ||||
|         "resourceDisk": { | ||||
|             "size": "16384" | ||||
|         } | ||||
|     }, | ||||
|     "subscriptionId": "xxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxx", | ||||
|     "tags": "azsecpack:nonprod;platformsettings.host_environment.service.platform_optedin_for_rootcerts:true", | ||||
|     "tagsList": [ | ||||
|         { | ||||
|             "name": "azsecpack", | ||||
|             "value": "nonprod" | ||||
|         }, | ||||
|         { | ||||
|             "name": "platformsettings.host_environment.service.platform_optedin_for_rootcerts", | ||||
|             "value": "true" | ||||
|         } | ||||
|     ], | ||||
|     "userData": "", | ||||
|     "version": "20.04.202307240", | ||||
|     "virtualMachineScaleSet": { | ||||
|         "id": "/subscriptions/xxxxxxxx-xxxxx-xxx-xxx-xxxx/resourceGroups/resource-group-name/providers/Microsoft.Compute/virtualMachineScaleSets/virtual-machine-scale-set-name" | ||||
|     }, | ||||
|     "vmId": "02aab8a4-74ef-476e-8182-f6d2ba4166a6", | ||||
|     "vmScaleSetName": "crpteste9vflji9", | ||||
|     "vmSize": "Standard_A3", | ||||
|     "zone": "1" | ||||
| } | ||||
| """ | ||||
| WINDOWS_JSON =""" | ||||
| { | ||||
|     "additionalCapabilities": { | ||||
|         "hibernationEnabled": "false" | ||||
|     }, | ||||
|     "azEnvironment": "AzurePublicCloud", | ||||
|     "customData": "", | ||||
|     "evictionPolicy": "", | ||||
|     "extendedLocation": { | ||||
|         "name": "", | ||||
|         "type": "" | ||||
|     }, | ||||
|     "host": { | ||||
|         "id": "" | ||||
|     }, | ||||
|     "hostGroup": { | ||||
|         "id": "" | ||||
|     }, | ||||
|     "isHostCompatibilityLayerVm": "true", | ||||
|     "licenseType": "Windows_Client", | ||||
|     "location": "westus", | ||||
|     "name": "examplevmname", | ||||
|     "offer": "WindowsServer", | ||||
|     "osProfile": { | ||||
|         "adminUsername": "azureuser", | ||||
|         "computerName": "examplevmname", | ||||
|         "disablePasswordAuthentication": "true" | ||||
|     }, | ||||
|     "osType": "Windows", | ||||
|     "placementGroupId": "", | ||||
|     "plan": { | ||||
|         "name": "", | ||||
|         "product": "", | ||||
|         "publisher": "" | ||||
|     }, | ||||
|     "platformFaultDomain": "0", | ||||
|     "platformSubFaultDomain": "", | ||||
|     "platformUpdateDomain": "0", | ||||
|     "priority": "", | ||||
|     "provider": "Microsoft.Compute", | ||||
|     "publicKeys": [ | ||||
|         { | ||||
|             "keyData": "ssh-rsa 0", | ||||
|             "path": "/home/user/.ssh/authorized_keys0" | ||||
|         }, | ||||
|         { | ||||
|             "keyData": "ssh-rsa 1", | ||||
|             "path": "/home/user/.ssh/authorized_keys1" | ||||
|         } | ||||
|     ], | ||||
|     "publisher": "RDFE-Test-Microsoft-Windows-Server-Group", | ||||
|     "resourceGroupName": "macikgo-test-may-23", | ||||
|     "resourceId": "/subscriptions/xxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxx/resourceGroups/macikgo-test-may-23/providers/Microsoft.Compute/virtualMachines/examplevmname", | ||||
|     "securityProfile": { | ||||
|         "encryptionAtHost": "false", | ||||
|         "secureBootEnabled": "true", | ||||
|         "securityType": "TrustedLaunch", | ||||
|         "virtualTpmEnabled": "true" | ||||
|     }, | ||||
|     "sku": "2019-Datacenter", | ||||
|     "storageProfile": { | ||||
|         "dataDisks": [ | ||||
|             { | ||||
|                 "bytesPerSecondThrottle": "979202048", | ||||
|                 "caching": "None", | ||||
|                 "createOption": "Empty", | ||||
|                 "diskCapacityBytes": "274877906944", | ||||
|                 "diskSizeGB": "1024", | ||||
|                 "image": { | ||||
|                     "uri": "" | ||||
|                 }, | ||||
|                 "isSharedDisk": "false", | ||||
|                 "isUltraDisk": "true", | ||||
|                 "lun": "0", | ||||
|                 "managedDisk": { | ||||
|                     "id": "/subscriptions/xxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxx/resourceGroups/macikgo-test-may-23/providers/Microsoft.Compute/disks/exampledatadiskname", | ||||
|                     "storageAccountType": "StandardSSD_LRS" | ||||
|                 }, | ||||
|                 "name": "exampledatadiskname", | ||||
|                 "opsPerSecondThrottle": "65280", | ||||
|                 "vhd": { | ||||
|                     "uri": "" | ||||
|                 }, | ||||
|                 "writeAcceleratorEnabled": "false" | ||||
|             } | ||||
|         ], | ||||
|         "imageReference": { | ||||
|             "id": "", | ||||
|             "offer": "WindowsServer", | ||||
|             "publisher": "MicrosoftWindowsServer", | ||||
|             "sku": "2019-Datacenter", | ||||
|             "version": "latest" | ||||
|         }, | ||||
|         "osDisk": { | ||||
|             "caching": "ReadWrite", | ||||
|             "createOption": "FromImage", | ||||
|             "diffDiskSettings": { | ||||
|                 "option": "" | ||||
|             }, | ||||
|             "diskSizeGB": "30", | ||||
|             "encryptionSettings": { | ||||
|                 "enabled": "false", | ||||
|                 "diskEncryptionKey": { | ||||
|                     "sourceVault": { | ||||
|                         "id": "/subscriptions/test-source-guid/resourceGroups/testrg/providers/Microsoft.KeyVault/vaults/test-kv" | ||||
|                     }, | ||||
|                     "secretUrl": "https://test-disk.vault.azure.net/secrets/xxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxx/xxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxx" | ||||
|                 }, | ||||
|                 "keyEncryptionKey": { | ||||
|                     "sourceVault": { | ||||
|                         "id": "/subscriptions/test-key-guid/resourceGroups/testrg/providers/Microsoft.KeyVault/vaults/test-kv" | ||||
|                     }, | ||||
|                     "keyUrl": "https://test-key.vault.azure.net/secrets/xxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxx/xxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxx" | ||||
|                 } | ||||
|             }, | ||||
|             "image": { | ||||
|                 "uri": "" | ||||
|             }, | ||||
|             "managedDisk": { | ||||
|                 "id": "/subscriptions/xxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxx/resourceGroups/macikgo-test-may-23/providers/Microsoft.Compute/disks/exampleosdiskname", | ||||
|                 "storageAccountType": "StandardSSD_LRS" | ||||
|             }, | ||||
|             "name": "exampledatadiskname", | ||||
|             "osType": "Windows", | ||||
|             "vhd": { | ||||
|                 "uri": "" | ||||
|             }, | ||||
|             "writeAcceleratorEnabled": "false" | ||||
|         }, | ||||
|         "resourceDisk": { | ||||
|             "size": "16384" | ||||
|         } | ||||
|     }, | ||||
|     "subscriptionId": "xxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxx", | ||||
|     "tags": "azsecpack:nonprod;platformsettings.host_environment.service.platform_optedin_for_rootcerts:true", | ||||
|     "userData": "Zm9vYmFy", | ||||
|     "tagsList": [ | ||||
|         { | ||||
|             "name": "azsecpack", | ||||
|             "value": "nonprod" | ||||
|         }, | ||||
|         { | ||||
|             "name": "platformsettings.host_environment.service.platform_optedin_for_rootcerts", | ||||
|             "value": "true" | ||||
|         } | ||||
|     ], | ||||
|     "userData": "", | ||||
|     "version": "20.04.202307240", | ||||
|     "virtualMachineScaleSet": { | ||||
|         "id": "/subscriptions/xxxxxxxx-xxxxx-xxx-xxx-xxxx/resourceGroups/resource-group-name/providers/Microsoft.Compute/virtualMachineScaleSets/virtual-machine-scale-set-name" | ||||
|     }, | ||||
|     "vmId": "02aab8a4-74ef-476e-8182-f6d2ba4166a6", | ||||
|     "vmScaleSetName": "crpteste9vflji9", | ||||
|     "vmSize": "Standard_A3", | ||||
|     "zone": "1" | ||||
| } | ||||
| """ | ||||
| LINUX_ATTRIBUTES = { | ||||
|     "azure.vm.scaleset.name": "crpteste9vflji9", | ||||
|     "azure.vm.sku": "20_04-lts-gen2", | ||||
|     "cloud.platform": "azure_vm", | ||||
|     "cloud.provider": "azure", | ||||
|     "cloud.region": "westus", | ||||
|     "cloud.resource_id": "/subscriptions/xxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxx/resourceGroups/macikgo-test-may-23/providers/Microsoft.Compute/virtualMachines/examplevmname", | ||||
|     "host.id": "02aab8a4-74ef-476e-8182-f6d2ba4166a6", | ||||
|     "host.name": "examplevmname", | ||||
|     "host.type": "Standard_A3", | ||||
|     "os.type": "Linux", | ||||
|     "os.version": "20.04.202307240", | ||||
|     "service.instance.id": "02aab8a4-74ef-476e-8182-f6d2ba4166a6", | ||||
| } | ||||
| WINDOWS_ATTRIBUTES = { | ||||
|     "azure.vm.scaleset.name": "crpteste9vflji9", | ||||
|     "azure.vm.sku": "2019-Datacenter", | ||||
|     "cloud.platform": "azure_vm", | ||||
|     "cloud.provider": "azure", | ||||
|     "cloud.region": "westus", | ||||
|     "cloud.resource_id": "/subscriptions/xxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxx/resourceGroups/macikgo-test-may-23/providers/Microsoft.Compute/virtualMachines/examplevmname", | ||||
|     "host.id": "02aab8a4-74ef-476e-8182-f6d2ba4166a6", | ||||
|     "host.name": "examplevmname", | ||||
|     "host.type": "Standard_A3", | ||||
|     "os.type": "Windows", | ||||
|     "os.version": "20.04.202307240", | ||||
|     "service.instance.id": "02aab8a4-74ef-476e-8182-f6d2ba4166a6", | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| class TestAzureVMResourceDetector(unittest.TestCase): | ||||
|     @patch("opentelemetry.resource.detector.azure.vm.urlopen") | ||||
|     def test_linux(self, mock_urlopen): | ||||
|         mock_open = Mock() | ||||
|         mock_urlopen.return_value = mock_open | ||||
|         mock_open.read.return_value = LINUX_JSON | ||||
|         attributes = AzureVMResourceDetector().detect().attributes | ||||
|         for attribute_key in LINUX_ATTRIBUTES: | ||||
|             self.assertEqual(attributes[attribute_key], LINUX_ATTRIBUTES[attribute_key]) | ||||
| 
 | ||||
|     @patch("opentelemetry.resource.detector.azure.vm.urlopen") | ||||
|     def test_windows(self, mock_urlopen): | ||||
|         mock_open = Mock() | ||||
|         mock_urlopen.return_value = mock_open | ||||
|         mock_open.read.return_value = WINDOWS_JSON | ||||
|         attributes = AzureVMResourceDetector().detect().attributes | ||||
|         for attribute_key in WINDOWS_ATTRIBUTES: | ||||
|             self.assertEqual(attributes[attribute_key], WINDOWS_ATTRIBUTES[attribute_key]) | ||||
|  | @ -0,0 +1,9 @@ | |||
| graft src | ||||
| graft tests | ||||
| global-exclude *.pyc | ||||
| global-exclude *.pyo | ||||
| global-exclude __pycache__/* | ||||
| include CHANGELOG.md | ||||
| include MANIFEST.in | ||||
| include README.rst | ||||
| include LICENSE | ||||
		Loading…
	
		Reference in New Issue