Skip to content
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

[CI Visibility] UDS and NamedPipes support #5634

Merged
merged 25 commits into from
Jun 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
c000840
[CI Visibility] UDS and NamedPipes support
tonyredondo May 31, 2024
6ff4327
Fix and add support for the EVP proxy part
tonyredondo May 31, 2024
8a129d8
Reuse AgentTransportStrategy
tonyredondo May 31, 2024
5f70ddf
reuse code and snapshots
tonyredondo May 31, 2024
ebdc23e
NamedPipes tests only on Windows.
tonyredondo Jun 3, 2024
acd2313
Ignore pipes tests on non windows
tonyredondo Jun 3, 2024
cd4eb0e
moar logs
tonyredondo Jun 3, 2024
d7af2aa
Disable parallelism
tonyredondo Jun 3, 2024
d4c1972
Add missing gac installer/uninstaller for windows tests
tonyredondo Jun 4, 2024
35478fc
Fix missing GAC bits for .NET Framework
tonyredondo Jun 5, 2024
469523d
Failure improvements???
tonyredondo Jun 5, 2024
3cb30b3
Merge branch 'master' into tony/civisibility-uds-pipes-support
tonyredondo Jun 5, 2024
8f1600c
moar debug?
tonyredondo Jun 5, 2024
cd856d5
Merge branch 'master' into tony/civisibility-uds-pipes-support
tonyredondo Jun 5, 2024
1c27808
Fix
tonyredondo Jun 5, 2024
16618cf
Fix instrumentation
tonyredondo Jun 5, 2024
34fd92c
stop polluting CI logs with the environment variables
tonyredondo Jun 5, 2024
59b1f4c
fixes
tonyredondo Jun 5, 2024
f0d2eca
Merge branch 'master' into tony/civisibility-uds-pipes-support
tonyredondo Jun 5, 2024
a0f9816
fixes
tonyredondo Jun 5, 2024
9c78586
fixes test helper for dotnet vstest in windows x86
tonyredondo Jun 6, 2024
15956bc
Merge branch 'master' into tony/civisibility-uds-pipes-support
tonyredondo Jun 6, 2024
0feca6b
Removing the DD_TRACE_DEBUG environment variable and increasing the r…
tonyredondo Jun 7, 2024
5dc9c9d
Remove Debug enabled flag
tonyredondo Jun 7, 2024
03fcca7
Merge branch 'master' into tony/civisibility-uds-pipes-support
tonyredondo Jun 7, 2024
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
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
// </copyright>

