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