github.com/hanks177/podman/v4@v4.1.3-0.20220613032544-16d90015bc83/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/cgroups"
    15  	"github.com/containers/common/pkg/config"
    16  	"github.com/containers/image/v5/manifest"
    17  	"github.com/hanks177/podman/v4/libpod"
    18  	"github.com/hanks177/podman/v4/libpod/define"
    19  	"github.com/hanks177/podman/v4/libpod/events"
    20  	"github.com/hanks177/podman/v4/libpod/logs"
    21  	"github.com/hanks177/podman/v4/pkg/checkpoint"
    22  	"github.com/hanks177/podman/v4/pkg/domain/entities"
    23  	"github.com/hanks177/podman/v4/pkg/domain/entities/reports"
    24  	dfilters "github.com/hanks177/podman/v4/pkg/domain/filters"
    25  	"github.com/hanks177/podman/v4/pkg/domain/infra/abi/terminal"
    26  	"github.com/hanks177/podman/v4/pkg/errorhandling"
    27  	parallelctr "github.com/hanks177/podman/v4/pkg/parallel/ctr"
    28  	"github.com/hanks177/podman/v4/pkg/ps"
    29  	"github.com/hanks177/podman/v4/pkg/rootless"
    30  	"github.com/hanks177/podman/v4/pkg/signal"
    31  	"github.com/hanks177/podman/v4/pkg/specgen"
    32  	"github.com/hanks177/podman/v4/pkg/specgen/generate"
    33  	"github.com/hanks177/podman/v4/pkg/specgenutil"
    34  	"github.com/hanks177/podman/v4/pkg/util"
    35  	"github.com/containers/storage"
    36  	"github.com/pkg/errors"
    37  	"github.com/sirupsen/logrus"
    38  )
    39  
    40  // getContainersAndInputByContext gets containers whether all, latest, or a slice of names/ids
    41  // is specified.  It also returns a list of the corresponding input name used to lookup each container.
    42  func getContainersAndInputByContext(all, latest bool, names []string, runtime *libpod.Runtime) (ctrs []*libpod.Container, rawInput []string, err error) {
    43  	var ctr *libpod.Container
    44  	ctrs = []*libpod.Container{}
    45  
    46  	switch {
    47  	case all:
    48  		ctrs, err = runtime.GetAllContainers()
    49  	case latest:
    50  		ctr, err = runtime.GetLatestContainer()
    51  		if err == nil {
    52  			rawInput = append(rawInput, ctr.ID())
    53  			ctrs = append(ctrs, ctr)
    54  		}
    55  	default:
    56  		for _, n := range names {
    57  			ctr, e := runtime.LookupContainer(n)
    58  			if e != nil {
    59  				// Log all errors here, so callers don't need to.
    60  				logrus.Debugf("Error looking up container %q: %v", n, e)
    61  				if err == nil {
    62  					err = e
    63  				}
    64  			} else {
    65  				rawInput = append(rawInput, n)
    66  				ctrs = append(ctrs, ctr)
    67  			}
    68  		}
    69  	}
    70  	return
    71  }
    72  
    73  // getContainersByContext gets containers whether all, latest, or a slice of names/ids
    74  // is specified.
    75  func getContainersByContext(all, latest bool, names []string, runtime *libpod.Runtime) (ctrs []*libpod.Container, err error) {
    76  	ctrs, _, err = getContainersAndInputByContext(all, latest, names, runtime)
    77  	return
    78  }
    79  
    80  // ContainerExists returns whether the container exists in container storage
    81  func (ic *ContainerEngine) ContainerExists(ctx context.Context, nameOrID string, options entities.ContainerExistsOptions) (*entities.BoolReport, error) {
    82  	_, err := ic.Libpod.LookupContainer(nameOrID)
    83  	if err != nil {
    84  		if errors.Cause(err) != define.ErrNoSuchCtr {
    85  			return nil, err
    86  		}
    87  		if options.External {
    88  			// Check if container exists in storage
    89  			if _, storageErr := ic.Libpod.StorageContainer(nameOrID); storageErr == nil {
    90  				err = nil
    91  			}
    92  		}
    93  	}
    94  	return &entities.BoolReport{Value: err == nil}, nil
    95  }
    96  
    97  func (ic *ContainerEngine) ContainerWait(ctx context.Context, namesOrIds []string, options entities.WaitOptions) ([]entities.WaitReport, error) {
    98  	ctrs, err := getContainersByContext(false, options.Latest, namesOrIds, ic.Libpod)
    99  	if err != nil {
   100  		return nil, err
   101  	}
   102  	responses := make([]entities.WaitReport, 0, len(ctrs))
   103  	for _, c := range ctrs {
   104  		response := entities.WaitReport{Id: c.ID()}
   105  		exitCode, err := c.WaitForConditionWithInterval(ctx, options.Interval, options.Condition...)
   106  		if err != nil {
   107  			response.Error = err
   108  		} else {
   109  			response.ExitCode = exitCode
   110  		}
   111  		responses = append(responses, response)
   112  	}
   113  	return responses, nil
   114  }
   115  
   116  func (ic *ContainerEngine) ContainerPause(ctx context.Context, namesOrIds []string, options entities.PauseUnPauseOptions) ([]*entities.PauseUnpauseReport, error) {
   117  	ctrs, err := getContainersByContext(options.All, false, namesOrIds, ic.Libpod)
   118  	if err != nil {
   119  		return nil, err
   120  	}
   121  	report := make([]*entities.PauseUnpauseReport, 0, len(ctrs))
   122  	for _, c := range ctrs {
   123  		err := c.Pause()
   124  		if err != nil && options.All && errors.Cause(err) == define.ErrCtrStateInvalid {
   125  			logrus.Debugf("Container %s is not running", c.ID())
   126  			continue
   127  		}
   128  		report = append(report, &entities.PauseUnpauseReport{Id: c.ID(), Err: err})
   129  	}
   130  	return report, nil
   131  }
   132  
   133  func (ic *ContainerEngine) ContainerUnpause(ctx context.Context, namesOrIds []string, options entities.PauseUnPauseOptions) ([]*entities.PauseUnpauseReport, error) {
   134  	ctrs, err := getContainersByContext(options.All, false, namesOrIds, ic.Libpod)
   135  	if err != nil {
   136  		return nil, err
   137  	}
   138  	report := make([]*entities.PauseUnpauseReport, 0, len(ctrs))
   139  	for _, c := range ctrs {
   140  		err := c.Unpause()
   141  		if err != nil && options.All && errors.Cause(err) == define.ErrCtrStateInvalid {
   142  			logrus.Debugf("Container %s is not paused", c.ID())
   143  			continue
   144  		}
   145  		report = append(report, &entities.PauseUnpauseReport{Id: c.ID(), Err: err})
   146  	}
   147  	return report, nil
   148  }
   149  func (ic *ContainerEngine) ContainerStop(ctx context.Context, namesOrIds []string, options entities.StopOptions) ([]*entities.StopReport, error) {
   150  	names := namesOrIds
   151  	ctrs, rawInputs, err := getContainersAndInputByContext(options.All, options.Latest, names, ic.Libpod)
   152  	if err != nil && !(options.Ignore && errors.Cause(err) == define.ErrNoSuchCtr) {
   153  		return nil, err
   154  	}
   155  	ctrMap := map[string]string{}
   156  	if len(rawInputs) == len(ctrs) {
   157  		for i := range ctrs {
   158  			ctrMap[ctrs[i].ID()] = rawInputs[i]
   159  		}
   160  	}
   161  	errMap, err := parallelctr.ContainerOp(ctx, ctrs, func(c *libpod.Container) error {
   162  		var err error
   163  		if options.Timeout != nil {
   164  			err = c.StopWithTimeout(*options.Timeout)
   165  		} else {
   166  			err = c.Stop()
   167  		}
   168  		if err != nil {
   169  			switch {
   170  			case errors.Cause(err) == define.ErrCtrStopped:
   171  				logrus.Debugf("Container %s is already stopped", c.ID())
   172  			case options.All && errors.Cause(err) == define.ErrCtrStateInvalid:
   173  				logrus.Debugf("Container %s is not running, could not stop", c.ID())
   174  			// container never created in OCI runtime
   175  			// docker parity: do nothing just return container id
   176  			case errors.Cause(err) == define.ErrCtrStateInvalid:
   177  				logrus.Debugf("Container %s is either not created on runtime or is in a invalid state", c.ID())
   178  			default:
   179  				return err
   180  			}
   181  		}
   182  		err = c.Cleanup(ctx)
   183  		if err != nil {
   184  			// Issue #7384 and #11384: If the container is configured for
   185  			// auto-removal, it might already have been removed at this point.
   186  			// We still need to to cleanup since we do not know if the other cleanup process is successful
   187  			if c.AutoRemove() && (errors.Is(err, define.ErrNoSuchCtr) || errors.Is(err, define.ErrCtrRemoved)) {
   188  				return nil
   189  			}
   190  			return err
   191  		}
   192  		return nil
   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  		if options.All {
   202  			report.RawInput = ctr.ID()
   203  		} else {
   204  			report.RawInput = ctrMap[ctr.ID()]
   205  		}
   206  		report.Err = err
   207  		reports = append(reports, report)
   208  	}
   209  	return reports, nil
   210  }
   211  
   212  func (ic *ContainerEngine) ContainerPrune(ctx context.Context, options entities.ContainerPruneOptions) ([]*reports.PruneReport, error) {
   213  	filterFuncs := make([]libpod.ContainerFilter, 0, len(options.Filters))
   214  	for k, v := range options.Filters {
   215  		generatedFunc, err := dfilters.GeneratePruneContainerFilterFuncs(k, v, ic.Libpod)
   216  		if err != nil {
   217  			return nil, err
   218  		}
   219  		filterFuncs = append(filterFuncs, generatedFunc)
   220  	}
   221  	return ic.Libpod.PruneContainers(filterFuncs)
   222  }
   223  
   224  func (ic *ContainerEngine) ContainerKill(ctx context.Context, namesOrIds []string, options entities.KillOptions) ([]*entities.KillReport, error) {
   225  	sig, err := signal.ParseSignalNameOrNumber(options.Signal)
   226  	if err != nil {
   227  		return nil, err
   228  	}
   229  	ctrs, rawInputs, err := getContainersAndInputByContext(options.All, options.Latest, namesOrIds, ic.Libpod)
   230  	if err != nil {
   231  		return nil, err
   232  	}
   233  	ctrMap := map[string]string{}
   234  	if len(rawInputs) == len(ctrs) {
   235  		for i := range ctrs {
   236  			ctrMap[ctrs[i].ID()] = rawInputs[i]
   237  		}
   238  	}
   239  	reports := make([]*entities.KillReport, 0, len(ctrs))
   240  	for _, con := range ctrs {
   241  		err := con.Kill(uint(sig))
   242  		if options.All && errors.Cause(err) == define.ErrCtrStateInvalid {
   243  			logrus.Debugf("Container %s is not running", con.ID())
   244  			continue
   245  		}
   246  		reports = append(reports, &entities.KillReport{
   247  			Id:       con.ID(),
   248  			Err:      err,
   249  			RawInput: ctrMap[con.ID()],
   250  		})
   251  	}
   252  	return reports, nil
   253  }
   254  
   255  func (ic *ContainerEngine) ContainerRestart(ctx context.Context, namesOrIds []string, options entities.RestartOptions) ([]*entities.RestartReport, error) {
   256  	var (
   257  		ctrs []*libpod.Container
   258  		err  error
   259  	)
   260  
   261  	if options.Running {
   262  		ctrs, err = ic.Libpod.GetRunningContainers()
   263  		if err != nil {
   264  			return nil, err
   265  		}
   266  	} else {
   267  		ctrs, err = getContainersByContext(options.All, options.Latest, namesOrIds, ic.Libpod)
   268  		if err != nil {
   269  			return nil, err
   270  		}
   271  	}
   272  
   273  	reports := make([]*entities.RestartReport, 0, len(ctrs))
   274  	for _, con := range ctrs {
   275  		timeout := con.StopTimeout()
   276  		if options.Timeout != nil {
   277  			timeout = *options.Timeout
   278  		}
   279  		reports = append(reports, &entities.RestartReport{
   280  			Id:  con.ID(),
   281  			Err: con.RestartWithTimeout(ctx, timeout),
   282  		})
   283  	}
   284  	return reports, nil
   285  }
   286  
   287  func (ic *ContainerEngine) removeContainer(ctx context.Context, ctr *libpod.Container, options entities.RmOptions) error {
   288  	err := ic.Libpod.RemoveContainer(ctx, ctr, options.Force, options.Volumes, options.Timeout)
   289  	if err == nil {
   290  		return nil
   291  	}
   292  	logrus.Debugf("Failed to remove container %s: %s", ctr.ID(), err.Error())
   293  	switch errors.Cause(err) {
   294  	case define.ErrNoSuchCtr:
   295  		// Ignore if the container does not exist (anymore) when either
   296  		// it has been requested by the user of if the container is a
   297  		// service one.  Service containers are removed along with its
   298  		// pods which in turn are removed along with their infra
   299  		// container.  Hence, there is an inherent race when removing
   300  		// infra containers with service containers in parallel.
   301  		if options.Ignore || ctr.IsService() {
   302  			logrus.Debugf("Ignoring error (--allow-missing): %v", err)
   303  			return nil
   304  		}
   305  	case define.ErrCtrRemoved:
   306  		return nil
   307  	}
   308  	return err
   309  }
   310  
   311  func (ic *ContainerEngine) ContainerRm(ctx context.Context, namesOrIds []string, options entities.RmOptions) ([]*reports.RmReport, error) {
   312  	rmReports := []*reports.RmReport{}
   313  
   314  	names := namesOrIds
   315  	// Attempt to remove named containers directly from storage, if container is defined in libpod
   316  	// this will fail and code will fall through to removing the container from libpod.`
   317  	tmpNames := []string{}
   318  	for _, ctr := range names {
   319  		report := reports.RmReport{Id: ctr}
   320  		report.Err = ic.Libpod.RemoveStorageContainer(ctr, options.Force)
   321  		switch errors.Cause(report.Err) {
   322  		case nil:
   323  			// remove container names that we successfully deleted
   324  			rmReports = append(rmReports, &report)
   325  		case define.ErrNoSuchCtr, define.ErrCtrExists:
   326  			// There is still a potential this is a libpod container
   327  			tmpNames = append(tmpNames, ctr)
   328  		default:
   329  			if _, err := ic.Libpod.LookupContainer(ctr); errors.Cause(err) == define.ErrNoSuchCtr {
   330  				// remove container failed, but not a libpod container
   331  				rmReports = append(rmReports, &report)
   332  				continue
   333  			}
   334  			// attempt to remove as a libpod container
   335  			tmpNames = append(tmpNames, ctr)
   336  		}
   337  	}
   338  	names = tmpNames
   339  
   340  	ctrs, err := getContainersByContext(options.All, options.Latest, names, ic.Libpod)
   341  	if err != nil && !(options.Ignore && errors.Cause(err) == define.ErrNoSuchCtr) {
   342  		// Failed to get containers. If force is specified, get the containers ID
   343  		// and evict them
   344  		if !options.Force {
   345  			return nil, err
   346  		}
   347  
   348  		for _, ctr := range names {
   349  			logrus.Debugf("Evicting container %q", ctr)
   350  			report := reports.RmReport{Id: ctr}
   351  			_, err := ic.Libpod.EvictContainer(ctx, ctr, options.Volumes)
   352  			if err != nil {
   353  				if options.Ignore && errors.Cause(err) == define.ErrNoSuchCtr {
   354  					logrus.Debugf("Ignoring error (--allow-missing): %v", err)
   355  					rmReports = append(rmReports, &report)
   356  					continue
   357  				}
   358  				report.Err = err
   359  				rmReports = append(rmReports, &report)
   360  				continue
   361  			}
   362  			rmReports = append(rmReports, &report)
   363  		}
   364  		return rmReports, nil
   365  	}
   366  
   367  	alreadyRemoved := make(map[string]bool)
   368  	addReports := func(newReports []*reports.RmReport) {
   369  		for i := range newReports {
   370  			alreadyRemoved[newReports[i].Id] = true
   371  			rmReports = append(rmReports, newReports[i])
   372  		}
   373  	}
   374  	if !options.All && options.Depend {
   375  		// Add additional containers based on dependencies to container map
   376  		for _, ctr := range ctrs {
   377  			if alreadyRemoved[ctr.ID()] {
   378  				continue
   379  			}
   380  			reports, err := ic.Libpod.RemoveDepend(ctx, ctr, options.Force, options.Volumes, options.Timeout)
   381  			if err != nil {
   382  				return rmReports, err
   383  			}
   384  			addReports(reports)
   385  		}
   386  		return rmReports, nil
   387  	}
   388  
   389  	// If --all is set, make sure to remove the infra containers'
   390  	// dependencies before doing the parallel removal below.
   391  	if options.All {
   392  		for _, ctr := range ctrs {
   393  			if alreadyRemoved[ctr.ID()] || !ctr.IsInfra() {
   394  				continue
   395  			}
   396  			reports, err := ic.Libpod.RemoveDepend(ctx, ctr, options.Force, options.Volumes, options.Timeout)
   397  			if err != nil {
   398  				return rmReports, err
   399  			}
   400  			addReports(reports)
   401  		}
   402  	}
   403  
   404  	errMap, err := parallelctr.ContainerOp(ctx, ctrs, func(c *libpod.Container) error {
   405  		if alreadyRemoved[c.ID()] {
   406  			return nil
   407  		}
   408  		return ic.removeContainer(ctx, c, options)
   409  	})
   410  	if err != nil {
   411  		return nil, err
   412  	}
   413  	for ctr, err := range errMap {
   414  		if alreadyRemoved[ctr.ID()] {
   415  			continue
   416  		}
   417  		report := new(reports.RmReport)
   418  		report.Id = ctr.ID()
   419  		report.Err = err
   420  		rmReports = append(rmReports, report)
   421  	}
   422  	return rmReports, nil
   423  }
   424  
   425  func (ic *ContainerEngine) ContainerInspect(ctx context.Context, namesOrIds []string, options entities.InspectOptions) ([]*entities.ContainerInspectReport, []error, error) {
   426  	if options.Latest {
   427  		ctr, err := ic.Libpod.GetLatestContainer()
   428  		if err != nil {
   429  			if errors.Is(err, define.ErrNoSuchCtr) {
   430  				return nil, []error{errors.Wrapf(err, "no containers to inspect")}, nil
   431  			}
   432  			return nil, nil, err
   433  		}
   434  
   435  		inspect, err := ctr.Inspect(options.Size)
   436  		if err != nil {
   437  			return nil, nil, err
   438  		}
   439  
   440  		return []*entities.ContainerInspectReport{
   441  			{
   442  				InspectContainerData: inspect,
   443  			},
   444  		}, nil, nil
   445  	}
   446  	var (
   447  		reports = make([]*entities.ContainerInspectReport, 0, len(namesOrIds))
   448  		errs    = []error{}
   449  	)
   450  	for _, name := range namesOrIds {
   451  		ctr, err := ic.Libpod.LookupContainer(name)
   452  		if err != nil {
   453  			// ErrNoSuchCtr is non-fatal, other errors will be
   454  			// treated as fatal.
   455  			if errors.Is(err, define.ErrNoSuchCtr) {
   456  				errs = append(errs, errors.Errorf("no such container %s", name))
   457  				continue
   458  			}
   459  			return nil, nil, err
   460  		}
   461  
   462  		inspect, err := ctr.Inspect(options.Size)
   463  		if err != nil {
   464  			// ErrNoSuchCtr is non-fatal, other errors will be
   465  			// treated as fatal.
   466  			if errors.Is(err, define.ErrNoSuchCtr) {
   467  				errs = append(errs, errors.Errorf("no such container %s", name))
   468  				continue
   469  			}
   470  			return nil, nil, err
   471  		}
   472  
   473  		reports = append(reports, &entities.ContainerInspectReport{InspectContainerData: inspect})
   474  	}
   475  	return reports, errs, nil
   476  }
   477  
   478  func (ic *ContainerEngine) ContainerTop(ctx context.Context, options entities.TopOptions) (*entities.StringSliceReport, error) {
   479  	var (
   480  		container *libpod.Container
   481  		err       error
   482  	)
   483  
   484  	// Look up the container.
   485  	if options.Latest {
   486  		container, err = ic.Libpod.GetLatestContainer()
   487  	} else {
   488  		container, err = ic.Libpod.LookupContainer(options.NameOrID)
   489  	}
   490  	if err != nil {
   491  		return nil, errors.Wrap(err, "unable to lookup requested container")
   492  	}
   493  
   494  	// Run Top.
   495  	report := &entities.StringSliceReport{}
   496  	report.Value, err = container.Top(options.Descriptors)
   497  	return report, err
   498  }
   499  
   500  func (ic *ContainerEngine) ContainerCommit(ctx context.Context, nameOrID string, options entities.CommitOptions) (*entities.CommitReport, error) {
   501  	var (
   502  		mimeType string
   503  	)
   504  	ctr, err := ic.Libpod.LookupContainer(nameOrID)
   505  	if err != nil {
   506  		return nil, err
   507  	}
   508  	rtc, err := ic.Libpod.GetConfig()
   509  	if err != nil {
   510  		return nil, err
   511  	}
   512  	switch options.Format {
   513  	case "oci":
   514  		mimeType = buildah.OCIv1ImageManifest
   515  		if len(options.Message) > 0 {
   516  			return nil, errors.Errorf("messages are only compatible with the docker image format (-f docker)")
   517  		}
   518  	case "docker":
   519  		mimeType = manifest.DockerV2Schema2MediaType
   520  	default:
   521  		return nil, errors.Errorf("unrecognized image format %q", options.Format)
   522  	}
   523  
   524  	sc := ic.Libpod.SystemContext()
   525  	coptions := buildah.CommitOptions{
   526  		SignaturePolicyPath:   rtc.Engine.SignaturePolicyPath,
   527  		ReportWriter:          options.Writer,
   528  		SystemContext:         sc,
   529  		PreferredManifestType: mimeType,
   530  	}
   531  	opts := libpod.ContainerCommitOptions{
   532  		CommitOptions:  coptions,
   533  		Pause:          options.Pause,
   534  		IncludeVolumes: options.IncludeVolumes,
   535  		Message:        options.Message,
   536  		Changes:        options.Changes,
   537  		Author:         options.Author,
   538  		Squash:         options.Squash,
   539  	}
   540  	newImage, err := ctr.Commit(ctx, options.ImageName, opts)
   541  	if err != nil {
   542  		return nil, err
   543  	}
   544  	return &entities.CommitReport{Id: newImage.ID()}, nil
   545  }
   546  
   547  func (ic *ContainerEngine) ContainerExport(ctx context.Context, nameOrID string, options entities.ContainerExportOptions) error {
   548  	ctr, err := ic.Libpod.LookupContainer(nameOrID)
   549  	if err != nil {
   550  		return err
   551  	}
   552  	return ctr.Export(options.Output)
   553  }
   554  
   555  func (ic *ContainerEngine) ContainerCheckpoint(ctx context.Context, namesOrIds []string, options entities.CheckpointOptions) ([]*entities.CheckpointReport, error) {
   556  	var (
   557  		err  error
   558  		cons []*libpod.Container
   559  	)
   560  	checkOpts := libpod.ContainerCheckpointOptions{
   561  		Keep:           options.Keep,
   562  		TCPEstablished: options.TCPEstablished,
   563  		TargetFile:     options.Export,
   564  		IgnoreRootfs:   options.IgnoreRootFS,
   565  		IgnoreVolumes:  options.IgnoreVolumes,
   566  		KeepRunning:    options.LeaveRunning,
   567  		PreCheckPoint:  options.PreCheckPoint,
   568  		WithPrevious:   options.WithPrevious,
   569  		Compression:    options.Compression,
   570  		PrintStats:     options.PrintStats,
   571  		FileLocks:      options.FileLocks,
   572  		CreateImage:    options.CreateImage,
   573  	}
   574  
   575  	if options.All {
   576  		running := func(c *libpod.Container) bool {
   577  			state, _ := c.State()
   578  			return state == define.ContainerStateRunning
   579  		}
   580  		cons, err = ic.Libpod.GetContainers(running)
   581  	} else {
   582  		cons, err = getContainersByContext(false, options.Latest, namesOrIds, ic.Libpod)
   583  	}
   584  	if err != nil {
   585  		return nil, err
   586  	}
   587  	reports := make([]*entities.CheckpointReport, 0, len(cons))
   588  	for _, con := range cons {
   589  		criuStatistics, runtimeCheckpointDuration, err := con.Checkpoint(ctx, checkOpts)
   590  		reports = append(reports, &entities.CheckpointReport{
   591  			Err:             err,
   592  			Id:              con.ID(),
   593  			RuntimeDuration: runtimeCheckpointDuration,
   594  			CRIUStatistics:  criuStatistics,
   595  		})
   596  	}
   597  	return reports, nil
   598  }
   599  
   600  func (ic *ContainerEngine) ContainerRestore(ctx context.Context, namesOrIds []string, options entities.RestoreOptions) ([]*entities.RestoreReport, error) {
   601  	var (
   602  		containers                  []*libpod.Container
   603  		checkpointImageImportErrors []error
   604  		err                         error
   605  	)
   606  
   607  	restoreOptions := libpod.ContainerCheckpointOptions{
   608  		Keep:            options.Keep,
   609  		TCPEstablished:  options.TCPEstablished,
   610  		TargetFile:      options.Import,
   611  		Name:            options.Name,
   612  		IgnoreRootfs:    options.IgnoreRootFS,
   613  		IgnoreVolumes:   options.IgnoreVolumes,
   614  		IgnoreStaticIP:  options.IgnoreStaticIP,
   615  		IgnoreStaticMAC: options.IgnoreStaticMAC,
   616  		ImportPrevious:  options.ImportPrevious,
   617  		Pod:             options.Pod,
   618  		PrintStats:      options.PrintStats,
   619  	}
   620  
   621  	filterFuncs := []libpod.ContainerFilter{
   622  		func(c *libpod.Container) bool {
   623  			state, _ := c.State()
   624  			return state == define.ContainerStateExited
   625  		},
   626  	}
   627  
   628  	switch {
   629  	case options.Import != "":
   630  		containers, err = checkpoint.CRImportCheckpointTar(ctx, ic.Libpod, options)
   631  	case options.All:
   632  		containers, err = ic.Libpod.GetContainers(filterFuncs...)
   633  	case options.Latest:
   634  		containers, err = getContainersByContext(false, options.Latest, namesOrIds, ic.Libpod)
   635  	default:
   636  		for _, nameOrID := range namesOrIds {
   637  			logrus.Debugf("lookup container: %q", nameOrID)
   638  			ctr, err := ic.Libpod.LookupContainer(nameOrID)
   639  			if err == nil {
   640  				containers = append(containers, ctr)
   641  			} else {
   642  				// If container was not found, check if this is a checkpoint image
   643  				logrus.Debugf("lookup image: %q", nameOrID)
   644  				img, _, err := ic.Libpod.LibimageRuntime().LookupImage(nameOrID, nil)
   645  				if err != nil {
   646  					return nil, fmt.Errorf("no such container or image: %s", nameOrID)
   647  				}
   648  				restoreOptions.CheckpointImageID = img.ID()
   649  				mountPoint, err := img.Mount(ctx, nil, "")
   650  				defer func() {
   651  					if err := img.Unmount(true); err != nil {
   652  						logrus.Errorf("Failed to unmount image: %v", err)
   653  					}
   654  				}()
   655  				if err != nil {
   656  					return nil, err
   657  				}
   658  				importedContainers, err := checkpoint.CRImportCheckpoint(ctx, ic.Libpod, options, mountPoint)
   659  				if err != nil {
   660  					// CRImportCheckpoint is expected to import exactly one container from checkpoint image
   661  					checkpointImageImportErrors = append(
   662  						checkpointImageImportErrors,
   663  						errors.Errorf("unable to import checkpoint from image: %q: %v", nameOrID, err),
   664  					)
   665  				} else {
   666  					containers = append(containers, importedContainers[0])
   667  				}
   668  			}
   669  		}
   670  	}
   671  	if err != nil {
   672  		return nil, err
   673  	}
   674  
   675  	reports := make([]*entities.RestoreReport, 0, len(containers))
   676  	for _, con := range containers {
   677  		criuStatistics, runtimeRestoreDuration, err := con.Restore(ctx, restoreOptions)
   678  		reports = append(reports, &entities.RestoreReport{
   679  			Err:             err,
   680  			Id:              con.ID(),
   681  			RuntimeDuration: runtimeRestoreDuration,
   682  			CRIUStatistics:  criuStatistics,
   683  		})
   684  	}
   685  
   686  	for _, importErr := range checkpointImageImportErrors {
   687  		reports = append(reports, &entities.RestoreReport{
   688  			Err: importErr,
   689  		})
   690  	}
   691  
   692  	return reports, nil
   693  }
   694  
   695  func (ic *ContainerEngine) ContainerCreate(ctx context.Context, s *specgen.SpecGenerator) (*entities.ContainerCreateReport, error) {
   696  	warn, err := generate.CompleteSpec(ctx, ic.Libpod, s)
   697  	if err != nil {
   698  		return nil, err
   699  	}
   700  	// Print warnings
   701  	for _, w := range warn {
   702  		fmt.Fprintf(os.Stderr, "%s\n", w)
   703  	}
   704  	rtSpec, spec, opts, err := generate.MakeContainer(context.Background(), ic.Libpod, s, false, nil)
   705  	if err != nil {
   706  		return nil, err
   707  	}
   708  	ctr, err := generate.ExecuteCreate(ctx, ic.Libpod, rtSpec, spec, false, opts...)
   709  	if err != nil {
   710  		return nil, err
   711  	}
   712  	return &entities.ContainerCreateReport{Id: ctr.ID()}, nil
   713  }
   714  
   715  func (ic *ContainerEngine) ContainerAttach(ctx context.Context, nameOrID string, options entities.AttachOptions) error {
   716  	ctrs, err := getContainersByContext(false, options.Latest, []string{nameOrID}, ic.Libpod)
   717  	if err != nil {
   718  		return err
   719  	}
   720  	ctr := ctrs[0]
   721  	conState, err := ctr.State()
   722  	if err != nil {
   723  		return errors.Wrapf(err, "unable to determine state of %s", ctr.ID())
   724  	}
   725  	if conState != define.ContainerStateRunning {
   726  		return errors.Errorf("you can only attach to running containers")
   727  	}
   728  
   729  	// If the container is in a pod, also set to recursively start dependencies
   730  	err = terminal.StartAttachCtr(ctx, ctr, options.Stdout, options.Stderr, options.Stdin, options.DetachKeys, options.SigProxy, false)
   731  	if err != nil && errors.Cause(err) != define.ErrDetach {
   732  		return errors.Wrapf(err, "error attaching to container %s", ctr.ID())
   733  	}
   734  	os.Stdout.WriteString("\n")
   735  	return nil
   736  }
   737  
   738  func makeExecConfig(options entities.ExecOptions, rt *libpod.Runtime) (*libpod.ExecConfig, error) {
   739  	execConfig := new(libpod.ExecConfig)
   740  	execConfig.Command = options.Cmd
   741  	execConfig.Terminal = options.Tty
   742  	execConfig.Privileged = options.Privileged
   743  	execConfig.Environment = options.Envs
   744  	execConfig.User = options.User
   745  	execConfig.WorkDir = options.WorkDir
   746  	execConfig.DetachKeys = &options.DetachKeys
   747  	execConfig.PreserveFDs = options.PreserveFDs
   748  	execConfig.AttachStdin = options.Interactive
   749  
   750  	// Make an exit command
   751  	storageConfig := rt.StorageConfig()
   752  	runtimeConfig, err := rt.GetConfig()
   753  	if err != nil {
   754  		return nil, errors.Wrapf(err, "error retrieving Libpod configuration to build exec exit command")
   755  	}
   756  	// TODO: Add some ability to toggle syslog
   757  	exitCommandArgs, err := specgenutil.CreateExitCommandArgs(storageConfig, runtimeConfig, logrus.IsLevelEnabled(logrus.DebugLevel), false, true)
   758  	if err != nil {
   759  		return nil, errors.Wrapf(err, "error constructing exit command for exec session")
   760  	}
   761  	execConfig.ExitCommand = exitCommandArgs
   762  
   763  	return execConfig, nil
   764  }
   765  
   766  func checkExecPreserveFDs(options entities.ExecOptions) error {
   767  	if options.PreserveFDs > 0 {
   768  		entries, err := ioutil.ReadDir("/proc/self/fd")
   769  		if err != nil {
   770  			return err
   771  		}
   772  
   773  		m := make(map[int]bool)
   774  		for _, e := range entries {
   775  			i, err := strconv.Atoi(e.Name())
   776  			if err != nil {
   777  				return errors.Wrapf(err, "cannot parse %s in /proc/self/fd", e.Name())
   778  			}
   779  			m[i] = true
   780  		}
   781  
   782  		for i := 3; i < 3+int(options.PreserveFDs); i++ {
   783  			if _, found := m[i]; !found {
   784  				return errors.New("invalid --preserve-fds=N specified. Not enough FDs available")
   785  			}
   786  		}
   787  	}
   788  	return nil
   789  }
   790  
   791  func (ic *ContainerEngine) ContainerExec(ctx context.Context, nameOrID string, options entities.ExecOptions, streams define.AttachStreams) (int, error) {
   792  	ec := define.ExecErrorCodeGeneric
   793  	err := checkExecPreserveFDs(options)
   794  	if err != nil {
   795  		return ec, err
   796  	}
   797  	ctrs, err := getContainersByContext(false, options.Latest, []string{nameOrID}, ic.Libpod)
   798  	if err != nil {
   799  		return ec, err
   800  	}
   801  	ctr := ctrs[0]
   802  
   803  	execConfig, err := makeExecConfig(options, ic.Libpod)
   804  	if err != nil {
   805  		return ec, err
   806  	}
   807  
   808  	ec, err = terminal.ExecAttachCtr(ctx, ctr, execConfig, &streams)
   809  	return define.TranslateExecErrorToExitCode(ec, err), err
   810  }
   811  
   812  func (ic *ContainerEngine) ContainerExecDetached(ctx context.Context, nameOrID string, options entities.ExecOptions) (string, error) {
   813  	err := checkExecPreserveFDs(options)
   814  	if err != nil {
   815  		return "", err
   816  	}
   817  	ctrs, err := getContainersByContext(false, options.Latest, []string{nameOrID}, ic.Libpod)
   818  	if err != nil {
   819  		return "", err
   820  	}
   821  	ctr := ctrs[0]
   822  
   823  	execConfig, err := makeExecConfig(options, ic.Libpod)
   824  	if err != nil {
   825  		return "", err
   826  	}
   827  
   828  	// Create and start the exec session
   829  	id, err := ctr.ExecCreate(execConfig)
   830  	if err != nil {
   831  		return "", err
   832  	}
   833  
   834  	// TODO: we should try and retrieve exit code if this fails.
   835  	if err := ctr.ExecStart(id); err != nil {
   836  		return "", err
   837  	}
   838  	return id, nil
   839  }
   840  
   841  func (ic *ContainerEngine) ContainerStart(ctx context.Context, namesOrIds []string, options entities.ContainerStartOptions) ([]*entities.ContainerStartReport, error) {
   842  	reports := []*entities.ContainerStartReport{}
   843  	var exitCode = define.ExecErrorCodeGeneric
   844  	containersNamesOrIds := namesOrIds
   845  	all := options.All
   846  	if len(options.Filters) > 0 {
   847  		all = false
   848  		filterFuncs := make([]libpod.ContainerFilter, 0, len(options.Filters))
   849  		if len(options.Filters) > 0 {
   850  			for k, v := range options.Filters {
   851  				generatedFunc, err := dfilters.GenerateContainerFilterFuncs(k, v, ic.Libpod)
   852  				if err != nil {
   853  					return nil, err
   854  				}
   855  				filterFuncs = append(filterFuncs, generatedFunc)
   856  			}
   857  		}
   858  		candidates, err := ic.Libpod.GetContainers(filterFuncs...)
   859  		if err != nil {
   860  			return nil, err
   861  		}
   862  		containersNamesOrIds = []string{}
   863  		for _, candidate := range candidates {
   864  			if options.All {
   865  				containersNamesOrIds = append(containersNamesOrIds, candidate.ID())
   866  				continue
   867  			}
   868  			for _, nameOrID := range namesOrIds {
   869  				if nameOrID == candidate.ID() || nameOrID == candidate.Name() {
   870  					containersNamesOrIds = append(containersNamesOrIds, nameOrID)
   871  				}
   872  			}
   873  		}
   874  	}
   875  	ctrs, rawInputs, err := getContainersAndInputByContext(all, options.Latest, containersNamesOrIds, ic.Libpod)
   876  	if err != nil {
   877  		return nil, err
   878  	}
   879  	// There can only be one container if attach was used
   880  	for i := range ctrs {
   881  		ctr := ctrs[i]
   882  		rawInput := ctr.ID()
   883  		if !options.All {
   884  			rawInput = rawInputs[i]
   885  		}
   886  		ctrState, err := ctr.State()
   887  		if err != nil {
   888  			return nil, err
   889  		}
   890  		ctrRunning := ctrState == define.ContainerStateRunning
   891  
   892  		if options.Attach {
   893  			err = terminal.StartAttachCtr(ctx, ctr, options.Stdout, options.Stderr, options.Stdin, options.DetachKeys, options.SigProxy, !ctrRunning)
   894  			if errors.Cause(err) == define.ErrDetach {
   895  				// User manually detached
   896  				// Exit cleanly immediately
   897  				reports = append(reports, &entities.ContainerStartReport{
   898  					Id:       ctr.ID(),
   899  					RawInput: rawInput,
   900  					Err:      nil,
   901  					ExitCode: 0,
   902  				})
   903  				return reports, nil
   904  			}
   905  
   906  			if errors.Cause(err) == define.ErrWillDeadlock {
   907  				logrus.Debugf("Deadlock error: %v", err)
   908  				reports = append(reports, &entities.ContainerStartReport{
   909  					Id:       ctr.ID(),
   910  					RawInput: rawInput,
   911  					Err:      err,
   912  					ExitCode: define.ExitCode(err),
   913  				})
   914  				return reports, errors.Errorf("attempting to start container %s would cause a deadlock; please run 'podman system renumber' to resolve", ctr.ID())
   915  			}
   916  
   917  			if ctrRunning {
   918  				reports = append(reports, &entities.ContainerStartReport{
   919  					Id:       ctr.ID(),
   920  					RawInput: rawInput,
   921  					Err:      nil,
   922  					ExitCode: 0,
   923  				})
   924  				return reports, err
   925  			}
   926  
   927  			if err != nil {
   928  				reports = append(reports, &entities.ContainerStartReport{
   929  					Id:       ctr.ID(),
   930  					RawInput: rawInput,
   931  					Err:      err,
   932  					ExitCode: exitCode,
   933  				})
   934  				if ctr.AutoRemove() {
   935  					if err := ic.removeContainer(ctx, ctr, entities.RmOptions{}); err != nil {
   936  						logrus.Errorf("Removing container %s: %v", ctr.ID(), err)
   937  					}
   938  				}
   939  				return reports, errors.Wrapf(err, "unable to start container %s", ctr.ID())
   940  			}
   941  			exitCode = ic.GetContainerExitCode(ctx, ctr)
   942  			reports = append(reports, &entities.ContainerStartReport{
   943  				Id:       ctr.ID(),
   944  				RawInput: rawInput,
   945  				Err:      err,
   946  				ExitCode: exitCode,
   947  			})
   948  			return reports, nil
   949  		} // end attach
   950  
   951  		// Start the container if it's not running already.
   952  		if !ctrRunning {
   953  			// Handle non-attach start
   954  			// If the container is in a pod, also set to recursively start dependencies
   955  			report := &entities.ContainerStartReport{
   956  				Id:       ctr.ID(),
   957  				RawInput: rawInput,
   958  				ExitCode: 125,
   959  			}
   960  			if err := ctr.Start(ctx, true); err != nil {
   961  				report.Err = err
   962  				if errors.Cause(err) == define.ErrWillDeadlock {
   963  					report.Err = errors.Wrapf(err, "please run 'podman system renumber' to resolve deadlocks")
   964  					reports = append(reports, report)
   965  					continue
   966  				}
   967  				report.Err = errors.Wrapf(err, "unable to start container %q", ctr.ID())
   968  				reports = append(reports, report)
   969  				if ctr.AutoRemove() {
   970  					if err := ic.removeContainer(ctx, ctr, entities.RmOptions{}); err != nil {
   971  						logrus.Errorf("Removing container %s: %v", ctr.ID(), err)
   972  					}
   973  				}
   974  				continue
   975  			}
   976  			report.ExitCode = 0
   977  			reports = append(reports, report)
   978  		}
   979  	}
   980  	return reports, nil
   981  }
   982  
   983  func (ic *ContainerEngine) ContainerList(ctx context.Context, options entities.ContainerListOptions) ([]entities.ListContainer, error) {
   984  	if options.Latest {
   985  		options.Last = 1
   986  	}
   987  	return ps.GetContainerLists(ic.Libpod, options)
   988  }
   989  
   990  func (ic *ContainerEngine) ContainerListExternal(ctx context.Context) ([]entities.ListContainer, error) {
   991  	return ps.GetExternalContainerLists(ic.Libpod)
   992  }
   993  
   994  // Diff provides changes to given container
   995  func (ic *ContainerEngine) Diff(ctx context.Context, namesOrIDs []string, opts entities.DiffOptions) (*entities.DiffReport, error) {
   996  	var (
   997  		base   string
   998  		parent string
   999  	)
  1000  	if opts.Latest {
  1001  		ctnr, err := ic.Libpod.GetLatestContainer()
  1002  		if err != nil {
  1003  			return nil, errors.Wrap(err, "unable to get latest container")
  1004  		}
  1005  		base = ctnr.ID()
  1006  	}
  1007  	if len(namesOrIDs) > 0 {
  1008  		base = namesOrIDs[0]
  1009  		if len(namesOrIDs) > 1 {
  1010  			parent = namesOrIDs[1]
  1011  		}
  1012  	}
  1013  	changes, err := ic.Libpod.GetDiff(parent, base, opts.Type)
  1014  	return &entities.DiffReport{Changes: changes}, err
  1015  }
  1016  
  1017  func (ic *ContainerEngine) ContainerRun(ctx context.Context, opts entities.ContainerRunOptions) (*entities.ContainerRunReport, error) {
  1018  	warn, err := generate.CompleteSpec(ctx, ic.Libpod, opts.Spec)
  1019  	if err != nil {
  1020  		return nil, err
  1021  	}
  1022  	// Print warnings
  1023  	for _, w := range warn {
  1024  		fmt.Fprintf(os.Stderr, "%s\n", w)
  1025  	}
  1026  
  1027  	rtSpec, spec, optsN, err := generate.MakeContainer(ctx, ic.Libpod, opts.Spec, false, nil)
  1028  	if err != nil {
  1029  		return nil, err
  1030  	}
  1031  	ctr, err := generate.ExecuteCreate(ctx, ic.Libpod, rtSpec, spec, false, optsN...)
  1032  	if err != nil {
  1033  		return nil, err
  1034  	}
  1035  
  1036  	if opts.CIDFile != "" {
  1037  		if err := util.CreateCidFile(opts.CIDFile, ctr.ID()); err != nil {
  1038  			return nil, err
  1039  		}
  1040  	}
  1041  
  1042  	report := entities.ContainerRunReport{Id: ctr.ID()}
  1043  
  1044  	if logrus.GetLevel() == logrus.DebugLevel {
  1045  		cgroupPath, err := ctr.CgroupPath()
  1046  		if err == nil {
  1047  			logrus.Debugf("container %q has CgroupParent %q", ctr.ID(), cgroupPath)
  1048  		}
  1049  	}
  1050  	if opts.Detach {
  1051  		// if the container was created as part of a pod, also start its dependencies, if any.
  1052  		if err := ctr.Start(ctx, true); err != nil {
  1053  			// This means the command did not exist
  1054  			report.ExitCode = define.ExitCode(err)
  1055  			return &report, err
  1056  		}
  1057  
  1058  		return &report, nil
  1059  	}
  1060  
  1061  	// if the container was created as part of a pod, also start its dependencies, if any.
  1062  	if err := terminal.StartAttachCtr(ctx, ctr, opts.OutputStream, opts.ErrorStream, opts.InputStream, opts.DetachKeys, opts.SigProxy, true); err != nil {
  1063  		// We've manually detached from the container
  1064  		// Do not perform cleanup, or wait for container exit code
  1065  		// Just exit immediately
  1066  		if errors.Cause(err) == define.ErrDetach {
  1067  			report.ExitCode = 0
  1068  			return &report, nil
  1069  		}
  1070  		if opts.Rm {
  1071  			var timeout *uint
  1072  			if deleteError := ic.Libpod.RemoveContainer(ctx, ctr, true, false, timeout); deleteError != nil {
  1073  				logrus.Debugf("unable to remove container %s after failing to start and attach to it", ctr.ID())
  1074  			}
  1075  		}
  1076  		if errors.Cause(err) == define.ErrWillDeadlock {
  1077  			logrus.Debugf("Deadlock error on %q: %v", ctr.ID(), err)
  1078  			report.ExitCode = define.ExitCode(err)
  1079  			return &report, errors.Errorf("attempting to start container %s would cause a deadlock; please run 'podman system renumber' to resolve", ctr.ID())
  1080  		}
  1081  		report.ExitCode = define.ExitCode(err)
  1082  		return &report, err
  1083  	}
  1084  	report.ExitCode = ic.GetContainerExitCode(ctx, ctr)
  1085  	if opts.Rm && !ctr.ShouldRestart(ctx) {
  1086  		var timeout *uint
  1087  		if err := ic.Libpod.RemoveContainer(ctx, ctr, false, true, timeout); err != nil {
  1088  			if errors.Cause(err) == define.ErrNoSuchCtr ||
  1089  				errors.Cause(err) == define.ErrCtrRemoved {
  1090  				logrus.Infof("Container %s was already removed, skipping --rm", ctr.ID())
  1091  			} else {
  1092  				logrus.Errorf("Removing container %s: %v", ctr.ID(), err)
  1093  			}
  1094  		}
  1095  	}
  1096  	return &report, nil
  1097  }
  1098  
  1099  func (ic *ContainerEngine) GetContainerExitCode(ctx context.Context, ctr *libpod.Container) int {
  1100  	exitCode, err := ctr.Wait(ctx)
  1101  	if err == nil {
  1102  		return int(exitCode)
  1103  	}
  1104  	if errors.Cause(err) != define.ErrNoSuchCtr {
  1105  		logrus.Errorf("Could not retrieve exit code: %v", err)
  1106  		return define.ExecErrorCodeNotFound
  1107  	}
  1108  	// Make 4 attempt with 0.25s backoff between each for 1 second total
  1109  	var event *events.Event
  1110  	for i := 0; i < 4; i++ {
  1111  		event, err = ic.Libpod.GetLastContainerEvent(ctx, ctr.ID(), events.Exited)
  1112  		if err != nil {
  1113  			time.Sleep(250 * time.Millisecond)
  1114  			continue
  1115  		}
  1116  		return event.ContainerExitCode
  1117  	}
  1118  	logrus.Errorf("Could not retrieve exit code from event: %v", err)
  1119  	return define.ExecErrorCodeNotFound
  1120  }
  1121  
  1122  func (ic *ContainerEngine) ContainerLogs(ctx context.Context, containers []string, options entities.ContainerLogsOptions) error {
  1123  	if options.StdoutWriter == nil && options.StderrWriter == nil {
  1124  		return errors.New("no io.Writer set for container logs")
  1125  	}
  1126  
  1127  	var wg sync.WaitGroup
  1128  
  1129  	ctrs, err := getContainersByContext(false, options.Latest, containers, ic.Libpod)
  1130  	if err != nil {
  1131  		return err
  1132  	}
  1133  
  1134  	logOpts := &logs.LogOptions{
  1135  		Multi:      len(ctrs) > 1,
  1136  		Details:    options.Details,
  1137  		Follow:     options.Follow,
  1138  		Since:      options.Since,
  1139  		Until:      options.Until,
  1140  		Tail:       options.Tail,
  1141  		Timestamps: options.Timestamps,
  1142  		Colors:     options.Colors,
  1143  		UseName:    options.Names,
  1144  		WaitGroup:  &wg,
  1145  	}
  1146  
  1147  	chSize := len(ctrs) * int(options.Tail)
  1148  	if chSize <= 0 {
  1149  		chSize = 1
  1150  	}
  1151  	logChannel := make(chan *logs.LogLine, chSize)
  1152  
  1153  	if err := ic.Libpod.Log(ctx, ctrs, logOpts, logChannel); err != nil {
  1154  		return err
  1155  	}
  1156  
  1157  	go func() {
  1158  		wg.Wait()
  1159  		close(logChannel)
  1160  	}()
  1161  
  1162  	for line := range logChannel {
  1163  		line.Write(options.StdoutWriter, options.StderrWriter, logOpts)
  1164  	}
  1165  
  1166  	return nil
  1167  }
  1168  
  1169  func (ic *ContainerEngine) ContainerCleanup(ctx context.Context, namesOrIds []string, options entities.ContainerCleanupOptions) ([]*entities.ContainerCleanupReport, error) {
  1170  	reports := []*entities.ContainerCleanupReport{}
  1171  	ctrs, err := getContainersByContext(options.All, options.Latest, namesOrIds, ic.Libpod)
  1172  	if err != nil {
  1173  		return nil, err
  1174  	}
  1175  	for _, ctr := range ctrs {
  1176  		var err error
  1177  		report := entities.ContainerCleanupReport{Id: ctr.ID()}
  1178  
  1179  		if options.Exec != "" {
  1180  			if options.Remove {
  1181  				if err := ctr.ExecRemove(options.Exec, false); err != nil {
  1182  					return nil, err
  1183  				}
  1184  			} else {
  1185  				if err := ctr.ExecCleanup(options.Exec); err != nil {
  1186  					return nil, err
  1187  				}
  1188  			}
  1189  			return []*entities.ContainerCleanupReport{}, nil
  1190  		}
  1191  
  1192  		if options.Remove && !ctr.ShouldRestart(ctx) {
  1193  			var timeout *uint
  1194  			err = ic.Libpod.RemoveContainer(ctx, ctr, false, true, timeout)
  1195  			if err != nil {
  1196  				report.RmErr = errors.Wrapf(err, "failed to cleanup and remove container %v", ctr.ID())
  1197  			}
  1198  		} else {
  1199  			err := ctr.Cleanup(ctx)
  1200  			if err != nil {
  1201  				report.CleanErr = errors.Wrapf(err, "failed to cleanup container %v", ctr.ID())
  1202  			}
  1203  		}
  1204  
  1205  		if options.RemoveImage {
  1206  			_, imageName := ctr.Image()
  1207  			imageEngine := ImageEngine{Libpod: ic.Libpod}
  1208  			_, rmErrors := imageEngine.Remove(ctx, []string{imageName}, entities.ImageRemoveOptions{})
  1209  			report.RmiErr = errorhandling.JoinErrors(rmErrors)
  1210  		}
  1211  
  1212  		reports = append(reports, &report)
  1213  	}
  1214  	return reports, nil
  1215  }
  1216  
  1217  func (ic *ContainerEngine) ContainerInit(ctx context.Context, namesOrIds []string, options entities.ContainerInitOptions) ([]*entities.ContainerInitReport, error) {
  1218  	ctrs, err := getContainersByContext(options.All, options.Latest, namesOrIds, ic.Libpod)
  1219  	if err != nil {
  1220  		return nil, err
  1221  	}
  1222  	reports := make([]*entities.ContainerInitReport, 0, len(ctrs))
  1223  	for _, ctr := range ctrs {
  1224  		report := entities.ContainerInitReport{Id: ctr.ID()}
  1225  		err := ctr.Init(ctx, ctr.PodID() != "")
  1226  
  1227  		// If we're initializing all containers, ignore invalid state errors
  1228  		if options.All && errors.Cause(err) == define.ErrCtrStateInvalid {
  1229  			err = nil
  1230  		}
  1231  		report.Err = err
  1232  		reports = append(reports, &report)
  1233  	}
  1234  	return reports, nil
  1235  }
  1236  
  1237  func (ic *ContainerEngine) ContainerMount(ctx context.Context, nameOrIDs []string, options entities.ContainerMountOptions) ([]*entities.ContainerMountReport, error) {
  1238  	if os.Geteuid() != 0 {
  1239  		if driver := ic.Libpod.StorageConfig().GraphDriverName; driver != "vfs" {
  1240  			// Do not allow to mount a graphdriver that is not vfs if we are creating the userns as part
  1241  			// of the mount command.
  1242  			return nil, fmt.Errorf("cannot mount using driver %s in rootless mode", driver)
  1243  		}
  1244  
  1245  		became, ret, err := rootless.BecomeRootInUserNS("")
  1246  		if err != nil {
  1247  			return nil, err
  1248  		}
  1249  		if became {
  1250  			os.Exit(ret)
  1251  		}
  1252  	}
  1253  	reports := []*entities.ContainerMountReport{}
  1254  	// Attempt to mount named containers directly from storage,
  1255  	// this will fail and code will fall through to removing the container from libpod.`
  1256  	names := []string{}
  1257  	for _, ctr := range nameOrIDs {
  1258  		report := entities.ContainerMountReport{Id: ctr}
  1259  		if report.Path, report.Err = ic.Libpod.MountStorageContainer(ctr); report.Err != nil {
  1260  			names = append(names, ctr)
  1261  		} else {
  1262  			reports = append(reports, &report)
  1263  		}
  1264  	}
  1265  
  1266  	ctrs, err := getContainersByContext(options.All, options.Latest, names, ic.Libpod)
  1267  	if err != nil {
  1268  		return nil, err
  1269  	}
  1270  	for _, ctr := range ctrs {
  1271  		report := entities.ContainerMountReport{Id: ctr.ID()}
  1272  		report.Path, report.Err = ctr.Mount()
  1273  		reports = append(reports, &report)
  1274  	}
  1275  	if len(reports) > 0 {
  1276  		return reports, nil
  1277  	}
  1278  
  1279  	storageCtrs, err := ic.Libpod.StorageContainers()
  1280  	if err != nil {
  1281  		return nil, err
  1282  	}
  1283  
  1284  	for _, sctr := range storageCtrs {
  1285  		mounted, path, err := ic.Libpod.IsStorageContainerMounted(sctr.ID)
  1286  		if err != nil {
  1287  			return nil, err
  1288  		}
  1289  
  1290  		var name string
  1291  		if len(sctr.Names) > 0 {
  1292  			name = sctr.Names[0]
  1293  		}
  1294  		if mounted {
  1295  			reports = append(reports, &entities.ContainerMountReport{
  1296  				Id:   sctr.ID,
  1297  				Name: name,
  1298  				Path: path,
  1299  			})
  1300  		}
  1301  	}
  1302  
  1303  	// No containers were passed, so we send back what is mounted
  1304  	ctrs, err = getContainersByContext(true, false, []string{}, ic.Libpod)
  1305  	if err != nil {
  1306  		return nil, err
  1307  	}
  1308  	for _, ctr := range ctrs {
  1309  		mounted, path, err := ctr.Mounted()
  1310  		if err != nil {
  1311  			return nil, err
  1312  		}
  1313  
  1314  		if mounted {
  1315  			reports = append(reports, &entities.ContainerMountReport{
  1316  				Id:   ctr.ID(),
  1317  				Name: ctr.Name(),
  1318  				Path: path,
  1319  			})
  1320  		}
  1321  	}
  1322  
  1323  	return reports, nil
  1324  }
  1325  
  1326  func (ic *ContainerEngine) ContainerUnmount(ctx context.Context, nameOrIDs []string, options entities.ContainerUnmountOptions) ([]*entities.ContainerUnmountReport, error) {
  1327  	reports := []*entities.ContainerUnmountReport{}
  1328  	names := []string{}
  1329  	if options.All {
  1330  		storageCtrs, err := ic.Libpod.StorageContainers()
  1331  		if err != nil {
  1332  			return nil, err
  1333  		}
  1334  		for _, sctr := range storageCtrs {
  1335  			mounted, _, _ := ic.Libpod.IsStorageContainerMounted(sctr.ID)
  1336  			if mounted {
  1337  				report := entities.ContainerUnmountReport{Id: sctr.ID}
  1338  				if _, report.Err = ic.Libpod.UnmountStorageContainer(sctr.ID, options.Force); report.Err != nil {
  1339  					if errors.Cause(report.Err) != define.ErrCtrExists {
  1340  						reports = append(reports, &report)
  1341  					}
  1342  				} else {
  1343  					reports = append(reports, &report)
  1344  				}
  1345  			}
  1346  		}
  1347  	}
  1348  	for _, ctr := range nameOrIDs {
  1349  		report := entities.ContainerUnmountReport{Id: ctr}
  1350  		if _, report.Err = ic.Libpod.UnmountStorageContainer(ctr, options.Force); report.Err != nil {
  1351  			names = append(names, ctr)
  1352  		} else {
  1353  			reports = append(reports, &report)
  1354  		}
  1355  	}
  1356  	ctrs, err := getContainersByContext(options.All, options.Latest, names, ic.Libpod)
  1357  	if err != nil {
  1358  		return nil, err
  1359  	}
  1360  	for _, ctr := range ctrs {
  1361  		state, err := ctr.State()
  1362  		if err != nil {
  1363  			logrus.Debugf("Error umounting container %s state: %s", ctr.ID(), err.Error())
  1364  			continue
  1365  		}
  1366  		if state == define.ContainerStateRunning {
  1367  			logrus.Debugf("Error umounting container %s, is running", ctr.ID())
  1368  			continue
  1369  		}
  1370  
  1371  		report := entities.ContainerUnmountReport{Id: ctr.ID()}
  1372  		if err := ctr.Unmount(options.Force); err != nil {
  1373  			if options.All && errors.Cause(err) == storage.ErrLayerNotMounted {
  1374  				logrus.Debugf("Error umounting container %s, storage.ErrLayerNotMounted", ctr.ID())
  1375  				continue
  1376  			}
  1377  			report.Err = errors.Wrapf(err, "error unmounting container %s", ctr.ID())
  1378  		}
  1379  		reports = append(reports, &report)
  1380  	}
  1381  	return reports, nil
  1382  }
  1383  
  1384  // GetConfig returns a copy of the configuration used by the runtime
  1385  func (ic *ContainerEngine) Config(_ context.Context) (*config.Config, error) {
  1386  	return ic.Libpod.GetConfig()
  1387  }
  1388  
  1389  func (ic *ContainerEngine) ContainerPort(ctx context.Context, nameOrID string, options entities.ContainerPortOptions) ([]*entities.ContainerPortReport, error) {
  1390  	ctrs, err := getContainersByContext(options.All, options.Latest, []string{nameOrID}, ic.Libpod)
  1391  	if err != nil {
  1392  		return nil, err
  1393  	}
  1394  	reports := []*entities.ContainerPortReport{}
  1395  	for _, con := range ctrs {
  1396  		state, err := con.State()
  1397  		if err != nil {
  1398  			return nil, err
  1399  		}
  1400  		if state != define.ContainerStateRunning {
  1401  			continue
  1402  		}
  1403  		portmappings, err := con.PortMappings()
  1404  		if err != nil {
  1405  			return nil, err
  1406  		}
  1407  		if len(portmappings) > 0 {
  1408  			reports = append(reports, &entities.ContainerPortReport{
  1409  				Id:    con.ID(),
  1410  				Ports: portmappings,
  1411  			})
  1412  		}
  1413  	}
  1414  	return reports, nil
  1415  }
  1416  
  1417  // Shutdown Libpod engine
  1418  func (ic *ContainerEngine) Shutdown(_ context.Context) {
  1419  	shutdownSync.Do(func() {
  1420  		_ = ic.Libpod.Shutdown(false)
  1421  	})
  1422  }
  1423  
  1424  func (ic *ContainerEngine) ContainerStats(ctx context.Context, namesOrIds []string, options entities.ContainerStatsOptions) (statsChan chan entities.ContainerStatsReport, err error) {
  1425  	if options.Interval < 1 {
  1426  		return nil, errors.New("Invalid interval, must be a positive number greater zero")
  1427  	}
  1428  	if rootless.IsRootless() {
  1429  		unified, err := cgroups.IsCgroup2UnifiedMode()
  1430  		if err != nil {
  1431  			return nil, err
  1432  		}
  1433  		if !unified {
  1434  			return nil, errors.New("stats is not supported in rootless mode without cgroups v2")
  1435  		}
  1436  	}
  1437  	statsChan = make(chan entities.ContainerStatsReport, 1)
  1438  
  1439  	containerFunc := ic.Libpod.GetRunningContainers
  1440  	queryAll := false
  1441  	switch {
  1442  	case options.Latest:
  1443  		containerFunc = func() ([]*libpod.Container, error) {
  1444  			lastCtr, err := ic.Libpod.GetLatestContainer()
  1445  			if err != nil {
  1446  				return nil, err
  1447  			}
  1448  			return []*libpod.Container{lastCtr}, nil
  1449  		}
  1450  	case len(namesOrIds) > 0:
  1451  		containerFunc = func() ([]*libpod.Container, error) { return ic.Libpod.GetContainersByList(namesOrIds) }
  1452  	default:
  1453  		// No containers, no latest -> query all!
  1454  		queryAll = true
  1455  		containerFunc = ic.Libpod.GetAllContainers
  1456  	}
  1457  
  1458  	go func() {
  1459  		defer close(statsChan)
  1460  		var (
  1461  			err            error
  1462  			containers     []*libpod.Container
  1463  			containerStats map[string]*define.ContainerStats
  1464  		)
  1465  		containerStats = make(map[string]*define.ContainerStats)
  1466  
  1467  	stream: // label to flatten the scope
  1468  		select {
  1469  		case <-ctx.Done():
  1470  			// client cancelled
  1471  			logrus.Debugf("Container stats stopped: context cancelled")
  1472  			return
  1473  		default:
  1474  			// just fall through and do work
  1475  		}
  1476  
  1477  		// Anonymous func to easily use the return values for streaming.
  1478  		computeStats := func() ([]define.ContainerStats, error) {
  1479  			containers, err = containerFunc()
  1480  			if err != nil {
  1481  				return nil, errors.Wrapf(err, "unable to get list of containers")
  1482  			}
  1483  
  1484  			reportStats := []define.ContainerStats{}
  1485  			for _, ctr := range containers {
  1486  				stats, err := ctr.GetContainerStats(containerStats[ctr.ID()])
  1487  				if err != nil {
  1488  					cause := errors.Cause(err)
  1489  					if queryAll && (cause == define.ErrCtrRemoved || cause == define.ErrNoSuchCtr || cause == define.ErrCtrStateInvalid) {
  1490  						continue
  1491  					}
  1492  					if cause == cgroups.ErrCgroupV1Rootless {
  1493  						err = cause
  1494  					}
  1495  					return nil, err
  1496  				}
  1497  
  1498  				containerStats[ctr.ID()] = stats
  1499  				reportStats = append(reportStats, *stats)
  1500  			}
  1501  			return reportStats, nil
  1502  		}
  1503  
  1504  		report := entities.ContainerStatsReport{}
  1505  		report.Stats, report.Error = computeStats()
  1506  		statsChan <- report
  1507  
  1508  		if report.Error != nil || !options.Stream {
  1509  			return
  1510  		}
  1511  
  1512  		time.Sleep(time.Second * time.Duration(options.Interval))
  1513  		goto stream
  1514  	}()
  1515  
  1516  	return statsChan, nil
  1517  }
  1518  
  1519  // ShouldRestart returns whether the container should be restarted
  1520  func (ic *ContainerEngine) ShouldRestart(ctx context.Context, nameOrID string) (*entities.BoolReport, error) {
  1521  	ctr, err := ic.Libpod.LookupContainer(nameOrID)
  1522  	if err != nil {
  1523  		return nil, err
  1524  	}
  1525  
  1526  	return &entities.BoolReport{Value: ctr.ShouldRestart(ctx)}, nil
  1527  }
  1528  
  1529  // ContainerRename renames the given container.
  1530  func (ic *ContainerEngine) ContainerRename(ctx context.Context, nameOrID string, opts entities.ContainerRenameOptions) error {
  1531  	ctr, err := ic.Libpod.LookupContainer(nameOrID)
  1532  	if err != nil {
  1533  		return err
  1534  	}
  1535  
  1536  	if _, err := ic.Libpod.RenameContainer(ctx, ctr, opts.NewName); err != nil {
  1537  		return err
  1538  	}
  1539  
  1540  	return nil
  1541  }
  1542  
  1543  func (ic *ContainerEngine) ContainerClone(ctx context.Context, ctrCloneOpts entities.ContainerCloneOptions) (*entities.ContainerCreateReport, error) {
  1544  	spec := specgen.NewSpecGenerator(ctrCloneOpts.Image, ctrCloneOpts.CreateOpts.RootFS)
  1545  	var c *libpod.Container
  1546  	c, _, err := generate.ConfigToSpec(ic.Libpod, spec, ctrCloneOpts.ID)
  1547  	if err != nil {
  1548  		return nil, err
  1549  	}
  1550  
  1551  	if ctrCloneOpts.CreateOpts.Pod != "" {
  1552  		pod, err := ic.Libpod.LookupPod(ctrCloneOpts.CreateOpts.Pod)
  1553  		if err != nil {
  1554  			return nil, err
  1555  		}
  1556  
  1557  		if len(spec.Networks) > 0 && pod.SharesNet() {
  1558  			logrus.Warning("resetting network config, cannot specify a network other than the pod's when sharing the net namespace")
  1559  			spec.Networks = nil
  1560  			spec.NetworkOptions = nil
  1561  		}
  1562  
  1563  		allNamespaces := []struct {
  1564  			isShared bool
  1565  			value    *specgen.Namespace
  1566  		}{
  1567  			{pod.SharesPID(), &spec.PidNS},
  1568  			{pod.SharesNet(), &spec.NetNS},
  1569  			{pod.SharesCgroup(), &spec.CgroupNS},
  1570  			{pod.SharesIPC(), &spec.IpcNS},
  1571  			{pod.SharesUTS(), &spec.UtsNS},
  1572  		}
  1573  
  1574  		printWarning := false
  1575  		for _, n := range allNamespaces {
  1576  			if n.isShared && !n.value.IsDefault() {
  1577  				*n.value = specgen.Namespace{NSMode: specgen.Default}
  1578  				printWarning = true
  1579  			}
  1580  		}
  1581  		if printWarning {
  1582  			logrus.Warning("At least one namespace was reset to the default configuration")
  1583  		}
  1584  	}
  1585  
  1586  	err = specgenutil.FillOutSpecGen(spec, &ctrCloneOpts.CreateOpts, []string{})
  1587  	if err != nil {
  1588  		return nil, err
  1589  	}
  1590  	out, err := generate.CompleteSpec(ctx, ic.Libpod, spec)
  1591  	if err != nil {
  1592  		return nil, err
  1593  	}
  1594  
  1595  	// Print warnings
  1596  	if len(out) > 0 {
  1597  		for _, w := range out {
  1598  			fmt.Println("Could not properly complete the spec as expected:")
  1599  			fmt.Fprintf(os.Stderr, "%s\n", w)
  1600  		}
  1601  	}
  1602  
  1603  	if len(ctrCloneOpts.CreateOpts.Name) > 0 {
  1604  		spec.Name = ctrCloneOpts.CreateOpts.Name
  1605  	} else {
  1606  		n := c.Name()
  1607  		_, err := ic.Libpod.LookupContainer(c.Name() + "-clone")
  1608  		if err == nil {
  1609  			n += "-clone"
  1610  		}
  1611  		switch {
  1612  		case strings.Contains(n, "-clone"):
  1613  			ind := strings.Index(n, "-clone") + 6
  1614  			num, _ := strconv.Atoi(n[ind:])
  1615  			if num == 0 { // clone1 is hard to get with this logic, just check for it here.
  1616  				_, err = ic.Libpod.LookupContainer(n + "1")
  1617  				if err != nil {
  1618  					spec.Name = n + "1"
  1619  					break
  1620  				}
  1621  			} else {
  1622  				n = n[0:ind]
  1623  			}
  1624  			err = nil
  1625  			count := num
  1626  			for err == nil {
  1627  				count++
  1628  				tempN := n + strconv.Itoa(count)
  1629  				_, err = ic.Libpod.LookupContainer(tempN)
  1630  			}
  1631  			n += strconv.Itoa(count)
  1632  			spec.Name = n
  1633  		default:
  1634  			spec.Name = c.Name() + "-clone"
  1635  		}
  1636  	}
  1637  
  1638  	rtSpec, spec, opts, err := generate.MakeContainer(context.Background(), ic.Libpod, spec, true, c)
  1639  	if err != nil {
  1640  		return nil, err
  1641  	}
  1642  	ctr, err := generate.ExecuteCreate(ctx, ic.Libpod, rtSpec, spec, false, opts...)
  1643  	if err != nil {
  1644  		return nil, err
  1645  	}
  1646  
  1647  	if ctrCloneOpts.Destroy {
  1648  		var time *uint
  1649  		err = ic.Libpod.RemoveContainer(context.Background(), c, ctrCloneOpts.Force, false, time)
  1650  		if err != nil {
  1651  			return nil, err
  1652  		}
  1653  	}
  1654  
  1655  	if ctrCloneOpts.Run {
  1656  		if err := ctr.Start(ctx, true); err != nil {
  1657  			return nil, err
  1658  		}
  1659  	}
  1660  
  1661  	return &entities.ContainerCreateReport{Id: ctr.ID()}, nil
  1662  }