using System;
using Datadog.Trace.Agent;
using Datadog.Trace.Ci.Configuration;
using Datadog.Trace.Telemetry.Metrics;
using Datadog.Trace.Util;
Expand Down Expand Up @@ -142,7 +143,18 @@ private void EnsureUrl()
else
{
// Use Agent EVP Proxy
builder = new UriBuilder(_settings.TracerSettings.ExporterInternal.AgentUriInternal);
switch (_settings.TracerSettings.ExporterInternal.TracesTransport)
{
case TracesTransportType.WindowsNamedPipe:
case TracesTransportType.UnixDomainSocket:
builder = new UriBuilder("http://localhost");
break;
case TracesTransportType.Default:
default:
builder = new UriBuilder(_settings.TracerSettings.ExporterInternal.AgentUriInternal);
break;
}

if (CIVisibility.EventPlatformProxySupport == EventPlatformProxySupport.V4)
{
builder.Path = $"/evp_proxy/v4/{EventPlatformPath}";
Expand Down
80 changes: 46 additions & 34 deletions tracer/src/Datadog.Trace/Ci/CIVisibility.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,12 @@
using System.Threading.Tasks;
using Datadog.Trace.Agent;
using Datadog.Trace.Agent.DiscoveryService;
using Datadog.Trace.Agent.StreamFactories;
using Datadog.Trace.Agent.Transports;
using Datadog.Trace.Ci.CiEnvironment;
using Datadog.Trace.Ci.Configuration;
using Datadog.Trace.Configuration;
using Datadog.Trace.HttpOverStreams;
using Datadog.Trace.Logging;
using Datadog.Trace.Pdb;
using Datadog.Trace.PlatformHelpers;
Expand Down Expand Up @@ -425,48 +427,57 @@ internal static IApiRequestFactory GetRequestFactory(ImmutableTracerSettings set
internal static IApiRequestFactory GetRequestFactory(ImmutableTracerSettings tracerSettings, TimeSpan timeout)
{
IApiRequestFactory? factory = null;

var exporterSettings = tracerSettings.ExporterInternal;
if (exporterSettings.TracesTransport != TracesTransportType.Default)
{
factory = AgentTransportStrategy.Get(
exporterSettings,
productName: "CI Visibility",
tcpTimeout: null,
AgentHttpHeaderNames.DefaultHeaders,
() => new TraceAgentHttpHeaderHelper(),
uri => uri);
}
else
{
#if NETCOREAPP
Log.Information("Using {FactoryType} for trace transport.", nameof(HttpClientRequestFactory));
factory = new HttpClientRequestFactory(
tracerSettings.ExporterInternal.AgentUriInternal,
AgentHttpHeaderNames.DefaultHeaders,
handler: new System.Net.Http.HttpClientHandler
{
AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate,
},
timeout: timeout);
Log.Information("Using {FactoryType} for trace transport.", nameof(HttpClientRequestFactory));
factory = new HttpClientRequestFactory(
exporterSettings.AgentUriInternal,
AgentHttpHeaderNames.DefaultHeaders,
handler: new System.Net.Http.HttpClientHandler { AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate, },
timeout: timeout);
#else
Log.Information("Using {FactoryType} for trace transport.", nameof(ApiWebRequestFactory));
factory = new ApiWebRequestFactory(tracerSettings.ExporterInternal.AgentUriInternal, AgentHttpHeaderNames.DefaultHeaders, timeout: timeout);
Log.Information("Using {FactoryType} for trace transport.", nameof(ApiWebRequestFactory));
factory = new ApiWebRequestFactory(tracerSettings.ExporterInternal.AgentUriInternal, AgentHttpHeaderNames.DefaultHeaders, timeout: timeout);
#endif
var settings = Settings;
if (!string.IsNullOrWhiteSpace(settings.ProxyHttps))
{
var proxyHttpsUriBuilder = new UriBuilder(settings.ProxyHttps);

var settings = Settings;
if (!string.IsNullOrWhiteSpace(settings.ProxyHttps))
{
var proxyHttpsUriBuilder = new UriBuilder(settings.ProxyHttps);
var userName = proxyHttpsUriBuilder.UserName;
var password = proxyHttpsUriBuilder.Password;

var userName = proxyHttpsUriBuilder.UserName;
var password = proxyHttpsUriBuilder.Password;
proxyHttpsUriBuilder.UserName = string.Empty;
proxyHttpsUriBuilder.Password = string.Empty;

proxyHttpsUriBuilder.UserName = string.Empty;
proxyHttpsUriBuilder.Password = string.Empty;
if (proxyHttpsUriBuilder.Scheme == "https")
{
// HTTPS proxy is not supported by .NET BCL
Log.Error("HTTPS proxy is not supported. ({ProxyHttpsUriBuilder})", proxyHttpsUriBuilder);
return factory;
}

if (proxyHttpsUriBuilder.Scheme == "https")
{
// HTTPS proxy is not supported by .NET BCL
Log.Error("HTTPS proxy is not supported. ({ProxyHttpsUriBuilder})", proxyHttpsUriBuilder);
return factory;
}
NetworkCredential? credential = null;
if (!string.IsNullOrWhiteSpace(userName))
{
credential = new NetworkCredential(userName, password);
}

NetworkCredential? credential = null;
if (!string.IsNullOrWhiteSpace(userName))
{
credential = new NetworkCredential(userName, password);
Log.Information("Setting proxy to: {ProxyHttps}", proxyHttpsUriBuilder.Uri.ToString());
factory.SetProxy(new WebProxy(proxyHttpsUriBuilder.Uri, true, settings.ProxyNoProxy, credential), credential);
}

Log.Information("Setting proxy to: {ProxyHttps}", proxyHttpsUriBuilder.Uri.ToString());
factory.SetProxy(new WebProxy(proxyHttpsUriBuilder.Uri, true, settings.ProxyNoProxy, credential), credential);
}

return factory;
Expand Down Expand Up @@ -608,7 +619,8 @@ private static bool InternalEnabled()
Environment.CommandLine.IndexOf("dotnet.dll\" test", StringComparison.OrdinalIgnoreCase) == -1 &&
Environment.CommandLine.IndexOf("dotnet.dll' test", StringComparison.OrdinalIgnoreCase) == -1 &&
Environment.CommandLine.IndexOf(" test ", StringComparison.OrdinalIgnoreCase) == -1 &&
Environment.CommandLine.IndexOf("datacollector", StringComparison.OrdinalIgnoreCase) == -1)
Environment.CommandLine.IndexOf("datacollector", StringComparison.OrdinalIgnoreCase) == -1 &&
Environment.CommandLine.IndexOf("vstest.console.dll", StringComparison.OrdinalIgnoreCase) == -1)
{
Log.Information("CI Visibility disabled because the process name is 'dotnet' but the commandline doesn't contain 'testhost.dll': {Cmdline}", Environment.CommandLine);
return false;
Expand Down
21 changes: 10 additions & 11 deletions tracer/src/Datadog.Trace/Ci/IntelligentTestRunnerClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -143,23 +143,22 @@ public IntelligentTestRunnerClient(string? workingDirectory, CIVisibilitySetting
else
{
// Use Agent EVP Proxy
var agentUrl = _settings.TracerSettings.ExporterInternal.AgentUriInternal;
_eventPlatformProxySupport = CIVisibility.EventPlatformProxySupport;
switch (_eventPlatformProxySupport)
{
case EventPlatformProxySupport.V2:
_settingsUrl = UriHelpers.Combine(agentUrl, $"evp_proxy/v2/{settingsUrlPath}");
_searchCommitsUrl = UriHelpers.Combine(agentUrl, $"evp_proxy/v2/{searchCommitsUrlPath}");
_packFileUrl = UriHelpers.Combine(agentUrl, $"evp_proxy/v2/{packFileUrlPath}");
_skippableTestsUrl = UriHelpers.Combine(agentUrl, $"evp_proxy/v2/{skippableTestsUrlPath}");
_earlyFlakeDetectionTestsUrl = UriHelpers.Combine(agentUrl, $"evp_proxy/v2/{efdTestsUrlPath}");
_settingsUrl = _apiRequestFactory.GetEndpoint($"evp_proxy/v2/{settingsUrlPath}");
_searchCommitsUrl = _apiRequestFactory.GetEndpoint($"evp_proxy/v2/{searchCommitsUrlPath}");
_packFileUrl = _apiRequestFactory.GetEndpoint($"evp_proxy/v2/{packFileUrlPath}");
_skippableTestsUrl = _apiRequestFactory.GetEndpoint($"evp_proxy/v2/{skippableTestsUrlPath}");
_earlyFlakeDetectionTestsUrl = _apiRequestFactory.GetEndpoint($"evp_proxy/v2/{efdTestsUrlPath}");
break;
case EventPlatformProxySupport.V4:
_settingsUrl = UriHelpers.Combine(agentUrl, $"evp_proxy/v4/{settingsUrlPath}");
_searchCommitsUrl = UriHelpers.Combine(agentUrl, $"evp_proxy/v4/{searchCommitsUrlPath}");
_packFileUrl = UriHelpers.Combine(agentUrl, $"evp_proxy/v4/{packFileUrlPath}");
_skippableTestsUrl = UriHelpers.Combine(agentUrl, $"evp_proxy/v4/{skippableTestsUrlPath}");
_earlyFlakeDetectionTestsUrl = UriHelpers.Combine(agentUrl, $"evp_proxy/v4/{efdTestsUrlPath}");
_settingsUrl = _apiRequestFactory.GetEndpoint($"evp_proxy/v4/{settingsUrlPath}");
_searchCommitsUrl = _apiRequestFactory.GetEndpoint($"evp_proxy/v4/{searchCommitsUrlPath}");
_packFileUrl = _apiRequestFactory.GetEndpoint($"evp_proxy/v4/{packFileUrlPath}");
_skippableTestsUrl = _apiRequestFactory.GetEndpoint($"evp_proxy/v4/{skippableTestsUrlPath}");
_earlyFlakeDetectionTestsUrl = _apiRequestFactory.GetEndpoint($"evp_proxy/v4/{efdTestsUrlPath}");
break;
default:
throw new NotSupportedException("Event platform proxy not supported by the agent.");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
using Datadog.Trace.Configuration;
using Datadog.Trace.ExtensionMethods;
using Datadog.Trace.Logging;
using Datadog.Trace.Propagators;
using Datadog.Trace.Util;
using Datadog.Trace.Vendors.Serilog.Events;

Expand Down Expand Up @@ -51,6 +52,16 @@ internal static bool IsDataCollectorDomain
return null;
}

// Let's detect if we already have a session for this test process
if (SpanContextPropagator.Instance.Extract(
EnvironmentHelpers.GetEnvironmentVariables(),
new DictionaryGetterAndSetter(DictionaryGetterAndSetter.EnvironmentVariableKeyProcessor)) is not null)
{
// Session found in the environment variables
// let's bail-out
return null;
}

var ciVisibilitySettings = CIVisibility.Settings;
var agentless = ciVisibilitySettings.Agentless;
var isEvpProxy = CIVisibility.EventPlatformProxySupport != EventPlatformProxySupport.None;
Expand Down
3 changes: 2 additions & 1 deletion tracer/src/Datadog.Tracer.Native/cor_profiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,8 @@ HRESULT STDMETHODCALLTYPE CorProfiler::Initialize(IUnknown* cor_profiler_info_un
// these are executed with exec, so we could check for that, but the
// below check is more conservative, so leaving at that
process_command_line.find(WStr("testhost")) == WSTRING::npos &&
process_command_line.find(WStr("datacollector")) == WSTRING::npos)
process_command_line.find(WStr("datacollector")) == WSTRING::npos &&
process_command_line.find(WStr("vstest.console.dll")) == WSTRING::npos)
{
Logger::Info("The Tracer Profiler has been disabled because the process is running in CI Visibility "
"mode, the name is 'dotnet' but the commandline doesn't contain 'testhost'");
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
// <copyright file="PipesXUnitEvpTests.cs" company="Datadog">
// Unless explicitly stated otherwise all files in this repository are licensed under the Apache 2 License.
// This product includes software developed at Datadog (https://www.datadoghq.com/). Copyright 2017 Datadog, Inc.
// </copyright>
#if NETCOREAPP3_1_OR_GREATER
using System;
using System.Threading.Tasks;
using Datadog.Trace.Configuration;
using Datadog.Trace.TestHelpers;
using Xunit;
using Xunit.Abstractions;

namespace Datadog.Trace.ClrProfiler.IntegrationTests.CI;

[Collection(nameof(TransportTestsCollection))]
public class PipesXUnitEvpTests(ITestOutputHelper output) : XUnitEvpTests(output)
{
[SkippableTheory]
[MemberData(nameof(GetData))]
[Trait("RunOnWindows", "True")]
[Trait("Category", "EndToEnd")]
[Trait("Category", "TestIntegrations")]
public override async Task SubmitTraces(string packageVersion, string evpVersionToRemove, bool expectedGzip)
{
SkipOn.Platform(SkipOn.PlatformValue.MacOs);
SkipOn.Platform(SkipOn.PlatformValue.Linux);
EnvironmentHelper.EnableWindowsNamedPipes();

// The server implementation of named pipes is flaky so have 5 attempts
var attemptsRemaining = 5;
Comment on lines +29 to +30
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

5 attempts? Is it really that flaky?! IIRC, looking at the metrics, we normally need 1 retry, tops 😬

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I saw a fail with 3 attempts, so I'm trying to play safe...

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I still find 3 consecutive failures concerning 🙈

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Next week I'll look deeper on why the flakiness happens, but seems like something related to our mock server, the test being flaky do parallel connections and send approx 120 spans using those. Is very stable for small payloads.

while (true)
{
try
{
attemptsRemaining--;
await base.SubmitTraces(packageVersion, evpVersionToRemove, expectedGzip);
return;
}
catch (Exception ex) when (attemptsRemaining > 0 && ex is not SkipException)
{
await ReportRetry(Output, attemptsRemaining, ex);
}
}
}

[SkippableTheory]
[MemberData(nameof(GetDataForEarlyFlakeDetection))]
[Trait("RunOnWindows", "True")]
[Trait("Category", "EndToEnd")]
[Trait("Category", "TestIntegrations")]
[Trait("Category", "EarlyFlakeDetection")]
public override async Task EarlyFlakeDetection(string packageVersion, string evpVersionToRemove, bool expectedGzip, string settingsJson, string testsJson, int expectedSpans, string friendlyName)
{
SkipOn.Platform(SkipOn.PlatformValue.MacOs);
SkipOn.Platform(SkipOn.PlatformValue.Linux);
EnvironmentHelper.EnableWindowsNamedPipes();

// The server implementation of named pipes is flaky so have 5 attempts
var attemptsRemaining = 5;
while (true)
{
try
{
attemptsRemaining--;
await base.EarlyFlakeDetection(packageVersion, evpVersionToRemove, expectedGzip, settingsJson, testsJson, expectedSpans, friendlyName);
return;
}
catch (Exception ex) when (attemptsRemaining > 0 && ex is not SkipException)
{
await ReportRetry(Output, attemptsRemaining, ex);
}
}
}
}
#endif
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
// <copyright file="PipesXUnitTests.cs" company="Datadog">
// Unless explicitly stated otherwise all files in this repository are licensed under the Apache 2 License.
// This product includes software developed at Datadog (https://www.datadoghq.com/). Copyright 2017 Datadog, Inc.
// </copyright>

#if NETCOREAPP3_1_OR_GREATER
using System;
using System.Threading.Tasks;
using Datadog.Trace.Configuration;
using Datadog.Trace.TestHelpers;
using Xunit;
using Xunit.Abstractions;

namespace Datadog.Trace.ClrProfiler.IntegrationTests.CI;

[Collection(nameof(TransportTestsCollection))]
public class PipesXUnitTests(ITestOutputHelper output) : XUnitTests(output)
{
[SkippableTheory]
[MemberData(nameof(PackageVersions.XUnit), MemberType = typeof(PackageVersions))]
[Trait("RunOnWindows", "True")]
[Trait("Category", "EndToEnd")]
[Trait("Category", "TestIntegrations")]
public override async Task SubmitTraces(string packageVersion)
{
SkipOn.Platform(SkipOn.PlatformValue.MacOs);
SkipOn.Platform(SkipOn.PlatformValue.Linux);
EnvironmentHelper.EnableWindowsNamedPipes();

// The server implementation of named pipes is flaky so have 5 attempts
var attemptsRemaining = 5;
while (true)
{
try
{
attemptsRemaining--;
await base.SubmitTraces(packageVersion);
return;
}
catch (Exception ex) when (attemptsRemaining > 0 && ex is not SkipException)
{
await ReportRetry(Output, attemptsRemaining, ex);
}
}
}
}

#endif
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// <copyright file="TcpXUnitEvpTests.cs" company="Datadog">
// Unless explicitly stated otherwise all files in this repository are licensed under the Apache 2 License.
// This product includes software developed at Datadog (https://www.datadoghq.com/). Copyright 2017 Datadog, Inc.
// </copyright>
#if NETCOREAPP3_1_OR_GREATER
using System.Threading.Tasks;
using Xunit;
using Xunit.Abstractions;

namespace Datadog.Trace.ClrProfiler.IntegrationTests.CI;

[Collection(nameof(TransportTestsCollection))]
public class TcpXUnitEvpTests(ITestOutputHelper output) : XUnitEvpTests(output)
{
[SkippableTheory]
[MemberData(nameof(GetData))]
[Trait("Category", "EndToEnd")]
[Trait("Category", "TestIntegrations")]
public override Task SubmitTraces(string packageVersion, string evpVersionToRemove, bool expectedGzip)
{
EnvironmentHelper.EnableDefaultTransport();
return base.SubmitTraces(packageVersion, evpVersionToRemove, expectedGzip);
}

[SkippableTheory]
[MemberData(nameof(GetDataForEarlyFlakeDetection))]
[Trait("Category", "EndToEnd")]
[Trait("Category", "TestIntegrations")]
[Trait("Category", "EarlyFlakeDetection")]
public override Task EarlyFlakeDetection(string packageVersion, string evpVersionToRemove, bool expectedGzip, string settingsJson, string testsJson, int expectedSpans, string friendlyName)
{
EnvironmentHelper.EnableDefaultTransport();
return base.EarlyFlakeDetection(packageVersion, evpVersionToRemove, expectedGzip, settingsJson, testsJson, expectedSpans, friendlyName);
}
}
#endif
Loading
Loading