github.com/sams1990/dockerrepo@v17.12.1-ce-rc2+incompatible/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  }