github.com/mweagle/Sparta@v1.15.0/docs_source/content/reference/application/custom_lambda_resources.md (about) 1 --- 2 date: 2016-03-09T19:56:50+01:00 3 title: CloudFormation Resources 4 weight: 150 5 --- 6 7 In addition to per-lambda [custom resources](/reference/custom_resources/), a service may benefit from the ability to 8 include a service-scoped [Lambda backed CustomResource](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/template-custom-resources-lambda.html). 9 10 Including a custom service scoped resource is a multi-step process. The code excerpts below are from the [SpartaCustomResource](https://github.com/mweagle/SpartaCustomResource) sample application. 11 12 ## 1. Resource Type 13 14 The first step is to define a custom [CloudFormation Resource Type](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/template-custom-resources.html) 15 16 ```go 17 18 //////////////////////////////////////////////////////////////////////////////// 19 // 1 - Define the custom type 20 const spartaHelloWorldResourceType = "Custom::sparta::HelloWorldResource" 21 ``` 22 23 ## 2. Request Parameters 24 25 The next step is to define the parameters that are supplied to the custom resource 26 invocation. This is done via a `struct` that will be later embedded into the 27 [CustomResourceCommand](https://godoc.org/github.com/mweagle/Sparta/aws/cloudformation/resources#CustomResourceCommand). 28 29 ```go 30 // SpartaCustomResourceRequest is what the UserProperties 31 // should be set to in the CustomResource invocation 32 type SpartaCustomResourceRequest struct { 33 Message *gocf.StringExpr 34 } 35 ``` 36 37 ## 3. Command Handler 38 39 With the parameters defined, define the 40 [CustomResourceCommand](https://godoc.org/github.com/mweagle/Sparta/aws/cloudformation/resources#CustomResourceCommand) 41 that is responsible for performing the external operations based on the specified request 42 parameters. 43 44 ```go 45 // SpartaHelloWorldResource is a simple POC showing how to create custom resources 46 type SpartaHelloWorldResource struct { 47 gocf.CloudFormationCustomResource 48 SpartaCustomResourceRequest 49 } 50 51 // Create implements resource create 52 func (command SpartaHelloWorldResource) Create(awsSession *session.Session, 53 event *spartaAWSResource.CloudFormationLambdaEvent, 54 logger *logrus.Logger) (map[string]interface{}, error) { 55 56 requestPropsErr := json.Unmarshal(event.ResourceProperties, &command) 57 if requestPropsErr != nil { 58 return nil, requestPropsErr 59 } 60 logger.Info("create: ", command.Message.Literal) 61 return map[string]interface{}{ 62 "Resource": "Created message: " + command.Message.Literal, 63 }, nil 64 } 65 66 // Update implements resource update 67 func (command SpartaHelloWorldResource) Update(awsSession *session.Session, 68 event *spartaAWSResource.CloudFormationLambdaEvent, 69 logger *logrus.Logger) (map[string]interface{}, error) { 70 return "", nil 71 } 72 73 // Delete implements resource delete 74 func (command SpartaHelloWorldResource) Delete(awsSession *session.Session, 75 event *spartaAWSResource.CloudFormationLambdaEvent, 76 logger *logrus.Logger) (map[string]interface{}, error) { 77 return "", nil 78 } 79 ``` 80 81 ## 4. Register Type Provider 82 83 To make the new type available to Sparta's internal CloudFormation template 84 marshalling, register the new type via [go-cloudformation.RegisterCustomResourceProvider](https://godoc.org/github.com/mweagle/go-cloudformation#RegisterCustomResourceProvider): 85 86 ```go 87 func init() { 88 customResourceFactory := func(resourceType string) gocf.ResourceProperties { 89 switch resourceType { 90 case spartaHelloWorldResourceType: 91 return &SpartaHelloWorldResource{} 92 } 93 return nil 94 } 95 gocf.RegisterCustomResourceProvider(customResourceFactory) 96 } 97 ``` 98 99 ## 5. Annotate Template 100 101 The final step is to ensure the custom resource command is included in the Sparta 102 binary that defines your service and then create an invocation of that command. The 103 annotation is expressed as a [ServiceDecoratorHookHandler](https://godoc.org/github.com/mweagle/Sparta#ServiceDecoratorHookHandler) 104 that performs both operations as part of the general service build 105 lifecycle... 106 107 ```go 108 func customResourceHooks() *sparta.WorkflowHooks { 109 // Add the custom resource decorator 110 customResourceDecorator := func(context map[string]interface{}, 111 serviceName string, 112 template *gocf.Template, 113 S3Bucket string, 114 S3Key string, 115 buildID string, 116 awsSession *session.Session, 117 noop bool, 118 logger *logrus.Logger) error { 119 120 // 1. Ensure the Lambda Function is registered 121 customResourceName, customResourceNameErr := sparta.EnsureCustomResourceHandler(serviceName, 122 spartaHelloWorldResourceType, 123 nil, // This custom action doesn't need to access other AWS resources 124 []string{}, 125 template, 126 S3Bucket, 127 S3Key, 128 logger) 129 130 if customResourceNameErr != nil { 131 return customResourceNameErr 132 } 133 134 // 2. Create the request for the invocation of the lambda resource with 135 // parameters 136 spartaCustomResource := &SpartaHelloWorldResource{} 137 spartaCustomResource.ServiceToken = gocf.GetAtt(customResourceName, "Arn") 138 spartaCustomResource.Message = gocf.String("Custom resource activated!") 139 140 resourceInvokerName := sparta.CloudFormationResourceName("SpartaCustomResource", 141 fmt.Sprintf("%v", S3Bucket), 142 fmt.Sprintf("%v", S3Key)) 143 144 // Add it 145 template.AddResource(resourceInvokerName, spartaCustomResource) 146 return nil 147 } 148 // Add the decorator to the template 149 hooks := &sparta.WorkflowHooks{} 150 hooks.ServiceDecorators = []sparta.ServiceDecoratorHookHandler{ 151 sparta.ServiceDecoratorHookFunc(customResourceDecorator), 152 } 153 return hooks 154 } 155 ``` 156 157 Provide the hooks structure to [MainEx](https://godoc.org/github.com/mweagle/Sparta#MainEx) to 158 include this custom resource with your service's provisioning lifecycle. 159