mirror of https://github.com/linkerd/linkerd2.git
viz: Prohibit authority resource targets in stat commands (#13578)
There are plans to remove the authority label in inbound proxy metrics. When that happens we would not longer be able to use the viz stat/top commands to query by `authority`. This is a change to disable being able to invoke these commands with an `authority` resource target. Signed-off-by: Zahari Dichev <zaharidichev@gmail.com>
This commit is contained in:
parent
a726757fb1
commit
31a580683e
|
|
@ -12,7 +12,6 @@ import (
|
||||||
// These constants are string representations of Kubernetes resource types.
|
// These constants are string representations of Kubernetes resource types.
|
||||||
const (
|
const (
|
||||||
All = "all"
|
All = "all"
|
||||||
Authority = "authority"
|
|
||||||
ConfigMap = "configmap"
|
ConfigMap = "configmap"
|
||||||
CronJob = "cronjob"
|
CronJob = "cronjob"
|
||||||
DaemonSet = "daemonset"
|
DaemonSet = "daemonset"
|
||||||
|
|
@ -73,7 +72,6 @@ type resourceName struct {
|
||||||
|
|
||||||
// AllResources is a sorted list of all resources defined as constants above.
|
// AllResources is a sorted list of all resources defined as constants above.
|
||||||
var AllResources = []string{
|
var AllResources = []string{
|
||||||
Authority,
|
|
||||||
AuthorizationPolicy,
|
AuthorizationPolicy,
|
||||||
CronJob,
|
CronJob,
|
||||||
DaemonSet,
|
DaemonSet,
|
||||||
|
|
@ -100,7 +98,6 @@ var StatAllResourceTypes = []string{
|
||||||
ReplicationController,
|
ReplicationController,
|
||||||
Pod,
|
Pod,
|
||||||
Service,
|
Service,
|
||||||
Authority,
|
|
||||||
CronJob,
|
CronJob,
|
||||||
ReplicaSet,
|
ReplicaSet,
|
||||||
}
|
}
|
||||||
|
|
@ -115,13 +112,11 @@ var CompletionResourceTypes = []string{
|
||||||
ReplicationController,
|
ReplicationController,
|
||||||
Pod,
|
Pod,
|
||||||
Service,
|
Service,
|
||||||
Authority,
|
|
||||||
CronJob,
|
CronJob,
|
||||||
ReplicaSet,
|
ReplicaSet,
|
||||||
}
|
}
|
||||||
|
|
||||||
var resourceNames = []resourceName{
|
var resourceNames = []resourceName{
|
||||||
{"au", "authority", "authorities"},
|
|
||||||
{"cj", "cronjob", "cronjobs"},
|
{"cj", "cronjob", "cronjobs"},
|
||||||
{"ds", "daemonset", "daemonsets"},
|
{"ds", "daemonset", "daemonsets"},
|
||||||
{"deploy", "deployment", "deployments"},
|
{"deploy", "deployment", "deployments"},
|
||||||
|
|
@ -190,8 +185,6 @@ func PluralResourceNameFromFriendlyName(friendlyName string) (string, error) {
|
||||||
// Essentially the reverse of CanonicalResourceNameFromFriendlyName
|
// Essentially the reverse of CanonicalResourceNameFromFriendlyName
|
||||||
func ShortNameFromCanonicalResourceName(canonicalName string) string {
|
func ShortNameFromCanonicalResourceName(canonicalName string) string {
|
||||||
switch canonicalName {
|
switch canonicalName {
|
||||||
case Authority:
|
|
||||||
return "au"
|
|
||||||
case CronJob:
|
case CronJob:
|
||||||
return "cj"
|
return "cj"
|
||||||
case DaemonSet:
|
case DaemonSet:
|
||||||
|
|
|
||||||
|
|
@ -32,8 +32,6 @@ func TestCanonicalResourceNameFromFriendlyName(t *testing.T) {
|
||||||
"pod": Pod,
|
"pod": Pod,
|
||||||
"deployment": Deployment,
|
"deployment": Deployment,
|
||||||
"deployments": Deployment,
|
"deployments": Deployment,
|
||||||
"au": Authority,
|
|
||||||
"authorities": Authority,
|
|
||||||
"cj": CronJob,
|
"cj": CronJob,
|
||||||
"cronjob": CronJob,
|
"cronjob": CronJob,
|
||||||
"serverauthz": ServerAuthorization,
|
"serverauthz": ServerAuthorization,
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,6 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"strconv"
|
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
@ -37,7 +36,7 @@ func TestMain(m *testing.M) {
|
||||||
// requesting, and the test will pass.
|
// requesting, and the test will pass.
|
||||||
func TestCliStatForLinkerdNamespace(t *testing.T) {
|
func TestCliStatForLinkerdNamespace(t *testing.T) {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
var prometheusPod, prometheusAuthority, prometheusNamespace, prometheusDeployment, metricsPod string
|
var prometheusPod, prometheusNamespace, prometheusDeployment, metricsPod string
|
||||||
// Get Metrics Pod
|
// Get Metrics Pod
|
||||||
pods, err := TestHelper.GetPodNamesForDeployment(ctx, TestHelper.GetVizNamespace(), "metrics-api")
|
pods, err := TestHelper.GetPodNamesForDeployment(ctx, TestHelper.GetVizNamespace(), "metrics-api")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -62,13 +61,11 @@ func TestCliStatForLinkerdNamespace(t *testing.T) {
|
||||||
testutil.Fatalf(t, "expected 1 pod for prometheus, got %d", len(pods))
|
testutil.Fatalf(t, "expected 1 pod for prometheus, got %d", len(pods))
|
||||||
}
|
}
|
||||||
prometheusPod = pods[0]
|
prometheusPod = pods[0]
|
||||||
prometheusAuthority = prometheusDeployment + "." + prometheusNamespace + ".svc.cluster.local:9090"
|
|
||||||
|
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
args []string
|
args []string
|
||||||
expectedRows map[string]string
|
expectedRows map[string]string
|
||||||
status string
|
status string
|
||||||
isAuthority bool
|
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
args: []string{"viz", "stat", "deploy", "-n", TestHelper.GetLinkerdNamespace()},
|
args: []string{"viz", "stat", "deploy", "-n", TestHelper.GetLinkerdNamespace()},
|
||||||
|
|
@ -103,27 +100,6 @@ func TestCliStatForLinkerdNamespace(t *testing.T) {
|
||||||
"metrics-api": "1/1",
|
"metrics-api": "1/1",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
args: []string{"viz", "stat", "po", "-n", TestHelper.GetVizNamespace(), "--to", fmt.Sprintf("au/%s", prometheusAuthority), "--to-namespace", prometheusNamespace},
|
|
||||||
expectedRows: map[string]string{
|
|
||||||
metricsPod: "1/1",
|
|
||||||
},
|
|
||||||
status: "Running",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
args: []string{"viz", "stat", "au", "-n", TestHelper.GetVizNamespace(), "--to", fmt.Sprintf("po/%s", prometheusPod), "--to-namespace", prometheusNamespace},
|
|
||||||
expectedRows: map[string]string{
|
|
||||||
prometheusAuthority: "-",
|
|
||||||
},
|
|
||||||
isAuthority: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
args: []string{"viz", "stat", "au", "-n", TestHelper.GetVizNamespace(), "--to", fmt.Sprintf("po/%s", prometheusPod), "--to-namespace", prometheusNamespace},
|
|
||||||
expectedRows: map[string]string{
|
|
||||||
prometheusAuthority: "-",
|
|
||||||
},
|
|
||||||
isAuthority: true,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if !TestHelper.ExternalPrometheus() {
|
if !TestHelper.ExternalPrometheus() {
|
||||||
|
|
@ -131,7 +107,6 @@ func TestCliStatForLinkerdNamespace(t *testing.T) {
|
||||||
args []string
|
args []string
|
||||||
expectedRows map[string]string
|
expectedRows map[string]string
|
||||||
status string
|
status string
|
||||||
isAuthority bool
|
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
args: []string{"viz", "stat", "deploy", "-n", TestHelper.GetVizNamespace()},
|
args: []string{"viz", "stat", "deploy", "-n", TestHelper.GetVizNamespace()},
|
||||||
|
|
@ -162,7 +137,6 @@ func TestCliStatForLinkerdNamespace(t *testing.T) {
|
||||||
args []string
|
args []string
|
||||||
expectedRows map[string]string
|
expectedRows map[string]string
|
||||||
status string
|
status string
|
||||||
isAuthority bool
|
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
args: []string{"viz", "stat", "deploy", "-n", TestHelper.GetVizNamespace()},
|
args: []string{"viz", "stat", "deploy", "-n", TestHelper.GetVizNamespace()},
|
||||||
|
|
@ -212,7 +186,6 @@ func TestCliStatForLinkerdNamespace(t *testing.T) {
|
||||||
args []string
|
args []string
|
||||||
expectedRows map[string]string
|
expectedRows map[string]string
|
||||||
status string
|
status string
|
||||||
isAuthority bool
|
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
args: []string{"viz", "stat", "svc", "-n", prefixedNs},
|
args: []string{"viz", "stat", "svc", "-n", prefixedNs},
|
||||||
|
|
@ -244,9 +217,6 @@ func TestCliStatForLinkerdNamespace(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
expectedColumnCount := 8
|
expectedColumnCount := 8
|
||||||
if tt.isAuthority {
|
|
||||||
expectedColumnCount = 7
|
|
||||||
}
|
|
||||||
if tt.status != "" {
|
if tt.status != "" {
|
||||||
expectedColumnCount++
|
expectedColumnCount++
|
||||||
}
|
}
|
||||||
|
|
@ -256,7 +226,7 @@ func TestCliStatForLinkerdNamespace(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
for name, meshed := range tt.expectedRows {
|
for name, meshed := range tt.expectedRows {
|
||||||
if err := validateRowStats(name, meshed, tt.status, rowStats, tt.isAuthority); err != nil {
|
if err := validateRowStats(name, meshed, tt.status, rowStats); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -271,7 +241,7 @@ func TestCliStatForLinkerdNamespace(t *testing.T) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func validateRowStats(name, expectedMeshCount, expectedStatus string, rowStats map[string]*testutil.RowStat, isAuthority bool) error {
|
func validateRowStats(name, expectedMeshCount, expectedStatus string, rowStats map[string]*testutil.RowStat) error {
|
||||||
stat, ok := rowStats[name]
|
stat, ok := rowStats[name]
|
||||||
if !ok {
|
if !ok {
|
||||||
return fmt.Errorf("no stats found for [%s]", name)
|
return fmt.Errorf("no stats found for [%s]", name)
|
||||||
|
|
@ -313,12 +283,5 @@ func validateRowStats(name, expectedMeshCount, expectedStatus string, rowStats m
|
||||||
name, stat.P99Latency)
|
name, stat.P99Latency)
|
||||||
}
|
}
|
||||||
|
|
||||||
if stat.TCPOpenConnections != "-" && !isAuthority {
|
|
||||||
_, err := strconv.Atoi(stat.TCPOpenConnections)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("error parsing number of TCP connections [%s]: %w", stat.TCPOpenConnections, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,6 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"strconv"
|
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
@ -37,7 +36,7 @@ func TestMain(m *testing.M) {
|
||||||
// requesting, and the test will pass.
|
// requesting, and the test will pass.
|
||||||
func TestCliStatForLinkerdNamespace(t *testing.T) {
|
func TestCliStatForLinkerdNamespace(t *testing.T) {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
var prometheusPod, prometheusAuthority, prometheusNamespace, prometheusDeployment, metricsPod string
|
var prometheusPod, prometheusNamespace, prometheusDeployment, metricsPod string
|
||||||
// Get Metrics Pod
|
// Get Metrics Pod
|
||||||
pods, err := TestHelper.GetPodNamesForDeployment(ctx, TestHelper.GetVizNamespace(), "metrics-api")
|
pods, err := TestHelper.GetPodNamesForDeployment(ctx, TestHelper.GetVizNamespace(), "metrics-api")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -62,13 +61,11 @@ func TestCliStatForLinkerdNamespace(t *testing.T) {
|
||||||
testutil.Fatalf(t, "expected 1 pod for prometheus, got %d", len(pods))
|
testutil.Fatalf(t, "expected 1 pod for prometheus, got %d", len(pods))
|
||||||
}
|
}
|
||||||
prometheusPod = pods[0]
|
prometheusPod = pods[0]
|
||||||
prometheusAuthority = prometheusDeployment + "." + prometheusNamespace + ".svc.cluster.local:9090"
|
|
||||||
|
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
args []string
|
args []string
|
||||||
expectedRows map[string]string
|
expectedRows map[string]string
|
||||||
status string
|
status string
|
||||||
isAuthority bool
|
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
args: []string{"viz", "stat", "deploy", "-n", TestHelper.GetLinkerdNamespace()},
|
args: []string{"viz", "stat", "deploy", "-n", TestHelper.GetLinkerdNamespace()},
|
||||||
|
|
@ -103,27 +100,6 @@ func TestCliStatForLinkerdNamespace(t *testing.T) {
|
||||||
"metrics-api": "1/1",
|
"metrics-api": "1/1",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
args: []string{"viz", "stat", "po", "-n", TestHelper.GetVizNamespace(), "--to", fmt.Sprintf("au/%s", prometheusAuthority), "--to-namespace", prometheusNamespace},
|
|
||||||
expectedRows: map[string]string{
|
|
||||||
metricsPod: "1/1",
|
|
||||||
},
|
|
||||||
status: "Running",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
args: []string{"viz", "stat", "au", "-n", TestHelper.GetVizNamespace(), "--to", fmt.Sprintf("po/%s", prometheusPod), "--to-namespace", prometheusNamespace},
|
|
||||||
expectedRows: map[string]string{
|
|
||||||
prometheusAuthority: "-",
|
|
||||||
},
|
|
||||||
isAuthority: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
args: []string{"viz", "stat", "au", "-n", TestHelper.GetVizNamespace(), "--to", fmt.Sprintf("po/%s", prometheusPod), "--to-namespace", prometheusNamespace},
|
|
||||||
expectedRows: map[string]string{
|
|
||||||
prometheusAuthority: "-",
|
|
||||||
},
|
|
||||||
isAuthority: true,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if !TestHelper.ExternalPrometheus() {
|
if !TestHelper.ExternalPrometheus() {
|
||||||
|
|
@ -131,7 +107,6 @@ func TestCliStatForLinkerdNamespace(t *testing.T) {
|
||||||
args []string
|
args []string
|
||||||
expectedRows map[string]string
|
expectedRows map[string]string
|
||||||
status string
|
status string
|
||||||
isAuthority bool
|
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
args: []string{"viz", "stat", "deploy", "-n", TestHelper.GetVizNamespace()},
|
args: []string{"viz", "stat", "deploy", "-n", TestHelper.GetVizNamespace()},
|
||||||
|
|
@ -162,7 +137,6 @@ func TestCliStatForLinkerdNamespace(t *testing.T) {
|
||||||
args []string
|
args []string
|
||||||
expectedRows map[string]string
|
expectedRows map[string]string
|
||||||
status string
|
status string
|
||||||
isAuthority bool
|
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
args: []string{"viz", "stat", "deploy", "-n", TestHelper.GetVizNamespace()},
|
args: []string{"viz", "stat", "deploy", "-n", TestHelper.GetVizNamespace()},
|
||||||
|
|
@ -212,7 +186,6 @@ func TestCliStatForLinkerdNamespace(t *testing.T) {
|
||||||
args []string
|
args []string
|
||||||
expectedRows map[string]string
|
expectedRows map[string]string
|
||||||
status string
|
status string
|
||||||
isAuthority bool
|
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
args: []string{"viz", "stat", "svc", "-n", prefixedNs},
|
args: []string{"viz", "stat", "svc", "-n", prefixedNs},
|
||||||
|
|
@ -244,9 +217,6 @@ func TestCliStatForLinkerdNamespace(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
expectedColumnCount := 8
|
expectedColumnCount := 8
|
||||||
if tt.isAuthority {
|
|
||||||
expectedColumnCount = 7
|
|
||||||
}
|
|
||||||
if tt.status != "" {
|
if tt.status != "" {
|
||||||
expectedColumnCount++
|
expectedColumnCount++
|
||||||
}
|
}
|
||||||
|
|
@ -256,7 +226,7 @@ func TestCliStatForLinkerdNamespace(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
for name, meshed := range tt.expectedRows {
|
for name, meshed := range tt.expectedRows {
|
||||||
if err := validateRowStats(name, meshed, tt.status, rowStats, tt.isAuthority); err != nil {
|
if err := validateRowStats(name, meshed, tt.status, rowStats); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -271,7 +241,7 @@ func TestCliStatForLinkerdNamespace(t *testing.T) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func validateRowStats(name, expectedMeshCount, expectedStatus string, rowStats map[string]*testutil.RowStat, isAuthority bool) error {
|
func validateRowStats(name, expectedMeshCount, expectedStatus string, rowStats map[string]*testutil.RowStat) error {
|
||||||
stat, ok := rowStats[name]
|
stat, ok := rowStats[name]
|
||||||
if !ok {
|
if !ok {
|
||||||
return fmt.Errorf("No stats found for [%s]", name)
|
return fmt.Errorf("No stats found for [%s]", name)
|
||||||
|
|
@ -313,12 +283,5 @@ func validateRowStats(name, expectedMeshCount, expectedStatus string, rowStats m
|
||||||
name, stat.P99Latency)
|
name, stat.P99Latency)
|
||||||
}
|
}
|
||||||
|
|
||||||
if stat.TCPOpenConnections != "-" && !isAuthority {
|
|
||||||
_, err := strconv.Atoi(stat.TCPOpenConnections)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("Error parsing number of TCP connections [%s]: %w", stat.TCPOpenConnections, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -67,7 +67,7 @@ func TestEdges(t *testing.T) {
|
||||||
t.Run("Returns an error if request is for authority", func(t *testing.T) {
|
t.Run("Returns an error if request is for authority", func(t *testing.T) {
|
||||||
options.outputFormat = tableOutput
|
options.outputFormat = tableOutput
|
||||||
args := []string{"authority"}
|
args := []string{"authority"}
|
||||||
expectedError := "Resource type is not supported: authority"
|
expectedError := "cannot find Kubernetes canonical name from friendly name [authority]"
|
||||||
|
|
||||||
_, err := buildEdgesRequests(args, options)
|
_, err := buildEdgesRequests(args, options)
|
||||||
if err == nil || err.Error() != expectedError {
|
if err == nil || err.Error() != expectedError {
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,6 @@ import (
|
||||||
|
|
||||||
pkgcmd "github.com/linkerd/linkerd2/pkg/cmd"
|
pkgcmd "github.com/linkerd/linkerd2/pkg/cmd"
|
||||||
"github.com/linkerd/linkerd2/pkg/healthcheck"
|
"github.com/linkerd/linkerd2/pkg/healthcheck"
|
||||||
"github.com/linkerd/linkerd2/pkg/k8s"
|
|
||||||
pb "github.com/linkerd/linkerd2/viz/metrics-api/gen/viz"
|
pb "github.com/linkerd/linkerd2/viz/metrics-api/gen/viz"
|
||||||
"github.com/linkerd/linkerd2/viz/metrics-api/util"
|
"github.com/linkerd/linkerd2/viz/metrics-api/util"
|
||||||
"github.com/linkerd/linkerd2/viz/pkg/api"
|
"github.com/linkerd/linkerd2/viz/pkg/api"
|
||||||
|
|
@ -379,7 +378,7 @@ func buildTopRoutesRequest(resource string, options *routesOptions) (*pb.TopRout
|
||||||
LabelSelector: options.labelSelector,
|
LabelSelector: options.labelSelector,
|
||||||
}
|
}
|
||||||
|
|
||||||
options.dstIsService = target.GetType() != k8s.Authority
|
options.dstIsService = true
|
||||||
|
|
||||||
if options.toResource != "" {
|
if options.toResource != "" {
|
||||||
if options.toNamespace == "" {
|
if options.toNamespace == "" {
|
||||||
|
|
@ -390,7 +389,7 @@ func buildTopRoutesRequest(resource string, options *routesOptions) (*pb.TopRout
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
options.dstIsService = toRes.GetType() != k8s.Authority
|
options.dstIsService = true
|
||||||
|
|
||||||
requestParams.ToName = toRes.Name
|
requestParams.ToName = toRes.Name
|
||||||
requestParams.ToNamespace = toRes.Namespace
|
requestParams.ToNamespace = toRes.Namespace
|
||||||
|
|
|
||||||
|
|
@ -372,7 +372,7 @@ func statHasRequestData(stat *pb.BasicStats) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
func isPodOwnerResource(typ string) bool {
|
func isPodOwnerResource(typ string) bool {
|
||||||
return typ != k8s.Authority && typ != k8s.Service && typ != k8s.Server && typ != k8s.ServerAuthorization && typ != k8s.AuthorizationPolicy && typ != k8s.HTTPRoute
|
return typ != k8s.Service && typ != k8s.Server && typ != k8s.ServerAuthorization && typ != k8s.AuthorizationPolicy && typ != k8s.HTTPRoute
|
||||||
}
|
}
|
||||||
|
|
||||||
func writeStatsToBuffer(rows []*pb.StatTable_PodGroup_Row, w *tabwriter.Writer, options *statOptions) {
|
func writeStatsToBuffer(rows []*pb.StatTable_PodGroup_Row, w *tabwriter.Writer, options *statOptions) {
|
||||||
|
|
@ -433,7 +433,7 @@ func writeStatsToBuffer(rows []*pb.StatTable_PodGroup_Row, w *tabwriter.Writer,
|
||||||
statTables[resourceKey][key] = &row{}
|
statTables[resourceKey][key] = &row{}
|
||||||
if resourceKey != k8s.Server && resourceKey != k8s.ServerAuthorization {
|
if resourceKey != k8s.Server && resourceKey != k8s.ServerAuthorization {
|
||||||
meshedCount := fmt.Sprintf("%d/%d", r.MeshedPodCount, r.RunningPodCount)
|
meshedCount := fmt.Sprintf("%d/%d", r.MeshedPodCount, r.RunningPodCount)
|
||||||
if resourceKey == k8s.Authority || resourceKey == k8s.Service {
|
if resourceKey == k8s.Service {
|
||||||
meshedCount = "-"
|
meshedCount = "-"
|
||||||
}
|
}
|
||||||
statTables[resourceKey][key] = &row{
|
statTables[resourceKey][key] = &row{
|
||||||
|
|
@ -503,7 +503,7 @@ func showTCPBytes(options *statOptions, resourceType string) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
func showTCPConns(resourceType string) bool {
|
func showTCPConns(resourceType string) bool {
|
||||||
return resourceType != k8s.Authority && resourceType != k8s.ServerAuthorization && resourceType != k8s.AuthorizationPolicy && resourceType != k8s.HTTPRoute
|
return resourceType != k8s.ServerAuthorization && resourceType != k8s.AuthorizationPolicy && resourceType != k8s.HTTPRoute
|
||||||
}
|
}
|
||||||
|
|
||||||
func printSingleStatTable(stats map[string]*row, resourceTypeLabel, resourceType string, w *tabwriter.Writer, maxNameLength, maxNamespaceLength, maxLeafLength, maxApexLength, maxDstLength, maxWeightLength int, options *statOptions) {
|
func printSingleStatTable(stats map[string]*row, resourceTypeLabel, resourceType string, w *tabwriter.Writer, maxNameLength, maxNamespaceLength, maxLeafLength, maxApexLength, maxDstLength, maxWeightLength int, options *statOptions) {
|
||||||
|
|
|
||||||
|
|
@ -125,9 +125,7 @@ func (s *grpcServer) StatSummary(ctx context.Context, req *pb.StatSummaryRequest
|
||||||
statReq.Selector.Resource.Type = resource
|
statReq.Selector.Resource.Type = resource
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
if prometheus.IsNonK8sResourceQuery(statReq.GetSelector().GetResource().GetType()) {
|
if statReq.GetSelector().GetResource().GetType() == k8s.Service {
|
||||||
resultChan <- s.nonK8sResourceQuery(ctx, statReq)
|
|
||||||
} else if statReq.GetSelector().GetResource().GetType() == k8s.Service {
|
|
||||||
resultChan <- s.serviceResourceQuery(ctx, statReq)
|
resultChan <- s.serviceResourceQuery(ctx, statReq)
|
||||||
} else if isPolicyResource(statReq.GetSelector().GetResource()) {
|
} else if isPolicyResource(statReq.GetSelector().GetResource()) {
|
||||||
resultChan <- s.policyResourceQuery(ctx, statReq)
|
resultChan <- s.policyResourceQuery(ctx, statReq)
|
||||||
|
|
@ -362,42 +360,6 @@ func sortTrafficSplitRows(rows []*pb.StatTable_PodGroup_Row) []*pb.StatTable_Pod
|
||||||
return rows
|
return rows
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *grpcServer) nonK8sResourceQuery(ctx context.Context, req *pb.StatSummaryRequest) resourceResult {
|
|
||||||
var requestMetrics map[rKey]*pb.BasicStats
|
|
||||||
if !req.SkipStats {
|
|
||||||
var err error
|
|
||||||
requestMetrics, _, err = s.getStatMetrics(ctx, req, req.TimeWindow)
|
|
||||||
if err != nil {
|
|
||||||
return resourceResult{res: nil, err: err}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
rows := make([]*pb.StatTable_PodGroup_Row, 0)
|
|
||||||
|
|
||||||
for rkey, metrics := range requestMetrics {
|
|
||||||
rkey.Type = req.GetSelector().GetResource().GetType()
|
|
||||||
|
|
||||||
row := pb.StatTable_PodGroup_Row{
|
|
||||||
Resource: &pb.Resource{
|
|
||||||
Type: rkey.Type,
|
|
||||||
Namespace: rkey.Namespace,
|
|
||||||
Name: rkey.Name,
|
|
||||||
},
|
|
||||||
TimeWindow: req.TimeWindow,
|
|
||||||
Stats: metrics,
|
|
||||||
}
|
|
||||||
rows = append(rows, &row)
|
|
||||||
}
|
|
||||||
|
|
||||||
rsp := pb.StatTable{
|
|
||||||
Table: &pb.StatTable_PodGroup_{
|
|
||||||
PodGroup: &pb.StatTable_PodGroup{
|
|
||||||
Rows: rows,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
return resourceResult{res: &rsp, err: nil}
|
|
||||||
}
|
|
||||||
|
|
||||||
// get the list of objects for which we want to return results
|
// get the list of objects for which we want to return results
|
||||||
func getResultKeys(
|
func getResultKeys(
|
||||||
req *pb.StatSummaryRequest,
|
req *pb.StatSummaryRequest,
|
||||||
|
|
|
||||||
|
|
@ -22,11 +22,11 @@ type statSumExpected struct {
|
||||||
|
|
||||||
func prometheusMetric(resName string, resType string) model.Vector {
|
func prometheusMetric(resName string, resType string) model.Vector {
|
||||||
return model.Vector{
|
return model.Vector{
|
||||||
genPromSample(resName, resType, "emojivoto", false),
|
genPromSample(resName, resType, false),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func genPromSample(resName string, resType string, resNs string, isDst bool) *model.Sample {
|
func genPromSample(resName string, resType string, isDst bool) *model.Sample {
|
||||||
labelName := model.LabelName(resType)
|
labelName := model.LabelName(resType)
|
||||||
namespaceLabel := model.LabelName("namespace")
|
namespaceLabel := model.LabelName("namespace")
|
||||||
|
|
||||||
|
|
@ -38,7 +38,7 @@ func genPromSample(resName string, resType string, resNs string, isDst bool) *mo
|
||||||
return &model.Sample{
|
return &model.Sample{
|
||||||
Metric: model.Metric{
|
Metric: model.Metric{
|
||||||
labelName: model.LabelValue(resName),
|
labelName: model.LabelValue(resName),
|
||||||
namespaceLabel: model.LabelValue(resNs),
|
namespaceLabel: model.LabelValue("emojivoto"),
|
||||||
"classification": model.LabelValue("success"),
|
"classification": model.LabelValue("success"),
|
||||||
"tls": model.LabelValue("true"),
|
"tls": model.LabelValue("true"),
|
||||||
},
|
},
|
||||||
|
|
@ -865,7 +865,7 @@ status:
|
||||||
`,
|
`,
|
||||||
},
|
},
|
||||||
mockPromResponse: model.Vector{
|
mockPromResponse: model.Vector{
|
||||||
genPromSample("emojivoto-1", "pod", "emojivoto", false),
|
genPromSample("emojivoto-1", "pod", false),
|
||||||
},
|
},
|
||||||
expectedPrometheusQueries: []string{
|
expectedPrometheusQueries: []string{
|
||||||
`histogram_quantile(0.5, sum(irate(response_latency_ms_bucket{direction="outbound", dst_namespace="emojivoto", dst_pod="emojivoto-2", namespace="emojivoto", pod="emojivoto-1"}[1m])) by (le, namespace, pod))`,
|
`histogram_quantile(0.5, sum(irate(response_latency_ms_bucket{direction="outbound", dst_namespace="emojivoto", dst_pod="emojivoto-2", namespace="emojivoto", pod="emojivoto-1"}[1m])) by (le, namespace, pod))`,
|
||||||
|
|
@ -922,7 +922,7 @@ status:
|
||||||
`,
|
`,
|
||||||
},
|
},
|
||||||
mockPromResponse: model.Vector{
|
mockPromResponse: model.Vector{
|
||||||
genPromSample("emojivoto-1", "pod", "emojivoto", false),
|
genPromSample("emojivoto-1", "pod", false),
|
||||||
},
|
},
|
||||||
expectedPrometheusQueries: []string{
|
expectedPrometheusQueries: []string{
|
||||||
`histogram_quantile(0.5, sum(irate(response_latency_ms_bucket{direction="outbound", dst_namespace="totallydifferent", dst_pod="emojivoto-2", namespace="emojivoto", pod="emojivoto-1"}[1m])) by (le, namespace, pod))`,
|
`histogram_quantile(0.5, sum(irate(response_latency_ms_bucket{direction="outbound", dst_namespace="totallydifferent", dst_pod="emojivoto-2", namespace="emojivoto", pod="emojivoto-1"}[1m])) by (le, namespace, pod))`,
|
||||||
|
|
@ -990,7 +990,7 @@ status:
|
||||||
`,
|
`,
|
||||||
},
|
},
|
||||||
mockPromResponse: model.Vector{
|
mockPromResponse: model.Vector{
|
||||||
genPromSample("emojivoto-1", "pod", "emojivoto", true),
|
genPromSample("emojivoto-1", "pod", true),
|
||||||
},
|
},
|
||||||
expectedPrometheusQueries: []string{
|
expectedPrometheusQueries: []string{
|
||||||
`histogram_quantile(0.5, sum(irate(response_latency_ms_bucket{direction="outbound", pod="emojivoto-2"}[1m])) by (le, dst_namespace, dst_pod))`,
|
`histogram_quantile(0.5, sum(irate(response_latency_ms_bucket{direction="outbound", pod="emojivoto-2"}[1m])) by (le, dst_namespace, dst_pod))`,
|
||||||
|
|
@ -1058,7 +1058,7 @@ status:
|
||||||
`,
|
`,
|
||||||
},
|
},
|
||||||
mockPromResponse: model.Vector{
|
mockPromResponse: model.Vector{
|
||||||
genPromSample("emojivoto-1", "pod", "emojivoto", true),
|
genPromSample("emojivoto-1", "pod", true),
|
||||||
},
|
},
|
||||||
expectedPrometheusQueries: []string{
|
expectedPrometheusQueries: []string{
|
||||||
`histogram_quantile(0.5, sum(irate(response_latency_ms_bucket{direction="outbound", dst_namespace="emojivoto", dst_pod="emojivoto-1", namespace="totallydifferent", pod="emojivoto-2"}[1m])) by (le, dst_namespace, dst_pod))`,
|
`histogram_quantile(0.5, sum(irate(response_latency_ms_bucket{direction="outbound", dst_namespace="emojivoto", dst_pod="emojivoto-1", namespace="totallydifferent", pod="emojivoto-2"}[1m])) by (le, dst_namespace, dst_pod))`,
|
||||||
|
|
@ -1226,28 +1226,6 @@ status:
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
Table: &pb.StatTable_PodGroup_{
|
|
||||||
PodGroup: &pb.StatTable_PodGroup{
|
|
||||||
Rows: []*pb.StatTable_PodGroup_Row{
|
|
||||||
{
|
|
||||||
Resource: &pb.Resource{
|
|
||||||
Namespace: "emojivoto",
|
|
||||||
Type: pkgK8s.Authority,
|
|
||||||
},
|
|
||||||
TimeWindow: "1m",
|
|
||||||
Stats: &pb.BasicStats{
|
|
||||||
SuccessCount: 123,
|
|
||||||
FailureCount: 0,
|
|
||||||
LatencyMsP50: 123,
|
|
||||||
LatencyMsP95: 123,
|
|
||||||
LatencyMsP99: 123,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
Table: &pb.StatTable_PodGroup_{
|
Table: &pb.StatTable_PodGroup_{
|
||||||
PodGroup: &pb.StatTable_PodGroup{
|
PodGroup: &pb.StatTable_PodGroup{
|
||||||
|
|
@ -1686,146 +1664,6 @@ status:
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("Queries prometheus for authority stats", func(t *testing.T) {
|
|
||||||
expectations := []statSumExpected{
|
|
||||||
{
|
|
||||||
expectedStatRPC: expectedStatRPC{
|
|
||||||
err: nil,
|
|
||||||
k8sConfigs: []string{`
|
|
||||||
apiVersion: v1
|
|
||||||
kind: Pod
|
|
||||||
metadata:
|
|
||||||
name: emojivoto-1
|
|
||||||
namespace: emojivoto
|
|
||||||
labels:
|
|
||||||
app: emoji-svc
|
|
||||||
linkerd.io/control-plane-ns: linkerd
|
|
||||||
status:
|
|
||||||
phase: Running
|
|
||||||
`,
|
|
||||||
},
|
|
||||||
mockPromResponse: model.Vector{
|
|
||||||
genPromSample("10.1.1.239:9995", "authority", "linkerd", false),
|
|
||||||
},
|
|
||||||
expectedPrometheusQueries: []string{
|
|
||||||
`histogram_quantile(0.5, sum(irate(response_latency_ms_bucket{direction="inbound", namespace="linkerd"}[1m])) by (le, namespace, authority))`,
|
|
||||||
`histogram_quantile(0.95, sum(irate(response_latency_ms_bucket{direction="inbound", namespace="linkerd"}[1m])) by (le, namespace, authority))`,
|
|
||||||
`histogram_quantile(0.99, sum(irate(response_latency_ms_bucket{direction="inbound", namespace="linkerd"}[1m])) by (le, namespace, authority))`,
|
|
||||||
`sum(increase(response_total{direction="inbound", namespace="linkerd"}[1m])) by (namespace, authority, classification, tls)`,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
req: &pb.StatSummaryRequest{
|
|
||||||
Selector: &pb.ResourceSelection{
|
|
||||||
Resource: &pb.Resource{
|
|
||||||
Namespace: "linkerd",
|
|
||||||
Type: pkgK8s.Authority,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
TimeWindow: "1m",
|
|
||||||
},
|
|
||||||
expectedResponse: GenStatSummaryResponse("10.1.1.239:9995", pkgK8s.Authority, []string{"linkerd"}, nil, true, false),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
testStatSummary(t, expectations)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("Queries prometheus for authority stats when --from deployment is used", func(t *testing.T) {
|
|
||||||
expectations := []statSumExpected{
|
|
||||||
{
|
|
||||||
expectedStatRPC: expectedStatRPC{
|
|
||||||
err: nil,
|
|
||||||
k8sConfigs: []string{`
|
|
||||||
apiVersion: v1
|
|
||||||
kind: Pod
|
|
||||||
metadata:
|
|
||||||
name: emojivoto-1
|
|
||||||
namespace: emojivoto
|
|
||||||
labels:
|
|
||||||
app: emoji-svc
|
|
||||||
linkerd.io/control-plane-ns: linkerd
|
|
||||||
status:
|
|
||||||
phase: Running
|
|
||||||
`,
|
|
||||||
},
|
|
||||||
mockPromResponse: model.Vector{
|
|
||||||
genPromSample("10.1.1.239:9995", "authority", "linkerd", false),
|
|
||||||
},
|
|
||||||
expectedPrometheusQueries: []string{
|
|
||||||
`histogram_quantile(0.5, sum(irate(response_latency_ms_bucket{deployment="emojivoto", direction="outbound"}[1m])) by (le, dst_namespace, authority))`,
|
|
||||||
`histogram_quantile(0.95, sum(irate(response_latency_ms_bucket{deployment="emojivoto", direction="outbound"}[1m])) by (le, dst_namespace, authority))`,
|
|
||||||
`histogram_quantile(0.99, sum(irate(response_latency_ms_bucket{deployment="emojivoto", direction="outbound"}[1m])) by (le, dst_namespace, authority))`,
|
|
||||||
`sum(increase(response_total{deployment="emojivoto", direction="outbound"}[1m])) by (dst_namespace, authority, classification, tls)`,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
req: &pb.StatSummaryRequest{
|
|
||||||
Selector: &pb.ResourceSelection{
|
|
||||||
Resource: &pb.Resource{
|
|
||||||
Namespace: "linkerd",
|
|
||||||
Type: pkgK8s.Authority,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
TimeWindow: "1m",
|
|
||||||
Outbound: &pb.StatSummaryRequest_FromResource{
|
|
||||||
FromResource: &pb.Resource{
|
|
||||||
Name: "emojivoto",
|
|
||||||
Namespace: "",
|
|
||||||
Type: pkgK8s.Deployment,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
expectedResponse: GenStatSummaryResponse("10.1.1.239:9995", pkgK8s.Authority, []string{""}, nil, true, false),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
testStatSummary(t, expectations)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("Queries prometheus for a named authority", func(t *testing.T) {
|
|
||||||
expectations := []statSumExpected{
|
|
||||||
{
|
|
||||||
expectedStatRPC: expectedStatRPC{
|
|
||||||
err: nil,
|
|
||||||
k8sConfigs: []string{`
|
|
||||||
apiVersion: v1
|
|
||||||
kind: Pod
|
|
||||||
metadata:
|
|
||||||
name: emojivoto-1
|
|
||||||
namespace: emojivoto
|
|
||||||
labels:
|
|
||||||
app: emoji-svc
|
|
||||||
linkerd.io/control-plane-ns: linkerd
|
|
||||||
status:
|
|
||||||
phase: Running
|
|
||||||
`,
|
|
||||||
},
|
|
||||||
mockPromResponse: model.Vector{
|
|
||||||
genPromSample("10.1.1.239:9995", "authority", "linkerd", false),
|
|
||||||
},
|
|
||||||
expectedPrometheusQueries: []string{
|
|
||||||
`histogram_quantile(0.5, sum(irate(response_latency_ms_bucket{authority="10.1.1.239:9995", direction="inbound", namespace="linkerd"}[1m])) by (le, namespace, authority))`,
|
|
||||||
`histogram_quantile(0.95, sum(irate(response_latency_ms_bucket{authority="10.1.1.239:9995", direction="inbound", namespace="linkerd"}[1m])) by (le, namespace, authority))`,
|
|
||||||
`histogram_quantile(0.99, sum(irate(response_latency_ms_bucket{authority="10.1.1.239:9995", direction="inbound", namespace="linkerd"}[1m])) by (le, namespace, authority))`,
|
|
||||||
`sum(increase(response_total{authority="10.1.1.239:9995", direction="inbound", namespace="linkerd"}[1m])) by (namespace, authority, classification, tls)`,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
req: &pb.StatSummaryRequest{
|
|
||||||
Selector: &pb.ResourceSelection{
|
|
||||||
Resource: &pb.Resource{
|
|
||||||
Namespace: "linkerd",
|
|
||||||
Type: pkgK8s.Authority,
|
|
||||||
Name: "10.1.1.239:9995",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
TimeWindow: "1m",
|
|
||||||
},
|
|
||||||
expectedResponse: GenStatSummaryResponse("10.1.1.239:9995", pkgK8s.Authority, []string{"linkerd"}, nil, true, false),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
testStatSummary(t, expectations)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("Stats returned are nil when SkipStats is true", func(t *testing.T) {
|
t.Run("Stats returned are nil when SkipStats is true", func(t *testing.T) {
|
||||||
expectations := []statSumExpected{
|
expectations := []statSumExpected{
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,6 @@ package api
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
@ -58,11 +57,6 @@ func (s *grpcServer) TopRoutes(ctx context.Context, req *pb.TopRoutesRequest) (*
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if targetResource.GetType() == k8s.Authority {
|
|
||||||
// Authority cannot be the target because authorities don't have namespaces,
|
|
||||||
// therefore there is no namespace in which to look for a service profile.
|
|
||||||
return topRoutesError(req, "Authority cannot be the target of a routes query; try using an authority in the --to flag instead"), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
err = s.validateTimeWindow(ctx, req.TimeWindow)
|
err = s.validateTimeWindow(ctx, req.TimeWindow)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -139,31 +133,22 @@ func (s *grpcServer) topRoutesFor(ctx context.Context, req *pb.TopRoutesRequest,
|
||||||
|
|
||||||
profiles := make(map[string]*sp.ServiceProfile)
|
profiles := make(map[string]*sp.ServiceProfile)
|
||||||
|
|
||||||
if requestedResource.GetType() == k8s.Authority {
|
// Lookup individual resource objects.
|
||||||
// Authorities may not be a source, so we know this is a ToResource.
|
objects, err := s.k8sAPI.GetObjects(requestedResource.Namespace, requestedResource.Type, requestedResource.Name, labelSelector)
|
||||||
profiles, err = s.getProfilesForAuthority(requestedResource.GetName(), clientNs, labelSelector)
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// Find service profiles for all services in all objects in the resource.
|
||||||
|
for _, obj := range objects {
|
||||||
|
// Lookup services for each object.
|
||||||
|
services, err := s.k8sAPI.GetServicesFor(obj, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
// Non-authority resource.
|
|
||||||
// Lookup individual resource objects.
|
|
||||||
objects, err := s.k8sAPI.GetObjects(requestedResource.Namespace, requestedResource.Type, requestedResource.Name, labelSelector)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
// Find service profiles for all services in all objects in the resource.
|
|
||||||
for _, obj := range objects {
|
|
||||||
// Lookup services for each object.
|
|
||||||
services, err := s.k8sAPI.GetServicesFor(obj, false)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, svc := range services {
|
for _, svc := range services {
|
||||||
p := s.k8sAPI.GetServiceProfileFor(svc, clientNs, s.clusterDomain)
|
p := s.k8sAPI.GetServiceProfileFor(svc, clientNs, s.clusterDomain)
|
||||||
profiles[svc.GetName()] = p
|
profiles[svc.GetName()] = p
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -197,43 +182,13 @@ func validateRequest(req *pb.TopRoutesRequest) *pb.TopRoutesResponse {
|
||||||
if req.GetNone() == nil {
|
if req.GetNone() == nil {
|
||||||
// This is an outbound (--to) request.
|
// This is an outbound (--to) request.
|
||||||
targetType := req.GetSelector().GetResource().GetType()
|
targetType := req.GetSelector().GetResource().GetType()
|
||||||
if targetType == k8s.Service || targetType == k8s.Authority {
|
if targetType == k8s.Service {
|
||||||
return topRoutesError(req, fmt.Sprintf("The %s resource type is not supported with 'to' queries", targetType))
|
return topRoutesError(req, fmt.Sprintf("The %s resource type is not supported with 'to' queries", targetType))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *grpcServer) getProfilesForAuthority(authority string, clientNs string, labelSelector labels.Selector) (map[string]*sp.ServiceProfile, error) {
|
|
||||||
if authority == "" {
|
|
||||||
// All authorities
|
|
||||||
ps, err := s.k8sAPI.SP().Lister().ServiceProfiles(clientNs).List(labelSelector)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(ps) == 0 {
|
|
||||||
return nil, errors.New("No ServiceProfiles found")
|
|
||||||
}
|
|
||||||
|
|
||||||
profiles := make(map[string]*sp.ServiceProfile)
|
|
||||||
|
|
||||||
for _, p := range ps {
|
|
||||||
profiles[p.Name] = p
|
|
||||||
}
|
|
||||||
|
|
||||||
return profiles, nil
|
|
||||||
}
|
|
||||||
// Specific authority
|
|
||||||
p, err := s.k8sAPI.SP().Lister().ServiceProfiles(clientNs).Get(authority)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return map[string]*sp.ServiceProfile{
|
|
||||||
p.Name: p,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *grpcServer) getRouteMetrics(ctx context.Context, req *pb.TopRoutesRequest, profiles map[string]*sp.ServiceProfile, resource *pb.Resource) (indexedTable, error) {
|
func (s *grpcServer) getRouteMetrics(ctx context.Context, req *pb.TopRoutesRequest, profiles map[string]*sp.ServiceProfile, resource *pb.Resource) (indexedTable, error) {
|
||||||
timeWindow := req.TimeWindow
|
timeWindow := req.TimeWindow
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -460,44 +460,4 @@ func TestTopRoutes(t *testing.T) {
|
||||||
|
|
||||||
testTopRoutes(t, expectations)
|
testTopRoutes(t, expectations)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("Successfully performs an outbound authority query", func(t *testing.T) {
|
|
||||||
routes := []string{"/a"}
|
|
||||||
counts := []uint64{123}
|
|
||||||
expectations := []topRoutesExpected{
|
|
||||||
{
|
|
||||||
expectedStatRPC: expectedStatRPC{
|
|
||||||
err: nil,
|
|
||||||
mockPromResponse: routesMetric([]string{"/a"}),
|
|
||||||
expectedPrometheusQueries: []string{
|
|
||||||
`histogram_quantile(0.5, sum(irate(route_response_latency_ms_bucket{deployment="books", direction="outbound", dst=~"(books.default.svc.cluster.local)(:\\d+)?", namespace="default"}[1m])) by (le, dst, rt_route))`,
|
|
||||||
`histogram_quantile(0.95, sum(irate(route_response_latency_ms_bucket{deployment="books", direction="outbound", dst=~"(books.default.svc.cluster.local)(:\\d+)?", namespace="default"}[1m])) by (le, dst, rt_route))`,
|
|
||||||
`histogram_quantile(0.99, sum(irate(route_response_latency_ms_bucket{deployment="books", direction="outbound", dst=~"(books.default.svc.cluster.local)(:\\d+)?", namespace="default"}[1m])) by (le, dst, rt_route))`,
|
|
||||||
`sum(increase(route_response_total{deployment="books", direction="outbound", dst=~"(books.default.svc.cluster.local)(:\\d+)?", namespace="default"}[1m])) by (rt_route, dst, classification)`,
|
|
||||||
`sum(increase(route_actual_response_total{deployment="books", direction="outbound", dst=~"(books.default.svc.cluster.local)(:\\d+)?", namespace="default"}[1m])) by (rt_route, dst, classification)`,
|
|
||||||
},
|
|
||||||
k8sConfigs: booksConfig,
|
|
||||||
},
|
|
||||||
req: &pb.TopRoutesRequest{
|
|
||||||
Selector: &pb.ResourceSelection{
|
|
||||||
Resource: &pb.Resource{
|
|
||||||
Namespace: "default",
|
|
||||||
Type: pkgK8s.Deployment,
|
|
||||||
Name: "books",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Outbound: &pb.TopRoutesRequest_ToResource{
|
|
||||||
ToResource: &pb.Resource{
|
|
||||||
Type: pkgK8s.Authority,
|
|
||||||
Name: "books.default.svc.cluster.local",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
TimeWindow: "1m",
|
|
||||||
},
|
|
||||||
expectedResponse: GenTopRoutesResponse(routes, counts, true, "books.default.svc.cluster.local"),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
testTopRoutes(t, expectations)
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -274,9 +274,7 @@ func validateFromResourceType(resourceType string) (string, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
if name == k8s.Authority {
|
|
||||||
return "", errors.New("cannot query traffic --from an authority")
|
|
||||||
}
|
|
||||||
return name, nil
|
return name, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -63,10 +63,7 @@ func QueryLabels(resource *pb.Resource) model.LabelSet {
|
||||||
// note that metricToKey assumes the label ordering (namespace, name)
|
// note that metricToKey assumes the label ordering (namespace, name)
|
||||||
func DstGroupByLabelNames(resource *pb.Resource) model.LabelNames {
|
func DstGroupByLabelNames(resource *pb.Resource) model.LabelNames {
|
||||||
names := model.LabelNames{DstNamespaceLabel}
|
names := model.LabelNames{DstNamespaceLabel}
|
||||||
|
if resource.Type != k8s.Namespace {
|
||||||
if IsNonK8sResourceQuery(resource.GetType()) {
|
|
||||||
names = append(names, ResourceType(resource))
|
|
||||||
} else if resource.Type != k8s.Namespace {
|
|
||||||
names = append(names, "dst_"+ResourceType(resource))
|
names = append(names, "dst_"+ResourceType(resource))
|
||||||
}
|
}
|
||||||
return names
|
return names
|
||||||
|
|
@ -76,14 +73,11 @@ func DstGroupByLabelNames(resource *pb.Resource) model.LabelNames {
|
||||||
func DstQueryLabels(resource *pb.Resource) model.LabelSet {
|
func DstQueryLabels(resource *pb.Resource) model.LabelSet {
|
||||||
set := model.LabelSet{}
|
set := model.LabelSet{}
|
||||||
if resource.Name != "" {
|
if resource.Name != "" {
|
||||||
if IsNonK8sResourceQuery(resource.GetType()) {
|
set["dst_"+ResourceType(resource)] = model.LabelValue(resource.Name)
|
||||||
set[ResourceType(resource)] = model.LabelValue(resource.Name)
|
if shouldAddNamespaceLabel(resource) {
|
||||||
} else {
|
set[DstNamespaceLabel] = model.LabelValue(resource.Namespace)
|
||||||
set["dst_"+ResourceType(resource)] = model.LabelValue(resource.Name)
|
|
||||||
if shouldAddNamespaceLabel(resource) {
|
|
||||||
set[DstNamespaceLabel] = model.LabelValue(resource.Namespace)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return set
|
return set
|
||||||
|
|
@ -98,7 +92,3 @@ func ResourceType(resource *pb.Resource) model.LabelName {
|
||||||
func shouldAddNamespaceLabel(resource *pb.Resource) bool {
|
func shouldAddNamespaceLabel(resource *pb.Resource) bool {
|
||||||
return resource.Type != k8s.Namespace && resource.Namespace != ""
|
return resource.Type != k8s.Namespace && resource.Namespace != ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func IsNonK8sResourceQuery(resourceType string) bool {
|
|
||||||
return resourceType == k8s.Authority
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,6 @@ import (
|
||||||
// - target resource on an outbound 'to' query
|
// - target resource on an outbound 'to' query
|
||||||
// - destination resource on an outbound 'from' query
|
// - destination resource on an outbound 'from' query
|
||||||
var ValidTargets = []string{
|
var ValidTargets = []string{
|
||||||
k8s.Authority,
|
|
||||||
k8s.CronJob,
|
k8s.CronJob,
|
||||||
k8s.DaemonSet,
|
k8s.DaemonSet,
|
||||||
k8s.Deployment,
|
k8s.Deployment,
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue