mirror of
				https://github.com/containers/podman.git
				synced 2025-11-04 08:56:05 +08:00 
			
		
		
		
	Changes since 2022-05-31: - add --omit-history option (buildah PR 4028) Signed-off-by: Ed Santiago <santiago@redhat.com> Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
		
			
				
	
	
		
			233 lines
		
	
	
		
			6.3 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			233 lines
		
	
	
		
			6.3 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
package libimage
 | 
						|
 | 
						|
import (
 | 
						|
	"context"
 | 
						|
	"time"
 | 
						|
 | 
						|
	"github.com/containers/image/v5/manifest"
 | 
						|
	"github.com/containers/image/v5/types"
 | 
						|
	"github.com/opencontainers/go-digest"
 | 
						|
	ociv1 "github.com/opencontainers/image-spec/specs-go/v1"
 | 
						|
	"github.com/sirupsen/logrus"
 | 
						|
)
 | 
						|
 | 
						|
// ImageData contains the inspected data of an image.
 | 
						|
type ImageData struct {
 | 
						|
	ID           string                        `json:"Id"`
 | 
						|
	Digest       digest.Digest                 `json:"Digest"`
 | 
						|
	RepoTags     []string                      `json:"RepoTags"`
 | 
						|
	RepoDigests  []string                      `json:"RepoDigests"`
 | 
						|
	Parent       string                        `json:"Parent"`
 | 
						|
	Comment      string                        `json:"Comment"`
 | 
						|
	Created      *time.Time                    `json:"Created"`
 | 
						|
	Config       *ociv1.ImageConfig            `json:"Config"`
 | 
						|
	Version      string                        `json:"Version"`
 | 
						|
	Author       string                        `json:"Author"`
 | 
						|
	Architecture string                        `json:"Architecture"`
 | 
						|
	Os           string                        `json:"Os"`
 | 
						|
	Size         int64                         `json:"Size"`
 | 
						|
	VirtualSize  int64                         `json:"VirtualSize"`
 | 
						|
	GraphDriver  *DriverData                   `json:"GraphDriver"`
 | 
						|
	RootFS       *RootFS                       `json:"RootFS"`
 | 
						|
	Labels       map[string]string             `json:"Labels"`
 | 
						|
	Annotations  map[string]string             `json:"Annotations"`
 | 
						|
	ManifestType string                        `json:"ManifestType"`
 | 
						|
	User         string                        `json:"User"`
 | 
						|
	History      []ociv1.History               `json:"History"`
 | 
						|
	NamesHistory []string                      `json:"NamesHistory"`
 | 
						|
	HealthCheck  *manifest.Schema2HealthConfig `json:"Healthcheck,omitempty"`
 | 
						|
}
 | 
						|
 | 
						|
// DriverData includes data on the storage driver of the image.
 | 
						|
type DriverData struct {
 | 
						|
	Name string            `json:"Name"`
 | 
						|
	Data map[string]string `json:"Data"`
 | 
						|
}
 | 
						|
 | 
						|
// RootFS includes data on the root filesystem of the image.
 | 
						|
type RootFS struct {
 | 
						|
	Type   string          `json:"Type"`
 | 
						|
	Layers []digest.Digest `json:"Layers"`
 | 
						|
}
 | 
						|
 | 
						|
// InspectOptions allow for customizing inspecting images.
 | 
						|
type InspectOptions struct {
 | 
						|
	// Compute the size of the image (expensive).
 | 
						|
	WithSize bool
 | 
						|
	// Compute the parent of the image (expensive).
 | 
						|
	WithParent bool
 | 
						|
}
 | 
						|
 | 
						|
// Inspect inspects the image.
 | 
						|
