Skip to content

Commit d2b81c0

Browse files
committed
add option to override period triggers for discovery and bundle plugin
- control timing of f.ex. bundle download directly - fail fast for non-recoverable errors Signed-off-by: Torsten Wunderlich <[email protected]>
1 parent ec2a21e commit d2b81c0

File tree

7 files changed

+783
-155
lines changed

7 files changed

+783
-155
lines changed

Diff for: config/config.go

+25-16
Original file line numberDiff line numberDiff line change
@@ -294,14 +294,17 @@ type Config struct {
294294
LuaModules *listFlag `yaml:"lua-modules"`
295295
LuaSources *listFlag `yaml:"lua-sources"`
296296

297-
EnableOpenPolicyAgent bool `yaml:"enable-open-policy-agent"`
298-
OpenPolicyAgentConfigTemplate string `yaml:"open-policy-agent-config-template"`
299-
OpenPolicyAgentEnvoyMetadata string `yaml:"open-policy-agent-envoy-metadata"`
300-
OpenPolicyAgentCleanerInterval time.Duration `yaml:"open-policy-agent-cleaner-interval"`
301-
OpenPolicyAgentStartupTimeout time.Duration `yaml:"open-policy-agent-startup-timeout"`
302-
OpenPolicyAgentRequestBodyBufferSize int64 `yaml:"open-policy-agent-request-body-buffer-size"`
303-
OpenPolicyAgentMaxRequestBodySize int64 `yaml:"open-policy-agent-max-request-body-size"`
304-
OpenPolicyAgentMaxMemoryBodyParsing int64 `yaml:"open-policy-agent-max-memory-body-parsing"`
297+
EnableOpenPolicyAgent bool `yaml:"enable-open-policy-agent"`
298+
EnableOpenPolicyAgentOverridePeriodTriggers bool `yaml:"enable-open-policy-agent-override-period-triggers"`
299+
OpenPolicyAgentConfigTemplate string `yaml:"open-policy-agent-config-template"`
300+
OpenPolicyAgentEnvoyMetadata string `yaml:"open-policy-agent-envoy-metadata"`
301+
OpenPolicyAgentCleanerInterval time.Duration `yaml:"open-policy-agent-cleaner-interval"`
302+
OpenPolicyAgentPluginTriggerInterval time.Duration `yaml:"open-policy-agent-plugin-trigger-interval"`
303+
OpenPolicyAgentMaxPluginTriggerJitter time.Duration `yaml:"open-policy-agent-max-plugin-trigger-jitter"`
304+
OpenPolicyAgentStartupTimeout time.Duration `yaml:"open-policy-agent-startup-timeout"`
305+
OpenPolicyAgentRequestBodyBufferSize int64 `yaml:"open-policy-agent-request-body-buffer-size"`
306+
OpenPolicyAgentMaxRequestBodySize int64 `yaml:"open-policy-agent-max-request-body-size"`
307+
OpenPolicyAgentMaxMemoryBodyParsing int64 `yaml:"open-policy-agent-max-memory-body-parsing"`
305308

306309
PassiveHealthCheck mapFlags `yaml:"passive-health-check"`
307310
}
@@ -524,9 +527,12 @@ func NewConfig() *Config {
524527
flag.Var(cfg.CredentialPaths, "credentials-paths", "directories or files to watch for credentials to use by bearerinjector filter")
525528
flag.DurationVar(&cfg.CredentialsUpdateInterval, "credentials-update-interval", 10*time.Minute, "sets the interval to update secrets")
526529
flag.BoolVar(&cfg.EnableOpenPolicyAgent, "enable-open-policy-agent", false, "enables Open Policy Agent filters")
530+
flag.BoolVar(&cfg.EnableOpenPolicyAgentOverridePeriodTriggers, "enable-open-policy-agent-override-period-triggers", false, "when enabled skipper will set all plugin triggers to manual and trigger all plugins directly, which includes f.ex. to download of new bundles")
527531
flag.StringVar(&cfg.OpenPolicyAgentConfigTemplate, "open-policy-agent-config-template", "", "file containing a template for an Open Policy Agent configuration file that is interpolated for each OPA filter instance")
528532
flag.StringVar(&cfg.OpenPolicyAgentEnvoyMetadata, "open-policy-agent-envoy-metadata", "", "JSON file containing meta-data passed as input for compatibility with Envoy policies in the format")
529533
flag.DurationVar(&cfg.OpenPolicyAgentCleanerInterval, "open-policy-agent-cleaner-interval", openpolicyagent.DefaultCleanIdlePeriod, "Duration in seconds to wait before cleaning up unused opa instances")
534+
flag.DurationVar(&cfg.OpenPolicyAgentPluginTriggerInterval, "open-policy-agent-plugin-trigger-interval", openpolicyagent.DefaultPluginTriggerInterval, "Interval between triggering the opa plugins to f.ex. download new bundles. Only applies when overriding period triggers is enabled")
535+
flag.DurationVar(&cfg.OpenPolicyAgentMaxPluginTriggerJitter, "open-policy-agent-max-plugin-trigger-jitter", openpolicyagent.DefaultMaxPluginTriggerJitter, "Maximum jitter to add to the plugin trigger interval. Only applies when overriding period triggers is enabled")
530536
flag.DurationVar(&cfg.OpenPolicyAgentStartupTimeout, "open-policy-agent-startup-timeout", openpolicyagent.DefaultOpaStartupTimeout, "Maximum duration in seconds to wait for the open policy agent to start up")
531537
flag.Int64Var(&cfg.OpenPolicyAgentMaxRequestBodySize, "open-policy-agent-max-request-body-size", openpolicyagent.DefaultMaxRequestBodySize, "Maximum number of bytes from a http request body that are passed as input to the policy")
532538
flag.Int64Var(&cfg.OpenPolicyAgentRequestBodyBufferSize, "open-policy-agent-request-body-buffer-size", openpolicyagent.DefaultRequestBodyBufferSize, "Read buffer size for the request body")
@@ -978,14 +984,17 @@ func (c *Config) ToOptions() skipper.Options {
978984
LuaModules: c.LuaModules.values,
979985
LuaSources: c.LuaSources.values,
980986

981-
EnableOpenPolicyAgent: c.EnableOpenPolicyAgent,
982-
OpenPolicyAgentConfigTemplate: c.OpenPolicyAgentConfigTemplate,
983-
OpenPolicyAgentEnvoyMetadata: c.OpenPolicyAgentEnvoyMetadata,
984-
OpenPolicyAgentCleanerInterval: c.OpenPolicyAgentCleanerInterval,
985-
OpenPolicyAgentStartupTimeout: c.OpenPolicyAgentStartupTimeout,
986-
OpenPolicyAgentMaxRequestBodySize: c.OpenPolicyAgentMaxRequestBodySize,
987-
OpenPolicyAgentRequestBodyBufferSize: c.OpenPolicyAgentRequestBodyBufferSize,
988-
OpenPolicyAgentMaxMemoryBodyParsing: c.OpenPolicyAgentMaxMemoryBodyParsing,
987+
EnableOpenPolicyAgent: c.EnableOpenPolicyAgent,
988+
EnableOpenPolicyAgentOverridePeriodTriggers: c.EnableOpenPolicyAgentOverridePeriodTriggers,
989+
OpenPolicyAgentConfigTemplate: c.OpenPolicyAgentConfigTemplate,
990+
OpenPolicyAgentEnvoyMetadata: c.OpenPolicyAgentEnvoyMetadata,
991+
OpenPolicyAgentCleanerInterval: c.OpenPolicyAgentCleanerInterval,
992+
OpenPolicyAgentPluginTriggerInterval: c.OpenPolicyAgentPluginTriggerInterval,
993+
OpenPolicyAgentMaxPluginTriggerJitter: c.OpenPolicyAgentMaxPluginTriggerJitter,
994+
OpenPolicyAgentStartupTimeout: c.OpenPolicyAgentStartupTimeout,
995+
OpenPolicyAgentMaxRequestBodySize: c.OpenPolicyAgentMaxRequestBodySize,
996+
OpenPolicyAgentRequestBodyBufferSize: c.OpenPolicyAgentRequestBodyBufferSize,
997+
OpenPolicyAgentMaxMemoryBodyParsing: c.OpenPolicyAgentMaxMemoryBodyParsing,
989998

990999
PassiveHealthCheck: c.PassiveHealthCheck.values,
9911000
}

Diff for: config/config_test.go

+3-1
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,9 @@ func defaultConfig(with func(*Config)) *Config {
165165
LuaModules: commaListFlag(),
166166
LuaSources: commaListFlag(),
167167
OpenPolicyAgentCleanerInterval: openpolicyagent.DefaultCleanIdlePeriod,
168-
OpenPolicyAgentStartupTimeout: 30 * time.Second,
168+
OpenPolicyAgentStartupTimeout: openpolicyagent.DefaultOpaStartupTimeout,
169+
OpenPolicyAgentPluginTriggerInterval: openpolicyagent.DefaultPluginTriggerInterval,
170+
OpenPolicyAgentMaxPluginTriggerJitter: openpolicyagent.DefaultMaxPluginTriggerJitter,
169171
OpenPolicyAgentMaxRequestBodySize: openpolicyagent.DefaultMaxRequestBodySize,
170172
OpenPolicyAgentMaxMemoryBodyParsing: openpolicyagent.DefaultMaxMemoryBodyParsing,
171173
OpenPolicyAgentRequestBodyBufferSize: openpolicyagent.DefaultRequestBodyBufferSize,

Diff for: filters/openpolicyagent/internal/confighook.go

+80
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
package internal
2+
3+
import (
4+
"context"
5+
"encoding/json"
6+
"github.com/open-policy-agent/opa/v1/config"
7+
"github.com/open-policy-agent/opa/v1/plugins"
8+
"github.com/open-policy-agent/opa/v1/plugins/bundle"
9+
"github.com/open-policy-agent/opa/v1/plugins/discovery"
10+
)
11+
12+
// ManualOverride is override the plugin trigger to manual trigger mode, allowing the openpolicyagent filter
13+
// to take control of the trigger mechanism.
14+
// * OnConfig will handle a general config change and will override the trigger mode for both discovery
15+
// and bundle plugins.
16+
// * OnConfigDiscovery will handle a config change via discovery mechanism and will only override
17+
// the trigger mode for the bundle plugin as the discovery plugin is involved in the trigger for
18+
// this config change.
19+
// See https://github.com/open-policy-agent/opa/pull/6053 for details on the hooks.
20+
21+
type ManualOverride struct {
22+
}
23+
24+
func (m *ManualOverride) OnConfig(ctx context.Context, config *config.Config) (*config.Config, error) {
25+
config, err := discoveryPluginOverride(config)
26+
if err != nil {
27+
return config, err
28+
}
29+
return bundlePluginConfigOverride(config)
30+
}
31+
32+
func (m *ManualOverride) OnConfigDiscovery(ctx context.Context, config *config.Config) (*config.Config, error) {
33+
return bundlePluginConfigOverride(config)
34+
}
35+
36+
func discoveryPluginOverride(config *config.Config) (*config.Config, error) {
37+
var (
38+
discoveryConfig discovery.Config
39+
triggerManual = plugins.TriggerManual
40+
message []byte
41+
)
42+
43+
if config.Discovery != nil {
44+
if err := json.Unmarshal(config.Discovery, &discoveryConfig); err == nil {
45+
discoveryConfig.Trigger = &triggerManual
46+
if message, err = json.Marshal(discoveryConfig); err == nil {
47+
config.Discovery = message
48+
} else {
49+
return config, err
50+
}
51+
} else {
52+
return config, err
53+
}
54+
}
55+
return config, nil
56+
}
57+
58+
func bundlePluginConfigOverride(config *config.Config) (*config.Config, error) {
59+
var (
60+
bundlesConfig map[string]*bundle.Source
61+
manualTrigger = plugins.TriggerManual
62+
message []byte
63+
)
64+
65+
if config.Bundles != nil {
66+
if err := json.Unmarshal(config.Bundles, &bundlesConfig); err == nil {
67+
for _, bndlCfg := range bundlesConfig {
68+
bndlCfg.Trigger = &manualTrigger
69+
}
70+
if message, err = json.Marshal(bundlesConfig); err == nil {
71+
config.Bundles = message
72+
} else {
73+
return config, err
74+
}
75+
} else {
76+
return config, err
77+
}
78+
}
79+
return config, nil
80+
}

Diff for: filters/openpolicyagent/internal/confighook_test.go

+138
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
package internal
2+
3+
import (
4+
"context"
5+
"encoding/json"
6+
"github.com/open-policy-agent/opa/v1/config"
7+
"github.com/open-policy-agent/opa/v1/plugins"
8+
"github.com/open-policy-agent/opa/v1/plugins/bundle"
9+
"github.com/open-policy-agent/opa/v1/plugins/discovery"
10+
"github.com/stretchr/testify/assert"
11+
"testing"
12+
)
13+
14+
func TestManualOverride_OnConfig_WithDiscoveryConfig(t *testing.T) {
15+
config := config.Config{
16+
Discovery: []byte(`{
17+
"resource": "discovery",
18+
"service": "test",
19+
"persist": false
20+
}`),
21+
}
22+
23+
m := &ManualOverride{}
24+
m.OnConfig(context.Background(), &config)
25+
26+
var discoveryConfig discovery.Config
27+
28+
err := json.Unmarshal(config.Discovery, &discoveryConfig)
29+
assert.NoError(t, err)
30+
31+
// verify trigger is set to manual
32+
assert.Equal(t, *discoveryConfig.Trigger, plugins.TriggerManual)
33+
34+
// verify existing config is untouched
35+
assert.Equal(t, *discoveryConfig.Resource, "discovery")
36+
assert.Equal(t, discoveryConfig.Service, "test")
37+
assert.Equal(t, discoveryConfig.Persist, false)
38+
}
39+
40+
func TestManualOverride_OnConfig_WithBundlesConfig(t *testing.T) {
41+
config := config.Config{
42+
Bundles: []byte(`{"test":{
43+
"resource": "test-bundle",
44+
"service": "test",
45+
"persist": false
46+
}}`),
47+
}
48+
49+
m := &ManualOverride{}
50+
m.OnConfig(context.Background(), &config)
51+
52+
var bundlesConfig map[string]*bundle.Source
53+
54+
err := json.Unmarshal(config.Bundles, &bundlesConfig)
55+
assert.NoError(t, err)
56+
57+
// verify trigger is set to manual
58+
assert.Equal(t, *bundlesConfig["test"].Trigger, plugins.TriggerManual)
59+
}
60+
61+
func TestManualOverride_OnConfig_WithEmptyConfig(t *testing.T) {
62+
config := &config.Config{}
63+
64+
m := &ManualOverride{}
65+
processedConfig, err := m.OnConfig(context.Background(), config)
66+
67+
assert.NoError(t, err)
68+
assert.Equal(t, config, processedConfig)
69+
}
70+
71+
func TestManualOverride_OnConfig_InvalidDiscoveryConfig(t *testing.T) {
72+
config := config.Config{
73+
Discovery: []byte(`invalid`),
74+
}
75+
76+
m := &ManualOverride{}
77+
_, err := m.OnConfig(context.Background(), &config)
78+
79+
assert.ErrorContains(t, err, "invalid character")
80+
}
81+
82+
func TestManualOverride_OnConfig_InvalidBundlesConfig(t *testing.T) {
83+
config := config.Config{
84+
Bundles: []byte(`invalid`),
85+
}
86+
87+
m := &ManualOverride{}
88+
_, err := m.OnConfig(context.Background(), &config)
89+
90+
assert.ErrorContains(t, err, "invalid character")
91+
}
92+
93+
func TestManualOverride_OnConfigDiscovery(t *testing.T) {
94+
config := config.Config{
95+
Bundles: []byte(`{"test":{
96+
"resource": "test-bundle",
97+
"service": "test",
98+
"persist": false
99+
}}`),
100+
}
101+
102+
m := &ManualOverride{}
103+
m.OnConfigDiscovery(context.Background(), &config)
104+
105+
var bundlesConfig map[string]*bundle.Source
106+
107+
err := json.Unmarshal(config.Bundles, &bundlesConfig)
108+
assert.NoError(t, err)
109+
110+
// verify trigger is set to manual
111+
assert.Equal(t, *bundlesConfig["test"].Trigger, plugins.TriggerManual)
112+
113+
// verify existing config is untouched
114+
assert.Equal(t, bundlesConfig["test"].Resource, "test-bundle")
115+
assert.Equal(t, bundlesConfig["test"].Service, "test")
116+
assert.Equal(t, bundlesConfig["test"].Persist, false)
117+
}
118+
119+
func TestManualOverride_OnConfigDiscovery_WithoutBundlesConfig(t *testing.T) {
120+
config := &config.Config{}
121+
122+
m := &ManualOverride{}
123+
processedConfig, err := m.OnConfigDiscovery(context.Background(), config)
124+
125+
assert.NoError(t, err)
126+
assert.Equal(t, config, processedConfig)
127+
}
128+
129+
func TestManualOverride_OnConfigDiscovery_InvalidBundlesConfig(t *testing.T) {
130+
config := config.Config{
131+
Bundles: []byte(`invalid`),
132+
}
133+
134+
m := &ManualOverride{}
135+
_, err := m.OnConfigDiscovery(context.Background(), &config)
136+
137+
assert.ErrorContains(t, err, "invalid character")
138+
}

0 commit comments

Comments
 (0)