Skip to content

Commit d55567f

Browse files
authored
feat: Allow container linking for AWS ECS applications. (#2683)
1 parent 80cf9ef commit d55567f

File tree

3 files changed

+423
-75
lines changed

3 files changed

+423
-75
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// Copyright 2020 New Relic, Inc. All rights reserved.
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
using Newtonsoft.Json;
5+
6+
namespace NewRelic.Agent.Core.Utilization
7+
{
8+
public class EcsVendorModel : IVendorModel
9+
{
10+
private readonly string _ecsDockerId;
11+
12+
public string VendorName { get { return "ecs"; } }
13+
14+
[JsonProperty("ecsDockerId", NullValueHandling = NullValueHandling.Ignore)]
15+
public string EcsDockerId { get { return _ecsDockerId; } }
16+
17+
public EcsVendorModel(string ecsDockerId)
18+
{
19+
_ecsDockerId = ecsDockerId;
20+
}
21+
}
22+
}

src/Agent/NewRelic/Agent/Core/Utilization/VendorInfo.cs

+71-45
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,9 @@ namespace NewRelic.Agent.Core.Utilization
2020
public class VendorInfo
2121
{
2222
private const string ValidateMetadataRegex = @"^[a-zA-Z0-9-_. /]*$";
23-
private const string ContainerIdV1Regex = @".*cpu.*([0-9a-f]{64})";
24-
private const string ContainerIdV2Regex = ".*/docker/containers/([0-9a-f]{64})/.*";
23+
private const string StandardDockerIdRegex = "([0-9a-f]{64})";
24+
private const string ContainerIdV1Regex = @".*cpu.*" + StandardDockerIdRegex;
25+
private const string ContainerIdV2Regex = ".*/docker/containers/" + StandardDockerIdRegex + "/.*";
2526
private const string AwsEcsMetadataV3EnvVar = "ECS_CONTAINER_METADATA_URI";
2627
private const string AwsEcsMetadataV4EnvVar = "ECS_CONTAINER_METADATA_URI_V4";
2728

@@ -32,7 +33,7 @@ public class VendorInfo
3233
private const string PcfName = @"pcf";
3334
private const string DockerName = @"docker";
3435
private const string KubernetesName = @"kubernetes";
35-
private const string EcsFargateName = @"ecs-fargate";
36+
private const string EcsName = @"ecs";
3637

3738
private readonly string AwsTokenUri = @"http://169.254.169.254/latest/api/token";
3839
private readonly string AwsMetadataUri = @"http://169.254.169.254/latest/dynamic/instance-identity/document";
@@ -72,15 +73,33 @@ public IDictionary<string, IVendorModel> GetVendors()
7273
var vendorMethods = new List<Func<IVendorModel>>();
7374

7475
if (_configuration.UtilizationDetectAws)
76+
{
7577
vendorMethods.Add(GetAwsVendorInfo);
78+
79+
// Directly add the ECS vendor info if AWS is enabled and not null.
80+
var ecsVendorInfo = GetEcsVendorInfo();
81+
if (ecsVendorInfo != null)
82+
{
83+
vendors.Add(ecsVendorInfo.VendorName, ecsVendorInfo);
84+
}
85+
86+
}
7687
if (_configuration.UtilizationDetectAzure)
88+
{
7789
vendorMethods.Add(GetAzureVendorInfo);
90+
}
7891
if (_configuration.UtilizationDetectGcp)
92+
{
7993
vendorMethods.Add(GetGcpVendorInfo);
94+
}
8095
if (_configuration.UtilizationDetectPcf)
96+
{
8197
vendorMethods.Add(GetPcfVendorInfo);
98+
}
8299
if (_configuration.UtilizationDetectAzureFunction)
100+
{
83101
vendorMethods.Add(GetAzureFunctionVendorInfo);
102+
}
84103

85104
foreach (var vendorMethod in vendorMethods)
86105
{
@@ -94,8 +113,9 @@ public IDictionary<string, IVendorModel> GetVendors()
94113
}
95114
}
96115

97-
// If Docker info is set to be checked, it must be checked for all vendors.
98-
if (_configuration.UtilizationDetectDocker)
116+
// If Docker info is set to be checked, it must be checked for all vendors even disabled ones.
117+
// If we get AWS ECS info, we don't need to check Docker.
118+
if (_configuration.UtilizationDetectDocker && !vendors.ContainsKey(EcsName))
99119
{
100120
var dockerVendorInfo = GetDockerVendorInfo(new FileReaderWrapper(), IsLinux());
101121
if (dockerVendorInfo != null)
@@ -322,42 +342,6 @@ public IVendorModel GetDockerVendorInfo(IFileReaderWrapper fileReaderWrapper, bo
322342
}
323343
}
324344

325-
if (vendorModel == null)
326-
{
327-
try
328-
{
329-
var metadataUri = GetProcessEnvironmentVariable(AwsEcsMetadataV4EnvVar);
330-
if (!string.IsNullOrWhiteSpace(metadataUri))
331-
{
332-
vendorModel = TryGetEcsFargateDockerId(metadataUri);
333-
if (vendorModel == null)
334-
Log.Finest($"Found {AwsEcsMetadataV4EnvVar} but failed to parse Docker container id.");
335-
}
336-
}
337-
catch (Exception ex)
338-
{
339-
Log.Finest(ex, $"Failed to parse Docker container id from {AwsEcsMetadataV4EnvVar}.");
340-
}
341-
}
342-
343-
if (vendorModel == null)
344-
{
345-
try
346-
{
347-
var metadataUri = GetProcessEnvironmentVariable(AwsEcsMetadataV3EnvVar);
348-
if (!string.IsNullOrWhiteSpace(metadataUri))
349-
{
350-
vendorModel = TryGetEcsFargateDockerId(metadataUri);
351-
if (vendorModel == null)
352-
Log.Finest($"Found {AwsEcsMetadataV3EnvVar} but failed to parse Docker container id.");
353-
}
354-
}
355-
catch (Exception ex)
356-
{
357-
Log.Finest(ex, $"Failed to parse Docker container id from {AwsEcsMetadataV3EnvVar}.");
358-
}
359-
}
360-
361345
return vendorModel;
362346
}
363347

