github.com/mweagle/Sparta@v1.15.0/docs_source/content/reference/discovery.md (about)

     1  ---
     2  date: 2016-03-09T19:56:50+01:00
     3  title: Discovery Service
     4  weight: 150
     5  ---
     6  
     7  The ability to provision [dynamic infrastructure](/reference/dynamic_infrastructure) (see also the [SES Event Source Example](/reference/eventsources/ses/#dynamic-resources:d680e8a854a7cbad6d490c445cba2eba)) as part of a Sparta application creates a need to discover those resources at lambda execution time.
     8  
     9  Sparta exposes this functionality via [sparta.Discover](https://godoc.org/github.com/mweagle/Sparta#Discover).  This function returns information about the current stack (eg, name, region, ID) as well as metadata about the immediate dependencies of the calling **go** lambda function.
    10  
    11  The following sections walk through provisioning a S3 bucket, declaring an explicit dependency on that resource, and then discovering the resource at lambda execution time.  It is extracted from `appendDynamicS3BucketLambda` in the  [SpartaApplication](https://github.com/mweagle/SpartaApplication/blob/master/application.go) source.
    12  
    13  If you haven't already done so, please review the [Dynamic Infrastructure](/reference/dynamic_infrastructure) section for background on dynamic infrastructure provisioning.
    14  
    15  
    16  # Discovery
    17  
    18  For reference, we provision an S3 bucket and declare an explicit dependency with the code below.  Because our `gocf.S3Bucket{}` struct uses a zero-length [BucketName](http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-s3-bucket.html#cfn-s3-bucket-name) property, CloudFormation will dynamically assign one.
    19  
    20  ```go
    21  
    22  s3BucketResourceName := sparta.CloudFormationResourceName("S3DynamicBucket")
    23  lambdaFn, _ := sparta.NewAWSLambda(sparta.LambdaName(echoS3DynamicBucketEvent),
    24    echoS3DynamicBucketEvent,
    25    sparta.IAMRoleDefinition{})
    26  lambdaFn.Permissions = append(lambdaFn.Permissions, sparta.S3Permission{
    27    BasePermission: sparta.BasePermission{
    28      SourceArn: gocf.Ref(s3BucketResourceName),
    29    },
    30    Events: []string{"s3:ObjectCreated:*", "s3:ObjectRemoved:*"},
    31  })
    32  lambdaFn.DependsOn = append(lambdaFn.DependsOn, s3BucketResourceName)
    33  
    34  // Add permission s.t. the lambda function could read from the S3 bucket
    35  lambdaFn.RoleDefinition.Privileges = append(lambdaFn.RoleDefinition.Privileges,
    36    sparta.IAMRolePrivilege{
    37      Actions:  []string{"s3:GetObject", "s3:HeadObject"},
    38      Resource: spartaCF.S3AllKeysArnForBucket(gocf.Ref(s3BucketResourceName)),
    39    })
    40  
    41  lambdaFn.Decorator = func(serviceName string,
    42    lambdaResourceName string,
    43    lambdaResource gocf.LambdaFunction,
    44    resourceMetadata map[string]interface{},
    45    S3Bucket string,
    46    S3Key string,
    47    buildID string,
    48    template *gocf.Template,
    49    context map[string]interface{},
    50    logger *logrus.Logger) error {
    51    cfResource := template.AddResource(s3BucketResourceName, &gocf.S3Bucket{
    52      AccessControl: gocf.String("PublicRead"),
    53      Tags: &gocf.TagList{gocf.Tag{
    54        Key:   gocf.String("SpecialKey"),
    55        Value: gocf.String("SpecialValue"),
    56      },
    57      },
    58    })
    59    cfResource.DeletionPolicy = "Delete"
    60    return nil
    61  }
    62  ```
    63  
    64  The key to `sparta.Discovery` is the `DependsOn` slice value.
    65  
    66  # Template Marshaling & Decoration
    67  
    68  By default, Sparta uses CloudFormation to update service state.  During template marshaling, Sparta scans for `DependsOn` relationships and propagates information (immediate-children only) across CloudFormation resource definitions.  Most importantly, this information includes `Ref` and any other [outputs](https://github.com/mweagle/Sparta/blob/master/cloudformation_resources.go#L16) of referred resources.  This information then becomes available as a [DisocveryInfo](https://godoc.org/github.com/mweagle/Sparta#DiscoveryInfo) value returned by `sparta.Discovery()`. Behind the scenes, Sparta
    69  
    70  # Sample DiscoveryInfo
    71  
    72  In our example, a `DiscoveryInfo` from a sample stack might be:
    73  
    74  ```json
    75  {
    76      "ResourceID": "mainechoS3DynamicBucketEventLambda41ca034273726cf36154137cbf8d7e5bd45f863a",
    77      "Region": "us-west-2",
    78      "StackID": "arn:aws:cloudformation:us-west-2:123412341234:stack/SpartaApplication-mweagle/d4e07d80-03eb-11e8-b6fd-50d5ca789e4a",
    79      "StackName": "SpartaApplication-mweagle",
    80      "Resources": {
    81          "S3DynamicBucket62b0e7a664dc29c1c4fbe231fbcef30f8463aaa3": {
    82              "ResourceID": "S3DynamicBucket62b0e7a664dc29c1c4fbe231fbcef30f8463aaa3",
    83              "ResourceRef": "spartaapplication-mweagl-s3dynamicbucket62b0e7a66-194zzvtfk757a",
    84              "ResourceType": "AWS::S3::Bucket",
    85              "Properties": {
    86                  "DomainName": "spartaapplication-mweagl-s3dynamicbucket62b0e7a66-194zzvtfk757a.s3.amazonaws.com",
    87                  "WebsiteURL": "http://spartaapplication-mweagl-s3dynamicbucket62b0e7a66-194zzvtfk757a.s3-website-us-west-2.amazonaws.com"
    88              }
    89          }
    90      }
    91  }
    92  ```
    93  
    94  
    95  This JSON data is Base64 encoded and published into the Lambda function's _Environment_ using the `SPARTA_DISCOVERY_INFO` key. The `sparta.Discover()` function is responsible for
    96  accessing the encoded discovery information:
    97  
    98  ```go
    99  configuration, _ := sparta.Discover()
   100  bucketName := ""
   101  for _, eachResource := range configuration.Resources {
   102    if eachResource.ResourceType == "AWS::S3::Bucket" {
   103      bucketName = eachResource.ResourceRef
   104    }
   105  }
   106  ```
   107  
   108  
   109  The `Properties` object includes resource-specific [Fn::GetAtt](http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference-getatt.html) outputs (see each resource type's [documentation](http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-template-resource-type-ref.html) for the complete set)
   110  
   111  # Wrapping Up
   112  
   113  Combined with [dynamic infrastructure](/reference/dynamic_infrastructure), `sparta.Discover()` enables a Sparta service to define its entire AWS infrastructure requirements.  Coupling application logic with infrastructure requirements moves a service towards being completely self-contained and in the direction of [immutable infrastructure](https://fugue.co/oreilly/).
   114  
   115  # Notes
   116    - `sparta.Discovery()` **only** succeeds within a Sparta-compliant lambda function call block.
   117      - Call-site restrictions are validated in the [discovery_tests.go](https://github.com/mweagle/Sparta/blob/master/discovery_test.go) tests.