问题描述
在使用Terraform时,有一个需求是希望在读取文件时,如果文件存在则读取,但如果文件不存在则不抛出致命错误。用户尝试使用data.local_sensitive_file
来读取文件,但当文件不存在时,会导致编译错误。
解决方案
请注意以下操作注意版本差异及修改前做好备份。
方案1
在Terraform中,你可以使用fileexists
函数来检查文件是否存在,然后再尝试使用它。这个函数返回一个布尔值,指示指定的文件是否存在。
在你的情况下,你可以使用以下代码来处理文件可能不存在的情况:
filename = fileexists("/tmp/foo") ? "/tmp/foo" : "/tmp/whateverfile_you_want_if_foo_doesn't_exist"
如果文件存在,filename
将为/tmp/foo
,如果文件不存在,filename
将为/tmp/whateverfile_you_want_if_foo_doesn't_exist
。
方案2
在这种特殊情况下,如果路径是已知的,我通常会使用file
函数而不是local_sensitive_file
数据源,因为数据源主要用于在Terraform运行时动态生成的文件。
以下是使用file
函数的示例代码:
locals {
filename = "${path.module}/whatever.txt"
example = fileexists(local.filename) ? sensitive(file(local.filename)) : null
}
如果在你的实际配置中,这是一个来自Terraform配置之外的文件或者是由你的配置动态生成的文件,你可以通过告诉Terraform,如果文件不存在,则不应该有此数据资源的实例,来达到类似的效果:
locals {
filename = "${path.module}/whatever.txt"
}
data "local_sensitive_file" "example" {
count = fileexists(local.filename) ? 1 : 0
filename = local.filename
}
locals {
file_content = one(data.local_sensitive_file.example[*].content)
}
上面的代码中,使用one
函数的最后一个表达式是一种简洁的方式,可以获取content
的一个值,如果没有此资源的实例,则返回null
。因此,local.file_content
将是文件的内容,如果文件不存在,则为null
。
需要注意的是,如果应用此Terraform配置可能会改变文件是否存在,那么声明”仅在文件存在时使用”的规则可能会有问题。因为在规划阶段,Terraform会做出一些假设,而这些假设在应用阶段可能不成立,从而导致Terraform表现出未指定的行为。因此,建议明确指定文件是否应该存在,以便Terraform可以立即告诉你是否做出了错误的假设。
例如,你可以声明一个输入变量,其存在明确表示文件应该存在,但在不需要存在时可以省略:
variable "filename" {
type = string
default = null
}
data "local_sensitive_file" "example" {
count = var.filename != null ? 1 : 0
filename = var.filename
}
locals {
file_content = one(data.local_sensitive_file.example[*].content)
}
这与前面的示例基本相同,只是现在决定是否读取文件的谓词是是否指定了文件名,因此,如果调用此模块的用户在编写文件名时出现拼写错误,或者假设文件存在但实际上不存在,Terraform可以快速给出反馈。
请注意,以上解决方案中的代码仅供参考,具体实现可能需要根据实际情况进行调整。