github.com/containers/podman/v2@v2.2.2-0.20210501105131-c1e07d070c4c/pkg/domain/infra/abi/containers.go (about)

     1  package abi
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"io/ioutil"
     7  	"os"
     8  	"strconv"
     9  	"strings"
    10  	"sync"
    11  	"time"
    12  
    13  	"github.com/containers/buildah"
    14  	"github.com/containers/common/pkg/config"
    15  	"github.com/containers/image/v5/manifest"
    16  	"github.com/containers/podman/v2/libpod"
    17  	"github.com/containers/podman/v2/libpod/define"
    18  	"github.com/containers/podman/v2/libpod/events"
    19  	lpfilters "github.com/containers/podman/v2/libpod/filters"
    20  	"github.com/containers/podman/v2/libpod/image"
    21  	"github.com/containers/podman/v2/libpod/logs"
    22  	"github.com/containers/podman/v2/pkg/cgroups"
    23  	"github.com/containers/podman/v2/pkg/checkpoint"
    24  	"github.com/containers/podman/v2/pkg/domain/entities"
    25  	"github.com/containers/podman/v2/pkg/domain/infra/abi/terminal"
    26  	parallelctr "github.com/containers/podman/v2/pkg/parallel/ctr"
    27  	"github.com/containers/podman/v2/pkg/ps"
    28  	"github.com/containers/podman/v2/pkg/rootless"
    29  	"github.com/containers/podman/v2/pkg/signal"
    30  	"github.com/containers/podman/v2/pkg/specgen"
    31  	"github.com/containers/podman/v2/pkg/specgen/generate"
    32  	"github.com/containers/podman/v2/pkg/util"
    33  	"github.com/containers/storage"
    34  	"github.com/pkg/errors"
    35  	"github.com/sirupsen/logrus"
    36  )
    37  
    38  // getContainersAndInputByContext gets containers whether all, latest, or a slice of names/ids
    39  // is specified.  It also returns a list of the corresponding input name used to lookup each container.
    40  func getContainersAndInputByContext(all, latest bool, names []string, runtime *libpod.Runtime) (ctrs []*libpod.Container, rawInput []string, err error) {
    41  	var ctr *libpod.Container
    42  	ctrs = []*libpod.Container{}
    43  
    44  	switch {
    45  	case all:
    46  		ctrs, err = runtime.GetAllContainers()
    47  	case latest:
    48  		ctr, err = runtime.GetLatestContainer()
    49  		if err == nil {
    50  			rawInput = append(rawInput, ctr.ID())
    51  			ctrs = append(ctrs, ctr)
    52  		}
    53  	default:
    54  		for _, n := range names {
    55  			ctr, e := runtime.LookupContainer(n)
    56  			if e != nil {
    57  				// Log all errors here, so callers don't need to.
    58  				logrus.Debugf("Error looking up container %q: %v", n, e)
    59  				if err == nil {
    60  					err = e
    61  				}
    62  			} else {
    63  				rawInput = append(rawInput, n)
    64  				ctrs = append(ctrs, ctr)
    65  			}
    66  		}
    67  	}
    68  	return
    69  }
    70  
    71  // getContainersByContext gets containers whether all, latest, or a slice of names/ids
    72  // is specified.
    73  func getContainersByContext(all, latest bool, names []string, runtime *libpod.Runtime) (ctrs []*libpod.Container, err error) {
    74  	ctrs, _, err = getContainersAndInputByContext(all, latest, names, runtime)
    75  	return
    76  }
    77  
    78  // ContainerExists returns whether the container exists in container storage
    79  func (ic *ContainerEngine) ContainerExists(ctx context.Context, nameOrID string, options entities.ContainerExistsOptions) (*entities.BoolReport, error) {
    80  	_, err := ic.Libpod.LookupContainer(nameOrID)
    81  	if err != nil {
    82  		if errors.Cause(err) != define.ErrNoSuchCtr {
    83  			return nil, err
    84  		}
    85  		if options.External {
    86  			// Check if container exists in storage
    87  			if _, storageErr := ic.Libpod.StorageContainer(nameOrID); storageErr == nil {
    88  				err = nil
    89  			}
    90  		}
    91  	}
    92  	return &entities.BoolReport{Value: err == nil}, nil
    93  }
    94  
    95  func (ic *ContainerEngine) ContainerWait(ctx context.Context, namesOrIds []string, options entities.WaitOptions) ([]entities.WaitReport, error) {
    96  	ctrs, err := getContainersByContext(false, options.Latest, namesOrIds, ic.Libpod)
    97  	if err != nil {
    98  		return nil, err
    99  	}
   100  	responses := make([]entities.WaitReport, 0, len(ctrs))
   101  	for _, c := range ctrs {
   102  		response := entities.WaitReport{Id: c.ID()}
   103  		exitCode, err := c.WaitForConditionWithInterval(options.Interval, options.Condition)
   104  		if err != nil {
   105  			response.Error = err
   106  		} else {
   107  			response.ExitCode = exitCode
   108  		}
   109  		responses = append(responses, response)
   110  	}
   111  	return responses, nil
   112  }
   113  
   114  func (ic *ContainerEngine) ContainerPause(ctx context.Context, namesOrIds []string, options entities.PauseUnPauseOptions) ([]*entities.PauseUnpauseReport, error) {
   115  	var (
   116  		err error
   117  	)
   118  	ctrs := []*libpod.Container{} //nolint
   119  	if options.All {
   120  		ctrs, err = ic.Libpod.GetAllContainers()
   121  	} else {
   122  		ctrs, err = getContainersByContext(false, false, namesOrIds, ic.Libpod)
   123  	}
   124  	if err != nil {
   125  		return nil, err
   126  	}
   127  	report := make([]*entities.PauseUnpauseReport, 0, len(ctrs))
   128  	for _, c := range ctrs {
   129  		err := c.Pause()
   130  		report = append(report, &entities.PauseUnpauseReport{Id: c.ID(), Err: err})
   131  	}
   132  	return report, nil
   133  }
   134  
   135  func (ic *ContainerEngine) ContainerUnpause(ctx context.Context, namesOrIds []string, options entities.PauseUnPauseOptions) ([]*entities.PauseUnpauseReport, error) {
   136  	var (
   137  		err error
   138  	)
   139  	ctrs := []*libpod.Container{} //nolint
   140  	if options.All {
   141  		ctrs, err = ic.Libpod.GetAllContainers()
   142  	} else {
   143  		ctrs, err = getContainersByContext(false, false, namesOrIds, ic.Libpod)
   144  	}
   145  	if err != nil {
   146  		return nil, err
   147  	}
   148  	report := make([]*entities.PauseUnpauseReport, 0, len(ctrs))
   149  	for _, c := range ctrs {
   150  		err := c.Unpause()
   151  		report = append(report, &entities.PauseUnpauseReport{Id: c.ID(), Err: err})
   152  	}
   153  	return report, nil
   154  }
   155  func (ic *ContainerEngine) ContainerStop(ctx context.Context, namesOrIds []string, options entities.StopOptions) ([]*entities.StopReport, error) {
   156  	names := namesOrIds
   157  	for _, cidFile := range options.CIDFiles {
   158  		content, err := ioutil.ReadFile(cidFile)
   159  		if err != nil {
   160  			return nil, errors.Wrap(err, "error reading CIDFile")
   161  		}
   162  		id := strings.Split(string(content), "\n")[0]
   163  		names = append(names, id)
   164  	}
   165  	ctrs, err := getContainersByContext(options.All, options.Latest, names, ic.Libpod)
   166  	if err != nil && !(options.Ignore && errors.Cause(err) == define.ErrNoSuchCtr) {
   167  		return nil, err
   168  	}
   169  	errMap, err := parallelctr.ContainerOp(ctx, ctrs, func(c *libpod.Container) error {
   170  		var err error
   171  		if options.Timeout != nil {
   172  			err = c.StopWithTimeout(*options.Timeout)
   173  		} else {
   174  			err = c.Stop()
   175  		}
   176  		if err != nil {
   177  			switch {
   178  			case errors.Cause(err) == define.ErrCtrStopped:
   179  				logrus.Debugf("Container %s is already stopped", c.ID())
   180  			case options.All && errors.Cause(err) == define.ErrCtrStateInvalid:
   181  				logrus.Debugf("Container %s is not running, could not stop", c.ID())
   182  			default:
   183  				return err
   184  			}
   185  		}
   186  		if c.AutoRemove() {
   187  			// Issue #7384: if the container is configured for
   188  			// auto-removal, it might already have been removed at
   189  			// this point.
   190  			return nil
   191  		}
   192  		return c.Cleanup(ctx)
   193  	})
   194  	if err != nil {
   195  		return nil, err
   196  	}
   197  	reports := make([]*entities.StopReport, 0, len(errMap))
   198  	for ctr, err := range errMap {
   199  		report := new(entities.StopReport)
   200  		report.Id = ctr.ID()
   201  		report.Err = err
   202  		reports = append(reports, report)
   203  	}
   204  	return reports, nil
   205  }
   206  
   207  func (ic *ContainerEngine) ContainerPrune(ctx context.Context, options entities.ContainerPruneOptions) (*entities.ContainerPruneReport, error) {
   208  	filterFuncs := make([]libpod.ContainerFilter, 0, len(options.Filters))
   209  	for k, v := range options.Filters {
   210  		generatedFunc, err := lpfilters.GenerateContainerFilterFuncs(k, v, ic.Libpod)
   211  		if err != nil {
   212  			return nil, err
   213  		}
   214  		filterFuncs = append(filterFuncs, generatedFunc)
   215  	}
   216  	return ic.pruneContainersHelper(filterFuncs)
   217  }
   218  
   219  func (ic *ContainerEngine) pruneContainersHelper(filterFuncs []libpod.ContainerFilter) (*entities.ContainerPruneReport, error) {
   220  	prunedContainers, pruneErrors, err := ic.Libpod.PruneContainers(filterFuncs)
   221  	if err != nil {
   222  		return nil, err
   223  	}
   224  	report := entities.ContainerPruneReport{
   225  		ID:  prunedContainers,
   226  		Err: pruneErrors,
   227  	}
   228  	return &report, nil
   229  }
   230  
   231  func (ic *ContainerEngine) ContainerKill(ctx context.Context, namesOrIds []string, options entities.KillOptions) ([]*entities.KillReport, error) {
   232  	sig, err := signal.ParseSignalNameOrNumber(options.Signal)
   233  	if err != nil {
   234  		return nil, err
   235  	}
   236  	ctrs, err := getContainersByContext(options.All, options.Latest, namesOrIds, ic.Libpod)
   237  	if err != nil {
   238  		return nil, err
   239  	}
   240  	reports := make([]*entities.KillReport, 0, len(ctrs))
   241  	for _, con := range ctrs {
   242  		reports = append(reports, &entities.KillReport{
   243  			Id:  con.ID(),
   244  			Err: con.Kill(uint(sig)),
   245  		})
   246  	}
   247  	return reports, nil
   248  }
   249  func (ic *ContainerEngine) ContainerRestart(ctx context.Context, namesOrIds []string, options entities.RestartOptions) ([]*entities.RestartReport, error) {
   250  	var (
   251  		ctrs []*libpod.Container
   252  		err  error
   253  	)
   254  
   255  	if options.Running {
   256  		ctrs, err = ic.Libpod.GetRunningContainers()
   257  		if err != nil {
   258  			return nil, err
   259  		}
   260  	} else {
   261  		ctrs, err = getContainersByContext(options.All, options.Latest, namesOrIds, ic.Libpod)
   262  		if err != nil {
   263  			return nil, err
   264  		}
   265  	}
   266  
   267  	reports := make([]*entities.RestartReport, 0, len(ctrs))
   268  	for _, con := range ctrs {
   269  		timeout := con.StopTimeout()
   270  		if options.Timeout != nil {
   271  			timeout = *options.Timeout
   272  		}
   273  		reports = append(reports, &entities.RestartReport{
   274  			Id:  con.ID(),
   275  			Err: con.RestartWithTimeout(ctx, timeout),
   276  		})
   277  	}
   278  	return reports, nil
   279  }
   280  
   281  func (ic *ContainerEngine) ContainerRm(ctx context.Context, namesOrIds []string, options entities.RmOptions) ([]*entities.RmReport, error) {
   282  	reports := []*entities.RmReport{}
   283  
   284  	names := namesOrIds
   285  	for _, cidFile := range options.CIDFiles {
   286  		content, err := ioutil.ReadFile(cidFile)
   287  		if err != nil {
   288  			return nil, errors.Wrap(err, "error reading CIDFile")
   289  		}
   290  		id := strings.Split(string(content), "\n")[0]
   291  		names = append(names, id)
   292  	}
   293  
   294  	// Attempt to remove named containers directly from storage, if container is defined in libpod
   295  	// this will fail and code will fall through to removing the container from libpod.`
   296  	tmpNames := []string{}
   297  	for _, ctr := range names {
   298  		report := entities.RmReport{Id: ctr}
   299  		if err := ic.Libpod.RemoveStorageContainer(ctr, options.Force); err != nil {
   300  			// remove container names that we successfully deleted
   301  			tmpNames = append(tmpNames, ctr)
   302  		} else {
   303  			reports = append(reports, &report)
   304  		}
   305  	}
   306  	if len(tmpNames) < len(names) {
   307  		names = tmpNames
   308  	}
   309  
   310  	ctrs, err := getContainersByContext(options.All, options.Latest, names, ic.Libpod)
   311  	if err != nil && !(options.Ignore && errors.Cause(err) == define.ErrNoSuchCtr) {
   312  		// Failed to get containers. If force is specified, get the containers ID
   313  		// and evict them
   314  		if !options.Force {
   315  			return nil, err
   316  		}
   317  
   318  		for _, ctr := range names {
   319  			logrus.Debugf("Evicting container %q", ctr)
   320  			report := entities.RmReport{Id: ctr}
   321  			id, err := ic.Libpod.EvictContainer(ctx, ctr, options.Volumes)
   322  			if err != nil {
   323  				if options.Ignore && errors.Cause(err) == define.ErrNoSuchCtr {
   324  					logrus.Debugf("Ignoring error (--allow-missing): %v", err)
   325  					reports = append(reports, &report)
   326  					continue
   327  				}
   328  				report.Err = errors.Wrapf(err, "failed to evict container: %q", id)
   329  				reports = append(reports, &report)
   330  				continue
   331  			}
   332  			reports = append(reports, &report)
   333  		}
   334  		return reports, nil
   335  	}
   336  
   337  	errMap, err := parallelctr.ContainerOp(ctx, ctrs, func(c *libpod.Container) error {
   338  		err := ic.Libpod.RemoveContainer(ctx, c, options.Force, options.Volumes)
   339  		if err != nil {
   340  			if options.Ignore && errors.Cause(err) == define.ErrNoSuchCtr {
   341  				logrus.Debugf("Ignoring error (--allow-missing): %v", err)
   342  				return nil
   343  			}
   344  			logrus.Debugf("Failed to remove container %s: %s", c.ID(), err.Error())
   345  		}
   346  		return err
   347  	})
   348  	if err != nil {
   349  		return nil, err
   350  	}
   351  	for ctr, err := range errMap {
   352  		report := new(entities.RmReport)
   353  		report.Id = ctr.ID()
   354  		report.Err = err
   355  		reports = append(reports, report)
   356  	}
   357  	return reports, nil
   358  }
   359  
   360  func (ic *ContainerEngine) ContainerInspect(ctx context.Context, namesOrIds []string, options entities.InspectOptions) ([]*entities.ContainerInspectReport, []error, error) {
   361  	if options.Latest {
   362  		ctr, err := ic.Libpod.GetLatestContainer()
   363  		if err != nil {
   364  			if errors.Cause(err) == define.ErrNoSuchCtr {
   365  				return nil, []error{errors.Wrapf(err, "no containers to inspect")}, nil
   366  			}
   367  			return nil, nil, err
   368  		}
   369  
   370  		inspect, err := ctr.Inspect(options.Size)
   371  		if err != nil {
   372  			return nil, nil, err
   373  		}
   374  
   375  		return []*entities.ContainerInspectReport{
   376  			{
   377  				InspectContainerData: inspect,
   378  			},
   379  		}, nil, nil
   380  	}
   381  	var (
   382  		reports = make([]*entities.ContainerInspectReport, 0, len(namesOrIds))
   383  		errs    = []error{}
   384  	)
   385  	for _, name := range namesOrIds {
   386  		ctr, err := ic.Libpod.LookupContainer(name)
   387  		if err != nil {
   388  			// ErrNoSuchCtr is non-fatal, other errors will be
   389  			// treated as fatal.
   390  			if errors.Cause(err) == define.ErrNoSuchCtr {
   391  				errs = append(errs, errors.Errorf("no such container %s", name))
   392  				continue
   393  			}
   394  			return nil, nil, err
   395  		}
   396  
   397  		inspect, err := ctr.Inspect(options.Size)
   398  		if err != nil {
   399  			return nil, nil, err
   400  		}
   401  
   402  		reports = append(reports, &entities.ContainerInspectReport{InspectContainerData: inspect})
   403  	}
   404  	return reports, errs, nil
   405  }
   406  
   407  func (ic *ContainerEngine) ContainerTop(ctx context.Context, options entities.TopOptions) (*entities.StringSliceReport, error) {
   408  	var (
   409  		container *libpod.Container
   410  		err       error
   411  	)
   412  
   413  	// Look up the container.
   414  	if options.Latest {
   415  		container, err = ic.Libpod.GetLatestContainer()
   416  	} else {
   417  		container, err = ic.Libpod.LookupContainer(options.NameOrID)
   418  	}
   419  	if err != nil {
   420  		return nil, errors.Wrap(err, "unable to lookup requested container")
   421  	}
   422  
   423  	// Run Top.
   424  	report := &entities.StringSliceReport{}
   425  	report.Value, err = container.Top(options.Descriptors)
   426  	return report, err
   427  }
   428  
   429  func (ic *ContainerEngine) ContainerCommit(ctx context.Context, nameOrID string, options entities.CommitOptions) (*entities.CommitReport, error) {
   430  	var (
   431  		mimeType string
   432  	)
   433  	ctr, err := ic.Libpod.LookupContainer(nameOrID)
   434  	if err != nil {
   435  		return nil, err
   436  	}
   437  	rtc, err := ic.Libpod.GetConfig()
   438  	if err != nil {
   439  		return nil, err
   440  	}
   441  	switch options.Format {
   442  	case "oci":
   443  		mimeType = buildah.OCIv1ImageManifest
   444  		if len(options.Message) > 0 {
   445  			return nil, errors.Errorf("messages are only compatible with the docker image format (-f docker)")
   446  		}
   447  	case "docker":
   448  		mimeType = manifest.DockerV2Schema2MediaType
   449  	default:
   450  		return nil, errors.Errorf("unrecognized image format %q", options.Format)
   451  	}
   452  	sc := image.GetSystemContext(rtc.Engine.SignaturePolicyPath, "", false)
   453  	coptions := buildah.CommitOptions{
   454  		SignaturePolicyPath:   rtc.Engine.SignaturePolicyPath,
   455  		ReportWriter:          options.Writer,
   456  		SystemContext:         sc,
   457  		PreferredManifestType: mimeType,
   458  	}
   459  	opts := libpod.ContainerCommitOptions{
   460  		CommitOptions:  coptions,
   461  		Pause:          options.Pause,
   462  		IncludeVolumes: options.IncludeVolumes,
   463  		Message:        options.Message,
   464  		Changes:        options.Changes,
   465  		Author:         options.Author,
   466  	}
   467  	newImage, err := ctr.Commit(ctx, options.ImageName, opts)
   468  	if err != nil {
   469  		return nil, err
   470  	}
   471  	return &entities.CommitReport{Id: newImage.ID()}, nil
   472  }
   473  
   474  func (ic *ContainerEngine) ContainerExport(ctx context.Context, nameOrID string, options entities.ContainerExportOptions) error {
   475  	ctr, err := ic.Libpod.LookupContainer(nameOrID)
   476  	if err != nil {
   477  		return err
   478  	}
   479  	return ctr.Export(options.Output)
   480  }
   481  
   482  func (ic *ContainerEngine) ContainerCheckpoint(ctx context.Context, namesOrIds []string, options entities.CheckpointOptions) ([]*entities.CheckpointReport, error) {
   483  	var (
   484  		err  error
   485  		cons []*libpod.Container
   486  	)
   487  	checkOpts := libpod.ContainerCheckpointOptions{
   488  		Keep:           options.Keep,
   489  		TCPEstablished: options.TCPEstablished,
   490  		TargetFile:     options.Export,
   491  		IgnoreRootfs:   options.IgnoreRootFS,
   492  		KeepRunning:    options.LeaveRunning,
   493  	}
   494  
   495  	if options.All {
   496  		running := func(c *libpod.Container) bool {
   497  			state, _ := c.State()
   498  			return state == define.ContainerStateRunning
   499  		}
   500  		cons, err = ic.Libpod.GetContainers(running)
   501  	} else {
   502  		cons, err = getContainersByContext(false, options.Latest, namesOrIds, ic.Libpod)
   503  	}
   504  	if err != nil {
   505  		return nil, err
   506  	}
   507  	reports := make([]*entities.CheckpointReport, 0, len(cons))
   508  	for _, con := range cons {
   509  		err = con.Checkpoint(ctx, checkOpts)
   510  		reports = append(reports, &entities.CheckpointReport{
   511  			Err: err,
   512  			Id:  con.ID(),
   513  		})
   514  	}
   515  	return reports, nil
   516  }
   517  
   518  func (ic *ContainerEngine) ContainerRestore(ctx context.Context, namesOrIds []string, options entities.RestoreOptions) ([]*entities.RestoreReport, error) {
   519  	var (
   520  		cons []*libpod.Container
   521  		err  error
   522  	)
   523  
   524  	restoreOptions := libpod.ContainerCheckpointOptions{
   525  		Keep:            options.Keep,
   526  		TCPEstablished:  options.TCPEstablished,
   527  		TargetFile:      options.Import,
   528  		Name:            options.Name,
   529  		IgnoreRootfs:    options.IgnoreRootFS,
   530  		IgnoreStaticIP:  options.IgnoreStaticIP,
   531  		IgnoreStaticMAC: options.IgnoreStaticMAC,
   532  	}
   533  
   534  	filterFuncs := []libpod.ContainerFilter{
   535  		func(c *libpod.Container) bool {
   536  			state, _ := c.State()
   537  			return state == define.ContainerStateExited
   538  		},
   539  	}
   540  
   541  	switch {
   542  	case options.Import != "":
   543  		cons, err = checkpoint.CRImportCheckpoint(ctx, ic.Libpod, options.Import, options.Name)
   544  	case options.All:
   545  		cons, err = ic.Libpod.GetContainers(filterFuncs...)
   546  	default:
   547  		cons, err = getContainersByContext(false, options.Latest, namesOrIds, ic.Libpod)
   548  	}
   549  	if err != nil {
   550  		return nil, err
   551  	}
   552  	reports := make([]*entities.RestoreReport, 0, len(cons))
   553  	for _, con := range cons {
   554  		err := con.Restore(ctx, restoreOptions)
   555  		reports = append(reports, &entities.RestoreReport{
   556  			Err: err,
   557  			Id:  con.ID(),
   558  		})
   559  	}
   560  	return reports, nil
   561  }
   562  
   563  func (ic *ContainerEngine) ContainerCreate(ctx context.Context, s *specgen.SpecGenerator) (*entities.ContainerCreateReport, error) {
   564  	warn, err := generate.CompleteSpec(ctx, ic.Libpod, s)
   565  	if err != nil {
   566  		return nil, err
   567  	}
   568  	// Print warnings
   569  	for _, w := range warn {
   570  		fmt.Fprintf(os.Stderr, "%s\n", w)
   571  	}
   572  	ctr, err := generate.MakeContainer(ctx, ic.Libpod, s)
   573  	if err != nil {
   574  		return nil, err
   575  	}
   576  	return &entities.ContainerCreateReport{Id: ctr.ID()}, nil
   577  }
   578  
   579  func (ic *ContainerEngine) ContainerAttach(ctx context.Context, nameOrID string, options entities.AttachOptions) error {
   580  	ctrs, err := getContainersByContext(false, options.Latest, []string{nameOrID}, ic.Libpod)
   581  	if err != nil {
   582  		return err
   583  	}
   584  	ctr := ctrs[0]
   585  	conState, err := ctr.State()
   586  	if err != nil {
   587  		return errors.Wrapf(err, "unable to determine state of %s", ctr.ID())
   588  	}
   589  	if conState != define.ContainerStateRunning {
   590  		return errors.Errorf("you can only attach to running containers")
   591  	}
   592  
   593  	// If the container is in a pod, also set to recursively start dependencies
   594  	err = terminal.StartAttachCtr(ctx, ctr, options.Stdout, options.Stderr, options.Stdin, options.DetachKeys, options.SigProxy, false, ctr.PodID() != "")
   595  	if err != nil && errors.Cause(err) != define.ErrDetach {
   596  		return errors.Wrapf(err, "error attaching to container %s", ctr.ID())
   597  	}
   598  	os.Stdout.WriteString("\n")
   599  	return nil
   600  }
   601  
   602  func makeExecConfig(options entities.ExecOptions) *libpod.ExecConfig {
   603  	execConfig := new(libpod.ExecConfig)
   604  	execConfig.Command = options.Cmd
   605  	execConfig.Terminal = options.Tty
   606  	execConfig.Privileged = options.Privileged
   607  	execConfig.Environment = options.Envs
   608  	execConfig.User = options.User
   609  	execConfig.WorkDir = options.WorkDir
   610  	execConfig.DetachKeys = &options.DetachKeys
   611  	execConfig.PreserveFDs = options.PreserveFDs
   612  	execConfig.AttachStdin = options.Interactive
   613  
   614  	return execConfig
   615  }
   616  
   617  func checkExecPreserveFDs(options entities.ExecOptions) error {
   618  	if options.PreserveFDs > 0 {
   619  		entries, err := ioutil.ReadDir("/proc/self/fd")
   620  		if err != nil {
   621  			return err
   622  		}
   623  
   624  		m := make(map[int]bool)
   625  		for _, e := range entries {
   626  			i, err := strconv.Atoi(e.Name())
   627  			if err != nil {
   628  				return errors.Wrapf(err, "cannot parse %s in /proc/self/fd", e.Name())
   629  			}
   630  			m[i] = true
   631  		}
   632  
   633  		for i := 3; i < 3+int(options.PreserveFDs); i++ {
   634  			if _, found := m[i]; !found {
   635  				return errors.New("invalid --preserve-fds=N specified. Not enough FDs available")
   636  			}
   637  		}
   638  	}
   639  	return nil
   640  }
   641  
   642  func (ic *ContainerEngine) ContainerExec(ctx context.Context, nameOrID string, options entities.ExecOptions, streams define.AttachStreams) (int, error) {
   643  	ec := define.ExecErrorCodeGeneric
   644  	err := checkExecPreserveFDs(options)
   645  	if err != nil {
   646  		return ec, err
   647  	}
   648  	ctrs, err := getContainersByContext(false, options.Latest, []string{nameOrID}, ic.Libpod)
   649  	if err != nil {
   650  		return ec, err
   651  	}
   652  	ctr := ctrs[0]
   653  
   654  	execConfig := makeExecConfig(options)
   655  
   656  	ec, err = terminal.ExecAttachCtr(ctx, ctr, execConfig, &streams)
   657  	return define.TranslateExecErrorToExitCode(ec, err), err
   658  }
   659  
   660  func (ic *ContainerEngine) ContainerExecDetached(ctx context.Context, nameOrID string, options entities.ExecOptions) (string, error) {
   661  	err := checkExecPreserveFDs(options)
   662  	if err != nil {
   663  		return "", err
   664  	}
   665  	ctrs, err := getContainersByContext(false, options.Latest, []string{nameOrID}, ic.Libpod)
   666  	if err != nil {
   667  		return "", err
   668  	}
   669  	ctr := ctrs[0]
   670  
   671  	execConfig := makeExecConfig(options)
   672  
   673  	// Make an exit command
   674  	storageConfig := ic.Libpod.StorageConfig()
   675  	runtimeConfig, err := ic.Libpod.GetConfig()
   676  	if err != nil {
   677  		return "", errors.Wrapf(err, "error retrieving Libpod configuration to build exec exit command")
   678  	}
   679  	// TODO: Add some ability to toggle syslog
   680  	exitCommandArgs, err := generate.CreateExitCommandArgs(storageConfig, runtimeConfig, false, true, true)
   681  	if err != nil {
   682  		return "", errors.Wrapf(err, "error constructing exit command for exec session")
   683  	}
   684  	execConfig.ExitCommand = exitCommandArgs
   685  
   686  	// Create and start the exec session
   687  	id, err := ctr.ExecCreate(execConfig)
   688  	if err != nil {
   689  		return "", err
   690  	}
   691  
   692  	// TODO: we should try and retrieve exit code if this fails.
   693  	if err := ctr.ExecStart(id); err != nil {
   694  		return "", err
   695  	}
   696  	return id, nil
   697  }
   698  
   699  func (ic *ContainerEngine) ContainerStart(ctx context.Context, namesOrIds []string, options entities.ContainerStartOptions) ([]*entities.ContainerStartReport, error) {
   700  	reports := []*entities.ContainerStartReport{}
   701  	var exitCode = define.ExecErrorCodeGeneric
   702  	ctrs, rawInputs, err := getContainersAndInputByContext(false, options.Latest, namesOrIds, ic.Libpod)
   703  	if err != nil {
   704  		return nil, err
   705  	}
   706  	// There can only be one container if attach was used
   707  	for i := range ctrs {
   708  		ctr := ctrs[i]
   709  		rawInput := rawInputs[i]
   710  		ctrState, err := ctr.State()
   711  		if err != nil {
   712  			return nil, err
   713  		}
   714  		ctrRunning := ctrState == define.ContainerStateRunning
   715  
   716  		if options.Attach {
   717  			err = terminal.StartAttachCtr(ctx, ctr, options.Stdout, options.Stderr, options.Stdin, options.DetachKeys, options.SigProxy, !ctrRunning, ctr.PodID() != "")
   718  			if errors.Cause(err) == define.ErrDetach {
   719  				// User manually detached
   720  				// Exit cleanly immediately
   721  				reports = append(reports, &entities.ContainerStartReport{
   722  					Id:       ctr.ID(),
   723  					RawInput: rawInput,
   724  					Err:      nil,
   725  					ExitCode: 0,
   726  				})
   727  				return reports, nil
   728  			}
   729  
   730  			if errors.Cause(err) == define.ErrWillDeadlock {
   731  				logrus.Debugf("Deadlock error: %v", err)
   732  				reports = append(reports, &entities.ContainerStartReport{
   733  					Id:       ctr.ID(),
   734  					RawInput: rawInput,
   735  					Err:      err,
   736  					ExitCode: define.ExitCode(err),
   737  				})
   738  				return reports, errors.Errorf("attempting to start container %s would cause a deadlock; please run 'podman system renumber' to resolve", ctr.ID())
   739  			}
   740  
   741  			if ctrRunning {
   742  				reports = append(reports, &entities.ContainerStartReport{
   743  					Id:       ctr.ID(),
   744  					RawInput: rawInput,
   745  					Err:      nil,
   746  					ExitCode: 0,
   747  				})
   748  				return reports, err
   749  			}
   750  
   751  			if err != nil {
   752  				reports = append(reports, &entities.ContainerStartReport{
   753  					Id:       ctr.ID(),
   754  					RawInput: rawInput,
   755  					Err:      err,
   756  					ExitCode: exitCode,
   757  				})
   758  				return reports, errors.Wrapf(err, "unable to start container %s", ctr.ID())
   759  			}
   760  
   761  			if ecode, err := ctr.Wait(); err != nil {
   762  				if errors.Cause(err) == define.ErrNoSuchCtr {
   763  					// Check events
   764  					event, err := ic.Libpod.GetLastContainerEvent(ctx, ctr.ID(), events.Exited)
   765  					if err != nil {
   766  						logrus.Errorf("Cannot get exit code: %v", err)
   767  						exitCode = define.ExecErrorCodeNotFound
   768  					} else {
   769  						exitCode = event.ContainerExitCode
   770  					}
   771  				}
   772  			} else {
   773  				exitCode = int(ecode)
   774  			}
   775  			reports = append(reports, &entities.ContainerStartReport{
   776  				Id:       ctr.ID(),
   777  				RawInput: rawInput,
   778  				Err:      err,
   779  				ExitCode: exitCode,
   780  			})
   781  			return reports, nil
   782  		} // end attach
   783  
   784  		// Start the container if it's not running already.
   785  		if !ctrRunning {
   786  			// Handle non-attach start
   787  			// If the container is in a pod, also set to recursively start dependencies
   788  			report := &entities.ContainerStartReport{
   789  				Id:       ctr.ID(),
   790  				RawInput: rawInput,
   791  				ExitCode: 125,
   792  			}
   793  			if err := ctr.Start(ctx, ctr.PodID() != ""); err != nil {
   794  				// if lastError != nil {
   795  				//	fmt.Fprintln(os.Stderr, lastError)
   796  				// }
   797  				report.Err = err
   798  				if errors.Cause(err) == define.ErrWillDeadlock {
   799  					report.Err = errors.Wrapf(err, "please run 'podman system renumber' to resolve deadlocks")
   800  					reports = append(reports, report)
   801  					continue
   802  				}
   803  				report.Err = errors.Wrapf(err, "unable to start container %q", ctr.ID())
   804  				reports = append(reports, report)
   805  				continue
   806  			}
   807  			report.ExitCode = 0
   808  			reports = append(reports, report)
   809  		}
   810  	}
   811  	return reports, nil
   812  }
   813  
   814  func (ic *ContainerEngine) ContainerList(ctx context.Context, options entities.ContainerListOptions) ([]entities.ListContainer, error) {
   815  	if options.Latest {
   816  		options.Last = 1
   817  	}
   818  	return ps.GetContainerLists(ic.Libpod, options)
   819  }
   820  
   821  // ContainerDiff provides changes to given container
   822  func (ic *ContainerEngine) ContainerDiff(ctx context.Context, nameOrID string, opts entities.DiffOptions) (*entities.DiffReport, error) {
   823  	if opts.Latest {
   824  		ctnr, err := ic.Libpod.GetLatestContainer()
   825  		if err != nil {
   826  			return nil, errors.Wrap(err, "unable to get latest container")
   827  		}
   828  		nameOrID = ctnr.ID()
   829  	}
   830  	changes, err := ic.Libpod.GetDiff("", nameOrID)
   831  	return &entities.DiffReport{Changes: changes}, err
   832  }
   833  
   834  func (ic *ContainerEngine) ContainerRun(ctx context.Context, opts entities.ContainerRunOptions) (*entities.ContainerRunReport, error) {
   835  	warn, err := generate.CompleteSpec(ctx, ic.Libpod, opts.Spec)
   836  	if err != nil {
   837  		return nil, err
   838  	}
   839  	// Print warnings
   840  	for _, w := range warn {
   841  		fmt.Fprintf(os.Stderr, "%s\n", w)
   842  	}
   843  	ctr, err := generate.MakeContainer(ctx, ic.Libpod, opts.Spec)
   844  	if err != nil {
   845  		return nil, err
   846  	}
   847  
   848  	if opts.CIDFile != "" {
   849  		if err := util.CreateCidFile(opts.CIDFile, ctr.ID()); err != nil {
   850  			return nil, err
   851  		}
   852  	}
   853  
   854  	var joinPod bool
   855  	if len(ctr.PodID()) > 0 {
   856  		joinPod = true
   857  	}
   858  	report := entities.ContainerRunReport{Id: ctr.ID()}
   859  
   860  	if logrus.GetLevel() == logrus.DebugLevel {
   861  		cgroupPath, err := ctr.CGroupPath()
   862  		if err == nil {
   863  			logrus.Debugf("container %q has CgroupParent %q", ctr.ID(), cgroupPath)
   864  		}
   865  	}
   866  	if opts.Detach {
   867  		// if the container was created as part of a pod, also start its dependencies, if any.
   868  		if err := ctr.Start(ctx, joinPod); err != nil {
   869  			// This means the command did not exist
   870  			report.ExitCode = define.ExitCode(err)
   871  			return &report, err
   872  		}
   873  
   874  		return &report, nil
   875  	}
   876  
   877  	// if the container was created as part of a pod, also start its dependencies, if any.
   878  	if err := terminal.StartAttachCtr(ctx, ctr, opts.OutputStream, opts.ErrorStream, opts.InputStream, opts.DetachKeys, opts.SigProxy, true, joinPod); err != nil {
   879  		// We've manually detached from the container
   880  		// Do not perform cleanup, or wait for container exit code
   881  		// Just exit immediately
   882  		if errors.Cause(err) == define.ErrDetach {
   883  			report.ExitCode = 0
   884  			return &report, nil
   885  		}
   886  		if opts.Rm {
   887  			if deleteError := ic.Libpod.RemoveContainer(ctx, ctr, true, false); deleteError != nil {
   888  				logrus.Debugf("unable to remove container %s after failing to start and attach to it", ctr.ID())
   889  			}
   890  		}
   891  		if errors.Cause(err) == define.ErrWillDeadlock {
   892  			logrus.Debugf("Deadlock error on %q: %v", ctr.ID(), err)
   893  			report.ExitCode = define.ExitCode(err)
   894  			return &report, errors.Errorf("attempting to start container %s would cause a deadlock; please run 'podman system renumber' to resolve", ctr.ID())
   895  		}
   896  		report.ExitCode = define.ExitCode(err)
   897  		return &report, err
   898  	}
   899  
   900  	if ecode, err := ctr.Wait(); err != nil {
   901  		if errors.Cause(err) == define.ErrNoSuchCtr {
   902  			// Check events
   903  			event, err := ic.Libpod.GetLastContainerEvent(ctx, ctr.ID(), events.Exited)
   904  			if err != nil {
   905  				logrus.Errorf("Cannot get exit code: %v", err)
   906  				report.ExitCode = define.ExecErrorCodeNotFound
   907  			} else {
   908  				report.ExitCode = event.ContainerExitCode
   909  			}
   910  		}
   911  	} else {
   912  		report.ExitCode = int(ecode)
   913  	}
   914  	if opts.Rm && !ctr.ShouldRestart(ctx) {
   915  		if err := ic.Libpod.RemoveContainer(ctx, ctr, false, true); err != nil {
   916  			if errors.Cause(err) == define.ErrNoSuchCtr ||
   917  				errors.Cause(err) == define.ErrCtrRemoved {
   918  				logrus.Warnf("Container %s does not exist: %v", ctr.ID(), err)
   919  			} else {
   920  				logrus.Errorf("Error removing container %s: %v", ctr.ID(), err)
   921  			}
   922  		}
   923  	}
   924  	return &report, nil
   925  }
   926  
   927  func (ic *ContainerEngine) ContainerLogs(ctx context.Context, containers []string, options entities.ContainerLogsOptions) error {
   928  	if options.Writer == nil {
   929  		return errors.New("no io.Writer set for container logs")
   930  	}
   931  
   932  	var wg sync.WaitGroup
   933  
   934  	ctrs, err := getContainersByContext(false, options.Latest, containers, ic.Libpod)
   935  	if err != nil {
   936  		return err
   937  	}
   938  
   939  	logOpts := &logs.LogOptions{
   940  		Multi:      len(ctrs) > 1,
   941  		Details:    options.Details,
   942  		Follow:     options.Follow,
   943  		Since:      options.Since,
   944  		Tail:       options.Tail,
   945  		Timestamps: options.Timestamps,
   946  		UseName:    options.Names,
   947  		WaitGroup:  &wg,
   948  	}
   949  
   950  	chSize := len(ctrs) * int(options.Tail)
   951  	if chSize <= 0 {
   952  		chSize = 1
   953  	}
   954  	logChannel := make(chan *logs.LogLine, chSize)
   955  
   956  	if err := ic.Libpod.Log(ctx, ctrs, logOpts, logChannel); err != nil {
   957  		return err
   958  	}
   959  
   960  	go func() {
   961  		wg.Wait()
   962  		close(logChannel)
   963  	}()
   964  
   965  	for line := range logChannel {
   966  		fmt.Fprintln(options.Writer, line.String(logOpts))
   967  	}
   968  
   969  	return nil
   970  }
   971  
   972  func (ic *ContainerEngine) ContainerCleanup(ctx context.Context, namesOrIds []string, options entities.ContainerCleanupOptions) ([]*entities.ContainerCleanupReport, error) {
   973  	reports := []*entities.ContainerCleanupReport{}
   974  	ctrs, err := getContainersByContext(options.All, options.Latest, namesOrIds, ic.Libpod)
   975  	if err != nil {
   976  		return nil, err
   977  	}
   978  	for _, ctr := range ctrs {
   979  		var err error
   980  		report := entities.ContainerCleanupReport{Id: ctr.ID()}
   981  
   982  		if options.Exec != "" {
   983  			if options.Remove {
   984  				if err := ctr.ExecRemove(options.Exec, false); err != nil {
   985  					return nil, err
   986  				}
   987  			} else {
   988  				if err := ctr.ExecCleanup(options.Exec); err != nil {
   989  					return nil, err
   990  				}
   991  			}
   992  			return []*entities.ContainerCleanupReport{}, nil
   993  		}
   994  
   995  		if options.Remove && !ctr.ShouldRestart(ctx) {
   996  			err = ic.Libpod.RemoveContainer(ctx, ctr, false, true)
   997  			if err != nil {
   998  				report.RmErr = errors.Wrapf(err, "failed to cleanup and remove container %v", ctr.ID())
   999  			}
  1000  		} else {
  1001  			err := ctr.Cleanup(ctx)
  1002  			if err != nil {
  1003  				report.CleanErr = errors.Wrapf(err, "failed to cleanup container %v", ctr.ID())
  1004  			}
  1005  		}
  1006  
  1007  		if options.RemoveImage {
  1008  			_, imageName := ctr.Image()
  1009  			ctrImage, err := ic.Libpod.ImageRuntime().NewFromLocal(imageName)
  1010  			if err != nil {
  1011  				report.RmiErr = err
  1012  				reports = append(reports, &report)
  1013  				continue
  1014  			}
  1015  			_, err = ic.Libpod.RemoveImage(ctx, ctrImage, false)
  1016  			report.RmiErr = err
  1017  		}
  1018  
  1019  		reports = append(reports, &report)
  1020  	}
  1021  	return reports, nil
  1022  }
  1023  
  1024  func (ic *ContainerEngine) ContainerInit(ctx context.Context, namesOrIds []string, options entities.ContainerInitOptions) ([]*entities.ContainerInitReport, error) {
  1025  	ctrs, err := getContainersByContext(options.All, options.Latest, namesOrIds, ic.Libpod)
  1026  	if err != nil {
  1027  		return nil, err
  1028  	}
  1029  	reports := make([]*entities.ContainerInitReport, 0, len(ctrs))
  1030  	for _, ctr := range ctrs {
  1031  		report := entities.ContainerInitReport{Id: ctr.ID()}
  1032  		err := ctr.Init(ctx, ctr.PodID() != "")
  1033  
  1034  		// If we're initializing all containers, ignore invalid state errors
  1035  		if options.All && errors.Cause(err) == define.ErrCtrStateInvalid {
  1036  			err = nil
  1037  		}
  1038  		report.Err = err
  1039  		reports = append(reports, &report)
  1040  	}
  1041  	return reports, nil
  1042  }
  1043  
  1044  func (ic *ContainerEngine) ContainerMount(ctx context.Context, nameOrIDs []string, options entities.ContainerMountOptions) ([]*entities.ContainerMountReport, error) {
  1045  	if os.Geteuid() != 0 {
  1046  		if driver := ic.Libpod.StorageConfig().GraphDriverName; driver != "vfs" {
  1047  			// Do not allow to mount a graphdriver that is not vfs if we are creating the userns as part
  1048  			// of the mount command.
  1049  			return nil, fmt.Errorf("cannot mount using driver %s in rootless mode", driver)
  1050  		}
  1051  
  1052  		became, ret, err := rootless.BecomeRootInUserNS("")
  1053  		if err != nil {
  1054  			return nil, err
  1055  		}
  1056  		if became {
  1057  			os.Exit(ret)
  1058  		}
  1059  	}
  1060  	reports := []*entities.ContainerMountReport{}
  1061  	// Attempt to mount named containers directly from storage,
  1062  	// this will fail and code will fall through to removing the container from libpod.`
  1063  	names := []string{}
  1064  	for _, ctr := range nameOrIDs {
  1065  		report := entities.ContainerMountReport{Id: ctr}
  1066  		if report.Path, report.Err = ic.Libpod.MountStorageContainer(ctr); report.Err != nil {
  1067  			names = append(names, ctr)
  1068  		} else {
  1069  			reports = append(reports, &report)
  1070  		}
  1071  	}
  1072  
  1073  	ctrs, err := getContainersByContext(options.All, options.Latest, names, ic.Libpod)
  1074  	if err != nil {
  1075  		return nil, err
  1076  	}
  1077  	for _, ctr := range ctrs {
  1078  		report := entities.ContainerMountReport{Id: ctr.ID()}
  1079  		report.Path, report.Err = ctr.Mount()
  1080  		reports = append(reports, &report)
  1081  	}
  1082  	if len(reports) > 0 {
  1083  		return reports, nil
  1084  	}
  1085  
  1086  	storageCtrs, err := ic.Libpod.StorageContainers()
  1087  	if err != nil {
  1088  		return nil, err
  1089  	}
  1090  
  1091  	for _, sctr := range storageCtrs {
  1092  		mounted, path, err := ic.Libpod.IsStorageContainerMounted(sctr.ID)
  1093  		if err != nil {
  1094  			return nil, err
  1095  		}
  1096  
  1097  		var name string
  1098  		if len(sctr.Names) > 0 {
  1099  			name = sctr.Names[0]
  1100  		}
  1101  		if mounted {
  1102  			reports = append(reports, &entities.ContainerMountReport{
  1103  				Id:   sctr.ID,
  1104  				Name: name,
  1105  				Path: path,
  1106  			})
  1107  		}
  1108  	}
  1109  
  1110  	// No containers were passed, so we send back what is mounted
  1111  	ctrs, err = getContainersByContext(true, false, []string{}, ic.Libpod)
  1112  	if err != nil {
  1113  		return nil, err
  1114  	}
  1115  	for _, ctr := range ctrs {
  1116  		mounted, path, err := ctr.Mounted()
  1117  		if err != nil {
  1118  			return nil, err
  1119  		}
  1120  
  1121  		if mounted {
  1122  			reports = append(reports, &entities.ContainerMountReport{
  1123  				Id:   ctr.ID(),
  1124  				Name: ctr.Name(),
  1125  				Path: path,
  1126  			})
  1127  		}
  1128  	}
  1129  
  1130  	return reports, nil
  1131  }
  1132  
  1133  func (ic *ContainerEngine) ContainerUnmount(ctx context.Context, nameOrIDs []string, options entities.ContainerUnmountOptions) ([]*entities.ContainerUnmountReport, error) {
  1134  	reports := []*entities.ContainerUnmountReport{}
  1135  	names := []string{}
  1136  	if options.All {
  1137  		storageCtrs, err := ic.Libpod.StorageContainers()
  1138  		if err != nil {
  1139  			return nil, err
  1140  		}
  1141  		for _, sctr := range storageCtrs {
  1142  			mounted, _, _ := ic.Libpod.IsStorageContainerMounted(sctr.ID)
  1143  			if mounted {
  1144  				report := entities.ContainerUnmountReport{Id: sctr.ID}
  1145  				if _, report.Err = ic.Libpod.UnmountStorageContainer(sctr.ID, options.Force); report.Err != nil {
  1146  					if errors.Cause(report.Err) != define.ErrCtrExists {
  1147  						reports = append(reports, &report)
  1148  					}
  1149  				} else {
  1150  					reports = append(reports, &report)
  1151  				}
  1152  			}
  1153  		}
  1154  	}
  1155  	for _, ctr := range nameOrIDs {
  1156  		report := entities.ContainerUnmountReport{Id: ctr}
  1157  		if _, report.Err = ic.Libpod.UnmountStorageContainer(ctr, options.Force); report.Err != nil {
  1158  			names = append(names, ctr)
  1159  		} else {
  1160  			reports = append(reports, &report)
  1161  		}
  1162  	}
  1163  	ctrs, err := getContainersByContext(options.All, options.Latest, names, ic.Libpod)
  1164  	if err != nil {
  1165  		return nil, err
  1166  	}
  1167  	for _, ctr := range ctrs {
  1168  		state, err := ctr.State()
  1169  		if err != nil {
  1170  			logrus.Debugf("Error umounting container %s state: %s", ctr.ID(), err.Error())
  1171  			continue
  1172  		}
  1173  		if state == define.ContainerStateRunning {
  1174  			logrus.Debugf("Error umounting container %s, is running", ctr.ID())
  1175  			continue
  1176  		}
  1177  
  1178  		report := entities.ContainerUnmountReport{Id: ctr.ID()}
  1179  		if err := ctr.Unmount(options.Force); err != nil {
  1180  			if options.All && errors.Cause(err) == storage.ErrLayerNotMounted {
  1181  				logrus.Debugf("Error umounting container %s, storage.ErrLayerNotMounted", ctr.ID())
  1182  				continue
  1183  			}
  1184  			report.Err = errors.Wrapf(err, "error unmounting container %s", ctr.ID())
  1185  		}
  1186  		reports = append(reports, &report)
  1187  	}
  1188  	return reports, nil
  1189  }
  1190  
  1191  // GetConfig returns a copy of the configuration used by the runtime
  1192  func (ic *ContainerEngine) Config(_ context.Context) (*config.Config, error) {
  1193  	return ic.Libpod.GetConfig()
  1194  }
  1195  
  1196  func (ic *ContainerEngine) ContainerPort(ctx context.Context, nameOrID string, options entities.ContainerPortOptions) ([]*entities.ContainerPortReport, error) {
  1197  	ctrs, err := getContainersByContext(options.All, options.Latest, []string{nameOrID}, ic.Libpod)
  1198  	if err != nil {
  1199  		return nil, err
  1200  	}
  1201  	reports := []*entities.ContainerPortReport{}
  1202  	for _, con := range ctrs {
  1203  		state, err := con.State()
  1204  		if err != nil {
  1205  			return nil, err
  1206  		}
  1207  		if state != define.ContainerStateRunning {
  1208  			continue
  1209  		}
  1210  		portmappings, err := con.PortMappings()
  1211  		if err != nil {
  1212  			return nil, err
  1213  		}
  1214  		if len(portmappings) > 0 {
  1215  			reports = append(reports, &entities.ContainerPortReport{
  1216  				Id:    con.ID(),
  1217  				Ports: portmappings,
  1218  			})
  1219  		}
  1220  	}
  1221  	return reports, nil
  1222  }
  1223  
  1224  // Shutdown Libpod engine
  1225  func (ic *ContainerEngine) Shutdown(_ context.Context) {
  1226  	shutdownSync.Do(func() {
  1227  		_ = ic.Libpod.Shutdown(false)
  1228  	})
  1229  }
  1230  
  1231  func (ic *ContainerEngine) ContainerStats(ctx context.Context, namesOrIds []string, options entities.ContainerStatsOptions) (statsChan chan entities.ContainerStatsReport, err error) {
  1232  	statsChan = make(chan entities.ContainerStatsReport, 1)
  1233  
  1234  	containerFunc := ic.Libpod.GetRunningContainers
  1235  	queryAll := false
  1236  	switch {
  1237  	case options.Latest:
  1238  		containerFunc = func() ([]*libpod.Container, error) {
  1239  			lastCtr, err := ic.Libpod.GetLatestContainer()
  1240  			if err != nil {
  1241  				return nil, err
  1242  			}
  1243  			return []*libpod.Container{lastCtr}, nil
  1244  		}
  1245  	case len(namesOrIds) > 0:
  1246  		containerFunc = func() ([]*libpod.Container, error) { return ic.Libpod.GetContainersByList(namesOrIds) }
  1247  	default:
  1248  		// No containers, no latest -> query all!
  1249  		queryAll = true
  1250  		containerFunc = ic.Libpod.GetAllContainers
  1251  	}
  1252  
  1253  	go func() {
  1254  		defer close(statsChan)
  1255  		var (
  1256  			err            error
  1257  			containers     []*libpod.Container
  1258  			containerStats map[string]*define.ContainerStats
  1259  		)
  1260  		containerStats = make(map[string]*define.ContainerStats)
  1261  
  1262  	stream: // label to flatten the scope
  1263  		select {
  1264  		case <-ctx.Done():
  1265  			// client cancelled
  1266  			logrus.Debugf("Container stats stopped: context cancelled")
  1267  			return
  1268  		default:
  1269  			// just fall through and do work
  1270  		}
  1271  
  1272  		// Anonymous func to easily use the return values for streaming.
  1273  		computeStats := func() ([]define.ContainerStats, error) {
  1274  			containers, err = containerFunc()
  1275  			if err != nil {
  1276  				return nil, errors.Wrapf(err, "unable to get list of containers")
  1277  			}
  1278  
  1279  			reportStats := []define.ContainerStats{}
  1280  			for _, ctr := range containers {
  1281  				prev, ok := containerStats[ctr.ID()]
  1282  				if !ok {
  1283  					prev = &define.ContainerStats{}
  1284  				}
  1285  
  1286  				stats, err := ctr.GetContainerStats(prev)
  1287  				if err != nil {
  1288  					cause := errors.Cause(err)
  1289  					if queryAll && (cause == define.ErrCtrRemoved || cause == define.ErrNoSuchCtr || cause == define.ErrCtrStateInvalid) {
  1290  						continue
  1291  					}
  1292  					if cause == cgroups.ErrCgroupV1Rootless {
  1293  						err = cause
  1294  					}
  1295  					return nil, err
  1296  				}
  1297  
  1298  				containerStats[ctr.ID()] = stats
  1299  				reportStats = append(reportStats, *stats)
  1300  			}
  1301  			return reportStats, nil
  1302  		}
  1303  
  1304  		report := entities.ContainerStatsReport{}
  1305  		report.Stats, report.Error = computeStats()
  1306  		statsChan <- report
  1307  
  1308  		if report.Error != nil || !options.Stream {
  1309  			return
  1310  		}
  1311  
  1312  		time.Sleep(time.Second)
  1313  		goto stream
  1314  	}()
  1315  
  1316  	return statsChan, nil
  1317  }
  1318  
  1319  // ShouldRestart returns whether the container should be restarted
  1320  func (ic *ContainerEngine) ShouldRestart(ctx context.Context, nameOrID string) (*entities.BoolReport, error) {
  1321  	ctr, err := ic.Libpod.LookupContainer(nameOrID)
  1322  	if err != nil {
  1323  		return nil, err
  1324  	}
  1325  
  1326  	return &entities.BoolReport{Value: ctr.ShouldRestart(ctx)}, nil
  1327  }