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