graph.go 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532
  1. package graph
  2. import (
  3. "compress/gzip"
  4. "crypto/sha256"
  5. "encoding/json"
  6. "errors"
  7. "fmt"
  8. "io"
  9. "io/ioutil"
  10. "os"
  11. "path/filepath"
  12. "runtime"
  13. "strconv"
  14. "strings"
  15. "sync"
  16. "time"
  17. "github.com/Sirupsen/logrus"
  18. "github.com/docker/distribution/digest"
  19. "github.com/docker/docker/autogen/dockerversion"
  20. "github.com/docker/docker/daemon/graphdriver"
  21. "github.com/docker/docker/image"
  22. "github.com/docker/docker/pkg/archive"
  23. "github.com/docker/docker/pkg/progressreader"
  24. "github.com/docker/docker/pkg/streamformatter"
  25. "github.com/docker/docker/pkg/stringid"
  26. "github.com/docker/docker/pkg/system"
  27. "github.com/docker/docker/pkg/truncindex"
  28. "github.com/docker/docker/runconfig"
  29. )
  30. // The type is used to protect pulling or building related image
  31. // layers from deleteing when filtered by dangling=true
  32. // The key of layers is the images ID which is pulling or building
  33. // The value of layers is a slice which hold layer IDs referenced to
  34. // pulling or building images
  35. type retainedLayers struct {
  36. layerHolders map[string]map[string]struct{} // map[layerID]map[sessionID]
  37. sync.Mutex
  38. }
  39. func (r *retainedLayers) Add(sessionID string, layerIDs []string) {
  40. r.Lock()
  41. defer r.Unlock()
  42. for _, layerID := range layerIDs {
  43. if r.layerHolders[layerID] == nil {
  44. r.layerHolders[layerID] = map[string]struct{}{}
  45. }
  46. r.layerHolders[layerID][sessionID] = struct{}{}
  47. }
  48. }
  49. func (r *retainedLayers) Delete(sessionID string, layerIDs []string) {
  50. r.Lock()
  51. defer r.Unlock()
  52. for _, layerID := range layerIDs {
  53. holders, ok := r.layerHolders[layerID]
  54. if !ok {
  55. continue
  56. }
  57. delete(holders, sessionID)
  58. if len(holders) == 0 {
  59. delete(r.layerHolders, layerID) // Delete any empty reference set.
  60. }
  61. }
  62. }
  63. func (r *retainedLayers) Exists(layerID string) bool {
  64. r.Lock()
  65. _, exists := r.layerHolders[layerID]
  66. r.Unlock()
  67. return exists
  68. }
  69. // A Graph is a store for versioned filesystem images and the relationship between them.
  70. type Graph struct {
  71. root string
  72. idIndex *truncindex.TruncIndex
  73. driver graphdriver.Driver
  74. imageMutex imageMutex // protect images in driver.
  75. retained *retainedLayers
  76. }
  77. // file names for ./graph/<ID>/
  78. const (
  79. jsonFileName = "json"
  80. layersizeFileName = "layersize"
  81. digestFileName = "checksum"
  82. tardataFileName = "tar-data.json.gz"
  83. )
  84. var (
  85. // ErrDigestNotSet is used when request the digest for a layer
  86. // but the layer has no digest value or content to compute the
  87. // the digest.
  88. ErrDigestNotSet = errors.New("digest is not set for layer")
  89. )
  90. // NewGraph instantiates a new graph at the given root path in the filesystem.
  91. // `root` will be created if it doesn't exist.
  92. func NewGraph(root string, driver graphdriver.Driver) (*Graph, error) {
  93. abspath, err := filepath.Abs(root)
  94. if err != nil {
  95. return nil, err
  96. }
  97. // Create the root directory if it doesn't exists
  98. if err := system.MkdirAll(root, 0700); err != nil && !os.IsExist(err) {
  99. return nil, err
  100. }
  101. graph := &Graph{
  102. root: abspath,
  103. idIndex: truncindex.NewTruncIndex([]string{}),
  104. driver: driver,
  105. retained: &retainedLayers{layerHolders: make(map[string]map[string]struct{})},
  106. }
  107. if err := graph.restore(); err != nil {
  108. return nil, err
  109. }
  110. return graph, nil
  111. }
  112. // IsHeld returns whether the given layerID is being used by an ongoing pull or build.
  113. func (graph *Graph) IsHeld(layerID string) bool {
  114. return graph.retained.Exists(layerID)
  115. }
  116. func (graph *Graph) restore() error {
  117. dir, err := ioutil.ReadDir(graph.root)
  118. if err != nil {
  119. return err
  120. }
  121. var ids = []string{}
  122. for _, v := range dir {
  123. id := v.Name()
  124. if graph.driver.Exists(id) {
  125. ids = append(ids, id)
  126. }
  127. }
  128. baseIds, err := graph.restoreBaseImages()
  129. if err != nil {
  130. return err
  131. }
  132. ids = append(ids, baseIds...)
  133. graph.idIndex = truncindex.NewTruncIndex(ids)
  134. logrus.Debugf("Restored %d elements", len(ids))
  135. return nil
  136. }
  137. // FIXME: Implement error subclass instead of looking at the error text
  138. // Note: This is the way golang implements os.IsNotExists on Plan9
  139. func (graph *Graph) IsNotExist(err error, id string) bool {
  140. 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)
  141. }
  142. // Exists returns true if an image is registered at the given id.
  143. // If the image doesn't exist or if an error is encountered, false is returned.
  144. func (graph *Graph) Exists(id string) bool {
  145. if _, err := graph.Get(id); err != nil {
  146. return false
  147. }
  148. return true
  149. }
  150. // Get returns the image with the given id, or an error if the image doesn't exist.
  151. func (graph *Graph) Get(name string) (*image.Image, error) {
  152. id, err := graph.idIndex.Get(name)
  153. if err != nil {
  154. return nil, fmt.Errorf("could not find image: %v", err)
  155. }
  156. img, err := graph.loadImage(id)
  157. if err != nil {
  158. return nil, err
  159. }
  160. if img.ID != id {
  161. return nil, fmt.Errorf("Image stored at '%s' has wrong id '%s'", id, img.ID)
  162. }
  163. if img.Size < 0 {
  164. size, err := graph.driver.DiffSize(img.ID, img.Parent)
  165. if err != nil {
  166. return nil, fmt.Errorf("unable to calculate size of image id %q: %s", img.ID, err)
  167. }
  168. img.Size = size
  169. if err := graph.saveSize(graph.imageRoot(id), int(img.Size)); err != nil {
  170. return nil, err
  171. }
  172. }
  173. return img, nil
  174. }
  175. // Create creates a new image and registers it in the graph.
  176. func (graph *Graph) Create(layerData archive.ArchiveReader, containerID, containerImage, comment, author string, containerConfig, config *runconfig.Config) (*image.Image, error) {
  177. img := &image.Image{
  178. ID: stringid.GenerateRandomID(),
  179. Comment: comment,
  180. Created: time.Now().UTC(),
  181. DockerVersion: dockerversion.VERSION,
  182. Author: author,
  183. Config: config,
  184. Architecture: runtime.GOARCH,
  185. OS: runtime.GOOS,
  186. }
  187. if containerID != "" {
  188. img.Parent = containerImage
  189. img.Container = containerID
  190. img.ContainerConfig = *containerConfig
  191. }
  192. if err := graph.Register(img, layerData); err != nil {
  193. return nil, err
  194. }
  195. return img, nil
  196. }
  197. // Register imports a pre-existing image into the graph.
  198. func (graph *Graph) Register(img *image.Image, layerData archive.ArchiveReader) (err error) {
  199. if err := image.ValidateID(img.ID); err != nil {
  200. return err
  201. }
  202. // We need this entire operation to be atomic within the engine. Note that
  203. // this doesn't mean Register is fully safe yet.
  204. graph.imageMutex.Lock(img.ID)
  205. defer graph.imageMutex.Unlock(img.ID)
  206. // The returned `error` must be named in this function's signature so that
  207. // `err` is not shadowed in this deferred cleanup.
  208. defer func() {
  209. // If any error occurs, remove the new dir from the driver.
  210. // Don't check for errors since the dir might not have been created.
  211. if err != nil {
  212. graph.driver.Remove(img.ID)
  213. }
  214. }()
  215. // (This is a convenience to save time. Race conditions are taken care of by os.Rename)
  216. if graph.Exists(img.ID) {
  217. return fmt.Errorf("Image %s already exists", img.ID)
  218. }
  219. // Ensure that the image root does not exist on the filesystem
  220. // when it is not registered in the graph.
  221. // This is common when you switch from one graph driver to another
  222. if err := os.RemoveAll(graph.imageRoot(img.ID)); err != nil && !os.IsNotExist(err) {
  223. return err
  224. }
  225. // If the driver has this ID but the graph doesn't, remove it from the driver to start fresh.
  226. // (the graph is the source of truth).
  227. // Ignore errors, since we don't know if the driver correctly returns ErrNotExist.
  228. // (FIXME: make that mandatory for drivers).
  229. graph.driver.Remove(img.ID)
  230. tmp, err := graph.mktemp("")
  231. defer os.RemoveAll(tmp)
  232. if err != nil {
  233. return fmt.Errorf("mktemp failed: %s", err)
  234. }
  235. // Create root filesystem in the driver
  236. if err := createRootFilesystemInDriver(graph, img, layerData); err != nil {
  237. return err
  238. }
  239. // Apply the diff/layer
  240. if err := graph.storeImage(img, layerData, tmp); err != nil {
  241. return err
  242. }
  243. // Commit
  244. if err := os.Rename(tmp, graph.imageRoot(img.ID)); err != nil {
  245. return err
  246. }
  247. graph.idIndex.Add(img.ID)
  248. return nil
  249. }
  250. // TempLayerArchive creates a temporary archive of the given image's filesystem layer.
  251. // The archive is stored on disk and will be automatically deleted as soon as has been read.
  252. // If output is not nil, a human-readable progress bar will be written to it.
  253. func (graph *Graph) TempLayerArchive(id string, sf *streamformatter.StreamFormatter, output io.Writer) (*archive.TempArchive, error) {
  254. image, err := graph.Get(id)
  255. if err != nil {
  256. return nil, err
  257. }
  258. tmp, err := graph.mktemp("")
  259. if err != nil {
  260. return nil, err
  261. }
  262. a, err := graph.TarLayer(image)
  263. if err != nil {
  264. return nil, err
  265. }
  266. progressReader := progressreader.New(progressreader.Config{
  267. In: a,
  268. Out: output,
  269. Formatter: sf,
  270. Size: 0,
  271. NewLines: false,
  272. ID: stringid.TruncateID(id),
  273. Action: "Buffering to disk",
  274. })
  275. defer progressReader.Close()
  276. return archive.NewTempArchive(progressReader, tmp)
  277. }
  278. // mktemp creates a temporary sub-directory inside the graph's filesystem.
  279. func (graph *Graph) mktemp(id string) (string, error) {
  280. dir := filepath.Join(graph.root, "_tmp", stringid.GenerateRandomID())
  281. if err := system.MkdirAll(dir, 0700); err != nil {
  282. return "", err
  283. }
  284. return dir, nil
  285. }
  286. func (graph *Graph) newTempFile() (*os.File, error) {
  287. tmp, err := graph.mktemp("")
  288. if err != nil {
  289. return nil, err
  290. }
  291. return ioutil.TempFile(tmp, "")
  292. }
  293. func bufferToFile(f *os.File, src io.Reader) (int64, digest.Digest, error) {
  294. var (
  295. h = sha256.New()
  296. w = gzip.NewWriter(io.MultiWriter(f, h))
  297. )
  298. _, err := io.Copy(w, src)
  299. w.Close()
  300. if err != nil {
  301. return 0, "", err
  302. }
  303. n, err := f.Seek(0, os.SEEK_CUR)
  304. if err != nil {
  305. return 0, "", err
  306. }
  307. if _, err := f.Seek(0, 0); err != nil {
  308. return 0, "", err
  309. }
  310. return n, digest.NewDigest("sha256", h), nil
  311. }
  312. // Delete atomically removes an image from the graph.
  313. func (graph *Graph) Delete(name string) error {
  314. id, err := graph.idIndex.Get(name)
  315. if err != nil {
  316. return err
  317. }
  318. tmp, err := graph.mktemp("")
  319. graph.idIndex.Delete(id)
  320. if err == nil {
  321. if err := os.Rename(graph.imageRoot(id), tmp); err != nil {
  322. // On err make tmp point to old dir and cleanup unused tmp dir
  323. os.RemoveAll(tmp)
  324. tmp = graph.imageRoot(id)
  325. }
  326. } else {
  327. // On err make tmp point to old dir for cleanup
  328. tmp = graph.imageRoot(id)
  329. }
  330. // Remove rootfs data from the driver
  331. graph.driver.Remove(id)
  332. // Remove the trashed image directory
  333. return os.RemoveAll(tmp)
  334. }
  335. // Map returns a list of all images in the graph, addressable by ID.
  336. func (graph *Graph) Map() map[string]*image.Image {
  337. images := make(map[string]*image.Image)
  338. graph.walkAll(func(image *image.Image) {
  339. images[image.ID] = image
  340. })
  341. return images
  342. }
  343. // walkAll iterates over each image in the graph, and passes it to a handler.
  344. // The walking order is undetermined.
  345. func (graph *Graph) walkAll(handler func(*image.Image)) {
  346. graph.idIndex.Iterate(func(id string) {
  347. if img, err := graph.Get(id); err != nil {
  348. return
  349. } else if handler != nil {
  350. handler(img)
  351. }
  352. })
  353. }
  354. // ByParent returns a lookup table of images by their parent.
  355. // If an image of id ID has 3 children images, then the value for key ID
  356. // will be a list of 3 images.
  357. // If an image has no children, it will not have an entry in the table.
  358. func (graph *Graph) ByParent() map[string][]*image.Image {
  359. byParent := make(map[string][]*image.Image)
  360. graph.walkAll(func(img *image.Image) {
  361. parent, err := graph.Get(img.Parent)
  362. if err != nil {
  363. return
  364. }
  365. if children, exists := byParent[parent.ID]; exists {
  366. byParent[parent.ID] = append(children, img)
  367. } else {
  368. byParent[parent.ID] = []*image.Image{img}
  369. }
  370. })
  371. return byParent
  372. }
  373. // If the images and layers are in pulling chain, retain them.
  374. // If not, they may be deleted by rmi with dangling condition.
  375. func (graph *Graph) Retain(sessionID string, layerIDs ...string) {
  376. graph.retained.Add(sessionID, layerIDs)
  377. }
  378. // Release removes the referenced image id from the provided set of layers.
  379. func (graph *Graph) Release(sessionID string, layerIDs ...string) {
  380. graph.retained.Delete(sessionID, layerIDs)
  381. }
  382. // Heads returns all heads in the graph, keyed by id.
  383. // A head is an image which is not the parent of another image in the graph.
  384. func (graph *Graph) Heads() map[string]*image.Image {
  385. heads := make(map[string]*image.Image)
  386. byParent := graph.ByParent()
  387. graph.walkAll(func(image *image.Image) {
  388. // If it's not in the byParent lookup table, then
  389. // it's not a parent -> so it's a head!
  390. if _, exists := byParent[image.ID]; !exists {
  391. heads[image.ID] = image
  392. }
  393. })
  394. return heads
  395. }
  396. func (graph *Graph) imageRoot(id string) string {
  397. return filepath.Join(graph.root, id)
  398. }
  399. // loadImage fetches the image with the given id from the graph.
  400. func (graph *Graph) loadImage(id string) (*image.Image, error) {
  401. root := graph.imageRoot(id)
  402. // Open the JSON file to decode by streaming
  403. jsonSource, err := os.Open(jsonPath(root))
  404. if err != nil {
  405. return nil, err
  406. }
  407. defer jsonSource.Close()
  408. img := &image.Image{}
  409. dec := json.NewDecoder(jsonSource)
  410. // Decode the JSON data
  411. if err := dec.Decode(img); err != nil {
  412. return nil, err
  413. }
  414. if err := image.ValidateID(img.ID); err != nil {
  415. return nil, err
  416. }
  417. if buf, err := ioutil.ReadFile(filepath.Join(root, layersizeFileName)); err != nil {
  418. if !os.IsNotExist(err) {
  419. return nil, err
  420. }
  421. // If the layersize file does not exist then set the size to a negative number
  422. // because a layer size of 0 (zero) is valid
  423. img.Size = -1
  424. } else {
  425. // Using Atoi here instead would temporarily convert the size to a machine
  426. // dependent integer type, which causes images larger than 2^31 bytes to
  427. // display negative sizes on 32-bit machines:
  428. size, err := strconv.ParseInt(string(buf), 10, 64)
  429. if err != nil {
  430. return nil, err
  431. }
  432. img.Size = int64(size)
  433. }
  434. return img, nil
  435. }
  436. // saveSize stores the `size` in the provided graph `img` directory `root`.
  437. func (graph *Graph) saveSize(root string, size int) error {
  438. if err := ioutil.WriteFile(filepath.Join(root, layersizeFileName), []byte(strconv.Itoa(size)), 0600); err != nil {
  439. return fmt.Errorf("Error storing image size in %s/%s: %s", root, layersizeFileName, err)
  440. }
  441. return nil
  442. }
  443. // SetDigest sets the digest for the image layer to the provided value.
  444. func (graph *Graph) SetDigest(id string, dgst digest.Digest) error {
  445. root := graph.imageRoot(id)
  446. if err := ioutil.WriteFile(filepath.Join(root, digestFileName), []byte(dgst.String()), 0600); err != nil {
  447. return fmt.Errorf("Error storing digest in %s/%s: %s", root, digestFileName, err)
  448. }
  449. return nil
  450. }
  451. // GetDigest gets the digest for the provide image layer id.
  452. func (graph *Graph) GetDigest(id string) (digest.Digest, error) {
  453. root := graph.imageRoot(id)
  454. cs, err := ioutil.ReadFile(filepath.Join(root, digestFileName))
  455. if err != nil {
  456. if os.IsNotExist(err) {
  457. return "", ErrDigestNotSet
  458. }
  459. return "", err
  460. }
  461. return digest.ParseDigest(string(cs))
  462. }
  463. // RawJSON returns the JSON representation for an image as a byte array.
  464. func (graph *Graph) RawJSON(id string) ([]byte, error) {
  465. root := graph.imageRoot(id)
  466. buf, err := ioutil.ReadFile(jsonPath(root))
  467. if err != nil {
  468. return nil, fmt.Errorf("Failed to read json for image %s: %s", id, err)
  469. }
  470. return buf, nil
  471. }
  472. func jsonPath(root string) string {
  473. return filepath.Join(root, jsonFileName)
  474. }