protected override Task <bool> PerformActionAsync() { EnsureInProjectDirectory(); // Disable interactive since this command is intended to be run as part of a pipeline. this.DisableInteractive = true; return(Task.Run(() => { // Release will be the default configuration if nothing set. var configuration = this.GetStringValueOrDefault(this.Configuration, CommonDefinedCommandOptions.ARGUMENT_CONFIGURATION, false); var targetFramework = this.GetStringValueOrDefault(this.TargetFramework, CommonDefinedCommandOptions.ARGUMENT_FRAMEWORK, true); var projectLocation = this.GetStringValueOrDefault(this.ProjectLocation, CommonDefinedCommandOptions.ARGUMENT_PROJECT_LOCATION, false); var msbuildParameters = this.GetStringValueOrDefault(this.MSBuildParameters, CommonDefinedCommandOptions.ARGUMENT_MSBUILD_PARAMETERS, false); var disableVersionCheck = this.GetBoolValueOrDefault(this.DisableVersionCheck, LambdaDefinedCommandOptions.ARGUMENT_DISABLE_VERSION_CHECK, false).GetValueOrDefault(); var zipArchivePath = GetStringValueOrDefault(this.OutputPackageFileName, LambdaDefinedCommandOptions.ARGUMENT_OUTPUT_PACKAGE, false); string publishLocation; var success = LambdaPackager.CreateApplicationBundle(this.DefaultConfig, this.Logger, this.WorkingDirectory, projectLocation, configuration, targetFramework, msbuildParameters, disableVersionCheck, out publishLocation, ref zipArchivePath); if (!success) { this.Logger.WriteLine("Failed to create application package"); return false; } this.Logger.WriteLine("Lambda project successfully packaged: " + zipArchivePath); return true; })); }
protected override async Task <bool> PerformActionAsync() { EnsureInProjectDirectory(); // Disable interactive since this command is intended to be run as part of a pipeline. DisableInteractive = true; string projectLocation = this.GetStringValueOrDefault(this.ProjectLocation, CommonDefinedCommandOptions.ARGUMENT_PROJECT_LOCATION, false); string s3Bucket = this.GetStringValueOrDefault(this.S3Bucket, LambdaDefinedCommandOptions.ARGUMENT_S3_BUCKET, true); string s3Prefix = this.GetStringValueOrDefault(this.S3Prefix, LambdaDefinedCommandOptions.ARGUMENT_S3_PREFIX, false); string templatePath = this.GetStringValueOrDefault(this.CloudFormationTemplate, LambdaDefinedCommandOptions.ARGUMENT_CLOUDFORMATION_TEMPLATE, true); string outputTemplatePath = this.GetStringValueOrDefault(this.CloudFormationOutputTemplate, LambdaDefinedCommandOptions.ARGUMENT_OUTPUT_CLOUDFORMATION_TEMPLATE, true); if (!Path.IsPathRooted(templatePath)) { templatePath = Path.Combine(Utilities.DetermineProjectLocation(this.WorkingDirectory, projectLocation), templatePath); } if (!File.Exists(templatePath)) { throw new LambdaToolsException($"Template file {templatePath} cannot be found.", LambdaToolsException.LambdaErrorCode.ServerlessTemplateNotFound); } await Utilities.ValidateBucketRegionAsync(this.S3Client, s3Bucket); string zipArchivePath = null; var configuration = this.GetStringValueOrDefault(this.Configuration, CommonDefinedCommandOptions.ARGUMENT_CONFIGURATION, true); var targetFramework = this.GetStringValueOrDefault(this.TargetFramework, CommonDefinedCommandOptions.ARGUMENT_FRAMEWORK, true); var msbuildParameters = this.GetStringValueOrDefault(this.MSBuildParameters, CommonDefinedCommandOptions.ARGUMENT_MSBUILD_PARAMETERS, false); var disableVersionCheck = this.GetBoolValueOrDefault(this.DisableVersionCheck, LambdaDefinedCommandOptions.ARGUMENT_DISABLE_VERSION_CHECK, false).GetValueOrDefault(); string publishLocation; LambdaPackager.CreateApplicationBundle(this.DefaultConfig, this.Logger, this.WorkingDirectory, projectLocation, configuration, targetFramework, msbuildParameters, disableVersionCheck, out publishLocation, ref zipArchivePath); if (string.IsNullOrEmpty(zipArchivePath)) { return(false); } string s3KeyApplicationBundle; using (var stream = new MemoryStream(File.ReadAllBytes(zipArchivePath))) { s3KeyApplicationBundle = await Utilities.UploadToS3Async(this.Logger, this.S3Client, s3Bucket, s3Prefix, Path.GetFileName(zipArchivePath), stream); } this.Logger.WriteLine($"Updating CloudFormation template to point to application bundle: s3://{s3Bucket}/{s3KeyApplicationBundle}"); var templateBody = File.ReadAllText(templatePath); // Process any template substitutions templateBody = LambdaUtilities.ProcessTemplateSubstitions(this.Logger, templateBody, this.GetKeyValuePairOrDefault(this.TemplateSubstitutions, LambdaDefinedCommandOptions.ARGUMENT_CLOUDFORMATION_TEMPLATE_SUBSTITUTIONS, false), Utilities.DetermineProjectLocation(this.WorkingDirectory, projectLocation)); var transformedBody = LambdaUtilities.UpdateCodeLocationInTemplate(templateBody, s3Bucket, s3KeyApplicationBundle); this.Logger.WriteLine($"Writing updated template: {outputTemplatePath}"); File.WriteAllText(outputTemplatePath, transformedBody); return(true); }
public override Task <bool> ExecuteAsync() { // Disable interactive since this command is intended to be run as part of a pipeline. this.DisableInteractive = true; return(Task.Run(() => { try { string configuration = this.GetStringValueOrDefault(this.Configuration, DefinedCommandOptions.ARGUMENT_CONFIGURATION, true); string targetFramework = this.GetStringValueOrDefault(this.TargetFramework, DefinedCommandOptions.ARGUMENT_FRAMEWORK, true); string projectLocation = this.GetStringValueOrDefault(this.ProjectLocation, DefinedCommandOptions.ARGUMENT_PROJECT_LOCATION, false); string msbuildParameters = this.GetStringValueOrDefault(this.MSBuildParameters, DefinedCommandOptions.ARGUMENT_MSBUILD_PARAMETERS, false); bool disableVersionCheck = this.GetBoolValueOrDefault(this.DisableVersionCheck, DefinedCommandOptions.ARGUMENT_DISABLE_VERSION_CHECK, false).GetValueOrDefault(); var zipArchivePath = GetStringValueOrDefault(this.OutputPackageFileName, DefinedCommandOptions.ARGUMENT_OUTPUT_PACKAGE, false); string publishLocation; bool success = LambdaPackager.CreateApplicationBundle(this.DefaultConfig, this.Logger, this.WorkingDirectory, projectLocation, configuration, targetFramework, msbuildParameters, disableVersionCheck, out publishLocation, ref zipArchivePath); if (!success) { this.Logger.WriteLine("Failed to create application package"); return false; } this.Logger.WriteLine("Lambda project successfully packaged: " + zipArchivePath); return true; } catch (LambdaToolsException e) { this.Logger.WriteLine(e.Message); this.LastToolsException = e; return false; } catch (Exception e) { this.Logger.WriteLine($"Unknown error executing Lambda packaging: {e.Message}"); this.Logger.WriteLine(e.StackTrace); return false; } })); }
public override Task <bool> ExecuteAsync() { return(Task.Run(() => { try { string configuration = this.GetStringValueOrDefault(this.Configuration, DefinedCommandOptions.ARGUMENT_CONFIGURATION, true); string targetFramework = this.GetStringValueOrDefault(this.TargetFramework, DefinedCommandOptions.ARGUMENT_FRAMEWORK, true); string projectLocation = this.GetStringValueOrDefault(this.ProjectLocation, DefinedCommandOptions.ARGUMENT_PROJECT_LOCATION, false); var zipArchivePath = GetStringValueOrDefault(this.OutputPackageFileName, DefinedCommandOptions.ARGUMENT_OUTPUT_PACKAGE, false); string publishLocation; bool success = LambdaPackager.CreateApplicationBundle(this.DefaultConfig, this.Logger, this.WorkingDirectory, projectLocation, configuration, targetFramework, out publishLocation, ref zipArchivePath); if (!success) { this.Logger.WriteLine("Failed to create application package"); return false; } this.Logger.WriteLine("Lambda project successfully packaged: " + zipArchivePath); return true; } catch (LambdaToolsException e) { this.Logger.WriteLine(e.Message); this.LastToolsException = e; return false; } catch (Exception e) { this.Logger.WriteLine($"Unknown error executing Lambda packaging: {e.Message}"); this.Logger.WriteLine(e.StackTrace); return false; } })); }
public override async Task <bool> ExecuteAsync() { try { string projectLocation = this.GetStringValueOrDefault(this.ProjectLocation, DefinedCommandOptions.ARGUMENT_PROJECT_LOCATION, false); string zipArchivePath = null; string publishLocation = null; string package = this.GetStringValueOrDefault(this.Package, DefinedCommandOptions.ARGUMENT_PACKAGE, false); if (string.IsNullOrEmpty(package)) { string configuration = this.GetStringValueOrDefault(this.Configuration, DefinedCommandOptions.ARGUMENT_CONFIGURATION, true); string targetFramework = this.GetStringValueOrDefault(this.TargetFramework, DefinedCommandOptions.ARGUMENT_FRAMEWORK, true); ValidateTargetFrameworkAndLambdaRuntime(); LambdaPackager.CreateApplicationBundle(this.DefaultConfig, this.Logger, this.WorkingDirectory, projectLocation, configuration, targetFramework, out publishLocation, ref zipArchivePath); if (string.IsNullOrEmpty(zipArchivePath)) { return(false); } } else { if (!File.Exists(package)) { throw new LambdaToolsException($"Package {package} does not exist", LambdaToolsException.ErrorCode.InvalidPackage); } if (!string.Equals(Path.GetExtension(package), ".zip", StringComparison.OrdinalIgnoreCase)) { throw new LambdaToolsException($"Package {package} must be a zip file", LambdaToolsException.ErrorCode.InvalidPackage); } this.Logger.WriteLine($"Skipping compilation and using precompiled package {package}"); zipArchivePath = package; } using (var stream = new MemoryStream(File.ReadAllBytes(zipArchivePath))) { var s3Bucket = this.GetStringValueOrDefault(this.S3Bucket, DefinedCommandOptions.ARGUMENT_S3_BUCKET, false); string s3Key = null; if (!string.IsNullOrEmpty(s3Bucket)) { await Utilities.ValidateBucketRegionAsync(this.S3Client, s3Bucket); var functionName = this.GetStringValueOrDefault(this.FunctionName, DefinedCommandOptions.ARGUMENT_FUNCTION_NAME, true); var s3Prefix = this.GetStringValueOrDefault(this.S3Prefix, DefinedCommandOptions.ARGUMENT_S3_PREFIX, false); s3Key = await Utilities.UploadToS3Async(this.Logger, this.S3Client, s3Bucket, s3Prefix, functionName, stream); } var currentConfiguration = await GetFunctionConfigurationAsync(); if (currentConfiguration == null) { this.Logger.WriteLine($"Creating new Lambda function {this.FunctionName}"); var createRequest = new CreateFunctionRequest { FunctionName = this.GetStringValueOrDefault(this.FunctionName, DefinedCommandOptions.ARGUMENT_FUNCTION_NAME, true), Description = this.GetStringValueOrDefault(this.Description, DefinedCommandOptions.ARGUMENT_FUNCTION_DESCRIPTION, false), Role = this.GetStringValueOrDefault(this.Role, DefinedCommandOptions.ARGUMENT_FUNCTION_ROLE, true), Handler = this.GetStringValueOrDefault(this.Handler, DefinedCommandOptions.ARGUMENT_FUNCTION_HANDLER, true), Publish = this.GetBoolValueOrDefault(this.Publish, DefinedCommandOptions.ARGUMENT_FUNCTION_PUBLISH, false).GetValueOrDefault(), MemorySize = this.GetIntValueOrDefault(this.MemorySize, DefinedCommandOptions.ARGUMENT_FUNCTION_MEMORY_SIZE, true).GetValueOrDefault(), Runtime = this.GetStringValueOrDefault(this.Runtime, DefinedCommandOptions.ARGUMENT_FUNCTION_RUNTIME, true), Timeout = this.GetIntValueOrDefault(this.Timeout, DefinedCommandOptions.ARGUMENT_FUNCTION_TIMEOUT, true).GetValueOrDefault(), KMSKeyArn = this.GetStringValueOrDefault(this.KMSKeyArn, DefinedCommandOptions.ARGUMENT_KMS_KEY_ARN, false), VpcConfig = new VpcConfig { SubnetIds = this.GetStringValuesOrDefault(this.SubnetIds, DefinedCommandOptions.ARGUMENT_FUNCTION_SUBNETS, false)?.ToList(), SecurityGroupIds = this.GetStringValuesOrDefault(this.SecurityGroupIds, DefinedCommandOptions.ARGUMENT_FUNCTION_SECURITY_GROUPS, false)?.ToList() } }; var environmentVariables = this.GetKeyValuePairOrDefault(this.EnvironmentVariables, DefinedCommandOptions.ARGUMENT_ENVIRONMENT_VARIABLES, false); if (environmentVariables != null && environmentVariables.Count > 0) { createRequest.Environment = new Model.Environment { Variables = environmentVariables }; } var deadLetterQueue = this.GetStringValueOrDefault(this.DeadLetterTargetArn, DefinedCommandOptions.ARGUMENT_DEADLETTER_TARGET_ARN, false); if (!string.IsNullOrEmpty(deadLetterQueue)) { createRequest.DeadLetterConfig = new DeadLetterConfig { TargetArn = deadLetterQueue }; } if (s3Bucket != null) { createRequest.Code = new FunctionCode { S3Bucket = s3Bucket, S3Key = s3Key }; } else { createRequest.Code = new FunctionCode { ZipFile = stream }; } if (!this.SkipHandlerValidation && !string.IsNullOrEmpty(publishLocation)) { createRequest.Handler = EnsureFunctionHandlerIsValid(publishLocation, createRequest.Handler); } 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.ErrorCode.LambdaCreateFunction, e); } } else { if (!this.SkipHandlerValidation && !string.IsNullOrEmpty(publishLocation)) { if (!string.IsNullOrEmpty(this.Handler)) { this.Handler = EnsureFunctionHandlerIsValid(publishLocation, this.Handler); } else { this.Handler = EnsureFunctionHandlerIsValid(publishLocation, currentConfiguration.Handler); } } this.Logger.WriteLine($"Updating code for existing function {this.FunctionName}"); var updateCodeRequest = new UpdateFunctionCodeRequest { FunctionName = this.GetStringValueOrDefault(this.FunctionName, DefinedCommandOptions.ARGUMENT_FUNCTION_NAME, true) }; if (s3Bucket != null) { updateCodeRequest.S3Bucket = s3Bucket; updateCodeRequest.S3Key = s3Key; } else { updateCodeRequest.ZipFile = stream; } try { await this.LambdaClient.UpdateFunctionCodeAsync(updateCodeRequest); } catch (Exception e) { throw new LambdaToolsException($"Error updating code for Lambda function: {e.Message}", LambdaToolsException.ErrorCode.LambdaUpdateFunctionCode, e); } await base.UpdateConfigAsync(currentConfiguration); } } if (this.GetBoolValueOrDefault(this.PersistConfigFile, DefinedCommandOptions.ARGUMENT_PERSIST_CONFIG_FILE, false).GetValueOrDefault()) { this.SaveConfigFile(); } return(true); } catch (LambdaToolsException e) { this.Logger.WriteLine(e.Message); this.LastToolsException = e; return(false); } catch (Exception e) { this.Logger.WriteLine($"Unknown error executing Lambda deployment: {e.Message}"); this.Logger.WriteLine(e.StackTrace); return(false); } }
protected override async Task <bool> PerformActionAsync() { string projectLocation = 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); Lambda.PackageType packageType = DeterminePackageType(); string ecrImageUri = null; if (packageType == Lambda.PackageType.Image) { var pushResults = await PushLambdaImageAsync(); if (!pushResults.Success) { if (pushResults.LastToolsException != null) { throw pushResults.LastToolsException; } return(false); } 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(Utilities.DetermineProjectLocation(this.WorkingDirectory, 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); ValidateTargetFrameworkAndLambdaRuntime(targetFramework); bool disableVersionCheck = this.GetBoolValueOrDefault(this.DisableVersionCheck, LambdaDefinedCommandOptions.ARGUMENT_DISABLE_VERSION_CHECK, false).GetValueOrDefault(); string publishLocation; LambdaPackager.CreateApplicationBundle(this.DefaultConfig, this.Logger, this.WorkingDirectory, projectLocation, configuration, targetFramework, msbuildParameters, disableVersionCheck, layerPackageInfo, out publishLocation, ref zipArchivePath); if (string.IsNullOrEmpty(zipArchivePath)) { return(false); } } 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); string s3Key = null; if (zipArchivePath != null && !string.IsNullOrEmpty(s3Bucket)) { 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() } }; 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 <string, string>(); } 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); } } 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) }; // 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; } try { await this.LambdaClient.UpdateFunctionCodeAsync(updateCodeRequest); } catch (Exception e) { throw new LambdaToolsException($"Error updating code for Lambda function: {e.Message}", LambdaToolsException.LambdaErrorCode.LambdaUpdateFunctionCode, e); } await base.UpdateConfigAsync(currentConfiguration, layerPackageInfo.GenerateDotnetSharedStoreValue()); 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); }
public override async Task <bool> ExecuteAsync() { try { string projectLocation = this.GetStringValueOrDefault(this.ProjectLocation, DefinedCommandOptions.ARGUMENT_PROJECT_LOCATION, false); string stackName = this.GetStringValueOrDefault(this.StackName, DefinedCommandOptions.ARGUMENT_STACK_NAME, true); string s3Bucket = this.GetStringValueOrDefault(this.S3Bucket, DefinedCommandOptions.ARGUMENT_S3_BUCKET, true); string s3Prefix = this.GetStringValueOrDefault(this.S3Prefix, DefinedCommandOptions.ARGUMENT_S3_PREFIX, false); string templatePath = this.GetStringValueOrDefault(this.CloudFormationTemplate, DefinedCommandOptions.ARGUMENT_CLOUDFORMATION_TEMPLATE, true); await Utilities.ValidateBucketRegionAsync(this.S3Client, s3Bucket); if (!Path.IsPathRooted(templatePath)) { templatePath = Path.Combine(Utilities.DetermineProjectLocation(this.WorkingDirectory, projectLocation), templatePath); } if (!File.Exists(templatePath)) { throw new LambdaToolsException($"Template file {templatePath} cannot be found.", LambdaToolsException.ErrorCode.ServerlessTemplateNotFound); } // Build and bundle up the users project. string publishLocation; string zipArchivePath = null; string package = this.GetStringValueOrDefault(this.Package, DefinedCommandOptions.ARGUMENT_PACKAGE, false); if (string.IsNullOrEmpty(package)) { string configuration = this.GetStringValueOrDefault(this.Configuration, DefinedCommandOptions.ARGUMENT_CONFIGURATION, true); string targetFramework = this.GetStringValueOrDefault(this.TargetFramework, DefinedCommandOptions.ARGUMENT_FRAMEWORK, true); LambdaPackager.CreateApplicationBundle(this.DefaultConfig, this.Logger, this.WorkingDirectory, projectLocation, configuration, targetFramework, out publishLocation, ref zipArchivePath); if (string.IsNullOrEmpty(zipArchivePath)) { return(false); } } else { if (!File.Exists(package)) { throw new LambdaToolsException($"Package {package} does not exist", LambdaToolsException.ErrorCode.InvalidPackage); } if (!string.Equals(Path.GetExtension(package), ".zip", StringComparison.OrdinalIgnoreCase)) { throw new LambdaToolsException($"Package {package} must be a zip file", LambdaToolsException.ErrorCode.InvalidPackage); } this.Logger.WriteLine($"Skipping compilation and using precompiled package {package}"); zipArchivePath = package; } // Upload the app bundle to S3 string s3KeyApplicationBundle; using (var stream = new MemoryStream(File.ReadAllBytes(zipArchivePath))) { s3KeyApplicationBundle = await Utilities.UploadToS3Async(this.Logger, this.S3Client, s3Bucket, s3Prefix, stackName, stream); } // Read in the serverless template and update all the locations for Lambda functions to point to the app bundle that was just uploaded. string templateBody = File.ReadAllText(templatePath); // Process any template substitutions templateBody = Utilities.ProcessTemplateSubstitions(this.Logger, templateBody, this.GetKeyValuePairOrDefault(this.TemplateSubstitutions, DefinedCommandOptions.ARGUMENT_CLOUDFORMATION_TEMPLATE_SUBSTITUTIONS, false), Utilities.DetermineProjectLocation(this.WorkingDirectory, projectLocation)); templateBody = UpdateCodeLocationInTemplate(templateBody, s3Bucket, s3KeyApplicationBundle); // Upload the template to S3 instead of sending it straight to CloudFormation to avoid the size limitation string s3KeyTemplate; using (var stream = new MemoryStream(System.Text.Encoding.UTF8.GetBytes(templateBody))) { s3KeyTemplate = await Utilities.UploadToS3Async(this.Logger, this.S3Client, s3Bucket, s3Prefix, stackName + "-" + Path.GetFileName(templatePath), stream); } var existingStack = await GetExistingStackAsync(stackName); this.Logger.WriteLine("Found existing stack: " + (existingStack != null)); var changeSetName = "Lambda-Tools-" + DateTime.Now.Ticks; // Determine if the stack is in a good state to be updated. ChangeSetType changeSetType; if (existingStack == null || existingStack.StackStatus == StackStatus.REVIEW_IN_PROGRESS || existingStack.StackStatus == StackStatus.DELETE_COMPLETE) { changeSetType = ChangeSetType.CREATE; } // If the status was ROLLBACK_COMPLETE that means the stack failed on initial creation // and the resources were cleaned up. It is safe to delete the stack so we can recreate it. else if (existingStack.StackStatus == StackStatus.ROLLBACK_COMPLETE) { await DeleteRollbackCompleteStackAsync(existingStack); changeSetType = ChangeSetType.CREATE; } // If the status was ROLLBACK_IN_PROGRESS that means the initial creation is failing. // Wait to see if it goes into ROLLBACK_COMPLETE status meaning everything got cleaned up and then delete it. else if (existingStack.StackStatus == StackStatus.ROLLBACK_IN_PROGRESS) { existingStack = await WaitForNoLongerInProgress(existingStack.StackName); if (existingStack != null && existingStack.StackStatus == StackStatus.ROLLBACK_COMPLETE) { await DeleteRollbackCompleteStackAsync(existingStack); } changeSetType = ChangeSetType.CREATE; } // If the status was DELETE_IN_PROGRESS then just wait for delete to complete else if (existingStack.StackStatus == StackStatus.DELETE_IN_PROGRESS) { await WaitForNoLongerInProgress(existingStack.StackName); changeSetType = ChangeSetType.CREATE; } // The Stack state is in a normal state and ready to be updated. else if (existingStack.StackStatus == StackStatus.CREATE_COMPLETE || existingStack.StackStatus == StackStatus.UPDATE_COMPLETE || existingStack.StackStatus == StackStatus.UPDATE_ROLLBACK_COMPLETE) { changeSetType = ChangeSetType.UPDATE; } // All other states means the Stack is in an inconsistent state. else { this.Logger.WriteLine($"The stack's current state of {existingStack.StackStatus} is invalid for updating"); return(false); } CreateChangeSetResponse changeSetResponse; try { var templateParameters = GetTemplateParameters(changeSetType == ChangeSetType.UPDATE ? existingStack : null); if (templateParameters?.Count > 0) { var setParameters = templateParameters.Where(x => !x.UsePreviousValue); if (setParameters?.Count() > 0) { this.Logger.WriteLine("Template Parameters Applied:"); foreach (var parameter in setParameters) { this.Logger.WriteLine($"\t{parameter.ParameterKey}: {parameter.ParameterValue}"); } } } var capabilities = new List <string>(); var disabledCapabilties = GetStringValuesOrDefault(this.DisabledCapabilities, DefinedCommandOptions.ARGUMENT_CLOUDFORMATION_DISABLE_CAPABILITIES, false); if (disabledCapabilties?.FirstOrDefault(x => string.Equals(x, "CAPABILITY_IAM", StringComparison.OrdinalIgnoreCase)) == null) { capabilities.Add("CAPABILITY_IAM"); } if (disabledCapabilties?.FirstOrDefault(x => string.Equals(x, "CAPABILITY_NAMED_IAM", StringComparison.OrdinalIgnoreCase)) == null) { capabilities.Add("CAPABILITY_NAMED_IAM"); } var changeSetRequest = new CreateChangeSetRequest { StackName = stackName, Parameters = templateParameters, ChangeSetName = changeSetName, ChangeSetType = changeSetType, Capabilities = capabilities, RoleARN = this.GetStringValueOrDefault(this.CloudFormationRole, DefinedCommandOptions.ARGUMENT_CLOUDFORMATION_ROLE, false), Tags = new List <Tag> { new Tag { Key = Constants.SERVERLESS_TAG_NAME, Value = "true" } } }; if (new FileInfo(templatePath).Length < Constants.MAX_TEMPLATE_BODY_IN_REQUEST_SIZE) { changeSetRequest.TemplateBody = templateBody; } else { changeSetRequest.TemplateURL = this.S3Client.GetPreSignedURL(new S3.Model.GetPreSignedUrlRequest { BucketName = s3Bucket, Key = s3KeyTemplate, Expires = DateTime.Now.AddHours(1) }); } // Create the change set which performs the transformation on the Serverless resources in the template. changeSetResponse = await this.CloudFormationClient.CreateChangeSetAsync(changeSetRequest); this.Logger.WriteLine("CloudFormation change set created"); } catch (LambdaToolsException) { throw; } catch (Exception e) { throw new LambdaToolsException($"Error creating CloudFormation change set: {e.Message}", LambdaToolsException.ErrorCode.CloudFormationCreateStack, e); } // The change set can take a few seconds to be reviewed and be ready to be executed. if (!await WaitForChangeSetBeingAvailableAsync(changeSetResponse.Id, existingStack != null)) { return(false); } var executeChangeSetRequest = new ExecuteChangeSetRequest { StackName = stackName, ChangeSetName = changeSetResponse.Id }; // Execute the change set. DateTime timeChangeSetExecuted = DateTime.Now; ExecuteChangeSetResponse executeChangeSetResponse; try { executeChangeSetResponse = await this.CloudFormationClient.ExecuteChangeSetAsync(executeChangeSetRequest); if (changeSetType == ChangeSetType.CREATE) { this.Logger.WriteLine($"Created CloudFormation stack {stackName}"); } else { this.Logger.WriteLine($"Initiated CloudFormation stack update on {stackName}"); } } catch (Exception e) { throw new LambdaToolsException($"Error executing CloudFormation change set: {e.Message}", LambdaToolsException.ErrorCode.CloudFormationCreateChangeSet, e); } // Wait for the stack to finish unless the user opts out of waiting. The VS Toolkit opts out and // instead shows the stack view in the IDE, enabling the user to view progress. var shouldWait = GetBoolValueOrDefault(this.WaitForStackToComplete, DefinedCommandOptions.ARGUMENT_STACK_WAIT, false); if (!shouldWait.HasValue || shouldWait.Value) { var updatedStack = await WaitStackToCompleteAsync(stackName, timeChangeSetExecuted); if (updatedStack.StackStatus == StackStatus.CREATE_COMPLETE || updatedStack.StackStatus == StackStatus.UPDATE_COMPLETE) { this.Logger.WriteLine($"Stack finished updating with status: {updatedStack.StackStatus}"); // Display the output parameters. DisplayOutputs(updatedStack); } else { this.Logger.WriteLine($"Stack update failed with status: {updatedStack.StackStatus} ({updatedStack.StackStatusReason})"); return(false); } } if (this.GetBoolValueOrDefault(this.PersistConfigFile, DefinedCommandOptions.ARGUMENT_PERSIST_CONFIG_FILE, false).GetValueOrDefault()) { this.SaveConfigFile(); } return(true); } catch (LambdaToolsException e) { this.Logger.WriteLine(e.Message); this.LastToolsException = e; return(false); } catch (Exception e) { this.Logger.WriteLine($"Unknown error executing AWS Serverless deployment: {e.Message}"); this.Logger.WriteLine(e.StackTrace); return(false); } }
protected override async Task <bool> PerformActionAsync() { EnsureInProjectDirectory(); // Disable interactive since this command is intended to be run as part of a pipeline. this.DisableInteractive = true; var layerVersionArns = this.GetStringValuesOrDefault(this.LayerVersionArns, LambdaDefinedCommandOptions.ARGUMENT_FUNCTION_LAYERS, false); LayerPackageInfo layerPackageInfo = null; if (layerVersionArns != null) { if (!this.DisableRegionAndCredentialsCheck) { // Region and credentials are only required if using layers. This is new behavior so do a preemptive check when there are layers to // see if region and credentials are set. If they are not set give a specific error message about region and credentials required // when using layers. try { base.DetermineAWSRegion(); } catch (Exception) { throw new ToolsException("Region is required for the package command when layers are specified. The layers must be inspected to see how they affect packaging.", ToolsException.CommonErrorCode.RegionNotConfigured); } try { base.DetermineAWSCredentials(); } catch (Exception) { throw new ToolsException("AWS credentials are required for the package command when layers are specified. The layers must be inspected to see how they affect packaging.", ToolsException.CommonErrorCode.InvalidCredentialConfiguration); } } layerPackageInfo = await LambdaUtilities.LoadLayerPackageInfos(this.Logger, this.LambdaClient, this.S3Client, layerVersionArns); } else { layerPackageInfo = new LayerPackageInfo(); } var projectLocation = this.GetStringValueOrDefault(this.ProjectLocation, CommonDefinedCommandOptions.ARGUMENT_PROJECT_LOCATION, false); // Release will be the default configuration if nothing set. var 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(Utilities.DetermineProjectLocation(this.WorkingDirectory, projectLocation)); } var msbuildParameters = this.GetStringValueOrDefault(this.MSBuildParameters, CommonDefinedCommandOptions.ARGUMENT_MSBUILD_PARAMETERS, false); var disableVersionCheck = this.GetBoolValueOrDefault(this.DisableVersionCheck, LambdaDefinedCommandOptions.ARGUMENT_DISABLE_VERSION_CHECK, false).GetValueOrDefault(); var zipArchivePath = GetStringValueOrDefault(this.OutputPackageFileName, LambdaDefinedCommandOptions.ARGUMENT_OUTPUT_PACKAGE, false); string publishLocation; var success = LambdaPackager.CreateApplicationBundle(this.DefaultConfig, this.Logger, this.WorkingDirectory, projectLocation, configuration, targetFramework, msbuildParameters, disableVersionCheck, layerPackageInfo, out publishLocation, ref zipArchivePath); if (!success) { this.Logger.WriteLine("Failed to create application package"); return(false); } this.Logger.WriteLine("Lambda project successfully packaged: " + zipArchivePath); var dotnetSharedStoreValue = layerPackageInfo.GenerateDotnetSharedStoreValue(); if (!string.IsNullOrEmpty(dotnetSharedStoreValue)) { this.NewDotnetSharedStoreValue = dotnetSharedStoreValue; this.Logger.WriteLine($"\nWarning: You must set the {LambdaConstants.ENV_DOTNET_SHARED_STORE} environment variable when deploying the package. " + "If not set the layers specified will not be located by the .NET Core runtime. The trailing '/' is required."); this.Logger.WriteLine($"{LambdaConstants.ENV_DOTNET_SHARED_STORE}: {dotnetSharedStoreValue}"); } return(true); }
protected override async Task <bool> PerformActionAsync() { string projectLocation = this.GetStringValueOrDefault(this.ProjectLocation, CommonDefinedCommandOptions.ARGUMENT_PROJECT_LOCATION, false); string zipArchivePath = null; string package = this.GetStringValueOrDefault(this.Package, LambdaDefinedCommandOptions.ARGUMENT_PACKAGE, false); if (string.IsNullOrEmpty(package)) { EnsureInProjectDirectory(); string configuration = this.GetStringValueOrDefault(this.Configuration, CommonDefinedCommandOptions.ARGUMENT_CONFIGURATION, true); string targetFramework = this.GetStringValueOrDefault(this.TargetFramework, CommonDefinedCommandOptions.ARGUMENT_FRAMEWORK, true); string msbuildParameters = this.GetStringValueOrDefault(this.MSBuildParameters, CommonDefinedCommandOptions.ARGUMENT_MSBUILD_PARAMETERS, false); ValidateTargetFrameworkAndLambdaRuntime(); bool disableVersionCheck = this.GetBoolValueOrDefault(this.DisableVersionCheck, LambdaDefinedCommandOptions.ARGUMENT_DISABLE_VERSION_CHECK, false).GetValueOrDefault(); string publishLocation; LambdaPackager.CreateApplicationBundle(this.DefaultConfig, this.Logger, this.WorkingDirectory, projectLocation, configuration, targetFramework, msbuildParameters, disableVersionCheck, out publishLocation, ref zipArchivePath); if (string.IsNullOrEmpty(zipArchivePath)) { return(false); } } 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; } using (var stream = new MemoryStream(File.ReadAllBytes(zipArchivePath))) { var s3Bucket = this.GetStringValueOrDefault(this.S3Bucket, LambdaDefinedCommandOptions.ARGUMENT_S3_BUCKET, false); string s3Key = null; if (!string.IsNullOrEmpty(s3Bucket)) { 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, stream); } var currentConfiguration = await GetFunctionConfigurationAsync(); if (currentConfiguration == null) { this.Logger.WriteLine($"Creating new Lambda function {this.FunctionName}"); var createRequest = new CreateFunctionRequest { 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), Handler = this.GetStringValueOrDefault(this.Handler, LambdaDefinedCommandOptions.ARGUMENT_FUNCTION_HANDLER, true), Publish = this.GetBoolValueOrDefault(this.Publish, LambdaDefinedCommandOptions.ARGUMENT_FUNCTION_PUBLISH, false).GetValueOrDefault(), MemorySize = this.GetIntValueOrDefault(this.MemorySize, LambdaDefinedCommandOptions.ARGUMENT_FUNCTION_MEMORY_SIZE, true).GetValueOrDefault(), Runtime = this.GetStringValueOrDefault(this.Runtime, LambdaDefinedCommandOptions.ARGUMENT_FUNCTION_RUNTIME, true), 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 environmentVariables = GetEnvironmentVariables(null); 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 }; } if (s3Bucket != null) { createRequest.Code = new FunctionCode { S3Bucket = s3Bucket, S3Key = s3Key }; } else { createRequest.Code = new FunctionCode { ZipFile = stream }; } 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); } } 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 (s3Bucket != null) { updateCodeRequest.S3Bucket = s3Bucket; updateCodeRequest.S3Key = s3Key; } else { updateCodeRequest.ZipFile = stream; } try { await this.LambdaClient.UpdateFunctionCodeAsync(updateCodeRequest); } catch (Exception e) { throw new LambdaToolsException($"Error updating code for Lambda function: {e.Message}", LambdaToolsException.LambdaErrorCode.LambdaUpdateFunctionCode, e); } await base.UpdateConfigAsync(currentConfiguration); await base.ApplyTags(currentConfiguration.FunctionArn); var publish = this.GetBoolValueOrDefault(this.Publish, LambdaDefinedCommandOptions.ARGUMENT_FUNCTION_PUBLISH, false).GetValueOrDefault(); if (publish) { await base.PublishFunctionAsync(updateCodeRequest.FunctionName); } } } return(true); }