store.go 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347
  1. package image // import "github.com/docker/docker/image"
  2. import (
  3. "context"
  4. "fmt"
  5. "sync"
  6. "time"
  7. "github.com/containerd/log"
  8. "github.com/docker/docker/errdefs"
  9. "github.com/docker/docker/layer"
  10. "github.com/opencontainers/go-digest"
  11. "github.com/opencontainers/go-digest/digestset"
  12. "github.com/pkg/errors"
  13. )
  14. // Store is an interface for creating and accessing images
  15. type Store interface {
  16. Create(config []byte) (ID, error)
  17. Get(id ID) (*Image, error)
  18. Delete(id ID) ([]layer.Metadata, error)
  19. Search(partialID string) (ID, error)
  20. SetParent(id ID, parent ID) error
  21. GetParent(id ID) (ID, error)
  22. SetLastUpdated(id ID) error
  23. GetLastUpdated(id ID) (time.Time, error)
  24. Children(id ID) []ID
  25. Map() map[ID]*Image
  26. Heads() map[ID]*Image
  27. Len() int
  28. }
  29. // LayerGetReleaser is a minimal interface for getting and releasing images.
  30. type LayerGetReleaser interface {
  31. Get(layer.ChainID) (layer.Layer, error)
  32. Release(layer.Layer) ([]layer.Metadata, error)
  33. }
  34. type imageMeta struct {
  35. layer layer.Layer
  36. children map[ID]struct{}
  37. }
  38. type store struct {
  39. sync.RWMutex
  40. lss LayerGetReleaser
  41. images map[ID]*imageMeta
  42. fs StoreBackend
  43. digestSet *digestset.Set
  44. }
  45. // NewImageStore returns new store object for given set of layer stores
  46. func NewImageStore(fs StoreBackend, lss LayerGetReleaser) (Store, error) {
  47. is := &store{
  48. lss: lss,
  49. images: make(map[ID]*imageMeta),
  50. fs: fs,
  51. digestSet: digestset.NewSet(),
  52. }
  53. // load all current images and retain layers
  54. if err := is.restore(); err != nil {
  55. return nil, err
  56. }
  57. return is, nil
  58. }
  59. func (is *store) restore() error {
  60. // As the code below is run when restoring all images (which can be "many"),
  61. // constructing the "log.G(ctx).WithFields" is deliberately not "DRY", as the
  62. // logger is only used for error-cases, and we don't want to do allocations
  63. // if we don't need it. The "f" type alias is here is just for convenience,
  64. // and to make the code _slightly_ more DRY. See the discussion on GitHub;
  65. // https://github.com/moby/moby/pull/44426#discussion_r1059519071
  66. type f = log.Fields
  67. err := is.fs.Walk(func(dgst digest.Digest) error {
  68. img, err := is.Get(ID(dgst))
  69. if err != nil {
  70. log.G(context.TODO()).WithFields(f{"digest": dgst, "err": err}).Error("invalid image")
  71. return nil
  72. }
  73. var l layer.Layer
  74. if chainID := img.RootFS.ChainID(); chainID != "" {
  75. if err := CheckOS(img.OperatingSystem()); err != nil {
  76. log.G(context.TODO()).WithFields(f{"chainID": chainID, "os": img.OperatingSystem()}).Error("not restoring image with unsupported operating system")
  77. return nil
  78. }
  79. l, err = is.lss.Get(chainID)
  80. if err != nil {
  81. if errors.Is(err, layer.ErrLayerDoesNotExist) {
  82. log.G(context.TODO()).WithFields(f{"chainID": chainID, "os": img.OperatingSystem(), "err": err}).Error("not restoring image")
  83. return nil
  84. }
  85. return err
  86. }
  87. }
  88. if err := is.digestSet.Add(dgst); err != nil {
  89. return err
  90. }
  91. is.images[ID(dgst)] = &imageMeta{
  92. layer: l,
  93. children: make(map[ID]struct{}),
  94. }
  95. return nil
  96. })
  97. if err != nil {
  98. return err
  99. }
  100. // Second pass to fill in children maps
  101. for id := range is.images {
  102. if parent, err := is.GetParent(id); err == nil {
  103. if parentMeta := is.images[parent]; parentMeta != nil {
  104. parentMeta.children[id] = struct{}{}
  105. }
  106. }
  107. }
  108. return nil
  109. }
  110. func (is *store) Create(config []byte) (ID, error) {
  111. var img *Image
  112. img, err := NewFromJSON(config)
  113. if err != nil {
  114. return "", err
  115. }
  116. // Must reject any config that references diffIDs from the history
  117. // which aren't among the rootfs layers.
  118. rootFSLayers := make(map[layer.DiffID]struct{})
  119. for _, diffID := range img.RootFS.DiffIDs {
  120. rootFSLayers[diffID] = struct{}{}
  121. }
  122. layerCounter := 0
  123. for _, h := range img.History {
  124. if !h.EmptyLayer {
  125. layerCounter++
  126. }
  127. }
  128. if layerCounter > len(img.RootFS.DiffIDs) {
  129. return "", errdefs.InvalidParameter(errors.New("too many non-empty layers in History section"))
  130. }
  131. imageDigest, err := is.fs.Set(config)
  132. if err != nil {
  133. return "", errdefs.InvalidParameter(err)
  134. }
  135. is.Lock()
  136. defer is.Unlock()
  137. imageID := ID(imageDigest)
  138. if _, exists := is.images[imageID]; exists {
  139. return imageID, nil
  140. }
  141. layerID := img.RootFS.ChainID()
  142. var l layer.Layer
  143. if layerID != "" {
  144. if err := CheckOS(img.OperatingSystem()); err != nil {
  145. return "", err
  146. }
  147. l, err = is.lss.Get(layerID)
  148. if err != nil {
  149. return "", errdefs.InvalidParameter(errors.Wrapf(err, "failed to get layer %s", layerID))
  150. }
  151. }
  152. is.images[imageID] = &imageMeta{
  153. layer: l,
  154. children: make(map[ID]struct{}),
  155. }
  156. if err = is.digestSet.Add(imageDigest); err != nil {
  157. delete(is.images, imageID)
  158. return "", errdefs.InvalidParameter(err)
  159. }
  160. return imageID, nil
  161. }
  162. type imageNotFoundError string
  163. func (e imageNotFoundError) Error() string {
  164. return "No such image: " + string(e)
  165. }
  166. func (imageNotFoundError) NotFound() {}
  167. func (is *store) Search(term string) (ID, error) {
  168. dgst, err := is.digestSet.Lookup(term)
  169. if err != nil {
  170. if err == digestset.ErrDigestNotFound {
  171. err = imageNotFoundError(term)
  172. }
  173. return "", errors.WithStack(err)
  174. }
  175. return ID(dgst), nil
  176. }
  177. func (is *store) Get(id ID) (*Image, error) {
  178. // todo: Check if image is in images
  179. // todo: Detect manual insertions and start using them
  180. config, err := is.fs.Get(id.Digest())
  181. if err != nil {
  182. return nil, errdefs.NotFound(err)
  183. }
  184. img, err := NewFromJSON(config)
  185. if err != nil {
  186. return nil, errdefs.InvalidParameter(err)
  187. }
  188. img.computedID = id
  189. img.Parent, err = is.GetParent(id)
  190. if err != nil {
  191. img.Parent = ""
  192. }
  193. return img, nil
  194. }
  195. func (is *store) Delete(id ID) ([]layer.Metadata, error) {
  196. is.Lock()
  197. defer is.Unlock()
  198. imgMeta := is.images[id]
  199. if imgMeta == nil {
  200. return nil, errdefs.NotFound(fmt.Errorf("unrecognized image ID %s", id.String()))
  201. }
  202. _, err := is.Get(id)
  203. if err != nil {
  204. return nil, errdefs.NotFound(fmt.Errorf("unrecognized image %s, %v", id.String(), err))
  205. }
  206. for cID := range imgMeta.children {
  207. is.fs.DeleteMetadata(cID.Digest(), "parent")
  208. }
  209. if parent, err := is.GetParent(id); err == nil && is.images[parent] != nil {
  210. delete(is.images[parent].children, id)
  211. }
  212. if err := is.digestSet.Remove(id.Digest()); err != nil {
  213. log.G(context.TODO()).Errorf("error removing %s from digest set: %q", id, err)
  214. }
  215. delete(is.images, id)
  216. is.fs.Delete(id.Digest())
  217. if imgMeta.layer != nil {
  218. return is.lss.Release(imgMeta.layer)
  219. }
  220. return nil, nil
  221. }
  222. func (is *store) SetParent(id, parentID ID) error {
  223. is.Lock()
  224. defer is.Unlock()
  225. parentMeta := is.images[parentID]
  226. if parentMeta == nil {
  227. return errdefs.NotFound(fmt.Errorf("unknown parent image ID %s", parentID.String()))
  228. }
  229. if parent, err := is.GetParent(id); err == nil && is.images[parent] != nil {
  230. delete(is.images[parent].children, id)
  231. }
  232. parentMeta.children[id] = struct{}{}
  233. return is.fs.SetMetadata(id.Digest(), "parent", []byte(parentID))
  234. }
  235. func (is *store) GetParent(id ID) (ID, error) {
  236. d, err := is.fs.GetMetadata(id.Digest(), "parent")
  237. if err != nil {
  238. return "", errdefs.NotFound(err)
  239. }
  240. return ID(d), nil // todo: validate?
  241. }
  242. // SetLastUpdated time for the image ID to the current time
  243. func (is *store) SetLastUpdated(id ID) error {
  244. lastUpdated := []byte(time.Now().Format(time.RFC3339Nano))
  245. return is.fs.SetMetadata(id.Digest(), "lastUpdated", lastUpdated)
  246. }
  247. // GetLastUpdated time for the image ID
  248. func (is *store) GetLastUpdated(id ID) (time.Time, error) {
  249. bytes, err := is.fs.GetMetadata(id.Digest(), "lastUpdated")
  250. if err != nil || len(bytes) == 0 {
  251. // No lastUpdated time
  252. return time.Time{}, nil
  253. }
  254. return time.Parse(time.RFC3339Nano, string(bytes))
  255. }
  256. func (is *store) Children(id ID) []ID {
  257. is.RLock()
  258. defer is.RUnlock()
  259. return is.children(id)
  260. }
  261. func (is *store) children(id ID) []ID {
  262. var ids []ID
  263. if is.images[id] != nil {
  264. for id := range is.images[id].children {
  265. ids = append(ids, id)
  266. }
  267. }
  268. return ids
  269. }
  270. func (is *store) Heads() map[ID]*Image {
  271. return is.imagesMap(false)
  272. }
  273. func (is *store) Map() map[ID]*Image {
  274. return is.imagesMap(true)
  275. }
  276. func (is *store) imagesMap(all bool) map[ID]*Image {
  277. is.RLock()
  278. defer is.RUnlock()
  279. images := make(map[ID]*Image)
  280. for id := range is.images {
  281. if !all && len(is.children(id)) > 0 {
  282. continue
  283. }
  284. img, err := is.Get(id)
  285. if err != nil {
  286. log.G(context.TODO()).Errorf("invalid image access: %q, error: %q", id, err)
  287. continue
  288. }
  289. images[id] = img
  290. }
  291. return images
  292. }
  293. func (is *store) Len() int {
  294. is.RLock()
  295. defer is.RUnlock()
  296. return len(is.images)
  297. }