Provides infrastructure layer compute capabilities, including both bare metal and virtual servers with various optimizations includins compute, memory, IO, and disk. Also supports accelerations options such as GPUs, FPGAs, Inferentia and Trainium.
Provides image recognition capability for images (in batch or real-time) and video that provides a analysis of the content such as real-world objects, faces, celebrities, and path mapping.
Provides a publish/subscribe notification service with multiple subscription types including Amazon Simple Queue Service (SQS), Amazon Kinesis Data Firehose, AWS Lambda, generic HTTPS endpoints, SMS and email.
A serverless, fully-managed, message queue service that supports producing, store, and consuming messages and enables loose coupling between applications.
Provides private networking capability spanning multiple availability zones and supporting subnets, routing, network access control groups, security groups and gateways.
Provides tracing of service invocations in distributed applications for observability, allowing users to diagnose issues or optimize their service interactions.
All about Cloud, mostly about Amazon Web Services (AWS)
Building CloudFormation Custom Resources in Go
2018-01-20 / 1343 words / 7 minutes
Recently Amazon announced support for the Go programming language (also known as GoLang) in AWS Lambda. Go is unusual amongst modern languages (such as Java, C#, or JavaScript) because it isn’t interpreted or compiled into bytecode that runs within a container (like the .Net Runtime or Java Virtual Machine). Instead, Go compiles into executable machine code. This avoids the startup cost of Java and runs much faster than Python or Node.js. So, how do we go about Building AWS CloudFormation Custom Resources in Go? This post explains it.
Building CloudFormation Custom Resources in Go
There are basically two phases:
First we’ll install the Go based Lambda function, and then,
We’ll upload and execute the CloudFormation template.
Since Custom Resources in CloudFormation is quite an advanced topic, some aspects of this tutorial will be very high level. In particular, creating Lambda functions in general, creating IAM roles, and working with CloudFormation.
Installing a Go based Lambda Function
Installing Go is quite simple. Navigate to https://golang.org/dl/ and follow the instructions there. By default, Go likes a directory called “go” in the home directory, (we’re all about taking the defaults), so create a directory in your home directory called “go”. Next, we need to install some additional packages:
$ go get github.com/aws/aws-lambda-go/lambda
$ go get github.com/google/uuid
$ go get github.com/aws/aws-lambda-go/lambda
$ go get github.com/google/uuid
Then, copy the Go program listed below into that directory:
packagemainimport (
"bytes""encoding/json""fmt""io/ioutil""log""net/http""github.com/aws/aws-lambda-go/lambda""github.com/google/uuid")
typeRequeststruct {
RequestTypestring`json:"RequestType"`/*
The request type is set by the AWS CloudFormation stack operation (create-stack, update-stack, or delete-stack) that was initiated by the template developer for the stack that contains the custom resource.
Must be one of: Create, Update, or Delete. For more information, see Custom Resource Request Types.
Required: Yes
Type: String
*/ResponseURLstring`json:"ResponseURL"`/*
The response URL identifies a presigned S3 bucket that receives responses from the custom resource provider to AWS CloudFormation.
Required: Yes
Type: String
*/StackIdstring`json:"StackId"`/*
The Amazon Resource Name (ARN) that identifies the stack that contains the custom resource.
Combining the StackId with the RequestId forms a value that you can use to uniquely identify a request on a particular custom resource.
Required: Yes
Type: String
*/RequestIdstring`json:"RequestId"`/*
A unique ID for the request.
Combining the StackId with the RequestId forms a value that you can use to uniquely identify a request on a particular custom resource.
Required: Yes
Type: String
*/ResourceTypestring`json:"ResourceType"`/*
The template developer-chosen resource type of the custom resource in the AWS CloudFormation template. Custom resource type names can be up to 60 characters long and can include alphanumeric and the following characters: _@-.
Required: Yes
Type: String
*/LogicalResourceIdstring`json:"LogicalResourceId"`/*
The template developer-chosen name (logical ID) of the custom resource in the AWS CloudFormation template. This is provided to facilitate communication between the custom resource provider and the template developer.
Required: Yes
Type: String
*/PhysicalResourceIdstring`json:"PhysicalResourceId"`/*
A required custom resource provider-defined physical ID that is unique for that provider.
Required: Always sent with Update and Delete requests; never sent with Create.
Type: String
*//*
ResourceProperties string `json:"ResourceProperties"`
This field contains the contents of the Properties object sent by the template developer. Its contents are defined by the custom resource provider.
Required: No
Type: JSON object
*//*
OldResourceProperties object `json:"OldResourceProperties"`
Used only for Update requests. Contains the resource properties that were declared previous to the update request.
Required: Yes
Type: JSON object
*/}
typeResponsestruct {
StackIdstring`json:"StackId"`RequestIdstring`json:"RequestId"`LogicalResourceIdstring`json:"LogicalResourceId"`PhysicalResourceIdstring`json:"PhysicalResourceId"`Statusstring`json:"Status"`Reasonstring`json:"Reason"`Datastruct {
Valuestring`json:"Value"` }
}
funcHandler(requestRequest) {
log.Println("Go Lambda: ", request)
varresponseResponseresponse = buildResponse(request, "SUCCESS", "", "Hello, from Go!")
log.Println(" created response: ", response)
doPut(request.ResponseURL, response)
log.Println(" sent message to "+request.ResponseURL)
}
funcdoPut(urlstring, responseResponse) {
client:=&http.Client{}
byteData, _:=json.MarshalIndent(response, "", " ")
jsonData:=bytes.NewReader(byteData)
fmt.Println(" Writing JSON: "+ string(byteData))
request, _:=http.NewRequest("PUT", url, jsonData)
request.ContentLength = int64(len(string(byteData)))
responseData, err:=client.Do(request)
iferr!=nil {
log.Fatal("Failed to PUT: ", err)
} else {
deferresponseData.Body.Close()
contents, err:=ioutil.ReadAll(responseData.Body)
iferr!=nil {
log.Fatal("Response Error: ", err)
}
fmt.Println(" Status: ", responseData.StatusCode)
hdr:=responseData.Headerforkey, value:=rangehdr {
fmt.Println(" Header: ", key, ":", value)
}
fmt.Println(" Response: ", contents)
}
}
funcbuildResponse(requestRequest, statusstring, reasonstring, valuestring) Response {
varresponseResponseresponse.StackId = request.StackIdresponse.RequestId = request.RequestIdresponse.LogicalResourceId = request.LogicalResourceIdresponse.PhysicalResourceId = uuid.New().String()
response.Status = statusresponse.Reason = reasonresponse.Data.Value = valuereturnresponse}
funcmain() {
lambda.Start(Handler)
}
The code consists of six main parts:
Request struct. The Request struct represents the incoming request. Details of the format of this data can be found here. There’s a few parts missing from the Go structure because no parameters are passed in this simple example.
Response struct. The Response struct represents the response from the Lambda function. Note that this response isn’t returned to the caller, but instead gets uploaded to Amazon Simple Storage Service (S3) at a location specified in the Request struct.
Handler. The Handler function performs the work. It receives a Request struct as a parameter.
doPut. The doPut function writes the Response struct to the S3 bucket.
buildResponse. The buildResponse func creates a Response struct.
main. The main func registers the Handler function for use with CloudFormation.
We need to compile the source code into an executable. If you’re running this on Linux, it’s easy to build the executable using go build -o main. On my Mac, I need to build a Linux executable. Go makes this really easy:
GOOS=linux go build -o main
Next, we need to create a ZIP file. The command on the Mac is:
zip -v deployment.zip main
Create a new role which should include the AWSLambdaBasicExecutionRole policy.
Finally, we need to upload the code into AWS Lambda. Use the following command and replace with the ARN identifier for the role just created, labelled “Role ARN”.
Outputs:
outval1:
Description: Information about the value
Value:
Fn::GetAtt:
- GoCFCR1
- Value
The must be replaced with your account number.
Create a new (or reuse an existing) Amazon Simple Storage Service (S3) bucket and upload the CloudFormation template to it. Then, create the stack.
If everything worked as expected, the stack should complete successfully, and there should be an output called “Value” set to “Hello, from Go!”. Now, you know how to go about building CloudFormation Custom Resources in Go.
All data and information provided on this site is for informational
purposes only. cloudninja.cloud makes no representations as to accuracy,
completeness, currentness, suitability, or validity of any information
on this site and will not be liable for any errors, omissions, or
delays in this information or any losses, injuries, or damages
arising from its display or use. All information is provided on an
as-is basis.
This is a personal weblog. The opinions expressed here represent my
own and not those of my employer. My opinions may change over time.