mirror of https://github.com/hashicorp/consul
Browse Source
NET-3860 - [Supportability] consul troubleshoot CLI for verifying ports (#18329) * init * udp * added support for custom port * removed grpc * rename constants * removed udp * added change log * fix synopsis * pr comment chagnes * make private * added tests * added one more test case * defer close results channel * removed unwanted comment * licence update * updated docs * fix indent * fix path * example update * Update website/content/commands/troubleshoot/ports.mdx * Update website/content/commands/troubleshoot/ports.mdx * Update command/troubleshoot/ports/troubleshoot_ports.go * Update website/content/commands/troubleshoot/ports.mdx * Update website/content/commands/troubleshoot/index.mdx * Update command/troubleshoot/ports/troubleshoot_ports.go * Update command/troubleshoot/ports/troubleshoot_ports.go * Update website/content/commands/troubleshoot/ports.mdx * Update website/content/commands/troubleshoot/ports.mdx * Update website/content/commands/troubleshoot/ports.mdx * pr comment resolved --------- Co-authored-by: Ashesh Vidyut <134911583+absolutelightning@users.noreply.github.com> Co-authored-by: trujillo-adam <47586768+trujillo-adam@users.noreply.github.com>pull/20274/head
John Maguire
10 months ago
committed by
GitHub
13 changed files with 303 additions and 10 deletions
@ -0,0 +1,4 @@
|
||||
```release-note:improvement |
||||
cli: Adds cli support for checking TCP connection for ports. If -ports flag is not given, it will check for |
||||
default ports of consul listed here - https://developer.hashicorp.com/consul/docs/install/ports |
||||
``` |
@ -0,0 +1,89 @@
|
||||
// Copyright (c) HashiCorp, Inc.
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
package ports |
||||
|
||||
import ( |
||||
"flag" |
||||
"fmt" |
||||
"github.com/hashicorp/consul/troubleshoot/ports" |
||||
"os" |
||||
|
||||
"github.com/hashicorp/consul/command/cli" |
||||
"github.com/hashicorp/consul/command/flags" |
||||
) |
||||
|
||||
func New(ui cli.Ui) *cmd { |
||||
c := &cmd{UI: ui} |
||||
c.init() |
||||
return c |
||||
} |
||||
|
||||
type cmd struct { |
||||
UI cli.Ui |
||||
flags *flag.FlagSet |
||||
help string |
||||
|
||||
// flags
|
||||
host string |
||||
ports string |
||||
} |
||||
|
||||
func (c *cmd) init() { |
||||
c.flags = flag.NewFlagSet("", flag.ContinueOnError) |
||||
|
||||
c.flags.StringVar(&c.host, "host", os.Getenv("CONSUL_HTTP_ADDR"), "The consul server host") |
||||
|
||||
c.flags.StringVar(&c.ports, "ports", "", "Custom ports to troubleshoot") |
||||
|
||||
c.help = flags.Usage(help, c.flags) |
||||
} |
||||
|
||||
func (c *cmd) Run(args []string) int { |
||||
|
||||
if err := c.flags.Parse(args); err != nil { |
||||
c.UI.Error(fmt.Sprintf("Failed to parse args: %v", err)) |
||||
return 1 |
||||
} |
||||
|
||||
if c.host == "" { |
||||
c.UI.Error("-host is required. or set environment variable CONSUL_HTTP_ADDR") |
||||
return 1 |
||||
} |
||||
|
||||
if c.ports == "" { |
||||
ports.TroubleshootDefaultPorts(c.host) |
||||
} else { |
||||
ports.TroubleShootCustomPorts(c.host, c.ports) |
||||
} |
||||
return 0 |
||||
} |
||||
|
||||
func (c *cmd) Synopsis() string { |
||||
return synopsis |
||||
} |
||||
|
||||
func (c *cmd) Help() string { |
||||
return c.help |
||||
} |
||||
|
||||
const ( |
||||
synopsis = "Prints open and closed ports on the Consul server" |
||||
help = ` |
||||
Usage: consul troubleshoot ports [options] |
||||
Checks ports for TCP connectivity. Add the -ports flag to check specific ports or omit the -ports flag to check default ports.
|
||||
Refer to the following reference for default ports: https://developer.hashicorp.com/consul/docs/install/ports
|
||||
|
||||
consul troubleshoot ports -host localhost |
||||
|
||||
or
|
||||
export CONSUL_HTTP_ADDR=localhost |
||||
consul troubleshoot ports
|
||||
|
||||
Use the -ports flag to check non-default ports, for example: |
||||
consul troubleshoot ports -host localhost -ports 1023,1024 |
||||
or
|
||||
export CONSUL_HTTP_ADDR=localhost |
||||
consul troubleshoot ports -ports 1234,8500
|
||||
` |
||||
) |
@ -0,0 +1,9 @@
|
||||
// Copyright (c) HashiCorp, Inc.
|
||||
// SPDX-License-Identifier: BUSL-1.1
|
||||
|
||||
package ports |
||||
|
||||
type hostPort struct { |
||||
host string |
||||
port string |
||||
} |
@ -0,0 +1,53 @@
|
||||
// Copyright (c) HashiCorp, Inc.
|
||||
// SPDX-License-Identifier: BUSL-1.1
|
||||
|
||||
package ports |
||||
|
||||
import ( |
||||
"fmt" |
||||
"strings" |
||||
) |
||||
|
||||
func TroubleshootDefaultPorts(host string) []string { |
||||
// Source - https://developer.hashicorp.com/consul/docs/install/ports
|
||||
ports := []string{"8600", "8500", "8501", "8502", "8503", "8301", "8302", "8300"} |
||||
return troubleshootRun(ports, host) |
||||
} |
||||
|
||||
func TroubleShootCustomPorts(host string, ports string) []string { |
||||
portsArr := strings.Split(ports, ",") |
||||
return troubleshootRun(portsArr, host) |
||||
} |
||||
|
||||
func troubleshootRun(ports []string, host string) []string { |
||||
|
||||
resultsChannel := make(chan string) |
||||
defer close(resultsChannel) |
||||
|
||||
var counter = 0 |
||||
|
||||
for _, port := range ports { |
||||
counter += 1 |
||||
tcpTroubleShoot := troubleShootTcp{} |
||||
port := port |
||||
go func() { |
||||
err := tcpTroubleShoot.dialPort(&hostPort{host: host, port: port}) |
||||
var res string |
||||
if err != nil { |
||||
res = fmt.Sprintf("TCP: Port %s on %s is closed, unreachable, or the connection timed out.\n", port, host) |
||||
} else { |
||||
// If no error occurs, the connection was successful, and the port is open.
|
||||
res = fmt.Sprintf("TCP: Port %s on %s is open.\n", port, host) |
||||
} |
||||
resultsChannel <- res |
||||
}() |
||||
} |
||||
|
||||
resultsArr := make([]string, counter) |
||||
for itr := 0; itr < counter; itr++ { |
||||
res := <-resultsChannel |
||||
fmt.Print(res) |
||||
resultsArr[itr] = res |
||||
} |
||||
return resultsArr |
||||
} |
@ -0,0 +1,55 @@
|
||||
// Copyright (c) HashiCorp, Inc.
|
||||
// SPDX-License-Identifier: BUSL-1.1
|
||||
|
||||
package ports |
||||
|
||||
import ( |
||||
"fmt" |
||||
"github.com/hashicorp/consul/sdk/testutil" |
||||
"github.com/stretchr/testify/require" |
||||
"strconv" |
||||
"strings" |
||||
"testing" |
||||
) |
||||
|
||||
func TestTroubleShootCustom_Ports(t *testing.T) { |
||||
// Create a test Consul server
|
||||
srv1, err := testutil.NewTestServerConfigT(t, nil) |
||||
if err != nil { |
||||
t.Fatal(err) |
||||
} |
||||
|
||||
results := TroubleShootCustomPorts("127.0.0.1", strings.Join([]string{ |
||||
strconv.Itoa(srv1.Config.Ports.HTTP), |
||||
strconv.Itoa(srv1.Config.Ports.DNS), |
||||
strconv.Itoa(srv1.Config.Ports.HTTPS), |
||||
strconv.Itoa(srv1.Config.Ports.GRPC), |
||||
strconv.Itoa(srv1.Config.Ports.SerfLan), |
||||
strconv.Itoa(srv1.Config.Ports.SerfWan), |
||||
strconv.Itoa(srv1.Config.Ports.Server)}, ",")) |
||||
expectedResults := []string{ |
||||
fmt.Sprintf("TCP: Port %s on 127.0.0.1 is open.\n", strconv.Itoa(srv1.Config.Ports.HTTP)), |
||||
fmt.Sprintf("TCP: Port %s on 127.0.0.1 is open.\n", strconv.Itoa(srv1.Config.Ports.GRPC)), |
||||
fmt.Sprintf("TCP: Port %s on 127.0.0.1 is open.\n", strconv.Itoa(srv1.Config.Ports.HTTPS)), |
||||
fmt.Sprintf("TCP: Port %s on 127.0.0.1 is open.\n", strconv.Itoa(srv1.Config.Ports.SerfLan)), |
||||
fmt.Sprintf("TCP: Port %s on 127.0.0.1 is open.\n", strconv.Itoa(srv1.Config.Ports.SerfWan)), |
||||
fmt.Sprintf("TCP: Port %s on 127.0.0.1 is open.\n", strconv.Itoa(srv1.Config.Ports.DNS)), |
||||
fmt.Sprintf("TCP: Port %s on 127.0.0.1 is open.\n", strconv.Itoa(srv1.Config.Ports.Server)), |
||||
} |
||||
for _, res := range expectedResults { |
||||
require.Contains(t, results, res) |
||||
} |
||||
defer srv1.Stop() |
||||
} |
||||
|
||||
func TestTroubleShootCustom_Ports_Not_Reachable(t *testing.T) { |
||||
results := TroubleShootCustomPorts("127.0.0.1", strings.Join([]string{"8777", "8888"}, ",")) |
||||
|
||||
expectedResults := []string{ |
||||
fmt.Sprintf("TCP: Port 8777 on 127.0.0.1 is closed, unreachable, or the connection timed out.\n"), |
||||
fmt.Sprintf("TCP: Port 8888 on 127.0.0.1 is closed, unreachable, or the connection timed out.\n"), |
||||
} |
||||
for _, res := range expectedResults { |
||||
require.Contains(t, results, res) |
||||
} |
||||
} |
@ -0,0 +1,8 @@
|
||||
// Copyright (c) HashiCorp, Inc.
|
||||
// SPDX-License-Identifier: BUSL-1.1
|
||||
|
||||
package ports |
||||
|
||||
type troubleShootProtocol interface { |
||||
dialPort(hostPort *hostPort) error |
||||
} |
@ -0,0 +1,24 @@
|
||||
// Copyright (c) HashiCorp, Inc.
|
||||
// SPDX-License-Identifier: BUSL-1.1
|
||||
|
||||
package ports |
||||
|
||||
import ( |
||||
"net" |
||||
"time" |
||||
) |
||||
|
||||
type troubleShootTcp struct { |
||||
} |
||||
|
||||
func (tcp *troubleShootTcp) dialPort(hostPort *hostPort) error { |
||||
address := net.JoinHostPort(hostPort.host, hostPort.port) |
||||
|
||||
// Attempt to establish a TCP connection with a timeout.
|
||||
conn, err := net.DialTimeout("tcp", address, 5*time.Second) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
defer conn.Close() |
||||
return nil |
||||
} |
@ -0,0 +1,47 @@
|
||||
--- |
||||
layout: commands |
||||
page_title: 'Commands: Troubleshoot Ports' |
||||
description: >- |
||||
The `consul troubleshoot ports` Helps troubleshoot TCP ports by printing if they are open or closed. |
||||
--- |
||||
|
||||
# Consul Troubleshoot Upstreams |
||||
|
||||
Command: `consul troubleshoot ports` |
||||
|
||||
The `troubleshoot ports` prints TCP port statuses to help you troubleshoot port connectivity. |
||||
|
||||
## Usage |
||||
|
||||
Usage: `consul troubleshoot ports [options]` |
||||
|
||||
#### Command Options |
||||
|
||||
- `-host=<value>` - Host name to troubleshoot TCP ports for. You can also set the `CONSUL_HTTP_ADDR` environment variable instead of using the `-host` flag. |
||||
- `-ports=<value>` - Specifies a comma-separated list of custom ports to check. |
||||
|
||||
## Examples |
||||
|
||||
The following example checks the default ports Consul server uses for TCP connectivity. Note that the `CONSUL_HTTP_ADDR` environment variable is set to `localhost`. As a result, the `-host` flag is not required. |
||||
Refer to [Required Ports](/consul/docs/install/ports) for additional information. |
||||
|
||||
```shell-session |
||||
$ export CONSUL_HTTP_ADDR=localhost |
||||
$ consul troubleshoot ports |
||||
TCP: Port 8501 on localhost is open. |
||||
TCP: Port 8502 on localhost is open. |
||||
TCP: Port 8503 on localhost is open. |
||||
TCP: Port 8302 on localhost is open. |
||||
TCP: Port 8300 on localhost is open. |
||||
TCP: Port 8600 on localhost is open. |
||||
TCP: Port 8301 on localhost is open. |
||||
TCP: Port 8500 on localhost is open. |
||||
``` |
||||
|
||||
The following example checks TCP ports status on the `hashicorp.com` host. |
||||
|
||||
```shell-session |
||||
$ consul troubleshoot ports -host hashicorp.com -ports 80,8077 |
||||
TCP: Port 80 on hashicorp.com is open. |
||||
TCP: Port 8077 on hashicorp.com is closed, unreachable, or the connection timed out. |
||||
``` |
Loading…
Reference in new issue