diff options
Diffstat (limited to 'pkg')
27 files changed, 209 insertions, 132 deletions
diff --git a/pkg/api/handlers/compat/containers_stats.go b/pkg/api/handlers/compat/containers_stats.go index 6855e369b..d6bc26416 100644 --- a/pkg/api/handlers/compat/containers_stats.go +++ b/pkg/api/handlers/compat/containers_stats.go @@ -58,7 +58,7 @@ func StatsContainer(w http.ResponseWriter, r *http.Request) { flusher.Flush() } - // Setup JSON encoder for streaming. + // Set up JSON encoder for streaming. coder.SetEscapeHTML(true) var preRead time.Time var preCPUStats CPUStats @@ -132,6 +132,12 @@ streamLabel: // A label to flatten the scope InstanceID: "", } + cfg := ctnr.Config() + memoryLimit := cgroupStat.Memory.Usage.Limit + if cfg.Spec.Linux != nil && cfg.Spec.Linux.Resources != nil && cfg.Spec.Linux.Resources.Memory != nil && *cfg.Spec.Linux.Resources.Memory.Limit > 0 { + memoryLimit = uint64(*cfg.Spec.Linux.Resources.Memory.Limit) + } + systemUsage, _ := cgroups.GetSystemCPUUsage() s := StatsJSON{ Stats: Stats{ @@ -173,7 +179,7 @@ streamLabel: // A label to flatten the scope MaxUsage: cgroupStat.Memory.Usage.Limit, Stats: nil, Failcnt: 0, - Limit: cgroupStat.Memory.Usage.Limit, + Limit: memoryLimit, Commit: 0, CommitPeak: 0, PrivateWorkingSet: 0, diff --git a/pkg/api/handlers/libpod/containers.go b/pkg/api/handlers/libpod/containers.go index 6b5bee403..deddcaf93 100644 --- a/pkg/api/handlers/libpod/containers.go +++ b/pkg/api/handlers/libpod/containers.go @@ -115,10 +115,6 @@ func ListContainers(w http.ResponseWriter, r *http.Request) { utils.InternalServerError(w, err) return } - if len(pss) == 0 { - utils.WriteResponse(w, http.StatusOK, "[]") - return - } utils.WriteResponse(w, http.StatusOK, pss) } diff --git a/pkg/api/handlers/libpod/containers_stats.go b/pkg/api/handlers/libpod/containers_stats.go index d34254fd7..46d722a3d 100644 --- a/pkg/api/handlers/libpod/containers_stats.go +++ b/pkg/api/handlers/libpod/containers_stats.go @@ -66,7 +66,7 @@ func StatsContainer(w http.ResponseWriter, r *http.Request) { flusher.Flush() } - // Setup JSON encoder for streaming. + // Set up JSON encoder for streaming. coder := json.NewEncoder(w) coder.SetEscapeHTML(true) diff --git a/pkg/api/handlers/utils/containers.go b/pkg/api/handlers/utils/containers.go index 8588b49ba..1795f6ce1 100644 --- a/pkg/api/handlers/utils/containers.go +++ b/pkg/api/handlers/utils/containers.go @@ -191,7 +191,6 @@ func waitDockerCondition(ctx context.Context, containerName string, interval tim var notRunningStates = []define.ContainerStatus{ define.ContainerStateCreated, define.ContainerStateRemoving, - define.ContainerStateStopped, define.ContainerStateExited, define.ContainerStateConfigured, } diff --git a/pkg/api/server/listener_api.go b/pkg/api/server/listener_api.go index 2d02df7dc..aaaf6688e 100644 --- a/pkg/api/server/listener_api.go +++ b/pkg/api/server/listener_api.go @@ -11,7 +11,7 @@ import ( // ListenUnix follows stdlib net.Listen() API, providing a unix listener for given path // ListenUnix will delete and create files/directories as needed func ListenUnix(network string, path string) (net.Listener, error) { - // setup custom listener for API server + // set up custom listener for API server err := os.MkdirAll(filepath.Dir(path), 0770) if err != nil { return nil, errors.Wrapf(err, "api.ListenUnix() failed to create %s", filepath.Dir(path)) diff --git a/pkg/bindings/connection.go b/pkg/bindings/connection.go index c21834e35..6b3576f31 100644 --- a/pkg/bindings/connection.go +++ b/pkg/bindings/connection.go @@ -95,7 +95,7 @@ func NewConnectionWithIdentity(ctx context.Context, uri string, identity string) return nil, errors.Wrapf(err, "Value of CONTAINER_HOST is not a valid url: %s", uri) } - // Now we setup the http Client to use the connection above + // Now we set up the http Client to use the connection above var connection Connection switch _url.Scheme { case "ssh": @@ -164,7 +164,7 @@ func pingNewConnection(ctx context.Context) (*semver.Version, error) { if response.StatusCode == http.StatusOK { versionHdr := response.Header.Get("Libpod-API-Version") if versionHdr == "" { - logrus.Info("Service did not provide Libpod-API-Version Header") + logrus.Warn("Service did not provide Libpod-API-Version Header") return new(semver.Version), nil } versionSrv, err := semver.ParseTolerant(versionHdr) diff --git a/pkg/bindings/containers/attach.go b/pkg/bindings/containers/attach.go index d84b47052..303fc65bd 100644 --- a/pkg/bindings/containers/attach.go +++ b/pkg/bindings/containers/attach.go @@ -54,8 +54,6 @@ func Attach(ctx context.Context, nameOrID string, stdin io.Reader, stdout io.Wri stderr = (io.Writer)(nil) } - logrus.Infof("Going to attach to container %q", nameOrID) - conn, err := bindings.GetClient(ctx) if err != nil { return err @@ -357,7 +355,7 @@ func attachHandleResize(ctx, winCtx context.Context, winChange chan os.Signal, i resizeErr = ResizeContainerTTY(ctx, id, new(ResizeTTYOptions).WithHeight(h).WithWidth(w)) } if resizeErr != nil { - logrus.Infof("Failed to resize TTY: %v", resizeErr) + logrus.Debugf("Failed to resize TTY: %v", resizeErr) } } diff --git a/pkg/bindings/containers/containers.go b/pkg/bindings/containers/containers.go index 2d3422411..ea01bc7d9 100644 --- a/pkg/bindings/containers/containers.go +++ b/pkg/bindings/containers/containers.go @@ -13,7 +13,6 @@ import ( "github.com/containers/podman/v4/pkg/domain/entities" "github.com/containers/podman/v4/pkg/domain/entities/reports" "github.com/pkg/errors" - "github.com/sirupsen/logrus" ) var ( @@ -201,7 +200,6 @@ func Start(ctx context.Context, nameOrID string, options *StartOptions) error { if options == nil { options = new(StartOptions) } - logrus.Infof("Going to start container %q", nameOrID) conn, err := bindings.GetClient(ctx) if err != nil { return err diff --git a/pkg/bindings/manifests/types.go b/pkg/bindings/manifests/types.go index d0b0b2e71..e23ef798d 100644 --- a/pkg/bindings/manifests/types.go +++ b/pkg/bindings/manifests/types.go @@ -44,16 +44,18 @@ type RemoveOptions struct { type ModifyOptions struct { // Operation values are "update", "remove" and "annotate". This allows the service to // efficiently perform each update on a manifest list. - Operation *string - All *bool // All when true, operate on all images in a manifest list that may be included in Images - Annotations map[string]string // Annotations to add to manifest list - Arch *string // Arch overrides the architecture for the image - Features []string // Feature list for the image - Images []string // Images is an optional list of images to add/remove to/from manifest list depending on operation - OS *string // OS overrides the operating system for the image - OSFeatures []string // OS features for the image - OSVersion *string // OSVersion overrides the operating system for the image - Variant *string // Variant overrides the operating system variant for the image + Operation *string + All *bool // All when true, operate on all images in a manifest list that may be included in Images + Annotations map[string]string // Annotations to add to manifest list + Arch *string // Arch overrides the architecture for the image + Features []string // Feature list for the image + Images []string // Images is an optional list of images to add/remove to/from manifest list depending on operation + OS *string // OS overrides the operating system for the image + // OS features for the image + OSFeatures []string `json:"os_features" schema:"os_features"` + // OSVersion overrides the operating system for the image + OSVersion *string `json:"os_version" schema:"os_version"` + Variant *string // Variant overrides the operating system variant for the image Authfile *string Password *string Username *string diff --git a/pkg/bindings/manifests/types_modify_options.go b/pkg/bindings/manifests/types_modify_options.go index 9d2ed2613..ab00cb2c5 100644 --- a/pkg/bindings/manifests/types_modify_options.go +++ b/pkg/bindings/manifests/types_modify_options.go @@ -122,13 +122,13 @@ func (o *ModifyOptions) GetOS() string { return *o.OS } -// WithOSFeatures set oS features for the image +// WithOSFeatures set field OSFeatures to given value func (o *ModifyOptions) WithOSFeatures(value []string) *ModifyOptions { o.OSFeatures = value return o } -// GetOSFeatures returns value of oS features for the image +// GetOSFeatures returns value of field OSFeatures func (o *ModifyOptions) GetOSFeatures() []string { if o.OSFeatures == nil { var z []string @@ -137,13 +137,13 @@ func (o *ModifyOptions) GetOSFeatures() []string { return o.OSFeatures } -// WithOSVersion set oSVersion overrides the operating system for the image +// WithOSVersion set field OSVersion to given value func (o *ModifyOptions) WithOSVersion(value string) *ModifyOptions { o.OSVersion = &value return o } -// GetOSVersion returns value of oSVersion overrides the operating system for the image +// GetOSVersion returns value of field OSVersion func (o *ModifyOptions) GetOSVersion() string { if o.OSVersion == nil { var z string diff --git a/pkg/domain/entities/system.go b/pkg/domain/entities/system.go index 21026477d..331d2bcdc 100644 --- a/pkg/domain/entities/system.go +++ b/pkg/domain/entities/system.go @@ -28,6 +28,7 @@ type SystemPruneReport struct { PodPruneReport []*PodPruneReport ContainerPruneReports []*reports.PruneReport ImagePruneReports []*reports.PruneReport + NetworkPruneReports []*reports.PruneReport VolumePruneReports []*reports.PruneReport ReclaimedSpace uint64 } diff --git a/pkg/domain/infra/abi/containers.go b/pkg/domain/infra/abi/containers.go index c7cd0cb56..281e448f6 100644 --- a/pkg/domain/infra/abi/containers.go +++ b/pkg/domain/infra/abi/containers.go @@ -16,7 +16,6 @@ import ( "github.com/containers/image/v5/manifest" "github.com/containers/podman/v4/libpod" "github.com/containers/podman/v4/libpod/define" - "github.com/containers/podman/v4/libpod/events" "github.com/containers/podman/v4/libpod/logs" "github.com/containers/podman/v4/pkg/checkpoint" "github.com/containers/podman/v4/pkg/domain/entities" @@ -38,7 +37,7 @@ import ( ) // getContainersAndInputByContext gets containers whether all, latest, or a slice of names/ids -// is specified. It also returns a list of the corresponding input name used to lookup each container. +// is specified. It also returns a list of the corresponding input name used to look up each container. func getContainersAndInputByContext(all, latest bool, names []string, runtime *libpod.Runtime) (ctrs []*libpod.Container, rawInput []string, err error) { var ctr *libpod.Container ctrs = []*libpod.Container{} @@ -183,7 +182,7 @@ func (ic *ContainerEngine) ContainerStop(ctx context.Context, namesOrIds []strin if err != nil { // Issue #7384 and #11384: If the container is configured for // auto-removal, it might already have been removed at this point. - // We still need to to cleanup since we do not know if the other cleanup process is successful + // We still need to clean up since we do not know if the other cleanup process is successful if c.AutoRemove() && (errors.Is(err, define.ErrNoSuchCtr) || errors.Is(err, define.ErrCtrRemoved)) { return nil } @@ -488,7 +487,7 @@ func (ic *ContainerEngine) ContainerTop(ctx context.Context, options entities.To container, err = ic.Libpod.LookupContainer(options.NameOrID) } if err != nil { - return nil, errors.Wrap(err, "unable to lookup requested container") + return nil, errors.Wrap(err, "unable to look up requested container") } // Run Top. @@ -635,13 +634,13 @@ func (ic *ContainerEngine) ContainerRestore(ctx context.Context, namesOrIds []st containers, err = getContainersByContext(false, options.Latest, namesOrIds, ic.Libpod) default: for _, nameOrID := range namesOrIds { - logrus.Debugf("lookup container: %q", nameOrID) + logrus.Debugf("look up container: %q", nameOrID) ctr, err := ic.Libpod.LookupContainer(nameOrID) if err == nil { containers = append(containers, ctr) } else { // If container was not found, check if this is a checkpoint image - logrus.Debugf("lookup image: %q", nameOrID) + logrus.Debugf("look up image: %q", nameOrID) img, _, err := ic.Libpod.LibimageRuntime().LookupImage(nameOrID, nil) if err != nil { return nil, fmt.Errorf("no such container or image: %s", nameOrID) @@ -939,6 +938,7 @@ func (ic *ContainerEngine) ContainerStart(ctx context.Context, namesOrIds []stri } return reports, errors.Wrapf(err, "unable to start container %s", ctr.ID()) } + exitCode = ic.GetContainerExitCode(ctx, ctr) reports = append(reports, &entities.ContainerStartReport{ Id: ctr.ID(), @@ -1099,25 +1099,11 @@ func (ic *ContainerEngine) ContainerRun(ctx context.Context, opts entities.Conta func (ic *ContainerEngine) GetContainerExitCode(ctx context.Context, ctr *libpod.Container) int { exitCode, err := ctr.Wait(ctx) - if err == nil { - return int(exitCode) - } - if errors.Cause(err) != define.ErrNoSuchCtr { - logrus.Errorf("Could not retrieve exit code: %v", err) + if err != nil { + logrus.Errorf("Waiting for container %s: %v", ctr.ID(), err) return define.ExecErrorCodeNotFound } - // Make 4 attempt with 0.25s backoff between each for 1 second total - var event *events.Event - for i := 0; i < 4; i++ { - event, err = ic.Libpod.GetLastContainerEvent(ctx, ctr.ID(), events.Exited) - if err != nil { - time.Sleep(250 * time.Millisecond) - continue - } - return event.ContainerExitCode - } - logrus.Errorf("Could not retrieve exit code from event: %v", err) - return define.ExecErrorCodeNotFound + return int(exitCode) } func (ic *ContainerEngine) ContainerLogs(ctx context.Context, containers []string, options entities.ContainerLogsOptions) error { @@ -1194,12 +1180,12 @@ func (ic *ContainerEngine) ContainerCleanup(ctx context.Context, namesOrIds []st var timeout *uint err = ic.Libpod.RemoveContainer(ctx, ctr, false, true, timeout) if err != nil { - report.RmErr = errors.Wrapf(err, "failed to cleanup and remove container %v", ctr.ID()) + report.RmErr = errors.Wrapf(err, "failed to clean up and remove container %v", ctr.ID()) } } else { err := ctr.Cleanup(ctx) if err != nil { - report.CleanErr = errors.Wrapf(err, "failed to cleanup container %v", ctr.ID()) + report.CleanErr = errors.Wrapf(err, "failed to clean up container %v", ctr.ID()) } } diff --git a/pkg/domain/infra/abi/network.go b/pkg/domain/infra/abi/network.go index 47f7917f4..8b95607f4 100644 --- a/pkg/domain/infra/abi/network.go +++ b/pkg/domain/infra/abi/network.go @@ -2,6 +2,7 @@ package abi import ( "context" + "strconv" "github.com/containers/common/libnetwork/types" netutil "github.com/containers/common/libnetwork/util" @@ -12,10 +13,39 @@ import ( ) func (ic *ContainerEngine) NetworkList(ctx context.Context, options entities.NetworkListOptions) ([]types.Network, error) { + // dangling filter is not provided by netutil + var wantDangling bool + + val, filterDangling := options.Filters["dangling"] + if filterDangling { + switch len(val) { + case 0: + return nil, errors.Errorf("got no values for filter key \"dangling\"") + case 1: + var err error + wantDangling, err = strconv.ParseBool(val[0]) + if err != nil { + return nil, errors.Errorf("invalid dangling filter value \"%v\"", val[0]) + } + delete(options.Filters, "dangling") + default: + return nil, errors.Errorf("got more than one value for filter key \"dangling\"") + } + } + filters, err := netutil.GenerateNetworkFilters(options.Filters) if err != nil { return nil, err } + + if filterDangling { + danglingFilterFunc, err := ic.createDanglingFilterFunc(wantDangling) + if err != nil { + return nil, err + } + + filters = append(filters, danglingFilterFunc) + } nets, err := ic.Libpod.Network().NetworkList(filters...) return nets, err } @@ -142,8 +172,35 @@ func (ic *ContainerEngine) NetworkExists(ctx context.Context, networkname string }, nil } -// Network prune removes unused cni networks +// Network prune removes unused networks func (ic *ContainerEngine) NetworkPrune(ctx context.Context, options entities.NetworkPruneOptions) ([]*entities.NetworkPruneReport, error) { + // get all filters + filters, err := netutil.GenerateNetworkPruneFilters(options.Filters) + if err != nil { + return nil, err + } + danglingFilterFunc, err := ic.createDanglingFilterFunc(true) + if err != nil { + return nil, err + } + filters = append(filters, danglingFilterFunc) + nets, err := ic.Libpod.Network().NetworkList(filters...) + if err != nil { + return nil, err + } + + pruneReport := make([]*entities.NetworkPruneReport, 0, len(nets)) + for _, net := range nets { + pruneReport = append(pruneReport, &entities.NetworkPruneReport{ + Name: net.Name, + Error: ic.Libpod.Network().NetworkRemove(net.Name), + }) + } + return pruneReport, nil +} + +// danglingFilter function is special and not implemented in libnetwork filters +func (ic *ContainerEngine) createDanglingFilterFunc(wantDangling bool) (types.FilterFunc, error) { cons, err := ic.Libpod.GetAllContainers() if err != nil { return nil, err @@ -163,31 +220,12 @@ func (ic *ContainerEngine) NetworkPrune(ctx context.Context, options entities.Ne // ignore the default network, this one cannot be deleted networksToKeep[ic.Libpod.GetDefaultNetworkName()] = true - // get all filters - filters, err := netutil.GenerateNetworkPruneFilters(options.Filters) - if err != nil { - return nil, err - } - danglingFilterFunc := func(net types.Network) bool { + return func(net types.Network) bool { for network := range networksToKeep { if network == net.Name { - return false + return !wantDangling } } - return true - } - filters = append(filters, danglingFilterFunc) - nets, err := ic.Libpod.Network().NetworkList(filters...) - if err != nil { - return nil, err - } - - pruneReport := make([]*entities.NetworkPruneReport, 0, len(nets)) - for _, net := range nets { - pruneReport = append(pruneReport, &entities.NetworkPruneReport{ - Name: net.Name, - Error: ic.Libpod.Network().NetworkRemove(net.Name), - }) - } - return pruneReport, nil + return wantDangling + }, nil } diff --git a/pkg/domain/infra/abi/play.go b/pkg/domain/infra/abi/play.go index e04ab3a1a..e14a819fa 100644 --- a/pkg/domain/infra/abi/play.go +++ b/pkg/domain/infra/abi/play.go @@ -31,7 +31,7 @@ import ( "github.com/opencontainers/go-digest" "github.com/pkg/errors" "github.com/sirupsen/logrus" - yamlv2 "gopkg.in/yaml.v2" + yamlv3 "gopkg.in/yaml.v3" ) // createServiceContainer creates a container that can later on @@ -790,7 +790,7 @@ func readConfigMapFromFile(r io.Reader) (v1.ConfigMap, error) { func splitMultiDocYAML(yamlContent []byte) ([][]byte, error) { var documentList [][]byte - d := yamlv2.NewDecoder(bytes.NewReader(yamlContent)) + d := yamlv3.NewDecoder(bytes.NewReader(yamlContent)) for { var o interface{} // read individual document @@ -804,7 +804,7 @@ func splitMultiDocYAML(yamlContent []byte) ([][]byte, error) { if o != nil { // back to bytes - document, err := yamlv2.Marshal(o) + document, err := yamlv3.Marshal(o) if err != nil { return nil, errors.Wrapf(err, "individual doc yaml could not be marshalled") } diff --git a/pkg/domain/infra/abi/pods.go b/pkg/domain/infra/abi/pods.go index 8638f4783..3e9cb7f5e 100644 --- a/pkg/domain/infra/abi/pods.go +++ b/pkg/domain/infra/abi/pods.go @@ -393,7 +393,7 @@ func (ic *ContainerEngine) PodTop(ctx context.Context, options entities.PodTopOp pod, err = ic.Libpod.LookupPod(options.NameOrID) } if err != nil { - return nil, errors.Wrap(err, "unable to lookup requested container") + return nil, errors.Wrap(err, "unable to look up requested container") } // Run Top. @@ -494,7 +494,7 @@ func (ic *ContainerEngine) PodInspect(ctx context.Context, options entities.PodI pod, err = ic.Libpod.LookupPod(options.NameOrID) } if err != nil { - return nil, errors.Wrap(err, "unable to lookup requested container") + return nil, errors.Wrap(err, "unable to look up requested container") } inspect, err := pod.Inspect() if err != nil { diff --git a/pkg/domain/infra/abi/system.go b/pkg/domain/infra/abi/system.go index 762f0d79a..6e26026d4 100644 --- a/pkg/domain/infra/abi/system.go +++ b/pkg/domain/infra/abi/system.go @@ -125,8 +125,14 @@ func (ic *ContainerEngine) SetupRootless(_ context.Context, noMoveProcess bool) paths = append(paths, ctr.Config().ConmonPidFile) } - became, ret, err = rootless.TryJoinFromFilePaths(pausePidPath, true, paths) - utils.MovePauseProcessToScope(pausePidPath) + if len(paths) > 0 { + became, ret, err = rootless.TryJoinFromFilePaths(pausePidPath, true, paths) + } else { + became, ret, err = rootless.BecomeRootInUserNS(pausePidPath) + if err == nil { + utils.MovePauseProcessToScope(pausePidPath) + } + } if err != nil { logrus.Error(errors.Wrapf(err, "invalid internal status, try resetting the pause process with %q", os.Args[0]+" system migrate")) os.Exit(1) @@ -137,7 +143,7 @@ func (ic *ContainerEngine) SetupRootless(_ context.Context, noMoveProcess bool) return nil } -// SystemPrune removes unused data from the system. Pruning pods, containers, volumes and images. +// SystemPrune removes unused data from the system. Pruning pods, containers, networks, volumes and images. func (ic *ContainerEngine) SystemPrune(ctx context.Context, options entities.SystemPruneOptions) (*entities.SystemPruneReport, error) { var systemPruneReport = new(entities.SystemPruneReport) filters := []string{} @@ -148,6 +154,9 @@ func (ic *ContainerEngine) SystemPrune(ctx context.Context, options entities.Sys found := true for found { found = false + + // TODO: Figure out cleaner way to handle all of the different PruneOptions + // Remove all unused pods. podPruneReport, err := ic.prunePodHelper(ctx) if err != nil { return nil, err @@ -155,9 +164,10 @@ func (ic *ContainerEngine) SystemPrune(ctx context.Context, options entities.Sys if len(podPruneReport) > 0 { found = true } + systemPruneReport.PodPruneReport = append(systemPruneReport.PodPruneReport, podPruneReport...) - // TODO: Figure out cleaner way to handle all of the different PruneOptions + // Remove all unused containers. containerPruneOptions := entities.ContainerPruneOptions{} containerPruneOptions.Filters = (url.Values)(options.Filters) @@ -165,16 +175,18 @@ func (ic *ContainerEngine) SystemPrune(ctx context.Context, options entities.Sys if err != nil { return nil, err } + reclaimedSpace += reports.PruneReportsSize(containerPruneReports) systemPruneReport.ContainerPruneReports = append(systemPruneReport.ContainerPruneReports, containerPruneReports...) + + // Remove all unused images. imagePruneOptions := entities.ImagePruneOptions{ All: options.All, Filter: filters, } + imageEngine := ImageEngine{Libpod: ic.Libpod} imagePruneReports, err := imageEngine.Prune(ctx, imagePruneOptions) - reclaimedSpace += reports.PruneReportsSize(imagePruneReports) - if err != nil { return nil, err } @@ -182,10 +194,33 @@ func (ic *ContainerEngine) SystemPrune(ctx context.Context, options entities.Sys found = true } + reclaimedSpace += reports.PruneReportsSize(imagePruneReports) systemPruneReport.ImagePruneReports = append(systemPruneReport.ImagePruneReports, imagePruneReports...) + + // Remove all unused networks. + networkPruneOptions := entities.NetworkPruneOptions{} + networkPruneOptions.Filters = options.Filters + + networkPruneReport, err := ic.NetworkPrune(ctx, networkPruneOptions) + if err != nil { + return nil, err + } + if len(networkPruneReport) > 0 { + found = true + } + for _, net := range networkPruneReport { + systemPruneReport.NetworkPruneReports = append(systemPruneReport.NetworkPruneReports, &reports.PruneReport{ + Id: net.Name, + Err: net.Error, + Size: 0, + }) + } + + // Remove unused volume data. if options.Volume { volumePruneOptions := entities.VolumePruneOptions{} volumePruneOptions.Filters = (url.Values)(options.Filters) + volumePruneReport, err := ic.VolumePrune(ctx, volumePruneOptions) if err != nil { return nil, err @@ -193,6 +228,7 @@ func (ic *ContainerEngine) SystemPrune(ctx context.Context, options entities.Sys if len(volumePruneReport) > 0 { found = true } + reclaimedSpace += reports.PruneReportsSize(volumePruneReport) systemPruneReport.VolumePruneReports = append(systemPruneReport.VolumePruneReports, volumePruneReport...) } @@ -368,9 +404,9 @@ func (ic *ContainerEngine) Unshare(ctx context.Context, args []string, options e } // Make sure to unlock, unshare can run for a long time. rootlessNetNS.Lock.Unlock() - // We do not want to cleanup the netns after unshare. - // The problem is that we cannot know if we need to cleanup and - // secondly unshare should allow user to setup the namespace with + // We do not want to clean up the netns after unshare. + // The problem is that we cannot know if we need to clean up and + // secondly unshare should allow user to set up the namespace with // special things, e.g. potentially macvlan or something like that. return rootlessNetNS.Do(unshare) } diff --git a/pkg/domain/infra/runtime_libpod.go b/pkg/domain/infra/runtime_libpod.go index 03e7ffb5d..162025969 100644 --- a/pkg/domain/infra/runtime_libpod.go +++ b/pkg/domain/infra/runtime_libpod.go @@ -342,7 +342,7 @@ func ParseIDMapping(mode namespaces.UsernsMode, uidMapSlice, gidMapSlice []strin options.HostUIDMapping = false options.HostGIDMapping = false - // Simply ignore the setting and do not setup an inner namespace for root as it is a no-op + // Simply ignore the setting and do not set up an inner namespace for root as it is a no-op return &options, nil } @@ -394,7 +394,7 @@ func ParseIDMapping(mode namespaces.UsernsMode, uidMapSlice, gidMapSlice []strin // StartWatcher starts a new SIGHUP go routine for the current config. func StartWatcher(rt *libpod.Runtime) { - // Setup the signal notifier + // Set up the signal notifier ch := make(chan os.Signal, 1) signal.Notify(ch, syscall.SIGHUP) diff --git a/pkg/domain/infra/tunnel/helpers.go b/pkg/domain/infra/tunnel/helpers.go index 5b14fac37..6c043465c 100644 --- a/pkg/domain/infra/tunnel/helpers.go +++ b/pkg/domain/infra/tunnel/helpers.go @@ -20,7 +20,7 @@ func getContainersByContext(contextWithConnection context.Context, all, ignore b func getContainersAndInputByContext(contextWithConnection context.Context, all, ignore bool, namesOrIDs []string) ([]entities.ListContainer, []string, error) { if all && len(namesOrIDs) > 0 { - return nil, nil, errors.New("cannot lookup containers and all") + return nil, nil, errors.New("cannot look up containers and all") } options := new(containers.ListOptions).WithAll(true).WithSync(true) allContainers, err := containers.List(contextWithConnection, options) @@ -77,7 +77,7 @@ func getContainersAndInputByContext(contextWithConnection context.Context, all, func getPodsByContext(contextWithConnection context.Context, all bool, namesOrIDs []string) ([]*entities.ListPodsReport, error) { if all && len(namesOrIDs) > 0 { - return nil, errors.New("cannot lookup specific pods and all") + return nil, errors.New("cannot look up specific pods and all") } allPods, err := pods.List(contextWithConnection, nil) diff --git a/pkg/machine/ignition.go b/pkg/machine/ignition.go index 35a9a30cb..f4602cc95 100644 --- a/pkg/machine/ignition.go +++ b/pkg/machine/ignition.go @@ -93,7 +93,7 @@ func NewIgnitionFile(ign DynamicIgnition) error { tz string ) // local means the same as the host - // lookup where it is pointing to on the host + // look up where it is pointing to on the host if ign.TimeZone == "local" { tz, err = getLocalTimeZone() if err != nil { @@ -348,7 +348,7 @@ Delegate=memory pids cpu io }, }) - // Setup /etc/subuid and /etc/subgid + // Set up /etc/subuid and /etc/subgid for _, sub := range []string{"/etc/subuid", "/etc/subgid"} { files = append(files, File{ Node: Node{ diff --git a/pkg/machine/qemu/machine.go b/pkg/machine/qemu/machine.go index 288b2eeb0..5094345ea 100644 --- a/pkg/machine/qemu/machine.go +++ b/pkg/machine/qemu/machine.go @@ -209,7 +209,7 @@ func migrateVM(configPath string, config []byte, vm *MachineVM) error { vm.Rootful = old.Rootful vm.UID = old.UID - // Backup the original config file + // Back up the original config file if err := os.Rename(configPath, configPath+".orig"); err != nil { return err } @@ -580,7 +580,7 @@ func (v *MachineVM) Start(name string, _ machine.StartOptions) error { if !errors.Is(err, os.ErrNotExist) { return err } - // lookup qemu again maybe the path was changed, https://github.com/containers/podman/issues/13394 + // look up qemu again maybe the path was changed, https://github.com/containers/podman/issues/13394 cfg, err := config.Default() if err != nil { return err @@ -1142,7 +1142,7 @@ func (p *Provider) CheckExclusiveActiveVM() (bool, string, error) { } // startHostNetworking runs a binary on the host system that allows users -// to setup port forwarding to the podman virtual machine +// to set up port forwarding to the podman virtual machine func (v *MachineVM) startHostNetworking() (string, apiForwardingState, error) { cfg, err := config.Default() if err != nil { diff --git a/pkg/namespaces/namespaces.go b/pkg/namespaces/namespaces.go index c95f8e275..8eacb8da7 100644 --- a/pkg/namespaces/namespaces.go +++ b/pkg/namespaces/namespaces.go @@ -112,7 +112,7 @@ func (n UsernsMode) IsDefaultValue() bool { return n == "" || n == defaultType } -// GetAutoOptions returns a AutoUserNsOptions with the settings to setup automatically +// GetAutoOptions returns a AutoUserNsOptions with the settings to automatically set up // a user namespace. func (n UsernsMode) GetAutoOptions() (*types.AutoUserNsOptions, error) { parts := strings.SplitN(string(n), ":", 2) diff --git a/pkg/rootless/rootless_linux.c b/pkg/rootless/rootless_linux.c index 94bd40f86..3588313c6 100644 --- a/pkg/rootless/rootless_linux.c +++ b/pkg/rootless/rootless_linux.c @@ -178,7 +178,7 @@ get_cmd_line_args () char *tmp = realloc (buffer, allocated); if (tmp == NULL) return NULL; - buffer = tmp; + buffer = tmp; } } @@ -243,7 +243,7 @@ can_use_shortcut () } if (argv[argc+1] != NULL && (strcmp (argv[argc], "container") == 0 || - strcmp (argv[argc], "image") == 0) && + strcmp (argv[argc], "image") == 0) && (strcmp (argv[argc+1], "mount") == 0 || strcmp (argv[argc+1], "scp") == 0)) { ret = false; @@ -512,7 +512,9 @@ create_pause_process (const char *pause_pid_file_path, char **argv) r = TEMP_FAILURE_RETRY (read (p[0], &b, 1)); close (p[0]); - reexec_in_user_namespace_wait (pid, 0); + r = reexec_in_user_namespace_wait (pid, 0); + if (r != 0) + return -1; return r == 1 && b == '0' ? 0 : -1; } @@ -757,6 +759,7 @@ reexec_userns_join (int pid_to_join, char *pause_pid_file_path) } execvp (argv[0], argv); + fprintf (stderr, "failed to execvp %s: %m\n", argv[0]); _exit (EXIT_FAILURE); } @@ -788,7 +791,10 @@ copy_file_to_fd (const char *file_to_read, int outfd) fd = open (file_to_read, O_RDONLY); if (fd < 0) - return fd; + { + fprintf (stderr, "open `%s`: %m\n", file_to_read); + return fd; + } for (;;) { @@ -796,7 +802,10 @@ copy_file_to_fd (const char *file_to_read, int outfd) r = TEMP_FAILURE_RETRY (read (fd, buf, sizeof buf)); if (r < 0) - return r; + { + fprintf (stderr, "read from `%s`: %m\n", file_to_read); + return r; + } if (r == 0) break; @@ -805,7 +814,10 @@ copy_file_to_fd (const char *file_to_read, int outfd) { w = TEMP_FAILURE_RETRY (write (outfd, &buf[t], r - t)); if (w < 0) - return w; + { + fprintf (stderr, "write file to output fd `%s`: %m\n", file_to_read); + return w; + } t += w; } } diff --git a/pkg/rootless/rootless_linux.go b/pkg/rootless/rootless_linux.go index 5af9a978b..fde621b72 100644 --- a/pkg/rootless/rootless_linux.go +++ b/pkg/rootless/rootless_linux.go @@ -154,7 +154,7 @@ func tryMappingTool(uid bool, pid int, hostID int, mappings []idtools.IDMap) err if output, err := cmd.CombinedOutput(); err != nil { logrus.Errorf("running `%s`: %s", strings.Join(args, " "), output) - errorStr := fmt.Sprintf("cannot setup namespace using %q", path) + errorStr := fmt.Sprintf("cannot set up namespace using %q", path) if isSet, err := unshare.IsSetID(cmd.Path, mode, cap); err != nil { logrus.Errorf("Failed to check for %s on %s: %v", idtype, path, err) } else if !isSet { @@ -182,7 +182,7 @@ func joinUserAndMountNS(pid uint, pausePid string) (bool, int, error) { pidC := C.reexec_userns_join(C.int(pid), cPausePid) if int(pidC) < 0 { - return false, -1, errors.Errorf("cannot re-exec process") + return false, -1, errors.Errorf("cannot re-exec process to join the existing user namespace") } ret := C.reexec_in_user_namespace_wait(pidC, 0) @@ -303,7 +303,7 @@ func becomeRootInUserNS(pausePid, fileToRead string, fileOutput *os.File) (_ boo if retErr != nil && pid > 0 { if err := unix.Kill(pid, unix.SIGKILL); err != nil { if err != unix.ESRCH { - logrus.Errorf("Failed to cleanup process %d: %v", pid, err) + logrus.Errorf("Failed to clean up process %d: %v", pid, err) } } C.reexec_in_user_namespace_wait(C.int(pid), 0) @@ -461,13 +461,8 @@ func BecomeRootInUserNS(pausePid string) (bool, int, error) { // different uidmap and the unprivileged user has no way to read the // file owned by the root in the container. func TryJoinFromFilePaths(pausePidPath string, needNewNamespace bool, paths []string) (bool, int, error) { - if len(paths) == 0 { - return BecomeRootInUserNS(pausePidPath) - } - var lastErr error var pausePid int - foundProcess := false for _, path := range paths { if !needNewNamespace { @@ -479,12 +474,9 @@ func TryJoinFromFilePaths(pausePidPath string, needNewNamespace bool, paths []st pausePid, err = strconv.Atoi(string(data)) if err != nil { - lastErr = errors.Wrapf(err, "cannot parse file %s", path) + lastErr = errors.Wrapf(err, "cannot parse file %q", path) continue } - - lastErr = nil - break } else { r, w, err := os.Pipe() if err != nil { @@ -511,26 +503,29 @@ func TryJoinFromFilePaths(pausePidPath string, needNewNamespace bool, paths []st n, err := r.Read(b) if err != nil { - lastErr = errors.Wrapf(err, "cannot read %s\n", path) + lastErr = errors.Wrapf(err, "cannot read %q", path) continue } pausePid, err = strconv.Atoi(string(b[:n])) - if err == nil && unix.Kill(pausePid, 0) == nil { - foundProcess = true - lastErr = nil - break + if err != nil { + lastErr = err + continue } } - } - if !foundProcess && pausePidPath != "" { - return BecomeRootInUserNS(pausePidPath) + + if pausePid > 0 && unix.Kill(pausePid, 0) == nil { + joined, pid, err := joinUserAndMountNS(uint(pausePid), pausePidPath) + if err == nil { + return joined, pid, nil + } + lastErr = err + } } if lastErr != nil { return false, 0, lastErr } - - return joinUserAndMountNS(uint(pausePid), pausePidPath) + return false, 0, errors.Wrapf(unix.ESRCH, "could not find any running process") } // ReadMappingsProc parses and returns the ID mappings at the specified path. diff --git a/pkg/specgen/generate/container.go b/pkg/specgen/generate/container.go index 0ed3c79ef..30c759495 100644 --- a/pkg/specgen/generate/container.go +++ b/pkg/specgen/generate/container.go @@ -506,6 +506,7 @@ func ConfigToSpec(rt *libpod.Runtime, specg *specgen.SpecGenerator, contaierID s specg.Mounts = mounts specg.HostDeviceList = conf.DeviceHostSrc specg.Networks = conf.Networks + specg.ShmSize = &conf.ShmSize mapSecurityConfig(conf, specg) diff --git a/pkg/specgen/generate/container_create.go b/pkg/specgen/generate/container_create.go index 7faf13465..0dec943d1 100644 --- a/pkg/specgen/generate/container_create.go +++ b/pkg/specgen/generate/container_create.go @@ -564,5 +564,10 @@ func Inherit(infra libpod.Container, s *specgen.SpecGenerator, rt *libpod.Runtim if err != nil { return nil, nil, nil, err } + + // this causes errors when shmSize is the default value, it will still get passed down unless we manually override. + if s.IpcNS.NSMode == specgen.Host && (compatibleOptions.ShmSize != nil && compatibleOptions.IsDefaultShmSize()) { + s.ShmSize = nil + } return options, infraSpec, compatibleOptions, nil } diff --git a/pkg/specgen/podspecgen.go b/pkg/specgen/podspecgen.go index 777097ac5..02ba06be1 100644 --- a/pkg/specgen/podspecgen.go +++ b/pkg/specgen/podspecgen.go @@ -183,6 +183,10 @@ type PodStorageConfig struct { // comma-separated options. Valid options are 'ro', 'rw', and 'z'. // Options will be used for all volumes sourced from the container. VolumesFrom []string `json:"volumes_from,omitempty"` + // ShmSize is the size of the tmpfs to mount in at /dev/shm, in bytes. + // Conflicts with ShmSize if IpcNS is not private. + // Optional. + ShmSize *int64 `json:"shm_size,omitempty"` } // PodCgroupConfig contains configuration options about a pod's cgroups. diff --git a/pkg/systemd/generate/containers.go b/pkg/systemd/generate/containers.go index d552e21ed..e953a1f1f 100644 --- a/pkg/systemd/generate/containers.go +++ b/pkg/systemd/generate/containers.go @@ -204,7 +204,7 @@ func generateContainerInfo(ctr *libpod.Container, options entities.GenerateSyste } else { runRoot = ctr.Runtime().RunRoot() if runRoot == "" { - return nil, errors.Errorf("could not lookup container's runroot: got empty string") + return nil, errors.Errorf("could not look up container's runroot: got empty string") } } |
