猿问

如何在 go 中编写前/后流量钩子函数?

我开始使用 AWS SAM,现在我只有一些单元测试,但我想尝试在预流量挂钩函数中运行集成测试。

不幸的是,似乎没有 Golang 的代码示例,我只能找到 Javascript 的代码示例。


我想从测试一个简单查询 DynamoDB 的 lambda 函数开始。


三国纷争
浏览 121回答 2
2回答

慕斯709654

这样的事情有效:package mainimport (    "context"    "encoding/json"    "github.com/aws/aws-lambda-go/lambda"    "github.com/aws/aws-sdk-go/aws/session"    "github.com/aws/aws-sdk-go/service/codedeploy")type CodeDeployEvent struct {    DeploymentId                  string `json:"deploymentId"`    LifecycleEventHookExecutionId string `json:"lifecycleEventHookExecutionId"`}func HandleRequest(ctx context.Context, event CodeDeployEvent) (string, error) {    // add some tests here and change status flag as needed . . .    client := codedeploy.New(session.New())    params := &codedeploy.PutLifecycleEventHookExecutionStatusInput{        DeploymentId:                  &event.DeploymentId,        LifecycleEventHookExecutionId: &event.LifecycleEventHookExecutionId,        Status:                        "Succeeded",    }    req, _ := client.PutLifecycleEventHookExecutionStatusRequest(params)    _ = req.Send()}

12345678_0001

我开始实施这个并想分享我的完整解决方案。在弄清楚如何使用它之后,我决定不使用它,因为它有几个缺点。无法将新版本的金丝雀公开给用户群的专用部分,这意味着有时他们会使用新版本或旧版本调用发布到 sns 的函数会触发所有下游动作,这可能会获取下游服务的新版本或旧版本,这会在破坏 API 的情况下导致很多问题IAM 更改会立即影响两个版本,可能会破坏旧版本。相反,我将所有内容部署到预生产帐户,运行我的集成和端到端测试,如果它们成功,我将部署到生产创建金丝雀部署的 cdk 代码:const versionAlias = new lambda.Alias(this, 'Alias', {    aliasName: "alias",    version: this.lambda.currentVersion,})const preHook = new lambda.Function(this, 'LambdaPreHook', {    description: "pre hook",    code: lambda.Code.fromAsset('dist/upload/convert-pre-hook'),    handler: 'main',    runtime: lambda.Runtime.GO_1_X,    memorySize: 128,    timeout: cdk.Duration.minutes(1),    environment: {        FUNCTION_NAME: this.lambda.currentVersion.functionName,    },    reservedConcurrentExecutions: 5,    logRetention: RetentionDays.ONE_WEEK,})// this.lambda.grantInvoke(preHook) // this doesn't work, I need to grant invoke to all functions :spreHook.addToRolePolicy(new iam.PolicyStatement({    actions: [        "lambda:InvokeFunction",    ],    resources: ["*"],    effect: iam.Effect.ALLOW,}))const application = new codedeploy.LambdaApplication(this, 'CodeDeployApplication')new codedeploy.LambdaDeploymentGroup(this, 'CanaryDeployment', {    application: application,    alias: versionAlias,    deploymentConfig: codedeploy.LambdaDeploymentConfig.ALL_AT_ONCE,    preHook: preHook,    autoRollback: {        failedDeployment: true,        stoppedDeployment: true,        deploymentInAlarm: false,    },    ignorePollAlarmsFailure: false,    // alarms:    // autoRollback: codedeploy.A    // postHook:})我的pre hook函数的go代码。PutLifecycleEventHookExecutionStatus如果预挂钩成功,则告诉代码部署。不幸的是,如果部署消息失败,您在 cdk 部署输出中获得的消息将毫无用处,因此您需要检查挂钩前/后日志。为了实际运行集成测试,我只需调用 lambda 并检查是否发生错误。package mainimport (    "encoding/base64"    "fmt"    "log"    "os"    "github.com/aws/aws-lambda-go/lambda"    "github.com/aws/aws-sdk-go/aws"    "github.com/aws/aws-sdk-go/aws/session"    "github.com/aws/aws-sdk-go/service/codedeploy"    lambdaService "github.com/aws/aws-sdk-go/service/lambda")var svc *codedeploy.CodeDeployvar lambdaSvc *lambdaService.Lambdatype codeDeployEvent struct {    DeploymentId                  string `json:"deploymentId"`    LifecycleEventHookExecutionId string `json:"lifecycleEventHookExecutionId"`}func handler(e codeDeployEvent) error {    params := &codedeploy.PutLifecycleEventHookExecutionStatusInput{        DeploymentId:                  &e.DeploymentId,        LifecycleEventHookExecutionId: &e.LifecycleEventHookExecutionId,    }    err := handle()    if err != nil {        log.Println(err)        params.Status = aws.String(codedeploy.LifecycleEventStatusFailed)    } else {        params.Status = aws.String(codedeploy.LifecycleEventStatusSucceeded)    }    _, err = svc.PutLifecycleEventHookExecutionStatus(params)    if err != nil {        return fmt.Errorf("failed putting the lifecycle event hook execution status. the status was %s", *params.Status)    }    return nil}func handle() error {    functionName := os.Getenv("FUNCTION_NAME")    if functionName == "" {        return fmt.Errorf("FUNCTION_NAME not set")    }    log.Printf("function name: %s", functionName)    // invoke lambda via sdk    input := &lambdaService.InvokeInput{        FunctionName:   &functionName,        Payload:        nil,        LogType:        aws.String(lambdaService.LogTypeTail),                   // returns the log in the response        InvocationType: aws.String(lambdaService.InvocationTypeRequestResponse), // synchronous - default    }    err := input.Validate()    if err != nil {        return fmt.Errorf("validating the input failed: %v", err)    }    resp, err := lambdaSvc.Invoke(input)    if err != nil {        return fmt.Errorf("failed to invoke lambda: %v", err)    }    decodeString, err := base64.StdEncoding.DecodeString(*resp.LogResult)    if err != nil {        return fmt.Errorf("failed to decode the log: %v", err)    }    log.Printf("log result: %s", decodeString)    if resp.FunctionError != nil {        return fmt.Errorf("lambda was invoked but returned error: %s", *resp.FunctionError)    }    return nil}func main() {    sess, err := session.NewSession()    if err != nil {        return    }    svc = codedeploy.New(sess)    lambdaSvc = lambdaService.New(sess)    lambda.Start(handler)}
随时随地看视频慕课网APP

相关分类

Go
我要回答