github.com/containers/libpod@v1.9.4-0.20220419124438-4284fd425507/libpod/storage.go (about) 1 package libpod 2 3 import ( 4 "context" 5 "time" 6 7 istorage "github.com/containers/image/v5/storage" 8 "github.com/containers/image/v5/types" 9 "github.com/containers/libpod/libpod/define" 10 "github.com/containers/storage" 11 "github.com/containers/storage/pkg/idtools" 12 v1 "github.com/opencontainers/image-spec/specs-go/v1" 13 "github.com/opentracing/opentracing-go" 14 "github.com/pkg/errors" 15 "github.com/sirupsen/logrus" 16 ) 17 18 type storageService struct { 19 store storage.Store 20 } 21 22 // getStorageService returns a storageService which can create container root 23 // filesystems from images 24 func getStorageService(store storage.Store) (*storageService, error) { 25 return &storageService{store: store}, nil 26 } 27 28 // ContainerInfo wraps a subset of information about a container: the locations 29 // of its nonvolatile and volatile per-container directories, along with a copy 30 // of the configuration blob from the image that was used to create the 31 // container, if the image had a configuration. 32 // It also returns the ProcessLabel and MountLabel selected for the container 33 type ContainerInfo struct { 34 Dir string 35 RunDir string 36 Config *v1.Image 37 ProcessLabel string 38 MountLabel string 39 UIDMap []idtools.IDMap 40 GIDMap []idtools.IDMap 41 } 42 43 // RuntimeContainerMetadata is the structure that we encode as JSON and store 44 // in the metadata field of storage.Container objects. It is used for 45 // specifying attributes containers when they are being created, and allows a 46 // container's MountLabel, and possibly other values, to be modified in one 47 // read/write cycle via calls to storageService.ContainerMetadata, 48 // RuntimeContainerMetadata.SetMountLabel, and 49 // storageService.SetContainerMetadata. 50 type RuntimeContainerMetadata struct { 51 // The provided name and the ID of the image that was used to 52 // instantiate the container. 53 ImageName string `json:"image-name"` // Applicable to both PodSandboxes and Containers 54 ImageID string `json:"image-id"` // Applicable to both PodSandboxes and Containers 55 // The container's name, which for an infrastructure container is usually PodName + "-infra". 56 ContainerName string `json:"name"` // Applicable to both PodSandboxes and Containers, mandatory 57 CreatedAt int64 `json:"created-at"` // Applicable to both PodSandboxes and Containers 58 MountLabel string `json:"mountlabel,omitempty"` // Applicable to both PodSandboxes and Containers 59 } 60 61 // SetMountLabel updates the mount label held by a RuntimeContainerMetadata 62 // object. 63 func (metadata *RuntimeContainerMetadata) SetMountLabel(mountLabel string) { 64 metadata.MountLabel = mountLabel 65 } 66 67 // CreateContainerStorage creates the storage end of things. We already have the container spec created 68 // TO-DO We should be passing in an Image object in the future. 69 func (r *storageService) CreateContainerStorage(ctx context.Context, systemContext *types.SystemContext, imageName, imageID, containerName, containerID string, options storage.ContainerOptions) (cinfo ContainerInfo, err error) { 70 span, _ := opentracing.StartSpanFromContext(ctx, "createContainerStorage") 71 span.SetTag("type", "storageService") 72 defer span.Finish() 73 74 var imageConfig *v1.Image 75 if imageName != "" { 76 var ref types.ImageReference 77 if containerName == "" { 78 return ContainerInfo{}, define.ErrEmptyID 79 } 80 // Check if we have the specified image. 81 ref, err := istorage.Transport.ParseStoreReference(r.store, imageID) 82 if err != nil { 83 return ContainerInfo{}, err 84 } 85 img, err := istorage.Transport.GetStoreImage(r.store, ref) 86 if err != nil { 87 return ContainerInfo{}, err 88 } 89 // Pull out a copy of the image's configuration. 90 image, err := ref.NewImage(ctx, systemContext) 91 if err != nil { 92 return ContainerInfo{}, err 93 } 94 defer image.Close() 95 96 // Get OCI configuration of image 97 imageConfig, err = image.OCIConfig(ctx) 98 if err != nil { 99 return ContainerInfo{}, err 100 } 101 102 // Update the image name and ID. 103 if imageName == "" && len(img.Names) > 0 { 104 imageName = img.Names[0] 105 } 106 imageID = img.ID 107 } 108 109 // Build metadata to store with the container. 110 metadata := RuntimeContainerMetadata{ 111 ImageName: imageName, 112 ImageID: imageID, 113 ContainerName: containerName, 114 CreatedAt: time.Now().Unix(), 115 } 116 mdata, err := json.Marshal(&metadata) 117 if err != nil { 118 return ContainerInfo{}, err 119 } 120 121 // Build the container. 122 names := []string{containerName} 123 124 container, err := r.store.CreateContainer(containerID, names, imageID, "", string(mdata), &options) 125 if err != nil { 126 logrus.Debugf("failed to create container %s(%s): %v", metadata.ContainerName, containerID, err) 127 128 return ContainerInfo{}, err 129 } 130 logrus.Debugf("created container %q", container.ID) 131 132 // If anything fails after this point, we need to delete the incomplete 133 // container before returning. 134 defer func() { 135 if err != nil { 136 if err2 := r.store.DeleteContainer(container.ID); err2 != nil { 137 logrus.Infof("%v deleting partially-created container %q", err2, container.ID) 138 139 return 140 } 141 logrus.Infof("deleted partially-created container %q", container.ID) 142 } 143 }() 144 145 // Add a name to the container's layer so that it's easier to follow 146 // what's going on if we're just looking at the storage-eye view of things. 147 layerName := metadata.ContainerName + "-layer" 148 names, err = r.store.Names(container.LayerID) 149 if err != nil { 150 return ContainerInfo{}, err 151 } 152 names = append(names, layerName) 153 err = r.store.SetNames(container.LayerID, names) 154 if err != nil { 155 return ContainerInfo{}, err 156 } 157 158 // Find out where the container work directories are, so that we can return them. 159 containerDir, err := r.store.ContainerDirectory(container.ID) 160 if err != nil { 161 return ContainerInfo{}, err 162 } 163 logrus.Debugf("container %q has work directory %q", container.ID, containerDir) 164 165 containerRunDir, err := r.store.ContainerRunDirectory(container.ID) 166 if err != nil { 167 return ContainerInfo{}, err 168 } 169 logrus.Debugf("container %q has run directory %q", container.ID, containerRunDir) 170 171 return ContainerInfo{ 172 UIDMap: options.UIDMap, 173 GIDMap: options.GIDMap, 174 Dir: containerDir, 175 RunDir: containerRunDir, 176 Config: imageConfig, 177 ProcessLabel: container.ProcessLabel(), 178 MountLabel: container.MountLabel(), 179 }, nil 180 } 181 182 func (r *storageService) DeleteContainer(idOrName string) error { 183 if idOrName == "" { 184 return define.ErrEmptyID 185 } 186 container, err := r.store.Container(idOrName) 187 if err != nil { 188 return err 189 } 190 err = r.store.DeleteContainer(container.ID) 191 if err != nil { 192 logrus.Debugf("failed to delete container %q: %v", container.ID, err) 193 return err 194 } 195 return nil 196 } 197 198 func (r *storageService) SetContainerMetadata(idOrName string, metadata RuntimeContainerMetadata) error { 199 mdata, err := json.Marshal(&metadata) 200 if err != nil { 201 logrus.Debugf("failed to encode metadata for %q: %v", idOrName, err) 202 return err 203 } 204 return r.store.SetMetadata(idOrName, string(mdata)) 205 } 206 207 func (r *storageService) GetContainerMetadata(idOrName string) (RuntimeContainerMetadata, error) { 208 metadata := RuntimeContainerMetadata{} 209 mdata, err := r.store.Metadata(idOrName) 210 if err != nil { 211 return metadata, err 212 } 213 if err = json.Unmarshal([]byte(mdata), &metadata); err != nil { 214 return metadata, err 215 } 216 return metadata, nil 217 } 218 219 func (r *storageService) MountContainerImage(idOrName string) (string, error) { 220 container, err := r.store.Container(idOrName) 221 if err != nil { 222 if errors.Cause(err) == storage.ErrContainerUnknown { 223 return "", define.ErrNoSuchCtr 224 } 225 return "", err 226 } 227 metadata := RuntimeContainerMetadata{} 228 if err = json.Unmarshal([]byte(container.Metadata), &metadata); err != nil { 229 return "", err 230 } 231 mountPoint, err := r.store.Mount(container.ID, metadata.MountLabel) 232 if err != nil { 233 logrus.Debugf("failed to mount container %q: %v", container.ID, err) 234 return "", err 235 } 236 logrus.Debugf("mounted container %q at %q", container.ID, mountPoint) 237 return mountPoint, nil 238 } 239 240 func (r *storageService) UnmountContainerImage(idOrName string, force bool) (bool, error) { 241 if idOrName == "" { 242 return false, define.ErrEmptyID 243 } 244 container, err := r.store.Container(idOrName) 245 if err != nil { 246 return false, err 247 } 248 249 if !force { 250 mounted, err := r.store.Mounted(container.ID) 251 if err != nil { 252 return false, err 253 } 254 if mounted == 0 { 255 return false, storage.ErrLayerNotMounted 256 } 257 } 258 mounted, err := r.store.Unmount(container.ID, force) 259 if err != nil { 260 logrus.Debugf("failed to unmount container %q: %v", container.ID, err) 261 return false, err 262 } 263 logrus.Debugf("unmounted container %q", container.ID) 264 return mounted, nil 265 } 266 267 func (r *storageService) MountedContainerImage(idOrName string) (int, error) { 268 if idOrName == "" { 269 return 0, define.ErrEmptyID 270 } 271 container, err := r.store.Container(idOrName) 272 if err != nil { 273 return 0, err 274 } 275 mounted, err := r.store.Mounted(container.ID) 276 if err != nil { 277 return 0, err 278 } 279 return mounted, nil 280 } 281 282 func (r *storageService) GetMountpoint(id string) (string, error) { 283 container, err := r.store.Container(id) 284 if err != nil { 285 if errors.Cause(err) == storage.ErrContainerUnknown { 286 return "", define.ErrNoSuchCtr 287 } 288 return "", err 289 } 290 layer, err := r.store.Layer(container.LayerID) 291 if err != nil { 292 return "", err 293 } 294 295 return layer.MountPoint, nil 296 } 297 298 func (r *storageService) GetWorkDir(id string) (string, error) { 299 container, err := r.store.Container(id) 300 if err != nil { 301 if errors.Cause(err) == storage.ErrContainerUnknown { 302 return "", define.ErrNoSuchCtr 303 } 304 return "", err 305 } 306 return r.store.ContainerDirectory(container.ID) 307 } 308 309 func (r *storageService) GetRunDir(id string) (string, error) { 310 container, err := r.store.Container(id) 311 if err != nil { 312 if errors.Cause(err) == storage.ErrContainerUnknown { 313 return "", define.ErrNoSuchCtr 314 } 315 return "", err 316 } 317 return r.store.ContainerRunDirectory(container.ID) 318 }