首页 >后端开发 >Golang >如何让 Golang 脚本修改 Terraform(HCL 格式)文件中的值?

如何让 Golang 脚本修改 Terraform(HCL 格式)文件中的值?

WBOY
WBOY转载
2024-02-09 12:06:28936浏览

如何让 Golang 脚本修改 Terraform(HCL 格式)文件中的值?

php小编柚子教你如何使用Golang脚本修改Terraform(HCL格式)文件中的值。Terraform是一种基础设施即代码工具,可以帮助我们管理和自动化云基础设施。但是,如果我们需要频繁地修改Terraform文件中的某些值,手动操作将变得非常繁琐。因此,使用Golang脚本来修改Terraform文件中的值将会是一个更高效的方法。在本文中,我将向您展示如何使用Golang编写一个脚本来实现这一目标,以便您能够轻松地在Terraform文件中进行值的修改。

问题内容

我正在尝试对我拥有的 terraform 文件进行少量自动化,该文件定义了 azure 网络安全组。本质上,我有一个网站和 ssh 访问,我只想允许我的公共 ip 地址,我可以从 icanhazip.com 获取该地址。我希望使用 golang 脚本将我的 ip 写入 .tf 文件的相关部分(本质上是设置 security_rule.source_address_prefixes 的值)。

我正在尝试在 golang 中使用 hclsimple 库,并尝试了 gohclhclwrite 等,但本质上我在将 hcl 文件转换为 golang 结构方面没有取得任何进展。

我的 terraform 文件(我相信是 hcl 格式)如下:

resource "azurerm_network_security_group" "my_nsg" {
  name                = "my_nsg"
  location            = "loc"
  resource_group_name = "rgname"

  security_rule       = [
           {
               access                                     = "deny"
               description                                = "desc"
               destination_address_prefix                 = "*"
               destination_address_prefixes               = []
               destination_application_security_group_ids = []
               destination_port_range                     = ""
               destination_port_ranges                    = [
                   "123",
                   "456",
                   "789",
                   "1001",
                ]
               direction                                  = "inbound"
               name                                       = "allowinboundthing"
               priority                                   = 100
               protocol                                   = "*"
               source_address_prefix                      = "*"
               source_address_prefixes                    = [
                  # obtain from icanhazip.com
                  "1.2.3.4"
               ]
               source_application_security_group_ids      = []
               source_port_range                          = "*"
               source_port_ranges                         = []
            },
           {
               access                                     = "allow"
               description                                = "grant acccess to app"
               destination_address_prefix                 = "*"
               destination_address_prefixes               = []
               destination_application_security_group_ids = []
               destination_port_range                     = ""
               destination_port_ranges                    = [
                   "443",
                   "80",
                ]
               direction                                  = "inbound"
               name                                       = "allowipinbound"
               priority                                   = 200
               protocol                                   = "*"
               source_address_prefix                      = ""
               source_address_prefixes                    = [
                # obtain from icanhazip.com
                   "1.2.3.4"
                ]
               source_application_security_group_ids      = []
               source_port_range                          = "*"
               source_port_ranges                         = []
            }
        ]
}

