Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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 @@ -41,6 +41,7 @@ public static IServiceCollection AddBuildScriptGeneratorServices(this IServiceCo
services.AddSingleton<DefaultPlatformsInformationProvider>();
services.AddSingleton<PlatformsInstallationScriptProvider>();
services.AddSingleton<IExternalSdkProvider, ExternalSdkProvider>();
services.AddSingleton<IMcrSdkProvider, McrSdkProvider>();
services.AddHttpClient("general", httpClient =>
{
// NOTE: Setting user agent is required to avoid receiving 403 Forbidden response.
Expand Down
25 changes: 25 additions & 0 deletions src/BuildScriptGenerator/Contracts/IMcrSdkProvider.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// --------------------------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
// --------------------------------------------------------------------------------------------

using System.Threading.Tasks;

namespace Microsoft.Oryx.BuildScriptGenerator
{
/// <summary>
/// Interface for pulling SDKs from MCR/ACR container images.
/// </summary>
public interface IMcrSdkProvider
{
/// <summary>
/// Pulls the SDK tarball from an MCR/ACR container image and places it
/// in the external SDKs storage directory so existing installation logic can use it.
/// </summary>
/// <param name="platformName">The platform name (e.g. "nodejs", "python", "dotnet", "php").</param>
/// <param name="version">The platform version (e.g. "18.20.8").</param>
/// <param name="debianFlavor">The debian flavor (e.g. "bookworm").</param>
/// <returns>True if the SDK was pulled and cached successfully.</returns>
Task<bool> PullSdkAsync(string platformName, string version, string debianFlavor);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,11 @@ public IEnumerable<PlatformInfo> GetPlatformsInfo(RepositoryContext context)
this.outputWriter.WriteLine("External SDK provider is enabled.");
}

if (this.commonOptions.EnableMcrSdkProvider)
{
this.outputWriter.WriteLine("MCR SDK provider is enabled.");
}

foreach (var platform in this.platforms)
{
// Check if a platform is enabled or not
Expand Down
123 changes: 100 additions & 23 deletions src/BuildScriptGenerator/DotNetCore/DotnetCorePlatform.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ internal class DotNetCorePlatform : IProgrammingPlatform
private readonly DotNetCorePlatformInstaller platformInstaller;
private readonly GlobalJsonSdkResolver globalJsonSdkResolver;
private readonly IExternalSdkProvider externalSdkProvider;
private readonly IMcrSdkProvider mcrSdkProvider;
private readonly TelemetryClient telemetryClient;

/// <summary>
Expand All @@ -47,6 +48,7 @@ internal class DotNetCorePlatform : IProgrammingPlatform
/// <param name="dotNetCoreScriptGeneratorOptions">The options if .NET platform.</param>
/// <param name="platformInstaller">The <see cref="DotNetCorePlatformInstaller"/>.</param>
/// <param name="globalJsonSdkResolver">The <see cref="GlobalJsonSdkResolver"/>.</param>
/// <param name="mcrSdkProvider">The <see cref="IMcrSdkProvider"/>.</param>
public DotNetCorePlatform(
IDotNetCoreVersionProvider versionProvider,
ILogger<DotNetCorePlatform> logger,
Expand All @@ -56,6 +58,7 @@ public DotNetCorePlatform(
DotNetCorePlatformInstaller platformInstaller,
GlobalJsonSdkResolver globalJsonSdkResolver,
IExternalSdkProvider externalSdkProvider,
IMcrSdkProvider mcrSdkProvider,
TelemetryClient telemetryClient)
{
this.versionProvider = versionProvider;
Expand All @@ -66,6 +69,7 @@ public DotNetCorePlatform(
this.platformInstaller = platformInstaller;
this.globalJsonSdkResolver = globalJsonSdkResolver;
this.externalSdkProvider = externalSdkProvider;
this.mcrSdkProvider = mcrSdkProvider;
this.telemetryClient = telemetryClient;
}

Expand Down Expand Up @@ -244,30 +248,18 @@ public string GetInstallerScriptSnippet(
}
else
{
if (this.commonOptions.EnableExternalSdkProvider)
// Try external SDK provider first (blob storage via socket)
bool sdkFetched = this.TryFetchSdkFromExternalProvider(this.Name, dotNetCorePlatformDetectorResult.SdkVersion);

// Try MCR SDK provider (container image pull)
if (!sdkFetched)
{
sdkFetched = this.TryPullSdkFromMcr(this.Name, dotNetCorePlatformDetectorResult.SdkVersion);
}

if (sdkFetched)
{
this.logger.LogDebug("DotNetCore SDK version {version} is not installed. External SDK provider is enabled so trying to fetch SDK using it.", dotNetCorePlatformDetectorResult.SdkVersion);

try
{
var blobName = BlobNameHelper.GetBlobNameForVersion(this.Name, dotNetCorePlatformDetectorResult.SdkVersion, this.commonOptions.DebianFlavor);
var isExternalFetchSuccess = this.externalSdkProvider.RequestBlobAsync(this.Name, blobName).Result;
if (isExternalFetchSuccess)
{
this.logger.LogDebug("DotNetCore SDK version {version} is fetched successfully using external SDK provider. So generating an installation script snippet which skips platform binary download.", dotNetCorePlatformDetectorResult.SdkVersion);
installationScriptSnippet = this.platformInstaller.GetInstallerScriptSnippet(dotNetCorePlatformDetectorResult.SdkVersion, skipSdkBinaryDownload: true);
}
else
{
this.logger.LogDebug("DotNetCore SDK version {version} is not fetched successfully using external SDK provider. So generating an installation script snippet for it.", dotNetCorePlatformDetectorResult.SdkVersion);
installationScriptSnippet = this.platformInstaller.GetInstallerScriptSnippet(dotNetCorePlatformDetectorResult.SdkVersion);
}
}
catch (Exception ex)
{
this.logger.LogError(ex, "Error while fetching DotNetCore SDK version version {version} using external SDK provider.", dotNetCorePlatformDetectorResult.SdkVersion);
installationScriptSnippet = this.platformInstaller.GetInstallerScriptSnippet(dotNetCorePlatformDetectorResult.SdkVersion);
}
installationScriptSnippet = this.platformInstaller.GetInstallerScriptSnippet(dotNetCorePlatformDetectorResult.SdkVersion, skipSdkBinaryDownload: true);
}
else
{
Expand Down Expand Up @@ -477,5 +469,90 @@ private bool TryGetExplicitVersion(out string explicitVersion)

return false;
}

/// <summary>
/// Tries to fetch the SDK from the external SDK provider (blob storage via Unix socket) if enabled.
/// </summary>
/// <returns>True if the SDK was successfully fetched from the external provider.</returns>
private bool TryFetchSdkFromExternalProvider(string platformName, string version)
{
if (!this.commonOptions.EnableExternalSdkProvider)
{
return false;
}

this.logger.LogDebug(
"{platform} version {version} is not installed. " +
"External SDK provider is enabled so trying to fetch SDK using it.",
platformName,
version);

try
{
var blobName = BlobNameHelper.GetBlobNameForVersion(platformName, version, this.commonOptions.DebianFlavor);
var success = this.externalSdkProvider.RequestBlobAsync(platformName, blobName).Result;
if (success)
{
this.logger.LogDebug(
"{platform} version {version} fetched successfully using external SDK provider.",
platformName,
version);
return true;
}

this.logger.LogDebug(
"{platform} version {version} could not be fetched using external SDK provider. Falling through to next provider.",
platformName,
version);
}
catch (Exception ex)
{
this.logger.LogError(ex, "Error while fetching {platform} version {version} using external SDK provider.", platformName, version);
}

return false;
}

/// <summary>
/// Tries to pull the SDK from MCR container image if enabled.
/// </summary>
/// <returns>True if the SDK was successfully fetched from MCR.</returns>
private bool TryPullSdkFromMcr(string platformName, string version)
{
if (!this.commonOptions.EnableMcrSdkProvider)
{
return false;
}

this.logger.LogDebug(
"{platform} version {version} is not installed. " +
"MCR SDK provider is enabled so trying to fetch SDK from container image.",
platformName,
version);

try
{
var success = this.mcrSdkProvider.PullSdkAsync(platformName, version, this.commonOptions.DebianFlavor).Result;
if (success)
{
this.logger.LogDebug(
"{platform} version {version} fetched successfully using MCR SDK provider.",
platformName,
version);
return true;
}

this.logger.LogDebug(
"{platform} version {version} could not be fetched using MCR SDK provider. Falling through to next provider.",
platformName,
version);
}
catch (Exception ex)
{
this.logger.LogError(ex, "Error while fetching {platform} version {version} using MCR SDK provider.", platformName, version);
}

return false;
}
}
}
Loading