github.com/hernad/nomad@v1.6.112/command/volume_register_test.go (about)

     1  // Copyright (c) HashiCorp, Inc.
     2  // SPDX-License-Identifier: MPL-2.0
     3  
     4  package command
     5  
     6  import (
     7  	"testing"
     8  
     9  	"github.com/hashicorp/hcl"
    10  	"github.com/hernad/nomad/api"
    11  	"github.com/hernad/nomad/ci"
    12  	"github.com/stretchr/testify/require"
    13  )
    14  
    15  func TestVolumeDispatchParse(t *testing.T) {
    16  	ci.Parallel(t)
    17  
    18  	cases := []struct {
    19  		hcl string
    20  		t   string
    21  		err string
    22  	}{{
    23  		hcl: `
    24  type = "foo"
    25  rando = "bar"
    26  `,
    27  		t:   "foo",
    28  		err: "",
    29  	}, {
    30  		hcl: `{"id": "foo", "type": "foo", "other": "bar"}`,
    31  		t:   "foo",
    32  		err: "",
    33  	}}
    34  
    35  	for _, c := range cases {
    36  		t.Run(c.hcl, func(t *testing.T) {
    37  			_, s, err := parseVolumeType(c.hcl)
    38  			require.Equal(t, c.t, s)
    39  			if c.err == "" {
    40  				require.NoError(t, err)
    41  			} else {
    42  				require.Contains(t, err.Error(), c.err)
    43  			}
    44  
    45  		})
    46  	}
    47  }
    48  
    49  func TestCSIVolumeDecode(t *testing.T) {
    50  	ci.Parallel(t)
    51  
    52  	cases := []struct {
    53  		name     string
    54  		hcl      string
    55  		expected *api.CSIVolume
    56  		err      string
    57  	}{{
    58  		name: "volume creation",
    59  		hcl: `
    60  id              = "testvolume"
    61  namespace       = "prod"
    62  name            = "test"
    63  type            = "csi"
    64  plugin_id       = "myplugin"
    65  
    66  capacity_min = "10 MiB"
    67  capacity_max = "1G"
    68  snapshot_id  = "snap-12345"
    69  
    70  mount_options {
    71    fs_type     = "ext4"
    72    mount_flags = ["ro"]
    73  }
    74  
    75  secrets {
    76    password = "xyzzy"
    77  }
    78  
    79  parameters {
    80    skuname = "Premium_LRS"
    81  }
    82  
    83  capability {
    84    access_mode     = "single-node-writer"
    85    attachment_mode = "file-system"
    86  }
    87  
    88  capability {
    89    access_mode     = "single-node-reader-only"
    90    attachment_mode = "block-device"
    91  }
    92  
    93  topology_request {
    94    preferred {
    95      topology { segments {rack = "R1"} }
    96    }
    97  
    98    required {
    99      topology { segments {rack = "R1"} }
   100      topology { segments {rack = "R2", zone = "us-east-1a"} }
   101    }
   102  }
   103  `,
   104  		expected: &api.CSIVolume{
   105  			ID:                   "testvolume",
   106  			Namespace:            "prod",
   107  			Name:                 "test",
   108  			PluginID:             "myplugin",
   109  			SnapshotID:           "snap-12345",
   110  			RequestedCapacityMin: 10485760,
   111  			RequestedCapacityMax: 1000000000,
   112  			RequestedCapabilities: []*api.CSIVolumeCapability{
   113  				{
   114  					AccessMode:     api.CSIVolumeAccessModeSingleNodeWriter,
   115  					AttachmentMode: api.CSIVolumeAttachmentModeFilesystem,
   116  				},
   117  				{
   118  					AccessMode:     api.CSIVolumeAccessModeSingleNodeReader,
   119  					AttachmentMode: api.CSIVolumeAttachmentModeBlockDevice,
   120  				},
   121  			},
   122  			MountOptions: &api.CSIMountOptions{
   123  				FSType:     "ext4",
   124  				MountFlags: []string{"ro"},
   125  			},
   126  			Parameters: map[string]string{"skuname": "Premium_LRS"},
   127  			Secrets:    map[string]string{"password": "xyzzy"},
   128  			RequestedTopologies: &api.CSITopologyRequest{
   129  				Required: []*api.CSITopology{
   130  					{Segments: map[string]string{"rack": "R1"}},
   131  					{Segments: map[string]string{"rack": "R2", "zone": "us-east-1a"}},
   132  				},
   133  				Preferred: []*api.CSITopology{
   134  					{Segments: map[string]string{"rack": "R1"}},
   135  				},
   136  			},
   137  			Topologies: nil, // this is left empty
   138  		},
   139  		err: "",
   140  	}, {
   141  		name: "volume registration",
   142  		hcl: `
   143  id              = "testvolume"
   144  namespace       = "prod"
   145  external_id     = "vol-12345"
   146  name            = "test"
   147  type            = "csi"
   148  plugin_id       = "myplugin"
   149  capacity_min    = "" # meaningless for registration
   150  
   151  capability {
   152    access_mode     = "single-node-writer"
   153    attachment_mode = "file-system"
   154  }
   155  
   156  topology_request {
   157    # make sure we safely handle empty blocks even
   158    # if they're invalid
   159    preferred {
   160      topology {}
   161      topology { segments {} }
   162    }
   163  
   164    required {
   165      topology { segments { rack = "R2", zone = "us-east-1a"} }
   166    }
   167  }
   168  `,
   169  		expected: &api.CSIVolume{
   170  			ID:         "testvolume",
   171  			Namespace:  "prod",
   172  			ExternalID: "vol-12345",
   173  			Name:       "test",
   174  			PluginID:   "myplugin",
   175  			RequestedCapabilities: []*api.CSIVolumeCapability{
   176  				{
   177  					AccessMode:     api.CSIVolumeAccessModeSingleNodeWriter,
   178  					AttachmentMode: api.CSIVolumeAttachmentModeFilesystem,
   179  				},
   180  			},
   181  			RequestedTopologies: &api.CSITopologyRequest{
   182  				Required: []*api.CSITopology{
   183  					{Segments: map[string]string{"rack": "R2", "zone": "us-east-1a"}},
   184  				},
   185  				Preferred: nil,
   186  			},
   187  			Topologies: nil,
   188  		},
   189  		err: "",
   190  	},
   191  	}
   192  
   193  	for _, c := range cases {
   194  		t.Run(c.name, func(t *testing.T) {
   195  			ast, err := hcl.ParseString(c.hcl)
   196  			require.NoError(t, err)
   197  			vol, err := csiDecodeVolume(ast)
   198  			if c.err == "" {
   199  				require.NoError(t, err)
   200  			} else {
   201  				require.Contains(t, err.Error(), c.err)
   202  			}
   203  			require.Equal(t, c.expected, vol)
   204  
   205  		})
   206  
   207  	}
   208  }