这是我用我的 golang 脚本所得到的,试图将上述数据表示为结构,然后解码 .tf 文件本身(我从 hclsimple 本地复制了几个方法,以便拥有它按照其文档中的建议解码 .tf 文件。

package main

import (
    "fmt"
    "io"
    "io/ioutil"
    "log"
    "os"
    "path/filepath"
    "strings"

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

type config struct {
    networksecuritygroup []networksecuritygroup `hcl:"resource,block"`
}

type networksecuritygroup struct {
    type              string         `hcl:"azurerm_network_security_group,label"`
    name              string         `hcl:"mick-linux3-nsg,label"`
    nameattr          string         `hcl:"name"`
    location          string         `hcl:"location"`
    resourcegroupname string         `hcl:"resource_group_name"`
    securityrule      []securityrule `hcl:"security_rule,block"`
}

type securityrule struct {
    access                                 string   `hcl:"access"`
    description                            string   `hcl:"description"`
    destinationaddressprefix               string   `hcl:"destination_address_prefix"`
    destinationaddressprefixes             []string `hcl:"destination_address_prefixes"`
    destinationapplicationsecuritygroupids []string `hcl:"destination_application_security_group_ids"`
    destinationportrange                   string   `hcl:"destination_port_range"`
    destinationportranges                  []string `hcl:"destination_port_ranges"`
    direction                              string   `hcl:"direction"`
    name                                   string   `hcl:"name"`
    priority                               int      `hcl:"priority"`
    protocol                               string   `hcl:"protocol"`
    sourceaddressprefix                    string   `hcl:"source_address_prefix"`
    sourceaddressprefixes                  []string `hcl:"source_address_prefixes"`
    sourceapplicationsecuritygroupids      []string `hcl:"source_application_security_group_ids"`
    sourceportrange                        string   `hcl:"source_port_range"`
    sourceportranges                       []string `hcl:"source_port_ranges"`
}

func main() {
    // lets pass this in as a param?
    configfilepath := "nsg.tf"

    // create new config struct
    var config config

    // this decodes the tf file into the config struct, and hydrates the values
    err := mydecodefile(configfilepath, nil, &config)
    if err != nil {
        log.fatalf("failed to load configuration: %s", err)
    }
    log.printf("configuration is %#v", config)

    // let's read in the file contents
    file, err := os.open(configfilepath)
    if err != nil {
        fmt.printf("failed to read file: %v\n", err)
        return
    }
    defer file.close()

    // read the file and output as a []bytes
    bytes, err := io.readall(file)
    if err != nil {
        fmt.println("error reading file:", err)
        return
    }

    // parse, decode and evaluate the config of the .tf file
    hclsimple.decode(configfilepath, bytes, nil, &config)

    // iterate through the rules until we find one with
    // description = "grant acccess to flask app"

    // code go here
    for _, nsg := range config.networksecuritygroup {
        fmt.printf("security rule: %s", nsg.securityrule)
    }
}

// basically copied from here https://github.com/hashicorp/hcl/blob/v2.16.2/hclsimple/hclsimple.go#l59
// but modified to handle .tf files too
func mydecode(filename string, src []byte, ctx *hcl.evalcontext, target interface{}) error {
    var file *hcl.file
    var diags hcl.diagnostics

    switch suffix := strings.tolower(filepath.ext(filename)); suffix {
    case ".tf":
        file, diags = hclsyntax.parseconfig(src, filename, hcl.pos{line: 1, column: 1})
    case ".hcl":
        file, diags = hclsyntax.parseconfig(src, filename, hcl.pos{line: 1, column: 1})
    case ".json":
        file, diags = json.parse(src, filename)
    default:
        diags = diags.append(&hcl.diagnostic{
            severity: hcl.diagerror,
            summary:  "unsupported file format",
            detail:   fmt.sprintf("cannot read from %s: unrecognized file format suffix %q.", filename, suffix),
        })
        return diags
    }
    if diags.haserrors() {
        return diags
    }

    diags = gohcl.decodebody(file.body, ctx, target)
    if diags.haserrors() {
        return diags
    }
    return nil
}

// taken from here https://github.com/hashicorp/hcl/blob/v2.16.2/hclsimple/hclsimple.go#l89
func mydecodefile(filename string, ctx *hcl.evalcontext, target interface{}) error {
    src, err := ioutil.readfile(filename)
    if err != nil {
        if os.isnotexist(err) {
            return hcl.diagnostics{
                {
                    severity: hcl.diagerror,
                    summary:  "configuration file not found",
                    detail:   fmt.sprintf("the configuration file %s does not exist.", filename),
                },
            }
        }
        return hcl.diagnostics{
            {
                severity: hcl.diagerror,
                summary:  "failed to read configuration",
                detail:   fmt.sprintf("can't read %s: %s.", filename, err),
            },
        }
    }
    return mydecode(filename, src, ctx, target)
}

当我运行代码时,本质上我正在努力定义 networksecuritygroup.securityrule,并使用上述代码收到以下错误:

2023/05/24 11:42:11 Failed to load configuration: nsg.tf:6,3-16: Unsupported argument; An argument named "security_rule" is not expected here. Did you mean to define a block of type "security_rule"?
exit status 1

非常感谢任何建议

解决方法

因此,目前 https://www.php.cn/link/f56de5ef149cf0aedcc8f4797031e229 是不可能的(请参阅这里 https://www.php.cn/link/f56de5ef149cf0aedcc8f4797031e229/issues/50 - 这个建议 hclwrite 本身需要进行更改以方便)

所以我按照@martin atkins 的建议进行了解决:

我创建了一个包含 locals 变量的 locals.tf 文件,然后我在 nsg 安全规则中引用该变量:

locals {
    my_ip = "1.2.3.4"
}

现在我只需获取我的 ip 并使用 sed 更新 locals.tf 文件中的值

my_ip=$(curl -s -4 icanhazip.com)
sed -i "s|my_ip = \".*\"|my_ip = \"$my_ip\"|" locals.tf

以上是如何让 Golang 脚本修改 Terraform(HCL 格式)文件中的值?的详细内容。更多信息请关注PHP中文网其他相关文章!

声明:
本文转载于:stackoverflow.com。如有侵权,请联系admin@php.cn删除