2023-02-06 17:14:35 +00:00
|
|
|
package troubleshoot
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"net"
|
|
|
|
|
|
|
|
envoy_admin_v3 "github.com/envoyproxy/go-control-plane/envoy/admin/v3"
|
2023-02-07 22:57:31 +00:00
|
|
|
|
2023-02-06 17:14:35 +00:00
|
|
|
"github.com/hashicorp/consul/api"
|
2023-02-08 21:03:15 +00:00
|
|
|
"github.com/hashicorp/consul/troubleshoot/validate"
|
2023-02-06 17:14:35 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
2023-02-07 22:57:31 +00:00
|
|
|
listeners string = "type.googleapis.com/envoy.admin.v3.ListenersConfigDump"
|
|
|
|
clusters string = "type.googleapis.com/envoy.admin.v3.ClustersConfigDump"
|
|
|
|
routes string = "type.googleapis.com/envoy.admin.v3.RoutesConfigDump"
|
|
|
|
endpoints string = "type.googleapis.com/envoy.admin.v3.EndpointsConfigDump"
|
|
|
|
bootstrap string = "type.googleapis.com/envoy.admin.v3.BootstrapConfigDump"
|
|
|
|
httpConnManager string = "type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager"
|
2023-02-06 17:14:35 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
type Troubleshoot struct {
|
|
|
|
client *api.Client
|
|
|
|
envoyAddr net.IPAddr
|
|
|
|
envoyAdminPort string
|
|
|
|
|
|
|
|
TroubleshootInfo
|
|
|
|
}
|
|
|
|
|
|
|
|
type TroubleshootInfo struct {
|
|
|
|
envoyClusters *envoy_admin_v3.Clusters
|
|
|
|
envoyConfigDump *envoy_admin_v3.ConfigDump
|
|
|
|
envoyCerts *envoy_admin_v3.Certificates
|
|
|
|
envoyStats []*envoy_admin_v3.SimpleMetric
|
|
|
|
}
|
|
|
|
|
|
|
|
func NewTroubleshoot(envoyIP *net.IPAddr, envoyPort string) (*Troubleshoot, error) {
|
|
|
|
cfg := api.DefaultConfig()
|
|
|
|
c, err := api.NewClient(cfg)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2023-02-07 17:58:00 +00:00
|
|
|
|
|
|
|
if envoyIP == nil {
|
|
|
|
return nil, fmt.Errorf("envoy address is empty")
|
|
|
|
}
|
|
|
|
|
2023-02-06 17:14:35 +00:00
|
|
|
return &Troubleshoot{
|
|
|
|
client: c,
|
|
|
|
envoyAddr: *envoyIP,
|
|
|
|
envoyAdminPort: envoyPort,
|
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
|
2023-02-09 00:05:22 +00:00
|
|
|
func (t *Troubleshoot) RunAllTests(upstreamEnvoyID, upstreamIP string) (validate.Messages, error) {
|
2023-02-08 21:03:15 +00:00
|
|
|
var allTestMessages validate.Messages
|
2023-02-06 17:14:35 +00:00
|
|
|
|
2023-02-08 21:03:15 +00:00
|
|
|
// Get all info from proxy to set up validations.
|
|
|
|
err := t.GetEnvoyConfigDump()
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("unable to get Envoy config dump: cannot connect to Envoy: %w", err)
|
|
|
|
}
|
|
|
|
err = t.getEnvoyClusters()
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("unable to get Envoy clusters: cannot connect to Envoy: %w", err)
|
|
|
|
}
|
2023-02-06 17:14:35 +00:00
|
|
|
certs, err := t.getEnvoyCerts()
|
|
|
|
if err != nil {
|
2023-02-08 21:03:15 +00:00
|
|
|
return nil, fmt.Errorf("unable to get Envoy certificates: cannot connect to Envoy: %w", err)
|
|
|
|
}
|
|
|
|
indexedResources, err := ProxyConfigDumpToIndexedResources(t.envoyConfigDump)
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("unable to index Envoy resources: %w", err)
|
2023-02-06 17:14:35 +00:00
|
|
|
}
|
|
|
|
|
2023-02-08 21:03:15 +00:00
|
|
|
// Validate certs.
|
|
|
|
messages := t.validateCerts(certs)
|
|
|
|
allTestMessages = append(allTestMessages, messages...)
|
|
|
|
if errors := messages.Errors(); len(errors) == 0 {
|
|
|
|
msg := validate.Message{
|
|
|
|
Success: true,
|
|
|
|
Message: "certificates are valid",
|
2023-02-06 17:14:35 +00:00
|
|
|
}
|
2023-02-08 21:03:15 +00:00
|
|
|
allTestMessages = append(allTestMessages, msg)
|
2023-02-06 17:14:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// getStats usage example
|
2023-02-09 20:06:31 +00:00
|
|
|
messages, err = t.troubleshootStats()
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("unable to get stats: %w", err)
|
|
|
|
}
|
|
|
|
allTestMessages = append(allTestMessages, messages...)
|
2023-02-06 17:14:35 +00:00
|
|
|
|
2023-02-08 21:03:15 +00:00
|
|
|
// Validate listeners, routes, clusters, endpoints.
|
2023-02-09 00:05:22 +00:00
|
|
|
messages = Validate(indexedResources, upstreamEnvoyID, upstreamIP, true, t.envoyClusters)
|
2023-02-08 21:03:15 +00:00
|
|
|
allTestMessages = append(allTestMessages, messages...)
|
|
|
|
if errors := messages.Errors(); len(errors) == 0 {
|
|
|
|
msg := validate.Message{
|
|
|
|
Success: true,
|
|
|
|
Message: "upstream resources are valid",
|
|
|
|
}
|
|
|
|
allTestMessages = append(allTestMessages, msg)
|
2023-02-06 17:14:35 +00:00
|
|
|
}
|
|
|
|
|
2023-02-08 21:03:15 +00:00
|
|
|
return allTestMessages, nil
|
2023-02-06 17:14:35 +00:00
|
|
|
}
|