mirror of
https://github.com/linuxkit/linuxkit.git
synced 2025-07-21 01:59:07 +00:00
Merge pull request #3863 from deitch/rationalize-build-pull
Rationalize build pull
This commit is contained in:
commit
860163a9c7
57
src/cmd/linuxkit/cache/write.go
vendored
57
src/cmd/linuxkit/cache/write.go
vendored
@ -353,3 +353,60 @@ func (p *Provider) DescriptorWrite(ref *reference.Spec, desc v1.Descriptor) (lkt
|
|||||||
&desc,
|
&desc,
|
||||||
), nil
|
), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *Provider) ImageInCache(ref *reference.Spec, trustedRef, architecture string) (bool, error) {
|
||||||
|
if _, err := p.findImage(ref.String(), architecture); err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ImageInRegistry takes an image name and checks that the image manifest or index to which it refers
|
||||||
|
// exists in the registry.
|
||||||
|
func (p *Provider) ImageInRegistry(ref *reference.Spec, trustedRef, architecture string) (bool, error) {
|
||||||
|
image := ref.String()
|
||||||
|
remoteOptions := []remote.Option{remote.WithAuthFromKeychain(authn.DefaultKeychain)}
|
||||||
|
log.Debugf("Checking image %s in registry", image)
|
||||||
|
|
||||||
|
remoteRef, err := name.ParseReference(image)
|
||||||
|
if err != nil {
|
||||||
|
return false, fmt.Errorf("invalid image name %s: %v", image, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
desc, err := remote.Get(remoteRef, remoteOptions...)
|
||||||
|
if err != nil {
|
||||||
|
return false, fmt.Errorf("error getting manifest for image %s: %v", image, err)
|
||||||
|
}
|
||||||
|
// first attempt as an index
|
||||||
|
ii, err := desc.ImageIndex()
|
||||||
|
if err == nil {
|
||||||
|
log.Debugf("ImageExists retrieved %s as index", remoteRef)
|
||||||
|
im, err := ii.IndexManifest()
|
||||||
|
if err != nil {
|
||||||
|
return false, fmt.Errorf("unable to get IndexManifest: %v", err)
|
||||||
|
}
|
||||||
|
for _, m := range im.Manifests {
|
||||||
|
if m.MediaType.IsImage() && (m.Platform == nil || m.Platform.Architecture == architecture) {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// we went through all of the manifests and did not find one that matches the target architecture
|
||||||
|
} else {
|
||||||
|
var im v1.Image
|
||||||
|
// try an image
|
||||||
|
im, err = desc.Image()
|
||||||
|
if err != nil {
|
||||||
|
return false, fmt.Errorf("provided image is neither an image nor an index: %s", image)
|
||||||
|
}
|
||||||
|
log.Debugf("ImageExists retrieved %s as image", remoteRef)
|
||||||
|
conf, err := im.ConfigFile()
|
||||||
|
if err != nil {
|
||||||
|
return false, fmt.Errorf("unable to get ConfigFile: %v", err)
|
||||||
|
}
|
||||||
|
if conf.Architecture == architecture {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
// the image had the wrong architecture
|
||||||
|
}
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
@ -38,6 +38,7 @@ func pkgBuildPush(args []string, withPush bool) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
force := flags.Bool("force", false, "Force rebuild even if image is in local cache")
|
force := flags.Bool("force", false, "Force rebuild even if image is in local cache")
|
||||||
|
pull := flags.Bool("pull", false, "Pull image if in registry but not in local cache; conflicts with --force")
|
||||||
ignoreCache := flags.Bool("ignore-cached", false, "Ignore cached intermediate images, always pulling from registry")
|
ignoreCache := flags.Bool("ignore-cached", false, "Ignore cached intermediate images, always pulling from registry")
|
||||||
docker := flags.Bool("docker", false, "Store the built image in the docker image cache instead of the default linuxkit cache")
|
docker := flags.Bool("docker", false, "Store the built image in the docker image cache instead of the default linuxkit cache")
|
||||||
platforms := flags.String("platforms", "", "Which platforms to build for, defaults to all of those for which the package can be built")
|
platforms := flags.String("platforms", "", "Which platforms to build for, defaults to all of those for which the package can be built")
|
||||||
@ -49,8 +50,10 @@ func pkgBuildPush(args []string, withPush bool) {
|
|||||||
flags.Var(&cacheDir, "cache", fmt.Sprintf("Directory for caching and finding cached image, overrides env var %s", envVarCacheDir))
|
flags.Var(&cacheDir, "cache", fmt.Sprintf("Directory for caching and finding cached image, overrides env var %s", envVarCacheDir))
|
||||||
|
|
||||||
// some logic clarification:
|
// some logic clarification:
|
||||||
// pkg build - always builds unless is in cache
|
// pkg build - builds unless is in cache or published in registry
|
||||||
// pkg build --force - always builds even if is in cache
|
// pkg build --pull - builds unless is in cache or published in registry; pulls from registry if not in cache
|
||||||
|
// pkg build --force - always builds even if is in cache or published in registry
|
||||||
|
// pkg build --force --pull - always builds even if is in cache or published in registry; --pull ignored
|
||||||
// pkg push - always builds unless is in cache
|
// pkg push - always builds unless is in cache
|
||||||
// pkg push --force - always builds even if is in cache
|
// pkg push --force - always builds even if is in cache
|
||||||
// pkg push --nobuild - skips build; if not in cache, fails
|
// pkg push --nobuild - skips build; if not in cache, fails
|
||||||
@ -78,6 +81,10 @@ func pkgBuildPush(args []string, withPush bool) {
|
|||||||
fmt.Fprint(os.Stderr, "flags -force and -nobuild conflict")
|
fmt.Fprint(os.Stderr, "flags -force and -nobuild conflict")
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
if *pull && *force {
|
||||||
|
fmt.Fprint(os.Stderr, "flags -force and -pull conflict")
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
var opts []pkglib.BuildOpt
|
var opts []pkglib.BuildOpt
|
||||||
if *force {
|
if *force {
|
||||||
@ -86,6 +93,9 @@ func pkgBuildPush(args []string, withPush bool) {
|
|||||||
if *ignoreCache {
|
if *ignoreCache {
|
||||||
opts = append(opts, pkglib.WithBuildIgnoreCache())
|
opts = append(opts, pkglib.WithBuildIgnoreCache())
|
||||||
}
|
}
|
||||||
|
if *pull {
|
||||||
|
opts = append(opts, pkglib.WithBuildPull())
|
||||||
|
}
|
||||||
|
|
||||||
opts = append(opts, pkglib.WithBuildCacheDir(cacheDir.String()))
|
opts = append(opts, pkglib.WithBuildCacheDir(cacheDir.String()))
|
||||||
|
|
||||||
|
@ -27,6 +27,7 @@ import (
|
|||||||
type buildOpts struct {
|
type buildOpts struct {
|
||||||
skipBuild bool
|
skipBuild bool
|
||||||
force bool
|
force bool
|
||||||
|
pull bool
|
||||||
ignoreCache bool
|
ignoreCache bool
|
||||||
push bool
|
push bool
|
||||||
release string
|
release string
|
||||||
@ -61,6 +62,14 @@ func WithBuildForce() BuildOpt {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WithBuildPull pull down the image to cache if it already exists in registry
|
||||||
|
func WithBuildPull() BuildOpt {
|
||||||
|
return func(bo *buildOpts) error {
|
||||||
|
bo.pull = true
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// WithBuildPush pushes the result of the build to the registry
|
// WithBuildPush pushes the result of the build to the registry
|
||||||
func WithBuildPush() BuildOpt {
|
func WithBuildPush() BuildOpt {
|
||||||
return func(bo *buildOpts) error {
|
return func(bo *buildOpts) error {
|
||||||
@ -89,6 +98,7 @@ func WithRelease(r string) BuildOpt {
|
|||||||
func WithBuildTargetDockerCache() BuildOpt {
|
func WithBuildTargetDockerCache() BuildOpt {
|
||||||
return func(bo *buildOpts) error {
|
return func(bo *buildOpts) error {
|
||||||
bo.targetDocker = true
|
bo.targetDocker = true
|
||||||
|
bo.pull = true // if we are to load it into docker, it must be in local cache
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -225,13 +235,28 @@ func (p Pkg) Build(bos ...BuildOpt) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var platformsToBuild []imagespec.Platform
|
var platformsToBuild []imagespec.Platform
|
||||||
if bo.force {
|
switch {
|
||||||
|
case bo.force && bo.skipBuild:
|
||||||
|
return errors.New("cannot force build and skip build")
|
||||||
|
case bo.force:
|
||||||
|
// force local build
|
||||||
platformsToBuild = bo.platforms
|
platformsToBuild = bo.platforms
|
||||||
} else if !bo.skipBuild {
|
case bo.skipBuild:
|
||||||
fmt.Fprintf(writer, "checking for %s in local cache, fallback to remote registry...\n", ref)
|
// do not build anything if we explicitly did skipBuild
|
||||||
|
platformsToBuild = nil
|
||||||
|
default:
|
||||||
|
// check local cache, fallback to check registry / pull image from registry, fallback to build
|
||||||
|
fmt.Fprintf(writer, "checking for %s in local cache...\n", ref)
|
||||||
for _, platform := range bo.platforms {
|
for _, platform := range bo.platforms {
|
||||||
|
if exists, err := c.ImageInCache(&ref, "", platform.Architecture); err == nil && exists {
|
||||||
|
fmt.Fprintf(writer, "found %s in local cache, skipping build\n", ref)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if bo.pull {
|
||||||
|
// need to pull the image from the registry, else build
|
||||||
|
fmt.Fprintf(writer, "%s %s not found in local cache, trying to pull\n", ref, platform.Architecture)
|
||||||
if _, err := c.ImagePull(&ref, "", platform.Architecture, false); err == nil {
|
if _, err := c.ImagePull(&ref, "", platform.Architecture, false); err == nil {
|
||||||
fmt.Fprintf(writer, "%s found or pulled\n", ref)
|
fmt.Fprintf(writer, "%s pulled\n", ref)
|
||||||
if bo.targetDocker {
|
if bo.targetDocker {
|
||||||
archRef, err := reference.Parse(fmt.Sprintf("%s-%s", p.FullTag(), platform.Architecture))
|
archRef, err := reference.Parse(fmt.Sprintf("%s-%s", p.FullTag(), platform.Architecture))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -245,9 +270,26 @@ func (p Pkg) Build(bos ...BuildOpt) error {
|
|||||||
platformsToBuild = append(platformsToBuild, platform)
|
platformsToBuild = append(platformsToBuild, platform)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
// successfully pulled, no need to build, continue with next platform
|
||||||
|
continue
|
||||||
|
}
|
||||||
fmt.Fprintf(writer, "%s not found, will build: %s\n", ref, err)
|
fmt.Fprintf(writer, "%s not found, will build: %s\n", ref, err)
|
||||||
platformsToBuild = append(platformsToBuild, platform)
|
platformsToBuild = append(platformsToBuild, platform)
|
||||||
|
} else {
|
||||||
|
// do not pull, just check if it exists in a registry
|
||||||
|
fmt.Fprintf(writer, "%s %s not found in local cache, checking registry\n", ref, platform.Architecture)
|
||||||
|
exists, err := c.ImageInRegistry(&ref, "", platform.Architecture)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error checking remote registry for %s: %v", ref, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if exists {
|
||||||
|
fmt.Fprintf(writer, "%s %s found on registry\n", ref, platform.Architecture)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
fmt.Fprintf(writer, "%s %s not found, will build\n", ref, platform.Architecture)
|
||||||
|
platformsToBuild = append(platformsToBuild, platform)
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -112,6 +112,24 @@ func (c *cacheMocker) ImagePull(ref *reference.Spec, trustedRef, architecture st
|
|||||||
return c.imageWriteStream(ref, architecture, bytes.NewReader(b))
|
return c.imageWriteStream(ref, architecture, bytes.NewReader(b))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *cacheMocker) ImageInCache(ref *reference.Spec, trustedRef, architecture string) (bool, error) {
|
||||||
|
image := ref.String()
|
||||||
|
desc, ok := c.images[image]
|
||||||
|
if !ok {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
for _, d := range desc {
|
||||||
|
if d.Platform != nil && d.Platform.Architecture == architecture {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *cacheMocker) ImageInRegistry(ref *reference.Spec, trustedRef, architecture string) (bool, error) {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (c *cacheMocker) ImageLoad(ref *reference.Spec, architecture string, r io.Reader) (lktspec.ImageSource, error) {
|
func (c *cacheMocker) ImageLoad(ref *reference.Spec, architecture string, r io.Reader) (lktspec.ImageSource, error) {
|
||||||
if !c.enableImageLoad {
|
if !c.enableImageLoad {
|
||||||
return nil, errors.New("ImageLoad disabled")
|
return nil, errors.New("ImageLoad disabled")
|
||||||
|
@ -20,6 +20,12 @@ type CacheProvider interface {
|
|||||||
// efficient and only write missing blobs, based on their content hash. If the ref already
|
// efficient and only write missing blobs, based on their content hash. If the ref already
|
||||||
// exists in the cache, it should not pull anything, unless alwaysPull is set to true.
|
// exists in the cache, it should not pull anything, unless alwaysPull is set to true.
|
||||||
ImagePull(ref *reference.Spec, trustedRef, architecture string, alwaysPull bool) (ImageSource, error)
|
ImagePull(ref *reference.Spec, trustedRef, architecture string, alwaysPull bool) (ImageSource, error)
|
||||||
|
// ImageInCache takes an image name and checks if it exists in the cache, including checking that the given
|
||||||
|
// architecture is complete. Like ImagePull, it should be efficient and only write missing blobs, based on
|
||||||
|
// their content hash.
|
||||||
|
ImageInCache(ref *reference.Spec, trustedRef, architecture string) (bool, error)
|
||||||
|
// ImageInRegistry takes an image name and checks if it exists in the registry.
|
||||||
|
ImageInRegistry(ref *reference.Spec, trustedRef, architecture string) (bool, error)
|
||||||
// IndexWrite takes an image name and creates an index for the descriptors to which it points.
|
// IndexWrite takes an image name and creates an index for the descriptors to which it points.
|
||||||
// Cache implementation determines whether it should pull missing blobs from a remote registry.
|
// Cache implementation determines whether it should pull missing blobs from a remote registry.
|
||||||
// If the provided reference already exists and it is an index, updates the manifests in the
|
// If the provided reference already exists and it is an index, updates the manifests in the
|
||||||
|
Loading…
Reference in New Issue
Block a user