


How can I have a Golang script modify values in a Terraform (HCL format) file?
php Xiaobian Youzi teaches you how to use Golang script to modify the value in the Terraform (HCL format) file. Terraform is an infrastructure-as-code tool that helps us manage and automate cloud infrastructure. However, if we need to frequently modify certain values in the Terraform file, manual operations will become very tedious. Therefore, using Golang scripts to modify values in Terraform files will be a more efficient method. In this article, I will show you how to write a script using Golang to achieve this goal, so that you can easily modify the values in the Terraform file.
Question content
I'm trying to do a small amount of automation on a terraform file I have that defines an azure network security group. Essentially, I have a website and ssh access, I just want to allow my public ip address, which I can get from icanhazip.com
. I want to use a golang script to write my ip to the relevant part of a .tf file (essentially setting the value of security_rule.source_address_prefixes
).
I am trying to use hclsimple
library in golang and tried gohcl
, hclwrite
etc. but essentially I am converting hcl file to golang No progress was made on the structure.
My terraform file (in hcl format I believe) is as follows:
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 = [] } ] }
This is what I got with my golang script trying to represent the above data as a structure and then decoding the .tf file itself (I copied a few methods locally from hclsimple
in order to have it as per Recommendations in its documentation decode .tf files.
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) }
When I run the code, essentially I am trying to define the networksecuritygroup.securityrule, and receive the following error using the above code:
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
Any suggestions are greatly appreciated
Workarounds
Therefore, currently https://www.php.cn/link/f56de5ef149cf0aedcc8f4797031e229 is not possible (see Herehttps://www.php.cn/link/f56de5ef149cf0aedcc8f4797031e229/issues/50 - This suggestionhclwrite
itself needs to be changed for convenience)
So I solved it as @martin atkins suggested:
I created a locals.tf
file containing the locals variable, which I then referenced in the nsg security rule:
locals { my_ip = "1.2.3.4" }
Now I just get my ip and update the value in the locals.tf file using sed
my_ip=$(curl -s -4 icanhazip.com) sed -i "s|my_ip = \".*\"|my_ip = \"$my_ip\"|" locals.tf
The above is the detailed content of How can I have a Golang script modify values in a Terraform (HCL format) file?. For more information, please follow other related articles on the PHP Chinese website!

Hot AI Tools

Undresser.AI Undress
AI-powered app for creating realistic nude photos

AI Clothes Remover
Online AI tool for removing clothes from photos.

Undress AI Tool
Undress images for free

Clothoff.io
AI clothes remover

AI Hentai Generator
Generate AI Hentai for free.

Hot Article

Hot Tools

Notepad++7.3.1
Easy-to-use and free code editor

SublimeText3 Chinese version
Chinese version, very easy to use

Zend Studio 13.0.1
Powerful PHP integrated development environment

Dreamweaver CS6
Visual web development tools

SublimeText3 Mac version
God-level code editing software (SublimeText3)

Hot Topics

The article explains how to use the pprof tool for analyzing Go performance, including enabling profiling, collecting data, and identifying common bottlenecks like CPU and memory issues.Character count: 159

The article discusses writing unit tests in Go, covering best practices, mocking techniques, and tools for efficient test management.

This article demonstrates creating mocks and stubs in Go for unit testing. It emphasizes using interfaces, provides examples of mock implementations, and discusses best practices like keeping mocks focused and using assertion libraries. The articl

This article explores Go's custom type constraints for generics. It details how interfaces define minimum type requirements for generic functions, improving type safety and code reusability. The article also discusses limitations and best practices

This article explores using tracing tools to analyze Go application execution flow. It discusses manual and automatic instrumentation techniques, comparing tools like Jaeger, Zipkin, and OpenTelemetry, and highlighting effective data visualization

The article discusses Go's reflect package, used for runtime manipulation of code, beneficial for serialization, generic programming, and more. It warns of performance costs like slower execution and higher memory use, advising judicious use and best

The article discusses using table-driven tests in Go, a method that uses a table of test cases to test functions with multiple inputs and outcomes. It highlights benefits like improved readability, reduced duplication, scalability, consistency, and a

The article discusses managing Go module dependencies via go.mod, covering specification, updates, and conflict resolution. It emphasizes best practices like semantic versioning and regular updates.
