mirror of
https://github.com/containers/podman.git
synced 2025-05-17 23:26:08 +08:00

Closes: https://github.com/containers/podman/issues/22825 Signed-off-by: Giuseppe Scrivano <gscrivan@redhat.com>
296 lines
8.2 KiB
Go
296 lines
8.2 KiB
Go
//go:build !remote
|
|
|
|
package libpod
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
|
|
"github.com/containers/common/libimage"
|
|
"github.com/containers/common/libnetwork/types"
|
|
blobinfocache "github.com/containers/image/v5/pkg/blobinfocache"
|
|
"github.com/containers/podman/v5/libpod/define"
|
|
"github.com/containers/podman/v5/pkg/errorhandling"
|
|
"github.com/containers/podman/v5/pkg/util"
|
|
"github.com/containers/storage"
|
|
"github.com/containers/storage/pkg/lockfile"
|
|
stypes "github.com/containers/storage/types"
|
|
"github.com/sirupsen/logrus"
|
|
)
|
|
|
|
// removeAllDirs removes all Podman storage directories. It is intended to be
|
|
// used as a backup for reset() when that function cannot be used due to
|
|
// failures in initializing libpod.
|
|
// It does not expect that all the directories match what is in use by Podman,
|
|
// as this is a common failure point for `system reset`. As such, our ability to
|
|
// interface with containers and pods is somewhat limited.
|
|
// This function assumes that we do not have a working c/storage store.
|
|
func (r *Runtime) removeAllDirs() error {
|
|
var lastErr error
|
|
|
|
// Grab the runtime alive lock.
|
|
// This ensures that no other Podman process can run while we are doing
|
|
// a reset, so no race conditions with containers/pods/etc being created
|
|
// while we are resetting storage.
|
|
// TODO: maybe want a helper for getting the path? This is duped from
|
|
// runtime.go
|
|
runtimeAliveLock := filepath.Join(r.config.Engine.TmpDir, "alive.lck")
|
|
aliveLock, err := lockfile.GetLockFile(runtimeAliveLock)
|
|
if err != nil {
|
|
logrus.Errorf("Lock runtime alive lock %s: %v", runtimeAliveLock, err)
|
|
} else {
|
|
aliveLock.Lock()
|
|
defer aliveLock.Unlock()
|
|
}
|
|
|
|
// We do not have a store - so we can't really try and remove containers
|
|
// or pods or volumes...
|
|
// Try and remove the directories, in hopes that they are unmounted.
|
|
// This is likely to fail but it's the best we can do.
|
|
|
|
// Volume path
|
|
if err := os.RemoveAll(r.config.Engine.VolumePath); err != nil {
|
|
lastErr = fmt.Errorf("removing volume path: %w", err)
|
|
}
|
|
|
|
// Tmpdir
|
|
if err := os.RemoveAll(r.config.Engine.TmpDir); err != nil {
|
|
if lastErr != nil {
|
|
logrus.Errorf("Reset: %v", lastErr)
|
|
}
|
|
lastErr = fmt.Errorf("removing tmp dir: %w", err)
|
|
}
|
|
|
|
// Runroot
|
|
if err := os.RemoveAll(r.storageConfig.RunRoot); err != nil {
|
|
if lastErr != nil {
|
|
logrus.Errorf("Reset: %v", lastErr)
|
|
}
|
|
lastErr = fmt.Errorf("removing run root: %w", err)
|
|
}
|
|
|
|
// Static dir
|
|
if err := os.RemoveAll(r.config.Engine.StaticDir); err != nil {
|
|
if lastErr != nil {
|
|
logrus.Errorf("Reset: %v", lastErr)
|
|
}
|
|
lastErr = fmt.Errorf("removing static dir: %w", err)
|
|
}
|
|
|
|
// Graph root
|
|
if err := os.RemoveAll(r.storageConfig.GraphRoot); err != nil {
|
|
if lastErr != nil {
|
|
logrus.Errorf("Reset: %v", lastErr)
|
|
}
|
|
lastErr = fmt.Errorf("removing graph root: %w", err)
|
|
}
|
|
|
|
return lastErr
|
|
}
|
|
|
|
// Reset removes all Libpod files.
|
|
// All containers, images, volumes, pods, and networks will be removed.
|
|
// Calls Shutdown(), rendering the runtime unusable after this is run.
|
|
func (r *Runtime) Reset(ctx context.Context) error {
|
|
// Acquire the alive lock and hold it.
|
|
// Ensures that we don't let other Podman commands run while we are
|
|
// removing everything.
|
|
aliveLock, err := r.getRuntimeAliveLock()
|
|
if err != nil {
|
|
return fmt.Errorf("retrieving alive lock: %w", err)
|
|
}
|
|
aliveLock.Lock()
|
|
defer aliveLock.Unlock()
|
|
|
|
if !r.valid {
|
|
return define.ErrRuntimeStopped
|
|
}
|
|
|
|
var timeout uint = 0
|
|
pods, err := r.GetAllPods()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
for _, p := range pods {
|
|
if ctrs, err := r.RemovePod(ctx, p, true, true, &timeout); err != nil {
|
|
if errors.Is(err, define.ErrNoSuchPod) {
|
|
continue
|
|
}
|
|
for ctr, err := range ctrs {
|
|
if err != nil {
|
|
logrus.Errorf("Error removing pod %s container %s: %v", p.ID(), ctr, err)
|
|
}
|
|
}
|
|
logrus.Errorf("Removing Pod %s: %v", p.ID(), err)
|
|
}
|
|
}
|
|
|
|
ctrs, err := r.GetAllContainers()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
for _, c := range ctrs {
|
|
if ctrs, _, err := r.RemoveContainerAndDependencies(ctx, c, true, true, &timeout); err != nil {
|
|
for ctr, err := range ctrs {
|
|
logrus.Errorf("Error removing container %s: %v", ctr, err)
|
|
}
|
|
|
|
if errors.Is(err, define.ErrNoSuchCtr) || errors.Is(err, define.ErrCtrRemoved) {
|
|
continue
|
|
}
|
|
|
|
logrus.Errorf("Removing container %s: %v", c.ID(), err)
|
|
|
|
// There's no point trying a storage container removal
|
|
// here. High likelihood it doesn't work
|
|
// (RemoveStorageContainer will refuse to remove if a
|
|
// container exists in the Libpod database) and, even if
|
|
// it would, we'll get the container later on during
|
|
// image removal.
|
|
}
|
|
}
|
|
|
|
if err := r.stopPauseProcess(); err != nil {
|
|
logrus.Errorf("Stopping pause process: %v", err)
|
|
}
|
|
|
|
// Volumes before images, as volumes can mount images.
|
|
volumes, err := r.state.AllVolumes()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
for _, v := range volumes {
|
|
if err := r.RemoveVolume(ctx, v, true, &timeout); err != nil {
|
|
if errors.Is(err, define.ErrNoSuchVolume) {
|
|
continue
|
|
}
|
|
logrus.Errorf("Removing volume %s: %v", v.config.Name, err)
|
|
}
|
|
}
|
|
|
|
// Set force and ignore.
|
|
// Ignore shouldn't be necessary, but it seems safer. We want everything
|
|
// gone anyways...
|
|
rmiOptions := &libimage.RemoveImagesOptions{
|
|
Force: true,
|
|
Ignore: true,
|
|
RemoveContainerFunc: r.RemoveContainersForImageCallback(ctx),
|
|
Filters: []string{"readonly=false"},
|
|
}
|
|
if _, rmiErrors := r.LibimageRuntime().RemoveImages(ctx, nil, rmiOptions); rmiErrors != nil {
|
|
return errorhandling.JoinErrors(rmiErrors)
|
|
}
|
|
|
|
// remove all networks
|
|
nets, err := r.network.NetworkList()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
for _, net := range nets {
|
|
// do not delete the default network
|
|
if net.Name == r.network.DefaultNetworkName() {
|
|
continue
|
|
}
|
|
// ignore not exists errors because of the TOCTOU problem
|
|
if err := r.network.NetworkRemove(net.Name); err != nil && !errors.Is(err, types.ErrNoSuchNetwork) {
|
|
logrus.Errorf("Removing network %s: %v", net.Name, err)
|
|
}
|
|
}
|
|
|
|
xdgRuntimeDir := os.Getenv("XDG_RUNTIME_DIR")
|
|
if xdgRuntimeDir != "" {
|
|
xdgRuntimeDir, err = filepath.EvalSymlinks(xdgRuntimeDir)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
_, prevError := r.store.Shutdown(true)
|
|
graphRoot := filepath.Clean(r.store.GraphRoot())
|
|
if graphRoot == xdgRuntimeDir {
|
|
if prevError != nil {
|
|
logrus.Error(prevError)
|
|
}
|
|
prevError = fmt.Errorf("failed to remove runtime graph root dir %s, since it is the same as XDG_RUNTIME_DIR", graphRoot)
|
|
} else {
|
|
if err := os.RemoveAll(graphRoot); err != nil {
|
|
if prevError != nil {
|
|
logrus.Error(prevError)
|
|
}
|
|
prevError = err
|
|
}
|
|
}
|
|
runRoot := filepath.Clean(r.store.RunRoot())
|
|
if runRoot == xdgRuntimeDir {
|
|
if prevError != nil {
|
|
logrus.Error(prevError)
|
|
}
|
|
prevError = fmt.Errorf("failed to remove runtime root dir %s, since it is the same as XDG_RUNTIME_DIR", runRoot)
|
|
} else {
|
|
if err := os.RemoveAll(runRoot); err != nil {
|
|
if prevError != nil {
|
|
logrus.Error(prevError)
|
|
}
|
|
prevError = err
|
|
}
|
|
}
|
|
runtimeDir, err := util.GetRootlessRuntimeDir()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
tempDir := r.config.Engine.TmpDir
|
|
if tempDir == runtimeDir {
|
|
tempDir = filepath.Join(tempDir, "containers")
|
|
}
|
|
if filepath.Clean(tempDir) == xdgRuntimeDir {
|
|
if prevError != nil {
|
|
logrus.Error(prevError)
|
|
}
|
|
prevError = fmt.Errorf("failed to remove runtime tmpdir %s, since it is the same as XDG_RUNTIME_DIR", tempDir)
|
|
} else {
|
|
if err := os.RemoveAll(tempDir); err != nil {
|
|
if prevError != nil {
|
|
logrus.Error(prevError)
|
|
}
|
|
prevError = err
|
|
}
|
|
}
|
|
|
|
if err := blobinfocache.CleanupDefaultCache(nil); err != nil {
|
|
if prevError != nil {
|
|
logrus.Error(prevError)
|
|
}
|
|
prevError = err
|
|
}
|
|
|
|
if storageConfPath, err := storage.DefaultConfigFile(); err == nil {
|
|
switch storageConfPath {
|
|
case stypes.SystemConfigFile:
|
|
break
|
|
default:
|
|
if _, err = os.Stat(storageConfPath); err == nil {
|
|
fmt.Printf(" A %q config file exists.\n", storageConfPath)
|
|
fmt.Println("Remove this file if you did not modify the configuration.")
|
|
}
|
|
}
|
|
} else {
|
|
if prevError != nil {
|
|
logrus.Error(prevError)
|
|
}
|
|
prevError = err
|
|
}
|
|
|
|
// Shut down the runtime, it's no longer usable after mass-deletion.
|
|
if err := r.Shutdown(false); err != nil {
|
|
if prevError != nil {
|
|
logrus.Error(prevError)
|
|
}
|
|
prevError = err
|
|
}
|
|
|
|
return prevError
|
|
}
|