Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -454,6 +454,9 @@ the WebAssembly plugin is required, then the NRI provides a host function helper
[`Log`](https://github.com/containerd/nri/blob/8ebdb076ea6aa524094a7f1c2c9ca31c30852328/plugins/wasm/plugin.go#L31-L36)
for that.

WebAssembly support is enabled by default. It can be disabled at compile
time using the `nri_no_wasm` build tag.

## Security Considerations

From a security perspective NRI plugins should be considered part of the
Expand Down
26 changes: 8 additions & 18 deletions pkg/adaptation/adaptation.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,6 @@ import (
"github.com/containerd/nri/pkg/log"
validator "github.com/containerd/nri/plugins/default-validator/builtin"
"github.com/containerd/ttrpc"
"github.com/tetratelabs/wazero"
"github.com/tetratelabs/wazero/imports/wasi_snapshot_preview1"

"google.golang.org/protobuf/proto"
)
Expand Down Expand Up @@ -80,6 +78,9 @@ type Adaptation struct {
var (
// Used instead of nil Context in logging.
noCtx = context.TODO()

// ErrWasmDisabled is returned for WASM initialization if WASM support is disabled.
ErrWasmDisabled = errors.New("WASM support is disabled (at build time)")
)

// Option to apply to the NRI runtime.
Expand Down Expand Up @@ -155,23 +156,12 @@ func New(name, version string, syncFn SyncFn, updateFn UpdateFn, opts ...Option)
return nil, fmt.Errorf("failed to create NRI adaptation, nil UpdateFn")
}

wasmWithCloseOnContextDone := func(ctx context.Context) (wazero.Runtime, error) {
var (
cfg = wazero.NewRuntimeConfig().WithCloseOnContextDone(true)
r = wazero.NewRuntimeWithConfig(ctx, cfg)
)
if _, err := wasi_snapshot_preview1.Instantiate(ctx, r); err != nil {
wasmService, err := getWasmService()
if err != nil {
log.Errorf(noCtx, "failed to initialize WASM support: %v", err)
if !errors.Is(err, ErrWasmDisabled) {
return nil, err
}
return r, nil
}

wasmPlugins, err := api.NewPluginPlugin(
context.Background(),
api.WazeroRuntime(wasmWithCloseOnContextDone),
)
if err != nil {
return nil, fmt.Errorf("unable to initialize WASM service: %w", err)
}

r := &Adaptation{
Expand All @@ -183,7 +173,7 @@ func New(name, version string, syncFn SyncFn, updateFn UpdateFn, opts ...Option)
dropinPath: DefaultPluginConfigPath,
socketPath: DefaultSocketPath,
syncLock: sync.RWMutex{},
wasmService: wasmPlugins,
wasmService: wasmService,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was originally considering if this could be a functional option (WithWASMService); that could potentially allow the caller to either pass, or not pass the option.

Compile-time could still be an option for that if a stub WithWASMService was created (that would either return an error, or nil).

}

for _, o := range opts {
Expand Down
4 changes: 4 additions & 0 deletions pkg/adaptation/plugin.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,10 @@ func (r *Adaptation) newLaunchedPlugin(dir, idx, base, cfg string) (p *plugin, r
fullPath := filepath.Join(dir, name)

if isWasm(fullPath) {
if r.wasmService == nil {
return nil, fmt.Errorf("can't load WASM plugin %s: no WASM support", fullPath)
}

log.Infof(noCtx, "Found WASM plugin: %s", fullPath)
wasm, err := r.wasmService.Load(context.Background(), fullPath, wasmHostFunctions{})
if err != nil {
Expand Down
27 changes: 27 additions & 0 deletions pkg/adaptation/wasm-disabled.go
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think using underscores instead of hyphens is more common in Go; perhaps adaptation_wasm.go and adaptation_nowasm.go could work?

Copy link
Member Author

@klihub klihub Dec 11, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that calling it adaptation_wasm.go would not work. It would break the builds, because wasm is a valid GOARCH, so it would be excluded from x86_64 and arm builds.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh! good call, forgot that wasm was a builtin... 😢

Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
//go:build nri_no_wasm

/*
Copyright The containerd Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package adaptation

import (
"github.com/containerd/nri/pkg/api"
)

func getWasmService() (*api.PluginPlugin, error) {
return nil, ErrWasmDisabled
}
51 changes: 51 additions & 0 deletions pkg/adaptation/wasm-enabled.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
//go:build !nri_no_wasm

/*
Copyright The containerd Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package adaptation

import (
"context"
"fmt"

"github.com/containerd/nri/pkg/api"
"github.com/tetratelabs/wazero"
"github.com/tetratelabs/wazero/imports/wasi_snapshot_preview1"
)

func getWasmService() (*api.PluginPlugin, error) {
wasmWithCloseOnContextDone := func(ctx context.Context) (wazero.Runtime, error) {
var (
cfg = wazero.NewRuntimeConfig().WithCloseOnContextDone(true)
r = wazero.NewRuntimeWithConfig(ctx, cfg)
)
if _, err := wasi_snapshot_preview1.Instantiate(ctx, r); err != nil {
return nil, err
}
return r, nil
}

wasmPlugins, err := api.NewPluginPlugin(
context.Background(),
api.WazeroRuntime(wasmWithCloseOnContextDone),
)
if err != nil {
return nil, fmt.Errorf("unable to initialize WASM service: %w", err)
}

return wasmPlugins, nil
}
Loading