Upgrade dependent version: github.com/open-policy-agent/opa (#5315)
Upgrade dependent version: github.com/open-policy-agent/opa v0.18.0 -> v0.45.0 Signed-off-by: hongzhouzi <hongzhouzi@kubesphere.io> Signed-off-by: hongzhouzi <hongzhouzi@kubesphere.io>
This commit is contained in:
350
vendor/github.com/open-policy-agent/opa/storage/inmem/index.go
generated
vendored
350
vendor/github.com/open-policy-agent/opa/storage/inmem/index.go
generated
vendored
@@ -1,350 +0,0 @@
|
||||
// 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 inmem
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"hash/fnv"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/open-policy-agent/opa/ast"
|
||||
"github.com/open-policy-agent/opa/storage"
|
||||
"github.com/open-policy-agent/opa/util"
|
||||
)
|
||||
|
||||
// indices contains a mapping of non-ground references to values to sets of bindings.
|
||||
//
|
||||
// +------+------------------------------------+
|
||||
// | ref1 | val1 | bindings-1, bindings-2, ... |
|
||||
// | +------+-----------------------------+
|
||||
// | | val2 | bindings-m, bindings-m, ... |
|
||||
// | +------+-----------------------------+
|
||||
// | | .... | ... |
|
||||
// +------+------+-----------------------------+
|
||||
// | ref2 | .... | ... |
|
||||
// +------+------+-----------------------------+
|
||||
// | ... |
|
||||
// +-------------------------------------------+
|
||||
//
|
||||
// The "value" is the data value stored at the location referred to by the ground
|
||||
// reference obtained by plugging bindings into the non-ground reference that is the
|
||||
// index key.
|
||||
//
|
||||
type indices struct {
|
||||
mu sync.Mutex
|
||||
table map[int]*indicesNode
|
||||
}
|
||||
|
||||
type indicesNode struct {
|
||||
key ast.Ref
|
||||
val *bindingIndex
|
||||
next *indicesNode
|
||||
}
|
||||
|
||||
func newIndices() *indices {
|
||||
return &indices{
|
||||
table: map[int]*indicesNode{},
|
||||
}
|
||||
}
|
||||
|
||||
func (ind *indices) Build(ctx context.Context, store storage.Store, txn storage.Transaction, ref ast.Ref) (*bindingIndex, error) {
|
||||
|
||||
ind.mu.Lock()
|
||||
defer ind.mu.Unlock()
|
||||
|
||||
if exist := ind.get(ref); exist != nil {
|
||||
return exist, nil
|
||||
}
|
||||
|
||||
index := newBindingIndex()
|
||||
|
||||
if err := iterStorage(ctx, store, txn, ref, ast.EmptyRef(), ast.NewValueMap(), index.Add); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
hashCode := ref.Hash()
|
||||
head := ind.table[hashCode]
|
||||
entry := &indicesNode{
|
||||
key: ref,
|
||||
val: index,
|
||||
next: head,
|
||||
}
|
||||
|
||||
ind.table[hashCode] = entry
|
||||
|
||||
return index, nil
|
||||
}
|
||||
|
||||
func (ind *indices) get(ref ast.Ref) *bindingIndex {
|
||||
node := ind.getNode(ref)
|
||||
if node != nil {
|
||||
return node.val
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ind *indices) iter(iter func(ast.Ref, *bindingIndex) error) error {
|
||||
for _, head := range ind.table {
|
||||
for entry := head; entry != nil; entry = entry.next {
|
||||
if err := iter(entry.key, entry.val); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ind *indices) getNode(ref ast.Ref) *indicesNode {
|
||||
hashCode := ref.Hash()
|
||||
for entry := ind.table[hashCode]; entry != nil; entry = entry.next {
|
||||
if entry.key.Equal(ref) {
|
||||
return entry
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ind *indices) String() string {
|
||||
buf := []string{}
|
||||
for _, head := range ind.table {
|
||||
for entry := head; entry != nil; entry = entry.next {
|
||||
str := fmt.Sprintf("%v: %v", entry.key, entry.val)
|
||||
buf = append(buf, str)
|
||||
}
|
||||
}
|
||||
return "{" + strings.Join(buf, ", ") + "}"
|
||||
}
|
||||
|
||||
// bindingIndex contains a mapping of values to bindings.
|
||||
type bindingIndex struct {
|
||||
table map[int]*indexNode
|
||||
}
|
||||
|
||||
type indexNode struct {
|
||||
key interface{}
|
||||
val *bindingSet
|
||||
next *indexNode
|
||||
}
|
||||
|
||||
func newBindingIndex() *bindingIndex {
|
||||
return &bindingIndex{
|
||||
table: map[int]*indexNode{},
|
||||
}
|
||||
}
|
||||
|
||||
func (ind *bindingIndex) Add(val interface{}, bindings *ast.ValueMap) {
|
||||
|
||||
node := ind.getNode(val)
|
||||
if node != nil {
|
||||
node.val.Add(bindings)
|
||||
return
|
||||
}
|
||||
|
||||
hashCode := hash(val)
|
||||
bindingsSet := newBindingSet()
|
||||
bindingsSet.Add(bindings)
|
||||
|
||||
entry := &indexNode{
|
||||
key: val,
|
||||
val: bindingsSet,
|
||||
next: ind.table[hashCode],
|
||||
}
|
||||
|
||||
ind.table[hashCode] = entry
|
||||
}
|
||||
|
||||
func (ind *bindingIndex) Lookup(_ context.Context, _ storage.Transaction, val interface{}, iter storage.IndexIterator) error {
|
||||
node := ind.getNode(val)
|
||||
if node == nil {
|
||||
return nil
|
||||
}
|
||||
return node.val.Iter(iter)
|
||||
}
|
||||
|
||||
func (ind *bindingIndex) getNode(val interface{}) *indexNode {
|
||||
hashCode := hash(val)
|
||||
head := ind.table[hashCode]
|
||||
for entry := head; entry != nil; entry = entry.next {
|
||||
if util.Compare(entry.key, val) == 0 {
|
||||
return entry
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ind *bindingIndex) String() string {
|
||||
|
||||
buf := []string{}
|
||||
|
||||
for _, head := range ind.table {
|
||||
for entry := head; entry != nil; entry = entry.next {
|
||||
str := fmt.Sprintf("%v: %v", entry.key, entry.val)
|
||||
buf = append(buf, str)
|
||||
}
|
||||
}
|
||||
|
||||
return "{" + strings.Join(buf, ", ") + "}"
|
||||
}
|
||||
|
||||
type bindingSetNode struct {
|
||||
val *ast.ValueMap
|
||||
next *bindingSetNode
|
||||
}
|
||||
|
||||
type bindingSet struct {
|
||||
table map[int]*bindingSetNode
|
||||
}
|
||||
|
||||
func newBindingSet() *bindingSet {
|
||||
return &bindingSet{
|
||||
table: map[int]*bindingSetNode{},
|
||||
}
|
||||
}
|
||||
|
||||
func (set *bindingSet) Add(val *ast.ValueMap) {
|
||||
node := set.getNode(val)
|
||||
if node != nil {
|
||||
return
|
||||
}
|
||||
hashCode := val.Hash()
|
||||
head := set.table[hashCode]
|
||||
set.table[hashCode] = &bindingSetNode{val, head}
|
||||
}
|
||||
|
||||
func (set *bindingSet) Iter(iter func(*ast.ValueMap) error) error {
|
||||
for _, head := range set.table {
|
||||
for entry := head; entry != nil; entry = entry.next {
|
||||
if err := iter(entry.val); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (set *bindingSet) String() string {
|
||||
buf := []string{}
|
||||
set.Iter(func(bindings *ast.ValueMap) error {
|
||||
buf = append(buf, bindings.String())
|
||||
return nil
|
||||
})
|
||||
return "{" + strings.Join(buf, ", ") + "}"
|
||||
}
|
||||
|
||||
func (set *bindingSet) getNode(val *ast.ValueMap) *bindingSetNode {
|
||||
hashCode := val.Hash()
|
||||
for entry := set.table[hashCode]; entry != nil; entry = entry.next {
|
||||
if entry.val.Equal(val) {
|
||||
return entry
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func hash(v interface{}) int {
|
||||
switch v := v.(type) {
|
||||
case []interface{}:
|
||||
var h int
|
||||
for _, e := range v {
|
||||
h += hash(e)
|
||||
}
|
||||
return h
|
||||
case map[string]interface{}:
|
||||
var h int
|
||||
for k, v := range v {
|
||||
h += hash(k) + hash(v)
|
||||
}
|
||||
return h
|
||||
case string:
|
||||
h := fnv.New64a()
|
||||
h.Write([]byte(v))
|
||||
return int(h.Sum64())
|
||||
case bool:
|
||||
if v {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
case nil:
|
||||
return 0
|
||||
case json.Number:
|
||||
h := fnv.New64a()
|
||||
h.Write([]byte(v))
|
||||
return int(h.Sum64())
|
||||
}
|
||||
panic(fmt.Sprintf("illegal argument: %v (%T)", v, v))
|
||||
}
|
||||
|
||||
func iterStorage(ctx context.Context, store storage.Store, txn storage.Transaction, nonGround, ground ast.Ref, bindings *ast.ValueMap, iter func(interface{}, *ast.ValueMap)) error {
|
||||
|
||||
if len(nonGround) == 0 {
|
||||
path, err := storage.NewPathForRef(ground)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
node, err := store.Read(ctx, txn, path)
|
||||
if err != nil {
|
||||
if storage.IsNotFound(err) {
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
iter(node, bindings)
|
||||
return nil
|
||||
}
|
||||
|
||||
head := nonGround[0]
|
||||
tail := nonGround[1:]
|
||||
|
||||
headVar, isVar := head.Value.(ast.Var)
|
||||
|
||||
if !isVar || len(ground) == 0 {
|
||||
ground = append(ground, head)
|
||||
return iterStorage(ctx, store, txn, tail, ground, bindings, iter)
|
||||
}
|
||||
|
||||
path, err := storage.NewPathForRef(ground)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
node, err := store.Read(ctx, txn, path)
|
||||
if err != nil {
|
||||
if storage.IsNotFound(err) {
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
switch node := node.(type) {
|
||||
case map[string]interface{}:
|
||||
for key := range node {
|
||||
ground = append(ground, ast.StringTerm(key))
|
||||
cpy := bindings.Copy()
|
||||
cpy.Put(headVar, ast.String(key))
|
||||
err := iterStorage(ctx, store, txn, tail, ground, cpy, iter)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ground = ground[:len(ground)-1]
|
||||
}
|
||||
case []interface{}:
|
||||
for i := range node {
|
||||
idx := ast.IntNumberTerm(i)
|
||||
ground = append(ground, idx)
|
||||
cpy := bindings.Copy()
|
||||
cpy.Put(headVar, idx.Value)
|
||||
err := iterStorage(ctx, store, txn, tail, ground, cpy, iter)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ground = ground[:len(ground)-1]
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
227
vendor/github.com/open-policy-agent/opa/storage/inmem/inmem.go
generated
vendored
227
vendor/github.com/open-policy-agent/opa/storage/inmem/inmem.go
generated
vendored
@@ -19,27 +19,46 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
|
||||
"github.com/open-policy-agent/opa/ast"
|
||||
"github.com/open-policy-agent/opa/internal/merge"
|
||||
"github.com/open-policy-agent/opa/storage"
|
||||
"github.com/open-policy-agent/opa/util"
|
||||
)
|
||||
|
||||
// New returns an empty in-memory store.
|
||||
func New() storage.Store {
|
||||
return &store{
|
||||
data: map[string]interface{}{},
|
||||
triggers: map[*handle]storage.TriggerConfig{},
|
||||
policies: map[string][]byte{},
|
||||
indices: newIndices(),
|
||||
return NewWithOpts()
|
||||
}
|
||||
|
||||
// NewWithOpts returns an empty in-memory store, with extra options passed.
|
||||
func NewWithOpts(opts ...Opt) storage.Store {
|
||||
s := &store{
|
||||
data: map[string]interface{}{},
|
||||
triggers: map[*handle]storage.TriggerConfig{},
|
||||
policies: map[string][]byte{},
|
||||
roundTripOnWrite: true,
|
||||
}
|
||||
|
||||
for _, opt := range opts {
|
||||
opt(s)
|
||||
}
|
||||
|
||||
return s
|
||||
}
|
||||
|
||||
// NewFromObject returns a new in-memory store from the supplied data object.
|
||||
func NewFromObject(data map[string]interface{}) storage.Store {
|
||||
db := New()
|
||||
return NewFromObjectWithOpts(data)
|
||||
}
|
||||
|
||||
// NewFromObject returns a new in-memory store from the supplied data object, with the
|
||||
// options passed.
|
||||
func NewFromObjectWithOpts(data map[string]interface{}, opts ...Opt) storage.Store {
|
||||
db := NewWithOpts(opts...)
|
||||
ctx := context.Background()
|
||||
txn, err := db.NewTransaction(ctx, storage.WriteParams)
|
||||
if err != nil {
|
||||
@@ -57,12 +76,18 @@ func NewFromObject(data map[string]interface{}) storage.Store {
|
||||
// NewFromReader returns a new in-memory store from a reader that produces a
|
||||
// JSON serialized object. This function is for test purposes.
|
||||
func NewFromReader(r io.Reader) storage.Store {
|
||||
return NewFromReaderWithOpts(r)
|
||||
}
|
||||
|
||||
// NewFromReader returns a new in-memory store from a reader that produces a
|
||||
// JSON serialized object, with extra options. This function is for test purposes.
|
||||
func NewFromReaderWithOpts(r io.Reader, opts ...Opt) storage.Store {
|
||||
d := util.NewJSONDecoder(r)
|
||||
var data map[string]interface{}
|
||||
if err := d.Decode(&data); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return NewFromObject(data)
|
||||
return NewFromObjectWithOpts(data, opts...)
|
||||
}
|
||||
|
||||
type store struct {
|
||||
@@ -72,19 +97,22 @@ type store struct {
|
||||
data map[string]interface{} // raw data
|
||||
policies map[string][]byte // raw policies
|
||||
triggers map[*handle]storage.TriggerConfig // registered triggers
|
||||
indices *indices // data ref indices
|
||||
|
||||
// roundTripOnWrite, if true, means that every call to Write round trips the
|
||||
// data through JSON before adding the data to the store. Defaults to true.
|
||||
roundTripOnWrite bool
|
||||
}
|
||||
|
||||
type handle struct {
|
||||
db *store
|
||||
}
|
||||
|
||||
func (db *store) NewTransaction(ctx context.Context, params ...storage.TransactionParams) (storage.Transaction, error) {
|
||||
func (db *store) NewTransaction(_ context.Context, params ...storage.TransactionParams) (storage.Transaction, error) {
|
||||
var write bool
|
||||
var context *storage.Context
|
||||
var ctx *storage.Context
|
||||
if len(params) > 0 {
|
||||
write = params[0].Write
|
||||
context = params[0].Context
|
||||
ctx = params[0].Context
|
||||
}
|
||||
xid := atomic.AddUint64(&db.xid, uint64(1))
|
||||
if write {
|
||||
@@ -92,7 +120,90 @@ func (db *store) NewTransaction(ctx context.Context, params ...storage.Transacti
|
||||
} else {
|
||||
db.rmu.RLock()
|
||||
}
|
||||
return newTransaction(xid, write, context, db), nil
|
||||
return newTransaction(xid, write, ctx, db), nil
|
||||
}
|
||||
|
||||
// Truncate implements the storage.Store interface. This method must be called within a transaction.
|
||||
func (db *store) Truncate(ctx context.Context, txn storage.Transaction, params storage.TransactionParams, it storage.Iterator) error {
|
||||
var update *storage.Update
|
||||
var err error
|
||||
mergedData := map[string]interface{}{}
|
||||
|
||||
underlying, err := db.underlying(txn)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for {
|
||||
update, err = it.Next()
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
|
||||
if update.IsPolicy {
|
||||
err = underlying.UpsertPolicy(strings.TrimLeft(update.Path.String(), "/"), update.Value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
var value interface{}
|
||||
err = util.Unmarshal(update.Value, &value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var key []string
|
||||
dirpath := strings.TrimLeft(update.Path.String(), "/")
|
||||
if len(dirpath) > 0 {
|
||||
key = strings.Split(dirpath, "/")
|
||||
}
|
||||
|
||||
if value != nil {
|
||||
obj, err := mktree(key, value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
merged, ok := merge.InterfaceMaps(mergedData, obj)
|
||||
if !ok {
|
||||
return fmt.Errorf("failed to insert data file from path %s", filepath.Join(key...))
|
||||
}
|
||||
mergedData = merged
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if err != nil && err != io.EOF {
|
||||
return err
|
||||
}
|
||||
|
||||
// For backwards compatibility, check if `RootOverwrite` was configured.
|
||||
if params.RootOverwrite {
|
||||
newPath, ok := storage.ParsePathEscaped("/")
|
||||
if !ok {
|
||||
return fmt.Errorf("storage path invalid: %v", newPath)
|
||||
}
|
||||
return underlying.Write(storage.AddOp, newPath, mergedData)
|
||||
}
|
||||
|
||||
for _, root := range params.BasePaths {
|
||||
newPath, ok := storage.ParsePathEscaped("/" + root)
|
||||
if !ok {
|
||||
return fmt.Errorf("storage path invalid: %v", newPath)
|
||||
}
|
||||
|
||||
if value, ok := lookup(newPath, mergedData); ok {
|
||||
if len(newPath) > 0 {
|
||||
if err := storage.MakeDir(ctx, db, txn, newPath[:len(newPath)-1]); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if err := underlying.Write(storage.AddOp, newPath, value); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (db *store) Commit(ctx context.Context, txn storage.Transaction) error {
|
||||
@@ -103,9 +214,8 @@ func (db *store) Commit(ctx context.Context, txn storage.Transaction) error {
|
||||
if underlying.write {
|
||||
db.rmu.Lock()
|
||||
event := underlying.Commit()
|
||||
db.indices = newIndices()
|
||||
db.runOnCommitTriggers(ctx, txn, event)
|
||||
// Mark the transaction stale after executing triggers so they can
|
||||
// Mark the transaction stale after executing triggers, so they can
|
||||
// perform store operations if needed.
|
||||
underlying.stale = true
|
||||
db.rmu.Unlock()
|
||||
@@ -116,7 +226,7 @@ func (db *store) Commit(ctx context.Context, txn storage.Transaction) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (db *store) Abort(ctx context.Context, txn storage.Transaction) {
|
||||
func (db *store) Abort(_ context.Context, txn storage.Transaction) {
|
||||
underlying, err := db.underlying(txn)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
@@ -164,7 +274,7 @@ func (db *store) DeletePolicy(_ context.Context, txn storage.Transaction, id str
|
||||
return underlying.DeletePolicy(id)
|
||||
}
|
||||
|
||||
func (db *store) Register(ctx context.Context, txn storage.Transaction, config storage.TriggerConfig) (storage.TriggerHandle, error) {
|
||||
func (db *store) Register(_ context.Context, txn storage.Transaction, config storage.TriggerConfig) (storage.TriggerHandle, error) {
|
||||
underlying, err := db.underlying(txn)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -180,7 +290,7 @@ func (db *store) Register(ctx context.Context, txn storage.Transaction, config s
|
||||
return h, nil
|
||||
}
|
||||
|
||||
func (db *store) Read(ctx context.Context, txn storage.Transaction, path storage.Path) (interface{}, error) {
|
||||
func (db *store) Read(_ context.Context, txn storage.Transaction, path storage.Path) (interface{}, error) {
|
||||
underlying, err := db.underlying(txn)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -188,33 +298,21 @@ func (db *store) Read(ctx context.Context, txn storage.Transaction, path storage
|
||||
return underlying.Read(path)
|
||||
}
|
||||
|
||||
func (db *store) Write(ctx context.Context, txn storage.Transaction, op storage.PatchOp, path storage.Path, value interface{}) error {
|
||||
func (db *store) Write(_ context.Context, txn storage.Transaction, op storage.PatchOp, path storage.Path, value interface{}) error {
|
||||
underlying, err := db.underlying(txn)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
val := util.Reference(value)
|
||||
if err := util.RoundTrip(val); err != nil {
|
||||
return err
|
||||
if db.roundTripOnWrite {
|
||||
if err := util.RoundTrip(val); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return underlying.Write(op, path, *val)
|
||||
}
|
||||
|
||||
func (db *store) Build(ctx context.Context, txn storage.Transaction, ref ast.Ref) (storage.Index, error) {
|
||||
underlying, err := db.underlying(txn)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if underlying.write {
|
||||
return nil, &storage.Error{
|
||||
Code: storage.IndexingNotSupportedErr,
|
||||
Message: "in-memory store does not support indexing on write transactions",
|
||||
}
|
||||
}
|
||||
return db.indices.Build(ctx, db, txn, ref)
|
||||
}
|
||||
|
||||
func (h *handle) Unregister(ctx context.Context, txn storage.Transaction) {
|
||||
func (h *handle) Unregister(_ context.Context, txn storage.Transaction) {
|
||||
underlying, err := h.db.underlying(txn)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
@@ -257,11 +355,8 @@ func (db *store) underlying(txn storage.Transaction) (*transaction, error) {
|
||||
return underlying, nil
|
||||
}
|
||||
|
||||
var doesNotExistMsg = "document does not exist"
|
||||
var rootMustBeObjectMsg = "root must be object"
|
||||
var rootCannotBeRemovedMsg = "root cannot be removed"
|
||||
var outOfRangeMsg = "array index out of range"
|
||||
var arrayIndexTypeMsg = "array index must be integer"
|
||||
const rootMustBeObjectMsg = "root must be object"
|
||||
const rootCannotBeRemovedMsg = "root cannot be removed"
|
||||
|
||||
func invalidPatchError(f string, a ...interface{}) *storage.Error {
|
||||
return &storage.Error{
|
||||
@@ -270,18 +365,42 @@ func invalidPatchError(f string, a ...interface{}) *storage.Error {
|
||||
}
|
||||
}
|
||||
|
||||
func notFoundError(path storage.Path) *storage.Error {
|
||||
return notFoundErrorHint(path, doesNotExistMsg)
|
||||
}
|
||||
|
||||
func notFoundErrorHint(path storage.Path, hint string) *storage.Error {
|
||||
return notFoundErrorf("%v: %v", path.String(), hint)
|
||||
}
|
||||
|
||||
func notFoundErrorf(f string, a ...interface{}) *storage.Error {
|
||||
msg := fmt.Sprintf(f, a...)
|
||||
return &storage.Error{
|
||||
Code: storage.NotFoundErr,
|
||||
Message: msg,
|
||||
func mktree(path []string, value interface{}) (map[string]interface{}, error) {
|
||||
if len(path) == 0 {
|
||||
// For 0 length path the value is the full tree.
|
||||
obj, ok := value.(map[string]interface{})
|
||||
if !ok {
|
||||
return nil, invalidPatchError(rootMustBeObjectMsg)
|
||||
}
|
||||
return obj, nil
|
||||
}
|
||||
|
||||
dir := map[string]interface{}{}
|
||||
for i := len(path) - 1; i > 0; i-- {
|
||||
dir[path[i]] = value
|
||||
value = dir
|
||||
dir = map[string]interface{}{}
|
||||
}
|
||||
dir[path[0]] = value
|
||||
|
||||
return dir, nil
|
||||
}
|
||||
|
||||
func lookup(path storage.Path, data map[string]interface{}) (interface{}, bool) {
|
||||
if len(path) == 0 {
|
||||
return data, true
|
||||
}
|
||||
for i := 0; i < len(path)-1; i++ {
|
||||
value, ok := data[path[i]]
|
||||
if !ok {
|
||||
return nil, false
|
||||
}
|
||||
obj, ok := value.(map[string]interface{})
|
||||
if !ok {
|
||||
return nil, false
|
||||
}
|
||||
data = obj
|
||||
}
|
||||
value, ok := data[path[len(path)-1]]
|
||||
return value, ok
|
||||
}
|
||||
|
||||
25
vendor/github.com/open-policy-agent/opa/storage/inmem/opts.go
generated
vendored
Normal file
25
vendor/github.com/open-policy-agent/opa/storage/inmem/opts.go
generated
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
package inmem
|
||||
|
||||
// An Opt modifies store at instantiation.
|
||||
type Opt func(*store)
|
||||
|
||||
// OptRoundTripOnWrite sets whether incoming objects written to store are
|
||||
// round-tripped through JSON to ensure they are serializable to JSON.
|
||||
//
|
||||
// Callers should disable this if they can guarantee all objects passed to
|
||||
// Write() are serializable to JSON. Failing to do so may result in undefined
|
||||
// behavior, including panics.
|
||||
//
|
||||
// Usually, when only storing objects in the inmem store that have been read
|
||||
// via encoding/json, this is safe to disable, and comes with an improvement
|
||||
// in performance and memory use.
|
||||
//
|
||||
// If setting to false, callers should deep-copy any objects passed to Write()
|
||||
// unless they can guarantee the objects will not be mutated after being written,
|
||||
// and that mutations happening to the objects after they have been passed into
|
||||
// Write() don't affect their logic.
|
||||
func OptRoundTripOnWrite(enabled bool) Opt {
|
||||
return func(s *store) {
|
||||
s.roundTripOnWrite = enabled
|
||||
}
|
||||
}
|
||||
100
vendor/github.com/open-policy-agent/opa/storage/inmem/txn.go
generated
vendored
100
vendor/github.com/open-policy-agent/opa/storage/inmem/txn.go
generated
vendored
@@ -9,7 +9,10 @@ import (
|
||||
"encoding/json"
|
||||
"strconv"
|
||||
|
||||
"github.com/open-policy-agent/opa/internal/deepcopy"
|
||||
"github.com/open-policy-agent/opa/storage"
|
||||
"github.com/open-policy-agent/opa/storage/internal/errors"
|
||||
"github.com/open-policy-agent/opa/storage/internal/ptr"
|
||||
)
|
||||
|
||||
// transaction implements the low-level read/write operations on the in-memory
|
||||
@@ -81,7 +84,7 @@ func (txn *transaction) Write(op storage.PatchOp, path storage.Path, value inter
|
||||
if update.path.Equal(path) {
|
||||
if update.remove {
|
||||
if op != storage.AddOp {
|
||||
return notFoundError(path)
|
||||
return errors.NewNotFoundError(path)
|
||||
}
|
||||
}
|
||||
txn.updates.Remove(curr)
|
||||
@@ -102,7 +105,7 @@ func (txn *transaction) Write(op storage.PatchOp, path storage.Path, value inter
|
||||
// existing update is mutated.
|
||||
if path.HasPrefix(update.path) {
|
||||
if update.remove {
|
||||
return notFoundError(path)
|
||||
return errors.NewNotFoundError(path)
|
||||
}
|
||||
suffix := path[len(update.path):]
|
||||
newUpdate, err := newUpdate(update.value, op, suffix, 0, value)
|
||||
@@ -173,7 +176,7 @@ func (txn *transaction) Commit() (result storage.TriggerEvent) {
|
||||
func (txn *transaction) Read(path storage.Path) (interface{}, error) {
|
||||
|
||||
if !txn.write {
|
||||
return ptr(txn.db.data, path)
|
||||
return ptr.Ptr(txn.db.data, path)
|
||||
}
|
||||
|
||||
merge := []*update{}
|
||||
@@ -184,9 +187,9 @@ func (txn *transaction) Read(path storage.Path) (interface{}, error) {
|
||||
|
||||
if path.HasPrefix(update.path) {
|
||||
if update.remove {
|
||||
return nil, notFoundError(path)
|
||||
return nil, errors.NewNotFoundError(path)
|
||||
}
|
||||
return ptr(update.value, path[len(update.path):])
|
||||
return ptr.Ptr(update.value, path[len(update.path):])
|
||||
}
|
||||
|
||||
if update.path.HasPrefix(path) {
|
||||
@@ -194,7 +197,7 @@ func (txn *transaction) Read(path storage.Path) (interface{}, error) {
|
||||
}
|
||||
}
|
||||
|
||||
data, err := ptr(txn.db.data, path)
|
||||
data, err := ptr.Ptr(txn.db.data, path)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -204,7 +207,7 @@ func (txn *transaction) Read(path storage.Path) (interface{}, error) {
|
||||
return data, nil
|
||||
}
|
||||
|
||||
cpy := deepCopy(data)
|
||||
cpy := deepcopy.DeepCopy(data)
|
||||
|
||||
for _, update := range merge {
|
||||
cpy = update.Relative(path).Apply(cpy)
|
||||
@@ -233,12 +236,12 @@ func (txn *transaction) GetPolicy(id string) ([]byte, error) {
|
||||
if !update.remove {
|
||||
return update.value, nil
|
||||
}
|
||||
return nil, notFoundErrorf("policy id %q", id)
|
||||
return nil, errors.NewNotFoundErrorf("policy id %q", id)
|
||||
}
|
||||
if exist, ok := txn.db.policies[id]; ok {
|
||||
return exist, nil
|
||||
}
|
||||
return nil, notFoundErrorf("policy id %q", id)
|
||||
return nil, errors.NewNotFoundErrorf("policy id %q", id)
|
||||
}
|
||||
|
||||
func (txn *transaction) UpsertPolicy(id string, bs []byte) error {
|
||||
@@ -281,7 +284,7 @@ func newUpdate(data interface{}, op storage.PatchOp, path storage.Path, idx int,
|
||||
return newUpdateArray(data, op, path, idx, value)
|
||||
|
||||
case nil, bool, json.Number, string:
|
||||
return nil, notFoundError(path)
|
||||
return nil, errors.NewNotFoundError(path)
|
||||
}
|
||||
|
||||
return nil, &storage.Error{
|
||||
@@ -293,7 +296,7 @@ func newUpdate(data interface{}, op storage.PatchOp, path storage.Path, idx int,
|
||||
func newUpdateArray(data []interface{}, op storage.PatchOp, path storage.Path, idx int, value interface{}) (*update, error) {
|
||||
|
||||
if idx == len(path)-1 {
|
||||
if path[idx] == "-" {
|
||||
if path[idx] == "-" || path[idx] == strconv.Itoa(len(data)) {
|
||||
if op != storage.AddOp {
|
||||
return nil, invalidPatchError("%v: invalid patch path", path)
|
||||
}
|
||||
@@ -303,25 +306,26 @@ func newUpdateArray(data []interface{}, op storage.PatchOp, path storage.Path, i
|
||||
return &update{path[:len(path)-1], false, cpy}, nil
|
||||
}
|
||||
|
||||
pos, err := validateArrayIndex(data, path[idx], path)
|
||||
pos, err := ptr.ValidateArrayIndex(data, path[idx], path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if op == storage.AddOp {
|
||||
switch op {
|
||||
case storage.AddOp:
|
||||
cpy := make([]interface{}, len(data)+1)
|
||||
copy(cpy[:pos], data[:pos])
|
||||
copy(cpy[pos+1:], data[pos:])
|
||||
cpy[pos] = value
|
||||
return &update{path[:len(path)-1], false, cpy}, nil
|
||||
|
||||
} else if op == storage.RemoveOp {
|
||||
case storage.RemoveOp:
|
||||
cpy := make([]interface{}, len(data)-1)
|
||||
copy(cpy[:pos], data[:pos])
|
||||
copy(cpy[pos:], data[pos+1:])
|
||||
return &update{path[:len(path)-1], false, cpy}, nil
|
||||
|
||||
} else {
|
||||
default:
|
||||
cpy := make([]interface{}, len(data))
|
||||
copy(cpy, data)
|
||||
cpy[pos] = value
|
||||
@@ -329,7 +333,7 @@ func newUpdateArray(data []interface{}, op storage.PatchOp, path storage.Path, i
|
||||
}
|
||||
}
|
||||
|
||||
pos, err := validateArrayIndex(data, path[idx], path)
|
||||
pos, err := ptr.ValidateArrayIndex(data, path[idx], path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -343,7 +347,7 @@ func newUpdateObject(data map[string]interface{}, op storage.PatchOp, path stora
|
||||
switch op {
|
||||
case storage.ReplaceOp, storage.RemoveOp:
|
||||
if _, ok := data[path[idx]]; !ok {
|
||||
return nil, notFoundError(path)
|
||||
return nil, errors.NewNotFoundError(path)
|
||||
}
|
||||
}
|
||||
return &update{path, op == storage.RemoveOp, value}, nil
|
||||
@@ -353,13 +357,13 @@ func newUpdateObject(data map[string]interface{}, op storage.PatchOp, path stora
|
||||
return newUpdate(data, op, path, idx+1, value)
|
||||
}
|
||||
|
||||
return nil, notFoundError(path)
|
||||
return nil, errors.NewNotFoundError(path)
|
||||
}
|
||||
func (u *update) Apply(data interface{}) interface{} {
|
||||
if len(u.path) == 0 {
|
||||
return u.value
|
||||
}
|
||||
parent, err := ptr(data, u.path[:len(u.path)-1])
|
||||
parent, err := ptr.Ptr(data, u.path[:len(u.path)-1])
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
@@ -371,6 +375,9 @@ func (u *update) Apply(data interface{}) interface{} {
|
||||
}
|
||||
switch parent := parent.(type) {
|
||||
case map[string]interface{}:
|
||||
if parent == nil {
|
||||
parent = make(map[string]interface{}, 1)
|
||||
}
|
||||
parent[key] = u.value
|
||||
case []interface{}:
|
||||
idx, err := strconv.Atoi(key)
|
||||
@@ -387,58 +394,3 @@ func (u *update) Relative(path storage.Path) *update {
|
||||
cpy.path = cpy.path[len(path):]
|
||||
return &cpy
|
||||
}
|
||||
|
||||
func deepCopy(val interface{}) interface{} {
|
||||
switch val := val.(type) {
|
||||
case []interface{}:
|
||||
cpy := make([]interface{}, len(val))
|
||||
for i := range cpy {
|
||||
cpy[i] = deepCopy(val[i])
|
||||
}
|
||||
return cpy
|
||||
case map[string]interface{}:
|
||||
cpy := make(map[string]interface{}, len(val))
|
||||
for k := range val {
|
||||
cpy[k] = deepCopy(val[k])
|
||||
}
|
||||
return cpy
|
||||
default:
|
||||
return val
|
||||
}
|
||||
}
|
||||
|
||||
func ptr(data interface{}, path storage.Path) (interface{}, error) {
|
||||
|
||||
node := data
|
||||
for i := range path {
|
||||
key := path[i]
|
||||
switch curr := node.(type) {
|
||||
case map[string]interface{}:
|
||||
var ok bool
|
||||
if node, ok = curr[key]; !ok {
|
||||
return nil, notFoundError(path)
|
||||
}
|
||||
case []interface{}:
|
||||
pos, err := validateArrayIndex(curr, key, path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
node = curr[pos]
|
||||
default:
|
||||
return nil, notFoundError(path)
|
||||
}
|
||||
}
|
||||
|
||||
return node, nil
|
||||
}
|
||||
|
||||
func validateArrayIndex(arr []interface{}, s string, path storage.Path) (int, error) {
|
||||
idx, err := strconv.Atoi(s)
|
||||
if err != nil {
|
||||
return 0, notFoundErrorHint(path, arrayIndexTypeMsg)
|
||||
}
|
||||
if idx < 0 || idx >= len(arr) {
|
||||
return 0, notFoundErrorHint(path, outOfRangeMsg)
|
||||
}
|
||||
return idx, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user