1711 lines
		
	
	
		
			51 KiB
		
	
	
	
		
			Go
		
	
	
	
			
		
		
	
	
			1711 lines
		
	
	
		
			51 KiB
		
	
	
	
		
			Go
		
	
	
	
package abi
 | 
						|
 | 
						|
import (
 | 
						|
	"context"
 | 
						|
	"errors"
 | 
						|
	"fmt"
 | 
						|
	"io/ioutil"
 | 
						|
	"os"
 | 
						|
	"strconv"
 | 
						|
	"strings"
 | 
						|
	"sync"
 | 
						|
	"time"
 | 
						|
 | 
						|
	"github.com/containers/buildah"
 | 
						|
	"github.com/containers/common/pkg/cgroups"
 | 
						|
	"github.com/containers/common/pkg/config"
 | 
						|
	"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/logs"
 | 
						|
	"github.com/containers/podman/v4/pkg/checkpoint"
 | 
						|
	"github.com/containers/podman/v4/pkg/domain/entities"
 | 
						|
	"github.com/containers/podman/v4/pkg/domain/entities/reports"
 | 
						|
	dfilters "github.com/containers/podman/v4/pkg/domain/filters"
 | 
						|
	"github.com/containers/podman/v4/pkg/domain/infra/abi/terminal"
 | 
						|
	"github.com/containers/podman/v4/pkg/errorhandling"
 | 
						|
	parallelctr "github.com/containers/podman/v4/pkg/parallel/ctr"
 | 
						|
	"github.com/containers/podman/v4/pkg/ps"
 | 
						|
	"github.com/containers/podman/v4/pkg/rootless"
 | 
						|
	"github.com/containers/podman/v4/pkg/signal"
 | 
						|
	"github.com/containers/podman/v4/pkg/specgen"
 | 
						|
	"github.com/containers/podman/v4/pkg/specgen/generate"
 | 
						|
	"github.com/containers/podman/v4/pkg/specgenutil"
 | 
						|
	"github.com/containers/podman/v4/pkg/util"
 | 
						|
	"github.com/containers/storage"
 | 
						|
	"github.com/sirupsen/logrus"
 | 
						|
)
 | 
						|
 | 
						|
// 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.
 | 
						|
