migration_test.go 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435
  1. package layer
  2. import (
  3. "bytes"
  4. "compress/gzip"
  5. "fmt"
  6. "io"
  7. "io/ioutil"
  8. "os"
  9. "path/filepath"
  10. "testing"
  11. "github.com/docker/docker/daemon/graphdriver"
  12. "github.com/docker/docker/pkg/archive"
  13. "github.com/docker/docker/pkg/stringid"
  14. "github.com/vbatts/tar-split/tar/asm"
  15. "github.com/vbatts/tar-split/tar/storage"
  16. )
  17. func writeTarSplitFile(name string, tarContent []byte) error {
  18. f, err := os.OpenFile(name, os.O_TRUNC|os.O_CREATE|os.O_WRONLY, 0644)
  19. if err != nil {
  20. return err
  21. }
  22. defer f.Close()
  23. fz := gzip.NewWriter(f)
  24. metaPacker := storage.NewJSONPacker(fz)
  25. defer fz.Close()
  26. rdr, err := asm.NewInputTarStream(bytes.NewReader(tarContent), metaPacker, nil)
  27. if err != nil {
  28. return err
  29. }
  30. if _, err := io.Copy(ioutil.Discard, rdr); err != nil {
  31. return err
  32. }
  33. return nil
  34. }
  35. func TestLayerMigration(t *testing.T) {
  36. td, err := ioutil.TempDir("", "migration-test-")
  37. if err != nil {
  38. t.Fatal(err)
  39. }
  40. defer os.RemoveAll(td)
  41. layer1Files := []FileApplier{
  42. newTestFile("/root/.bashrc", []byte("# Boring configuration"), 0644),
  43. newTestFile("/etc/profile", []byte("# Base configuration"), 0644),
  44. }
  45. layer2Files := []FileApplier{
  46. newTestFile("/root/.bashrc", []byte("# Updated configuration"), 0644),
  47. }
  48. tar1, err := tarFromFiles(layer1Files...)
  49. if err != nil {
  50. t.Fatal(err)
  51. }
  52. tar2, err := tarFromFiles(layer2Files...)
  53. if err != nil {
  54. t.Fatal(err)
  55. }
  56. graph, err := newVFSGraphDriver(filepath.Join(td, "graphdriver-"))
  57. if err != nil {
  58. t.Fatal(err)
  59. }
  60. graphID1 := stringid.GenerateRandomID()
  61. if err := graph.Create(graphID1, "", ""); err != nil {
  62. t.Fatal(err)
  63. }
  64. if _, err := graph.ApplyDiff(graphID1, "", archive.Reader(bytes.NewReader(tar1))); err != nil {
  65. t.Fatal(err)
  66. }
  67. tf1 := filepath.Join(td, "tar1.json.gz")
  68. if err := writeTarSplitFile(tf1, tar1); err != nil {
  69. t.Fatal(err)
  70. }
  71. fms, err := NewFSMetadataStore(filepath.Join(td, "layers"))
  72. if err != nil {
  73. t.Fatal(err)
  74. }
  75. ls, err := NewStoreFromGraphDriver(fms, graph)
  76. if err != nil {
  77. t.Fatal(err)
  78. }
  79. newTarDataPath := filepath.Join(td, ".migration-tardata")
  80. diffID, size, err := ls.(*layerStore).ChecksumForGraphID(graphID1, "", tf1, newTarDataPath)
  81. if err != nil {
  82. t.Fatal(err)
  83. }
  84. layer1a, err := ls.(*layerStore).RegisterByGraphID(graphID1, "", diffID, newTarDataPath, size)
  85. if err != nil {
  86. t.Fatal(err)
  87. }
  88. layer1b, err := ls.Register(bytes.NewReader(tar1), "")
  89. if err != nil {
  90. t.Fatal(err)
  91. }
  92. assertReferences(t, layer1a, layer1b)
  93. // Attempt register, should be same
  94. layer2a, err := ls.Register(bytes.NewReader(tar2), layer1a.ChainID())
  95. if err != nil {
  96. t.Fatal(err)
  97. }
  98. graphID2 := stringid.GenerateRandomID()
  99. if err := graph.Create(graphID2, graphID1, ""); err != nil {
  100. t.Fatal(err)
  101. }
  102. if _, err := graph.ApplyDiff(graphID2, graphID1, archive.Reader(bytes.NewReader(tar2))); err != nil {
  103. t.Fatal(err)
  104. }
  105. tf2 := filepath.Join(td, "tar2.json.gz")
  106. if err := writeTarSplitFile(tf2, tar2); err != nil {
  107. t.Fatal(err)
  108. }
  109. diffID, size, err = ls.(*layerStore).ChecksumForGraphID(graphID2, graphID1, tf2, newTarDataPath)
  110. if err != nil {
  111. t.Fatal(err)
  112. }
  113. layer2b, err := ls.(*layerStore).RegisterByGraphID(graphID2, layer1a.ChainID(), diffID, tf2, size)
  114. if err != nil {
  115. t.Fatal(err)
  116. }
  117. assertReferences(t, layer2a, layer2b)
  118. if metadata, err := ls.Release(layer2a); err != nil {
  119. t.Fatal(err)
  120. } else if len(metadata) > 0 {
  121. t.Fatalf("Unexpected layer removal after first release: %#v", metadata)
  122. }
  123. metadata, err := ls.Release(layer2b)
  124. if err != nil {
  125. t.Fatal(err)
  126. }
  127. assertMetadata(t, metadata, createMetadata(layer2a))
  128. }
  129. func tarFromFilesInGraph(graph graphdriver.Driver, graphID, parentID string, files ...FileApplier) ([]byte, error) {
  130. t, err := tarFromFiles(files...)
  131. if err != nil {
  132. return nil, err
  133. }
  134. if err := graph.Create(graphID, parentID, ""); err != nil {
  135. return nil, err
  136. }
  137. if _, err := graph.ApplyDiff(graphID, parentID, archive.Reader(bytes.NewReader(t))); err != nil {
  138. return nil, err
  139. }
  140. ar, err := graph.Diff(graphID, parentID)
  141. if err != nil {
  142. return nil, err
  143. }
  144. defer ar.Close()
  145. return ioutil.ReadAll(ar)
  146. }
  147. func TestLayerMigrationNoTarsplit(t *testing.T) {
  148. td, err := ioutil.TempDir("", "migration-test-")
  149. if err != nil {
  150. t.Fatal(err)
  151. }
  152. defer os.RemoveAll(td)
  153. layer1Files := []FileApplier{
  154. newTestFile("/root/.bashrc", []byte("# Boring configuration"), 0644),
  155. newTestFile("/etc/profile", []byte("# Base configuration"), 0644),
  156. }
  157. layer2Files := []FileApplier{
  158. newTestFile("/root/.bashrc", []byte("# Updated configuration"), 0644),
  159. }
  160. graph, err := newVFSGraphDriver(filepath.Join(td, "graphdriver-"))
  161. if err != nil {
  162. t.Fatal(err)
  163. }
  164. graphID1 := stringid.GenerateRandomID()
  165. graphID2 := stringid.GenerateRandomID()
  166. tar1, err := tarFromFilesInGraph(graph, graphID1, "", layer1Files...)
  167. if err != nil {
  168. t.Fatal(err)
  169. }
  170. tar2, err := tarFromFilesInGraph(graph, graphID2, graphID1, layer2Files...)
  171. if err != nil {
  172. t.Fatal(err)
  173. }
  174. fms, err := NewFSMetadataStore(filepath.Join(td, "layers"))
  175. if err != nil {
  176. t.Fatal(err)
  177. }
  178. ls, err := NewStoreFromGraphDriver(fms, graph)
  179. if err != nil {
  180. t.Fatal(err)
  181. }
  182. newTarDataPath := filepath.Join(td, ".migration-tardata")
  183. diffID, size, err := ls.(*layerStore).ChecksumForGraphID(graphID1, "", "", newTarDataPath)
  184. if err != nil {
  185. t.Fatal(err)
  186. }
  187. layer1a, err := ls.(*layerStore).RegisterByGraphID(graphID1, "", diffID, newTarDataPath, size)
  188. if err != nil {
  189. t.Fatal(err)
  190. }
  191. layer1b, err := ls.Register(bytes.NewReader(tar1), "")
  192. if err != nil {
  193. t.Fatal(err)
  194. }
  195. assertReferences(t, layer1a, layer1b)
  196. // Attempt register, should be same
  197. layer2a, err := ls.Register(bytes.NewReader(tar2), layer1a.ChainID())
  198. if err != nil {
  199. t.Fatal(err)
  200. }
  201. diffID, size, err = ls.(*layerStore).ChecksumForGraphID(graphID2, graphID1, "", newTarDataPath)
  202. if err != nil {
  203. t.Fatal(err)
  204. }
  205. layer2b, err := ls.(*layerStore).RegisterByGraphID(graphID2, layer1a.ChainID(), diffID, newTarDataPath, size)
  206. if err != nil {
  207. t.Fatal(err)
  208. }
  209. assertReferences(t, layer2a, layer2b)
  210. if metadata, err := ls.Release(layer2a); err != nil {
  211. t.Fatal(err)
  212. } else if len(metadata) > 0 {
  213. t.Fatalf("Unexpected layer removal after first release: %#v", metadata)
  214. }
  215. metadata, err := ls.Release(layer2b)
  216. if err != nil {
  217. t.Fatal(err)
  218. }
  219. assertMetadata(t, metadata, createMetadata(layer2a))
  220. }
  221. func TestMountMigration(t *testing.T) {
  222. ls, cleanup := newTestStore(t)
  223. defer cleanup()
  224. baseFiles := []FileApplier{
  225. newTestFile("/root/.bashrc", []byte("# Boring configuration"), 0644),
  226. newTestFile("/etc/profile", []byte("# Base configuration"), 0644),
  227. }
  228. initFiles := []FileApplier{
  229. newTestFile("/etc/hosts", []byte{}, 0644),
  230. newTestFile("/etc/resolv.conf", []byte{}, 0644),
  231. }
  232. mountFiles := []FileApplier{
  233. newTestFile("/etc/hosts", []byte("localhost 127.0.0.1"), 0644),
  234. newTestFile("/root/.bashrc", []byte("# Updated configuration"), 0644),
  235. newTestFile("/root/testfile1.txt", []byte("nothing valuable"), 0644),
  236. }
  237. initTar, err := tarFromFiles(initFiles...)
  238. if err != nil {
  239. t.Fatal(err)
  240. }
  241. mountTar, err := tarFromFiles(mountFiles...)
  242. if err != nil {
  243. t.Fatal(err)
  244. }
  245. graph := ls.(*layerStore).driver
  246. layer1, err := createLayer(ls, "", initWithFiles(baseFiles...))
  247. if err != nil {
  248. t.Fatal(err)
  249. }
  250. graphID1 := layer1.(*referencedCacheLayer).cacheID
  251. containerID := stringid.GenerateRandomID()
  252. containerInit := fmt.Sprintf("%s-init", containerID)
  253. if err := graph.Create(containerInit, graphID1, ""); err != nil {
  254. t.Fatal(err)
  255. }
  256. if _, err := graph.ApplyDiff(containerInit, graphID1, archive.Reader(bytes.NewReader(initTar))); err != nil {
  257. t.Fatal(err)
  258. }
  259. if err := graph.Create(containerID, containerInit, ""); err != nil {
  260. t.Fatal(err)
  261. }
  262. if _, err := graph.ApplyDiff(containerID, containerInit, archive.Reader(bytes.NewReader(mountTar))); err != nil {
  263. t.Fatal(err)
  264. }
  265. if err := ls.(*layerStore).CreateRWLayerByGraphID("migration-mount", containerID, layer1.ChainID()); err != nil {
  266. t.Fatal(err)
  267. }
  268. rwLayer1, err := ls.GetRWLayer("migration-mount")
  269. if err != nil {
  270. t.Fatal(err)
  271. }
  272. if _, err := rwLayer1.Mount(""); err != nil {
  273. t.Fatal(err)
  274. }
  275. changes, err := rwLayer1.Changes()
  276. if err != nil {
  277. t.Fatal(err)
  278. }
  279. if expected := 5; len(changes) != expected {
  280. t.Logf("Changes %#v", changes)
  281. t.Fatalf("Wrong number of changes %d, expected %d", len(changes), expected)
  282. }
  283. sortChanges(changes)
  284. assertChange(t, changes[0], archive.Change{
  285. Path: "/etc",
  286. Kind: archive.ChangeModify,
  287. })
  288. assertChange(t, changes[1], archive.Change{
  289. Path: "/etc/hosts",
  290. Kind: archive.ChangeModify,
  291. })
  292. assertChange(t, changes[2], archive.Change{
  293. Path: "/root",
  294. Kind: archive.ChangeModify,
  295. })
  296. assertChange(t, changes[3], archive.Change{
  297. Path: "/root/.bashrc",
  298. Kind: archive.ChangeModify,
  299. })
  300. assertChange(t, changes[4], archive.Change{
  301. Path: "/root/testfile1.txt",
  302. Kind: archive.ChangeAdd,
  303. })
  304. assertActivityCount(t, rwLayer1, 1)
  305. if _, err := ls.CreateRWLayer("migration-mount", layer1.ChainID(), "", nil); err == nil {
  306. t.Fatal("Expected error creating mount with same name")
  307. } else if err != ErrMountNameConflict {
  308. t.Fatal(err)
  309. }
  310. rwLayer2, err := ls.GetRWLayer("migration-mount")
  311. if err != nil {
  312. t.Fatal(err)
  313. }
  314. if getMountLayer(rwLayer1) != getMountLayer(rwLayer2) {
  315. t.Fatal("Expected same layer from get with same name as from migrate")
  316. }
  317. if _, err := rwLayer2.Mount(""); err != nil {
  318. t.Fatal(err)
  319. }
  320. assertActivityCount(t, rwLayer2, 1)
  321. assertActivityCount(t, rwLayer1, 1)
  322. if _, err := rwLayer2.Mount(""); err != nil {
  323. t.Fatal(err)
  324. }
  325. assertActivityCount(t, rwLayer2, 2)
  326. assertActivityCount(t, rwLayer1, 1)
  327. if metadata, err := ls.Release(layer1); err != nil {
  328. t.Fatal(err)
  329. } else if len(metadata) > 0 {
  330. t.Fatalf("Expected no layers to be deleted, deleted %#v", metadata)
  331. }
  332. if err := rwLayer1.Unmount(); err != nil {
  333. t.Fatal(err)
  334. }
  335. assertActivityCount(t, rwLayer2, 2)
  336. assertActivityCount(t, rwLayer1, 0)
  337. if _, err := ls.ReleaseRWLayer(rwLayer1); err != nil {
  338. t.Fatal(err)
  339. }
  340. if err := rwLayer2.Unmount(); err != nil {
  341. t.Fatal(err)
  342. }
  343. if _, err := ls.ReleaseRWLayer(rwLayer2); err == nil {
  344. t.Fatal("Expected error deleting active mount")
  345. }
  346. if err := rwLayer2.Unmount(); err != nil {
  347. t.Fatal(err)
  348. }
  349. metadata, err := ls.ReleaseRWLayer(rwLayer2)
  350. if err != nil {
  351. t.Fatal(err)
  352. }
  353. if len(metadata) == 0 {
  354. t.Fatal("Expected base layer to be deleted when deleting mount")
  355. }
  356. assertMetadata(t, metadata, createMetadata(layer1))
  357. }