1
1
mirror of https://github.com/adammck/terraform-inventory synced 2024-11-26 07:43:46 +01:00

Add TF_HOSTNAME_KEY_NAME to specify which hostname to return (#94)

Overwrite with the environment variable TF_HOSTNAME_KEY_NAME which attribute is to be used for the ansible inventory name. By default, the IP address is used. The Ansible variable "ansible_host" is used to connect to the host.
This commit is contained in:
Christian Groschupp 2018-09-20 16:22:53 +02:00 committed by Adam Mckaig
parent 842b8f7278
commit 2365c9b801
4 changed files with 94 additions and 8 deletions

@ -147,6 +147,11 @@ to `private_ip` before running the playbook, like:
TF_KEY_NAME=private_ip ansible-playbook --inventory-file=/path/to/terraform-inventory deploy/playbook.yml
By default, the ip address is the ansible inventory name. The `TF_HOSTNAME_KEY_NAME` environment variable allows
you to overwrite the source of the ansible inventory name.
TF_HOSTNAME_KEY_NAME=name ansible-playbook --inventory-file=/path/to/terraform-inventory deploy/playbook.yml
## Development
It's just a Go app, so the usual:

18
cli.go

@ -55,20 +55,20 @@ func gatherResources(s *state) map[string]interface{} {
for _, res := range s.resources() {
// place in list of all resources
all.Hosts = appendUniq(all.Hosts, res.Address())
all.Hosts = appendUniq(all.Hosts, res.Hostname())
// place in list of resource types
tp := fmt.Sprintf("type_%s", res.resourceType)
types[tp] = appendUniq(types[tp], res.Address())
types[tp] = appendUniq(types[tp], res.Hostname())
unsortedOrdered[res.baseName] = append(unsortedOrdered[res.baseName], res)
// store as invdividual host (eg. <name>.<count>)
invdName := fmt.Sprintf("%s.%d", res.baseName, res.counter)
if old, exists := individual[invdName]; exists {
fmt.Fprintf(os.Stderr, "overwriting already existing individual key %s, old: %v, new: %v", invdName, old, res.Address())
fmt.Fprintf(os.Stderr, "overwriting already existing individual key %s, old: %v, new: %v", invdName, old, res.Hostname())
}
individual[invdName] = []string{res.Address()}
individual[invdName] = []string{res.Hostname()}
// inventorize tags
for k, v := range res.Tags() {
@ -77,7 +77,7 @@ func gatherResources(s *state) map[string]interface{} {
if v != "" {
tag = fmt.Sprintf("%s_%s", k, v)
}
tags[tag] = appendUniq(tags[tag], res.Address())
tags[tag] = appendUniq(tags[tag], res.Hostname())
}
}
@ -94,7 +94,7 @@ func gatherResources(s *state) map[string]interface{} {
sort.Sort(cs)
for i := range resources {
ordered[basename] = append(ordered[basename], resources[i].Address())
ordered[basename] = append(ordered[basename], resources[i].Hostname())
}
}
@ -187,8 +187,10 @@ func checkErr(err error, stderr io.Writer) int {
func cmdHost(stdout io.Writer, stderr io.Writer, s *state, hostname string) int {
for _, res := range s.resources() {
if hostname == res.Address() {
return output(stdout, stderr, res.Attributes())
if hostname == res.Hostname() {
attributes := res.Attributes()
attributes["ansible_host"] = res.Address()
return output(stdout, stderr, attributes)
}
}

@ -3,12 +3,52 @@ package main
import (
"bytes"
"encoding/json"
"os"
"strings"
"testing"
"github.com/stretchr/testify/assert"
)
const exampleStateFileEnvHostname = `
{
"version": 1,
"serial": 1,
"modules": [
{
"resources": {
"libvirt_domain.fourteen": {
"type": "libvirt_domain",
"primary": {
"id": "824c29be-2164-44c8-83e0-787705571d95",
"attributes": {
"name": "fourteen",
"network_interface.#": "1",
"network_interface.0.addresses.#": "1",
"network_interface.0.addresses.0": "192.168.102.14",
"network_interface.0.mac": "96:EE:4D:BD:B2:45"
}
}
}
}
}
]
}`
const expectedListOutputEnvHostname = `
{
"all": {
"hosts": [
"fourteen"
],
"vars": {
}
},
"fourteen": ["fourteen"],
"fourteen.0": ["fourteen"],
"type_libvirt_domain": ["fourteen"]
}`
const exampleStateFile = `
{
"version": 1,
@ -633,6 +673,7 @@ olddatacenter="\u003c0.7_format"
const expectedHostOneOutput = `
{
"ansible_host": "10.0.0.1",
"id":"i-aaaaaaaa",
"private_ip":"10.0.0.1",
"tags.#": "1",
@ -665,6 +706,33 @@ func TestListCommand(t *testing.T) {
assert.Equal(t, exp, act)
}
func TestListCommandEnvHostname(t *testing.T) {
var s state
r := strings.NewReader(exampleStateFileEnvHostname)
err := s.read(r)
assert.NoError(t, err)
// Decode expectation as JSON
var exp interface{}
err = json.Unmarshal([]byte(expectedListOutputEnvHostname), &exp)
assert.NoError(t, err)
// Run the command, capture the output
var stdout, stderr bytes.Buffer
os.Setenv("TF_HOSTNAME_KEY_NAME", "name")
exitCode := cmdList(&stdout, &stderr, &s)
os.Unsetenv("TF_HOSTNAME_KEY_NAME")
assert.Equal(t, 0, exitCode)
assert.Equal(t, "", stderr.String())
// Decode the output to compare
var act interface{}
err = json.Unmarshal([]byte(stdout.String()), &act)
assert.NoError(t, err)
assert.Equal(t, exp, act)
}
func TestHostCommand(t *testing.T) {
var s state
r := strings.NewReader(exampleStateFile)

@ -164,6 +164,17 @@ 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 != "" {
if ip := r.State.Primary.Attributes[keyName]; ip != "" {
return ip
}
}
return r.Address()
}
// Address returns the IP address of this resource.
func (r Resource) Address() string {
if keyName := os.Getenv("TF_KEY_NAME"); keyName != "" {