From 3ddca0eadce99ddb2c1800bbce25f472a347977a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Lambert?= Date: Wed, 16 Feb 2022 14:39:16 -0500 Subject: [PATCH 1/6] Add delay in the agent between each metrics push MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Kévin Lambert --- pkg/agent/agent.go | 45 +++- pkg/agent/agent_metrics_test.go | 98 ++++++++ pkg/agent/comm_internal_test.go | 28 ++- pkg/agent/utils.go | 16 ++ .../github.com/stretchr/testify/suite/doc.go | 65 ++++++ .../stretchr/testify/suite/interfaces.go | 53 +++++ .../stretchr/testify/suite/stats.go | 46 ++++ .../stretchr/testify/suite/suite.go | 209 ++++++++++++++++++ vendor/modules.txt | 1 + 9 files changed, 555 insertions(+), 6 deletions(-) create mode 100644 pkg/agent/agent_metrics_test.go create mode 100644 pkg/agent/utils.go create mode 100644 vendor/github.com/stretchr/testify/suite/doc.go create mode 100644 vendor/github.com/stretchr/testify/suite/interfaces.go create mode 100644 vendor/github.com/stretchr/testify/suite/stats.go create mode 100644 vendor/github.com/stretchr/testify/suite/suite.go diff --git a/pkg/agent/agent.go b/pkg/agent/agent.go index 6f267de4fa..d43c70832a 100644 --- a/pkg/agent/agent.go +++ b/pkg/agent/agent.go @@ -104,6 +104,12 @@ type Agent struct { // Field selector for the k8s resources that the agent watches agentWatchFieldSelector string + + // A mutex related to the metrics endpoint action, to avoid concurrent (and useless) pushes. + metricsPushMutex sync.Mutex + // Timestamp to keep in memory to Prevent from making too many requests to the Ambassador + // Cloud API. + metricsRelayDeadline time.Time } func getEnvWithDefault(envVarKey string, defaultValue string) string { @@ -149,6 +155,7 @@ func NewAgent(directiveHandler DirectiveHandler, rolloutsGetterFactory rolloutsG directiveHandler: directiveHandler, reportRunning: atomicBool{value: false}, agentWatchFieldSelector: getEnvWithDefault("AGENT_WATCH_FIELD_SELECTOR", "metadata.namespace!=kube-system"), + metricsRelayDeadline: time.Now(), } } @@ -609,15 +616,33 @@ func (a *Agent) ProcessSnapshot(ctx context.Context, snapshot *snapshotTypes.Sna var allowedMetricsSuffixes = []string{"upstream_rq_total", "upstream_rq_time", "upstream_rq_5xx"} -func (a *Agent) MetricsRelayHandler(logCtx context.Context, in *envoyMetrics.StreamMetricsMessage) { +// MetricsRelayHandler is invoked as a callback when the agent receive metrics from Envoy (sink). +func (a *Agent) MetricsRelayHandler( + logCtx context.Context, + in *envoyMetrics.StreamMetricsMessage, +) { + a.metricsPushMutex.Lock() + defer a.metricsPushMutex.Unlock() + metrics := in.GetEnvoyMetrics() - dlog.Debugf(logCtx, "received %d metrics", len(metrics)) + metricCount := len(metrics) + + if !time.Now().After(a.metricsRelayDeadline) { + dlog.Debugf(logCtx, "Drop %d metric(s); next push scheduled for %s", + metricCount, a.metricsRelayDeadline.String()) + return + } + if a.comm != nil && !a.reportingStopped { + + dlog.Infof(logCtx, "Received %d metric(s)", metricCount) + a.ambassadorAPIKeyMutex.Lock() apikey := a.ambassadorAPIKey a.ambassadorAPIKeyMutex.Unlock() outMetrics := make([]*io_prometheus_client.MetricFamily, 0, len(metrics)) + for _, metricFamily := range metrics { for _, suffix := range allowedMetricsSuffixes { if strings.HasSuffix(metricFamily.GetName(), suffix) { @@ -631,9 +656,19 @@ func (a *Agent) MetricsRelayHandler(logCtx context.Context, in *envoyMetrics.Str Identity: a.agentID, EnvoyMetrics: outMetrics, } - dlog.Debugf(logCtx, "relaying %d metrics", len(outMessage.GetEnvoyMetrics())) - if err := a.comm.StreamMetrics(logCtx, outMessage, apikey); err != nil { - dlog.Errorf(logCtx, "Error streaming metrics: %+v", err) + + if relayedMetricCount := len(outMessage.GetEnvoyMetrics()); relayedMetricCount > 0 { + + dlog.Infof(logCtx, "Relaying %d metric(s)", relayedMetricCount) + + if err := a.comm.StreamMetrics(logCtx, outMessage, apikey); err != nil { + dlog.Errorf(logCtx, "error streaming metric(s): %+v", err) + } + + a.metricsRelayDeadline = time.Now().Add(defaultMinReportPeriod) + + dlog.Infof(logCtx, "Next metrics relay scheduled for %s", + a.metricsRelayDeadline.UTC().String()) } } } diff --git a/pkg/agent/agent_metrics_test.go b/pkg/agent/agent_metrics_test.go new file mode 100644 index 0000000000..d772c9de22 --- /dev/null +++ b/pkg/agent/agent_metrics_test.go @@ -0,0 +1,98 @@ +package agent + +import ( + "context" + "github.com/datawire/ambassador/v2/pkg/api/agent" + envoyMetrics "github.com/datawire/ambassador/v2/pkg/api/envoy/service/metrics/v3" + io_prometheus_client "github.com/prometheus/client_model/go" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/suite" + "testing" + "time" +) + +var ( + counterType = io_prometheus_client.MetricType_COUNTER + acceptedMetric = &io_prometheus_client.MetricFamily{ + Name: StrToPointer("cluster.apple_prod_443.upstream_rq_total"), + Type: &counterType, + Metric: []*io_prometheus_client.Metric{ + { + Counter: &io_prometheus_client.Counter{ + Value: Float64ToPointer(42), + }, + TimestampMs: Int64ToPointer(time.Now().Unix() * 1000), + }, + }, + } + ignoredMetric = &io_prometheus_client.MetricFamily{ + Name: StrToPointer("cluster.apple_prod_443.metric_to_ignore"), + Type: &counterType, + Metric: []*io_prometheus_client.Metric{ + { + Counter: &io_prometheus_client.Counter{ + Value: Float64ToPointer(42), + }, + TimestampMs: Int64ToPointer(time.Now().Unix() * 1000), + }, + }, + } +) + +type AgentMetricsSuite struct { + suite.Suite + + clientMock *MockClient + + stubbedAgent *Agent +} + +func (s *AgentMetricsSuite) SetupTest() { + s.clientMock = &MockClient{} + + s.stubbedAgent = &Agent{ + metricsRelayDeadline: time.Time{}, + comm: &RPCComm{ + client: s.clientMock, + }, + } +} + +func (s *AgentMetricsSuite) AfterTest(suiteName, testName string) { + return +} + +func (s *AgentMetricsSuite) TestMetricsHandlerWithRelay() { + //given + ctx := context.TODO() + + //when + s.stubbedAgent.MetricsRelayHandler(ctx, &envoyMetrics.StreamMetricsMessage{ + Identifier: nil, + EnvoyMetrics: []*io_prometheus_client.MetricFamily{ignoredMetric, acceptedMetric}, + }) + + //then + assert.Equal(s.T(), []*agent.StreamMetricsMessage{{ + EnvoyMetrics: []*io_prometheus_client.MetricFamily{acceptedMetric}, + }}, s.clientMock.SentMetrics) +} + +func (s *AgentMetricsSuite) TestMetricsHandlerWithRelayPass() { + //given + ctx := context.TODO() + s.stubbedAgent.metricsRelayDeadline = time.Now().Add(defaultMinReportPeriod) + + //when + s.stubbedAgent.MetricsRelayHandler(ctx, &envoyMetrics.StreamMetricsMessage{ + Identifier: nil, + EnvoyMetrics: []*io_prometheus_client.MetricFamily{acceptedMetric}, + }) + + //then + assert.Equal(s.T(), 0, len(s.clientMock.SentMetrics)) +} + +func TestSuiteAgentMetrics(t *testing.T) { + suite.Run(t, new(AgentMetricsSuite)) +} diff --git a/pkg/agent/comm_internal_test.go b/pkg/agent/comm_internal_test.go index 8f89efe318..fef610f225 100644 --- a/pkg/agent/comm_internal_test.go +++ b/pkg/agent/comm_internal_test.go @@ -20,6 +20,7 @@ import ( type MockClient struct { Counter int64 grpc.ClientStream + SentMetrics []*agent.StreamMetricsMessage SentSnapshots []*agent.Snapshot snapMux sync.Mutex reportFunc func(context.Context, *agent.Snapshot) (*agent.SnapshotResponse, error) @@ -64,9 +65,34 @@ func (m *MockClient) Report(ctx context.Context, in *agent.Snapshot, opts ...grp } func (m *MockClient) StreamMetrics(ctx context.Context, opts ...grpc.CallOption) (agent.Director_StreamMetricsClient, error) { - panic("implement me") + return &mockStreamMetricsClient{ + ctx: ctx, + opts: opts, + parent: m, + }, nil +} + +type mockStreamMetricsClient struct { + ctx context.Context + opts []grpc.CallOption + parent *MockClient } +func (s *mockStreamMetricsClient) Send(msg *agent.StreamMetricsMessage) error { + s.parent.SentMetrics = append(s.parent.SentMetrics, msg) + return nil +} +func (s *mockStreamMetricsClient) CloseAndRecv() (*agent.StreamMetricsResponse, error) { + return nil, nil +} + +func (s *mockStreamMetricsClient) Header() (metadata.MD, error) { return nil, nil } +func (s *mockStreamMetricsClient) Trailer() metadata.MD { return nil } +func (s *mockStreamMetricsClient) CloseSend() error { return nil } +func (s *mockStreamMetricsClient) Context() context.Context { return s.ctx } +func (s *mockStreamMetricsClient) SendMsg(m interface{}) error { return nil } +func (s *mockStreamMetricsClient) RecvMsg(m interface{}) error { return nil } + type mockReportStreamClient struct { ctx context.Context opts []grpc.CallOption diff --git a/pkg/agent/utils.go b/pkg/agent/utils.go new file mode 100644 index 0000000000..f0b7557001 --- /dev/null +++ b/pkg/agent/utils.go @@ -0,0 +1,16 @@ +package agent + +// StrToPointer will return the pointer to the given string. +func StrToPointer(str string) *string { + return &str +} + +// Float64ToPointer will return the pointer to the given float. +func Float64ToPointer(f float64) *float64 { + return &f +} + +// Int64ToPointer will return the pointer to the given int64. +func Int64ToPointer(i int64) *int64 { + return &i +} diff --git a/vendor/github.com/stretchr/testify/suite/doc.go b/vendor/github.com/stretchr/testify/suite/doc.go new file mode 100644 index 0000000000..f91a245d3f --- /dev/null +++ b/vendor/github.com/stretchr/testify/suite/doc.go @@ -0,0 +1,65 @@ +// Package suite contains logic for creating testing suite structs +// and running the methods on those structs as tests. The most useful +// piece of this package is that you can create setup/teardown methods +// on your testing suites, which will run before/after the whole suite +// or individual tests (depending on which interface(s) you +// implement). +// +// A testing suite is usually built by first extending the built-in +// suite functionality from suite.Suite in testify. Alternatively, +// you could reproduce that logic on your own if you wanted (you +// just need to implement the TestingSuite interface from +// suite/interfaces.go). +// +// After that, you can implement any of the interfaces in +// suite/interfaces.go to add setup/teardown functionality to your +// suite, and add any methods that start with "Test" to add tests. +// Methods that do not match any suite interfaces and do not begin +// with "Test" will not be run by testify, and can safely be used as +// helper methods. +// +// Once you've built your testing suite, you need to run the suite +// (using suite.Run from testify) inside any function that matches the +// identity that "go test" is already looking for (i.e. +// func(*testing.T)). +// +// Regular expression to select test suites specified command-line +// argument "-run". Regular expression to select the methods +// of test suites specified command-line argument "-m". +// Suite object has assertion methods. +// +// A crude example: +// // Basic imports +// import ( +// "testing" +// "github.com/stretchr/testify/assert" +// "github.com/stretchr/testify/suite" +// ) +// +// // Define the suite, and absorb the built-in basic suite +// // functionality from testify - including a T() method which +// // returns the current testing context +// type ExampleTestSuite struct { +// suite.Suite +// VariableThatShouldStartAtFive int +// } +// +// // Make sure that VariableThatShouldStartAtFive is set to five +// // before each test +// func (suite *ExampleTestSuite) SetupTest() { +// suite.VariableThatShouldStartAtFive = 5 +// } +// +// // All methods that begin with "Test" are run as tests within a +// // suite. +// func (suite *ExampleTestSuite) TestExample() { +// assert.Equal(suite.T(), 5, suite.VariableThatShouldStartAtFive) +// suite.Equal(5, suite.VariableThatShouldStartAtFive) +// } +// +// // In order for 'go test' to run this suite, we need to create +// // a normal test function and pass our suite to suite.Run +// func TestExampleTestSuite(t *testing.T) { +// suite.Run(t, new(ExampleTestSuite)) +// } +package suite diff --git a/vendor/github.com/stretchr/testify/suite/interfaces.go b/vendor/github.com/stretchr/testify/suite/interfaces.go new file mode 100644 index 0000000000..8b98a8af27 --- /dev/null +++ b/vendor/github.com/stretchr/testify/suite/interfaces.go @@ -0,0 +1,53 @@ +package suite + +import "testing" + +// TestingSuite can store and return the current *testing.T context +// generated by 'go test'. +type TestingSuite interface { + T() *testing.T + SetT(*testing.T) +} + +// SetupAllSuite has a SetupSuite method, which will run before the +// tests in the suite are run. +type SetupAllSuite interface { + SetupSuite() +} + +// SetupTestSuite has a SetupTest method, which will run before each +// test in the suite. +type SetupTestSuite interface { + SetupTest() +} + +// TearDownAllSuite has a TearDownSuite method, which will run after +// all the tests in the suite have been run. +type TearDownAllSuite interface { + TearDownSuite() +} + +// TearDownTestSuite has a TearDownTest method, which will run after +// each test in the suite. +type TearDownTestSuite interface { + TearDownTest() +} + +// BeforeTest has a function to be executed right before the test +// starts and receives the suite and test names as input +type BeforeTest interface { + BeforeTest(suiteName, testName string) +} + +// AfterTest has a function to be executed right after the test +// finishes and receives the suite and test names as input +type AfterTest interface { + AfterTest(suiteName, testName string) +} + +// WithStats implements HandleStats, a function that will be executed +// when a test suite is finished. The stats contain information about +// the execution of that suite and its tests. +type WithStats interface { + HandleStats(suiteName string, stats *SuiteInformation) +} diff --git a/vendor/github.com/stretchr/testify/suite/stats.go b/vendor/github.com/stretchr/testify/suite/stats.go new file mode 100644 index 0000000000..261da37f78 --- /dev/null +++ b/vendor/github.com/stretchr/testify/suite/stats.go @@ -0,0 +1,46 @@ +package suite + +import "time" + +// SuiteInformation stats stores stats for the whole suite execution. +type SuiteInformation struct { + Start, End time.Time + TestStats map[string]*TestInformation +} + +// TestInformation stores information about the execution of each test. +type TestInformation struct { + TestName string + Start, End time.Time + Passed bool +} + +func newSuiteInformation() *SuiteInformation { + testStats := make(map[string]*TestInformation) + + return &SuiteInformation{ + TestStats: testStats, + } +} + +func (s SuiteInformation) start(testName string) { + s.TestStats[testName] = &TestInformation{ + TestName: testName, + Start: time.Now(), + } +} + +func (s SuiteInformation) end(testName string, passed bool) { + s.TestStats[testName].End = time.Now() + s.TestStats[testName].Passed = passed +} + +func (s SuiteInformation) Passed() bool { + for _, stats := range s.TestStats { + if !stats.Passed { + return false + } + } + + return true +} diff --git a/vendor/github.com/stretchr/testify/suite/suite.go b/vendor/github.com/stretchr/testify/suite/suite.go new file mode 100644 index 0000000000..b9b5d1c56c --- /dev/null +++ b/vendor/github.com/stretchr/testify/suite/suite.go @@ -0,0 +1,209 @@ +package suite + +import ( + "flag" + "fmt" + "os" + "reflect" + "regexp" + "runtime/debug" + "testing" + "time" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +var allTestsFilter = func(_, _ string) (bool, error) { return true, nil } +var matchMethod = flag.String("testify.m", "", "regular expression to select tests of the testify suite to run") + +// Suite is a basic testing suite with methods for storing and +// retrieving the current *testing.T context. +type Suite struct { + *assert.Assertions + require *require.Assertions + t *testing.T +} + +// T retrieves the current *testing.T context. +func (suite *Suite) T() *testing.T { + return suite.t +} + +// SetT sets the current *testing.T context. +func (suite *Suite) SetT(t *testing.T) { + suite.t = t + suite.Assertions = assert.New(t) + suite.require = require.New(t) +} + +// Require returns a require context for suite. +func (suite *Suite) Require() *require.Assertions { + if suite.require == nil { + suite.require = require.New(suite.T()) + } + return suite.require +} + +// Assert returns an assert context for suite. Normally, you can call +// `suite.NoError(expected, actual)`, but for situations where the embedded +// methods are overridden (for example, you might want to override +// assert.Assertions with require.Assertions), this method is provided so you +// can call `suite.Assert().NoError()`. +func (suite *Suite) Assert() *assert.Assertions { + if suite.Assertions == nil { + suite.Assertions = assert.New(suite.T()) + } + return suite.Assertions +} + +func failOnPanic(t *testing.T) { + r := recover() + if r != nil { + t.Errorf("test panicked: %v\n%s", r, debug.Stack()) + t.FailNow() + } +} + +// Run provides suite functionality around golang subtests. It should be +// called in place of t.Run(name, func(t *testing.T)) in test suite code. +// The passed-in func will be executed as a subtest with a fresh instance of t. +// Provides compatibility with go test pkg -run TestSuite/TestName/SubTestName. +func (suite *Suite) Run(name string, subtest func()) bool { + oldT := suite.T() + defer suite.SetT(oldT) + return oldT.Run(name, func(t *testing.T) { + suite.SetT(t) + subtest() + }) +} + +// Run takes a testing suite and runs all of the tests attached +// to it. +func Run(t *testing.T, suite TestingSuite) { + defer failOnPanic(t) + + suite.SetT(t) + + var suiteSetupDone bool + + var stats *SuiteInformation + if _, ok := suite.(WithStats); ok { + stats = newSuiteInformation() + } + + tests := []testing.InternalTest{} + methodFinder := reflect.TypeOf(suite) + suiteName := methodFinder.Elem().Name() + + for i := 0; i < methodFinder.NumMethod(); i++ { + method := methodFinder.Method(i) + + ok, err := methodFilter(method.Name) + if err != nil { + fmt.Fprintf(os.Stderr, "testify: invalid regexp for -m: %s\n", err) + os.Exit(1) + } + + if !ok { + continue + } + + if !suiteSetupDone { + if stats != nil { + stats.Start = time.Now() + } + + if setupAllSuite, ok := suite.(SetupAllSuite); ok { + setupAllSuite.SetupSuite() + } + + suiteSetupDone = true + } + + test := testing.InternalTest{ + Name: method.Name, + F: func(t *testing.T) { + parentT := suite.T() + suite.SetT(t) + defer failOnPanic(t) + defer func() { + if stats != nil { + passed := !t.Failed() + stats.end(method.Name, passed) + } + + if afterTestSuite, ok := suite.(AfterTest); ok { + afterTestSuite.AfterTest(suiteName, method.Name) + } + + if tearDownTestSuite, ok := suite.(TearDownTestSuite); ok { + tearDownTestSuite.TearDownTest() + } + + suite.SetT(parentT) + }() + + if setupTestSuite, ok := suite.(SetupTestSuite); ok { + setupTestSuite.SetupTest() + } + if beforeTestSuite, ok := suite.(BeforeTest); ok { + beforeTestSuite.BeforeTest(methodFinder.Elem().Name(), method.Name) + } + + if stats != nil { + stats.start(method.Name) + } + + method.Func.Call([]reflect.Value{reflect.ValueOf(suite)}) + }, + } + tests = append(tests, test) + } + if suiteSetupDone { + defer func() { + if tearDownAllSuite, ok := suite.(TearDownAllSuite); ok { + tearDownAllSuite.TearDownSuite() + } + + if suiteWithStats, measureStats := suite.(WithStats); measureStats { + stats.End = time.Now() + suiteWithStats.HandleStats(suiteName, stats) + } + }() + } + + runTests(t, tests) +} + +// Filtering method according to set regular expression +// specified command-line argument -m +func methodFilter(name string) (bool, error) { + if ok, _ := regexp.MatchString("^Test", name); !ok { + return false, nil + } + return regexp.MatchString(*matchMethod, name) +} + +func runTests(t testing.TB, tests []testing.InternalTest) { + if len(tests) == 0 { + t.Log("warning: no tests to run") + return + } + + r, ok := t.(runner) + if !ok { // backwards compatibility with Go 1.6 and below + if !testing.RunTests(allTestsFilter, tests) { + t.Fail() + } + return + } + + for _, test := range tests { + r.Run(test.Name, test.F) + } +} + +type runner interface { + Run(name string, f func(t *testing.T)) bool +} diff --git a/vendor/modules.txt b/vendor/modules.txt index 60b77a655d..ee8d260f9b 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -315,6 +315,7 @@ github.com/spf13/pflag ## explicit; go 1.13 github.com/stretchr/testify/assert github.com/stretchr/testify/require +github.com/stretchr/testify/suite # github.com/xlab/treeprint v1.1.0 ## explicit; go 1.13 github.com/xlab/treeprint From 934ed65bc4f63dfd4cf39e78cb36d6203f57d58c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Lambert?= Date: Mon, 11 Apr 2022 10:55:59 -0400 Subject: [PATCH 2/6] Add optional RPC header to debug with telepresence MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Kévin Lambert --- pkg/agent/agent.go | 19 ++++++++++++++++++- pkg/agent/comm.go | 36 +++++++++++++++++++++++++----------- 2 files changed, 43 insertions(+), 12 deletions(-) diff --git a/pkg/agent/agent.go b/pkg/agent/agent.go index d43c70832a..0c54de3c4d 100644 --- a/pkg/agent/agent.go +++ b/pkg/agent/agent.go @@ -110,6 +110,9 @@ type Agent struct { // Timestamp to keep in memory to Prevent from making too many requests to the Ambassador // Cloud API. metricsRelayDeadline time.Time + + // Extra headers to inject into RPC requests to ambassador cloud. + rpcExtraHeaders []string } func getEnvWithDefault(envVarKey string, defaultValue string) string { @@ -141,6 +144,17 @@ func NewAgent(directiveHandler DirectiveHandler, rolloutsGetterFactory rolloutsG } } + var rpcExtraHeaders = make([]string, 0) + + if os.Getenv("RPC_INTERCEPT_HEADER_KEY") != "" && + os.Getenv("RPC_INTERCEPT_HEADER_VALUE") != "" { + rpcExtraHeaders = append( + rpcExtraHeaders, + os.Getenv("RPC_INTERCEPT_HEADER_KEY"), + os.Getenv("RPC_INTERCEPT_HEADER_VALUE"), + ) + } + return &Agent{ minReportPeriod: reportPeriod, reportComplete: make(chan error), @@ -156,6 +170,7 @@ func NewAgent(directiveHandler DirectiveHandler, rolloutsGetterFactory rolloutsG reportRunning: atomicBool{value: false}, agentWatchFieldSelector: getEnvWithDefault("AGENT_WATCH_FIELD_SELECTOR", "metadata.namespace!=kube-system"), metricsRelayDeadline: time.Now(), + rpcExtraHeaders: rpcExtraHeaders, } } @@ -476,7 +491,9 @@ func (a *Agent) MaybeReport(ctx context.Context) { // The communications channel to the DCP was not yet created or was // closed above, due to a change in identity, or close elsewhere, due to // a change in endpoint configuration. - newComm, err := NewComm(ctx, a.connInfo, a.agentID, a.ambassadorAPIKey) + newComm, err := NewComm( + ctx, a.connInfo, a.agentID, a.ambassadorAPIKey, a.rpcExtraHeaders) + if err != nil { dlog.Warnf(ctx, "Failed to dial the DCP: %v", err) dlog.Warn(ctx, "DCP functionality disabled until next retry") diff --git a/pkg/agent/comm.go b/pkg/agent/comm.go index 0bc9d9b4ef..ef3193f160 100644 --- a/pkg/agent/comm.go +++ b/pkg/agent/comm.go @@ -27,6 +27,7 @@ type RPCComm struct { agentID *agent.Identity directives chan *agent.Directive metricsStreamWriterMutex sync.Mutex + extraHeaders []string } const ( @@ -64,7 +65,13 @@ func connInfoFromAddress(address string) (*ConnInfo, error) { return &ConnInfo{hostname, port, secure}, nil } -func NewComm(ctx context.Context, connInfo *ConnInfo, agentID *agent.Identity, apiKey string) (*RPCComm, error) { +func NewComm( + ctx context.Context, + connInfo *ConnInfo, + agentID *agent.Identity, + apiKey string, + extraHeaders []string, +) (*RPCComm, error) { ctx = dlog.WithField(ctx, "agent", "comm") opts := make([]grpc.DialOption, 0, 1) address := connInfo.hostname + ":" + connInfo.port @@ -88,20 +95,26 @@ func NewComm(ctx context.Context, connInfo *ConnInfo, agentID *agent.Identity, a retCtx, retCancel := context.WithCancel(ctx) c := &RPCComm{ - conn: conn, - client: client, - retCancel: retCancel, - agentID: agentID, - directives: make(chan *agent.Directive, 1), - rptWake: make(chan struct{}, 1), + conn: conn, + client: client, + retCancel: retCancel, + agentID: agentID, + directives: make(chan *agent.Directive, 1), + rptWake: make(chan struct{}, 1), + extraHeaders: extraHeaders, } - retCtx = metadata.AppendToOutgoingContext(retCtx, APIKeyMetadataKey, apiKey) + retCtx = metadata.AppendToOutgoingContext(ctx, c.getHeaders(apiKey)...) go c.retrieveLoop(retCtx) return c, nil } +func (c *RPCComm) getHeaders(apiKey string) []string { + return append([]string{ + APIKeyMetadataKey, apiKey}, c.extraHeaders...) +} + func (c *RPCComm) retrieveLoop(ctx context.Context) { ctx = dlog.WithField(ctx, "agent", "retriever") @@ -146,7 +159,7 @@ func (c *RPCComm) Close() error { } func (c *RPCComm) ReportCommandResult(ctx context.Context, result *agent.CommandResult, apiKey string) error { - ctx = metadata.AppendToOutgoingContext(ctx, APIKeyMetadataKey, apiKey) + ctx = metadata.AppendToOutgoingContext(ctx, c.getHeaders(apiKey)...) _, err := c.client.ReportCommandResult(ctx, result, grpc.EmptyCallOption{}) if err != nil { return fmt.Errorf("ReportCommandResult error: %w", err) @@ -159,7 +172,7 @@ func (c *RPCComm) Report(ctx context.Context, report *agent.Snapshot, apiKey str case c.rptWake <- struct{}{}: default: } - ctx = metadata.AppendToOutgoingContext(ctx, APIKeyMetadataKey, apiKey) + ctx = metadata.AppendToOutgoingContext(ctx, c.getHeaders(apiKey)...) // marshal snapshot data, err := json.Marshal(report) @@ -206,8 +219,9 @@ func (c *RPCComm) StreamMetrics(ctx context.Context, metrics *agent.StreamMetric c.metricsStreamWriterMutex.Lock() defer c.metricsStreamWriterMutex.Unlock() - ctx = metadata.AppendToOutgoingContext(ctx, APIKeyMetadataKey, apiKey) + ctx = metadata.AppendToOutgoingContext(ctx, c.getHeaders(apiKey)...) streamClient, err := c.client.StreamMetrics(ctx) + if err != nil { return err } From e3fab070109525237607ddd1a0ced98b5f1534a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Lambert?= Date: Mon, 11 Apr 2022 14:37:34 -0400 Subject: [PATCH 3/6] Use vanilla testing, variable renaming MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Kévin Lambert --- pkg/agent/agent.go | 18 +- pkg/agent/agent_metrics_test.go | 79 +++---- .../github.com/stretchr/testify/suite/doc.go | 65 ------ .../stretchr/testify/suite/interfaces.go | 53 ----- .../stretchr/testify/suite/stats.go | 46 ---- .../stretchr/testify/suite/suite.go | 209 ------------------ vendor/modules.txt | 1 - 7 files changed, 43 insertions(+), 428 deletions(-) delete mode 100644 vendor/github.com/stretchr/testify/suite/doc.go delete mode 100644 vendor/github.com/stretchr/testify/suite/interfaces.go delete mode 100644 vendor/github.com/stretchr/testify/suite/stats.go delete mode 100644 vendor/github.com/stretchr/testify/suite/suite.go diff --git a/pkg/agent/agent.go b/pkg/agent/agent.go index 0c54de3c4d..7b6e4e1322 100644 --- a/pkg/agent/agent.go +++ b/pkg/agent/agent.go @@ -106,10 +106,10 @@ type Agent struct { agentWatchFieldSelector string // A mutex related to the metrics endpoint action, to avoid concurrent (and useless) pushes. - metricsPushMutex sync.Mutex + metricsRelayMutex sync.Mutex // Timestamp to keep in memory to Prevent from making too many requests to the Ambassador // Cloud API. - metricsRelayDeadline time.Time + metricsBackoffUntil time.Time // Extra headers to inject into RPC requests to ambassador cloud. rpcExtraHeaders []string @@ -169,7 +169,7 @@ func NewAgent(directiveHandler DirectiveHandler, rolloutsGetterFactory rolloutsG directiveHandler: directiveHandler, reportRunning: atomicBool{value: false}, agentWatchFieldSelector: getEnvWithDefault("AGENT_WATCH_FIELD_SELECTOR", "metadata.namespace!=kube-system"), - metricsRelayDeadline: time.Now(), + metricsBackoffUntil: time.Now(), rpcExtraHeaders: rpcExtraHeaders, } } @@ -638,15 +638,15 @@ func (a *Agent) MetricsRelayHandler( logCtx context.Context, in *envoyMetrics.StreamMetricsMessage, ) { - a.metricsPushMutex.Lock() - defer a.metricsPushMutex.Unlock() + a.metricsRelayMutex.Lock() + defer a.metricsRelayMutex.Unlock() metrics := in.GetEnvoyMetrics() metricCount := len(metrics) - if !time.Now().After(a.metricsRelayDeadline) { + if !time.Now().After(a.metricsBackoffUntil) { dlog.Debugf(logCtx, "Drop %d metric(s); next push scheduled for %s", - metricCount, a.metricsRelayDeadline.String()) + metricCount, a.metricsBackoffUntil.String()) return } @@ -682,10 +682,10 @@ func (a *Agent) MetricsRelayHandler( dlog.Errorf(logCtx, "error streaming metric(s): %+v", err) } - a.metricsRelayDeadline = time.Now().Add(defaultMinReportPeriod) + a.metricsBackoffUntil = time.Now().Add(defaultMinReportPeriod) dlog.Infof(logCtx, "Next metrics relay scheduled for %s", - a.metricsRelayDeadline.UTC().String()) + a.metricsBackoffUntil.UTC().String()) } } } diff --git a/pkg/agent/agent_metrics_test.go b/pkg/agent/agent_metrics_test.go index d772c9de22..59f5116f15 100644 --- a/pkg/agent/agent_metrics_test.go +++ b/pkg/agent/agent_metrics_test.go @@ -1,12 +1,11 @@ package agent import ( - "context" "github.com/datawire/ambassador/v2/pkg/api/agent" envoyMetrics "github.com/datawire/ambassador/v2/pkg/api/envoy/service/metrics/v3" + "github.com/datawire/dlib/dlog" io_prometheus_client "github.com/prometheus/client_model/go" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/suite" "testing" "time" ) @@ -39,60 +38,50 @@ var ( } ) -type AgentMetricsSuite struct { - suite.Suite +func agentMetricsSetupTest() (*MockClient, *Agent) { + clientMock := &MockClient{} - clientMock *MockClient - - stubbedAgent *Agent -} - -func (s *AgentMetricsSuite) SetupTest() { - s.clientMock = &MockClient{} - - s.stubbedAgent = &Agent{ - metricsRelayDeadline: time.Time{}, + stubbedAgent := &Agent{ + metricsBackoffUntil: time.Time{}, comm: &RPCComm{ - client: s.clientMock, + client: clientMock, }, } -} -func (s *AgentMetricsSuite) AfterTest(suiteName, testName string) { - return + return clientMock, stubbedAgent } -func (s *AgentMetricsSuite) TestMetricsHandlerWithRelay() { - //given - ctx := context.TODO() +func TestMetricsRelayHandler(t *testing.T) { - //when - s.stubbedAgent.MetricsRelayHandler(ctx, &envoyMetrics.StreamMetricsMessage{ - Identifier: nil, - EnvoyMetrics: []*io_prometheus_client.MetricFamily{ignoredMetric, acceptedMetric}, - }) - - //then - assert.Equal(s.T(), []*agent.StreamMetricsMessage{{ - EnvoyMetrics: []*io_prometheus_client.MetricFamily{acceptedMetric}, - }}, s.clientMock.SentMetrics) -} + t.Run("will relay the metrics", func(t *testing.T) { + //given + clientMock, stubbedAgent := agentMetricsSetupTest() + ctx := dlog.NewTestContext(t, true) -func (s *AgentMetricsSuite) TestMetricsHandlerWithRelayPass() { - //given - ctx := context.TODO() - s.stubbedAgent.metricsRelayDeadline = time.Now().Add(defaultMinReportPeriod) + //when + stubbedAgent.MetricsRelayHandler(ctx, &envoyMetrics.StreamMetricsMessage{ + Identifier: nil, + EnvoyMetrics: []*io_prometheus_client.MetricFamily{ignoredMetric, acceptedMetric}, + }) - //when - s.stubbedAgent.MetricsRelayHandler(ctx, &envoyMetrics.StreamMetricsMessage{ - Identifier: nil, - EnvoyMetrics: []*io_prometheus_client.MetricFamily{acceptedMetric}, + //then + assert.Equal(t, []*agent.StreamMetricsMessage{{ + EnvoyMetrics: []*io_prometheus_client.MetricFamily{acceptedMetric}, + }}, clientMock.SentMetrics) }) + t.Run("will not relay the metrics since it is in cool down period.", func(t *testing.T) { + //given + clientMock, stubbedAgent := agentMetricsSetupTest() + ctx := dlog.NewTestContext(t, true) + stubbedAgent.metricsBackoffUntil = time.Now().Add(defaultMinReportPeriod) - //then - assert.Equal(s.T(), 0, len(s.clientMock.SentMetrics)) -} + //when + stubbedAgent.MetricsRelayHandler(ctx, &envoyMetrics.StreamMetricsMessage{ + Identifier: nil, + EnvoyMetrics: []*io_prometheus_client.MetricFamily{acceptedMetric}, + }) -func TestSuiteAgentMetrics(t *testing.T) { - suite.Run(t, new(AgentMetricsSuite)) + //then + assert.Equal(t, 0, len(clientMock.SentMetrics)) + }) } diff --git a/vendor/github.com/stretchr/testify/suite/doc.go b/vendor/github.com/stretchr/testify/suite/doc.go deleted file mode 100644 index f91a245d3f..0000000000 --- a/vendor/github.com/stretchr/testify/suite/doc.go +++ /dev/null @@ -1,65 +0,0 @@ -// Package suite contains logic for creating testing suite structs -// and running the methods on those structs as tests. The most useful -// piece of this package is that you can create setup/teardown methods -// on your testing suites, which will run before/after the whole suite -// or individual tests (depending on which interface(s) you -// implement). -// -// A testing suite is usually built by first extending the built-in -// suite functionality from suite.Suite in testify. Alternatively, -// you could reproduce that logic on your own if you wanted (you -// just need to implement the TestingSuite interface from -// suite/interfaces.go). -// -// After that, you can implement any of the interfaces in -// suite/interfaces.go to add setup/teardown functionality to your -// suite, and add any methods that start with "Test" to add tests. -// Methods that do not match any suite interfaces and do not begin -// with "Test" will not be run by testify, and can safely be used as -// helper methods. -// -// Once you've built your testing suite, you need to run the suite -// (using suite.Run from testify) inside any function that matches the -// identity that "go test" is already looking for (i.e. -// func(*testing.T)). -// -// Regular expression to select test suites specified command-line -// argument "-run". Regular expression to select the methods -// of test suites specified command-line argument "-m". -// Suite object has assertion methods. -// -// A crude example: -// // Basic imports -// import ( -// "testing" -// "github.com/stretchr/testify/assert" -// "github.com/stretchr/testify/suite" -// ) -// -// // Define the suite, and absorb the built-in basic suite -// // functionality from testify - including a T() method which -// // returns the current testing context -// type ExampleTestSuite struct { -// suite.Suite -// VariableThatShouldStartAtFive int -// } -// -// // Make sure that VariableThatShouldStartAtFive is set to five -// // before each test -// func (suite *ExampleTestSuite) SetupTest() { -// suite.VariableThatShouldStartAtFive = 5 -// } -// -// // All methods that begin with "Test" are run as tests within a -// // suite. -// func (suite *ExampleTestSuite) TestExample() { -// assert.Equal(suite.T(), 5, suite.VariableThatShouldStartAtFive) -// suite.Equal(5, suite.VariableThatShouldStartAtFive) -// } -// -// // In order for 'go test' to run this suite, we need to create -// // a normal test function and pass our suite to suite.Run -// func TestExampleTestSuite(t *testing.T) { -// suite.Run(t, new(ExampleTestSuite)) -// } -package suite diff --git a/vendor/github.com/stretchr/testify/suite/interfaces.go b/vendor/github.com/stretchr/testify/suite/interfaces.go deleted file mode 100644 index 8b98a8af27..0000000000 --- a/vendor/github.com/stretchr/testify/suite/interfaces.go +++ /dev/null @@ -1,53 +0,0 @@ -package suite - -import "testing" - -// TestingSuite can store and return the current *testing.T context -// generated by 'go test'. -type TestingSuite interface { - T() *testing.T - SetT(*testing.T) -} - -// SetupAllSuite has a SetupSuite method, which will run before the -// tests in the suite are run. -type SetupAllSuite interface { - SetupSuite() -} - -// SetupTestSuite has a SetupTest method, which will run before each -// test in the suite. -type SetupTestSuite interface { - SetupTest() -} - -// TearDownAllSuite has a TearDownSuite method, which will run after -// all the tests in the suite have been run. -type TearDownAllSuite interface { - TearDownSuite() -} - -// TearDownTestSuite has a TearDownTest method, which will run after -// each test in the suite. -type TearDownTestSuite interface { - TearDownTest() -} - -// BeforeTest has a function to be executed right before the test -// starts and receives the suite and test names as input -type BeforeTest interface { - BeforeTest(suiteName, testName string) -} - -// AfterTest has a function to be executed right after the test -// finishes and receives the suite and test names as input -type AfterTest interface { - AfterTest(suiteName, testName string) -} - -// WithStats implements HandleStats, a function that will be executed -// when a test suite is finished. The stats contain information about -// the execution of that suite and its tests. -type WithStats interface { - HandleStats(suiteName string, stats *SuiteInformation) -} diff --git a/vendor/github.com/stretchr/testify/suite/stats.go b/vendor/github.com/stretchr/testify/suite/stats.go deleted file mode 100644 index 261da37f78..0000000000 --- a/vendor/github.com/stretchr/testify/suite/stats.go +++ /dev/null @@ -1,46 +0,0 @@ -package suite - -import "time" - -// SuiteInformation stats stores stats for the whole suite execution. -type SuiteInformation struct { - Start, End time.Time - TestStats map[string]*TestInformation -} - -// TestInformation stores information about the execution of each test. -type TestInformation struct { - TestName string - Start, End time.Time - Passed bool -} - -func newSuiteInformation() *SuiteInformation { - testStats := make(map[string]*TestInformation) - - return &SuiteInformation{ - TestStats: testStats, - } -} - -func (s SuiteInformation) start(testName string) { - s.TestStats[testName] = &TestInformation{ - TestName: testName, - Start: time.Now(), - } -} - -func (s SuiteInformation) end(testName string, passed bool) { - s.TestStats[testName].End = time.Now() - s.TestStats[testName].Passed = passed -} - -func (s SuiteInformation) Passed() bool { - for _, stats := range s.TestStats { - if !stats.Passed { - return false - } - } - - return true -} diff --git a/vendor/github.com/stretchr/testify/suite/suite.go b/vendor/github.com/stretchr/testify/suite/suite.go deleted file mode 100644 index b9b5d1c56c..0000000000 --- a/vendor/github.com/stretchr/testify/suite/suite.go +++ /dev/null @@ -1,209 +0,0 @@ -package suite - -import ( - "flag" - "fmt" - "os" - "reflect" - "regexp" - "runtime/debug" - "testing" - "time" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" -) - -var allTestsFilter = func(_, _ string) (bool, error) { return true, nil } -var matchMethod = flag.String("testify.m", "", "regular expression to select tests of the testify suite to run") - -// Suite is a basic testing suite with methods for storing and -// retrieving the current *testing.T context. -type Suite struct { - *assert.Assertions - require *require.Assertions - t *testing.T -} - -// T retrieves the current *testing.T context. -func (suite *Suite) T() *testing.T { - return suite.t -} - -// SetT sets the current *testing.T context. -func (suite *Suite) SetT(t *testing.T) { - suite.t = t - suite.Assertions = assert.New(t) - suite.require = require.New(t) -} - -// Require returns a require context for suite. -func (suite *Suite) Require() *require.Assertions { - if suite.require == nil { - suite.require = require.New(suite.T()) - } - return suite.require -} - -// Assert returns an assert context for suite. Normally, you can call -// `suite.NoError(expected, actual)`, but for situations where the embedded -// methods are overridden (for example, you might want to override -// assert.Assertions with require.Assertions), this method is provided so you -// can call `suite.Assert().NoError()`. -func (suite *Suite) Assert() *assert.Assertions { - if suite.Assertions == nil { - suite.Assertions = assert.New(suite.T()) - } - return suite.Assertions -} - -func failOnPanic(t *testing.T) { - r := recover() - if r != nil { - t.Errorf("test panicked: %v\n%s", r, debug.Stack()) - t.FailNow() - } -} - -// Run provides suite functionality around golang subtests. It should be -// called in place of t.Run(name, func(t *testing.T)) in test suite code. -// The passed-in func will be executed as a subtest with a fresh instance of t. -// Provides compatibility with go test pkg -run TestSuite/TestName/SubTestName. -func (suite *Suite) Run(name string, subtest func()) bool { - oldT := suite.T() - defer suite.SetT(oldT) - return oldT.Run(name, func(t *testing.T) { - suite.SetT(t) - subtest() - }) -} - -// Run takes a testing suite and runs all of the tests attached -// to it. -func Run(t *testing.T, suite TestingSuite) { - defer failOnPanic(t) - - suite.SetT(t) - - var suiteSetupDone bool - - var stats *SuiteInformation - if _, ok := suite.(WithStats); ok { - stats = newSuiteInformation() - } - - tests := []testing.InternalTest{} - methodFinder := reflect.TypeOf(suite) - suiteName := methodFinder.Elem().Name() - - for i := 0; i < methodFinder.NumMethod(); i++ { - method := methodFinder.Method(i) - - ok, err := methodFilter(method.Name) - if err != nil { - fmt.Fprintf(os.Stderr, "testify: invalid regexp for -m: %s\n", err) - os.Exit(1) - } - - if !ok { - continue - } - - if !suiteSetupDone { - if stats != nil { - stats.Start = time.Now() - } - - if setupAllSuite, ok := suite.(SetupAllSuite); ok { - setupAllSuite.SetupSuite() - } - - suiteSetupDone = true - } - - test := testing.InternalTest{ - Name: method.Name, - F: func(t *testing.T) { - parentT := suite.T() - suite.SetT(t) - defer failOnPanic(t) - defer func() { - if stats != nil { - passed := !t.Failed() - stats.end(method.Name, passed) - } - - if afterTestSuite, ok := suite.(AfterTest); ok { - afterTestSuite.AfterTest(suiteName, method.Name) - } - - if tearDownTestSuite, ok := suite.(TearDownTestSuite); ok { - tearDownTestSuite.TearDownTest() - } - - suite.SetT(parentT) - }() - - if setupTestSuite, ok := suite.(SetupTestSuite); ok { - setupTestSuite.SetupTest() - } - if beforeTestSuite, ok := suite.(BeforeTest); ok { - beforeTestSuite.BeforeTest(methodFinder.Elem().Name(), method.Name) - } - - if stats != nil { - stats.start(method.Name) - } - - method.Func.Call([]reflect.Value{reflect.ValueOf(suite)}) - }, - } - tests = append(tests, test) - } - if suiteSetupDone { - defer func() { - if tearDownAllSuite, ok := suite.(TearDownAllSuite); ok { - tearDownAllSuite.TearDownSuite() - } - - if suiteWithStats, measureStats := suite.(WithStats); measureStats { - stats.End = time.Now() - suiteWithStats.HandleStats(suiteName, stats) - } - }() - } - - runTests(t, tests) -} - -// Filtering method according to set regular expression -// specified command-line argument -m -func methodFilter(name string) (bool, error) { - if ok, _ := regexp.MatchString("^Test", name); !ok { - return false, nil - } - return regexp.MatchString(*matchMethod, name) -} - -func runTests(t testing.TB, tests []testing.InternalTest) { - if len(tests) == 0 { - t.Log("warning: no tests to run") - return - } - - r, ok := t.(runner) - if !ok { // backwards compatibility with Go 1.6 and below - if !testing.RunTests(allTestsFilter, tests) { - t.Fail() - } - return - } - - for _, test := range tests { - r.Run(test.Name, test.F) - } -} - -type runner interface { - Run(name string, f func(t *testing.T)) bool -} diff --git a/vendor/modules.txt b/vendor/modules.txt index ee8d260f9b..60b77a655d 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -315,7 +315,6 @@ github.com/spf13/pflag ## explicit; go 1.13 github.com/stretchr/testify/assert github.com/stretchr/testify/require -github.com/stretchr/testify/suite # github.com/xlab/treeprint v1.1.0 ## explicit; go 1.13 github.com/xlab/treeprint From ad0bfa75c60b12ec6f4eb7fe32ca40c2c0fa4370 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Lambert?= Date: Tue, 12 Apr 2022 14:06:25 -0400 Subject: [PATCH 4/6] Add changelog for emissary-agent metric changes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Kévin Lambert --- CHANGELOG.md | 3 +++ docs/releaseNotes.yml | 8 ++++++++ 2 files changed, 11 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ac712542c9..05cb92b7dd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -111,7 +111,10 @@ Please see the [Envoy documentation](https://www.envoyproxy.io/docs/envoy/latest - Bugfix: Kubernetes Secrets that should contain an EC (Elliptic Curve) TLS Private Key are now properly validated. ([4134]) +- Change: The new delay between two syncs is 30s. ([#4122]) + [4134]: https://github.com/emissary-ingress/emissary/issues/4134 +[#4122]: https://github.com/emissary-ingress/emissary/pull/4122 ## [2.2.1] February 22, 2022 [2.2.1]: https://github.com/emissary-ingress/emissary/compare/v2.2.0...v2.2.1 diff --git a/docs/releaseNotes.yml b/docs/releaseNotes.yml index 5220fe09ea..edc792e666 100644 --- a/docs/releaseNotes.yml +++ b/docs/releaseNotes.yml @@ -68,6 +68,14 @@ items: link: https://github.com/emissary-ingress/emissary/issues/4134 docs: https://github.com/emissary-ingress/emissary/issues/4134 + - title: Decrease metric sync frequency + type: change + body: >- + The new delay between two syncs is 30s. + github: + - title: "#4122" + link: https://github.com/emissary-ingress/emissary/pull/4122 + - version: 2.2.1 date: '2022-02-22' notes: From e4154354d3d01f427befc0803fa01ffdc4998a8b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Lambert?= Date: Wed, 27 Apr 2022 12:41:31 -0400 Subject: [PATCH 5/6] Rephrase changelog title Signed-off-by: AliceProxy --- CHANGELOG.md | 2 +- docs/releaseNotes.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 05cb92b7dd..884e78e04e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -111,7 +111,7 @@ Please see the [Envoy documentation](https://www.envoyproxy.io/docs/envoy/latest - Bugfix: Kubernetes Secrets that should contain an EC (Elliptic Curve) TLS Private Key are now properly validated. ([4134]) -- Change: The new delay between two syncs is 30s. ([#4122]) +- Change: The new delay between two metrics syncs is now 30s. ([#4122]) [4134]: https://github.com/emissary-ingress/emissary/issues/4134 [#4122]: https://github.com/emissary-ingress/emissary/pull/4122 diff --git a/docs/releaseNotes.yml b/docs/releaseNotes.yml index edc792e666..2770fbd6cd 100644 --- a/docs/releaseNotes.yml +++ b/docs/releaseNotes.yml @@ -71,7 +71,7 @@ items: - title: Decrease metric sync frequency type: change body: >- - The new delay between two syncs is 30s. + The new delay between two metrics syncs is now 30s. github: - title: "#4122" link: https://github.com/emissary-ingress/emissary/pull/4122 From 1fefde90ab6698d229bb403dc5d3cc7521a3c18c Mon Sep 17 00:00:00 2001 From: AliceProxy Date: Wed, 27 Apr 2022 12:17:42 -0700 Subject: [PATCH 6/6] modify cast parse_bool to satisfy linter Signed-off-by: AliceProxy --- python/ambassador/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/ambassador/utils.py b/python/ambassador/utils.py index 3ff0d7cce3..92fff12bc7 100644 --- a/python/ambassador/utils.py +++ b/python/ambassador/utils.py @@ -169,7 +169,7 @@ def parse_bool(s: Optional[Union[str, bool]]) -> bool: # OK, we got _something_, so try strtobool. try: - return strtobool(s) + return bool(strtobool(s)) # the linter does not like a Literal[0, 1] being returned here except ValueError: return False