image.go 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672
  1. package docker
  2. import (
  3. "crypto/rand"
  4. "encoding/hex"
  5. "encoding/json"
  6. "fmt"
  7. "github.com/dotcloud/docker/utils"
  8. "github.com/dotcloud/docker/devmapper"
  9. "io"
  10. "io/ioutil"
  11. "os"
  12. "path"
  13. "path/filepath"
  14. "strconv"
  15. "strings"
  16. "syscall"
  17. "time"
  18. )
  19. type Image struct {
  20. ID string `json:"id"`
  21. Parent string `json:"parent,omitempty"`
  22. Comment string `json:"comment,omitempty"`
  23. Created time.Time `json:"created"`
  24. Container string `json:"container,omitempty"`
  25. ContainerConfig Config `json:"container_config,omitempty"`
  26. DockerVersion string `json:"docker_version,omitempty"`
  27. Author string `json:"author,omitempty"`
  28. Config *Config `json:"config,omitempty"`
  29. Architecture string `json:"architecture,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. } else {
  51. if size, err := strconv.Atoi(string(buf)); err != nil {
  52. return nil, err
  53. } else {
  54. img.Size = int64(size)
  55. }
  56. }
  57. // Check that the filesystem layer exists
  58. // FIXME: once an image is added into device mapper, the layer is no longer needed
  59. if stat, err := os.Stat(layerPath(root)); err != nil {
  60. if os.IsNotExist(err) {
  61. return nil, fmt.Errorf("Couldn't load image %s: no filesystem layer", img.ID)
  62. }
  63. return nil, err
  64. } else if !stat.IsDir() {
  65. return nil, fmt.Errorf("Couldn't load image %s: %s is not a directory", img.ID, layerPath(root))
  66. }
  67. return img, nil
  68. }
  69. func StoreImage(img *Image, jsonData []byte, layerData Archive, root string) error {
  70. // Check that root doesn't already exist
  71. if _, err := os.Stat(root); err == nil {
  72. return fmt.Errorf("Image %s already exists", img.ID)
  73. } else if !os.IsNotExist(err) {
  74. return err
  75. }
  76. // Store the layer
  77. layer := layerPath(root)
  78. if err := os.MkdirAll(layer, 0755); err != nil {
  79. return err
  80. }
  81. // If layerData is not nil, unpack it into the new layer
  82. if layerData != nil {
  83. start := time.Now()
  84. utils.Debugf("Start untar layer")
  85. if err := Untar(layerData, layer); err != nil {
  86. return err
  87. }
  88. utils.Debugf("Untar time: %vs\n", time.Now().Sub(start).Seconds())
  89. }
  90. // If raw json is provided, then use it
  91. if jsonData != nil {
  92. return ioutil.WriteFile(jsonPath(root), jsonData, 0600)
  93. } else { // Otherwise, unmarshal the image
  94. jsonData, err := json.Marshal(img)
  95. if err != nil {
  96. return err
  97. }
  98. if err := ioutil.WriteFile(jsonPath(root), jsonData, 0600); err != nil {
  99. return err
  100. }
  101. }
  102. return StoreSize(img, root)
  103. }
  104. func StoreSize(img *Image, root string) error {
  105. layer := layerPath(root)
  106. var totalSize int64 = 0
  107. filepath.Walk(layer, func(path string, fileInfo os.FileInfo, err error) error {
  108. totalSize += fileInfo.Size()
  109. return nil
  110. })
  111. img.Size = totalSize
  112. if err := ioutil.WriteFile(path.Join(root, "layersize"), []byte(strconv.Itoa(int(totalSize))), 0600); err != nil {
  113. return nil
  114. }
  115. return nil
  116. }
  117. func layerPath(root string) string {
  118. return path.Join(root, "layer")
  119. }
  120. func jsonPath(root string) string {
  121. return path.Join(root, "json")
  122. }
  123. func mountPath(root string) string {
  124. return path.Join(root, "mount")
  125. }
  126. // TarLayer returns a tar archive of the image's filesystem layer.
  127. func (image *Image) TarLayer(compression Compression) (Archive, error) {
  128. layerPath, err := image.layer()
  129. if err != nil {
  130. return nil, err
  131. }
  132. return Tar(layerPath, compression)
  133. }
  134. type TimeUpdate struct {
  135. path string
  136. time []syscall.Timeval
  137. mode uint32
  138. }
  139. func (image *Image) applyLayer(layer, target string) error {
  140. var updateTimes []TimeUpdate
  141. oldmask := syscall.Umask(0)
  142. defer syscall.Umask(oldmask)
  143. err := filepath.Walk(layer, func(srcPath string, f os.FileInfo, err error) error {
  144. if err != nil {
  145. return err
  146. }
  147. // Skip root
  148. if srcPath == layer {
  149. return nil
  150. }
  151. var srcStat syscall.Stat_t
  152. err = syscall.Lstat(srcPath, &srcStat)
  153. if err != nil {
  154. return err
  155. }
  156. relPath, err := filepath.Rel(layer, srcPath)
  157. if err != nil {
  158. return err
  159. }
  160. targetPath := filepath.Join(target, relPath)
  161. // Skip AUFS metadata
  162. if matched, err := filepath.Match(".wh..wh.*", relPath); err != nil || matched {
  163. if err != nil || !f.IsDir() {
  164. return err
  165. }
  166. return filepath.SkipDir
  167. }
  168. // Find out what kind of modification happened
  169. file := filepath.Base(srcPath)
  170. // If there is a whiteout, then the file was removed
  171. if strings.HasPrefix(file, ".wh.") {
  172. originalFile := file[len(".wh."):]
  173. deletePath := filepath.Join(filepath.Dir(targetPath), originalFile)
  174. err = os.RemoveAll(deletePath)
  175. if err != nil {
  176. return err
  177. }
  178. } else {
  179. var targetStat = &syscall.Stat_t{}
  180. err := syscall.Lstat(targetPath, targetStat)
  181. if err != nil {
  182. if !os.IsNotExist(err) {
  183. return err
  184. }
  185. targetStat = nil
  186. }
  187. if targetStat != nil && !(targetStat.Mode&syscall.S_IFDIR == syscall.S_IFDIR && srcStat.Mode&syscall.S_IFDIR == syscall.S_IFDIR) {
  188. // Unless both src and dest are directories we remove the target and recreate it
  189. // This is a bit wasteful in the case of only a mode change, but that is unlikely
  190. // to matter much
  191. err = os.RemoveAll(targetPath)
  192. if err != nil {
  193. return err
  194. }
  195. targetStat = nil
  196. }
  197. if f.IsDir() {
  198. // Source is a directory
  199. if targetStat == nil {
  200. err = syscall.Mkdir(targetPath, srcStat.Mode&07777)
  201. if err != nil {
  202. return err
  203. }
  204. }
  205. } else if srcStat.Mode&syscall.S_IFLNK == syscall.S_IFLNK {
  206. // Source is symlink
  207. link, err := os.Readlink(srcPath)
  208. if err != nil {
  209. return err
  210. }
  211. err = os.Symlink(link, targetPath)
  212. if err != nil {
  213. return err
  214. }
  215. } else if srcStat.Mode&syscall.S_IFBLK == syscall.S_IFBLK ||
  216. srcStat.Mode&syscall.S_IFCHR == syscall.S_IFCHR ||
  217. srcStat.Mode&syscall.S_IFIFO == syscall.S_IFIFO ||
  218. srcStat.Mode&syscall.S_IFSOCK == syscall.S_IFSOCK {
  219. // Source is special file
  220. err = syscall.Mknod(targetPath, srcStat.Mode, int(srcStat.Rdev))
  221. if err != nil {
  222. return err
  223. }
  224. } else if srcStat.Mode&syscall.S_IFREG == syscall.S_IFREG {
  225. // Source is regular file
  226. fd, err := syscall.Open(targetPath, syscall.O_CREAT|syscall.O_WRONLY, srcStat.Mode&07777)
  227. if err != nil {
  228. return err
  229. }
  230. dstFile := os.NewFile(uintptr(fd), targetPath)
  231. srcFile, err := os.Open(srcPath)
  232. if err != nil {
  233. _ = dstFile.Close()
  234. return err
  235. }
  236. err = CopyFile(dstFile, srcFile)
  237. _ = dstFile.Close()
  238. _ = srcFile.Close()
  239. if err != nil {
  240. return err
  241. }
  242. } else {
  243. return fmt.Errorf("Unknown type for file %s", srcPath)
  244. }
  245. err = syscall.Lchown(targetPath, int(srcStat.Uid), int(srcStat.Gid))
  246. if err != nil {
  247. return err
  248. }
  249. if srcStat.Mode&syscall.S_IFLNK != syscall.S_IFLNK {
  250. err = syscall.Chmod(targetPath, srcStat.Mode&07777)
  251. if err != nil {
  252. return err
  253. }
  254. }
  255. ts := []syscall.Timeval{
  256. syscall.NsecToTimeval(srcStat.Atim.Nano()),
  257. syscall.NsecToTimeval(srcStat.Mtim.Nano()),
  258. }
  259. u := TimeUpdate{
  260. path: targetPath,
  261. time: ts,
  262. mode: srcStat.Mode,
  263. }
  264. // Delay time updates until all other changes done, or it is
  265. // overwritten for directories (by child changes)
  266. updateTimes = append(updateTimes, u)
  267. }
  268. return nil
  269. })
  270. if err != nil {
  271. return err
  272. }
  273. // We do this in reverse order so that children are updated before parents
  274. for i := len(updateTimes) - 1; i >= 0; i-- {
  275. update := updateTimes[i]
  276. O_PATH := 010000000 // Not in syscall yet
  277. var err error
  278. if update.mode&syscall.S_IFLNK == syscall.S_IFLNK {
  279. // Update time on the symlink via O_PATH + futimes(), if supported by the kernel
  280. fd, err := syscall.Open(update.path, syscall.O_RDWR|O_PATH|syscall.O_NOFOLLOW, 0600)
  281. if err == syscall.EISDIR || err == syscall.ELOOP {
  282. // O_PATH not supported by kernel, nothing to do, ignore
  283. } else if err != nil {
  284. return err
  285. } else {
  286. syscall.Futimes(fd, update.time)
  287. syscall.Close(fd)
  288. }
  289. } else {
  290. err = syscall.Utimes(update.path, update.time)
  291. if err != nil {
  292. return err
  293. }
  294. }
  295. }
  296. return nil
  297. }
  298. func (image *Image) ensureImageDevice(devices *devmapper.DeviceSet) error {
  299. if devices.HasInitializedDevice(image.ID) {
  300. return nil
  301. }
  302. if image.Parent != "" && !devices.HasInitializedDevice(image.Parent) {
  303. parentImg, err := image.GetParent()
  304. if err != nil {
  305. return fmt.Errorf("Error while getting parent image: %v", err)
  306. }
  307. err = parentImg.ensureImageDevice(devices)
  308. if err != nil {
  309. return err
  310. }
  311. }
  312. root, err := image.root()
  313. if err != nil {
  314. return err
  315. }
  316. mountDir := mountPath(root)
  317. if err := os.Mkdir(mountDir, 0600); err != nil && !os.IsExist(err) {
  318. return err
  319. }
  320. mounted, err := Mounted(mountDir)
  321. if err == nil && mounted {
  322. utils.Debugf("Image %s is unexpectedly mounted, unmounting...", image.ID)
  323. err = syscall.Unmount(mountDir, 0)
  324. if err != nil {
  325. return err
  326. }
  327. }
  328. if devices.HasDevice(image.ID) {
  329. utils.Debugf("Found non-initialized demove-mapper device for image %s, removing", image.ID)
  330. err = devices.RemoveDevice(image.ID)
  331. if err != nil {
  332. return err
  333. }
  334. }
  335. utils.Debugf("Creating device-mapper device for image id %s", image.ID)
  336. if err := devices.AddDevice(image.ID, image.Parent); err != nil {
  337. utils.Debugf("Error add device: %s", err)
  338. return err
  339. }
  340. if err := devices.MountDevice(image.ID, mountDir, false); err != nil {
  341. utils.Debugf("Error mounting device: %s", err)
  342. devices.RemoveDevice(image.ID)
  343. return err
  344. }
  345. if err = image.applyLayer(layerPath(root), mountDir); err != nil {
  346. utils.Debugf("Error applying layer: %s", err)
  347. devices.UnmountDevice(image.ID, mountDir, true)
  348. devices.RemoveDevice(image.ID)
  349. return err
  350. }
  351. // The docker init layer is conceptually above all other layers, so we apply
  352. // it for every image. This is safe because the layer directory is the
  353. // definition of the image, and the device-mapper device is just a cache
  354. // of it instantiated. Diffs/commit compare the container device with the
  355. // image device, which will then *not* pick up the init layer changes as
  356. // part of the container changes
  357. dockerinitLayer, err := image.getDockerInitLayer()
  358. if err != nil {
  359. devices.UnmountDevice(image.ID, mountDir, true)
  360. devices.RemoveDevice(image.ID)
  361. return err
  362. }
  363. if err := image.applyLayer(dockerinitLayer, mountDir); err != nil {
  364. devices.UnmountDevice(image.ID, mountDir, true)
  365. devices.RemoveDevice(image.ID)
  366. return err
  367. }
  368. if err := devices.UnmountDevice(image.ID, mountDir, true); err != nil {
  369. devices.RemoveDevice(image.ID)
  370. return err
  371. }
  372. devices.SetInitialized(image.ID)
  373. return nil
  374. }
  375. func (image *Image) Mounted(runtime *Runtime, root, rw string) (bool, error) {
  376. return Mounted(root)
  377. }
  378. func (image *Image) Mount(runtime *Runtime, root, rw string, id string) error {
  379. if mounted, _ := image.Mounted(runtime, root, rw); mounted {
  380. return fmt.Errorf("%s is already mounted", root)
  381. }
  382. // Create the target directories if they don't exist
  383. if err := os.Mkdir(root, 0755); err != nil && !os.IsExist(err) {
  384. return err
  385. }
  386. devices, err := runtime.GetDeviceSet()
  387. if err != nil {
  388. return err
  389. }
  390. if err := image.ensureImageDevice(devices); err != nil {
  391. return err
  392. }
  393. if !devices.HasDevice(id) {
  394. utils.Debugf("Creating device %s for container based on image %s", id, image.ID)
  395. err = devices.AddDevice(id, image.ID)
  396. if err != nil {
  397. return err
  398. }
  399. }
  400. utils.Debugf("Mounting container %s at %s for container", id, root)
  401. if err := devices.MountDevice(id, root, false); err != nil {
  402. return err
  403. }
  404. return nil
  405. }
  406. func (image *Image) Unmount(runtime *Runtime, root string, id string) error {
  407. // Try to deactivate the device as generally there is no use for it anymore
  408. devices, err := runtime.GetDeviceSet()
  409. if err != nil {
  410. return err
  411. }
  412. if err = devices.UnmountDevice(id, root, true); err != nil {
  413. return err
  414. }
  415. return nil
  416. }
  417. func (image *Image) Changes(runtime *Runtime, root, rw, id string) ([]Change, error) {
  418. devices, err := runtime.GetDeviceSet()
  419. if err != nil {
  420. return nil, err
  421. }
  422. if err := os.Mkdir(rw, 0755); err != nil && !os.IsExist(err) {
  423. return nil, err
  424. }
  425. wasActivated := devices.HasActivatedDevice(image.ID)
  426. // We re-use rw for the temporary mount of the base image as its
  427. // not used by device-mapper otherwise
  428. err = devices.MountDevice(image.ID, rw, true)
  429. if err != nil {
  430. return nil, err
  431. }
  432. changes, err := ChangesDirs(root, rw)
  433. devices.UnmountDevice(image.ID, rw, !wasActivated)
  434. if err != nil {
  435. return nil, err
  436. }
  437. return changes, nil
  438. }
  439. func (image *Image) ExportChanges(runtime *Runtime, root, rw, id string) (Archive, error) {
  440. changes, err := image.Changes(runtime, root, rw, id)
  441. if err != nil {
  442. return nil, err
  443. }
  444. files := make([]string, 0)
  445. deletions := make([]string, 0)
  446. for _, change := range changes {
  447. if change.Kind == ChangeModify || change.Kind == ChangeAdd {
  448. files = append(files, change.Path)
  449. }
  450. if change.Kind == ChangeDelete {
  451. base := filepath.Base(change.Path)
  452. dir := filepath.Dir(change.Path)
  453. deletions = append(deletions, filepath.Join(dir, ".wh."+base))
  454. }
  455. }
  456. return TarFilter(root, Uncompressed, files, false, deletions)
  457. }
  458. func (image *Image) ShortID() string {
  459. return utils.TruncateID(image.ID)
  460. }
  461. func ValidateID(id string) error {
  462. if id == "" {
  463. return fmt.Errorf("Image id can't be empty")
  464. }
  465. if strings.Contains(id, ":") {
  466. return fmt.Errorf("Invalid character in image id: ':'")
  467. }
  468. return nil
  469. }
  470. func GenerateID() string {
  471. id := make([]byte, 32)
  472. _, err := io.ReadFull(rand.Reader, id)
  473. if err != nil {
  474. panic(err) // This shouldn't happen
  475. }
  476. return hex.EncodeToString(id)
  477. }
  478. // Image includes convenience proxy functions to its graph
  479. // These functions will return an error if the image is not registered
  480. // (ie. if image.graph == nil)
  481. func (img *Image) History() ([]*Image, error) {
  482. var parents []*Image
  483. if err := img.WalkHistory(
  484. func(img *Image) error {
  485. parents = append(parents, img)
  486. return nil
  487. },
  488. ); err != nil {
  489. return nil, err
  490. }
  491. return parents, nil
  492. }
  493. // layers returns all the filesystem layers needed to mount an image
  494. // FIXME: @shykes refactor this function with the new error handling
  495. // (I'll do it if I have time tonight, I focus on the rest)
  496. func (img *Image) layers() ([]string, error) {
  497. var list []string
  498. var e error
  499. if err := img.WalkHistory(
  500. func(img *Image) (err error) {
  501. if layer, err := img.layer(); err != nil {
  502. e = err
  503. } else if layer != "" {
  504. list = append(list, layer)
  505. }
  506. return err
  507. },
  508. ); err != nil {
  509. return nil, err
  510. } else if e != nil { // Did an error occur inside the handler?
  511. return nil, e
  512. }
  513. if len(list) == 0 {
  514. return nil, fmt.Errorf("No layer found for image %s\n", img.ID)
  515. }
  516. // Inject the dockerinit layer (empty place-holder for mount-binding dockerinit)
  517. if dockerinitLayer, err := img.getDockerInitLayer(); err != nil {
  518. return nil, err
  519. } else {
  520. list = append([]string{dockerinitLayer}, list...)
  521. }
  522. return list, nil
  523. }
  524. func (img *Image) WalkHistory(handler func(*Image) error) (err error) {
  525. currentImg := img
  526. for currentImg != nil {
  527. if handler != nil {
  528. if err := handler(currentImg); err != nil {
  529. return err
  530. }
  531. }
  532. currentImg, err = currentImg.GetParent()
  533. if err != nil {
  534. return fmt.Errorf("Error while getting parent image: %v", err)
  535. }
  536. }
  537. return nil
  538. }
  539. func (img *Image) GetParent() (*Image, error) {
  540. if img.Parent == "" {
  541. return nil, nil
  542. }
  543. if img.graph == nil {
  544. return nil, fmt.Errorf("Can't lookup parent of unregistered image")
  545. }
  546. return img.graph.Get(img.Parent)
  547. }
  548. func (img *Image) getDockerInitLayer() (string, error) {
  549. if img.graph == nil {
  550. return "", fmt.Errorf("Can't lookup dockerinit layer of unregistered image")
  551. }
  552. return img.graph.getDockerInitLayer()
  553. }
  554. func (img *Image) root() (string, error) {
  555. if img.graph == nil {
  556. return "", fmt.Errorf("Can't lookup root of unregistered image")
  557. }
  558. return img.graph.imageRoot(img.ID), nil
  559. }
  560. // Return the path of an image's layer
  561. func (img *Image) layer() (string, error) {
  562. root, err := img.root()
  563. if err != nil {
  564. return "", err
  565. }
  566. return layerPath(root), nil
  567. }
  568. func (img *Image) getParentsSize(size int64) int64 {
  569. parentImage, err := img.GetParent()
  570. if err != nil || parentImage == nil {
  571. return size
  572. }
  573. size += parentImage.Size
  574. return parentImage.getParentsSize(size)
  575. }
  576. // Build an Image object from raw json data
  577. func NewImgJSON(src []byte) (*Image, error) {
  578. ret := &Image{}
  579. utils.Debugf("Json string: {%s}\n", src)
  580. // FIXME: Is there a cleaner way to "purify" the input json?
  581. if err := json.Unmarshal(src, ret); err != nil {
  582. return nil, err
  583. }
  584. return ret, nil
  585. }