1 package api
2
3 import (
4 "context"
5 "fmt"
6
7 pb "github.com/linkerd/linkerd2/viz/metrics-api/gen/viz"
8 "github.com/prometheus/common/model"
9 log "github.com/sirupsen/logrus"
10 )
11
12 func (s *grpcServer) Authz(ctx context.Context, req *pb.AuthzRequest) (*pb.AuthzResponse, error) {
13
14
15 if req.GetResource() == nil {
16 return &pb.AuthzResponse{
17 Response: &pb.AuthzResponse_Error{
18 Error: &pb.ResourceError{
19 Error: "AuthzRequest missing resource",
20 },
21 },
22 }, nil
23 }
24
25 labels := promQueryLabels(req.GetResource())
26 reqLabels := labels.Merge(model.LabelSet{
27 "direction": model.LabelValue("inbound"),
28 })
29
30 groupBy := model.LabelNames{
31 routeKindLabel, routeNameLabel, authorizationKindLabel, authorizationNameLabel, serverKindLabel, serverNameLabel,
32 }
33 promQueries := make(map[promType]string)
34 promQueries[promRequests] = fmt.Sprintf(reqQuery, reqLabels, req.TimeWindow, groupBy.String())
35
36 promQueries[promAllowedRequests] = fmt.Sprintf(httpAuthzAllowQuery, labels, req.TimeWindow, groupBy.String())
37 promQueries[promDeniedRequests] = fmt.Sprintf(httpAuthzDenyQuery, labels, req.TimeWindow, groupBy.String())
38 quantileQueries := generateQuantileQueries(latencyQuantileQuery, reqLabels.String(), req.TimeWindow, groupBy.String())
39 results, err := s.getPrometheusMetrics(ctx, promQueries, quantileQueries)
40 if err != nil {
41 return &pb.AuthzResponse{
42 Response: &pb.AuthzResponse_Error{
43 Error: &pb.ResourceError{
44 Error: err.Error(),
45 },
46 },
47 }, nil
48 }
49
50 type rowKey struct {
51 routeName string
52 routeKind string
53 serverName string
54 serverKind string
55 authzName string
56 authzKind string
57 }
58 rows := map[rowKey]*pb.StatTable_PodGroup_Row{}
59
60 for _, result := range results {
61 for _, sample := range result.vec {
62 key := rowKey{
63 routeName: string(sample.Metric[routeNameLabel]),
64 routeKind: string(sample.Metric[routeKindLabel]),
65 serverName: string(sample.Metric[serverNameLabel]),
66 serverKind: string(sample.Metric[serverKindLabel]),
67 authzName: string(sample.Metric[authorizationNameLabel]),
68 authzKind: string(sample.Metric[authorizationKindLabel]),
69 }
70
71 row := rows[key]
72 if row == nil {
73 row = &pb.StatTable_PodGroup_Row{
74 Resource: req.Resource,
75 Stats: &pb.BasicStats{},
76 SrvStats: &pb.ServerStats{
77 Srv: &pb.Resource{
78 Namespace: string(sample.Metric[namespaceLabel]),
79 Type: key.serverKind,
80 Name: key.serverName,
81 },
82 Route: &pb.Resource{
83 Namespace: string(sample.Metric[namespaceLabel]),
84 Type: key.routeKind,
85 Name: key.routeName,
86 },
87 Authz: &pb.Resource{
88 Namespace: string(sample.Metric[namespaceLabel]),
89 Type: key.authzKind,
90 Name: key.authzName,
91 },
92 },
93 }
94 rows[key] = row
95 }
96
97 value := extractSampleValue(sample)
98 switch result.prom {
99 case promRequests:
100 switch string(sample.Metric[model.LabelName("classification")]) {
101 case success:
102 row.Stats.SuccessCount += value
103 case failure:
104 row.Stats.FailureCount += value
105 }
106 case promLatencyP50:
107 row.Stats.LatencyMsP50 = value
108 case promLatencyP95:
109 row.Stats.LatencyMsP95 = value
110 case promLatencyP99:
111 row.Stats.LatencyMsP99 = value
112 case promAllowedRequests:
113 row.SrvStats.AllowedCount = value
114 case promDeniedRequests:
115 row.SrvStats.DeniedCount = value
116 }
117 }
118 }
119
120 table := []*pb.StatTable_PodGroup_Row{}
121 for _, row := range rows {
122 table = append(table, row)
123 }
124
125 rsp := pb.AuthzResponse{
126 Response: &pb.AuthzResponse_Ok_{
127 Ok: &pb.AuthzResponse_Ok{
128 StatTable: &pb.StatTable{
129 Table: &pb.StatTable_PodGroup_{
130 PodGroup: &pb.StatTable_PodGroup{
131 Rows: table,
132 },
133 },
134 },
135 },
136 },
137 }
138
139 log.Debugf("Sent response as %+v\n", table)
140 return &rsp, nil
141 }
142
View as plain text