using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Amazon.Lambda.Model;
using ThirdParty.Json.LitJson;
using Amazon.Common.DotNetCli.Tools;
using Amazon.Common.DotNetCli.Tools.Commands;
using Amazon.Common.DotNetCli.Tools.Options;
using Amazon.Runtime.Internal;
namespace Amazon.Lambda.Tools.Commands
{
///
/// Command to deploy a function to AWS Lambda. When redeploying an existing function only function configuration properties
/// that were explicitly set will be used. Default function configuration values are ignored for redeploy. This
/// is to avoid any accidental changes to the function.
///
public class DeployFunctionCommand : UpdateFunctionConfigCommand
{
public const string COMMAND_DEPLOY_NAME = "deploy-function";
public const string COMMAND_DEPLOY_DESCRIPTION = "Command to deploy the project to AWS Lambda";
public const string COMMAND_DEPLOY_ARGUMENTS = " The name of the function to deploy";
public static readonly IList DeployCommandOptions = BuildLineOptions(new List
{
CommonDefinedCommandOptions.ARGUMENT_CONFIGURATION,
CommonDefinedCommandOptions.ARGUMENT_FRAMEWORK,
CommonDefinedCommandOptions.ARGUMENT_MSBUILD_PARAMETERS,
LambdaDefinedCommandOptions.ARGUMENT_PACKAGE,
LambdaDefinedCommandOptions.ARGUMENT_FUNCTION_NAME,
LambdaDefinedCommandOptions.ARGUMENT_FUNCTION_DESCRIPTION,
LambdaDefinedCommandOptions.ARGUMENT_PACKAGE_TYPE,
LambdaDefinedCommandOptions.ARGUMENT_FUNCTION_PUBLISH,
LambdaDefinedCommandOptions.ARGUMENT_FUNCTION_MEMORY_SIZE,
LambdaDefinedCommandOptions.ARGUMENT_FUNCTION_ROLE,
LambdaDefinedCommandOptions.ARGUMENT_FUNCTION_TIMEOUT,
LambdaDefinedCommandOptions.ARGUMENT_FUNCTION_HANDLER,
LambdaDefinedCommandOptions.ARGUMENT_FUNCTION_RUNTIME,
LambdaDefinedCommandOptions.ARGUMENT_FUNCTION_ARCHITECTURE,
LambdaDefinedCommandOptions.ARGUMENT_FUNCTION_LAYERS,
LambdaDefinedCommandOptions.ARGUMENT_IMAGE_ENTRYPOINT,
LambdaDefinedCommandOptions.ARGUMENT_IMAGE_COMMAND,
LambdaDefinedCommandOptions.ARGUMENT_IMAGE_WORKING_DIRECTORY,
CommonDefinedCommandOptions.ARGUMENT_DOCKER_TAG,
LambdaDefinedCommandOptions.ARGUMENT_EPHEMERAL_STORAGE_SIZE,
LambdaDefinedCommandOptions.ARGUMENT_FUNCTION_URL_ENABLE,
LambdaDefinedCommandOptions.ARGUMENT_FUNCTION_URL_AUTH,
LambdaDefinedCommandOptions.ARGUMENT_FUNCTION_TAGS,
LambdaDefinedCommandOptions.ARGUMENT_FUNCTION_SUBNETS,
LambdaDefinedCommandOptions.ARGUMENT_FUNCTION_SECURITY_GROUPS,
LambdaDefinedCommandOptions.ARGUMENT_DEADLETTER_TARGET_ARN,
LambdaDefinedCommandOptions.ARGUMENT_TRACING_MODE,
LambdaDefinedCommandOptions.ARGUMENT_ENVIRONMENT_VARIABLES,
LambdaDefinedCommandOptions.ARGUMENT_APPEND_ENVIRONMENT_VARIABLES,
LambdaDefinedCommandOptions.ARGUMENT_KMS_KEY_ARN,
LambdaDefinedCommandOptions.ARGUMENT_APPLY_DEFAULTS_FOR_UPDATE_OBSOLETE,
LambdaDefinedCommandOptions.ARGUMENT_RESOLVE_S3,
LambdaDefinedCommandOptions.ARGUMENT_S3_BUCKET,
LambdaDefinedCommandOptions.ARGUMENT_S3_PREFIX,
LambdaDefinedCommandOptions.ARGUMENT_DISABLE_VERSION_CHECK,
CommonDefinedCommandOptions.ARGUMENT_LOCAL_DOCKER_IMAGE,
CommonDefinedCommandOptions.ARGUMENT_DOCKERFILE,
CommonDefinedCommandOptions.ARGUMENT_DOCKER_BUILD_OPTIONS,
CommonDefinedCommandOptions.ARGUMENT_DOCKER_BUILD_WORKING_DIRECTORY,
CommonDefinedCommandOptions.ARGUMENT_HOST_BUILD_OUTPUT,
LambdaDefinedCommandOptions.ARGUMENT_USE_CONTAINER_FOR_BUILD,
LambdaDefinedCommandOptions.ARGUMENT_CONTAINER_IMAGE_FOR_BUILD,
LambdaDefinedCommandOptions.ARGUMENT_CODE_MOUNT_DIRECTORY
});
public string Architecture { get; set; }
public string Configuration { get; set; }
public string TargetFramework { get; set; }
public string Package { get; set; }
public string MSBuildParameters { get; set; }
public bool? ResolveS3 { get; set; }
public string S3Bucket { get; set; }
public string S3Prefix { get; set; }
public bool? DisableVersionCheck { get; set; }
public string DockerFile { get; set; }
public string DockerBuildOptions { get; set; }
public string DockerBuildWorkingDirectory { get; set; }
public string DockerImageTag { get; set; }
public string HostBuildOutput { get; set; }
public string LocalDockerImage { get; set; }
public bool? UseContainerForBuild { get; set; }
public string ContainerImageForBuild { get; set; }
public string CodeMountDirectory { get; set; }
public DeployFunctionCommand(IToolLogger logger, string workingDirectory, string[] args)
: base(logger, workingDirectory, DeployCommandOptions, args)
{
}
///
/// Parse the CommandOptions into the Properties on the command.
///
///
protected override void ParseCommandArguments(CommandOptions values)
{
base.ParseCommandArguments(values);
if (values.Arguments.Count > 0)
{
this.FunctionName = values.Arguments[0];
}
Tuple tuple;
if ((tuple = values.FindCommandOption(CommonDefinedCommandOptions.ARGUMENT_CONFIGURATION.Switch)) != null)
this.Configuration = tuple.Item2.StringValue;
if ((tuple = values.FindCommandOption(CommonDefinedCommandOptions.ARGUMENT_FRAMEWORK.Switch)) != null)
this.TargetFramework = tuple.Item2.StringValue;
if ((tuple = values.FindCommandOption(LambdaDefinedCommandOptions.ARGUMENT_PACKAGE.Switch)) != null)
this.Package = tuple.Item2.StringValue;
if ((tuple = values.FindCommandOption(LambdaDefinedCommandOptions.ARGUMENT_RESOLVE_S3.Switch)) != null)
this.ResolveS3 = tuple.Item2.BoolValue;
if ((tuple = values.FindCommandOption(LambdaDefinedCommandOptions.ARGUMENT_S3_BUCKET.Switch)) != null)
this.S3Bucket = tuple.Item2.StringValue;
if ((tuple = values.FindCommandOption(LambdaDefinedCommandOptions.ARGUMENT_S3_PREFIX.Switch)) != null)
this.S3Prefix = tuple.Item2.StringValue;
if ((tuple = values.FindCommandOption(LambdaDefinedCommandOptions.ARGUMENT_DISABLE_VERSION_CHECK.Switch)) != null)
this.DisableVersionCheck = tuple.Item2.BoolValue;
if ((tuple = values.FindCommandOption(LambdaDefinedCommandOptions.ARGUMENT_FUNCTION_ARCHITECTURE.Switch)) != null)
this.Architecture = tuple.Item2.StringValue;
if ((tuple = values.FindCommandOption(CommonDefinedCommandOptions.ARGUMENT_MSBUILD_PARAMETERS.Switch)) != null)
this.MSBuildParameters = tuple.Item2.StringValue;
if (!string.IsNullOrEmpty(values.MSBuildParameters))
{
if (this.MSBuildParameters == null)
this.MSBuildParameters = values.MSBuildParameters;
else
this.MSBuildParameters += " " + values.MSBuildParameters;
}
if ((tuple = values.FindCommandOption(LambdaDefinedCommandOptions.ARGUMENT_PACKAGE_TYPE.Switch)) != null)
this.PackageType = tuple.Item2.StringValue;
if ((tuple = values.FindCommandOption(CommonDefinedCommandOptions.ARGUMENT_DOCKERFILE.Switch)) != null)
this.DockerFile = tuple.Item2.StringValue;
if ((tuple = values.FindCommandOption(CommonDefinedCommandOptions.ARGUMENT_DOCKER_BUILD_OPTIONS.Switch)) != null)
this.DockerBuildOptions = tuple.Item2.StringValue;
if ((tuple = values.FindCommandOption(CommonDefinedCommandOptions.ARGUMENT_DOCKER_BUILD_WORKING_DIRECTORY.Switch)) != null)
this.DockerBuildWorkingDirectory = tuple.Item2.StringValue;
if ((tuple = values.FindCommandOption(LambdaDefinedCommandOptions.ARGUMENT_IMAGE_TAG.Switch)) != null)
this.DockerImageTag = tuple.Item2.StringValue;
if ((tuple = values.FindCommandOption(CommonDefinedCommandOptions.ARGUMENT_HOST_BUILD_OUTPUT.Switch)) != null)
this.HostBuildOutput = tuple.Item2.StringValue;
if ((tuple = values.FindCommandOption(CommonDefinedCommandOptions.ARGUMENT_LOCAL_DOCKER_IMAGE.Switch)) != null)
this.LocalDockerImage = tuple.Item2.StringValue;
if ((tuple = values.FindCommandOption(LambdaDefinedCommandOptions.ARGUMENT_USE_CONTAINER_FOR_BUILD.Switch)) != null)
this.UseContainerForBuild = tuple.Item2.BoolValue;
if ((tuple = values.FindCommandOption(LambdaDefinedCommandOptions.ARGUMENT_CONTAINER_IMAGE_FOR_BUILD.Switch)) != null)
this.ContainerImageForBuild = tuple.Item2.StringValue;
if ((tuple = values.FindCommandOption(LambdaDefinedCommandOptions.ARGUMENT_CODE_MOUNT_DIRECTORY.Switch)) != null)
this.CodeMountDirectory = tuple.Item2.StringValue;
}
protected override async Task PerformActionAsync()
{
string projectLocation = Utilities.DetermineProjectLocation(this.WorkingDirectory, this.GetStringValueOrDefault(this.ProjectLocation, CommonDefinedCommandOptions.ARGUMENT_PROJECT_LOCATION, false));
string zipArchivePath = null;
string package = this.GetStringValueOrDefault(this.Package, LambdaDefinedCommandOptions.ARGUMENT_PACKAGE, false);
var layerVersionArns = this.GetStringValuesOrDefault(this.LayerVersionArns, LambdaDefinedCommandOptions.ARGUMENT_FUNCTION_LAYERS, false);
var layerPackageInfo = await LambdaUtilities.LoadLayerPackageInfos(this.Logger, this.LambdaClient, this.S3Client, layerVersionArns);
var architecture = this.GetStringValueOrDefault(this.Architecture, LambdaDefinedCommandOptions.ARGUMENT_FUNCTION_ARCHITECTURE, false);
Lambda.PackageType packageType = DeterminePackageType();
string ecrImageUri = null;
if (packageType == Lambda.PackageType.Image)
{
var pushResults = await PushLambdaImageAsync();
if (!pushResults.Success)
{
if (pushResults.LastException != null)
throw pushResults.LastException;
throw new LambdaToolsException("Failed to push container image to ECR.", LambdaToolsException.LambdaErrorCode.FailedToPushImage);
}
ecrImageUri = pushResults.ImageUri;
}
else
{
if (string.IsNullOrEmpty(package))
{
EnsureInProjectDirectory();
// Release will be the default configuration if nothing set.
string configuration = this.GetStringValueOrDefault(this.Configuration, CommonDefinedCommandOptions.ARGUMENT_CONFIGURATION, false);
var targetFramework = this.GetStringValueOrDefault(this.TargetFramework, CommonDefinedCommandOptions.ARGUMENT_FRAMEWORK, false);
if (string.IsNullOrEmpty(targetFramework))
{
targetFramework = Utilities.LookupTargetFrameworkFromProjectFile(projectLocation);
// If we still don't know what the target framework is ask the user what targetframework to use.
// This is common when a project is using multi targeting.
if(string.IsNullOrEmpty(targetFramework))
{
targetFramework = this.GetStringValueOrDefault(this.TargetFramework, CommonDefinedCommandOptions.ARGUMENT_FRAMEWORK, true);
}
}
string msbuildParameters = this.GetStringValueOrDefault(this.MSBuildParameters, CommonDefinedCommandOptions.ARGUMENT_MSBUILD_PARAMETERS, false);
bool isNativeAot = Utilities.LookPublishAotFlag(projectLocation, this.MSBuildParameters);
ValidateTargetFrameworkAndLambdaRuntime(targetFramework);
bool disableVersionCheck = this.GetBoolValueOrDefault(this.DisableVersionCheck, LambdaDefinedCommandOptions.ARGUMENT_DISABLE_VERSION_CHECK, false).GetValueOrDefault();
string publishLocation;
LambdaPackager.CreateApplicationBundle(defaults: this.DefaultConfig,
logger: this.Logger,
workingDirectory: this.WorkingDirectory,
projectLocation: projectLocation,
configuration: configuration,
targetFramework: targetFramework,
msbuildParameters: msbuildParameters,
architecture: architecture,
disableVersionCheck: disableVersionCheck,
layerPackageInfo: layerPackageInfo,
isNativeAot: isNativeAot,
useContainerForBuild: GetBoolValueOrDefault(this.UseContainerForBuild, LambdaDefinedCommandOptions.ARGUMENT_USE_CONTAINER_FOR_BUILD, false),
containerImageForBuild: GetStringValueOrDefault(this.ContainerImageForBuild, LambdaDefinedCommandOptions.ARGUMENT_CONTAINER_IMAGE_FOR_BUILD, false),
codeMountDirectory: GetStringValueOrDefault(this.CodeMountDirectory, LambdaDefinedCommandOptions.ARGUMENT_CODE_MOUNT_DIRECTORY, false),
publishLocation: out publishLocation,
zipArchivePath: ref zipArchivePath
);
if (string.IsNullOrEmpty(zipArchivePath))
throw new LambdaToolsException("Failed to create Lambda deployment bundle.", ToolsException.CommonErrorCode.DotnetPublishFailed);
}
else
{
if (!File.Exists(package))
throw new LambdaToolsException($"Package {package} does not exist", LambdaToolsException.LambdaErrorCode.InvalidPackage);
if (!string.Equals(Path.GetExtension(package), ".zip", StringComparison.OrdinalIgnoreCase))
throw new LambdaToolsException($"Package {package} must be a zip file", LambdaToolsException.LambdaErrorCode.InvalidPackage);
this.Logger.WriteLine($"Skipping compilation and using precompiled package {package}");
zipArchivePath = package;
}
}
MemoryStream lambdaZipArchiveStream = null;
if(zipArchivePath != null)
{
lambdaZipArchiveStream = new MemoryStream(File.ReadAllBytes(zipArchivePath));
}
try
{
var s3Bucket = this.GetStringValueOrDefault(this.S3Bucket, LambdaDefinedCommandOptions.ARGUMENT_S3_BUCKET, false);
bool? resolveS3 = this.GetBoolValueOrDefault(this.ResolveS3, LambdaDefinedCommandOptions.ARGUMENT_RESOLVE_S3, false);
string s3Key = null;
if (zipArchivePath != null && (resolveS3 == true || !string.IsNullOrEmpty(s3Bucket)))
{
if(string.IsNullOrEmpty(s3Bucket))
{
s3Bucket = await LambdaUtilities.ResolveDefaultS3Bucket(this.Logger, this.S3Client, this.STSClient);
}
else
{
await Utilities.ValidateBucketRegionAsync(this.S3Client, s3Bucket);
}
var functionName = this.GetStringValueOrDefault(this.FunctionName, LambdaDefinedCommandOptions.ARGUMENT_FUNCTION_NAME, true);
var s3Prefix = this.GetStringValueOrDefault(this.S3Prefix, LambdaDefinedCommandOptions.ARGUMENT_S3_PREFIX, false);
s3Key = await Utilities.UploadToS3Async(this.Logger, this.S3Client, s3Bucket, s3Prefix, functionName, lambdaZipArchiveStream);
}
var currentConfiguration = await GetFunctionConfigurationAsync();
if (currentConfiguration == null)
{
this.Logger.WriteLine($"Creating new Lambda function {this.FunctionName}");
var createRequest = new CreateFunctionRequest
{
PackageType = packageType,
FunctionName = this.GetStringValueOrDefault(this.FunctionName, LambdaDefinedCommandOptions.ARGUMENT_FUNCTION_NAME, true),
Description = this.GetStringValueOrDefault(this.Description, LambdaDefinedCommandOptions.ARGUMENT_FUNCTION_DESCRIPTION, false),
Role = this.GetRoleValueOrDefault(this.Role, LambdaDefinedCommandOptions.ARGUMENT_FUNCTION_ROLE,
Constants.LAMBDA_PRINCIPAL, LambdaConstants.AWS_LAMBDA_MANAGED_POLICY_PREFIX,
LambdaConstants.KNOWN_MANAGED_POLICY_DESCRIPTIONS, true),
Publish = this.GetBoolValueOrDefault(this.Publish, LambdaDefinedCommandOptions.ARGUMENT_FUNCTION_PUBLISH, false).GetValueOrDefault(),
MemorySize = this.GetIntValueOrDefault(this.MemorySize, LambdaDefinedCommandOptions.ARGUMENT_FUNCTION_MEMORY_SIZE, true).GetValueOrDefault(),
Timeout = this.GetIntValueOrDefault(this.Timeout, LambdaDefinedCommandOptions.ARGUMENT_FUNCTION_TIMEOUT, true).GetValueOrDefault(),
KMSKeyArn = this.GetStringValueOrDefault(this.KMSKeyArn, LambdaDefinedCommandOptions.ARGUMENT_KMS_KEY_ARN, false),
VpcConfig = new VpcConfig
{
SubnetIds = this.GetStringValuesOrDefault(this.SubnetIds, LambdaDefinedCommandOptions.ARGUMENT_FUNCTION_SUBNETS, false)?.ToList(),
SecurityGroupIds = this.GetStringValuesOrDefault(this.SecurityGroupIds, LambdaDefinedCommandOptions.ARGUMENT_FUNCTION_SECURITY_GROUPS, false)?.ToList()
}
};
var ephemeralSize = this.GetIntValueOrDefault(this.EphemeralStorageSize, LambdaDefinedCommandOptions.ARGUMENT_EPHEMERAL_STORAGE_SIZE, false);
if(ephemeralSize.HasValue)
{
createRequest.EphemeralStorage = new EphemeralStorage
{
Size = ephemeralSize.Value
};
}
if (!string.IsNullOrEmpty(architecture))
{
createRequest.Architectures = new List { architecture };
}
if(packageType == Lambda.PackageType.Zip)
{
createRequest.Handler = this.GetStringValueOrDefault(this.Handler, LambdaDefinedCommandOptions.ARGUMENT_FUNCTION_HANDLER, true);
createRequest.Runtime = this.GetStringValueOrDefault(this.Runtime, LambdaDefinedCommandOptions.ARGUMENT_FUNCTION_RUNTIME, true);
createRequest.Layers = layerVersionArns?.ToList();
if (s3Bucket != null)
{
createRequest.Code = new FunctionCode
{
S3Bucket = s3Bucket,
S3Key = s3Key
};
}
else
{
createRequest.Code = new FunctionCode
{
ZipFile = lambdaZipArchiveStream
};
}
}
else if(packageType == Lambda.PackageType.Image)
{
createRequest.Code = new FunctionCode
{
ImageUri = ecrImageUri
};
createRequest.ImageConfig = new ImageConfig
{
Command = this.GetStringValuesOrDefault(this.ImageCommand, LambdaDefinedCommandOptions.ARGUMENT_IMAGE_COMMAND, false)?.ToList(),
EntryPoint = this.GetStringValuesOrDefault(this.ImageEntryPoint, LambdaDefinedCommandOptions.ARGUMENT_IMAGE_ENTRYPOINT, false)?.ToList(),
WorkingDirectory = this.GetStringValueOrDefault(this.ImageWorkingDirectory, LambdaDefinedCommandOptions.ARGUMENT_IMAGE_WORKING_DIRECTORY, false)
};
}
var environmentVariables = GetEnvironmentVariables(null);
var dotnetShareStoreVal = layerPackageInfo.GenerateDotnetSharedStoreValue();
if(!string.IsNullOrEmpty(dotnetShareStoreVal))
{
if(environmentVariables == null)
{
environmentVariables = new Dictionary();
}
environmentVariables[LambdaConstants.ENV_DOTNET_SHARED_STORE] = dotnetShareStoreVal;
}
if (environmentVariables != null && environmentVariables.Count > 0)
{
createRequest.Environment = new Model.Environment
{
Variables = environmentVariables
};
}
var tags = this.GetKeyValuePairOrDefault(this.Tags, LambdaDefinedCommandOptions.ARGUMENT_FUNCTION_TAGS, false);
if(tags != null && tags.Count > 0)
{
createRequest.Tags = tags;
}
var deadLetterQueue = this.GetStringValueOrDefault(this.DeadLetterTargetArn, LambdaDefinedCommandOptions.ARGUMENT_DEADLETTER_TARGET_ARN, false);
if(!string.IsNullOrEmpty(deadLetterQueue))
{
createRequest.DeadLetterConfig = new DeadLetterConfig {TargetArn = deadLetterQueue };
}
var tracingMode = this.GetStringValueOrDefault(this.TracingMode, LambdaDefinedCommandOptions.ARGUMENT_TRACING_MODE, false);
if(!string.IsNullOrEmpty(tracingMode))
{
createRequest.TracingConfig = new TracingConfig { Mode = tracingMode };
}
try
{
await this.LambdaClient.CreateFunctionAsync(createRequest);
this.Logger.WriteLine("New Lambda function created");
}
catch (Exception e)
{
throw new LambdaToolsException($"Error creating Lambda function: {e.Message}", LambdaToolsException.LambdaErrorCode.LambdaCreateFunction, e);
}
if(this.GetBoolValueOrDefault(this.FunctionUrlEnable, LambdaDefinedCommandOptions.ARGUMENT_FUNCTION_URL_ENABLE, false).GetValueOrDefault())
{
var authType = this.GetStringValueOrDefault(this.FunctionUrlAuthType, LambdaDefinedCommandOptions.ARGUMENT_FUNCTION_URL_AUTH, false);
await base.CreateFunctionUrlConfig(createRequest.FunctionName, authType);
this.Logger.WriteLine($"Function url config created: {this.FunctionUrlLink}");
}
}
else
{
this.Logger.WriteLine($"Updating code for existing function {this.FunctionName}");
var updateCodeRequest = new UpdateFunctionCodeRequest
{
FunctionName = this.GetStringValueOrDefault(this.FunctionName, LambdaDefinedCommandOptions.ARGUMENT_FUNCTION_NAME, true)
};
if (!string.IsNullOrEmpty(architecture))
{
updateCodeRequest.Architectures = new List { architecture };
}
// In case the function is currently being updated from previous deployment wait till it available
// to be updated.
if (currentConfiguration.LastUpdateStatus == LastUpdateStatus.InProgress)
{
await LambdaUtilities.WaitTillFunctionAvailableAsync(Logger, this.LambdaClient, updateCodeRequest.FunctionName);
}
if (packageType == Lambda.PackageType.Zip)
{
if (s3Bucket != null)
{
updateCodeRequest.S3Bucket = s3Bucket;
updateCodeRequest.S3Key = s3Key;
}
else
{
updateCodeRequest.ZipFile = lambdaZipArchiveStream;
}
}
else if (packageType == Lambda.PackageType.Image)
{
updateCodeRequest.ImageUri = ecrImageUri;
}
var configUpdated = false;
try
{
// Update config should run before updating the function code to avoid a situation such as
// upgrading from an EOL .NET version to a supported version where the update would fail
// since lambda thinks we are updating an EOL version instead of upgrading.
configUpdated = await base.UpdateConfigAsync(currentConfiguration, layerPackageInfo.GenerateDotnetSharedStoreValue());
}
catch (Exception e)
{
throw new LambdaToolsException($"Error updating configuration for Lambda function: {e.Message}", LambdaToolsException.LambdaErrorCode.LambdaUpdateFunctionConfiguration, e);
}
try
{
await LambdaUtilities.WaitTillFunctionAvailableAsync(Logger, this.LambdaClient, updateCodeRequest.FunctionName);
await this.LambdaClient.UpdateFunctionCodeAsync(updateCodeRequest);
}
catch (Exception e)
{
if (configUpdated)
{
await base.AttemptRevertConfigAsync(currentConfiguration);
}
throw new LambdaToolsException($"Error updating code for Lambda function: {e.Message}", LambdaToolsException.LambdaErrorCode.LambdaUpdateFunctionCode, e);
}
await base.ApplyTags(currentConfiguration.FunctionArn);
var publish = this.GetBoolValueOrDefault(this.Publish, LambdaDefinedCommandOptions.ARGUMENT_FUNCTION_PUBLISH, false).GetValueOrDefault();
if(publish)
{
await base.PublishFunctionAsync(updateCodeRequest.FunctionName);
}
}
}
finally
{
lambdaZipArchiveStream?.Dispose();
}
return true;
}
private Lambda.PackageType DeterminePackageType()
{
var strPackageType = this.GetStringValueOrDefault(this.PackageType, LambdaDefinedCommandOptions.ARGUMENT_PACKAGE_TYPE, false);
return LambdaUtilities.DeterminePackageType(strPackageType);
}
private async Task PushLambdaImageAsync()
{
var pushCommand = new PushDockerImageCommand(this.Logger, this.WorkingDirectory, this.OriginalCommandLineArguments)
{
ConfigFile = this.ConfigFile,
DisableInteractive = this.DisableInteractive,
Credentials = this.Credentials,
ECRClient = this.ECRClient,
Profile = this.Profile,
ProfileLocation = this.ProfileLocation,
ProjectLocation = this.ProjectLocation,
Region = this.Region,
WorkingDirectory = this.WorkingDirectory,
PushDockerImageProperties = new BasePushDockerImageCommand.PushDockerImagePropertyContainer
{
Configuration = this.GetStringValueOrDefault(this.Configuration, CommonDefinedCommandOptions.ARGUMENT_CONFIGURATION, false),
TargetFramework = this.GetStringValueOrDefault(this.TargetFramework, CommonDefinedCommandOptions.ARGUMENT_FRAMEWORK, false),
LocalDockerImage = this.GetStringValueOrDefault(this.LocalDockerImage, CommonDefinedCommandOptions.ARGUMENT_LOCAL_DOCKER_IMAGE, false),
DockerFile = this.GetStringValueOrDefault(this.DockerFile, CommonDefinedCommandOptions.ARGUMENT_DOCKERFILE, false),
DockerBuildOptions = this.GetStringValueOrDefault(this.DockerBuildOptions, CommonDefinedCommandOptions.ARGUMENT_DOCKER_BUILD_OPTIONS, false),
DockerBuildWorkingDirectory = this.GetStringValueOrDefault(this.DockerBuildWorkingDirectory, CommonDefinedCommandOptions.ARGUMENT_DOCKER_BUILD_WORKING_DIRECTORY, false),
DockerImageTag = this.GetStringValueOrDefault(this.DockerImageTag, LambdaDefinedCommandOptions.ARGUMENT_IMAGE_TAG, false),
PublishOptions = this.GetStringValueOrDefault(this.MSBuildParameters, CommonDefinedCommandOptions.ARGUMENT_MSBUILD_PARAMETERS, false),
HostBuildOutput = this.GetStringValueOrDefault(this.HostBuildOutput, CommonDefinedCommandOptions.ARGUMENT_HOST_BUILD_OUTPUT, false)
}
};
var result = new PushLambdaImageResult();
result.Success = await pushCommand.ExecuteAsync();
result.ImageUri = pushCommand.PushedImageUri;
result.LastException = pushCommand.LastException;
return result;
}
private void ValidateTargetFrameworkAndLambdaRuntime(string targetFramework)
{
string runtimeName = this.GetStringValueOrDefault(this.Runtime, LambdaDefinedCommandOptions.ARGUMENT_FUNCTION_RUNTIME, true);
LambdaUtilities.ValidateTargetFrameworkAndLambdaRuntime(runtimeName, targetFramework);
}
protected override void SaveConfigFile(JsonData data)
{
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));
data.SetIfNotNull(CommonDefinedCommandOptions.ARGUMENT_CONFIGURATION.ConfigFileKey, this.GetStringValueOrDefault(this.Configuration, CommonDefinedCommandOptions.ARGUMENT_CONFIGURATION, false));
data.SetIfNotNull(CommonDefinedCommandOptions.ARGUMENT_FRAMEWORK.ConfigFileKey, this.GetStringValueOrDefault(this.TargetFramework, CommonDefinedCommandOptions.ARGUMENT_FRAMEWORK, false));
data.SetIfNotNull(CommonDefinedCommandOptions.ARGUMENT_MSBUILD_PARAMETERS.ConfigFileKey, this.GetStringValueOrDefault(this.MSBuildParameters, CommonDefinedCommandOptions.ARGUMENT_MSBUILD_PARAMETERS, false));
data.SetIfNotNull(LambdaDefinedCommandOptions.ARGUMENT_FUNCTION_NAME.ConfigFileKey, this.GetStringValueOrDefault(this.FunctionName, LambdaDefinedCommandOptions.ARGUMENT_FUNCTION_NAME, false));
data.SetIfNotNull(LambdaDefinedCommandOptions.ARGUMENT_FUNCTION_DESCRIPTION.ConfigFileKey, this.GetStringValueOrDefault(this.Description, LambdaDefinedCommandOptions.ARGUMENT_FUNCTION_DESCRIPTION, false));
data.SetIfNotNull(LambdaDefinedCommandOptions.ARGUMENT_FUNCTION_TAGS.ConfigFileKey, LambdaToolsDefaults.FormatKeyValue(this.GetKeyValuePairOrDefault(this.Tags, LambdaDefinedCommandOptions.ARGUMENT_FUNCTION_TAGS, false)));
data.SetIfNotNull(LambdaDefinedCommandOptions.ARGUMENT_PACKAGE_TYPE.ConfigFileKey, this.GetStringValueOrDefault(this.PackageType, LambdaDefinedCommandOptions.ARGUMENT_PACKAGE_TYPE, false));
data.SetIfNotNull(LambdaDefinedCommandOptions.ARGUMENT_FUNCTION_PUBLISH.ConfigFileKey, this.GetBoolValueOrDefault(this.Publish, LambdaDefinedCommandOptions.ARGUMENT_FUNCTION_PUBLISH, false));
data.SetIfNotNull(LambdaDefinedCommandOptions.ARGUMENT_FUNCTION_HANDLER.ConfigFileKey, this.GetStringValueOrDefault(this.Handler, LambdaDefinedCommandOptions.ARGUMENT_FUNCTION_HANDLER, false));
data.SetIfNotNull(LambdaDefinedCommandOptions.ARGUMENT_FUNCTION_MEMORY_SIZE.ConfigFileKey, this.GetIntValueOrDefault(this.MemorySize, LambdaDefinedCommandOptions.ARGUMENT_FUNCTION_MEMORY_SIZE, false));
data.SetIfNotNull(LambdaDefinedCommandOptions.ARGUMENT_FUNCTION_ROLE.ConfigFileKey, this.GetStringValueOrDefault(this.Role, LambdaDefinedCommandOptions.ARGUMENT_FUNCTION_ROLE, false));
data.SetIfNotNull(LambdaDefinedCommandOptions.ARGUMENT_FUNCTION_TIMEOUT.ConfigFileKey, this.GetIntValueOrDefault(this.Timeout, LambdaDefinedCommandOptions.ARGUMENT_FUNCTION_TIMEOUT, false));
data.SetIfNotNull(LambdaDefinedCommandOptions.ARGUMENT_FUNCTION_RUNTIME.ConfigFileKey, this.GetStringValueOrDefault(this.Runtime, LambdaDefinedCommandOptions.ARGUMENT_FUNCTION_RUNTIME, false));
data.SetIfNotNull(LambdaDefinedCommandOptions.ARGUMENT_FUNCTION_ARCHITECTURE.ConfigFileKey, this.GetStringValueOrDefault(this.Architecture, LambdaDefinedCommandOptions.ARGUMENT_FUNCTION_ARCHITECTURE, false));
data.SetIfNotNull(LambdaDefinedCommandOptions.ARGUMENT_FUNCTION_LAYERS.ConfigFileKey, LambdaToolsDefaults.FormatCommaDelimitedList(this.GetStringValuesOrDefault(this.LayerVersionArns, LambdaDefinedCommandOptions.ARGUMENT_FUNCTION_LAYERS, false)));
data.SetIfNotNull(LambdaDefinedCommandOptions.ARGUMENT_EPHEMERAL_STORAGE_SIZE.ConfigFileKey, this.GetIntValueOrDefault(this.EphemeralStorageSize, LambdaDefinedCommandOptions.ARGUMENT_EPHEMERAL_STORAGE_SIZE, false));
data.SetIfNotNull(LambdaDefinedCommandOptions.ARGUMENT_FUNCTION_URL_ENABLE.ConfigFileKey, this.GetBoolValueOrDefault(this.FunctionUrlEnable, LambdaDefinedCommandOptions.ARGUMENT_FUNCTION_URL_ENABLE, false));
data.SetIfNotNull(LambdaDefinedCommandOptions.ARGUMENT_FUNCTION_URL_AUTH.ConfigFileKey, this.GetStringValueOrDefault(this.FunctionUrlAuthType, LambdaDefinedCommandOptions.ARGUMENT_FUNCTION_URL_AUTH, false));
data.SetIfNotNull(LambdaDefinedCommandOptions.ARGUMENT_IMAGE_ENTRYPOINT.ConfigFileKey, LambdaToolsDefaults.FormatCommaDelimitedList(this.GetStringValuesOrDefault(this.ImageEntryPoint, LambdaDefinedCommandOptions.ARGUMENT_IMAGE_ENTRYPOINT, false)));
data.SetIfNotNull(LambdaDefinedCommandOptions.ARGUMENT_IMAGE_COMMAND.ConfigFileKey, LambdaToolsDefaults.FormatCommaDelimitedList(this.GetStringValuesOrDefault(this.ImageCommand, LambdaDefinedCommandOptions.ARGUMENT_IMAGE_COMMAND, false)));
data.SetIfNotNull(LambdaDefinedCommandOptions.ARGUMENT_IMAGE_WORKING_DIRECTORY.ConfigFileKey, this.GetStringValueOrDefault(this.ImageWorkingDirectory, LambdaDefinedCommandOptions.ARGUMENT_IMAGE_WORKING_DIRECTORY, false));
data.SetIfNotNull(LambdaDefinedCommandOptions.ARGUMENT_FUNCTION_SUBNETS.ConfigFileKey, LambdaToolsDefaults.FormatCommaDelimitedList(this.GetStringValuesOrDefault(this.SubnetIds, LambdaDefinedCommandOptions.ARGUMENT_FUNCTION_SUBNETS, false)));
data.SetIfNotNull(LambdaDefinedCommandOptions.ARGUMENT_FUNCTION_SECURITY_GROUPS.ConfigFileKey, LambdaToolsDefaults.FormatCommaDelimitedList(this.GetStringValuesOrDefault(this.SecurityGroupIds, LambdaDefinedCommandOptions.ARGUMENT_FUNCTION_SECURITY_GROUPS, false)));
data.SetIfNotNull(LambdaDefinedCommandOptions.ARGUMENT_DEADLETTER_TARGET_ARN.ConfigFileKey, this.GetStringValueOrDefault(this.DeadLetterTargetArn, LambdaDefinedCommandOptions.ARGUMENT_DEADLETTER_TARGET_ARN, false));
data.SetIfNotNull(LambdaDefinedCommandOptions.ARGUMENT_TRACING_MODE.ConfigFileKey, this.GetStringValueOrDefault(this.TracingMode, LambdaDefinedCommandOptions.ARGUMENT_TRACING_MODE, false));
data.SetIfNotNull(LambdaDefinedCommandOptions.ARGUMENT_ENVIRONMENT_VARIABLES.ConfigFileKey, LambdaToolsDefaults.FormatKeyValue(this.GetKeyValuePairOrDefault(this.EnvironmentVariables, LambdaDefinedCommandOptions.ARGUMENT_ENVIRONMENT_VARIABLES, false)));
data.SetIfNotNull(LambdaDefinedCommandOptions.ARGUMENT_APPEND_ENVIRONMENT_VARIABLES.ConfigFileKey, LambdaToolsDefaults.FormatKeyValue(this.GetKeyValuePairOrDefault(this.AppendEnvironmentVariables, LambdaDefinedCommandOptions.ARGUMENT_APPEND_ENVIRONMENT_VARIABLES, false)));
data.SetIfNotNull(LambdaDefinedCommandOptions.ARGUMENT_KMS_KEY_ARN.ConfigFileKey, this.GetStringValueOrDefault(this.KMSKeyArn, LambdaDefinedCommandOptions.ARGUMENT_KMS_KEY_ARN, false));
data.SetIfNotNull(LambdaDefinedCommandOptions.ARGUMENT_RESOLVE_S3.ConfigFileKey, this.GetBoolValueOrDefault(this.ResolveS3, LambdaDefinedCommandOptions.ARGUMENT_RESOLVE_S3, false));
data.SetIfNotNull(LambdaDefinedCommandOptions.ARGUMENT_S3_BUCKET.ConfigFileKey, this.GetStringValueOrDefault(this.S3Bucket, LambdaDefinedCommandOptions.ARGUMENT_S3_BUCKET, false));
data.SetIfNotNull(LambdaDefinedCommandOptions.ARGUMENT_S3_PREFIX.ConfigFileKey, this.GetStringValueOrDefault(this.S3Prefix, LambdaDefinedCommandOptions.ARGUMENT_S3_PREFIX, false));
var projectLocation = Utilities.DetermineProjectLocation(this.WorkingDirectory, this.GetStringValueOrDefault(this.ProjectLocation, CommonDefinedCommandOptions.ARGUMENT_PROJECT_LOCATION, false));
data.SetFilePathIfNotNull(CommonDefinedCommandOptions.ARGUMENT_DOCKERFILE.ConfigFileKey, this.GetStringValueOrDefault(this.DockerFile, CommonDefinedCommandOptions.ARGUMENT_DOCKERFILE, false), projectLocation);
data.SetIfNotNull(CommonDefinedCommandOptions.ARGUMENT_DOCKER_BUILD_OPTIONS.ConfigFileKey, this.GetStringValueOrDefault(this.DockerBuildOptions, CommonDefinedCommandOptions.ARGUMENT_DOCKER_BUILD_OPTIONS, false));
data.SetIfNotNull(CommonDefinedCommandOptions.ARGUMENT_DOCKER_BUILD_WORKING_DIRECTORY.ConfigFileKey, this.GetStringValueOrDefault(this.DockerBuildWorkingDirectory, CommonDefinedCommandOptions.ARGUMENT_DOCKER_BUILD_WORKING_DIRECTORY, false));
data.SetIfNotNull(CommonDefinedCommandOptions.ARGUMENT_HOST_BUILD_OUTPUT.ConfigFileKey, this.GetStringValueOrDefault(this.HostBuildOutput, CommonDefinedCommandOptions.ARGUMENT_HOST_BUILD_OUTPUT, false));
data.SetIfNotNull(LambdaDefinedCommandOptions.ARGUMENT_IMAGE_TAG.ConfigFileKey, this.GetStringValueOrDefault(this.DockerImageTag, LambdaDefinedCommandOptions.ARGUMENT_IMAGE_TAG, false));
data.SetIfNotNull(LambdaDefinedCommandOptions.ARGUMENT_USE_CONTAINER_FOR_BUILD.ConfigFileKey, this.GetBoolValueOrDefault(this.UseContainerForBuild, LambdaDefinedCommandOptions.ARGUMENT_USE_CONTAINER_FOR_BUILD, false));
data.SetIfNotNull(LambdaDefinedCommandOptions.ARGUMENT_CONTAINER_IMAGE_FOR_BUILD.ConfigFileKey, this.GetStringValueOrDefault(this.ContainerImageForBuild, LambdaDefinedCommandOptions.ARGUMENT_CONTAINER_IMAGE_FOR_BUILD, false));
data.SetIfNotNull(LambdaDefinedCommandOptions.ARGUMENT_CODE_MOUNT_DIRECTORY.ConfigFileKey, this.GetStringValueOrDefault(this.CodeMountDirectory, LambdaDefinedCommandOptions.ARGUMENT_CODE_MOUNT_DIRECTORY, false));
}
}
}