mirror of
https://github.com/opencloud-eu/opencloud.git
synced 2026-01-24 13:58:12 -05:00
248 lines
7.5 KiB
Go
248 lines
7.5 KiB
Go
// Copyright 2016 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 storage
|
|
|
|
import (
|
|
"context"
|
|
|
|
"github.com/open-policy-agent/opa/metrics"
|
|
)
|
|
|
|
// Transaction defines the interface that identifies a consistent snapshot over
|
|
// the policy engine's storage layer.
|
|
type Transaction interface {
|
|
ID() uint64
|
|
}
|
|
|
|
// Store defines the interface for the storage layer's backend.
|
|
type Store interface {
|
|
Trigger
|
|
Policy
|
|
|
|
// NewTransaction is called create a new transaction in the store.
|
|
NewTransaction(context.Context, ...TransactionParams) (Transaction, error)
|
|
|
|
// Read is called to fetch a document referred to by path.
|
|
Read(context.Context, Transaction, Path) (interface{}, error)
|
|
|
|
// Write is called to modify a document referred to by path.
|
|
Write(context.Context, Transaction, PatchOp, Path, interface{}) error
|
|
|
|
// Commit is called to finish the transaction. If Commit returns an error, the
|
|
// transaction must be automatically aborted by the Store implementation.
|
|
Commit(context.Context, Transaction) error
|
|
|
|
// Truncate is called to make a copy of the underlying store, write documents in the new store
|
|
// by creating multiple transactions in the new store as needed and finally swapping
|
|
// over to the new storage instance. This method must be called within a transaction on the original store.
|
|
Truncate(context.Context, Transaction, TransactionParams, Iterator) error
|
|
|
|
// Abort is called to cancel the transaction.
|
|
Abort(context.Context, Transaction)
|
|
}
|
|
|
|
// MakeDirer defines the interface a Store could realize to override the
|
|
// generic MakeDir functionality in storage.MakeDir
|
|
type MakeDirer interface {
|
|
MakeDir(context.Context, Transaction, Path) error
|
|
}
|
|
|
|
// TransactionParams describes a new transaction.
|
|
type TransactionParams struct {
|
|
|
|
// BasePaths indicates the top-level paths where write operations will be performed in this transaction.
|
|
BasePaths []string
|
|
|
|
// RootOverwrite is deprecated. Use BasePaths instead.
|
|
RootOverwrite bool
|
|
|
|
// Write indicates if this transaction will perform any write operations.
|
|
Write bool
|
|
|
|
// Context contains key/value pairs passed to triggers.
|
|
Context *Context
|
|
}
|
|
|
|
// Context is a simple container for key/value pairs.
|
|
type Context struct {
|
|
values map[interface{}]interface{}
|
|
}
|
|
|
|
// NewContext returns a new context object.
|
|
func NewContext() *Context {
|
|
return &Context{
|
|
values: map[interface{}]interface{}{},
|
|
}
|
|
}
|
|
|
|
// Get returns the key value in the context.
|
|
func (ctx *Context) Get(key interface{}) interface{} {
|
|
if ctx == nil {
|
|
return nil
|
|
}
|
|
return ctx.values[key]
|
|
}
|
|
|
|
// Put adds a key/value pair to the context.
|
|
func (ctx *Context) Put(key, value interface{}) {
|
|
ctx.values[key] = value
|
|
}
|
|
|
|
var metricsKey = struct{}{}
|
|
|
|
// WithMetrics allows passing metrics via the Context.
|
|
// It puts the metrics object in the ctx, and returns the same
|
|
// ctx (not a copy) for convenience.
|
|
func (ctx *Context) WithMetrics(m metrics.Metrics) *Context {
|
|
ctx.values[metricsKey] = m
|
|
return ctx
|
|
}
|
|
|
|
// Metrics() allows using a Context's metrics. Returns nil if metrics
|
|
// were not attached to the Context.
|
|
func (ctx *Context) Metrics() metrics.Metrics {
|
|
if m, ok := ctx.values[metricsKey]; ok {
|
|
if met, ok := m.(metrics.Metrics); ok {
|
|
return met
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// WriteParams specifies the TransactionParams for a write transaction.
|
|
var WriteParams = TransactionParams{
|
|
Write: true,
|
|
}
|
|
|
|
// PatchOp is the enumeration of supposed modifications.
|
|
type PatchOp int
|
|
|
|
// Patch supports add, remove, and replace operations.
|
|
const (
|
|
AddOp PatchOp = iota
|
|
RemoveOp = iota
|
|
ReplaceOp = iota
|
|
)
|
|
|
|
// WritesNotSupported provides a default implementation of the write
|
|
// interface which may be used if the backend does not support writes.
|
|
type WritesNotSupported struct{}
|
|
|
|
func (WritesNotSupported) Write(context.Context, Transaction, PatchOp, Path, interface{}) error {
|
|
return writesNotSupportedError()
|
|
}
|
|
|
|
// Policy defines the interface for policy module storage.
|
|
type Policy interface {
|
|
ListPolicies(context.Context, Transaction) ([]string, error)
|
|
GetPolicy(context.Context, Transaction, string) ([]byte, error)
|
|
UpsertPolicy(context.Context, Transaction, string, []byte) error
|
|
DeletePolicy(context.Context, Transaction, string) error
|
|
}
|
|
|
|
// PolicyNotSupported provides a default implementation of the policy interface
|
|
// which may be used if the backend does not support policy storage.
|
|
type PolicyNotSupported struct{}
|
|
|
|
// ListPolicies always returns a PolicyNotSupportedErr.
|
|
func (PolicyNotSupported) ListPolicies(context.Context, Transaction) ([]string, error) {
|
|
return nil, policyNotSupportedError()
|
|
}
|
|
|
|
// GetPolicy always returns a PolicyNotSupportedErr.
|
|
func (PolicyNotSupported) GetPolicy(context.Context, Transaction, string) ([]byte, error) {
|
|
return nil, policyNotSupportedError()
|
|
}
|
|
|
|
// UpsertPolicy always returns a PolicyNotSupportedErr.
|
|
func (PolicyNotSupported) UpsertPolicy(context.Context, Transaction, string, []byte) error {
|
|
return policyNotSupportedError()
|
|
}
|
|
|
|
// DeletePolicy always returns a PolicyNotSupportedErr.
|
|
func (PolicyNotSupported) DeletePolicy(context.Context, Transaction, string) error {
|
|
return policyNotSupportedError()
|
|
}
|
|
|
|
// PolicyEvent describes a change to a policy.
|
|
type PolicyEvent struct {
|
|
ID string
|
|
Data []byte
|
|
Removed bool
|
|
}
|
|
|
|
// DataEvent describes a change to a base data document.
|
|
type DataEvent struct {
|
|
Path Path
|
|
Data interface{}
|
|
Removed bool
|
|
}
|
|
|
|
// TriggerEvent describes the changes that caused the trigger to be invoked.
|
|
type TriggerEvent struct {
|
|
Policy []PolicyEvent
|
|
Data []DataEvent
|
|
Context *Context
|
|
}
|
|
|
|
// IsZero returns true if the TriggerEvent indicates no changes occurred. This
|
|
// function is primarily for test purposes.
|
|
func (e TriggerEvent) IsZero() bool {
|
|
return !e.PolicyChanged() && !e.DataChanged()
|
|
}
|
|
|
|
// PolicyChanged returns true if the trigger was caused by a policy change.
|
|
func (e TriggerEvent) PolicyChanged() bool {
|
|
return len(e.Policy) > 0
|
|
}
|
|
|
|
// DataChanged returns true if the trigger was caused by a data change.
|
|
func (e TriggerEvent) DataChanged() bool {
|
|
return len(e.Data) > 0
|
|
}
|
|
|
|
// TriggerConfig contains the trigger registration configuration.
|
|
type TriggerConfig struct {
|
|
|
|
// OnCommit is invoked when a transaction is successfully committed. The
|
|
// callback is invoked with a handle to the write transaction that
|
|
// successfully committed before other clients see the changes.
|
|
OnCommit func(context.Context, Transaction, TriggerEvent)
|
|
}
|
|
|
|
// Trigger defines the interface that stores implement to register for change
|
|
// notifications when the store is changed.
|
|
type Trigger interface {
|
|
Register(context.Context, Transaction, TriggerConfig) (TriggerHandle, error)
|
|
}
|
|
|
|
// TriggersNotSupported provides default implementations of the Trigger
|
|
// interface which may be used if the backend does not support triggers.
|
|
type TriggersNotSupported struct{}
|
|
|
|
// Register always returns an error indicating triggers are not supported.
|
|
func (TriggersNotSupported) Register(context.Context, Transaction, TriggerConfig) (TriggerHandle, error) {
|
|
return nil, triggersNotSupportedError()
|
|
}
|
|
|
|
// TriggerHandle defines the interface that can be used to unregister triggers that have
|
|
// been registered on a Store.
|
|
type TriggerHandle interface {
|
|
Unregister(context.Context, Transaction)
|
|
}
|
|
|
|
// Iterator defines the interface that can be used to read files from a directory starting with
|
|
// files at the base of the directory, then sub-directories etc.
|
|
type Iterator interface {
|
|
Next() (*Update, error)
|
|
}
|
|
|
|
// Update contains information about a file
|
|
type Update struct {
|
|
Path Path
|
|
Value []byte
|
|
IsPolicy bool
|
|
}
|