Files
Sebastian Spaink b2f2e73944 plugin/decision: upload events as soon as a chunk is ready (#8110)
This introduces a new trigger mode for the decision log plugin:

decision_logs.reporting.trigger=immediate

The immediate trigger mode will upload events as soon as enough events are received to hit the configured upload limit. If not enough events are received within the configured min-max delay, the events received so far are flushed and uploaded.

Signed-off-by: Sebastian Spaink <sebastianspaink@gmail.com>
2026-01-27 10:37:35 -06:00

282 lines
10 KiB
Go

// Copyright 2018 The OPA Authors. All rights reserved.
// Use of this source code is governed by an Apache2
// license that can be found in the LICENSE file.
// Package plugins implements plugin management for the policy engine.
package plugins
import (
"net/http"
"github.com/prometheus/client_golang/prometheus"
"go.opentelemetry.io/otel/sdk/trace"
"github.com/open-policy-agent/opa/ast"
"github.com/open-policy-agent/opa/bundle"
"github.com/open-policy-agent/opa/hooks"
"github.com/open-policy-agent/opa/loader"
"github.com/open-policy-agent/opa/logging"
"github.com/open-policy-agent/opa/resolver/wasm"
"github.com/open-policy-agent/opa/storage"
"github.com/open-policy-agent/opa/topdown/print"
"github.com/open-policy-agent/opa/tracing"
v1 "github.com/open-policy-agent/opa/v1/plugins"
)
// Factory defines the interface OPA uses to instantiate your plugin.
//
// When OPA processes it's configuration it looks for factories that
// have been registered by calling runtime.RegisterPlugin. Factories
// are registered to a name which is used to key into the
// configuration blob. If your plugin has not been configured, your
// factory will not be invoked.
//
// plugins:
// my_plugin1:
// some_key: foo
// # my_plugin2:
// # some_key2: bar
//
// If OPA was started with the configuration above and received two
// calls to runtime.RegisterPlugins (one with NAME "my_plugin1" and
// one with NAME "my_plugin2"), it would only invoke the factory for
// for my_plugin1.
//
// OPA instantiates and reconfigures plugins in two steps. First, OPA
// will call Validate to check the configuration. Assuming the
// configuration is valid, your factory should return a configuration
// value that can be used to construct your plugin. Second, OPA will
// call New to instantiate your plugin providing the configuration
// value returned from the Validate call.
//
// Validate receives a slice of bytes representing plugin
// configuration and returns a configuration value that can be used to
// instantiate your plugin. The manager is provided to give access to
// the OPA's compiler, storage layer, and global configuration. Your
// Validate function will typically:
//
// 1. Deserialize the raw config bytes
// 2. Validate the deserialized config for semantic errors
// 3. Inject default values
// 4. Return a deserialized/parsed config
//
// New receives a valid configuration for your plugin and returns a
// plugin object. Your New function will typically:
//
// 1. Cast the config value to it's own type
// 2. Instantiate a plugin object
// 3. Return the plugin object
// 4. Update status via `plugins.Manager#UpdatePluginStatus`
//
// After a plugin has been created subsequent status updates can be
// send anytime the plugin enters a ready or error state.
type Factory = v1.Factory
// Plugin defines the interface OPA uses to manage your plugin.
//
// When OPA starts it will start all of the plugins it was configured
// to instantiate. Each time a new plugin is configured (via
// discovery), OPA will start it. You can use the Start call to spawn
// additional goroutines or perform initialization tasks.
//
// Currently OPA will not call Stop on plugins.
//
// When OPA receives new configuration for your plugin via discovery
// it will first Validate the configuration using your factory and
// then call Reconfigure.
type Plugin = v1.Plugin
// Triggerable defines the interface plugins use for manual plugin triggers.
type Triggerable = v1.Triggerable
// State defines the state that a Plugin instance is currently
// in with pre-defined states.
type State = v1.State
const (
// StateNotReady indicates that the Plugin is not in an error state, but isn't
// ready for normal operation yet. This should only happen at
// initialization time.
StateNotReady = v1.StateNotReady
// StateOK signifies that the Plugin is operating normally.
StateOK = v1.StateOK
// StateErr indicates that the Plugin is in an error state and should not
// be considered as functional.
StateErr = v1.StateErr
// StateWarn indicates the Plugin is operating, but in a potentially dangerous or
// degraded state. It may be used to indicate manual remediation is needed, or to
// alert admins of some other noteworthy state.
StateWarn = v1.StateWarn
)
// TriggerMode defines the trigger mode utilized by a Plugin for bundle download,
// log upload etc.
type TriggerMode = v1.TriggerMode
const (
// TriggerImmediate represents uploading chunks when ready, flushed by the periodic polling mechanism
TriggerImmediate TriggerMode = v1.TriggerImmediate
// TriggerPeriodic represents periodic polling mechanism
TriggerPeriodic = v1.TriggerPeriodic
// TriggerManual represents manual triggering mechanism
TriggerManual = v1.TriggerManual
// DefaultTriggerMode represents default trigger mechanism
DefaultTriggerMode = v1.DefaultTriggerMode
)
// Status has a Plugin's current status plus an optional Message.
type Status = v1.Status
// StatusListener defines a handler to register for status updates.
type StatusListener v1.StatusListener
// Manager implements lifecycle management of plugins and gives plugins access
// to engine-wide components like storage.
type Manager = v1.Manager
// SetCompilerOnContext puts the compiler into the storage context. Calling this
// function before committing updated policies to storage allows the manager to
// skip parsing and compiling of modules. Instead, the manager will use the
// compiler that was stored on the context.
func SetCompilerOnContext(context *storage.Context, compiler *ast.Compiler) {
v1.SetCompilerOnContext(context, compiler)
}
// GetCompilerOnContext gets the compiler cached on the storage context.
func GetCompilerOnContext(context *storage.Context) *ast.Compiler {
return v1.GetCompilerOnContext(context)
}
// SetWasmResolversOnContext puts a set of Wasm Resolvers into the storage
// context. Calling this function before committing updated wasm modules to
// storage allows the manager to skip initializing modules before using them.
// Instead, the manager will use the compiler that was stored on the context.
func SetWasmResolversOnContext(context *storage.Context, rs []*wasm.Resolver) {
v1.SetWasmResolversOnContext(context, rs)
}
// ValidateAndInjectDefaultsForTriggerMode validates the trigger mode and injects default values
func ValidateAndInjectDefaultsForTriggerMode(a, b *TriggerMode) (*TriggerMode, error) {
return v1.ValidateAndInjectDefaultsForTriggerMode(a, b)
}
// Info sets the runtime information on the manager. The runtime information is
// propagated to opa.runtime() built-in function calls.
func Info(term *ast.Term) func(*Manager) {
return v1.Info(term)
}
// InitBundles provides the initial set of bundles to load.
func InitBundles(b map[string]*bundle.Bundle) func(*Manager) {
return v1.InitBundles(b)
}
// InitFiles provides the initial set of other data/policy files to load.
func InitFiles(f loader.Result) func(*Manager) {
return v1.InitFiles(f)
}
// MaxErrors sets the error limit for the manager's shared compiler.
func MaxErrors(n int) func(*Manager) {
return v1.MaxErrors(n)
}
// GracefulShutdownPeriod passes the configured graceful shutdown period to plugins
func GracefulShutdownPeriod(gracefulShutdownPeriod int) func(*Manager) {
return v1.GracefulShutdownPeriod(gracefulShutdownPeriod)
}
// Logger configures the passed logger on the plugin manager (useful to
// configure default fields)
func Logger(logger logging.Logger) func(*Manager) {
return v1.Logger(logger)
}
// ConsoleLogger sets the passed logger to be used by plugins that are
// configured with console logging enabled.
func ConsoleLogger(logger logging.Logger) func(*Manager) {
return v1.ConsoleLogger(logger)
}
func EnablePrintStatements(yes bool) func(*Manager) {
return v1.EnablePrintStatements(yes)
}
func PrintHook(h print.Hook) func(*Manager) {
return v1.PrintHook(h)
}
func WithRouter(r *http.ServeMux) func(*Manager) {
return v1.WithRouter(r)
}
// WithPrometheusRegister sets the passed prometheus.Registerer to be used by plugins
func WithPrometheusRegister(prometheusRegister prometheus.Registerer) func(*Manager) {
return v1.WithPrometheusRegister(prometheusRegister)
}
// WithTracerProvider sets the passed *trace.TracerProvider to be used by plugins
func WithTracerProvider(tracerProvider *trace.TracerProvider) func(*Manager) {
return v1.WithTracerProvider(tracerProvider)
}
// WithDistributedTracingOpts sets the options to be used by distributed tracing.
func WithDistributedTracingOpts(tr tracing.Options) func(*Manager) {
return v1.WithDistributedTracingOpts(tr)
}
// WithHooks allows passing hooks to the plugin manager.
func WithHooks(hs hooks.Hooks) func(*Manager) {
return v1.WithHooks(hs)
}
// WithParserOptions sets the parser options to be used by the plugin manager.
func WithParserOptions(opts ast.ParserOptions) func(*Manager) {
return v1.WithParserOptions(opts)
}
// WithEnableVersionCheck controls whether OPA will check for version updates.
func WithEnableVersionCheck(enable bool) func(*Manager) {
return v1.WithEnableVersionCheck(enable)
}
// WithEnableTelemetry controls whether OPA will check for version updates.
//
// Deprecated: Use WithEnableVersionCheck instead.
func WithEnableTelemetry(enableTelemetry bool) func(*Manager) {
return v1.WithEnableTelemetry(enableTelemetry)
}
// WithTelemetryGatherers allows registration of telemetry gatherers which enable injection of additional data in the
// telemetry report
//
// Deprecated: This function is deprecated as telemetry gathering has been removed.
func WithTelemetryGatherers(gs map[string]any) func(*Manager) {
return func(m *Manager) {
// No-op: telemetry gatherers are no longer used
}
}
// New creates a new Manager using config.
func New(raw []byte, id string, store storage.Store, opts ...func(*Manager)) (*Manager, error) {
options := make([]func(*Manager), 0, len(opts)+1)
options = append(options, opts...)
// Add option to apply default Rego version if not set. Must be last in list of options.
options = append(options, func(m *Manager) {
if m.ParserOptions().RegoVersion == ast.RegoUndefined {
cpy := m.ParserOptions()
cpy.RegoVersion = ast.DefaultRegoVersion
WithParserOptions(cpy)(m)
}
})
return v1.New(raw, id, store, options...)
}