image.go 6.6 KB

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