summaryrefslogtreecommitdiff
path: root/libpod/runtime_cstorage.go
blob: 586db5a1e4f50d8366c9c9a98e3f825c2d1705ae (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
package libpod

import (
	"github.com/containers/libpod/libpod/define"
	"github.com/containers/storage"
	"github.com/pkg/errors"
	"github.com/sirupsen/logrus"
)

// StorageContainer represents a container present in c/storage but not in
// libpod.
type StorageContainer struct {
	ID              string
	Names           []string
	PresentInLibpod bool
}

// ListStorageContainers lists all containers visible to c/storage.
func (r *Runtime) ListStorageContainers() ([]*StorageContainer, error) {
	r.lock.RLock()
	defer r.lock.RUnlock()

	finalCtrs := []*StorageContainer{}

	ctrs, err := r.store.Containers()
	if err != nil {
		return nil, err
	}

	for _, ctr := range ctrs {
		storageCtr := new(StorageContainer)
		storageCtr.ID = ctr.ID
		storageCtr.Names = ctr.Names

		// Look up if container is in state
		hasCtr, err := r.state.HasContainer(ctr.ID)
		if err != nil {
			return nil, errors.Wrapf(err, "error looking up container %s in state", ctr.ID)
		}

		storageCtr.PresentInLibpod = hasCtr

		finalCtrs = append(finalCtrs, storageCtr)
	}

	return finalCtrs, nil
}

// RemoveStorageContainer removes a container from c/storage.
// The container WILL NOT be removed if it exists in libpod.
// Accepts ID or full name of container.
// If force is set, the container will be unmounted first to ensure removal.
func (r *Runtime) RemoveStorageContainer(idOrName string, force bool) error {
	r.lock.Lock()
	defer r.lock.Unlock()

	targetID, err := r.store.Lookup(idOrName)
	if err != nil {
		if err == storage.ErrLayerUnknown {
			return errors.Wrapf(define.ErrNoSuchCtr, "no container with ID or name %q found", idOrName)
		}
		return errors.Wrapf(err, "error looking up container %q", idOrName)
	}

	// Lookup returns an ID but it's not guaranteed to be a container ID.
	// So we can still error here.
	ctr, err := r.store.Container(targetID)
	if err != nil {
		if err == storage.ErrContainerUnknown {
			return errors.Wrapf(define.ErrNoSuchCtr, "%q does not refer to a container", idOrName)
		}
		return errors.Wrapf(err, "error retrieving container %q", idOrName)
	}

	// Error out if the container exists in libpod
	exists, err := r.state.HasContainer(ctr.ID)
	if err != nil {
		return err
	}
	if exists {
		return errors.Wrapf(define.ErrCtrExists, "refusing to remove %q as it exists in libpod as container %s", idOrName, ctr.ID)
	}

	if !force {
		timesMounted, err := r.store.Mounted(ctr.ID)
		if err != nil {
			if err == storage.ErrContainerUnknown {
				// Container was removed from under us.
				// It's gone, so don't bother erroring.
				logrus.Warnf("Storage for container %s already removed", ctr.ID)
				return nil
			}
			return errors.Wrapf(err, "error looking up container %q mounts", idOrName)
		}
		if timesMounted > 0 {
			return errors.Wrapf(define.ErrCtrStateInvalid, "container %q is mounted and cannot be removed without using force", idOrName)
		}
	} else {
		if _, err := r.store.Unmount(ctr.ID, true); err != nil {
			if err == storage.ErrContainerUnknown {
				// Container again gone, no error
				logrus.Warnf("Storage for container %s already removed", ctr.ID)
				return nil
			}
			return errors.Wrapf(err, "error unmounting container %q", idOrName)
		}
	}

	if err := r.store.DeleteContainer(ctr.ID); err != nil {
		if err == storage.ErrContainerUnknown {
			// Container again gone, no error
			logrus.Warnf("Storage for container %s already removed", ctr.ID)
			return nil
		}
		return errors.Wrapf(err, "error removing storage for container %q", idOrName)
	}

	return nil
}