mirror of https://github.com/status-im/consul.git
cli: Add -node-name flag to redirect-traffic command (#14933)
This commit is contained in:
parent
eb26a7dee9
commit
4bc4ef135c
|
@ -0,0 +1,3 @@
|
||||||
|
```release-note:feature
|
||||||
|
cli: Add -node-name flag to redirect-traffic command to support running in environments without client agents.
|
||||||
|
```
|
|
@ -36,6 +36,7 @@ type cmd struct {
|
||||||
client *api.Client
|
client *api.Client
|
||||||
|
|
||||||
// Flags.
|
// Flags.
|
||||||
|
nodeName string
|
||||||
consulDNSIP string
|
consulDNSIP string
|
||||||
proxyUID string
|
proxyUID string
|
||||||
proxyID string
|
proxyID string
|
||||||
|
@ -51,6 +52,8 @@ type cmd struct {
|
||||||
func (c *cmd) init() {
|
func (c *cmd) init() {
|
||||||
c.flags = flag.NewFlagSet("", flag.ContinueOnError)
|
c.flags = flag.NewFlagSet("", flag.ContinueOnError)
|
||||||
|
|
||||||
|
c.flags.StringVar(&c.nodeName, "node-name", "",
|
||||||
|
"The node name where the proxy service is registered. It requires proxy-id to be specified. This is needed if running in an environment without client agents.")
|
||||||
c.flags.StringVar(&c.consulDNSIP, "consul-dns-ip", "", "IP used to reach Consul DNS. If provided, DNS queries will be redirected to Consul.")
|
c.flags.StringVar(&c.consulDNSIP, "consul-dns-ip", "", "IP used to reach Consul DNS. If provided, DNS queries will be redirected to Consul.")
|
||||||
c.flags.StringVar(&c.proxyUID, "proxy-uid", "", "The user ID of the proxy to exclude from traffic redirection.")
|
c.flags.StringVar(&c.proxyUID, "proxy-uid", "", "The user ID of the proxy to exclude from traffic redirection.")
|
||||||
c.flags.StringVar(&c.proxyID, "proxy-id", "", "The service ID of the proxy service registered with Consul.")
|
c.flags.StringVar(&c.proxyID, "proxy-id", "", "The service ID of the proxy service registered with Consul.")
|
||||||
|
@ -150,10 +153,28 @@ func (c *cmd) generateConfigFromFlags() (iptables.Config, error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
svc, _, err := c.client.Agent().Service(c.proxyID, nil)
|
var svc *api.AgentService
|
||||||
|
if c.nodeName == "" {
|
||||||
|
svc, _, err = c.client.Agent().Service(c.proxyID, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return iptables.Config{}, fmt.Errorf("failed to fetch proxy service from Consul Agent: %s", err)
|
return iptables.Config{}, fmt.Errorf("failed to fetch proxy service from Consul Agent: %s", err)
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
svcList, _, err := c.client.Catalog().NodeServiceList(c.nodeName, &api.QueryOptions{
|
||||||
|
Filter: fmt.Sprintf("ID == %q", c.proxyID),
|
||||||
|
MergeCentralConfig: true,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return iptables.Config{}, fmt.Errorf("failed to fetch proxy service from Consul: %s", err)
|
||||||
|
}
|
||||||
|
if len(svcList.Services) < 1 {
|
||||||
|
return iptables.Config{}, fmt.Errorf("proxy service with ID %q not found", c.proxyID)
|
||||||
|
}
|
||||||
|
if len(svcList.Services) > 1 {
|
||||||
|
return iptables.Config{}, fmt.Errorf("expected to find only one proxy service with ID %q, but more were found", c.proxyID)
|
||||||
|
}
|
||||||
|
svc = svcList.Services[0]
|
||||||
|
}
|
||||||
|
|
||||||
if svc.Proxy == nil {
|
if svc.Proxy == nil {
|
||||||
return iptables.Config{}, fmt.Errorf("service %s is not a proxy service", c.proxyID)
|
return iptables.Config{}, fmt.Errorf("service %s is not a proxy service", c.proxyID)
|
||||||
|
@ -205,8 +226,8 @@ func (c *cmd) generateConfigFromFlags() (iptables.Config, error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Exclude any exposed health check ports when Proxy.Expose.Checks is true.
|
// Exclude any exposed health check ports when Proxy.Expose.Checks is true and nodeName is not provided.
|
||||||
if svc.Proxy.Expose.Checks {
|
if svc.Proxy.Expose.Checks && c.nodeName == "" {
|
||||||
// Get the health checks of the destination service.
|
// Get the health checks of the destination service.
|
||||||
checks, err := c.client.Agent().ChecksWithFilter(fmt.Sprintf("ServiceName == %q", svc.Proxy.DestinationServiceName))
|
checks, err := c.client.Agent().ChecksWithFilter(fmt.Sprintf("ServiceName == %q", svc.Proxy.DestinationServiceName))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -572,6 +572,109 @@ func TestGenerateConfigFromFlags(t *testing.T) {
|
||||||
ExcludeInboundPorts: []string{"21500", "21501"},
|
ExcludeInboundPorts: []string{"21500", "21501"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "skips agent checks when node name is provided",
|
||||||
|
command: func() cmd {
|
||||||
|
var c cmd
|
||||||
|
c.init()
|
||||||
|
c.proxyUID = "1234"
|
||||||
|
c.proxyID = "test-proxy-id"
|
||||||
|
c.nodeName = "test-node"
|
||||||
|
return c
|
||||||
|
},
|
||||||
|
consulServices: []api.AgentServiceRegistration{
|
||||||
|
{
|
||||||
|
ID: "foo-id",
|
||||||
|
Name: "foo",
|
||||||
|
Port: 8080,
|
||||||
|
Address: "1.1.1.1",
|
||||||
|
Checks: []*api.AgentServiceCheck{
|
||||||
|
{
|
||||||
|
Name: "http",
|
||||||
|
HTTP: "1.1.1.1:8080/health",
|
||||||
|
Interval: "10s",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "grpc",
|
||||||
|
GRPC: "1.1.1.1:8081",
|
||||||
|
Interval: "10s",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Kind: api.ServiceKindConnectProxy,
|
||||||
|
ID: "test-proxy-id",
|
||||||
|
Name: "test-proxy",
|
||||||
|
Port: 20000,
|
||||||
|
Address: "1.1.1.1",
|
||||||
|
Proxy: &api.AgentServiceConnectProxyConfig{
|
||||||
|
DestinationServiceName: "foo",
|
||||||
|
DestinationServiceID: "foo-id",
|
||||||
|
Expose: api.ExposeConfig{
|
||||||
|
Checks: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expCfg: iptables.Config{
|
||||||
|
ProxyUserID: "1234",
|
||||||
|
ProxyInboundPort: 20000,
|
||||||
|
ProxyOutboundPort: iptables.DefaultTProxyOutboundPort,
|
||||||
|
//ExcludeInboundPorts: []string{"21500", "21501"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "proxyID with node name provided",
|
||||||
|
command: func() cmd {
|
||||||
|
var c cmd
|
||||||
|
c.init()
|
||||||
|
c.proxyUID = "1234"
|
||||||
|
c.proxyID = "test-proxy-id"
|
||||||
|
c.nodeName = "test-node"
|
||||||
|
return c
|
||||||
|
},
|
||||||
|
consulServices: []api.AgentServiceRegistration{
|
||||||
|
{
|
||||||
|
Kind: api.ServiceKindConnectProxy,
|
||||||
|
ID: "test-proxy-id",
|
||||||
|
Name: "test-proxy",
|
||||||
|
Port: 20000,
|
||||||
|
Address: "1.1.1.1",
|
||||||
|
Proxy: &api.AgentServiceConnectProxyConfig{
|
||||||
|
DestinationServiceName: "foo",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expCfg: iptables.Config{
|
||||||
|
ProxyUserID: "1234",
|
||||||
|
ProxyInboundPort: 20000,
|
||||||
|
ProxyOutboundPort: iptables.DefaultTProxyOutboundPort,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "errors if no proxy services are found when proxy ID and node name are provided",
|
||||||
|
command: func() cmd {
|
||||||
|
var c cmd
|
||||||
|
c.init()
|
||||||
|
c.proxyUID = "1234"
|
||||||
|
c.proxyID = "test-proxy-id"
|
||||||
|
c.nodeName = "test-node"
|
||||||
|
return c
|
||||||
|
},
|
||||||
|
consulServices: []api.AgentServiceRegistration{
|
||||||
|
{
|
||||||
|
Kind: api.ServiceKindConnectProxy,
|
||||||
|
ID: "some-other-id",
|
||||||
|
Name: "test-proxy",
|
||||||
|
Port: 20000,
|
||||||
|
Address: "1.1.1.1",
|
||||||
|
Proxy: &api.AgentServiceConnectProxyConfig{
|
||||||
|
DestinationServiceName: "foo",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expError: "proxy service with ID \"test-proxy-id\" not found",
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, c := range cases {
|
for _, c := range cases {
|
||||||
|
@ -580,7 +683,7 @@ func TestGenerateConfigFromFlags(t *testing.T) {
|
||||||
if c.consulServices != nil {
|
if c.consulServices != nil {
|
||||||
testServer, err := testutil.NewTestServerConfigT(t, nil)
|
testServer, err := testutil.NewTestServerConfigT(t, nil)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
testServer.WaitForLeader(t)
|
testServer.WaitForSerfCheck(t)
|
||||||
defer testServer.Stop()
|
defer testServer.Stop()
|
||||||
|
|
||||||
client, err := api.NewClient(&api.Config{Address: testServer.HTTPAddr})
|
client, err := api.NewClient(&api.Config{Address: testServer.HTTPAddr})
|
||||||
|
@ -588,6 +691,27 @@ func TestGenerateConfigFromFlags(t *testing.T) {
|
||||||
cmd.client = client
|
cmd.client = client
|
||||||
|
|
||||||
for _, service := range c.consulServices {
|
for _, service := range c.consulServices {
|
||||||
|
if cmd.nodeName != "" {
|
||||||
|
catalogRegistration := &api.CatalogRegistration{
|
||||||
|
Node: cmd.nodeName,
|
||||||
|
Address: "127.0.0.1",
|
||||||
|
Service: &api.AgentService{
|
||||||
|
Kind: service.Kind,
|
||||||
|
ID: service.ID,
|
||||||
|
Service: service.Name,
|
||||||
|
Port: service.Port,
|
||||||
|
Address: service.Address,
|
||||||
|
Proxy: service.Proxy,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := client.Catalog().Register(catalogRegistration, nil)
|
||||||
|
require.NoError(t, err)
|
||||||
|
}
|
||||||
|
// We are always registering services with the agent just so we can check that we're not
|
||||||
|
// trying to fetch agent checks in the case when Proxy.Expose.Checks and -node-name flag is provided.
|
||||||
|
// This is not a scenario that will happen realistically when running without client agents,
|
||||||
|
// but this test setup allows us to check the negative case.
|
||||||
err = client.Agent().ServiceRegister(&service)
|
err = client.Agent().ServiceRegister(&service)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,6 +32,8 @@ Usage: `consul connect redirect-traffic [options]`
|
||||||
|
|
||||||
#### Command Options
|
#### Command Options
|
||||||
|
|
||||||
|
- `-node-name` - The node name where the proxy service is registered. It requires proxy-id to be specified. This is needed if running in an environment without client agents.
|
||||||
|
|
||||||
- `-consul-dns-ip` - The IP address of the Consul DNS resolver. If provided, DNS queries will be redirected to the provided IP address for name resolution.
|
- `-consul-dns-ip` - The IP address of the Consul DNS resolver. If provided, DNS queries will be redirected to the provided IP address for name resolution.
|
||||||
|
|
||||||
- `-proxy-id` - The [proxy service](/docs/connect/registration/service-registration) ID.
|
- `-proxy-id` - The [proxy service](/docs/connect/registration/service-registration) ID.
|
||||||
|
|
Loading…
Reference in New Issue