volumes_unix_test.go 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256
  1. // +build !windows
  2. package daemon
  3. import (
  4. "encoding/json"
  5. "fmt"
  6. "reflect"
  7. "testing"
  8. containertypes "github.com/docker/docker/api/types/container"
  9. mounttypes "github.com/docker/docker/api/types/mount"
  10. "github.com/docker/docker/container"
  11. "github.com/docker/docker/volume"
  12. )
  13. func TestBackportMountSpec(t *testing.T) {
  14. d := Daemon{containers: container.NewMemoryStore()}
  15. c := &container.Container{
  16. State: &container.State{},
  17. MountPoints: map[string]*volume.MountPoint{
  18. "/apple": {Destination: "/apple", Source: "/var/lib/docker/volumes/12345678", Name: "12345678", RW: true, CopyData: true}, // anonymous volume
  19. "/banana": {Destination: "/banana", Source: "/var/lib/docker/volumes/data", Name: "data", RW: true, CopyData: true}, // named volume
  20. "/cherry": {Destination: "/cherry", Source: "/var/lib/docker/volumes/data", Name: "data", CopyData: true}, // RO named volume
  21. "/dates": {Destination: "/dates", Source: "/var/lib/docker/volumes/data", Name: "data"}, // named volume nocopy
  22. "/elderberry": {Destination: "/elderberry", Source: "/var/lib/docker/volumes/data", Name: "data"}, // masks anon vol
  23. "/fig": {Destination: "/fig", Source: "/data", RW: true}, // RW bind
  24. "/guava": {Destination: "/guava", Source: "/data", RW: false, Propagation: "shared"}, // RO bind + propagation
  25. "/kumquat": {Destination: "/kumquat", Name: "data", RW: false, CopyData: true}, // volumes-from
  26. // partially configured mountpoint due to #32613
  27. // specifically, `mp.Spec.Source` is not set
  28. "/honeydew": {
  29. Type: mounttypes.TypeVolume,
  30. Destination: "/honeydew",
  31. Name: "data",
  32. Source: "/var/lib/docker/volumes/data",
  33. Spec: mounttypes.Mount{Type: mounttypes.TypeVolume, Target: "/honeydew", VolumeOptions: &mounttypes.VolumeOptions{NoCopy: true}},
  34. },
  35. // from hostconfig.Mounts
  36. "/jambolan": {
  37. Type: mounttypes.TypeVolume,
  38. Destination: "/jambolan",
  39. Source: "/var/lib/docker/volumes/data",
  40. RW: true,
  41. Name: "data",
  42. Spec: mounttypes.Mount{Type: mounttypes.TypeVolume, Target: "/jambolan", Source: "data"},
  43. },
  44. },
  45. HostConfig: &containertypes.HostConfig{
  46. Binds: []string{
  47. "data:/banana",
  48. "data:/cherry:ro",
  49. "data:/dates:ro,nocopy",
  50. "data:/elderberry:ro,nocopy",
  51. "/data:/fig",
  52. "/data:/guava:ro,shared",
  53. "data:/honeydew:nocopy",
  54. },
  55. VolumesFrom: []string{"1:ro"},
  56. Mounts: []mounttypes.Mount{
  57. {Type: mounttypes.TypeVolume, Target: "/jambolan"},
  58. },
  59. },
  60. Config: &containertypes.Config{Volumes: map[string]struct{}{
  61. "/apple": {},
  62. "/elderberry": {},
  63. }},
  64. }
  65. d.containers.Add("1", &container.Container{
  66. State: &container.State{},
  67. ID: "1",
  68. MountPoints: map[string]*volume.MountPoint{
  69. "/kumquat": {Destination: "/kumquat", Name: "data", RW: false, CopyData: true},
  70. },
  71. HostConfig: &containertypes.HostConfig{
  72. Binds: []string{
  73. "data:/kumquat:ro",
  74. },
  75. },
  76. })
  77. type expected struct {
  78. mp *volume.MountPoint
  79. comment string
  80. }
  81. pretty := func(mp *volume.MountPoint) string {
  82. b, err := json.MarshalIndent(mp, "\t", " ")
  83. if err != nil {
  84. return fmt.Sprintf("%#v", mp)
  85. }
  86. return string(b)
  87. }
  88. for _, x := range []expected{
  89. {
  90. mp: &volume.MountPoint{
  91. Type: mounttypes.TypeVolume,
  92. Destination: "/apple",
  93. RW: true,
  94. Name: "12345678",
  95. Source: "/var/lib/docker/volumes/12345678",
  96. CopyData: true,
  97. Spec: mounttypes.Mount{
  98. Type: mounttypes.TypeVolume,
  99. Source: "",
  100. Target: "/apple",
  101. },
  102. },
  103. comment: "anonymous volume",
  104. },
  105. {
  106. mp: &volume.MountPoint{
  107. Type: mounttypes.TypeVolume,
  108. Destination: "/banana",
  109. RW: true,
  110. Name: "data",
  111. Source: "/var/lib/docker/volumes/data",
  112. CopyData: true,
  113. Spec: mounttypes.Mount{
  114. Type: mounttypes.TypeVolume,
  115. Source: "data",
  116. Target: "/banana",
  117. },
  118. },
  119. comment: "named volume",
  120. },
  121. {
  122. mp: &volume.MountPoint{
  123. Type: mounttypes.TypeVolume,
  124. Destination: "/cherry",
  125. Name: "data",
  126. Source: "/var/lib/docker/volumes/data",
  127. CopyData: true,
  128. Spec: mounttypes.Mount{
  129. Type: mounttypes.TypeVolume,
  130. Source: "data",
  131. Target: "/cherry",
  132. ReadOnly: true,
  133. },
  134. },
  135. comment: "read-only named volume",
  136. },
  137. {
  138. mp: &volume.MountPoint{
  139. Type: mounttypes.TypeVolume,
  140. Destination: "/dates",
  141. Name: "data",
  142. Source: "/var/lib/docker/volumes/data",
  143. Spec: mounttypes.Mount{
  144. Type: mounttypes.TypeVolume,
  145. Source: "data",
  146. Target: "/dates",
  147. ReadOnly: true,
  148. VolumeOptions: &mounttypes.VolumeOptions{NoCopy: true},
  149. },
  150. },
  151. comment: "named volume with nocopy",
  152. },
  153. {
  154. mp: &volume.MountPoint{
  155. Type: mounttypes.TypeVolume,
  156. Destination: "/elderberry",
  157. Name: "data",
  158. Source: "/var/lib/docker/volumes/data",
  159. Spec: mounttypes.Mount{
  160. Type: mounttypes.TypeVolume,
  161. Source: "data",
  162. Target: "/elderberry",
  163. ReadOnly: true,
  164. VolumeOptions: &mounttypes.VolumeOptions{NoCopy: true},
  165. },
  166. },
  167. comment: "masks an anonymous volume",
  168. },
  169. {
  170. mp: &volume.MountPoint{
  171. Type: mounttypes.TypeBind,
  172. Destination: "/fig",
  173. Source: "/data",
  174. RW: true,
  175. Spec: mounttypes.Mount{
  176. Type: mounttypes.TypeBind,
  177. Source: "/data",
  178. Target: "/fig",
  179. },
  180. },
  181. comment: "bind mount with read/write",
  182. },
  183. {
  184. mp: &volume.MountPoint{
  185. Type: mounttypes.TypeBind,
  186. Destination: "/guava",
  187. Source: "/data",
  188. RW: false,
  189. Propagation: "shared",
  190. Spec: mounttypes.Mount{
  191. Type: mounttypes.TypeBind,
  192. Source: "/data",
  193. Target: "/guava",
  194. ReadOnly: true,
  195. BindOptions: &mounttypes.BindOptions{Propagation: "shared"},
  196. },
  197. },
  198. comment: "bind mount with read/write + shared propagation",
  199. },
  200. {
  201. mp: &volume.MountPoint{
  202. Type: mounttypes.TypeVolume,
  203. Destination: "/honeydew",
  204. Source: "/var/lib/docker/volumes/data",
  205. RW: true,
  206. Propagation: "shared",
  207. Spec: mounttypes.Mount{
  208. Type: mounttypes.TypeVolume,
  209. Source: "data",
  210. Target: "/honeydew",
  211. VolumeOptions: &mounttypes.VolumeOptions{NoCopy: true},
  212. },
  213. },
  214. comment: "partially configured named volume caused by #32613",
  215. },
  216. {
  217. mp: &(*c.MountPoints["/jambolan"]), // copy the mountpoint, expect no changes
  218. comment: "volume defined in mounts API",
  219. },
  220. {
  221. mp: &volume.MountPoint{
  222. Type: mounttypes.TypeVolume,
  223. Destination: "/kumquat",
  224. Source: "/var/lib/docker/volumes/data",
  225. RW: false,
  226. Name: "data",
  227. Spec: mounttypes.Mount{
  228. Type: mounttypes.TypeVolume,
  229. Source: "data",
  230. Target: "/kumquat",
  231. ReadOnly: true,
  232. },
  233. },
  234. comment: "partially configured named volume caused by #32613",
  235. },
  236. } {
  237. mp := c.MountPoints[x.mp.Destination]
  238. d.backportMountSpec(c)
  239. if !reflect.DeepEqual(mp.Spec, x.mp.Spec) {
  240. t.Fatalf("%s\nexpected:\n\t%s\n\ngot:\n\t%s", x.comment, pretty(x.mp), pretty(mp))
  241. }
  242. }
  243. }