mirror of
https://github.com/adammck/terraform-inventory
synced 2025-04-10 06:53:28 +02:00
Fix parsing index
field in case of non-numeric string (as allowed in for_each
construct), fix sorting (#153)
* Fix parsing `index` field in case of non-numeric string (as allowed in `for_each` construct), fix sorting * Use newer Go versions in CI so functions like `errors.Unwrap` are available
This commit is contained in:
parent
bb01111c63
commit
8b4b0ccdc0
@ -4,8 +4,7 @@ env:
|
||||
- GO111MODULE=on
|
||||
|
||||
go:
|
||||
- "1.8"
|
||||
- "1.11.x"
|
||||
- "1.13"
|
||||
- "1.x" # latest
|
||||
|
||||
script:
|
||||
|
25
cli.go
25
cli.go
@ -6,6 +6,7 @@ import (
|
||||
"io"
|
||||
"os"
|
||||
"sort"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type counterSorter struct {
|
||||
@ -21,7 +22,7 @@ func (cs counterSorter) Swap(i, j int) {
|
||||
}
|
||||
|
||||
func (cs counterSorter) Less(i, j int) bool {
|
||||
return cs.resources[i].counter < cs.resources[j].counter
|
||||
return cs.resources[i].counterNumeric < cs.resources[j].counterNumeric || (cs.resources[i].counterNumeric == cs.resources[j].counterNumeric && cs.resources[i].counterStr < cs.resources[j].counterStr)
|
||||
}
|
||||
|
||||
type allGroup struct {
|
||||
@ -74,8 +75,13 @@ func gatherResourcesPre0dot12(s *state) map[string]interface{} {
|
||||
|
||||
unsortedOrdered[res.baseName] = append(unsortedOrdered[res.baseName], res)
|
||||
|
||||
// store as invdividual host (eg. <name>_<count>)
|
||||
invdName := fmt.Sprintf("%s_%d", res.baseName, res.counter)
|
||||
// store as individual host (e.g. <name>_<count>)
|
||||
var invdName string
|
||||
if res.counterStr != "" {
|
||||
invdName = fmt.Sprintf("%s_%s", res.baseName, strings.Replace(res.counterStr, ".", "_", -1))
|
||||
} else {
|
||||
invdName = fmt.Sprintf("%s_%d", res.baseName, res.counterNumeric)
|
||||
}
|
||||
if old, exists := individual[invdName]; exists {
|
||||
fmt.Fprintf(os.Stderr, "overwriting already existing individual key %s, old: %v, new: %v\n", invdName, old, res.Hostname())
|
||||
}
|
||||
@ -161,11 +167,17 @@ func gatherResources0dot12(s *stateTerraform0dot12) map[string]interface{} {
|
||||
// place in list of resource types
|
||||
tp := fmt.Sprintf("type_%s", res.resourceType)
|
||||
types[tp] = appendUniq(types[tp], res.Hostname())
|
||||
sort.Strings(types[tp])
|
||||
|
||||
unsortedOrdered[res.baseName] = append(unsortedOrdered[res.baseName], res)
|
||||
|
||||
// store as invdividual host (eg. <name>_<count>)
|
||||
invdName := fmt.Sprintf("%s_%d", res.baseName, res.counter)
|
||||
// store as individual host (e.g. <name>_<count>)
|
||||
var invdName string
|
||||
if res.counterStr != "" {
|
||||
invdName = fmt.Sprintf("%s_%s", res.baseName, strings.Replace(res.counterStr, ".", "_", -1))
|
||||
} else {
|
||||
invdName = fmt.Sprintf("%s_%d", res.baseName, res.counterNumeric)
|
||||
}
|
||||
if old, exists := individual[invdName]; exists {
|
||||
fmt.Fprintf(os.Stderr, "overwriting already existing individual key %s, old: %v, new: %v", invdName, old, res.Hostname())
|
||||
}
|
||||
@ -183,9 +195,12 @@ func gatherResources0dot12(s *stateTerraform0dot12) map[string]interface{} {
|
||||
tag = resourceIDNames[v]
|
||||
}
|
||||
tags[tag] = appendUniq(tags[tag], res.Hostname())
|
||||
sort.Strings(tags[tag])
|
||||
}
|
||||
}
|
||||
|
||||
sort.Strings(all.Hosts)
|
||||
|
||||
// inventorize outputs as variables
|
||||
if len(s.outputs()) > 0 {
|
||||
for _, out := range s.outputs() {
|
||||
|
@ -340,7 +340,7 @@ func (s *stateTerraform0dot12) resources() []*Resource {
|
||||
case float64:
|
||||
resourceKeyName += "." + strconv.Itoa(int(v))
|
||||
case string:
|
||||
resourceKeyName += "." + v
|
||||
resourceKeyName += "." + strings.Replace(v, ".", "_", -1)
|
||||
default:
|
||||
fmt.Fprintf(os.Stderr, "Warning: unknown index type %v\n", v)
|
||||
}
|
||||
|
@ -1190,6 +1190,41 @@ const exampleStateFileTerraform0dot12 = `
|
||||
}
|
||||
],
|
||||
"address": "module.my-module-three"
|
||||
},
|
||||
{
|
||||
"resources": [
|
||||
{
|
||||
"address": "aws_instance.host",
|
||||
"type": "aws_instance",
|
||||
"name": "host",
|
||||
"index": "for_each_example.first",
|
||||
"values": {
|
||||
"ami": "ami-00000000000000001",
|
||||
"id": "i-44444444444444444",
|
||||
"private_ip": "10.0.0.4",
|
||||
"public_ip": "",
|
||||
"tags": {
|
||||
"Name": "four-aws-instance"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"address": "aws_instance.host",
|
||||
"type": "aws_instance",
|
||||
"name": "host",
|
||||
"index": "for_each_example.second",
|
||||
"values": {
|
||||
"ami": "ami-00000000000000001",
|
||||
"id": "i-11144444444444444",
|
||||
"private_ip": "10.0.1.4",
|
||||
"public_ip": "",
|
||||
"tags": {
|
||||
"Name": "four-aws-instance"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"address": "module.my-module-four"
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -1203,9 +1238,11 @@ const expectedListOutputTerraform0dot12 = `
|
||||
"hosts": [
|
||||
"10.0.0.2",
|
||||
"10.0.0.3",
|
||||
"10.0.0.4",
|
||||
"10.0.1.3",
|
||||
"35.159.25.34",
|
||||
"12.34.56.78"
|
||||
"10.0.1.4",
|
||||
"12.34.56.78",
|
||||
"35.159.25.34"
|
||||
],
|
||||
"vars": {
|
||||
"my_endpoint": "a.b.c.d.example.com",
|
||||
@ -1215,14 +1252,18 @@ const expectedListOutputTerraform0dot12 = `
|
||||
},
|
||||
"one_0": ["35.159.25.34"],
|
||||
"one": ["35.159.25.34"],
|
||||
"module_my-module-four_host_for_each_example_first": ["10.0.0.4"],
|
||||
"module_my-module-four_host_for_each_example_second": ["10.0.1.4"],
|
||||
"module_my-module-four_host": ["10.0.0.4", "10.0.1.4"],
|
||||
"module_my-module-two_host_0": ["10.0.0.2"],
|
||||
"module_my-module-two_host": ["10.0.0.2"],
|
||||
"module_my-module-three_host_0": ["10.0.0.3"],
|
||||
"module_my-module-three_host_1": ["10.0.1.3"],
|
||||
"module_my-module-three_host": ["10.0.0.3", "10.0.1.3"],
|
||||
|
||||
"type_aws_instance": ["10.0.0.2", "10.0.0.3", "10.0.1.3", "35.159.25.34"],
|
||||
"type_aws_instance": ["10.0.0.2", "10.0.0.3", "10.0.0.4", "10.0.1.3", "10.0.1.4", "35.159.25.34"],
|
||||
|
||||
"name_four-aws-instance": ["10.0.0.4", "10.0.1.4"],
|
||||
"name_one-aws-instance": ["35.159.25.34"],
|
||||
"name_two-aws-instance": ["10.0.0.2"],
|
||||
"name_three-aws-instance": ["10.0.0.3", "10.0.1.3"],
|
||||
@ -1237,9 +1278,11 @@ const expectedListOutputTerraform0dot12 = `
|
||||
const expectedInventoryOutputTerraform0dot12 = `[all]
|
||||
10.0.0.2
|
||||
10.0.0.3
|
||||
10.0.0.4
|
||||
10.0.1.3
|
||||
35.159.25.34
|
||||
10.0.1.4
|
||||
12.34.56.78
|
||||
35.159.25.34
|
||||
|
||||
[all:vars]
|
||||
map={"first":"a","second":"b"}
|
||||
@ -1249,6 +1292,16 @@ my_password="1234"
|
||||
[foo_bar]
|
||||
12.34.56.78
|
||||
|
||||
[module_my-module-four_host]
|
||||
10.0.0.4
|
||||
10.0.1.4
|
||||
|
||||
[module_my-module-four_host_for_each_example_first]
|
||||
10.0.0.4
|
||||
|
||||
[module_my-module-four_host_for_each_example_second]
|
||||
10.0.1.4
|
||||
|
||||
[module_my-module-three_host]
|
||||
10.0.0.3
|
||||
10.0.1.3
|
||||
@ -1265,6 +1318,10 @@ my_password="1234"
|
||||
[module_my-module-two_host_0]
|
||||
10.0.0.2
|
||||
|
||||
[name_four-aws-instance]
|
||||
10.0.0.4
|
||||
10.0.1.4
|
||||
|
||||
[name_one-aws-instance]
|
||||
35.159.25.34
|
||||
|
||||
@ -1284,7 +1341,9 @@ my_password="1234"
|
||||
[type_aws_instance]
|
||||
10.0.0.2
|
||||
10.0.0.3
|
||||
10.0.0.4
|
||||
10.0.1.3
|
||||
10.0.1.4
|
||||
35.159.25.34
|
||||
|
||||
[type_vsphere_virtual_machine]
|
||||
|
36
resource.go
36
resource.go
@ -61,7 +61,13 @@ type Resource struct {
|
||||
// Extracted from keyName
|
||||
resourceType string
|
||||
baseName string
|
||||
counter int
|
||||
|
||||
// counterNumeric is 0 for resources created without `count=` attribute or
|
||||
// having a non-numeric string index
|
||||
counterNumeric int
|
||||
// counterStr is set if the resource index (e.g. in `for_each`-constructed
|
||||
// resources) is not a number.
|
||||
counterStr string
|
||||
}
|
||||
|
||||
func NewResource(keyName string, state resourceState) (*Resource, error) {
|
||||
@ -72,24 +78,28 @@ func NewResource(keyName string, state resourceState) (*Resource, error) {
|
||||
return nil, fmt.Errorf("couldn't parse resource keyName: %s", keyName)
|
||||
}
|
||||
|
||||
var c int
|
||||
counterNumeric := 0
|
||||
counterStr := ""
|
||||
var err error
|
||||
if m[3] != "" {
|
||||
// The third section should be the index, if it's present. Not sure what
|
||||
// else we can do other than panic (which seems highly undesirable) if that
|
||||
// isn't the case. With Terraform 0.12 for_each syntax, index is a string.
|
||||
c, err = strconv.Atoi(m[3])
|
||||
// isn't the case. With Terraform 0.12 for_each syntax, index can also be
|
||||
// a non-numeric string (loop over any string value).
|
||||
counterNumeric, err = strconv.Atoi(m[3])
|
||||
if err != nil {
|
||||
m[2] = fmt.Sprintf("%s.%s", m[2], m[3])
|
||||
counterNumeric = 0
|
||||
counterStr = m[3]
|
||||
}
|
||||
}
|
||||
|
||||
return &Resource{
|
||||
State: state,
|
||||
keyName: keyName,
|
||||
resourceType: m[1],
|
||||
baseName: m[2],
|
||||
counter: c,
|
||||
State: state,
|
||||
keyName: keyName,
|
||||
resourceType: m[1],
|
||||
baseName: m[2],
|
||||
counterNumeric: counterNumeric,
|
||||
counterStr: counterStr,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@ -210,12 +220,6 @@ func (r Resource) Attributes() map[string]string {
|
||||
return r.State.Primary.Attributes
|
||||
}
|
||||
|
||||
// NameWithCounter returns the resource name with its counter. For resources
|
||||
// created without a 'count=' attribute, this will always be zero.
|
||||
func (r Resource) NameWithCounter() string {
|
||||
return fmt.Sprintf("%s.%d", r.baseName, r.counter)
|
||||
}
|
||||
|
||||
// Hostname returns the hostname of this resource.
|
||||
func (r Resource) Hostname() string {
|
||||
if keyName := os.Getenv("TF_HOSTNAME_KEY_NAME"); keyName != "" {
|
||||
|
Loading…
Reference in New Issue
Block a user