graph.go 14 KB

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