From 43a74d7f4350c726c7c1f20627954b165ea126aa Mon Sep 17 00:00:00 2001 From: Swetha Ravichandran Date: Tue, 8 Feb 2022 11:36:26 -0800 Subject: [PATCH] https://github.com/open-telemetry/opentelemetry-dotnet-contrib/issues/201 - AWSEKSResourceDetector - Validate ClusterName/ContainerID independently before adding it to the resource - Validates ClusterName/ContainerID independently before adding it to the resource - Includes bug fix - IsEKSProcess should return non-null auth value to confirm if its running in EKS environment. - Handled exceptions separately with more error information - Added Unit Tests --- .../Resources/AWSEKSResourceDetector.cs | 111 ++++++++++-------- .../Resources/TestAWSEKSResourceDetector.cs | 31 +++++ 2 files changed, 96 insertions(+), 46 deletions(-) diff --git a/src/OpenTelemetry.Contrib.Extensions.AWSXRay/Resources/AWSEKSResourceDetector.cs b/src/OpenTelemetry.Contrib.Extensions.AWSXRay/Resources/AWSEKSResourceDetector.cs index 87b5834361..2bc5850515 100644 --- a/src/OpenTelemetry.Contrib.Extensions.AWSXRay/Resources/AWSEKSResourceDetector.cs +++ b/src/OpenTelemetry.Contrib.Extensions.AWSXRay/Resources/AWSEKSResourceDetector.cs @@ -40,26 +40,15 @@ public class AWSEKSResourceDetector : IResourceDetector /// List of key-value pairs of resource attributes. public IEnumerable> Detect() { - List> resourceAttributes = null; - - try - { - var clusterName = this.GetEKSClusterName(AWSEKSCredentialPath); - var containerId = this.GetEKSContainerId(AWSEKSMetadataFilePath); - - if (clusterName == null && containerId == null) - { - return resourceAttributes; - } - - resourceAttributes = this.ExtractResourceAttributes(clusterName, containerId); - } - catch (Exception ex) + var credentials = this.GetEKSCredentials(AWSEKSCredentialPath); + if (credentials == null || !this.IsEKSProcess(credentials)) { - AWSXRayEventSource.Log.ResourceAttributesExtractException(nameof(AWSEKSResourceDetector), ex); + return null; } - return resourceAttributes; + return this.ExtractResourceAttributes( + this.GetEKSClusterName(credentials), + this.GetEKSContainerId(AWSEKSMetadataFilePath)); } internal List> ExtractResourceAttributes(string clusterName, string containerId) @@ -68,46 +57,67 @@ internal List> ExtractResourceAttributes(string clu { new KeyValuePair(AWSSemanticConventions.AttributeCloudProvider, "aws"), new KeyValuePair(AWSSemanticConventions.AttributeCloudPlatform, "aws_eks"), - new KeyValuePair(AWSSemanticConventions.AttributeK8SClusterName, clusterName), - new KeyValuePair(AWSSemanticConventions.AttributeContainerID, containerId), }; + if (!string.IsNullOrEmpty(clusterName)) + { + resourceAttributes.Add(new KeyValuePair(AWSSemanticConventions.AttributeK8SClusterName, clusterName)); + } + + if (!string.IsNullOrEmpty(containerId)) + { + resourceAttributes.Add(new KeyValuePair(AWSSemanticConventions.AttributeContainerID, containerId)); + } + return resourceAttributes; } internal string GetEKSCredentials(string path) { - StringBuilder stringBuilder = new StringBuilder(); - - using (var streamReader = ResourceDetectorUtils.GetStreamReader(path)) + try { - while (!streamReader.EndOfStream) + StringBuilder stringBuilder = new StringBuilder(); + + using (var streamReader = ResourceDetectorUtils.GetStreamReader(path)) { - stringBuilder.Append(streamReader.ReadLine().Trim()); + while (!streamReader.EndOfStream) + { + stringBuilder.Append(streamReader.ReadLine().Trim()); + } } + + return "Bearer " + stringBuilder.ToString(); + } + catch (Exception ex) + { + AWSXRayEventSource.Log.ResourceAttributesExtractException($"{nameof(AWSEKSResourceDetector)} : Failed to load client token", ex); } - return "Bearer " + stringBuilder.ToString(); + return null; } internal string GetEKSContainerId(string path) { - string containerId = null; - - using (var streamReader = ResourceDetectorUtils.GetStreamReader(path)) + try { - while (!streamReader.EndOfStream) + using (var streamReader = ResourceDetectorUtils.GetStreamReader(path)) { - var trimmedLine = streamReader.ReadLine().Trim(); - if (trimmedLine.Length > 64) + while (!streamReader.EndOfStream) { - containerId = trimmedLine.Substring(trimmedLine.Length - 64); - return containerId; + var trimmedLine = streamReader.ReadLine().Trim(); + if (trimmedLine.Length > 64) + { + return trimmedLine.Substring(trimmedLine.Length - 64); + } } } } + catch (Exception ex) + { + AWSXRayEventSource.Log.ResourceAttributesExtractException($"{nameof(AWSEKSResourceDetector)} : Failed to get Container Id", ex); + } - return containerId; + return null; } internal AWSEKSClusterInformationModel DeserializeResponse(string response) @@ -115,26 +125,35 @@ internal AWSEKSClusterInformationModel DeserializeResponse(string response) return ResourceDetectorUtils.DeserializeFromString(response); } - private string GetEKSClusterName(string path) + private string GetEKSClusterName(string credentials) { - var credentials = this.GetEKSCredentials(path); - - if (!this.IsEKSProcess(credentials)) + try { - return null; + var clusterInfo = this.GetEKSClusterInfo(credentials); + return this.DeserializeResponse(clusterInfo)?.Data?.ClusterName; + } + catch (Exception ex) + { + AWSXRayEventSource.Log.ResourceAttributesExtractException($"{nameof(AWSEKSResourceDetector)} : Failed to get cluster information", ex); } - var clusterInfo = this.GetEKSClusterInfo(credentials); - var clusterInfoObject = this.DeserializeResponse(clusterInfo); - - return clusterInfoObject.Data?.ClusterName; + return null; } private bool IsEKSProcess(string credentials) { - var httpClientHandler = this.CreateHttpClientHandler(); - var awsAuth = ResourceDetectorUtils.SendOutRequest(AWSAuthUrl, "GET", new KeyValuePair("Authorization", credentials), httpClientHandler).Result; - return string.IsNullOrEmpty(awsAuth); + string awsAuth = null; + try + { + var httpClientHandler = this.CreateHttpClientHandler(); + awsAuth = ResourceDetectorUtils.SendOutRequest(AWSAuthUrl, "GET", new KeyValuePair("Authorization", credentials), httpClientHandler).Result; + } + catch (Exception ex) + { + AWSXRayEventSource.Log.ResourceAttributesExtractException($"{nameof(AWSEKSResourceDetector)} : Failed to get EKS information", ex); + } + + return !string.IsNullOrEmpty(awsAuth); } private string GetEKSClusterInfo(string credentials) diff --git a/test/OpenTelemetry.Contrib.Extensions.AWSXRay.Tests/Resources/TestAWSEKSResourceDetector.cs b/test/OpenTelemetry.Contrib.Extensions.AWSXRay.Tests/Resources/TestAWSEKSResourceDetector.cs index 961e654140..1273acabfc 100644 --- a/test/OpenTelemetry.Contrib.Extensions.AWSXRay.Tests/Resources/TestAWSEKSResourceDetector.cs +++ b/test/OpenTelemetry.Contrib.Extensions.AWSXRay.Tests/Resources/TestAWSEKSResourceDetector.cs @@ -44,12 +44,43 @@ public void TestExtractResourceAttributes() var resourceAttributes = eksResourceDetector.ExtractResourceAttributes(clusterName, containerId).ToDictionary(x => x.Key, x => x.Value); + Assert.Equal(4, resourceAttributes.Count); Assert.Equal("aws", resourceAttributes[AWSSemanticConventions.AttributeCloudProvider]); Assert.Equal("aws_eks", resourceAttributes[AWSSemanticConventions.AttributeCloudPlatform]); Assert.Equal("Test cluster name", resourceAttributes[AWSSemanticConventions.AttributeK8SClusterName]); Assert.Equal("Test container id", resourceAttributes[AWSSemanticConventions.AttributeContainerID]); } + [Fact] + public void TestExtractResourceAttributesWithEmptyClusterName() + { + var eksResourceDetector = new AWSEKSResourceDetector(); + var containerId = "Test container id"; + + var resourceAttributes = eksResourceDetector.ExtractResourceAttributes(string.Empty, containerId).ToDictionary(x => x.Key, x => x.Value); + + // Validate the count of resourceAttributes -> Excluding cluster name, there will be only three resourceAttributes + Assert.Equal(3, resourceAttributes.Count); + Assert.Equal("aws", resourceAttributes[AWSSemanticConventions.AttributeCloudProvider]); + Assert.Equal("aws_eks", resourceAttributes[AWSSemanticConventions.AttributeCloudPlatform]); + Assert.Equal("Test container id", resourceAttributes[AWSSemanticConventions.AttributeContainerID]); + } + + [Fact] + public void TestExtractResourceAttributesWithEmptyContainerId() + { + var eksResourceDetector = new AWSEKSResourceDetector(); + var clusterName = "Test cluster name"; + + var resourceAttributes = eksResourceDetector.ExtractResourceAttributes(clusterName, string.Empty).ToDictionary(x => x.Key, x => x.Value); + + // Validate the count of resourceAttributes -> Excluding container id, there will be only three resourceAttributes + Assert.Equal(3, resourceAttributes.Count); + Assert.Equal("aws", resourceAttributes[AWSSemanticConventions.AttributeCloudProvider]); + Assert.Equal("aws_eks", resourceAttributes[AWSSemanticConventions.AttributeCloudPlatform]); + Assert.Equal("Test cluster name", resourceAttributes[AWSSemanticConventions.AttributeK8SClusterName]); + } + [Fact] public void TestGetEKSCredentials() {