// 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" "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 }