podman

Форк
0
/
storage.go 
309 строк · 9.4 Кб
1
//go:build !remote
2

3
package libpod
4

5
import (
6
	"context"
7
	"errors"
8
	"time"
9

10
	istorage "github.com/containers/image/v5/storage"
11
	"github.com/containers/image/v5/types"
12
	"github.com/containers/podman/v5/libpod/define"
13
	"github.com/containers/storage"
14
	"github.com/containers/storage/pkg/idtools"
15
	v1 "github.com/opencontainers/image-spec/specs-go/v1"
16
	"github.com/sirupsen/logrus"
17
)
18

19
type storageService struct {
20
	store storage.Store
21
}
22

23
// getStorageService returns a storageService which can create container root
24
// filesystems from images
25
func getStorageService(store storage.Store) *storageService {
26
	return &storageService{store: store}
27
}
28

29
// ContainerInfo wraps a subset of information about a container: the locations
30
// of its nonvolatile and volatile per-container directories, along with a copy
31
// of the configuration blob from the image that was used to create the
32
// container, if the image had a configuration.
33
// It also returns the ProcessLabel and MountLabel selected for the container
34
type ContainerInfo struct {
35
	Dir          string
36
	RunDir       string
37
	Config       *v1.Image
38
	ProcessLabel string
39
	MountLabel   string
40
	UIDMap       []idtools.IDMap
41
	GIDMap       []idtools.IDMap
42
}
43

44
// RuntimeContainerMetadata is the structure that we encode as JSON and store
45
// in the metadata field of storage.Container objects.  It is used for
46
// specifying attributes containers when they are being created, and allows a
47
// container's MountLabel, and possibly other values, to be modified in one
48
// read/write cycle via calls to storageService.ContainerMetadata,
49
// RuntimeContainerMetadata.SetMountLabel, and
50
// storageService.SetContainerMetadata.
51
type RuntimeContainerMetadata struct {
52
	// The provided name and the ID of the image that was used to
53
	// instantiate the container.
54
	ImageName string `json:"image-name"` // Applicable to both PodSandboxes and Containers
55
	ImageID   string `json:"image-id"`   // Applicable to both PodSandboxes and Containers
56
	// The container's name, which for an infrastructure container is usually PodName + "-infra".
57
	ContainerName string `json:"name"`                 // Applicable to both PodSandboxes and Containers, mandatory
58
	CreatedAt     int64  `json:"created-at"`           // Applicable to both PodSandboxes and Containers
59
	MountLabel    string `json:"mountlabel,omitempty"` // Applicable to both PodSandboxes and Containers
60
}
61

62
// SetMountLabel updates the mount label held by a RuntimeContainerMetadata
63
// object.
64
func (metadata *RuntimeContainerMetadata) SetMountLabel(mountLabel string) {
65
	metadata.MountLabel = mountLabel
66
}
67

