正确的做法是告诉 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.4
,7.8
而是必须转到5.4 -> 5.6 -> 6.8 -> 7.8
。这是通过使用架构上允许的CustomizeDiff
属性来完成的您可以在计划时使用逻辑来给出与通常从静态配置中找到的结果不同的结果。
CustomizeDiff
foraws_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_version
7.4 -> 7.8
5.4 -> 7.8