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.