mirror of https://github.com/knative/caching.git
Auto-update dependencies (#48)
Produced via: `dep ensure -update github.com/knative/test-infra knative.dev/pkg` /assign @mattmoor
This commit is contained in:
parent
c4acbc0a45
commit
77d253c889
|
@ -261,7 +261,7 @@
|
|||
"tools/dep-collector",
|
||||
]
|
||||
pruneopts = "UT"
|
||||
revision = "2b0eeafd5300d91d0c96a719bd230fb3b3dd96ce"
|
||||
revision = "f7f13f8e3a8af17943e1a44102607f1d3fc4751d"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:5985ef4caf91ece5d54817c11ea25f182697534f8ae6521eadcd628c142ac4b6"
|
||||
|
@ -930,7 +930,7 @@
|
|||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:c1c7cfe29d74a22c0fbc3ab02907361f8f5cd7e4a6757b9452f64d21682b040b"
|
||||
digest = "1:ed15fad369d1d253ebcae3defd279859d26e54d83e1e601fb3cf40d192377404"
|
||||
name = "knative.dev/pkg"
|
||||
packages = [
|
||||
"apis",
|
||||
|
@ -949,7 +949,7 @@
|
|||
"metrics/metricskey",
|
||||
]
|
||||
pruneopts = "T"
|
||||
revision = "c9bcf7e03fb535c28eae2b5ec1cf70e9363e32a7"
|
||||
revision = "84d3910c565e397fa044f246398f94712da53303"
|
||||
|
||||
[solve-meta]
|
||||
analyzer-name = "dep"
|
||||
|
|
|
@ -300,14 +300,14 @@
|
|||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:bba4889bf4bf0a2f132ed8a2bbc4725c2877bc7b7dee37cdc551351b862a3559"
|
||||
digest = "1:1bc2182db9fca862cd2b3a028aad73e473705be1c3f2454429a37b8626e16eda"
|
||||
name = "github.com/knative/test-infra"
|
||||
packages = [
|
||||
"scripts",
|
||||
"tools/dep-collector",
|
||||
]
|
||||
pruneopts = "UT"
|
||||
revision = "91d37e4abc3047fc32ff6c0adcdea4fd29d47602"
|
||||
revision = "2b0eeafd5300d91d0c96a719bd230fb3b3dd96ce"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:56dbf15e091bf7926cb33a57cb6bdfc658fc6d3498d2f76f10a97ce7856f1fde"
|
||||
|
|
|
@ -0,0 +1,161 @@
|
|||
/*
|
||||
Copyright 2019 The Knative Authors
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package metricstest
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"go.opencensus.io/stats/view"
|
||||
)
|
||||
|
||||
// CheckStatsReported checks that there is a view registered with the given name for each string in names,
|
||||
// and that each view has at least one record.
|
||||
func CheckStatsReported(t *testing.T, names ...string) {
|
||||
t.Helper()
|
||||
for _, name := range names {
|
||||
d, err := view.RetrieveData(name)
|
||||
if err != nil {
|
||||
t.Errorf("For metric %s: Reporter.Report() error = %v", name, err)
|
||||
}
|
||||
if len(d) < 1 {
|
||||
t.Errorf("For metric %s: No data reported when data was expected, view data is empty.", name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// CheckStatsNotReported checks that there are no records for any views that a name matching a string in names.
|
||||
// Names that do not match registered views are considered not reported.
|
||||
func CheckStatsNotReported(t *testing.T, names ...string) {
|
||||
t.Helper()
|
||||
for _, name := range names {
|
||||
d, err := view.RetrieveData(name)
|
||||
// err == nil means a valid stat exists matching "name"
|
||||
// len(d) > 0 means a component recorded metrics for that stat
|
||||
if err == nil && len(d) > 0 {
|
||||
t.Errorf("For metric %s: Unexpected data reported when no data was expected. Reporter len(d) = %d", name, len(d))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// CheckCountData checks the view with a name matching string name to verify that the CountData stats
|
||||
// reported are tagged with the tags in wantTags and that wantValue matches reported count.
|
||||
func CheckCountData(t *testing.T, name string, wantTags map[string]string, wantValue int64) {
|
||||
t.Helper()
|
||||
if row := checkExactlyOneRow(t, name, wantTags); row != nil {
|
||||
checkRowTags(t, row, name, wantTags)
|
||||
|
||||
if s, ok := row.Data.(*view.CountData); !ok {
|
||||
t.Errorf("For metric %s: Reporter expected a CountData type", name)
|
||||
} else if s.Value != wantValue {
|
||||
t.Errorf("For metric %s: value = %v, want: %d", name, s.Value, wantValue)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// CheckDistributionData checks the view with a name matching string name to verify that the DistributionData stats reported
|
||||
// are tagged with the tags in wantTags and that expectedCount number of records were reported.
|
||||
// It also checks that expectedMin and expectedMax match the minimum and maximum reported values, respectively.
|
||||
func CheckDistributionData(t *testing.T, name string, wantTags map[string]string, expectedCount int64, expectedMin float64, expectedMax float64) {
|
||||
t.Helper()
|
||||
if row := checkExactlyOneRow(t, name, wantTags); row != nil {
|
||||
checkRowTags(t, row, name, wantTags)
|
||||
|
||||
if s, ok := row.Data.(*view.DistributionData); !ok {
|
||||
t.Errorf("For metric %s: Reporter expected a DistributionData type", name)
|
||||
} else {
|
||||
if s.Count != expectedCount {
|
||||
t.Errorf("For metric %s: reporter count = %d, want = %d", name, s.Count, expectedCount)
|
||||
}
|
||||
if s.Min != expectedMin {
|
||||
t.Errorf("For metric %s: reporter count = %f, want = %f", name, s.Min, expectedMin)
|
||||
}
|
||||
if s.Max != expectedMax {
|
||||
t.Errorf("For metric %s: reporter count = %f, want = %f", name, s.Max, expectedMax)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// CheckLastValueData checks the view with a name matching string name to verify that the LastValueData stats
|
||||
// reported are tagged with the tags in wantTags and that wantValue matches reported last value.
|
||||
func CheckLastValueData(t *testing.T, name string, wantTags map[string]string, wantValue float64) {
|
||||
t.Helper()
|
||||
if row := checkExactlyOneRow(t, name, wantTags); row != nil {
|
||||
checkRowTags(t, row, name, wantTags)
|
||||
|
||||
if s, ok := row.Data.(*view.LastValueData); !ok {
|
||||
t.Errorf("For metric %s: Reporter.Report() expected a LastValueData type", name)
|
||||
} else if s.Value != wantValue {
|
||||
t.Errorf("For metric %s: Reporter.Report() expected %v got %v", name, s.Value, wantValue)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// CheckSumData checks the view with a name matching string name to verify that the SumData stats
|
||||
// reported are tagged with the tags in wantTags and that wantValue matches the reported sum.
|
||||
func CheckSumData(t *testing.T, name string, wantTags map[string]string, wantValue float64) {
|
||||
t.Helper()
|
||||
if row := checkExactlyOneRow(t, name, wantTags); row != nil {
|
||||
checkRowTags(t, row, name, wantTags)
|
||||
|
||||
if s, ok := row.Data.(*view.SumData); !ok {
|
||||
t.Errorf("For metric %s: Reporter expected a SumData type", name)
|
||||
} else if s.Value != wantValue {
|
||||
t.Errorf("For metric %s: value = %v, want: %v", name, s.Value, wantValue)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Unregister unregisters the metrics that were registered.
|
||||
// This is useful for testing since golang execute test iterations within the same process and
|
||||
// opencensus views maintain global state. At the beginning of each test, tests should
|
||||
// unregister for all metrics and then re-register for the same metrics. This effectively clears
|
||||
// out any existing data and avoids a panic due to re-registering a metric.
|
||||
//
|
||||
// In normal process shutdown, metrics do not need to be unregistered.
|
||||
func Unregister(names ...string) {
|
||||
for _, n := range names {
|
||||
if v := view.Find(n); v != nil {
|
||||
view.Unregister(v)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func checkExactlyOneRow(t *testing.T, name string, wantTags map[string]string) *view.Row {
|
||||
t.Helper()
|
||||
d, err := view.RetrieveData(name)
|
||||
if err != nil {
|
||||
t.Errorf("For metric %s: Reporter.Report() error = %v", name, err)
|
||||
return nil
|
||||
}
|
||||
if len(d) != 1 {
|
||||
t.Errorf("For metric %s: Reporter.Report() len(d)=%v, want 1", name, len(d))
|
||||
}
|
||||
|
||||
return d[0]
|
||||
}
|
||||
|
||||
func checkRowTags(t *testing.T, row *view.Row, name string, wantTags map[string]string) {
|
||||
t.Helper()
|
||||
for _, got := range row.Tags {
|
||||
n := got.Key.Name()
|
||||
if want, ok := wantTags[n]; !ok {
|
||||
t.Errorf("For metric %s: Reporter got an extra tag %v: %v", name, n, got.Value)
|
||||
} else if got.Value != want {
|
||||
t.Errorf("For metric %s: Reporter expected a different tag value for key: %s, got: %s, want: %s", name, n, got.Value, want)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -54,3 +54,14 @@ func Record(ctx context.Context, ms stats.Measurement) {
|
|||
stats.Record(ctx, ms)
|
||||
}
|
||||
}
|
||||
|
||||
// Buckets125 generates an array of buckets with approximate powers-of-two
|
||||
// buckets that also aligns with powers of 10 on every 3rd step. This can
|
||||
// be used to create a view.Distribution.
|
||||
func Buckets125(low, high float64) []float64 {
|
||||
buckets := []float64{low}
|
||||
for last := low; last < high; last = last * 10 {
|
||||
buckets = append(buckets, 2*last, 5*last, 10*last)
|
||||
}
|
||||
return buckets
|
||||
}
|
||||
|
|
|
@ -0,0 +1,151 @@
|
|||
/*
|
||||
Copyright 2019 The Knative Authors
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package webhook
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"go.opencensus.io/stats"
|
||||
"go.opencensus.io/stats/view"
|
||||
"go.opencensus.io/tag"
|
||||
admissionv1beta1 "k8s.io/api/admission/v1beta1"
|
||||
"knative.dev/pkg/metrics"
|
||||
)
|
||||
|
||||
const (
|
||||
requestCountName = "request_count"
|
||||
requestLatenciesName = "request_latencies"
|
||||
)
|
||||
|
||||
var (
|
||||
requestCountM = stats.Int64(
|
||||
requestCountName,
|
||||
"The number of requests that are routed to webhook",
|
||||
stats.UnitDimensionless)
|
||||
responseTimeInMsecM = stats.Float64(
|
||||
requestLatenciesName,
|
||||
"The response time in milliseconds",
|
||||
stats.UnitMilliseconds)
|
||||
|
||||
// Create the tag keys that will be used to add tags to our measurements.
|
||||
// Tag keys must conform to the restrictions described in
|
||||
// go.opencensus.io/tag/validate.go. Currently those restrictions are:
|
||||
// - length between 1 and 255 inclusive
|
||||
// - characters are printable US-ASCII
|
||||
requestOperationKey = mustNewTagKey("request_operation")
|
||||
kindGroupKey = mustNewTagKey("kind_group")
|
||||
kindVersionKey = mustNewTagKey("kind_version")
|
||||
kindKindKey = mustNewTagKey("kind_kind")
|
||||
resourceGroupKey = mustNewTagKey("resource_group")
|
||||
resourceVersionKey = mustNewTagKey("resource_version")
|
||||
resourceResourceKey = mustNewTagKey("resource_resource")
|
||||
resourceNameKey = mustNewTagKey("resource_name")
|
||||
resourceNamespaceKey = mustNewTagKey("resource_namespace")
|
||||
admissionAllowedKey = mustNewTagKey("admission_allowed")
|
||||
)
|
||||
|
||||
func init() {
|
||||
register()
|
||||
}
|
||||
|
||||
// StatsReporter reports webhook metrics
|
||||
type StatsReporter interface {
|
||||
ReportRequest(request *admissionv1beta1.AdmissionRequest, response *admissionv1beta1.AdmissionResponse, d time.Duration) error
|
||||
}
|
||||
|
||||
// reporter implements StatsReporter interface
|
||||
type reporter struct {
|
||||
ctx context.Context
|
||||
}
|
||||
|
||||
// NewStatsReporter creaters a reporter for webhook metrics
|
||||
func NewStatsReporter() (StatsReporter, error) {
|
||||
ctx, err := tag.New(
|
||||
context.Background(),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &reporter{ctx: ctx}, nil
|
||||
}
|
||||
|
||||
// Captures req count metric, recording the count and the duration
|
||||
func (r *reporter) ReportRequest(req *admissionv1beta1.AdmissionRequest, resp *admissionv1beta1.AdmissionResponse, d time.Duration) error {
|
||||
ctx, err := tag.New(
|
||||
r.ctx,
|
||||
tag.Insert(requestOperationKey, string(req.Operation)),
|
||||
tag.Insert(kindGroupKey, req.Kind.Group),
|
||||
tag.Insert(kindVersionKey, req.Kind.Version),
|
||||
tag.Insert(kindKindKey, req.Kind.Kind),
|
||||
tag.Insert(resourceGroupKey, req.Resource.Group),
|
||||
tag.Insert(resourceVersionKey, req.Resource.Version),
|
||||
tag.Insert(resourceResourceKey, req.Resource.Resource),
|
||||
tag.Insert(resourceNameKey, req.Name),
|
||||
tag.Insert(resourceNamespaceKey, req.Namespace),
|
||||
tag.Insert(admissionAllowedKey, strconv.FormatBool(resp.Allowed)),
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
metrics.Record(ctx, requestCountM.M(1))
|
||||
// Convert time.Duration in nanoseconds to milliseconds
|
||||
metrics.Record(ctx, responseTimeInMsecM.M(float64(d/time.Millisecond)))
|
||||
return nil
|
||||
}
|
||||
|
||||
func register() {
|
||||
tagKeys := []tag.Key{
|
||||
requestOperationKey,
|
||||
kindGroupKey,
|
||||
kindVersionKey,
|
||||
kindKindKey,
|
||||
resourceGroupKey,
|
||||
resourceVersionKey,
|
||||
resourceResourceKey,
|
||||
resourceNamespaceKey,
|
||||
resourceNameKey,
|
||||
admissionAllowedKey}
|
||||
|
||||
if err := view.Register(
|
||||
&view.View{
|
||||
Description: requestCountM.Description(),
|
||||
Measure: requestCountM,
|
||||
Aggregation: view.Count(),
|
||||
TagKeys: tagKeys,
|
||||
},
|
||||
&view.View{
|
||||
Description: responseTimeInMsecM.Description(),
|
||||
Measure: responseTimeInMsecM,
|
||||
Aggregation: view.Distribution(metrics.Buckets125(1, 100000)...), // [1 2 5 10 20 50 100 200 500 1000 2000 5000 10000 20000 50000 100000]ms
|
||||
TagKeys: tagKeys,
|
||||
},
|
||||
); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func mustNewTagKey(s string) tag.Key {
|
||||
tagKey, err := tag.NewKey(s)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return tagKey
|
||||
}
|
|
@ -114,10 +114,11 @@ type ResourceDefaulter func(patches *[]jsonpatch.JsonPatchOperation, crd Generic
|
|||
// AdmissionController implements the external admission webhook for validation of
|
||||
// pilot configuration.
|
||||
type AdmissionController struct {
|
||||
Client kubernetes.Interface
|
||||
Options ControllerOptions
|
||||
Handlers map[schema.GroupVersionKind]GenericCRD
|
||||
Logger *zap.SugaredLogger
|
||||
Client kubernetes.Interface
|
||||
Options ControllerOptions
|
||||
Handlers map[schema.GroupVersionKind]GenericCRD
|
||||
Logger *zap.SugaredLogger
|
||||
StatsReporter StatsReporter
|
||||
|
||||
WithContext func(context.Context) context.Context
|
||||
DisallowUnknownFields bool
|
||||
|
@ -408,6 +409,7 @@ func (ac *AdmissionController) register(
|
|||
// ServeHTTP implements the external admission webhook for mutating
|
||||
// serving resources.
|
||||
func (ac *AdmissionController) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
var ttStart = time.Now()
|
||||
logger := ac.Logger
|
||||
logger.Infof("Webhook ServeHTTP request=%#v", r)
|
||||
|
||||
|
@ -452,6 +454,9 @@ func (ac *AdmissionController) ServeHTTP(w http.ResponseWriter, r *http.Request)
|
|||
http.Error(w, fmt.Sprintf("could encode response: %v", err), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
// Only report valid requests
|
||||
ac.StatsReporter.ReportRequest(review.Request, response.Response, time.Since(ttStart))
|
||||
}
|
||||
|
||||
func makeErrorStatus(reason string, args ...interface{}) *admissionv1beta1.AdmissionResponse {
|
||||
|
|
Loading…
Reference in New Issue