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