github.com/mweagle/Sparta@v1.15.0/docs_source/content/reference/application/custom_resources.md (about) 1 --- 2 date: 2016-03-09T19:56:50+01:00 3 title: Custom Resources 4 weight: 150 5 --- 6 7 In some circumstances your service may need to provision or access resources that fall outside the standard workflow. In this case you can use [CloudFormation Lambda-backed CustomResources](http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/template-custom-resources-lambda.html) to create or access resources during your CloudFormation stack's lifecycle. 8 9 Sparta provides unchecked access to the CloudFormation resource lifecycle via the [RequireCustomResource](https://godoc.org/github.com/mweagle/Sparta#LambdaAWSInfo.RequireCustomResource) function. This function registers an AWS Lambda Function as an CloudFormation custom resource [lifecycle](http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/crpg-ref-requesttypes.html). 10 11 In this section we'll walk through a sample user-defined custom resource and discuss how a custom resource's outputs can be propagated to an application-level Sparta lambda function. 12 13 ## Components 14 15 Defining a custom resource is a two stage process, depending on whether your application-level lambda function requires access to the custom resource outputs: 16 17 1. The user-defined AWS Lambda Function 18 - This function defines your resource's logic. The multiple return value is `map[string]interface{}, error` which signify resource results and operation error, respectively. 19 1. The `LambdaAWSInfo` struct which declares a dependency on your custom resource via the [RequireCustomResource](https://godoc.org/github.com/mweagle/Sparta#LambdaAWSInfo.RequireCustomResource) member function. 20 1. *Optional* - A call to _github.com/mweagle/Sparta/aws/cloudformation/resources.SendCloudFormationResponse_ to signal CloudFormation creation status. 21 1. *Optional* - The template decorator that binds your CustomResource's [data results](http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/crpg-ref-responses.html) to the owning `LambdaAWSInfo` caller. 22 1. *Optional* - A call from your standard Lambda's function body to discover the CustomResource outputs via `sparta.Discover()`. 23 24 ### Custom Resource Functioon 25 26 A Custom Resource Function is a standard AWS Lambda Go function type that 27 accepts a `CloudFormationLambdaEvent` input type. This type holds all information 28 for the requested [operation](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/template-custom-resources-lambda.html). 29 30 The multiple return values denote success with non-empty results, or an error. 31 32 As an example, we'll use the following custom resource function: 33 34 ```go 35 import ( 36 awsLambdaCtx "github.com/aws/aws-lambda-go/lambdacontext" 37 spartaCFResources "github.com/mweagle/Sparta/aws/cloudformation/resources" 38 ) 39 40 // User defined λ-backed CloudFormation CustomResource 41 func userDefinedCustomResource(ctx context.Context, 42 event spartaCFResources.CloudFormationLambdaEvent) (map[string]interface{}, error) { 43 44 logger, _ := ctx.Value(ContextKeyLogger).(*logrus.Logger) 45 lambdaCtx, _ := awsLambdaCtx.FromContext(ctx) 46 47 var opResults = map[string]interface{}{ 48 "CustomResourceResult": "Victory!", 49 } 50 51 opErr := spartaCFResources.SendCloudFormationResponse(lambdaCtx, 52 &event, 53 opResults, 54 nil, 55 logger) 56 return opResults, opErr 57 } 58 ``` 59 60 61 This function always succeeds and publishes a non-empty map consisting of a single key (`CustomResourceResult`) 62 to CloudFormation. This value can be accessed by other CloudFormation resources. 63 64 ### RequireCustomResource 65 66 The next step is to associate this custom resource function with a previously created Sparta `LambdaAWSInfo` instance via [RequireCustomResource](https://godoc.org/github.com/mweagle/Sparta#LambdaAWSInfo.RequireCustomResource). This function accepts: 67 68 * `roleNameOrIAMRoleDefinition`: The IAM role name or definition under which the custom resource function should be executed. Equivalent to the same argument in [NewAWSLambda](https://godoc.org/github.com/mweagle/Sparta#NewAWSLambda). 69 * `userFunc`: Custom resource function handler 70 * `lambdaOptions`: Lambda execution options. Equivalent to the same argument in [NewAWSLambda](https://godoc.org/github.com/mweagle/Sparta#NewAWSLambda). 71 * `resourceProps`: Arbitrary, optional properties that will be provided to the `userFunc` during execution. 72 73 The multiple return values denote the logical, stable CloudFormation resource ID of the new custom resource, or an error if one occurred. 74 75 For example, our custom resource function above can be associated via: 76 77 ```go 78 // Standard AWS λ function 79 func helloWorld(ctx context.Context) (string, error) { 80 return "Hello World", nil 81 } 82 83 func ExampleLambdaAWSInfo_RequireCustomResource() { 84 lambdaFn, _ := sparta.NewAWSLambda(sparta.LambdaName(helloWorld), 85 helloWorld, 86 sparta.IAMRoleDefinition{}) 87 88 cfResName, _ := lambdaFn.RequireCustomResource(IAMRoleDefinition{}, 89 userDefinedCustomResource, 90 nil, 91 nil) 92 } 93 ``` 94 95 96 Since our custom resource function doesn't require any additional AWS resources, we provide an empty [IAMRoleDefinition](https://godoc.org/github.com/mweagle/Sparta#IAMRoleDefinition). 97 98 These two steps are sufficient to include your custom resource function in the CloudFormation stack lifecycle. 99 100 It's possible to share state from the custom resource to a standard Sparta lambda function by annotating your Sparta lambda function's metadata and then discovering it at execution time. 101 102 ### Optional - Template Decorator 103 104 To link these resources together, the first step is to include a [TemplateDecorator](https://godoc.org/github.com/mweagle/Sparta#TemplateDecorator) that annotates your Sparta lambda function's CloudFormation resource metadata. This function specifies which user defined output keys (`CustomResourceResult` in this example) you wish to make available during your lambda function's execution. 105 106 ```go 107 lambdaFn.Decorator = func(serviceName string, 108 lambdaResourceName string, 109 lambdaResource gocf.LambdaFunction, 110 resourceMetadata map[string]interface{}, 111 S3Bucket string, 112 S3Key string, 113 buildID string, 114 cfTemplate *gocf.Template, 115 context map[string]interface{}, 116 logger *logrus.Logger) error { 117 118 // Pass CustomResource outputs to the λ function 119 resourceMetadata["CustomResource"] = gocf.GetAtt(cfResName, "CustomResourceResult") 120 return nil 121 } 122 ``` 123 124 125 The `cfResName` value is the CloudFormation resource name returned by `RequireCustomResource`. The template decorator specifies which of your [CustomResourceFunction](https://godoc.org/github.com/mweagle/Sparta#CustomResourceFunction) outputs should be discoverable during the paren't lambda functions execution time through a [go-cloudformation](https://godoc.org/github.com/crewjam/go-cloudformation#GetAtt) version of [Fn::GetAtt](http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference-getatt.html). 126 127 ### Optional - Discovery 128 129 Discovery is handled by [sparta.Discover()](https://godoc.org/github.com/mweagle/Sparta#Discover) which returns a [DiscoveryInfo](https://godoc.org/github.com/mweagle/Sparta#DiscoveryInfo) instance pointer containing the linked Custom Resource outputs. The calling Sparta lambda function can discover its own [DiscoveryResource](https://godoc.org/github.com/mweagle/Sparta#DiscoveryResource) keyname via the top-level `ResourceID` field. Once found, the calling function then looks up the linked custom resource output via the `Properties` field using the keyname (`CustomResource`) provided in the previous template decorator. 130 131 In this example, the unmarshalled _DiscoveryInfo_ struct looks like: 132 133 ```json 134 { 135 "Discovery": { 136 "ResourceID": "mainhelloWorldLambda837e49c53be175a0f75018a148ab6cd22841cbfb", 137 "Region": "us-west-2", 138 "StackID": "arn:aws:cloudformation:us-west-2:123412341234:stack/SpartaHelloWorld/70b28170-13f9-11e6-b0c7-50d5ca11b8d2", 139 "StackName": "SpartaHelloWorld", 140 "Resources": { 141 "mainhelloWorldLambda837e49c53be175a0f75018a148ab6cd22841cbfb": { 142 "ResourceID": "mainhelloWorldLambda837e49c53be175a0f75018a148ab6cd22841cbfb", 143 "Properties": { 144 "CustomResource": "Victory!" 145 }, 146 "Tags": {} 147 } 148 } 149 }, 150 "level": "info", 151 "msg": "Custom resource request", 152 "time": "2016-05-07T14:13:37Z" 153 } 154 ``` 155 156 To lookup the output, the calling function might do something like: 157 158 ```go 159 configuration, _ := sparta.Discover() 160 customResult := configuration.Resources[configuration.ResourceID].Properties["CustomResourceResult"] 161 ``` 162 163 ## Wrapping Up 164 165 CloudFormation Custom Resources are a powerful tool that can help pre-existing applications migrate to a Sparta application. 166 167 # Notes 168 * Sparta uses [Lambda-backed CustomResource](http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/template-custom-resources-lambda.html) functions, so they are subject to the same [Lambda limits](http://docs.aws.amazon.com/lambda/latest/dg/limits.html) as application-level Sparta lambda functions. 169 * Returning an error from the CustomResourceFunction will result in a _FAILED_ reason being returned in the CloudFormation [response object](http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/crpg-ref-responses.html). 170