/
utils.go
145 lines (126 loc) · 4.39 KB
/
utils.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
// Copyright 2020 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 bundle
import (
"context"
"fmt"
"io"
"os"
"path/filepath"
"github.com/open-policy-agent/opa/ast"
"github.com/open-policy-agent/opa/bundle"
"github.com/open-policy-agent/opa/resolver/wasm"
"github.com/open-policy-agent/opa/storage"
)
// LoadWasmResolversFromStore will lookup all Wasm modules from the store along with the
// associated bundle manifest configuration and instantiate the respective resolvers.
func LoadWasmResolversFromStore(ctx context.Context, store storage.Store, txn storage.Transaction, otherBundles map[string]*bundle.Bundle) ([]*wasm.Resolver, error) {
bundleNames, err := bundle.ReadBundleNamesFromStore(ctx, store, txn)
if err != nil && !storage.IsNotFound(err) {
return nil, err
}
var resolversToLoad []*bundle.WasmModuleFile
for _, bundleName := range bundleNames {
var wasmResolverConfigs []bundle.WasmResolver
rawModules := map[string][]byte{}
// Save round-tripping the bundle that was just activated
if _, ok := otherBundles[bundleName]; ok {
wasmResolverConfigs = otherBundles[bundleName].Manifest.WasmResolvers
for _, wmf := range otherBundles[bundleName].WasmModules {
rawModules[wmf.Path] = wmf.Raw
}
} else {
wasmResolverConfigs, err = bundle.ReadWasmMetadataFromStore(ctx, store, txn, bundleName)
if err != nil && !storage.IsNotFound(err) {
return nil, fmt.Errorf("failed to read wasm module manifest from store: %s", err)
}
rawModules, err = bundle.ReadWasmModulesFromStore(ctx, store, txn, bundleName)
if err != nil && !storage.IsNotFound(err) {
return nil, fmt.Errorf("failed to read wasm modules from store: %s", err)
}
}
for path, raw := range rawModules {
wmf := &bundle.WasmModuleFile{
URL: path,
Path: path,
Raw: raw,
}
for _, resolverConf := range wasmResolverConfigs {
if resolverConf.Module == path {
ref, err := ast.PtrRef(ast.DefaultRootDocument, resolverConf.Entrypoint)
if err != nil {
return nil, fmt.Errorf("failed to parse wasm module entrypoint '%s': %s", resolverConf.Entrypoint, err)
}
wmf.Entrypoints = append(wmf.Entrypoints, ref)
}
}
if len(wmf.Entrypoints) > 0 {
resolversToLoad = append(resolversToLoad, wmf)
}
}
}
var resolvers []*wasm.Resolver
if len(resolversToLoad) > 0 {
// Get a full snapshot of the current data (including any from "outside" the bundles)
data, err := store.Read(ctx, txn, storage.Path{})
if err != nil {
return nil, fmt.Errorf("failed to initialize wasm runtime: %s", err)
}
for _, wmf := range resolversToLoad {
resolver, err := wasm.New(wmf.Entrypoints, wmf.Raw, data)
if err != nil {
return nil, fmt.Errorf("failed to initialize wasm module for entrypoints '%s': %s", wmf.Entrypoints, err)
}
resolvers = append(resolvers, resolver)
}
}
return resolvers, nil
}
// LoadBundleFromDisk loads a previously persisted activated bundle from disk
func LoadBundleFromDisk(path, name string, bvc *bundle.VerificationConfig) (*bundle.Bundle, error) {
return LoadBundleFromDiskForRegoVersion(ast.RegoV0, path, name, bvc)
}
func LoadBundleFromDiskForRegoVersion(regoVersion ast.RegoVersion, path, name string, bvc *bundle.VerificationConfig) (*bundle.Bundle, error) {
bundlePath := filepath.Join(path, name, "bundle.tar.gz")
if _, err := os.Stat(bundlePath); err == nil {
f, err := os.Open(filepath.Join(bundlePath))
if err != nil {
return nil, err
}
defer f.Close()
r := bundle.NewCustomReader(bundle.NewTarballLoaderWithBaseURL(f, "")).
WithRegoVersion(regoVersion)
if bvc != nil {
r = r.WithBundleVerificationConfig(bvc)
}
b, err := r.Read()
if err != nil {
return nil, err
}
return &b, nil
} else if os.IsNotExist(err) {
return nil, nil
} else {
return nil, err
}
}
// SaveBundleToDisk saves the given raw bytes representing the bundle's content to disk
func SaveBundleToDisk(path string, raw io.Reader) (string, error) {
if _, err := os.Stat(path); os.IsNotExist(err) {
err = os.MkdirAll(path, os.ModePerm)
if err != nil {
return "", err
}
}
if raw == nil {
return "", fmt.Errorf("no raw bundle bytes to persist to disk")
}
dest, err := os.CreateTemp(path, ".bundle.tar.gz.*.tmp")
if err != nil {
return "", err
}
defer dest.Close()
_, err = io.Copy(dest, raw)
return dest.Name(), err
}