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

HCL Decoding: Blocks with multiple labels

我的目标是解析一个HCL配置(Terraform Configuration),然后将收集到的有关变量、输出、资源块和数据块的数据写入Markdown文件。

变量和输出没问题,但是,一旦我尝试解码具有多个标签的资源块。

作品:

variable "foo" {
  type = "bar"
}

无效:

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

错误:Extraneous label for resource; Only 1 labels (name) are expected for resource blocks.

类型声明代码:

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
}

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

您分享的错误是由于 type Resource 的定义造成的。 Terraform 中的 resource 个块(和 data 个块)需要 两个 标签,指示资源类型和名称。要将您暗示的模式与这些结构类型相匹配,您需要定义标记为 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"`
}

虽然这应该适用于您在此处显示的有限输入,但我要提醒您,您使用的是 higher-level gohcl API,它只能解码 HCL 的一个子集很好地映射到 Go 的结构类型。 Terraform 本身直接使用 hcl.Body and hcl.Expression 的 lower-level API,这使得 Terraform 语言可以包含一些 gohcl API 不能直接表示的 HCL 特性。 =22=]

根据您的目标,您可能会发现使用官方库更好terraform-config-inspect, which can parse, decode, and describe a subset of the Terraform language at a higher level of abstraction than the HCL API itself. It also supports modules written for Terraform versions going all the way back to Terraform v0.11, and is the implementation that backs the analysis of modules done by Terraform Registry