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 }