Skip to content
Draft
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
47 changes: 28 additions & 19 deletions pkg/adaptation/adaptation.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,25 +58,26 @@ type UpdateFn func(context.Context, []*ContainerUpdate) ([]*ContainerUpdate, err
// Adaptation is the NRI abstraction for container runtime NRI adaptation/integration.
type Adaptation struct {
sync.Mutex
name string
version string
nriVersion string
dropinPath string
pluginPath string
socketPath string
dontListen bool
syncFn SyncFn
updateFn UpdateFn
clientOpts []ttrpc.ClientOpts
serverOpts []ttrpc.ServerOpt
listener net.Listener
plugins []*plugin
validators []*plugin
builtin []*builtin.BuiltinPlugin
syncLock sync.RWMutex
wasmService *api.PluginPlugin
metrics Metrics
deprecation DeprecationRecorder
name string
version string
nriVersion string
dropinPath string
pluginPath string
socketPath string
dontListen bool
syncFn SyncFn
updateFn UpdateFn
clientOpts []ttrpc.ClientOpts
serverOpts []ttrpc.ServerOpt
listener net.Listener
plugins []*plugin
validators []*plugin
builtin []*builtin.BuiltinPlugin
syncLock sync.RWMutex
wasmService *api.PluginPlugin
metrics Metrics
deprecation DeprecationRecorder
capabilities CapabilityMask
}

var (
Expand Down Expand Up @@ -168,6 +169,14 @@ func WithDeprecationRecorder(d DeprecationRecorder) Option {
}
}

// WithSupportedCapabilities sets up the supported capabilities reported to plugins.
func WithSupportedCapabilities(capabilities CapabilityMask) Option {
return func(r *Adaptation) error {
r.capabilities = capabilities.Clone()
return nil
}
}

// New creates a new NRI Runtime.
func New(name, version string, syncFn SyncFn, updateFn UpdateFn, opts ...Option) (*Adaptation, error) {
var err error
Expand Down
134 changes: 134 additions & 0 deletions pkg/adaptation/adaptation_suite_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ import (
nri "github.com/containerd/nri/pkg/adaptation"
"github.com/containerd/nri/pkg/api"
"github.com/containerd/nri/pkg/plugin"
"github.com/containerd/nri/pkg/stub"
validator "github.com/containerd/nri/plugins/default-validator/builtin"
)

Expand Down Expand Up @@ -3385,6 +3386,139 @@ var _ = Describe("NRI version exchange", func() {

})

var _ = Describe("Advertised NRI capabilities", func() {
var (
s = &Suite{}
)

AfterEach(func() {
s.Cleanup()
})

BeforeEach(func() {
s.Prepare(&mockRuntime{})
})

It("should be passed to plugins", func() {
var (
runtimeName = "test-runtime"
runtimeVersion = "1.2.3"
supportedCapabilities = []api.Capability{
api.Capability_ADJUST_POSIX_RLIMITS,
api.Capability_INPUT_POSIX_RLIMITS,
api.Capability_ADJUST_LINUX_IO_PRIORITY,
api.Capability_INPUT_LINUX_IO_PRIORITY,
api.Capability_INPUT_IP_ADDRESSES,
api.Capability_ADJUST_LINUX_CONTAINER_ARGS,
}
)

s.runtime.name = runtimeName
s.runtime.version = runtimeVersion
s.runtime.options = append(s.runtime.options,
nri.WithSupportedCapabilities(
api.NewCapabilityMask(supportedCapabilities...),
),
)

s.Startup()
s.StartPlugins(&mockPlugin{idx: "00", name: "test"})
s.WaitForPluginsToSync(s.plugin("00-test"))

Expect(s.plugins[0].RuntimeName()).To(Equal(runtimeName))
Expect(s.plugins[0].RuntimeVersion()).To(Equal(runtimeVersion))
Expect(s.plugins[0].RuntimeCapabilities()).To(Equal(
api.NewCapabilityMask(supportedCapabilities...),
))
})

It("should allow startup of plugins with satisfied capability requirements", func() {
var (
runtimeName = "test-runtime"
runtimeVersion = "1.2.3"
supportedCapabilities = []api.Capability{
api.Capability_ADJUST_POSIX_RLIMITS,
api.Capability_INPUT_POSIX_RLIMITS,
api.Capability_ADJUST_LINUX_IO_PRIORITY,
api.Capability_INPUT_LINUX_IO_PRIORITY,
api.Capability_INPUT_IP_ADDRESSES,
api.Capability_ADJUST_LINUX_CONTAINER_ARGS,
}
subsetCapabilities = []api.Capability{
api.Capability_INPUT_POSIX_RLIMITS,
api.Capability_INPUT_IP_ADDRESSES,
api.Capability_ADJUST_LINUX_CONTAINER_ARGS,
}
plugins = []*mockPlugin{
{
idx: "00",
name: "test",
options: []stub.Option{
stub.WithRequiredRuntimeCapabilities(supportedCapabilities...),
},
},
{
idx: "01",
name: "test",
options: []stub.Option{
stub.WithRequiredRuntimeCapabilities(subsetCapabilities...),
},
},
}
)

s.runtime.name = runtimeName
s.runtime.version = runtimeVersion
s.runtime.options = append(s.runtime.options,
nri.WithSupportedCapabilities(
api.NewCapabilityMask(supportedCapabilities...),
),
)

s.Startup()
s.StartPlugins(plugins...)
s.WaitForPluginsToSync(plugins[0], plugins[1])
})

It("should prevent startup of plugins with unsatisfied capability requirements", func() {
var (
runtimeName = "test-runtime"
runtimeVersion = "1.2.3"
supportedCapabilities = []api.Capability{
api.Capability_ADJUST_POSIX_RLIMITS,
api.Capability_INPUT_POSIX_RLIMITS,
api.Capability_ADJUST_LINUX_IO_PRIORITY,
api.Capability_INPUT_LINUX_IO_PRIORITY,
api.Capability_INPUT_IP_ADDRESSES,
api.Capability_ADJUST_LINUX_CONTAINER_ARGS,
}
requiredCapabilities = []api.Capability{
api.Capability_ADJUST_LINUX_SCHEDULING_POLICY,
}
plugin = &mockPlugin{
idx: "00",
name: "test",
options: []stub.Option{
stub.WithRequiredRuntimeCapabilities(requiredCapabilities...),
},
}
)

s.runtime.name = runtimeName
s.runtime.version = runtimeVersion
s.runtime.options = append(s.runtime.options,
nri.WithSupportedCapabilities(
api.NewCapabilityMask(supportedCapabilities...),
),
)

s.Startup()
err := plugin.Start(s.dir)
Expect(err).ToNot(BeNil())
Expect(strings.Contains(err.Error(), "lacks required capabilities")).To(BeTrue())
})
})

func protoDiff(a, b proto.Message) string {
return cmp.Diff(a, b, protocmp.Transform())
}
Expand Down
5 changes: 3 additions & 2 deletions pkg/adaptation/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,8 +109,9 @@ type (
SecurityProfile = api.SecurityProfile
User = api.User

Event = api.Event
EventMask = api.EventMask
Event = api.Event
EventMask = api.EventMask
CapabilityMask = api.CapabilityMask
)

// Aliased consts for api/api.proto.
Expand Down
1 change: 1 addition & 0 deletions pkg/adaptation/plugin.go
Original file line number Diff line number Diff line change
Expand Up @@ -480,6 +480,7 @@ func (p *plugin) configure(ctx context.Context, name, version, config string) (e
RegistrationTimeout: getPluginRegistrationTimeout().Milliseconds(),
RequestTimeout: getPluginRequestTimeout().Milliseconds(),
NRIVersion: p.r.nriVersion,
Capabilities: p.r.capabilities,
}

rpl, err := p.impl.Configure(ctx, req)
Expand Down
7 changes: 7 additions & 0 deletions pkg/adaptation/suite_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -564,6 +564,13 @@ func (m *mockPlugin) RuntimeNRIVersion() string {
return m.stub.RuntimeNRIVersion()
}

func (m *mockPlugin) RuntimeCapabilities() api.CapabilityMask {
if m.stub == nil {
return api.NewCapabilityMask()
}
return m.stub.RuntimeCapabilities()
}

func (m *mockPlugin) onClose() {
if m.stub != nil {
m.stub.Stop()
Expand Down
Loading
Loading