mirror of
https://github.com/open-policy-agent/opa.git
synced 2026-08-12 19:32:48 -06:00
Prepare v1.12.3 release (#8217)
Signed-off-by: Johan Fylling <johan.dev@fylling.se>
This commit is contained in:
@@ -3,6 +3,23 @@
|
||||
All notable changes to this project will be documented in this file. This
|
||||
project adheres to [Semantic Versioning](http://semver.org/).
|
||||
|
||||
## 1.12.3
|
||||
|
||||
This is a bug fix release addressing two issues:
|
||||
|
||||
### Bundle polling is being misconfigured when discovery bundle is updated ([#8215](https://github.com/open-policy-agent/opa/issues/8215))
|
||||
|
||||
This is an issue where the polling interval for discovery (`discovery.polling.min_delay_seconds` and `discovery.polling.max_delay_seconds`) were misinterpreted on reconfiguration, causing extremely long update intervals.
|
||||
|
||||
Reported by @loganmiller-chime, authored by @sspaink
|
||||
|
||||
### Decision log `size` buffer `buffer_size_limit_bytes` misconfigured during reconfiguration ([#8213](https://github.com/open-policy-agent/opa/pull/8213))
|
||||
|
||||
This is a regression in the decision log, where the `decision_logs.reporting.buffer_size_limit_bytes` was mistakenly assigned the value of `decision_logs.reporting.upload_size_limit_bytes` during reconfiguration.
|
||||
This issue is only present when `decision_logs.reporting.buffer_type` is set to `size`, which is the default value.
|
||||
|
||||
Authored by @sspaink
|
||||
|
||||
## 1.12.2
|
||||
|
||||
This bug fix release address issues found in the new string interpolation feature
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -25,8 +25,10 @@ const (
|
||||
|
||||
// PollingConfig represents polling configuration for the downloader.
|
||||
type PollingConfig struct {
|
||||
MinDelaySeconds *int64 `json:"min_delay_seconds,omitempty"` // min amount of time to wait between successful poll attempts
|
||||
MaxDelaySeconds *int64 `json:"max_delay_seconds,omitempty"` // max amount of time to wait between poll attempts
|
||||
MinDelaySeconds *int64 `json:"min_delay_seconds,omitempty"` // min amount of time to wait between successful poll attempts, represents the user provided value
|
||||
MaxDelaySeconds *int64 `json:"max_delay_seconds,omitempty"` // max amount of time to wait between poll attempts, represents the user provided value
|
||||
parsedMinDelaySeconds *int64 // nanosecond resolution of MinDelaySeconds
|
||||
parsedMaxDelaySeconds *int64 // nanosecond resolution of MaxDelaySeconds
|
||||
LongPollingTimeoutSeconds *int64 `json:"long_polling_timeout_seconds,omitempty"` // max amount of time the server should wait before issuing a timeout if there's no update available
|
||||
}
|
||||
|
||||
@@ -70,10 +72,10 @@ func (c *Config) ValidateAndInjectDefaults() error {
|
||||
|
||||
// scale to seconds
|
||||
minSeconds := int64(time.Duration(min) * time.Second)
|
||||
c.Polling.MinDelaySeconds = &minSeconds
|
||||
c.Polling.parsedMinDelaySeconds = &minSeconds
|
||||
|
||||
maxSeconds := int64(time.Duration(max) * time.Second)
|
||||
c.Polling.MaxDelaySeconds = &maxSeconds
|
||||
c.Polling.parsedMaxDelaySeconds = &maxSeconds
|
||||
|
||||
if c.Polling.LongPollingTimeoutSeconds != nil {
|
||||
if *c.Polling.LongPollingTimeoutSeconds < 1 {
|
||||
|
||||
+106
-11
@@ -6,6 +6,7 @@ package download
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
@@ -16,8 +17,10 @@ func TestConfigValidation(t *testing.T) {
|
||||
note string
|
||||
input string
|
||||
wantErr bool
|
||||
expMin time.Duration
|
||||
expMax time.Duration
|
||||
expMin *int64
|
||||
expMax *int64
|
||||
expParsedMin time.Duration
|
||||
expParsedMax time.Duration
|
||||
}{
|
||||
{
|
||||
note: "min > max",
|
||||
@@ -32,8 +35,10 @@ func TestConfigValidation(t *testing.T) {
|
||||
{
|
||||
note: "empty",
|
||||
input: `{}`,
|
||||
expMin: time.Second * time.Duration(defaultMinDelaySeconds),
|
||||
expMax: time.Second * time.Duration(defaultMaxDelaySeconds),
|
||||
expMin: nil,
|
||||
expMax: nil,
|
||||
expParsedMin: time.Second * time.Duration(defaultMinDelaySeconds),
|
||||
expParsedMax: time.Second * time.Duration(defaultMaxDelaySeconds),
|
||||
},
|
||||
{
|
||||
note: "min missing",
|
||||
@@ -61,8 +66,16 @@ func TestConfigValidation(t *testing.T) {
|
||||
"max_delay_seconds": 30
|
||||
}
|
||||
}`,
|
||||
expMin: time.Second * 10,
|
||||
expMax: time.Second * 30,
|
||||
expMin: func() *int64 {
|
||||
min := int64(10)
|
||||
return &min
|
||||
}(),
|
||||
expMax: func() *int64 {
|
||||
max := int64(30)
|
||||
return &max
|
||||
}(),
|
||||
expParsedMin: time.Second * 10,
|
||||
expParsedMax: time.Second * 30,
|
||||
},
|
||||
{
|
||||
note: "long polling timeout < 1",
|
||||
@@ -76,25 +89,107 @@ func TestConfigValidation(t *testing.T) {
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
|
||||
t.Run(test.note, func(t *testing.T) {
|
||||
var config Config
|
||||
|
||||
if err := json.Unmarshal([]byte(test.input), &config); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// no matter how many calls to ValidateAndInjectDefaults, the values should stay the same
|
||||
for range 3 {
|
||||
err := config.ValidateAndInjectDefaults()
|
||||
if err != nil && !test.wantErr {
|
||||
t.Errorf("Unexpected error on: %v, err: %v", test.input, err)
|
||||
} else if err != nil && test.wantErr {
|
||||
return
|
||||
}
|
||||
|
||||
if err == nil {
|
||||
if time.Duration(*config.Polling.MinDelaySeconds) != test.expMin {
|
||||
if config.Polling.MinDelaySeconds == nil && test.expMin != nil {
|
||||
t.Fatal("Expected min delay seconds to be set")
|
||||
}
|
||||
if config.Polling.MinDelaySeconds != nil && *config.Polling.MinDelaySeconds != *test.expMin {
|
||||
t.Errorf("For %q expected min %v but got %v", test.note, test.expMin, time.Duration(*config.Polling.MinDelaySeconds))
|
||||
}
|
||||
if time.Duration(*config.Polling.MaxDelaySeconds) != test.expMax {
|
||||
t.Errorf("For %q expected min %v but got %v", test.note, test.expMax, time.Duration(*config.Polling.MaxDelaySeconds))
|
||||
if config.Polling.MaxDelaySeconds == nil && test.expMax != nil {
|
||||
t.Fatal("Expected min delay seconds to be set")
|
||||
}
|
||||
if config.Polling.MaxDelaySeconds != nil && *config.Polling.MaxDelaySeconds != *test.expMax {
|
||||
t.Errorf("For %q expected max %v but got %v", test.note, test.expMax, time.Duration(*config.Polling.MaxDelaySeconds))
|
||||
}
|
||||
|
||||
if time.Duration(*config.Polling.parsedMinDelaySeconds) != test.expParsedMin {
|
||||
t.Errorf("For %q expected min %v but got %v", test.note, test.expParsedMin, time.Duration(*config.Polling.MinDelaySeconds))
|
||||
}
|
||||
if time.Duration(*config.Polling.parsedMaxDelaySeconds) != test.expParsedMax {
|
||||
t.Errorf("For %q expected max %v but got %v", test.note, test.expParsedMax, time.Duration(*config.Polling.MaxDelaySeconds))
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestConfigValidationUpdate(t *testing.T) {
|
||||
expMin := int64(10)
|
||||
expMax := int64(30)
|
||||
expParsedMin := time.Second * time.Duration(expMin)
|
||||
expParsedMax := time.Second * time.Duration(expMax)
|
||||
var config Config
|
||||
|
||||
if err := json.Unmarshal([]byte(fmt.Sprintf(`{
|
||||
"polling": {
|
||||
"min_delay_seconds": %d,
|
||||
"max_delay_seconds": %d
|
||||
}
|
||||
}`, expMin, expMax)), &config); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err := config.ValidateAndInjectDefaults()
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected error: %v", err)
|
||||
}
|
||||
|
||||
if *config.Polling.MinDelaySeconds != expMin {
|
||||
t.Errorf("expected min %v but got %v", expMin, time.Duration(*config.Polling.MinDelaySeconds))
|
||||
}
|
||||
|
||||
if config.Polling.MaxDelaySeconds != nil && *config.Polling.MaxDelaySeconds != expMax {
|
||||
t.Errorf("expected max %v but got %v", expMax, time.Duration(*config.Polling.MaxDelaySeconds))
|
||||
}
|
||||
|
||||
if time.Duration(*config.Polling.parsedMinDelaySeconds) != expParsedMin {
|
||||
t.Errorf("expected min %v but got %v", expParsedMin, time.Duration(*config.Polling.MinDelaySeconds))
|
||||
}
|
||||
if time.Duration(*config.Polling.parsedMaxDelaySeconds) != expParsedMax {
|
||||
t.Errorf("expected max %v but got %v", expParsedMax, time.Duration(*config.Polling.MaxDelaySeconds))
|
||||
}
|
||||
|
||||
expMin = int64(50)
|
||||
expMax = int64(100)
|
||||
expParsedMin = time.Second * time.Duration(expMin)
|
||||
expParsedMax = time.Second * time.Duration(expMax)
|
||||
|
||||
config.Polling.MinDelaySeconds = &expMin
|
||||
config.Polling.MaxDelaySeconds = &expMax
|
||||
|
||||
err = config.ValidateAndInjectDefaults()
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected error: %v", err)
|
||||
}
|
||||
|
||||
if *config.Polling.MinDelaySeconds != expMin {
|
||||
t.Errorf("expected min %v but got %v", expMin, time.Duration(*config.Polling.MinDelaySeconds))
|
||||
}
|
||||
|
||||
if config.Polling.MaxDelaySeconds != nil && *config.Polling.MaxDelaySeconds != expMax {
|
||||
t.Errorf("expected max %v but got %v", expMax, time.Duration(*config.Polling.MaxDelaySeconds))
|
||||
}
|
||||
|
||||
if time.Duration(*config.Polling.parsedMinDelaySeconds) != expParsedMin {
|
||||
t.Errorf("expected min %v but got %v", expParsedMin, time.Duration(*config.Polling.MinDelaySeconds))
|
||||
}
|
||||
if time.Duration(*config.Polling.parsedMaxDelaySeconds) != expParsedMax {
|
||||
t.Errorf("expected max %v but got %v", expParsedMax, time.Duration(*config.Polling.MaxDelaySeconds))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -231,7 +231,7 @@ func (d *Downloader) loop(ctx context.Context) {
|
||||
// are scaled from int seconds to ns in ValidateAndInjectDefaults.
|
||||
if err != nil {
|
||||
// when there was an error, use a delay that's based on the retry count
|
||||
delay = util.DefaultBackoff(float64(minRetryDelay), float64(*d.config.Polling.MaxDelaySeconds), retry)
|
||||
delay = util.DefaultBackoff(float64(minRetryDelay), float64(*d.config.Polling.parsedMaxDelaySeconds), retry)
|
||||
} else if !d.longPollingEnabled || d.config.Polling.LongPollingTimeoutSeconds == nil {
|
||||
// revert the response header timeout value on the http client's transport
|
||||
if *d.client.Config().ResponseHeaderTimeoutSeconds == 0 {
|
||||
@@ -239,8 +239,8 @@ func (d *Downloader) loop(ctx context.Context) {
|
||||
}
|
||||
|
||||
// when polling, use a jittered delay based on min and max delay config
|
||||
min := float64(*d.config.Polling.MinDelaySeconds)
|
||||
max := float64(*d.config.Polling.MaxDelaySeconds)
|
||||
min := float64(*d.config.Polling.parsedMinDelaySeconds)
|
||||
max := float64(*d.config.Polling.parsedMaxDelaySeconds)
|
||||
delay = time.Duration(((max - min) * rand.Float64()) + min)
|
||||
}
|
||||
|
||||
|
||||
@@ -177,11 +177,11 @@ func (d *OCIDownloader) loop(ctx context.Context) {
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
delay = util.DefaultBackoff(float64(minRetryDelay), float64(*d.config.Polling.MaxDelaySeconds), retry)
|
||||
delay = util.DefaultBackoff(float64(minRetryDelay), float64(*d.config.Polling.parsedMaxDelaySeconds), retry)
|
||||
} else {
|
||||
// revert the response header timeout value on the http client's transport
|
||||
min := float64(*d.config.Polling.MinDelaySeconds)
|
||||
max := float64(*d.config.Polling.MaxDelaySeconds)
|
||||
min := float64(*d.config.Polling.parsedMinDelaySeconds)
|
||||
max := float64(*d.config.Polling.parsedMaxDelaySeconds)
|
||||
delay = time.Duration(((max - min) * rand.Float64()) + min)
|
||||
}
|
||||
|
||||
|
||||
@@ -147,7 +147,7 @@ func (p *Plugin) Stop(ctx context.Context) {
|
||||
|
||||
// Reconfigure notifies the plugin that it's configuration has changed.
|
||||
// Any bundle configs that have changed or been added/removed will take
|
||||
// affect.
|
||||
// effect.
|
||||
func (p *Plugin) Reconfigure(ctx context.Context, config any) {
|
||||
// Reconfiguring should not occur in parallel, lock to ensure
|
||||
// nothing swaps underneath us with the current p.config and the updated one.
|
||||
|
||||
@@ -7573,6 +7573,41 @@ result := true`,
|
||||
}
|
||||
}
|
||||
|
||||
func TestMultipleCallsToReconfigure(t *testing.T) {
|
||||
minDelaySeconds := int64(60)
|
||||
maxDelaySeconds := int64(120)
|
||||
|
||||
store := inmem.NewWithOpts(inmem.OptRoundTripOnWrite(false), inmem.OptReturnASTValuesOnRead(true))
|
||||
manager := getTestManagerWithOpts(nil, store)
|
||||
|
||||
cfg := Config{
|
||||
Bundles: map[string]*Source{
|
||||
"b1": {
|
||||
Config: download.Config{
|
||||
Polling: download.PollingConfig{
|
||||
MinDelaySeconds: &minDelaySeconds,
|
||||
MaxDelaySeconds: &maxDelaySeconds,
|
||||
},
|
||||
},
|
||||
Resource: "/b1",
|
||||
SizeLimitBytes: int64(bundle.DefaultSizeLimitBytes),
|
||||
},
|
||||
},
|
||||
}
|
||||
plugin := New(&cfg, manager)
|
||||
|
||||
plugin.Reconfigure(t.Context(), &plugin.config)
|
||||
plugin.Reconfigure(t.Context(), &plugin.config)
|
||||
|
||||
// after multiple calls to reconfigure with the same plugin config, the values should stay the same
|
||||
if *plugin.config.Bundles["b1"].Polling.MaxDelaySeconds != maxDelaySeconds {
|
||||
t.Fatalf("expected MaxDelaySeconds to be %d but got %d", maxDelaySeconds, *plugin.config.Bundles["b1"].Polling.MaxDelaySeconds)
|
||||
}
|
||||
if *plugin.config.Bundles["b1"].Polling.MinDelaySeconds != minDelaySeconds {
|
||||
t.Fatalf("expected MaxDelaySeconds to be %d but got %d", maxDelaySeconds, *plugin.config.Bundles["b1"].Polling.MaxDelaySeconds)
|
||||
}
|
||||
}
|
||||
|
||||
type testModule struct {
|
||||
Path string
|
||||
Data string
|
||||
|
||||
@@ -951,7 +951,7 @@ func (p *Plugin) reconfigure(ctx context.Context, config any) {
|
||||
case eventBufferType:
|
||||
limit = *p.config.Reporting.BufferSizeLimitEvents
|
||||
case sizeBufferType:
|
||||
limit = *p.config.Reporting.UploadSizeLimitBytes
|
||||
limit = *p.config.Reporting.BufferSizeLimitBytes
|
||||
}
|
||||
p.b.Reconfigure(
|
||||
limit,
|
||||
|
||||
@@ -10,7 +10,7 @@ import (
|
||||
"runtime/debug"
|
||||
)
|
||||
|
||||
var Version = "1.12.2"
|
||||
var Version = "1.12.3"
|
||||
|
||||
// GoVersion is the version of Go this was built with
|
||||
var GoVersion = runtime.Version()
|
||||
|
||||
Reference in New Issue
Block a user