public static async Task <IEnumerable <StackResourceSummary> > GetStackResourcesAsync(this IAmazonCloudFormation cfnClient, string stackName) { var result = new List <StackResourceSummary>(); var request = new ListStackResourcesRequest { StackName = stackName }; do { var attempts = 0; again: try { var response = await cfnClient.ListStackResourcesAsync(request); result.AddRange(response.StackResourceSummaries); request.NextToken = response.NextToken; } catch (AmazonCloudFormationException e) when( (e.Message == "Rate exceeded") && (++attempts < 30) ) { await Task.Delay(TimeSpan.FromSeconds(attempts)); goto again; } } while(request.NextToken != null); return(result); }
public override void Invoke(AWSCredentials creds, RegionEndpoint region, int maxItems) { AmazonCloudFormationConfig config = new AmazonCloudFormationConfig(); config.RegionEndpoint = region; ConfigureClient(config); AmazonCloudFormationClient client = new AmazonCloudFormationClient(creds, config); ListStackResourcesResponse resp = new ListStackResourcesResponse(); do { ListStackResourcesRequest req = new ListStackResourcesRequest { NextToken = resp.NextToken }; resp = client.ListStackResources(req); CheckError(resp.HttpStatusCode, "200"); foreach (var obj in resp.StackResourceSummaries) { AddObject(obj); } }while (!string.IsNullOrEmpty(resp.NextToken)); }
internal ListStackResourcesResponse ListStackResources(ListStackResourcesRequest request) { var marshaller = new ListStackResourcesRequestMarshaller(); var unmarshaller = ListStackResourcesResponseUnmarshaller.Instance; return(Invoke <ListStackResourcesRequest, ListStackResourcesResponse>(request, marshaller, unmarshaller)); }
/// <summary> /// <para> Returns descriptions for all resources of the specified stack. </para> <para>For deleted stacks, ListStackResources returns resource /// information for up to 90 days after the stack has been deleted. </para> /// </summary> /// /// <param name="listStackResourcesRequest">Container for the necessary parameters to execute the ListStackResources service method on /// AmazonCloudFormation.</param> /// /// <returns>The response from the ListStackResources service method, as returned by AmazonCloudFormation.</returns> /// public ListStackResourcesResponse ListStackResources(ListStackResourcesRequest listStackResourcesRequest) { IRequest <ListStackResourcesRequest> request = new ListStackResourcesRequestMarshaller().Marshall(listStackResourcesRequest); ListStackResourcesResponse response = Invoke <ListStackResourcesRequest, ListStackResourcesResponse> (request, this.signer, ListStackResourcesResponseUnmarshaller.GetInstance()); return(response); }
/// <summary> /// Initiates the asynchronous execution of the ListStackResources operation. /// <seealso cref="Amazon.CloudFormation.IAmazonCloudFormation.ListStackResources"/> /// </summary> /// /// <param name="request">Container for the necessary parameters to execute the ListStackResources operation.</param> /// <param name="cancellationToken"> /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. /// </param> /// <returns>The task object representing the asynchronous operation.</returns> public Task <ListStackResourcesResponse> ListStackResourcesAsync(ListStackResourcesRequest request, CancellationToken cancellationToken = default(CancellationToken)) { var marshaller = new ListStackResourcesRequestMarshaller(); var unmarshaller = ListStackResourcesResponseUnmarshaller.GetInstance(); return(Invoke <IRequest, ListStackResourcesRequest, ListStackResourcesResponse>(request, marshaller, unmarshaller, signer, cancellationToken)); }
private void ProcessLiveStackResourcess(ListStackResourcesResponse liveStackResources, CFStack stack, AmazonEC2Client ec2Client, Dictionary <string, string> secGroupMap, string stackName, AmazonCloudFormationClient cfClient) { foreach (StackResourceSummary liveStackResource in liveStackResources.StackResourceSummaries) { switch (liveStackResource.ResourceType) { case "AWS::EC2::SecurityGroup": AWSUtils.ProcessEC2SecurityGroupFromAWS(liveStackResource, stack, ec2Client, secGroupMap, stackName); break; case "AWS::EC2::NetworkAcl": AWSUtils.ProcessNetworkAclFromAWS(liveStackResource, stack, ec2Client, stackName); break; default: break; } } if (liveStackResources.NextToken != null) { ListStackResourcesRequest lr = new ListStackResourcesRequest(); lr.StackName = stackName; lr.NextToken = liveStackResources.NextToken; liveStackResources = cfClient.ListStackResources(lr); ProcessLiveStackResourcess(liveStackResources, stack, ec2Client, secGroupMap, stackName, cfClient); } }
/// <summary> /// Initiates the asynchronous execution of the ListStackResources operation. /// </summary> /// /// <param name="request">Container for the necessary parameters to execute the ListStackResources operation.</param> /// <param name="cancellationToken"> /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. /// </param> /// <returns>The task object representing the asynchronous operation.</returns> public Task <ListStackResourcesResponse> ListStackResourcesAsync(ListStackResourcesRequest request, System.Threading.CancellationToken cancellationToken = default(CancellationToken)) { var marshaller = new ListStackResourcesRequestMarshaller(); var unmarshaller = ListStackResourcesResponseUnmarshaller.Instance; return(InvokeAsync <ListStackResourcesRequest, ListStackResourcesResponse>(request, marshaller, unmarshaller, cancellationToken)); }
/// <summary> /// <para>Returns descriptions of all resources of the specified stack.</para> <para>For deleted stacks, ListStackResources returns resource /// information for up to 90 days after the stack has been deleted.</para> /// </summary> /// /// <param name="request">Container for the necessary parameters to execute the ListStackResources service method on /// AmazonCloudFormation.</param> /// /// <returns>The response from the ListStackResources service method, as returned by AmazonCloudFormation.</returns> public ListStackResourcesResponse ListStackResources(ListStackResourcesRequest request) { var task = ListStackResourcesAsync(request); try { return(task.Result); } catch (AggregateException e) { ExceptionDispatchInfo.Capture(e.InnerException).Throw(); return(null); } }
//private ListStackResourcesResponse ListStackResources(string stackName, AmazonCloudFormationClient cfClient, string nextToken = null) //{ // ListStackResourcesRequest lr = new ListStackResourcesRequest(); // lr.StackName = stackName; // lr.NextToken = nextToken; // ListStackResourcesResponse liveStackResources = cfClient.ListStackResources(lr); // return liveStackResources; //} private void ProcessLiveStack(string stackName, AmazonCloudFormationClient cfClient, AmazonEC2Client ec2Client, RichTextBox rtb, CFStack stack) { Dictionary <string, string> secGroupMap = new Dictionary <string, string>(); DescribeSecurityGroupsRequest secGroupRequestAll = new DescribeSecurityGroupsRequest(); //Get all security group Id's and cf logicalId's (if any) DescribeSecurityGroupsResponse secGroupResponseAll = ec2Client.DescribeSecurityGroups(secGroupRequestAll); foreach (SecurityGroup sg in secGroupResponseAll.SecurityGroups) { string value = "none"; foreach (Amazon.EC2.Model.Tag tag in sg.Tags) { if (tag.Key.Contains("aws:cloudformation:logical-id")) { value = tag.Value; } } secGroupMap.Add(sg.GroupId, value); } //Get Live Stack DescribeStacksRequest cfRequest = new DescribeStacksRequest(); cfRequest.StackName = stackName; DescribeStacksResponse liveStack = cfClient.DescribeStacks(cfRequest); stack.Description = liveStack.Stacks[0].Description; //Get Stack Resouces //Need to use ListStackResourcesRequest to be able to get stacks with more than 100 resources ListStackResourcesRequest lr = new ListStackResourcesRequest(); lr.StackName = stackName; ListStackResourcesResponse liveStackResources = cfClient.ListStackResources(lr); ProcessLiveStackResourcess(liveStackResources, stack, ec2Client, secGroupMap, stackName, cfClient); stack.Resources.Sort((a, b) => a.LogicalId.CompareTo(b.LogicalId)); WriteOutput(stack, rtb, source1_CB.Text, templateOrStack1_TB.Text); }
private async Task <string> GetStackResource(SnapStackRequest input, string stackName) { var cfClient = new AmazonCloudFormationClient(RegionEndpoint.EUWest1); //TODO: Paginate var request = new ListStackResourcesRequest { StackName = stackName }; var json = new JObject(); var resourceList = await cfClient.ListStackResourcesAsync(request); foreach (var resource in resourceList.StackResourceSummaries) { json.Add($"{resource.ResourceType}_{resource.LogicalResourceId}", resource.PhysicalResourceId); } return(json.ToString(Formatting.Indented)); }
public async Task ListLambdasAsync(string awsProfile, string awsRegion) { Console.WriteLine(); // initialize AWS profile await InitializeAwsProfile(awsProfile, awsRegion : awsRegion); var cfnClient = new AmazonCloudFormationClient(AWSConfigs.RegionEndpoint); var lambdaClient = new AmazonLambdaClient(AWSConfigs.RegionEndpoint); var logsClient = new AmazonCloudWatchLogsClient(AWSConfigs.RegionEndpoint); // fetch all Lambda functions on account var globalFunctions = (await ListLambdasAsync()) .ToDictionary(function => function.FunctionName, function => function); // fetch all stacks on account var stacks = await ListStacksAsync(); Console.WriteLine($"Analyzing {stacks.Count():N0} CloudFormation stacks and {globalFunctions.Count():N0} Lambda functions"); // fetch most recent CloudWatch log stream for each Lambda function var logStreamsTask = Task.Run(async() => (await Task.WhenAll(globalFunctions.Select(async kv => { try { var response = await logsClient.DescribeLogStreamsAsync(new DescribeLogStreamsRequest { Descending = true, LogGroupName = $"/aws/lambda/{kv.Value.FunctionName}", OrderBy = OrderBy.LastEventTime, Limit = 1 }); return(Name: kv.Value.FunctionName, Streams: response.LogStreams.FirstOrDefault()); } catch { // log group doesn't exist return(Name: kv.Value.FunctionName, Streams: null); } }))).ToDictionary(tuple => tuple.Name, tuple => tuple.Streams)); // fetch all functions belonging to a CloudFormation stack var stacksWithFunctionsTask = Task.Run(async() => stacks.Zip( await Task.WhenAll(stacks.Select(stack => ListStackFunctionsAsync(stack.StackId))), (stack, stackFunctions) => (Stack: stack, Functions: stackFunctions) ).ToList() ); // wait for both fetch operations to finish await Task.WhenAll(logStreamsTask, stacksWithFunctionsTask); var logStreams = logStreamsTask.GetAwaiter().GetResult(); var stacksWithFunctions = stacksWithFunctionsTask.GetAwaiter().GetResult(); // remove all the functions that were discovered inside a stack from the orphaned list of functions foreach (var function in stacksWithFunctions.SelectMany(stackWithFunctions => stackWithFunctions.Functions)) { globalFunctions.Remove(function.Configuration.FunctionName); } // compute the max width for the function name (use logical ID if it belongs to the stack) var maxFunctionNameWidth = stacksWithFunctions .SelectMany(stackWithFunctions => stackWithFunctions.Functions) .Select(function => function.Name.Length) .Union(globalFunctions.Values.Select(function => function.FunctionName.Length)) .Append(0) .Max(); // compute max width for the function runtime name var maxRuntimeWidth = stacksWithFunctions .SelectMany(stackWithFunctions => stackWithFunctions.Functions) .Select(stackFunction => stackFunction.Configuration.Runtime.ToString().Length) .Union(globalFunctions.Values.Select(function => function.Runtime.ToString().Length)) .Append(0) .Max(); // print Lambda functions belonging to stacks var showAsteriskExplanation = false; foreach (var stackWithFunctions in stacksWithFunctions .Where(stackWithFunction => stackWithFunction.Functions.Any()) .OrderBy(stackWithFunction => stackWithFunction.Stack.StackName) ) { Console.WriteLine(); // check if CloudFormation stack was deployed by LambdaSharp var moduleInfoOutput = stackWithFunctions.Stack.Outputs .FirstOrDefault(output => (output.OutputKey == "ModuleInfo") || (output.OutputKey == "Module")) ?.OutputValue; var lambdaSharpToolOutput = stackWithFunctions.Stack.Outputs .FirstOrDefault(output => output.OutputKey == "LambdaSharpTool") ?.OutputValue; // NOTE (2020-05-06, bjorg): pre-0.6, the module information was emitted as two output values var moduleNameOutput = stackWithFunctions.Stack.Outputs .FirstOrDefault(output => output.OutputKey == "ModuleName") ?.OutputValue; var moduleVersionOutput = stackWithFunctions.Stack.Outputs .FirstOrDefault(output => output.OutputKey == "ModuleVersion") ?.OutputValue; // show CloudFormation stack name and optionally LambdaSharp module information Console.Write($"{Settings.OutputColor}{stackWithFunctions.Stack.StackName}{Settings.ResetColor}"); if (ModuleInfo.TryParse(moduleInfoOutput, out var moduleInfo)) { Console.Write($" ({Settings.InfoColor}{moduleInfo.FullName}:{moduleInfo.Version}{Settings.ResetColor}) [lash {lambdaSharpToolOutput ?? "pre-0.6.1"}]"); } else if ((moduleNameOutput != null) && (moduleVersionOutput != null)) { Console.Write($" ({Settings.InfoColor}{moduleNameOutput}:{moduleVersionOutput}{Settings.ResetColor}) [lash pre-0.6]"); } Console.WriteLine(":"); foreach (var function in stackWithFunctions.Functions.OrderBy(function => function.Name)) { PrintFunction(function.Name, function.Configuration); } } // print orphan Lambda functions if (globalFunctions.Any()) { Console.WriteLine(); Console.WriteLine("ORPHANS:"); foreach (var function in globalFunctions.Values.OrderBy(function => function.FunctionName)) { PrintFunction(function.FunctionName, function); } } // show optional (*) explanation if it was printed if (showAsteriskExplanation) { Console.WriteLine(); Console.WriteLine("(*) Showing Lambda last-modified date, because last event timestamp in CloudWatch log stream is not available"); } // local functions async Task <IEnumerable <FunctionConfiguration> > ListLambdasAsync() { var result = new List <FunctionConfiguration>(); var request = new ListFunctionsRequest(); do { var response = await lambdaClient.ListFunctionsAsync(request); result.AddRange(response.Functions); request.Marker = response.NextMarker; } while(request.Marker != null); return(result); } async Task <IEnumerable <Stack> > ListStacksAsync() { var result = new List <Stack>(); var request = new DescribeStacksRequest(); do { var response = await cfnClient.DescribeStacksAsync(request); result.AddRange(response.Stacks); request.NextToken = response.NextToken; } while(request.NextToken != null); return(result); } async Task <IEnumerable <(string Name, FunctionConfiguration Configuration)> > ListStackFunctionsAsync(string stackName) { var result = new List <(string, FunctionConfiguration)>(); var request = new ListStackResourcesRequest { StackName = stackName }; do { var attempts = 0; again: try { var response = await cfnClient.ListStackResourcesAsync(request); result.AddRange( response.StackResourceSummaries .Where(resourceSummary => resourceSummary.ResourceType == "AWS::Lambda::Function") .Select(summary => { globalFunctions.TryGetValue(summary.PhysicalResourceId, out var configuration); return(Name: summary.LogicalResourceId, Configuration: configuration); }) .Where(tuple => tuple.Configuration != null) ); request.NextToken = response.NextToken; } catch (AmazonCloudFormationException e) when( (e.Message == "Rate exceeded") && (++attempts < 30) ) { await Task.Delay(TimeSpan.FromSeconds(attempts)); goto again; } } while(request.NextToken != null); return(result); } void PrintFunction(string name, FunctionConfiguration function) { Console.Write(" "); Console.Write(name); Console.Write("".PadRight(maxFunctionNameWidth - name.Length + 4)); Console.Write(function.Runtime); Console.Write("".PadRight(maxRuntimeWidth - function.Runtime.ToString().Length + 4)); if ( !logStreams.TryGetValue(function.FunctionName, out var logStream) || (logStream?.LastEventTimestamp == null) ) { Console.Write(DateTimeOffset.Parse(function.LastModified).ToString("yyyy-MM-dd")); Console.Write("(*)"); showAsteriskExplanation = true; } else { Console.Write(logStream.LastEventTimestamp.ToString("yyyy-MM-dd")); } Console.WriteLine(); } }
public static async Task <AwsSettings> GetAwsSettings(string profileName, string stackName) { if (string.IsNullOrEmpty(profileName)) { throw new Exception($"Error: No ProfileName provided"); } if (string.IsNullOrEmpty(stackName)) { throw new Exception($"Error: No StackName provided"); } var sharedCredentialsFile = new SharedCredentialsFile(); // AWS finds the shared credentials store for us CredentialProfile profile = null; if (!sharedCredentialsFile.TryGetProfile(profileName, out profile)) { throw new Exception($"Error: Aws Profile \"{profileName}\" not found in shared credentials store."); } AWSCredentials creds = null; if (!AWSCredentialsFactory.TryGetAWSCredentials(profile, sharedCredentialsFile, out creds)) { throw new Exception($"Error: Could not get AWS Credentials using specified profile \"{profileName}\"."); } var awsSettings = new AwsSettings(); awsSettings["StackName"] = stackName; // Get Original Template AmazonCloudFormationClient cfClient = null; GetTemplateRequest getTemplateRequestOriginal = null; try { // Note the need to extract region from the profile! cfClient = new AmazonCloudFormationClient(creds, profile.Region); getTemplateRequestOriginal = new GetTemplateRequest() { StackName = stackName, TemplateStage = Amazon.CloudFormation.TemplateStage.Original }; } catch (Exception ex) { throw new Exception($"Could not create AmazonCloudFormationClient"); } var templateReponse = cfClient.GetTemplateAsync(getTemplateRequestOriginal).GetAwaiter().GetResult(); //var templateBodyIndex = templateReponse.StagesAvailable.IndexOf("Original"); var templateBody = templateReponse.TemplateBody; // Original is in yaml form //var tmplYaml = new StringReader(new YamlDotNet.Serialization.SerializerBuilder().Build().Serialize(templateBody)); var tmplYaml = new StringReader(templateBody); var templYamlObj = new YamlDotNet.Serialization.DeserializerBuilder().Build().Deserialize(tmplYaml); templateBody = new YamlDotNet.Serialization.SerializerBuilder().JsonCompatible().Build().Serialize(templYamlObj); var jTemplateObjOriginal = JObject.Parse(templateBody); // Get Processed Template var getTemplateRequestProcessed = new GetTemplateRequest() { StackName = stackName, TemplateStage = Amazon.CloudFormation.TemplateStage.Processed }; templateReponse = cfClient.GetTemplateAsync(getTemplateRequestProcessed).GetAwaiter().GetResult(); //var templateBodyIndex = templateReponse.StagesAvailable.IndexOf("Original"); templateBody = templateReponse.TemplateBody; var jTemplateObjProcessed = JObject.Parse(templateBody); // Get Stack Resources - note: this call only returns the first 100 resources. // We are calling it to get the StackId var describeStackResourcesRequest = new DescribeStackResourcesRequest() { StackName = stackName }; var describeStackResourcesResponse = await cfClient.DescribeStackResourcesAsync(describeStackResourcesRequest); if (describeStackResourcesResponse.StackResources.Count == 0) { throw new Exception($"Error: No resources found for specified stack."); } // Extract region from StackId ARN -- "arn:aws:cloudformation:us-east-1:..." var stackIdParts = describeStackResourcesResponse.StackResources[0].StackId.Split(':'); var region = stackIdParts[3]; awsSettings["Region"] = region; // Get all stack resources - paginated // The the ListStackResourcesResponse does not contain the StackId. string nextToken = null; string apiName = null; int resourceCount = 0; var apiGateways = new Dictionary <string, AwsSettings.Api>(); awsSettings["ApiGateways"] = apiGateways; do { var listStackResourcesRequest = new ListStackResourcesRequest() { StackName = stackName, NextToken = nextToken }; var listStackResourcesResponse = await cfClient.ListStackResourcesAsync(listStackResourcesRequest); nextToken = listStackResourcesResponse.NextToken; foreach (var resource in listStackResourcesResponse.StackResourceSummaries) { resourceCount++; switch (resource.ResourceType) { case "AWS::Cognito::UserPool": case "AWS::Cognito::IdentityPool": case "AWS::Cognito::UserPoolClient": awsSettings[resource.LogicalResourceId] = resource.PhysicalResourceId; break; case "AWS::ApiGatewayV2::Api": var httpApi = new AwsSettings.Api(); apiGateways.Add(resource.LogicalResourceId, httpApi); httpApi.Id = resource.PhysicalResourceId; httpApi.Type = "HttpApi"; apiName = resource.LogicalResourceId; try { var HttpApiSecureAuthType = (string)jTemplateObjProcessed["Resources"][apiName]["Properties"]["Body"]["components"]["securitySchemes"]["OpenIdAuthorizer"]["type"]; if (HttpApiSecureAuthType.Equals("oauth2")) { httpApi.SecurityLevel = AwsSettings.SecurityLevel.JWT; } else { httpApi.SecurityLevel = AwsSettings.SecurityLevel.None; } } catch { httpApi.SecurityLevel = AwsSettings.SecurityLevel.None; } httpApi.Stage = (string)jTemplateObjOriginal["Resources"][apiName]["Properties"]["StageName"]; break; case "AWS::ApiGateway::RestApi": var restApi = new AwsSettings.Api(); apiGateways.Add(resource.LogicalResourceId, restApi); restApi.Id = resource.PhysicalResourceId; restApi.Type = "Api"; apiName = resource.LogicalResourceId; try { var apiAuthSecurityType = (string)jTemplateObjProcessed["Resources"][apiName]["Properties"]["Body"]["securityDefinitions"]["AWS_IAM"]["x-amazon-apigateway-authtype"]; if (apiAuthSecurityType.Equals("awsSigv4")) { restApi.SecurityLevel = AwsSettings.SecurityLevel.AwsSignatureVersion4; } else { restApi.SecurityLevel = AwsSettings.SecurityLevel.None; } } catch { restApi.SecurityLevel = AwsSettings.SecurityLevel.None; } restApi.Stage = (string)jTemplateObjOriginal["Resources"][apiName]["Properties"]["StageName"]; break; } } } while (nextToken != null); if (resourceCount == 0) { throw new Exception($"Error: No resources found for specified stack."); } return(awsSettings); }
public static async Task <string> GenerateMethodMapJsonAsync( string profileName, string stackName) { if (string.IsNullOrEmpty(profileName)) { throw new Exception($"Error: No ProfileName provided"); } if (string.IsNullOrEmpty(stackName)) { throw new Exception($"Error: No StackName provided"); } var sharedCredentialsFile = new SharedCredentialsFile(); // AWS finds the shared credentials store for us CredentialProfile profile = null; if (!sharedCredentialsFile.TryGetProfile(profileName, out profile)) { throw new Exception($"Error: Aws Profile \"{profileName}\" not found in shared credentials store."); } AWSCredentials creds = null; if (!AWSCredentialsFactory.TryGetAWSCredentials(profile, sharedCredentialsFile, out creds)) { throw new Exception($"Error: Could not get AWS Credentials using specified profile \"{profileName}\"."); } var awsSettings = new AwsSettings(); if (!awsSettings.ContainsKey("StackName")) { awsSettings.Add("StackName", stackName); } else { awsSettings["StackName"] = stackName; } // Get Original Template var cfClient = new AmazonCloudFormationClient(creds); var getTemplateRequestOriginal = new GetTemplateRequest() { StackName = stackName, TemplateStage = Amazon.CloudFormation.TemplateStage.Original }; var templateReponse = cfClient.GetTemplateAsync(getTemplateRequestOriginal).GetAwaiter().GetResult(); //var templateBodyIndex = templateReponse.StagesAvailable.IndexOf("Original"); var templateBody = templateReponse.TemplateBody; // Original is in yaml form //var tmplYaml = new StringReader(new YamlDotNet.Serialization.SerializerBuilder().Build().Serialize(templateBody)); var tmplYaml = new StringReader(templateBody); var templYamlObj = new YamlDotNet.Serialization.DeserializerBuilder().Build().Deserialize(tmplYaml); templateBody = new YamlDotNet.Serialization.SerializerBuilder().JsonCompatible().Build().Serialize(templYamlObj); var jTemplateObjOriginal = JObject.Parse(templateBody); // Get all Stack Resources string nextToken = null; bool foundResources = false; var methodMap = new Dictionary <string, string>(); do { var listStackResourcesRequest = new ListStackResourcesRequest() { StackName = stackName, NextToken = nextToken }; var listStackResourcesResponse = await cfClient.ListStackResourcesAsync(listStackResourcesRequest); nextToken = listStackResourcesResponse.NextToken; foreach (var resource in listStackResourcesResponse.StackResourceSummaries) { switch (resource.ResourceType) { case "AWS::Lambda::Function": foundResources = true; var funcName = resource.LogicalResourceId; var lambdaEvents = jTemplateObjOriginal["Resources"][funcName]["Properties"]["Events"].Children(); foreach (JToken le in lambdaEvents) { var jObject = new JObject(le); var name = jObject.First.First.Path; var type = jObject[name]["Type"].ToString(); var apiId = string.Empty; if (type.Equals("HttpApi")) { apiId = jObject[name]["Properties"]["ApiId"]["Ref"].ToString(); } else if (type.Equals("Api")) { apiId = jObject[name]["Properties"]["RestApiId"]["Ref"].ToString(); } if (!string.IsNullOrEmpty(apiId)) { methodMap.Add(name + "Async", apiId); } } break; } } } while (nextToken != null); if (!foundResources) { throw new Exception($"Error: No Lambda resources found for specified stack."); } var result = $"{{\"MethodMap\": {Newtonsoft.Json.JsonConvert.SerializeObject(methodMap, Newtonsoft.Json.Formatting.Indented)}}}"; return(result); }