add support for building from cached images

Signed-off-by: Avi Deitcher <avi@deitcher.net>
This commit is contained in:
Avi Deitcher 2022-07-01 15:23:28 +03:00
parent 44dfac2725
commit a90ff542cd
31 changed files with 734 additions and 175 deletions

View File

@ -2,8 +2,10 @@ package cache
import (
"fmt"
"strings"
"github.com/google/go-containerregistry/pkg/v1"
"github.com/containerd/containerd/reference"
v1 "github.com/google/go-containerregistry/pkg/v1"
"github.com/google/go-containerregistry/pkg/v1/match"
"github.com/google/go-containerregistry/pkg/v1/partial"
)
@ -48,20 +50,46 @@ func (p *Provider) findImage(imageName, architecture string) (v1.Image, error) {
return nil, fmt.Errorf("no image found for %s", imageName)
}
// FindDescriptor get the first descriptor pointed to by the image name
func (p *Provider) FindDescriptor(name string) (*v1.Descriptor, error) {
// FindDescriptor get the first descriptor pointed to by the image reference, whether tagged or digested
func (p *Provider) FindDescriptor(ref *reference.Spec) (*v1.Descriptor, error) {
index, err := p.cache.ImageIndex()
// if there is no root index, we are broken
if err != nil {
return nil, fmt.Errorf("invalid image cache: %v", err)
}
descs, err := partial.FindManifests(index, match.Name(name))
// parse the ref.Object to determine what it is, then search by that
dig := ref.Digest()
hash, err := v1.NewHash(dig.String())
// if we had a valid hash, search by that
if err == nil {
// we had a valid hash, so we should search by it
descs, err := partial.FindManifests(index, match.Digests(hash))
if err != nil {
return nil, err
}
if len(descs) < 1 {
return nil, nil
}
if len(descs) > 0 {
return &descs[0], nil
}
// we had a valid hash, but didn't find any descriptors
return nil, nil
}
// no valid hash, try the tag
tag := ref.Object
// remove anything after an '@'
n := strings.LastIndex(tag, "@")
if n == 0 {
return nil, fmt.Errorf("invalid tag, was not digest, yet began with '@': %s", tag)
}
if n >= 0 {
tag = tag[:n]
}
descs, err := partial.FindManifests(index, match.Name(fmt.Sprintf("%s:%s", ref.Locator, tag)))
if err != nil {
return nil, err
}
if len(descs) > 0 {
return &descs[0], nil
}
return nil, nil
}

View File

@ -1,12 +1,15 @@
package cache
import (
"github.com/containerd/containerd/content"
"github.com/containerd/containerd/content/local"
"github.com/google/go-containerregistry/pkg/v1/layout"
)
// Provider cache implementation of cacheProvider
type Provider struct {
cache layout.Path
store content.Store
}
// NewProvider create a new CacheProvider based in the provided directory
@ -15,5 +18,9 @@ func NewProvider(dir string) (*Provider, error) {
if err != nil {
return nil, err
}
return &Provider{p}, nil
store, err := local.NewStore(dir)
if err != nil {
return nil, err
}
return &Provider{p, store}, nil
}

10
src/cmd/linuxkit/cache/store.go vendored Normal file
View File

@ -0,0 +1,10 @@
package cache
import (
"github.com/containerd/containerd/content"
)
// Store get content.Store referencing the cache
func (p *Provider) Store() (content.Store, error) {
return p.store, nil
}

View File

@ -35,14 +35,14 @@ func cacheExport(args []string) {
if err != nil {
log.Fatalf("unable to read a local cache: %v", err)
}
desc, err := p.FindDescriptor(fullname)
if err != nil {
log.Fatalf("unable to find image named %s: %v", name, err)
}
ref, err := reference.Parse(fullname)
if err != nil {
log.Fatalf("invalid image name %s: %v", name, err)
}
desc, err := p.FindDescriptor(&ref)
if err != nil {
log.Fatalf("unable to find image named %s: %v", name, err)
}
src := p.NewSource(&ref, *arch, desc)
reader, err := src.V1TarReader()

View File

@ -26,11 +26,12 @@ require (
github.com/gophercloud/gophercloud v0.1.0
github.com/gophercloud/utils v0.0.0-20181029231510-34f5991525d1
github.com/hashicorp/go-version v1.2.0
github.com/moby/buildkit v0.10.1-0.20220614084718-b3d272e22672
github.com/moby/buildkit v0.10.1-0.20220617010517-a6a114a1a476
github.com/moby/hyperkit v0.0.0-20180416161519-d65b09c1c28a
github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6
github.com/moby/vpnkit v0.4.1-0.20200311130018-2ffc1dd8a84e
github.com/moul/gotty-client v1.7.1-0.20180526075433-e5589f6df359
github.com/opencontainers/go-digest v1.0.0 // indirect
github.com/opencontainers/image-spec v1.0.3-0.20211202183452-c5a74bcca799
github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417
github.com/packethost/packngo v0.1.1-0.20171201154433-f1be085ecd6f

View File

@ -1066,6 +1066,8 @@ github.com/moby/buildkit v0.8.1/go.mod h1:/kyU1hKy/aYCuP39GZA9MaKioovHku57N6cqlK
github.com/moby/buildkit v0.10.1-0.20220403220257-10e6f94bf90d/go.mod h1:WvwAZv8aRScHkqc/+X46cRC2CKMKpqcaX+pRvUTtPes=
github.com/moby/buildkit v0.10.1-0.20220614084718-b3d272e22672 h1:cDyvSdAMu2BSuEaodU0d9Jm7ki/wWibm/s8G/xRurYA=
github.com/moby/buildkit v0.10.1-0.20220614084718-b3d272e22672/go.mod h1:yle9eiU1fiJ/WhC4VTLOaQ6rxFou1mc4AhwScHwysi0=
github.com/moby/buildkit v0.10.1-0.20220617010517-a6a114a1a476 h1:quXwiNE0nC/0bHFJkQKcwetpk1jNHIwwzDpq9hVmxSM=
github.com/moby/buildkit v0.10.1-0.20220617010517-a6a114a1a476/go.mod h1:yle9eiU1fiJ/WhC4VTLOaQ6rxFou1mc4AhwScHwysi0=
github.com/moby/hyperkit v0.0.0-20180416161519-d65b09c1c28a h1:hExo7kltIidoitYnXsnqfvkJXG3YEMbHuQbf9nOMvow=
github.com/moby/hyperkit v0.0.0-20180416161519-d65b09c1c28a/go.mod h1:zGAVB/FkAf4ozkR8CCuj4LcVuErrNsj9APTDFvhOckw=
github.com/moby/locker v1.0.1 h1:fOXqR41zeveg4fFODix+1Ch4mj/gT0NE1XJbp/epuBg=

View File

@ -13,7 +13,9 @@ import (
const (
buildersEnvVar = "LINUXKIT_BUILDERS"
defaultBuilderImage = "moby/buildkit:v0.10.3"
// this is the most recent manifest pointed to by moby/buildkit:master as of 2022-07-13, so it includes
// our required commit. Once there is a normal semver tag later than this, we should switch to it.
defaultBuilderImage = "moby/buildkit@sha256:e7b24395dff0280513cb795fe6dbd77d8f22e49ef9401eedc311c08b2b7fdd0b"
)
func pkgBuild(args []string) {
@ -35,6 +37,7 @@ func pkgBuildPush(args []string, withPush bool) {
}
force := flags.Bool("force", false, "Force rebuild even if image is in local cache")
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")
platforms := flags.String("platforms", "", "Which platforms to build for, defaults to all of those for which the package can be built")
skipPlatforms := flags.String("skip-platforms", "", "Platforms that should be skipped, even if present in build.yml")
@ -78,6 +81,9 @@ func pkgBuildPush(args []string, withPush bool) {
if *force {
opts = append(opts, pkglib.WithBuildForce())
}
if *ignoreCache {
opts = append(opts, pkglib.WithBuildIgnoreCache())
}
opts = append(opts, pkglib.WithBuildCacheDir(*buildCacheDir))
if withPush {

View File

@ -31,6 +31,7 @@ const (
type buildOpts struct {
skipBuild bool
force bool
ignoreCache bool
push bool
release string
manifest bool
@ -161,6 +162,14 @@ func WithBuildBuilderRestart(restart bool) BuildOpt {
}
}
// WithBuildIgnoreCache when building an image, do not look in local cache for dependent images
func WithBuildIgnoreCache() BuildOpt {
return func(bo *buildOpts) error {
bo.ignoreCache = true
return nil
}
}
// Build builds the package
func (p Pkg) Build(bos ...BuildOpt) error {
var bo buildOpts
@ -321,7 +330,7 @@ func (p Pkg) Build(bos ...BuildOpt) error {
}
// get descriptor for root of manifest
desc, err := c.FindDescriptor(p.FullTag())
desc, err := c.FindDescriptor(&ref)
if err != nil {
return err
}
@ -403,7 +412,7 @@ func (p Pkg) buildArch(ctx context.Context, d dockerRunner, c lktspec.CacheProvi
}
if _, err := c.ImagePull(&ref, "", arch, false); err == nil {
fmt.Fprintf(writer, "image already found %s for arch %s", ref, arch)
desc, err := c.FindDescriptor(ref.String())
desc, err := c.FindDescriptor(&ref)
if err != nil {
return nil, fmt.Errorf("could not find root descriptor for %s: %v", ref, err)
}
@ -452,7 +461,12 @@ func (p Pkg) buildArch(ctx context.Context, d dockerRunner, c lktspec.CacheProvi
buildCtx := &buildCtx{sources: p.sources}
platform := fmt.Sprintf("linux/%s", arch)
if err := d.build(ctx, tagArch, p.path, builderName, builderImage, platform, restart, buildCtx.Reader(), stdout, imageBuildOpts); err != nil {
// if we were told to ignore cached dependent images, pass it a nil cache so it cannot read anything
passCache := c
if bo.ignoreCache {
passCache = nil
}
if err := d.build(ctx, tagArch, p.path, builderName, builderImage, platform, restart, passCache, buildCtx.Reader(), stdout, imageBuildOpts); err != nil {
stdoutCloser()
if strings.Contains(err.Error(), "executor failed running [/dev/.buildkit_qemu_emulator") {
return nil, fmt.Errorf("buildkit was unable to emulate %s. check binfmt has been set up and works for this platform: %v", platform, err)

View File

@ -13,10 +13,12 @@ import (
"strings"
"testing"
"github.com/containerd/containerd/content"
"github.com/containerd/containerd/reference"
dockertypes "github.com/docker/docker/api/types"
registry "github.com/google/go-containerregistry/pkg/v1"
"github.com/google/go-containerregistry/pkg/v1/types"
"github.com/linuxkit/linuxkit/src/cmd/linuxkit/spec"
lktspec "github.com/linuxkit/linuxkit/src/cmd/linuxkit/spec"
imagespec "github.com/opencontainers/image-spec/specs-go/v1"
)
@ -52,7 +54,7 @@ func (d *dockerMocker) contextSupportCheck() error {
return errors.New("contexts not supported")
}
func (d *dockerMocker) build(ctx context.Context, tag, pkg, dockerContext, builderImage, platform string, builderRestart bool, stdin io.Reader, stdout io.Writer, imageBuildOpts dockertypes.ImageBuildOptions) error {
func (d *dockerMocker) build(ctx context.Context, tag, pkg, dockerContext, builderImage, platform string, builderRestart bool, c spec.CacheProvider, r io.Reader, stdout io.Writer, imageBuildOpts dockertypes.ImageBuildOptions) error {
if !d.enableBuild {
return errors.New("build disabled")
}
@ -237,7 +239,8 @@ func (c *cacheMocker) DescriptorWrite(ref *reference.Spec, desc registry.Descrip
return c.NewSource(ref, "", &root), nil
}
func (c *cacheMocker) FindDescriptor(name string) (*registry.Descriptor, error) {
func (c *cacheMocker) FindDescriptor(ref *reference.Spec) (*registry.Descriptor, error) {
name := ref.String()
if desc, ok := c.images[name]; ok && len(desc) > 0 {
return &desc[0], nil
}
@ -259,6 +262,11 @@ func (c *cacheMocker) appendImage(image string, root registry.Descriptor) {
c.images[image] = append(c.images[image], root)
}
// Store get content.Store referencing the cache
func (c *cacheMocker) Store() (content.Store, error) {
return nil, errors.New("unsupported")
}
type cacheMockerSource struct {
c *cacheMocker
ref *reference.Spec

View File

@ -15,14 +15,19 @@ import (
"io/ioutil"
"os"
"os/exec"
"path"
"runtime"
"strings"
"time"
"github.com/containerd/containerd/content"
"github.com/containerd/containerd/reference"
"github.com/docker/buildx/util/progress"
"github.com/docker/docker/api/types"
versioncompare "github.com/hashicorp/go-version"
"github.com/linuxkit/linuxkit/src/cmd/linuxkit/registry"
"github.com/linuxkit/linuxkit/src/cmd/linuxkit/spec"
"github.com/linuxkit/linuxkit/src/cmd/linuxkit/util"
buildkitClient "github.com/moby/buildkit/client"
// golint requires comments on non-main(test)
@ -30,6 +35,8 @@ import (
_ "github.com/moby/buildkit/client/connhelper/dockercontainer"
_ "github.com/moby/buildkit/client/connhelper/ssh"
"github.com/moby/buildkit/frontend/dockerfile/builder"
"github.com/moby/buildkit/frontend/dockerfile/instructions"
"github.com/moby/buildkit/frontend/dockerfile/parser"
"github.com/moby/buildkit/session/upload/uploadprovider"
log "github.com/sirupsen/logrus"
)
@ -44,7 +51,7 @@ const (
type dockerRunner interface {
tag(ref, tag string) error
build(ctx context.Context, tag, pkg, dockerContext, builderImage, platform string, restart bool, stdin io.Reader, stdout io.Writer, imageBuildOpts types.ImageBuildOptions) error
build(ctx context.Context, tag, pkg, dockerContext, builderImage, platform string, restart bool, c spec.CacheProvider, r io.Reader, stdout io.Writer, imageBuildOpts types.ImageBuildOptions) error
save(tgt string, refs ...string) error
load(src io.Reader) error
pull(img string) (bool, error)
@ -367,7 +374,7 @@ func (dr *dockerRunnerImpl) tag(ref, tag string) error {
return dr.command(nil, nil, nil, "image", "tag", ref, tag)
}
func (dr *dockerRunnerImpl) build(ctx context.Context, tag, pkg, dockerContext, builderImage, platform string, restart bool, stdin io.Reader, stdout io.Writer, imageBuildOpts types.ImageBuildOptions) error {
func (dr *dockerRunnerImpl) build(ctx context.Context, tag, pkg, dockerContext, builderImage, platform string, restart bool, c spec.CacheProvider, stdin io.Reader, stdout io.Writer, imageBuildOpts types.ImageBuildOptions) error {
// ensure we have a builder
client, err := dr.builder(ctx, dockerContext, builderImage, platform, restart)
if err != nil {
@ -427,6 +434,59 @@ func (dr *dockerRunnerImpl) build(ctx context.Context, tag, pkg, dockerContext,
}
}
// go through the dockerfile to see if we have any provided images cached
if c != nil {
dockerfile := path.Join(pkg, "Dockerfile")
f, err := os.Open(dockerfile)
if err != nil {
return fmt.Errorf("error opening dockerfile %s: %v", dockerfile, err)
}
defer f.Close()
ast, err := parser.Parse(f)
if err != nil {
return fmt.Errorf("error parsing dockerfile from bytes into AST %s: %v", dockerfile, err)
}
stages, _, err := instructions.Parse(ast.AST)
if err != nil {
return fmt.Errorf("error parsing dockerfile from AST into stages %s: %v", dockerfile, err)
}
// go through each stage, get the basename of the image, see if we have it in the linuxkit cache
imageStores := map[string]string{}
for _, stage := range stages {
// see if the provided image name is tagged (docker.io/linuxkit/foo:latest) or digested (docker.io/linuxkit/foo@sha256:abcdefg)
// if neither, we have an error
ref, err := reference.Parse(util.ReferenceExpand(stage.BaseName))
if err != nil {
return fmt.Errorf("could not resolve references for image %s: %v", stage.BaseName, err)
}
gdesc, err := c.FindDescriptor(&ref)
if err != nil {
return fmt.Errorf("invalid name %s", stage.BaseName)
}
// not found, so nothing to look up
if gdesc == nil {
continue
}
hash := gdesc.Digest
imageStores[stage.BaseName] = hash.String()
}
if len(imageStores) > 0 {
// if we made it here, we found the reference
store, err := c.Store()
if err != nil {
return fmt.Errorf("unable to get content store from cache: %v", err)
}
if solveOpts.OCIStores == nil {
solveOpts.OCIStores = map[string]content.Store{}
}
solveOpts.OCIStores["linuxkit-cache"] = store
for image, hash := range imageStores {
solveOpts.FrontendAttrs["context:"+image] = fmt.Sprintf("oci-layout:%s@%s", "linuxkit-cache", hash)
}
}
}
ctx2, cancel := context.WithCancel(context.TODO())
defer cancel()
printer := progress.NewPrinter(ctx2, os.Stderr, os.Stderr, "auto")

View File

@ -3,14 +3,19 @@ package spec
import (
"io"
"github.com/containerd/containerd/content"
"github.com/containerd/containerd/reference"
v1 "github.com/google/go-containerregistry/pkg/v1"
)
// CacheProvider interface for a provide of a cache.
type CacheProvider interface {
// FindDescriptor get the first descriptor pointed to by the image name
FindDescriptor(name string) (*v1.Descriptor, error)
// FindDescriptor find the descriptor pointed to by the reference in the cache.
// ref is a valid reference, such as docker.io/library/alpine:3.15 or alpine@sha256:4edbd2beb5f78b1014028f4fbb99f3237d9561100b6881aabbf5acce2c4f9454
// If both tag and digest are provided, will use digest exclusively.
// Will expand to full names, so "alpine" becomes "docker.io/library/alpine:latest".
// If none is found, returns nil Descriptor and no error.
FindDescriptor(ref *reference.Spec) (*v1.Descriptor, error)
// ImagePull takes an image name and pulls it from a registry to the cache. It should be
// 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.
@ -30,4 +35,6 @@ type CacheProvider interface {
Push(name string) error
// NewSource return an ImageSource for a specific ref and architecture in the cache.
NewSource(ref *reference.Spec, architecture string, descriptor *v1.Descriptor) ImageSource
// Store get content.Store referencing the cache
Store() (content.Store, error)
}

View File

@ -34,8 +34,17 @@ type ImageMetaResolver interface {
ResolveImageConfig(ctx context.Context, ref string, opt ResolveImageConfigOpt) (digest.Digest, []byte, error)
}
type ResolverType int
const (
ResolverTypeRegistry ResolverType = iota
ResolverTypeOCILayout
)
type ResolveImageConfigOpt struct {
Platform *ocispecs.Platform
ResolveMode string
LogName string
ResolverType // default is ResolverTypeRegistry
SessionID string
}

View File

@ -4,6 +4,7 @@ import (
"context"
_ "crypto/sha256" // for opencontainers/go-digest
"encoding/json"
"fmt"
"os"
"strconv"
"strings"
@ -134,6 +135,7 @@ func Image(ref string, opts ...ImageOption) State {
_, dt, err := info.metaResolver.ResolveImageConfig(ctx, ref, ResolveImageConfigOpt{
Platform: p,
ResolveMode: info.resolveMode.String(),
ResolverType: ResolverTypeRegistry,
})
if err != nil {
return State{}, err
@ -149,6 +151,7 @@ func Image(ref string, opts ...ImageOption) State {
dgst, dt, err := info.metaResolver.ResolveImageConfig(context.TODO(), ref, ResolveImageConfigOpt{
Platform: p,
ResolveMode: info.resolveMode.String(),
ResolverType: ResolverTypeRegistry,
})
if err != nil {
return State{}, err
@ -452,6 +455,57 @@ func Differ(t DiffType, required bool) LocalOption {
})
}
func OCILayout(contentStoreID string, dig digest.Digest, opts ...OCILayoutOption) State {
gi := &OCILayoutInfo{}
for _, o := range opts {
o.SetOCILayoutOption(gi)
}
attrs := map[string]string{}
if gi.sessionID != "" {
attrs[pb.AttrOCILayoutSessionID] = gi.sessionID
addCap(&gi.Constraints, pb.CapSourceOCILayoutSessionID)
}
if ll := gi.layerLimit; ll != nil {
attrs[pb.AttrOCILayoutLayerLimit] = strconv.FormatInt(int64(*ll), 10)
addCap(&gi.Constraints, pb.CapSourceOCILayoutLayerLimit)
}
addCap(&gi.Constraints, pb.CapSourceOCILayout)
source := NewSource(fmt.Sprintf("oci-layout://%s@%s", contentStoreID, dig), attrs, gi.Constraints)
return NewState(source.Output())
}
type OCILayoutOption interface {
SetOCILayoutOption(*OCILayoutInfo)
}
type ociLayoutOptionFunc func(*OCILayoutInfo)
func (fn ociLayoutOptionFunc) SetOCILayoutOption(li *OCILayoutInfo) {
fn(li)
}
func OCISessionID(id string) OCILayoutOption {
return ociLayoutOptionFunc(func(oi *OCILayoutInfo) {
oi.sessionID = id
})
}
func OCILayerLimit(limit int) OCILayoutOption {
return ociLayoutOptionFunc(func(oi *OCILayoutInfo) {
oi.layerLimit = &limit
})
}
type OCILayoutInfo struct {
constraintsWrapper
sessionID string
layerLimit *int
}
type DiffType string
const (

View File

@ -455,6 +455,7 @@ type ConstraintsOpt interface {
HTTPOption
ImageOption
GitOption
OCILayoutOption
}
type constraintsOptFunc func(m *Constraints)
@ -471,6 +472,10 @@ func (fn constraintsOptFunc) SetLocalOption(li *LocalInfo) {
li.applyConstraints(fn)
}
func (fn constraintsOptFunc) SetOCILayoutOption(oi *OCILayoutInfo) {
oi.applyConstraints(fn)
}
func (fn constraintsOptFunc) SetHTTPOption(hi *HTTPInfo) {
hi.applyConstraints(fn)
}

View File

@ -33,6 +33,7 @@ import (
type SolveOpt struct {
Exports []ExportEntry
LocalDirs map[string]string
OCIStores map[string]content.Store
SharedKey string
Frontend string
FrontendAttrs map[string]string
@ -158,8 +159,27 @@ func (c *Client) solve(ctx context.Context, def *llb.Definition, runGateway runG
}
}
if len(cacheOpt.contentStores) > 0 {
s.Allow(sessioncontent.NewAttachable(cacheOpt.contentStores))
// this is a new map that contains both cacheOpt stores and OCILayout stores
contentStores := make(map[string]content.Store, len(cacheOpt.contentStores)+len(opt.OCIStores))
// copy over the stores references from cacheOpt
for key, store := range cacheOpt.contentStores {
contentStores[key] = store
}
// copy over the stores references from ociLayout opts
for key, store := range opt.OCIStores {
// conflicts are not allowed
if _, ok := contentStores[key]; ok {
// we probably should check if the store is identical, but given that
// https://pkg.go.dev/github.com/containerd/containerd/content#Store
// is just an interface, composing 4 others, that is rather hard to do.
// For a future iteration.
return nil, errors.Errorf("contentStore key %s exists in both cache and OCI layouts", key)
}
contentStores[key] = store
}
if len(contentStores) > 0 {
s.Allow(sessioncontent.NewAttachable(contentStores))
}
eg.Go(func() error {

View File

@ -0,0 +1,115 @@
package exptypes
import (
"fmt"
"regexp"
"github.com/containerd/containerd/platforms"
ocispecs "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/pkg/errors"
)
const (
AnnotationIndex = "index"
AnnotationIndexDescriptor = "index-descriptor"
AnnotationManifest = "manifest"
AnnotationManifestDescriptor = "manifest-descriptor"
)
var (
keyAnnotationRegexp = regexp.MustCompile(`^annotation(?:-([a-z-]+))?(?:\[([A-Za-z0-9_/-]+)\])?\.(\S+)$`)
)
type AnnotationKey struct {
Type string
Platform *ocispecs.Platform
Key string
}
func (k AnnotationKey) String() string {
prefix := "annotation"
switch k.Type {
case "":
case AnnotationManifest, AnnotationManifestDescriptor:
prefix += fmt.Sprintf("-%s", k.Type)
if p := k.PlatformString(); p != "" {
prefix += fmt.Sprintf("[%s]", p)
}
case AnnotationIndex, AnnotationIndexDescriptor:
prefix += "-" + k.Type
default:
panic("unknown annotation type")
}
return fmt.Sprintf("%s.%s", prefix, k.Key)
}
func (k AnnotationKey) PlatformString() string {
if k.Platform == nil {
return ""
}
return platforms.Format(*k.Platform)
}
func AnnotationIndexKey(key string) string {
return AnnotationKey{
Type: AnnotationIndex,
Key: key,
}.String()
}
func AnnotationIndexDescriptorKey(key string) string {
return AnnotationKey{
Type: AnnotationIndexDescriptor,
Key: key,
}.String()
}
func AnnotationManifestKey(p *ocispecs.Platform, key string) string {
return AnnotationKey{
Type: AnnotationManifest,
Platform: p,
Key: key,
}.String()
}
func AnnotationManifestDescriptorKey(p *ocispecs.Platform, key string) string {
return AnnotationKey{
Type: AnnotationManifestDescriptor,
Platform: p,
Key: key,
}.String()
}
func ParseAnnotationKey(result string) (AnnotationKey, bool, error) {
groups := keyAnnotationRegexp.FindStringSubmatch(result)
if groups == nil {
return AnnotationKey{}, false, nil
}
tp, platform, key := groups[1], groups[2], groups[3]
switch tp {
case AnnotationIndex, AnnotationIndexDescriptor, AnnotationManifest, AnnotationManifestDescriptor:
case "":
tp = AnnotationManifest
default:
return AnnotationKey{}, true, errors.Errorf("unrecognized annotation type %s", tp)
}
var ociPlatform *ocispecs.Platform
if platform != "" {
p, err := platforms.Parse(platform)
if err != nil {
return AnnotationKey{}, true, err
}
ociPlatform = &p
}
annotation := AnnotationKey{
Type: tp,
Platform: ociPlatform,
Key: key,
}
return annotation, true, nil
}

View File

@ -27,6 +27,7 @@ import (
"github.com/moby/buildkit/solver/errdefs"
"github.com/moby/buildkit/solver/pb"
binfotypes "github.com/moby/buildkit/util/buildinfo/types"
digest "github.com/opencontainers/go-digest"
ocispecs "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/pkg/errors"
"golang.org/x/sync/errgroup"
@ -455,7 +456,7 @@ func Build(ctx context.Context, c client.Client) (*client.Result, error) {
}
c.Warn(ctx, defVtx, msg, warnOpts(sourceMap, location, detail, url))
},
ContextByName: contextByNameFunc(c, tp),
ContextByName: contextByNameFunc(c, c.BuildOpts().SessionID, tp),
})
if err != nil {
@ -787,7 +788,7 @@ func warnOpts(sm *llb.SourceMap, r *parser.Range, detail [][]byte, url string) c
return opts
}
func contextByNameFunc(c client.Client, p *ocispecs.Platform) func(context.Context, string, string) (*llb.State, *dockerfile2llb.Image, *binfotypes.BuildInfo, error) {
func contextByNameFunc(c client.Client, sessionID string, p *ocispecs.Platform) func(context.Context, string, string) (*llb.State, *dockerfile2llb.Image, *binfotypes.BuildInfo, error) {
return func(ctx context.Context, name, resolveMode string) (*llb.State, *dockerfile2llb.Image, *binfotypes.BuildInfo, error) {
named, err := reference.ParseNormalizedNamed(name)
if err != nil {
@ -801,7 +802,7 @@ func contextByNameFunc(c client.Client, p *ocispecs.Platform) func(context.Conte
}
if p != nil {
name := name + "::" + platforms.Format(platforms.Normalize(*p))
st, img, bi, err := contextByName(ctx, c, name, p, resolveMode)
st, img, bi, err := contextByName(ctx, c, sessionID, name, p, resolveMode)
if err != nil {
return nil, nil, nil, err
}
@ -809,11 +810,11 @@ func contextByNameFunc(c client.Client, p *ocispecs.Platform) func(context.Conte
return st, img, bi, nil
}
}
return contextByName(ctx, c, name, p, resolveMode)
return contextByName(ctx, c, sessionID, name, p, resolveMode)
}
}
func contextByName(ctx context.Context, c client.Client, name string, platform *ocispecs.Platform, resolveMode string) (*llb.State, *dockerfile2llb.Image, *binfotypes.BuildInfo, error) {
func contextByName(ctx context.Context, c client.Client, sessionID, name string, platform *ocispecs.Platform, resolveMode string) (*llb.State, *dockerfile2llb.Image, *binfotypes.BuildInfo, error) {
opts := c.BuildOpts().Opts
v, ok := opts["context:"+name]
if !ok {
@ -849,6 +850,8 @@ func contextByName(ctx context.Context, c client.Client, name string, platform *
Platform: platform,
ResolveMode: resolveMode,
LogName: fmt.Sprintf("[context %s] load metadata for %s", name, ref),
ResolverType: llb.ResolverTypeRegistry,
SessionID: sessionID,
})
if err != nil {
return nil, nil, nil, err
@ -878,6 +881,49 @@ func contextByName(ctx context.Context, c client.Client, name string, platform *
st = &httpst
}
return st, nil, nil, nil
case "oci-layout":
ref := strings.TrimPrefix(vv[1], "//")
// expected format is storeID@hash
parts := strings.SplitN(ref, "@", 2)
if len(parts) != 2 {
return nil, nil, nil, errors.Errorf("invalid oci-layout format '%s', must be oci-layout:///content-store@sha256:digest", vv[1])
}
storeID := parts[0]
dig, err := digest.Parse(parts[1])
if err != nil {
return nil, nil, nil, errors.Errorf("invalid digest format '%s', must be oci-layout:///content-store@sha256:digest", vv[1])
}
// the ref now is "content-store@sha256:digest"
// ResolveImageConfig will try to treat that as a valid reference,
// to be parsed with https://pkg.go.dev/github.com/containerd/containerd@v1.6.6/reference#Parse
// That will fail, because it will think that "content-store@sha256" is a host and "digest" is a port.
// To get it to pass, we need to jury-rig it with a host, so that it is a legitimate ref and can
// be processed.
// A reasonable format is storeID as host, so
// storeID/image@digest
// We do not support any image lookup for now, so any image will do; it is ignored.
usableRef := fmt.Sprintf("%s/%s@%s", storeID, "image", dig)
_, data, err := c.ResolveImageConfig(ctx, usableRef, llb.ResolveImageConfigOpt{
Platform: platform,
ResolveMode: resolveMode,
LogName: fmt.Sprintf("[context %s] load metadata for %s", name, ref),
ResolverType: llb.ResolverTypeOCILayout,
})
if err != nil {
return nil, nil, nil, err
}
st := llb.OCILayout(storeID, dig,
llb.WithCustomName("[context "+name+"] OCI load from client"),
llb.OCISessionID(c.BuildOpts().SessionID),
)
st, err = st.WithImageConfig(data)
if err != nil {
return nil, nil, nil, err
}
return &st, nil, nil, nil
case "local":
st := llb.Local(vv[1],
llb.SessionID(c.BuildOpts().SessionID),

View File

@ -335,6 +335,7 @@ func Dockerfile2LLB(ctx context.Context, dt []byte, opt ConvertOpt) (*llb.State,
Platform: platform,
ResolveMode: opt.ImageResolveMode.String(),
LogName: fmt.Sprintf("%s load metadata for %s", prefix, d.stage.BaseName),
ResolverType: llb.ResolverTypeRegistry,
})
if err != nil {
return suggest.WrapError(errors.Wrap(err, origName), origName, append(allStageNames, commonImageNames()...), true)

View File

@ -459,7 +459,7 @@ func (c *grpcClient) ResolveImageConfig(ctx context.Context, ref string, opt llb
OSFeatures: platform.OSFeatures,
}
}
resp, err := c.client.ResolveImageConfig(ctx, &pb.ResolveImageConfigRequest{Ref: ref, Platform: p, ResolveMode: opt.ResolveMode, LogName: opt.LogName})
resp, err := c.client.ResolveImageConfig(ctx, &pb.ResolveImageConfigRequest{Ref: ref, Platform: p, ResolveMode: opt.ResolveMode, LogName: opt.LogName, ResolverType: int32(opt.ResolverType), SessionID: opt.SessionID})
if err != nil {
return "", nil, err
}

View File

@ -489,6 +489,8 @@ type ResolveImageConfigRequest struct {
Platform *pb.Platform `protobuf:"bytes,2,opt,name=Platform,proto3" json:"Platform,omitempty"`
ResolveMode string `protobuf:"bytes,3,opt,name=ResolveMode,proto3" json:"ResolveMode,omitempty"`
LogName string `protobuf:"bytes,4,opt,name=LogName,proto3" json:"LogName,omitempty"`
ResolverType int32 `protobuf:"varint,5,opt,name=ResolverType,proto3" json:"ResolverType,omitempty"`
SessionID string `protobuf:"bytes,6,opt,name=SessionID,proto3" json:"SessionID,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
@ -555,6 +557,20 @@ func (m *ResolveImageConfigRequest) GetLogName() string {
return ""
}
func (m *ResolveImageConfigRequest) GetResolverType() int32 {
if m != nil {
return m.ResolverType
}
return 0
}
func (m *ResolveImageConfigRequest) GetSessionID() string {
if m != nil {
return m.SessionID
}
return ""
}
type ResolveImageConfigResponse struct {
Digest github_com_opencontainers_go_digest.Digest `protobuf:"bytes,1,opt,name=Digest,proto3,customtype=github.com/opencontainers/go-digest.Digest" json:"Digest"`
Config []byte `protobuf:"bytes,2,opt,name=Config,proto3" json:"Config,omitempty"`
@ -2248,136 +2264,138 @@ func init() {
func init() { proto.RegisterFile("gateway.proto", fileDescriptor_f1a937782ebbded5) }
var fileDescriptor_f1a937782ebbded5 = []byte{
// 2060 bytes of a gzipped FileDescriptorProto
// 2086 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x58, 0xcd, 0x6f, 0xe3, 0xc6,
0x15, 0x37, 0x2d, 0xd9, 0x92, 0x9e, 0x3e, 0xd6, 0x99, 0xa4, 0x29, 0x43, 0x04, 0x1b, 0x87, 0x4d,
0x5d, 0xed, 0xc6, 0xa1, 0x52, 0x6f, 0x02, 0x6f, 0xbd, 0x45, 0xd2, 0xf5, 0x17, 0xec, 0xc4, 0xf6,
0xba, 0xe3, 0x14, 0x0b, 0x04, 0x29, 0x50, 0x5a, 0x1c, 0x69, 0x89, 0xa5, 0x39, 0xec, 0x70, 0xb4,
0x5e, 0x27, 0x97, 0xf6, 0xd6, 0x63, 0x81, 0x02, 0xbd, 0x16, 0xe8, 0x5f, 0xd0, 0x53, 0x8f, 0x3d,
0xe7, 0xd8, 0x63, 0xd1, 0x43, 0x50, 0xec, 0x1f, 0x51, 0xa0, 0xb7, 0xe2, 0xcd, 0x0c, 0x25, 0x4a,
0x96, 0x29, 0x0b, 0x39, 0x69, 0xe6, 0xf1, 0xfd, 0xde, 0xbc, 0xaf, 0x79, 0xef, 0x8d, 0xa0, 0xd9,
0xf7, 0x25, 0xbb, 0xf4, 0xaf, 0xbc, 0x44, 0x70, 0xc9, 0xc9, 0x5b, 0x17, 0xfc, 0xfc, 0xca, 0x3b,
0x1f, 0x84, 0x51, 0xf0, 0x3c, 0x94, 0xde, 0x8b, 0x9f, 0x7a, 0x3d, 0xc1, 0x63, 0xc9, 0xe2, 0xc0,
0xf9, 0xa0, 0x1f, 0xca, 0x67, 0x83, 0x73, 0xaf, 0xcb, 0x2f, 0x3a, 0x7d, 0xde, 0xe7, 0x1d, 0x85,
0x38, 0x1f, 0xf4, 0xd4, 0x4e, 0x6d, 0xd4, 0x4a, 0x4b, 0x72, 0x36, 0x26, 0xd9, 0xfb, 0x9c, 0xf7,
0x23, 0xe6, 0x27, 0x61, 0x6a, 0x96, 0x1d, 0x91, 0x74, 0x3b, 0xa9, 0xf4, 0xe5, 0x20, 0x35, 0x98,
0xf5, 0x1c, 0x06, 0x15, 0xe9, 0x64, 0x8a, 0x74, 0x52, 0x1e, 0xbd, 0x60, 0xa2, 0x93, 0x9c, 0x77,
0x78, 0x92, 0x71, 0x77, 0x6e, 0xe4, 0xf6, 0x93, 0xb0, 0x23, 0xaf, 0x12, 0x96, 0x76, 0x2e, 0xb9,
0x78, 0xce, 0x84, 0x01, 0x3c, 0xb8, 0x11, 0x30, 0x90, 0x61, 0x84, 0xa8, 0xae, 0x9f, 0xa4, 0x78,
0x08, 0xfe, 0x1a, 0x50, 0xde, 0x6c, 0xc9, 0xe3, 0x30, 0x95, 0x61, 0xd8, 0x0f, 0x3b, 0xbd, 0x54,
0x61, 0xf4, 0x29, 0x68, 0x84, 0x66, 0x77, 0xff, 0x50, 0x82, 0x65, 0xca, 0xd2, 0x41, 0x24, 0xc9,
0x1a, 0x34, 0x05, 0xeb, 0xed, 0xb2, 0x44, 0xb0, 0xae, 0x2f, 0x59, 0x60, 0x5b, 0xab, 0x56, 0xbb,
0x76, 0xb0, 0x40, 0xc7, 0xc9, 0xe4, 0x57, 0xd0, 0x12, 0xac, 0x97, 0xe6, 0x18, 0x17, 0x57, 0xad,
0x76, 0x7d, 0xe3, 0x7d, 0xef, 0xc6, 0x60, 0x78, 0x94, 0xf5, 0x8e, 0xfd, 0x64, 0x04, 0x39, 0x58,
0xa0, 0x13, 0x42, 0xc8, 0x06, 0x94, 0x04, 0xeb, 0xd9, 0x25, 0x25, 0xeb, 0x6e, 0xb1, 0xac, 0x83,
0x05, 0x8a, 0xcc, 0x64, 0x13, 0xca, 0x28, 0xc5, 0x2e, 0x2b, 0xd0, 0xbb, 0x33, 0x15, 0x38, 0x58,
0xa0, 0x0a, 0x40, 0x3e, 0x87, 0xea, 0x05, 0x93, 0x7e, 0xe0, 0x4b, 0xdf, 0x86, 0xd5, 0x52, 0xbb,
0xbe, 0xd1, 0x29, 0x04, 0xa3, 0x83, 0xbc, 0x63, 0x83, 0xd8, 0x8b, 0xa5, 0xb8, 0xa2, 0x43, 0x01,
0xce, 0x23, 0x68, 0x8e, 0x7d, 0x22, 0x2b, 0x50, 0x7a, 0xce, 0xae, 0xb4, 0xff, 0x28, 0x2e, 0xc9,
0x1b, 0xb0, 0xf4, 0xc2, 0x8f, 0x06, 0x4c, 0xb9, 0xaa, 0x41, 0xf5, 0x66, 0x6b, 0xf1, 0xa1, 0xb5,
0x5d, 0x85, 0x65, 0xa1, 0xc4, 0xbb, 0x7f, 0xb6, 0x60, 0x65, 0xd2, 0x4f, 0xe4, 0xd0, 0x58, 0x68,
0x29, 0x25, 0x3f, 0x9e, 0xc3, 0xc5, 0x48, 0x48, 0xb5, 0xaa, 0x4a, 0x84, 0xb3, 0x09, 0xb5, 0x21,
0x69, 0x96, 0x8a, 0xb5, 0x9c, 0x8a, 0xee, 0x26, 0x94, 0x28, 0xeb, 0x91, 0x16, 0x2c, 0x86, 0x26,
0x29, 0xe8, 0x62, 0x18, 0x90, 0x55, 0x28, 0x05, 0xac, 0x67, 0x82, 0xdf, 0xf2, 0x92, 0x73, 0x6f,
0x97, 0xf5, 0xc2, 0x38, 0x94, 0x21, 0x8f, 0x29, 0x7e, 0x72, 0xff, 0x6a, 0x61, 0x72, 0xa1, 0x5a,
0xe4, 0xd3, 0x31, 0x3b, 0x66, 0xa7, 0xca, 0x35, 0xed, 0x9f, 0x16, 0x6b, 0xff, 0x51, 0x5e, 0xfb,
0x99, 0xf9, 0x93, 0xb7, 0x4e, 0x42, 0x93, 0x32, 0x39, 0x10, 0x31, 0x65, 0xbf, 0x1d, 0xb0, 0x54,
0x92, 0x9f, 0x65, 0x11, 0x51, 0xf2, 0x67, 0xa5, 0x15, 0x32, 0x52, 0x03, 0x20, 0x6d, 0x58, 0x62,
0x42, 0x70, 0x61, 0xb4, 0x20, 0x9e, 0xae, 0x1c, 0x9e, 0x48, 0xba, 0xde, 0x99, 0xaa, 0x1c, 0x54,
0x33, 0xb8, 0x2b, 0xd0, 0xca, 0x4e, 0x4d, 0x13, 0x1e, 0xa7, 0xcc, 0xbd, 0x03, 0xcd, 0xc3, 0x38,
0x19, 0xc8, 0xd4, 0xe8, 0xe1, 0xfe, 0xc3, 0x82, 0x56, 0x46, 0xd1, 0x3c, 0xe4, 0x2b, 0xa8, 0x8f,
0x7c, 0x9c, 0x39, 0x73, 0xab, 0x40, 0xbf, 0x71, 0x7c, 0x2e, 0x40, 0xc6, 0xb7, 0x79, 0x71, 0xce,
0x09, 0xac, 0x4c, 0x32, 0x4c, 0xf1, 0xf4, 0x7b, 0xe3, 0x9e, 0x9e, 0x0c, 0x7c, 0xce, 0xb3, 0x7f,
0xb2, 0xe0, 0x2d, 0xca, 0x54, 0x29, 0x3c, 0xbc, 0xf0, 0xfb, 0x6c, 0x87, 0xc7, 0xbd, 0xb0, 0x9f,
0xb9, 0x79, 0x45, 0x65, 0x55, 0x26, 0x19, 0x13, 0xac, 0x0d, 0xd5, 0xd3, 0xc8, 0x97, 0x3d, 0x2e,
0x2e, 0x8c, 0xf0, 0x06, 0x0a, 0xcf, 0x68, 0x74, 0xf8, 0x95, 0xac, 0x42, 0xdd, 0x08, 0x3e, 0xe6,
0x01, 0x53, 0x35, 0xa3, 0x46, 0xf3, 0x24, 0x62, 0x43, 0xe5, 0x88, 0xf7, 0x4f, 0xfc, 0x0b, 0xa6,
0x8a, 0x43, 0x8d, 0x66, 0x5b, 0xf7, 0x77, 0x16, 0x38, 0xd3, 0xb4, 0x32, 0x2e, 0xfe, 0x0c, 0x96,
0x77, 0xc3, 0x3e, 0x4b, 0x75, 0xf4, 0x6b, 0xdb, 0x1b, 0xdf, 0x7e, 0xf7, 0xce, 0xc2, 0xbf, 0xbf,
0x7b, 0xe7, 0x7e, 0xae, 0xae, 0xf2, 0x84, 0xc5, 0x5d, 0x1e, 0x4b, 0x3f, 0x8c, 0x99, 0xc0, 0xf6,
0xf0, 0x41, 0xa0, 0x20, 0x9e, 0x46, 0x52, 0x23, 0x81, 0xbc, 0x09, 0xcb, 0x5a, 0xba, 0xb9, 0xf6,
0x66, 0xe7, 0xfe, 0x7d, 0x09, 0x1a, 0x67, 0xa8, 0x40, 0xe6, 0x0b, 0x0f, 0x60, 0xe4, 0x42, 0x93,
0x76, 0x93, 0x8e, 0xcd, 0x71, 0x10, 0x07, 0xaa, 0xfb, 0x26, 0xc4, 0xe6, 0xba, 0x0e, 0xf7, 0xe4,
0x4b, 0xa8, 0x67, 0xeb, 0x27, 0x89, 0xb4, 0x4b, 0x2a, 0x47, 0x1e, 0x16, 0xe4, 0x48, 0x5e, 0x13,
0x2f, 0x07, 0x35, 0x19, 0x92, 0xa3, 0x90, 0x75, 0x78, 0xcd, 0x8f, 0x22, 0x7e, 0x69, 0xd2, 0x5e,
0x25, 0xb0, 0xbd, 0xb4, 0x6a, 0xb5, 0xab, 0xf4, 0xfa, 0x07, 0xf2, 0x21, 0xbc, 0x9e, 0x23, 0x3e,
0x16, 0xc2, 0xbf, 0xc2, 0x88, 0x2f, 0x2b, 0xfe, 0x69, 0x9f, 0xb0, 0x06, 0xed, 0x87, 0xb1, 0x1f,
0xd9, 0xa0, 0x78, 0xf4, 0x86, 0xb8, 0xd0, 0xd8, 0x7b, 0x99, 0x70, 0x21, 0x99, 0x78, 0x2c, 0xa5,
0xb0, 0xeb, 0xca, 0x99, 0x63, 0x34, 0x72, 0x0a, 0x8d, 0x1d, 0xbf, 0xfb, 0x8c, 0x1d, 0x5e, 0x20,
0x31, 0xb5, 0x1b, 0xca, 0xec, 0xf5, 0x02, 0xb3, 0x15, 0xfb, 0x93, 0x24, 0x77, 0x19, 0xc6, 0x24,
0x90, 0x2e, 0xb4, 0x32, 0xd3, 0xf5, 0x2d, 0xb2, 0x9b, 0x4a, 0xe6, 0xa3, 0x79, 0x5d, 0xa9, 0xd1,
0xfa, 0x88, 0x09, 0x91, 0x18, 0xc8, 0x3d, 0xbc, 0x30, 0xbe, 0x64, 0x76, 0x4b, 0xd9, 0x3c, 0xdc,
0x3b, 0x9f, 0xc0, 0xca, 0x64, 0x34, 0xe6, 0x29, 0xdb, 0xce, 0x2f, 0xe1, 0xf5, 0x29, 0x2a, 0x7c,
0xaf, 0x1b, 0xfd, 0x37, 0x0b, 0x5e, 0xbb, 0xe6, 0x37, 0x42, 0xa0, 0xfc, 0xc5, 0x55, 0xc2, 0x8c,
0x48, 0xb5, 0x26, 0xc7, 0xb0, 0x84, 0x71, 0x49, 0xed, 0x45, 0xe5, 0xb4, 0xcd, 0x79, 0x02, 0xe1,
0x29, 0xa4, 0x76, 0x98, 0x96, 0xe2, 0x3c, 0x04, 0x18, 0x11, 0xe7, 0x6a, 0x5e, 0x5f, 0x41, 0xd3,
0x44, 0xc5, 0x5c, 0xf0, 0x15, 0x3d, 0x67, 0x18, 0x30, 0x4e, 0x11, 0xa3, 0x82, 0x5f, 0x9a, 0xb3,
0xe0, 0xbb, 0xdf, 0xc0, 0x1d, 0xca, 0xfc, 0x60, 0x3f, 0x8c, 0xd8, 0xcd, 0x75, 0x0d, 0x6f, 0x6b,
0x18, 0xb1, 0x53, 0x5f, 0x3e, 0x1b, 0xde, 0x56, 0xb3, 0x27, 0x5b, 0xb0, 0x44, 0xfd, 0xb8, 0xcf,
0xcc, 0xd1, 0xef, 0x15, 0x1c, 0xad, 0x0e, 0x41, 0x5e, 0xaa, 0x21, 0xee, 0x23, 0xa8, 0x0d, 0x69,
0x58, 0x6b, 0x9e, 0xf4, 0x7a, 0x29, 0xd3, 0x75, 0xab, 0x44, 0xcd, 0x0e, 0xe9, 0x47, 0x2c, 0xee,
0x9b, 0xa3, 0x4b, 0xd4, 0xec, 0xdc, 0x35, 0x1c, 0x36, 0x32, 0xcd, 0x8d, 0x6b, 0x08, 0x94, 0x77,
0x71, 0x22, 0xb2, 0xd4, 0x05, 0x53, 0x6b, 0x37, 0xc0, 0x46, 0xe5, 0x07, 0xbb, 0xa1, 0xb8, 0xd9,
0x40, 0x1b, 0x2a, 0xbb, 0xa1, 0xc8, 0xd9, 0x97, 0x6d, 0xc9, 0x1a, 0xb6, 0xb0, 0x6e, 0x34, 0x08,
0xd0, 0x5a, 0xc9, 0x44, 0x6c, 0x6a, 0xf5, 0x04, 0xd5, 0xfd, 0x54, 0xfb, 0x51, 0x9d, 0x62, 0x94,
0x59, 0x87, 0x0a, 0x8b, 0xa5, 0x08, 0x59, 0xd6, 0xe7, 0x88, 0xa7, 0x87, 0x58, 0x4f, 0x0d, 0xb1,
0xaa, 0x9f, 0xd2, 0x8c, 0xc5, 0xdd, 0x84, 0x3b, 0x48, 0x28, 0x0e, 0x04, 0x81, 0x72, 0x4e, 0x49,
0xb5, 0x76, 0xb7, 0x60, 0x65, 0x04, 0x34, 0x47, 0xaf, 0x41, 0x19, 0x47, 0x64, 0x53, 0x88, 0xa7,
0x9d, 0xab, 0xbe, 0xbb, 0x4d, 0xa8, 0x9f, 0x86, 0x71, 0xd6, 0xd1, 0xdc, 0x57, 0x16, 0x34, 0x4e,
0x79, 0x3c, 0xea, 0x25, 0xa7, 0x70, 0x27, 0xbb, 0x81, 0x8f, 0x4f, 0x0f, 0x77, 0xfc, 0x24, 0x33,
0x65, 0xf5, 0x7a, 0x98, 0xcd, 0x34, 0xef, 0x69, 0xc6, 0xed, 0x32, 0xb6, 0x1d, 0x3a, 0x09, 0x27,
0xbf, 0x80, 0xca, 0xd1, 0xd1, 0xb6, 0x92, 0xb4, 0x38, 0x97, 0xa4, 0x0c, 0x46, 0x3e, 0x81, 0xca,
0x53, 0xf5, 0xc8, 0x48, 0x4d, 0x6b, 0x98, 0x92, 0x72, 0xda, 0x50, 0xcd, 0x46, 0x59, 0x97, 0x8b,
0x80, 0x66, 0x20, 0xf7, 0xbf, 0x16, 0xd4, 0x9f, 0xfa, 0xa3, 0x69, 0xe9, 0x33, 0x58, 0x0e, 0xbe,
0x77, 0xbf, 0xd4, 0x5b, 0xbc, 0xc5, 0x11, 0x7b, 0xc1, 0x22, 0x93, 0xaa, 0x7a, 0x83, 0xd4, 0xf4,
0x19, 0x17, 0xfa, 0x76, 0x36, 0xa8, 0xde, 0x60, 0x5e, 0x07, 0x4c, 0xfa, 0x61, 0x64, 0x97, 0x57,
0x4b, 0xd8, 0x5b, 0xf5, 0x0e, 0xa3, 0x3e, 0x10, 0x91, 0x6a, 0x4a, 0x35, 0x8a, 0x4b, 0xe2, 0x42,
0x39, 0x8c, 0x7b, 0x5c, 0xf5, 0x1d, 0x53, 0xdd, 0xce, 0xf8, 0x40, 0x74, 0xd9, 0x61, 0xdc, 0xe3,
0x54, 0x7d, 0x23, 0xef, 0xc2, 0xb2, 0xc0, 0x6b, 0x94, 0xda, 0x15, 0xe5, 0x94, 0x1a, 0x72, 0xe9,
0xcb, 0x66, 0x3e, 0xb8, 0x2d, 0x68, 0x68, 0xbb, 0xcd, 0xbc, 0xf6, 0xc7, 0x45, 0x78, 0xfd, 0x84,
0x5d, 0xee, 0x64, 0x76, 0x65, 0x0e, 0x59, 0x85, 0xfa, 0x90, 0x76, 0xb8, 0x6b, 0xd2, 0x2f, 0x4f,
0xc2, 0xc3, 0x8e, 0xf9, 0x20, 0x96, 0x59, 0x0c, 0xd5, 0x61, 0x8a, 0x42, 0xcd, 0x07, 0xf2, 0x63,
0xa8, 0x9c, 0x30, 0x89, 0xaf, 0x41, 0x65, 0x75, 0x6b, 0xa3, 0x8e, 0x3c, 0x27, 0x4c, 0xe2, 0x70,
0x43, 0xb3, 0x6f, 0x38, 0x31, 0x25, 0xd9, 0xc4, 0x54, 0x9e, 0x36, 0x31, 0x65, 0x5f, 0xc9, 0x26,
0xd4, 0xbb, 0x3c, 0x4e, 0xa5, 0xf0, 0x43, 0x3c, 0x78, 0x49, 0x31, 0xff, 0x00, 0x99, 0x75, 0x60,
0x77, 0x46, 0x1f, 0x69, 0x9e, 0x93, 0xdc, 0x07, 0x60, 0x2f, 0xa5, 0xf0, 0x0f, 0x78, 0x2a, 0x53,
0x7b, 0x59, 0x29, 0x0c, 0x88, 0x43, 0xc2, 0xe1, 0x29, 0xcd, 0x7d, 0x75, 0xdf, 0x84, 0x37, 0xc6,
0x3d, 0x62, 0x5c, 0xf5, 0x08, 0x7e, 0x48, 0x59, 0xc4, 0xfc, 0x94, 0xcd, 0xef, 0x2d, 0xd7, 0x01,
0xfb, 0x3a, 0xd8, 0x08, 0xfe, 0x5f, 0x09, 0xea, 0x7b, 0x2f, 0x59, 0xf7, 0x98, 0xa5, 0xa9, 0xdf,
0x67, 0xe4, 0x6d, 0xa8, 0x9d, 0x0a, 0xde, 0x65, 0x69, 0x3a, 0x94, 0x35, 0x22, 0x90, 0x9f, 0x43,
0xf9, 0x30, 0x0e, 0xa5, 0x69, 0x73, 0x6b, 0x85, 0x63, 0x73, 0x28, 0x8d, 0x4c, 0x7c, 0x32, 0xe2,
0x96, 0x6c, 0x41, 0x19, 0x8b, 0xc4, 0x6d, 0x0a, 0x75, 0x90, 0xc3, 0x22, 0x86, 0x6c, 0xab, 0x47,
0x76, 0xf8, 0x35, 0x33, 0x51, 0x6a, 0x17, 0x77, 0x98, 0xf0, 0x6b, 0x36, 0x92, 0x60, 0x90, 0x64,
0x0f, 0x2a, 0x67, 0xd2, 0x17, 0xf8, 0xde, 0xd6, 0xd1, 0xbb, 0x57, 0x34, 0x88, 0x68, 0xce, 0x91,
0x94, 0x0c, 0x8b, 0x4e, 0xd8, 0x7b, 0x19, 0x4a, 0x73, 0x1b, 0x8a, 0x9c, 0x80, 0x6c, 0x39, 0x43,
0x70, 0x8b, 0xe8, 0x5d, 0x1e, 0x33, 0xbb, 0x32, 0x13, 0x8d, 0x6c, 0x39, 0x34, 0x6e, 0xd1, 0x0d,
0x67, 0x61, 0x1f, 0xe7, 0xbb, 0xea, 0x4c, 0x37, 0x68, 0xc6, 0x9c, 0x1b, 0x34, 0x61, 0xbb, 0x02,
0x4b, 0x6a, 0x9a, 0x71, 0xff, 0x62, 0x41, 0x3d, 0x17, 0xa7, 0x5b, 0xdc, 0xbb, 0xb7, 0xa1, 0x8c,
0xef, 0x74, 0x13, 0xff, 0xaa, 0xba, 0x75, 0x4c, 0xfa, 0x54, 0x51, 0xb1, 0x70, 0xec, 0x07, 0xba,
0x28, 0x36, 0x29, 0x2e, 0x91, 0xf2, 0x85, 0xbc, 0x52, 0x21, 0xab, 0x52, 0x5c, 0x92, 0x75, 0xa8,
0x9e, 0xb1, 0xee, 0x40, 0x84, 0xf2, 0x4a, 0x05, 0xa1, 0xb5, 0xb1, 0xa2, 0xca, 0x89, 0xa1, 0xa9,
0xcb, 0x39, 0xe4, 0x70, 0x3f, 0xc7, 0xe4, 0x1c, 0x29, 0x48, 0xa0, 0xbc, 0x83, 0xaf, 0x15, 0xd4,
0xac, 0x49, 0xd5, 0x1a, 0x1f, 0x8c, 0x7b, 0xb3, 0x1e, 0x8c, 0x7b, 0xd9, 0x83, 0x71, 0x3c, 0xa8,
0xd8, 0x7d, 0x72, 0x4e, 0x76, 0x1f, 0x43, 0x6d, 0x98, 0x78, 0xf8, 0x56, 0xdf, 0x0f, 0xcc, 0x49,
0x8b, 0xfb, 0x01, 0x9a, 0xb2, 0xf7, 0x64, 0x5f, 0x9d, 0x52, 0xa5, 0xb8, 0x1c, 0xf6, 0xfa, 0x52,
0xae, 0xd7, 0x6f, 0xe2, 0x53, 0x38, 0x97, 0x7d, 0xc8, 0x44, 0xf9, 0x65, 0x9a, 0xa9, 0x8c, 0x6b,
0x6d, 0x46, 0x94, 0x2a, 0x59, 0xca, 0x8c, 0x28, 0x75, 0x7f, 0x04, 0xcd, 0xb1, 0x78, 0x21, 0x93,
0x7a, 0x7b, 0x99, 0x91, 0x10, 0xd7, 0x1b, 0xff, 0xaa, 0x41, 0xed, 0xe8, 0x68, 0x7b, 0x5b, 0x84,
0x41, 0x9f, 0x91, 0xdf, 0x5b, 0x40, 0xae, 0x3f, 0xc3, 0xc8, 0x47, 0xc5, 0x37, 0x63, 0xfa, 0x5b,
0xd2, 0xf9, 0x78, 0x4e, 0x94, 0xe9, 0xcf, 0x5f, 0xc2, 0x92, 0x9a, 0x0d, 0xc9, 0x4f, 0x6e, 0x39,
0xd3, 0x3b, 0xed, 0xd9, 0x8c, 0x46, 0x76, 0x17, 0xaa, 0xd9, 0x7c, 0x45, 0xee, 0x17, 0xaa, 0x37,
0x36, 0x3e, 0x3a, 0xef, 0xdf, 0x8a, 0xd7, 0x1c, 0xf2, 0x1b, 0xa8, 0x98, 0xb1, 0x89, 0xdc, 0x9b,
0x81, 0x1b, 0x0d, 0x70, 0xce, 0xfd, 0xdb, 0xb0, 0x8e, 0xcc, 0xc8, 0xc6, 0xa3, 0x42, 0x33, 0x26,
0x86, 0xaf, 0x42, 0x33, 0xae, 0xcd, 0x5b, 0x4f, 0xa1, 0x8c, 0x73, 0x14, 0x29, 0xaa, 0x27, 0xb9,
0x41, 0xcb, 0x29, 0x0a, 0xd7, 0xd8, 0x00, 0xf6, 0x6b, 0xac, 0xbb, 0xea, 0x2d, 0x5a, 0x5c, 0x71,
0x73, 0x7f, 0xff, 0x38, 0xf7, 0x6e, 0xc1, 0x39, 0x12, 0x6f, 0xde, 0x71, 0xed, 0x5b, 0xfc, 0x07,
0x33, 0x5b, 0xfc, 0xc4, 0xbf, 0x3d, 0x1c, 0x1a, 0xf9, 0x76, 0x4a, 0xbc, 0x02, 0xe8, 0x94, 0x49,
0xc4, 0xe9, 0xdc, 0x9a, 0xdf, 0x1c, 0xf8, 0x0d, 0xbe, 0x09, 0xc6, 0x5b, 0x2d, 0xd9, 0x28, 0x74,
0xc7, 0xd4, 0xa6, 0xee, 0x3c, 0x98, 0x0b, 0x63, 0x0e, 0xf7, 0x75, 0x2b, 0x37, 0xed, 0x9a, 0x14,
0x77, 0xa6, 0x61, 0xcb, 0x77, 0x6e, 0xc9, 0xd7, 0xb6, 0x3e, 0xb4, 0x30, 0xcf, 0x70, 0x84, 0x2b,
0x94, 0x9d, 0x9b, 0x6d, 0x0b, 0xf3, 0x2c, 0x3f, 0x0b, 0x6e, 0x37, 0xbe, 0x7d, 0x75, 0xd7, 0xfa,
0xe7, 0xab, 0xbb, 0xd6, 0x7f, 0x5e, 0xdd, 0xb5, 0xce, 0x97, 0xd5, 0x5f, 0xeb, 0x0f, 0xfe, 0x1f,
0x00, 0x00, 0xff, 0xff, 0xce, 0x5a, 0x92, 0x41, 0xac, 0x18, 0x00, 0x00,
0x15, 0x37, 0xad, 0xef, 0xa7, 0x8f, 0x75, 0x26, 0x69, 0xca, 0x10, 0xc1, 0xc6, 0x61, 0x53, 0x57,
0xbb, 0x71, 0xa8, 0xd4, 0x9b, 0xc0, 0x5b, 0x6f, 0x91, 0x74, 0xfd, 0x05, 0x2b, 0xb1, 0xbd, 0xee,
0x38, 0xc5, 0x02, 0x41, 0x0a, 0x94, 0x16, 0x47, 0x5a, 0x62, 0x69, 0x92, 0x1d, 0x8e, 0xd6, 0xeb,
0xe4, 0xd2, 0xde, 0x7a, 0xec, 0xa9, 0xd7, 0x02, 0xfd, 0x0b, 0x7a, 0xea, 0xb1, 0xe7, 0x1c, 0x7b,
0x29, 0x50, 0xf4, 0x10, 0x14, 0xfb, 0x47, 0x14, 0xe8, 0xad, 0x78, 0x33, 0x43, 0x89, 0x92, 0x65,
0x4a, 0x42, 0x4e, 0x9a, 0x79, 0x7c, 0xbf, 0x37, 0xef, 0x6b, 0xde, 0x7b, 0x23, 0x68, 0x0e, 0x5c,
0xc1, 0xae, 0xdc, 0x6b, 0x27, 0xe6, 0x91, 0x88, 0xc8, 0x5b, 0x97, 0xd1, 0xc5, 0xb5, 0x73, 0x31,
0xf4, 0x03, 0xef, 0xb9, 0x2f, 0x9c, 0x17, 0x3f, 0x75, 0xfa, 0x3c, 0x0a, 0x05, 0x0b, 0x3d, 0xeb,
0x83, 0x81, 0x2f, 0x9e, 0x0d, 0x2f, 0x9c, 0x5e, 0x74, 0xd9, 0x19, 0x44, 0x83, 0xa8, 0x23, 0x11,
0x17, 0xc3, 0xbe, 0xdc, 0xc9, 0x8d, 0x5c, 0x29, 0x49, 0xd6, 0xd6, 0x34, 0xfb, 0x20, 0x8a, 0x06,
0x01, 0x73, 0x63, 0x3f, 0xd1, 0xcb, 0x0e, 0x8f, 0x7b, 0x9d, 0x44, 0xb8, 0x62, 0x98, 0x68, 0xcc,
0x66, 0x06, 0x83, 0x8a, 0x74, 0x52, 0x45, 0x3a, 0x49, 0x14, 0xbc, 0x60, 0xbc, 0x13, 0x5f, 0x74,
0xa2, 0x38, 0xe5, 0xee, 0xdc, 0xca, 0xed, 0xc6, 0x7e, 0x47, 0x5c, 0xc7, 0x2c, 0xe9, 0x5c, 0x45,
0xfc, 0x39, 0xe3, 0x1a, 0xf0, 0xe0, 0x56, 0xc0, 0x50, 0xf8, 0x01, 0xa2, 0x7a, 0x6e, 0x9c, 0xe0,
0x21, 0xf8, 0xab, 0x41, 0x59, 0xb3, 0x45, 0x14, 0xfa, 0x89, 0xf0, 0xfd, 0x81, 0xdf, 0xe9, 0x27,
0x12, 0xa3, 0x4e, 0x41, 0x23, 0x14, 0xbb, 0xfd, 0x87, 0x02, 0x94, 0x29, 0x4b, 0x86, 0x81, 0x20,
0x1b, 0xd0, 0xe4, 0xac, 0xbf, 0xcf, 0x62, 0xce, 0x7a, 0xae, 0x60, 0x9e, 0x69, 0xac, 0x1b, 0xed,
0xda, 0xd1, 0x0a, 0x9d, 0x24, 0x93, 0x5f, 0x41, 0x8b, 0xb3, 0x7e, 0x92, 0x61, 0x5c, 0x5d, 0x37,
0xda, 0xf5, 0xad, 0xf7, 0x9d, 0x5b, 0x83, 0xe1, 0x50, 0xd6, 0x3f, 0x71, 0xe3, 0x31, 0xe4, 0x68,
0x85, 0x4e, 0x09, 0x21, 0x5b, 0x50, 0xe0, 0xac, 0x6f, 0x16, 0xa4, 0xac, 0xbb, 0xf9, 0xb2, 0x8e,
0x56, 0x28, 0x32, 0x93, 0x6d, 0x28, 0xa2, 0x14, 0xb3, 0x28, 0x41, 0xef, 0xce, 0x55, 0xe0, 0x68,
0x85, 0x4a, 0x00, 0xf9, 0x1c, 0xaa, 0x97, 0x4c, 0xb8, 0x9e, 0x2b, 0x5c, 0x13, 0xd6, 0x0b, 0xed,
0xfa, 0x56, 0x27, 0x17, 0x8c, 0x0e, 0x72, 0x4e, 0x34, 0xe2, 0x20, 0x14, 0xfc, 0x9a, 0x8e, 0x04,
0x58, 0x8f, 0xa0, 0x39, 0xf1, 0x89, 0xac, 0x41, 0xe1, 0x39, 0xbb, 0x56, 0xfe, 0xa3, 0xb8, 0x24,
0x6f, 0x40, 0xe9, 0x85, 0x1b, 0x0c, 0x99, 0x74, 0x55, 0x83, 0xaa, 0xcd, 0xce, 0xea, 0x43, 0x63,
0xb7, 0x0a, 0x65, 0x2e, 0xc5, 0xdb, 0x7f, 0x32, 0x60, 0x6d, 0xda, 0x4f, 0xa4, 0xab, 0x2d, 0x34,
0xa4, 0x92, 0x1f, 0x2f, 0xe1, 0x62, 0x24, 0x24, 0x4a, 0x55, 0x29, 0xc2, 0xda, 0x86, 0xda, 0x88,
0x34, 0x4f, 0xc5, 0x5a, 0x46, 0x45, 0x7b, 0x1b, 0x0a, 0x94, 0xf5, 0x49, 0x0b, 0x56, 0x7d, 0x9d,
0x14, 0x74, 0xd5, 0xf7, 0xc8, 0x3a, 0x14, 0x3c, 0xd6, 0xd7, 0xc1, 0x6f, 0x39, 0xf1, 0x85, 0xb3,
0xcf, 0xfa, 0x7e, 0xe8, 0x0b, 0x3f, 0x0a, 0x29, 0x7e, 0xb2, 0xff, 0x62, 0x60, 0x72, 0xa1, 0x5a,
0xe4, 0xd3, 0x09, 0x3b, 0xe6, 0xa7, 0xca, 0x0d, 0xed, 0x9f, 0xe6, 0x6b, 0xff, 0x51, 0x56, 0xfb,
0xb9, 0xf9, 0x93, 0xb5, 0x4e, 0x40, 0x93, 0x32, 0x31, 0xe4, 0x21, 0x65, 0xbf, 0x1d, 0xb2, 0x44,
0x90, 0x9f, 0xa5, 0x11, 0x91, 0xf2, 0xe7, 0xa5, 0x15, 0x32, 0x52, 0x0d, 0x20, 0x6d, 0x28, 0x31,
0xce, 0x23, 0xae, 0xb5, 0x20, 0x8e, 0xaa, 0x1c, 0x0e, 0x8f, 0x7b, 0xce, 0xb9, 0xac, 0x1c, 0x54,
0x31, 0xd8, 0x6b, 0xd0, 0x4a, 0x4f, 0x4d, 0xe2, 0x28, 0x4c, 0x98, 0x7d, 0x07, 0x9a, 0xdd, 0x30,
0x1e, 0x8a, 0x44, 0xeb, 0x61, 0xff, 0xdd, 0x80, 0x56, 0x4a, 0x51, 0x3c, 0xe4, 0x2b, 0xa8, 0x8f,
0x7d, 0x9c, 0x3a, 0x73, 0x27, 0x47, 0xbf, 0x49, 0x7c, 0x26, 0x40, 0xda, 0xb7, 0x59, 0x71, 0xd6,
0x29, 0xac, 0x4d, 0x33, 0xcc, 0xf0, 0xf4, 0x7b, 0x93, 0x9e, 0x9e, 0x0e, 0x7c, 0xc6, 0xb3, 0xff,
0x34, 0xe0, 0x2d, 0xca, 0x64, 0x29, 0xec, 0x5e, 0xba, 0x03, 0xb6, 0x17, 0x85, 0x7d, 0x7f, 0x90,
0xba, 0x79, 0x4d, 0x66, 0x55, 0x2a, 0x19, 0x13, 0xac, 0x0d, 0xd5, 0xb3, 0xc0, 0x15, 0xfd, 0x88,
0x5f, 0x6a, 0xe1, 0x0d, 0x14, 0x9e, 0xd2, 0xe8, 0xe8, 0x2b, 0x59, 0x87, 0xba, 0x16, 0x7c, 0x12,
0x79, 0x4c, 0xd6, 0x8c, 0x1a, 0xcd, 0x92, 0x88, 0x09, 0x95, 0xe3, 0x68, 0x70, 0xea, 0x5e, 0x32,
0x59, 0x1c, 0x6a, 0x34, 0xdd, 0x12, 0x1b, 0x1a, 0x9a, 0x91, 0x7f, 0x71, 0x1d, 0x33, 0xb3, 0xb4,
0x6e, 0xb4, 0x4b, 0x74, 0x82, 0x46, 0xde, 0x86, 0xda, 0x39, 0x4b, 0x12, 0x3f, 0x0a, 0xbb, 0xfb,
0x66, 0x59, 0xe2, 0xc7, 0x04, 0xfb, 0x77, 0x06, 0x58, 0xb3, 0xec, 0xd2, 0x41, 0xfa, 0x0c, 0xca,
0xfb, 0xfe, 0x80, 0x25, 0x2a, 0x7f, 0x6a, 0xbb, 0x5b, 0xdf, 0x7e, 0xf7, 0xce, 0xca, 0xbf, 0xbf,
0x7b, 0xe7, 0x7e, 0xa6, 0x32, 0x47, 0x31, 0x0b, 0x7b, 0x51, 0x28, 0x5c, 0x3f, 0x64, 0x1c, 0x1b,
0xcc, 0x07, 0x9e, 0x84, 0x38, 0x0a, 0x49, 0xb5, 0x04, 0xf2, 0x26, 0x94, 0x95, 0x74, 0x5d, 0x38,
0xf4, 0xce, 0xfe, 0x5b, 0x09, 0x1a, 0xe7, 0xa8, 0x40, 0xea, 0x4d, 0x07, 0x60, 0x1c, 0x04, 0x9d,
0xb8, 0xd3, 0xa1, 0xc9, 0x70, 0x10, 0x0b, 0xaa, 0x87, 0x3a, 0x49, 0xf4, 0x85, 0x1f, 0xed, 0xc9,
0x97, 0x50, 0x4f, 0xd7, 0x4f, 0x62, 0x61, 0x16, 0x64, 0x96, 0x3d, 0xcc, 0xc9, 0xb2, 0xac, 0x26,
0x4e, 0x06, 0xaa, 0x73, 0x2c, 0x43, 0x21, 0x9b, 0xf0, 0x9a, 0x1b, 0x04, 0xd1, 0x95, 0xbe, 0x38,
0xf2, 0x0a, 0xc8, 0x10, 0x54, 0xe9, 0xcd, 0x0f, 0xe4, 0x43, 0x78, 0x3d, 0x43, 0x7c, 0xcc, 0xb9,
0x7b, 0x8d, 0x39, 0x53, 0x96, 0xfc, 0xb3, 0x3e, 0x61, 0x15, 0x3b, 0xf4, 0x43, 0x37, 0x30, 0x41,
0xf2, 0xa8, 0x0d, 0xc6, 0xfc, 0xe0, 0x65, 0x1c, 0x71, 0xc1, 0xf8, 0x63, 0x21, 0xb8, 0x59, 0x97,
0xce, 0x9c, 0xa0, 0x91, 0x33, 0x68, 0xec, 0xb9, 0xbd, 0x67, 0xac, 0x7b, 0x89, 0xc4, 0xc4, 0x6c,
0x48, 0xb3, 0x37, 0x73, 0xcc, 0x96, 0xec, 0x4f, 0xe2, 0xcc, 0x75, 0x9a, 0x90, 0x40, 0x7a, 0xd0,
0x4a, 0x4d, 0x57, 0xf7, 0xd0, 0x6c, 0x4a, 0x99, 0x8f, 0x96, 0x75, 0xa5, 0x42, 0xab, 0x23, 0xa6,
0x44, 0x62, 0x20, 0x0f, 0xf0, 0xca, 0xb9, 0x82, 0x99, 0x2d, 0x69, 0xf3, 0x68, 0x6f, 0x7d, 0x02,
0x6b, 0xd3, 0xd1, 0x58, 0xa6, 0xf0, 0x5b, 0xbf, 0x84, 0xd7, 0x67, 0xa8, 0xf0, 0xbd, 0x6a, 0xc2,
0x5f, 0x0d, 0x78, 0xed, 0x86, 0xdf, 0x08, 0x81, 0xa2, 0xbc, 0x8b, 0x4a, 0xa4, 0x5c, 0x93, 0x13,
0x28, 0x61, 0x5c, 0x12, 0x73, 0x55, 0x3a, 0x6d, 0x7b, 0x99, 0x40, 0x38, 0x12, 0xa9, 0x1c, 0xa6,
0xa4, 0x58, 0x0f, 0x01, 0xc6, 0xc4, 0xa5, 0xda, 0xdf, 0x57, 0xd0, 0xd4, 0x51, 0xd1, 0x17, 0x7c,
0x4d, 0x4d, 0x2a, 0x1a, 0x8c, 0x73, 0xc8, 0xb8, 0x65, 0x14, 0x96, 0x6c, 0x19, 0xf6, 0x37, 0x70,
0x87, 0x32, 0xd7, 0x3b, 0xf4, 0x03, 0x76, 0x7b, 0x65, 0xc4, 0xdb, 0xea, 0x07, 0xec, 0xcc, 0x15,
0xcf, 0x46, 0xb7, 0x55, 0xef, 0xc9, 0x0e, 0x94, 0xa8, 0x1b, 0x0e, 0x98, 0x3e, 0xfa, 0xbd, 0x9c,
0xa3, 0xe5, 0x21, 0xc8, 0x4b, 0x15, 0xc4, 0x7e, 0x04, 0xb5, 0x11, 0x0d, 0x6b, 0xcd, 0x93, 0x7e,
0x3f, 0x61, 0xaa, 0x6e, 0x15, 0xa8, 0xde, 0x21, 0xfd, 0x98, 0x85, 0x03, 0x7d, 0x74, 0x81, 0xea,
0x9d, 0xbd, 0x81, 0xe3, 0x4a, 0xaa, 0xb9, 0x76, 0x0d, 0x81, 0xe2, 0x3e, 0xce, 0x54, 0x86, 0xbc,
0x60, 0x72, 0x6d, 0x7b, 0xd8, 0xea, 0x5c, 0x6f, 0xdf, 0xe7, 0xb7, 0x1b, 0x68, 0x42, 0x65, 0xdf,
0xe7, 0x19, 0xfb, 0xd2, 0x2d, 0xd9, 0xc0, 0x26, 0xd8, 0x0b, 0x86, 0x1e, 0x5a, 0x2b, 0x18, 0x0f,
0x75, 0xb5, 0x9f, 0xa2, 0xda, 0x9f, 0x2a, 0x3f, 0xca, 0x53, 0xb4, 0x32, 0x9b, 0x50, 0x61, 0xa1,
0xe0, 0x3e, 0x4b, 0x3b, 0x25, 0x71, 0xd4, 0x18, 0xec, 0xc8, 0x31, 0x58, 0x76, 0x64, 0x9a, 0xb2,
0xd8, 0xdb, 0x70, 0x07, 0x09, 0xf9, 0x81, 0x20, 0x50, 0xcc, 0x28, 0x29, 0xd7, 0xf6, 0x0e, 0xac,
0x8d, 0x81, 0xfa, 0xe8, 0x0d, 0x28, 0xe2, 0x90, 0xad, 0x0b, 0xf1, 0xac, 0x73, 0xe5, 0x77, 0xbb,
0x09, 0xf5, 0x33, 0x3f, 0x4c, 0x7b, 0xa2, 0xfd, 0xca, 0x80, 0xc6, 0x59, 0x14, 0x8e, 0x7b, 0xc9,
0x19, 0xdc, 0x49, 0x6f, 0xe0, 0xe3, 0xb3, 0xee, 0x9e, 0x1b, 0xa7, 0xa6, 0xac, 0xdf, 0x0c, 0xb3,
0x7e, 0x0f, 0x38, 0x8a, 0x71, 0xb7, 0x88, 0x6d, 0x87, 0x4e, 0xc3, 0xc9, 0x2f, 0xa0, 0x72, 0x7c,
0xbc, 0x2b, 0x25, 0xad, 0x2e, 0x25, 0x29, 0x85, 0x91, 0x4f, 0xa0, 0xf2, 0x54, 0x3e, 0x53, 0x12,
0xdd, 0x1a, 0x66, 0xa4, 0x9c, 0x32, 0x54, 0xb1, 0x51, 0xd6, 0x8b, 0xb8, 0x47, 0x53, 0x90, 0xfd,
0x5f, 0x03, 0xea, 0x4f, 0xdd, 0xf1, 0xbc, 0xf5, 0x19, 0x94, 0xbd, 0xef, 0xdd, 0x2f, 0xd5, 0x16,
0x6f, 0x71, 0xc0, 0x5e, 0xb0, 0x40, 0xa7, 0xaa, 0xda, 0x20, 0x35, 0x79, 0x16, 0x71, 0x75, 0x3b,
0x1b, 0x54, 0x6d, 0x30, 0xaf, 0x3d, 0x26, 0x5c, 0x3f, 0x30, 0x8b, 0xeb, 0x05, 0xec, 0xad, 0x6a,
0x87, 0x51, 0x1f, 0xf2, 0x40, 0x36, 0xa5, 0x1a, 0xc5, 0x25, 0xb1, 0xa1, 0xe8, 0x87, 0xfd, 0x48,
0xf6, 0x1d, 0x5d, 0xdd, 0xce, 0xa3, 0x21, 0xef, 0xb1, 0x6e, 0xd8, 0x8f, 0xa8, 0xfc, 0x46, 0xde,
0x85, 0x32, 0xc7, 0x6b, 0x94, 0x98, 0x15, 0xe9, 0x94, 0x1a, 0x72, 0xa9, 0xcb, 0xa6, 0x3f, 0xd8,
0x2d, 0x68, 0x28, 0xbb, 0xf5, 0xc4, 0xf7, 0xc7, 0x55, 0x78, 0xfd, 0x94, 0x5d, 0xed, 0xa5, 0x76,
0xa5, 0x0e, 0x59, 0x87, 0xfa, 0x88, 0xd6, 0xdd, 0xd7, 0xe9, 0x97, 0x25, 0xe1, 0x61, 0x27, 0xd1,
0x30, 0x14, 0x69, 0x0c, 0xe5, 0x61, 0x92, 0x42, 0xf5, 0x07, 0xf2, 0x63, 0xa8, 0x9c, 0x32, 0x81,
0xef, 0x49, 0x69, 0x75, 0x6b, 0xab, 0x8e, 0x3c, 0xa7, 0x4c, 0xe0, 0x78, 0x44, 0xd3, 0x6f, 0x38,
0x73, 0xc5, 0xe9, 0xcc, 0x55, 0x9c, 0x35, 0x73, 0xa5, 0x5f, 0xc9, 0x36, 0xd4, 0x7b, 0x51, 0x98,
0x08, 0xee, 0xfa, 0x78, 0x70, 0x49, 0x32, 0xff, 0x00, 0x99, 0x55, 0x60, 0xf7, 0xc6, 0x1f, 0x69,
0x96, 0x93, 0xdc, 0x07, 0x60, 0x2f, 0x05, 0x77, 0x8f, 0xa2, 0x44, 0x24, 0x66, 0x59, 0x2a, 0x0c,
0x88, 0x43, 0x42, 0xf7, 0x8c, 0x66, 0xbe, 0xda, 0x6f, 0xc2, 0x1b, 0x93, 0x1e, 0xd1, 0xae, 0x7a,
0x04, 0x3f, 0xa4, 0x2c, 0x60, 0x6e, 0xc2, 0x96, 0xf7, 0x96, 0x6d, 0x81, 0x79, 0x13, 0xac, 0x05,
0xff, 0xaf, 0x00, 0xf5, 0x83, 0x97, 0xac, 0x77, 0xc2, 0x92, 0xc4, 0x1d, 0xc8, 0xc9, 0xef, 0x8c,
0x47, 0x3d, 0x96, 0x24, 0x23, 0x59, 0x63, 0x02, 0xf9, 0x39, 0x14, 0xbb, 0xa1, 0x2f, 0x74, 0x9b,
0xdb, 0xc8, 0x1d, 0xbc, 0x7d, 0xa1, 0x65, 0xe2, 0xa3, 0x13, 0xb7, 0x64, 0x07, 0x8a, 0x58, 0x24,
0x16, 0x29, 0xd4, 0x5e, 0x06, 0x8b, 0x18, 0xb2, 0x2b, 0x9f, 0xe9, 0xfe, 0xd7, 0x4c, 0x47, 0xa9,
0x9d, 0xdf, 0x61, 0xfc, 0xaf, 0xd9, 0x58, 0x82, 0x46, 0x92, 0x03, 0xa8, 0x9c, 0x0b, 0x97, 0xe3,
0x8b, 0x5d, 0x45, 0xef, 0x5e, 0xde, 0x20, 0xa2, 0x38, 0xc7, 0x52, 0x52, 0x2c, 0x3a, 0xe1, 0xe0,
0xa5, 0x2f, 0xf4, 0x6d, 0xc8, 0x73, 0x02, 0xb2, 0x65, 0x0c, 0xc1, 0x2d, 0xa2, 0xf7, 0xa3, 0x90,
0x99, 0x95, 0xb9, 0x68, 0x64, 0xcb, 0xa0, 0x71, 0x8b, 0x6e, 0x38, 0xf7, 0x07, 0x38, 0xdf, 0x55,
0xe7, 0xba, 0x41, 0x31, 0x66, 0xdc, 0xa0, 0x08, 0xbb, 0x15, 0x28, 0xc9, 0x69, 0xc6, 0xfe, 0xb3,
0x01, 0xf5, 0x4c, 0x9c, 0x16, 0xb8, 0x77, 0x6f, 0x43, 0x11, 0x5f, 0xfa, 0x3a, 0xfe, 0x55, 0x79,
0xeb, 0x98, 0x70, 0xa9, 0xa4, 0x62, 0xe1, 0x38, 0xf4, 0x54, 0x51, 0x6c, 0x52, 0x5c, 0x22, 0xe5,
0x0b, 0x71, 0x2d, 0x43, 0x56, 0xa5, 0xb8, 0x24, 0x9b, 0x50, 0x3d, 0x67, 0xbd, 0x21, 0xf7, 0xc5,
0xb5, 0x0c, 0x42, 0x6b, 0x6b, 0x4d, 0x96, 0x13, 0x4d, 0x93, 0x97, 0x73, 0xc4, 0x61, 0x7f, 0x8e,
0xc9, 0x39, 0x56, 0x90, 0x40, 0x71, 0x0f, 0xdf, 0x3b, 0xa8, 0x59, 0x93, 0xca, 0x35, 0x3e, 0x39,
0x0f, 0xe6, 0x3d, 0x39, 0x0f, 0xd2, 0x27, 0xe7, 0x64, 0x50, 0xb1, 0xfb, 0x64, 0x9c, 0x6c, 0x3f,
0x86, 0xda, 0x28, 0xf1, 0xf0, 0xb5, 0x7f, 0xe8, 0xe9, 0x93, 0x56, 0x0f, 0x3d, 0x34, 0xe5, 0xe0,
0xc9, 0xa1, 0x3c, 0xa5, 0x4a, 0x71, 0x39, 0xea, 0xf5, 0x85, 0x4c, 0xaf, 0xdf, 0xc6, 0xc7, 0x74,
0x26, 0xfb, 0x90, 0x89, 0x46, 0x57, 0x49, 0xaa, 0x32, 0xae, 0x95, 0x19, 0x41, 0x22, 0x65, 0x49,
0x33, 0x82, 0xc4, 0xfe, 0x11, 0x34, 0x27, 0xe2, 0x85, 0x4c, 0xf2, 0xf5, 0xa6, 0x47, 0x42, 0x5c,
0x6f, 0xfd, 0xab, 0x06, 0xb5, 0xe3, 0xe3, 0xdd, 0x5d, 0xee, 0x7b, 0x03, 0x46, 0x7e, 0x6f, 0x00,
0xb9, 0xf9, 0x0c, 0x23, 0x1f, 0xe5, 0xdf, 0x8c, 0xd9, 0xaf, 0x51, 0xeb, 0xe3, 0x25, 0x51, 0xba,
0x3f, 0x7f, 0x09, 0x25, 0x39, 0x1b, 0x92, 0x9f, 0x2c, 0x38, 0xd3, 0x5b, 0xed, 0xf9, 0x8c, 0x5a,
0x76, 0x0f, 0xaa, 0xe9, 0x7c, 0x45, 0xee, 0xe7, 0xaa, 0x37, 0x31, 0x3e, 0x5a, 0xef, 0x2f, 0xc4,
0xab, 0x0f, 0xf9, 0x0d, 0x54, 0xf4, 0xd8, 0x44, 0xee, 0xcd, 0xc1, 0x8d, 0x07, 0x38, 0xeb, 0xfe,
0x22, 0xac, 0x63, 0x33, 0xd2, 0xf1, 0x28, 0xd7, 0x8c, 0xa9, 0xe1, 0x2b, 0xd7, 0x8c, 0x1b, 0xf3,
0xd6, 0x53, 0x28, 0xe2, 0x1c, 0x45, 0xf2, 0xea, 0x49, 0x66, 0xd0, 0xb2, 0xf2, 0xc2, 0x35, 0x31,
0x80, 0xfd, 0x1a, 0xeb, 0xae, 0x7c, 0x8b, 0xe6, 0x57, 0xdc, 0xcc, 0x1f, 0x48, 0xd6, 0xbd, 0x05,
0x38, 0xc7, 0xe2, 0xf5, 0x3b, 0xae, 0xbd, 0xc0, 0xbf, 0x38, 0xf3, 0xc5, 0x4f, 0xfd, 0x5f, 0x14,
0x41, 0x23, 0xdb, 0x4e, 0x89, 0x93, 0x03, 0x9d, 0x31, 0x89, 0x58, 0x9d, 0x85, 0xf9, 0xf5, 0x81,
0xdf, 0xe0, 0x9b, 0x60, 0xb2, 0xd5, 0x92, 0xad, 0x5c, 0x77, 0xcc, 0x6c, 0xea, 0xd6, 0x83, 0xa5,
0x30, 0xfa, 0x70, 0x57, 0xb5, 0x72, 0xdd, 0xae, 0x49, 0x7e, 0x67, 0x1a, 0xb5, 0x7c, 0x6b, 0x41,
0xbe, 0xb6, 0xf1, 0xa1, 0x81, 0x79, 0x86, 0x23, 0x5c, 0xae, 0xec, 0xcc, 0x6c, 0x9b, 0x9b, 0x67,
0xd9, 0x59, 0x70, 0xb7, 0xf1, 0xed, 0xab, 0xbb, 0xc6, 0x3f, 0x5e, 0xdd, 0x35, 0xfe, 0xf3, 0xea,
0xae, 0x71, 0x51, 0x96, 0x7f, 0xce, 0x3f, 0xf8, 0x7f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x29, 0xd9,
0x1c, 0x06, 0xee, 0x18, 0x00, 0x00,
}
// Reference imports to suppress errors if they are not otherwise used.
@ -3364,6 +3382,18 @@ func (m *ResolveImageConfigRequest) MarshalToSizedBuffer(dAtA []byte) (int, erro
i -= len(m.XXX_unrecognized)
copy(dAtA[i:], m.XXX_unrecognized)
}
if len(m.SessionID) > 0 {
i -= len(m.SessionID)
copy(dAtA[i:], m.SessionID)
i = encodeVarintGateway(dAtA, i, uint64(len(m.SessionID)))
i--
dAtA[i] = 0x32
}
if m.ResolverType != 0 {
i = encodeVarintGateway(dAtA, i, uint64(m.ResolverType))
i--
dAtA[i] = 0x28
}
if len(m.LogName) > 0 {
i -= len(m.LogName)
copy(dAtA[i:], m.LogName)
@ -5102,6 +5132,13 @@ func (m *ResolveImageConfigRequest) Size() (n int) {
if l > 0 {
n += 1 + l + sovGateway(uint64(l))
}
if m.ResolverType != 0 {
n += 1 + sovGateway(uint64(m.ResolverType))
}
l = len(m.SessionID)
if l > 0 {
n += 1 + l + sovGateway(uint64(l))
}
if m.XXX_unrecognized != nil {
n += len(m.XXX_unrecognized)
}
@ -7147,6 +7184,57 @@ func (m *ResolveImageConfigRequest) Unmarshal(dAtA []byte) error {
}
m.LogName = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
case 5:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field ResolverType", wireType)
}
m.ResolverType = 0
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowGateway
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
m.ResolverType |= int32(b&0x7F) << shift
if b < 0x80 {
break
}
}
case 6:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field SessionID", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowGateway
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
stringLen |= uint64(b&0x7F) << shift
if b < 0x80 {
break
}
}
intStringLen := int(stringLen)
if intStringLen < 0 {
return ErrInvalidLengthGateway
}
postIndex := iNdEx + intStringLen
if postIndex < 0 {
return ErrInvalidLengthGateway
}
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.SessionID = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
default:
iNdEx = preIndex
skippy, err := skipGateway(dAtA[iNdEx:])

View File

@ -83,6 +83,8 @@ message ResolveImageConfigRequest {
pb.Platform Platform = 2;
string ResolveMode = 3;
string LogName = 4;
int32 ResolverType = 5;
string SessionID = 6;
}
message ResolveImageConfigResponse {

View File

@ -28,6 +28,9 @@ const AttrImageResolveModePreferLocal = "local"
const AttrImageRecordType = "image.recordtype"
const AttrImageLayerLimit = "image.layerlimit"
const AttrOCILayoutSessionID = "oci.session"
const AttrOCILayoutLayerLimit = "oci.layerlimit"
const AttrLocalDiffer = "local.differ"
const AttrLocalDifferNone = "none"
const AttrLocalDifferMetadata = "metadata"

View File

@ -35,6 +35,10 @@ const (
CapSourceHTTPPerm apicaps.CapID = "source.http.perm"
CapSourceHTTPUIDGID apicaps.CapID = "soruce.http.uidgid"
CapSourceOCILayout apicaps.CapID = "source.ocilayout"
CapSourceOCILayoutSessionID apicaps.CapID = "source.ocilayout.sessionid"
CapSourceOCILayoutLayerLimit apicaps.CapID = "source.ocilayout.layerlimit"
CapBuildOpLLBFileName apicaps.CapID = "source.buildop.llbfilename"
CapExecMetaBase apicaps.CapID = "exec.meta.base"
@ -74,6 +78,8 @@ const (
CapMergeOp apicaps.CapID = "mergeop"
CapDiffOp apicaps.CapID = "diffop"
CapAnnotations apicaps.CapID = "exporter.image.annotations"
)
func init() {
@ -203,6 +209,24 @@ func init() {
Status: apicaps.CapStatusExperimental,
})
Caps.Init(apicaps.Cap{
ID: CapSourceOCILayout,
Enabled: true,
Status: apicaps.CapStatusExperimental,
})
Caps.Init(apicaps.Cap{
ID: CapSourceOCILayoutSessionID,
Enabled: true,
Status: apicaps.CapStatusExperimental,
})
Caps.Init(apicaps.Cap{
ID: CapSourceOCILayoutLayerLimit,
Enabled: true,
Status: apicaps.CapStatusExperimental,
})
Caps.Init(apicaps.Cap{
ID: CapSourceHTTPUIDGID,
Enabled: true,
@ -392,19 +416,28 @@ func init() {
Enabled: true,
Status: apicaps.CapStatusExperimental,
})
Caps.Init(apicaps.Cap{
ID: CapRemoteCacheS3,
Enabled: true,
Status: apicaps.CapStatusExperimental,
})
Caps.Init(apicaps.Cap{
ID: CapMergeOp,
Enabled: true,
Status: apicaps.CapStatusExperimental,
})
Caps.Init(apicaps.Cap{
ID: CapDiffOp,
Enabled: true,
Status: apicaps.CapStatusExperimental,
})
Caps.Init(apicaps.Cap{
ID: CapAnnotations,
Enabled: true,
Status: apicaps.CapStatusExperimental,
})
}

View File

@ -6,4 +6,5 @@ const (
LocalScheme = "local"
HTTPScheme = "http"
HTTPSScheme = "https"
OCIScheme = "oci-layout"
)

View File

@ -335,7 +335,7 @@ github.com/linuxkit/virtsock/pkg/vsock
github.com/matttproud/golang_protobuf_extensions/pbutil
# github.com/mitchellh/go-ps v0.0.0-20190716172923-621e5597135b
github.com/mitchellh/go-ps
# github.com/moby/buildkit v0.10.1-0.20220614084718-b3d272e22672
# github.com/moby/buildkit v0.10.1-0.20220617010517-a6a114a1a476
## explicit
github.com/moby/buildkit/api/services/control
github.com/moby/buildkit/api/types
@ -414,6 +414,7 @@ github.com/morikuni/aec
## explicit
github.com/moul/gotty-client
# github.com/opencontainers/go-digest v1.0.0
## explicit
github.com/opencontainers/go-digest
# github.com/opencontainers/image-spec v1.0.3-0.20211202183452-c5a74bcca799
## explicit

View File

@ -0,0 +1,3 @@
FROM alpine:3.15
COPY foo /foo

View File

@ -0,0 +1,5 @@
image: chained-build-image1-test-does-not-exist-anywhere-else-123456789 # this must be used as FROM in the chained image
network: true
arches:
- amd64
- arm64

View File

@ -0,0 +1 @@
bar

View File

@ -0,0 +1,5 @@
# this FROM *must* be updated when changing ../build1; just run `lkt pkg show-tag ../build1` and place it here
FROM linuxkit/chained-build-image1-test-does-not-exist-anywhere-else-123456789:ad06eb29c48f0daab0cc2836a1351a053948100c as src
FROM alpine:3.15
COPY --from=src /foo /foo
RUN cat /foo

View File

@ -0,0 +1,5 @@
image: chained-build-test-second
network: true
arches:
- amd64
- arm64

View File

@ -0,0 +1,19 @@
#!/bin/sh
# SUMMARY: Check that chained builds get the output of one for the next
# LABELS:
# REPEAT:
set -ex
# Source libraries. Uncomment if needed/defined
#. "${RT_LIB}"
. "${RT_PROJECT_ROOT}/_lib/lib.sh"
# Test code goes here
echo linuxkit is "$(which linuxkit)"
# build the first, use it to build the second
linuxkit pkg build --force ./build1
linuxkit pkg build --force ./build2
exit 0