summaryrefslogtreecommitdiff
path: root/libpod/runtime_pod.go
blob: b142472e84f5b544b4e5fc05aead9bc03fa7b40b (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
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
package libpod

import (
	"context"
	"time"

	"github.com/containers/podman/v3/libpod/define"
	"github.com/containers/podman/v3/pkg/util"
	"github.com/pkg/errors"
)

// Contains the public Runtime API for pods

// A PodCreateOption is a functional option which alters the Pod created by
// NewPod
type PodCreateOption func(*Pod) error

// PodFilter is a function to determine whether a pod is included in command
// output. Pods to be outputted are tested using the function. A true return
// will include the pod, a false return will exclude it.
type PodFilter func(*Pod) bool

// RemovePod removes a pod
// If removeCtrs is specified, containers will be removed
// Otherwise, a pod that is not empty will return an error and not be removed
// If force is specified with removeCtrs, all containers will be stopped before
// being removed
// Otherwise, the pod will not be removed if any containers are running
func (r *Runtime) RemovePod(ctx context.Context, p *Pod, removeCtrs, force bool) error {
	r.lock.Lock()
	defer r.lock.Unlock()

	if !r.valid {
		return define.ErrRuntimeStopped
	}

	if !p.valid {
		if ok, _ := r.state.HasPod(p.ID()); !ok {
			// Pod probably already removed
			// Or was never in the runtime to begin with
			return nil
		}
	}

	p.lock.Lock()
	defer p.lock.Unlock()

	return r.removePod(ctx, p, removeCtrs, force)
}

// GetPod retrieves a pod by its ID
func (r *Runtime) GetPod(id string) (*Pod, error) {
	r.lock.RLock()
	defer r.lock.RUnlock()

	if !r.valid {
		return nil, define.ErrRuntimeStopped
	}

	return r.state.Pod(id)
}

// HasPod checks to see if a pod with the given ID exists
func (r *Runtime) HasPod(id string) (bool, error) {
	r.lock.RLock()
	defer r.lock.RUnlock()

	if !r.valid {
		return false, define.ErrRuntimeStopped
	}

	return r.state.HasPod(id)
}

// LookupPod retrieves a pod by its name or a partial ID
// If a partial ID is not unique, an error will be returned
func (r *Runtime) LookupPod(idOrName string) (*Pod, error) {
	r.lock.RLock()
	defer r.lock.RUnlock()

	if !r.valid {
		return nil, define.ErrRuntimeStopped
	}

	return r.state.LookupPod(idOrName)
}

// Pods retrieves all pods
// Filters can be provided which will determine which pods are included in the
// output. Multiple filters are handled by ANDing their output, so only pods
// matching all filters are returned
func (r *Runtime) Pods(filters ...PodFilter) ([]*Pod, error) {
	pods, err := r.GetAllPods()
	if err != nil {
		return nil, err
	}
	podsFiltered := make([]*Pod, 0, len(pods))
	for _, pod := range pods {
		include := true
		for _, filter := range filters {
			include = include && filter(pod)
		}

		if include {
			podsFiltered = append(podsFiltered, pod)
		}
	}

	return podsFiltered, nil
}

// GetAllPods retrieves all pods
func (r *Runtime) GetAllPods() ([]*Pod, error) {
	r.lock.RLock()
	defer r.lock.RUnlock()

	if !r.valid {
		return nil, define.ErrRuntimeStopped
	}

	return r.state.AllPods()
}

// GetLatestPod returns a pod object of the latest created pod.
func (r *Runtime) GetLatestPod() (*Pod, error) {
	lastCreatedIndex := -1
	var lastCreatedTime time.Time
	pods, err := r.GetAllPods()
	if err != nil {
		return nil, errors.Wrapf(err, "unable to get all pods")
	}
	if len(pods) == 0 {
		return nil, define.ErrNoSuchPod
	}
	for podIndex, pod := range pods {
		createdTime := pod.config.CreatedTime
		if createdTime.After(lastCreatedTime) {
			lastCreatedTime = createdTime
			lastCreatedIndex = podIndex
		}
	}
	return pods[lastCreatedIndex], nil
}

// GetRunningPods returns an array of running pods
func (r *Runtime) GetRunningPods() ([]*Pod, error) {
	var (
		pods        []string
		runningPods []*Pod
	)
	r.lock.RLock()
	defer r.lock.RUnlock()

	if !r.valid {
		return nil, define.ErrRuntimeStopped
	}
	containers, err := r.GetRunningContainers()
	if err != nil {
		return nil, err
	}
	// Assemble running pods
	for _, c := range containers {
		if !util.StringInSlice(c.PodID(), pods) {
			pods = append(pods, c.PodID())
			pod, err := r.GetPod(c.PodID())
			if err != nil {
				if errors.Cause(err) == define.ErrPodRemoved || errors.Cause(err) == define.ErrNoSuchPod {
					continue
				}
				return nil, err
			}
			runningPods = append(runningPods, pod)
		}
	}
	return runningPods, nil
}

// PrunePods removes unused pods and their containers from local storage.
func (r *Runtime) PrunePods(ctx context.Context) (map[string]error, error) {
	response := make(map[string]error)
	states := []string{define.PodStateStopped, define.PodStateExited}
	filterFunc := func(p *Pod) bool {
		state, _ := p.GetPodStatus()
		for _, status := range states {
			if state == status {
				return true
			}
		}
		return false
	}
	pods, err := r.Pods(filterFunc)
	if err != nil {
		return nil, err
	}
	if len(pods) < 1 {
		return response, nil
	}
	for _, pod := range pods {
		err := r.removePod(context.TODO(), pod, true, false)
		response[pod.ID()] = err
	}
	return response, nil
}