github.com/containers/podman/v4@v4.9.4/libpod/container_api.go (about)

     1  //go:build !remote
     2  // +build !remote
     3  
     4  package libpod
     5  
     6  import (
     7  	"context"
     8  	"errors"
     9  	"fmt"
    10  	"io"
    11  	"net/http"
    12  	"os"
    13  	"sync"
    14  	"time"
    15  
    16  	"github.com/containers/common/pkg/resize"
    17  	"github.com/containers/podman/v4/libpod/define"
    18  	"github.com/containers/podman/v4/libpod/events"
    19  	"github.com/containers/podman/v4/pkg/signal"
    20  	"github.com/containers/storage/pkg/archive"
    21  	spec "github.com/opencontainers/runtime-spec/specs-go"
    22  	"github.com/sirupsen/logrus"
    23  	"golang.org/x/sys/unix"
    24  )
    25  
    26  // Init creates a container in the OCI runtime, moving a container from
    27  // ContainerStateConfigured, ContainerStateStopped, or ContainerStateExited to
    28  // ContainerStateCreated. Once in Created state, Conmon will be running, which
    29  // allows the container to be attached to. The container can subsequently
    30  // transition to ContainerStateRunning via Start(), or be transitioned back to
    31  // ContainerStateConfigured by Cleanup() (which will stop conmon and unmount the
    32  // container).
    33  // Init requires that all dependency containers be started (e.g. pod infra
    34  // containers). The `recursive` parameter will, if set to true, start these
    35  // dependency containers before initializing this container.
    36  func (c *Container) Init(ctx context.Context, recursive bool) error {
    37  	if !c.batched {
    38  		c.lock.Lock()
    39  		defer c.lock.Unlock()
    40  
    41  		if err := c.syncContainer(); err != nil {
    42  			return err
    43  		}
    44  	}
    45  
    46  	if !c.ensureState(define.ContainerStateConfigured, define.ContainerStateStopped, define.ContainerStateExited) {
    47  		return fmt.Errorf("container %s has already been created in runtime: %w", c.ID(), define.ErrCtrStateInvalid)
    48  	}
    49  
    50  	if !recursive {
    51  		if err := c.checkDependenciesAndHandleError(); err != nil {
    52  			return err
    53  		}
    54  	} else {
    55  		if err := c.startDependencies(ctx); err != nil {
    56  			return err
    57  		}
    58  	}
    59  
    60  	if err := c.prepare(); err != nil {
    61  		if err2 := c.cleanup(ctx); err2 != nil {
    62  			logrus.Errorf("Cleaning up container %s: %v", c.ID(), err2)
    63  		}
    64  		return err
    65  	}
    66  
    67  	if c.state.State == define.ContainerStateStopped {
    68  		// Reinitialize the container
    69  		return c.reinit(ctx, false)
    70  	}
    71  
    72  	// Initialize the container for the first time
    73  	return c.init(ctx, false)
    74  }
    75  
    76  // Start starts the given container.
    77  // Start will accept container in ContainerStateConfigured,
    78  // ContainerStateCreated, ContainerStateStopped, and ContainerStateExited, and
    79  // transition them to ContainerStateRunning (all containers not in
    80  // ContainerStateCreated will make an intermediate stop there via the Init API).
    81  // Once in ContainerStateRunning, the container can be transitioned to
    82  // ContainerStatePaused via Pause(), or to ContainerStateStopped by the process
    83  // stopping (either due to exit, or being forced to stop by the Kill or Stop API
    84  // calls).
    85  // Start requires that all dependency containers (e.g. pod infra containers) are
    86  // running before starting the container. The recursive parameter, if set, will start all
    87  // dependencies before starting this container.
    88  func (c *Container) Start(ctx context.Context, recursive bool) (finalErr error) {
    89  	defer func() {
    90  		if finalErr != nil {
    91  			// Have to re-lock.
    92  			// As this is the first defer, it's the last thing to
    93  			// happen in the function - so `defer c.lock.Unlock()`
    94  			// below already fired.
    95  			if !c.batched {
    96  				c.lock.Lock()
    97  				defer c.lock.Unlock()
    98  			}
    99  
   100  			if err := saveContainerError(c, finalErr); err != nil {
   101  				logrus.Debug(err)
   102  			}
   103  		}
   104  	}()
   105  
   106  	if !c.batched {
   107  		c.lock.Lock()
   108  		defer c.lock.Unlock()
   109  
   110  		if err := c.syncContainer(); err != nil {
   111  			return err
   112  		}
   113  	}
   114  	if err := c.prepareToStart(ctx, recursive); err != nil {
   115  		return err
   116  	}
   117  
   118  	// Start the container
   119  	return c.start(ctx)
   120  }
   121  
   122  // Update updates the given container.
   123  // only the cgroup config can be updated and therefore only a linux resource spec is passed.
   124  func (c *Container) Update(res *spec.LinuxResources) error {
   125  	if err := c.syncContainer(); err != nil {
   126  		return err
   127  	}
   128  	return c.update(res)
   129  }
   130  
   131  // StartAndAttach starts a container and attaches to it.
   132  // This acts as a combination of the Start and Attach APIs, ensuring proper
   133  // ordering of the two such that no output from the container is lost (e.g. the
   134  // Attach call occurs before Start).
   135  // In overall functionality, it is identical to the Start call, with the added
   136  // side effect that an attach session will also be started.
   137  func (c *Container) StartAndAttach(ctx context.Context, streams *define.AttachStreams, keys string, resize <-chan resize.TerminalSize, recursive bool) (retChan <-chan error, finalErr error) {
   138  	defer func() {
   139  		if finalErr != nil {
   140  			// Have to re-lock.
   141  			// As this is the first defer, it's the last thing to
   142  			// happen in the function - so `defer c.lock.Unlock()`
   143  			// below already fired.
   144  			if !c.batched {
   145  				c.lock.Lock()
   146  				defer c.lock.Unlock()
   147  			}
   148  
   149  			if err := saveContainerError(c, finalErr); err != nil {
   150  				logrus.Debug(err)
   151  			}
   152  		}
   153  	}()
   154  
   155  	if !c.batched {
   156  		c.lock.Lock()
   157  		defer c.lock.Unlock()
   158  
   159  		if err := c.syncContainer(); err != nil {
   160  			return nil, err
   161  		}
   162  	}
   163  
   164  	if err := c.prepareToStart(ctx, recursive); err != nil {
   165  		return nil, err
   166  	}
   167  	attachChan := make(chan error)
   168  
   169  	// We need to ensure that we don't return until start() fired in attach.
   170  	// Use a channel to sync
   171  	startedChan := make(chan bool)
   172  
   173  	// Attach to the container before starting it
   174  	go func() {
   175  		// Start resizing
   176  		if c.LogDriver() != define.PassthroughLogging {
   177  			registerResizeFunc(resize, c.bundlePath())
   178  		}
   179  
   180  		opts := new(AttachOptions)
   181  		opts.Streams = streams
   182  		opts.DetachKeys = &keys
   183  		opts.Start = true
   184  		opts.Started = startedChan
   185  
   186  		if err := c.ociRuntime.Attach(c, opts); err != nil {
   187  			attachChan <- err
   188  		}
   189  		close(attachChan)
   190  	}()
   191  
   192  	select {
   193  	case err := <-attachChan:
   194  		return nil, err
   195  	case <-startedChan:
   196  		c.newContainerEvent(events.Attach)
   197  	}
   198  
   199  	return attachChan, nil
   200  }
   201  
   202  // RestartWithTimeout restarts a running container and takes a given timeout in uint
   203  func (c *Container) RestartWithTimeout(ctx context.Context, timeout uint) error {
   204  	if !c.batched {
   205  		c.lock.Lock()
   206  		defer c.lock.Unlock()
   207  
   208  		if err := c.syncContainer(); err != nil {
   209  			return err
   210  		}
   211  	}
   212  
   213  	if err := c.checkDependenciesAndHandleError(); err != nil {
   214  		return err
   215  	}
   216  
   217  	return c.restartWithTimeout(ctx, timeout)
   218  }
   219  
   220  // Stop uses the container's stop signal (or SIGTERM if no signal was specified)
   221  // to stop the container, and if it has not stopped after container's stop
   222  // timeout, SIGKILL is used to attempt to forcibly stop the container
   223  // Default stop timeout is 10 seconds, but can be overridden when the container
   224  // is created
   225  func (c *Container) Stop() error {
   226  	// Stop with the container's given timeout
   227  	return c.StopWithTimeout(c.config.StopTimeout)
   228  }
   229  
   230  // StopWithTimeout is a version of Stop that allows a timeout to be specified
   231  // manually. If timeout is 0, SIGKILL will be used immediately to kill the
   232  // container.
   233  func (c *Container) StopWithTimeout(timeout uint) (finalErr error) {
   234  	defer func() {
   235  		if finalErr != nil {
   236  			// Have to re-lock.
   237  			// As this is the first defer, it's the last thing to
   238  			// happen in the function - so `defer c.lock.Unlock()`
   239  			// below already fired.
   240  			if !c.batched {
   241  				c.lock.Lock()
   242  				defer c.lock.Unlock()
   243  			}
   244  
   245  			if err := saveContainerError(c, finalErr); err != nil {
   246  				logrus.Debug(err)
   247  			}
   248  		}
   249  	}()
   250  
   251  	if !c.batched {
   252  		c.lock.Lock()
   253  		defer c.lock.Unlock()
   254  
   255  		if err := c.syncContainer(); err != nil {
   256  			return err
   257  		}
   258  	}
   259  
   260  	return c.stop(timeout)
   261  }
   262  
   263  // Kill sends a signal to a container
   264  func (c *Container) Kill(signal uint) error {
   265  	if !c.batched {
   266  		c.lock.Lock()
   267  		defer c.lock.Unlock()
   268  
   269  		if err := c.syncContainer(); err != nil {
   270  			return err
   271  		}
   272  	}
   273  
   274  	switch c.state.State {
   275  	case define.ContainerStateRunning, define.ContainerStateStopping, define.ContainerStatePaused:
   276  		// Note that killing containers in "stopping" state is okay.
   277  		// In that state, the Podman is waiting for the runtime to
   278  		// stop the container and if that is taking too long, a user
   279  		// may have decided to kill the container after all.
   280  	default:
   281  		return fmt.Errorf("can only kill running containers. %s is in state %s: %w", c.ID(), c.state.State.String(), define.ErrCtrStateInvalid)
   282  	}
   283  
   284  	// Hardcode all = false, we only use all when removing.
   285  	if err := c.ociRuntime.KillContainer(c, signal, false); err != nil {
   286  		return err
   287  	}
   288  
   289  	c.state.StoppedByUser = true
   290  
   291  	c.newContainerEvent(events.Kill)
   292  
   293  	// Make sure to wait for the container to exit in case of SIGKILL.
   294  	if signal == uint(unix.SIGKILL) {
   295  		return c.waitForConmonToExitAndSave()
   296  	}
   297  
   298  	return c.save()
   299  }
   300  
   301  // Attach attaches to a container.
   302  // This function returns when the attach finishes. It does not hold the lock for
   303  // the duration of its runtime, only using it at the beginning to verify state.
   304  func (c *Container) Attach(streams *define.AttachStreams, keys string, resize <-chan resize.TerminalSize) error {
   305  	if c.LogDriver() == define.PassthroughLogging {
   306  		return fmt.Errorf("this container is using the 'passthrough' log driver, cannot attach: %w", define.ErrNoLogs)
   307  	}
   308  	if !c.batched {
   309  		c.lock.Lock()
   310  		if err := c.syncContainer(); err != nil {
   311  			c.lock.Unlock()
   312  			return err
   313  		}
   314  		// We are NOT holding the lock for the duration of the function.
   315  		c.lock.Unlock()
   316  	}
   317  
   318  	if !c.ensureState(define.ContainerStateCreated, define.ContainerStateRunning) {
   319  		return fmt.Errorf("can only attach to created or running containers: %w", define.ErrCtrStateInvalid)
   320  	}
   321  
   322  	// HACK: This is really gross, but there isn't a better way without
   323  	// splitting attach into separate versions for StartAndAttach and normal
   324  	// attaching, and I really do not want to do that right now.
   325  	// Send a SIGWINCH after attach succeeds so that most programs will
   326  	// redraw the screen for the new attach session.
   327  	attachRdy := make(chan bool, 1)
   328  	if c.Terminal() {
   329  		go func() {
   330  			<-attachRdy
   331  			c.lock.Lock()
   332  			defer c.lock.Unlock()
   333  			if err := c.ociRuntime.KillContainer(c, uint(signal.SIGWINCH), false); err != nil {
   334  				logrus.Warnf("Unable to send SIGWINCH to container %s after attach: %v", c.ID(), err)
   335  			}
   336  		}()
   337  	}
   338  
   339  	// Start resizing
   340  	if c.LogDriver() != define.PassthroughLogging {
   341  		registerResizeFunc(resize, c.bundlePath())
   342  	}
   343  
   344  	opts := new(AttachOptions)
   345  	opts.Streams = streams
   346  	opts.DetachKeys = &keys
   347  	opts.AttachReady = attachRdy
   348  
   349  	c.newContainerEvent(events.Attach)
   350  	return c.ociRuntime.Attach(c, opts)
   351  }
   352  
   353  // HTTPAttach forwards an attach session over a hijacked HTTP session.
   354  // HTTPAttach will consume and close the included httpCon, which is expected to
   355  // be sourced from a hijacked HTTP connection.
   356  // The cancel channel is optional, and can be used to asynchronously cancel the
   357  // attach session.
   358  // The streams variable is only supported if the container was not a terminal,
   359  // and allows specifying which of the container's standard streams will be
   360  // forwarded to the client.
   361  // This function returns when the attach finishes. It does not hold the lock for
   362  // the duration of its runtime, only using it at the beginning to verify state.
   363  // The streamLogs parameter indicates that all the container's logs until present
   364  // will be streamed at the beginning of the attach.
   365  // The streamAttach parameter indicates that the attach itself will be streamed
   366  // over the socket; if this is not set, but streamLogs is, only the logs will be
   367  // sent.
   368  // At least one of streamAttach and streamLogs must be set.
   369  func (c *Container) HTTPAttach(r *http.Request, w http.ResponseWriter, streams *HTTPAttachStreams, detachKeys *string, cancel <-chan bool, streamAttach, streamLogs bool, hijackDone chan<- bool) error {
   370  	// Ensure we don't leak a goroutine if we exit before hijack completes.
   371  	defer func() {
   372  		close(hijackDone)
   373  	}()
   374  
   375  	if !c.batched {
   376  		c.lock.Lock()
   377  		if err := c.syncContainer(); err != nil {
   378  			c.lock.Unlock()
   379  
   380  			return err
   381  		}
   382  		// We are NOT holding the lock for the duration of the function.
   383  		c.lock.Unlock()
   384  	}
   385  
   386  	if !c.ensureState(define.ContainerStateCreated, define.ContainerStateRunning) {
   387  		return fmt.Errorf("can only attach to created or running containers: %w", define.ErrCtrStateInvalid)
   388  	}
   389  
   390  	if !streamAttach && !streamLogs {
   391  		return fmt.Errorf("must specify at least one of stream or logs: %w", define.ErrInvalidArg)
   392  	}
   393  
   394  	logrus.Infof("Performing HTTP Hijack attach to container %s", c.ID())
   395  
   396  	c.newContainerEvent(events.Attach)
   397  	return c.ociRuntime.HTTPAttach(c, r, w, streams, detachKeys, cancel, hijackDone, streamAttach, streamLogs)
   398  }
   399  
   400  // AttachResize resizes the container's terminal, which is displayed by Attach
   401  // and HTTPAttach.
   402  func (c *Container) AttachResize(newSize resize.TerminalSize) error {
   403  	if !c.batched {
   404  		c.lock.Lock()
   405  		defer c.lock.Unlock()
   406  
   407  		if err := c.syncContainer(); err != nil {
   408  			return err
   409  		}
   410  	}
   411  
   412  	if !c.ensureState(define.ContainerStateCreated, define.ContainerStateRunning) {
   413  		return fmt.Errorf("can only resize created or running containers: %w", define.ErrCtrStateInvalid)
   414  	}
   415  
   416  	logrus.Infof("Resizing TTY of container %s", c.ID())
   417  
   418  	return c.ociRuntime.AttachResize(c, newSize)
   419  }
   420  
   421  // Mount mounts a container's filesystem on the host
   422  // The path where the container has been mounted is returned
   423  func (c *Container) Mount() (string, error) {
   424  	if !c.batched {
   425  		c.lock.Lock()
   426  		defer c.lock.Unlock()
   427  
   428  		if err := c.syncContainer(); err != nil {
   429  			return "", err
   430  		}
   431  	}
   432  
   433  	defer c.newContainerEvent(events.Mount)
   434  	return c.mount()
   435  }
   436  
   437  // Unmount unmounts a container's filesystem on the host
   438  func (c *Container) Unmount(force bool) error {
   439  	if !c.batched {
   440  		c.lock.Lock()
   441  		defer c.lock.Unlock()
   442  
   443  		if err := c.syncContainer(); err != nil {
   444  			return err
   445  		}
   446  	}
   447  	if c.state.Mounted {
   448  		mounted, err := c.runtime.storageService.MountedContainerImage(c.ID())
   449  		if err != nil {
   450  			return fmt.Errorf("can't determine how many times %s is mounted, refusing to unmount: %w", c.ID(), err)
   451  		}
   452  		if mounted == 1 {
   453  			if c.ensureState(define.ContainerStateRunning, define.ContainerStatePaused) {
   454  				return fmt.Errorf("cannot unmount storage for container %s as it is running or paused: %w", c.ID(), define.ErrCtrStateInvalid)
   455  			}
   456  			execSessions, err := c.getActiveExecSessions()
   457  			if err != nil {
   458  				return err
   459  			}
   460  			if len(execSessions) != 0 {
   461  				return fmt.Errorf("container %s has active exec sessions, refusing to unmount: %w", c.ID(), define.ErrCtrStateInvalid)
   462  			}
   463  			return fmt.Errorf("can't unmount %s last mount, it is still in use: %w", c.ID(), define.ErrInternal)
   464  		}
   465  	}
   466  	defer c.newContainerEvent(events.Unmount)
   467  	return c.unmount(force)
   468  }
   469  
   470  // Pause pauses a container
   471  func (c *Container) Pause() error {
   472  	if !c.batched {
   473  		c.lock.Lock()
   474  		defer c.lock.Unlock()
   475  
   476  		if err := c.syncContainer(); err != nil {
   477  			return err
   478  		}
   479  	}
   480  
   481  	if c.state.State == define.ContainerStatePaused {
   482  		return fmt.Errorf("%q is already paused: %w", c.ID(), define.ErrCtrStateInvalid)
   483  	}
   484  	if c.state.State != define.ContainerStateRunning {
   485  		return fmt.Errorf("%q is not running, can't pause: %w", c.state.State, define.ErrCtrStateInvalid)
   486  	}
   487  	defer c.newContainerEvent(events.Pause)
   488  	return c.pause()
   489  }
   490  
   491  // Unpause unpauses a container
   492  func (c *Container) Unpause() error {
   493  	if !c.batched {
   494  		c.lock.Lock()
   495  		defer c.lock.Unlock()
   496  
   497  		if err := c.syncContainer(); err != nil {
   498  			return err
   499  		}
   500  	}
   501  
   502  	if c.state.State != define.ContainerStatePaused {
   503  		return fmt.Errorf("%q is not paused, can't unpause: %w", c.ID(), define.ErrCtrStateInvalid)
   504  	}
   505  	defer c.newContainerEvent(events.Unpause)
   506  	return c.unpause()
   507  }
   508  
   509  // Export exports a container's root filesystem as a tar archive
   510  // The archive will be saved as a file at the given path
   511  func (c *Container) Export(out io.Writer) error {
   512  	if !c.batched {
   513  		c.lock.Lock()
   514  		defer c.lock.Unlock()
   515  
   516  		if err := c.syncContainer(); err != nil {
   517  			return err
   518  		}
   519  	}
   520  
   521  	if c.state.State == define.ContainerStateRemoving {
   522  		return fmt.Errorf("cannot mount container %s as it is being removed: %w", c.ID(), define.ErrCtrStateInvalid)
   523  	}
   524  
   525  	defer c.newContainerEvent(events.Mount)
   526  	return c.export(out)
   527  }
   528  
   529  // AddArtifact creates and writes to an artifact file for the container
   530  func (c *Container) AddArtifact(name string, data []byte) error {
   531  	if !c.valid {
   532  		return define.ErrCtrRemoved
   533  	}
   534  
   535  	return os.WriteFile(c.getArtifactPath(name), data, 0o740)
   536  }
   537  
   538  // GetArtifact reads the specified artifact file from the container
   539  func (c *Container) GetArtifact(name string) ([]byte, error) {
   540  	if !c.valid {
   541  		return nil, define.ErrCtrRemoved
   542  	}
   543  
   544  	return os.ReadFile(c.getArtifactPath(name))
   545  }
   546  
   547  // RemoveArtifact deletes the specified artifacts file
   548  func (c *Container) RemoveArtifact(name string) error {
   549  	if !c.valid {
   550  		return define.ErrCtrRemoved
   551  	}
   552  
   553  	return os.Remove(c.getArtifactPath(name))
   554  }
   555  
   556  // Wait blocks until the container exits and returns its exit code.
   557  func (c *Container) Wait(ctx context.Context) (int32, error) {
   558  	return c.WaitForExit(ctx, DefaultWaitInterval)
   559  }
   560  
   561  // WaitForExit blocks until the container exits and returns its exit code. The
   562  // argument is the interval at which checks the container's status.
   563  func (c *Container) WaitForExit(ctx context.Context, pollInterval time.Duration) (int32, error) {
   564  	if !c.valid {
   565  		return -1, define.ErrCtrRemoved
   566  	}
   567  
   568  	id := c.ID()
   569  	var conmonTimer time.Timer
   570  	conmonTimerSet := false
   571  
   572  	conmonPidFd := c.getConmonPidFd()
   573  	if conmonPidFd != -1 {
   574  		defer unix.Close(conmonPidFd)
   575  	}
   576  	conmonPidFdTriggered := false
   577  
   578  	getExitCode := func() (bool, int32, error) {
   579  		containerRemoved := false
   580  		if !c.batched {
   581  			c.lock.Lock()
   582  			defer c.lock.Unlock()
   583  		}
   584  
   585  		if err := c.syncContainer(); err != nil {
   586  			if !errors.Is(err, define.ErrNoSuchCtr) {
   587  				return false, -1, err
   588  			}
   589  			containerRemoved = true
   590  		}
   591  
   592  		// If conmon is not alive anymore set a timer to make sure
   593  		// we're returning even if conmon has forcefully been killed.
   594  		if !conmonTimerSet && !containerRemoved {
   595  			conmonAlive, err := c.ociRuntime.CheckConmonRunning(c)
   596  			switch {
   597  			case errors.Is(err, define.ErrNoSuchCtr):
   598  				// Container has been removed, so we assume the
   599  				// exit code is present in the DB.
   600  				containerRemoved = true
   601  			case err != nil:
   602  				return false, -1, err
   603  			case !conmonAlive:
   604  				// Give the exit code at most 20 seconds to
   605  				// show up in the DB.  That should largely be
   606  				// enough for the cleanup process.
   607  				timerDuration := time.Second * 20
   608  				conmonTimer = *time.NewTimer(timerDuration)
   609  				conmonTimerSet = true
   610  			case conmonAlive:
   611  				// Continue waiting if conmon's still running.
   612  				return false, -1, nil
   613  			}
   614  		}
   615  
   616  		timedout := ""
   617  		if !containerRemoved {
   618  			// If conmon is dead for more than $timerDuration or if the
   619  			// container has exited properly, try to look up the exit code.
   620  			select {
   621  			case <-conmonTimer.C:
   622  				logrus.Debugf("Exceeded conmon timeout waiting for container %s to exit", id)
   623  				timedout = " [exceeded conmon timeout waiting for container to exit]"
   624  			default:
   625  				switch c.state.State {
   626  				case define.ContainerStateExited, define.ContainerStateConfigured:
   627  					// Container exited, so we can look up the exit code.
   628  				case define.ContainerStateStopped:
   629  					// Continue looping unless the restart policy is always.
   630  					// In this case, the container would never transition to
   631  					// the exited state, so we need to look up the exit code.
   632  					if c.config.RestartPolicy != define.RestartPolicyAlways {
   633  						return false, -1, nil
   634  					}
   635  				default:
   636  					// Continue looping
   637  					return false, -1, nil
   638  				}
   639  			}
   640  		}
   641  
   642  		exitCode, err := c.runtime.state.GetContainerExitCode(id)
   643  		if err != nil {
   644  			if errors.Is(err, define.ErrNoSuchExitCode) {
   645  				// If the container is configured or created, we must assume it never ran.
   646  				if c.ensureState(define.ContainerStateConfigured, define.ContainerStateCreated) {
   647  					return true, 0, nil
   648  				}
   649  			}
   650  			return true, -1, fmt.Errorf("%w (container in state %s)%s", err, c.state.State, timedout)
   651  		}
   652  
   653  		return true, exitCode, nil
   654  	}
   655  
   656  	for {
   657  		hasExited, exitCode, err := getExitCode()
   658  		if hasExited {
   659  			return exitCode, err
   660  		}
   661  		if err != nil {
   662  			return -1, err
   663  		}
   664  		select {
   665  		case <-ctx.Done():
   666  			return -1, fmt.Errorf("waiting for exit code of container %s canceled", id)
   667  		default:
   668  			if conmonPidFd != -1 && !conmonPidFdTriggered {
   669  				// If possible (pidfd works), the first cycle we block until conmon dies
   670  				// If this happens, and we fall back to the old poll delay
   671  				// There is a deadlock in the cleanup code for "play kube" which causes
   672  				// conmon to not exit, so unfortunately we have to use the poll interval
   673  				// timeout here to avoid hanging.
   674  				fds := []unix.PollFd{{Fd: int32(conmonPidFd), Events: unix.POLLIN}}
   675  				_, _ = unix.Poll(fds, int(pollInterval.Milliseconds()))
   676  				conmonPidFdTriggered = true
   677  			} else {
   678  				time.Sleep(pollInterval)
   679  			}
   680  		}
   681  	}
   682  }
   683  
   684  type waitResult struct {
   685  	code int32
   686  	err  error
   687  }
   688  
   689  func (c *Container) WaitForConditionWithInterval(ctx context.Context, waitTimeout time.Duration, conditions ...string) (int32, error) {
   690  	if !c.valid {
   691  		return -1, define.ErrCtrRemoved
   692  	}
   693  
   694  	if len(conditions) == 0 {
   695  		panic("at least one condition should be passed")
   696  	}
   697  
   698  	ctx, cancelFn := context.WithCancel(ctx)
   699  	defer cancelFn()
   700  
   701  	resultChan := make(chan waitResult)
   702  	waitForExit := false
   703  	wantedStates := make(map[define.ContainerStatus]bool, len(conditions))
   704  	wantedHealthStates := make(map[string]bool)
   705  
   706  	for _, rawCondition := range conditions {
   707  		switch rawCondition {
   708  		case define.HealthCheckHealthy, define.HealthCheckUnhealthy:
   709  			if !c.HasHealthCheck() {
   710  				return -1, fmt.Errorf("cannot use condition %q: container %s has no healthcheck", rawCondition, c.ID())
   711  			}
   712  			wantedHealthStates[rawCondition] = true
   713  		default:
   714  			condition, err := define.StringToContainerStatus(rawCondition)
   715  			if err != nil {
   716  				return -1, err
   717  			}
   718  			switch condition {
   719  			case define.ContainerStateExited, define.ContainerStateStopped:
   720  				waitForExit = true
   721  			default:
   722  				wantedStates[condition] = true
   723  			}
   724  		}
   725  	}
   726  
   727  	trySend := func(code int32, err error) {
   728  		select {
   729  		case resultChan <- waitResult{code, err}:
   730  		case <-ctx.Done():
   731  		}
   732  	}
   733  
   734  	var wg sync.WaitGroup
   735  
   736  	if waitForExit {
   737  		wg.Add(1)
   738  		go func() {
   739  			defer wg.Done()
   740  
   741  			code, err := c.WaitForExit(ctx, waitTimeout)
   742  			trySend(code, err)
   743  		}()
   744  	}
   745  
   746  	if len(wantedStates) > 0 || len(wantedHealthStates) > 0 {
   747  		wg.Add(1)
   748  		go func() {
   749  			defer wg.Done()
   750  
   751  			for {
   752  				if len(wantedStates) > 0 {
   753  					state, err := c.State()
   754  					if err != nil {
   755  						trySend(-1, err)
   756  						return
   757  					}
   758  					if _, found := wantedStates[state]; found {
   759  						trySend(-1, nil)
   760  						return
   761  					}
   762  				}
   763  				if len(wantedHealthStates) > 0 {
   764  					status, err := c.HealthCheckStatus()
   765  					if err != nil {
   766  						trySend(-1, err)
   767  						return
   768  					}
   769  					if _, found := wantedHealthStates[status]; found {
   770  						trySend(-1, nil)
   771  						return
   772  					}
   773  				}
   774  				select {
   775  				case <-ctx.Done():
   776  					return
   777  				case <-time.After(waitTimeout):
   778  					continue
   779  				}
   780  			}
   781  		}()
   782  	}
   783  
   784  	var result waitResult
   785  	select {
   786  	case result = <-resultChan:
   787  		cancelFn()
   788  	case <-ctx.Done():
   789  		result = waitResult{-1, define.ErrCanceled}
   790  	}
   791  	wg.Wait()
   792  	return result.code, result.err
   793  }
   794  
   795  // Cleanup unmounts all mount points in container and cleans up container storage
   796  // It also cleans up the network stack
   797  func (c *Container) Cleanup(ctx context.Context) error {
   798  	if !c.batched {
   799  		c.lock.Lock()
   800  		defer c.lock.Unlock()
   801  
   802  		if err := c.syncContainer(); err != nil {
   803  			// When the container has already been removed, the OCI runtime directory remains.
   804  			if errors.Is(err, define.ErrNoSuchCtr) || errors.Is(err, define.ErrCtrRemoved) {
   805  				if err := c.cleanupRuntime(ctx); err != nil {
   806  					return fmt.Errorf("cleaning up container %s from OCI runtime: %w", c.ID(), err)
   807  				}
   808  				return nil
   809  			}
   810  			logrus.Errorf("Syncing container %s status: %v", c.ID(), err)
   811  			return err
   812  		}
   813  	}
   814  
   815  	// Check if state is good
   816  	if !c.ensureState(define.ContainerStateConfigured, define.ContainerStateCreated, define.ContainerStateStopped, define.ContainerStateStopping, define.ContainerStateExited) {
   817  		return fmt.Errorf("container %s is running or paused, refusing to clean up: %w", c.ID(), define.ErrCtrStateInvalid)
   818  	}
   819  
   820  	// if the container was not created in the oci runtime or was already cleaned up, then do nothing
   821  	if c.ensureState(define.ContainerStateConfigured, define.ContainerStateExited) {
   822  		return nil
   823  	}
   824  
   825  	// Handle restart policy.
   826  	// Returns a bool indicating whether we actually restarted.
   827  	// If we did, don't proceed to cleanup - just exit.
   828  	didRestart, err := c.handleRestartPolicy(ctx)
   829  	if err != nil {
   830  		return err
   831  	}
   832  	if didRestart {
   833  		return nil
   834  	}
   835  
   836  	// If we didn't restart, we perform a normal cleanup
   837  
   838  	// make sure all the container processes are terminated if we are running without a pid namespace.
   839  	hasPidNs := false
   840  	if c.config.Spec.Linux != nil {
   841  		for _, i := range c.config.Spec.Linux.Namespaces {
   842  			if i.Type == spec.PIDNamespace {
   843  				hasPidNs = true
   844  				break
   845  			}
   846  		}
   847  	}
   848  	if !hasPidNs {
   849  		// do not fail on errors
   850  		_ = c.ociRuntime.KillContainer(c, uint(unix.SIGKILL), true)
   851  	}
   852  
   853  	// Check for running exec sessions
   854  	sessions, err := c.getActiveExecSessions()
   855  	if err != nil {
   856  		return err
   857  	}
   858  	if len(sessions) > 0 {
   859  		return fmt.Errorf("container %s has active exec sessions, refusing to clean up: %w", c.ID(), define.ErrCtrStateInvalid)
   860  	}
   861  
   862  	defer c.newContainerEvent(events.Cleanup)
   863  	return c.cleanup(ctx)
   864  }
   865  
   866  // Batch starts a batch operation on the given container
   867  // All commands in the passed function will execute under the same lock and
   868  // without synchronizing state after each operation
   869  // This will result in substantial performance benefits when running numerous
   870  // commands on the same container
   871  // Note that the container passed into the Batch function cannot be removed
   872  // during batched operations. runtime.RemoveContainer can only be called outside
   873  // of Batch
   874  // Any error returned by the given batch function will be returned unmodified by
   875  // Batch
   876  // As Batch normally disables updating the current state of the container, the
   877  // Sync() function is provided to enable container state to be updated and
   878  // checked within Batch.
   879  func (c *Container) Batch(batchFunc func(*Container) error) error {
   880  	c.lock.Lock()
   881  	defer c.lock.Unlock()
   882  
   883  	newCtr := new(Container)
   884  	newCtr.config = c.config
   885  	newCtr.state = c.state
   886  	newCtr.runtime = c.runtime
   887  	newCtr.ociRuntime = c.ociRuntime
   888  	newCtr.lock = c.lock
   889  	newCtr.valid = true
   890  
   891  	newCtr.batched = true
   892  	err := batchFunc(newCtr)
   893  	newCtr.batched = false
   894  
   895  	return err
   896  }
   897  
   898  // Sync updates the status of a container by querying the OCI runtime.
   899  // If the container has not been created inside the OCI runtime, nothing will be
   900  // done.
   901  // Most of the time, Podman does not explicitly query the OCI runtime for
   902  // container status, and instead relies upon exit files created by conmon.
   903  // This can cause a disconnect between running state and what Podman sees in
   904  // cases where Conmon was killed unexpectedly, or runc was upgraded.
   905  // Running a manual Sync() ensures that container state will be correct in
   906  // such situations.
   907  func (c *Container) Sync() error {
   908  	if !c.batched {
   909  		c.lock.Lock()
   910  		defer c.lock.Unlock()
   911  	}
   912  
   913  	if err := c.syncContainer(); err != nil {
   914  		return err
   915  	}
   916  
   917  	defer c.newContainerEvent(events.Sync)
   918  	return nil
   919  }
   920  
   921  // ReloadNetwork reconfigures the container's network.
   922  // Technically speaking, it will tear down and then reconfigure the container's
   923  // network namespace, which will result in all firewall rules being recreated.
   924  // It is mostly intended to be used in cases where the system firewall has been
   925  // reloaded, and existing rules have been wiped out. It is expected that some
   926  // downtime will result, as the rules are destroyed as part of this process.
   927  // At present, this only works on root containers; it may be expanded to restart
   928  // slirp4netns in the future to work with rootless containers as well.
   929  // Requires that the container must be running or created.
   930  func (c *Container) ReloadNetwork() error {
   931  	if !c.batched {
   932  		c.lock.Lock()
   933  		defer c.lock.Unlock()
   934  
   935  		if err := c.syncContainer(); err != nil {
   936  			return err
   937  		}
   938  	}
   939  
   940  	if !c.ensureState(define.ContainerStateCreated, define.ContainerStateRunning) {
   941  		return fmt.Errorf("cannot reload network unless container network has been configured: %w", define.ErrCtrStateInvalid)
   942  	}
   943  
   944  	return c.reloadNetwork()
   945  }
   946  
   947  // Refresh is DEPRECATED and REMOVED.
   948  func (c *Container) Refresh(ctx context.Context) error {
   949  	// This has been deprecated for a long while, and is in the process of
   950  	// being removed.
   951  	return define.ErrNotImplemented
   952  }
   953  
   954  // ContainerCheckpointOptions is a struct used to pass the parameters
   955  // for checkpointing (and restoring) to the corresponding functions
   956  type ContainerCheckpointOptions struct {
   957  	// Keep tells the API to not delete checkpoint artifacts
   958  	Keep bool
   959  	// KeepRunning tells the API to keep the container running
   960  	// after writing the checkpoint to disk
   961  	KeepRunning bool
   962  	// TCPEstablished tells the API to checkpoint a container
   963  	// even if it contains established TCP connections
   964  	TCPEstablished bool
   965  	// TargetFile tells the API to read (or write) the checkpoint image
   966  	// from (or to) the filename set in TargetFile
   967  	TargetFile string
   968  	// CheckpointImageID tells the API to restore the container from
   969  	// checkpoint image with ID set in CheckpointImageID
   970  	CheckpointImageID string
   971  	// Name tells the API that during restore from an exported
   972  	// checkpoint archive a new name should be used for the
   973  	// restored container
   974  	Name string
   975  	// IgnoreRootfs tells the API to not export changes to
   976  	// the container's root file-system (or to not import)
   977  	IgnoreRootfs bool
   978  	// IgnoreStaticIP tells the API to ignore the IP set
   979  	// during 'podman run' with '--ip'. This is especially
   980  	// important to be able to restore a container multiple
   981  	// times with '--import --name'.
   982  	IgnoreStaticIP bool
   983  	// IgnoreStaticMAC tells the API to ignore the MAC set
   984  	// during 'podman run' with '--mac-address'. This is especially
   985  	// important to be able to restore a container multiple
   986  	// times with '--import --name'.
   987  	IgnoreStaticMAC bool
   988  	// IgnoreVolumes tells the API to not export or not to import
   989  	// the content of volumes associated with the container
   990  	IgnoreVolumes bool
   991  	// Pre Checkpoint container and leave container running
   992  	PreCheckPoint bool
   993  	// Dump container with Pre Checkpoint images
   994  	WithPrevious bool
   995  	// ImportPrevious tells the API to restore container with two
   996  	// images. One is TargetFile, the other is ImportPrevious.
   997  	ImportPrevious string
   998  	// CreateImage tells Podman to create an OCI image from container
   999  	// checkpoint in the local image store.
  1000  	CreateImage string
  1001  	// Compression tells the API which compression to use for
  1002  	// the exported checkpoint archive.
  1003  	Compression archive.Compression
  1004  	// If Pod is set the container should be restored into the
  1005  	// given Pod. If Pod is empty it is a restore without a Pod.
  1006  	// Restoring a non Pod container into a Pod or a Pod container
  1007  	// without a Pod is theoretically possible, but will
  1008  	// probably not work if a PID namespace is shared.
  1009  	// A shared PID namespace means that a Pod container has PID 1
  1010  	// in the infrastructure container, but without the infrastructure
  1011  	// container no PID 1 will be in the namespace and that is not
  1012  	// possible.
  1013  	Pod string
  1014  	// PrintStats tells the API to fill out the statistics about
  1015  	// how much time each component in the stack requires to
  1016  	// checkpoint a container.
  1017  	PrintStats bool
  1018  	// FileLocks tells the API to checkpoint/restore a container
  1019  	// with file-locks
  1020  	FileLocks bool
  1021  }
  1022  
  1023  // Checkpoint checkpoints a container
  1024  // The return values *define.CRIUCheckpointRestoreStatistics and int64 (time
  1025  // the runtime needs to checkpoint the container) are only set if
  1026  // options.PrintStats is set to true. Not setting options.PrintStats to true
  1027  // will return nil and 0.
  1028  func (c *Container) Checkpoint(ctx context.Context, options ContainerCheckpointOptions) (*define.CRIUCheckpointRestoreStatistics, int64, error) {
  1029  	logrus.Debugf("Trying to checkpoint container %s", c.ID())
  1030  
  1031  	if options.TargetFile != "" {
  1032  		if err := c.prepareCheckpointExport(); err != nil {
  1033  			return nil, 0, err
  1034  		}
  1035  	}
  1036  
  1037  	if options.WithPrevious {
  1038  		if err := c.canWithPrevious(); err != nil {
  1039  			return nil, 0, err
  1040  		}
  1041  	}
  1042  
  1043  	if !c.batched {
  1044  		c.lock.Lock()
  1045  		defer c.lock.Unlock()
  1046  
  1047  		if err := c.syncContainer(); err != nil {
  1048  			return nil, 0, err
  1049  		}
  1050  	}
  1051  	return c.checkpoint(ctx, options)
  1052  }
  1053  
  1054  // Restore restores a container
  1055  // The return values *define.CRIUCheckpointRestoreStatistics and int64 (time
  1056  // the runtime needs to restore the container) are only set if
  1057  // options.PrintStats is set to true. Not setting options.PrintStats to true
  1058  // will return nil and 0.
  1059  func (c *Container) Restore(ctx context.Context, options ContainerCheckpointOptions) (*define.CRIUCheckpointRestoreStatistics, int64, error) {
  1060  	if options.Pod == "" {
  1061  		logrus.Debugf("Trying to restore container %s", c.ID())
  1062  	} else {
  1063  		logrus.Debugf("Trying to restore container %s into pod %s", c.ID(), options.Pod)
  1064  	}
  1065  	if !c.batched {
  1066  		c.lock.Lock()
  1067  		defer c.lock.Unlock()
  1068  
  1069  		if err := c.syncContainer(); err != nil {
  1070  			return nil, 0, err
  1071  		}
  1072  	}
  1073  	defer c.newContainerEvent(events.Restore)
  1074  	return c.restore(ctx, options)
  1075  }
  1076  
  1077  // Indicate whether or not the container should restart
  1078  func (c *Container) ShouldRestart(ctx context.Context) bool {
  1079  	logrus.Debugf("Checking if container %s should restart", c.ID())
  1080  	if !c.batched {
  1081  		c.lock.Lock()
  1082  		defer c.lock.Unlock()
  1083  
  1084  		if err := c.syncContainer(); err != nil {
  1085  			return false
  1086  		}
  1087  	}
  1088  	return c.shouldRestart()
  1089  }
  1090  
  1091  // CopyFromArchive copies the contents from the specified tarStream to path
  1092  // *inside* the container.
  1093  func (c *Container) CopyFromArchive(_ context.Context, containerPath string, chown, noOverwriteDirNonDir bool, rename map[string]string, tarStream io.Reader) (func() error, error) {
  1094  	if !c.batched {
  1095  		c.lock.Lock()
  1096  		defer c.lock.Unlock()
  1097  
  1098  		if err := c.syncContainer(); err != nil {
  1099  			return nil, err
  1100  		}
  1101  	}
  1102  
  1103  	return c.copyFromArchive(containerPath, chown, noOverwriteDirNonDir, rename, tarStream)
  1104  }
  1105  
  1106  // CopyToArchive copies the contents from the specified path *inside* the
  1107  // container to the tarStream.
  1108  func (c *Container) CopyToArchive(ctx context.Context, containerPath string, tarStream io.Writer) (func() error, error) {
  1109  	if !c.batched {
  1110  		c.lock.Lock()
  1111  		defer c.lock.Unlock()
  1112  
  1113  		if err := c.syncContainer(); err != nil {
  1114  			return nil, err
  1115  		}
  1116  	}
  1117  
  1118  	return c.copyToArchive(containerPath, tarStream)
  1119  }
  1120  
  1121  // Stat the specified path *inside* the container and return a file info.
  1122  func (c *Container) Stat(ctx context.Context, containerPath string) (*define.FileInfo, error) {
  1123  	if !c.batched {
  1124  		c.lock.Lock()
  1125  		defer c.lock.Unlock()
  1126  
  1127  		if err := c.syncContainer(); err != nil {
  1128  			return nil, err
  1129  		}
  1130  	}
  1131  
  1132  	var mountPoint string
  1133  	var err error
  1134  	if c.state.Mounted {
  1135  		mountPoint = c.state.Mountpoint
  1136  	} else {
  1137  		mountPoint, err = c.mount()
  1138  		if err != nil {
  1139  			return nil, err
  1140  		}
  1141  		defer func() {
  1142  			if err := c.unmount(false); err != nil {
  1143  				logrus.Errorf("Unmounting container %s: %v", c.ID(), err)
  1144  			}
  1145  		}()
  1146  	}
  1147  
  1148  	info, _, _, err := c.stat(mountPoint, containerPath)
  1149  	return info, err
  1150  }
  1151  
  1152  func saveContainerError(c *Container, err error) error {
  1153  	c.state.Error = err.Error()
  1154  	return c.save()
  1155  }