Skip to content

Commit

Permalink
feature(config): Add go-sockaddr templating support to nomad consul a…
Browse files Browse the repository at this point in the history
…ddress
  • Loading branch information
Nkmol committed Feb 19, 2022
1 parent cc3a7bf commit a092991
Show file tree
Hide file tree
Showing 5 changed files with 83 additions and 24 deletions.
28 changes: 5 additions & 23 deletions command/agent/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"github.com/hashicorp/go-sockaddr/template"
client "github.com/hashicorp/nomad/client/config"
"github.com/hashicorp/nomad/helper"
helperConfig "github.com/hashicorp/nomad/helper/config"
"github.com/hashicorp/nomad/nomad"
"github.com/hashicorp/nomad/nomad/structs"
"github.com/hashicorp/nomad/nomad/structs/config"
Expand Down Expand Up @@ -1213,7 +1214,7 @@ func (c *Config) Merge(b *Config) *Config {
// initialized and have reasonable defaults.
func (c *Config) normalizeAddrs() error {
if c.BindAddr != "" {
ipStr, err := parseSingleIPTemplate(c.BindAddr)
ipStr, err := helperConfig.ParseSingleIPTemplate(c.BindAddr)
if err != nil {
return fmt.Errorf("Bind address resolution failed: %v", err)
}
Expand Down Expand Up @@ -1308,25 +1309,6 @@ func parseSingleInterfaceTemplate(tpl string) (string, error) {
return out, nil
}

// parseSingleIPTemplate is used as a helper function to parse out a single IP
// address from a config parameter.
func parseSingleIPTemplate(ipTmpl string) (string, error) {
out, err := template.Parse(ipTmpl)
if err != nil {
return "", fmt.Errorf("Unable to parse address template %q: %v", ipTmpl, err)
}

ips := strings.Split(out, " ")
switch len(ips) {
case 0:
return "", errors.New("No addresses found, please configure one.")
case 1:
return ips[0], nil
default:
return "", fmt.Errorf("Multiple addresses found (%q), please configure one.", out)
}
}

// parseMultipleIPTemplate is used as a helper function to parse out a multiple IP
// addresses from a config parameter.
func parseMultipleIPTemplate(ipTmpl string) ([]string, error) {
Expand All @@ -1350,7 +1332,7 @@ func normalizeBind(addr, bind string) (string, error) {
if addr == "" {
return bind, nil
}
return parseSingleIPTemplate(addr)
return helperConfig.ParseSingleIPTemplate(addr)
}

// normalizeMultipleBind returns normalized bind addresses.
Expand All @@ -1376,7 +1358,7 @@ func normalizeMultipleBind(addr, bind string) ([]string, error) {
//
// Loopback is only considered a valid advertise address in dev mode.
func normalizeAdvertise(addr string, bind string, defport int, dev bool) (string, error) {
addr, err := parseSingleIPTemplate(addr)
addr, err := helperConfig.ParseSingleIPTemplate(addr)
if err != nil {
return "", fmt.Errorf("Error parsing advertise address template: %v", err)
}
Expand Down Expand Up @@ -1417,7 +1399,7 @@ func normalizeAdvertise(addr string, bind string, defport int, dev bool) (string
}

// Bind is not localhost but not a valid advertise IP, use first private IP
addr, err = parseSingleIPTemplate("{{ GetPrivateIP }}")
addr, err = helperConfig.ParseSingleIPTemplate("{{ GetPrivateIP }}")
if err != nil {
return "", fmt.Errorf("Unable to parse default advertise address: %v", err)
}
Expand Down
28 changes: 28 additions & 0 deletions helper/config/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package config

import (
"errors"
"fmt"
"strings"

"github.com/hashicorp/go-sockaddr/template"
)

// ParseSingleIPTemplate is used as a helper function to parse out a single IP
// address from a config parameter.
func ParseSingleIPTemplate(ipTmpl string) (string, error) {
out, err := template.Parse(ipTmpl)
if err != nil {
return "", fmt.Errorf("unable to parse address template %q: %v", ipTmpl, err)
}

ips := strings.Split(out, " ")
switch len(ips) {
case 0:
return "", errors.New("no addresses found, please configure one")
case 1:
return strings.TrimSpace(ips[0]), nil
default:
return "", fmt.Errorf("multiple addresses found (%q), please configure one", out)
}
}
8 changes: 7 additions & 1 deletion nomad/structs/config/consul.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
package config

import (
"fmt"
"net/http"
"strings"
"time"

consul "github.com/hashicorp/consul/api"
"github.com/hashicorp/nomad/helper"
helperConfig "github.com/hashicorp/nomad/helper/config"
)

// ConsulConfig contains the configuration information necessary to
Expand Down Expand Up @@ -251,7 +253,11 @@ func (c *ConsulConfig) ApiConfig() (*consul.Config, error) {
// http.Transport.
config := consul.DefaultConfig()
if c.Addr != "" {
config.Address = c.Addr
ipStr, err := helperConfig.ParseSingleIPTemplate(c.Addr)
if err != nil {
return nil, fmt.Errorf("unable to parse address template %q: %v", c.Addr, err)
}
config.Address = ipStr
}
if c.Token != "" {
config.Token = c.Token
Expand Down
41 changes: 41 additions & 0 deletions nomad/structs/config/consul_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@ import (
"fmt"
"os"
"os/exec"
"strings"
"testing"
"time"

consulapi "github.com/hashicorp/consul/api"
sockaddr "github.com/hashicorp/go-sockaddr"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
Expand Down Expand Up @@ -167,3 +169,42 @@ func TestConsulConfig_Exec(t *testing.T) {
require.NotNil(t, conf.VerifySSL)
assert.True(t, *conf.VerifySSL)
}

func TestConsulConfig_StringAddr(t *testing.T) {
t.Parallel()

conf := ConsulConfig{
Addr: "10.0.1.0:8500",
}

apiConf, err := conf.ApiConfig()
assert.Nil(t, err)
assert.Equal(t, apiConf.Address, "10.0.1.0:8500")
}

func TestConsulConfig_SockAddr(t *testing.T) {
t.Parallel()

privateIps, err := sockaddr.GetPrivateIP()
if err != nil {
t.Fatalf("failed to get private IPs: %v", err)
}
privateIp := strings.Split(privateIps, " ")[0]
conf := ConsulConfig{
Addr: "{{ GetPrivateIP }}:8500",
}

apiConf, err := conf.ApiConfig()
assert.Nil(t, err)
assert.Equal(t, apiConf.Address, privateIp+":8500")
}

func TestConsulConfig_SockAddrOnlyOneIP(t *testing.T) {
conf := ConsulConfig{
Addr: "{{ GetPrivateIPs }}",
}

result, err := conf.ApiConfig()
assert.Nil(t, result)
assert.NotNil(t, err)
}
2 changes: 2 additions & 0 deletions website/content/docs/configuration/consul.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ configuring Nomad to talk to Consul via DNS such as consul.service.consul
Consul agent, given in the format `host:port`. Supports Unix sockets with the
format: `unix:///tmp/consul/consul.sock`. Will default to the
`CONSUL_HTTP_ADDR` environment variable if set.
The value supports [go-sockaddr/template format][go-sockaddr/template].

- `allow_unauthenticated` `(bool: true)` - Specifies if users submitting jobs to
the Nomad server should be required to provide their own Consul token, proving
Expand Down Expand Up @@ -225,3 +226,4 @@ namespace "nomad-ns" {

[consul]: https://www.consul.io/ 'Consul by HashiCorp'
[bootstrap]: https://learn.hashicorp.com/tutorials/nomad/clustering 'Automatic Bootstrapping'
[go-sockaddr/template]: https://godoc.org/github.com/hashicorp/go-sockaddr/template

0 comments on commit a092991

Please sign in to comment.