Context:按照官方教程,通过TF Provider SDKv2实现Terraform Provider。
因此,相应Terraform Provider资源aws_launch_configuration中的所有架构元素都标记为ForceNew:true。此行为指示Terraform在配置中的任何属性发生更改时,首先销毁资源,然后重新创建资源,而不是尝试更新现有资源。
TF教程建议我们应该为每个不可更新的字段添加ForceNew: true
,如:
"base_image": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
resource "example_instance" "ex" {
name = "bastion host"
base_image = "ubuntu_17.10" # base_image updates are not supported
}
然而,可能会遇到以下情况:
让我们考虑一下"重要";具有name
属性的资源foo_db_instance
(在特殊情况下应该删除/重新创建的DB实例((相关的未回答问题(:
resource "foo_db_instance" "ex" {
name = "bar" # name updates are not supported
...
}
然而,它的底层API是以一种奇怪的方式编写的,并且它不支持name
属性的更新。有两种选择:
按照教程的方法,我们可能会添加
ForceNew: true
,然后,如果用户不注意terraform plan
的输出,它可能会在意外更新name
属性时重新创建foo_db_instance.ex
,这将导致中断。不要遵循教程中的方法,也不要添加
ForceNew: true
。因此,terraform plan
将不会输出错误,并且它将使更新看起来是可能的。然而,当运行terraform apply
时,如果我们向resourceUpdate()
添加自定义代码,用户将遇到错误,如下所示:
func resourceUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
if d.HasChanges("name) {
return diag.Errorf("error updating foo_db_instance: name attribute updates are not supported")
}
...
}
这种方法有两个缺点:
terraform plan
无故障输出- 我们可能需要一些破解来恢复tf状态以覆盖CCD_ 14
哪种方法应该更可取?
我知道有prevent_destroy = true
生命周期属性,但它似乎不会阻止这种特定的场景(它只防止意外的terraform destroy
(。
最典型的答案是遵循您的第一个选项,然后允许Terraform在其UI中报告更改需要替换,并允许用户决定如何继续。
的确,如果有人没有阅读计划输出,那么他们可能会做出他们不打算做出的改变,但在这种情况下,用户没有使用Terraform提供的特定机制来帮助用户避免做出不希望的改变。
您提到了prevent_destroy = true
,事实上,这是一个与这种情况相关的设置,事实上正是该选项的用途:如果计划中包含";替换";使用该设置注释的资源的操作,从而防止用户接受计划,从而避免破坏对象。
一些用户还将Terraform封装在自动化中,这将对生成的计划执行更复杂的自定义策略检查,要么实现与prevent_destroy
类似的效果(完全阻止操作(,要么只需要额外的确认来帮助确保操作员意识到发生了不寻常的事情。例如,在Terraform Cloud中,程序化策略可以报告";软故障";这导致了额外的确认步骤,该步骤可能只有一小部分运营商才能批准,这些运营商更有能力理解提议的影响。
原则上可以在CustomizeDiff
函数(在计划期间运行(或Update
函数(在应用步骤期间运行(中写入逻辑,以在这种情况下或您可以用Go编程语言为其编写逻辑的任何其他情况下返回错误。在这两个选项中,我想说CustomizeDiff
将是更好的,因为这将完全阻止创建计划,而不是允许创建计划,然后在应用步骤的中途失败,此时可能已经应用了一些其他上游更改。
然而,做这两件事中的任何一件都与用户期望的Terraform提供者的通常行为不一致。Terraform提供商的预期模型是尽可能准确地描述变更的影响,然后允许运营商就拟议的变更是否可接受做出最终决定,如果不可接受,则取消计划并选择另一种策略。