graph.go 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416
  1. package graph
  2. import (
  3. "fmt"
  4. "github.com/dotcloud/docker/archive"
  5. "github.com/dotcloud/docker/daemon/graphdriver"
  6. "github.com/dotcloud/docker/dockerversion"
  7. "github.com/dotcloud/docker/image"
  8. "github.com/dotcloud/docker/runconfig"
  9. "github.com/dotcloud/docker/utils"
  10. "io"
  11. "io/ioutil"
  12. "os"
  13. "path"
  14. "path/filepath"
  15. "runtime"
  16. "strings"
  17. "syscall"
  18. "time"
  19. )
  20. // A Graph is a store for versioned filesystem images and the relationship between them.
  21. type Graph struct {
  22. Root string
  23. idIndex *utils.TruncIndex
  24. driver graphdriver.Driver
  25. }
  26. // NewGraph instantiates a new graph at the given root path in the filesystem.
  27. // `root` will be created if it doesn't exist.
  28. func NewGraph(root string, driver graphdriver.Driver) (*Graph, error) {
  29. abspath, err := filepath.Abs(root)
  30. if err != nil {
  31. return nil, err
  32. }
  33. // Create the root directory if it doesn't exists
  34. if err := os.MkdirAll(root, 0700); err != nil && !os.IsExist(err) {
  35. return nil, err
  36. }
  37. graph := &Graph{
  38. Root: abspath,
  39. idIndex: utils.NewTruncIndex([]string{}),
  40. driver: driver,
  41. }
  42. if err := graph.restore(); err != nil {
  43. return nil, err
  44. }
  45. return graph, nil
  46. }
  47. func (graph *Graph) restore() error {
  48. dir, err := ioutil.ReadDir(graph.Root)
  49. if err != nil {
  50. return err
  51. }
  52. var ids = []string{}
  53. for _, v := range dir {
  54. id := v.Name()
  55. if graph.driver.Exists(id) {
  56. ids = append(ids, id)
  57. }
  58. }
  59. graph.idIndex = utils.NewTruncIndex(ids)
  60. utils.Debugf("Restored %d elements", len(dir))
  61. return nil
  62. }
  63. // FIXME: Implement error subclass instead of looking at the error text
  64. // Note: This is the way golang implements os.IsNotExists on Plan9
  65. func (graph *Graph) IsNotExist(err error) bool {
  66. return err != nil && (strings.Contains(err.Error(), "does not exist") || strings.Contains(err.Error(), "No such"))
  67. }
  68. // Exists returns true if an image is registered at the given id.
  69. // If the image doesn't exist or if an error is encountered, false is returned.
  70. func (graph *Graph) Exists(id string) bool {
  71. if _, err := graph.Get(id); err != nil {
  72. return false
  73. }
  74. return true
  75. }
  76. // Get returns the image with the given id, or an error if the image doesn't exist.
  77. func (graph *Graph) Get(name string) (*image.Image, error) {
  78. id, err := graph.idIndex.Get(name)
  79. if err != nil {
  80. return nil, err
  81. }
  82. // FIXME: return nil when the image doesn't exist, instead of an error
  83. img, err := image.LoadImage(graph.ImageRoot(id))
  84. if err != nil {
  85. return nil, err
  86. }
  87. if img.ID != id {
  88. return nil, fmt.Errorf("Image stored at '%s' has wrong id '%s'", id, img.ID)
  89. }
  90. img.SetGraph(graph)
  91. if img.Size < 0 {
  92. rootfs, err := graph.driver.Get(img.ID, "")
  93. if err != nil {
  94. return nil, fmt.Errorf("Driver %s failed to get image rootfs %s: %s", graph.driver, img.ID, err)
  95. }
  96. defer graph.driver.Put(img.ID)
  97. var size int64
  98. if img.Parent == "" {
  99. if size, err = utils.TreeSize(rootfs); err != nil {
  100. return nil, err
  101. }
  102. } else {
  103. parentFs, err := graph.driver.Get(img.Parent, "")
  104. if err != nil {
  105. return nil, err
  106. }
  107. changes, err := archive.ChangesDirs(rootfs, parentFs)
  108. if err != nil {
  109. return nil, err
  110. }
  111. size = archive.ChangesSize(rootfs, changes)
  112. }
  113. img.Size = size
  114. if err := img.SaveSize(graph.ImageRoot(id)); err != nil {
  115. return nil, err
  116. }
  117. }
  118. return img, nil
  119. }
  120. // Create creates a new image and registers it in the graph.
  121. func (graph *Graph) Create(layerData archive.ArchiveReader, containerID, containerImage, comment, author string, containerConfig, config *runconfig.Config) (*image.Image, error) {
  122. img := &image.Image{
  123. ID: utils.GenerateRandomID(),
  124. Comment: comment,
  125. Created: time.Now().UTC(),
  126. DockerVersion: dockerversion.VERSION,
  127. Author: author,
  128. Config: config,
  129. Architecture: runtime.GOARCH,
  130. OS: runtime.GOOS,
  131. }
  132. if containerID != "" {
  133. img.Parent = containerImage
  134. img.Container = containerID
  135. img.ContainerConfig = *containerConfig
  136. }
  137. if err := graph.Register(nil, layerData, img); err != nil {
  138. return nil, err
  139. }
  140. return img, nil
  141. }
  142. // Register imports a pre-existing image into the graph.
  143. // FIXME: pass img as first argument
  144. func (graph *Graph) Register(jsonData []byte, layerData archive.ArchiveReader, img *image.Image) (err error) {
  145. defer func() {
  146. // If any error occurs, remove the new dir from the driver.
  147. // Don't check for errors since the dir might not have been created.
  148. // FIXME: this leaves a possible race condition.
  149. if err != nil {
  150. graph.driver.Remove(img.ID)
  151. }
  152. }()
  153. if err := utils.ValidateID(img.ID); err != nil {
  154. return err
  155. }
  156. // (This is a convenience to save time. Race conditions are taken care of by os.Rename)
  157. if graph.Exists(img.ID) {
  158. return fmt.Errorf("Image %s already exists", img.ID)
  159. }
  160. // Ensure that the image root does not exist on the filesystem
  161. // when it is not registered in the graph.
  162. // This is common when you switch from one graph driver to another
  163. if err := os.RemoveAll(graph.ImageRoot(img.ID)); err != nil && !os.IsNotExist(err) {
  164. return err
  165. }
  166. // If the driver has this ID but the graph doesn't, remove it from the driver to start fresh.
  167. // (the graph is the source of truth).
  168. // Ignore errors, since we don't know if the driver correctly returns ErrNotExist.
  169. // (FIXME: make that mandatory for drivers).
  170. graph.driver.Remove(img.ID)
  171. tmp, err := graph.Mktemp("")
  172. defer os.RemoveAll(tmp)
  173. if err != nil {
  174. return fmt.Errorf("Mktemp failed: %s", err)
  175. }
  176. // Create root filesystem in the driver
  177. if err := graph.driver.Create(img.ID, img.Parent); err != nil {
  178. return fmt.Errorf("Driver %s failed to create image rootfs %s: %s", graph.driver, img.ID, err)
  179. }
  180. // Mount the root filesystem so we can apply the diff/layer
  181. rootfs, err := graph.driver.Get(img.ID, "")
  182. if err != nil {
  183. return fmt.Errorf("Driver %s failed to get image rootfs %s: %s", graph.driver, img.ID, err)
  184. }
  185. defer graph.driver.Put(img.ID)
  186. img.SetGraph(graph)
  187. if err := image.StoreImage(img, jsonData, layerData, tmp, rootfs); err != nil {
  188. return err
  189. }
  190. // Commit
  191. if err := os.Rename(tmp, graph.ImageRoot(img.ID)); err != nil {
  192. return err
  193. }
  194. graph.idIndex.Add(img.ID)
  195. return nil
  196. }
  197. // TempLayerArchive creates a temporary archive of the given image's filesystem layer.
  198. // The archive is stored on disk and will be automatically deleted as soon as has been read.
  199. // If output is not nil, a human-readable progress bar will be written to it.
  200. // FIXME: does this belong in Graph? How about MktempFile, let the caller use it for archives?
  201. func (graph *Graph) TempLayerArchive(id string, compression archive.Compression, sf *utils.StreamFormatter, output io.Writer) (*archive.TempArchive, error) {
  202. image, err := graph.Get(id)
  203. if err != nil {
  204. return nil, err
  205. }
  206. tmp, err := graph.Mktemp("")
  207. if err != nil {
  208. return nil, err
  209. }
  210. a, err := image.TarLayer()
  211. if err != nil {
  212. return nil, err
  213. }
  214. progress := utils.ProgressReader(a, 0, output, sf, false, utils.TruncateID(id), "Buffering to disk")
  215. defer progress.Close()
  216. return archive.NewTempArchive(progress, tmp)
  217. }
  218. // Mktemp creates a temporary sub-directory inside the graph's filesystem.
  219. func (graph *Graph) Mktemp(id string) (string, error) {
  220. dir := path.Join(graph.Root, "_tmp", utils.GenerateRandomID())
  221. if err := os.MkdirAll(dir, 0700); err != nil {
  222. return "", err
  223. }
  224. return dir, nil
  225. }
  226. // setupInitLayer populates a directory with mountpoints suitable
  227. // for bind-mounting dockerinit into the container. The mountpoint is simply an
  228. // empty file at /.dockerinit
  229. //
  230. // This extra layer is used by all containers as the top-most ro layer. It protects
  231. // the container from unwanted side-effects on the rw layer.
  232. func SetupInitLayer(initLayer string) error {
  233. for pth, typ := range map[string]string{
  234. "/dev/pts": "dir",
  235. "/dev/shm": "dir",
  236. "/proc": "dir",
  237. "/run": "dir",
  238. "/sys": "dir",
  239. "/.dockerinit": "file",
  240. "/.dockerenv": "file",
  241. "/etc/resolv.conf": "file",
  242. "/etc/hosts": "file",
  243. "/etc/hostname": "file",
  244. "/dev/console": "file",
  245. "/etc/mtab": "/proc/mounts",
  246. // "var/run": "dir",
  247. // "var/lock": "dir",
  248. } {
  249. parts := strings.Split(pth, "/")
  250. prev := "/"
  251. for _, p := range parts[1:] {
  252. prev = path.Join(prev, p)
  253. syscall.Unlink(path.Join(initLayer, prev))
  254. }
  255. if _, err := os.Stat(path.Join(initLayer, pth)); err != nil {
  256. if os.IsNotExist(err) {
  257. if err := os.MkdirAll(path.Join(initLayer, path.Dir(pth)), 0755); err != nil {
  258. return err
  259. }
  260. switch typ {
  261. case "dir":
  262. if err := os.MkdirAll(path.Join(initLayer, pth), 0755); err != nil {
  263. return err
  264. }
  265. case "file":
  266. f, err := os.OpenFile(path.Join(initLayer, pth), os.O_CREATE, 0755)
  267. if err != nil {
  268. return err
  269. }
  270. f.Close()
  271. default:
  272. if err := os.Symlink(typ, path.Join(initLayer, pth)); err != nil {
  273. return err
  274. }
  275. }
  276. } else {
  277. return err
  278. }
  279. }
  280. }
  281. // Layer is ready to use, if it wasn't before.
  282. return nil
  283. }
  284. // Check if given error is "not empty".
  285. // Note: this is the way golang does it internally with os.IsNotExists.
  286. func isNotEmpty(err error) bool {
  287. switch pe := err.(type) {
  288. case nil:
  289. return false
  290. case *os.PathError:
  291. err = pe.Err
  292. case *os.LinkError:
  293. err = pe.Err
  294. }
  295. return strings.Contains(err.Error(), " not empty")
  296. }
  297. // Delete atomically removes an image from the graph.
  298. func (graph *Graph) Delete(name string) error {
  299. id, err := graph.idIndex.Get(name)
  300. if err != nil {
  301. return err
  302. }
  303. tmp, err := graph.Mktemp("")
  304. if err != nil {
  305. return err
  306. }
  307. graph.idIndex.Delete(id)
  308. err = os.Rename(graph.ImageRoot(id), tmp)
  309. if err != nil {
  310. return err
  311. }
  312. // Remove rootfs data from the driver
  313. graph.driver.Remove(id)
  314. // Remove the trashed image directory
  315. return os.RemoveAll(tmp)
  316. }
  317. // Map returns a list of all images in the graph, addressable by ID.
  318. func (graph *Graph) Map() (map[string]*image.Image, error) {
  319. images := make(map[string]*image.Image)
  320. err := graph.walkAll(func(image *image.Image) {
  321. images[image.ID] = image
  322. })
  323. if err != nil {
  324. return nil, err
  325. }
  326. return images, nil
  327. }
  328. // walkAll iterates over each image in the graph, and passes it to a handler.
  329. // The walking order is undetermined.
  330. func (graph *Graph) walkAll(handler func(*image.Image)) error {
  331. files, err := ioutil.ReadDir(graph.Root)
  332. if err != nil {
  333. return err
  334. }
  335. for _, st := range files {
  336. if img, err := graph.Get(st.Name()); err != nil {
  337. // Skip image
  338. continue
  339. } else if handler != nil {
  340. handler(img)
  341. }
  342. }
  343. return nil
  344. }
  345. // ByParent returns a lookup table of images by their parent.
  346. // If an image of id ID has 3 children images, then the value for key ID
  347. // will be a list of 3 images.
  348. // If an image has no children, it will not have an entry in the table.
  349. func (graph *Graph) ByParent() (map[string][]*image.Image, error) {
  350. byParent := make(map[string][]*image.Image)
  351. err := graph.walkAll(func(img *image.Image) {
  352. parent, err := graph.Get(img.Parent)
  353. if err != nil {
  354. return
  355. }
  356. if children, exists := byParent[parent.ID]; exists {
  357. byParent[parent.ID] = append(children, img)
  358. } else {
  359. byParent[parent.ID] = []*image.Image{img}
  360. }
  361. })
  362. return byParent, err
  363. }
  364. // Heads returns all heads in the graph, keyed by id.
  365. // A head is an image which is not the parent of another image in the graph.
  366. func (graph *Graph) Heads() (map[string]*image.Image, error) {
  367. heads := make(map[string]*image.Image)
  368. byParent, err := graph.ByParent()
  369. if err != nil {
  370. return nil, err
  371. }
  372. err = graph.walkAll(func(image *image.Image) {
  373. // If it's not in the byParent lookup table, then
  374. // it's not a parent -> so it's a head!
  375. if _, exists := byParent[image.ID]; !exists {
  376. heads[image.ID] = image
  377. }
  378. })
  379. return heads, err
  380. }
  381. func (graph *Graph) ImageRoot(id string) string {
  382. return path.Join(graph.Root, id)
  383. }
  384. func (graph *Graph) Driver() graphdriver.Driver {
  385. return graph.driver
  386. }