diff --git a/.autover/changes/7107587d-3fa8-4094-aa23-7b1d1f92b562.json b/.autover/changes/7107587d-3fa8-4094-aa23-7b1d1f92b562.json
new file mode 100644
index 00000000..8223afd3
--- /dev/null
+++ b/.autover/changes/7107587d-3fa8-4094-aa23-7b1d1f92b562.json
@@ -0,0 +1,30 @@
+{
+ "Projects": [
+ {
+ "Name": "Amazon.ECS.Tools",
+ "Type": "Major",
+ "ChangelogMessages": [
+ "Updated to V4 of the AWS SDK for .NET",
+ "Updated the minimum requirement from .NET Core 3.1 to .NET 6"
+ ]
+ },
+ {
+ "Name": "Amazon.ElasticBeanstalk.Tools",
+ "Type": "Major",
+ "ChangelogMessages": [
+ "Updated to V4 of the AWS SDK for .NET",
+ "Updated the minimum requirement from .NET Core 3.1 to .NET 6"
+ ]
+ },
+ {
+ "Name": "Amazon.Lambda.Tools",
+ "Type": "Major",
+ "ChangelogMessages": [
+ "Updated to V4 of the AWS SDK for .NET",
+ "Updated the minimum requirement from .NET Core 3.1 to .NET 6",
+ "Fixed \"The image manifest or layer media type for the source image is not supported.\" issue when container image was built for a Lambda function by adding the \"--provenance=false\" switch for the docker buildx command"
+ ]
+ }
+
+ ]
+}
\ No newline at end of file
diff --git a/src/Amazon.Common.DotNetCli.Tools/Amazon.Common.DotNetCli.Tools.csproj b/src/Amazon.Common.DotNetCli.Tools/Amazon.Common.DotNetCli.Tools.csproj
index 8500202a..8661764e 100644
--- a/src/Amazon.Common.DotNetCli.Tools/Amazon.Common.DotNetCli.Tools.csproj
+++ b/src/Amazon.Common.DotNetCli.Tools/Amazon.Common.DotNetCli.Tools.csproj
@@ -1,19 +1,25 @@
- netcoreapp3.1;net6.0
+ net6.0;net8.0
+
+ 7.3
-
-
-
-
-
-
-
+
+
+
+
+
+
+
- 1701;1702;1705;1591
+ true
+ 1701;1702;1705;1591;NETSDK1138
\ No newline at end of file
diff --git a/src/Amazon.Common.DotNetCli.Tools/Commands/BaseCommand.cs b/src/Amazon.Common.DotNetCli.Tools/Commands/BaseCommand.cs
index 0312a34f..a431e006 100644
--- a/src/Amazon.Common.DotNetCli.Tools/Commands/BaseCommand.cs
+++ b/src/Amazon.Common.DotNetCli.Tools/Commands/BaseCommand.cs
@@ -7,14 +7,15 @@
using System.Linq;
using System.Reflection;
using System.Text;
+using System.Text.Json;
using System.Threading.Tasks;
-using ThirdParty.Json.LitJson;
using Amazon.ECR;
using Amazon.IdentityManagement;
using Amazon.IdentityManagement.Model;
using Amazon.S3;
using Amazon.SecurityToken;
+using Amazon.Runtime.Credentials;
namespace Amazon.Common.DotNetCli.Tools.Commands
{
@@ -36,7 +37,7 @@ public BaseCommand(IToolLogger logger, string workingDirectory)
public BaseCommand(IToolLogger logger, string workingDirectory, IList possibleOptions, string[] args)
: this(logger, workingDirectory)
{
- args = args ?? new string[0];
+ args = args ?? Array.Empty();
this.OriginalCommandLineArguments = args;
var values = CommandLineParser.ParseArguments(possibleOptions, args);
ParseCommandArguments(values);
@@ -250,12 +251,12 @@ protected AWSCredentials DetermineAWSCredentials()
var chain = new CredentialProfileStoreChain(this.ProfileLocation);
if (!chain.TryGetAWSCredentials(profile, out this._resolvedCredentials))
{
- this._resolvedCredentials = FallbackCredentialsFactory.GetCredentials();
+ this._resolvedCredentials = DefaultAWSCredentialsIdentityResolver.GetCredentials();
}
}
else
{
- this._resolvedCredentials = FallbackCredentialsFactory.GetCredentials();
+ this._resolvedCredentials = DefaultAWSCredentialsIdentityResolver.GetCredentials();
}
if(this._resolvedCredentials is AssumeRoleAWSCredentials)
@@ -384,12 +385,12 @@ public string GetRoleValueOrDefault(string propertyValue, CommandOption option,
}
///
- /// Complex parameters are formatted as a JSON string. This method parses the string into the JsonData object
+ /// Complex parameters are formatted as a JSON string. This method parses the string into the JsonElement object
///
///
///
///
- public JsonData GetJsonValueOrDefault(string propertyValue, CommandOption option)
+ public JsonElement? GetJsonValueOrDefault(string propertyValue, CommandOption option)
{
string jsonContent = GetStringValueOrDefault(propertyValue, option, false);
if (string.IsNullOrWhiteSpace(jsonContent))
@@ -397,8 +398,10 @@ public JsonData GetJsonValueOrDefault(string propertyValue, CommandOption option
try
{
- var data = JsonMapper.ToObject(jsonContent);
- return data;
+ using (JsonDocument doc = JsonDocument.Parse(jsonContent))
+ {
+ return doc.RootElement.Clone();
+ }
}
catch(Exception e)
{
@@ -697,7 +700,7 @@ protected string PromptForValue(CommandOption option)
return cachedValue;
}
- string input = null;
+ string input;
Console.Out.WriteLine($"Enter {option.Name}: ({option.Description})");
@@ -838,29 +841,27 @@ protected void SaveConfigFile()
{
try
{
- JsonData data;
+ var data = new Dictionary();
if (File.Exists(this.DefaultConfig.SourceFile))
{
- data = JsonMapper.ToObject(File.ReadAllText(this.DefaultConfig.SourceFile));
- }
- else
- {
- data = new JsonData();
+ string existingJson = File.ReadAllText(this.DefaultConfig.SourceFile);
+ using (JsonDocument doc = JsonDocument.Parse(existingJson))
+ {
+ foreach (JsonProperty prop in doc.RootElement.EnumerateObject())
+ {
+ data[prop.Name] = prop.Value.GetJsonValue();
+ }
+ }
}
data.SetIfNotNull(CommonDefinedCommandOptions.ARGUMENT_AWS_REGION.ConfigFileKey, this.GetStringValueOrDefault(this.Region, CommonDefinedCommandOptions.ARGUMENT_AWS_REGION, false));
data.SetIfNotNull(CommonDefinedCommandOptions.ARGUMENT_AWS_PROFILE.ConfigFileKey, this.GetStringValueOrDefault(this.Profile, CommonDefinedCommandOptions.ARGUMENT_AWS_PROFILE, false));
data.SetIfNotNull(CommonDefinedCommandOptions.ARGUMENT_AWS_PROFILE_LOCATION.ConfigFileKey, this.GetStringValueOrDefault(this.ProfileLocation, CommonDefinedCommandOptions.ARGUMENT_AWS_PROFILE_LOCATION, false));
-
SaveConfigFile(data);
- StringBuilder sb = new StringBuilder();
- JsonWriter writer = new JsonWriter(sb);
- writer.PrettyPrint = true;
- JsonMapper.ToJson(data, writer);
-
- var json = sb.ToString();
+ var options = new JsonSerializerOptions { WriteIndented = true };
+ var json = JsonSerializer.Serialize(data, options);
File.WriteAllText(this.DefaultConfig.SourceFile, json);
this.Logger?.WriteLine($"Config settings saved to {this.DefaultConfig.SourceFile}");
}
@@ -870,7 +871,7 @@ protected void SaveConfigFile()
}
}
- protected abstract void SaveConfigFile(JsonData data);
+ protected abstract void SaveConfigFile(Dictionary data);
public bool ConfirmDeletion(string resource)
{
diff --git a/src/Amazon.Common.DotNetCli.Tools/Commands/BasePushDockerImageCommand.cs b/src/Amazon.Common.DotNetCli.Tools/Commands/BasePushDockerImageCommand.cs
index 95067d53..1cdb044f 100644
--- a/src/Amazon.Common.DotNetCli.Tools/Commands/BasePushDockerImageCommand.cs
+++ b/src/Amazon.Common.DotNetCli.Tools/Commands/BasePushDockerImageCommand.cs
@@ -5,7 +5,6 @@
using Amazon.ECR.Model;
using Amazon.ECR;
-using ThirdParty.Json.LitJson;
using System.IO;
using Amazon.Common.DotNetCli.Tools.Options;
using Amazon.Common.DotNetCli.Tools;
@@ -338,7 +337,7 @@ private async Task SetupECRRepository(string ecrRepositoryName)
}
Repository repository;
- if (describeResponse != null && describeResponse.Repositories.Count == 1)
+ if (describeResponse != null && describeResponse.Repositories != null && describeResponse.Repositories.Count == 1)
{
this.Logger?.WriteLine($"Found existing ECR Repository {ecrRepositoryName}");
repository = describeResponse.Repositories[0];
@@ -367,6 +366,11 @@ private async Task InitiateDockerLogin(DockerCLIWrapper dockerCLI)
this.Logger?.WriteLine("Fetching ECR authorization token to use to login with the docker CLI");
var response = await this.ECRClient.GetAuthorizationTokenAsync(new GetAuthorizationTokenRequest());
+ if (response.AuthorizationData == null || response.AuthorizationData.Count == 0)
+ {
+ throw new ToolsException("No authorization data returned from ECR", ToolsException.CommonErrorCode.GetECRAuthTokens);
+ }
+
var authTokenBytes = Convert.FromBase64String(response.AuthorizationData[0].AuthorizationToken);
var authToken = Encoding.UTF8.GetString(authTokenBytes);
var decodedTokens = authToken.Split(':');
@@ -387,7 +391,7 @@ private async Task InitiateDockerLogin(DockerCLIWrapper dockerCLI)
}
}
- protected override void SaveConfigFile(JsonData data)
+ protected override void SaveConfigFile(Dictionary data)
{
this.PushDockerImageProperties.PersistSettings(this, data);
}
@@ -490,7 +494,7 @@ public void ParseCommandArguments(CommandOptions values)
}
- public void PersistSettings(BaseCommand command, JsonData data)
+ public void PersistSettings(BaseCommand command, Dictionary data)
{
data.SetIfNotNull(CommonDefinedCommandOptions.ARGUMENT_CONFIGURATION.ConfigFileKey, command.GetStringValueOrDefault(this.Configuration, CommonDefinedCommandOptions.ARGUMENT_CONFIGURATION, false));
data.SetIfNotNull(CommonDefinedCommandOptions.ARGUMENT_FRAMEWORK.ConfigFileKey, command.GetStringValueOrDefault(this.TargetFramework, CommonDefinedCommandOptions.ARGUMENT_FRAMEWORK, false));
diff --git a/src/Amazon.Common.DotNetCli.Tools/DefaultConfigFile.cs b/src/Amazon.Common.DotNetCli.Tools/DefaultConfigFile.cs
index 4c27dfe6..0b96cfbf 100644
--- a/src/Amazon.Common.DotNetCli.Tools/DefaultConfigFile.cs
+++ b/src/Amazon.Common.DotNetCli.Tools/DefaultConfigFile.cs
@@ -3,27 +3,27 @@
using System.Collections.Generic;
using System.IO;
using System.Text;
-using ThirdParty.Json.LitJson;
+using System.Text.Json;
namespace Amazon.Common.DotNetCli.Tools
{
public abstract class DefaultConfigFile
{
- JsonData _rootData;
+ JsonElement _rootData;
public DefaultConfigFile()
- : this(new JsonData(), string.Empty)
+ : this(new JsonElement(), string.Empty)
{
}
public DefaultConfigFile(string sourceFile)
- : this(new JsonData(), sourceFile)
+ : this(new JsonElement(), sourceFile)
{
}
- public DefaultConfigFile(JsonData data, string sourceFile)
+ public DefaultConfigFile(JsonElement data, string sourceFile)
{
- this._rootData = data ?? new JsonData();
+ this._rootData = data;
this.SourceFile = sourceFile;
}
@@ -47,17 +47,18 @@ public void LoadDefaults(string projectLocation, string configFile)
if (!File.Exists(path))
return;
- using (var reader = new StreamReader(File.OpenRead(path)))
+ try
{
- try
+ string json = File.ReadAllText(path);
+ using (JsonDocument doc = JsonDocument.Parse(json))
{
- this._rootData = JsonMapper.ToObject(reader) as JsonData;
- this.SourceFile = path;
- }
- catch (Exception e)
- {
- throw new ToolsException($"Error parsing default config {path}: {e.Message}", ToolsException.CommonErrorCode.DefaultsParseFail, e);
+ this._rootData = doc.RootElement.Clone();
}
+ this.SourceFile = path;
+ }
+ catch (Exception e)
+ {
+ throw new ToolsException($"Error parsing default config {path}: {e.Message}", ToolsException.CommonErrorCode.DefaultsParseFail, e);
}
}
@@ -73,42 +74,45 @@ public object this[string fullSwitchName]
if (fullSwitchName.StartsWith("--"))
fullSwitchName = fullSwitchName.Substring(2);
- if (this._rootData[fullSwitchName] == null)
+ if (_rootData.ValueKind == JsonValueKind.Undefined || !_rootData.TryGetProperty(fullSwitchName, out JsonElement element))
return null;
- if (this._rootData[fullSwitchName].IsString)
- return this._rootData[fullSwitchName].ToString();
- if (this._rootData[fullSwitchName].IsInt)
- return (int)this._rootData[fullSwitchName];
- if (this._rootData[fullSwitchName].IsBoolean)
- return (bool)this._rootData[fullSwitchName];
- if (this._rootData[fullSwitchName].IsArray)
- {
- var items = new string[this._rootData[fullSwitchName].Count];
- for (int i = 0; i < items.Length; i++)
- {
- items[i] = this._rootData[fullSwitchName][i].ToString();
- }
- return items;
- }
- if (this._rootData[fullSwitchName].IsObject)
+ switch (element.ValueKind)
{
- var obj = new Dictionary();
- foreach (var key in this._rootData[fullSwitchName].PropertyNames)
- {
- obj[key] = this._rootData[key]?.ToString();
- }
- return obj;
+ case JsonValueKind.String:
+ return element.GetString();
+ case JsonValueKind.Number:
+ return element.GetInt32();
+ case JsonValueKind.True:
+ case JsonValueKind.False:
+ return element.GetBoolean();
+ case JsonValueKind.Array:
+ var items = new string[element.GetArrayLength()];
+ int index = 0;
+ foreach (JsonElement item in element.EnumerateArray())
+ {
+ items[index++] = item.ToString();
+ }
+ return items;
+ case JsonValueKind.Object:
+ var obj = new Dictionary();
+ foreach (JsonProperty prop in element.EnumerateObject())
+ {
+ obj[prop.Name] = prop.Value.ToString();
+ }
+ return obj;
+ default:
+ return null;
}
-
- return null;
}
}
- protected JsonData GetValue(CommandOption option)
+ protected JsonElement GetValue(CommandOption option)
{
var key = option.Switch.Substring(2);
- return this._rootData[key];
+ if (_rootData.ValueKind == JsonValueKind.Undefined || !_rootData.TryGetProperty(key, out JsonElement element))
+ return new JsonElement();
+ return element;
}
///
@@ -119,18 +123,21 @@ protected JsonData GetValue(CommandOption option)
public string GetValueAsString(CommandOption option)
{
var key = option.Switch.Substring(2);
- var data = this._rootData[key];
- if (data == null)
+ if (_rootData.ValueKind == JsonValueKind.Undefined || !_rootData.TryGetProperty(key, out JsonElement element))
return null;
- if (data.IsString)
- return data.ToString();
- else if (data.IsBoolean)
- return ((bool)data).ToString();
- else if (data.IsInt)
- return ((int)data).ToString();
-
- return null;
+ switch (element.ValueKind)
+ {
+ case JsonValueKind.String:
+ return element.GetString();
+ case JsonValueKind.True:
+ case JsonValueKind.False:
+ return element.GetBoolean().ToString();
+ case JsonValueKind.Number:
+ return element.GetInt32().ToString();
+ default:
+ return null;
+ }
}
@@ -159,11 +166,10 @@ public static string FormatKeyValue(IDictionary values)
public string GetRawString(string key)
{
- var data = this._rootData[key];
- if (data == null || !data.IsString)
+ if (_rootData.ValueKind == JsonValueKind.Undefined || !_rootData.TryGetProperty(key, out JsonElement element) || element.ValueKind != JsonValueKind.String)
return null;
- return data.ToString();
+ return element.GetString();
}
}
}
diff --git a/src/Amazon.Common.DotNetCli.Tools/DockerCLIWrapper.cs b/src/Amazon.Common.DotNetCli.Tools/DockerCLIWrapper.cs
index a7e8f713..89b6b042 100644
--- a/src/Amazon.Common.DotNetCli.Tools/DockerCLIWrapper.cs
+++ b/src/Amazon.Common.DotNetCli.Tools/DockerCLIWrapper.cs
@@ -30,19 +30,17 @@ public int Build(string workingDirectory, string dockerFile, string imageTag, st
var arguments = new StringBuilder();
-#if NETCOREAPP3_1_OR_GREATER
- var runningOnLinuxArm64 = RuntimeInformation.IsOSPlatform(OSPlatform.Linux) && RuntimeInformation.ProcessArchitecture == Architecture.Arm64;
-#else
- var runningOnLinuxArm64 = false;
-#endif
- if (arm64Build && !runningOnLinuxArm64)
+ // The --provenance=false switch is added to force docker to not build an image index which is an image with a manifest.
+ // Lambda does not support containers of this type. This can be verified by running "docker inspect" on the build
+ // image. The mediaType should be application/vnd.docker.distribution.manifest.v2+json but without
+ // the --provenance=false the mediaType will be application/vnd.oci.image.index.v1+json.
+ if (arm64Build)
{
- _logger?.WriteLine("The docker CLI \"buildx\" command is used to build ARM64 images. This requires version 20 or later of the docker CLI.");
- arguments.Append($"buildx build --platform linux/arm64 ");
+ arguments.Append($"buildx build --platform linux/arm64 --provenance=false ");
}
else
{
- arguments.Append($"build ");
+ arguments.Append($"buildx build --platform linux/amd64 --provenance=false ");
}
arguments.Append($" -f \"{dockerFile}\" -t {imageTag}");
diff --git a/src/Amazon.Common.DotNetCli.Tools/ExtensionMethods.cs b/src/Amazon.Common.DotNetCli.Tools/ExtensionMethods.cs
index 0b642d1b..2e067b31 100644
--- a/src/Amazon.Common.DotNetCli.Tools/ExtensionMethods.cs
+++ b/src/Amazon.Common.DotNetCli.Tools/ExtensionMethods.cs
@@ -1,21 +1,21 @@
using System;
-using System.IO;
using System.Collections.Generic;
+using System.IO;
using System.Text;
-using ThirdParty.Json.LitJson;
+using System.Text.Json;
namespace Amazon.Common.DotNetCli.Tools
{
public static class ExtensionMethods
{
- public static void SetIfNotNull(this JsonData data, string key, string value)
+ public static void SetIfNotNull(this Dictionary data, string key, string value)
{
if (value == null)
return;
data[key] = value;
}
- public static void SetFilePathIfNotNull(this JsonData data, string key, string filepath, string rootPath)
+ public static void SetFilePathIfNotNull(this Dictionary data, string key, string filepath, string rootPath)
{
if (string.IsNullOrEmpty(filepath))
return;
@@ -30,19 +30,51 @@ public static void SetFilePathIfNotNull(this JsonData data, string key, string f
data[key] = filepath;
}
- public static void SetIfNotNull(this JsonData data, string key, bool? value)
+ public static void SetIfNotNull(this Dictionary data, string key, bool? value)
{
if (!value.HasValue)
return;
data[key] = value.Value;
}
- public static void SetIfNotNull(this JsonData data, string key, int? value)
+ public static void SetIfNotNull(this Dictionary data, string key, int? value)
{
if (!value.HasValue)
return;
data[key] = value.Value;
}
+
+ public static object GetJsonValue(this JsonElement element)
+ {
+ switch (element.ValueKind)
+ {
+ case JsonValueKind.String:
+ return element.GetString();
+ case JsonValueKind.Number:
+ if (element.TryGetInt32(out int intValue))
+ return intValue;
+ return element.GetDouble();
+ case JsonValueKind.True:
+ case JsonValueKind.False:
+ return element.GetBoolean();
+ case JsonValueKind.Array:
+ var array = new List