graph.go 14 KB

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