mirror of
https://github.com/containerd/containerd.git
synced 2026-11-06 05:17:02 +00:00
Implement UpdatePodSandboxResources CRI API handler
Signed-off-by: Chris Henzie <chrishenzie@google.com>
This commit is contained in:
1 parent
a800acbac8
commit
ffd3691c92
9 files changed
+258
-27
No files matched your search
@@ -85,6 +85,8 @@ type PodSandboxManager interface {
|
||||
// RunPodSandbox creates and starts a pod-level sandbox. Runtimes should ensure
|
||||
// the sandbox is in ready state.
|
||||
RunPodSandbox(config *runtimeapi.PodSandboxConfig, runtimeHandler string, opts ...grpc.CallOption) (string, error)
|
||||
// UpdatePodSandboxResources updates the cgroup resources for the sandbox.
|
||||
UpdatePodSandboxResources(podSandboxID string, overhead *runtimeapi.LinuxContainerResources, resources *runtimeapi.LinuxContainerResources, opts ...grpc.CallOption) error
|
||||
// StopPodSandbox stops the sandbox. If there are any running containers in the
|
||||
// sandbox, they should be force terminated.
|
||||
StopPodSandbox(podSandboxID string, opts ...grpc.CallOption) error
|
||||
|
||||
+107
-23
@@ -531,6 +531,48 @@ func TestNriLinuxMemsetAdjustmentUpdate(t *testing.T) {
|
||||
require.Equal(t, expected, string(chk), "check result")
|
||||
}
|
||||
|
||||
// Test pod sandbox updates received by NRI plugins.
|
||||
func TestNriUpdatePodSandbox(t *testing.T) {
|
||||
skipNriTestIfNecessary(t)
|
||||
|
||||
t.Log("Test that NRI plugins receive pod sandbox updates.")
|
||||
|
||||
var (
|
||||
tc = &nriTest{
|
||||
t: t,
|
||||
plugins: []*mockPlugin{{}},
|
||||
}
|
||||
overheadMemLimit int64
|
||||
resMemLimit int64
|
||||
updateMemLimit = func(mp *mockPlugin, pod *api.PodSandbox, overhead *api.LinuxResources, res *api.LinuxResources) error {
|
||||
overheadMemLimit = overhead.GetMemory().GetLimit().GetValue()
|
||||
resMemLimit = res.GetMemory().GetLimit().GetValue()
|
||||
return nil
|
||||
}
|
||||
)
|
||||
|
||||
tc.plugins[0].updatePodSandbox = updateMemLimit
|
||||
tc.setup()
|
||||
|
||||
podID := tc.runPod("pod0")
|
||||
_ = tc.startContainer(podID, "ctr0")
|
||||
|
||||
overhead := &runtime.LinuxContainerResources{MemoryLimitInBytes: 10}
|
||||
res := &runtime.LinuxContainerResources{MemoryLimitInBytes: 5}
|
||||
err := tc.runtime.UpdatePodSandboxResources(podID, overhead, res)
|
||||
assert.NoError(tc.t, err, "update pod sandbox")
|
||||
|
||||
timeout := time.After(pluginSyncTimeout)
|
||||
err = tc.plugins[0].Wait(PodSandboxEvent(tc.plugins[0].pods[podID], UpdatePodSandbox), timeout)
|
||||
assert.NoError(tc.t, err, "wait for update pod sandbox")
|
||||
|
||||
err = tc.plugins[0].Wait(PodSandboxEvent(tc.plugins[0].pods[podID], PostUpdatePodSandbox), timeout)
|
||||
assert.NoError(tc.t, err, "wait for post update pod sandbox")
|
||||
|
||||
assert.Equal(t, overheadMemLimit, overhead.MemoryLimitInBytes)
|
||||
assert.Equal(t, resMemLimit, res.MemoryLimitInBytes)
|
||||
}
|
||||
|
||||
// Test NRI vs. containerd restart.
|
||||
func TestNriPluginContainerdRestart(t *testing.T) {
|
||||
skipNriTestIfNecessary(t)
|
||||
@@ -706,18 +748,20 @@ type mockPlugin struct {
|
||||
pods map[string]*api.PodSandbox
|
||||
ctrs map[string]*api.Container
|
||||
|
||||
closed bool
|
||||
namespace string
|
||||
logf func(string, ...interface{})
|
||||
synchronize func(*mockPlugin, []*api.PodSandbox, []*api.Container) ([]*api.ContainerUpdate, error)
|
||||
runPodSandbox func(*mockPlugin, *api.PodSandbox) error
|
||||
stopPodSandbox func(*mockPlugin, *api.PodSandbox) error
|
||||
removePodSandbox func(*mockPlugin, *api.PodSandbox) error
|
||||
createContainer func(*mockPlugin, *api.PodSandbox, *api.Container) (*api.ContainerAdjustment, []*api.ContainerUpdate, error)
|
||||
postCreateContainer func(*mockPlugin, *api.PodSandbox, *api.Container)
|
||||
updateContainer func(*mockPlugin, *api.PodSandbox, *api.Container) ([]*api.ContainerUpdate, error)
|
||||
postUpdateContainer func(*mockPlugin, *api.PodSandbox, *api.Container)
|
||||
stopContainer func(*mockPlugin, *api.PodSandbox, *api.Container) ([]*api.ContainerUpdate, error)
|
||||
closed bool
|
||||
namespace string
|
||||
logf func(string, ...interface{})
|
||||
synchronize func(*mockPlugin, []*api.PodSandbox, []*api.Container) ([]*api.ContainerUpdate, error)
|
||||
runPodSandbox func(*mockPlugin, *api.PodSandbox) error
|
||||
updatePodSandbox func(*mockPlugin, *api.PodSandbox, *api.LinuxResources, *api.LinuxResources) error
|
||||
postUpdatePodSandbox func(*mockPlugin, *api.PodSandbox) error
|
||||
stopPodSandbox func(*mockPlugin, *api.PodSandbox) error
|
||||
removePodSandbox func(*mockPlugin, *api.PodSandbox) error
|
||||
createContainer func(*mockPlugin, *api.PodSandbox, *api.Container) (*api.ContainerAdjustment, []*api.ContainerUpdate, error)
|
||||
postCreateContainer func(*mockPlugin, *api.PodSandbox, *api.Container)
|
||||
updateContainer func(*mockPlugin, *api.PodSandbox, *api.Container) ([]*api.ContainerUpdate, error)
|
||||
postUpdateContainer func(*mockPlugin, *api.PodSandbox, *api.Container)
|
||||
stopContainer func(*mockPlugin, *api.PodSandbox, *api.Container) ([]*api.ContainerUpdate, error)
|
||||
}
|
||||
|
||||
func (m *mockPlugin) Start() error {
|
||||
@@ -733,6 +777,8 @@ func (m *mockPlugin) Start() error {
|
||||
if m.mask == 0 {
|
||||
m.mask.Set(
|
||||
api.Event_RUN_POD_SANDBOX,
|
||||
api.Event_UPDATE_POD_SANDBOX,
|
||||
api.Event_POST_UPDATE_POD_SANDBOX,
|
||||
api.Event_STOP_POD_SANDBOX,
|
||||
api.Event_REMOVE_POD_SANDBOX,
|
||||
api.Event_CREATE_CONTAINER,
|
||||
@@ -768,6 +814,12 @@ func (m *mockPlugin) Start() error {
|
||||
if m.runPodSandbox == nil {
|
||||
m.runPodSandbox = nopRunPodSandbox
|
||||
}
|
||||
if m.updatePodSandbox == nil {
|
||||
m.updatePodSandbox = nopUpdatePodSandbox
|
||||
}
|
||||
if m.postUpdatePodSandbox == nil {
|
||||
m.postUpdatePodSandbox = nopPostUpdatePodSandbox
|
||||
}
|
||||
if m.stopPodSandbox == nil {
|
||||
m.stopPodSandbox = nopStopPodSandbox
|
||||
}
|
||||
@@ -860,6 +912,28 @@ func (m *mockPlugin) RunPodSandbox(ctx context.Context, pod *api.PodSandbox) err
|
||||
return m.runPodSandbox(m, pod)
|
||||
}
|
||||
|
||||
func (m *mockPlugin) UpdatePodSandbox(ctx context.Context, pod *api.PodSandbox, overhead *api.LinuxResources, res *api.LinuxResources) error {
|
||||
if !m.inNamespace(pod.Namespace) {
|
||||
return nil
|
||||
}
|
||||
|
||||
m.Log("UpdatePodSandbox %s/%s", pod.Namespace, pod.Name)
|
||||
m.pods[pod.Id] = pod
|
||||
m.q.Add(PodSandboxEvent(pod, UpdatePodSandbox))
|
||||
return m.updatePodSandbox(m, pod, overhead, res)
|
||||
}
|
||||
|
||||
func (m *mockPlugin) PostUpdatePodSandbox(ctx context.Context, pod *api.PodSandbox) error {
|
||||
if !m.inNamespace(pod.Namespace) {
|
||||
return nil
|
||||
}
|
||||
|
||||
m.Log("PostUpdatePodSandbox %s/%s", pod.Namespace, pod.Name)
|
||||
m.pods[pod.Id] = pod
|
||||
m.q.Add(PodSandboxEvent(pod, PostUpdatePodSandbox))
|
||||
return m.postUpdatePodSandbox(m, pod)
|
||||
}
|
||||
|
||||
func (m *mockPlugin) StopPodSandbox(ctx context.Context, pod *api.PodSandbox) error {
|
||||
if !m.inNamespace(pod.Namespace) {
|
||||
return nil
|
||||
@@ -994,6 +1068,14 @@ func nopRunPodSandbox(*mockPlugin, *api.PodSandbox) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func nopUpdatePodSandbox(*mockPlugin, *api.PodSandbox, *api.LinuxResources, *api.LinuxResources) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func nopPostUpdatePodSandbox(*mockPlugin, *api.PodSandbox) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func nopStopPodSandbox(*mockPlugin, *api.PodSandbox) error {
|
||||
return nil
|
||||
}
|
||||
@@ -1031,17 +1113,19 @@ const (
|
||||
Disconnected = "closed"
|
||||
Stopped = "stopped"
|
||||
|
||||
RunPodSandbox = "RunPodSandbox"
|
||||
StopPodSandbox = "StopPodSandbox"
|
||||
RemovePodSandbox = "RemovePodSandbox"
|
||||
CreateContainer = "CreateContainer"
|
||||
StartContainer = "StartContainer"
|
||||
UpdateContainer = "UpdateContainer"
|
||||
StopContainer = "StopContainer"
|
||||
RemoveContainer = "RemoveContainer"
|
||||
PostCreateContainer = "PostCreateContainer"
|
||||
PostStartContainer = "PostStartContainer"
|
||||
PostUpdateContainer = "PostUpdateContainer"
|
||||
RunPodSandbox = "RunPodSandbox"
|
||||
UpdatePodSandbox = "UpdatePodSandbox"
|
||||
PostUpdatePodSandbox = "PostUpdatePodSandbox"
|
||||
StopPodSandbox = "StopPodSandbox"
|
||||
RemovePodSandbox = "RemovePodSandbox"
|
||||
CreateContainer = "CreateContainer"
|
||||
StartContainer = "StartContainer"
|
||||
UpdateContainer = "UpdateContainer"
|
||||
StopContainer = "StopContainer"
|
||||
RemoveContainer = "RemoveContainer"
|
||||
PostCreateContainer = "PostCreateContainer"
|
||||
PostStartContainer = "PostStartContainer"
|
||||
PostUpdateContainer = "PostUpdateContainer"
|
||||
|
||||
Error = "Error"
|
||||
Timeout = ""
|
||||
|
||||
@@ -144,6 +144,28 @@ func (r *RuntimeService) RunPodSandbox(config *runtimeapi.PodSandboxConfig, runt
|
||||
return resp.PodSandboxId, nil
|
||||
}
|
||||
|
||||
// UpdatePodSandboxResources updates the cgroup resources for the sandbox.
|
||||
func (r *RuntimeService) UpdatePodSandboxResources(podSandBoxID string, overhead *runtimeapi.LinuxContainerResources, resources *runtimeapi.LinuxContainerResources, opts ...grpc.CallOption) error {
|
||||
log.L.Infof("[RuntimeService] UpdatePodSandboxResources (podSandboxID=%v, timeout=%v)", podSandBoxID, r.timeout)
|
||||
|
||||
ctx, cancel := getContextWithTimeout(r.timeout)
|
||||
defer cancel()
|
||||
|
||||
_, err := r.runtimeClient.UpdatePodSandboxResources(ctx, &runtimeapi.UpdatePodSandboxResourcesRequest{
|
||||
PodSandboxId: podSandBoxID,
|
||||
Overhead: overhead,
|
||||
Resources: resources,
|
||||
}, opts...)
|
||||
if err != nil {
|
||||
log.L.WithError(err).Errorf("UpdatePodSandboxResources %q from runtime service failed", podSandBoxID)
|
||||
return err
|
||||
}
|
||||
|
||||
log.L.Infof("[RuntimeService] UpdatePodSandboxResources Response (podSandboxID=%v)", podSandBoxID)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// StopPodSandbox stops the sandbox. If there are any running containers in the
|
||||
// sandbox, they should be forced to termination.
|
||||
func (r *RuntimeService) StopPodSandbox(podSandBoxID string, opts ...grpc.CallOption) error {
|
||||
|
||||
@@ -18,7 +18,6 @@ package instrument
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
|
||||
"github.com/containerd/errdefs"
|
||||
"github.com/containerd/errdefs/pkg/errgrpc"
|
||||
@@ -656,5 +655,17 @@ func (in *instrumentedService) RuntimeConfig(ctx context.Context, r *runtime.Run
|
||||
}
|
||||
|
||||
func (in *instrumentedService) UpdatePodSandboxResources(ctx context.Context, r *runtime.UpdatePodSandboxResourcesRequest) (res *runtime.UpdatePodSandboxResourcesResponse, err error) {
|
||||
return nil, errors.New("not implemented yet")
|
||||
if err := in.checkInitialized(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
log.G(ctx).Infof("UpdatePodSandboxResources for %q with Overhead: %+v / Resources: %+v", r.GetPodSandboxId(), r.GetOverhead(), r.GetResources())
|
||||
defer func() {
|
||||
if err != nil {
|
||||
log.G(ctx).WithError(err).Errorf("UpdatePodSandboxResources for %q failed", r.GetPodSandboxId())
|
||||
} else {
|
||||
log.G(ctx).Infof("UpdatePodSandboxResources for %q returns successfully", r.GetPodSandboxId())
|
||||
}
|
||||
}()
|
||||
res, err = in.c.UpdatePodSandboxResources(ctrdutil.WithNamespace(ctx), r)
|
||||
return res, errgrpc.ToGRPC(err)
|
||||
}
|
||||
@@ -94,6 +94,28 @@ func (a *API) RunPodSandbox(ctx context.Context, criPod *sstore.Sandbox) error {
|
||||
return err
|
||||
}
|
||||
|
||||
func (a *API) UpdatePodSandboxResources(ctx context.Context, criPod *sstore.Sandbox, overhead *cri.LinuxContainerResources, req *cri.LinuxContainerResources) error {
|
||||
if a.IsDisabled() {
|
||||
return nil
|
||||
}
|
||||
|
||||
pod := a.nriPodSandbox(criPod)
|
||||
err := a.nri.UpdatePodSandbox(ctx, pod, fromCRILinuxResources(overhead), fromCRILinuxResources(req))
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (a *API) PostUpdatePodSandboxResources(ctx context.Context, criPod *sstore.Sandbox) error {
|
||||
if a.IsDisabled() {
|
||||
return nil
|
||||
}
|
||||
|
||||
pod := a.nriPodSandbox(criPod)
|
||||
err := a.nri.PostUpdatePodSandbox(ctx, pod)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (a *API) StopPodSandbox(ctx context.Context, criPod *sstore.Sandbox) error {
|
||||
if a.IsDisabled() {
|
||||
return nil
|
||||
|
||||
@@ -57,6 +57,14 @@ func (*API) RunPodSandbox(context.Context, *sstore.Sandbox) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *API) UpdatePodSandboxResources(context.Context, *sstore.Sandbox, *cri.LinuxContainerResources, *cri.LinuxContainerResources) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *API) PostUpdatePodSandboxResources(context.Context, *sstore.Sandbox) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (*API) StopPodSandbox(context.Context, *sstore.Sandbox) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -18,11 +18,50 @@ package server
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
runtime "k8s.io/cri-api/pkg/apis/runtime/v1"
|
||||
|
||||
sstore "github.com/containerd/containerd/v2/internal/cri/store/sandbox"
|
||||
"github.com/containerd/containerd/v2/pkg/tracing"
|
||||
"github.com/containerd/log"
|
||||
)
|
||||
|
||||
func (c *criService) UpdatePodSandboxResources(ctx context.Context, r *runtime.UpdatePodSandboxResourcesRequest) (*runtime.UpdatePodSandboxResourcesResponse, error) {
|
||||
return nil, errors.New("not implemented yet")
|
||||
span := tracing.SpanFromContext(ctx)
|
||||
sandbox, err := c.sandboxStore.Get(r.GetPodSandboxId())
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to find sandbox: %w", err)
|
||||
}
|
||||
|
||||
span.SetAttributes(tracing.Attribute("sandbox.id", sandbox.ID))
|
||||
|
||||
overhead := r.GetOverhead()
|
||||
resources := r.GetResources()
|
||||
err = c.nri.UpdatePodSandboxResources(ctx, &sandbox, overhead, resources)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("NRI sandbox update failed: %w", err)
|
||||
}
|
||||
|
||||
err = sandbox.Status.Update(
|
||||
func(status sstore.Status) (sstore.Status, error) {
|
||||
status.Overhead = &runtime.ContainerResources{
|
||||
Linux: overhead,
|
||||
}
|
||||
status.Resources = &runtime.ContainerResources{
|
||||
Linux: resources,
|
||||
}
|
||||
return status, nil
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to update sandbox store: %w", err)
|
||||
}
|
||||
|
||||
err = c.nri.PostUpdatePodSandboxResources(ctx, &sandbox)
|
||||
if err != nil {
|
||||
log.G(ctx).WithError(err).Errorf("NRI post-update notification failed")
|
||||
}
|
||||
|
||||
return &runtime.UpdatePodSandboxResourcesResponse{}, nil
|
||||
}
|
||||
@@ -105,6 +105,10 @@ type Status struct {
|
||||
ExitStatus uint32
|
||||
// State is the state of the sandbox.
|
||||
State State
|
||||
// Overhead has sandbox resource overhead.
|
||||
Overhead *runtime.ContainerResources
|
||||
// Resources has sandbox resource constraints.
|
||||
Resources *runtime.ContainerResources
|
||||
}
|
||||
|
||||
// UpdateFunc is function used to update the sandbox status. If there
|
||||
|
||||
@@ -48,6 +48,12 @@ type API interface {
|
||||
// RunPodSandbox relays pod creation events to NRI.
|
||||
RunPodSandbox(context.Context, PodSandbox) error
|
||||
|
||||
// UpdatePodSandbox relays pod update requests to NRI.
|
||||
UpdatePodSandbox(context.Context, PodSandbox, *nri.LinuxResources, *nri.LinuxResources) error
|
||||
|
||||
// PostUpdatePodSandbox relays successful pod update events to NRI.
|
||||
PostUpdatePodSandbox(context.Context, PodSandbox) error
|
||||
|
||||
// StopPodSandbox relays pod shutdown events to NRI.
|
||||
StopPodSandbox(context.Context, PodSandbox) error
|
||||
|
||||
@@ -184,6 +190,39 @@ func (l *local) RunPodSandbox(ctx context.Context, pod PodSandbox) error {
|
||||
return err
|
||||
}
|
||||
|
||||
func (l *local) UpdatePodSandbox(ctx context.Context, pod PodSandbox, overhead *nri.LinuxResources, req *nri.LinuxResources) error {
|
||||
if !l.IsEnabled() {
|
||||
return nil
|
||||
}
|
||||
|
||||
l.Lock()
|
||||
defer l.Unlock()
|
||||
|
||||
request := &nri.UpdatePodSandboxRequest{
|
||||
Pod: podSandboxToNRI(pod),
|
||||
OverheadLinuxResources: overhead,
|
||||
LinuxResources: req,
|
||||
}
|
||||
|
||||
_, err := l.nri.UpdatePodSandbox(ctx, request)
|
||||
return err
|
||||
}
|
||||
|
||||
func (l *local) PostUpdatePodSandbox(ctx context.Context, pod PodSandbox) error {
|
||||
if !l.IsEnabled() {
|
||||
return nil
|
||||
}
|
||||
|
||||
l.Lock()
|
||||
defer l.Unlock()
|
||||
|
||||
request := &nri.PostUpdatePodSandboxRequest{
|
||||
Pod: podSandboxToNRI(pod),
|
||||
}
|
||||
|
||||
return l.nri.PostUpdatePodSandbox(ctx, request)
|
||||
}
|
||||
|
||||
func (l *local) StopPodSandbox(ctx context.Context, pod PodSandbox) error {
|
||||
if !l.IsEnabled() {
|
||||
return nil
|
||||
|
||||
Reference in new issue
Block a user