如何解决无法将 terraform variables.tf 文件读入 may go program
我正在尝试编写一个 go 程序,该程序读取 terraform variables.tf
并填充一个结构以供以后操作。但是,在尝试“解析”文件时出现错误。我希望有人能告诉我我做错了什么:
代码:
package main
import (
"fmt"
"io/ioutil"
"log"
"os"
"github.com/hashicorp/hcl/v2"
"github.com/hashicorp/hcl/v2/gohcl"
"github.com/hashicorp/hcl/v2/hclsyntax"
)
type Config struct {
Upstreams []*TfVariable `hcl:"variable,block"`
}
type TfVariable struct {
Name string `hcl:",label"`
// Default string `hcl:"default,optional"`
Type string `hcl:"type"`
Description string `hcl:"description,attr"`
// validation block
Sensitive bool `hcl:"sensitive,optional"`
}
func main() {
readHCLFile("examples/string.tf")
}
// Exits program by sending error message to standard error and specified error code.
func abort(errorMessage string,exitcode int) {
fmt.Fprintln(os.Stderr,errorMessage)
os.Exit(exitcode)
}
func readHCLFile(filePath string) {
content,err := ioutil.ReadFile(filePath)
if err != nil {
log.Fatal(err)
}
fmt.Printf("File contents: %s",content) // TODO: Remove me
file,diags := hclsyntax.ParseConfig(content,filePath,hcl.Pos{Line: 1,Column: 1})
if diags.HasErrors() {
log.Fatal(fmt.Errorf("ParseConfig: %w",diags))
}
c := &Config{}
diags = gohcl.DecodeBody(file.Body,nil,c)
if diags.HasErrors() {
log.Fatal(fmt.Errorf("DecodeBody: %w",diags))
}
fmt.Println(c) // TODO: Remove me
}
错误
File contents: variable "image_id" {
type = string
description = "The id of the machine image (AMI) to use for the server."
sensitive = false
}
variable "other_id" {
type = string
description = "The id of the machine image (AMI) to use for the server."
sensitive = true
}
2021/03/13 19:55:49 DecodeBody: examples/string.tf:2,17-23: Variables not allowed; Variables may not be used here.,and 3 other diagnostic(s)
exit status 1
堆栈驱动程序 question 可悲地用于 hcl1
Blog post 我正在引用。
解决方法
它看起来像是库的错误/功能,因为一旦您将 string
更改为 "string"
,例如,
variable "image_id" {
type = string
...
到
variable "image_id" {
type = "string"
...
gohcl.DecodeBody
成功。
--- 更新---
所以,他们确实在 Terraform 中使用了这个包,但是他们 custom-parse configs,即他们不使用 gohcl.DecodeBody
。它们还通过使用 type
(custom-treat 和 hcl.ExprAsKeyword
)来 compare description
属性。正如您所假设的,它们确实对 type
使用了 custom type,但您不必使用自定义解析。
下面是一个工作示例:
package main
import (
"fmt"
"log"
"os"
"github.com/hashicorp/hcl/v2"
"github.com/hashicorp/hcl/v2/gohcl"
"github.com/hashicorp/hcl/v2/hclsyntax"
)
var (
configFileSchema = &hcl.BodySchema{
Blocks: []hcl.BlockHeaderSchema{
{
Type: "variable",LabelNames: []string{"name"},},}
variableBlockSchema = &hcl.BodySchema{
Attributes: []hcl.AttributeSchema{
{
Name: "description",{
Name: "type",{
Name: "sensitive",}
)
type Config struct {
Variables []*Variable
}
type Variable struct {
Name string
Description string
Type string
Sensitive bool
}
func main() {
config := configFromFile("examples/string.tf")
for _,v := range config.Variables {
fmt.Printf("%+v\n",v)
}
}
func configFromFile(filePath string) *Config {
content,err := os.ReadFile(filePath) // go 1.16
if err != nil {
log.Fatal(err)
}
file,diags := hclsyntax.ParseConfig(content,filePath,hcl.Pos{Line: 1,Column: 1})
if diags.HasErrors() {
log.Fatal("ParseConfig",diags)
}
bodyCont,diags := file.Body.Content(configFileSchema)
if diags.HasErrors() {
log.Fatal("file content",diags)
}
res := &Config{}
for _,block := range bodyCont.Blocks {
v := &Variable{
Name: block.Labels[0],}
blockCont,diags := block.Body.Content(variableBlockSchema)
if diags.HasErrors() {
log.Fatal("block content",diags)
}
if attr,exists := blockCont.Attributes["description"]; exists {
diags := gohcl.DecodeExpression(attr.Expr,nil,&v.Description)
if diags.HasErrors() {
log.Fatal("description attr",diags)
}
}
if attr,exists := blockCont.Attributes["sensitive"]; exists {
diags := gohcl.DecodeExpression(attr.Expr,&v.Sensitive)
if diags.HasErrors() {
log.Fatal("sensitive attr",exists := blockCont.Attributes["type"]; exists {
v.Type = hcl.ExprAsKeyword(attr.Expr)
if v.Type == "" {
log.Fatal("type attr","invalid value")
}
}
res.Variables = append(res.Variables,v)
}
return res
}
为完整性添加,example/string.tf
:
variable "image_id" {
type = string
description = "The id of the machine image (AMI) to use for the server."
sensitive = false
}
variable "other_id" {
type = string
description = "The id of the machine image (AMI) to use for the server."
sensitive = true
}
,
由于 Terraform 语言广泛使用了需要使用低级 HCL API 进行自定义编程的各种 HCL 功能,因此 Terraform 团队维护了一个 Go 库 terraform-config-inspect,它对 Terraform 语言的理解足以提取有关 top 的静态元数据级对象,包括变量。它还处理这样一个事实,即 Terraform 允许在与其他声明交错的任何 .tf
或 .tf.json
文件中定义变量;将它们放在 variables.tf
中只是一种约定。
例如:
mod,diags := tfconfig.LoadModule("examples")
if diags.HasErrors() {
log.Fatalf(diags.Error())
}
for _,variable := range mod.Variables {
fmt.Printf("%#v\n",variable)
}
此库与 Terraform Registry 用于生成 the documentation about module input variables 的代码相同,因此它支持 Terraform Registry 所做的所有 Terraform 语言版本(在撰写本文时,可以追溯到 Terraform v0.1)。 10 语言,因为这是第一个可以从注册表安装模块的版本)并支持 Terraform 语言的 HCL 原生语法和 JSON 表示。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。