68
// CreateContainerStorage creates the storage end of things.  We already have the container spec created.
69
// imageID and imageName must both be either empty or non-empty.
70
// TO-DO We should be passing in an Image object in the future.
71
func (r *storageService) CreateContainerStorage(ctx context.Context, systemContext *types.SystemContext, imageName, imageID, containerName, containerID string, options storage.ContainerOptions) (_ ContainerInfo, retErr error) {
72
	var imageConfig *v1.Image
73
	if imageID != "" {
74
		if containerName == "" {
75
			return ContainerInfo{}, define.ErrEmptyID
76
		}
77
		// Check if we have the specified image.
78
		ref, err := istorage.Transport.NewStoreReference(r.store, nil, imageID)
79
		if err != nil {
80
			return ContainerInfo{}, err
81
		}
82
		// Pull out a copy of the image's configuration.
83
		image, err := ref.NewImage(ctx, systemContext)
84
		if err != nil {
85
			return ContainerInfo{}, err
86
		}
87
		defer image.Close()
88

89
		// Get OCI configuration of image
90
		imageConfig, err = image.OCIConfig(ctx)
91
		if err != nil {
92
			return ContainerInfo{}, err
93
		}
94
	}
95

96
	// Build metadata to store with the container.
97
	metadata := RuntimeContainerMetadata{
98
		ImageName:     imageName,
99
		ImageID:       imageID,
100
		ContainerName: containerName,
101
		CreatedAt:     time.Now().Unix(),
102
	}
103
	mdata, err := json.Marshal(&metadata)
104
	if err != nil {
105
		return ContainerInfo{}, err
106
	}
107

108
	// Build the container.
109
	names := []string{containerName}
110

111
	container, err := r.store.CreateContainer(containerID, names, imageID, "", string(mdata), &options)
112
	if err != nil {
113
		logrus.Debugf("Failed to create container %s(%s): %v", metadata.ContainerName, containerID, err)
114

115
		return ContainerInfo{}, err
116
	}
117
	logrus.Debugf("Created container %q", container.ID)
118

119
	// If anything fails after this point, we need to delete the incomplete
120
	// container before returning.
121
	defer func() {
122
		if retErr != nil {
123
			if err := r.store.DeleteContainer(container.ID); err != nil {
124
				logrus.Infof("Error deleting partially-created container %q: %v", container.ID, err)
125

126
				return
127
			}
128
			logrus.Infof("Deleted partially-created container %q", container.ID)
129
		}
130
	}()
131

132
	// Add a name to the container's layer so that it's easier to follow
133
	// what's going on if we're just looking at the storage-eye view of things.
134
	layerName := metadata.ContainerName + "-layer"
135
	names, err = r.store.Names(container.LayerID)
136
	if err != nil {
137
		return ContainerInfo{}, err
138
	}
139
	names = append(names, layerName)
140
	err = r.store.SetNames(container.LayerID, names)
141
	if err != nil {
142
		return ContainerInfo{}, err
143
	}
144

145
	// Find out where the container work directories are, so that we can return them.
146
	containerDir, err := r.store.ContainerDirectory(container.ID)
147
	if err != nil {
148
		return ContainerInfo{}, err
149
	}
150
	logrus.Debugf("Container %q has work directory %q", container.ID, containerDir)
151

152
	containerRunDir, err := r.store.ContainerRunDirectory(container.ID)
153
	if err != nil {
154
		return ContainerInfo{}, err
155
	}
156
	logrus.Debugf("Container %q has run directory %q", container.ID, containerRunDir)
157

158
	return ContainerInfo{
159
		UIDMap:       container.UIDMap,
160
		GIDMap:       container.GIDMap,
161
		Dir:          containerDir,
162
		RunDir:       containerRunDir,
163
		Config:       imageConfig,
164
		ProcessLabel: container.ProcessLabel(),
165
		MountLabel:   container.MountLabel(),
166
	}, nil
167
}
168

169
func (r *storageService) DeleteContainer(idOrName string) error {
170
	if idOrName == "" {
171
		return define.ErrEmptyID
172
	}
173
	container, err := r.store.Container(idOrName)
174
	if err != nil {
175
		return err
176
	}
177
	err = r.store.DeleteContainer(container.ID)
178
	if err != nil {
179
		if errors.Is(err, storage.ErrNotAContainer) || errors.Is(err, storage.ErrContainerUnknown) {
180
			logrus.Infof("Storage for container %s already removed", container.ID)
181
		} else {
182
			logrus.Debugf("Failed to delete container %q: %v", container.ID, err)
183
			return err
184
		}
185
	}
186
	return nil
187
}
188

189
func (r *storageService) SetContainerMetadata(idOrName string, metadata RuntimeContainerMetadata) error {
190
	mdata, err := json.Marshal(&metadata)
191
	if err != nil {
192
		logrus.Debugf("Failed to encode metadata for %q: %v", idOrName, err)
193
		return err
194
	}
195
	return r.store.SetMetadata(idOrName, string(mdata))
196
}
197

