mirror of
https://github.com/open-policy-agent/opa.git
synced 2026-08-12 19:32:48 -06:00
Add config option to disable named inter-query built-in cache (#8287)
Signed-off-by: Sebastian Spaink <sebastianspaink@gmail.com>
This commit is contained in:
@@ -924,7 +924,9 @@ that requires GraphQL schemas.
|
||||
| `caching.inter_query_builtin_cache.stale_entry_eviction_period_seconds` | `int64` | No | Stale entry eviction period in seconds. OPA will drop expired items from the cache every `stale_entry_eviction_period_seconds`. By default, set to `0` indicating stale entry eviction is disabled. |
|
||||
| `caching.inter_query_builtin_value_cache.max_num_entries` | `int` | No | Maximum number of entries in the Inter-query value cache. OPA will drop random items from the cache if this limit is exceeded. By default, set to `0` indicating unlimited size. |
|
||||
| `caching.inter_query_builtin_value_cache.named.io_jwt.max_num_entries` | `int` | No | Maximum number of entries in the `io_jwt` cache, used by the [`io.jwt` token verification](./policy-reference/builtins/tokens) built-in functions. OPA will drop random items from the cache if this limit is exceeded. By default, this cache is disabled. |
|
||||
| `caching.inter_query_builtin_value_cache.named.io_jwt.disabled` | `bool` | No | Explicitly disable `io_jwt`, by default this is `true`. Setting this to `false` will enable `io_jwt` and set `max_num_entries` to `0` unless configured otherwise. |
|
||||
| `caching.inter_query_builtin_value_cache.named.graphql.max_num_entries` | `int` | No | Maximum number of entries in the `graphql` cache, used by the [`graphql` builtins](./policy-reference/builtins/graphql) built-in functions to cache parsed schemas. OPA will drop random items from the cache if this limit is exceeded. By default, this cache is set to a maximum of 10 entries. |
|
||||
| `caching.inter_query_builtin_value_cache.named.graphql.disabled` | `bool` | No | Explicitly disable `graphql`, by default this is `false`. Setting this to `true` will disable `graphql`. |
|
||||
|
||||
## Distributed tracing
|
||||
|
||||
|
||||
Vendored
+20
-5
@@ -32,7 +32,7 @@ func getDefaultInterQueryBuiltinValueCacheConfig(name string) *NamedValueCacheCo
|
||||
|
||||
// RegisterDefaultInterQueryBuiltinValueCacheConfig registers a default configuration for the inter-query value cache;
|
||||
// used when none has been explicitly configured.
|
||||
// To disable a named cache when not configured, pass a nil config.
|
||||
// To disable a named cache when not configured, pass a config with the disabled value set to true.
|
||||
func RegisterDefaultInterQueryBuiltinValueCacheConfig(name string, config *NamedValueCacheConfig) {
|
||||
interQueryBuiltinValueCacheDefaultConfigs[name] = config
|
||||
}
|
||||
@@ -58,7 +58,8 @@ func (c *Config) Clone() *Config {
|
||||
// NamedValueCacheConfig represents the configuration of a named cache that built-in functions can utilize.
|
||||
// A default configuration to be used if not explicitly configured can be registered using RegisterDefaultInterQueryBuiltinValueCacheConfig.
|
||||
type NamedValueCacheConfig struct {
|
||||
MaxNumEntries *int `json:"max_num_entries,omitempty"`
|
||||
MaxNumEntries *int `json:"max_num_entries,omitempty"`
|
||||
Disabled *bool `json:"disabled,omitempty"`
|
||||
}
|
||||
|
||||
// Clone creates a deep copy of NamedValueCacheConfig.
|
||||
@@ -73,6 +74,10 @@ func (n *NamedValueCacheConfig) Clone() *NamedValueCacheConfig {
|
||||
maxEntries := *n.MaxNumEntries
|
||||
clone.MaxNumEntries = &maxEntries
|
||||
}
|
||||
if n.Disabled != nil {
|
||||
disabled := *n.Disabled
|
||||
clone.Disabled = &disabled
|
||||
}
|
||||
|
||||
return clone
|
||||
}
|
||||
@@ -220,9 +225,15 @@ func (c *Config) validateAndInjectDefaults() error {
|
||||
}
|
||||
|
||||
for name, namedConfig := range c.InterQueryBuiltinValueCache.NamedCacheConfigs {
|
||||
numEntries := *namedConfig.MaxNumEntries
|
||||
if numEntries < 0 {
|
||||
return fmt.Errorf("invalid max_num_entries %v for named cache %v", numEntries, name)
|
||||
if namedConfig == nil || (namedConfig.MaxNumEntries == nil && namedConfig.Disabled == nil) {
|
||||
return fmt.Errorf("missing configuration for named cache %v", name)
|
||||
}
|
||||
|
||||
if namedConfig.MaxNumEntries != nil {
|
||||
numEntries := *namedConfig.MaxNumEntries
|
||||
if numEntries < 0 {
|
||||
return fmt.Errorf("invalid max_num_entries %v for named cache %v", numEntries, name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -605,6 +616,10 @@ func (c *interQueryBuiltinValueCache) GetCache(name string) InterQueryValueCache
|
||||
return nil
|
||||
}
|
||||
|
||||
if config.Disabled != nil && *config.Disabled {
|
||||
return nil
|
||||
}
|
||||
|
||||
nc = &interQueryValueCacheBucket{
|
||||
items: *newItemsMap(),
|
||||
config: config,
|
||||
|
||||
Vendored
+168
-13
@@ -27,7 +27,7 @@ func TestParseCachingConfig(t *testing.T) {
|
||||
maxNumEntriesInterQueryValueCache := new(int)
|
||||
*maxNumEntriesInterQueryValueCache = defaultInterQueryBuiltinValueCacheSize
|
||||
|
||||
expected := &Config{
|
||||
defaultExpected := &Config{
|
||||
InterQueryBuiltinCache: InterQueryBuiltinCacheConfig{
|
||||
MaxSizeBytes: maxSize,
|
||||
StaleEntryEvictionPeriodSeconds: period,
|
||||
@@ -39,20 +39,64 @@ func TestParseCachingConfig(t *testing.T) {
|
||||
}
|
||||
|
||||
tests := map[string]struct {
|
||||
input []byte
|
||||
wantErr bool
|
||||
input []byte
|
||||
wantErr bool
|
||||
expectedConfig *Config
|
||||
}{
|
||||
"empty_config": {
|
||||
input: nil,
|
||||
input: nil,
|
||||
wantErr: false,
|
||||
expectedConfig: defaultExpected,
|
||||
},
|
||||
"invalid_config_missing_configuration": {
|
||||
input: []byte(`inter_query_builtin_value_cache:
|
||||
named:
|
||||
io_jwt:`),
|
||||
wantErr: true,
|
||||
},
|
||||
"invalid_config_missing_values": {
|
||||
input: []byte(`inter_query_builtin_value_cache:
|
||||
named:
|
||||
io_jwt:
|
||||
disabled:
|
||||
max_num_entries: `),
|
||||
wantErr: true,
|
||||
},
|
||||
"valid_config_using_disabled": {
|
||||
input: []byte(`inter_query_builtin_value_cache:
|
||||
named:
|
||||
io_jwt:
|
||||
disabled: true`),
|
||||
wantErr: false,
|
||||
expectedConfig: func() *Config {
|
||||
disabled := true
|
||||
n := NamedValueCacheConfig{
|
||||
Disabled: &disabled,
|
||||
}
|
||||
return &Config{
|
||||
InterQueryBuiltinCache: InterQueryBuiltinCacheConfig{
|
||||
MaxSizeBytes: maxSize,
|
||||
StaleEntryEvictionPeriodSeconds: period,
|
||||
ForcedEvictionThresholdPercentage: threshold,
|
||||
},
|
||||
InterQueryBuiltinValueCache: InterQueryBuiltinValueCacheConfig{
|
||||
MaxNumEntries: maxNumEntriesInterQueryValueCache,
|
||||
NamedCacheConfigs: map[string]*NamedValueCacheConfig{
|
||||
"io_jwt": &n,
|
||||
},
|
||||
},
|
||||
}
|
||||
}(),
|
||||
},
|
||||
"default_limit": {
|
||||
input: []byte(`{"inter_query_builtin_cache": {},}`),
|
||||
wantErr: false,
|
||||
input: []byte(`{"inter_query_builtin_cache": {},}`),
|
||||
wantErr: false,
|
||||
expectedConfig: defaultExpected,
|
||||
},
|
||||
"default_num_entries": {
|
||||
input: []byte(`{"inter_query_builtin_value_cache": {},}`),
|
||||
wantErr: false,
|
||||
input: []byte(`{"inter_query_builtin_value_cache": {},}`),
|
||||
wantErr: false,
|
||||
expectedConfig: defaultExpected,
|
||||
},
|
||||
"bad_limit": {
|
||||
input: []byte(`{"inter_query_builtin_cache": {"max_size_bytes": "100"},}`),
|
||||
@@ -77,8 +121,8 @@ func TestParseCachingConfig(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
if !tc.wantErr && !reflect.DeepEqual(config, expected) {
|
||||
t.Fatalf("want %v got %v", expected, config)
|
||||
if !tc.wantErr && !reflect.DeepEqual(config, tc.expectedConfig) {
|
||||
t.Fatalf("want %v got %v", tc.expectedConfig, config)
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -92,13 +136,63 @@ func TestParseCachingConfig(t *testing.T) {
|
||||
}
|
||||
|
||||
limit := int64(100)
|
||||
expected.InterQueryBuiltinCache.MaxSizeBytes = &limit
|
||||
defaultExpected.InterQueryBuiltinCache.MaxSizeBytes = &limit
|
||||
|
||||
if !reflect.DeepEqual(config, expected) {
|
||||
t.Fatalf("want %v got %v", expected, config)
|
||||
if !reflect.DeepEqual(config, defaultExpected) {
|
||||
t.Fatalf("want %v got %v", defaultExpected, config)
|
||||
}
|
||||
}
|
||||
|
||||
func TestInterValueCache_DisabledConfig(t *testing.T) {
|
||||
t.Run("config disabled", func(t *testing.T) {
|
||||
// user configured `baz` to be disabled
|
||||
disabled := true
|
||||
cacheConfig := Config{
|
||||
InterQueryBuiltinValueCache: InterQueryBuiltinValueCacheConfig{
|
||||
NamedCacheConfigs: map[string]*NamedValueCacheConfig{
|
||||
"baz": {
|
||||
Disabled: &disabled,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
// by default, it is enabled
|
||||
var defaultDisabled bool
|
||||
RegisterDefaultInterQueryBuiltinValueCacheConfig("baz", &NamedValueCacheConfig{
|
||||
Disabled: &defaultDisabled,
|
||||
})
|
||||
|
||||
c := NewInterQueryValueCache(t.Context(), &cacheConfig)
|
||||
if c.GetCache("baz") != nil {
|
||||
t.Fatal("Expected cache to be disabled")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("config enabled", func(t *testing.T) {
|
||||
var disabled bool
|
||||
cacheConfig := Config{
|
||||
InterQueryBuiltinValueCache: InterQueryBuiltinValueCacheConfig{
|
||||
NamedCacheConfigs: map[string]*NamedValueCacheConfig{
|
||||
"baz": {
|
||||
Disabled: &disabled,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
defaultDisabled := true
|
||||
RegisterDefaultInterQueryBuiltinValueCacheConfig("baz", &NamedValueCacheConfig{
|
||||
Disabled: &defaultDisabled,
|
||||
})
|
||||
|
||||
c := NewInterQueryValueCache(t.Context(), &cacheConfig)
|
||||
if c.GetCache("baz") == nil {
|
||||
t.Fatal("Expected cache to be enabled")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestInterValueCache_DefaultConfiguration(t *testing.T) {
|
||||
t.Run("default config not set", func(t *testing.T) {
|
||||
config := Config{
|
||||
@@ -168,6 +262,67 @@ func TestInterValueCache_DefaultConfiguration(t *testing.T) {
|
||||
func TestInterValueCache_NamedCaches(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
t.Run("configured disable is respected", func(t *testing.T) {
|
||||
disabled := true
|
||||
config := Config{
|
||||
InterQueryBuiltinValueCache: InterQueryBuiltinValueCacheConfig{
|
||||
NamedCacheConfigs: map[string]*NamedValueCacheConfig{
|
||||
"foo": {
|
||||
Disabled: &disabled,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
c := NewInterQueryValueCache(t.Context(), &config)
|
||||
|
||||
nc := c.GetCache("foo")
|
||||
if nc != nil {
|
||||
t.Fatalf("Expected cache to be disabled, but got %v", nc)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("configured enable is respected", func(t *testing.T) {
|
||||
var disabled bool
|
||||
config := Config{
|
||||
InterQueryBuiltinValueCache: InterQueryBuiltinValueCacheConfig{
|
||||
NamedCacheConfigs: map[string]*NamedValueCacheConfig{
|
||||
"foo": {
|
||||
Disabled: &disabled,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
c := NewInterQueryValueCache(t.Context(), &config)
|
||||
|
||||
nc := c.GetCache("foo")
|
||||
if nc == nil {
|
||||
t.Fatalf("Expected cache to be enabled, but got %v", nc)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("Disable respected even if max_num_entries is specified", func(t *testing.T) {
|
||||
disabled := true
|
||||
config := Config{
|
||||
InterQueryBuiltinValueCache: InterQueryBuiltinValueCacheConfig{
|
||||
NamedCacheConfigs: map[string]*NamedValueCacheConfig{
|
||||
"foo": {
|
||||
MaxNumEntries: &[]int{5}[0],
|
||||
Disabled: &disabled,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
c := NewInterQueryValueCache(t.Context(), &config)
|
||||
|
||||
nc := c.GetCache("foo")
|
||||
if nc != nil {
|
||||
t.Fatalf("Expected cache to be disabled, but got %v", nc)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("configured max is respected", func(t *testing.T) {
|
||||
config := Config{
|
||||
InterQueryBuiltinValueCache: InterQueryBuiltinValueCacheConfig{
|
||||
|
||||
@@ -1290,7 +1290,11 @@ func createTokenCacheKey(serializedJwt ast.Value, publicKey ast.Value) ast.Value
|
||||
|
||||
func init() {
|
||||
// By default, the JWT cache is disabled.
|
||||
cache.RegisterDefaultInterQueryBuiltinValueCacheConfig(tokenCacheName, nil)
|
||||
disabled := true
|
||||
var tokenCache = cache.NamedValueCacheConfig{
|
||||
Disabled: &disabled,
|
||||
}
|
||||
cache.RegisterDefaultInterQueryBuiltinValueCacheConfig(tokenCacheName, &tokenCache)
|
||||
|
||||
RegisterBuiltinFunc(ast.JWTDecode.Name, builtinJWTDecode)
|
||||
RegisterBuiltinFunc(ast.JWTVerifyRS256.Name, builtinJWTVerifyRS256)
|
||||
|
||||
@@ -79,6 +79,11 @@ func populateDefaultTypes(t *testing.T, fieldType reflect.Type, fieldValue refle
|
||||
populateStruct(t, fieldType.Elem(), newStruct.Elem())
|
||||
fieldValue.Set(newStruct)
|
||||
|
||||
return true
|
||||
case reflect.Bool:
|
||||
newBool := true
|
||||
fieldValue.Set(reflect.ValueOf(&newBool))
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user