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