Golang中如何在Lambda使用Cfn.response

Golang中如何在Lambda使用Cfn.response 我正在尝试通过使用自定义资源让Lambda函数向AWS内部的CloudFormation部署发送消息。执行流程应该是:

  1. CloudFormation开始部署并执行
  2. Lambda执行任务,然后向CloudFormation发送响应以指示任务已完成
  3. CloudFormation部署剩余资源

我尝试利用以下包来完成这项工作:

GitHub aws/aws-lambda-go

我的代码如下:

package main

import (
	"context"
	"fmt"

	"github.com/aws/aws-lambda-go/cfn"

	"github.com/aws/aws-lambda-go/lambda"
)

// Event 是函数将从cloudformation接收的结构体
// 其结构应模仿附带事件(sampleevent.json)的结构
type Event struct {
	StackID            string `json:"StackId"`
	ResponseURL        string `json:"ResponseURL"`
	ResourceProperties struct {
		SourceBucket string   `json:"SourceBucket"`
		SourcePrefix string   `json:"SourcePrefix"`
		Bucket       string   `json:"Bucket"`
		List         []string `json:"List"`
	} `json:"ResourceProperties"`
	RequestType       string `json:"RequestType"`
	ResourceType      string `json:"ResourceType"`
	RequestID         string `json:"RequestId"`
	LogicalResourceID string `json:"LogicalResourceId"`
}

func handler(ctx context.Context, event Event) {

	r := cfn.NewResponse(&cfn.Event{
		RequestID:         event.RequestID,
		ResponseURL:       event.ResponseURL,
		LogicalResourceID: event.LogicalResourceID,
		StackID:           event.StackID,
	})

	const StatusSuccess cfn.StatusType = "SUCCESS"

	er := r.Send
	if er != nil {
		fmt.Println(er)
	}

}

func main() {
	lambda.Start(handler)
}

事件JSON如下:

{
    "StackId": "arn:aws:cloudformation:us-west-2:EXAMPLE/stack-name/guid",
    "ResponseURL": "http://pre-signed-S3-url-for-response",
    "ResourceProperties": {
      "SourceBucket": "iamyourfather22",
      "SourcePrefix": "WebApplication/1_StaticWebHosting",
      "Bucket": "wildrydes-ap-southeast-2",
      "List": [
        "1",
        "2",
        "3"
      ]
    },
    "RequestType": "Create",
    "ResourceType": "Custom::TestResource",
    "RequestId": "unique id for this create request",
    "LogicalResourceId": "MyTestResource"
  }

当.send运行时,我可以看到它获取了正确的URL,但一直缺少成功消息。当Lambda执行时,它会记录无效的响应对象“”不是有效的ResponseStatus。

如何将ResponseStatus注入到接收器类型中,以便它随.send方法一起发送?

如果术语使用有误,我表示歉意,我学习GO才一个月。很喜欢它,但学习曲线确实很陡峭。


更多关于Golang中如何在Lambda使用Cfn.response的实战教程也可以访问 https://www.itying.com/category-94-b0.html

3 回复

您的处理程序签名不正确。应该是以下之一:

  • func ()
  • func () error
  • func (TIn) error
  • func () (TOut, error)
  • func (context.Context) error
  • func (context.Context, TIn) error
  • func (context.Context) (TOut, error)
  • func (context.Context, TIn) (TOut, error)

参见:https://docs.aws.amazon.com/lambda/latest/dg/go-programming-model-handler-types.html

更多关于Golang中如何在Lambda使用Cfn.response的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


感谢您的帮助。通过将我的处理程序设置为以下内容,成功使其工作:

func handler(ctx context.Context, event cfn.Event)

忘记了Todd McLeod的第一课:Go语言的核心就是类型。我引用了错误的事件类型,这让我陷入了困惑。

谢谢, Steve

在您的代码中,问题在于没有正确设置响应状态和响应数据。cfn.NewResponse 创建了一个响应对象,但您需要调用其方法来设置状态和数据,然后发送响应。

以下是修正后的代码:

package main

import (
	"context"
	"fmt"

	"github.com/aws/aws-lambda-go/cfn"
	"github.com/aws/aws-lambda-go/lambda"
)

type Event struct {
	StackID            string `json:"StackId"`
	ResponseURL        string `json:"ResponseURL"`
	ResourceProperties struct {
		SourceBucket string   `json:"SourceBucket"`
		SourcePrefix string   `json:"SourcePrefix"`
		Bucket       string   `json:"Bucket"`
		List         []string `json:"List"`
	} `json:"ResourceProperties"`
	RequestType       string `json:"RequestType"`
	ResourceType      string `json:"ResourceType"`
	RequestID         string `json:"RequestId"`
	LogicalResourceID string `json:"LogicalResourceId"`
}

func handler(ctx context.Context, event Event) {
	// 创建响应对象
	response := cfn.NewResponse(&cfn.Event{
		RequestID:         event.RequestID,
		ResponseURL:       event.ResponseURL,
		LogicalResourceID: event.LogicalResourceID,
		StackID:           event.StackID,
	})

	// 设置响应状态为SUCCESS
	response.Status = cfn.StatusSuccess
	
	// 设置响应数据(可选)
	response.Data = map[string]interface{}{
		"Message": "Custom resource operation completed successfully",
	}

	// 发送响应
	if err := response.Send(); err != nil {
		fmt.Printf("Error sending response: %v\n", err)
		return
	}

	fmt.Println("Successfully sent response to CloudFormation")
}

func main() {
	lambda.Start(handler)
}

关键修改点:

  1. 直接设置 response.Status = cfn.StatusSuccess 来指定成功状态
  2. 可选地设置 response.Data 来包含返回给CloudFormation的数据
  3. 调用 response.Send() 而不是将方法赋值给变量

如果您需要处理不同的请求类型(Create/Update/Delete),可以这样扩展:

func handler(ctx context.Context, event Event) {
	response := cfn.NewResponse(&cfn.Event{
		RequestID:         event.RequestID,
		ResponseURL:       event.ResponseURL,
		LogicalResourceID: event.LogicalResourceID,
		StackID:           event.StackID,
	})

	// 根据请求类型处理逻辑
	switch event.RequestType {
	case "Create":
		fmt.Println("Handling Create request")
		// 执行创建逻辑
		response.Status = cfn.StatusSuccess
		response.Data = map[string]interface{}{
			"Message": "Resource created successfully",
		}
	case "Update":
		fmt.Println("Handling Update request")
		// 执行更新逻辑
		response.Status = cfn.StatusSuccess
		response.Data = map[string]interface{}{
			"Message": "Resource updated successfully",
		}
	case "Delete":
		fmt.Println("Handling Delete request")
		// 执行删除逻辑
		response.Status = cfn.StatusSuccess
		response.Data = map[string]interface{}{
			"Message": "Resource deleted successfully",
		}
	default:
		response.Status = cfn.StatusFailed
		response.Reason = fmt.Sprintf("Unknown request type: %s", event.RequestType)
	}

	if err := response.Send(); err != nil {
		fmt.Printf("Error sending response: %v\n", err)
	}
}

这样设置后,Lambda函数将能够正确地向CloudFormation发送包含成功状态的响应。

回到顶部