summaryrefslogtreecommitdiff
path: root/pkg
diff options
context:
space:
mode:
Diffstat (limited to 'pkg')
-rw-r--r--pkg/api/handlers/libpod/containers.go25
-rw-r--r--pkg/api/handlers/swagger/responses.go5
-rw-r--r--pkg/api/handlers/types.go7
-rw-r--r--pkg/api/server/register_containers.go30
-rw-r--r--pkg/api/server/register_secrets.go2
-rw-r--r--pkg/bindings/containers/update.go31
-rw-r--r--pkg/domain/entities/containers.go6
-rw-r--r--pkg/domain/entities/engine_container.go1
-rw-r--r--pkg/domain/entities/pods.go9
-rw-r--r--pkg/domain/infra/abi/containers.go24
-rw-r--r--pkg/domain/infra/tunnel/containers.go13
-rw-r--r--pkg/machine/machine_windows.go20
-rw-r--r--pkg/machine/qemu/machine.go24
-rw-r--r--pkg/machine/qemu/machine_unix.go33
-rw-r--r--pkg/machine/qemu/machine_unsupported.go4
-rw-r--r--pkg/machine/qemu/machine_windows.go27
-rw-r--r--pkg/machine/qemu/options_windows.go13
-rw-r--r--pkg/machine/wsl/machine.go2
-rw-r--r--pkg/machine/wsl/util_windows.go12
-rw-r--r--pkg/specgen/generate/container.go70
-rw-r--r--pkg/specgen/generate/container_create.go2
-rw-r--r--pkg/specgen/generate/kube/kube.go7
-rw-r--r--pkg/specgen/generate/pod_create.go12
-rw-r--r--pkg/specgen/utils.go14
-rw-r--r--pkg/specgen/utils_linux.go103
-rw-r--r--pkg/specgenutil/specgen.go85
26 files changed, 424 insertions, 157 deletions
diff --git a/pkg/api/handlers/libpod/containers.go b/pkg/api/handlers/libpod/containers.go
index 5d85d4009..d1460569f 100644
--- a/pkg/api/handlers/libpod/containers.go
+++ b/pkg/api/handlers/libpod/containers.go
@@ -1,6 +1,7 @@
package libpod
import (
+ "encoding/json"
"errors"
"fmt"
"io/ioutil"
@@ -10,6 +11,7 @@ import (
"github.com/containers/podman/v4/libpod"
"github.com/containers/podman/v4/libpod/define"
+ "github.com/containers/podman/v4/pkg/api/handlers"
"github.com/containers/podman/v4/pkg/api/handlers/compat"
"github.com/containers/podman/v4/pkg/api/handlers/utils"
api "github.com/containers/podman/v4/pkg/api/types"
@@ -17,6 +19,7 @@ import (
"github.com/containers/podman/v4/pkg/domain/infra/abi"
"github.com/containers/podman/v4/pkg/util"
"github.com/gorilla/schema"
+ "github.com/opencontainers/runtime-spec/specs-go"
"github.com/sirupsen/logrus"
)
@@ -391,6 +394,28 @@ func InitContainer(w http.ResponseWriter, r *http.Request) {
utils.WriteResponse(w, http.StatusNoContent, "")
}
+func UpdateContainer(w http.ResponseWriter, r *http.Request) {
+ name := utils.GetName(r)
+ runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
+ ctr, err := runtime.LookupContainer(name)
+ if err != nil {
+ utils.ContainerNotFound(w, name, err)
+ return
+ }
+
+ options := &handlers.UpdateEntities{Resources: &specs.LinuxResources{}}
+ if err := json.NewDecoder(r.Body).Decode(&options.Resources); err != nil {
+ utils.Error(w, http.StatusInternalServerError, fmt.Errorf("decode(): %w", err))
+ return
+ }
+ err = ctr.Update(options.Resources)
+ if err != nil {
+ utils.InternalServerError(w, err)
+ return
+ }
+ utils.WriteResponse(w, http.StatusCreated, ctr.ID())
+}
+
func ShouldRestart(w http.ResponseWriter, r *http.Request) {
runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
// Now use the ABI implementation to prevent us from having duplicate
diff --git a/pkg/api/handlers/swagger/responses.go b/pkg/api/handlers/swagger/responses.go
index 93a508b39..3de9b06e9 100644
--- a/pkg/api/handlers/swagger/responses.go
+++ b/pkg/api/handlers/swagger/responses.go
@@ -313,6 +313,11 @@ type containerCreateResponse struct {
Body entities.ContainerCreateResponse
}
+type containerUpdateResponse struct {
+ // in:body
+ ID string
+}
+
// Wait container
// swagger:response
type containerWaitResponse struct {
diff --git a/pkg/api/handlers/types.go b/pkg/api/handlers/types.go
index aab905878..bb416d9f4 100644
--- a/pkg/api/handlers/types.go
+++ b/pkg/api/handlers/types.go
@@ -11,6 +11,7 @@ import (
dockerContainer "github.com/docker/docker/api/types/container"
dockerNetwork "github.com/docker/docker/api/types/network"
"github.com/docker/go-connections/nat"
+ "github.com/opencontainers/runtime-spec/specs-go"
)
type AuthConfig struct {
@@ -64,6 +65,12 @@ type LibpodContainersRmReport struct {
RmError string `json:"Err,omitempty"`
}
+// UpdateEntities used to wrap the oci resource spec in a swagger model
+// swagger:model
+type UpdateEntities struct {
+ Resources *specs.LinuxResources
+}
+
type Info struct {
docker.Info
BuildahVersion string
diff --git a/pkg/api/server/register_containers.go b/pkg/api/server/register_containers.go
index 8aba4ea05..7e9c02816 100644
--- a/pkg/api/server/register_containers.go
+++ b/pkg/api/server/register_containers.go
@@ -212,7 +212,6 @@ func (s *APIServer) registerContainersHandlers(r *mux.Router) error {
// - in: query
// name: signal
// type: string
- // default: TERM
// description: signal to be sent to container
// default: SIGKILL
// produces:
@@ -723,6 +722,7 @@ func (s *APIServer) registerContainersHandlers(r *mux.Router) error {
// type: boolean
// description: Include namespace information
// default: false
+ // - in: query
// name: pod
// type: boolean
// default: false
@@ -1626,5 +1626,33 @@ func (s *APIServer) registerContainersHandlers(r *mux.Router) error {
// 500:
// $ref: "#/responses/internalError"
r.HandleFunc(VersionedPath("/libpod/containers/{name}/rename"), s.APIHandler(compat.RenameContainer)).Methods(http.MethodPost)
+ // swagger:operation POST /libpod/containers/{name}/update libpod ContainerUpdateLibpod
+ // ---
+ // tags:
+ // - containers
+ // summary: Update an existing containers cgroup configuration
+ // description: Update an existing containers cgroup configuration.
+ // parameters:
+ // - in: path
+ // name: name
+ // type: string
+ // required: true
+ // description: Full or partial ID or full name of the container to update
+ // - in: body
+ // name: resources
+ // description: attributes for updating the container
+ // schema:
+ // $ref: "#/definitions/UpdateEntities"
+ // produces:
+ // - application/json
+ // responses:
+ // responses:
+ // 201:
+ // $ref: "#/responses/containerUpdateResponse"
+ // 404:
+ // $ref: "#/responses/containerNotFound"
+ // 500:
+ // $ref: "#/responses/internalError"
+ r.HandleFunc(VersionedPath("/libpod/containers/{name}/update"), s.APIHandler(libpod.UpdateContainer)).Methods(http.MethodPost)
return nil
}
diff --git a/pkg/api/server/register_secrets.go b/pkg/api/server/register_secrets.go
index f4608baa6..8918ad238 100644
--- a/pkg/api/server/register_secrets.go
+++ b/pkg/api/server/register_secrets.go
@@ -54,7 +54,6 @@ func (s *APIServer) registerSecretHandlers(r *mux.Router) error {
// - `id=[id]` Matches for full or partial ID.
// produces:
// - application/json
- // parameters:
// responses:
// '200':
// "$ref": "#/responses/SecretListResponse"
@@ -128,7 +127,6 @@ func (s *APIServer) registerSecretHandlers(r *mux.Router) error {
// - `id=[id]` Matches for full or partial ID.
// produces:
// - application/json
- // parameters:
// responses:
// '200':
// "$ref": "#/responses/SecretListCompatResponse"
diff --git a/pkg/bindings/containers/update.go b/pkg/bindings/containers/update.go
new file mode 100644
index 000000000..7cda7c306
--- /dev/null
+++ b/pkg/bindings/containers/update.go
@@ -0,0 +1,31 @@
+package containers
+
+import (
+ "context"
+ "net/http"
+ "strings"
+
+ "github.com/containers/podman/v4/pkg/bindings"
+ "github.com/containers/podman/v4/pkg/domain/entities"
+ jsoniter "github.com/json-iterator/go"
+)
+
+func Update(ctx context.Context, options *entities.ContainerUpdateOptions) (string, error) {
+ conn, err := bindings.GetClient(ctx)
+ if err != nil {
+ return "", err
+ }
+
+ resources, err := jsoniter.MarshalToString(options.Specgen.ResourceLimits)
+ if err != nil {
+ return "", err
+ }
+ stringReader := strings.NewReader(resources)
+ response, err := conn.DoRequest(ctx, stringReader, http.MethodPost, "/containers/%s/update", nil, nil, options.NameOrID)
+ if err != nil {
+ return "", err
+ }
+ defer response.Body.Close()
+
+ return options.NameOrID, response.Process(nil)
+}
diff --git a/pkg/domain/entities/containers.go b/pkg/domain/entities/containers.go
index 91ccdc2b2..47225f25c 100644
--- a/pkg/domain/entities/containers.go
+++ b/pkg/domain/entities/containers.go
@@ -495,3 +495,9 @@ type ContainerCloneOptions struct {
Run bool
Force bool
}
+
+// ContainerUpdateOptions containers options for updating an existing containers cgroup configuration
+type ContainerUpdateOptions struct {
+ NameOrID string
+ Specgen *specgen.SpecGenerator
+}
diff --git a/pkg/domain/entities/engine_container.go b/pkg/domain/entities/engine_container.go
index 6a766eb84..69adc9732 100644
--- a/pkg/domain/entities/engine_container.go
+++ b/pkg/domain/entities/engine_container.go
@@ -51,6 +51,7 @@ type ContainerEngine interface {
ContainerTop(ctx context.Context, options TopOptions) (*StringSliceReport, error)
ContainerUnmount(ctx context.Context, nameOrIDs []string, options ContainerUnmountOptions) ([]*ContainerUnmountReport, error)
ContainerUnpause(ctx context.Context, namesOrIds []string, options PauseUnPauseOptions) ([]*PauseUnpauseReport, error)
+ ContainerUpdate(ctx context.Context, options *ContainerUpdateOptions) (string, error)
ContainerWait(ctx context.Context, namesOrIds []string, options WaitOptions) ([]WaitReport, error)
Diff(ctx context.Context, namesOrIds []string, options DiffOptions) (*DiffReport, error)
Events(ctx context.Context, opts EventsOptions) error
diff --git a/pkg/domain/entities/pods.go b/pkg/domain/entities/pods.go
index 33ca2c807..b672434d8 100644
--- a/pkg/domain/entities/pods.go
+++ b/pkg/domain/entities/pods.go
@@ -164,6 +164,15 @@ type PodCloneOptions struct {
Start bool
}
+type ContainerMode string
+
+const (
+ InfraMode = ContainerMode("infra")
+ CloneMode = ContainerMode("clone")
+ UpdateMode = ContainerMode("update")
+ CreateMode = ContainerMode("create")
+)
+
type ContainerCreateOptions struct {
Annotation []string
Attach []string
diff --git a/pkg/domain/infra/abi/containers.go b/pkg/domain/infra/abi/containers.go
index 0a8e5bc2f..dfa3c5ba0 100644
--- a/pkg/domain/infra/abi/containers.go
+++ b/pkg/domain/infra/abi/containers.go
@@ -1715,3 +1715,27 @@ func (ic *ContainerEngine) ContainerClone(ctx context.Context, ctrCloneOpts enti
return &entities.ContainerCreateReport{Id: ctr.ID()}, nil
}
+
+// 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) {
+ err := specgen.WeightDevices(updateOptions.Specgen)
+ if err != nil {
+ return "", err
+ }
+ err = specgen.FinishThrottleDevices(updateOptions.Specgen)
+ if err != nil {
+ return "", err
+ }
+ ctrs, err := getContainersByContext(false, false, []string{updateOptions.NameOrID}, ic.Libpod)
+ if err != nil {
+ return "", err
+ }
+ if len(ctrs) != 1 {
+ return "", fmt.Errorf("container not found")
+ }
+
+ if err = ctrs[0].Update(updateOptions.Specgen.ResourceLimits); err != nil {
+ return "", err
+ }
+ return ctrs[0].ID(), nil
+}
diff --git a/pkg/domain/infra/tunnel/containers.go b/pkg/domain/infra/tunnel/containers.go
index 023bee430..68ca788b8 100644
--- a/pkg/domain/infra/tunnel/containers.go
+++ b/pkg/domain/infra/tunnel/containers.go
@@ -1024,3 +1024,16 @@ func (ic *ContainerEngine) ContainerRename(ctx context.Context, nameOrID string,
func (ic *ContainerEngine) ContainerClone(ctx context.Context, ctrCloneOpts entities.ContainerCloneOptions) (*entities.ContainerCreateReport, error) {
return nil, errors.New("cloning a container is not supported on the remote client")
}
+
+// 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) {
+ err := specgen.WeightDevices(updateOptions.Specgen)
+ if err != nil {
+ return "", err
+ }
+ err = specgen.FinishThrottleDevices(updateOptions.Specgen)
+ if err != nil {
+ return "", err
+ }
+ return containers.Update(ic.ClientCtx, updateOptions)
+}
diff --git a/pkg/machine/machine_windows.go b/pkg/machine/machine_windows.go
new file mode 100644
index 000000000..c414986cf
--- /dev/null
+++ b/pkg/machine/machine_windows.go
@@ -0,0 +1,20 @@
+//go:build windows
+// +build windows
+
+package machine
+
+import (
+ "syscall"
+)
+
+func GetProcessState(pid int) (active bool, exitCode int) {
+ const da = syscall.STANDARD_RIGHTS_READ | syscall.PROCESS_QUERY_INFORMATION | syscall.SYNCHRONIZE
+ handle, err := syscall.OpenProcess(da, false, uint32(pid))
+ if err != nil {
+ return false, int(syscall.ERROR_PROC_NOT_FOUND)
+ }
+
+ var code uint32
+ syscall.GetExitCodeProcess(handle, &code)
+ return code == 259, int(code)
+}
diff --git a/pkg/machine/qemu/machine.go b/pkg/machine/qemu/machine.go
index e97b68e31..b59f07876 100644
--- a/pkg/machine/qemu/machine.go
+++ b/pkg/machine/qemu/machine.go
@@ -1,5 +1,5 @@
-//go:build (amd64 && !windows) || (arm64 && !windows)
-// +build amd64,!windows arm64,!windows
+//go:build amd64 || arm64
+// +build amd64 arm64
package qemu
@@ -33,7 +33,6 @@ import (
"github.com/digitalocean/go-qemu/qmp"
"github.com/docker/go-units"
"github.com/sirupsen/logrus"
- "golang.org/x/sys/unix"
)
var (
@@ -125,7 +124,7 @@ func (p *Provider) NewMachine(opts machine.InitOptions) (machine.VM, error) {
return nil, err
}
vm.QMPMonitor = monitor
- cmd = append(cmd, []string{"-qmp", monitor.Network + ":/" + monitor.Address.GetPath() + ",server=on,wait=off"}...)
+ cmd = append(cmd, []string{"-qmp", monitor.Network + ":" + monitor.Address.GetPath() + ",server=on,wait=off"}...)
// Add network
// Right now the mac address is hardcoded so that the host networking gives it a specific IP address. This is
@@ -629,14 +628,9 @@ func (v *MachineVM) Start(name string, _ machine.StartOptions) error {
break
}
// check if qemu is still alive
- var status syscall.WaitStatus
- pid, err := syscall.Wait4(cmd.Process.Pid, &status, syscall.WNOHANG, nil)
+ err := checkProcessStatus("qemu", cmd.Process.Pid, stderrBuf)
if err != nil {
- return fmt.Errorf("failed to read qemu process status: %w", err)
- }
- if pid > 0 {
- // child exited
- return fmt.Errorf("qemu exited unexpectedly with exit code %d, stderr: %s", status.ExitStatus(), stderrBuf.String())
+ return err
}
time.Sleep(wait)
wait++
@@ -1724,14 +1718,6 @@ func (p *Provider) RemoveAndCleanMachines() error {
return prevErr
}
-func isProcessAlive(pid int) bool {
- err := unix.Kill(pid, syscall.Signal(0))
- if err == nil || err == unix.EPERM {
- return true
- }
- return false
-}
-
func (p *Provider) VMType() string {
return vmtype
}
diff --git a/pkg/machine/qemu/machine_unix.go b/pkg/machine/qemu/machine_unix.go
new file mode 100644
index 000000000..84ee191d1
--- /dev/null
+++ b/pkg/machine/qemu/machine_unix.go
@@ -0,0 +1,33 @@
+//go:build darwin || dragonfly || freebsd || linux || netbsd || openbsd
+// +build darwin dragonfly freebsd linux netbsd openbsd
+
+package qemu
+
+import (
+ "bytes"
+ "fmt"
+ "syscall"
+
+ "golang.org/x/sys/unix"
+)
+
+func isProcessAlive(pid int) bool {
+ err := unix.Kill(pid, syscall.Signal(0))
+ if err == nil || err == unix.EPERM {
+ return true
+ }
+ return false
+}
+
+func checkProcessStatus(processHint string, pid int, stderrBuf *bytes.Buffer) error {
+ var status syscall.WaitStatus
+ pid, err := syscall.Wait4(pid, &status, syscall.WNOHANG, nil)
+ if err != nil {
+ return fmt.Errorf("failed to read qem%su process status: %w", processHint, err)
+ }
+ if pid > 0 {
+ // child exited
+ return fmt.Errorf("%s exited unexpectedly with exit code %d, stderr: %s", processHint, status.ExitStatus(), stderrBuf.String())
+ }
+ return nil
+}
diff --git a/pkg/machine/qemu/machine_unsupported.go b/pkg/machine/qemu/machine_unsupported.go
index 794e710f9..7a9a2531d 100644
--- a/pkg/machine/qemu/machine_unsupported.go
+++ b/pkg/machine/qemu/machine_unsupported.go
@@ -1,4 +1,4 @@
-//go:build (!amd64 && !arm64) || windows
-// +build !amd64,!arm64 windows
+//go:build (!amd64 && !arm64)
+// +build !amd64,!arm64
package qemu
diff --git a/pkg/machine/qemu/machine_windows.go b/pkg/machine/qemu/machine_windows.go
new file mode 100644
index 000000000..6c63faf50
--- /dev/null
+++ b/pkg/machine/qemu/machine_windows.go
@@ -0,0 +1,27 @@
+package qemu
+
+import (
+ "bytes"
+ "fmt"
+
+ "github.com/containers/podman/v4/pkg/machine"
+)
+
+func isProcessAlive(pid int) bool {
+ if checkProcessStatus("process", pid, nil) == nil {
+ return true
+ }
+ return false
+}
+
+func checkProcessStatus(processHint string, pid int, stderrBuf *bytes.Buffer) error {
+ active, exitCode := machine.GetProcessState(pid)
+ if !active {
+ if stderrBuf != nil {
+ return fmt.Errorf("%s exited unexpectedly, exit code: %d stderr: %s", processHint, exitCode, stderrBuf.String())
+ } else {
+ return fmt.Errorf("%s exited unexpectedly, exit code: %d", processHint, exitCode)
+ }
+ }
+ return nil
+}
diff --git a/pkg/machine/qemu/options_windows.go b/pkg/machine/qemu/options_windows.go
new file mode 100644
index 000000000..69652ee39
--- /dev/null
+++ b/pkg/machine/qemu/options_windows.go
@@ -0,0 +1,13 @@
+package qemu
+
+import (
+ "os"
+)
+
+func getRuntimeDir() (string, error) {
+ tmpDir, ok := os.LookupEnv("TEMP")
+ if !ok {
+ tmpDir = os.Getenv("LOCALAPPDATA") + "\\Temp"
+ }
+ return tmpDir, nil
+}
diff --git a/pkg/machine/wsl/machine.go b/pkg/machine/wsl/machine.go
index 8f6ef7a43..b89e2f720 100644
--- a/pkg/machine/wsl/machine.go
+++ b/pkg/machine/wsl/machine.go
@@ -1063,7 +1063,7 @@ func launchWinProxy(v *MachineVM) (bool, string, error) {
}
return globalName, pipePrefix + waitPipe, waitPipeExists(waitPipe, 30, func() error {
- active, exitCode := getProcessState(cmd.Process.Pid)
+ active, exitCode := machine.GetProcessState(cmd.Process.Pid)
if !active {
return fmt.Errorf("win-sshproxy.exe failed to start, exit code: %d (see windows event logs)", exitCode)
}
diff --git a/pkg/machine/wsl/util_windows.go b/pkg/machine/wsl/util_windows.go
index 43f54fdd4..6c74e5652 100644
--- a/pkg/machine/wsl/util_windows.go
+++ b/pkg/machine/wsl/util_windows.go
@@ -280,18 +280,6 @@ func obtainShutdownPrivilege() error {
return nil
}
-func getProcessState(pid int) (active bool, exitCode int) {
- const da = syscall.STANDARD_RIGHTS_READ | syscall.PROCESS_QUERY_INFORMATION | syscall.SYNCHRONIZE
- handle, err := syscall.OpenProcess(da, false, uint32(pid))
- if err != nil {
- return false, int(syscall.ERROR_PROC_NOT_FOUND)
- }
-
- var code uint32
- syscall.GetExitCodeProcess(handle, &code)
- return code == 259, int(code)
-}
-
func addRunOnceRegistryEntry(command string) error {
k, _, err := registry.CreateKey(registry.CURRENT_USER, `Software\Microsoft\Windows\CurrentVersion\RunOnce`, registry.WRITE)
if err != nil {
diff --git a/pkg/specgen/generate/container.go b/pkg/specgen/generate/container.go
index d57efa0d1..46b7a2dc2 100644
--- a/pkg/specgen/generate/container.go
+++ b/pkg/specgen/generate/container.go
@@ -21,7 +21,6 @@ import (
spec "github.com/opencontainers/runtime-spec/specs-go"
"github.com/openshift/imagebuilder"
"github.com/sirupsen/logrus"
- "golang.org/x/sys/unix"
)
func getImageFromSpec(ctx context.Context, r *libpod.Runtime, s *specgen.SpecGenerator) (*libimage.Image, string, *libimage.ImageData, error) {
@@ -518,75 +517,6 @@ func mapSecurityConfig(c *libpod.ContainerConfig, s *specgen.SpecGenerator) {
s.HostUsers = c.HostUsers
}
-// FinishThrottleDevices takes the temporary representation of the throttle
-// devices in the specgen and looks up the major and major minors. it then
-// sets the throttle devices proper in the specgen
-func FinishThrottleDevices(s *specgen.SpecGenerator) error {
- if s.ResourceLimits == nil {
- s.ResourceLimits = &spec.LinuxResources{}
- }
- if bps := s.ThrottleReadBpsDevice; len(bps) > 0 {
- if s.ResourceLimits.BlockIO == nil {
- s.ResourceLimits.BlockIO = &spec.LinuxBlockIO{}
- }
- for k, v := range bps {
- statT := unix.Stat_t{}
- if err := unix.Stat(k, &statT); err != nil {
- return fmt.Errorf("could not parse throttle device at %s: %w", k, err)
- }
- v.Major = (int64(unix.Major(uint64(statT.Rdev)))) //nolint: unconvert
- v.Minor = (int64(unix.Minor(uint64(statT.Rdev)))) //nolint: unconvert
- if s.ResourceLimits.BlockIO == nil {
- s.ResourceLimits.BlockIO = new(spec.LinuxBlockIO)
- }
- s.ResourceLimits.BlockIO.ThrottleReadBpsDevice = append(s.ResourceLimits.BlockIO.ThrottleReadBpsDevice, v)
- }
- }
- if bps := s.ThrottleWriteBpsDevice; len(bps) > 0 {
- if s.ResourceLimits.BlockIO == nil {
- s.ResourceLimits.BlockIO = &spec.LinuxBlockIO{}
- }
- for k, v := range bps {
- statT := unix.Stat_t{}
- if err := unix.Stat(k, &statT); err != nil {
- return fmt.Errorf("could not parse throttle device at %s: %w", k, err)
- }
- v.Major = (int64(unix.Major(uint64(statT.Rdev)))) //nolint: unconvert
- v.Minor = (int64(unix.Minor(uint64(statT.Rdev)))) //nolint: unconvert
- s.ResourceLimits.BlockIO.ThrottleWriteBpsDevice = append(s.ResourceLimits.BlockIO.ThrottleWriteBpsDevice, v)
- }
- }
- if iops := s.ThrottleReadIOPSDevice; len(iops) > 0 {
- if s.ResourceLimits.BlockIO == nil {
- s.ResourceLimits.BlockIO = &spec.LinuxBlockIO{}
- }
- for k, v := range iops {
- statT := unix.Stat_t{}
- if err := unix.Stat(k, &statT); err != nil {
- return fmt.Errorf("could not parse throttle device at %s: %w", k, err)
- }
- v.Major = (int64(unix.Major(uint64(statT.Rdev)))) //nolint: unconvert
- v.Minor = (int64(unix.Minor(uint64(statT.Rdev)))) //nolint: unconvert
- s.ResourceLimits.BlockIO.ThrottleReadIOPSDevice = append(s.ResourceLimits.BlockIO.ThrottleReadIOPSDevice, v)
- }
- }
- if iops := s.ThrottleWriteIOPSDevice; len(iops) > 0 {
- if s.ResourceLimits.BlockIO == nil {
- s.ResourceLimits.BlockIO = &spec.LinuxBlockIO{}
- }
- for k, v := range iops {
- statT := unix.Stat_t{}
- if err := unix.Stat(k, &statT); err != nil {
- return fmt.Errorf("could not parse throttle device at %s: %w", k, err)
- }
- v.Major = (int64(unix.Major(uint64(statT.Rdev)))) //nolint: unconvert
- v.Minor = (int64(unix.Minor(uint64(statT.Rdev)))) //nolint: unconvert
- s.ResourceLimits.BlockIO.ThrottleWriteIOPSDevice = append(s.ResourceLimits.BlockIO.ThrottleWriteIOPSDevice, v)
- }
- }
- return nil
-}
-
// Check name looks for existing containers/pods with the same name, and modifies the given string until a new name is found
func CheckName(rt *libpod.Runtime, n string, kind bool) string {
switch {
diff --git a/pkg/specgen/generate/container_create.go b/pkg/specgen/generate/container_create.go
index 819800176..4d5ac22ad 100644
--- a/pkg/specgen/generate/container_create.go
+++ b/pkg/specgen/generate/container_create.go
@@ -56,7 +56,7 @@ func MakeContainer(ctx context.Context, rt *libpod.Runtime, s *specgen.SpecGener
}
}
- if err := FinishThrottleDevices(s); err != nil {
+ if err := specgen.FinishThrottleDevices(s); err != nil {
return nil, nil, nil, err
}
diff --git a/pkg/specgen/generate/kube/kube.go b/pkg/specgen/generate/kube/kube.go
index 375b719d3..5862d3f1c 100644
--- a/pkg/specgen/generate/kube/kube.go
+++ b/pkg/specgen/generate/kube/kube.go
@@ -357,8 +357,11 @@ func ToSpecGen(ctx context.Context, opts *CtrSpecGenOptions) (*specgen.SpecGener
// a selinux mount option exists for it
for k, v := range opts.Annotations {
// Make sure the z/Z option is not already there (from editing the YAML)
- if strings.Replace(k, define.BindMountPrefix, "", 1) == volumeSource.Source && !cutil.StringInSlice("z", options) && !cutil.StringInSlice("Z", options) {
- options = append(options, v)
+ if k == define.BindMountPrefix {
+ lastIndex := strings.LastIndex(v, ":")
+ if v[:lastIndex] == volumeSource.Source && !cutil.StringInSlice("z", options) && !cutil.StringInSlice("Z", options) {
+ options = append(options, v[lastIndex+1:])
+ }
}
}
mount := spec.Mount{
diff --git a/pkg/specgen/generate/pod_create.go b/pkg/specgen/generate/pod_create.go
index d6063b9a0..14d390e49 100644
--- a/pkg/specgen/generate/pod_create.go
+++ b/pkg/specgen/generate/pod_create.go
@@ -45,7 +45,7 @@ func MakePod(p *entities.PodSpec, rt *libpod.Runtime) (*libpod.Pod, error) {
}
if !p.PodSpecGen.NoInfra {
- err := FinishThrottleDevices(p.PodSpecGen.InfraContainerSpec)
+ err := specgen.FinishThrottleDevices(p.PodSpecGen.InfraContainerSpec)
if err != nil {
return nil, err
}
@@ -53,17 +53,11 @@ func MakePod(p *entities.PodSpec, rt *libpod.Runtime) (*libpod.Pod, error) {
p.PodSpecGen.ResourceLimits.BlockIO = p.PodSpecGen.InfraContainerSpec.ResourceLimits.BlockIO
}
- weightDevices, err := WeightDevices(p.PodSpecGen.InfraContainerSpec.WeightDevice)
+ err = specgen.WeightDevices(p.PodSpecGen.InfraContainerSpec)
if err != nil {
return nil, err
}
-
- if p.PodSpecGen.ResourceLimits != nil && len(weightDevices) > 0 {
- if p.PodSpecGen.ResourceLimits.BlockIO == nil {
- p.PodSpecGen.ResourceLimits.BlockIO = &specs.LinuxBlockIO{}
- }
- p.PodSpecGen.ResourceLimits.BlockIO.WeightDevice = weightDevices
- }
+ p.PodSpecGen.ResourceLimits = p.PodSpecGen.InfraContainerSpec.ResourceLimits
}
options, err := createPodOptions(&p.PodSpecGen)
diff --git a/pkg/specgen/utils.go b/pkg/specgen/utils.go
new file mode 100644
index 000000000..dc9127bb3
--- /dev/null
+++ b/pkg/specgen/utils.go
@@ -0,0 +1,14 @@
+//go:build !linux
+// +build !linux
+
+package specgen
+
+// FinishThrottleDevices cannot be called on non-linux OS' due to importing unix functions
+func FinishThrottleDevices(s *SpecGenerator) error {
+ return nil
+}
+
+// WeightDevices cannot be called on non-linux OS' due to importing unix functions
+func WeightDevices(s *SpecGenerator) error {
+ return nil
+}
diff --git a/pkg/specgen/utils_linux.go b/pkg/specgen/utils_linux.go
new file mode 100644
index 000000000..d8e4cbae3
--- /dev/null
+++ b/pkg/specgen/utils_linux.go
@@ -0,0 +1,103 @@
+//go:build linux
+// +build linux
+
+package specgen
+
+import (
+ "fmt"
+
+ spec "github.com/opencontainers/runtime-spec/specs-go"
+ "golang.org/x/sys/unix"
+)
+
+// FinishThrottleDevices takes the temporary representation of the throttle
+// devices in the specgen and looks up the major and major minors. it then
+// sets the throttle devices proper in the specgen
+func FinishThrottleDevices(s *SpecGenerator) error {
+ if s.ResourceLimits == nil {
+ s.ResourceLimits = &spec.LinuxResources{}
+ }
+ if bps := s.ThrottleReadBpsDevice; len(bps) > 0 {
+ if s.ResourceLimits.BlockIO == nil {
+ s.ResourceLimits.BlockIO = &spec.LinuxBlockIO{}
+ }
+ for k, v := range bps {
+ statT := unix.Stat_t{}
+ if err := unix.Stat(k, &statT); err != nil {
+ return fmt.Errorf("could not parse throttle device at %s: %w", k, err)
+ }
+ v.Major = (int64(unix.Major(uint64(statT.Rdev)))) //nolint: unconvert
+ v.Minor = (int64(unix.Minor(uint64(statT.Rdev)))) //nolint: unconvert
+ if s.ResourceLimits.BlockIO == nil {
+ s.ResourceLimits.BlockIO = new(spec.LinuxBlockIO)
+ }
+ s.ResourceLimits.BlockIO.ThrottleReadBpsDevice = append(s.ResourceLimits.BlockIO.ThrottleReadBpsDevice, v)
+ }
+ }
+ if bps := s.ThrottleWriteBpsDevice; len(bps) > 0 {
+ if s.ResourceLimits.BlockIO == nil {
+ s.ResourceLimits.BlockIO = &spec.LinuxBlockIO{}
+ }
+ for k, v := range bps {
+ statT := unix.Stat_t{}
+ if err := unix.Stat(k, &statT); err != nil {
+ return fmt.Errorf("could not parse throttle device at %s: %w", k, err)
+ }
+ v.Major = (int64(unix.Major(uint64(statT.Rdev)))) //nolint: unconvert
+ v.Minor = (int64(unix.Minor(uint64(statT.Rdev)))) //nolint: unconvert
+ s.ResourceLimits.BlockIO.ThrottleWriteBpsDevice = append(s.ResourceLimits.BlockIO.ThrottleWriteBpsDevice, v)
+ }
+ }
+ if iops := s.ThrottleReadIOPSDevice; len(iops) > 0 {
+ if s.ResourceLimits.BlockIO == nil {
+ s.ResourceLimits.BlockIO = &spec.LinuxBlockIO{}
+ }
+ for k, v := range iops {
+ statT := unix.Stat_t{}
+ if err := unix.Stat(k, &statT); err != nil {
+ return fmt.Errorf("could not parse throttle device at %s: %w", k, err)
+ }
+ v.Major = (int64(unix.Major(uint64(statT.Rdev)))) //nolint: unconvert
+ v.Minor = (int64(unix.Minor(uint64(statT.Rdev)))) //nolint: unconvert
+ s.ResourceLimits.BlockIO.ThrottleReadIOPSDevice = append(s.ResourceLimits.BlockIO.ThrottleReadIOPSDevice, v)
+ }
+ }
+ if iops := s.ThrottleWriteIOPSDevice; len(iops) > 0 {
+ if s.ResourceLimits.BlockIO == nil {
+ s.ResourceLimits.BlockIO = &spec.LinuxBlockIO{}
+ }
+ for k, v := range iops {
+ statT := unix.Stat_t{}
+ if err := unix.Stat(k, &statT); err != nil {
+ return fmt.Errorf("could not parse throttle device at %s: %w", k, err)
+ }
+ v.Major = (int64(unix.Major(uint64(statT.Rdev)))) //nolint: unconvert
+ v.Minor = (int64(unix.Minor(uint64(statT.Rdev)))) //nolint: unconvert
+ s.ResourceLimits.BlockIO.ThrottleWriteIOPSDevice = append(s.ResourceLimits.BlockIO.ThrottleWriteIOPSDevice, v)
+ }
+ }
+ return nil
+}
+
+func WeightDevices(specgen *SpecGenerator) error {
+ devs := []spec.LinuxWeightDevice{}
+ if specgen.ResourceLimits == nil {
+ specgen.ResourceLimits = &spec.LinuxResources{}
+ }
+ for k, v := range specgen.WeightDevice {
+ statT := unix.Stat_t{}
+ if err := unix.Stat(k, &statT); err != nil {
+ return fmt.Errorf("failed to inspect '%s' in --blkio-weight-device: %w", k, err)
+ }
+ dev := new(spec.LinuxWeightDevice)
+ dev.Major = (int64(unix.Major(uint64(statT.Rdev)))) //nolint: unconvert
+ dev.Minor = (int64(unix.Minor(uint64(statT.Rdev)))) //nolint: unconvert
+ dev.Weight = v.Weight
+ devs = append(devs, *dev)
+ if specgen.ResourceLimits.BlockIO == nil {
+ specgen.ResourceLimits.BlockIO = &spec.LinuxBlockIO{}
+ }
+ specgen.ResourceLimits.BlockIO.WeightDevice = devs
+ }
+ return nil
+}
diff --git a/pkg/specgenutil/specgen.go b/pkg/specgenutil/specgen.go
index d0e09fe72..439a13385 100644
--- a/pkg/specgenutil/specgen.go
+++ b/pkg/specgenutil/specgen.go
@@ -507,44 +507,9 @@ func FillOutSpecGen(s *specgen.SpecGenerator, c *entities.ContainerCreateOptions
s.ResourceLimits = &specs.LinuxResources{}
}
- if s.ResourceLimits.Memory == nil || (len(c.Memory) != 0 || len(c.MemoryReservation) != 0 || len(c.MemorySwap) != 0 || c.MemorySwappiness != 0) {
- s.ResourceLimits.Memory, err = getMemoryLimits(c)
- if err != nil {
- return err
- }
- }
- if s.ResourceLimits.BlockIO == nil || (len(c.BlkIOWeight) != 0 || len(c.BlkIOWeightDevice) != 0 || len(c.DeviceReadBPs) != 0 || len(c.DeviceWriteBPs) != 0) {
- s.ResourceLimits.BlockIO, err = getIOLimits(s, c)
- if err != nil {
- return err
- }
- }
- if c.PIDsLimit != nil {
- pids := specs.LinuxPids{
- Limit: *c.PIDsLimit,
- }
-
- s.ResourceLimits.Pids = &pids
- }
-
- if s.ResourceLimits.CPU == nil || (c.CPUPeriod != 0 || c.CPUQuota != 0 || c.CPURTPeriod != 0 || c.CPURTRuntime != 0 || c.CPUS != 0 || len(c.CPUSetCPUs) != 0 || len(c.CPUSetMems) != 0 || c.CPUShares != 0) {
- s.ResourceLimits.CPU = getCPULimits(c)
- }
-
- unifieds := make(map[string]string)
- for _, unified := range c.CgroupConf {
- splitUnified := strings.SplitN(unified, "=", 2)
- if len(splitUnified) < 2 {
- return errors.New("--cgroup-conf must be formatted KEY=VALUE")
- }
- unifieds[splitUnified[0]] = splitUnified[1]
- }
- if len(unifieds) > 0 {
- s.ResourceLimits.Unified = unifieds
- }
-
- if s.ResourceLimits.CPU == nil && s.ResourceLimits.Pids == nil && s.ResourceLimits.BlockIO == nil && s.ResourceLimits.Memory == nil && s.ResourceLimits.Unified == nil {
- s.ResourceLimits = nil
+ s.ResourceLimits, err = GetResources(s, c)
+ if err != nil {
+ return err
}
if s.LogConfiguration == nil {
@@ -1171,3 +1136,47 @@ func parseLinuxResourcesDeviceAccess(device string) (specs.LinuxDeviceCgroup, er
Access: access,
}, nil
}
+
+func GetResources(s *specgen.SpecGenerator, c *entities.ContainerCreateOptions) (*specs.LinuxResources, error) {
+ var err error
+ if s.ResourceLimits.Memory == nil || (len(c.Memory) != 0 || len(c.MemoryReservation) != 0 || len(c.MemorySwap) != 0 || c.MemorySwappiness != 0) {
+ s.ResourceLimits.Memory, err = getMemoryLimits(c)
+ if err != nil {
+ return nil, err
+ }
+ }
+ if s.ResourceLimits.BlockIO == nil || (len(c.BlkIOWeight) != 0 || len(c.BlkIOWeightDevice) != 0 || len(c.DeviceReadBPs) != 0 || len(c.DeviceWriteBPs) != 0) {
+ s.ResourceLimits.BlockIO, err = getIOLimits(s, c)
+ if err != nil {
+ return nil, err
+ }
+ }
+ if c.PIDsLimit != nil {
+ pids := specs.LinuxPids{
+ Limit: *c.PIDsLimit,
+ }
+
+ s.ResourceLimits.Pids = &pids
+ }
+
+ if s.ResourceLimits.CPU == nil || (c.CPUPeriod != 0 || c.CPUQuota != 0 || c.CPURTPeriod != 0 || c.CPURTRuntime != 0 || c.CPUS != 0 || len(c.CPUSetCPUs) != 0 || len(c.CPUSetMems) != 0 || c.CPUShares != 0) {
+ s.ResourceLimits.CPU = getCPULimits(c)
+ }
+
+ unifieds := make(map[string]string)
+ for _, unified := range c.CgroupConf {
+ splitUnified := strings.SplitN(unified, "=", 2)
+ if len(splitUnified) < 2 {
+ return nil, errors.New("--cgroup-conf must be formatted KEY=VALUE")
+ }
+ unifieds[splitUnified[0]] = splitUnified[1]
+ }
+ if len(unifieds) > 0 {
+ s.ResourceLimits.Unified = unifieds
+ }
+
+ if s.ResourceLimits.CPU == nil && s.ResourceLimits.Pids == nil && s.ResourceLimits.BlockIO == nil && s.ResourceLimits.Memory == nil && s.ResourceLimits.Unified == nil {
+ s.ResourceLimits = nil
+ }
+ return s.ResourceLimits, nil
+}