github.com/mweagle/Sparta@v1.15.0/docs_source/content/reference/decorators/cloudmap.md (about) 1 --- 2 date: 2019-05-27 22:31:25 3 title: CloudMap Service Discovery 4 weight: 10 5 alwaysopen: false 6 --- 7 8 The [CloudMapServiceDecorator](https://godoc.org/github.com/mweagle/Sparta/decorator#CloudMapServiceDecorator) allows your service to register a [service instance](https://docs.aws.amazon.com/cloud-map/latest/dg/working-with-instances.html) for your application. 9 10 For example, an application that provisions a SQS queue and an AWS Lambda function that consumes messages from that queue may need a way for the Lambda function to discover the dynamically provisioned queue. 11 12 Sparta supports an environment-based [discovery service](http://gosparta.io/reference/discovery/) but that discovery is limited to a single Service. 13 14 The `CloudMapServiceDecorator` leverages the [CloudMap](https://aws.amazon.com/cloud-map/) service to support intra- and inter-service resource discovery. 15 16 ## Definition 17 18 The first step is to create an instance of the `CloudMapServiceDecorator` type that can be used to register additional resources. 19 20 ```go 21 import ( 22 spartaDecorators "github.com/mweagle/Sparta/decorator" 23 ) 24 25 func main() { 26 27 ... 28 cloudMapDecorator, cloudMapDecoratorErr := spartaDecorators.NewCloudMapServiceDecorator(gocf.String("SpartaServices"), 29 gocf.String("SpartaSampleCloudMapService")) 30 ... 31 } 32 ``` 33 34 The first argument is the [Cloud Map Namespace ID](https://docs.aws.amazon.com/cloud-map/latest/dg/working-with-namespaces.html) value to which the service (_MyService_) will publish. 35 36 The decorator satisfies the [ServiceDecoratorHookHandler](https://godoc.org/github.com/mweagle/Sparta#ServiceDecoratorHookHandler). The instance should be provided as a `WorkflowHooks.ServiceDecorators` element to `MainEx` as in: 37 38 ```go 39 func main() { 40 // ... 41 cloudMapDecorator, cloudMapDecoratorErr := spartaDecorators.NewCloudMapServiceDecorator(gocf.String("SpartaServices"), 42 gocf.String("SpartaSampleCloudMapService")) 43 44 workflowHooks := &sparta.WorkflowHooks{ 45 ServiceDecorators: []sparta.ServiceDecoratorHookHandler{ 46 cloudMapDecorator, 47 }, 48 } 49 50 // ... 51 err := sparta.MainEx(awsName, 52 "Simple Sparta application that demonstrates core functionality", 53 lambdaFunctions, 54 nil, 55 nil, 56 workflowHooks, 57 false) 58 } 59 ``` 60 61 ## Registering 62 63 The returned `CloudMapServiceDecorator` instance satisfies the [ServiceDecoratorHookHandler](https://godoc.org/github.com/mweagle/Sparta#ServiceDecoratorHookHandler) interface. When invoked, it updates the content of you CloudFormation template with the resources and permissions as described below. `CloudMapServiceDecorator` implicitly creates a new [AWS::ServiceDiscovery::Service](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-servicediscovery-service.html) resource to which your resources will be published. 64 65 ### Lambda Functions 66 67 The `CloudMapServiceDecorator.PublishLambda` function publishes Lambda function information to the _(NamespaceID, ServiceID)_ pair. 68 69 ```go 70 lambdaFn, _ := sparta.NewAWSLambda("Hello World", 71 helloWorld, 72 sparta.IAMRoleDefinition{}) 73 cloudMapDecorator.PublishLambda("lambdaDiscoveryName", lambdaFn, nil) 74 ``` 75 76 The default properties published include the [Lambda Outputs](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-function.html) and Type information: 77 78 ```json 79 { 80 "Id": "CloudMapResbe2b7c536074312c-VuIPjfjuFaoc", 81 "Attributes": { 82 "Arn": "arn:aws:lambda:us-west-2:123412341234:function:MyHelloWorldStack-123412341234_Hello_World", 83 "Name": "lambdaDiscoveryName", 84 "Ref": "MyHelloWorldStack-123412341234_Hello_World", 85 "Type": "AWS::Lambda::Function" 86 } 87 } 88 ``` 89 90 ### Other Resources 91 92 The `CloudMapServiceDecorator.PublishResource` function publishes arbitrary CloudFormation resource outputs information to the _(NamespaceID, ServiceID)_ pair. 93 94 For instance, to publish SQS information in the context of a standard `ServiceDecorator` 95 96 ```go 97 func createSQSResourceDecorator(cloudMapDecorator *spartaDecorators.CloudMapServiceDecorator) sparta.ServiceDecoratorHookHandler { 98 return sparta.ServiceDecoratorHookFunc(func(context map[string]interface{}, 99 serviceName string, 100 template *gocf.Template, 101 S3Bucket string, 102 S3Key string, 103 buildID string, 104 awsSession *session.Session, 105 noop bool, 106 logger *logrus.Logger) error { 107 108 sqsResource := &gocf.SQSQueue{} 109 template.AddResource("SQSResource", sqsResource) 110 return cloudMapDecorator.PublishResource("SQSResource", 111 "SQSResource", 112 sqsResource, 113 nil) 114 }) 115 } 116 ``` 117 118 The default properties published include the [SQS Outputs](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sqs-queues.html) and Type information: 119 120 ```json 121 { 122 "Id": "CloudMapRes21cf275e8bbbe136-CqWZ27gdLHf8", 123 "Attributes": { 124 "Arn": "arn:aws:sqs:us-west-2:123412341234:MyHelloWorldStack-123412341234-SQSResource-S9DWKIFKP14U", 125 "Name": "SQSResource", 126 "QueueName": "MyHelloWorldStack-123412341234-SQSResource-S9DWKIFKP14U", 127 "Ref": "https://sqs.us-west-2.amazonaws.com/123412341234/MyHelloWorldStack-123412341234-SQSResource-S9DWKIFKP14U", 128 "Type": "AWS::SQS::Queue" 129 } 130 } 131 ``` 132 133 ## Enabling 134 135 Publishing instances to CloudMap only makes them available for other services to discover them. Call the `EnableDiscoverySupport` with your `*sparta.LambdaAWSInfo` instance as the only argument. This function updates your Lambda function's environment to include the provisioned _ServiceInstance_ and also the IAM role privileges to authorize: 136 137 * _servicediscovery:DiscoverInstances_ 138 * _servicediscovery:GetNamespace_ 139 * _servicediscovery:ListInstances_ 140 * _servicediscovery:GetService_ 141 142 For instance: 143 144 ```go 145 func main() { 146 // ... 147 148 lambdaFn, _ := sparta.NewAWSLambda("Hello World", 149 helloWorld, 150 sparta.IAMRoleDefinition{}) 151 152 // ... 153 154 cloudMapDecorator.EnableDiscoverySupport(lambdaFn) 155 156 // ... 157 } 158 159 ``` 160 161 ## Invoking 162 163 With the resources published and the lambda role properly updated, the last step is to dynamically discover the provisioned resources via CloudMap. Call `DiscoverInstancesWithContext` with the the set of key-value pairs to use for discovery as below: 164 165 ```go 166 167 func helloWorld(ctx context.Context) (string, error) { 168 // ... 169 170 props := map[string]string{ 171 "Type": "AWS::SQS::Queue", 172 } 173 results, resultsErr := spartaDecorators.DiscoverInstancesWithContext(ctx, 174 props, 175 logger) 176 logger.WithFields(logrus.Fields{ 177 "Instances": results, 178 "Error": resultsErr, 179 }).Info("Discovered instances!") 180 // ... 181 } 182 ``` 183 184 Given the previous example of a single lambda function and an SQS-queue provisioning decorator, the `DiscoverInstancesWithContext` would return the matching instance with data similar to: 185 186 ```json 187 { 188 "Instances": [ 189 { 190 "Attributes": { 191 "Arn": "arn:aws:sqs:us-west-2:123412341234:MyHelloWorldStack-123412341234-SQSResource-S9DWKIFKP14U", 192 "Name": "SQSResource", 193 "QueueName": "MyHelloWorldStack-123412341234-SQSResource-S9DWKIFKP14U", 194 "Ref": "https://sqs.us-west-2.amazonaws.com/123412341234/MyHelloWorldStack-123412341234-SQSResource-S9DWKIFKP14U", 195 "Type": "AWS::SQS::Queue" 196 }, 197 "HealthStatus": "HEALTHY", 198 "InstanceId": "CloudMapResd1a507076543ccd0-Fln1ITi5cf0y", 199 "NamespaceName": "SpartaServices", 200 "ServiceName": "SpartaSampleCloudMapService" 201 } 202 ] 203 } 204 ```