graph.go 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815
  1. package graph
  2. import (
  3. "compress/gzip"
  4. "encoding/json"
  5. "errors"
  6. "fmt"
  7. "io"
  8. "io/ioutil"
  9. "os"
  10. "path/filepath"
  11. "runtime"
  12. "strconv"
  13. "strings"
  14. "sync"
  15. "time"
  16. "github.com/Sirupsen/logrus"
  17. "github.com/docker/distribution/digest"
  18. "github.com/docker/docker/autogen/dockerversion"
  19. "github.com/docker/docker/daemon/graphdriver"
  20. "github.com/docker/docker/image"
  21. "github.com/docker/docker/pkg/archive"
  22. "github.com/docker/docker/pkg/idtools"
  23. "github.com/docker/docker/pkg/locker"
  24. "github.com/docker/docker/pkg/progressreader"
  25. "github.com/docker/docker/pkg/streamformatter"
  26. "github.com/docker/docker/pkg/stringid"
  27. "github.com/docker/docker/pkg/truncindex"
  28. "github.com/docker/docker/runconfig"
  29. "github.com/vbatts/tar-split/tar/asm"
  30. "github.com/vbatts/tar-split/tar/storage"
  31. )
  32. // v1Descriptor is a non-content-addressable image descriptor
  33. type v1Descriptor struct {
  34. img *image.Image
  35. }
  36. // ID returns the image ID specified in the image structure.
  37. func (img v1Descriptor) ID() string {
  38. return img.img.ID
  39. }
  40. // Parent returns the parent ID specified in the image structure.
  41. func (img v1Descriptor) Parent() string {
  42. return img.img.Parent
  43. }
  44. // MarshalConfig renders the image structure into JSON.
  45. func (img v1Descriptor) MarshalConfig() ([]byte, error) {
  46. return json.Marshal(img.img)
  47. }
  48. // The type is used to protect pulling or building related image
  49. // layers from deleteing when filtered by dangling=true
  50. // The key of layers is the images ID which is pulling or building
  51. // The value of layers is a slice which hold layer IDs referenced to
  52. // pulling or building images
  53. type retainedLayers struct {
  54. layerHolders map[string]map[string]struct{} // map[layerID]map[sessionID]
  55. sync.Mutex
  56. }
  57. func (r *retainedLayers) Add(sessionID string, layerIDs []string) {
  58. r.Lock()
  59. defer r.Unlock()
  60. for _, layerID := range layerIDs {
  61. if r.layerHolders[layerID] == nil {
  62. r.layerHolders[layerID] = map[string]struct{}{}
  63. }
  64. r.layerHolders[layerID][sessionID] = struct{}{}
  65. }
  66. }
  67. func (r *retainedLayers) Delete(sessionID string, layerIDs []string) {
  68. r.Lock()
  69. defer r.Unlock()
  70. for _, layerID := range layerIDs {
  71. holders, ok := r.layerHolders[layerID]
  72. if !ok {
  73. continue
  74. }
  75. delete(holders, sessionID)
  76. if len(holders) == 0 {
  77. delete(r.layerHolders, layerID) // Delete any empty reference set.
  78. }
  79. }
  80. }
  81. func (r *retainedLayers) Exists(layerID string) bool {
  82. r.Lock()
  83. _, exists := r.layerHolders[layerID]
  84. r.Unlock()
  85. return exists
  86. }
  87. // A Graph is a store for versioned filesystem images and the relationship between them.
  88. type Graph struct {
  89. root string
  90. idIndex *truncindex.TruncIndex
  91. driver graphdriver.Driver
  92. imagesMutex sync.Mutex
  93. imageMutex locker.Locker // protect images in driver.
  94. retained *retainedLayers
  95. tarSplitDisabled bool
  96. uidMaps []idtools.IDMap
  97. gidMaps []idtools.IDMap
  98. // access to parentRefs must be protected with imageMutex locking the image id
  99. // on the key of the map (e.g. imageMutex.Lock(img.ID), parentRefs[img.ID]...)
  100. parentRefs map[string]int
  101. }
  102. // file names for ./graph/<ID>/
  103. const (
  104. jsonFileName = "json"
  105. layersizeFileName = "layersize"
  106. digestFileName = "checksum"
  107. tarDataFileName = "tar-data.json.gz"
  108. v1CompatibilityFileName = "v1Compatibility"
  109. parentFileName = "parent"
  110. )
  111. var (
  112. // errDigestNotSet is used when request the digest for a layer
  113. // but the layer has no digest value or content to compute the
  114. // the digest.
  115. errDigestNotSet = errors.New("digest is not set for layer")
  116. )
  117. // NewGraph instantiates a new graph at the given root path in the filesystem.
  118. // `root` will be created if it doesn't exist.
  119. func NewGraph(root string, driver graphdriver.Driver, uidMaps, gidMaps []idtools.IDMap) (*Graph, error) {
  120. abspath, err := filepath.Abs(root)
  121. if err != nil {
  122. return nil, err
  123. }
  124. rootUID, rootGID, err := idtools.GetRootUIDGID(uidMaps, gidMaps)
  125. if err != nil {
  126. return nil, err
  127. }
  128. // Create the root directory if it doesn't exists
  129. if err := idtools.MkdirAllAs(root, 0700, rootUID, rootGID); err != nil && !os.IsExist(err) {
  130. return nil, err
  131. }
  132. graph := &Graph{
  133. root: abspath,
  134. idIndex: truncindex.NewTruncIndex([]string{}),
  135. driver: driver,
  136. retained: &retainedLayers{layerHolders: make(map[string]map[string]struct{})},
  137. uidMaps: uidMaps,
  138. gidMaps: gidMaps,
  139. parentRefs: make(map[string]int),
  140. }
  141. // Windows does not currently support tarsplit functionality.
  142. if runtime.GOOS == "windows" {
  143. graph.tarSplitDisabled = true
  144. }
  145. if err := graph.restore(); err != nil {
  146. return nil, err
  147. }
  148. return graph, nil
  149. }
  150. // IsHeld returns whether the given layerID is being used by an ongoing pull or build.
  151. func (graph *Graph) IsHeld(layerID string) bool {
  152. return graph.retained.Exists(layerID)
  153. }
  154. func (graph *Graph) restore() error {
  155. dir, err := ioutil.ReadDir(graph.root)
  156. if err != nil {
  157. return err
  158. }
  159. var ids = []string{}
  160. for _, v := range dir {
  161. id := v.Name()
  162. if graph.driver.Exists(id) {
  163. img, err := graph.loadImage(id)
  164. if err != nil {
  165. logrus.Warnf("ignoring image %s, it could not be restored: %v", id, err)
  166. continue
  167. }
  168. graph.imageMutex.Lock(img.Parent)
  169. graph.parentRefs[img.Parent]++
  170. graph.imageMutex.Unlock(img.Parent)
  171. ids = append(ids, id)
  172. }
  173. }
  174. graph.idIndex = truncindex.NewTruncIndex(ids)
  175. logrus.Debugf("Restored %d elements", len(ids))
  176. return nil
  177. }
  178. // IsNotExist detects whether an image exists by parsing the incoming error
  179. // message.
  180. func (graph *Graph) IsNotExist(err error, id string) bool {
  181. // FIXME: Implement error subclass instead of looking at the error text
  182. // Note: This is the way golang implements os.IsNotExists on Plan9
  183. return err != nil && (strings.Contains(strings.ToLower(err.Error()), "does not exist") || strings.Contains(strings.ToLower(err.Error()), "no such")) && strings.Contains(err.Error(), id)
  184. }
  185. // Exists returns true if an image is registered at the given id.
  186. // If the image doesn't exist or if an error is encountered, false is returned.
  187. func (graph *Graph) Exists(id string) bool {
  188. if _, err := graph.Get(id); err != nil {
  189. return false
  190. }
  191. return true
  192. }
  193. // Get returns the image with the given id, or an error if the image doesn't exist.
  194. func (graph *Graph) Get(name string) (*image.Image, error) {
  195. id, err := graph.idIndex.Get(name)
  196. if err != nil {
  197. if err == truncindex.ErrNotExist {
  198. return nil, fmt.Errorf("image %s does not exist", name)
  199. }
  200. return nil, err
  201. }
  202. img, err := graph.loadImage(id)
  203. if err != nil {
  204. return nil, err
  205. }
  206. if img.ID != id {
  207. return nil, fmt.Errorf("Image stored at '%s' has wrong id '%s'", id, img.ID)
  208. }
  209. if img.Size < 0 {
  210. size, err := graph.driver.DiffSize(img.ID, img.Parent)
  211. if err != nil {
  212. return nil, fmt.Errorf("unable to calculate size of image id %q: %s", img.ID, err)
  213. }
  214. img.Size = size
  215. if err := graph.saveSize(graph.imageRoot(id), img.Size); err != nil {
  216. return nil, err
  217. }
  218. }
  219. return img, nil
  220. }
  221. // Create creates a new image and registers it in the graph.
  222. func (graph *Graph) Create(layerData io.Reader, containerID, containerImage, comment, author string, containerConfig, config *runconfig.Config) (*image.Image, error) {
  223. img := &image.Image{
  224. ID: stringid.GenerateRandomID(),
  225. Comment: comment,
  226. Created: time.Now().UTC(),
  227. DockerVersion: dockerversion.VERSION,
  228. Author: author,
  229. Config: config,
  230. Architecture: runtime.GOARCH,
  231. OS: runtime.GOOS,
  232. }
  233. if containerID != "" {
  234. img.Parent = containerImage
  235. img.Container = containerID
  236. img.ContainerConfig = *containerConfig
  237. }
  238. if err := graph.Register(v1Descriptor{img}, layerData); err != nil {
  239. return nil, err
  240. }
  241. return img, nil
  242. }
  243. // Register imports a pre-existing image into the graph.
  244. // Returns nil if the image is already registered.
  245. func (graph *Graph) Register(im image.Descriptor, layerData io.Reader) (err error) {
  246. imgID := im.ID()
  247. if err := image.ValidateID(imgID); err != nil {
  248. return err
  249. }
  250. // this is needed cause pull_v2 attemptIDReuse could deadlock
  251. graph.imagesMutex.Lock()
  252. defer graph.imagesMutex.Unlock()
  253. // We need this entire operation to be atomic within the engine. Note that
  254. // this doesn't mean Register is fully safe yet.
  255. graph.imageMutex.Lock(imgID)
  256. defer graph.imageMutex.Unlock(imgID)
  257. return graph.register(im, layerData)
  258. }
  259. func (graph *Graph) register(im image.Descriptor, layerData io.Reader) (err error) {
  260. imgID := im.ID()
  261. // Skip register if image is already registered
  262. if graph.Exists(imgID) {
  263. return nil
  264. }
  265. // The returned `error` must be named in this function's signature so that
  266. // `err` is not shadowed in this deferred cleanup.
  267. defer func() {
  268. // If any error occurs, remove the new dir from the driver.
  269. // Don't check for errors since the dir might not have been created.
  270. if err != nil {
  271. graph.driver.Remove(imgID)
  272. }
  273. }()
  274. // Ensure that the image root does not exist on the filesystem
  275. // when it is not registered in the graph.
  276. // This is common when you switch from one graph driver to another
  277. if err := os.RemoveAll(graph.imageRoot(imgID)); err != nil && !os.IsNotExist(err) {
  278. return err
  279. }
  280. // If the driver has this ID but the graph doesn't, remove it from the driver to start fresh.
  281. // (the graph is the source of truth).
  282. // Ignore errors, since we don't know if the driver correctly returns ErrNotExist.
  283. // (FIXME: make that mandatory for drivers).
  284. graph.driver.Remove(imgID)
  285. tmp, err := graph.mktemp()
  286. if err != nil {
  287. return err
  288. }
  289. defer os.RemoveAll(tmp)
  290. parent := im.Parent()
  291. // Create root filesystem in the driver
  292. if err := createRootFilesystemInDriver(graph, imgID, parent); err != nil {
  293. return err
  294. }
  295. // Apply the diff/layer
  296. config, err := im.MarshalConfig()
  297. if err != nil {
  298. return err
  299. }
  300. if err := graph.storeImage(imgID, parent, config, layerData, tmp); err != nil {
  301. return err
  302. }
  303. // Commit
  304. if err := os.Rename(tmp, graph.imageRoot(imgID)); err != nil {
  305. return err
  306. }
  307. graph.idIndex.Add(imgID)
  308. graph.imageMutex.Lock(parent)
  309. graph.parentRefs[parent]++
  310. graph.imageMutex.Unlock(parent)
  311. return nil
  312. }
  313. func createRootFilesystemInDriver(graph *Graph, id, parent string) error {
  314. if err := graph.driver.Create(id, parent); err != nil {
  315. return fmt.Errorf("Driver %s failed to create image rootfs %s: %s", graph.driver, id, err)
  316. }
  317. return nil
  318. }
  319. // TempLayerArchive creates a temporary archive of the given image's filesystem layer.
  320. // The archive is stored on disk and will be automatically deleted as soon as has been read.
  321. // If output is not nil, a human-readable progress bar will be written to it.
  322. func (graph *Graph) tempLayerArchive(id string, sf *streamformatter.StreamFormatter, output io.Writer) (*archive.TempArchive, error) {
  323. image, err := graph.Get(id)
  324. if err != nil {
  325. return nil, err
  326. }
  327. tmp, err := graph.mktemp()
  328. if err != nil {
  329. return nil, err
  330. }
  331. defer os.RemoveAll(tmp)
  332. a, err := graph.tarLayer(image)
  333. if err != nil {
  334. return nil, err
  335. }
  336. progressReader := progressreader.New(progressreader.Config{
  337. In: a,
  338. Out: output,
  339. Formatter: sf,
  340. Size: 0,
  341. NewLines: false,
  342. ID: stringid.TruncateID(id),
  343. Action: "Buffering to disk",
  344. })
  345. defer progressReader.Close()
  346. return archive.NewTempArchive(progressReader, tmp)
  347. }
  348. // mktemp creates a temporary sub-directory inside the graph's filesystem.
  349. func (graph *Graph) mktemp() (string, error) {
  350. dir := filepath.Join(graph.root, "_tmp", stringid.GenerateNonCryptoID())
  351. rootUID, rootGID, err := idtools.GetRootUIDGID(graph.uidMaps, graph.gidMaps)
  352. if err != nil {
  353. return "", err
  354. }
  355. if err := idtools.MkdirAllAs(dir, 0700, rootUID, rootGID); err != nil {
  356. return "", err
  357. }
  358. return dir, nil
  359. }
  360. // Delete atomically removes an image from the graph.
  361. func (graph *Graph) Delete(name string) error {
  362. id, err := graph.idIndex.Get(name)
  363. if err != nil {
  364. return err
  365. }
  366. img, err := graph.Get(id)
  367. if err != nil {
  368. return err
  369. }
  370. graph.idIndex.Delete(id)
  371. tmp, err := graph.mktemp()
  372. if err != nil {
  373. tmp = graph.imageRoot(id)
  374. } else {
  375. if err := os.Rename(graph.imageRoot(id), tmp); err != nil {
  376. // On err make tmp point to old dir and cleanup unused tmp dir
  377. os.RemoveAll(tmp)
  378. tmp = graph.imageRoot(id)
  379. }
  380. }
  381. // Remove rootfs data from the driver
  382. graph.driver.Remove(id)
  383. graph.imageMutex.Lock(img.Parent)
  384. graph.parentRefs[img.Parent]--
  385. if graph.parentRefs[img.Parent] == 0 {
  386. delete(graph.parentRefs, img.Parent)
  387. }
  388. graph.imageMutex.Unlock(img.Parent)
  389. // Remove the trashed image directory
  390. return os.RemoveAll(tmp)
  391. }
  392. // Map returns a list of all images in the graph, addressable by ID.
  393. func (graph *Graph) Map() map[string]*image.Image {
  394. images := make(map[string]*image.Image)
  395. graph.walkAll(func(image *image.Image) {
  396. images[image.ID] = image
  397. })
  398. return images
  399. }
  400. // walkAll iterates over each image in the graph, and passes it to a handler.
  401. // The walking order is undetermined.
  402. func (graph *Graph) walkAll(handler func(*image.Image)) {
  403. graph.idIndex.Iterate(func(id string) {
  404. img, err := graph.Get(id)
  405. if err != nil {
  406. return
  407. }
  408. if handler != nil {
  409. handler(img)
  410. }
  411. })
  412. }
  413. // ByParent returns a lookup table of images by their parent.
  414. // If an image of key ID has 3 children images, then the value for key ID
  415. // will be a list of 3 images.
  416. // If an image has no children, it will not have an entry in the table.
  417. func (graph *Graph) ByParent() map[string][]*image.Image {
  418. byParent := make(map[string][]*image.Image)
  419. graph.walkAll(func(img *image.Image) {
  420. parent, err := graph.Get(img.Parent)
  421. if err != nil {
  422. return
  423. }
  424. if children, exists := byParent[parent.ID]; exists {
  425. byParent[parent.ID] = append(children, img)
  426. } else {
  427. byParent[parent.ID] = []*image.Image{img}
  428. }
  429. })
  430. return byParent
  431. }
  432. // HasChildren returns whether the given image has any child images.
  433. func (graph *Graph) HasChildren(imgID string) bool {
  434. graph.imageMutex.Lock(imgID)
  435. count := graph.parentRefs[imgID]
  436. graph.imageMutex.Unlock(imgID)
  437. return count > 0
  438. }
  439. // Retain keeps the images and layers that are in the pulling chain so that
  440. // they are not deleted. If not retained, they may be deleted by rmi.
  441. func (graph *Graph) Retain(sessionID string, layerIDs ...string) {
  442. graph.retained.Add(sessionID, layerIDs)
  443. }
  444. // Release removes the referenced image ID from the provided set of layers.
  445. func (graph *Graph) Release(sessionID string, layerIDs ...string) {
  446. graph.retained.Delete(sessionID, layerIDs)
  447. }
  448. // heads returns all heads in the graph, keyed by id.
  449. // A head is an image which is not the parent of another image in the graph.
  450. func (graph *Graph) heads() map[string]*image.Image {
  451. heads := make(map[string]*image.Image)
  452. graph.walkAll(func(image *image.Image) {
  453. // if it has no children, then it's not a parent, so it's an head
  454. if !graph.HasChildren(image.ID) {
  455. heads[image.ID] = image
  456. }
  457. })
  458. return heads
  459. }
  460. // tarLayer returns a tar archive of the image's filesystem layer.
  461. func (graph *Graph) tarLayer(img *image.Image) (arch io.ReadCloser, err error) {
  462. rdr, err := graph.assembleTarLayer(img)
  463. if err != nil {
  464. logrus.Debugf("[graph] tarLayer with traditional differ: %s", img.ID)
  465. return graph.driver.Diff(img.ID, img.Parent)
  466. }
  467. return rdr, nil
  468. }
  469. func (graph *Graph) imageRoot(id string) string {
  470. return filepath.Join(graph.root, id)
  471. }
  472. // loadImage fetches the image with the given id from the graph.
  473. func (graph *Graph) loadImage(id string) (*image.Image, error) {
  474. root := graph.imageRoot(id)
  475. // Open the JSON file to decode by streaming
  476. jsonSource, err := os.Open(jsonPath(root))
  477. if err != nil {
  478. return nil, err
  479. }
  480. defer jsonSource.Close()
  481. img := &image.Image{}
  482. dec := json.NewDecoder(jsonSource)
  483. // Decode the JSON data
  484. if err := dec.Decode(img); err != nil {
  485. return nil, err
  486. }
  487. if img.ID == "" {
  488. img.ID = id
  489. }
  490. if img.Parent == "" && img.ParentID != "" && img.ParentID.Validate() == nil {
  491. img.Parent = img.ParentID.Hex()
  492. }
  493. // compatibilityID for parent
  494. parent, err := ioutil.ReadFile(filepath.Join(root, parentFileName))
  495. if err == nil && len(parent) > 0 {
  496. img.Parent = string(parent)
  497. }
  498. if err := image.ValidateID(img.ID); err != nil {
  499. return nil, err
  500. }
  501. if buf, err := ioutil.ReadFile(filepath.Join(root, layersizeFileName)); err != nil {
  502. if !os.IsNotExist(err) {
  503. return nil, err
  504. }
  505. // If the layersize file does not exist then set the size to a negative number
  506. // because a layer size of 0 (zero) is valid
  507. img.Size = -1
  508. } else {
  509. // Using Atoi here instead would temporarily convert the size to a machine
  510. // dependent integer type, which causes images larger than 2^31 bytes to
  511. // display negative sizes on 32-bit machines:
  512. size, err := strconv.ParseInt(string(buf), 10, 64)
  513. if err != nil {
  514. return nil, err
  515. }
  516. img.Size = int64(size)
  517. }
  518. return img, nil
  519. }
  520. // saveSize stores the `size` in the provided graph `img` directory `root`.
  521. func (graph *Graph) saveSize(root string, size int64) error {
  522. if err := ioutil.WriteFile(filepath.Join(root, layersizeFileName), []byte(strconv.FormatInt(size, 10)), 0600); err != nil {
  523. return fmt.Errorf("Error storing image size in %s/%s: %s", root, layersizeFileName, err)
  524. }
  525. return nil
  526. }
  527. // setLayerDigestWithLock sets the digest for the image layer to the provided value.
  528. func (graph *Graph) setLayerDigestWithLock(id string, dgst digest.Digest) error {
  529. graph.imageMutex.Lock(id)
  530. defer graph.imageMutex.Unlock(id)
  531. return graph.setLayerDigest(id, dgst)
  532. }
  533. func (graph *Graph) setLayerDigest(id string, dgst digest.Digest) error {
  534. root := graph.imageRoot(id)
  535. if err := ioutil.WriteFile(filepath.Join(root, digestFileName), []byte(dgst.String()), 0600); err != nil {
  536. return fmt.Errorf("Error storing digest in %s/%s: %s", root, digestFileName, err)
  537. }
  538. return nil
  539. }
  540. // getLayerDigestWithLock gets the digest for the provide image layer id.
  541. func (graph *Graph) getLayerDigestWithLock(id string) (digest.Digest, error) {
  542. graph.imageMutex.Lock(id)
  543. defer graph.imageMutex.Unlock(id)
  544. return graph.getLayerDigest(id)
  545. }
  546. func (graph *Graph) getLayerDigest(id string) (digest.Digest, error) {
  547. root := graph.imageRoot(id)
  548. cs, err := ioutil.ReadFile(filepath.Join(root, digestFileName))
  549. if err != nil {
  550. if os.IsNotExist(err) {
  551. return "", errDigestNotSet
  552. }
  553. return "", err
  554. }
  555. return digest.ParseDigest(string(cs))
  556. }
  557. // setV1CompatibilityConfig stores the v1Compatibility JSON data associated
  558. // with the image in the manifest to the disk
  559. func (graph *Graph) setV1CompatibilityConfig(id string, data []byte) error {
  560. root := graph.imageRoot(id)
  561. return ioutil.WriteFile(filepath.Join(root, v1CompatibilityFileName), data, 0600)
  562. }
  563. // getV1CompatibilityConfig reads the v1Compatibility JSON data for the image
  564. // from the disk
  565. func (graph *Graph) getV1CompatibilityConfig(id string) ([]byte, error) {
  566. root := graph.imageRoot(id)
  567. return ioutil.ReadFile(filepath.Join(root, v1CompatibilityFileName))
  568. }
  569. // generateV1CompatibilityChain makes sure v1Compatibility JSON data exists
  570. // for the image. If it doesn't it generates and stores it for the image and
  571. // all of it's parents based on the image config JSON.
  572. func (graph *Graph) generateV1CompatibilityChain(id string) ([]byte, error) {
  573. graph.imageMutex.Lock(id)
  574. defer graph.imageMutex.Unlock(id)
  575. if v1config, err := graph.getV1CompatibilityConfig(id); err == nil {
  576. return v1config, nil
  577. }
  578. // generate new, store it to disk
  579. img, err := graph.Get(id)
  580. if err != nil {
  581. return nil, err
  582. }
  583. digestPrefix := string(digest.Canonical) + ":"
  584. img.ID = strings.TrimPrefix(img.ID, digestPrefix)
  585. if img.Parent != "" {
  586. parentConfig, err := graph.generateV1CompatibilityChain(img.Parent)
  587. if err != nil {
  588. return nil, err
  589. }
  590. var parent struct{ ID string }
  591. err = json.Unmarshal(parentConfig, &parent)
  592. if err != nil {
  593. return nil, err
  594. }
  595. img.Parent = parent.ID
  596. }
  597. json, err := json.Marshal(img)
  598. if err != nil {
  599. return nil, err
  600. }
  601. if err := graph.setV1CompatibilityConfig(id, json); err != nil {
  602. return nil, err
  603. }
  604. return json, nil
  605. }
  606. func jsonPath(root string) string {
  607. return filepath.Join(root, jsonFileName)
  608. }
  609. // storeImage stores file system layer data for the given image to the
  610. // graph's storage driver. Image metadata is stored in a file
  611. // at the specified root directory.
  612. func (graph *Graph) storeImage(id, parent string, config []byte, layerData io.Reader, root string) (err error) {
  613. var size int64
  614. // Store the layer. If layerData is not nil, unpack it into the new layer
  615. if layerData != nil {
  616. if size, err = graph.disassembleAndApplyTarLayer(id, parent, layerData, root); err != nil {
  617. return err
  618. }
  619. }
  620. if err := graph.saveSize(root, size); err != nil {
  621. return err
  622. }
  623. if err := ioutil.WriteFile(jsonPath(root), config, 0600); err != nil {
  624. return err
  625. }
  626. // If image is pointing to a parent via CompatibilityID write the reference to disk
  627. img, err := image.NewImgJSON(config)
  628. if err != nil {
  629. return err
  630. }
  631. if img.ParentID.Validate() == nil && parent != img.ParentID.Hex() {
  632. if err := ioutil.WriteFile(filepath.Join(root, parentFileName), []byte(parent), 0600); err != nil {
  633. return err
  634. }
  635. }
  636. return nil
  637. }
  638. func (graph *Graph) disassembleAndApplyTarLayer(id, parent string, layerData io.Reader, root string) (size int64, err error) {
  639. var ar io.Reader
  640. if graph.tarSplitDisabled {
  641. ar = layerData
  642. } else {
  643. // this is saving the tar-split metadata
  644. mf, err := os.OpenFile(filepath.Join(root, tarDataFileName), os.O_CREATE|os.O_WRONLY|os.O_TRUNC, os.FileMode(0600))
  645. if err != nil {
  646. return 0, err
  647. }
  648. mfz := gzip.NewWriter(mf)
  649. metaPacker := storage.NewJSONPacker(mfz)
  650. defer mf.Close()
  651. defer mfz.Close()
  652. inflatedLayerData, err := archive.DecompressStream(layerData)
  653. if err != nil {
  654. return 0, err
  655. }
  656. // we're passing nil here for the file putter, because the ApplyDiff will
  657. // handle the extraction of the archive
  658. rdr, err := asm.NewInputTarStream(inflatedLayerData, metaPacker, nil)
  659. if err != nil {
  660. return 0, err
  661. }
  662. ar = archive.Reader(rdr)
  663. }
  664. if size, err = graph.driver.ApplyDiff(id, parent, ar); err != nil {
  665. return 0, err
  666. }
  667. return
  668. }
  669. func (graph *Graph) assembleTarLayer(img *image.Image) (io.ReadCloser, error) {
  670. root := graph.imageRoot(img.ID)
  671. mFileName := filepath.Join(root, tarDataFileName)
  672. mf, err := os.Open(mFileName)
  673. if err != nil {
  674. if !os.IsNotExist(err) {
  675. logrus.Errorf("failed to open %q: %s", mFileName, err)
  676. }
  677. return nil, err
  678. }
  679. pR, pW := io.Pipe()
  680. // this will need to be in a goroutine, as we are returning the stream of a
  681. // tar archive, but can not close the metadata reader early (when this
  682. // function returns)...
  683. go func() {
  684. defer mf.Close()
  685. // let's reassemble!
  686. logrus.Debugf("[graph] TarLayer with reassembly: %s", img.ID)
  687. mfz, err := gzip.NewReader(mf)
  688. if err != nil {
  689. pW.CloseWithError(fmt.Errorf("[graph] error with %s: %s", mFileName, err))
  690. return
  691. }
  692. defer mfz.Close()
  693. // get our relative path to the container
  694. fsLayer, err := graph.driver.Get(img.ID, "")
  695. if err != nil {
  696. pW.CloseWithError(err)
  697. return
  698. }
  699. defer graph.driver.Put(img.ID)
  700. metaUnpacker := storage.NewJSONUnpacker(mfz)
  701. fileGetter := storage.NewPathFileGetter(fsLayer)
  702. logrus.Debugf("[graph] %s is at %q", img.ID, fsLayer)
  703. ots := asm.NewOutputTarStream(fileGetter, metaUnpacker)
  704. defer ots.Close()
  705. if _, err := io.Copy(pW, ots); err != nil {
  706. pW.CloseWithError(err)
  707. return
  708. }
  709. pW.Close()
  710. }()
  711. return pR, nil
  712. }