Skip to content

Commit

Permalink
Merge pull request #260 from hashicorp/service-address-resolve
Browse files Browse the repository at this point in the history
Resolve hostnames in service-address command
  • Loading branch information
lkysow authored May 13, 2020
2 parents 993ecf8 + f4344bc commit 0a42363
Show file tree
Hide file tree
Showing 2 changed files with 64 additions and 5 deletions.
29 changes: 28 additions & 1 deletion subcommand/service-address/command.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"flag"
"fmt"
"io/ioutil"
"net"
"os"
"sync"
"time"
Expand Down Expand Up @@ -103,7 +104,13 @@ func (c *Command) Run(args []string) int {
address = ingr.IP
return nil
} else if ingr.Hostname != "" {
address = ingr.Hostname
// todo: for now we're resolving this hostname to an IP
// because Consul doesn't yet support hostnames for its mesh
// gateway addresses. We will want to remove this when it's
// supported because in the case of EKS (the only cloud
// that returns hostnames for its LBs) the IPs may change
// so only the hostname is safe.
address, unretryableErr = resolveHostname(ingr.Hostname)
return nil
}
}
Expand Down Expand Up @@ -149,6 +156,26 @@ func (c *Command) validateFlags(args []string) error {
return nil
}

// resolveHostname returns the first ipv4 address for host.
func resolveHostname(host string) (string, error) {
ips, err := net.LookupIP(host)
if err != nil {
return "", fmt.Errorf("unable to resolve hostname: %s", err)
}
if len(ips) < 1 {
return "", fmt.Errorf("hostname %q had no resolveable IPs", host)
}

for _, ip := range ips {
v4 := ip.To4()
if v4 == nil {
continue
}
return ip.String(), nil
}
return "", fmt.Errorf("hostname %q had no ipv4 IPs", host)
}

// withErrLogger runs op and logs if op returns an error.
// It returns the result of op.
func withErrLogger(log hclog.Logger, op func() error) func() error {
Expand Down
40 changes: 36 additions & 4 deletions subcommand/service-address/command_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,10 +78,41 @@ func TestRun_UnableToWriteToFile(t *testing.T) {
"Unable to write address to file: open /this/filepath/does/not/exist: no such file or directory")
}

func TestRun_UnresolvableHostname(t *testing.T) {
t.Parallel()
require := require.New(t)

k8sNS := "default"
svcName := "service-name"

// Create the service.
k8s := fake.NewSimpleClientset()
_, err := k8s.CoreV1().Services(k8sNS).Create(kubeLoadBalancerSvc(svcName, "", "unresolvable"))
require.NoError(err)

// Run command.
ui := cli.NewMockUi()
cmd := Command{
UI: ui,
k8sClient: k8s,
}
tmpDir, err := ioutil.TempDir("", "")
require.NoError(err)
defer os.RemoveAll(tmpDir)
outputFile := filepath.Join(tmpDir, "address.txt")

responseCode := cmd.Run([]string{
"-k8s-namespace", k8sNS,
"-name", svcName,
"-output-file", outputFile,
})
require.Equal(1, responseCode)
require.Contains(ui.ErrorWriter.String(), "Unable to get service address: unable to resolve hostname:")
}

// Test running with different service types.
func TestRun_ServiceTypes(t *testing.T) {
t.Parallel()
require := require.New(t)

// All services will have the name "service-name"
cases := map[string]struct {
Expand All @@ -103,8 +134,8 @@ func TestRun_ServiceTypes(t *testing.T) {
ExpAddress: "1.2.3.4",
},
"LoadBalancer Hostname": {
Service: kubeLoadBalancerSvc("service-name", "", "example.com"),
ExpAddress: "example.com",
Service: kubeLoadBalancerSvc("service-name", "", "localhost"),
ExpAddress: "127.0.0.1",
},
"LoadBalancer IP and hostname": {
Service: kubeLoadBalancerSvc("service-name", "1.2.3.4", "example.com"),
Expand Down Expand Up @@ -140,7 +171,8 @@ func TestRun_ServiceTypes(t *testing.T) {
}

for name, c := range cases {
t.Run(name, func(t *testing.T) {
t.Run(name, func(tt *testing.T) {
require := require.New(tt)
k8sNS := "default"
svcName := "service-name"

Expand Down

0 comments on commit 0a42363

Please sign in to comment.