diff --git a/internal/cow/cow.go b/internal/cow/cow.go index 8193315f06..b8e2d4f30f 100644 --- a/internal/cow/cow.go +++ b/internal/cow/cow.go @@ -80,4 +80,6 @@ type Container interface { // container to be terminated by some error condition (including calling // Close). Wait() error + // Modify sends a request to modify container resources + Modify(ctx context.Context, config interface{}) error } diff --git a/internal/gcs/guestconnection.go b/internal/gcs/guestconnection.go index 47005acc1b..4745d8dd75 100644 --- a/internal/gcs/guestconnection.go +++ b/internal/gcs/guestconnection.go @@ -190,6 +190,25 @@ func (gc *GuestConnection) DeleteContainerState(ctx context.Context, cid string) return gc.brdg.RPC(ctx, rpcDeleteContainerState, &req, &resp, false) } +func (gc *GuestConnection) UpdateContainer(ctx context.Context, cid string, resources interface{}) (err error) { + ctx, span := trace.StartSpan(ctx, "gcs::GuestConnection::UpdateContainer") + defer span.End() + defer func() { oc.SetSpanStatus(span, err) }() + span.AddAttributes(trace.StringAttribute("cid", cid)) + + resourcesJSON, err := json.Marshal(resources) + if err != nil { + return err + } + + req := updateContainerRequest{ + requestBase: makeRequest(ctx, cid), + Resources: string(resourcesJSON), + } + var resp responseBase + return gc.brdg.RPC(ctx, rpcUpdateContainer, &req, &resp, false) +} + // Close terminates the guest connection. It is undefined to call any other // methods on the connection after this is called. func (gc *GuestConnection) Close() error { diff --git a/internal/gcs/protocol.go b/internal/gcs/protocol.go index 70a9c016fc..23acd3cabd 100644 --- a/internal/gcs/protocol.go +++ b/internal/gcs/protocol.go @@ -58,6 +58,7 @@ const ( rpcNegotiateProtocol rpcDumpStacks rpcDeleteContainerState + rpcUpdateContainer rpcLifecycleNotification ) @@ -118,6 +119,8 @@ func (typ msgType) String() string { s += "DumpStacks" case rpcDeleteContainerState: s += "DeleteContainerState" + case rpcUpdateContainer: + s += "UpdateContainer" case rpcLifecycleNotification: s += "LifecycleNotification" default: @@ -358,3 +361,8 @@ type containerGetPropertiesResponseV2 struct { responseBase Properties containerPropertiesV2 } + +type updateContainerRequest struct { + requestBase + Resources string +} diff --git a/internal/gcs/resourcepaths.go b/internal/gcs/resourcepaths.go new file mode 100644 index 0000000000..8540af96c7 --- /dev/null +++ b/internal/gcs/resourcepaths.go @@ -0,0 +1,10 @@ +package gcs + +const ( + // silo container resources paths + siloDeviceResourcePath string = "Container/Devices/Generic" + siloMappedDirectoryResourcePath string = "Container/MappedDirectories" + siloMappedPipeResourcePath string = "Container/MappedPipes" + siloMemoryResourcePath string = "Container/Memory/SizeInMB" + siloRegistryFlushStatePath string = "Container/RegistryFlushState" +) diff --git a/internal/schema1/schema1.go b/internal/schema1/schema1.go index 24bb3b46b4..cd1ec84abb 100644 --- a/internal/schema1/schema1.go +++ b/internal/schema1/schema1.go @@ -218,6 +218,7 @@ type GuestDefinedCapabilities struct { SignalProcessSupported bool `json:",omitempty"` DumpStacksSupported bool `json:",omitempty"` DeleteContainerStateSupported bool `json:",omitempty"` + UpdateContainerSupported bool `json:",omitempty"` } // GuestConnectionInfo is the structure of an iterm return by a GuestConnection call on a utility VM diff --git a/internal/uvm/update.go b/internal/uvm/update.go new file mode 100644 index 0000000000..ee576767df --- /dev/null +++ b/internal/uvm/update.go @@ -0,0 +1,12 @@ +package uvm + +import ( + "context" +) + +func (uvm *UtilityVM) UpdateContainer(ctx context.Context, cid string, resources interface{}) error { + if uvm.gc == nil || !uvm.guestCaps.UpdateContainerSupported { + return nil + } + return uvm.gc.UpdateContainer(ctx, cid, resources) +}