graph.go 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559
  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. "syscall"
  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. // A Graph is a store for versioned filesystem images and the relationship between them.
  31. type Graph struct {
  32. root string
  33. idIndex *truncindex.TruncIndex
  34. driver graphdriver.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. defer func() {
  142. // If any error occurs, remove the new dir from the driver.
  143. // Don't check for errors since the dir might not have been created.
  144. // FIXME: this leaves a possible race condition.
  145. if err != nil {
  146. graph.driver.Remove(img.ID)
  147. }
  148. }()
  149. if err := image.ValidateID(img.ID); err != nil {
  150. return err
  151. }
  152. // (This is a convenience to save time. Race conditions are taken care of by os.Rename)
  153. if graph.Exists(img.ID) {
  154. return fmt.Errorf("Image %s already exists", img.ID)
  155. }
  156. // Ensure that the image root does not exist on the filesystem
  157. // when it is not registered in the graph.
  158. // This is common when you switch from one graph driver to another
  159. if err := os.RemoveAll(graph.imageRoot(img.ID)); err != nil && !os.IsNotExist(err) {
  160. return err
  161. }
  162. // If the driver has this ID but the graph doesn't, remove it from the driver to start fresh.
  163. // (the graph is the source of truth).
  164. // Ignore errors, since we don't know if the driver correctly returns ErrNotExist.
  165. // (FIXME: make that mandatory for drivers).
  166. graph.driver.Remove(img.ID)
  167. tmp, err := graph.mktemp("")
  168. defer os.RemoveAll(tmp)
  169. if err != nil {
  170. return fmt.Errorf("mktemp failed: %s", err)
  171. }
  172. // Create root filesystem in the driver
  173. if err := graph.driver.Create(img.ID, img.Parent); err != nil {
  174. return fmt.Errorf("Driver %s failed to create image rootfs %s: %s", graph.driver, img.ID, err)
  175. }
  176. // Apply the diff/layer
  177. if err := graph.storeImage(img, layerData, tmp); err != nil {
  178. return err
  179. }
  180. // Commit
  181. if err := os.Rename(tmp, graph.imageRoot(img.ID)); err != nil {
  182. return err
  183. }
  184. graph.idIndex.Add(img.ID)
  185. return nil
  186. }
  187. // TempLayerArchive creates a temporary archive of the given image's filesystem layer.
  188. // The archive is stored on disk and will be automatically deleted as soon as has been read.
  189. // If output is not nil, a human-readable progress bar will be written to it.
  190. func (graph *Graph) TempLayerArchive(id string, sf *streamformatter.StreamFormatter, output io.Writer) (*archive.TempArchive, error) {
  191. image, err := graph.Get(id)
  192. if err != nil {
  193. return nil, err
  194. }
  195. tmp, err := graph.mktemp("")
  196. if err != nil {
  197. return nil, err
  198. }
  199. a, err := graph.TarLayer(image)
  200. if err != nil {
  201. return nil, err
  202. }
  203. progressReader := progressreader.New(progressreader.Config{
  204. In: a,
  205. Out: output,
  206. Formatter: sf,
  207. Size: 0,
  208. NewLines: false,
  209. ID: stringid.TruncateID(id),
  210. Action: "Buffering to disk",
  211. })
  212. defer progressReader.Close()
  213. return archive.NewTempArchive(progressReader, tmp)
  214. }
  215. // mktemp creates a temporary sub-directory inside the graph's filesystem.
  216. func (graph *Graph) mktemp(id string) (string, error) {
  217. dir := filepath.Join(graph.root, "_tmp", stringid.GenerateRandomID())
  218. if err := system.MkdirAll(dir, 0700); err != nil {
  219. return "", err
  220. }
  221. return dir, nil
  222. }
  223. func (graph *Graph) newTempFile() (*os.File, error) {
  224. tmp, err := graph.mktemp("")
  225. if err != nil {
  226. return nil, err
  227. }
  228. return ioutil.TempFile(tmp, "")
  229. }
  230. func bufferToFile(f *os.File, src io.Reader) (int64, digest.Digest, error) {
  231. var (
  232. h = sha256.New()
  233. w = gzip.NewWriter(io.MultiWriter(f, h))
  234. )
  235. _, err := io.Copy(w, src)
  236. w.Close()
  237. if err != nil {
  238. return 0, "", err
  239. }
  240. n, err := f.Seek(0, os.SEEK_CUR)
  241. if err != nil {
  242. return 0, "", err
  243. }
  244. if _, err := f.Seek(0, 0); err != nil {
  245. return 0, "", err
  246. }
  247. return n, digest.NewDigest("sha256", h), nil
  248. }
  249. // setupInitLayer populates a directory with mountpoints suitable
  250. // for bind-mounting dockerinit into the container. The mountpoint is simply an
  251. // empty file at /.dockerinit
  252. //
  253. // This extra layer is used by all containers as the top-most ro layer. It protects
  254. // the container from unwanted side-effects on the rw layer.
  255. func SetupInitLayer(initLayer string) error {
  256. for pth, typ := range map[string]string{
  257. "/dev/pts": "dir",
  258. "/dev/shm": "dir",
  259. "/proc": "dir",
  260. "/sys": "dir",
  261. "/.dockerinit": "file",
  262. "/.dockerenv": "file",
  263. "/etc/resolv.conf": "file",
  264. "/etc/hosts": "file",
  265. "/etc/hostname": "file",
  266. "/dev/console": "file",
  267. "/etc/mtab": "/proc/mounts",
  268. } {
  269. parts := strings.Split(pth, "/")
  270. prev := "/"
  271. for _, p := range parts[1:] {
  272. prev = filepath.Join(prev, p)
  273. syscall.Unlink(filepath.Join(initLayer, prev))
  274. }
  275. if _, err := os.Stat(filepath.Join(initLayer, pth)); err != nil {
  276. if os.IsNotExist(err) {
  277. if err := system.MkdirAll(filepath.Join(initLayer, filepath.Dir(pth)), 0755); err != nil {
  278. return err
  279. }
  280. switch typ {
  281. case "dir":
  282. if err := system.MkdirAll(filepath.Join(initLayer, pth), 0755); err != nil {
  283. return err
  284. }
  285. case "file":
  286. f, err := os.OpenFile(filepath.Join(initLayer, pth), os.O_CREATE, 0755)
  287. if err != nil {
  288. return err
  289. }
  290. f.Close()
  291. default:
  292. if err := os.Symlink(typ, filepath.Join(initLayer, pth)); err != nil {
  293. return err
  294. }
  295. }
  296. } else {
  297. return err
  298. }
  299. }
  300. }
  301. // Layer is ready to use, if it wasn't before.
  302. return nil
  303. }
  304. // Check if given error is "not empty".
  305. // Note: this is the way golang does it internally with os.IsNotExists.
  306. func isNotEmpty(err error) bool {
  307. switch pe := err.(type) {
  308. case nil:
  309. return false
  310. case *os.PathError:
  311. err = pe.Err
  312. case *os.LinkError:
  313. err = pe.Err
  314. }
  315. return strings.Contains(err.Error(), " not empty")
  316. }
  317. // Delete atomically removes an image from the graph.
  318. func (graph *Graph) Delete(name string) error {
  319. id, err := graph.idIndex.Get(name)
  320. if err != nil {
  321. return err
  322. }
  323. tmp, err := graph.mktemp("")
  324. graph.idIndex.Delete(id)
  325. if err == nil {
  326. if err := os.Rename(graph.imageRoot(id), tmp); err != nil {
  327. // On err make tmp point to old dir and cleanup unused tmp dir
  328. os.RemoveAll(tmp)
  329. tmp = graph.imageRoot(id)
  330. }
  331. } else {
  332. // On err make tmp point to old dir for cleanup
  333. tmp = graph.imageRoot(id)
  334. }
  335. // Remove rootfs data from the driver
  336. graph.driver.Remove(id)
  337. // Remove the trashed image directory
  338. return os.RemoveAll(tmp)
  339. }
  340. // Map returns a list of all images in the graph, addressable by ID.
  341. func (graph *Graph) Map() (map[string]*image.Image, error) {
  342. images := make(map[string]*image.Image)
  343. err := graph.walkAll(func(image *image.Image) {
  344. images[image.ID] = image
  345. })
  346. if err != nil {
  347. return nil, err
  348. }
  349. return images, nil
  350. }
  351. // walkAll iterates over each image in the graph, and passes it to a handler.
  352. // The walking order is undetermined.
  353. func (graph *Graph) walkAll(handler func(*image.Image)) error {
  354. files, err := ioutil.ReadDir(graph.root)
  355. if err != nil {
  356. return err
  357. }
  358. for _, st := range files {
  359. if img, err := graph.Get(st.Name()); err != nil {
  360. // Skip image
  361. continue
  362. } else if handler != nil {
  363. handler(img)
  364. }
  365. }
  366. return nil
  367. }
  368. // ByParent returns a lookup table of images by their parent.
  369. // If an image of id ID has 3 children images, then the value for key ID
  370. // will be a list of 3 images.
  371. // If an image has no children, it will not have an entry in the table.
  372. func (graph *Graph) ByParent() (map[string][]*image.Image, error) {
  373. byParent := make(map[string][]*image.Image)
  374. err := graph.walkAll(func(img *image.Image) {
  375. parent, err := graph.Get(img.Parent)
  376. if err != nil {
  377. return
  378. }
  379. if children, exists := byParent[parent.ID]; exists {
  380. byParent[parent.ID] = append(children, img)
  381. } else {
  382. byParent[parent.ID] = []*image.Image{img}
  383. }
  384. })
  385. return byParent, err
  386. }
  387. // Heads returns all heads in the graph, keyed by id.
  388. // A head is an image which is not the parent of another image in the graph.
  389. func (graph *Graph) Heads() (map[string]*image.Image, error) {
  390. heads := make(map[string]*image.Image)
  391. byParent, err := graph.ByParent()
  392. if err != nil {
  393. return nil, err
  394. }
  395. err = graph.walkAll(func(image *image.Image) {
  396. // If it's not in the byParent lookup table, then
  397. // it's not a parent -> so it's a head!
  398. if _, exists := byParent[image.ID]; !exists {
  399. heads[image.ID] = image
  400. }
  401. })
  402. return heads, err
  403. }
  404. func (graph *Graph) imageRoot(id string) string {
  405. return filepath.Join(graph.root, id)
  406. }
  407. // storeImage stores file system layer data for the given image to the
  408. // graph's storage driver. Image metadata is stored in a file
  409. // at the specified root directory.
  410. func (graph *Graph) storeImage(img *image.Image, layerData archive.ArchiveReader, root string) (err error) {
  411. // Store the layer. If layerData is not nil, unpack it into the new layer
  412. if layerData != nil {
  413. if img.Size, err = graph.driver.ApplyDiff(img.ID, img.Parent, layerData); err != nil {
  414. return err
  415. }
  416. }
  417. if err := graph.saveSize(root, int(img.Size)); err != nil {
  418. return err
  419. }
  420. f, err := os.OpenFile(jsonPath(root), os.O_CREATE|os.O_WRONLY|os.O_TRUNC, os.FileMode(0600))
  421. if err != nil {
  422. return err
  423. }
  424. defer f.Close()
  425. return json.NewEncoder(f).Encode(img)
  426. }
  427. // loadImage fetches the image with the given id from the graph.
  428. func (graph *Graph) loadImage(id string) (*image.Image, error) {
  429. root := graph.imageRoot(id)
  430. // Open the JSON file to decode by streaming
  431. jsonSource, err := os.Open(jsonPath(root))
  432. if err != nil {
  433. return nil, err
  434. }
  435. defer jsonSource.Close()
  436. img := &image.Image{}
  437. dec := json.NewDecoder(jsonSource)
  438. // Decode the JSON data
  439. if err := dec.Decode(img); err != nil {
  440. return nil, err
  441. }
  442. if err := image.ValidateID(img.ID); err != nil {
  443. return nil, err
  444. }
  445. if buf, err := ioutil.ReadFile(filepath.Join(root, "layersize")); err != nil {
  446. if !os.IsNotExist(err) {
  447. return nil, err
  448. }
  449. // If the layersize file does not exist then set the size to a negative number
  450. // because a layer size of 0 (zero) is valid
  451. img.Size = -1
  452. } else {
  453. // Using Atoi here instead would temporarily convert the size to a machine
  454. // dependent integer type, which causes images larger than 2^31 bytes to
  455. // display negative sizes on 32-bit machines:
  456. size, err := strconv.ParseInt(string(buf), 10, 64)
  457. if err != nil {
  458. return nil, err
  459. }
  460. img.Size = int64(size)
  461. }
  462. return img, nil
  463. }
  464. // saveSize stores the `size` in the provided graph `img` directory `root`.
  465. func (graph *Graph) saveSize(root string, size int) error {
  466. if err := ioutil.WriteFile(filepath.Join(root, "layersize"), []byte(strconv.Itoa(size)), 0600); err != nil {
  467. return fmt.Errorf("Error storing image size in %s/layersize: %s", root, err)
  468. }
  469. return nil
  470. }
  471. // SetDigest sets the digest for the image layer to the provided value.
  472. func (graph *Graph) SetDigest(id string, dgst digest.Digest) error {
  473. root := graph.imageRoot(id)
  474. if err := ioutil.WriteFile(filepath.Join(root, "checksum"), []byte(dgst.String()), 0600); err != nil {
  475. return fmt.Errorf("Error storing digest in %s/checksum: %s", root, err)
  476. }
  477. return nil
  478. }
  479. // GetDigest gets the digest for the provide image layer id.
  480. func (graph *Graph) GetDigest(id string) (digest.Digest, error) {
  481. root := graph.imageRoot(id)
  482. cs, err := ioutil.ReadFile(filepath.Join(root, "checksum"))
  483. if err != nil {
  484. if os.IsNotExist(err) {
  485. return "", ErrDigestNotSet
  486. }
  487. return "", err
  488. }
  489. return digest.ParseDigest(string(cs))
  490. }
  491. // RawJSON returns the JSON representation for an image as a byte array.
  492. func (graph *Graph) RawJSON(id string) ([]byte, error) {
  493. root := graph.imageRoot(id)
  494. buf, err := ioutil.ReadFile(jsonPath(root))
  495. if err != nil {
  496. return nil, fmt.Errorf("Failed to read json for image %s: %s", id, err)
  497. }
  498. return buf, nil
  499. }
  500. func jsonPath(root string) string {
  501. return filepath.Join(root, "json")
  502. }
  503. // TarLayer returns a tar archive of the image's filesystem layer.
  504. func (graph *Graph) TarLayer(img *image.Image) (arch archive.Archive, err error) {
  505. return graph.driver.Diff(img.ID, img.Parent)
  506. }