func (i *Image) Inspect(ctx context.Context, options *InspectOptions) (*ImageData, error) {
 | 
						|
	logrus.Debugf("Inspecting image %s", i.ID())
 | 
						|
 | 
						|
	if options == nil {
 | 
						|
		options = &InspectOptions{}
 | 
						|
	}
 | 
						|
 | 
						|
	if i.cached.completeInspectData != nil {
 | 
						|
		if options.WithSize && i.cached.completeInspectData.Size == int64(-1) {
 | 
						|
			size, err := i.Size()
 | 
						|
			if err != nil {
 | 
						|
				return nil, err
 | 
						|
			}
 | 
						|
			i.cached.completeInspectData.Size = size
 | 
						|
		}
 | 
						|
		if options.WithParent && i.cached.completeInspectData.Parent == "" {
 | 
						|
			parentImage, err := i.Parent(ctx)
 | 
						|
			if err != nil {
 | 
						|
				return nil, err
 | 
						|
			}
 | 
						|
			if parentImage != nil {
 | 
						|
				i.cached.completeInspectData.Parent = parentImage.ID()
 | 
						|
			}
 | 
						|
		}
 | 
						|
		return i.cached.completeInspectData, nil
 | 
						|
	}
 | 
						|
 | 
						|
	// First assemble data that does not depend on the format of the image.
 | 
						|
	info, err := i.inspectInfo(ctx)
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
	ociImage, err := i.toOCI(ctx)
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
 | 
						|
	repoTags, err := i.RepoTags()
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
	repoDigests, err := i.RepoDigests()
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
	driverData, err := i.driverData()
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
 | 
						|
	size := int64(-1)
 | 
						|
	if options.WithSize {
 | 
						|
		size, err = i.Size()
 | 
						|
		if err != nil {
 | 
						|
			return nil, err
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	data := &ImageData{
 | 
						|
		ID:           i.ID(),
 | 
						|
		RepoTags:     repoTags,
 | 
						|
		RepoDigests:  repoDigests,
 | 
						|
		Created:      ociImage.Created,
 | 
						|
		Author:       ociImage.Author,
 | 
						|
		Architecture: ociImage.Architecture,
 | 
						|
		Os:           ociImage.OS,
 | 
						|
		Config:       &ociImage.Config,
 | 
						|
		Version:      info.DockerVersion,
 | 
						|
		Size:         size,
 | 
						|
		VirtualSize:  size, // NOTE: same as size. Inherited from Docker where it's scheduled for deprecation.
 | 
						|
		Digest:       i.Digest(),
 | 
						|
		Labels:       info.Labels,
 | 
						|
		RootFS: &RootFS{
 | 
						|
			Type:   ociImage.RootFS.Type,
 | 
						|
			Layers: ociImage.RootFS.DiffIDs,
 | 
						|
		},
 | 
						|
		GraphDriver:  driverData,
 | 
						|
		User:         ociImage.Config.User,
 | 
						|
		History:      ociImage.History,
 | 
						|
		NamesHistory: i.NamesHistory(),
 | 
						|
	}
 | 
						|
 | 
						|
	if options.WithParent {
 | 
						|
		parentImage, err := i.Parent(ctx)
 | 
						|
		if err != nil {
 | 
						|
			return nil, err
 | 
						|
		}
 | 
						|
		if parentImage != nil {
 | 
						|
			data.Parent = parentImage.ID()
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	// Determine the format of the image.  How we determine certain data
 | 
						|
	// depends on the format (e.g., Docker v2s2, OCI v1).
 | 
						|
	src, err := i.source(ctx)
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
	manifestRaw, manifestType, err := src.GetManifest(ctx, nil)
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
 | 
						|
	data.ManifestType = manifestType
 | 
						|
 | 
						|
	switch manifestType {
 | 
						|
	// OCI image
 | 
						|
	case ociv1.MediaTypeImageManifest:
 | 
						|
		var ociManifest ociv1.Manifest
 | 
						|
		if err := json.Unmarshal(manifestRaw, &ociManifest); err != nil {
 | 
						|
			return nil, err
 | 
						|
		}
 | 
						|
		data.Annotations = ociManifest.Annotations
 | 
						|
		if len(ociImage.History) > 0 {
 | 
						|
			data.Comment = ociImage.History[0].Comment
 | 
						|
		}
 | 
						|
 | 
						|
	// Docker image
 | 
						|
	case manifest.DockerV2Schema1MediaType, manifest.DockerV2Schema2MediaType:
 | 
						|
		rawConfig, err := i.rawConfigBlob(ctx)
 | 
						|
		if err != nil {
 | 
						|
			return nil, err
 | 
						|
		}
 | 
						|
		var dockerManifest manifest.Schema2V1Image
 | 
						|
		if err := json.Unmarshal(rawConfig, &dockerManifest); err != nil {
 | 
						|
			return nil, err
 | 
						|
		}
 | 
						|
		data.Comment = dockerManifest.Comment
 | 
						|
		// NOTE: Health checks may be listed in the container config or
 | 
						|
		// the config.
 | 
						|
		data.HealthCheck = dockerManifest.ContainerConfig.Healthcheck
 | 
						|
		if data.HealthCheck == nil {
 | 
						|
			data.HealthCheck = dockerManifest.Config.Healthcheck
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	if data.Annotations == nil {
 | 
						|
		// Podman compat
 | 
						|
		data.Annotations = make(map[string]string)
 | 
						|
	}
 | 
						|
 | 
						|
	i.cached.completeInspectData = data
 | 
						|
 | 
						|
	return data, nil
 | 
						|
}
 | 
						|
 | 
						|
// inspectInfo returns the image inspect info.
 | 
						|
func (i *Image) inspectInfo(ctx context.Context) (*types.ImageInspectInfo, error) {
 | 
						|
	if i.cached.partialInspectData != nil {
 | 
						|
		return i.cached.partialInspectData, nil
 | 
						|
	}
 | 
						|
 | 
						|
	ref, err := i.StorageReference()
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
 | 
						|
	img, err := ref.NewImage(ctx, &i.runtime.systemContext)
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
	defer img.Close()
 | 
						|
 | 
						|
	data, err := img.Inspect(ctx)
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
 | 
						|
	i.cached.partialInspectData = data
 | 
						|
	return data, nil
 | 
						|
}
 |