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
|
package structs
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/hashicorp/consul/api"
|
"github.com/hashicorp/consul/api"
|
||||||
|
"github.com/hashicorp/consul/lib"
|
||||||
)
|
)
|
||||||
|
|
||||||
type MeshGatewayMode string
|
type MeshGatewayMode string
|
||||||
|
@ -81,6 +83,19 @@ type ConnectProxyConfig struct {
|
||||||
MeshGateway MeshGatewayConfig `json:",omitempty"`
|
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
|
// 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
|
// 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
|
// 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
|
address string
|
||||||
wanAddress string
|
wanAddress string
|
||||||
deregAfterCritical string
|
deregAfterCritical string
|
||||||
|
bindAddresses map[string]string
|
||||||
|
|
||||||
meshGatewaySvcName string
|
meshGatewaySvcName string
|
||||||
}
|
}
|
||||||
|
@ -117,6 +118,10 @@ func (c *cmd) init() {
|
||||||
c.flags.StringVar(&c.wanAddress, "wan-address", "",
|
c.flags.StringVar(&c.wanAddress, "wan-address", "",
|
||||||
"WAN address to advertise in the Mesh Gateway service registration")
|
"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",
|
c.flags.StringVar(&c.meshGatewaySvcName, "service", "mesh-gateway",
|
||||||
"Service name to use for the registration")
|
"Service name to use for the registration")
|
||||||
|
|
||||||
|
@ -160,6 +165,31 @@ func parseAddress(addrStr string) (string, int, error) {
|
||||||
return addr, port, nil
|
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 {
|
func (c *cmd) Run(args []string) int {
|
||||||
if err := c.flags.Parse(args); err != nil {
|
if err := c.flags.Parse(args); err != nil {
|
||||||
return 1
|
return 1
|
||||||
|
@ -215,8 +245,10 @@ func (c *cmd) Run(args []string) int {
|
||||||
taggedAddrs["lan"] = api.ServiceAddress{Address: lanAddr, Port: lanPort}
|
taggedAddrs["lan"] = api.ServiceAddress{Address: lanAddr, Port: lanPort}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
wanAddr := ""
|
||||||
|
wanPort := lanPort
|
||||||
if c.wanAddress != "" {
|
if c.wanAddress != "" {
|
||||||
wanAddr, wanPort, err := parseAddress(c.wanAddress)
|
wanAddr, wanPort, err = parseAddress(c.wanAddress)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.UI.Error(fmt.Sprintf("Failed to parse the -wan-address parameter: %v", err))
|
c.UI.Error(fmt.Sprintf("Failed to parse the -wan-address parameter: %v", err))
|
||||||
return 1
|
return 1
|
||||||
|
@ -233,13 +265,38 @@ func (c *cmd) Run(args []string) int {
|
||||||
|
|
||||||
var proxyConf *api.AgentServiceConnectProxyConfig
|
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{
|
proxyConf = &api.AgentServiceConnectProxyConfig{
|
||||||
Config: map[string]interface{}{
|
Config: map[string]interface{}{
|
||||||
"envoy_mesh_gateway_no_default_bind": true,
|
"envoy_mesh_gateway_no_default_bind": true,
|
||||||
"envoy_mesh_gateway_bind_tagged_addresses": 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{
|
svc := api.AgentServiceRegistration{
|
||||||
|
|
Loading…
Reference in New Issue