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"
|
|
|
|
"github.com/hashicorp/consul/api"
|
|
|
|
"github.com/hashicorp/go-multierror"
|
|
|
|
"google.golang.org/protobuf/proto"
|
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
|
|
|
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"
|
|
|
|
)
|
|
|
|
|
|
|
|
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
|
|
|
|
}
|
|
|
|
return &Troubleshoot{
|
|
|
|
client: c,
|
|
|
|
envoyAddr: *envoyIP,
|
|
|
|
envoyAdminPort: envoyPort,
|
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (t *Troubleshoot) RunAllTests(envoyID string) ([]string, error) {
|
|
|
|
var resultErr error
|
|
|
|
var output []string
|
|
|
|
|
|
|
|
// Validate certs
|
|
|
|
certs, err := t.getEnvoyCerts()
|
|
|
|
if err != nil {
|
|
|
|
resultErr = multierror.Append(resultErr, fmt.Errorf("unable to get certs: %w", err))
|
|
|
|
}
|
|
|
|
|
|
|
|
if certs != nil && len(certs.GetCertificates()) != 0 {
|
|
|
|
err = t.validateCerts(certs)
|
|
|
|
if err != nil {
|
|
|
|
resultErr = multierror.Append(resultErr, fmt.Errorf("unable to validate certs: %w", err))
|
|
|
|
} else {
|
|
|
|
output = append(output, "certs are valid")
|
|
|
|
}
|
|
|
|
|
|
|
|
} else {
|
|
|
|
resultErr = multierror.Append(resultErr, fmt.Errorf("no certificate found"))
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
// getStats usage example
|
|
|
|
// rejectionStats, err := t.getEnvoyStats("update_rejected")
|
|
|
|
// if err != nil {
|
|
|
|
// resultErr = multierror.Append(resultErr, err)
|
|
|
|
// }
|
|
|
|
|
|
|
|
// Validate listeners, routes, clusters, endpoints
|
|
|
|
t.GetEnvoyConfigDump()
|
|
|
|
t.getEnvoyClusters()
|
|
|
|
|
|
|
|
indexedResources, err := ProxyConfigDumpToIndexedResources(t.envoyConfigDump)
|
|
|
|
if err != nil {
|
|
|
|
resultErr = multierror.Append(resultErr, fmt.Errorf("unable to index resources: %v", err))
|
|
|
|
}
|
|
|
|
|
|
|
|
err = Validate(indexedResources, envoyID, "", true, t.envoyClusters)
|
|
|
|
if err != nil {
|
|
|
|
resultErr = multierror.Append(resultErr, fmt.Errorf("unable to validate proxy config: %v", err))
|
|
|
|
}
|
|
|
|
return output, resultErr
|
|
|
|
}
|
|
|
|
|
|
|
|
func (t *Troubleshoot) GetUpstreams() ([]string, error) {
|
|
|
|
|
|
|
|
upstreams := []string{}
|
|
|
|
|
|
|
|
err := t.GetEnvoyConfigDump()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, cfg := range t.envoyConfigDump.Configs {
|
|
|
|
switch cfg.TypeUrl {
|
|
|
|
case listeners:
|
|
|
|
lcd := &envoy_admin_v3.ListenersConfigDump{}
|
|
|
|
|
|
|
|
err := proto.Unmarshal(cfg.GetValue(), lcd)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, listener := range lcd.GetDynamicListeners() {
|
|
|
|
upstream := envoyID(listener.Name)
|
2023-02-07 02:48:55 +00:00
|
|
|
if upstream != "" && upstream != "public_listener" &&
|
|
|
|
upstream != "outbound_listener" &&
|
|
|
|
upstream != "inbound_listener" {
|
2023-02-06 17:14:35 +00:00
|
|
|
upstreams = append(upstreams, upstream)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return upstreams, nil
|
|
|
|
}
|