private static async Task <Stack> WaitForNoLongerInProgress(ILogger log, IAmazonCloudFormation cloudformation, string stackName) { try { long start = DateTime.Now.Ticks; Stack currentStack = null; do { if (currentStack != null) { log.Information($"... Waiting for stack's state to change from {currentStack.StackStatus}: {TimeSpan.FromTicks(DateTime.Now.Ticks - start).TotalSeconds.ToString("0").PadLeft(3)} secs"); } await Task.Delay(POLLING_PERIOD).ConfigureAwait(false); currentStack = await GetExistingStackAsync(cloudformation, stackName).ConfigureAwait(false); } while (currentStack != null && currentStack.StackStatus.ToString().EndsWith(IN_PROGRESS_SUFFIX)); return(currentStack); } catch (Exception e) { log.Error(e, "Error waiting for stack state change"); throw; } }
public CloudformationStackDeployer( IAlarmLogger logger, IAmazonCloudFormation cloudformation, IAmazonS3 s3Client, S3Location s3Location) : this(logger, cloudformation, s3Client, s3Location, TimeSpan.FromSeconds(2), TimeSpan.FromMinutes(5)) { }
public IAwsFactory <IAmazonCloudFormation> CreateCloudFormationFactory(IAmazonCloudFormation client) { var factory = Substitute.For <IAwsFactory <IAmazonCloudFormation> >(); factory.Create(Arg.Any <string>()).Returns(client); return(factory); }
internal static bool IsStackInState(IAmazonCloudFormation client, string stackName, HashSet <StackStatus> desiredStates, bool throwOnError) { try { var request = new DescribeStacksRequest { StackName = stackName }; #if DESKTOP var response = client.DescribeStacks(request); #elif CORECLR var response = client.DescribeStacksAsync(request).GetAwaiter().GetResult(); #else #error "Unknown build edition" #endif return(IsStackInState(response.Stacks[0].StackStatus, desiredStates)); } catch (Exception exc) { var webException = exc.InnerException as System.Net.WebException; if (webException != null) { throw new Exception(Utils.Common.FormatNameResolutionFailureMessage(client.Config, webException.Message), webException); } if (throwOnError) { throw; } } return(false); }
public static async Task <(bool Success, Stack Stack)> GetStackAsync(this IAmazonCloudFormation cfnClient, string stackName, LogErrorDelegate logError) { Stack stack = null; try { var describe = await cfnClient.DescribeStacksAsync(new DescribeStacksRequest { StackName = stackName }); // make sure the stack is in a stable state (not updating and not failed) stack = describe.Stacks.FirstOrDefault(); switch (stack?.StackStatus) { case null: case "CREATE_COMPLETE": case "ROLLBACK_COMPLETE": case "UPDATE_COMPLETE": case "UPDATE_ROLLBACK_COMPLETE": // we're good to go break; default: logError?.Invoke($"{stackName} is not in a valid state; module deployment must be complete and successful (status: {stack?.StackStatus})", null); return(false, null); } } catch (AmazonCloudFormationException) { // stack not found; nothing to do } return(true, stack); }
public StackEventMonitor(string stackName, IAWSClientFactory awsClientFactory, IToolInteractiveService interactiveService, OrchestratorSession session) { _stackName = stackName; _cloudFormationClient = awsClientFactory.GetAWSClient <IAmazonCloudFormation>(session.AWSCredentials, session.AWSRegion); _consoleUtilities = new ConsoleUtilities(interactiveService); }
public StackEventMonitor(string stackName, IAWSClientFactory awsClientFactory, IConsoleUtilities consoleUtilities) { _stackName = stackName; _consoleUtilities = consoleUtilities; _cloudFormationClient = awsClientFactory.GetAWSClient <IAmazonCloudFormation>(); }
public DeleteDeploymentCommand(IAWSClientFactory awsClientFactory, IToolInteractiveService interactiveService, OrchestratorSession session) { _awsClientFactory = awsClientFactory; _interactiveService = interactiveService; _session = session; _cloudFormationClient = _awsClientFactory.GetAWSClient <IAmazonCloudFormation>(_session.AWSCredentials, _session.AWSRegion); _consoleUtilities = new ConsoleUtilities(interactiveService); }
//--- Constructors --- /// <summary> /// Creates new instance of <see cref="LambdaFinalizerDependencyProvider"/>, which provides the implementation for the required dependencies for <see cref="ALambdaFinalizerFunction"/>. /// </summary> /// <param name="utcNowCallback">A function that return the current <c>DateTime</c> in UTC timezone. Defaults to <see cref="DateTime.UtcNow"/> when <c>null</c>.</param> /// <param name="logCallback">An action that logs a string message. Defaults to <see cref="LambdaLogger.Log"/> when <c>null</c>.</param> /// <param name="configSource">A <see cref="ILambdaConfigSource"/> instance from which the Lambda function configuration is read. Defaults to <see cref="LambdaSystemEnvironmentSource"/> instance when <c>null</c>.</param> /// <param name="kmsClient">A <see cref="IAmazonKeyManagementService"/> client instance. Defaults to <see cref="AmazonKeyManagementServiceClient"/> when <c>null</c>.</param> /// <param name="sqsClient">A <see cref="IAmazonSQS"/> client instance. Defaults to <see cref="AmazonSQSClient"/> when <c>null</c>.</param> /// <param name="cloudFormationClient">A <see cref="IAmazonCloudFormation"/> client instance. Defaults to <see cref="AmazonCloudFormationClient"/> when <c>null</c>.</param> public LambdaFinalizerDependencyProvider( Func <DateTime>?utcNowCallback = null, Action <string>?logCallback = null, ILambdaConfigSource?configSource = null, IAmazonKeyManagementService?kmsClient = null, IAmazonSQS?sqsClient = null, IAmazonCloudFormation?cloudFormationClient = null ) : base(utcNowCallback, logCallback, configSource, kmsClient, sqsClient) { _cloudFormationClient = cloudFormationClient ?? new AmazonCloudFormationClient(); }
private static async Task <Stack> WaitStackToCompleteAsync(ILogger log, IAmazonCloudFormation cloudformation, string stackName, DateTime mintimeStampForEvents) { const int TIMESTAMP_WIDTH = 20; const int LOGICAL_RESOURCE_WIDTH = 40; const int RESOURCE_STATUS = 40; var mostRecentEventId = ""; log.Information(" "); log.Information( "Timestamp".PadRight(TIMESTAMP_WIDTH) + " " + "Logical Resource Id".PadRight(LOGICAL_RESOURCE_WIDTH) + " " + "Status".PadRight(RESOURCE_STATUS) + " "); log.Information( new string('-', TIMESTAMP_WIDTH) + " " + new string('-', LOGICAL_RESOURCE_WIDTH) + " " + new string('-', RESOURCE_STATUS) + " "); Stack stack; do { await Task.Delay(POLLING_PERIOD).ConfigureAwait(false); stack = await GetExistingStackAsync(cloudformation, stackName).ConfigureAwait(false); var events = await GetLatestEventsAsync(log, cloudformation, stackName, mintimeStampForEvents, mostRecentEventId).ConfigureAwait(false); if (events.Count > 0) { mostRecentEventId = events[0].EventId; } for (int i = events.Count - 1; i >= 0; i--) { var line = events[i].Timestamp.ToString("g").PadRight(TIMESTAMP_WIDTH) + " " + events[i].LogicalResourceId.PadRight(LOGICAL_RESOURCE_WIDTH) + " " + events[i].ResourceStatus.ToString().PadRight(RESOURCE_STATUS); // To save screen space only show error messages. if (!events[i].ResourceStatus.ToString().EndsWith(IN_PROGRESS_SUFFIX) && !string.IsNullOrEmpty(events[i].ResourceStatusReason)) { line += " " + events[i].ResourceStatusReason; } log.Information(line); } } while (stack.StackStatus.ToString().EndsWith(IN_PROGRESS_SUFFIX)); return(stack); }
public CloudformationStackDeployer( IAlarmLogger logger, IAmazonCloudFormation cloudformation, IAmazonS3 s3Client, S3Location s3Location, TimeSpan wait, TimeSpan timeout) { _logger = logger; _cloudformation = cloudformation; _stackStatusCheckTimeout = timeout; _stackStatusCheckInterval = wait; _s3Client = s3Client; _s3Location = s3Location; }
public DeleteDeploymentCommand( IAWSClientFactory awsClientFactory, IToolInteractiveService interactiveService, IConsoleUtilities consoleUtilities, ILocalUserSettingsEngine localUserSettingsEngine, OrchestratorSession?session) { _awsClientFactory = awsClientFactory; _interactiveService = interactiveService; _consoleUtilities = consoleUtilities; _cloudFormationClient = _awsClientFactory.GetAWSClient <IAmazonCloudFormation>(); _localUserSettingsEngine = localUserSettingsEngine; _session = session; }
public async Task SetupCloudFormation() { cloudformation = new AmazonCloudFormationClient(); if (await cloudformation.StackExists(stackName)) { await cloudformation.DeleteStackAsync(new DeleteStackRequest { StackName = stackName }); await cloudformation.WaitUntilStackDoesNotExist(stackName); } }
public static async Task <bool> StackHasStatus(this IAmazonCloudFormation client, string stackName, string status) { try { var response = await client.DescribeStacksAsync(new DescribeStacksRequest { StackName = stackName }); return(response.Stacks.Count > 0 ? response.Stacks[0].StackStatus == status : false); } catch (Exception) { return(false); } }
public static async Task <StackSet> GetExistingStackSetAsync(IAmazonCloudFormation cloudformation, string stackSetName) { try { var request = new DescribeStackSetRequest { StackSetName = stackSetName }; var response = await cloudformation.DescribeStackSetAsync(request).ConfigureAwait(false); return(response.StackSet); } catch (AmazonCloudFormationException) { return(null); } }
public static async Task WaitUntilStackDoesNotExist(this IAmazonCloudFormation client, string stackName, int timeout = 300) { int tries = 0; while (await client.StackExists(stackName)) { if (tries > timeout) { throw new Exception("Timed out waiting for stack to finish deleting"); } await Task.Delay(1000); tries++; } }
public static async Task WaitUntilStackHasStatus(this IAmazonCloudFormation client, string stackName, string status, int timeout = 300) { int tries = 0; while (!await client.StackHasStatus(stackName, status)) { if (tries > timeout) { throw new Exception("Timed out waiting for stack"); } await Task.Delay(1000); tries++; } }
public LayerTestsFixture() { this.CFClient = new AmazonCloudFormationClient(RegionEndpoint.USEast1); this.S3Client = new AmazonS3Client(RegionEndpoint.USEast1); this.LambdaClient = new AmazonLambdaClient(RegionEndpoint.USEast1); this.Bucket = "dotnet-lambda-layer-tests-" + DateTime.Now.Ticks; Task.Run(async() => { await S3Client.PutBucketAsync(this.Bucket); // Wait for bucket to exist Thread.Sleep(10000); }).Wait(); }
private static async Task DeleteRollbackCompleteStackAsync(ILogger log, IAmazonCloudFormation cloudformation, Stack stack) { try { if (stack.StackStatus == StackStatus.ROLLBACK_COMPLETE) { await cloudformation.DeleteStackAsync(new DeleteStackRequest { StackName = stack.StackName }).ConfigureAwait(false); } await WaitForNoLongerInProgress(log, cloudformation, stack.StackName).ConfigureAwait(false); } catch (Exception ex) { log.Error(ex, "Error removing previous failed stack creation {stackName}", stack.StackName); throw; } }
public static async Task <string> GetOutputParameter(IAmazonCloudFormation cfClient, string stackName, string outputName) { var response = await cfClient.DescribeStacksAsync(new DescribeStacksRequest() { StackName = stackName }); foreach (var output in response.Stacks[0].Outputs) { if (string.Equals(output.OutputKey, outputName, StringComparison.OrdinalIgnoreCase)) { return(output.OutputValue); } } return(null); }
public static async Task <string> GetPhysicalCloudFormationResourceId(IAmazonCloudFormation cfClient, string stackName, string logicalId) { var response = await cfClient.DescribeStackResourcesAsync(new DescribeStackResourcesRequest() { StackName = stackName, LogicalResourceId = logicalId }); foreach (var resource in response.StackResources) { if (string.Equals(resource.LogicalResourceId, logicalId, StringComparison.OrdinalIgnoreCase)) { return(resource.PhysicalResourceId); } } return(null); }
public static async Task <string> GetMostRecentStackEventIdAsync(this IAmazonCloudFormation cfnClient, string stackName) { try { var response = await cfnClient.DescribeStackEventsAsync(new DescribeStackEventsRequest { StackName = stackName }); var mostRecentStackEvent = response.StackEvents.First(); // make sure the stack is not already in an update operation if (!mostRecentStackEvent.IsFinalStackEvent()) { throw new System.InvalidOperationException("stack appears to be undergoing an update operation"); } return(mostRecentStackEvent.EventId); } catch (AmazonCloudFormationException) { // NOTE (2018-12-11, bjorg): exception is thrown when stack doesn't exist; ignore it } return(null); }
private async Task <bool> DoesStackExist(DeployStackContext context, IAmazonCloudFormation cloudformationClient) { try { // if this throws, assume the stack does not exist. var describeStacksRequest = new DescribeStacksRequest { StackName = context.StackName }; var describeStacksResponse = await cloudformationClient.DescribeStacksAsync(describeStacksRequest); logger.LogInformation($"Got describe stacks response: {Serialize(describeStacksResponse)}"); return(describeStacksResponse.Stacks.Count() != 0); } catch (Exception e) { logger.LogError($"Describe stacks failure: {e.Message}\n{e.StackTrace}"); } return(false); }
public static async Task <bool> DeleteStackAsync(ILogger log, IAmazonCloudFormation cloudformation, string stackName, string roleArn) { var request = new DeleteStackRequest { StackName = stackName, RoleARN = roleArn }; try { await cloudformation.DeleteStackAsync(request).ConfigureAwait(false); log.Information("CloudFormation stack {stackName} deleted", request.StackName); return(true); } catch (Exception ex) { log.Error(ex, "Error deleting Cloudformation stack {stackName}", request.StackName); return(false); } }
public static async Task <(bool Success, Stack Stack)> GetStackAsync(this IAmazonCloudFormation cfnClient, string stackName, LogErrorDelegate logError) { Stack stack = null; var attempts = 0; try { var describe = await cfnClient.DescribeStacksAsync(new DescribeStacksRequest { StackName = stackName }); // make sure the stack is in a stable state (not updating and not failed) stack = describe.Stacks.FirstOrDefault(); switch (stack?.StackStatus) { case null: case "CREATE_COMPLETE": case "ROLLBACK_COMPLETE": case "UPDATE_COMPLETE": case "UPDATE_ROLLBACK_COMPLETE": // we're good to go break; default: logError?.Invoke($"{stackName} is not in a valid state; CloudFormation stack must be complete and successful (status: {stack?.StackStatus})", null); return(false, null); } } catch (AmazonCloudFormationException) { // stack not found; nothing to do } catch (HttpRequestException e) when(e.Message == "The requested name is valid, but no data of the requested type was found") { // NOTE (2020-03-31, bjorg): avoid sporadic DNS issues by waiting an trying again if (++attempts < 3) { await Task.Delay(TimeSpan.FromSeconds(attempts)); } } return(true, stack); }
private Amazon.CloudFormation.Model.TestTypeResponse CallAWSServiceOperation(IAmazonCloudFormation client, Amazon.CloudFormation.Model.TestTypeRequest request) { Utils.Common.WriteVerboseEndpointMessage(this, client.Config, "AWS CloudFormation", "TestType"); try { #if DESKTOP return(client.TestType(request)); #elif CORECLR return(client.TestTypeAsync(request).GetAwaiter().GetResult()); #else #error "Unknown build edition" #endif } catch (AmazonServiceException exc) { var webException = exc.InnerException as System.Net.WebException; if (webException != null) { throw new Exception(Utils.Common.FormatNameResolutionFailureMessage(client.Config, webException.Message), webException); } throw; } }
internal ListStackSetOperationResultsPaginator(IAmazonCloudFormation client, ListStackSetOperationResultsRequest request) { this._client = client; this._request = request; }
internal ListTypesPaginator(IAmazonCloudFormation client, ListTypesRequest request) { this._client = client; this._request = request; }
public static async Task <(Stack Stack, bool Success)> TrackStackUpdateAsync( this IAmazonCloudFormation cfnClient, string stackName, string stackId, string mostRecentStackEventId, ModuleNameMappings nameMappings = null, LogErrorDelegate logError = null ) { var seenEventIds = new HashSet <string>(); var foundMostRecentStackEvent = (mostRecentStackEventId == null); var request = new DescribeStackEventsRequest { StackName = stackId ?? stackName }; var eventList = new List <StackEvent>(); var ansiLinesPrinted = 0; // iterate as long as the stack is being created/updated var active = true; var success = false; while (active) { await Task.Delay(TimeSpan.FromSeconds(3)); // fetch as many events as possible for the current stack var events = new List <StackEvent>(); try { var response = await cfnClient.DescribeStackEventsAsync(request); events.AddRange(response.StackEvents); } catch (System.Net.Http.HttpRequestException e) when((e.InnerException is System.Net.Sockets.SocketException) && (e.InnerException.Message == "No such host is known")) { // ignore network issues and just try again continue; } events.Reverse(); // skip any events that preceded the most recent event before the stack update operation while (!foundMostRecentStackEvent && events.Any()) { var evt = events.First(); if (evt.EventId == mostRecentStackEventId) { foundMostRecentStackEvent = true; } seenEventIds.Add(evt.EventId); events.RemoveAt(0); } if (!foundMostRecentStackEvent) { throw new ApplicationException($"unable to find starting event for stack: {stackName}"); } // report only on new events foreach (var evt in events.Where(evt => !seenEventIds.Contains(evt.EventId))) { UpdateEvent(evt); if (!seenEventIds.Add(evt.EventId)) { // we found an event we already saw in the past, no point in looking at more events break; } if (IsFinalStackEvent(evt) && (evt.LogicalResourceId == stackName)) { // event signals stack creation/update completion; time to stop active = false; success = IsSuccessfulFinalStackEvent(evt); break; } } RenderEvents(); } if (!success) { return(Stack : null, Success : false); } // describe stack and report any output values var description = await cfnClient.DescribeStacksAsync(new DescribeStacksRequest { StackName = stackName }); return(Stack : description.Stacks.FirstOrDefault(), Success : success); // local function string TranslateLogicalIdToFullName(string logicalId) { var fullName = logicalId; nameMappings?.ResourceNameMappings?.TryGetValue(logicalId, out fullName); return(fullName ?? logicalId); } string TranslateResourceTypeToFullName(string awsType) { var fullName = awsType; nameMappings?.TypeNameMappings?.TryGetValue(awsType, out fullName); return(fullName ?? awsType); } void RenderEvents() { if (Settings.UseAnsiConsole) { if (ansiLinesPrinted > 0) { Console.Write(AnsiTerminal.MoveLineUp(ansiLinesPrinted)); } var maxResourceStatusLength = eventList.Any() ? eventList.Max(evt => evt.ResourceStatus.ToString().Length) : 0; var maxResourceTypeNameLength = eventList.Any() ? eventList.Max(evt => TranslateResourceTypeToFullName(evt.ResourceType).Length) : 0; foreach (var evt in eventList) { var resourceStatus = evt.ResourceStatus.ToString(); var resourceType = TranslateResourceTypeToFullName(evt.ResourceType); if (_ansiStatusColorCodes.TryGetValue(evt.ResourceStatus, out var ansiColor)) { // print resource status Console.Write(ansiColor); Console.Write(resourceStatus); Console.Write(AnsiTerminal.Reset); Console.Write("".PadRight(maxResourceStatusLength - resourceStatus.Length + 4)); // print resource type Console.Write(resourceType); Console.Write("".PadRight(maxResourceTypeNameLength - resourceType.Length + 4)); // print resource name Console.Write(TranslateLogicalIdToFullName(evt.LogicalResourceId)); // print status reason if ((logError == null) && (evt.ResourceStatusReason != null)) { Console.Write($" ({evt.ResourceStatusReason})"); } } else { Console.Write($"{resourceStatus} {resourceType} {TranslateLogicalIdToFullName(evt.LogicalResourceId)}{(evt.ResourceStatusReason != null ? $" ({evt.ResourceStatusReason})" : "")}"); } Console.Write(AnsiTerminal.ClearEndOfLine); Console.WriteLine(); } ansiLinesPrinted = eventList.Count; } } void UpdateEvent(StackEvent evt) { if (Settings.UseAnsiConsole) { var index = eventList.FindIndex(e => e.LogicalResourceId == evt.LogicalResourceId); if (index < 0) { eventList.Add(evt); } else { eventList[index] = evt; } } else { Console.WriteLine($"{evt.ResourceStatus,-35} {TranslateResourceTypeToFullName(evt.ResourceType),-55} {TranslateLogicalIdToFullName(evt.LogicalResourceId)}{(evt.ResourceStatusReason != null ? $" ({evt.ResourceStatusReason})" : "")}"); } // capture failed operation as an error switch (evt.ResourceStatus) { case "CREATE_FAILED": case "ROLLBACK_FAILED": case "UPDATE_FAILED": case "DELETE_FAILED": case "UPDATE_ROLLBACK_FAILED": case "UPDATE_ROLLBACK_IN_PROGRESS": if (evt.ResourceStatusReason != "Resource creation cancelled") { logError?.Invoke($"{evt.ResourceStatus} {TranslateLogicalIdToFullName(evt.LogicalResourceId)} [{TranslateResourceTypeToFullName(evt.ResourceType)}]: {evt.ResourceStatusReason}", /*Exception*/ null); } break; } } }
protected Func <Task <Settings> > CreateSettingsInitializer( CommandLineApplication cmd, bool requireAwsProfile = true, bool requireDeploymentTier = true ) { CommandOption tierOption = null; CommandOption awsProfileOption = null; // add misc options if (requireDeploymentTier) { tierOption = AddTierOption(cmd); } var toolProfileOption = cmd.Option("--cli-profile|-C <NAME>", "(optional) Use a specific LambdaSharp CLI profile (default: Default)", CommandOptionType.SingleValue); if (requireAwsProfile) { awsProfileOption = cmd.Option("--aws-profile|-P <NAME>", "(optional) Use a specific AWS profile from the AWS credentials file", CommandOptionType.SingleValue); } var verboseLevelOption = cmd.Option("--verbose|-V:<LEVEL>", "(optional) Show verbose output (0=quiet, 1=normal, 2=detailed, 3=exceptions)", CommandOptionType.SingleOrNoValue); // add hidden testing options var awsRegionOption = cmd.Option("--aws-region <NAME>", "(test only) Override AWS region (default: read from AWS profile)", CommandOptionType.SingleValue); var awsAccountIdOption = cmd.Option("--aws-account-id <VALUE>", "(test only) Override AWS account Id (default: read from AWS profile)", CommandOptionType.SingleValue); var awsUserArnOption = cmd.Option("--aws-user-arn <ARN>", "(test only) Override AWS user ARN (default: read from AWS profile)", CommandOptionType.SingleValue); var toolVersionOption = cmd.Option("--cli-version <VALUE>", "(test only) LambdaSharp CLI version for profile", CommandOptionType.SingleValue); var deploymentBucketNameOption = cmd.Option("--deployment-bucket-name <NAME>", "(test only) S3 Bucket name used to deploy modules (default: read from LambdaSharp CLI configuration)", CommandOptionType.SingleValue); var deploymentNotificationTopicOption = cmd.Option("--deployment-notifications-topic <ARN>", "(test only) SNS Topic for CloudFormation deployment notifications (default: read from LambdaSharp CLI configuration)", CommandOptionType.SingleValue); var moduleBucketNamesOption = cmd.Option("--module-bucket-names <NAMES>", "(test only) Comma-separated list of S3 Bucket names used to find modules (default: read from LambdaSharp CLI configuration)", CommandOptionType.SingleValue); var tierVersionOption = cmd.Option("--tier-version <VERSION>", "(test only) LambdaSharp tier version (default: read from deployment tier)", CommandOptionType.SingleValue); awsAccountIdOption.ShowInHelpText = false; awsRegionOption.ShowInHelpText = false; toolVersionOption.ShowInHelpText = false; deploymentBucketNameOption.ShowInHelpText = false; deploymentNotificationTopicOption.ShowInHelpText = false; moduleBucketNamesOption.ShowInHelpText = false; tierVersionOption.ShowInHelpText = false; return(async() => { // initialize logging level if (!TryParseEnumOption(verboseLevelOption, Tool.VerboseLevel.Normal, VerboseLevel.Detailed, out Settings.VerboseLevel)) { // NOTE (2018-08-04, bjorg): no need to add an error message since it's already added by 'TryParseEnumOption' return null; } // initialize CLI profile var toolProfile = toolProfileOption.Value() ?? Environment.GetEnvironmentVariable("LAMBDASHARP_PROFILE") ?? "Default"; // initialize deployment tier string tier = null; if (requireDeploymentTier) { tier = tierOption.Value() ?? Environment.GetEnvironmentVariable("LAMBDASHARP_TIER"); if (string.IsNullOrEmpty(tier)) { LogError("missing deployment tier name"); } else if (tier == "Default") { LogError("deployment tier cannot be 'Default' because it is a reserved name"); } } // initialize AWS profile try { AwsAccountInfo awsAccount = null; IAmazonSimpleSystemsManagement ssmClient = null; IAmazonCloudFormation cfClient = null; IAmazonKeyManagementService kmsClient = null; IAmazonS3 s3Client = null; if (requireAwsProfile) { awsAccount = await InitializeAwsProfile( awsProfileOption.Value(), awsAccountIdOption.Value(), awsRegionOption.Value(), awsUserArnOption.Value() ); // create AWS clients ssmClient = new AmazonSimpleSystemsManagementClient(); cfClient = new AmazonCloudFormationClient(); kmsClient = new AmazonKeyManagementServiceClient(); s3Client = new AmazonS3Client(); } if (HasErrors) { return null; } // initialize LambdaSharp deployment values var tierVersion = tierVersionOption.Value(); var deploymentBucketName = deploymentBucketNameOption.Value(); var deploymentNotificationTopic = deploymentNotificationTopicOption.Value(); var moduleBucketNames = moduleBucketNamesOption.Value()?.Split(','); // create a settings instance for each module filename return new Settings { ToolVersion = Version, ToolProfile = toolProfile, ToolProfileExplicitlyProvided = toolProfileOption.HasValue(), TierVersion = (tierVersion != null) ? VersionInfo.Parse(tierVersion) : null, Tier = tier, AwsRegion = awsAccount?.Region, AwsAccountId = awsAccount?.AccountId, AwsUserArn = awsAccount?.UserArn, DeploymentBucketName = deploymentBucketName, DeploymentNotificationsTopic = deploymentNotificationTopic, ModuleBucketNames = moduleBucketNames, SsmClient = ssmClient, CfnClient = cfClient, KmsClient = kmsClient, S3Client = s3Client }; } catch (AmazonClientException e) when(e.Message == "No RegionEndpoint or ServiceURL configured") { LogError("AWS profile configuration is missing a region specifier"); return null; } }); }
public StackService(IAmazonCloudFormation cloudFormationClient, IStorageService storageService, string bucket) { _cloudFormationClient = cloudFormationClient; _storageService = storageService; _bucket = bucket; }