2018-08-31 21:28:25 -04:00
|
|
|
package imagerefchecker
|
|
|
|
|
|
|
|
import (
|
|
|
|
"sync"
|
|
|
|
|
|
|
|
"github.com/docker/docker/image"
|
|
|
|
"github.com/docker/docker/layer"
|
|
|
|
"github.com/moby/buildkit/cache"
|
2022-03-04 08:49:42 -05:00
|
|
|
"github.com/opencontainers/go-digest"
|
2018-08-31 21:28:25 -04:00
|
|
|
)
|
|
|
|
|
|
|
|
// LayerGetter abstracts away the snapshotter
|
|
|
|
type LayerGetter interface {
|
|
|
|
GetLayer(string) (layer.Layer, error)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Opt represents the options needed to create a refchecker
|
|
|
|
type Opt struct {
|
|
|
|
LayerGetter LayerGetter
|
|
|
|
ImageStore image.Store
|
|
|
|
}
|
|
|
|
|
|
|
|
// New creates new image reference checker that can be used to see if a reference
|
|
|
|
// is being used by any of the images in the image store
|
|
|
|
func New(opt Opt) cache.ExternalRefCheckerFunc {
|
|
|
|
return func() (cache.ExternalRefChecker, error) {
|
|
|
|
return &checker{opt: opt, layers: lchain{}, cache: map[string]bool{}}, nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
type lchain map[layer.DiffID]lchain
|
|
|
|
|
|
|
|
func (c lchain) add(ids []layer.DiffID) {
|
|
|
|
if len(ids) == 0 {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
id := ids[0]
|
|
|
|
ch, ok := c[id]
|
|
|
|
if !ok {
|
|
|
|
ch = lchain{}
|
|
|
|
c[id] = ch
|
|
|
|
}
|
|
|
|
ch.add(ids[1:])
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c lchain) has(ids []layer.DiffID) bool {
|
|
|
|
if len(ids) == 0 {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
ch, ok := c[ids[0]]
|
|
|
|
return ok && ch.has(ids[1:])
|
|
|
|
}
|
|
|
|
|
|
|
|
type checker struct {
|
|
|
|
opt Opt
|
|
|
|
once sync.Once
|
|
|
|
layers lchain
|
|
|
|
cache map[string]bool
|
|
|
|
}
|
|
|
|
|
2019-10-09 20:20:17 -04:00
|
|
|
func (c *checker) Exists(key string, chain []digest.Digest) bool {
|
2018-08-31 21:28:25 -04:00
|
|
|
if c.opt.ImageStore == nil {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
c.once.Do(c.init)
|
|
|
|
|
|
|
|
if b, ok := c.cache[key]; ok {
|
|
|
|
return b
|
|
|
|
}
|
|
|
|
|
|
|
|
l, err := c.opt.LayerGetter.GetLayer(key)
|
|
|
|
if err != nil || l == nil {
|
|
|
|
c.cache[key] = false
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
ok := c.layers.has(diffIDs(l))
|
|
|
|
c.cache[key] = ok
|
|
|
|
return ok
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *checker) init() {
|
|
|
|
imgs := c.opt.ImageStore.Map()
|
|
|
|
|
|
|
|
for _, img := range imgs {
|
|
|
|
c.layers.add(img.RootFS.DiffIDs)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func diffIDs(l layer.Layer) []layer.DiffID {
|
|
|
|
p := l.Parent()
|
|
|
|
if p == nil {
|
|
|
|
return []layer.DiffID{l.DiffID()}
|
|
|
|
}
|
|
|
|
return append(diffIDs(p), l.DiffID())
|
|
|
|
}
|