github.com/Ilhicas/nomad@v1.0.4-0.20210304152020-e86851182bc3/client/allocrunner/taskrunner/volume_hook_test.go (about) 1 package taskrunner 2 3 import ( 4 "testing" 5 6 "github.com/hashicorp/nomad/client/allocrunner/interfaces" 7 "github.com/hashicorp/nomad/client/pluginmanager/csimanager" 8 cstructs "github.com/hashicorp/nomad/client/structs" 9 "github.com/hashicorp/nomad/client/taskenv" 10 "github.com/hashicorp/nomad/helper/testlog" 11 "github.com/hashicorp/nomad/nomad/mock" 12 "github.com/hashicorp/nomad/nomad/structs" 13 "github.com/hashicorp/nomad/plugins/drivers" 14 dtu "github.com/hashicorp/nomad/plugins/drivers/testutils" 15 "github.com/stretchr/testify/require" 16 ) 17 18 func TestVolumeHook_PartitionMountsByVolume_Works(t *testing.T) { 19 mounts := []*structs.VolumeMount{ 20 { 21 Volume: "foo", 22 Destination: "/tmp", 23 ReadOnly: false, 24 }, 25 { 26 Volume: "foo", 27 Destination: "/bar", 28 ReadOnly: false, 29 }, 30 { 31 Volume: "baz", 32 Destination: "/baz", 33 ReadOnly: false, 34 }, 35 } 36 37 expected := map[string][]*structs.VolumeMount{ 38 "foo": { 39 { 40 Volume: "foo", 41 Destination: "/tmp", 42 ReadOnly: false, 43 }, 44 { 45 Volume: "foo", 46 Destination: "/bar", 47 ReadOnly: false, 48 }, 49 }, 50 "baz": { 51 { 52 Volume: "baz", 53 Destination: "/baz", 54 ReadOnly: false, 55 }, 56 }, 57 } 58 59 // Test with a real collection 60 61 partitioned := partitionMountsByVolume(mounts) 62 require.Equal(t, expected, partitioned) 63 64 // Test with nil/emptylist 65 66 partitioned = partitionMountsByVolume(nil) 67 require.Equal(t, map[string][]*structs.VolumeMount{}, partitioned) 68 } 69 70 func TestVolumeHook_prepareCSIVolumes(t *testing.T) { 71 72 req := &interfaces.TaskPrestartRequest{ 73 Task: &structs.Task{ 74 Name: "test", 75 Driver: "mock", 76 VolumeMounts: []*structs.VolumeMount{ 77 { 78 Volume: "foo", 79 Destination: "/bar", 80 }, 81 }, 82 }, 83 } 84 85 volumes := map[string]*structs.VolumeRequest{ 86 "foo": { 87 Type: "csi", 88 Source: "my-test-volume", 89 }, 90 } 91 92 cases := []struct { 93 Name string 94 Driver drivers.DriverPlugin 95 Expected []*drivers.MountConfig 96 ExpectedError string 97 }{ 98 { 99 Name: "supported driver", 100 Driver: &dtu.MockDriver{ 101 CapabilitiesF: func() (*drivers.Capabilities, error) { 102 return &drivers.Capabilities{ 103 MountConfigs: drivers.MountConfigSupportAll, 104 }, nil 105 }, 106 }, 107 Expected: []*drivers.MountConfig{ 108 { 109 HostPath: "/mnt/my-test-volume", 110 TaskPath: "/bar", 111 }, 112 }, 113 }, 114 { 115 Name: "unsupported driver", 116 Driver: &dtu.MockDriver{ 117 CapabilitiesF: func() (*drivers.Capabilities, error) { 118 return &drivers.Capabilities{ 119 MountConfigs: drivers.MountConfigSupportNone, 120 }, nil 121 }, 122 }, 123 ExpectedError: "task driver \"mock\" for \"test\" does not support CSI", 124 }, 125 } 126 127 for _, tc := range cases { 128 t.Run(tc.Name, func(t *testing.T) { 129 130 tr := &TaskRunner{ 131 task: req.Task, 132 driver: tc.Driver, 133 allocHookResources: &cstructs.AllocHookResources{ 134 CSIMounts: map[string]*csimanager.MountInfo{ 135 "foo": { 136 Source: "/mnt/my-test-volume", 137 }, 138 }, 139 }, 140 } 141 142 hook := &volumeHook{ 143 logger: testlog.HCLogger(t), 144 alloc: structs.MockAlloc(), 145 runner: tr, 146 } 147 mounts, err := hook.prepareCSIVolumes(req, volumes) 148 149 if tc.ExpectedError != "" { 150 require.EqualError(t, err, tc.ExpectedError) 151 } else { 152 require.NoError(t, err) 153 } 154 require.Equal(t, tc.Expected, mounts) 155 }) 156 } 157 } 158 159 func TestVolumeHook_Interpolation(t *testing.T) { 160 161 alloc := mock.Alloc() 162 task := alloc.Job.TaskGroups[0].Tasks[0] 163 taskEnv := taskenv.NewBuilder(mock.Node(), alloc, task, "global").SetHookEnv("volume", 164 map[string]string{ 165 "PROPAGATION_MODE": "private", 166 "VOLUME_ID": "my-other-volume", 167 }, 168 ).Build() 169 170 mounts := []*structs.VolumeMount{ 171 { 172 Volume: "foo", 173 Destination: "/tmp", 174 ReadOnly: false, 175 PropagationMode: "bidirectional", 176 }, 177 { 178 Volume: "foo", 179 Destination: "/bar-${NOMAD_JOB_NAME}", 180 ReadOnly: false, 181 PropagationMode: "bidirectional", 182 }, 183 { 184 Volume: "${VOLUME_ID}", 185 Destination: "/baz", 186 ReadOnly: false, 187 PropagationMode: "bidirectional", 188 }, 189 { 190 Volume: "foo", 191 Destination: "/quux", 192 ReadOnly: false, 193 PropagationMode: "${PROPAGATION_MODE}", 194 }, 195 } 196 197 expected := []*structs.VolumeMount{ 198 { 199 Volume: "foo", 200 Destination: "/tmp", 201 ReadOnly: false, 202 PropagationMode: "bidirectional", 203 }, 204 { 205 Volume: "foo", 206 Destination: "/bar-my-job", 207 ReadOnly: false, 208 PropagationMode: "bidirectional", 209 }, 210 { 211 Volume: "my-other-volume", 212 Destination: "/baz", 213 ReadOnly: false, 214 PropagationMode: "bidirectional", 215 }, 216 { 217 Volume: "foo", 218 Destination: "/quux", 219 ReadOnly: false, 220 PropagationMode: "private", 221 }, 222 } 223 224 interpolateVolumeMounts(mounts, taskEnv) 225 require.Equal(t, expected, mounts) 226 }