async IAsyncEnumerable <DescribeStackEventsResponse> IPaginator <DescribeStackEventsResponse> .PaginateAsync(CancellationToken cancellationToken = default) { if (Interlocked.Exchange(ref _isPaginatorInUse, 1) != 0) { throw new System.InvalidOperationException("Paginator has already been consumed and cannot be reused. Please create a new instance."); } var nextToken = _request.NextToken; DescribeStackEventsResponse response; do { _request.NextToken = nextToken; response = await _client.DescribeStackEventsAsync(_request, cancellationToken).ConfigureAwait(false); nextToken = response.NextToken; cancellationToken.ThrowIfCancellationRequested(); yield return(response); }while (nextToken != 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 static async Task <List <StackEvent> > GetLatestEventsAsync(ILogger log, IAmazonCloudFormation cloudformation, string stackName, DateTime mintimeStampForEvents, string mostRecentEventId) { var noNewEvents = false; var events = new List <StackEvent>(); DescribeStackEventsResponse response = null; do { var request = new DescribeStackEventsRequest { StackName = stackName }; if (response != null) { request.NextToken = response.NextToken; } try { response = await cloudformation.DescribeStackEventsAsync(request).ConfigureAwait(false); } catch (Exception e) { log.Error(e, "Error getting events for stack"); throw; } foreach (var evnt in response.StackEvents) { if (string.Equals(evnt.EventId, mostRecentEventId) || evnt.Timestamp < mintimeStampForEvents) { noNewEvents = true; break; } events.Add(evnt); } } while (!noNewEvents && !string.IsNullOrEmpty(response.NextToken)); return(events); }
private Amazon.CloudFormation.Model.DescribeStackEventsResponse CallAWSServiceOperation(IAmazonCloudFormation client, Amazon.CloudFormation.Model.DescribeStackEventsRequest request) { Utils.Common.WriteVerboseEndpointMessage(this, client.Config, "AWS CloudFormation", "DescribeStackEvents"); try { #if DESKTOP return(client.DescribeStackEvents(request)); #elif CORECLR return(client.DescribeStackEventsAsync(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; } }
private async Task <List <StackEvent> > GetStackEvents(string?lastEventId, string stackId, DeployContext context, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); var request = new DescribeStackEventsRequest { StackName = stackId }; var response = await cloudformation.DescribeStackEventsAsync(request, cancellationToken); var relevantEvents = new List <StackEvent>(); foreach (var @event in response.StackEvents) { if (@event.EventId == lastEventId || @event.Timestamp < context.Timestamp) { break; } relevantEvents.Add(@event); } relevantEvents.Reverse(); return(relevantEvents); }
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; } } }