...

Source file src/github.com/linkerd/linkerd2/viz/metrics-api/authz.go

Documentation: github.com/linkerd/linkerd2/viz/metrics-api

     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  	// check for well-formed request
    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  	// Use `labels` as direction isn't present with authorization metrics
    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  			// Get the row if it exists or initialize an empty one
    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_{ // https://github.com/golang/protobuf/issues/205
   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