Configure containerd config based on specified annotation prefixes

Signed-off-by: Evan Lezar <elezar@nvidia.com>
This commit is contained in:
Evan Lezar 2023-03-23 21:12:23 +02:00
parent ee141f97dc
commit 149236b002
7 changed files with 81 additions and 17 deletions

View File

@ -50,12 +50,15 @@ func (c *ConfigV1) AddRuntime(name string, path string, setAsDefault bool) error
config.SetPath([]string{"plugins", "cri", "containerd", "runtimes", name, "runtime_engine"}, "") config.SetPath([]string{"plugins", "cri", "containerd", "runtimes", name, "runtime_engine"}, "")
config.SetPath([]string{"plugins", "cri", "containerd", "runtimes", name, "privileged_without_host_devices"}, false) config.SetPath([]string{"plugins", "cri", "containerd", "runtimes", name, "privileged_without_host_devices"}, false)
} }
cdiAnnotations := []interface{}{"cdi.k8s.io/*"}
containerAnnotations, ok := config.GetPath([]string{"plugins", "cri", "containerd", "runtimes", name, "container_annotations"}).([]interface{}) if len(c.ContainerAnnotations) > 0 {
if ok && containerAnnotations != nil { annotations, err := (*Config)(c).getRuntimeAnnotations([]string{"plugins", "cri", "containerd", "runtimes", name, "container_annotations"})
cdiAnnotations = append(containerAnnotations, cdiAnnotations...) if err != nil {
return err
}
annotations = append(c.ContainerAnnotations, annotations...)
config.SetPath([]string{"plugins", "cri", "containerd", "runtimes", name, "container_annotations"}, annotations)
} }
config.SetPath([]string{"plugins", "cri", "containerd", "runtimes", name, "container_annotations"}, cdiAnnotations)
config.SetPath([]string{"plugins", "cri", "containerd", "runtimes", name, "options", "BinaryName"}, path) config.SetPath([]string{"plugins", "cri", "containerd", "runtimes", name, "options", "BinaryName"}, path)
config.SetPath([]string{"plugins", "cri", "containerd", "runtimes", name, "options", "Runtime"}, path) config.SetPath([]string{"plugins", "cri", "containerd", "runtimes", name, "options", "Runtime"}, path)

View File

