Skip to content

Instantly share code, notes, and snippets.

@ApocDev
Created September 6, 2019 15:07
Show Gist options
  • Save ApocDev/11ce0d06ad06a0d63f67bbf184aa388b to your computer and use it in GitHub Desktop.
Save ApocDev/11ce0d06ad06a0d63f67bbf184aa388b to your computer and use it in GitHub Desktop.
using System;
using System.Net.Http;
using System.Threading.Tasks;
using Amazon.Lambda.Core;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace CloudFormationCustomResourceEvents
{
public abstract class CloudFormationCustomResourceFunction<T> where T : CloudFormationResourceProperties
{
public virtual async Task<CloudFormationResponse<T>> FunctionHandler(JToken input, ILambdaContext context)
{
LambdaLogger.Log("Received Event: " + input);
var req = input.ToObject<CloudFormationCustomResourceEventCommon<T>>();
try
{
switch (req.RequestType.ToUpperInvariant())
{
case "CREATE":
return await CloudFormationResponse<T>
.CompleteCloudFormationResponse(
await Create(input.ToObject<CloudFormationCustomResourceCreateEvent<T>>(), context)
.ConfigureAwait(false), req, context).ConfigureAwait(false);
case "UPDATE":
return await CloudFormationResponse<T>
.CompleteCloudFormationResponse(
await Update(input.ToObject<CloudFormationCustomResourceUpdateEvent<T>>(), context)
.ConfigureAwait(false), req, context).ConfigureAwait(false);
case "DELETE":
return await CloudFormationResponse<T>
.CompleteCloudFormationResponse(
await Delete(input.ToObject<CloudFormationCustomResourceDeleteEvent<T>>(), context)
.ConfigureAwait(false), req, context).ConfigureAwait(false);
default:
// Some unknown request type was sent
throw new ArgumentOutOfRangeException(nameof(req.RequestType),
"RequestType is invalid. Received: " + req.RequestType);
}
}
catch (Exception ex)
{
return await CloudFormationResponse<T>.CompleteCloudFormationResponse(ex, req, context);
}
}
protected abstract Task<object> Create(CloudFormationCustomResourceCreateEvent<T> evt, ILambdaContext context);
protected abstract Task<object> Update(CloudFormationCustomResourceUpdateEvent<T> evt, ILambdaContext context);
protected abstract Task<object> Delete(CloudFormationCustomResourceDeleteEvent<T> evt, ILambdaContext context);
}
public class CloudFormationResourceProperties
{
public string ServiceToken { get; set; }
}
public class CloudFormationCustomResourceCreateEvent<T> : CloudFormationCustomResourceEventCommon<T>
where T : CloudFormationResourceProperties
{
}
public class CloudFormationCustomResourceUpdateEvent<T> : CloudFormationCustomResourceEventCommon<T>
where T : CloudFormationResourceProperties
{
public string PhysicalResourceId { get; set; }
public T OldResourceProperties { get; set; }
}
public class CloudFormationCustomResourceDeleteEvent<T> : CloudFormationCustomResourceEventCommon<T>
where T : CloudFormationResourceProperties
{
public string PhysicalResourceId { get; set; }
}
public class CloudFormationCustomResourceEventCommon<T> where T : CloudFormationResourceProperties
{
public string StackId { get; set; }
public string ResponseURL { get; set; }
public string RequestType { get; set; }
public string ResourceType { get; set; }
public string RequestId { get; set; }
public string LogicalResourceId { get; set; }
public T ResourceProperties { get; set; }
}
public class CloudFormationResponse<T> where T : CloudFormationResourceProperties
{
public string Status { get; set; }
public string Reason { get; set; }
public string PhysicalResourceId { get; set; }
public string StackId { get; set; }
public string RequestId { get; set; }
public string LogicalResourceId { get; set; }
public object Data { get; set; }
public static async Task<CloudFormationResponse<T>> CompleteCloudFormationResponse(object data,
CloudFormationCustomResourceEventCommon<T> request, ILambdaContext context)
{
var responseBody = new CloudFormationResponse<T>
{
Status = data is Exception ? "FAILED" : "SUCCESS",
Reason = "See the details in CloudWatch Log Stream: " + context.LogStreamName,
PhysicalResourceId = context.LogStreamName,
StackId = request.StackId,
RequestId = request.RequestId,
LogicalResourceId = request.LogicalResourceId,
Data = data
};
try
{
using (var client = new HttpClient())
{
var jsonContent = new StringContent(JsonConvert.SerializeObject(responseBody));
jsonContent.Headers.Remove("Content-Type");
var postResponse = await client.PutAsync(request.ResponseURL, jsonContent);
postResponse.EnsureSuccessStatusCode();
}
}
catch (Exception ex)
{
LambdaLogger.Log("Exception: " + ex);
responseBody.Status = "FAILED";
responseBody.Data = ex;
}
return responseBody;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment