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