Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 14 additions & 2 deletions internal/cmd/egctl/collect.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
"time"

"github.com/spf13/cobra"
"k8s.io/apimachinery/pkg/util/sets"
cmdutil "k8s.io/kubectl/pkg/cmd/util"

"github.com/envoyproxy/gateway/internal/cmd/options"
Expand All @@ -26,6 +27,7 @@
type collectOptions struct {
outPath string
envoyGatewayNamespace string
proxyNamespaces []string
}

func newCollectCommand() *cobra.Command {
Expand All @@ -48,6 +50,8 @@
"Specify the output file path for collected data. If not specified, a timestamped file will be created in the current directory.")
collectCommand.PersistentFlags().StringVarP(&collectOpts.envoyGatewayNamespace, "envoy-system-namespace", "", "envoy-gateway-system",
"Specify the namespace where the Envoy Gateway controller is installed.")
collectCommand.PersistentFlags().StringArrayVarP(&collectOpts.proxyNamespaces, "envoy-proxy-namespaces", "", []string{},
"Specify the namespaces where Envoy proxies are running.")

Check warning on line 54 in internal/cmd/egctl/collect.go

View check run for this annotation

Codecov / codecov/patch

internal/cmd/egctl/collect.go#L53-L54

Added lines #L53 - L54 were not covered by tests

return collectCommand
}
Expand Down Expand Up @@ -88,8 +92,16 @@
return fmt.Errorf("create bundle dir: %w", err)
}

result := tb.CollectResult(ctx, restConfig, bundlePath, collectOpts.envoyGatewayNamespace)
return result.ArchiveSupportBundle(bundlePath, fmt.Sprintf("%s.tar.gz", basename))
proxyNamespaces := sets.New(collectOpts.proxyNamespaces...)
opts := tb.CollectOptions{
BundlePath: bundlePath,
CollectedNamespaces: []string{collectOpts.envoyGatewayNamespace},
}
if len(proxyNamespaces) > 0 {
opts.CollectedNamespaces = append(opts.CollectedNamespaces, proxyNamespaces.UnsortedList()...)
}
result := tb.CollectResult(ctx, restConfig, opts)
return result.ArchiveBundle(bundlePath, fmt.Sprintf("%s.tar.gz", basename))

Check warning on line 104 in internal/cmd/egctl/collect.go

View check run for this annotation

Codecov / codecov/patch

internal/cmd/egctl/collect.go#L95-L104

Added lines #L95 - L104 were not covered by tests
}

