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

     1  //go:build !remote
     2  // +build !remote
     3  
     4  package libpod
     5  
     6  import (
     7  	"fmt"
     8  	"net/http"
     9  	"path/filepath"
    10  	"sync"
    11  
    12  	"github.com/containers/common/pkg/resize"
    13  	"github.com/containers/podman/v4/libpod/define"
    14  	spec "github.com/opencontainers/runtime-spec/specs-go"
    15  	"github.com/sirupsen/logrus"
    16  )
    17  
    18  var (
    19  	// Only create each missing runtime once.
    20  	// Creation makes error messages we don't want to duplicate.
    21  	missingRuntimes map[string]*MissingRuntime
    22  	// We need a lock for this
    23  	missingRuntimesLock sync.Mutex
    24  )
    25  
    26  // MissingRuntime is used when the OCI runtime requested by the container is
    27  // missing (not installed or not in the configuration file).
    28  type MissingRuntime struct {
    29  	// Name is the name of the missing runtime. Will be used in errors.
    30  	name string
    31  	// exitsDir is the directory for exit files.
    32  	exitsDir string
    33  }
    34  
    35  // Get a new MissingRuntime for the given name.
    36  // Requires a libpod Runtime so we can make a sane path for the exits dir.
    37  func getMissingRuntime(name string, r *Runtime) OCIRuntime {
    38  	missingRuntimesLock.Lock()
    39  	defer missingRuntimesLock.Unlock()
    40  
    41  	if missingRuntimes == nil {
    42  		missingRuntimes = make(map[string]*MissingRuntime)
    43  	}
    44  
    45  	runtime, ok := missingRuntimes[name]
    46  	if ok {
    47  		return runtime
    48  	}
    49  
    50  	// Once for each missing runtime, we want to error.
    51  	logrus.Errorf("OCI Runtime %s is in use by a container, but is not available (not in configuration file or not installed)", name)
    52  
    53  	newRuntime := new(MissingRuntime)
    54  	newRuntime.name = name
    55  	newRuntime.exitsDir = filepath.Join(r.config.Engine.TmpDir, "exits")
    56  
    57  	missingRuntimes[name] = newRuntime
    58  
    59  	return newRuntime
    60  }
    61  
    62  // Name is the name of the missing runtime
    63  func (r *MissingRuntime) Name() string {
    64  	return fmt.Sprintf("%s (missing/not available)", r.name)
    65  }
    66  
    67  // Path is not available as the runtime is missing
    68  func (r *MissingRuntime) Path() string {
    69  	return "(missing/not available)"
    70  }
    71  
    72  // CreateContainer is not available as the runtime is missing
    73  func (r *MissingRuntime) CreateContainer(ctr *Container, restoreOptions *ContainerCheckpointOptions) (int64, error) {
    74  	return 0, r.printError()
    75  }
    76  
    77  // UpdateContainerStatus is not available as the runtime is missing
    78  func (r *MissingRuntime) UpdateContainerStatus(ctr *Container) error {
    79  	return r.printError()
    80  }
    81  
    82  // StartContainer is not available as the runtime is missing
    83  func (r *MissingRuntime) StartContainer(ctr *Container) error {
    84  	return r.printError()
    85  }
    86  
    87  // UpdateContainer is not available as the runtime is missing
    88  func (r *MissingRuntime) UpdateContainer(ctr *Container, resources *spec.LinuxResources) error {
    89  	return r.printError()
    90  }
    91  
    92  // KillContainer is not available as the runtime is missing
    93  // TODO: We could attempt to unix.Kill() the PID as recorded in the state if we
    94  // really want to smooth things out? Won't be perfect, but if the container has
    95  // a PID namespace it could be enough?
    96  func (r *MissingRuntime) KillContainer(ctr *Container, signal uint, all bool) error {
    97  	return r.printError()
    98  }
    99  
   100  // StopContainer is not available as the runtime is missing
   101  func (r *MissingRuntime) StopContainer(ctr *Container, timeout uint, all bool) error {
   102  	return r.printError()
   103  }
   104  
   105  // DeleteContainer is not available as the runtime is missing
   106  func (r *MissingRuntime) DeleteContainer(ctr *Container) error {
   107  	return r.printError()
   108  }
   109  
   110  // PauseContainer is not available as the runtime is missing
   111  func (r *MissingRuntime) PauseContainer(ctr *Container) error {
   112  	return r.printError()
   113  }
   114  
   115  // UnpauseContainer is not available as the runtime is missing
   116  func (r *MissingRuntime) UnpauseContainer(ctr *Container) error {
   117  	return r.printError()
   118  }
   119  
   120  // Attach is not available as the runtime is missing
   121  func (r *MissingRuntime) Attach(ctr *Container, params *AttachOptions) error {
   122  	return r.printError()
   123  }
   124  
   125  // HTTPAttach is not available as the runtime is missing
   126  func (r *MissingRuntime) HTTPAttach(ctr *Container, req *http.Request, w http.ResponseWriter, streams *HTTPAttachStreams, detachKeys *string, cancel <-chan bool, hijackDone chan<- bool, streamAttach, streamLogs bool) error {
   127  	return r.printError()
   128  }
   129  
   130  // AttachResize is not available as the runtime is missing
   131  func (r *MissingRuntime) AttachResize(ctr *Container, newSize resize.TerminalSize) error {
   132  	return r.printError()
   133  }
   134  
   135  // ExecContainer is not available as the runtime is missing
   136  func (r *MissingRuntime) ExecContainer(ctr *Container, sessionID string, options *ExecOptions, streams *define.AttachStreams, newSize *resize.TerminalSize) (int, chan error, error) {
   137  	return -1, nil, r.printError()
   138  }
   139  
   140  // ExecContainerHTTP is not available as the runtime is missing
   141  func (r *MissingRuntime) ExecContainerHTTP(ctr *Container, sessionID string, options *ExecOptions, req *http.Request, w http.ResponseWriter,
   142  	streams *HTTPAttachStreams, cancel <-chan bool, hijackDone chan<- bool, holdConnOpen <-chan bool, newSize *resize.TerminalSize) (int, chan error, error) {
   143  	return -1, nil, r.printError()
   144  }
   145  
   146  // ExecContainerDetached is not available as the runtime is missing
   147  func (r *MissingRuntime) ExecContainerDetached(ctr *Container, sessionID string, options *ExecOptions, stdin bool) (int, error) {
   148  	return -1, r.printError()
   149  }
   150  
   151  // ExecAttachResize is not available as the runtime is missing.
   152  func (r *MissingRuntime) ExecAttachResize(ctr *Container, sessionID string, newSize resize.TerminalSize) error {
   153  	return r.printError()
   154  }
   155  
   156  // ExecStopContainer is not available as the runtime is missing.
   157  // TODO: We can also investigate using unix.Kill() on the PID of the exec
   158  // session here if we want to make stopping containers possible. Won't be
   159  // perfect, though.
   160  func (r *MissingRuntime) ExecStopContainer(ctr *Container, sessionID string, timeout uint) error {
   161  	return r.printError()
   162  }
   163  
   164  // ExecUpdateStatus is not available as the runtime is missing.
   165  func (r *MissingRuntime) ExecUpdateStatus(ctr *Container, sessionID string) (bool, error) {
   166  	return false, r.printError()
   167  }
   168  
   169  // CheckpointContainer is not available as the runtime is missing
   170  func (r *MissingRuntime) CheckpointContainer(ctr *Container, options ContainerCheckpointOptions) (int64, error) {
   171  	return 0, r.printError()
   172  }
   173  
   174  // CheckConmonRunning is not available as the runtime is missing
   175  func (r *MissingRuntime) CheckConmonRunning(ctr *Container) (bool, error) {
   176  	return false, r.printError()
   177  }
   178  
   179  // SupportsCheckpoint returns false as checkpointing requires a working runtime
   180  func (r *MissingRuntime) SupportsCheckpoint() bool {
   181  	return false
   182  }
   183  
   184  // SupportsJSONErrors returns false as there is no runtime to give errors
   185  func (r *MissingRuntime) SupportsJSONErrors() bool {
   186  	return false
   187  }
   188  
   189  // SupportsNoCgroups returns false as there is no runtime to create containers
   190  func (r *MissingRuntime) SupportsNoCgroups() bool {
   191  	return false
   192  }
   193  
   194  // SupportsKVM checks if the OCI runtime supports running containers
   195  // without KVM separation
   196  func (r *MissingRuntime) SupportsKVM() bool {
   197  	return false
   198  }
   199  
   200  // AttachSocketPath does not work as there is no runtime to attach to.
   201  // (Theoretically we could follow ExitFilePath but there is no guarantee the
   202  // container is running and thus has an attach socket...)
   203  func (r *MissingRuntime) AttachSocketPath(ctr *Container) (string, error) {
   204  	return "", r.printError()
   205  }
   206  
   207  // ExecAttachSocketPath does not work as there is no runtime to attach to.
   208  // (Again, we could follow ExitFilePath, but no guarantee there is an existing
   209  // and running exec session)
   210  func (r *MissingRuntime) ExecAttachSocketPath(ctr *Container, sessionID string) (string, error) {
   211  	return "", r.printError()
   212  }
   213  
   214  // ExitFilePath returns the exit file path for containers.
   215  // Here, we mimic what ConmonOCIRuntime does, because there is a chance that the
   216  // container in question is still running happily (config file modified to
   217  // remove a runtime, for example). We can't find the runtime to do anything to
   218  // the container, but Conmon should still place an exit file for it.
   219  func (r *MissingRuntime) ExitFilePath(ctr *Container) (string, error) {
   220  	if ctr == nil {
   221  		return "", fmt.Errorf("must provide a valid container to get exit file path: %w", define.ErrInvalidArg)
   222  	}
   223  	return filepath.Join(r.exitsDir, ctr.ID()), nil
   224  }
   225  
   226  // RuntimeInfo returns information on the missing runtime
   227  func (r *MissingRuntime) RuntimeInfo() (*define.ConmonInfo, *define.OCIRuntimeInfo, error) {
   228  	ocirt := define.OCIRuntimeInfo{
   229  		Name:    r.name,
   230  		Path:    "missing",
   231  		Package: "missing",
   232  		Version: "missing",
   233  	}
   234  	return nil, &ocirt, nil
   235  }
   236  
   237  // Return an error indicating the runtime is missing
   238  func (r *MissingRuntime) printError() error {
   239  	return fmt.Errorf("runtime %s is missing: %w", r.name, define.ErrOCIRuntimeNotFound)
   240  }