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  }