@ -45,12 +45,14 @@ func (c *Config) AddRuntime(name string, path string, setAsDefault bool) error {
config.SetPath([]string{"plugins", "io.containerd.grpc.v1.cri", "containerd", "runtimes", name, "privileged_without_host_devices"}, false) config.SetPath([]string{"plugins", "io.containerd.grpc.v1.cri", "containerd", "runtimes", name, "privileged_without_host_devices"}, false)
} }
cdiAnnotations := []interface{}{"cdi.k8s.io/*"} if len(c.ContainerAnnotations) > 0 {
containerAnnotations, ok := config.GetPath([]string{"plugins", "io.containerd.grpc.v1.cri", "containerd", "runtimes", name, "container_annotations"}).([]interface{}) annotations, err := c.getRuntimeAnnotations([]string{"plugins", "io.containerd.grpc.v1.cri", "containerd", "runtimes", name, "container_annotations"})
if ok && containerAnnotations != nil { if err != nil {
cdiAnnotations = append(containerAnnotations, cdiAnnotations...) return err
}
annotations = append(c.ContainerAnnotations, annotations...)
config.SetPath([]string{"plugins", "io.containerd.grpc.v1.cri", "containerd", "runtimes", name, "container_annotations"}, annotations)
} }
config.SetPath([]string{"plugins", "io.containerd.grpc.v1.cri", "containerd", "runtimes", name, "container_annotations"}, cdiAnnotations)
config.SetPath([]string{"plugins", "io.containerd.grpc.v1.cri", "containerd", "runtimes", name, "options", "BinaryName"}, path) config.SetPath([]string{"plugins", "io.containerd.grpc.v1.cri", "containerd", "runtimes", name, "options", "BinaryName"}, path)
@ -62,6 +64,32 @@ func (c *Config) AddRuntime(name string, path string, setAsDefault bool) error {
return nil return nil
} }
func (c *Config) getRuntimeAnnotations(path []string) ([]string, error) {
if c == nil || c.Tree == nil {
return nil, nil
}
config := *c.Tree
if !config.HasPath(path) {
return nil, nil
}
annotationsI, ok := config.GetPath(path).([]interface{})
if !ok {
return nil, fmt.Errorf("invalid annotations: %v", annotationsI)
}
var annotations []string
for _, annotation := range annotationsI {
a, ok := annotation.(string)
if !ok {
return nil, fmt.Errorf("invalid annotation: %v", annotation)
}
annotations = append(annotations, a)
}
return annotations, nil
}
// DefaultRuntime returns the default runtime for the cri-o config // DefaultRuntime returns the default runtime for the cri-o config
func (c Config) DefaultRuntime() string { func (c Config) DefaultRuntime() string {
if runtime, ok := c.GetPath([]string{"plugins", "io.containerd.grpc.v1.cri", "containerd", "default_runtime_name"}).(string); ok { if runtime, ok := c.GetPath([]string{"plugins", "io.containerd.grpc.v1.cri", "containerd", "default_runtime_name"}).(string); ok {

View File

@ -26,6 +26,7 @@ type Config struct {
*toml.Tree *toml.Tree
RuntimeType string RuntimeType string
UseDefaultRuntimeName bool UseDefaultRuntimeName bool
ContainerAnnotations []string
} }
// New creates a containerd config with the specified options // New creates a containerd config with the specified options

View File

@ -33,6 +33,7 @@ type builder struct {
path string path string
runtimeType string runtimeType string
useLegacyConfig bool useLegacyConfig bool
containerAnnotations []string
} }
// Option defines a function that can be used to configure the config builder // Option defines a function that can be used to configure the config builder
@ -59,6 +60,13 @@ func WithUseLegacyConfig(useLegacyConfig bool) Option {
} }
} }
// WithContainerAnnotations sets the container annotations for the config builder
func WithContainerAnnotations(containerAnnotations ...string) Option {
return func(b *builder) {
b.containerAnnotations = containerAnnotations
}
}
func (b *builder) build() (engine.Interface, error) { func (b *builder) build() (engine.Interface, error) {
if b.path == "" { if b.path == "" {
return nil, fmt.Errorf("config path is empty") return nil, fmt.Errorf("config path is empty")
@ -74,6 +82,7 @@ func (b *builder) build() (engine.Interface, error) {
} }
config.RuntimeType = b.runtimeType config.RuntimeType = b.runtimeType
config.UseDefaultRuntimeName = !b.useLegacyConfig config.UseDefaultRuntimeName = !b.useLegacyConfig
config.ContainerAnnotations = b.containerAnnotations
version, err := config.parseVersion(b.useLegacyConfig) version, err := config.parseVersion(b.useLegacyConfig)
if err != nil { if err != nil {

View File

@ -332,6 +332,7 @@ func TestUpdateV1Config(t *testing.T) {
Tree: config, Tree: config,
UseDefaultRuntimeName: true, UseDefaultRuntimeName: true,
RuntimeType: runtimeType, RuntimeType: runtimeType,
ContainerAnnotations: []string{"cdi.k8s.io/*"},
} }
err = UpdateConfig(v1, o) err = UpdateConfig(v1, o)
@ -585,6 +586,7 @@ func TestUpdateV1ConfigWithRuncPresent(t *testing.T) {
Tree: config, Tree: config,
UseDefaultRuntimeName: true, UseDefaultRuntimeName: true,
RuntimeType: runtimeType, RuntimeType: runtimeType,
ContainerAnnotations: []string{"cdi.k8s.io/*"},
} }
err = UpdateConfig(v1, o) err = UpdateConfig(v1, o)

View File

@ -281,6 +281,7 @@ func TestUpdateV2Config(t *testing.T) {
v2 := &containerd.Config{ v2 := &containerd.Config{
Tree: config, Tree: config,
RuntimeType: runtimeType, RuntimeType: runtimeType,
ContainerAnnotations: []string{"cdi.k8s.io/*"},
} }
err = UpdateConfig(v2, o) err = UpdateConfig(v2, o)
@ -522,6 +523,7 @@ func TestUpdateV2ConfigWithRuncPresent(t *testing.T) {
v2 := &containerd.Config{ v2 := &containerd.Config{
Tree: config, Tree: config,
RuntimeType: runtimeType, RuntimeType: runtimeType,
ContainerAnnotations: []string{"cdi.k8s.io/*"},
} }
err = UpdateConfig(v2, o) err = UpdateConfig(v2, o)

View File

@ -72,6 +72,8 @@ type options struct {
hostRootMount string hostRootMount string
runtimeDir string runtimeDir string
useLegacyConfig bool useLegacyConfig bool
ContainerRuntimeModesCDIAnnotationPrefixes cli.StringSlice
} }
func main() { func main() {
@ -173,6 +175,11 @@ func main() {
Destination: &options.useLegacyConfig, Destination: &options.useLegacyConfig,
EnvVars: []string{"CONTAINERD_USE_LEGACY_CONFIG"}, EnvVars: []string{"CONTAINERD_USE_LEGACY_CONFIG"},
}, },
&cli.StringSliceFlag{
Name: "nvidia-container-runtime-modes.cdi.annotation-prefixes",
Destination: &options.ContainerRuntimeModesCDIAnnotationPrefixes,
EnvVars: []string{"NVIDIA_CONTAINER_RUNTIME_MODES_CDI_ANNOTATION_PREFIXES"},
},
} }
// Update the subcommand flags with the common subcommand flags // Update the subcommand flags with the common subcommand flags
@ -199,6 +206,7 @@ func Setup(c *cli.Context, o *options) error {
containerd.WithPath(o.config), containerd.WithPath(o.config),
containerd.WithRuntimeType(o.runtimeType), containerd.WithRuntimeType(o.runtimeType),
containerd.WithUseLegacyConfig(o.useLegacyConfig), containerd.WithUseLegacyConfig(o.useLegacyConfig),
containerd.WithContainerAnnotations(o.containerAnnotationsFromCDIPrefixes()...),
) )
if err != nil { if err != nil {
return fmt.Errorf("unable to load config: %v", err) return fmt.Errorf("unable to load config: %v", err)
@ -241,6 +249,7 @@ func Cleanup(c *cli.Context, o *options) error {
containerd.WithPath(o.config), containerd.WithPath(o.config),
containerd.WithRuntimeType(o.runtimeType), containerd.WithRuntimeType(o.runtimeType),
containerd.WithUseLegacyConfig(o.useLegacyConfig), containerd.WithUseLegacyConfig(o.useLegacyConfig),
containerd.WithContainerAnnotations(o.containerAnnotationsFromCDIPrefixes()...),
) )
if err != nil { if err != nil {
return fmt.Errorf("unable to load config: %v", err) return fmt.Errorf("unable to load config: %v", err)
@ -434,3 +443,13 @@ func RestartContainerdSystemd(hostRootMount string) error {
return nil return nil
} }
// containerAnnotationsFromCDIPrefixes returns the container annotations to set for the given CDI prefixes.
func (o *options) containerAnnotationsFromCDIPrefixes() []string {
var annotations []string
for _, prefix := range o.ContainerRuntimeModesCDIAnnotationPrefixes.Value() {
annotations = append(annotations, prefix+"*")
}
return annotations
}