image.go 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282
  1. package image
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. "io/ioutil"
  6. "os"
  7. "path"
  8. "strconv"
  9. "time"
  10. log "github.com/Sirupsen/logrus"
  11. "github.com/docker/docker/pkg/archive"
  12. "github.com/docker/docker/pkg/tarsum"
  13. "github.com/docker/docker/runconfig"
  14. "github.com/docker/docker/utils"
  15. )
  16. // Set the max depth to the aufs default that most
  17. // kernels are compiled with
  18. // For more information see: http://sourceforge.net/p/aufs/aufs3-standalone/ci/aufs3.12/tree/config.mk
  19. const MaxImageDepth = 127
  20. type Image struct {
  21. ID string `json:"id"`
  22. Parent string `json:"parent,omitempty"`
  23. Comment string `json:"comment,omitempty"`
  24. Created time.Time `json:"created"`
  25. Container string `json:"container,omitempty"`
  26. ContainerConfig runconfig.Config `json:"container_config,omitempty"`
  27. DockerVersion string `json:"docker_version,omitempty"`
  28. Author string `json:"author,omitempty"`
  29. Config *runconfig.Config `json:"config,omitempty"`
  30. Architecture string `json:"architecture,omitempty"`
  31. OS string `json:"os,omitempty"`
  32. Checksum string `json:"checksum"`
  33. Size int64
  34. graph Graph
  35. }
  36. func LoadImage(root string) (*Image, error) {
  37. // Open the JSON file to decode by streaming
  38. jsonSource, err := os.Open(jsonPath(root))
  39. if err != nil {
  40. return nil, err
  41. }
  42. defer jsonSource.Close()
  43. img := &Image{}
  44. dec := json.NewDecoder(jsonSource)
  45. // Decode the JSON data
  46. if err := dec.Decode(img); err != nil {
  47. return nil, err
  48. }
  49. if err := utils.ValidateID(img.ID); err != nil {
  50. return nil, err
  51. }
  52. if buf, err := ioutil.ReadFile(path.Join(root, "layersize")); err != nil {
  53. if !os.IsNotExist(err) {
  54. return nil, err
  55. }
  56. // If the layersize file does not exist then set the size to a negative number
  57. // because a layer size of 0 (zero) is valid
  58. img.Size = -1
  59. } else {
  60. // Using Atoi here instead would temporarily convert the size to a machine
  61. // dependent integer type, which causes images larger than 2^31 bytes to
  62. // display negative sizes on 32-bit machines:
  63. size, err := strconv.ParseInt(string(buf), 10, 64)
  64. if err != nil {
  65. return nil, err
  66. }
  67. img.Size = int64(size)
  68. }
  69. return img, nil
  70. }
  71. // StoreImage stores file system layer data for the given image to the
  72. // image's registered storage driver. Image metadata is stored in a file
  73. // at the specified root directory. This function also computes the TarSum
  74. // of `layerData` (currently using tarsum.dev).
  75. func StoreImage(img *Image, layerData archive.ArchiveReader, root string) error {
  76. // Store the layer
  77. var (
  78. size int64
  79. err error
  80. driver = img.graph.Driver()
  81. layerTarSum tarsum.TarSum
  82. )
  83. // If layerData is not nil, unpack it into the new layer
  84. if layerData != nil {
  85. layerDataDecompressed, err := archive.DecompressStream(layerData)
  86. if err != nil {
  87. return err
  88. }
  89. defer layerDataDecompressed.Close()
  90. if layerTarSum, err = tarsum.NewTarSum(layerDataDecompressed, true, tarsum.VersionDev); err != nil {
  91. return err
  92. }
  93. if size, err = driver.ApplyDiff(img.ID, img.Parent, layerTarSum); err != nil {
  94. return err
  95. }
  96. checksum := layerTarSum.Sum(nil)
  97. if img.Checksum != "" && img.Checksum != checksum {
  98. log.Warnf("image layer checksum mismatch: computed %q, expected %q", checksum, img.Checksum)
  99. }
  100. img.Checksum = checksum
  101. }
  102. img.Size = size
  103. if err := img.SaveSize(root); err != nil {
  104. return err
  105. }
  106. f, err := os.OpenFile(jsonPath(root), os.O_CREATE|os.O_WRONLY|os.O_TRUNC, os.FileMode(0600))
  107. if err != nil {
  108. return err
  109. }
  110. defer f.Close()
  111. return json.NewEncoder(f).Encode(img)
  112. }
  113. func (img *Image) SetGraph(graph Graph) {
  114. img.graph = graph
  115. }
  116. // SaveSize stores the current `size` value of `img` in the directory `root`.
  117. func (img *Image) SaveSize(root string) error {
  118. if err := ioutil.WriteFile(path.Join(root, "layersize"), []byte(strconv.Itoa(int(img.Size))), 0600); err != nil {
  119. return fmt.Errorf("Error storing image size in %s/layersize: %s", root, err)
  120. }
  121. return nil
  122. }
  123. func jsonPath(root string) string {
  124. return path.Join(root, "json")
  125. }
  126. func (img *Image) RawJson() ([]byte, error) {
  127. root, err := img.root()
  128. if err != nil {
  129. return nil, fmt.Errorf("Failed to get root for image %s: %s", img.ID, err)
  130. }
  131. fh, err := os.Open(jsonPath(root))
  132. if err != nil {
  133. return nil, fmt.Errorf("Failed to open json for image %s: %s", img.ID, err)
  134. }
  135. buf, err := ioutil.ReadAll(fh)
  136. if err != nil {
  137. return nil, fmt.Errorf("Failed to read json for image %s: %s", img.ID, err)
  138. }
  139. return buf, nil
  140. }
  141. // TarLayer returns a tar archive of the image's filesystem layer.
  142. func (img *Image) TarLayer() (arch archive.Archive, err error) {
  143. if img.graph == nil {
  144. return nil, fmt.Errorf("Can't load storage driver for unregistered image %s", img.ID)
  145. }
  146. driver := img.graph.Driver()
  147. return driver.Diff(img.ID, img.Parent)
  148. }
  149. // Image includes convenience proxy functions to its graph
  150. // These functions will return an error if the image is not registered
  151. // (ie. if image.graph == nil)
  152. func (img *Image) History() ([]*Image, error) {
  153. var parents []*Image
  154. if err := img.WalkHistory(
  155. func(img *Image) error {
  156. parents = append(parents, img)
  157. return nil
  158. },
  159. ); err != nil {
  160. return nil, err
  161. }
  162. return parents, nil
  163. }
  164. func (img *Image) WalkHistory(handler func(*Image) error) (err error) {
  165. currentImg := img
  166. for currentImg != nil {
  167. if handler != nil {
  168. if err := handler(currentImg); err != nil {
  169. return err
  170. }
  171. }
  172. currentImg, err = currentImg.GetParent()
  173. if err != nil {
  174. return fmt.Errorf("Error while getting parent image: %v", err)
  175. }
  176. }
  177. return nil
  178. }
  179. func (img *Image) GetParent() (*Image, error) {
  180. if img.Parent == "" {
  181. return nil, nil
  182. }
  183. if img.graph == nil {
  184. return nil, fmt.Errorf("Can't lookup parent of unregistered image")
  185. }
  186. return img.graph.Get(img.Parent)
  187. }
  188. func (img *Image) root() (string, error) {
  189. if img.graph == nil {
  190. return "", fmt.Errorf("Can't lookup root of unregistered image")
  191. }
  192. return img.graph.ImageRoot(img.ID), nil
  193. }
  194. func (img *Image) GetParentsSize(size int64) int64 {
  195. parentImage, err := img.GetParent()
  196. if err != nil || parentImage == nil {
  197. return size
  198. }
  199. size += parentImage.Size
  200. return parentImage.GetParentsSize(size)
  201. }
  202. // Depth returns the number of parents for a
  203. // current image
  204. func (img *Image) Depth() (int, error) {
  205. var (
  206. count = 0
  207. parent = img
  208. err error
  209. )
  210. for parent != nil {
  211. count++
  212. parent, err = parent.GetParent()
  213. if err != nil {
  214. return -1, err
  215. }
  216. }
  217. return count, nil
  218. }
  219. // CheckDepth returns an error if the depth of an image, as returned
  220. // by ImageDepth, is too large to support creating a container from it
  221. // on this daemon.
  222. func (img *Image) CheckDepth() error {
  223. // We add 2 layers to the depth because the container's rw and
  224. // init layer add to the restriction
  225. depth, err := img.Depth()
  226. if err != nil {
  227. return err
  228. }
  229. if depth+2 >= MaxImageDepth {
  230. return fmt.Errorf("Cannot create container with more than %d parents", MaxImageDepth)
  231. }
  232. return nil
  233. }
  234. // Build an Image object from raw json data
  235. func NewImgJSON(src []byte) (*Image, error) {
  236. ret := &Image{}
  237. log.Debugf("Json string: {%s}", src)
  238. // FIXME: Is there a cleaner way to "purify" the input json?
  239. if err := json.Unmarshal(src, ret); err != nil {
  240. return nil, err
  241. }
  242. return ret, nil
  243. }