Как показать предупреждение/ошибку при запуске «плана терраформирования»?

avatar
Zulhilmi Zainudin
9 августа 2021 в 04:05
1020
1
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?

enter image description here

Источник

Ответы (1)

avatar
ydaetskcoR
9 августа 2021 в 09:05
3

Здесь правильно было бы сообщить Terraform, что изменения в ресурсе не могут быть выполнены на месте, а вместо этого требуется воссоздание ресурса (обычно уничтожение с последующим созданием, но вы можете отменить это с помощью lifecycle.create_before_destroy<).>).

При создании провайдера это можно сделать с помощью параметра ForceNew в атрибуте схемы.

Например, ресурс aws_launch_configuration считается неизменным со стороны API AWS, поэтому каждый невычисляемый атрибут в схеме помечен 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.4 на 7.8 напрямую, а вместо этого должны перейти к 5.4 -> 5.6 -> 6.8 -> 7.8. Это делается с помощью атрибута CustomizeDiffCustomizeDiff в схеме, который позволяет использовать логику во время планирования, чтобы получить результат, отличный от того, который обычно получается при статической конфигурации.

Атрибут CustomizeDiff для атрибута aws_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,
        ),

Попытка обновить elasticsearch_version elasticsearch_version по принятому пути обновления (например, 7.4 -> 7.8) покажет, что это обновление на месте в плане, и применит это во время применения. С другой стороны, если вы попытались обновиться по пути, который не разрешен напрямую (например, 5.4 -> 7.8 напрямую), то план Terraform покажет, что необходимо уничтожить существующий домен Elasticsearch и создать новый.

Zulhilmi Zainudin
11 августа 2021 в 07:53
0

Спасибо за ваш ответ. Очень полезно.