mirror of https://github.com/containers/podman.git
170 lines
4.7 KiB
Go
170 lines
4.7 KiB
Go
package ocipull
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
|
|
"github.com/containers/image/v5/types"
|
|
"github.com/containers/podman/v5/pkg/machine/compression"
|
|
"github.com/containers/podman/v5/pkg/machine/define"
|
|
"github.com/containers/podman/v5/utils"
|
|
v1 "github.com/opencontainers/image-spec/specs-go/v1"
|
|
"github.com/sirupsen/logrus"
|
|
)
|
|
|
|
type Versioned struct {
|
|
blob *types.BlobInfo
|
|
blobDirPath string
|
|
cacheDir string
|
|
ctx context.Context
|
|
imageName string
|
|
machineImageDir string
|
|
machineVersion *OSVersion
|
|
vmName string
|
|
vmType string
|
|
finalPath *define.VMFile
|
|
}
|
|
|
|
func NewVersioned(ctx context.Context, machineImageDir *define.VMFile, vmName string, vmType string, finalPath *define.VMFile) (*Versioned, error) {
|
|
imageCacheDir := filepath.Join(machineImageDir.GetPath(), "cache")
|
|
if err := os.MkdirAll(imageCacheDir, 0777); err != nil {
|
|
return nil, err
|
|
}
|
|
o := getVersion()
|
|
return &Versioned{ctx: ctx, cacheDir: imageCacheDir, machineImageDir: machineImageDir.GetPath(), machineVersion: o, vmName: vmName, vmType: vmType, finalPath: finalPath}, nil
|
|
}
|
|
|
|
func (d *Versioned) LocalBlob() *types.BlobInfo {
|
|
return d.blob
|
|
}
|
|
|
|
func (d *Versioned) DiskEndpoint() string {
|
|
return d.machineVersion.diskImage(d.vmType)
|
|
}
|
|
|
|
func (d *Versioned) versionedOCICacheDir() string {
|
|
return filepath.Join(d.cacheDir, d.machineVersion.majorMinor())
|
|
}
|
|
|
|
func (d *Versioned) identifyImageNameFromOCIDir() (string, error) {
|
|
imageManifest, err := ReadImageManifestFromOCIPath(d.ctx, d.versionedOCICacheDir())
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
if len(imageManifest.Layers) > 1 {
|
|
return "", fmt.Errorf("podman machine images can have only one layer: %d found", len(imageManifest.Layers))
|
|
}
|
|
path := filepath.Join(d.versionedOCICacheDir(), "blobs", "sha256", imageManifest.Layers[0].Digest.Hex())
|
|
return findTarComponent(path)
|
|
}
|
|
|
|
func (d *Versioned) pull(path string) error {
|
|
fmt.Printf("Pulling %s\n", d.DiskEndpoint())
|
|
logrus.Debugf("pulling %s to %s", d.DiskEndpoint(), path)
|
|
return Pull(d.ctx, d.DiskEndpoint(), path, PullOptions{})
|
|
}
|
|
|
|
func (d *Versioned) Pull() error {
|
|
var (
|
|
err error
|
|
isUpdatable bool
|
|
localBlob *types.BlobInfo
|
|
remoteDescriptor *v1.Descriptor
|
|
)
|
|
|
|
remoteDiskImage := d.machineVersion.diskImage(d.vmType)
|
|
logrus.Debugf("podman disk image name: %s", remoteDiskImage)
|
|
|
|
// is there a valid oci dir in our cache
|
|
hasCache := d.localOCIDirExists()
|
|
|
|
if hasCache {
|
|
logrus.Debug("checking remote registry")
|
|
remoteDescriptor, err = GetRemoteDescriptor(d.ctx, remoteDiskImage)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
logrus.Debugf("working with local cache: %s", d.versionedOCICacheDir())
|
|
localBlob, err = GetLocalBlob(d.ctx, d.versionedOCICacheDir())
|
|
if err != nil {
|
|
return err
|
|
}
|
|
// determine if the local is same as remote
|
|
if remoteDescriptor.Digest.Hex() != localBlob.Digest.Hex() {
|
|
logrus.Debugf("new image is available: %s", remoteDescriptor.Digest.Hex())
|
|
isUpdatable = true
|
|
}
|
|
}
|
|
if !hasCache || isUpdatable {
|
|
if hasCache {
|
|
if err := utils.GuardedRemoveAll(d.versionedOCICacheDir()); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
if err := d.pull(d.versionedOCICacheDir()); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
imageName, err := d.identifyImageNameFromOCIDir()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
logrus.Debugf("image name: %s", imageName)
|
|
d.imageName = imageName
|
|
|
|
if localBlob == nil {
|
|
localBlob, err = GetLocalBlob(d.ctx, d.versionedOCICacheDir())
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
d.blob = localBlob
|
|
d.blobDirPath = d.versionedOCICacheDir()
|
|
logrus.Debugf("local oci disk image blob: %s", d.localOCIDiskImageDir(localBlob))
|
|
return nil
|
|
}
|
|
|
|
func (d *Versioned) Unpack() (*define.VMFile, error) {
|
|
tbPath := localOCIDiskImageDir(d.blobDirPath, d.blob)
|
|
unpackedFile, err := unpackOCIDir(tbPath, d.machineImageDir)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
d.imageName = unpackedFile.GetPath()
|
|
return unpackedFile, nil
|
|
}
|
|
|
|
func (d *Versioned) Decompress(compressedFile *define.VMFile) error {
|
|
return compression.Decompress(compressedFile, d.finalPath.GetPath())
|
|
}
|
|
|
|
func (d *Versioned) localOCIDiskImageDir(localBlob *types.BlobInfo) string {
|
|
return filepath.Join(d.versionedOCICacheDir(), "blobs", "sha256", localBlob.Digest.Hex())
|
|
}
|
|
|
|
func (d *Versioned) localOCIDirExists() bool {
|
|
_, indexErr := os.Stat(filepath.Join(d.versionedOCICacheDir(), "index.json"))
|
|
return indexErr == nil
|
|
}
|
|
|
|
func (d *Versioned) Get() error {
|
|
if err := d.Pull(); err != nil {
|
|
return err
|
|
}
|
|
unpacked, err := d.Unpack()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
defer func() {
|
|
logrus.Debugf("cleaning up %q", unpacked.GetPath())
|
|
if err := unpacked.Delete(); err != nil {
|
|
logrus.Errorf("unable to delete local compressed file %q:%v", unpacked.GetPath(), err)
|
|
}
|
|
}()
|
|
|
|
return d.Decompress(unpacked)
|
|
}
|