英文:
Logs show that Lambda ran completely, but function exits with exit status 1
问题
这是我的代码:
package main
import (
"context"
"fmt"
"log"
"github.com/aws/aws-sdk-go-v2/config"
"github.com/aws/aws-sdk-go-v2/service/ec2"
"github.com/aws/aws-sdk-go-v2/service/ec2/types"
)
func main() {
// 加载共享的 AWS 配置(~/.aws/config)
cfg, err := config.LoadDefaultConfig(context.TODO())
if err != nil {
log.Fatal(err)
}
// 创建 Amazon EC2 服务客户端
ec2ServiceClient := ec2.NewFromConfig(cfg)
// DescribeAddressesInput 没有过滤器表示列出所有地址
IpListFilter := &ec2.DescribeAddressesInput{}
// 请求 EC2 客户端列出所有弹性 IP
result, err := ec2ServiceClient.DescribeAddresses(context.TODO(), IpListFilter)
if err != nil {
fmt.Println("获取 Amazon 弹性 IP 信息时出错:")
fmt.Println(err)
return
}
// 对于所有的 IP,检查它们是否有分配 ID。如果没有,它们可以被删除
for _, a := range result.Addresses {
fmt.Println("分配 ID:" + *a.AllocationId)
fmt.Println("公共 IP:" + *a.PublicIp)
// 如果此 EIP 没有与任何 AWS 资源关联,继续删除
if a.AssociationId == nil {
// 额外的灵活性步骤
if isThisEIPKillable(a.Tags) {
fmt.Println("即将被删除")
// 释放/删除弹性 IP
ReleaseAddressFilter := &ec2.ReleaseAddressInput{AllocationId: a.AllocationId}
ec2ServiceClient.ReleaseAddress(context.TODO(), ReleaseAddressFilter)
fmt.Println(*a.PublicIp + " 已删除")
} else {
fmt.Println(*a.PublicIp + " 已启用 KILLERHOLD 并将保留")
}
} else {
fmt.Println("关联 ID:" + *a.AssociationId)
fmt.Println("实例 ID:" + *a.InstanceId)
fmt.Println("私有 IP 地址:" + *a.PrivateIpAddress)
}
fmt.Println("")
}
}
// isThisEIPKillable 扫描弹性 IP 的标签,只有当 EIPKILLER 标签设置为 true 时返回 false
func isThisEIPKillable(tags []types.Tag) bool {
for _, tag := range tags {
if *tag.Key == "KILLERHOLD" && *tag.Value == "true" {
return false
}
}
return true
}
Lambda 函数具有运行所需的权限,即允许运行 ec2:ReleaseAddress
和 ec2:DescribeAddresses
。
进行测试时,我有一个与一个 EC2 实例关联的 EIP。根据 Lambda 的逻辑,Lambda 应该只打印输出并在没有任何错误的情况下退出。
但是实际情况是这样的。我已经删除了一些字符串以保护隐私:
START RequestId: 5a7446ed-6896-4e65-b795-35d1bfd6ca60 Version: $LATEST
分配 ID: eipalloc-08fexample952a7f7
公共 IP: XXX.XXX.XXX.XXX
关联 ID: eipassoc-0112e332e17959d76
实例 ID: i-096561051e41c2d60
私有 IP 地址: 10.2.1.38
2022/08/26 14:25:38 <nil>
分配 ID: eipalloc-08fexample952a7f7
公共 IP: XXX.XXX.XXX.XXX
关联 ID: eipassoc-011example959d76
实例 ID: i-09656examplec2d60
私有 IP 地址: 10.2.1.38
2022/08/26 14:25:39 <nil>
END RequestId: 5a7446ed-6896-4e65-b795-3exampleca60
REPORT RequestId: 5a7446ed-6896-4e65-b795-3examplea60 Duration: 402.33 ms Billed Duration: 403 ms Memory Size: 512 MB Max Memory Used: 21 MB
RequestId: 5a7446ed-6896-4e65-b795-3exampleca60 Error: Runtime exited with error: exit status 1
Runtime.ExitError
英文:
Here is my code:
package main
import (
"context"
"fmt"
"log"
"github.com/aws/aws-sdk-go-v2/config"
"github.com/aws/aws-sdk-go-v2/service/ec2"
"github.com/aws/aws-sdk-go-v2/service/ec2/types"
)
func main() {
// Load the Shared AWS Configuration (~/.aws/config)
cfg, err := config.LoadDefaultConfig(context.TODO())
if err != nil {
log.Fatal(err)
}
// Create an Amazon EC2 service client
ec2ServiceClient := ec2.NewFromConfig(cfg)
// DescribeAddressesInput with no filter means list all addresses
IpListFilter := &ec2.DescribeAddressesInput{}
// Ask EC2 client to list all Elastic IPs.
result, err := ec2ServiceClient.DescribeAddresses(context.TODO(), IpListFilter)
if err != nil {
fmt.Println("Got an error retrieving information about your Amazon Elastic IPs:")
fmt.Println(err)
return
}
// Out of all IPs, check if they have an allocation ID. If not, they are candidate for deletion
for _, a := range result.Addresses {
fmt.Println("Allocation ID: " + *a.AllocationId)
fmt.Println("Public IP: " + *a.PublicIp)
// if this EIP is not associated with any AWS resources, proceed for killing.
if a.AssociationId == nil {
// extra step for flexibility
if isThisEIPKillable(a.Tags) {
fmt.Println("About to be killed")
// Release/kill the Elastic IP
ReleaseAddressFilter := &ec2.ReleaseAddressInput{AllocationId: a.AllocationId}
ec2ServiceClient.ReleaseAddress(context.TODO(), ReleaseAddressFilter)
fmt.Println(*a.PublicIp + " is not more")
} else {
fmt.Println(*a.PublicIp + " has KILLERHOLD enabled and is going to stay")
}
} else {
fmt.Println("Association ID: " + *a.AssociationId)
fmt.Println("Instance ID: " + *a.InstanceId)
fmt.Println("PrivateIpAddress: " + *a.PrivateIpAddress)
}
fmt.Println("")
}
}
// isThisEIPKillable scans to tags of Elastic IP and only return false when
// EIPKILLER is tag is set to true.
func isThisEIPKillable(tags []types.Tag) bool {
for _, tag := range tags {
if *tag.Key == "KILLERHOLD" && *tag.Value == "true" {
return false
}
}
return true
}
The Lambda function has the necessary permission to run i.e. it is allowed to run ec2:ReleaseAddress
and ec2:DescribeAddresses
.
For testing, I have one EIP associated with one EC2 instance. According to the Lambda logic, the lambda should just print output and exit without any error.
But this is what happens. I have redacted some strings for privacy:
START RequestId: 5a7446ed-6896-4e65-b795-35d1bfd6ca60 Version: $LATEST
Allocation ID: eipalloc-08fexample952a7f7
Public IP: XXX.XXX.XXX.XXX
Association ID: eipassoc-0112e332e17959d76
Instance ID: i-096561051e41c2d60
PrivateIpAddress: 10.2.1.38
2022/08/26 14:25:38 <nil>
Allocation ID: eipalloc-08fexample952a7f7
Public IP: XXX.XXX.XXX.XXX
Association ID: eipassoc-011example959d76
Instance ID: i-09656examplec2d60
PrivateIpAddress: 10.2.1.38
2022/08/26 14:25:39 <nil>
END RequestId: 5a7446ed-6896-4e65-b795-3exampleca60
REPORT RequestId: 5a7446ed-6896-4e65-b795-3examplea60 Duration: 402.33 ms Billed Duration: 403 ms Memory Size: 512 MB Max Memory Used: 21 MB
RequestId: 5a7446ed-6896-4e65-b795-3exampleca60 Error: Runtime exited with error: exit status 1
Runtime.ExitError
答案1
得分: 2
根据 @jarmod 和 @Daniel 的发现,你编写的函数不符合文档中规定的格式。
假设你已经将处理程序配置为 main
,下面是你旧代码与正确代码的差异。
@@ -5,14 +5,19 @@ import (
"fmt"
"log"
+ "github.com/aws/aws-lambda-go/lambda"
"github.com/aws/aws-sdk-go-v2/config"
"github.com/aws/aws-sdk-go-v2/service/ec2"
"github.com/aws/aws-sdk-go-v2/service/ec2/types"
)
-func main() {
+type MyEvent struct {
+ Name string `json:"name"`
+}
+
+func Handler(ctx context.Context, name MyEvent) (string, error) {
// Load the Shared AWS Configuration (~/.aws/config)
- cfg, err := config.LoadDefaultConfig(context.TODO())
+ cfg, err := config.LoadDefaultConfig(ctx)
if err != nil {
log.Fatal(err)
}
@@ -27,8 +32,7 @@ func main() {
result, err := ec2ServiceClient.DescribeAddresses(context.TODO(), IpListFilter)
if err != nil {
fmt.Println("Got an error retrieving information about your Amazon Elastic IPs:")
- fmt.Println(err)
- return
+ return "", err
}
// Out of all IPs, check if they have an allocation ID. If not, they are candidate for deletion
@@ -57,6 +61,7 @@ func main() {
fmt.Println("")
}
+ return "Done execution", nil
}
// isThisEIPKillable scans to tags of Elastic IP and only return false when
@@ -69,3 +74,7 @@ func isThisEIPKillable(tags []types.Tag) bool {
}
return true
}
+
+func main() {
+ lambda.Start(Handler)
+}
基本上将所有逻辑移动到一个不同的函数中,比如 Handler
,然后在 main
中使用 lambda.Start(Handler)
调用该函数。
参考 AWS Lambda function handler in Go 获取更多参考信息。
英文:
As figured out by @jarmod and @Daniel. The function you have written does not comply with the format prescribed in the docs.
Assuming that you have configured your handler to be main
, here is a diff of your old code vs what it should be.
@@ -5,14 +5,19 @@ import (
"fmt"
"log"
+ "github.com/aws/aws-lambda-go/lambda"
"github.com/aws/aws-sdk-go-v2/config"
"github.com/aws/aws-sdk-go-v2/service/ec2"
"github.com/aws/aws-sdk-go-v2/service/ec2/types"
)
-func main() {
+type MyEvent struct {
+ Name string `json:"name"`
+}
+
+func Handler(ctx context.Context, name MyEvent) (string, error) {
// Load the Shared AWS Configuration (~/.aws/config)
- cfg, err := config.LoadDefaultConfig(context.TODO())
+ cfg, err := config.LoadDefaultConfig(ctx)
if err != nil {
log.Fatal(err)
}
@@ -27,8 +32,7 @@ func main() {
result, err := ec2ServiceClient.DescribeAddresses(context.TODO(), IpListFilter)
if err != nil {
fmt.Println("Got an error retrieving information about your Amazon Elastic IPs:")
- fmt.Println(err)
- return
+ return "", err
}
// Out of all IPs, check if they have an allocation ID. If not, they are candidate for deletion
@@ -57,6 +61,7 @@ func main() {
fmt.Println("")
}
+ return "Done execution", nil
}
// isThisEIPKillable scans to tags of Elastic IP and only return false when
@@ -69,3 +74,7 @@ func isThisEIPKillable(tags []types.Tag) bool {
}
return true
}
+
+func main() {
+ lambda.Start(Handler)
+}
Basically move all the logic to a different function say Handler
, and then invoke that function in main using lambda.Start(Handler)
Refer to AWS Lambda function handler in Go for reference.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论