mirror of https://github.com/containers/podman.git
Fix device limitations in podman-remote update on remote systems
Fixes: https://issues.redhat.com/browse/RUN-2381 Signed-off-by: Jan Rodák <hony.com@seznam.cz>
This commit is contained in:
parent
992b80439a
commit
2f31a61cce
|
@ -113,6 +113,16 @@ func GetChangedHealthCheckConfiguration(cmd *cobra.Command, vals *entities.Conta
|
||||||
return updateHealthCheckConfig
|
return updateHealthCheckConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func GetChangedDeviceLimits(s *specgen.SpecGenerator) *define.UpdateContainerDevicesLimits {
|
||||||
|
updateDevicesLimits := define.UpdateContainerDevicesLimits{}
|
||||||
|
updateDevicesLimits.SetBlkIOWeightDevice(s.WeightDevice)
|
||||||
|
updateDevicesLimits.SetDeviceReadBPs(s.ThrottleReadBpsDevice)
|
||||||
|
updateDevicesLimits.SetDeviceWriteBPs(s.ThrottleWriteBpsDevice)
|
||||||
|
updateDevicesLimits.SetDeviceReadIOPs(s.ThrottleReadIOPSDevice)
|
||||||
|
updateDevicesLimits.SetDeviceWriteIOPs(s.ThrottleWriteIOPSDevice)
|
||||||
|
return &updateDevicesLimits
|
||||||
|
}
|
||||||
|
|
||||||
func update(cmd *cobra.Command, args []string) error {
|
func update(cmd *cobra.Command, args []string) error {
|
||||||
var err error
|
var err error
|
||||||
// use a specgen since this is the easiest way to hold resource info
|
// use a specgen since this is the easiest way to hold resource info
|
||||||
|
@ -124,33 +134,35 @@ func update(cmd *cobra.Command, args []string) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if updateOpts.Restart != "" {
|
|
||||||
policy, retries, err := util.ParseRestartPolicy(updateOpts.Restart)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
s.RestartPolicy = policy
|
|
||||||
if policy == define.RestartPolicyOnFailure {
|
|
||||||
s.RestartRetries = &retries
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// we need to pass the whole specgen since throttle devices are parsed later due to cross compat.
|
|
||||||
s.ResourceLimits, err = specgenutil.GetResources(s, &updateOpts)
|
s.ResourceLimits, err = specgenutil.GetResources(s, &updateOpts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
healthCheckConfig := GetChangedHealthCheckConfiguration(cmd, &updateOpts)
|
if s.ResourceLimits == nil {
|
||||||
if err != nil {
|
s.ResourceLimits = &specs.LinuxResources{}
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
healthCheckConfig := GetChangedHealthCheckConfiguration(cmd, &updateOpts)
|
||||||
|
|
||||||
opts := &entities.ContainerUpdateOptions{
|
opts := &entities.ContainerUpdateOptions{
|
||||||
NameOrID: strings.TrimPrefix(args[0], "/"),
|
NameOrID: strings.TrimPrefix(args[0], "/"),
|
||||||
Specgen: s,
|
Resources: s.ResourceLimits,
|
||||||
ChangedHealthCheckConfiguration: &healthCheckConfig,
|
ChangedHealthCheckConfiguration: &healthCheckConfig,
|
||||||
|
DevicesLimits: GetChangedDeviceLimits(s),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if cmd.Flags().Changed("restart") {
|
||||||
|
policy, retries, err := util.ParseRestartPolicy(updateOpts.Restart)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
opts.RestartPolicy = &policy
|
||||||
|
if policy == define.RestartPolicyOnFailure {
|
||||||
|
opts.RestartRetries = &retries
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
rep, err := registry.ContainerEngine().ContainerUpdate(context.Background(), opts)
|
rep, err := registry.ContainerEngine().ContainerUpdate(context.Background(), opts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
|
@ -2,6 +2,8 @@ package define
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/opencontainers/runtime-spec/specs-go"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Valid restart policy types.
|
// Valid restart policy types.
|
||||||
|
@ -64,3 +66,111 @@ const (
|
||||||
// a Job kube yaml spec
|
// a Job kube yaml spec
|
||||||
K8sKindJob = "job"
|
K8sKindJob = "job"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type WeightDevice struct {
|
||||||
|
Path string
|
||||||
|
Weight uint16
|
||||||
|
}
|
||||||
|
|
||||||
|
type ThrottleDevice struct {
|
||||||
|
Path string
|
||||||
|
Rate uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
type UpdateContainerDevicesLimits struct {
|
||||||
|
// Block IO weight (relative device weight) in the form:
|
||||||
|
// ```[{"Path": "device_path", "Weight": weight}]```
|
||||||
|
BlkIOWeightDevice []WeightDevice `json:",omitempty"`
|
||||||
|
// Limit read rate (bytes per second) from a device, in the form:
|
||||||
|
// ```[{"Path": "device_path", "Rate": rate}]```
|
||||||
|
DeviceReadBPs []ThrottleDevice `json:",omitempty"`
|
||||||
|
// Limit write rate (bytes per second) to a device, in the form:
|
||||||
|
// ```[{"Path": "device_path", "Rate": rate}]```
|
||||||
|
DeviceWriteBPs []ThrottleDevice `json:",omitempty"`
|
||||||
|
// Limit read rate (IO per second) from a device, in the form:
|
||||||
|
// ```[{"Path": "device_path", "Rate": rate}]```
|
||||||
|
DeviceReadIOPs []ThrottleDevice `json:",omitempty"`
|
||||||
|
// Limit write rate (IO per second) to a device, in the form:
|
||||||
|
// ```[{"Path": "device_path", "Rate": rate}]```
|
||||||
|
DeviceWriteIOPs []ThrottleDevice `json:",omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *WeightDevice) addToLinuxWeightDevice(wd map[string]specs.LinuxWeightDevice) {
|
||||||
|
wd[d.Path] = specs.LinuxWeightDevice{
|
||||||
|
Weight: &d.Weight,
|
||||||
|
LeafWeight: nil,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func LinuxWeightDeviceToWeightDevice(path string, d specs.LinuxWeightDevice) WeightDevice {
|
||||||
|
return WeightDevice{Path: path, Weight: *d.Weight}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *ThrottleDevice) addToLinuxThrottleDevice(td map[string]specs.LinuxThrottleDevice) {
|
||||||
|
td[d.Path] = specs.LinuxThrottleDevice{Rate: d.Rate}
|
||||||
|
}
|
||||||
|
|
||||||
|
func LinuxThrottleDevicesToThrottleDevices(path string, d specs.LinuxThrottleDevice) ThrottleDevice {
|
||||||
|
return ThrottleDevice{Path: path, Rate: d.Rate}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *UpdateContainerDevicesLimits) SetBlkIOWeightDevice(wd map[string]specs.LinuxWeightDevice) {
|
||||||
|
for path, dev := range wd {
|
||||||
|
u.BlkIOWeightDevice = append(u.BlkIOWeightDevice, LinuxWeightDeviceToWeightDevice(path, dev))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func copyLinuxThrottleDevicesFromMapToThrottleDevicesArray(source map[string]specs.LinuxThrottleDevice, dest []ThrottleDevice) []ThrottleDevice {
|
||||||
|
for path, dev := range source {
|
||||||
|
dest = append(dest, LinuxThrottleDevicesToThrottleDevices(path, dev))
|
||||||
|
}
|
||||||
|
return dest
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *UpdateContainerDevicesLimits) SetDeviceReadBPs(td map[string]specs.LinuxThrottleDevice) {
|
||||||
|
u.DeviceReadBPs = copyLinuxThrottleDevicesFromMapToThrottleDevicesArray(td, u.DeviceReadBPs)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *UpdateContainerDevicesLimits) SetDeviceWriteBPs(td map[string]specs.LinuxThrottleDevice) {
|
||||||
|
u.DeviceWriteBPs = copyLinuxThrottleDevicesFromMapToThrottleDevicesArray(td, u.DeviceWriteBPs)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *UpdateContainerDevicesLimits) SetDeviceReadIOPs(td map[string]specs.LinuxThrottleDevice) {
|
||||||
|
u.DeviceReadIOPs = copyLinuxThrottleDevicesFromMapToThrottleDevicesArray(td, u.DeviceReadIOPs)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *UpdateContainerDevicesLimits) SetDeviceWriteIOPs(td map[string]specs.LinuxThrottleDevice) {
|
||||||
|
u.DeviceWriteIOPs = copyLinuxThrottleDevicesFromMapToThrottleDevicesArray(td, u.DeviceWriteIOPs)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *UpdateContainerDevicesLimits) GetMapOfLinuxWeightDevice() map[string]specs.LinuxWeightDevice {
|
||||||
|
wd := make(map[string]specs.LinuxWeightDevice)
|
||||||
|
for _, dev := range u.BlkIOWeightDevice {
|
||||||
|
dev.addToLinuxWeightDevice(wd)
|
||||||
|
}
|
||||||
|
return wd
|
||||||
|
}
|
||||||
|
|
||||||
|
func getMapOfLinuxThrottleDevices(source []ThrottleDevice) map[string]specs.LinuxThrottleDevice {
|
||||||
|
td := make(map[string]specs.LinuxThrottleDevice)
|
||||||
|
for _, dev := range source {
|
||||||
|
dev.addToLinuxThrottleDevice(td)
|
||||||
|
}
|
||||||
|
return td
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *UpdateContainerDevicesLimits) GetMapOfDeviceReadBPs() map[string]specs.LinuxThrottleDevice {
|
||||||
|
return getMapOfLinuxThrottleDevices(u.DeviceReadBPs)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *UpdateContainerDevicesLimits) GetMapOfDeviceWriteBPs() map[string]specs.LinuxThrottleDevice {
|
||||||
|
return getMapOfLinuxThrottleDevices(u.DeviceWriteBPs)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *UpdateContainerDevicesLimits) GetMapOfDeviceReadIOPs() map[string]specs.LinuxThrottleDevice {
|
||||||
|
return getMapOfLinuxThrottleDevices(u.DeviceReadIOPs)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *UpdateContainerDevicesLimits) GetMapOfDeviceWriteIOPs() map[string]specs.LinuxThrottleDevice {
|
||||||
|
return getMapOfLinuxThrottleDevices(u.DeviceWriteIOPs)
|
||||||
|
}
|
||||||
|
|
|
@ -18,6 +18,7 @@ import (
|
||||||
api "github.com/containers/podman/v5/pkg/api/types"
|
api "github.com/containers/podman/v5/pkg/api/types"
|
||||||
"github.com/containers/podman/v5/pkg/domain/entities"
|
"github.com/containers/podman/v5/pkg/domain/entities"
|
||||||
"github.com/containers/podman/v5/pkg/domain/infra/abi"
|
"github.com/containers/podman/v5/pkg/domain/infra/abi"
|
||||||
|
"github.com/containers/podman/v5/pkg/specgenutil"
|
||||||
"github.com/containers/podman/v5/pkg/util"
|
"github.com/containers/podman/v5/pkg/util"
|
||||||
"github.com/gorilla/schema"
|
"github.com/gorilla/schema"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
|
@ -447,7 +448,14 @@ func UpdateContainer(w http.ResponseWriter, r *http.Request) {
|
||||||
utils.Error(w, http.StatusInternalServerError, fmt.Errorf("decode(): %w", err))
|
utils.Error(w, http.StatusInternalServerError, fmt.Errorf("decode(): %w", err))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
err = ctr.Update(&options.LinuxResources, restartPolicy, restartRetries, &options.UpdateHealthCheckConfig)
|
|
||||||
|
resourceLimits, err := specgenutil.UpdateMajorAndMinorNumbers(&options.LinuxResources, &options.UpdateContainerDevicesLimits)
|
||||||
|
if err != nil {
|
||||||
|
utils.InternalServerError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = ctr.Update(resourceLimits, restartPolicy, restartRetries, &options.UpdateHealthCheckConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.InternalServerError(w, err)
|
utils.InternalServerError(w, err)
|
||||||
return
|
return
|
||||||
|
|
|
@ -324,9 +324,13 @@ type containerCreateResponse struct {
|
||||||
Body entities.ContainerCreateResponse
|
Body entities.ContainerCreateResponse
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Update container
|
||||||
|
// swagger:response
|
||||||
type containerUpdateResponse struct {
|
type containerUpdateResponse struct {
|
||||||
// in:body
|
// in:body
|
||||||
|
Body struct {
|
||||||
ID string
|
ID string
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wait container
|
// Wait container
|
||||||
|
|
|
@ -76,6 +76,7 @@ type LibpodContainersRmReport struct {
|
||||||
type UpdateEntities struct {
|
type UpdateEntities struct {
|
||||||
specs.LinuxResources
|
specs.LinuxResources
|
||||||
define.UpdateHealthCheckConfig
|
define.UpdateHealthCheckConfig
|
||||||
|
define.UpdateContainerDevicesLimits
|
||||||
}
|
}
|
||||||
|
|
||||||
type Info struct {
|
type Info struct {
|
||||||
|
|
|
@ -1804,7 +1804,6 @@ func (s *APIServer) registerContainersHandlers(r *mux.Router) error {
|
||||||
// produces:
|
// produces:
|
||||||
// - application/json
|
// - application/json
|
||||||
// responses:
|
// responses:
|
||||||
// responses:
|
|
||||||
// 201:
|
// 201:
|
||||||
// $ref: "#/responses/containerUpdateResponse"
|
// $ref: "#/responses/containerUpdateResponse"
|
||||||
// 400:
|
// 400:
|
||||||
|
|
|
@ -20,15 +20,16 @@ func Update(ctx context.Context, options *types.ContainerUpdateOptions) (string,
|
||||||
}
|
}
|
||||||
|
|
||||||
params := url.Values{}
|
params := url.Values{}
|
||||||
if options.Specgen.RestartPolicy != "" {
|
if options.RestartPolicy != nil {
|
||||||
params.Set("restartPolicy", options.Specgen.RestartPolicy)
|
params.Set("restartPolicy", *options.RestartPolicy)
|
||||||
if options.Specgen.RestartRetries != nil {
|
if options.RestartRetries != nil {
|
||||||
params.Set("restartRetries", strconv.Itoa(int(*options.Specgen.RestartRetries)))
|
params.Set("restartRetries", strconv.Itoa(int(*options.RestartRetries)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
updateEntities := &handlers.UpdateEntities{
|
updateEntities := &handlers.UpdateEntities{
|
||||||
LinuxResources: *options.Specgen.ResourceLimits,
|
LinuxResources: *options.Resources,
|
||||||
UpdateHealthCheckConfig: *options.ChangedHealthCheckConfiguration,
|
UpdateHealthCheckConfig: *options.ChangedHealthCheckConfiguration,
|
||||||
|
UpdateContainerDevicesLimits: *options.DevicesLimits,
|
||||||
}
|
}
|
||||||
requestData, err := jsoniter.MarshalToString(updateEntities)
|
requestData, err := jsoniter.MarshalToString(updateEntities)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -3,6 +3,7 @@ package types
|
||||||
import (
|
import (
|
||||||
"github.com/containers/podman/v5/libpod/define"
|
"github.com/containers/podman/v5/libpod/define"
|
||||||
"github.com/containers/podman/v5/pkg/specgen"
|
"github.com/containers/podman/v5/pkg/specgen"
|
||||||
|
"github.com/opencontainers/runtime-spec/specs-go"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ContainerCopyFunc func() error
|
type ContainerCopyFunc func() error
|
||||||
|
@ -37,6 +38,49 @@ type ContainerStatsReport struct {
|
||||||
|
|
||||||
type ContainerUpdateOptions struct {
|
type ContainerUpdateOptions struct {
|
||||||
NameOrID string
|
NameOrID string
|
||||||
|
// This individual items of Specgen are used to update container configuration:
|
||||||
|
// - ResourceLimits
|
||||||
|
// - RestartPolicy
|
||||||
|
// - RestartRetries
|
||||||
|
//
|
||||||
|
// Deprecated: Specgen should not be used to change the container configuration.
|
||||||
|
// Specgen is processed first, so values will be overwritten by values from other fields.
|
||||||
|
//
|
||||||
|
// To change configuration use other fields in ContainerUpdateOptions struct:
|
||||||
|
// - Resources to change resource configuration
|
||||||
|
// - DevicesLimits to Limit device
|
||||||
|
// - RestartPolicy to change restart policy
|
||||||
|
// - RestartRetries to change restart retries
|
||||||
Specgen *specgen.SpecGenerator
|
Specgen *specgen.SpecGenerator
|
||||||
|
Resources *specs.LinuxResources
|
||||||
|
DevicesLimits *define.UpdateContainerDevicesLimits
|
||||||
ChangedHealthCheckConfiguration *define.UpdateHealthCheckConfig
|
ChangedHealthCheckConfiguration *define.UpdateHealthCheckConfig
|
||||||
|
RestartPolicy *string
|
||||||
|
RestartRetries *uint
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *ContainerUpdateOptions) ProcessSpecgen() {
|
||||||
|
if u.Specgen == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if u.Resources == nil {
|
||||||
|
u.Resources = u.Specgen.ResourceLimits
|
||||||
|
}
|
||||||
|
|
||||||
|
if u.DevicesLimits == nil {
|
||||||
|
u.DevicesLimits = new(define.UpdateContainerDevicesLimits)
|
||||||
|
u.DevicesLimits.SetBlkIOWeightDevice(u.Specgen.WeightDevice)
|
||||||
|
u.DevicesLimits.SetDeviceReadBPs(u.Specgen.ThrottleReadBpsDevice)
|
||||||
|
u.DevicesLimits.SetDeviceWriteBPs(u.Specgen.ThrottleWriteBpsDevice)
|
||||||
|
u.DevicesLimits.SetDeviceReadIOPs(u.Specgen.ThrottleReadIOPSDevice)
|
||||||
|
u.DevicesLimits.SetDeviceWriteIOPs(u.Specgen.ThrottleWriteIOPSDevice)
|
||||||
|
}
|
||||||
|
|
||||||
|
if u.RestartPolicy == nil {
|
||||||
|
u.RestartPolicy = &u.Specgen.RestartPolicy
|
||||||
|
}
|
||||||
|
if u.RestartRetries == nil {
|
||||||
|
u.RestartRetries = u.Specgen.RestartRetries
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1792,14 +1792,7 @@ func (ic *ContainerEngine) ContainerClone(ctx context.Context, ctrCloneOpts enti
|
||||||
|
|
||||||
// ContainerUpdate finds and updates the given container's cgroup config with the specified options
|
// ContainerUpdate finds and updates the given container's cgroup config with the specified options
|
||||||
func (ic *ContainerEngine) ContainerUpdate(ctx context.Context, updateOptions *entities.ContainerUpdateOptions) (string, error) {
|
func (ic *ContainerEngine) ContainerUpdate(ctx context.Context, updateOptions *entities.ContainerUpdateOptions) (string, error) {
|
||||||
err := specgen.WeightDevices(updateOptions.Specgen)
|
updateOptions.ProcessSpecgen()
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
err = specgen.FinishThrottleDevices(updateOptions.Specgen)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
containers, err := getContainers(ic.Libpod, getContainersOptions{names: []string{updateOptions.NameOrID}})
|
containers, err := getContainers(ic.Libpod, getContainersOptions{names: []string{updateOptions.NameOrID}})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
|
@ -1809,12 +1802,12 @@ func (ic *ContainerEngine) ContainerUpdate(ctx context.Context, updateOptions *e
|
||||||
}
|
}
|
||||||
container := containers[0].Container
|
container := containers[0].Container
|
||||||
|
|
||||||
var restartPolicy *string
|
resourceLimits, err := specgenutil.UpdateMajorAndMinorNumbers(updateOptions.Resources, updateOptions.DevicesLimits)
|
||||||
if updateOptions.Specgen.RestartPolicy != "" {
|
if err != nil {
|
||||||
restartPolicy = &updateOptions.Specgen.RestartPolicy
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = container.Update(updateOptions.Specgen.ResourceLimits, restartPolicy, updateOptions.Specgen.RestartRetries, updateOptions.ChangedHealthCheckConfiguration); err != nil {
|
if err = container.Update(resourceLimits, updateOptions.RestartPolicy, updateOptions.RestartRetries, updateOptions.ChangedHealthCheckConfiguration); err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
return containers[0].ID(), nil
|
return containers[0].ID(), nil
|
||||||
|
|
|
@ -1061,13 +1061,6 @@ func (ic *ContainerEngine) ContainerClone(ctx context.Context, ctrCloneOpts enti
|
||||||
|
|
||||||
// ContainerUpdate finds and updates the given container's cgroup config with the specified options
|
// ContainerUpdate finds and updates the given container's cgroup config with the specified options
|
||||||
func (ic *ContainerEngine) ContainerUpdate(ctx context.Context, updateOptions *entities.ContainerUpdateOptions) (string, error) {
|
func (ic *ContainerEngine) ContainerUpdate(ctx context.Context, updateOptions *entities.ContainerUpdateOptions) (string, error) {
|
||||||
err := specgen.WeightDevices(updateOptions.Specgen)
|
updateOptions.ProcessSpecgen()
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
err = specgen.FinishThrottleDevices(updateOptions.Specgen)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
return containers.Update(ic.ClientCtx, updateOptions)
|
return containers.Update(ic.ClientCtx, updateOptions)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1297,3 +1297,27 @@ func GetResources(s *specgen.SpecGenerator, c *entities.ContainerCreateOptions)
|
||||||
}
|
}
|
||||||
return s.ResourceLimits, nil
|
return s.ResourceLimits, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func UpdateMajorAndMinorNumbers(resources *specs.LinuxResources, devicesLimits *define.UpdateContainerDevicesLimits) (*specs.LinuxResources, error) {
|
||||||
|
spec := specgen.SpecGenerator{}
|
||||||
|
spec.ResourceLimits = &specs.LinuxResources{}
|
||||||
|
if resources != nil {
|
||||||
|
spec.ResourceLimits = resources
|
||||||
|
}
|
||||||
|
|
||||||
|
spec.WeightDevice = devicesLimits.GetMapOfLinuxWeightDevice()
|
||||||
|
spec.ThrottleReadBpsDevice = devicesLimits.GetMapOfDeviceReadBPs()
|
||||||
|
spec.ThrottleWriteBpsDevice = devicesLimits.GetMapOfDeviceWriteBPs()
|
||||||
|
spec.ThrottleReadIOPSDevice = devicesLimits.GetMapOfDeviceReadIOPs()
|
||||||
|
spec.ThrottleWriteIOPSDevice = devicesLimits.GetMapOfDeviceWriteIOPs()
|
||||||
|
|
||||||
|
err := specgen.WeightDevices(&spec)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
err = specgen.FinishThrottleDevices(&spec)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return spec.ResourceLimits, nil
|
||||||
|
}
|
||||||
|
|
|
@ -686,19 +686,57 @@ t GET libpod/containers/$cname/json 200 \
|
||||||
|
|
||||||
if root; then
|
if root; then
|
||||||
podman run -dt --name=updateCtr alpine
|
podman run -dt --name=updateCtr alpine
|
||||||
echo '{"Memory":{"Limit":500000}, "CPU":{"Shares":123}}' >${TMPD}/update.json
|
echo '{
|
||||||
|
"Memory":{"Limit":500000},
|
||||||
|
"CPU":{"Shares":123},
|
||||||
|
"DeviceReadBPs": [{ "Path": "/dev/zero", "Rate": 10485760 }],
|
||||||
|
"DeviceWriteBPs": [{ "Path": "/dev/zero", "Rate": 31457280 }],
|
||||||
|
"DeviceReadIOPs": [{ "Path": "/dev/zero", "Rate": 2000 }],
|
||||||
|
"DeviceWriteIOPs": [{ "Path": "/dev/zero", "Rate": 4000 }]
|
||||||
|
}' >${TMPD}/update.json
|
||||||
t POST libpod/containers/updateCtr/update ${TMPD}/update.json 201
|
t POST libpod/containers/updateCtr/update ${TMPD}/update.json 201
|
||||||
|
|
||||||
cgroupPath=/sys/fs/cgroup/cpu.weight
|
cgroupPath=/sys/fs/cgroup/cpu.weight
|
||||||
# 002 is the byte length
|
# 002 is the byte length
|
||||||
cpu_weight_expect=$'\001\0025'
|
cpu_weight_expect=$'\001\0025'
|
||||||
|
|
||||||
# Verify
|
# Verify CPU weight
|
||||||
echo '{ "AttachStdout":true,"Cmd":["cat", "'$cgroupPath'"]}' >${TMPD}/exec.json
|
echo '{ "AttachStdout":true,"Cmd":["cat", "'$cgroupPath'"]}' >${TMPD}/exec.json
|
||||||
t POST containers/updateCtr/exec ${TMPD}/exec.json 201 .Id~[0-9a-f]\\{64\\}
|
t POST containers/updateCtr/exec ${TMPD}/exec.json 201 .Id~[0-9a-f]\\{64\\}
|
||||||
eid=$(jq -r '.Id' <<<"$output")
|
eid=$(jq -r '.Id' <<<"$output")
|
||||||
t POST exec/$eid/start 200 $cpu_weight_expect
|
t POST exec/$eid/start 200 $cpu_weight_expect
|
||||||
|
|
||||||
|
BlkioDeviceReadBps_expected='[
|
||||||
|
{
|
||||||
|
"Path": "/dev/zero",
|
||||||
|
"Rate": 10485760
|
||||||
|
}
|
||||||
|
]'
|
||||||
|
BlkioDeviceWriteBPs_expected='[
|
||||||
|
{
|
||||||
|
"Path": "/dev/zero",
|
||||||
|
"Rate": 31457280
|
||||||
|
}
|
||||||
|
]'
|
||||||
|
BlkioDeviceReadIOPs_expected='[
|
||||||
|
{
|
||||||
|
"Path": "/dev/zero",
|
||||||
|
"Rate": 2000
|
||||||
|
}
|
||||||
|
]'
|
||||||
|
BlkioDeviceWriteIOPs_expected='[
|
||||||
|
{
|
||||||
|
"Path": "/dev/zero",
|
||||||
|
"Rate": 4000
|
||||||
|
}
|
||||||
|
]'
|
||||||
|
# Verify Device limits
|
||||||
|
t GET containers/updateCtr/json 200 \
|
||||||
|
.HostConfig.BlkioDeviceReadBps="$BlkioDeviceReadBps_expected" \
|
||||||
|
.HostConfig.BlkioDeviceWriteBps="$BlkioDeviceWriteBPs_expected" \
|
||||||
|
.HostConfig.BlkioDeviceReadIOps="$BlkioDeviceReadIOPs_expected" \
|
||||||
|
.HostConfig.BlkioDeviceWriteIOps="$BlkioDeviceWriteIOPs_expected" \
|
||||||
|
|
||||||
# Now use the compat API
|
# Now use the compat API
|
||||||
echo '{ "Memory": 536870912 }' >${TMPD}/compatupdate.json
|
echo '{ "Memory": 536870912 }' >${TMPD}/compatupdate.json
|
||||||
t POST containers/updateCtr/update ${TMPD}/compatupdate.json 200
|
t POST containers/updateCtr/update ${TMPD}/compatupdate.json 200
|
||||||
|
|
Loading…
Reference in New Issue