github.com/anth0d/nomad@v0.0.0-20221214183521-ae3a0a2cad06/command/volume_register_test.go (about)

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