func getContainersAndInputByContext(all, latest bool, names []string, filters map[string][]string, runtime *libpod.Runtime) (ctrs []*libpod.Container, rawInput []string, err error) {
 | 
						|
	var ctr *libpod.Container
 | 
						|
	ctrs = []*libpod.Container{}
 | 
						|
	filterFuncs := make([]libpod.ContainerFilter, 0, len(filters))
 | 
						|
 | 
						|
	switch {
 | 
						|
	case len(filters) > 0:
 | 
						|
		for k, v := range filters {
 | 
						|
			generatedFunc, err := dfilters.GenerateContainerFilterFuncs(k, v, runtime)
 | 
						|
			if err != nil {
 | 
						|
				return nil, nil, err
 | 
						|
			}
 | 
						|
			filterFuncs = append(filterFuncs, generatedFunc)
 | 
						|
		}
 | 
						|
		ctrs, err = runtime.GetContainers(filterFuncs...)
 | 
						|
		if err != nil {
 | 
						|
			return nil, nil, err
 | 
						|
		}
 | 
						|
		rawInput = []string{}
 | 
						|
		for _, candidate := range ctrs {
 | 
						|
			rawInput = append(rawInput, candidate.ID())
 | 
						|
		}
 | 
						|
	case all:
 | 
						|
		ctrs, err = runtime.GetAllContainers()
 | 
						|
		if err == nil {
 | 
						|
			for _, ctr := range ctrs {
 | 
						|
				rawInput = append(rawInput, ctr.ID())
 | 
						|
			}
 | 
						|
		}
 | 
						|
	case latest:
 | 
						|
		ctr, err = runtime.GetLatestContainer()
 | 
						|
		if err == nil {
 | 
						|
			rawInput = append(rawInput, ctr.ID())
 | 
						|
			ctrs = append(ctrs, ctr)
 | 
						|
		}
 | 
						|
	default:
 | 
						|
		for _, n := range names {
 | 
						|
			ctr, e := runtime.LookupContainer(n)
 | 
						|
			if e != nil {
 | 
						|
				// Log all errors here, so callers don't need to.
 | 
						|
				logrus.Debugf("Error looking up container %q: %v", n, e)
 | 
						|
				if err == nil {
 | 
						|
					err = e
 | 
						|
				}
 | 
						|
			} else {
 | 
						|
				rawInput = append(rawInput, n)
 | 
						|
				ctrs = append(ctrs, ctr)
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return ctrs, rawInput, err
 | 
						|
}
 | 
						|
 | 
						|
// getContainersByContext gets containers whether all, latest, or a slice of names/ids
 | 
						|
// is specified.
 | 
						|
func getContainersByContext(all, latest bool, names []string, runtime *libpod.Runtime) (ctrs []*libpod.Container, err error) {
 | 
						|
	ctrs, _, err = getContainersAndInputByContext(all, latest, names, nil, runtime)
 | 
						|
	return
 | 
						|
}
 | 
						|
 | 
						|
// ContainerExists returns whether the container exists in container storage
 | 
						|
func (ic *ContainerEngine) ContainerExists(ctx context.Context, nameOrID string, options entities.ContainerExistsOptions) (*entities.BoolReport, error) {
 | 
						|
	_, err := ic.Libpod.LookupContainer(nameOrID)
 | 
						|
	if err != nil {
 | 
						|
		if !errors.Is(err, define.ErrNoSuchCtr) {
 | 
						|
			return nil, err
 | 
						|
		}
 | 
						|
		if options.External {
 | 
						|
			// Check if container exists in storage
 | 
						|
			if _, storageErr := ic.Libpod.StorageContainer(nameOrID); storageErr == nil {
 | 
						|
				err = nil
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return &entities.BoolReport{Value: err == nil}, nil
 | 
						|
}
 | 
						|
 | 
						|
func (ic *ContainerEngine) ContainerWait(ctx context.Context, namesOrIds []string, options entities.WaitOptions) ([]entities.WaitReport, error) {
 | 
						|
	ctrs, err := getContainersByContext(false, options.Latest, namesOrIds, ic.Libpod)
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
	responses := make([]entities.WaitReport, 0, len(ctrs))
 | 
						|
	for _, c := range ctrs {
 | 
						|
		response := entities.WaitReport{Id: c.ID()}
 | 
						|
		if options.Condition == nil {
 | 
						|
			options.Condition = []define.ContainerStatus{define.ContainerStateStopped, define.ContainerStateExited}
 | 
						|
		}
 | 
						|
		exitCode, err := c.WaitForConditionWithInterval(ctx, options.Interval, options.Condition...)
 | 
						|
		if err != nil {
 | 
						|
			response.Error = err
 | 
						|
		} else {
 | 
						|
			response.ExitCode = exitCode
 | 
						|
		}
 | 
						|
		responses = append(responses, response)
 | 
						|
	}
 | 
						|
	return responses, nil
 | 
						|
}
 | 
						|
 | 
						|
func (ic *ContainerEngine) ContainerPause(ctx context.Context, namesOrIds []string, options entities.PauseUnPauseOptions) ([]*entities.PauseUnpauseReport, error) {
 | 
						|
	ctrs, rawInputs, err := getContainersAndInputByContext(options.All, options.Latest, namesOrIds, options.Filters, ic.Libpod)
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
	ctrMap := map[string]string{}
 | 
						|
	if len(rawInputs) == len(ctrs) {
 | 
						|
		for i := range ctrs {
 | 
						|
			ctrMap[ctrs[i].ID()] = rawInputs[i]
 | 
						|
		}
 | 
						|
	}
 | 
						|
	reports := make([]*entities.PauseUnpauseReport, 0, len(ctrs))
 | 
						|
	for _, c := range ctrs {
 | 
						|
		err := c.Pause()
 | 
						|
		if err != nil && options.All && errors.Is(err, define.ErrCtrStateInvalid) {
 | 
						|
			logrus.Debugf("Container %s is not running", c.ID())
 | 
						|
			continue
 | 
						|
		}
 | 
						|
		reports = append(reports, &entities.PauseUnpauseReport{
 | 
						|
			Id:       c.ID(),
 | 
						|
			Err:      err,
 | 
						|
			RawInput: ctrMap[c.ID()],
 | 
						|
		})
 | 
						|
	}
 | 
						|
	return reports, nil
 | 
						|
}
 | 
						|
 | 
						|
func (ic *ContainerEngine) ContainerUnpause(ctx context.Context, namesOrIds []string, options entities.PauseUnPauseOptions) ([]*entities.PauseUnpauseReport, error) {
 | 
						|
	ctrs, rawInputs, err := getContainersAndInputByContext(options.All, options.Latest, namesOrIds, options.Filters, ic.Libpod)
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
	ctrMap := map[string]string{}
 | 
						|
	if len(rawInputs) == len(ctrs) {
 | 
						|
		for i := range ctrs {
 | 
						|
			ctrMap[ctrs[i].ID()] = rawInputs[i]
 | 
						|
		}
 | 
						|
	}
 | 
						|
	reports := make([]*entities.PauseUnpauseReport, 0, len(ctrs))
 | 
						|
	for _, c := range ctrs {
 | 
						|
		err := c.Unpause()
 | 
						|
		if err != nil && options.All && errors.Is(err, define.ErrCtrStateInvalid) {
 | 
						|
			logrus.Debugf("Container %s is not paused", c.ID())
 | 
						|
			continue
 | 
						|
		}
 | 
						|
		reports = append(reports, &entities.PauseUnpauseReport{
 | 
						|
			Id:       c.ID(),
 | 
						|
			Err:      err,
 | 
						|
			RawInput: ctrMap[c.ID()],
 | 
						|
		})
 | 
						|
	}
 | 
						|
	return reports, nil
 | 
						|
}
 | 
						|
func (ic *ContainerEngine) ContainerStop(ctx context.Context, namesOrIds []string, options entities.StopOptions) ([]*entities.StopReport, error) {
 | 
						|
	names := namesOrIds
 | 
						|
	ctrs, rawInputs, err := getContainersAndInputByContext(options.All, options.Latest, names, options.Filters, ic.Libpod)
 | 
						|
	if err != nil && !(options.Ignore && errors.Is(err, define.ErrNoSuchCtr)) {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
	ctrMap := map[string]string{}
 | 
						|
	if len(rawInputs) == len(ctrs) {
 | 
						|
		for i := range ctrs {
 | 
						|
			ctrMap[ctrs[i].ID()] = rawInputs[i]
 | 
						|
		}
 | 
						|
	}
 | 
						|
	errMap, err := parallelctr.ContainerOp(ctx, ctrs, func(c *libpod.Container) error {
 | 
						|
		var err error
 | 
						|
		if options.Timeout != nil {
 | 
						|
			err = c.StopWithTimeout(*options.Timeout)
 | 
						|
		} else {
 | 
						|
			err = c.Stop()
 | 
						|
		}
 | 
						|
		if err != nil {
 | 
						|
			switch {
 | 
						|
			case errors.Is(err, define.ErrCtrStopped):
 | 
						|
				logrus.Debugf("Container %s is already stopped", c.ID())
 | 
						|
			case options.All && errors.Is(err, define.ErrCtrStateInvalid):
 | 
						|
				logrus.Debugf("Container %s is not running, could not stop", c.ID())
 | 
						|
			// container never created in OCI runtime
 | 
						|
			// docker parity: do nothing just return container id
 | 
						|
			case errors.Is(err, define.ErrCtrStateInvalid):
 | 
						|
				logrus.Debugf("Container %s is either not created on runtime or is in a invalid state", c.ID())
 | 
						|
			default:
 | 
						|
				return err
 | 
						|
			}
 | 
						|
		}
 | 
						|
		err = c.Cleanup(ctx)
 | 
						|
		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 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
 | 
						|
			}
 | 
						|
			return err
 | 
						|
		}
 | 
						|
		return nil
 | 
						|
	})
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
	reports := make([]*entities.StopReport, 0, len(errMap))
 | 
						|
	for ctr, err := range errMap {
 | 
						|
		report := new(entities.StopReport)
 | 
						|
		report.Id = ctr.ID()
 | 
						|
		if options.All {
 | 
						|
			report.RawInput = ctr.ID()
 | 
						|
		} else {
 | 
						|
			report.RawInput = ctrMap[ctr.ID()]
 | 
						|
		}
 | 
						|
		report.Err = err
 | 
						|
		reports = append(reports, report)
 | 
						|
	}
 | 
						|
	return reports, nil
 | 
						|
}
 | 
						|
 | 
						|
func (ic *ContainerEngine) ContainerPrune(ctx context.Context, options entities.ContainerPruneOptions) ([]*reports.PruneReport, error) {
 | 
						|
	filterFuncs := make([]libpod.ContainerFilter, 0, len(options.Filters))
 | 
						|
	for k, v := range options.Filters {
 | 
						|
		generatedFunc, err := dfilters.GeneratePruneContainerFilterFuncs(k, v, ic.Libpod)
 | 
						|
		if err != nil {
 | 
						|
			return nil, err
 | 
						|
		}
 | 
						|
 | 
						|
		filterFuncs = append(filterFuncs, generatedFunc)
 | 
						|
	}
 | 
						|
	return ic.Libpod.PruneContainers(filterFuncs)
 | 
						|
}
 | 
						|
 | 
						|
func (ic *ContainerEngine) ContainerKill(ctx context.Context, namesOrIds []string, options entities.KillOptions) ([]*entities.KillReport, error) {
 | 
						|
	sig, err := signal.ParseSignalNameOrNumber(options.Signal)
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
	ctrs, rawInputs, err := getContainersAndInputByContext(options.All, options.Latest, namesOrIds, nil, ic.Libpod)
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
	ctrMap := map[string]string{}
 | 
						|
	if len(rawInputs) == len(ctrs) {
 | 
						|
		for i := range ctrs {
 | 
						|
			ctrMap[ctrs[i].ID()] = rawInputs[i]
 | 
						|
		}
 | 
						|
	}
 | 
						|
	reports := make([]*entities.KillReport, 0, len(ctrs))
 | 
						|
	for _, con := range ctrs {
 | 
						|
		err := con.Kill(uint(sig))
 | 
						|
		if options.All && errors.Is(err, define.ErrCtrStateInvalid) {
 | 
						|
			logrus.Debugf("Container %s is not running", con.ID())
 | 
						|
			continue
 | 
						|
		}
 | 
						|
		reports = append(reports, &entities.KillReport{
 | 
						|
			Id:       con.ID(),
 | 
						|
			Err:      err,
 | 
						|
			RawInput: ctrMap[con.ID()],
 | 
						|
		})
 | 
						|
	}
 | 
						|
	return reports, nil
 | 
						|
}
 | 
						|
 | 
						|
func (ic *ContainerEngine) ContainerRestart(ctx context.Context, namesOrIds []string, options entities.RestartOptions) ([]*entities.RestartReport, error) {
 | 
						|
	var (
 | 
						|
		ctrs []*libpod.Container
 | 
						|
		err  error
 | 
						|
	)
 | 
						|
 | 
						|
	if options.Running {
 | 
						|
		ctrs, err = ic.Libpod.GetRunningContainers()
 | 
						|
		if err != nil {
 | 
						|
			return nil, err
 | 
						|
		}
 | 
						|
	} else {
 | 
						|
		ctrs, err = getContainersByContext(options.All, options.Latest, namesOrIds, ic.Libpod)
 | 
						|
		if err != nil {
 | 
						|
			return nil, err
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	reports := make([]*entities.RestartReport, 0, len(ctrs))
 | 
						|
	for _, con := range ctrs {
 | 
						|
		timeout := con.StopTimeout()
 | 
						|
		if options.Timeout != nil {
 | 
						|
			timeout = *options.Timeout
 | 
						|
		}
 | 
						|
		reports = append(reports, &entities.RestartReport{
 | 
						|
			Id:  con.ID(),
 | 
						|
			Err: con.RestartWithTimeout(ctx, timeout),
 | 
						|
		})
 | 
						|
	}
 | 
						|
	return reports, nil
 | 
						|
}
 | 
						|
 | 
						|
func (ic *ContainerEngine) removeContainer(ctx context.Context, ctr *libpod.Container, options entities.RmOptions) error {
 | 
						|
	err := ic.Libpod.RemoveContainer(ctx, ctr, options.Force, options.Volumes, options.Timeout)
 | 
						|
	if err == nil {
 | 
						|
		return nil
 | 
						|
	}
 | 
						|
	logrus.Debugf("Failed to remove container %s: %s", ctr.ID(), err.Error())
 | 
						|
	if errors.Is(err, define.ErrNoSuchCtr) {
 | 
						|
		// Ignore if the container does not exist (anymore) when either
 | 
						|
		// it has been requested by the user of if the container is a
 | 
						|
		// service one.  Service containers are removed along with its
 | 
						|
		// pods which in turn are removed along with their infra
 | 
						|
		// container.  Hence, there is an inherent race when removing
 | 
						|
		// infra containers with service containers in parallel.
 | 
						|
		if options.Ignore || ctr.IsService() {
 | 
						|
			logrus.Debugf("Ignoring error (--allow-missing): %v", err)
 | 
						|
			return nil
 | 
						|
		}
 | 
						|
	} else if errors.Is(err, define.ErrCtrRemoved) {
 | 
						|
		return nil
 | 
						|
	}
 | 
						|
	return err
 | 
						|
}
 | 
						|
 | 
						|
func (ic *ContainerEngine) ContainerRm(ctx context.Context, namesOrIds []string, options entities.RmOptions) ([]*reports.RmReport, error) {
 | 
						|
	rmReports := []*reports.RmReport{}
 | 
						|
 | 
						|
	names := namesOrIds
 | 
						|
	// Attempt to remove named containers directly from storage, if container is defined in libpod
 | 
						|
	// this will fail and code will fall through to removing the container from libpod.`
 | 
						|
	tmpNames := []string{}
 | 
						|
	for _, ctr := range names {
 | 
						|
		report := reports.RmReport{Id: ctr}
 | 
						|
		report.Err = ic.Libpod.RemoveStorageContainer(ctr, options.Force)
 | 
						|
		//nolint:gocritic
 | 
						|
		if report.Err == nil {
 | 
						|
			// remove container names that we successfully deleted
 | 
						|
			rmReports = append(rmReports, &report)
 | 
						|
		} else if errors.Is(report.Err, define.ErrNoSuchCtr) || errors.Is(report.Err, define.ErrCtrExists) {
 | 
						|
			// There is still a potential this is a libpod container
 | 
						|
			tmpNames = append(tmpNames, ctr)
 | 
						|
		} else {
 | 
						|
			if _, err := ic.Libpod.LookupContainer(ctr); errors.Is(err, define.ErrNoSuchCtr) {
 | 
						|
				// remove container failed, but not a libpod container
 | 
						|
				rmReports = append(rmReports, &report)
 | 
						|
				continue
 | 
						|
			}
 | 
						|
			// attempt to remove as a libpod container
 | 
						|
			tmpNames = append(tmpNames, ctr)
 | 
						|
		}
 | 
						|
	}
 | 
						|
	names = tmpNames
 | 
						|
 | 
						|
	ctrs, err := getContainersByContext(options.All, options.Latest, names, ic.Libpod)
 | 
						|
	if err != nil && !(options.Ignore && errors.Is(err, define.ErrNoSuchCtr)) {
 | 
						|
		// Failed to get containers. If force is specified, get the containers ID
 | 
						|
		// and evict them
 | 
						|
		if !options.Force {
 | 
						|
			return nil, err
 | 
						|
		}
 | 
						|
 | 
						|
		for _, ctr := range names {
 | 
						|
			logrus.Debugf("Evicting container %q", ctr)
 | 
						|
			report := reports.RmReport{Id: ctr}
 | 
						|
			_, err := ic.Libpod.EvictContainer(ctx, ctr, options.Volumes)
 | 
						|
			if err != nil {
 | 
						|
				if options.Ignore && errors.Is(err, define.ErrNoSuchCtr) {
 | 
						|
					logrus.Debugf("Ignoring error (--allow-missing): %v", err)
 | 
						|
					rmReports = append(rmReports, &report)
 | 
						|
					continue
 | 
						|
				}
 | 
						|
				report.Err = err
 | 
						|
				rmReports = append(rmReports, &report)
 | 
						|
				continue
 | 
						|
			}
 | 
						|
			rmReports = append(rmReports, &report)
 | 
						|
		}
 | 
						|
		return rmReports, nil
 | 
						|
	}
 | 
						|
 | 
						|
	alreadyRemoved := make(map[string]bool)
 | 
						|
	addReports := func(newReports []*reports.RmReport) {
 | 
						|
		for i := range newReports {
 | 
						|
			alreadyRemoved[newReports[i].Id] = true
 | 
						|
			rmReports = append(rmReports, newReports[i])
 | 
						|
		}
 | 
						|
	}
 | 
						|
	if !options.All && options.Depend {
 | 
						|
		// Add additional containers based on dependencies to container map
 | 
						|
		for _, ctr := range ctrs {
 | 
						|
			if alreadyRemoved[ctr.ID()] {
 | 
						|
				continue
 | 
						|
			}
 | 
						|
			reports, err := ic.Libpod.RemoveDepend(ctx, ctr, options.Force, options.Volumes, options.Timeout)
 | 
						|
			if err != nil {
 | 
						|
				return rmReports, err
 | 
						|
			}
 | 
						|
			addReports(reports)
 | 
						|
		}
 | 
						|
		return rmReports, nil
 | 
						|
	}
 | 
						|
 | 
						|
	// If --all is set, make sure to remove the infra containers'
 | 
						|
	// dependencies before doing the parallel removal below.
 | 
						|
	if options.All {
 | 
						|
		for _, ctr := range ctrs {
 | 
						|
			if alreadyRemoved[ctr.ID()] || !ctr.IsInfra() {
 | 
						|
				continue
 | 
						|
			}
 | 
						|
			reports, err := ic.Libpod.RemoveDepend(ctx, ctr, options.Force, options.Volumes, options.Timeout)
 | 
						|
			if err != nil {
 | 
						|
				return rmReports, err
 | 
						|
			}
 | 
						|
			addReports(reports)
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	errMap, err := parallelctr.ContainerOp(ctx, ctrs, func(c *libpod.Container) error {
 | 
						|
		if alreadyRemoved[c.ID()] {
 | 
						|
			return nil
 | 
						|
		}
 | 
						|
		return ic.removeContainer(ctx, c, options)
 | 
						|
	})
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
	for ctr, err := range errMap {
 | 
						|
		if alreadyRemoved[ctr.ID()] {
 | 
						|
			continue
 | 
						|
		}
 | 
						|
		report := new(reports.RmReport)
 | 
						|
		report.Id = ctr.ID()
 | 
						|
		report.Err = err
 | 
						|
		rmReports = append(rmReports, report)
 | 
						|
	}
 | 
						|
	return rmReports, nil
 | 
						|
}
 | 
						|
 | 
						|
func (ic *ContainerEngine) ContainerInspect(ctx context.Context, namesOrIds []string, options entities.InspectOptions) ([]*entities.ContainerInspectReport, []error, error) {
 | 
						|
	if options.Latest {
 | 
						|
		ctr, err := ic.Libpod.GetLatestContainer()
 | 
						|
		if err != nil {
 | 
						|
			if errors.Is(err, define.ErrNoSuchCtr) {
 | 
						|
				return nil, []error{fmt.Errorf("no containers to inspect: %w", err)}, nil
 | 
						|
			}
 | 
						|
			return nil, nil, err
 | 
						|
		}
 | 
						|
 | 
						|
		inspect, err := ctr.Inspect(options.Size)
 | 
						|
		if err != nil {
 | 
						|
			return nil, nil, err
 | 
						|
		}
 | 
						|
 | 
						|
		return []*entities.ContainerInspectReport{
 | 
						|
			{
 | 
						|
				InspectContainerData: inspect,
 | 
						|
			},
 | 
						|
		}, nil, nil
 | 
						|
	}
 | 
						|
	var (
 | 
						|
		reports = make([]*entities.ContainerInspectReport, 0, len(namesOrIds))
 | 
						|
		errs    = []error{}
 | 
						|
	)
 | 
						|
	for _, name := range namesOrIds {
 | 
						|
		ctr, err := ic.Libpod.LookupContainer(name)
 | 
						|
		if err != nil {
 | 
						|
			// ErrNoSuchCtr is non-fatal, other errors will be
 | 
						|
			// treated as fatal.
 | 
						|
			if errors.Is(err, define.ErrNoSuchCtr) {
 | 
						|
				errs = append(errs, fmt.Errorf("no such container %s", name))
 | 
						|
				continue
 | 
						|
			}
 | 
						|
			return nil, nil, err
 | 
						|
		}
 | 
						|
 | 
						|
		inspect, err := ctr.Inspect(options.Size)
 | 
						|
		if err != nil {
 | 
						|
			// ErrNoSuchCtr is non-fatal, other errors will be
 | 
						|
			// treated as fatal.
 | 
						|
			if errors.Is(err, define.ErrNoSuchCtr) {
 | 
						|
				errs = append(errs, fmt.Errorf("no such container %s", name))
 | 
						|
				continue
 | 
						|
			}
 | 
						|
			return nil, nil, err
 | 
						|
		}
 | 
						|
 | 
						|
		reports = append(reports, &entities.ContainerInspectReport{InspectContainerData: inspect})
 | 
						|
	}
 | 
						|
	return reports, errs, nil
 | 
						|
}
 | 
						|
 | 
						|
func (ic *ContainerEngine) ContainerTop(ctx context.Context, options entities.TopOptions) (*entities.StringSliceReport, error) {
 | 
						|
	var (
 | 
						|
		container *libpod.Container
 | 
						|
		err       error
 | 
						|
	)
 | 
						|
 | 
						|
	// Look up the container.
 | 
						|
	if options.Latest {
 | 
						|
		container, err = ic.Libpod.GetLatestContainer()
 | 
						|
	} else {
 | 
						|
		container, err = ic.Libpod.LookupContainer(options.NameOrID)
 | 
						|
	}
 | 
						|
	if err != nil {
 | 
						|
		return nil, fmt.Errorf("unable to look up requested container: %w", err)
 | 
						|
	}
 | 
						|
 | 
						|
	// Run Top.
 | 
						|
	report := &entities.StringSliceReport{}
 | 
						|
	report.Value, err = container.Top(options.Descriptors)
 | 
						|
	return report, err
 | 
						|
}
 | 
						|
 | 
						|
func (ic *ContainerEngine) ContainerCommit(ctx context.Context, nameOrID string, options entities.CommitOptions) (*entities.CommitReport, error) {
 | 
						|
	var (
 | 
						|
		mimeType string
 | 
						|
	)
 | 
						|
	ctr, err := ic.Libpod.LookupContainer(nameOrID)
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
	rtc, err := ic.Libpod.GetConfig()
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
	switch options.Format {
 | 
						|
	case "oci":
 | 
						|
		mimeType = buildah.OCIv1ImageManifest
 | 
						|
		if len(options.Message) > 0 {
 | 
						|
			return nil, fmt.Errorf("messages are only compatible with the docker image format (-f docker)")
 | 
						|
		}
 | 
						|
	case "docker":
 | 
						|
		mimeType = manifest.DockerV2Schema2MediaType
 | 
						|
	default:
 | 
						|
		return nil, fmt.Errorf("unrecognized image format %q", options.Format)
 | 
						|
	}
 | 
						|
 | 
						|
	sc := ic.Libpod.SystemContext()
 | 
						|
	coptions := buildah.CommitOptions{
 | 
						|
		SignaturePolicyPath:   rtc.Engine.SignaturePolicyPath,
 | 
						|
		ReportWriter:          options.Writer,
 | 
						|
		SystemContext:         sc,
 | 
						|
		PreferredManifestType: mimeType,
 | 
						|
	}
 | 
						|
	opts := libpod.ContainerCommitOptions{
 | 
						|
		CommitOptions:  coptions,
 | 
						|
		Pause:          options.Pause,
 | 
						|
		IncludeVolumes: options.IncludeVolumes,
 | 
						|
		Message:        options.Message,
 | 
						|
		Changes:        options.Changes,
 | 
						|
		Author:         options.Author,
 | 
						|
		Squash:         options.Squash,
 | 
						|
	}
 | 
						|
	newImage, err := ctr.Commit(ctx, options.ImageName, opts)
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
	return &entities.CommitReport{Id: newImage.ID()}, nil
 | 
						|
}
 | 
						|
 | 
						|
func (ic *ContainerEngine) ContainerExport(ctx context.Context, nameOrID string, options entities.ContainerExportOptions) error {
 | 
						|
	ctr, err := ic.Libpod.LookupContainer(nameOrID)
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	return ctr.Export(options.Output)
 | 
						|
}
 | 
						|
 | 
						|
func (ic *ContainerEngine) ContainerCheckpoint(ctx context.Context, namesOrIds []string, options entities.CheckpointOptions) ([]*entities.CheckpointReport, error) {
 | 
						|
	var (
 | 
						|
		err  error
 | 
						|
		cons []*libpod.Container
 | 
						|
	)
 | 
						|
	checkOpts := libpod.ContainerCheckpointOptions{
 | 
						|
		Keep:           options.Keep,
 | 
						|
		TCPEstablished: options.TCPEstablished,
 | 
						|
		TargetFile:     options.Export,
 | 
						|
		IgnoreRootfs:   options.IgnoreRootFS,
 | 
						|
		IgnoreVolumes:  options.IgnoreVolumes,
 | 
						|
		KeepRunning:    options.LeaveRunning,
 | 
						|
		PreCheckPoint:  options.PreCheckPoint,
 | 
						|
		WithPrevious:   options.WithPrevious,
 | 
						|
		Compression:    options.Compression,
 | 
						|
		PrintStats:     options.PrintStats,
 | 
						|
		FileLocks:      options.FileLocks,
 | 
						|
		CreateImage:    options.CreateImage,
 | 
						|
	}
 | 
						|
 | 
						|
	if options.All {
 | 
						|
		running := func(c *libpod.Container) bool {
 | 
						|
			state, _ := c.State()
 | 
						|
			return state == define.ContainerStateRunning
 | 
						|
		}
 | 
						|
		cons, err = ic.Libpod.GetContainers(running)
 | 
						|
	} else {
 | 
						|
		cons, err = getContainersByContext(false, options.Latest, namesOrIds, ic.Libpod)
 | 
						|
	}
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
	reports := make([]*entities.CheckpointReport, 0, len(cons))
 | 
						|
	for _, con := range cons {
 | 
						|
		criuStatistics, runtimeCheckpointDuration, err := con.Checkpoint(ctx, checkOpts)
 | 
						|
		reports = append(reports, &entities.CheckpointReport{
 | 
						|
			Err:             err,
 | 
						|
			Id:              con.ID(),
 | 
						|
			RuntimeDuration: runtimeCheckpointDuration,
 | 
						|
			CRIUStatistics:  criuStatistics,
 | 
						|
		})
 | 
						|
	}
 | 
						|
	return reports, nil
 | 
						|
}
 | 
						|
 | 
						|
func (ic *ContainerEngine) ContainerRestore(ctx context.Context, namesOrIds []string, options entities.RestoreOptions) ([]*entities.RestoreReport, error) {
 | 
						|
	var (
 | 
						|
		containers                  []*libpod.Container
 | 
						|
		checkpointImageImportErrors []error
 | 
						|
		err                         error
 | 
						|
	)
 | 
						|
 | 
						|
	restoreOptions := libpod.ContainerCheckpointOptions{
 | 
						|
		Keep:            options.Keep,
 | 
						|
		TCPEstablished:  options.TCPEstablished,
 | 
						|
		TargetFile:      options.Import,
 | 
						|
		Name:            options.Name,
 | 
						|
		IgnoreRootfs:    options.IgnoreRootFS,
 | 
						|
		IgnoreVolumes:   options.IgnoreVolumes,
 | 
						|
		IgnoreStaticIP:  options.IgnoreStaticIP,
 | 
						|
		IgnoreStaticMAC: options.IgnoreStaticMAC,
 | 
						|
		ImportPrevious:  options.ImportPrevious,
 | 
						|
		Pod:             options.Pod,
 | 
						|
		PrintStats:      options.PrintStats,
 | 
						|
		FileLocks:       options.FileLocks,
 | 
						|
	}
 | 
						|
 | 
						|
	filterFuncs := []libpod.ContainerFilter{
 | 
						|
		func(c *libpod.Container) bool {
 | 
						|
			state, _ := c.State()
 | 
						|
			return state == define.ContainerStateExited
 | 
						|
		},
 | 
						|
	}
 | 
						|
 | 
						|
	switch {
 | 
						|
	case options.Import != "":
 | 
						|
		containers, err = checkpoint.CRImportCheckpointTar(ctx, ic.Libpod, options)
 | 
						|
	case options.All:
 | 
						|
		containers, err = ic.Libpod.GetContainers(filterFuncs...)
 | 
						|
	case options.Latest:
 | 
						|
		containers, err = getContainersByContext(false, options.Latest, namesOrIds, ic.Libpod)
 | 
						|
	default:
 | 
						|
		for _, nameOrID := range namesOrIds {
 | 
						|
			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("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)
 | 
						|
				}
 | 
						|
				restoreOptions.CheckpointImageID = img.ID()
 | 
						|
				mountPoint, err := img.Mount(ctx, nil, "")
 | 
						|
				defer func() {
 | 
						|
					if err := img.Unmount(true); err != nil {
 | 
						|
						logrus.Errorf("Failed to unmount image: %v", err)
 | 
						|
					}
 | 
						|
				}()
 | 
						|
				if err != nil {
 | 
						|
					return nil, err
 | 
						|
				}
 | 
						|
				importedContainers, err := checkpoint.CRImportCheckpoint(ctx, ic.Libpod, options, mountPoint)
 | 
						|
				if err != nil {
 | 
						|
					// CRImportCheckpoint is expected to import exactly one container from checkpoint image
 | 
						|
					checkpointImageImportErrors = append(
 | 
						|
						checkpointImageImportErrors,
 | 
						|
						fmt.Errorf("unable to import checkpoint from image: %q: %v", nameOrID, err),
 | 
						|
					)
 | 
						|
				} else {
 | 
						|
					containers = append(containers, importedContainers[0])
 | 
						|
				}
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
 | 
						|
	reports := make([]*entities.RestoreReport, 0, len(containers))
 | 
						|
	for _, con := range containers {
 | 
						|
		criuStatistics, runtimeRestoreDuration, err := con.Restore(ctx, restoreOptions)
 | 
						|
		reports = append(reports, &entities.RestoreReport{
 | 
						|
			Err:             err,
 | 
						|
			Id:              con.ID(),
 | 
						|
			RuntimeDuration: runtimeRestoreDuration,
 | 
						|
			CRIUStatistics:  criuStatistics,
 | 
						|
		})
 | 
						|
	}
 | 
						|
 | 
						|
	for _, importErr := range checkpointImageImportErrors {
 | 
						|
		reports = append(reports, &entities.RestoreReport{
 | 
						|
			Err: importErr,
 | 
						|
		})
 | 
						|
	}
 | 
						|
 | 
						|
	return reports, nil
 | 
						|
}
 | 
						|
 | 
						|
func (ic *ContainerEngine) ContainerCreate(ctx context.Context, s *specgen.SpecGenerator) (*entities.ContainerCreateReport, error) {
 | 
						|
	warn, err := generate.CompleteSpec(ctx, ic.Libpod, s)
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
	// Print warnings
 | 
						|
	for _, w := range warn {
 | 
						|
		fmt.Fprintf(os.Stderr, "%s\n", w)
 | 
						|
	}
 | 
						|
	rtSpec, spec, opts, err := generate.MakeContainer(context.Background(), ic.Libpod, s, false, nil)
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
	ctr, err := generate.ExecuteCreate(ctx, ic.Libpod, rtSpec, spec, false, opts...)
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
	return &entities.ContainerCreateReport{Id: ctr.ID()}, nil
 | 
						|
}
 | 
						|
 | 
						|
func (ic *ContainerEngine) ContainerAttach(ctx context.Context, nameOrID string, options entities.AttachOptions) error {
 | 
						|
	ctrs, err := getContainersByContext(false, options.Latest, []string{nameOrID}, ic.Libpod)
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	ctr := ctrs[0]
 | 
						|
	conState, err := ctr.State()
 | 
						|
	if err != nil {
 | 
						|
		return fmt.Errorf("unable to determine state of %s: %w", ctr.ID(), err)
 | 
						|
	}
 | 
						|
	if conState != define.ContainerStateRunning {
 | 
						|
		return fmt.Errorf("you can only attach to running containers")
 | 
						|
	}
 | 
						|
 | 
						|
	// If the container is in a pod, also set to recursively start dependencies
 | 
						|
	err = terminal.StartAttachCtr(ctx, ctr, options.Stdout, options.Stderr, options.Stdin, options.DetachKeys, options.SigProxy, false)
 | 
						|
	if err != nil && !errors.Is(err, define.ErrDetach) {
 | 
						|
		return fmt.Errorf("error attaching to container %s: %w", ctr.ID(), err)
 | 
						|
	}
 | 
						|
	os.Stdout.WriteString("\n")
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
func makeExecConfig(options entities.ExecOptions, rt *libpod.Runtime) (*libpod.ExecConfig, error) {
 | 
						|
	execConfig := new(libpod.ExecConfig)
 | 
						|
	execConfig.Command = options.Cmd
 | 
						|
	execConfig.Terminal = options.Tty
 | 
						|
	execConfig.Privileged = options.Privileged
 | 
						|
	execConfig.Environment = options.Envs
 | 
						|
	execConfig.User = options.User
 | 
						|
	execConfig.WorkDir = options.WorkDir
 | 
						|
	execConfig.DetachKeys = &options.DetachKeys
 | 
						|
	execConfig.PreserveFDs = options.PreserveFDs
 | 
						|
	execConfig.AttachStdin = options.Interactive
 | 
						|
 | 
						|
	// Make an exit command
 | 
						|
	storageConfig := rt.StorageConfig()
 | 
						|
	runtimeConfig, err := rt.GetConfig()
 | 
						|
	if err != nil {
 | 
						|
		return nil, fmt.Errorf("error retrieving Libpod configuration to build exec exit command: %w", err)
 | 
						|
	}
 | 
						|
	// TODO: Add some ability to toggle syslog
 | 
						|
	exitCommandArgs, err := specgenutil.CreateExitCommandArgs(storageConfig, runtimeConfig, logrus.IsLevelEnabled(logrus.DebugLevel), false, true)
 | 
						|
	if err != nil {
 | 
						|
		return nil, fmt.Errorf("error constructing exit command for exec session: %w", err)
 | 
						|
	}
 | 
						|
	execConfig.ExitCommand = exitCommandArgs
 | 
						|
 | 
						|
	return execConfig, nil
 | 
						|
}
 | 
						|
 | 
						|
func checkExecPreserveFDs(options entities.ExecOptions) error {
 | 
						|
	if options.PreserveFDs > 0 {
 | 
						|
		entries, err := ioutil.ReadDir("/proc/self/fd")
 | 
						|
		if err != nil {
 | 
						|
			return err
 | 
						|
		}
 | 
						|
 | 
						|
		m := make(map[int]bool)
 | 
						|
		for _, e := range entries {
 | 
						|
			i, err := strconv.Atoi(e.Name())
 | 
						|
			if err != nil {
 | 
						|
				return fmt.Errorf("cannot parse %s in /proc/self/fd: %w", e.Name(), err)
 | 
						|
			}
 | 
						|
			m[i] = true
 | 
						|
		}
 | 
						|
 | 
						|
		for i := 3; i < 3+int(options.PreserveFDs); i++ {
 | 
						|
			if _, found := m[i]; !found {
 | 
						|
				return errors.New("invalid --preserve-fds=N specified. Not enough FDs available")
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
func (ic *ContainerEngine) ContainerExec(ctx context.Context, nameOrID string, options entities.ExecOptions, streams define.AttachStreams) (int, error) {
 | 
						|
	ec := define.ExecErrorCodeGeneric
 | 
						|
	err := checkExecPreserveFDs(options)
 | 
						|
	if err != nil {
 | 
						|
		return ec, err
 | 
						|
	}
 | 
						|
	ctrs, err := getContainersByContext(false, options.Latest, []string{nameOrID}, ic.Libpod)
 | 
						|
	if err != nil {
 | 
						|
		return ec, err
 | 
						|
	}
 | 
						|
	ctr := ctrs[0]
 | 
						|
 | 
						|
	execConfig, err := makeExecConfig(options, ic.Libpod)
 | 
						|
	if err != nil {
 | 
						|
		return ec, err
 | 
						|
	}
 | 
						|
 | 
						|
	ec, err = terminal.ExecAttachCtr(ctx, ctr, execConfig, &streams)
 | 
						|
	return define.TranslateExecErrorToExitCode(ec, err), err
 | 
						|
}
 | 
						|
 | 
						|
func (ic *ContainerEngine) ContainerExecDetached(ctx context.Context, nameOrID string, options entities.ExecOptions) (string, error) {
 | 
						|
	err := checkExecPreserveFDs(options)
 | 
						|
	if err != nil {
 | 
						|
		return "", err
 | 
						|
	}
 | 
						|
	ctrs, err := getContainersByContext(false, options.Latest, []string{nameOrID}, ic.Libpod)
 | 
						|
	if err != nil {
 | 
						|
		return "", err
 | 
						|
	}
 | 
						|
	ctr := ctrs[0]
 | 
						|
 | 
						|
	execConfig, err := makeExecConfig(options, ic.Libpod)
 | 
						|
	if err != nil {
 | 
						|
		return "", err
 | 
						|
	}
 | 
						|
 | 
						|
	// Create and start the exec session
 | 
						|
	id, err := ctr.ExecCreate(execConfig)
 | 
						|
	if err != nil {
 | 
						|
		return "", err
 | 
						|
	}
 | 
						|
 | 
						|
	// TODO: we should try and retrieve exit code if this fails.
 | 
						|
	if err := ctr.ExecStart(id); err != nil {
 | 
						|
		return "", err
 | 
						|
	}
 | 
						|
	return id, nil
 | 
						|
}
 | 
						|
 | 
						|
func (ic *ContainerEngine) ContainerStart(ctx context.Context, namesOrIds []string, options entities.ContainerStartOptions) ([]*entities.ContainerStartReport, error) {
 | 
						|
	reports := []*entities.ContainerStartReport{}
 | 
						|
	var exitCode = define.ExecErrorCodeGeneric
 | 
						|
	containersNamesOrIds := namesOrIds
 | 
						|
	all := options.All
 | 
						|
	if len(options.Filters) > 0 {
 | 
						|
		all = false
 | 
						|
		filterFuncs := make([]libpod.ContainerFilter, 0, len(options.Filters))
 | 
						|
		if len(options.Filters) > 0 {
 | 
						|
			for k, v := range options.Filters {
 | 
						|
				generatedFunc, err := dfilters.GenerateContainerFilterFuncs(k, v, ic.Libpod)
 | 
						|
				if err != nil {
 | 
						|
					return nil, err
 | 
						|
				}
 | 
						|
				filterFuncs = append(filterFuncs, generatedFunc)
 | 
						|
			}
 | 
						|
		}
 | 
						|
		candidates, err := ic.Libpod.GetContainers(filterFuncs...)
 | 
						|
		if err != nil {
 | 
						|
			return nil, err
 | 
						|
		}
 | 
						|
		containersNamesOrIds = []string{}
 | 
						|
		for _, candidate := range candidates {
 | 
						|
			if options.All {
 | 
						|
				containersNamesOrIds = append(containersNamesOrIds, candidate.ID())
 | 
						|
				continue
 | 
						|
			}
 | 
						|
			for _, nameOrID := range namesOrIds {
 | 
						|
				if nameOrID == candidate.ID() || nameOrID == candidate.Name() {
 | 
						|
					containersNamesOrIds = append(containersNamesOrIds, nameOrID)
 | 
						|
				}
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
	ctrs, rawInputs, err := getContainersAndInputByContext(all, options.Latest, containersNamesOrIds, options.Filters, ic.Libpod)
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
	// There can only be one container if attach was used
 | 
						|
	for i := range ctrs {
 | 
						|
		ctr := ctrs[i]
 | 
						|
		rawInput := ctr.ID()
 | 
						|
		if !options.All {
 | 
						|
			rawInput = rawInputs[i]
 | 
						|
		}
 | 
						|
		ctrState, err := ctr.State()
 | 
						|
		if err != nil {
 | 
						|
			return nil, err
 | 
						|
		}
 | 
						|
		ctrRunning := ctrState == define.ContainerStateRunning
 | 
						|
 | 
						|
		if options.Attach {
 | 
						|
			err = terminal.StartAttachCtr(ctx, ctr, options.Stdout, options.Stderr, options.Stdin, options.DetachKeys, options.SigProxy, !ctrRunning)
 | 
						|
			if errors.Is(err, define.ErrDetach) {
 | 
						|
				// User manually detached
 | 
						|
				// Exit cleanly immediately
 | 
						|
				reports = append(reports, &entities.ContainerStartReport{
 | 
						|
					Id:       ctr.ID(),
 | 
						|
					RawInput: rawInput,
 | 
						|
					Err:      nil,
 | 
						|
					ExitCode: 0,
 | 
						|
				})
 | 
						|
				return reports, nil
 | 
						|
			}
 | 
						|
 | 
						|
			if errors.Is(err, define.ErrWillDeadlock) {
 | 
						|
				logrus.Debugf("Deadlock error: %v", err)
 | 
						|
				reports = append(reports, &entities.ContainerStartReport{
 | 
						|
					Id:       ctr.ID(),
 | 
						|
					RawInput: rawInput,
 | 
						|
					Err:      err,
 | 
						|
					ExitCode: define.ExitCode(err),
 | 
						|
				})
 | 
						|
				return reports, fmt.Errorf("attempting to start container %s would cause a deadlock; please run 'podman system renumber' to resolve", ctr.ID())
 | 
						|
			}
 | 
						|
 | 
						|
			if ctrRunning {
 | 
						|
				reports = append(reports, &entities.ContainerStartReport{
 | 
						|
					Id:       ctr.ID(),
 | 
						|
					RawInput: rawInput,
 | 
						|
					Err:      nil,
 | 
						|
					ExitCode: 0,
 | 
						|
				})
 | 
						|
				return reports, err
 | 
						|
			}
 | 
						|
 | 
						|
			if err != nil {
 | 
						|
				reports = append(reports, &entities.ContainerStartReport{
 | 
						|
					Id:       ctr.ID(),
 | 
						|
					RawInput: rawInput,
 | 
						|
					Err:      err,
 | 
						|
					ExitCode: exitCode,
 | 
						|
				})
 | 
						|
				if ctr.AutoRemove() {
 | 
						|
					if err := ic.removeContainer(ctx, ctr, entities.RmOptions{}); err != nil {
 | 
						|
						logrus.Errorf("Removing container %s: %v", ctr.ID(), err)
 | 
						|
					}
 | 
						|
				}
 | 
						|
				return reports, fmt.Errorf("unable to start container %s: %w", ctr.ID(), err)
 | 
						|
			}
 | 
						|
 | 
						|
			exitCode = ic.GetContainerExitCode(ctx, ctr)
 | 
						|
			reports = append(reports, &entities.ContainerStartReport{
 | 
						|
				Id:       ctr.ID(),
 | 
						|
				RawInput: rawInput,
 | 
						|
				Err:      err,
 | 
						|
				ExitCode: exitCode,
 | 
						|
			})
 | 
						|
			return reports, nil
 | 
						|
		} // end attach
 | 
						|
 | 
						|
		// Start the container if it's not running already.
 | 
						|
		if !ctrRunning {
 | 
						|
			// Handle non-attach start
 | 
						|
			// If the container is in a pod, also set to recursively start dependencies
 | 
						|
			report := &entities.ContainerStartReport{
 | 
						|
				Id:       ctr.ID(),
 | 
						|
				RawInput: rawInput,
 | 
						|
				ExitCode: 125,
 | 
						|
			}
 | 
						|
			if err := ctr.Start(ctx, true); err != nil {
 | 
						|
				report.Err = err
 | 
						|
				if errors.Is(err, define.ErrWillDeadlock) {
 | 
						|
					report.Err = fmt.Errorf("please run 'podman system renumber' to resolve deadlocks: %w", err)
 | 
						|
					reports = append(reports, report)
 | 
						|
					continue
 | 
						|
				}
 | 
						|
				report.Err = fmt.Errorf("unable to start container %q: %w", ctr.ID(), err)
 | 
						|
				reports = append(reports, report)
 | 
						|
				if ctr.AutoRemove() {
 | 
						|
					if err := ic.removeContainer(ctx, ctr, entities.RmOptions{}); err != nil {
 | 
						|
						logrus.Errorf("Removing container %s: %v", ctr.ID(), err)
 | 
						|
					}
 | 
						|
				}
 | 
						|
				continue
 | 
						|
			}
 | 
						|
			report.ExitCode = 0
 | 
						|
			reports = append(reports, report)
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return reports, nil
 | 
						|
}
 | 
						|
 | 
						|
func (ic *ContainerEngine) ContainerList(ctx context.Context, options entities.ContainerListOptions) ([]entities.ListContainer, error) {
 | 
						|
	if options.Latest {
 | 
						|
		options.Last = 1
 | 
						|
	}
 | 
						|
	return ps.GetContainerLists(ic.Libpod, options)
 | 
						|
}
 | 
						|
 | 
						|
func (ic *ContainerEngine) ContainerListExternal(ctx context.Context) ([]entities.ListContainer, error) {
 | 
						|
	return ps.GetExternalContainerLists(ic.Libpod)
 | 
						|
}
 | 
						|
 | 
						|
// Diff provides changes to given container
 | 
						|
func (ic *ContainerEngine) Diff(ctx context.Context, namesOrIDs []string, opts entities.DiffOptions) (*entities.DiffReport, error) {
 | 
						|
	var (
 | 
						|
		base   string
 | 
						|
		parent string
 | 
						|
	)
 | 
						|
	if opts.Latest {
 | 
						|
		ctnr, err := ic.Libpod.GetLatestContainer()
 | 
						|
		if err != nil {
 | 
						|
			return nil, fmt.Errorf("unable to get latest container: %w", err)
 | 
						|
		}
 | 
						|
		base = ctnr.ID()
 | 
						|
	}
 | 
						|
	if len(namesOrIDs) > 0 {
 | 
						|
		base = namesOrIDs[0]
 | 
						|
		if len(namesOrIDs) > 1 {
 | 
						|
			parent = namesOrIDs[1]
 | 
						|
		}
 | 
						|
	}
 | 
						|
	changes, err := ic.Libpod.GetDiff(parent, base, opts.Type)
 | 
						|
	return &entities.DiffReport{Changes: changes}, err
 | 
						|
}
 | 
						|
 | 
						|
func (ic *ContainerEngine) ContainerRun(ctx context.Context, opts entities.ContainerRunOptions) (*entities.ContainerRunReport, error) {
 | 
						|
	removeContainer := func(ctr *libpod.Container, force bool) error {
 | 
						|
		var timeout *uint
 | 
						|
		if err := ic.Libpod.RemoveContainer(ctx, ctr, force, true, timeout); err != nil {
 | 
						|
			logrus.Debugf("unable to remove container %s after failing to start and attach to it: %v", ctr.ID(), err)
 | 
						|
			return err
 | 
						|
		}
 | 
						|
		return nil
 | 
						|
	}
 | 
						|
 | 
						|
	warn, err := generate.CompleteSpec(ctx, ic.Libpod, opts.Spec)
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
	// Print warnings
 | 
						|
	for _, w := range warn {
 | 
						|
		fmt.Fprintf(os.Stderr, "%s\n", w)
 | 
						|
	}
 | 
						|
 | 
						|
	rtSpec, spec, optsN, err := generate.MakeContainer(ctx, ic.Libpod, opts.Spec, false, nil)
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
	ctr, err := generate.ExecuteCreate(ctx, ic.Libpod, rtSpec, spec, false, optsN...)
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
 | 
						|
	if opts.CIDFile != "" {
 | 
						|
		if err := util.CreateCidFile(opts.CIDFile, ctr.ID()); err != nil {
 | 
						|
			// If you fail to create CIDFile then remove the container
 | 
						|
			_ = removeContainer(ctr, true)
 | 
						|
			return nil, err
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	report := entities.ContainerRunReport{Id: ctr.ID()}
 | 
						|
 | 
						|
	if logrus.GetLevel() == logrus.DebugLevel {
 | 
						|
		cgroupPath, err := ctr.CgroupPath()
 | 
						|
		if err == nil {
 | 
						|
			logrus.Debugf("container %q has CgroupParent %q", ctr.ID(), cgroupPath)
 | 
						|
		}
 | 
						|
	}
 | 
						|
	if opts.Detach {
 | 
						|
		// if the container was created as part of a pod, also start its dependencies, if any.
 | 
						|
		if err := ctr.Start(ctx, true); err != nil {
 | 
						|
			// This means the command did not exist
 | 
						|
			report.ExitCode = define.ExitCode(err)
 | 
						|
			if opts.Rm {
 | 
						|
				if rmErr := removeContainer(ctr, true); rmErr != nil && !errors.Is(rmErr, define.ErrNoSuchCtr) {
 | 
						|
					logrus.Errorf("Container %s failed to be removed", ctr.ID())
 | 
						|
				}
 | 
						|
			}
 | 
						|
			return &report, err
 | 
						|
		}
 | 
						|
 | 
						|
		return &report, nil
 | 
						|
	}
 | 
						|
 | 
						|
	// if the container was created as part of a pod, also start its dependencies, if any.
 | 
						|
	if err := terminal.StartAttachCtr(ctx, ctr, opts.OutputStream, opts.ErrorStream, opts.InputStream, opts.DetachKeys, opts.SigProxy, true); err != nil {
 | 
						|
		// We've manually detached from the container
 | 
						|
		// Do not perform cleanup, or wait for container exit code
 | 
						|
		// Just exit immediately
 | 
						|
		if errors.Is(err, define.ErrDetach) {
 | 
						|
			report.ExitCode = 0
 | 
						|
			return &report, nil
 | 
						|
		}
 | 
						|
		if opts.Rm {
 | 
						|
			_ = removeContainer(ctr, true)
 | 
						|
		}
 | 
						|
		if errors.Is(err, define.ErrWillDeadlock) {
 | 
						|
			logrus.Debugf("Deadlock error on %q: %v", ctr.ID(), err)
 | 
						|
			report.ExitCode = define.ExitCode(err)
 | 
						|
			return &report, fmt.Errorf("attempting to start container %s would cause a deadlock; please run 'podman system renumber' to resolve", ctr.ID())
 | 
						|
		}
 | 
						|
		report.ExitCode = define.ExitCode(err)
 | 
						|
		return &report, err
 | 
						|
	}
 | 
						|
	report.ExitCode = ic.GetContainerExitCode(ctx, ctr)
 | 
						|
	if opts.Rm && !ctr.ShouldRestart(ctx) {
 | 
						|
		if err := removeContainer(ctr, false); err != nil {
 | 
						|
			if errors.Is(err, define.ErrNoSuchCtr) ||
 | 
						|
				errors.Is(err, define.ErrCtrRemoved) {
 | 
						|
				logrus.Infof("Container %s was already removed, skipping --rm", ctr.ID())
 | 
						|
			} else {
 | 
						|
				logrus.Errorf("Removing container %s: %v", ctr.ID(), err)
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return &report, nil
 | 
						|
}
 | 
						|
 | 
						|
func (ic *ContainerEngine) GetContainerExitCode(ctx context.Context, ctr *libpod.Container) int {
 | 
						|
	exitCode, err := ctr.Wait(ctx)
 | 
						|
	if err != nil {
 | 
						|
		logrus.Errorf("Waiting for container %s: %v", ctr.ID(), err)
 | 
						|
		return define.ExecErrorCodeNotFound
 | 
						|
	}
 | 
						|
	return int(exitCode)
 | 
						|
}
 | 
						|
 | 
						|
func (ic *ContainerEngine) ContainerLogs(ctx context.Context, containers []string, options entities.ContainerLogsOptions) error {
 | 
						|
	if options.StdoutWriter == nil && options.StderrWriter == nil {
 | 
						|
		return errors.New("no io.Writer set for container logs")
 | 
						|
	}
 | 
						|
 | 
						|
	var wg sync.WaitGroup
 | 
						|
 | 
						|
	ctrs, err := getContainersByContext(false, options.Latest, containers, ic.Libpod)
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	logOpts := &logs.LogOptions{
 | 
						|
		Multi:      len(ctrs) > 1,
 | 
						|
		Details:    options.Details,
 | 
						|
		Follow:     options.Follow,
 | 
						|
		Since:      options.Since,
 | 
						|
		Until:      options.Until,
 | 
						|
		Tail:       options.Tail,
 | 
						|
		Timestamps: options.Timestamps,
 | 
						|
		Colors:     options.Colors,
 | 
						|
		UseName:    options.Names,
 | 
						|
		WaitGroup:  &wg,
 | 
						|
	}
 | 
						|
 | 
						|
	chSize := len(ctrs) * int(options.Tail)
 | 
						|
	if chSize <= 0 {
 | 
						|
		chSize = 1
 | 
						|
	}
 | 
						|
	logChannel := make(chan *logs.LogLine, chSize)
 | 
						|
 | 
						|
	if err := ic.Libpod.Log(ctx, ctrs, logOpts, logChannel); err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	go func() {
 | 
						|
		wg.Wait()
 | 
						|
		close(logChannel)
 | 
						|
	}()
 | 
						|
 | 
						|
	for line := range logChannel {
 | 
						|
		line.Write(options.StdoutWriter, options.StderrWriter, logOpts)
 | 
						|
	}
 | 
						|
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
func (ic *ContainerEngine) ContainerCleanup(ctx context.Context, namesOrIds []string, options entities.ContainerCleanupOptions) ([]*entities.ContainerCleanupReport, error) {
 | 
						|
	reports := []*entities.ContainerCleanupReport{}
 | 
						|
	ctrs, err := getContainersByContext(options.All, options.Latest, namesOrIds, ic.Libpod)
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
	for _, ctr := range ctrs {
 | 
						|
		var err error
 | 
						|
		report := entities.ContainerCleanupReport{Id: ctr.ID()}
 | 
						|
 | 
						|
		if options.Exec != "" {
 | 
						|
			if options.Remove {
 | 
						|
				if err := ctr.ExecRemove(options.Exec, false); err != nil {
 | 
						|
					return nil, err
 | 
						|
				}
 | 
						|
			} else {
 | 
						|
				if err := ctr.ExecCleanup(options.Exec); err != nil {
 | 
						|
					return nil, err
 | 
						|
				}
 | 
						|
			}
 | 
						|
			return []*entities.ContainerCleanupReport{}, nil
 | 
						|
		}
 | 
						|
 | 
						|
		if options.Remove && !ctr.ShouldRestart(ctx) {
 | 
						|
			var timeout *uint
 | 
						|
			err = ic.Libpod.RemoveContainer(ctx, ctr, false, true, timeout)
 | 
						|
			if err != nil {
 | 
						|
				report.RmErr = fmt.Errorf("failed to clean up and remove container %v: %w", ctr.ID(), err)
 | 
						|
			}
 | 
						|
		} else {
 | 
						|
			err := ctr.Cleanup(ctx)
 | 
						|
			if err != nil {
 | 
						|
				report.CleanErr = fmt.Errorf("failed to clean up container %v: %w", ctr.ID(), err)
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		if options.RemoveImage {
 | 
						|
			_, imageName := ctr.Image()
 | 
						|
			imageEngine := ImageEngine{Libpod: ic.Libpod}
 | 
						|
			_, rmErrors := imageEngine.Remove(ctx, []string{imageName}, entities.ImageRemoveOptions{})
 | 
						|
			report.RmiErr = errorhandling.JoinErrors(rmErrors)
 | 
						|
		}
 | 
						|
 | 
						|
		reports = append(reports, &report)
 | 
						|
	}
 | 
						|
	return reports, nil
 | 
						|
}
 | 
						|
 | 
						|
func (ic *ContainerEngine) ContainerInit(ctx context.Context, namesOrIds []string, options entities.ContainerInitOptions) ([]*entities.ContainerInitReport, error) {
 | 
						|
	ctrs, err := getContainersByContext(options.All, options.Latest, namesOrIds, ic.Libpod)
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
	reports := make([]*entities.ContainerInitReport, 0, len(ctrs))
 | 
						|
	for _, ctr := range ctrs {
 | 
						|
		report := entities.ContainerInitReport{Id: ctr.ID()}
 | 
						|
		err := ctr.Init(ctx, ctr.PodID() != "")
 | 
						|
 | 
						|
		// If we're initializing all containers, ignore invalid state errors
 | 
						|
		if options.All && errors.Is(err, define.ErrCtrStateInvalid) {
 | 
						|
			err = nil
 | 
						|
		}
 | 
						|
		report.Err = err
 | 
						|
		reports = append(reports, &report)
 | 
						|
	}
 | 
						|
	return reports, nil
 | 
						|
}
 | 
						|
 | 
						|
func (ic *ContainerEngine) ContainerMount(ctx context.Context, nameOrIDs []string, options entities.ContainerMountOptions) ([]*entities.ContainerMountReport, error) {
 | 
						|
	if os.Geteuid() != 0 {
 | 
						|
		if driver := ic.Libpod.StorageConfig().GraphDriverName; driver != "vfs" {
 | 
						|
			// Do not allow to mount a graphdriver that is not vfs if we are creating the userns as part
 | 
						|
			// of the mount command.
 | 
						|
			return nil, fmt.Errorf("cannot mount using driver %s in rootless mode", driver)
 | 
						|
		}
 | 
						|
 | 
						|
		became, ret, err := rootless.BecomeRootInUserNS("")
 | 
						|
		if err != nil {
 | 
						|
			return nil, err
 | 
						|
		}
 | 
						|
		if became {
 | 
						|
			os.Exit(ret)
 | 
						|
		}
 | 
						|
	}
 | 
						|
	reports := []*entities.ContainerMountReport{}
 | 
						|
	// Attempt to mount named containers directly from storage,
 | 
						|
	// this will fail and code will fall through to removing the container from libpod.`
 | 
						|
	names := []string{}
 | 
						|
	for _, ctr := range nameOrIDs {
 | 
						|
		report := entities.ContainerMountReport{Id: ctr}
 | 
						|
		if report.Path, report.Err = ic.Libpod.MountStorageContainer(ctr); report.Err != nil {
 | 
						|
			names = append(names, ctr)
 | 
						|
		} else {
 | 
						|
			reports = append(reports, &report)
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	ctrs, err := getContainersByContext(options.All, options.Latest, names, ic.Libpod)
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
	for _, ctr := range ctrs {
 | 
						|
		report := entities.ContainerMountReport{Id: ctr.ID()}
 | 
						|
		report.Path, report.Err = ctr.Mount()
 | 
						|
		reports = append(reports, &report)
 | 
						|
	}
 | 
						|
	if len(reports) > 0 {
 | 
						|
		return reports, nil
 | 
						|
	}
 | 
						|
 | 
						|
	storageCtrs, err := ic.Libpod.StorageContainers()
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
 | 
						|
	for _, sctr := range storageCtrs {
 | 
						|
		mounted, path, err := ic.Libpod.IsStorageContainerMounted(sctr.ID)
 | 
						|
		if err != nil {
 | 
						|
			return nil, err
 | 
						|
		}
 | 
						|
 | 
						|
		var name string
 | 
						|
		if len(sctr.Names) > 0 {
 | 
						|
			name = sctr.Names[0]
 | 
						|
		}
 | 
						|
		if mounted {
 | 
						|
			reports = append(reports, &entities.ContainerMountReport{
 | 
						|
				Id:   sctr.ID,
 | 
						|
				Name: name,
 | 
						|
				Path: path,
 | 
						|
			})
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	// No containers were passed, so we send back what is mounted
 | 
						|
	ctrs, err = getContainersByContext(true, false, []string{}, ic.Libpod)
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
	for _, ctr := range ctrs {
 | 
						|
		mounted, path, err := ctr.Mounted()
 | 
						|
		if err != nil {
 | 
						|
			return nil, err
 | 
						|
		}
 | 
						|
 | 
						|
		if mounted {
 | 
						|
			reports = append(reports, &entities.ContainerMountReport{
 | 
						|
				Id:   ctr.ID(),
 | 
						|
				Name: ctr.Name(),
 | 
						|
				Path: path,
 | 
						|
			})
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	return reports, nil
 | 
						|
}
 | 
						|
 | 
						|
func (ic *ContainerEngine) ContainerUnmount(ctx context.Context, nameOrIDs []string, options entities.ContainerUnmountOptions) ([]*entities.ContainerUnmountReport, error) {
 | 
						|
	reports := []*entities.ContainerUnmountReport{}
 | 
						|
	names := []string{}
 | 
						|
	if options.All {
 | 
						|
		storageCtrs, err := ic.Libpod.StorageContainers()
 | 
						|
		if err != nil {
 | 
						|
			return nil, err
 | 
						|
		}
 | 
						|
		for _, sctr := range storageCtrs {
 | 
						|
			mounted, _, _ := ic.Libpod.IsStorageContainerMounted(sctr.ID)
 | 
						|
			if mounted {
 | 
						|
				report := entities.ContainerUnmountReport{Id: sctr.ID}
 | 
						|
				if _, report.Err = ic.Libpod.UnmountStorageContainer(sctr.ID, options.Force); report.Err != nil {
 | 
						|
					if !errors.Is(report.Err, define.ErrCtrExists) {
 | 
						|
						reports = append(reports, &report)
 | 
						|
					}
 | 
						|
				} else {
 | 
						|
					reports = append(reports, &report)
 | 
						|
				}
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
	for _, ctr := range nameOrIDs {
 | 
						|
		report := entities.ContainerUnmountReport{Id: ctr}
 | 
						|
		if _, report.Err = ic.Libpod.UnmountStorageContainer(ctr, options.Force); report.Err != nil {
 | 
						|
			names = append(names, ctr)
 | 
						|
		} else {
 | 
						|
			reports = append(reports, &report)
 | 
						|
		}
 | 
						|
	}
 | 
						|
	ctrs, err := getContainersByContext(options.All, options.Latest, names, ic.Libpod)
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
	for _, ctr := range ctrs {
 | 
						|
		state, err := ctr.State()
 | 
						|
		if err != nil {
 | 
						|
			logrus.Debugf("Error umounting container %s state: %s", ctr.ID(), err.Error())
 | 
						|
			continue
 | 
						|
		}
 | 
						|
		if state == define.ContainerStateRunning {
 | 
						|
			logrus.Debugf("Error umounting container %s, is running", ctr.ID())
 | 
						|
			continue
 | 
						|
		}
 | 
						|
 | 
						|
		report := entities.ContainerUnmountReport{Id: ctr.ID()}
 | 
						|
		if err := ctr.Unmount(options.Force); err != nil {
 | 
						|
			if options.All && errors.Is(err, storage.ErrLayerNotMounted) {
 | 
						|
				logrus.Debugf("Error umounting container %s, storage.ErrLayerNotMounted", ctr.ID())
 | 
						|
				continue
 | 
						|
			}
 | 
						|
			report.Err = fmt.Errorf("error unmounting container %s: %w", ctr.ID(), err)
 | 
						|
		}
 | 
						|
		reports = append(reports, &report)
 | 
						|
	}
 | 
						|
	return reports, nil
 | 
						|
}
 | 
						|
 | 
						|
// GetConfig returns a copy of the configuration used by the runtime
 | 
						|
func (ic *ContainerEngine) Config(_ context.Context) (*config.Config, error) {
 | 
						|
	return ic.Libpod.GetConfig()
 | 
						|
}
 | 
						|
 | 
						|
func (ic *ContainerEngine) ContainerPort(ctx context.Context, nameOrID string, options entities.ContainerPortOptions) ([]*entities.ContainerPortReport, error) {
 | 
						|
	ctrs, err := getContainersByContext(options.All, options.Latest, []string{nameOrID}, ic.Libpod)
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
	reports := []*entities.ContainerPortReport{}
 | 
						|
	for _, con := range ctrs {
 | 
						|
		state, err := con.State()
 | 
						|
		if err != nil {
 | 
						|
			return nil, err
 | 
						|
		}
 | 
						|
		if state != define.ContainerStateRunning {
 | 
						|
			continue
 | 
						|
		}
 | 
						|
		portmappings, err := con.PortMappings()
 | 
						|
		if err != nil {
 | 
						|
			return nil, err
 | 
						|
		}
 | 
						|
		if len(portmappings) > 0 {
 | 
						|
			reports = append(reports, &entities.ContainerPortReport{
 | 
						|
				Id:    con.ID(),
 | 
						|
				Ports: portmappings,
 | 
						|
			})
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return reports, nil
 | 
						|
}
 | 
						|
 | 
						|
// Shutdown Libpod engine
 | 
						|
func (ic *ContainerEngine) Shutdown(_ context.Context) {
 | 
						|
	shutdownSync.Do(func() {
 | 
						|
		_ = ic.Libpod.Shutdown(false)
 | 
						|
	})
 | 
						|
}
 | 
						|
 | 
						|
func (ic *ContainerEngine) ContainerStats(ctx context.Context, namesOrIds []string, options entities.ContainerStatsOptions) (statsChan chan entities.ContainerStatsReport, err error) {
 | 
						|
	if options.Interval < 1 {
 | 
						|
		return nil, errors.New("invalid interval, must be a positive number greater zero")
 | 
						|
	}
 | 
						|
	if rootless.IsRootless() {
 | 
						|
		unified, err := cgroups.IsCgroup2UnifiedMode()
 | 
						|
		if err != nil {
 | 
						|
			return nil, err
 | 
						|
		}
 | 
						|
		if !unified {
 | 
						|
			return nil, errors.New("stats is not supported in rootless mode without cgroups v2")
 | 
						|
		}
 | 
						|
	}
 | 
						|
	statsChan = make(chan entities.ContainerStatsReport, 1)
 | 
						|
 | 
						|
	containerFunc := ic.Libpod.GetRunningContainers
 | 
						|
	queryAll := false
 | 
						|
	switch {
 | 
						|
	case options.Latest:
 | 
						|
		containerFunc = func() ([]*libpod.Container, error) {
 | 
						|
			lastCtr, err := ic.Libpod.GetLatestContainer()
 | 
						|
			if err != nil {
 | 
						|
				return nil, err
 | 
						|
			}
 | 
						|
			return []*libpod.Container{lastCtr}, nil
 | 
						|
		}
 | 
						|
	case len(namesOrIds) > 0:
 | 
						|
		containerFunc = func() ([]*libpod.Container, error) { return ic.Libpod.GetContainersByList(namesOrIds) }
 | 
						|
	default:
 | 
						|
		// No containers, no latest -> query all!
 | 
						|
		queryAll = true
 | 
						|
		containerFunc = ic.Libpod.GetAllContainers
 | 
						|
	}
 | 
						|
 | 
						|
	go func() {
 | 
						|
		defer close(statsChan)
 | 
						|
		var (
 | 
						|
			err            error
 | 
						|
			containers     []*libpod.Container
 | 
						|
			containerStats map[string]*define.ContainerStats
 | 
						|
		)
 | 
						|
		containerStats = make(map[string]*define.ContainerStats)
 | 
						|
 | 
						|
	stream: // label to flatten the scope
 | 
						|
		select {
 | 
						|
		case <-ctx.Done():
 | 
						|
			// client cancelled
 | 
						|
			logrus.Debugf("Container stats stopped: context cancelled")
 | 
						|
			return
 | 
						|
		default:
 | 
						|
			// just fall through and do work
 | 
						|
		}
 | 
						|
 | 
						|
		// Anonymous func to easily use the return values for streaming.
 | 
						|
		computeStats := func() ([]define.ContainerStats, error) {
 | 
						|
			containers, err = containerFunc()
 | 
						|
			if err != nil {
 | 
						|
				return nil, fmt.Errorf("unable to get list of containers: %w", err)
 | 
						|
			}
 | 
						|
 | 
						|
			reportStats := []define.ContainerStats{}
 | 
						|
			for _, ctr := range containers {
 | 
						|
				stats, err := ctr.GetContainerStats(containerStats[ctr.ID()])
 | 
						|
				if err != nil {
 | 
						|
					if queryAll && (errors.Is(err, define.ErrCtrRemoved) || errors.Is(err, define.ErrNoSuchCtr) || errors.Is(err, define.ErrCtrStateInvalid)) {
 | 
						|
						continue
 | 
						|
					}
 | 
						|
					if errors.Is(err, cgroups.ErrCgroupV1Rootless) {
 | 
						|
						err = cgroups.ErrCgroupV1Rootless
 | 
						|
					}
 | 
						|
					return nil, err
 | 
						|
				}
 | 
						|
 | 
						|
				containerStats[ctr.ID()] = stats
 | 
						|
				reportStats = append(reportStats, *stats)
 | 
						|
			}
 | 
						|
			return reportStats, nil
 | 
						|
		}
 | 
						|
 | 
						|
		report := entities.ContainerStatsReport{}
 | 
						|
		report.Stats, report.Error = computeStats()
 | 
						|
		statsChan <- report
 | 
						|
 | 
						|
		if report.Error != nil || !options.Stream {
 | 
						|
			return
 | 
						|
		}
 | 
						|
 | 
						|
		time.Sleep(time.Second * time.Duration(options.Interval))
 | 
						|
		goto stream
 | 
						|
	}()
 | 
						|
 | 
						|
	return statsChan, nil
 | 
						|
}
 | 
						|
 | 
						|
// ShouldRestart returns whether the container should be restarted
 | 
						|
func (ic *ContainerEngine) ShouldRestart(ctx context.Context, nameOrID string) (*entities.BoolReport, error) {
 | 
						|
	ctr, err := ic.Libpod.LookupContainer(nameOrID)
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
 | 
						|
	return &entities.BoolReport{Value: ctr.ShouldRestart(ctx)}, nil
 | 
						|
}
 | 
						|
 | 
						|
// ContainerRename renames the given container.
 | 
						|
func (ic *ContainerEngine) ContainerRename(ctx context.Context, nameOrID string, opts entities.ContainerRenameOptions) error {
 | 
						|
	ctr, err := ic.Libpod.LookupContainer(nameOrID)
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	if _, err := ic.Libpod.RenameContainer(ctx, ctr, opts.NewName); err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
func (ic *ContainerEngine) ContainerClone(ctx context.Context, ctrCloneOpts entities.ContainerCloneOptions) (*entities.ContainerCreateReport, error) {
 | 
						|
	spec := specgen.NewSpecGenerator(ctrCloneOpts.Image, ctrCloneOpts.CreateOpts.RootFS)
 | 
						|
	var c *libpod.Container
 | 
						|
	c, _, err := generate.ConfigToSpec(ic.Libpod, spec, ctrCloneOpts.ID)
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
 | 
						|
	if ctrCloneOpts.CreateOpts.Pod != "" {
 | 
						|
		pod, err := ic.Libpod.LookupPod(ctrCloneOpts.CreateOpts.Pod)
 | 
						|
		if err != nil {
 | 
						|
			return nil, err
 | 
						|
		}
 | 
						|
 | 
						|
		if len(spec.Networks) > 0 && pod.SharesNet() {
 | 
						|
			logrus.Warning("resetting network config, cannot specify a network other than the pod's when sharing the net namespace")
 | 
						|
			spec.Networks = nil
 | 
						|
			spec.NetworkOptions = nil
 | 
						|
		}
 | 
						|
 | 
						|
		allNamespaces := []struct {
 | 
						|
			isShared bool
 | 
						|
			value    *specgen.Namespace
 | 
						|
		}{
 | 
						|
			{pod.SharesPID(), &spec.PidNS},
 | 
						|
			{pod.SharesNet(), &spec.NetNS},
 | 
						|
			{pod.SharesCgroup(), &spec.CgroupNS},
 | 
						|
			{pod.SharesIPC(), &spec.IpcNS},
 | 
						|
			{pod.SharesUTS(), &spec.UtsNS},
 | 
						|
		}
 | 
						|
 | 
						|
		printWarning := false
 | 
						|
		for _, n := range allNamespaces {
 | 
						|
			if n.isShared && !n.value.IsDefault() {
 | 
						|
				*n.value = specgen.Namespace{NSMode: specgen.Default}
 | 
						|
				printWarning = true
 | 
						|
			}
 | 
						|
		}
 | 
						|
		if printWarning {
 | 
						|
			logrus.Warning("At least one namespace was reset to the default configuration")
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	err = specgenutil.FillOutSpecGen(spec, &ctrCloneOpts.CreateOpts, []string{})
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
	out, err := generate.CompleteSpec(ctx, ic.Libpod, spec)
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
 | 
						|
	conf := c.Config()
 | 
						|
	if conf.Spec != nil && conf.Spec.Process != nil && conf.Spec.Process.Terminal { // if we do not pass term, running ctrs exit
 | 
						|
		spec.Terminal = true
 | 
						|
	}
 | 
						|
 | 
						|
	// Print warnings
 | 
						|
	if len(out) > 0 {
 | 
						|
		for _, w := range out {
 | 
						|
			fmt.Println("Could not properly complete the spec as expected:")
 | 
						|
			fmt.Fprintf(os.Stderr, "%s\n", w)
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	if len(ctrCloneOpts.CreateOpts.Name) > 0 {
 | 
						|
		spec.Name = ctrCloneOpts.CreateOpts.Name
 | 
						|
	} else {
 | 
						|
		n := c.Name()
 | 
						|
		_, err := ic.Libpod.LookupContainer(c.Name() + "-clone")
 | 
						|
		if err == nil {
 | 
						|
			n += "-clone"
 | 
						|
		}
 | 
						|
		switch {
 | 
						|
		case strings.Contains(n, "-clone"):
 | 
						|
			ind := strings.Index(n, "-clone") + 6
 | 
						|
			num, err := strconv.Atoi(n[ind:])
 | 
						|
			if num == 0 && err != nil { // clone1 is hard to get with this logic, just check for it here.
 | 
						|
				_, err = ic.Libpod.LookupContainer(n + "1")
 | 
						|
				if err != nil {
 | 
						|
					spec.Name = n + "1"
 | 
						|
					break
 | 
						|
				}
 | 
						|
			} else {
 | 
						|
				n = n[0:ind]
 | 
						|
			}
 | 
						|
			err = nil
 | 
						|
			count := num
 | 
						|
			for err == nil {
 | 
						|
				count++
 | 
						|
				tempN := n + strconv.Itoa(count)
 | 
						|
				_, err = ic.Libpod.LookupContainer(tempN)
 | 
						|
			}
 | 
						|
			n += strconv.Itoa(count)
 | 
						|
			spec.Name = n
 | 
						|
		default:
 | 
						|
			spec.Name = c.Name() + "-clone"
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	rtSpec, spec, opts, err := generate.MakeContainer(context.Background(), ic.Libpod, spec, true, c)
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
	ctr, err := generate.ExecuteCreate(ctx, ic.Libpod, rtSpec, spec, false, opts...)
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
 | 
						|
	if ctrCloneOpts.Destroy {
 | 
						|
		var time *uint
 | 
						|
		err = ic.Libpod.RemoveContainer(context.Background(), c, ctrCloneOpts.Force, false, time)
 | 
						|
		if err != nil {
 | 
						|
			return nil, err
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	if ctrCloneOpts.Run {
 | 
						|
		if err := ctr.Start(ctx, true); err != nil {
 | 
						|
			return nil, err
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	return &entities.ContainerCreateReport{Id: ctr.ID()}, nil
 | 
						|
}
 |