0

我正在构建一个 Terraform 插件/提供程序(链接),它将帮助用户在云平台上管理他们的云资源,例如云实例、Kubernetes 集群等。

目前云平台不支持Kubernetes节点创建后改变大小。如果用户想要更改节点大小,他们需要创建一个具有新节点大小的新节点池。

所以我在我的插件代码中添加了这个块,特别是在 Kubernetes 集群更新方法(链接)中:

if d.HasChange("target_nodes_size") {
    errMsg := []string{
        "[ERR] Unable to update 'target_nodes_size' after creation.",
        "Please create a new node pool with the new node size.",
    }
    return fmt.Errorf(strings.Join(errMsg, " "))
}

问题是,错误仅在我运行terraform apply命令时出现。我想要的是,我希望它显示用户何时运行terraform plan命令,以便他们尽早知道如果不创建新节点池就无法更改节点大小。

如何使该target_nodes_size字段不可变并在输出早期显示错误terraform plan

在此处输入图像描述

4

1 回答 1

3

正确的做法是告诉 Terraform 无法就地完成对资源的更改,而是需要重新创建资源(通常先销毁,然后创建,但您可以使用 反转lifecycle.create_before_destroy)。

创建提供者时,您可以使用ForceNew模式属性上的参数来执行此操作。

例如,aws_launch_configuration资源在 AWS 的 API 端被认为是不可变的,因此架构中的每个非计算属性都用 标记ForceNew: true

func resourceAwsLaunchConfiguration() *schema.Resource {
    return &schema.Resource{
        Create: resourceAwsLaunchConfigurationCreate,
        Read:   resourceAwsLaunchConfigurationRead,
        Delete: resourceAwsLaunchConfigurationDelete,
        Importer: &schema.ResourceImporter{
            State: schema.ImportStatePassthrough,
        },

        Schema: map[string]*schema.Schema{
            "arn": {
                Type:     schema.TypeString,
                Computed: true,
            },

            "name": {
                Type:          schema.TypeString,
                Optional:      true,
                Computed:      true,
                ForceNew:      true,
                ConflictsWith: []string{"name_prefix"},
                ValidateFunc:  validation.StringLenBetween(1, 255),
            },
// ...

如果您随后尝试修改任何ForceNew: true字段,则 Terraform 的计划将显示它需要替换资源,并且在应用时,只要用户接受该计划,它就会自动执行此操作。

对于更复杂的示例,aws_elasticsearch_domain资源允许就地版本更改,但仅适用于特定版本升级路径(因此您不能例如直接转到5.47.8而是必须转到5.4 -> 5.6 -> 6.8 -> 7.8。这是通过使用架构上允许的CustomizeDiff属性来完成的您可以在计划时使用逻辑来给出与通常从静态配置中找到的结果不同的结果。

CustomizeDiffforaws_elasticsearch_domain elasticsearch_version属性如下所示:

func resourceAwsElasticSearchDomain() *schema.Resource {
    return &schema.Resource{
        Create: resourceAwsElasticSearchDomainCreate,
        Read:   resourceAwsElasticSearchDomainRead,
        Update: resourceAwsElasticSearchDomainUpdate,
        Delete: resourceAwsElasticSearchDomainDelete,
        Importer: &schema.ResourceImporter{
            State: resourceAwsElasticSearchDomainImport,
        },

        Timeouts: &schema.ResourceTimeout{
            Update: schema.DefaultTimeout(60 * time.Minute),
        },

        CustomizeDiff: customdiff.Sequence(
            customdiff.ForceNewIf("elasticsearch_version", func(_ context.Context, d *schema.ResourceDiff, meta interface{}) bool {
                newVersion := d.Get("elasticsearch_version").(string)
                domainName := d.Get("domain_name").(string)

                conn := meta.(*AWSClient).esconn
                resp, err := conn.GetCompatibleElasticsearchVersions(&elasticsearch.GetCompatibleElasticsearchVersionsInput{
                    DomainName: aws.String(domainName),
                })
                if err != nil {
                    log.Printf("[ERROR] Failed to get compatible ElasticSearch versions %s", domainName)
                    return false
                }
                if len(resp.CompatibleElasticsearchVersions) != 1 {
                    return true
                }
                for _, targetVersion := range resp.CompatibleElasticsearchVersions[0].TargetVersions {
                    if aws.StringValue(targetVersion) == newVersion {
                        return false
                    }
                }
                return true
            }),
            SetTagsDiff,
        ),

尝试在已接受的升级路径(例如 )上升级aws_elasticsearch_domain's将表明它是计划中的就地升级,并在应用时应用。另一方面,如果您尝试通过不允许直接(例如直接)的路径进行升级,那么 Terraform 的计划将表明它需要销毁现有的 Elasticsearch 域并创建一个新域。elasticsearch_version7.4 -> 7.85.4 -> 7.8

于 2021-08-09T09:05:29.587 回答