github.com/jiasir/docker@v1.3.3-0.20170609024000-252e610103e7/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  		CommonContainer: container.CommonContainer{
    22  			State: &container.State{},
    23  			MountPoints: map[string]*volume.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  		CommonContainer: container.CommonContainer{
    76  			State: &container.State{},
    77  			ID:    "1",
    78  			MountPoints: map[string]*volume.MountPoint{
    79  				"/kumquat": {Destination: "/kumquat", Name: "data", RW: false, CopyData: true},
    80  			},
    81  			HostConfig: &containertypes.HostConfig{
    82  				Binds: []string{
    83  					"data:/kumquat:ro",
    84  				},
    85  			},
    86  		},
    87  	})
    88  
    89  	type expected struct {
    90  		mp      *volume.MountPoint
    91  		comment string
    92  	}
    93  
    94  	pretty := func(mp *volume.MountPoint) string {
    95  		b, err := json.MarshalIndent(mp, "\t", "    ")
    96  		if err != nil {
    97  			return fmt.Sprintf("%#v", mp)
    98  		}
    99  		return string(b)
   100  	}
   101  
   102  	for _, x := range []expected{
   103  		{
   104  			mp: &volume.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: &volume.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: &volume.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: &volume.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: &volume.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: &volume.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: &volume.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 propgation",
   213  		},
   214  		{
   215  			mp: &volume.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:      &(*c.MountPoints["/jambolan"]), // copy the mountpoint, expect no changes
   232  			comment: "volume defined in mounts API",
   233  		},
   234  		{
   235  			mp: &volume.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  }