318 lines
9.4 KiB
Go
318 lines
9.4 KiB
Go
// +build ABISupport
|
|
|
|
package abi
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"io"
|
|
"os"
|
|
"strings"
|
|
|
|
"github.com/containers/image/v5/docker"
|
|
dockerarchive "github.com/containers/image/v5/docker/archive"
|
|
"github.com/containers/image/v5/docker/reference"
|
|
"github.com/containers/image/v5/transports/alltransports"
|
|
"github.com/containers/image/v5/types"
|
|
"github.com/containers/libpod/libpod/image"
|
|
libpodImage "github.com/containers/libpod/libpod/image"
|
|
"github.com/containers/libpod/pkg/domain/entities"
|
|
domainUtils "github.com/containers/libpod/pkg/domain/utils"
|
|
"github.com/containers/libpod/pkg/util"
|
|
"github.com/containers/storage"
|
|
"github.com/pkg/errors"
|
|
"github.com/sirupsen/logrus"
|
|
)
|
|
|
|
func (ir *ImageEngine) Exists(_ context.Context, nameOrId string) (*entities.BoolReport, error) {
|
|
if _, err := ir.Libpod.ImageRuntime().NewFromLocal(nameOrId); err != nil {
|
|
return &entities.BoolReport{}, nil
|
|
}
|
|
return &entities.BoolReport{Value: true}, nil
|
|
}
|
|
|
|
func (ir *ImageEngine) Delete(ctx context.Context, nameOrId []string, opts entities.ImageDeleteOptions) (*entities.ImageDeleteReport, error) {
|
|
report := entities.ImageDeleteReport{}
|
|
|
|
if opts.All {
|
|
var previousTargets []*libpodImage.Image
|
|
repeatRun:
|
|
targets, err := ir.Libpod.ImageRuntime().GetRWImages()
|
|
if err != nil {
|
|
return &report, errors.Wrapf(err, "unable to query local images")
|
|
}
|
|
|
|
if len(targets) > 0 && len(targets) == len(previousTargets) {
|
|
return &report, errors.New("unable to delete all images; re-run the rmi command again.")
|
|
}
|
|
previousTargets = targets
|
|
|
|
for _, img := range targets {
|
|
isParent, err := img.IsParent(ctx)
|
|
if err != nil {
|
|
return &report, err
|
|
}
|
|
if isParent {
|
|
continue
|
|
}
|
|
err = ir.deleteImage(ctx, img, opts, report)
|
|
report.Errors = append(report.Errors, err)
|
|
}
|
|
if len(previousTargets) != 1 {
|
|
goto repeatRun
|
|
}
|
|
return &report, nil
|
|
}
|
|
|
|
for _, id := range nameOrId {
|
|
image, err := ir.Libpod.ImageRuntime().NewFromLocal(id)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
err = ir.deleteImage(ctx, image, opts, report)
|
|
if err != nil {
|
|
return &report, err
|
|
}
|
|
}
|
|
return &report, nil
|
|
}
|
|
|
|
func (ir *ImageEngine) deleteImage(ctx context.Context, img *libpodImage.Image, opts entities.ImageDeleteOptions, report entities.ImageDeleteReport) error {
|
|
results, err := ir.Libpod.RemoveImage(ctx, img, opts.Force)
|
|
switch errors.Cause(err) {
|
|
case nil:
|
|
break
|
|
case storage.ErrImageUsedByContainer:
|
|
report.ImageInUse = errors.New(
|
|
fmt.Sprintf("A container associated with containers/storage, i.e. via Buildah, CRI-O, etc., may be associated with this image: %-12.12s\n", img.ID()))
|
|
return nil
|
|
case libpodImage.ErrNoSuchImage:
|
|
report.ImageNotFound = err
|
|
return nil
|
|
default:
|
|
return err
|
|
}
|
|
|
|
report.Deleted = append(report.Deleted, results.Deleted)
|
|
report.Untagged = append(report.Untagged, results.Untagged...)
|
|
return nil
|
|
}
|
|
|
|
func (ir *ImageEngine) Prune(ctx context.Context, opts entities.ImagePruneOptions) (*entities.ImagePruneReport, error) {
|
|
results, err := ir.Libpod.ImageRuntime().PruneImages(ctx, opts.All, opts.Filter)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
report := entities.ImagePruneReport{
|
|
Report: entities.Report{
|
|
Id: results,
|
|
Err: nil,
|
|
},
|
|
Size: 0,
|
|
}
|
|
return &report, nil
|
|
}
|
|
|
|
func (ir *ImageEngine) History(ctx context.Context, nameOrId string, opts entities.ImageHistoryOptions) (*entities.ImageHistoryReport, error) {
|
|
image, err := ir.Libpod.ImageRuntime().NewFromLocal(nameOrId)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
results, err := image.History(ctx)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
history := entities.ImageHistoryReport{
|
|
Layers: make([]entities.ImageHistoryLayer, len(results)),
|
|
}
|
|
|
|
for i, layer := range results {
|
|
history.Layers[i] = ToDomainHistoryLayer(layer)
|
|
}
|
|
return &history, nil
|
|
}
|
|
|
|
func ToDomainHistoryLayer(layer *libpodImage.History) entities.ImageHistoryLayer {
|
|
l := entities.ImageHistoryLayer{}
|
|
l.ID = layer.ID
|
|
l.Created = layer.Created.Unix()
|
|
l.CreatedBy = layer.CreatedBy
|
|
copy(l.Tags, layer.Tags)
|
|
l.Size = layer.Size
|
|
l.Comment = layer.Comment
|
|
return l
|
|
}
|
|
|
|
func (ir *ImageEngine) Pull(ctx context.Context, rawImage string, options entities.ImagePullOptions) (*entities.ImagePullReport, error) {
|
|
var writer io.Writer
|
|
if !options.Quiet {
|
|
writer = os.Stderr
|
|
}
|
|
|
|
dockerPrefix := fmt.Sprintf("%s://", docker.Transport.Name())
|
|
imageRef, err := alltransports.ParseImageName(rawImage)
|
|
if err != nil {
|
|
imageRef, err = alltransports.ParseImageName(fmt.Sprintf("%s%s", dockerPrefix, rawImage))
|
|
if err != nil {
|
|
return nil, errors.Errorf("invalid image reference %q", rawImage)
|
|
}
|
|
}
|
|
|
|
// Special-case for docker-archive which allows multiple tags.
|
|
if imageRef.Transport().Name() == dockerarchive.Transport.Name() {
|
|
newImage, err := ir.Libpod.ImageRuntime().LoadFromArchiveReference(ctx, imageRef, options.SignaturePolicy, writer)
|
|
if err != nil {
|
|
return nil, errors.Wrapf(err, "error pulling image %q", rawImage)
|
|
}
|
|
return &entities.ImagePullReport{Images: []string{newImage[0].ID()}}, nil
|
|
}
|
|
|
|
var registryCreds *types.DockerAuthConfig
|
|
if options.Credentials != "" {
|
|
creds, err := util.ParseRegistryCreds(options.Credentials)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
registryCreds = creds
|
|
}
|
|
dockerRegistryOptions := image.DockerRegistryOptions{
|
|
DockerRegistryCreds: registryCreds,
|
|
DockerCertPath: options.CertDir,
|
|
OSChoice: options.OverrideOS,
|
|
ArchitectureChoice: options.OverrideArch,
|
|
DockerInsecureSkipTLSVerify: options.TLSVerify,
|
|
}
|
|
|
|
if !options.AllTags {
|
|
newImage, err := ir.Libpod.ImageRuntime().New(ctx, rawImage, options.SignaturePolicy, options.Authfile, writer, &dockerRegistryOptions, image.SigningOptions{}, nil, util.PullImageAlways)
|
|
if err != nil {
|
|
return nil, errors.Wrapf(err, "error pulling image %q", rawImage)
|
|
}
|
|
return &entities.ImagePullReport{Images: []string{newImage.ID()}}, nil
|
|
}
|
|
|
|
// --all-tags requires the docker transport
|
|
if imageRef.Transport().Name() != docker.Transport.Name() {
|
|
return nil, errors.New("--all-tags requires docker transport")
|
|
}
|
|
|
|
// Trim the docker-transport prefix.
|
|
rawImage = strings.TrimPrefix(rawImage, docker.Transport.Name())
|
|
|
|
// all-tags doesn't work with a tagged reference, so let's check early
|
|
namedRef, err := reference.Parse(rawImage)
|
|
if err != nil {
|
|
return nil, errors.Wrapf(err, "error parsing %q", rawImage)
|
|
}
|
|
if _, isTagged := namedRef.(reference.Tagged); isTagged {
|
|
return nil, errors.New("--all-tags requires a reference without a tag")
|
|
|
|
}
|
|
|
|
systemContext := image.GetSystemContext("", options.Authfile, false)
|
|
tags, err := docker.GetRepositoryTags(ctx, systemContext, imageRef)
|
|
if err != nil {
|
|
return nil, errors.Wrapf(err, "error getting repository tags")
|
|
}
|
|
|
|
var foundIDs []string
|
|
for _, tag := range tags {
|
|
name := rawImage + ":" + tag
|
|
newImage, err := ir.Libpod.ImageRuntime().New(ctx, name, options.SignaturePolicy, options.Authfile, writer, &dockerRegistryOptions, image.SigningOptions{}, nil, util.PullImageAlways)
|
|
if err != nil {
|
|
logrus.Errorf("error pulling image %q", name)
|
|
continue
|
|
}
|
|
foundIDs = append(foundIDs, newImage.ID())
|
|
}
|
|
|
|
if len(tags) != len(foundIDs) {
|
|
return nil, errors.Errorf("error pulling image %q", rawImage)
|
|
}
|
|
return &entities.ImagePullReport{Images: foundIDs}, nil
|
|
}
|
|
|
|
func (ir *ImageEngine) Inspect(ctx context.Context, names []string, opts entities.InspectOptions) (*entities.ImageInspectReport, error) {
|
|
report := entities.ImageInspectReport{
|
|
Errors: make(map[string]error),
|
|
}
|
|
|
|
for _, id := range names {
|
|
img, err := ir.Libpod.ImageRuntime().NewFromLocal(id)
|
|
if err != nil {
|
|
report.Errors[id] = err
|
|
continue
|
|
}
|
|
|
|
results, err := img.Inspect(ctx)
|
|
if err != nil {
|
|
report.Errors[id] = err
|
|
continue
|
|
}
|
|
|
|
cookedResults := entities.ImageData{}
|
|
_ = domainUtils.DeepCopy(&cookedResults, results)
|
|
report.Images = append(report.Images, &cookedResults)
|
|
}
|
|
return &report, nil
|
|
}
|
|
|
|
// func (r *imageRuntime) Delete(ctx context.Context, nameOrId string, opts entities.ImageDeleteOptions) (*entities.ImageDeleteReport, error) {
|
|
// image, err := r.libpod.ImageEngine().NewFromLocal(nameOrId)
|
|
// if err != nil {
|
|
// return nil, err
|
|
// }
|
|
//
|
|
// results, err := r.libpod.RemoveImage(ctx, image, opts.Force)
|
|
// if err != nil {
|
|
// return nil, err
|
|
// }
|
|
//
|
|
// report := entities.ImageDeleteReport{}
|
|
// if err := domainUtils.DeepCopy(&report, results); err != nil {
|
|
// return nil, err
|
|
// }
|
|
// return &report, nil
|
|
// }
|
|
//
|
|
// func (r *imageRuntime) Prune(ctx context.Context, opts entities.ImagePruneOptions) (*entities.ImagePruneReport, error) {
|
|
// // TODO: map FilterOptions
|
|
// id, err := r.libpod.ImageEngine().PruneImages(ctx, opts.All, []string{})
|
|
// if err != nil {
|
|
// return nil, err
|
|
// }
|
|
//
|
|
// // TODO: Determine Size
|
|
// report := entities.ImagePruneReport{}
|
|
// copy(report.Report.Id, id)
|
|
// return &report, nil
|
|
// }
|
|
|
|
func (ir *ImageEngine) Tag(ctx context.Context, nameOrId string, tags []string, options entities.ImageTagOptions) error {
|
|
newImage, err := ir.Libpod.ImageRuntime().NewFromLocal(nameOrId)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
for _, tag := range tags {
|
|
if err := newImage.TagImage(tag); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
func (ir *ImageEngine) Untag(ctx context.Context, nameOrId string, tags []string, options entities.ImageUntagOptions) error {
|
|
newImage, err := ir.Libpod.ImageRuntime().NewFromLocal(nameOrId)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
for _, tag := range tags {
|
|
if err := newImage.UntagImage(tag); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
}
|