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