Skip to content

Commit

Permalink
Make agent update list of systems supporting .NET 6 periodically (#4081)
Browse files Browse the repository at this point in the history
* implemented logic to fetch net6.json from server every hour

* added await keyword

* Moved logic to set warning from ExecutionContext to JobRunner since InitializeJob method is not async

* fixed issue with condition in Equals method of OperatingSystem class

* small refactoring

* net6.json must be read only if it was not fetched from server

* refactored code of method "GetNet6SupportedSystems"

* restored field net6SupportedSystems to reduce IO oprations and cover case when agent started but net6.json is not older than 1 hour

Co-authored-by: Kirill Ivlev <102740624+kirill-ivlev@users.noreply.github.com>
  • Loading branch information
sergey-koryshev and kirill-ivlev authored Dec 16, 2022
1 parent 0f3401a commit 82f092c
Show file tree
Hide file tree
Showing 4 changed files with 73 additions and 53 deletions.
4 changes: 2 additions & 2 deletions src/Agent.Listener/SelfUpdater.cs
Original file line number Diff line number Diff line change
Expand Up @@ -160,10 +160,10 @@ private async Task<bool> UpdateNeeded(string targetVersion, CancellationToken to

Trace.Verbose($"The system you are running on: \"{systemId}\" ({systemVersion})");

if (PlatformUtil.DoesSystemPersistsInNet6Whitelist())
if (await PlatformUtil.DoesSystemPersistsInNet6Whitelist())
{
// Check version of the system
if (!PlatformUtil.IsNet6Supported())
if (!await PlatformUtil.IsNet6Supported())
{
Trace.Warning($"The operating system the agent is running on is \"{systemId}\" ({systemVersion}), which will not be supported by the .NET 6 based v3 agent. Please upgrade the operating system of this host to ensure compatibility with the v3 agent. See https://aka.ms/azdo-pipeline-agent-version");
return false;
Expand Down
48 changes: 34 additions & 14 deletions src/Agent.Sdk/Util/PlatformUtil.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,22 @@

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Net.Sockets;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Xml.Linq;
using Agent.Sdk.Knob;
using Agent.Sdk.Util;
using BuildXL.Cache.MemoizationStore.Interfaces.Caches;
using BuildXL.Utilities;
using Microsoft.TeamFoundation.Build.WebApi;
using Microsoft.VisualStudio.Services.Agent.Util;
using Microsoft.Win32;
using Newtonsoft.Json;
Expand All @@ -23,6 +29,7 @@ public static class PlatformUtil
{
private static UtilKnobValueContext _knobContext = UtilKnobValueContext.Instance();
private static OperatingSystem[] net6SupportedSystems;
private static HttpClient httpClient = new HttpClient();

// System.Runtime.InteropServices.OSPlatform is a struct, so it is
// not suitable for switch statements.
Expand Down Expand Up @@ -309,34 +316,47 @@ public static bool UseLegacyHttpHandler
get => AgentKnobs.UseLegacyHttpHandler.GetValue(_knobContext).AsBoolean();
}

private static OperatingSystem[] GetNet6SupportedSystems()
private async static Task<OperatingSystem[]> GetNet6SupportedSystems()
{
string serverFileUrl = "https://raw.githubusercontent.com/microsoft/azure-pipelines-agent/master/src/Agent.Listener/net6.json";
string supportOSfilePath = Path.Combine(Path.GetDirectoryName(Assembly.GetEntryAssembly().Location), "net6.json");
if (!File.Exists(supportOSfilePath))
string supportOSfileContent;

if (!File.Exists(supportOSfilePath) || File.GetLastWriteTimeUtc(supportOSfilePath) < DateTime.UtcNow.AddHours(-1)) {
HttpResponseMessage response = await httpClient.GetAsync(serverFileUrl);
if (!response.IsSuccessStatusCode)
{
throw new Exception($"Getting file \"net6.json\" from server failed. Status code: {response.StatusCode}");
}
supportOSfileContent = await response.Content.ReadAsStringAsync();
await File.WriteAllTextAsync(supportOSfilePath, supportOSfileContent);
}
else
{
return Array.Empty<OperatingSystem>();
if (net6SupportedSystems != null)
{
return net6SupportedSystems;
}

supportOSfileContent = await File.ReadAllTextAsync(supportOSfilePath);
}

string supportOSfileContent = File.ReadAllText(supportOSfilePath);
return JsonConvert.DeserializeObject<OperatingSystem[]>(supportOSfileContent)!;
net6SupportedSystems = JsonConvert.DeserializeObject<OperatingSystem[]>(supportOSfileContent);
return net6SupportedSystems;
}

public static bool IsNet6Supported()
public async static Task<bool> IsNet6Supported()
{
net6SupportedSystems ??= GetNet6SupportedSystems();
OperatingSystem[] net6SupportedSystems = await GetNet6SupportedSystems();

string systemId = PlatformUtil.GetSystemId();
SystemVersion systemVersion = PlatformUtil.GetSystemVersion();
return net6SupportedSystems.Any((s) => s.Equals(systemId, systemVersion));
}

public static bool DoesSystemPersistsInNet6Whitelist()
public async static Task<bool> DoesSystemPersistsInNet6Whitelist()
{
if (net6SupportedSystems == null)
{
net6SupportedSystems = GetNet6SupportedSystems();
}

OperatingSystem[] net6SupportedSystems = await GetNet6SupportedSystems();
string systemId = PlatformUtil.GetSystemId();

return net6SupportedSystems.Any((s) => s.Equals(systemId));
Expand Down Expand Up @@ -474,7 +494,7 @@ public bool Equals(string systemId) =>
this.Id.Equals(systemId, StringComparison.OrdinalIgnoreCase);

public bool Equals(string systemId, SystemVersion systemVersion) =>
this.Equals(systemId) || this.Versions.Length > 0
this.Equals(systemId) && this.Versions.Length > 0
? this.Versions.Any(version => version.Equals(systemVersion))
: false;
}
Expand Down
37 changes: 0 additions & 37 deletions src/Agent.Worker/ExecutionContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -666,43 +666,6 @@ public void InitializeJob(Pipelines.AgentJobRequestMessage message, Cancellation

// Hook up JobServerQueueThrottling event, we will log warning on server tarpit.
_jobServerQueue.JobServerQueueThrottling += JobServerQueueThrottling_EventReceived;

// Check if a system supports .NET 6
PackageVersion agentVersion = new PackageVersion(BuildConstants.AgentPackage.Version);

if (agentVersion.Major < 3)
{
try
{
Trace.Verbose("Checking if your system supports .NET 6");

string systemId = PlatformUtil.GetSystemId();
SystemVersion systemVersion = PlatformUtil.GetSystemVersion();
string notSupportNet6Message = null;

if (PlatformUtil.DoesSystemPersistsInNet6Whitelist())
{
// Check version of the system
if (!PlatformUtil.IsNet6Supported())
{
notSupportNet6Message = $"The operating system the agent is running on is \"{systemId}\" ({systemVersion}), which will not be supported by the .NET 6 based v3 agent. Please upgrade the operating system of this host to ensure compatibility with the v3 agent. See https://aka.ms/azdo-pipeline-agent-version";
}
}
else
{
notSupportNet6Message = $"The operating system the agent is running on is \"{systemId}\" ({systemVersion}), which has not been tested with the .NET 6 based v3 agent. The v2 agent wil not automatically upgrade to the v3 agent. You can manually download the .NET 6 based v3 agent from https://github.com/microsoft/azure-pipelines-agent/releases. See https://aka.ms/azdo-pipeline-agent-version";
}

if (!string.IsNullOrWhiteSpace(notSupportNet6Message))
{
AddIssue(new Issue() { Type = IssueType.Warning, Message = notSupportNet6Message });
}
}
catch (Exception ex)
{
Trace.Error($"Error has occurred while checking if system supports .NET 6: {ex}");
}
}
}

private string GetWorkspaceIdentifier(Pipelines.AgentJobRequestMessage message)
Expand Down
37 changes: 37 additions & 0 deletions src/Agent.Worker/JobRunner.cs
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,43 @@ public async Task<TaskResult> RunAsync(Pipelines.AgentJobRequestMessage message,
// Create the job execution context.
jobContext = HostContext.CreateService<IExecutionContext>();
jobContext.InitializeJob(message, jobRequestCancellationToken);

// Check if a system supports .NET 6
PackageVersion agentVersion = new PackageVersion(BuildConstants.AgentPackage.Version);
if (agentVersion.Major < 3)
{
try
{
Trace.Verbose("Checking if your system supports .NET 6");

string systemId = PlatformUtil.GetSystemId();
SystemVersion systemVersion = PlatformUtil.GetSystemVersion();
string notSupportNet6Message = null;

if (await PlatformUtil.DoesSystemPersistsInNet6Whitelist())
{
// Check version of the system
if (!await PlatformUtil.IsNet6Supported())
{
notSupportNet6Message = $"The operating system the agent is running on is \"{systemId}\" ({systemVersion}), which will not be supported by the .NET 6 based v3 agent. Please upgrade the operating system of this host to ensure compatibility with the v3 agent. See https://aka.ms/azdo-pipeline-agent-version";
}
}
else
{
notSupportNet6Message = $"The operating system the agent is running on is \"{systemId}\" ({systemVersion}), which has not been tested with the .NET 6 based v3 agent. The v2 agent wil not automatically upgrade to the v3 agent. You can manually download the .NET 6 based v3 agent from https://github.com/microsoft/azure-pipelines-agent/releases. See https://aka.ms/azdo-pipeline-agent-version";
}

if (!string.IsNullOrWhiteSpace(notSupportNet6Message))
{
jobContext.AddIssue(new Issue() { Type = IssueType.Warning, Message = notSupportNet6Message });
}
}
catch (Exception ex)
{
Trace.Error($"Error has occurred while checking if system supports .NET 6: {ex}");
}
}

Trace.Info("Starting the job execution context.");
jobContext.Start();
jobContext.Section(StringUtil.Loc("StepStarting", message.JobDisplayName));
Expand Down

0 comments on commit 82f092c

Please sign in to comment.