198
func (r *storageService) GetContainerMetadata(idOrName string) (RuntimeContainerMetadata, error) {
199
	metadata := RuntimeContainerMetadata{}
200
	mdata, err := r.store.Metadata(idOrName)
201
	if err != nil {
202
		return metadata, err
203
	}
204
	if err = json.Unmarshal([]byte(mdata), &metadata); err != nil {
205
		return metadata, err
206
	}
207
	return metadata, nil
208
}
209

210
func (r *storageService) MountContainerImage(idOrName string) (string, error) {
211
	container, err := r.store.Container(idOrName)
212
	if err != nil {
213
		if errors.Is(err, storage.ErrContainerUnknown) {
214
			return "", define.ErrNoSuchCtr
215
		}
216
		return "", err
217
	}
218
	metadata := RuntimeContainerMetadata{}
219
	if err = json.Unmarshal([]byte(container.Metadata), &metadata); err != nil {
220
		return "", err
221
	}
222
	mountPoint, err := r.store.Mount(container.ID, metadata.MountLabel)
223
	if err != nil {
224
		logrus.Debugf("Failed to mount container %q: %v", container.ID, err)
225
		return "", err
226
	}
227
	logrus.Debugf("Mounted container %q at %q", container.ID, mountPoint)
228
	return mountPoint, nil
229
}
230

231
func (r *storageService) UnmountContainerImage(idOrName string, force bool) (bool, error) {
232
	if idOrName == "" {
233
		return false, define.ErrEmptyID
234
	}
235
	container, err := r.store.Container(idOrName)
236
	if err != nil {
237
		return false, err
238
	}
239

240
	if !force {
241
		mounted, err := r.store.Mounted(container.ID)
242
		if err != nil {
243
			return false, err
244
		}
245
		if mounted == 0 {
246
			return false, storage.ErrLayerNotMounted
247
		}
248
	}
249
	mounted, err := r.store.Unmount(container.ID, force)
250
	if err != nil {
251
		logrus.Debugf("Failed to unmount container %q: %v", container.ID, err)
252
		return false, err
253
	}
254
	logrus.Debugf("Unmounted container %q", container.ID)
255
	return mounted, nil
256
}
257

258
func (r *storageService) MountedContainerImage(idOrName string) (int, error) {
259
	if idOrName == "" {
260
		return 0, define.ErrEmptyID
261
	}
262
	container, err := r.store.Container(idOrName)
263
	if err != nil {
264
		return 0, err
265
	}
266
	mounted, err := r.store.Mounted(container.ID)
267
	if err != nil {
268
		return 0, err
269
	}
270
	return mounted, nil
271
}
272

273
func (r *storageService) GetMountpoint(id string) (string, error) {
274
	container, err := r.store.Container(id)
275
	if err != nil {
276
		if errors.Is(err, storage.ErrContainerUnknown) {
277
			return "", define.ErrNoSuchCtr
278
		}
279
		return "", err
280
	}
281
	layer, err := r.store.Layer(container.LayerID)
282
	if err != nil {
283
		return "", err
284
	}
285

286
	return layer.MountPoint, nil
287
}
288

289
func (r *storageService) GetWorkDir(id string) (string, error) {
290
	container, err := r.store.Container(id)
291
	if err != nil {
292
		if errors.Is(err, storage.ErrContainerUnknown) {
293
			return "", define.ErrNoSuchCtr
294
		}
295
		return "", err
296
	}
297
	return r.store.ContainerDirectory(container.ID)
298
}
299

300
func (r *storageService) GetRunDir(id string) (string, error) {
301
	container, err := r.store.Container(id)
302
	if err != nil {
303
		if errors.Is(err, storage.ErrContainerUnknown) {
304
			return "", define.ErrNoSuchCtr
305
		}
306
		return "", err
307
	}
308
	return r.store.ContainerRunDirectory(container.ID)
309
}
310

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.