volumes_unix_test.go 7.5 KB

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