gpt4 book ai didi

amazon-web-services - 由于类似 catch22 的情况,AWS 自定义资源 ROLLBACK_FAILED

转载 作者:行者123 更新时间:2023-12-03 07:39:10 27 4
gpt4 key购买 nike

我有一个自定义资源,只要发生回滚,它就会陷入类似 catch22 的情况。

下面的代码是我的代码正在执行的操作的简化示例。如果是创建请求,它会创建一个表,如果是删除,它会删除,如果是更新,它会将旧属性与新属性进行比较,并在其中一列具有新值时返回错误(列更新不尚支持)。

出现问题的 ROLLBACK_FAILED 发生在

  1. [已解决] 每当创建请求类型失败时(例如由于 sql 语法错误)。在这种情况下,它将触发 ROLLBACK 阶段的删除请求,但该请求将失败,因为该表还不存在。
  2. 每当更新请求类型由于更新的列值而失败时。在这种情况下,它将触发 ROLLBACK 阶段的新更新请求,其中 event.ResourcePropertiesevent.OldResourceProperties 发生切换,这仍然会导致错误。<
package main

import (
"context"
"encoding/json"
"fmt"
"strings"

"github.com/aws/aws-lambda-go/cfn"
"github.com/aws/aws-lambda-go/lambda"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/rdsdataservice"
"github.com/google/uuid"
)

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

type properties struct {
TableName string
Columns []struct {
Name string
Value string
}
}

func handler(ctx context.Context, event cfn.Event) (physicalResourceID string, data map[string]interface{}, err error) {
prid := event.PhysicalResourceID
if event.RequestType == cfn.RequestCreate {
prid = strings.ReplaceAll(uuid.New().String(), "-", "")
}

var props properties
b, _ := json.Marshal(event.ResourceProperties)
json.Unmarshal(b, &props)

rds := rdsdataservice.New(nil)

if event.RequestType == cfn.RequestCreate {
rds.ExecuteStatement(&rdsdataservice.ExecuteStatementInput{
Sql: aws.String(fmt.Sprintf("CREATE TABLE %s", props.TableName)),
})
}

if event.RequestType == cfn.RequestDelete {
rds.ExecuteStatement(&rdsdataservice.ExecuteStatementInput{
Sql: aws.String(fmt.Sprintf("CREATE TABLE %s", props.TableName)),
})
}

if event.RequestType == cfn.RequestUpdate {
var oldProps properties
b, _ := json.Marshal(event.OldResourceProperties)
json.Unmarshal(b, &oldProps)

columns := map[string]string{}
for _, column := range props.Columns {
columns[column.Name] = column.Value
}

for _, column := range oldProps.Columns {
if val, ok := columns[column.Name]; ok {
if val != column.Value {
return "", nil, fmt.Errorf("cannot change column type")
}
}
}

// Do some extra stuff here for adding/removing columns
}
return prid, nil, nil
}

我想到了两种可能的解决方案。我可以实现其中之一,但存在潜在的问题。但在我看来应该有更好的方法,因为我不能是唯一遇到这个问题的人。或者我做了一些非常错误的事情..

  1. 在某些情况下仅对此特定资源禁用回滚(有时我仍然想要回滚)
  2. 可以访问最后的状态,以便我可以检查要做什么;如果删除的最后状态为 CREATE_FAILED,则不要执行任何操作。如果更新的最后状态为 UPDATE_FAILED,请不要执行任何操作。

我可以使用下面的代码来实现第二个选项。但随着事件数量的增加,这可能会变得非常成问题。

events, err := cloud.DescribeStackEvents(&cloudformation.DescribeStackEventsInput{
StackName: &event.StackID,
})

最佳答案

对于遇到同样问题的人;我通过查看堆栈事件解决了这个问题,并找到了正在更新的最后一个资源状态。由于当前状态始终在列表中,因此我忽略 IN_PROGRESS 值。如果状态 IN_PROGRESS 之后的第一个值为 FAILED,则表示该资源无法更新,因此可以应用不同的 ROLLBACK 策略。

GO中对应的函数

func isFailedEvent(sess *session.Session, event cfn.Event) (bool, error) {
cloud := cloudformation.New(sess)
var isFailedResource bool
if err := cloud.DescribeStackEventsPages(&cloudformation.DescribeStackEventsInput{
StackName: aws.String(event.StackID),
}, func(out *cloudformation.DescribeStackEventsOutput, lastPage bool) bool {
for _, e := range out.StackEvents {
if *e.LogicalResourceId == event.LogicalResourceID {
if strings.HasSuffix(*e.ResourceStatus, "IN_PROGRESS") {
continue
}
if strings.HasSuffix(*e.ResourceStatus, "FAILED") && !strings.Contains(*e.ResourceStatusReason, "cancelled") {
isFailedResource = true
}
return false
}
}
return true
}); err != nil {
return false, fmt.Errorf("describe stack events: %s", err)
}
return isFailedResource, nil
}

关于amazon-web-services - 由于类似 catch22 的情况,AWS 自定义资源 ROLLBACK_FAILED,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/74362326/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com