cli: Add -node-name flag to redirect-traffic command (#14933)
This commit is contained in:
parent
3c3ec4ed0b
commit
28b7dea973
3
.changelog/14933.txt
Normal file
3
.changelog/14933.txt
Normal file
|
@ -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
|
||||
|
||||
// Flags.
|
||||
nodeName string
|
||||
consulDNSIP string
|
||||
proxyUID string
|
||||
proxyID string
|
||||
|
@ -51,6 +52,8 @@ type cmd struct {
|
|||
func (c *cmd) init() {
|
||||
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.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.")
|
||||
|
@ -150,9 +153,27 @@ func (c *cmd) generateConfigFromFlags() (iptables.Config, error) {
|
|||
}
|
||||
}
|
||||
|
||||
svc, _, err := c.client.Agent().Service(c.proxyID, nil)
|
||||
if err != nil {
|
||||
return iptables.Config{}, fmt.Errorf("failed to fetch proxy service from Consul Agent: %s", err)
|
||||
var svc *api.AgentService
|
||||
if c.nodeName == "" {
|
||||
svc, _, err = c.client.Agent().Service(c.proxyID, nil)
|
||||
if err != nil {
|
||||
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 {
|
||||
|
@ -205,8 +226,8 @@ func (c *cmd) generateConfigFromFlags() (iptables.Config, error) {
|
|||
}
|
||||
}
|
||||
|
||||
// Exclude any exposed health check ports when Proxy.Expose.Checks is true.
|
||||
if svc.Proxy.Expose.Checks {
|
||||
// Exclude any exposed health check ports when Proxy.Expose.Checks is true and nodeName is not provided.
|
||||
if svc.Proxy.Expose.Checks && c.nodeName == "" {
|
||||
// Get the health checks of the destination service.
|
||||
checks, err := c.client.Agent().ChecksWithFilter(fmt.Sprintf("ServiceName == %q", svc.Proxy.DestinationServiceName))
|
||||
if err != nil {
|
||||
|
|
|
@ -572,6 +572,109 @@ func TestGenerateConfigFromFlags(t *testing.T) {
|
|||
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 {
|
||||
|
@ -580,7 +683,7 @@ func TestGenerateConfigFromFlags(t *testing.T) {
|
|||
if c.consulServices != nil {
|
||||
testServer, err := testutil.NewTestServerConfigT(t, nil)
|
||||
require.NoError(t, err)
|
||||
testServer.WaitForLeader(t)
|
||||
testServer.WaitForSerfCheck(t)
|
||||
defer testServer.Stop()
|
||||
|
||||
client, err := api.NewClient(&api.Config{Address: testServer.HTTPAddr})
|
||||
|
@ -588,6 +691,27 @@ func TestGenerateConfigFromFlags(t *testing.T) {
|
|||
cmd.client = client
|
||||
|
||||
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)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
|
|
@ -32,6 +32,8 @@ Usage: `consul connect redirect-traffic [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.
|
||||
|
||||
- `-proxy-id` - The [proxy service](/docs/connect/registration/service-registration) ID.
|
||||
|
|
Loading…
Reference in a new issue