Envoy CLI bind addresses (#6107)
* Ensure we MapWalk the proxy config in the NodeService and ServiceNode structs This gets rid of some json encoder errors in the catalog endpoints * Allow passing explicit bind addresses to envoy * Move map walking to the ConnectProxyConfig struct Any place where this struct gets JSON encoded will benefit as opposed to having to implement it everywhere. * Fail when a non-empty address is provided and not bindable * camel case * Update command/connect/envoy/envoy.go Co-Authored-By: Paul Banks <banks@banksco.de>
This commit is contained in:
parent
c7df80ebf9
commit
63c344727c
|
@ -1,9 +1,11 @@
|
|||
package structs
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/hashicorp/consul/api"
|
||||
"github.com/hashicorp/consul/lib"
|
||||
)
|
||||
|
||||
type MeshGatewayMode string
|
||||
|
@ -81,6 +83,19 @@ type ConnectProxyConfig struct {
|
|||
MeshGateway MeshGatewayConfig `json:",omitempty"`
|
||||
}
|
||||
|
||||
func (c *ConnectProxyConfig) MarshalJSON() ([]byte, error) {
|
||||
type typeCopy ConnectProxyConfig
|
||||
copy := typeCopy(*c)
|
||||
|
||||
proxyConfig, err := lib.MapWalk(copy.Config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
copy.Config = proxyConfig
|
||||
|
||||
return json.Marshal(©)
|
||||
}
|
||||
|
||||
// ToAPI returns the api struct with the same fields. We have duplicates to
|
||||
// avoid the api package depending on this one which imports a ton of Consul's
|
||||
// core which you don't want if you are just trying to use our client in your
|
||||
|
|
|
@ -1535,3 +1535,48 @@ func TestCheckServiceNode_BestAddress(t *testing.T) {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestNodeService_JSON_Marshal(t *testing.T) {
|
||||
ns := &NodeService{
|
||||
Service: "foo",
|
||||
Proxy: ConnectProxyConfig{
|
||||
Config: map[string]interface{}{
|
||||
"bind_addresses": map[string]interface{}{
|
||||
"default": map[string]interface{}{
|
||||
"Address": "0.0.0.0",
|
||||
"Port": "443",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
buf, err := json.Marshal(ns)
|
||||
require.NoError(t, err)
|
||||
|
||||
var out NodeService
|
||||
require.NoError(t, json.Unmarshal(buf, &out))
|
||||
require.Equal(t, *ns, out)
|
||||
}
|
||||
|
||||
func TestServiceNode_JSON_Marshal(t *testing.T) {
|
||||
sn := &ServiceNode{
|
||||
Node: "foo",
|
||||
ServiceName: "foo",
|
||||
ServiceProxy: ConnectProxyConfig{
|
||||
Config: map[string]interface{}{
|
||||
"bind_addresses": map[string]interface{}{
|
||||
"default": map[string]interface{}{
|
||||
"Address": "0.0.0.0",
|
||||
"Port": "443",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
buf, err := json.Marshal(sn)
|
||||
require.NoError(t, err)
|
||||
|
||||
var out ServiceNode
|
||||
require.NoError(t, json.Unmarshal(buf, &out))
|
||||
require.Equal(t, *sn, out)
|
||||
}
|
||||
|
|
|
@ -61,6 +61,7 @@ type cmd struct {
|
|||
address string
|
||||
wanAddress string
|
||||
deregAfterCritical string
|
||||
bindAddresses map[string]string
|
||||
|
||||
meshGatewaySvcName string
|
||||
}
|
||||
|
@ -117,6 +118,10 @@ func (c *cmd) init() {
|
|||
c.flags.StringVar(&c.wanAddress, "wan-address", "",
|
||||
"WAN address to advertise in the Mesh Gateway service registration")
|
||||
|
||||
c.flags.Var((*flags.FlagMapValue)(&c.bindAddresses), "bind-address", "Bind "+
|
||||
"address to use instead of the default binding rules given as `<name>=<ip>:<port>` "+
|
||||
"pairs. This flag may be specified multiple times to add multiple bind addresses.")
|
||||
|
||||
c.flags.StringVar(&c.meshGatewaySvcName, "service", "mesh-gateway",
|
||||
"Service name to use for the registration")
|
||||
|
||||
|
@ -160,6 +165,31 @@ func parseAddress(addrStr string) (string, int, error) {
|
|||
return addr, port, nil
|
||||
}
|
||||
|
||||
func canBind(addr string) bool {
|
||||
if addr == "" {
|
||||
return false
|
||||
}
|
||||
|
||||
ip := net.ParseIP(addr)
|
||||
if ip == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
ifAddrs, err := net.InterfaceAddrs()
|
||||
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
for _, addr := range ifAddrs {
|
||||
if addr.String() == ip.String() {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func (c *cmd) Run(args []string) int {
|
||||
if err := c.flags.Parse(args); err != nil {
|
||||
return 1
|
||||
|
@ -215,8 +245,10 @@ func (c *cmd) Run(args []string) int {
|
|||
taggedAddrs["lan"] = api.ServiceAddress{Address: lanAddr, Port: lanPort}
|
||||
}
|
||||
|
||||
wanAddr := ""
|
||||
wanPort := lanPort
|
||||
if c.wanAddress != "" {
|
||||
wanAddr, wanPort, err := parseAddress(c.wanAddress)
|
||||
wanAddr, wanPort, err = parseAddress(c.wanAddress)
|
||||
if err != nil {
|
||||
c.UI.Error(fmt.Sprintf("Failed to parse the -wan-address parameter: %v", err))
|
||||
return 1
|
||||
|
@ -233,13 +265,38 @@ func (c *cmd) Run(args []string) int {
|
|||
|
||||
var proxyConf *api.AgentServiceConnectProxyConfig
|
||||
|
||||
if lanAddr != "" {
|
||||
if len(c.bindAddresses) > 0 {
|
||||
// override all default binding rules and just bind to the user-supplied addresses
|
||||
bindAddresses := make(map[string]api.ServiceAddress)
|
||||
|
||||
for addrName, addrStr := range c.bindAddresses {
|
||||
addr, port, err := parseAddress(addrStr)
|
||||
if err != nil {
|
||||
c.UI.Error(fmt.Sprintf("Failed to parse the bind address: %s=%s: %v", addrName, addrStr, err))
|
||||
return 1
|
||||
}
|
||||
|
||||
bindAddresses[addrName] = api.ServiceAddress{Address: addr, Port: port}
|
||||
}
|
||||
|
||||
proxyConf = &api.AgentServiceConnectProxyConfig{
|
||||
Config: map[string]interface{}{
|
||||
"envoy_mesh_gateway_no_default_bind": true,
|
||||
"envoy_mesh_gateway_bind_addresses": bindAddresses,
|
||||
},
|
||||
}
|
||||
} else if canBind(lanAddr) && canBind(wanAddr) {
|
||||
// when both addresses are bindable then we bind to the tagged addresses
|
||||
// for creating the envoy listeners
|
||||
proxyConf = &api.AgentServiceConnectProxyConfig{
|
||||
Config: map[string]interface{}{
|
||||
"envoy_mesh_gateway_no_default_bind": true,
|
||||
"envoy_mesh_gateway_bind_tagged_addresses": true,
|
||||
},
|
||||
}
|
||||
} else if !canBind(lanAddr) && lanAddr != "" {
|
||||
c.UI.Error(fmt.Sprintf("The LAN address %q will not be bindable. Either set a bindable address or override the bind addresses with -bind-address", lanAddr))
|
||||
return 1
|
||||
}
|
||||
|
||||
svc := api.AgentServiceRegistration{
|
||||
|
|
Loading…
Reference in New Issue