pkg/nri: update NRI configuration.

Update NRI plugin configuration to match that of NRI. Remove
option for the eliminated NRI configuration file. Add option
to disable connections from externally launched plugins. Add
options to override default plugin registration and request
timeouts.

Signed-off-by: Krisztian Litkey <krisztian.litkey@intel.com>
This commit is contained in:
Krisztian Litkey 2023-02-06 20:05:59 +02:00
parent a18709442b
commit 310be5ce6e
14 changed files with 224 additions and 170 deletions

2
go.mod
View File

@ -17,7 +17,7 @@ require (
github.com/containerd/go-cni v1.1.9-0.20230211172349-6603d5bd8941
github.com/containerd/go-runc v1.0.0
github.com/containerd/imgcrypt v1.1.5-0.20220421044638-8ba028dca028
github.com/containerd/nri v0.2.1-0.20230131001841-b3cabdec0657
github.com/containerd/nri v0.3.0
github.com/containerd/ttrpc v1.1.1-0.20230127163717-32fab2374638
github.com/containerd/typeurl/v2 v2.1.0
github.com/containerd/zfs v1.0.0

4
go.sum
View File

@ -263,8 +263,8 @@ github.com/containerd/imgcrypt v1.1.5-0.20220421044638-8ba028dca028/go.mod h1:Lo
github.com/containerd/nri v0.0.0-20201007170849-eb1350a75164/go.mod h1:+2wGSDGFYfE5+So4M5syatU0N0f0LbWpuqyMi4/BE8c=
github.com/containerd/nri v0.0.0-20210316161719-dbaa18c31c14/go.mod h1:lmxnXF6oMkbqs39FiCt1s0R2HSMhcLel9vNL3m4AaeY=
github.com/containerd/nri v0.1.0/go.mod h1:lmxnXF6oMkbqs39FiCt1s0R2HSMhcLel9vNL3m4AaeY=
github.com/containerd/nri v0.2.1-0.20230131001841-b3cabdec0657 h1:mUUkDOlFTZXCQupsMlHbQflPVxbj1sT6YOSz/hvT4wE=
github.com/containerd/nri v0.2.1-0.20230131001841-b3cabdec0657/go.mod h1:Q2u9Sudol4IkJ6YK0gShznKMxM6Un0Y3O4Wslf5Nerg=
github.com/containerd/nri v0.3.0 h1:2ZM4WImye1ypSnE7COjOvPAiLv84kaPILBDvb1tbDK8=
github.com/containerd/nri v0.3.0/go.mod h1:Zw9q2lP16sdg0zYybemZ9yTDy8g7fPCIB3KXOGlggXI=
github.com/containerd/stargz-snapshotter/estargz v0.4.1/go.mod h1:x7Q9dg9QYb4+ELgxmo4gBUeJB0tl5dqH1Sdz0nJU1QM=
github.com/containerd/ttrpc v0.0.0-20190828154514-0e0f228740de/go.mod h1:PvCDdDGpgqzQIzDW1TphrGLssLDZp2GuS+X5DkEJB8o=
github.com/containerd/ttrpc v0.0.0-20190828172938-92c8520ef9f8/go.mod h1:PvCDdDGpgqzQIzDW1TphrGLssLDZp2GuS+X5DkEJB8o=

View File

@ -520,7 +520,7 @@ github.com/containerd/go-runc v0.0.0-20201020171139-16b287bc67d0/go.mod h1:cNU0Z
github.com/containerd/go-runc v1.0.0 h1:oU+lLv1ULm5taqgV/CJivypVODI4SUz1znWjv3nNYS0=
github.com/containerd/go-runc v1.0.0/go.mod h1:cNU0ZbCgCQVZK4lgG3P+9tn9/PaJNmoDXPpoJhDR+Ok=
github.com/containerd/imgcrypt v1.1.5-0.20220421044638-8ba028dca028/go.mod h1:LorQnPtzL/T0IyCeftcsMEO7AqxUDbdO8j/tSUpgxvo=
github.com/containerd/nri v0.2.1-0.20230131001841-b3cabdec0657/go.mod h1:Q2u9Sudol4IkJ6YK0gShznKMxM6Un0Y3O4Wslf5Nerg=
github.com/containerd/nri v0.3.0/go.mod h1:Zw9q2lP16sdg0zYybemZ9yTDy8g7fPCIB3KXOGlggXI=
github.com/containerd/stargz-snapshotter/estargz v0.4.1/go.mod h1:x7Q9dg9QYb4+ELgxmo4gBUeJB0tl5dqH1Sdz0nJU1QM=
github.com/containerd/stargz-snapshotter/estargz v0.12.1/go.mod h1:12VUuCq3qPq4y8yUW+l5w3+oXV3cx2Po3KSe/SmPGqw=
github.com/containerd/ttrpc v1.0.2/go.mod h1:UAxOpgT9ziI0gJrmKvgcZivgxOp8iFPSk8httJEt98Y=

View File

@ -17,6 +17,8 @@
package nri
import (
"time"
nri "github.com/containerd/nri/pkg/adaptation"
)
@ -24,35 +26,57 @@ import (
type Config struct {
// Disable this NRI plugin and containerd NRI functionality altogether.
Disable bool `toml:"disable" json:"disable"`
// ConfigPath is the path to the NRI configuration file to use.
ConfigPath string `toml:"config_file" json:"configFile"`
// SocketPath is the path to the NRI socket to create for NRI plugins to connect to.
SocketPath string `toml:"socket_path" json:"socketPath"`
// PluginPath is the path to search for NRI plugins to launch on startup.
PluginPath string `toml:"plugin_path" json:"pluginPath"`
// PluginConfigPath is the path to search for plugin-specific configuration.
PluginConfigPath string `toml:"plugin_config_path" json:"pluginConfigPath"`
// PluginRegistrationTimeout is the timeout for plugin registration.
PluginRegistrationTimeout time.Duration `toml:"plugin_registration_timeout" json:"pluginRegistrationTimeout"`
// PluginRequestTimeout is the timeout for a plugin to handle a request.
PluginRequestTimeout time.Duration `toml:"plugin_request_timeout" json:"pluginRequestTimeout"`
// DisableConnections disables connections from externally launched plugins.
DisableConnections bool `toml:"disable_connections" json:"disableConnections"`
}
// DefaultConfig returns the default configuration.
func DefaultConfig() *Config {
return &Config{
Disable: true,
ConfigPath: nri.DefaultConfigPath,
SocketPath: nri.DefaultSocketPath,
PluginPath: nri.DefaultPluginPath,
Disable: true,
SocketPath: nri.DefaultSocketPath,
PluginPath: nri.DefaultPluginPath,
PluginConfigPath: nri.DefaultPluginConfigPath,
PluginRegistrationTimeout: nri.DefaultPluginRegistrationTimeout,
PluginRequestTimeout: nri.DefaultPluginRequestTimeout,
}
}
// toOptions returns NRI options for this configuration.
func (c *Config) toOptions() []nri.Option {
opts := []nri.Option{}
if c.ConfigPath != "" {
opts = append(opts, nri.WithConfigPath(c.ConfigPath))
}
if c.SocketPath != "" {
opts = append(opts, nri.WithSocketPath(c.SocketPath))
}
if c.PluginPath != "" {
opts = append(opts, nri.WithPluginPath(c.PluginPath))
}
if c.PluginConfigPath != "" {
opts = append(opts, nri.WithPluginConfigPath(c.PluginConfigPath))
}
if c.DisableConnections {
opts = append(opts, nri.WithDisabledExternalConnections())
}
return opts
}
// ConfigureTimeouts sets timeout options for NRI.
func (c *Config) ConfigureTimeouts() {
if c.PluginRegistrationTimeout != 0 {
nri.SetPluginRegistrationTimeout(c.PluginRegistrationTimeout)
}
if c.PluginRequestTimeout != 0 {
nri.SetPluginRequestTimeout(c.PluginRequestTimeout)
}
}

View File

@ -123,6 +123,8 @@ func New(cfg *Config) (API, error) {
err error
)
cfg.ConfigureTimeouts()
l.nri, err = nri.New(name, version, syncFn, updateFn, opts...)
if err != nil {
return nil, fmt.Errorf("failed to initialize NRI interface: %w", err)

View File

@ -32,12 +32,12 @@ import (
)
const (
// DefaultConfigPath is the default path to the NRI configuration.
DefaultConfigPath = "/etc/nri/nri.conf"
// DefaultPluginPath is the default path to search for NRI plugins.
DefaultPluginPath = "/opt/nri/plugins"
// DefaultSocketPath is the default socket path for external plugins.
DefaultSocketPath = api.DefaultSocketPath
// PluginConfigDir is the drop-in directory for NRI-launched plugin configuration.
DefaultPluginConfigPath = "/etc/nri/conf.d"
)
// SyncFn is a container runtime function for state synchronization.
@ -54,12 +54,12 @@ type Adaptation struct {
sync.Mutex
name string
version string
configPath string
dropinPath string
pluginPath string
socketPath string
dontListen bool
syncFn SyncFn
updateFn UpdateFn
cfg *Config
listener net.Listener
plugins []*plugin
}
@ -72,23 +72,6 @@ var (
// Option to apply to the NRI runtime.
type Option func(*Adaptation) error
// WithConfigPath returns an option to override the default NRI config path.
func WithConfigPath(path string) Option {
return func(r *Adaptation) error {
r.configPath = path
return nil
}
}
// WithConfig returns an option to provide a pre-parsed NRI configuration.
func WithConfig(cfg *Config) Option {
return func(r *Adaptation) error {
r.cfg = cfg
r.configPath = cfg.path
return nil
}
}
// WithPluginPath returns an option to override the default NRI plugin path.
func WithPluginPath(path string) Option {
return func(r *Adaptation) error {
@ -97,6 +80,14 @@ func WithPluginPath(path string) Option {
}
}
// WithPluginConfigPath returns an option to override the default NRI plugin config path.
func WithPluginConfigPath(path string) Option {
return func(r *Adaptation) error {
r.dropinPath = path
return nil
}
}
// WithSocketPath returns an option to override the default NRI socket path.
func WithSocketPath(path string) Option {
return func(r *Adaptation) error {
@ -105,6 +96,14 @@ func WithSocketPath(path string) Option {
}
}
// WithDisabledExternalConnections returns an options to disable accepting plugin connections.
func WithDisabledExternalConnections() Option {
return func(r *Adaptation) error {
r.dontListen = true
return nil
}
}
// New creates a new NRI Runtime.
func New(name, version string, syncFn SyncFn, updateFn UpdateFn, opts ...Option) (*Adaptation, error) {
var err error
@ -121,8 +120,8 @@ func New(name, version string, syncFn SyncFn, updateFn UpdateFn, opts ...Option)
version: version,
syncFn: syncFn,
updateFn: updateFn,
configPath: DefaultConfigPath,
pluginPath: DefaultPluginPath,
dropinPath: DefaultPluginConfigPath,
socketPath: DefaultSocketPath,
}
@ -132,12 +131,6 @@ func New(name, version string, syncFn SyncFn, updateFn UpdateFn, opts ...Option)
}
}
if r.cfg == nil {
if r.cfg, err = ReadConfig(r.configPath); err != nil {
return nil, err
}
}
log.Infof(noCtx, "runtime interface created")
return r, nil
@ -374,13 +367,13 @@ func (r *Adaptation) removeClosedPlugins() {
}
func (r *Adaptation) startListener() error {
if r.cfg.DisableConnections {
if r.dontListen {
log.Infof(noCtx, "connection from external plugins disabled")
return nil
}
os.Remove(r.socketPath)
if err := os.MkdirAll(filepath.Dir(r.socketPath), 0755); err != nil {
if err := os.MkdirAll(filepath.Dir(r.socketPath), 0700); err != nil {
return fmt.Errorf("failed to create socket %q: %w", r.socketPath, err)
}
@ -481,7 +474,7 @@ func (r *Adaptation) discoverPlugins() ([]string, []string, []string, error) {
r.pluginPath, err)
}
cfg, err := r.cfg.getPluginConfig(idx, base)
cfg, err := r.getPluginConfig(idx, base)
if err != nil {
return nil, nil, nil, fmt.Errorf("failed to discover plugins in %s: %w",
r.pluginPath, err)

View File

@ -1,95 +0,0 @@
/*
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 (
"fmt"
"os"
"path/filepath"
"sigs.k8s.io/yaml"
)
const (
// PluginConfigSubdir is the drop-in directory for plugin configuration.
PluginConfigSubdir = "conf.d"
)
// Config is the runtime configuration for NRI.
type Config struct {
// DisableConnections disables plugin-initiated connections.
DisableConnections bool `json:"disableConnections"`
path string
dropIn string
}
// DefaultConfig returns the default NRI configuration for a given path.
// This configuration should be identical to what ReadConfig would return
// for an empty file at the given location. If the given path is empty,
// DefaultConfigPath is used instead.
func DefaultConfig(path string) *Config {
if path == "" {
path = DefaultConfigPath
}
return &Config{
path: path,
dropIn: filepath.Join(filepath.Dir(path), PluginConfigSubdir),
}
}
// ReadConfig reads the NRI runtime configuration from a file.
func ReadConfig(path string) (*Config, error) {
buf, err := os.ReadFile(path)
if os.IsNotExist(err) {
return nil, err
}
if err != nil {
return nil, fmt.Errorf("failed to read file %q: %w", path, err)
}
cfg := &Config{}
err = yaml.UnmarshalStrict(buf, cfg)
if err != nil {
return nil, fmt.Errorf("failed to parse file %q: %w", path, err)
}
cfg.path = path
cfg.dropIn = filepath.Join(filepath.Dir(path), PluginConfigSubdir)
return cfg, nil
}
func (cfg *Config) getPluginConfig(id, base string) (string, error) {
name := id + "-" + base
dropIns := []string{
filepath.Join(cfg.dropIn, name+".conf"),
filepath.Join(cfg.dropIn, base+".conf"),
}
for _, path := range dropIns {
buf, err := os.ReadFile(path)
if err == nil {
return string(buf), nil
}
if !os.IsNotExist(err) {
return "", fmt.Errorf("failed to read configuration for plugin %q: %w", name, err)
}
}
return "", nil
}

View File

@ -36,8 +36,16 @@ import (
)
const (
pluginRegistrationTimeout = 2 * time.Second
pluginRequestTimeout = 2 * time.Second
// DefaultPluginRegistrationTimeout is the default timeout for plugin registration.
DefaultPluginRegistrationTimeout = 5 * time.Second
// DefaultPluginRequestTimeout is the default timeout for plugins to handle a request.
DefaultPluginRequestTimeout = 2 * time.Second
)
var (
pluginRegistrationTimeout = DefaultPluginRegistrationTimeout
pluginRequestTimeout = DefaultPluginRequestTimeout
timeoutCfgLock sync.RWMutex
)
type plugin struct {
@ -59,6 +67,32 @@ type plugin struct {
r *Adaptation
}
// SetPluginRegistrationTimeout sets the timeout for plugin registration.
func SetPluginRegistrationTimeout(t time.Duration) {
timeoutCfgLock.Lock()
defer timeoutCfgLock.Unlock()
pluginRegistrationTimeout = t
}
func getPluginRegistrationTimeout() time.Duration {
timeoutCfgLock.RLock()
defer timeoutCfgLock.RUnlock()
return pluginRegistrationTimeout
}
// SetPluginRequestTimeout sets the timeout for plugins to handle a request.
func SetPluginRequestTimeout(t time.Duration) {
timeoutCfgLock.Lock()
defer timeoutCfgLock.Unlock()
pluginRequestTimeout = t
}
func getPluginRequestTimeout() time.Duration {
timeoutCfgLock.RLock()
defer timeoutCfgLock.RUnlock()
return pluginRequestTimeout
}
// Launch a pre-installed plugin with a pre-connected socketpair.
func (r *Adaptation) newLaunchedPlugin(dir, idx, base, cfg string) (p *plugin, retErr error) {
name := idx + "-" + base
@ -125,6 +159,27 @@ func (r *Adaptation) newExternalPlugin(conn stdnet.Conn) (p *plugin, retErr erro
return p, nil
}
// Get plugin-specific configuration for an NRI-launched plugin.
func (r *Adaptation) getPluginConfig(id, base string) (string, error) {
name := id + "-" + base
dropIns := []string{
filepath.Join(r.dropinPath, name+".conf"),
filepath.Join(r.dropinPath, base+".conf"),
}
for _, path := range dropIns {
buf, err := os.ReadFile(path)
if err == nil {
return string(buf), nil
}
if !os.IsNotExist(err) {
return "", fmt.Errorf("failed to read configuration for plugin %q: %w", name, err)
}
}
return "", nil
}
// Check if the plugin is external (was not launched by us).
func (p *plugin) isExternal() bool {
return p.cmd == nil
@ -189,7 +244,10 @@ func (p *plugin) connect(conn stdnet.Conn) (retErr error) {
// Start Runtime service, wait for plugin to register, then configure it.
func (p *plugin) start(name, version string) error {
var err error
var (
err error
timeout = getPluginRegistrationTimeout()
)
go func() {
err := p.rpcs.Serve(context.Background(), p.rpcl)
@ -208,7 +266,7 @@ func (p *plugin) start(name, version string) error {
}
case <-p.closeC:
return fmt.Errorf("failed to register plugin, connection closed")
case <-time.After(pluginRegistrationTimeout):
case <-time.After(timeout):
p.close()
p.stop()
return errors.New("plugin registration timed out")
@ -318,7 +376,7 @@ func (p *plugin) UpdateContainers(ctx context.Context, req *UpdateContainersRequ
// configure the plugin and subscribe it for the events it requested.
func (p *plugin) configure(ctx context.Context, name, version, config string) error {
ctx, cancel := context.WithTimeout(ctx, pluginRequestTimeout)
ctx, cancel := context.WithTimeout(ctx, getPluginRequestTimeout())
defer cancel()
rpl, err := p.stub.Configure(ctx, &ConfigureRequest{
@ -347,7 +405,7 @@ func (p *plugin) configure(ctx context.Context, name, version, config string) er
func (p *plugin) synchronize(ctx context.Context, pods []*PodSandbox, containers []*Container) ([]*ContainerUpdate, error) {
log.Infof(ctx, "synchronizing plugin %s", p.name())
ctx, cancel := context.WithTimeout(ctx, pluginRequestTimeout)
ctx, cancel := context.WithTimeout(ctx, getPluginRequestTimeout())
defer cancel()
req := &SynchronizeRequest{
@ -368,7 +426,7 @@ func (p *plugin) createContainer(ctx context.Context, req *CreateContainerReques
return nil, nil
}
ctx, cancel := context.WithTimeout(ctx, pluginRequestTimeout)
ctx, cancel := context.WithTimeout(ctx, getPluginRequestTimeout())
defer cancel()
rpl, err := p.stub.CreateContainer(ctx, req)
@ -391,7 +449,7 @@ func (p *plugin) updateContainer(ctx context.Context, req *UpdateContainerReques
return nil, nil
}
ctx, cancel := context.WithTimeout(ctx, pluginRequestTimeout)
ctx, cancel := context.WithTimeout(ctx, getPluginRequestTimeout())
defer cancel()
rpl, err := p.stub.UpdateContainer(ctx, req)
@ -414,7 +472,7 @@ func (p *plugin) stopContainer(ctx context.Context, req *StopContainerRequest) (
return nil, nil
}
ctx, cancel := context.WithTimeout(ctx, pluginRequestTimeout)
ctx, cancel := context.WithTimeout(ctx, getPluginRequestTimeout())
defer cancel()
rpl, err := p.stub.StopContainer(ctx, req)
@ -437,7 +495,7 @@ func (p *plugin) StateChange(ctx context.Context, evt *StateChangeEvent) error {
return nil
}
ctx, cancel := context.WithTimeout(ctx, pluginRequestTimeout)
ctx, cancel := context.WithTimeout(ctx, getPluginRequestTimeout())
defer cancel()
_, err := p.stub.StateChange(ctx, evt)

View File

@ -316,9 +316,7 @@ func (r *result) adjustMounts(mounts []*Mount, plugin string) error {
}
// finally, apply additions/modifications to plugin container creation request
for _, m := range add {
create.Container.Mounts = append(r.reply.adjust.Mounts, m)
}
create.Container.Mounts = append(create.Container.Mounts, add...)
return nil
}
@ -376,9 +374,7 @@ func (r *result) adjustDevices(devices []*LinuxDevice, plugin string) error {
}
// finally, apply additions/modifications to plugin container creation request
for _, d := range add {
create.Container.Linux.Devices = append(r.reply.adjust.Linux.Devices, d)
}
create.Container.Linux.Devices = append(create.Container.Linux.Devices, add...)
return nil
}

View File

@ -47,7 +47,6 @@ func (m *Mount) ToOCI(propagationQuery *string) rspec.Mount {
Destination: m.Destination,
Type: m.Type,
Source: m.Source,
Options: []string{},
}
for _, opt := range m.Options {
o.Options = append(o.Options, opt)

View File

@ -23,7 +23,7 @@ import (
const (
// DefaultSocketPath is the default socket path for external plugins.
DefaultSocketPath = "/var/run/nri.sock"
DefaultSocketPath = "/var/run/nri/nri.sock"
// PluginSocketEnvVar is used to inform plugins about pre-connected sockets.
PluginSocketEnvVar = "NRI_PLUGIN_SOCKET"
// PluginNameEnvVar is used to inform NRI-launched plugins about their name.

View File

@ -18,6 +18,9 @@ package generate
import (
"fmt"
"os"
"path/filepath"
"sort"
"strings"
rspec "github.com/opencontainers/runtime-spec/specs-go"
@ -212,13 +215,27 @@ func (g *Generator) AdjustResources(r *nri.LinuxResources) error {
g.initConfigLinux()
if r.Cpu != nil {
g.SetLinuxResourcesCPUPeriod(r.Cpu.GetPeriod().GetValue())
g.SetLinuxResourcesCPUQuota(r.Cpu.GetQuota().GetValue())
g.SetLinuxResourcesCPUShares(r.Cpu.GetShares().GetValue())
g.SetLinuxResourcesCPUCpus(r.Cpu.GetCpus())
g.SetLinuxResourcesCPUMems(r.Cpu.GetMems())
g.SetLinuxResourcesCPURealtimeRuntime(r.Cpu.GetRealtimeRuntime().GetValue())
g.SetLinuxResourcesCPURealtimePeriod(r.Cpu.GetRealtimePeriod().GetValue())
if r.Cpu.Period != nil {
g.SetLinuxResourcesCPUPeriod(r.Cpu.GetPeriod().GetValue())
}
if r.Cpu.Quota != nil {
g.SetLinuxResourcesCPUQuota(r.Cpu.GetQuota().GetValue())
}
if r.Cpu.Shares != nil {
g.SetLinuxResourcesCPUShares(r.Cpu.GetShares().GetValue())
}
if r.Cpu.Cpus != "" {
g.SetLinuxResourcesCPUCpus(r.Cpu.GetCpus())
}
if r.Cpu.Mems != "" {
g.SetLinuxResourcesCPUMems(r.Cpu.GetMems())
}
if r.Cpu.RealtimeRuntime != nil {
g.SetLinuxResourcesCPURealtimeRuntime(r.Cpu.GetRealtimeRuntime().GetValue())
}
if r.Cpu.RealtimePeriod != nil {
g.SetLinuxResourcesCPURealtimePeriod(r.Cpu.GetRealtimePeriod().GetValue())
}
}
if r.Memory != nil {
if l := r.Memory.GetLimit().GetValue(); l != 0 {
@ -305,19 +322,20 @@ func (g *Generator) AdjustDevices(devices []*nri.LinuxDevice) {
// AdjustMounts adjusts the mounts in the OCI Spec.
func (g *Generator) AdjustMounts(mounts []*nri.Mount) error {
var (
propagation string
)
if len(mounts) == 0 {
return nil
}
propagation := ""
for _, m := range mounts {
if destination, marked := m.IsMarkedForRemoval(); marked {
g.RemoveMount(destination)
continue
}
g.RemoveMount(m.Destination)
mnt := m.ToOCI(&propagation)
switch propagation {
case "rprivate":
case "rshared":
@ -340,10 +358,60 @@ func (g *Generator) AdjustMounts(mounts []*nri.Mount) error {
}
g.AddMount(mnt)
}
g.sortMounts()
return nil
}
// sortMounts sorts the mounts in the generated OCI Spec.
func (g *Generator) sortMounts() {
mounts := g.Generator.Mounts()
g.Generator.ClearMounts()
sort.Sort(orderedMounts(mounts))
// TODO(klihub): This is now a bit ugly maybe we should introduce a
// SetMounts([]rspec.Mount) to runtime-tools/generate.Generator. That
// could also take care of properly sorting the mount slice.
g.Generator.Config.Mounts = mounts
}
// orderedMounts defines how to sort an OCI Spec Mount slice.
// This is the almost the same implementation sa used by CRI-O and Docker,
// with a minor tweak for stable sorting order (easier to test):
//
// https://github.com/moby/moby/blob/17.05.x/daemon/volumes.go#L26
type orderedMounts []rspec.Mount
// Len returns the number of mounts. Used in sorting.
func (m orderedMounts) Len() int {
return len(m)
}
// Less returns true if the number of parts (a/b/c would be 3 parts) in the
// mount indexed by parameter 1 is less than that of the mount indexed by
// parameter 2. Used in sorting.
func (m orderedMounts) Less(i, j int) bool {
ip, jp := m.parts(i), m.parts(j)
if ip < jp {
return true
}
if jp < ip {
return false
}
return m[i].Destination < m[j].Destination
}
// Swap swaps two items in an array of mounts. Used in sorting
func (m orderedMounts) Swap(i, j int) {
m[i], m[j] = m[j], m[i]
}
// parts returns the number of parts in the destination of a mount. Used in sorting.
func (m orderedMounts) parts(i int) int {
return strings.Count(filepath.Clean(m[i].Destination), string(os.PathSeparator))
}
func nopFilter(m map[string]string) (map[string]string, error) {
return m, nil
}

View File

@ -18,6 +18,7 @@ package stub
import (
"context"
"errors"
"fmt"
stdnet "net"
"os"
@ -160,6 +161,10 @@ var (
// Used instead of a nil Context in logging.
noCtx = context.TODO()
// ErrNoService indicates that the stub has no runtime service/connection,
// for instance by UpdateContainers on a stub which has not been started.
ErrNoService = errors.New("stub: no service/connection")
)
// EventMask holds a mask of events for plugin subscription.
@ -515,6 +520,10 @@ func (stub *stub) connClosed() {
// UpdateContainers requests unsolicited updates to containers.
func (stub *stub) UpdateContainers(update []*api.ContainerUpdate) ([]*api.ContainerUpdate, error) {
if stub.runtime == nil {
return nil, ErrNoService
}
ctx := context.Background()
req := &api.UpdateContainersRequest{
Update: update,

4
vendor/modules.txt vendored
View File

@ -125,8 +125,8 @@ github.com/containerd/go-runc
## explicit; go 1.16
github.com/containerd/imgcrypt
github.com/containerd/imgcrypt/images/encryption
# github.com/containerd/nri v0.2.1-0.20230131001841-b3cabdec0657
## explicit; go 1.18
# github.com/containerd/nri v0.3.0
## explicit; go 1.19
github.com/containerd/nri
github.com/containerd/nri/pkg/adaptation
github.com/containerd/nri/pkg/api