diff --git a/.autover/changes/49c69f86-aa08-45d2-ba6b-70117f5f1d1d.json b/.autover/changes/49c69f86-aa08-45d2-ba6b-70117f5f1d1d.json new file mode 100644 index 0000000..c92ceed --- /dev/null +++ b/.autover/changes/49c69f86-aa08-45d2-ba6b-70117f5f1d1d.json @@ -0,0 +1,11 @@ +{ + "Projects": [ + { + "Name": "Amazon.ElasticBeanstalk.Tools", + "Type": "Patch", + "ChangelogMessages": [ + "Fixed an ElasticBeanstalk deployment issue for Linux platform where Procfile was sometimes being generated with incorrect entrypoint when multiple runtimeconfig.json files were present." + ] + } + ] +} \ No newline at end of file diff --git a/src/Amazon.ElasticBeanstalk.Tools/EBUtilities.cs b/src/Amazon.ElasticBeanstalk.Tools/EBUtilities.cs index 964397b..0aa71b9 100644 --- a/src/Amazon.ElasticBeanstalk.Tools/EBUtilities.cs +++ b/src/Amazon.ElasticBeanstalk.Tools/EBUtilities.cs @@ -3,7 +3,6 @@ using System.Globalization; using System.IO; using System.Linq; -using System.Runtime.CompilerServices; using Amazon.Common.DotNetCli.Tools; using Amazon.ElasticBeanstalk.Model; using Amazon.ElasticBeanstalk.Tools.Commands; @@ -108,26 +107,24 @@ public static bool IsLoadBalancedEnvironmentType(string environmentType) return string.Equals(environmentType, EBConstants.ENVIRONMENT_TYPE_LOADBALANCED, StringComparison.OrdinalIgnoreCase); } - public static void SetupPackageForLinux(IToolLogger logger, EBBaseCommand command, DeployEnvironmentProperties options, string publishLocation, string reverseProxy, int? applicationPort) { // Setup Procfile var procfilePath = Path.Combine(publishLocation, "Procfile"); - if(File.Exists(procfilePath)) + if (File.Exists(procfilePath)) { logger?.WriteLine("Found existing Procfile file found and using that for deployment"); return; } logger?.WriteLine("Writing Procfile for deployment bundle"); - - var runtimeConfigFilePath = Directory.GetFiles(publishLocation, "*.runtimeconfig.json").FirstOrDefault(); + string runtimeConfigFilePath = GetRuntimeConfigFilePath(publishLocation); var runtimeConfigFileName = Path.GetFileName(runtimeConfigFilePath); var executingAssembly = runtimeConfigFileName.Substring(0, runtimeConfigFileName.Length - "runtimeconfig.json".Length - 1); string webCommandLine; - if(IsSelfContainedPublish(runtimeConfigFilePath)) + if (IsSelfContainedPublish(runtimeConfigFilePath)) { webCommandLine = $"./{executingAssembly}"; } @@ -136,7 +133,7 @@ public static void SetupPackageForLinux(IToolLogger logger, EBBaseCommand comman webCommandLine = $"dotnet exec ./{executingAssembly}.dll"; } - if(string.Equals(reverseProxy, EBConstants.PROXY_SERVER_NONE, StringComparison.InvariantCulture)) + if (string.Equals(reverseProxy, EBConstants.PROXY_SERVER_NONE, StringComparison.InvariantCulture)) { logger?.WriteLine("... Proxy server disabled, configuring Kestrel to listen to traffic from all hosts"); var port = applicationPort.HasValue ? applicationPort.Value : EBConstants.DEFAULT_APPLICATION_PORT; @@ -175,5 +172,65 @@ public static string FindExistingValue(this List set var setting = settings?.FirstOrDefault(x => string.Equals(x.Namespace, ns, StringComparison.InvariantCulture) && string.Equals(x.OptionName, name, StringComparison.InvariantCulture)); return setting?.Value; } + + private static string GetRuntimeConfigFilePath(string publishLocation) + { + var runtimeConfigFiles = Directory.GetFiles(publishLocation, "*.runtimeconfig.json"); + + // Handle case where application could have multiple runtimeconfig.json files in publish location. + if (runtimeConfigFiles.Length > 1) + { + foreach (var file in runtimeConfigFiles) + { + var fileContent = File.ReadAllText(file); + + JsonData root = JsonMapper.ToObject(fileContent); + JsonData runtimeOptions = root["runtimeOptions"] as JsonData; + if (runtimeOptions == null) + { + continue; + } + + // runtimeOptions node can contain framework or frameworks (refer https://github.com/dotnet/sdk/blob/main/documentation/specs/runtime-configuration-file.md#runtimeoptions-section-runtimeconfigjson). + var frameworkNode = runtimeOptions["framework"]; + var frameworksNode = runtimeOptions["frameworks"]; + + if (IsAspNetFramework(frameworkNode)) + { + return file; + } + + if (frameworksNode != null && frameworksNode.Count > 0) + { + foreach (var framework in frameworksNode) + { + var tempNode = framework as JsonData; + if (IsAspNetFramework(tempNode)) + { + return file; + } + } + } + } + } + + return Directory.GetFiles(publishLocation, "*.runtimeconfig.json").FirstOrDefault(); + } + + private static bool IsAspNetFramework(JsonData frameworkNode) + { + if (frameworkNode != null) + { + var name = frameworkNode["name"]; + + if (name != null) + { + string frameworkName = (string)name; + return !string.IsNullOrEmpty(frameworkName) && frameworkName.StartsWith("Microsoft.AspNetCore"); + } + } + + return false; + } } }