func waitForSignal(c context.Context, cancel context.CancelFunc) {
Expand Down
8 changes: 7 additions & 1 deletion internal/cmd/egctl/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,17 @@

package egctl

import "github.com/spf13/cobra"
import (
"github.com/go-logr/logr"
"github.com/spf13/cobra"
"k8s.io/klog/v2"
)

// GetRootCommand returns the root cobra command to be executed
// by egctl main.
func GetRootCommand() *cobra.Command {
// discard klog logger
klog.SetLogger(logr.Discard())

Check warning on line 18 in internal/cmd/egctl/root.go

View check run for this annotation

Codecov / codecov/patch

internal/cmd/egctl/root.go#L17-L18

Added lines #L17 - L18 were not covered by tests
rootCmd := &cobra.Command{
Use: "egctl",
Long: "A command line utility for operating Envoy Gateway",
Expand Down
67 changes: 38 additions & 29 deletions internal/troubleshoot/collect.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,12 @@
"github.com/envoyproxy/gateway/internal/troubleshoot/collect"
)

func CollectResult(ctx context.Context, restConfig *rest.Config, bundlePath, egNamespace string) tbcollect.CollectorResult {
type CollectOptions struct {
CollectedNamespaces []string
BundlePath string
}

func CollectResult(ctx context.Context, restConfig *rest.Config, opts CollectOptions) tbcollect.CollectorResult {

Check warning on line 24 in internal/troubleshoot/collect.go

View check run for this annotation

Codecov / codecov/patch

internal/troubleshoot/collect.go#L24

Added line #L24 was not covered by tests
var result tbcollect.CollectorResult

progressChan := make(chan interface{})
Expand All @@ -33,40 +38,44 @@
// Collect the custom resources from Gateway API and EG
collect.CustomResource{
ClientConfig: restConfig,
BundlePath: bundlePath,
BundlePath: opts.BundlePath,

Check warning on line 41 in internal/troubleshoot/collect.go

View check run for this annotation

Codecov / codecov/patch

internal/troubleshoot/collect.go#L41

Added line #L41 was not covered by tests
IncludeGroups: []string{
"gateway.envoyproxy.io",
"gateway.networking.k8s.io",
},
},
// Collect resources from EnvoyGateway system namespace
collect.EnvoyGatewayResource{
ClientConfig: restConfig,
BundlePath: bundlePath,
Namespace: egNamespace,
},
// Collect logs from EnvoyGateway system namespace
&tbcollect.CollectLogs{
Collector: &troubleshootv1b2.Logs{
Name: "pod-logs",
Namespace: egNamespace,
}
for _, ns := range opts.CollectedNamespaces {
bundlePath := opts.BundlePath
collectors = append(collectors,
// Collect resources from EnvoyGateway system namespace
collect.EnvoyGatewayResource{
ClientConfig: restConfig,
BundlePath: bundlePath,
Namespace: ns,

Check warning on line 55 in internal/troubleshoot/collect.go

View check run for this annotation

Codecov / codecov/patch

internal/troubleshoot/collect.go#L47-L55

Added lines #L47 - L55 were not covered by tests
},
ClientConfig: restConfig,
BundlePath: bundlePath,
Context: ctx,
},
// Collect prometheus metrics from EnvoyGateway system namespace
collect.PrometheusMetric{
BundlePath: bundlePath,
ClientConfig: restConfig,
Namespace: egNamespace,
},
// Collect config dump from EnvoyGateway system namespace
collect.ConfigDump{
BundlePath: bundlePath,
ClientConfig: restConfig,
Namespace: egNamespace,
},
// Collect logs from EnvoyGateway system namespace
&tbcollect.CollectLogs{
Collector: &troubleshootv1b2.Logs{
Name: "pod-logs",
Namespace: ns,
},
ClientConfig: restConfig,
BundlePath: bundlePath,
Context: ctx,
},
// Collect prometheus metrics from EnvoyGateway system namespace
collect.PrometheusMetric{
BundlePath: bundlePath,
ClientConfig: restConfig,
Namespace: ns,
},
// Collect config dump from EnvoyGateway system namespace
collect.ConfigDump{
BundlePath: bundlePath,
ClientConfig: restConfig,
Namespace: ns,
})

Check warning on line 78 in internal/troubleshoot/collect.go

View check run for this annotation

Codecov / codecov/patch

internal/troubleshoot/collect.go#L57-L78

Added lines #L57 - L78 were not covered by tests
}
total := len(collectors)
allCollectedData := make(map[string][]byte)
Expand Down
3 changes: 1 addition & 2 deletions internal/troubleshoot/collect/config_dump.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,7 @@
continue
}

k := fmt.Sprintf("%s-%s.json", pod.Namespace, pod.Name)
_ = output.SaveResult(cd.BundlePath, path.Join("config-dumps", k), bytes.NewBuffer(data))
_ = output.SaveResult(cd.BundlePath, path.Join("config-dumps", pod.Namespace, fmt.Sprintf("%s.json", pod.Name)), bytes.NewBuffer(data))

Check warning on line 84 in internal/troubleshoot/collect/config_dump.go

View check run for this annotation

Codecov / codecov/patch

internal/troubleshoot/collect/config_dump.go#L84

Added line #L84 was not covered by tests
}
if len(logs) > 0 {
_ = output.SaveResult(cd.BundlePath, path.Join("config-dumps", "errors.log"), marshalErrors(logs))
Expand Down
54 changes: 36 additions & 18 deletions internal/troubleshoot/collect/prometheus_metrics.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
"k8s.io/client-go/rest"

kube "github.com/envoyproxy/gateway/internal/kubernetes"
"github.com/envoyproxy/gateway/internal/utils/str"
)

var _ tbcollect.Collector = &PrometheusMetric{}
Expand Down Expand Up @@ -76,32 +77,23 @@

logs := make([]string, 0)
for _, pod := range pods {
annos := pod.GetAnnotations()
if v, ok := annos["prometheus.io/scrape"]; !ok || v != "true" {
logs = append(logs, fmt.Sprintf("pod %s/%s is skipped because of missing annotation prometheus.io/scrape", pod.Namespace, pod.Name))
continue
}

nn, port, reqPath := types.NamespacedName{Namespace: pod.Namespace, Name: pod.Name}, 19001, "/metrics"
if v, ok := annos["prometheus.io/port"]; !ok {
port, err = strconv.Atoi(v)
if err != nil {
logs = append(logs, fmt.Sprintf("pod %s/%s is skipped because of invalid prometheus.io/port", pod.Namespace, pod.Name))
continue
}
scrape, reqPath, port, err := getPrometheusPathAndPort(&pod)
if err != nil {
logs = append(logs, fmt.Sprintf("pod %s/%s is skipped because of err: %v", pod.Namespace, pod.Name, err))

Check warning on line 83 in internal/troubleshoot/collect/prometheus_metrics.go

View check run for this annotation

Codecov / codecov/patch

internal/troubleshoot/collect/prometheus_metrics.go#L81-L83

Added lines #L81 - L83 were not covered by tests
}
if v, ok := annos["prometheus.io/path"]; ok {
reqPath = v
if !scrape {
logs = append(logs, fmt.Sprintf("pod %s/%s is skipped because of annotation prometheus.io/scrape=false", pod.Namespace, pod.Name))
continue

Check warning on line 87 in internal/troubleshoot/collect/prometheus_metrics.go

View check run for this annotation

Codecov / codecov/patch

internal/troubleshoot/collect/prometheus_metrics.go#L85-L87

Added lines #L85 - L87 were not covered by tests
}

data, err := RequestWithPortForwarder(cliClient, nn, port, reqPath)
data, err := RequestWithPortForwarder(cliClient, types.NamespacedName{Name: pod.Name, Namespace: pod.Namespace}, port, reqPath)

Check warning on line 90 in internal/troubleshoot/collect/prometheus_metrics.go

View check run for this annotation

Codecov / codecov/patch

internal/troubleshoot/collect/prometheus_metrics.go#L90

Added line #L90 was not covered by tests
if err != nil {
logs = append(logs, fmt.Sprintf("pod %s/%s is skipped because of err: %v", pod.Namespace, pod.Name, err))
logs = append(logs, fmt.Sprintf("pod %s/%s:%v%s is skipped because of err: %v", pod.Namespace, pod.Name, port, reqPath, err))

Check warning on line 92 in internal/troubleshoot/collect/prometheus_metrics.go

View check run for this annotation

Codecov / codecov/patch

internal/troubleshoot/collect/prometheus_metrics.go#L92

Added line #L92 was not covered by tests
continue
}

k := fmt.Sprintf("%s-%s.prom", pod.Namespace, pod.Name)
_ = output.SaveResult(p.BundlePath, path.Join("prometheus-metrics", k), bytes.NewBuffer(data))
_ = output.SaveResult(p.BundlePath, path.Join("prometheus-metrics", pod.Namespace, fmt.Sprintf("%s.prom", pod.Name)), bytes.NewBuffer(data))

Check warning on line 96 in internal/troubleshoot/collect/prometheus_metrics.go

View check run for this annotation

Codecov / codecov/patch

internal/troubleshoot/collect/prometheus_metrics.go#L96

Added line #L96 was not covered by tests
}
if len(logs) > 0 {
_ = output.SaveResult(p.BundlePath, path.Join("prometheus-metrics", "error.log"), bytes.NewBuffer([]byte(strings.Join(logs, "\n"))))
Expand All @@ -110,6 +102,32 @@
return output, nil
}

func getPrometheusPathAndPort(pod *corev1.Pod) (bool, string, int, error) {
reqPath := "/metrics"
port := 9090
scrape := false
annotations := pod.GetAnnotations()
for k, v := range annotations {
switch str.SanitizeLabelName(k) {
case "prometheus_io_scrape":
if v != "true" {
return false, "", 0, fmt.Errorf("pod %s/%s is skipped because of missing annotation prometheus.io/scrape", pod.Namespace, pod.Name)
}
scrape = true
case "prometheus_io_port":
p, err := strconv.Atoi(v)
if err != nil {
return false, "", 0, fmt.Errorf("failed to parse port from annotation: %w", err)
}
port = p
case "prometheus_io_path":
reqPath = v

Check warning on line 124 in internal/troubleshoot/collect/prometheus_metrics.go

View check run for this annotation

Codecov / codecov/patch

internal/troubleshoot/collect/prometheus_metrics.go#L105-L124

Added lines #L105 - L124 were not covered by tests
}
}

return scrape, reqPath, port, nil

Check warning on line 128 in internal/troubleshoot/collect/prometheus_metrics.go

View check run for this annotation

Codecov / codecov/patch

internal/troubleshoot/collect/prometheus_metrics.go#L128

Added line #L128 was not covered by tests
}

func listPods(ctx context.Context, client kubernetes.Interface, namespace string, selector labels.Selector) ([]corev1.Pod, error) {
pods, err := client.CoreV1().Pods(namespace).List(ctx, metav1.ListOptions{
LabelSelector: selector.String(),
Expand Down
22 changes: 22 additions & 0 deletions internal/utils/str/strconv.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// Copyright Envoy Gateway Authors
// SPDX-License-Identifier: Apache-2.0
// The full text of the Apache license is available in the LICENSE file at
// the root of the repo.

package str

// This file contains utility functions copied from github.com/prometheus/prometheus/util/strutil,
// which is conflicting with the current package.

import "regexp"

var invalidLabelCharRE = regexp.MustCompile(`[^a-zA-Z0-9_]`)

// SanitizeLabelName replaces anything that doesn't match
// client_label.LabelNameRE with an underscore.
// Note: this does not handle all Prometheus label name restrictions (such as
// not starting with a digit 0-9), and hence should only be used if the label
// name is prefixed with a known valid string.
func SanitizeLabelName(name string) string {
return invalidLabelCharRE.ReplaceAllString(name, "_")

Check warning on line 21 in internal/utils/str/strconv.go

View check run for this annotation

Codecov / codecov/patch

internal/utils/str/strconv.go#L20-L21

Added lines #L20 - L21 were not covered by tests
}
10 changes: 9 additions & 1 deletion test/e2e/tests/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -602,7 +602,15 @@ type LokiQueryResponse struct {
// CollectAndDump collects and dumps the cluster data for troubleshooting and log.
// This function should be call within t.Cleanup.
func CollectAndDump(t *testing.T, rest *rest.Config) {
result := tb.CollectResult(context.TODO(), rest, "", "envoy-gateway-system")
dumpedNamespaces := []string{"envoy-gateway-system"}
if IsGatewayNamespaceMode() {
dumpedNamespaces = append(dumpedNamespaces, ConformanceInfraNamespace)
}

result := tb.CollectResult(context.TODO(), rest, tb.CollectOptions{
BundlePath: "",
CollectedNamespaces: dumpedNamespaces,
})
for r, data := range result {
tlog.Logf(t, "\nfilename: %s", r)
tlog.Logf(t, "\ndata: \n%s", data)
Expand Down