github.com/kaisenlinux/docker.io@v0.0.0-20230510090727-ea55db55fac7/engine/builder/builder-next/adapters/localinlinecache/inlinecache.go (about) 1 package localinlinecache 2 3 import ( 4 "context" 5 "encoding/json" 6 "time" 7 8 "github.com/containerd/containerd/content" 9 "github.com/containerd/containerd/images" 10 "github.com/containerd/containerd/remotes/docker" 11 distreference "github.com/docker/distribution/reference" 12 imagestore "github.com/docker/docker/image" 13 "github.com/docker/docker/reference" 14 "github.com/moby/buildkit/cache/remotecache" 15 registryremotecache "github.com/moby/buildkit/cache/remotecache/registry" 16 v1 "github.com/moby/buildkit/cache/remotecache/v1" 17 "github.com/moby/buildkit/session" 18 "github.com/moby/buildkit/solver" 19 "github.com/moby/buildkit/worker" 20 digest "github.com/opencontainers/go-digest" 21 specs "github.com/opencontainers/image-spec/specs-go/v1" 22 "github.com/pkg/errors" 23 ) 24 25 func init() { 26 // See https://github.com/moby/buildkit/pull/1993. 27 v1.EmptyLayerRemovalSupported = false 28 } 29 30 // ResolveCacheImporterFunc returns a resolver function for local inline cache 31 func ResolveCacheImporterFunc(sm *session.Manager, resolverFunc docker.RegistryHosts, cs content.Store, rs reference.Store, is imagestore.Store) remotecache.ResolveCacheImporterFunc { 32 33 upstream := registryremotecache.ResolveCacheImporterFunc(sm, cs, resolverFunc) 34 35 return func(ctx context.Context, group session.Group, attrs map[string]string) (remotecache.Importer, specs.Descriptor, error) { 36 if dt, err := tryImportLocal(rs, is, attrs["ref"]); err == nil { 37 return newLocalImporter(dt), specs.Descriptor{}, nil 38 } 39 return upstream(ctx, group, attrs) 40 } 41 } 42 43 func tryImportLocal(rs reference.Store, is imagestore.Store, refStr string) ([]byte, error) { 44 ref, err := distreference.ParseNormalizedNamed(refStr) 45 if err != nil { 46 return nil, err 47 } 48 dgst, err := rs.Get(ref) 49 if err != nil { 50 return nil, err 51 } 52 img, err := is.Get(imagestore.ID(dgst)) 53 if err != nil { 54 return nil, err 55 } 56 57 return img.RawJSON(), nil 58 } 59 60 func newLocalImporter(dt []byte) remotecache.Importer { 61 return &localImporter{dt: dt} 62 } 63 64 type localImporter struct { 65 dt []byte 66 } 67 68 func (li *localImporter) Resolve(ctx context.Context, _ specs.Descriptor, id string, w worker.Worker) (solver.CacheManager, error) { 69 cc := v1.NewCacheChains() 70 if err := li.importInlineCache(ctx, li.dt, cc); err != nil { 71 return nil, err 72 } 73 74 keysStorage, resultStorage, err := v1.NewCacheKeyStorage(cc, w) 75 if err != nil { 76 return nil, err 77 } 78 return solver.NewCacheManager(id, keysStorage, resultStorage), nil 79 } 80 81 func (li *localImporter) importInlineCache(ctx context.Context, dt []byte, cc solver.CacheExporterTarget) error { 82 var img image 83 84 if err := json.Unmarshal(dt, &img); err != nil { 85 return err 86 } 87 88 if img.Cache == nil { 89 return nil 90 } 91 92 var config v1.CacheConfig 93 if err := json.Unmarshal(img.Cache, &config.Records); err != nil { 94 return err 95 } 96 97 createdDates, createdMsg, err := parseCreatedLayerInfo(img) 98 if err != nil { 99 return err 100 } 101 102 layers := v1.DescriptorProvider{} 103 for i, diffID := range img.Rootfs.DiffIDs { 104 dgst := digest.Digest(diffID.String()) 105 desc := specs.Descriptor{ 106 Digest: dgst, 107 Size: -1, 108 MediaType: images.MediaTypeDockerSchema2Layer, 109 Annotations: map[string]string{}, 110 } 111 if createdAt := createdDates[i]; createdAt != "" { 112 desc.Annotations["buildkit/createdat"] = createdAt 113 } 114 if createdBy := createdMsg[i]; createdBy != "" { 115 desc.Annotations["buildkit/description"] = createdBy 116 } 117 desc.Annotations["containerd.io/uncompressed"] = img.Rootfs.DiffIDs[i].String() 118 layers[dgst] = v1.DescriptorProviderPair{ 119 Descriptor: desc, 120 Provider: &emptyProvider{}, 121 } 122 config.Layers = append(config.Layers, v1.CacheLayer{ 123 Blob: dgst, 124 ParentIndex: i - 1, 125 }) 126 } 127 128 return v1.ParseConfig(config, layers, cc) 129 } 130 131 type image struct { 132 Rootfs struct { 133 DiffIDs []digest.Digest `json:"diff_ids"` 134 } `json:"rootfs"` 135 Cache []byte `json:"moby.buildkit.cache.v0"` 136 History []struct { 137 Created *time.Time `json:"created,omitempty"` 138 CreatedBy string `json:"created_by,omitempty"` 139 EmptyLayer bool `json:"empty_layer,omitempty"` 140 } `json:"history,omitempty"` 141 } 142 143 func parseCreatedLayerInfo(img image) ([]string, []string, error) { 144 dates := make([]string, 0, len(img.Rootfs.DiffIDs)) 145 createdBy := make([]string, 0, len(img.Rootfs.DiffIDs)) 146 for _, h := range img.History { 147 if !h.EmptyLayer { 148 str := "" 149 if h.Created != nil { 150 dt, err := h.Created.MarshalText() 151 if err != nil { 152 return nil, nil, err 153 } 154 str = string(dt) 155 } 156 dates = append(dates, str) 157 createdBy = append(createdBy, h.CreatedBy) 158 } 159 } 160 return dates, createdBy, nil 161 } 162 163 type emptyProvider struct { 164 } 165 166 func (p *emptyProvider) ReaderAt(ctx context.Context, dec specs.Descriptor) (content.ReaderAt, error) { 167 return nil, errors.Errorf("ReaderAt not implemented for empty provider") 168 }