2023-03-28 19:12:30 +00:00
// Copyright (c) HashiCorp, Inc.
2023-08-11 13:12:13 +00:00
// SPDX-License-Identifier: BUSL-1.1
2023-03-28 19:12:30 +00:00
2023-02-01 23:11:05 +00:00
package proxy
2023-02-01 19:37:30 +00:00
import (
"flag"
"fmt"
"net"
"os"
2023-02-10 19:12:13 +00:00
"github.com/hashicorp/consul/command/cli"
2023-02-01 19:37:30 +00:00
"github.com/hashicorp/consul/command/flags"
2023-02-06 17:14:35 +00:00
troubleshoot "github.com/hashicorp/consul/troubleshoot/proxy"
2023-02-01 19:37:30 +00:00
)
func New ( ui cli . Ui ) * cmd {
c := & cmd { UI : ui }
c . init ( )
return c
}
type cmd struct {
UI cli . Ui
flags * flag . FlagSet
http * flags . HTTPFlags
help string
// flags
2023-02-09 00:05:22 +00:00
upstreamEnvoyID string
upstreamIP string
envoyAdminEndpoint string
2023-02-01 19:37:30 +00:00
}
func ( c * cmd ) init ( ) {
c . flags = flag . NewFlagSet ( "" , flag . ContinueOnError )
2023-02-09 00:05:22 +00:00
c . flags . StringVar ( & c . upstreamEnvoyID , "upstream-envoy-id" , os . Getenv ( "UPSTREAM_ENVOY_ID" ) , "The envoy identifier of the upstream service that receives the communication. (explicit upstreams only)" )
c . flags . StringVar ( & c . upstreamIP , "upstream-ip" , os . Getenv ( "UPSTREAM_IP" ) , "The IP address of the upstream service that receives the communication. (transparent proxy only) " )
2023-02-01 19:37:30 +00:00
2023-02-09 00:05:22 +00:00
defaultEnvoyAdminEndpoint := "localhost:19000"
if envoyAdminEndpoint := os . Getenv ( "ENVOY_ADMIN_ENDPOINT" ) ; envoyAdminEndpoint != "" {
defaultEnvoyAdminEndpoint = envoyAdminEndpoint
2023-02-01 19:37:30 +00:00
}
2023-02-09 00:05:22 +00:00
c . flags . StringVar ( & c . envoyAdminEndpoint , "envoy-admin-endpoint" , defaultEnvoyAdminEndpoint , "The address:port that envoy's admin endpoint is on." )
2023-02-01 19:37:30 +00:00
c . http = & flags . HTTPFlags { }
flags . Merge ( c . flags , c . http . ClientFlags ( ) )
flags . Merge ( c . flags , c . http . ServerFlags ( ) )
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
}
2023-02-09 00:05:22 +00:00
if c . upstreamEnvoyID == "" && c . upstreamIP == "" {
c . UI . Error ( "-upstream-envoy-id OR -upstream-ip is required." )
c . UI . Error ( "Please run `consul troubleshoot upstreams` to find the corresponding upstream." )
2023-02-01 19:37:30 +00:00
return 1
}
2023-02-09 00:05:22 +00:00
adminAddr , adminPort , err := net . SplitHostPort ( c . envoyAdminEndpoint )
2023-02-01 19:37:30 +00:00
if err != nil {
c . UI . Error ( "Invalid Envoy Admin endpoint: " + err . Error ( ) )
return 1
}
// Envoy requires IP addresses to bind too when using static so resolve DNS or
// localhost here.
adminBindIP , err := net . ResolveIPAddr ( "ip" , adminAddr )
if err != nil {
2023-02-09 00:05:22 +00:00
c . UI . Error ( "Failed to resolve Envoy admin endpoint: " + err . Error ( ) )
c . UI . Error ( "Please make sure Envoy's Admin API is enabled." )
2023-02-01 19:37:30 +00:00
return 1
}
t , err := troubleshoot . NewTroubleshoot ( adminBindIP , adminPort )
if err != nil {
2023-02-17 15:43:05 +00:00
c . UI . Error ( "Error generating troubleshoot client: " + err . Error ( ) )
2023-02-01 19:37:30 +00:00
return 1
}
2023-02-09 00:05:22 +00:00
messages , err := t . RunAllTests ( c . upstreamEnvoyID , c . upstreamIP )
2023-02-01 19:37:30 +00:00
if err != nil {
2023-02-17 15:43:05 +00:00
c . UI . Error ( "Error running the tests: " + err . Error ( ) )
2023-02-01 19:37:30 +00:00
return 1
}
2023-02-02 22:24:18 +00:00
2023-02-10 19:12:13 +00:00
c . UI . HeaderOutput ( "Validation" )
2023-02-08 21:03:15 +00:00
for _ , o := range messages {
if o . Success {
2023-02-10 19:12:13 +00:00
c . UI . SuccessOutput ( o . Message )
2023-02-08 21:03:15 +00:00
} else {
2023-02-10 19:12:13 +00:00
c . UI . ErrorOutput ( o . Message )
2023-02-17 15:43:05 +00:00
for _ , action := range o . PossibleActions {
c . UI . UnchangedOutput ( "-> " + action )
2023-02-08 21:03:15 +00:00
}
}
2023-02-02 22:24:18 +00:00
}
2023-02-17 15:43:05 +00:00
if messages . Success ( ) {
c . UI . UnchangedOutput ( "If you are still experiencing issues, you can:" )
c . UI . UnchangedOutput ( "-> Check intentions to ensure the upstream allows traffic from this source" )
c . UI . UnchangedOutput ( "-> If using transparent proxy, ensure DNS resolution is to the same IP you have verified here" )
}
2023-02-01 19:37:30 +00:00
return 0
}
func ( c * cmd ) Synopsis ( ) string {
return synopsis
}
func ( c * cmd ) Help ( ) string {
return c . help
}
const (
2023-02-01 23:11:05 +00:00
synopsis = "Troubleshoots service mesh issues from the current envoy instance"
2023-02-01 19:37:30 +00:00
help = `
Usage : consul troubleshoot proxy [ options ]
2023-02-02 22:24:18 +00:00
2023-02-01 19:37:30 +00:00
Connects to local envoy proxy and troubleshoots service mesh communication issues .
2023-02-17 15:43:05 +00:00
Requires an upstream service identifier . When debugging explicitly configured upstreams ,
use - upstream - envoy - id , when debugging transparent proxy upstreams use - upstream - ip .
2023-02-01 19:37:30 +00:00
Examples :
2023-02-09 00:05:22 +00:00
( explicit upstreams only )
$ consul troubleshoot proxy - upstream - envoy - id foo
( transparent proxy only )
2023-02-17 15:43:05 +00:00
$ consul troubleshoot proxy - upstream - ip 240.0 .0 .1
2023-02-01 19:37:30 +00:00
2023-02-17 15:43:05 +00:00
where ' foo ' is the upstream envoy identifier and ' 240.0 .0 .1 ' is an upstream ip which
2023-02-01 19:37:30 +00:00
can be obtained by running :
$ consul troubleshoot upstreams [ options ]
`
)