diff --git a/pkg/cri/sbserver/helpers.go b/pkg/cri/sbserver/helpers.go index ca3b4aa71..07491c75e 100644 --- a/pkg/cri/sbserver/helpers.go +++ b/pkg/cri/sbserver/helpers.go @@ -348,6 +348,16 @@ func generateRuntimeOptions(r criconfig.Runtime, c criconfig.Config) (interface{ if err := optionsTree.Unmarshal(options); err != nil { return nil, err } + + // For generic configuration, if no config path specified (preserving old behavior), pass + // the whole TOML configuration section to the runtime. + if runtimeOpts, ok := options.(*runtimeoptions.Options); ok && runtimeOpts.ConfigPath == "" { + runtimeOpts.ConfigBody, err = optionsTree.Marshal() + if err != nil { + return nil, fmt.Errorf("failed to marshal TOML blob for runtime %q: %v", r.Type, err) + } + } + return options, nil } diff --git a/pkg/runtimeoptions/v1/api.pb.go b/pkg/runtimeoptions/v1/api.pb.go index 55b930b20..8a30127be 100644 --- a/pkg/runtimeoptions/v1/api.pb.go +++ b/pkg/runtimeoptions/v1/api.pb.go @@ -32,6 +32,9 @@ type Options struct { // ConfigPath specifies the filesystem location of the config file // used by the runtime. ConfigPath string `protobuf:"bytes,2,opt,name=config_path,json=configPath,proto3" json:"config_path,omitempty"` + // Blob specifies an in-memory TOML blob passed from containerd's configuration section + // for this runtime. This will be used if config_path is not specified. + ConfigBody []byte `protobuf:"bytes,3,opt,name=config_body,json=configBody,proto3" json:"config_body,omitempty"` } func (x *Options) Reset() { @@ -80,6 +83,13 @@ func (x *Options) GetConfigPath() string { return "" } +func (x *Options) GetConfigBody() []byte { + if x != nil { + return x.ConfigBody + } + return nil +} + var File_github_com_containerd_containerd_pkg_runtimeoptions_v1_api_proto protoreflect.FileDescriptor var file_github_com_containerd_containerd_pkg_runtimeoptions_v1_api_proto_rawDesc = []byte{ @@ -88,16 +98,19 @@ var file_github_com_containerd_containerd_pkg_runtimeoptions_v1_api_proto_rawDes 0x72, 0x64, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x76, 0x31, 0x2f, 0x61, 0x70, 0x69, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x11, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x70, 0x74, 0x69, 0x6f, - 0x6e, 0x73, 0x2e, 0x76, 0x31, 0x22, 0x45, 0x0a, 0x07, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, + 0x6e, 0x73, 0x2e, 0x76, 0x31, 0x22, 0x66, 0x0a, 0x07, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x19, 0x0a, 0x08, 0x74, 0x79, 0x70, 0x65, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x74, 0x79, 0x70, 0x65, 0x55, 0x72, 0x6c, 0x12, 0x1f, 0x0a, 0x0b, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x0a, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x50, 0x61, 0x74, 0x68, 0x42, 0x4a, 0x5a, 0x48, - 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x61, - 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, - 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x70, 0x74, 0x69, - 0x6f, 0x6e, 0x73, 0x2f, 0x76, 0x31, 0x3b, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x70, - 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x5f, 0x76, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x52, 0x0a, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x50, 0x61, 0x74, 0x68, 0x12, 0x1f, 0x0a, 0x0b, + 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x62, 0x6f, 0x64, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x0c, 0x52, 0x0a, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x42, 0x6f, 0x64, 0x79, 0x42, 0x4a, 0x5a, + 0x48, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x6e, 0x74, + 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, + 0x64, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x70, 0x74, + 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x76, 0x31, 0x3b, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x6f, + 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x5f, 0x76, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x33, } var ( diff --git a/pkg/runtimeoptions/v1/api.proto b/pkg/runtimeoptions/v1/api.proto index 2a975b928..d0ab0e2f9 100644 --- a/pkg/runtimeoptions/v1/api.proto +++ b/pkg/runtimeoptions/v1/api.proto @@ -11,4 +11,7 @@ message Options { // ConfigPath specifies the filesystem location of the config file // used by the runtime. string config_path = 2; + // Blob specifies an in-memory TOML blob passed from containerd's configuration section + // for this runtime. This will be used if config_path is not specified. + bytes config_body = 3; } diff --git a/runtime/v2/runc/manager/manager_linux.go b/runtime/v2/runc/manager/manager_linux.go index 3c5d8054c..8699573ab 100644 --- a/runtime/v2/runc/manager/manager_linux.go +++ b/runtime/v2/runc/manager/manager_linux.go @@ -20,7 +20,6 @@ import ( "context" "encoding/json" "fmt" - "io" "os" "path/filepath" goruntime "runtime" @@ -35,13 +34,10 @@ import ( "github.com/containerd/containerd/namespaces" "github.com/containerd/containerd/pkg/process" "github.com/containerd/containerd/pkg/schedcore" - "github.com/containerd/containerd/protobuf/proto" - ptypes "github.com/containerd/containerd/protobuf/types" "github.com/containerd/containerd/runtime/v2/runc" "github.com/containerd/containerd/runtime/v2/runc/options" "github.com/containerd/containerd/runtime/v2/shim" runcC "github.com/containerd/go-runc" - "github.com/containerd/typeurl" exec "golang.org/x/sys/execabs" "golang.org/x/sys/unix" ) @@ -200,39 +196,29 @@ func (manager) Start(ctx context.Context, id string, opts shim.StartOpts) (_ str }() // make sure to wait after start go cmd.Wait() - if data, err := io.ReadAll(os.Stdin); err == nil { - if len(data) > 0 { - var any ptypes.Any - if err := proto.Unmarshal(data, &any); err != nil { - return "", err - } - v, err := typeurl.UnmarshalAny(&any) - if err != nil { - return "", err - } - if opts, ok := v.(*options.Options); ok { - if opts.ShimCgroup != "" { - if cgroups.Mode() == cgroups.Unified { - cg, err := cgroupsv2.Load(opts.ShimCgroup) - if err != nil { - return "", fmt.Errorf("failed to load cgroup %s: %w", opts.ShimCgroup, err) - } - if err := cg.AddProc(uint64(cmd.Process.Pid)); err != nil { - return "", fmt.Errorf("failed to join cgroup %s: %w", opts.ShimCgroup, err) - } - } else { - cg, err := cgroup1.Load(cgroup1.StaticPath(opts.ShimCgroup)) - if err != nil { - return "", fmt.Errorf("failed to load cgroup %s: %w", opts.ShimCgroup, err) - } - if err := cg.AddProc(uint64(cmd.Process.Pid)); err != nil { - return "", fmt.Errorf("failed to join cgroup %s: %w", opts.ShimCgroup, err) - } - } + + if opts, err := shim.ReadRuntimeOptions[*options.Options](os.Stdin); err == nil { + if opts.ShimCgroup != "" { + if cgroups.Mode() == cgroups.Unified { + cg, err := cgroupsv2.Load(opts.ShimCgroup) + if err != nil { + return "", fmt.Errorf("failed to load cgroup %s: %w", opts.ShimCgroup, err) + } + if err := cg.AddProc(uint64(cmd.Process.Pid)); err != nil { + return "", fmt.Errorf("failed to join cgroup %s: %w", opts.ShimCgroup, err) + } + } else { + cg, err := cgroup1.Load(cgroup1.StaticPath(opts.ShimCgroup)) + if err != nil { + return "", fmt.Errorf("failed to load cgroup %s: %w", opts.ShimCgroup, err) + } + if err := cg.AddProc(uint64(cmd.Process.Pid)); err != nil { + return "", fmt.Errorf("failed to join cgroup %s: %w", opts.ShimCgroup, err) } } } } + if err := shim.AdjustOOMScore(cmd.Process.Pid); err != nil { return "", fmt.Errorf("failed to adjust OOM score for shim: %w", err) } diff --git a/runtime/v2/shim/util.go b/runtime/v2/shim/util.go index d1cd47946..34d0fb33e 100644 --- a/runtime/v2/shim/util.go +++ b/runtime/v2/shim/util.go @@ -21,16 +21,20 @@ import ( "context" "errors" "fmt" + "io" "net" "os" "path/filepath" "strings" "time" + "github.com/containerd/containerd/errdefs" "github.com/containerd/containerd/namespaces" "github.com/containerd/containerd/protobuf/proto" "github.com/containerd/containerd/protobuf/types" + ptypes "github.com/containerd/containerd/protobuf/types" "github.com/containerd/ttrpc" + "github.com/containerd/typeurl" exec "golang.org/x/sys/execabs" ) @@ -169,6 +173,41 @@ func ReadAddress(path string) (string, error) { return string(data), nil } +// ReadRuntimeOptions reads config bytes from io.Reader and unmarshals it into the provided type. +// The type must be registered with typeurl. +// +// The function will return ErrNotFound, if the config is not provided. +// And ErrInvalidArgument, if unable to cast the config to the provided type T. +func ReadRuntimeOptions[T any](reader io.Reader) (T, error) { + var config T + + data, err := io.ReadAll(reader) + if err != nil { + return config, fmt.Errorf("failed to read config bytes from stdin: %w", err) + } + + if len(data) == 0 { + return config, errdefs.ErrNotFound + } + + var any ptypes.Any + if err := proto.Unmarshal(data, &any); err != nil { + return config, err + } + + v, err := typeurl.UnmarshalAny(&any) + if err != nil { + return config, err + } + + config, ok := v.(T) + if !ok { + return config, fmt.Errorf("invalid type %T: %w", v, errdefs.ErrInvalidArgument) + } + + return config, nil +} + // chainUnaryServerInterceptors creates a single ttrpc server interceptor from // a chain of many interceptors executed from first to last. func chainUnaryServerInterceptors(interceptors ...ttrpc.UnaryServerInterceptor) ttrpc.UnaryServerInterceptor {