image.go 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292
  1. package image
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. "github.com/dotcloud/docker/archive"
  6. "github.com/dotcloud/docker/daemon/graphdriver"
  7. "github.com/dotcloud/docker/runconfig"
  8. "github.com/dotcloud/docker/utils"
  9. "io/ioutil"
  10. "os"
  11. "path"
  12. "strconv"
  13. "time"
  14. )
  15. type Image struct {
  16. ID string `json:"id"`
  17. Parent string `json:"parent,omitempty"`
  18. Comment string `json:"comment,omitempty"`
  19. Created time.Time `json:"created"`
  20. Container string `json:"container,omitempty"`
  21. ContainerConfig runconfig.Config `json:"container_config,omitempty"`
  22. DockerVersion string `json:"docker_version,omitempty"`
  23. Author string `json:"author,omitempty"`
  24. Config *runconfig.Config `json:"config,omitempty"`
  25. Architecture string `json:"architecture,omitempty"`
  26. OS string `json:"os,omitempty"`
  27. Size int64
  28. graph Graph
  29. }
  30. func LoadImage(root string) (*Image, error) {
  31. // Load the json data
  32. jsonData, err := ioutil.ReadFile(jsonPath(root))
  33. if err != nil {
  34. return nil, err
  35. }
  36. img := &Image{}
  37. if err := json.Unmarshal(jsonData, img); err != nil {
  38. return nil, err
  39. }
  40. if err := utils.ValidateID(img.ID); err != nil {
  41. return nil, err
  42. }
  43. if buf, err := ioutil.ReadFile(path.Join(root, "layersize")); err != nil {
  44. if !os.IsNotExist(err) {
  45. return nil, err
  46. }
  47. // If the layersize file does not exist then set the size to a negative number
  48. // because a layer size of 0 (zero) is valid
  49. img.Size = -1
  50. } else {
  51. size, err := strconv.Atoi(string(buf))
  52. if err != nil {
  53. return nil, err
  54. }
  55. img.Size = int64(size)
  56. }
  57. return img, nil
  58. }
  59. func StoreImage(img *Image, jsonData []byte, layerData archive.ArchiveReader, root, layer string) error {
  60. // Store the layer
  61. var (
  62. size int64
  63. err error
  64. driver = img.graph.Driver()
  65. )
  66. if err := os.MkdirAll(layer, 0755); err != nil {
  67. return err
  68. }
  69. // If layerData is not nil, unpack it into the new layer
  70. if layerData != nil {
  71. if differ, ok := driver.(graphdriver.Differ); ok {
  72. if err := differ.ApplyDiff(img.ID, layerData); err != nil {
  73. return err
  74. }
  75. if size, err = differ.DiffSize(img.ID); err != nil {
  76. return err
  77. }
  78. } else {
  79. start := time.Now().UTC()
  80. utils.Debugf("Start untar layer")
  81. if err := archive.ApplyLayer(layer, layerData); err != nil {
  82. return err
  83. }
  84. utils.Debugf("Untar time: %vs", time.Now().UTC().Sub(start).Seconds())
  85. if img.Parent == "" {
  86. if size, err = utils.TreeSize(layer); err != nil {
  87. return err
  88. }
  89. } else {
  90. parent, err := driver.Get(img.Parent, "")
  91. if err != nil {
  92. return err
  93. }
  94. defer driver.Put(img.Parent)
  95. changes, err := archive.ChangesDirs(layer, parent)
  96. if err != nil {
  97. return err
  98. }
  99. size = archive.ChangesSize(layer, changes)
  100. }
  101. }
  102. }
  103. img.Size = size
  104. if err := img.SaveSize(root); err != nil {
  105. return err
  106. }
  107. // If raw json is provided, then use it
  108. if jsonData != nil {
  109. if err := ioutil.WriteFile(jsonPath(root), jsonData, 0600); err != nil {
  110. return err
  111. }
  112. } else {
  113. if jsonData, err = json.Marshal(img); err != nil {
  114. return err
  115. }
  116. if err := ioutil.WriteFile(jsonPath(root), jsonData, 0600); err != nil {
  117. return err
  118. }
  119. }
  120. return nil
  121. }
  122. func (img *Image) SetGraph(graph Graph) {
  123. img.graph = graph
  124. }
  125. // SaveSize stores the current `size` value of `img` in the directory `root`.
  126. func (img *Image) SaveSize(root string) error {
  127. if err := ioutil.WriteFile(path.Join(root, "layersize"), []byte(strconv.Itoa(int(img.Size))), 0600); err != nil {
  128. return fmt.Errorf("Error storing image size in %s/layersize: %s", root, err)
  129. }
  130. return nil
  131. }
  132. func jsonPath(root string) string {
  133. return path.Join(root, "json")
  134. }
  135. // TarLayer returns a tar archive of the image's filesystem layer.
  136. func (img *Image) TarLayer() (arch archive.Archive, err error) {
  137. if img.graph == nil {
  138. return nil, fmt.Errorf("Can't load storage driver for unregistered image %s", img.ID)
  139. }
  140. driver := img.graph.Driver()
  141. if differ, ok := driver.(graphdriver.Differ); ok {
  142. return differ.Diff(img.ID)
  143. }
  144. imgFs, err := driver.Get(img.ID, "")
  145. if err != nil {
  146. return nil, err
  147. }
  148. defer func() {
  149. if err != nil {
  150. driver.Put(img.ID)
  151. }
  152. }()
  153. if img.Parent == "" {
  154. archive, err := archive.Tar(imgFs, archive.Uncompressed)
  155. if err != nil {
  156. return nil, err
  157. }
  158. return utils.NewReadCloserWrapper(archive, func() error {
  159. err := archive.Close()
  160. driver.Put(img.ID)
  161. return err
  162. }), nil
  163. }
  164. parentFs, err := driver.Get(img.Parent, "")
  165. if err != nil {
  166. return nil, err
  167. }
  168. defer driver.Put(img.Parent)
  169. changes, err := archive.ChangesDirs(imgFs, parentFs)
  170. if err != nil {
  171. return nil, err
  172. }
  173. archive, err := archive.ExportChanges(imgFs, changes)
  174. if err != nil {
  175. return nil, err
  176. }
  177. return utils.NewReadCloserWrapper(archive, func() error {
  178. err := archive.Close()
  179. driver.Put(img.ID)
  180. return err
  181. }), nil
  182. }
  183. // Image includes convenience proxy functions to its graph
  184. // These functions will return an error if the image is not registered
  185. // (ie. if image.graph == nil)
  186. func (img *Image) History() ([]*Image, error) {
  187. var parents []*Image
  188. if err := img.WalkHistory(
  189. func(img *Image) error {
  190. parents = append(parents, img)
  191. return nil
  192. },
  193. ); err != nil {
  194. return nil, err
  195. }
  196. return parents, nil
  197. }
  198. func (img *Image) WalkHistory(handler func(*Image) error) (err error) {
  199. currentImg := img
  200. for currentImg != nil {
  201. if handler != nil {
  202. if err := handler(currentImg); err != nil {
  203. return err
  204. }
  205. }
  206. currentImg, err = currentImg.GetParent()
  207. if err != nil {
  208. return fmt.Errorf("Error while getting parent image: %v", err)
  209. }
  210. }
  211. return nil
  212. }
  213. func (img *Image) GetParent() (*Image, error) {
  214. if img.Parent == "" {
  215. return nil, nil
  216. }
  217. if img.graph == nil {
  218. return nil, fmt.Errorf("Can't lookup parent of unregistered image")
  219. }
  220. return img.graph.Get(img.Parent)
  221. }
  222. func (img *Image) root() (string, error) {
  223. if img.graph == nil {
  224. return "", fmt.Errorf("Can't lookup root of unregistered image")
  225. }
  226. return img.graph.ImageRoot(img.ID), nil
  227. }
  228. func (img *Image) GetParentsSize(size int64) int64 {
  229. parentImage, err := img.GetParent()
  230. if err != nil || parentImage == nil {
  231. return size
  232. }
  233. size += parentImage.Size
  234. return parentImage.GetParentsSize(size)
  235. }
  236. // Depth returns the number of parents for a
  237. // current image
  238. func (img *Image) Depth() (int, error) {
  239. var (
  240. count = 0
  241. parent = img
  242. err error
  243. )
  244. for parent != nil {
  245. count++
  246. parent, err = parent.GetParent()
  247. if err != nil {
  248. return -1, err
  249. }
  250. }
  251. return count, nil
  252. }
  253. // Build an Image object from raw json data
  254. func NewImgJSON(src []byte) (*Image, error) {
  255. ret := &Image{}
  256. utils.Debugf("Json string: {%s}", src)
  257. // FIXME: Is there a cleaner way to "purify" the input json?
  258. if err := json.Unmarshal(src, ret); err != nil {
  259. return nil, err
  260. }
  261. return ret, nil
  262. }