HCL解码:具有多个标签的块

3
我的目标是解析一个HCL配置(Terraform配置),然后将关于变量、输出、资源块和数据块的收集数据写入一个Markdown文件。变量和输出没有问题,但是当我尝试解码具有多个标签的资源块时,就会出现问题。以下是可以工作的部分:
variable "foo" {
  type = "bar"
}

不能工作:

resource "foo" "bar" {
 name = "biz"
}

错误: 资源的多余标签; 资源块只期望有1个标签(名称)。 类型声明代码:
import (
    "log"
    "os"
    "strconv"

    "github.com/hashicorp/hcl/v2"
    "github.com/hashicorp/hcl/v2/gohcl"
    "github.com/hashicorp/hcl/v2/hclsyntax"
)

type Variable struct {
    Name        string         `hcl:",label"`
    Description string         `hcl:"description,optional"`
    Sensitive   bool           `hcl:"sensitive,optional"`
    Type        *hcl.Attribute `hcl:"type,optional"`
    Default     *hcl.Attribute `hcl:"default,optional"`
    Options     hcl.Body       `hcl:",remain"`
}

type Output struct {
    Name        string   `hcl:",label"`
    Description string   `hcl:"description,optional"`
    Sensitive   bool     `hcl:"sensitive,optional"`
    Value       string   `hcl:"value,optional"`
    Options     hcl.Body `hcl:",remain"`
}

type Resource struct {
    Name    string   `hcl:"name,label"`
    Options hcl.Body `hcl:",remain"`
}

type Data struct {
    Name    string   `hcl:"name,label"`
    Options hcl.Body `hcl:",remain"`
}

type Config struct {
    Outputs   []*Output   `hcl:"output,block"`
    Variables []*Variable `hcl:"variable,block"`
    Resources []*Resource `hcl:"resource,block"`
    Data      []*Data     `hcl:"data,block"`
}

代码解码:

func createDocs(hclPath string) map[string][]map[string]string {
    var variables, outputs []map[string]string

    parsedConfig := make(map[string][]map[string]string)
    hclConfig := make(map[string][]byte)

    c := &Config{}

    // Iterate all Terraform files and safe the contents in the hclConfig map
    for _, file := range filesInDirectory(hclPath, ".tf") {
        fileContent, err := os.ReadFile(hclPath + "/" + file.Name())
        if err != nil {
            log.Fatal(err)
        }
        hclConfig[file.Name()] = fileContent
    }

    // Iterate all file contents
    for k, v := range hclConfig {
        parsedConfig, diags := hclsyntax.ParseConfig(v, k, hcl.Pos{Line: 1, Column: 1})
        if diags.HasErrors() {
            log.Fatal(diags)
        }

        diags = gohcl.DecodeBody(parsedConfig.Body, nil, c)
        if diags.HasErrors() {
            log.Fatal(diags)
        }
    }

    for _, v := range c.Variables {
        var variableType string
        var variableDefault string

        if v.Type != nil {
            variableType = (v.Type.Expr).Variables()[0].RootName()
        }

        if v.Default != nil {
            variableDefault = (v.Default.Expr).Variables()[0].RootName()
        }

        variables = append(variables, map[string]string{"name": v.Name, "description": v.Description,
            "sensitive": strconv.FormatBool(v.Sensitive), "type": variableType, "default": variableDefault})
    }

    for _, v := range c.Outputs {
        outputs = append(outputs, map[string]string{"name": v.Name, "description": v.Description,
            "sensitive": strconv.FormatBool(v.Sensitive), "value": v.Value})
    }

    parsedConfig["variables"], parsedConfig["outputs"] = variables, outputs

    return parsedConfig
}

问题:如何从资源块中解析多个标签?


也许你可以参考如何解析JSON?https://github.com/hashicorp/hcl#information-model-and-syntax - Tony Yip
我也考虑过这个问题,但我得出结论,我不想走已知的简单路线,而是学习如何解析HCL。 - YoungGova
这可能是一个有趣的练习,但如果有关系的话,它听起来像是你正在尝试复制terrafrom-docs的一部分功能。 - Matt Schuchard
1个回答

1
你分享的错误是由于type Resource的定义而引起的。resource块(和data块)在Terraform中期望两个标签,表示资源类型和名称。为了与这些结构体类型暗示的模式匹配,您需要定义被标记为label的两个字段。
type Resource struct {
    Type    string   `hcl:"type,label"`
    Name    string   `hcl:"name,label"`
    Options hcl.Body `hcl:",remain"`
}

type Data struct {
    Type    string   `hcl:"type,label"`
    Name    string   `hcl:"name,label"`
    Options hcl.Body `hcl:",remain"`
}

虽然对于您在此处展示的有限输入,这应该可以工作,但我想提醒您正在使用更高级别的gohcl API,它只能解码一部分HCL并将其映射到Go的结构类型。 Terraform本身使用hcl.Bodyhcl.Expression的较低级别API直接,这允许Terraform语言包括一些gohcl API无法直接表示的HCL功能。
根据您的目标,您可能会发现最好使用官方库terraform-config-inspect,它可以在比HCL API本身更高的抽象级别上解析、解码和描述Terraform语言的子集。它还支持为Terraform v0.11及更高版本编写的模块,并且是由Terraform Registry执行的模块分析的实现。

谢谢你的回答,Martin。非常有帮助! - YoungGova

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接