store.go 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332
  1. package image
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. "strings"
  6. "sync"
  7. "time"
  8. "github.com/docker/distribution/digestset"
  9. "github.com/docker/docker/layer"
  10. "github.com/docker/docker/pkg/system"
  11. "github.com/opencontainers/go-digest"
  12. "github.com/pkg/errors"
  13. "github.com/sirupsen/logrus"
  14. )
  15. // Store is an interface for creating and accessing images
  16. type Store interface {
  17. Create(config []byte) (ID, error)
  18. Get(id ID) (*Image, error)
  19. Delete(id ID) ([]layer.Metadata, error)
  20. Search(partialID string) (ID, error)
  21. SetParent(id ID, parent ID) error
  22. GetParent(id ID) (ID, error)
  23. SetLastUpdated(id ID) error
  24. GetLastUpdated(id ID) (time.Time, error)
  25. Children(id ID) []ID
  26. Map() map[ID]*Image
  27. Heads() map[ID]*Image
  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. ls LayerGetReleaser
  41. images map[ID]*imageMeta
  42. fs StoreBackend
  43. digestSet *digestset.Set
  44. platform string
  45. }
  46. // NewImageStore returns new store object for given layer store
  47. func NewImageStore(fs StoreBackend, platform string, ls LayerGetReleaser) (Store, error) {
  48. is := &store{
  49. ls: ls,
  50. images: make(map[ID]*imageMeta),
  51. fs: fs,
  52. digestSet: digestset.NewSet(),
  53. platform: platform,
  54. }
  55. // load all current images and retain layers
  56. if err := is.restore(); err != nil {
  57. return nil, err
  58. }
  59. return is, nil
  60. }
  61. func (is *store) restore() error {
  62. err := is.fs.Walk(func(dgst digest.Digest) error {
  63. img, err := is.Get(IDFromDigest(dgst))
  64. if err != nil {
  65. logrus.Errorf("invalid image %v, %v", dgst, err)
  66. return nil
  67. }
  68. var l layer.Layer
  69. if chainID := img.RootFS.ChainID(); chainID != "" {
  70. l, err = is.ls.Get(chainID)
  71. if err != nil {
  72. return err
  73. }
  74. }
  75. if err := is.digestSet.Add(dgst); err != nil {
  76. return err
  77. }
  78. imageMeta := &imageMeta{
  79. layer: l,
  80. children: make(map[ID]struct{}),
  81. }
  82. is.images[IDFromDigest(dgst)] = imageMeta
  83. return nil
  84. })
  85. if err != nil {
  86. return err
  87. }
  88. // Second pass to fill in children maps
  89. for id := range is.images {
  90. if parent, err := is.GetParent(id); err == nil {
  91. if parentMeta := is.images[parent]; parentMeta != nil {
  92. parentMeta.children[id] = struct{}{}
  93. }
  94. }
  95. }
  96. return nil
  97. }
  98. func (is *store) Create(config []byte) (ID, error) {
  99. var img Image
  100. err := json.Unmarshal(config, &img)
  101. if err != nil {
  102. return "", err
  103. }
  104. // TODO @jhowardmsft - LCOW Support. This will need revisiting.
  105. // Integrity check - ensure we are creating something for the correct platform
  106. if system.LCOWSupported() {
  107. if strings.ToLower(img.Platform()) != strings.ToLower(is.platform) {
  108. return "", fmt.Errorf("cannot create entry for platform %q in image store for platform %q", img.Platform(), is.platform)
  109. }
  110. }
  111. // Must reject any config that references diffIDs from the history
  112. // which aren't among the rootfs layers.
  113. rootFSLayers := make(map[layer.DiffID]struct{})
  114. for _, diffID := range img.RootFS.DiffIDs {
  115. rootFSLayers[diffID] = struct{}{}
  116. }
  117. layerCounter := 0
  118. for _, h := range img.History {
  119. if !h.EmptyLayer {
  120. layerCounter++
  121. }
  122. }
  123. if layerCounter > len(img.RootFS.DiffIDs) {
  124. return "", errors.New("too many non-empty layers in History section")
  125. }
  126. dgst, err := is.fs.Set(config)
  127. if err != nil {
  128. return "", err
  129. }
  130. imageID := IDFromDigest(dgst)
  131. is.Lock()
  132. defer is.Unlock()
  133. if _, exists := is.images[imageID]; exists {
  134. return imageID, nil
  135. }
  136. layerID := img.RootFS.ChainID()
  137. var l layer.Layer
  138. if layerID != "" {
  139. l, err = is.ls.Get(layerID)
  140. if err != nil {
  141. return "", errors.Wrapf(err, "failed to get layer %s", layerID)
  142. }
  143. }
  144. imageMeta := &imageMeta{
  145. layer: l,
  146. children: make(map[ID]struct{}),
  147. }
  148. is.images[imageID] = imageMeta
  149. if err := is.digestSet.Add(imageID.Digest()); err != nil {
  150. delete(is.images, imageID)
  151. return "", err
  152. }
  153. return imageID, nil
  154. }
  155. type imageNotFoundError string
  156. func (e imageNotFoundError) Error() string {
  157. return "No such image: " + string(e)
  158. }
  159. func (imageNotFoundError) NotFound() {}
  160. func (is *store) Search(term string) (ID, error) {
  161. dgst, err := is.digestSet.Lookup(term)
  162. if err != nil {
  163. if err == digestset.ErrDigestNotFound {
  164. err = imageNotFoundError(term)
  165. }
  166. return "", errors.WithStack(err)
  167. }
  168. return IDFromDigest(dgst), nil
  169. }
  170. func (is *store) Get(id ID) (*Image, error) {
  171. // todo: Check if image is in images
  172. // todo: Detect manual insertions and start using them
  173. config, err := is.fs.Get(id.Digest())
  174. if err != nil {
  175. return nil, err
  176. }
  177. img, err := NewFromJSON(config)
  178. if err != nil {
  179. return nil, err
  180. }
  181. img.computedID = id
  182. img.Parent, err = is.GetParent(id)
  183. if err != nil {
  184. img.Parent = ""
  185. }
  186. return img, nil
  187. }
  188. func (is *store) Delete(id ID) ([]layer.Metadata, error) {
  189. is.Lock()
  190. defer is.Unlock()
  191. imageMeta := is.images[id]
  192. if imageMeta == nil {
  193. return nil, fmt.Errorf("unrecognized image ID %s", id.String())
  194. }
  195. for id := range imageMeta.children {
  196. is.fs.DeleteMetadata(id.Digest(), "parent")
  197. }
  198. if parent, err := is.GetParent(id); err == nil && is.images[parent] != nil {
  199. delete(is.images[parent].children, id)
  200. }
  201. if err := is.digestSet.Remove(id.Digest()); err != nil {
  202. logrus.Errorf("error removing %s from digest set: %q", id, err)
  203. }
  204. delete(is.images, id)
  205. is.fs.Delete(id.Digest())
  206. if imageMeta.layer != nil {
  207. return is.ls.Release(imageMeta.layer)
  208. }
  209. return nil, nil
  210. }
  211. func (is *store) SetParent(id, parent ID) error {
  212. is.Lock()
  213. defer is.Unlock()
  214. parentMeta := is.images[parent]
  215. if parentMeta == nil {
  216. return fmt.Errorf("unknown parent image ID %s", parent.String())
  217. }
  218. if parent, err := is.GetParent(id); err == nil && is.images[parent] != nil {
  219. delete(is.images[parent].children, id)
  220. }
  221. parentMeta.children[id] = struct{}{}
  222. return is.fs.SetMetadata(id.Digest(), "parent", []byte(parent))
  223. }
  224. func (is *store) GetParent(id ID) (ID, error) {
  225. d, err := is.fs.GetMetadata(id.Digest(), "parent")
  226. if err != nil {
  227. return "", err
  228. }
  229. return ID(d), nil // todo: validate?
  230. }
  231. // SetLastUpdated time for the image ID to the current time
  232. func (is *store) SetLastUpdated(id ID) error {
  233. lastUpdated := []byte(time.Now().Format(time.RFC3339Nano))
  234. return is.fs.SetMetadata(id.Digest(), "lastUpdated", lastUpdated)
  235. }
  236. // GetLastUpdated time for the image ID
  237. func (is *store) GetLastUpdated(id ID) (time.Time, error) {
  238. bytes, err := is.fs.GetMetadata(id.Digest(), "lastUpdated")
  239. if err != nil || len(bytes) == 0 {
  240. // No lastUpdated time
  241. return time.Time{}, nil
  242. }
  243. return time.Parse(time.RFC3339Nano, string(bytes))
  244. }
  245. func (is *store) Children(id ID) []ID {
  246. is.RLock()
  247. defer is.RUnlock()
  248. return is.children(id)
  249. }
  250. func (is *store) children(id ID) []ID {
  251. var ids []ID
  252. if is.images[id] != nil {
  253. for id := range is.images[id].children {
  254. ids = append(ids, id)
  255. }
  256. }
  257. return ids
  258. }
  259. func (is *store) Heads() map[ID]*Image {
  260. return is.imagesMap(false)
  261. }
  262. func (is *store) Map() map[ID]*Image {
  263. return is.imagesMap(true)
  264. }
  265. func (is *store) imagesMap(all bool) map[ID]*Image {
  266. is.RLock()
  267. defer is.RUnlock()
  268. images := make(map[ID]*Image)
  269. for id := range is.images {
  270. if !all && len(is.children(id)) > 0 {
  271. continue
  272. }
  273. img, err := is.Get(id)
  274. if err != nil {
  275. logrus.Errorf("invalid image access: %q, error: %q", id, err)
  276. continue
  277. }
  278. images[id] = img
  279. }
  280. return images
  281. }