@@ -403,13 +387,55 @@ private IVendorModel TryGetDockerCGroupV2(string fileContent)
403387
return id == null ? null : new DockerVendorModel(id);
404388
}
405389

406-
private IVendorModel TryGetEcsFargateDockerId(string metadataUri)
390+
public IVendorModel GetEcsVendorInfo()
407391
{
408-
var responseJson = _vendorHttpApiRequestor.CallVendorApi(new Uri(metadataUri), GetMethod, EcsFargateName);
392+
IVendorModel ecsVendorModel = null;
393+
try
394+
{
395+
var metadataUri = GetProcessEnvironmentVariable(AwsEcsMetadataV4EnvVar);
396+
if (!string.IsNullOrWhiteSpace(metadataUri))
397+
{
398+
ecsVendorModel = TryGetEcsVendorModel(metadataUri);
399+
if (ecsVendorModel == null)
400+
{
401+
Log.Finest($"Found {AwsEcsMetadataV4EnvVar} but failed to parse Docker container id.");
402+
}
403+
}
404+
}
405+
catch (Exception ex)
406+
{
407+
Log.Finest(ex, $"Failed to parse Docker container id from {AwsEcsMetadataV4EnvVar}.");
408+
}
409+
410+
if (ecsVendorModel == null)
411+
{
412+
try
413+
{
414+
var metadataUri = GetProcessEnvironmentVariable(AwsEcsMetadataV3EnvVar);
415+
if (!string.IsNullOrWhiteSpace(metadataUri))
416+
{
417+
ecsVendorModel = TryGetEcsVendorModel(metadataUri);
418+
if (ecsVendorModel == null)
419+
{
420+
Log.Finest($"Found {AwsEcsMetadataV3EnvVar} but failed to parse Docker container id.");
421+
}
422+
}
423+
}
424+
catch (Exception ex)
425+
{
426+
Log.Finest(ex, $"Failed to parse Docker container id from {AwsEcsMetadataV3EnvVar}.");
427+
}
428+
}
429+
430+
return ecsVendorModel;
431+
}
432+
433+
private IVendorModel TryGetEcsVendorModel(string metadataUri)
434+
{
435+
var responseJson = _vendorHttpApiRequestor.CallVendorApi(new Uri(metadataUri), GetMethod, EcsName);
409436
var jObject = JObject.Parse(responseJson);
410437
var idToken = jObject.SelectToken("DockerId");
411-
var id = NormalizeAndValidateMetadata((string)idToken, "DockerId", EcsFargateName);
412-
return id == null ? null : new DockerVendorModel(id);
438+
return idToken == null ? null : new EcsVendorModel((string)idToken);
413439
}
414440

415441
public IVendorModel GetKubernetesInfo()

0 commit comments

Comments
 (0)