|
@@ -0,0 +1,96 @@
|
|
|
|
+package imagerefchecker
|
|
|
|
+
|
|
|
|
+import (
|
|
|
|
+ "sync"
|
|
|
|
+
|
|
|
|
+ "github.com/docker/docker/image"
|
|
|
|
+ "github.com/docker/docker/layer"
|
|
|
|
+ "github.com/moby/buildkit/cache"
|
|
|
|
+)
|
|
|
|
+
|
|
|
|
+// 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
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+func (c *checker) Exists(key string) bool {
|
|
|
|
+ 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())
|
|
|
|
+}
|