From 6f03667ddf3d4a89dc90257ed1c44e67b65ce20d Mon Sep 17 00:00:00 2001 From: Prajwal V <91181612+prajwalv-netapp@users.noreply.github.com> Date: Fri, 29 Sep 2023 18:33:30 +0530 Subject: [PATCH] Changes for Kerberos support in ANF --- .../mock_azure/mock_api.go | 8 +- storage_drivers/azure/api/azure.go | 63 +- storage_drivers/azure/api/azure_structs.go | 28 +- storage_drivers/azure/api/types.go | 2 +- storage_drivers/azure/azure_anf.go | 121 +- .../azure/azure_anf_subvolume_test.go | 4 +- storage_drivers/azure/azure_anf_test.go | 1035 ++++++++++++++--- storage_drivers/types.go | 1 + 8 files changed, 1084 insertions(+), 178 deletions(-) diff --git a/mocks/mock_storage_drivers/mock_azure/mock_api.go b/mocks/mock_storage_drivers/mock_azure/mock_api.go index 005c123e2..129ac67cf 100644 --- a/mocks/mock_storage_drivers/mock_azure/mock_api.go +++ b/mocks/mock_storage_drivers/mock_azure/mock_api.go @@ -258,17 +258,17 @@ func (mr *MockAzureMockRecorder) Init(arg0, arg1 interface{}) *gomock.Call { } // ModifyVolume mocks base method. -func (m *MockAzure) ModifyVolume(arg0 context.Context, arg1 *api.FileSystem, arg2 map[string]string, arg3 *string, arg4 *bool) error { +func (m *MockAzure) ModifyVolume(arg0 context.Context, arg1 *api.FileSystem, arg2 map[string]string, arg3 *string, arg4 *bool, arg5 *api.ExportRule) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ModifyVolume", arg0, arg1, arg2, arg3, arg4) + ret := m.ctrl.Call(m, "ModifyVolume", arg0, arg1, arg2, arg3, arg4, arg5) ret0, _ := ret[0].(error) return ret0 } // ModifyVolume indicates an expected call of ModifyVolume. -func (mr *MockAzureMockRecorder) ModifyVolume(arg0, arg1, arg2, arg3, arg4 interface{}) *gomock.Call { +func (mr *MockAzureMockRecorder) ModifyVolume(arg0, arg1, arg2, arg3, arg4, arg5 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ModifyVolume", reflect.TypeOf((*MockAzure)(nil).ModifyVolume), arg0, arg1, arg2, arg3, arg4) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ModifyVolume", reflect.TypeOf((*MockAzure)(nil).ModifyVolume), arg0, arg1, arg2, arg3, arg4, arg5) } // RandomSubnetForStoragePool mocks base method. diff --git a/storage_drivers/azure/api/azure.go b/storage_drivers/azure/api/azure.go index da7d9aa34..f36215731 100644 --- a/storage_drivers/azure/api/azure.go +++ b/storage_drivers/azure/api/azure.go @@ -505,15 +505,27 @@ func exportPolicyExport(exportPolicy *ExportPolicy) *netapp.VolumePropertiesExpo nfsv3 := rule.Nfsv3 nfsv41 := rule.Nfsv41 allowedClients := rule.AllowedClients + kerberos5ReadOnly := rule.Kerberos5ReadOnly + kerberos5ReadWrite := rule.Kerberos5ReadWrite + kerberos5IReadOnly := rule.Kerberos5IReadOnly + kerberos5IReadWrite := rule.Kerberos5IReadWrite + kerberos5PReadOnly := rule.Kerberos5PReadOnly + kerberos5PReadWrite := rule.Kerberos5PReadWrite anfRule := netapp.ExportPolicyRule{ - RuleIndex: &ruleIndex, - UnixReadOnly: &unixReadOnly, - UnixReadWrite: &unixReadWrite, - Cifs: &cifs, - Nfsv3: &nfsv3, - Nfsv41: &nfsv41, - AllowedClients: &allowedClients, + RuleIndex: &ruleIndex, + UnixReadOnly: &unixReadOnly, + UnixReadWrite: &unixReadWrite, + Cifs: &cifs, + Nfsv3: &nfsv3, + Nfsv41: &nfsv41, + AllowedClients: &allowedClients, + Kerberos5ReadOnly: &kerberos5ReadOnly, + Kerberos5ReadWrite: &kerberos5ReadWrite, + Kerberos5IReadOnly: &kerberos5IReadOnly, + Kerberos5IReadWrite: &kerberos5IReadWrite, + Kerberos5PReadOnly: &kerberos5PReadOnly, + Kerberos5PReadWrite: &kerberos5PReadWrite, } anfRules = append(anfRules, &anfRule) @@ -535,13 +547,19 @@ func exportPolicyImport(anfExportPolicy *netapp.VolumePropertiesExportPolicy) *E for _, anfRule := range anfExportPolicy.Rules { rule := ExportRule{ - RuleIndex: DerefInt32(anfRule.RuleIndex), - UnixReadOnly: DerefBool(anfRule.UnixReadOnly), - UnixReadWrite: DerefBool(anfRule.UnixReadWrite), - Cifs: DerefBool(anfRule.Cifs), - Nfsv3: DerefBool(anfRule.Nfsv3), - Nfsv41: DerefBool(anfRule.Nfsv41), - AllowedClients: DerefString(anfRule.AllowedClients), + RuleIndex: DerefInt32(anfRule.RuleIndex), + UnixReadOnly: DerefBool(anfRule.UnixReadOnly), + UnixReadWrite: DerefBool(anfRule.UnixReadWrite), + Cifs: DerefBool(anfRule.Cifs), + Nfsv3: DerefBool(anfRule.Nfsv3), + Nfsv41: DerefBool(anfRule.Nfsv41), + AllowedClients: DerefString(anfRule.AllowedClients), + Kerberos5ReadOnly: DerefBool(anfRule.Kerberos5ReadOnly), + Kerberos5ReadWrite: DerefBool(anfRule.Kerberos5ReadWrite), + Kerberos5IReadOnly: DerefBool(anfRule.Kerberos5IReadOnly), + Kerberos5IReadWrite: DerefBool(anfRule.Kerberos5IReadWrite), + Kerberos5PReadOnly: DerefBool(anfRule.Kerberos5PReadOnly), + Kerberos5PReadWrite: DerefBool(anfRule.Kerberos5PReadWrite), } rules = append(rules, rule) @@ -598,6 +616,7 @@ func (c Client) newFileSystemFromVolume(ctx context.Context, vol *netapp.Volume) MountTargets: c.getMountTargetsFromVolume(ctx, vol), SubvolumesEnabled: c.getSubvolumesEnabledFromVolume(vol.Properties.EnableSubvolumes), NetworkFeatures: DerefNetworkFeatures(vol.Properties.NetworkFeatures), + KerberosEnabled: DerefBool(vol.Properties.KerberosEnabled), }, nil } @@ -624,7 +643,7 @@ func (c Client) getMountTargetsFromVolume(ctx context.Context, vol *netapp.Volum MountTargetID: DerefString(mtp.MountTargetID), FileSystemID: DerefString(mtp.FileSystemID), IPAddress: DerefString(mtp.IPAddress), - SmbServerFqdn: DerefString(mtp.SmbServerFqdn), + ServerFqdn: DerefString(mtp.SmbServerFqdn), } mounts = append(mounts, mt) @@ -940,6 +959,7 @@ func (c Client) CreateVolume(ctx context.Context, request *FilesystemCreateReque SubnetID: &request.SubnetID, SnapshotDirectoryVisible: &request.SnapshotDirectory, NetworkFeatures: &networkFeatures, + KerberosEnabled: &request.KerberosEnabled, }, } @@ -994,7 +1014,7 @@ func (c Client) CreateVolume(ctx context.Context, request *FilesystemCreateReque // ModifyVolume updates attributes of a volume. func (c Client) ModifyVolume( - ctx context.Context, filesystem *FileSystem, labels map[string]string, unixPermissions *string, snapshotDirAccess *bool, + ctx context.Context, filesystem *FileSystem, labels map[string]string, unixPermissions *string, snapshotDirAccess *bool, exportRule *ExportRule, ) error { logFields := LogFields{ "API": "VolumesClient.Get", @@ -1045,12 +1065,19 @@ func (c Client) ModifyVolume( anfVolume.Properties.SnapshotDirectoryVisible = snapshotDirAccess } + // Modify the export-rule to restrict the kerberos protocol type + anfVolume.Properties.ExportPolicy.Rules[0].Nfsv41 = &exportRule.Nfsv41 + anfVolume.Properties.ExportPolicy.Rules[0].Kerberos5ReadWrite = &exportRule.Kerberos5ReadWrite + anfVolume.Properties.ExportPolicy.Rules[0].Kerberos5ReadOnly = &exportRule.Kerberos5ReadOnly + anfVolume.Properties.ExportPolicy.Rules[0].Kerberos5IReadWrite = &exportRule.Kerberos5IReadWrite + anfVolume.Properties.ExportPolicy.Rules[0].Kerberos5IReadOnly = &exportRule.Kerberos5IReadOnly + anfVolume.Properties.ExportPolicy.Rules[0].Kerberos5PReadWrite = &exportRule.Kerberos5PReadWrite + anfVolume.Properties.ExportPolicy.Rules[0].Kerberos5PReadOnly = &exportRule.Kerberos5PReadOnly + // Clear out ReadOnly and other fields that we don't want to change when merely relabeling. serviceLevel := netapp.ServiceLevel("") anfVolume.Properties.ServiceLevel = &serviceLevel anfVolume.Properties.ProvisioningState = nil - anfVolume.Properties.ExportPolicy = nil - anfVolume.Properties.ProtocolTypes = nil anfVolume.Properties.MountTargets = nil anfVolume.Properties.ThroughputMibps = nil anfVolume.Properties.BaremetalTenantID = nil diff --git a/storage_drivers/azure/api/azure_structs.go b/storage_drivers/azure/api/azure_structs.go index 5c986671c..0da4119c4 100644 --- a/storage_drivers/azure/api/azure_structs.go +++ b/storage_drivers/azure/api/azure_structs.go @@ -23,6 +23,10 @@ const ( ProtocolTypeNFSv41 = ProtocolTypeNFSPrefix + "4.1" ProtocolTypeCIFS = "CIFS" + MountOptionKerberos5 = "sec=krb5" + MountOptionKerberos5I = "sec=krb5i" + MountOptionKerberos5P = "sec=krb5p" + ServiceLevelStandard = "Standard" ServiceLevelPremium = "Premium" ServiceLevelUltra = "Ultra" @@ -126,6 +130,7 @@ type FileSystem struct { MountTargets []MountTarget SubvolumesEnabled bool NetworkFeatures string + KerberosEnabled bool } // FilesystemCreateRequest embodies all the details of a volume to be created. @@ -144,6 +149,7 @@ type FilesystemCreateRequest struct { SnapshotID string UnixPermissions string NetworkFeatures string + KerberosEnabled bool } // ExportPolicy records details of a discovered Azure volume export policy. @@ -153,13 +159,19 @@ type ExportPolicy struct { // ExportRule records details of a discovered Azure volume export policy rule. type ExportRule struct { - AllowedClients string - Cifs bool - Nfsv3 bool - Nfsv41 bool - RuleIndex int32 - UnixReadOnly bool - UnixReadWrite bool + AllowedClients string + Cifs bool + Nfsv3 bool + Nfsv41 bool + RuleIndex int32 + UnixReadOnly bool + UnixReadWrite bool + Kerberos5ReadOnly bool + Kerberos5ReadWrite bool + Kerberos5IReadOnly bool + Kerberos5IReadWrite bool + Kerberos5PReadOnly bool + Kerberos5PReadWrite bool } // MountTarget records details of a discovered Azure volume mount target. @@ -167,7 +179,7 @@ type MountTarget struct { MountTargetID string FileSystemID string IPAddress string - SmbServerFqdn string + ServerFqdn string } // Snapshot records details of a discovered Azure snapshot. diff --git a/storage_drivers/azure/api/types.go b/storage_drivers/azure/api/types.go index ccb050c6d..0d7bd4574 100644 --- a/storage_drivers/azure/api/types.go +++ b/storage_drivers/azure/api/types.go @@ -35,7 +35,7 @@ type Azure interface { VolumeExistsByID(context.Context, string) (bool, *FileSystem, error) WaitForVolumeState(context.Context, *FileSystem, string, []string, time.Duration) (string, error) CreateVolume(context.Context, *FilesystemCreateRequest) (*FileSystem, error) - ModifyVolume(context.Context, *FileSystem, map[string]string, *string, *bool) error + ModifyVolume(context.Context, *FileSystem, map[string]string, *string, *bool, *ExportRule) error ResizeVolume(context.Context, *FileSystem, int64) error DeleteVolume(context.Context, *FileSystem) error diff --git a/storage_drivers/azure/azure_anf.go b/storage_drivers/azure/azure_anf.go index f930953c7..e996eafa8 100644 --- a/storage_drivers/azure/azure_anf.go +++ b/storage_drivers/azure/azure_anf.go @@ -31,13 +31,14 @@ const ( MinimumVolumeSizeBytes = uint64(1000000000) // 1 GB MinimumANFVolumeSizeBytes = uint64(107374182400) // 100 GiB - defaultUnixPermissions = "" // TODO (cknight): change to "0777" when whitelisted permissions feature reaches GA - defaultNfsMountOptions = "nfsvers=3" - defaultSnapshotDir = "false" - defaultLimitVolumeSize = "" - defaultExportRule = "0.0.0.0/0" - defaultVolumeSizeStr = "107374182400" - defaultNetworkFeatures = "" // Leave empty, some regions may never support this + defaultUnixPermissions = "" // TODO (cknight): change to "0777" when whitelisted permissions feature reaches GA + defaultNfsMountOptions = "nfsvers=3" + defaultKerberosNfsMountOptions = "nfsvers=4.1" + defaultSnapshotDir = "false" + defaultLimitVolumeSize = "" + defaultExportRule = "0.0.0.0/0" + defaultVolumeSizeStr = "107374182400" + defaultNetworkFeatures = "" // Leave empty, some regions may never support this // Constants for internal pool attributes @@ -53,6 +54,7 @@ const ( NetappAccounts = "netappAccounts" CapacityPools = "capacityPools" FilePoolVolumes = "filePoolVolumes" + Kerberos = "kerberos" nfsVersion3 = "3" nfsVersion4 = "4" @@ -258,7 +260,11 @@ func (d *NASStorageDriver) populateConfigurationDefaults( } if config.NfsMountOptions == "" { - config.NfsMountOptions = defaultNfsMountOptions + if config.Kerberos != "" { + config.NfsMountOptions = defaultKerberosNfsMountOptions + } else { + config.NfsMountOptions = defaultNfsMountOptions + } } if config.SnapshotDir == "" { @@ -332,6 +338,7 @@ func (d *NASStorageDriver) initializeStoragePools(ctx context.Context) { pool.InternalAttributes()[ResourceGroups] = strings.Join(d.Config.ResourceGroups, ",") pool.InternalAttributes()[NetappAccounts] = strings.Join(d.Config.NetappAccounts, ",") pool.InternalAttributes()[CapacityPools] = strings.Join(d.Config.CapacityPools, ",") + pool.InternalAttributes()[Kerberos] = d.Config.Kerberos pool.SetSupportedTopologies(d.Config.SupportedTopologies) @@ -413,6 +420,11 @@ func (d *NASStorageDriver) initializeStoragePools(ctx context.Context) { subnet = vpool.Subnet } + kerberos := d.Config.Kerberos + if vpool.Kerberos != "" { + kerberos = vpool.Kerberos + } + pool := storage.NewStoragePool(nil, d.poolName(fmt.Sprintf("pool_%d", index))) pool.Attributes()[sa.BackendType] = sa.NewStringOffer(d.Name()) @@ -447,6 +459,7 @@ func (d *NASStorageDriver) initializeStoragePools(ctx context.Context) { pool.InternalAttributes()[ResourceGroups] = strings.Join(resourceGroups, ",") pool.InternalAttributes()[NetappAccounts] = strings.Join(netappAccounts, ",") pool.InternalAttributes()[CapacityPools] = strings.Join(capacityPools, ",") + pool.InternalAttributes()[Kerberos] = kerberos pool.SetSupportedTopologies(supportedTopologies) @@ -620,6 +633,10 @@ func (d *NASStorageDriver) validate(ctx context.Context) error { default: return fmt.Errorf("invalid value for networkFeatures in pool %s", poolName) } + + if pool.InternalAttributes()[Kerberos] != "" && tridentconfig.DisableExtraFeatures { + return fmt.Errorf("kerberos support is not enabled ") + } } return nil @@ -748,12 +765,27 @@ func (d *NASStorageDriver) Create( mountOptions = volConfig.MountOptions } + // Take kerberos option from backend config first, then from pool + kerberos := d.Config.Kerberos + if kerberos == "" { + kerberos = pool.InternalAttributes()[Kerberos] + } + // Determine protocol from mount options var protocolTypes []string - var cifsAccess, nfsV3Access, nfsV41Access bool + var cifsAccess, nfsV3Access, nfsV41Access, kerberosEnabled bool var apiExportRule api.ExportRule var exportPolicy api.ExportPolicy + switch kerberos { + case api.MountOptionKerberos5, api.MountOptionKerberos5I, api.MountOptionKerberos5P: + kerberosEnabled = true + case "": + kerberosEnabled = false + default: + return fmt.Errorf("unsupported kerberos type: %s", kerberos) + } + if d.Config.NASType == sa.SMB { protocolTypes = []string{api.ProtocolTypeCIFS} } else { @@ -781,6 +813,24 @@ func (d *NASStorageDriver) Create( UnixReadOnly: false, UnixReadWrite: true, } + + if kerberosEnabled { + protocolTypes = []string{api.ProtocolTypeNFSv41} + apiExportRule.Nfsv3 = false + apiExportRule.Nfsv41 = true + apiExportRule.UnixReadOnly = false + apiExportRule.UnixReadWrite = false + + switch kerberos { + case api.MountOptionKerberos5: + apiExportRule.Kerberos5ReadWrite = true + case api.MountOptionKerberos5I: + apiExportRule.Kerberos5IReadWrite = true + case api.MountOptionKerberos5P: + apiExportRule.Kerberos5PReadWrite = true + } + } + exportPolicy = api.ExportPolicy{ Rules: []api.ExportRule{apiExportRule}, } @@ -856,6 +906,7 @@ func (d *NASStorageDriver) Create( QuotaInBytes: int64(sizeBytes), SnapshotDirectory: snapshotDirBool, NetworkFeatures: networkFeatures, + KerberosEnabled: kerberosEnabled, } // Add unix permissions and export policy fields only to NFS volume @@ -1056,6 +1107,7 @@ func (d *NASStorageDriver) CreateClone( if d.Config.NASType == sa.NFS { createRequest.ExportPolicy = sourceVolume.ExportPolicy createRequest.UnixPermissions = sourceVolume.UnixPermissions + createRequest.KerberosEnabled = sourceVolume.KerberosEnabled } // Clone the volume @@ -1126,6 +1178,38 @@ func (d *NASStorageDriver) Import(ctx context.Context, volConfig *storage.Volume } } + // Check for kerberos option from backend config first, then from pool + kerberos := d.Config.Kerberos + if kerberos == "" { + for _, pool := range d.pools { + // Update the first successful match, if there's more than one pool + if kerberos = pool.InternalAttributes()[Kerberos]; kerberos != "" { + break + } + } + } + + if kerberos != "" && !volume.KerberosEnabled { + return fmt.Errorf("could not import non-kerberos volume '%s', on a kerberos enabled backend", originalName) + } + + if kerberos == "" && volume.KerberosEnabled { + return fmt.Errorf("could not import kerberos volume '%s', on a non-kerberos enabled backend", originalName) + } + + modifiedExportRule := api.ExportRule{} + switch kerberos { + case api.MountOptionKerberos5: + modifiedExportRule.Nfsv41 = true + modifiedExportRule.Kerberos5ReadWrite = true + case api.MountOptionKerberos5I: + modifiedExportRule.Nfsv41 = true + modifiedExportRule.Kerberos5IReadWrite = true + case api.MountOptionKerberos5P: + modifiedExportRule.Nfsv41 = true + modifiedExportRule.Kerberos5PReadWrite = true + } + // Update the volume labels if storage.AllowPoolLabelOverwrite(storage.ProvisioningLabelTag, volume.Labels[storage.ProvisioningLabelTag]) { volume.Labels[storage.ProvisioningLabelTag] = "" @@ -1133,7 +1217,7 @@ func (d *NASStorageDriver) Import(ctx context.Context, volConfig *storage.Volume labels := d.updateTelemetryLabels(ctx, volume) if d.Config.NASType == sa.SMB && volume.ProtocolTypes[0] == api.ProtocolTypeCIFS { - if err = d.SDK.ModifyVolume(ctx, volume, labels, nil, &snapshotDirAccess); err != nil { + if err = d.SDK.ModifyVolume(ctx, volume, labels, nil, &snapshotDirAccess, &modifiedExportRule); err != nil { Logc(ctx).WithField("originalName", originalName).WithError(err).Error( "Could not import volume, volume modify failed.") return fmt.Errorf("could not import volume %s, volume modify failed; %v", originalName, err) @@ -1161,7 +1245,8 @@ func (d *NASStorageDriver) Import(ctx context.Context, volConfig *storage.Volume return fmt.Errorf("could not import volume %s; %v", originalName, err) } } - if err = d.SDK.ModifyVolume(ctx, volume, labels, &unixPermissions, &snapshotDirAccess); err != nil { + + if err = d.SDK.ModifyVolume(ctx, volume, labels, &unixPermissions, &snapshotDirAccess, &modifiedExportRule); err != nil { Logc(ctx).WithField("originalName", originalName).WithError(err).Error( "Could not import volume, volume modify failed.") return fmt.Errorf("could not import volume %s, volume modify failed; %v", originalName, err) @@ -1377,7 +1462,7 @@ func (d *NASStorageDriver) Publish( // Add required fields for attaching SMB volume if d.Config.NASType == sa.SMB { publishInfo.SMBPath = volConfig.AccessInfo.SMBPath - publishInfo.SMBServer = (volume.MountTargets)[0].SmbServerFqdn + publishInfo.SMBServer = (volume.MountTargets)[0].ServerFqdn publishInfo.FilesystemType = sa.SMB } else { // Add fields needed by Attach @@ -1387,6 +1472,11 @@ func (d *NASStorageDriver) Publish( publishInfo.MountOptions = mountOptions } + // Replace server IP with FQDN for kerberos volume + if volume.KerberosEnabled { + publishInfo.NfsServerIP = (volume.MountTargets)[0].ServerFqdn + } + return nil } @@ -1887,7 +1977,7 @@ func (d *NASStorageDriver) CreateFollowup(ctx context.Context, volConfig *storag // Set the mount target based on the NASType if d.Config.NASType == sa.SMB { volConfig.AccessInfo.SMBPath = constructVolumeAccessPath(volConfig, volume, sa.SMB) - volConfig.AccessInfo.SMBServer = (volume.MountTargets)[0].SmbServerFqdn + volConfig.AccessInfo.SMBServer = (volume.MountTargets)[0].ServerFqdn volConfig.FileSystem = sa.SMB } else { volConfig.AccessInfo.NfsPath = constructVolumeAccessPath(volConfig, volume, sa.NFS) @@ -1895,6 +1985,11 @@ func (d *NASStorageDriver) CreateFollowup(ctx context.Context, volConfig *storag volConfig.FileSystem = sa.NFS } + // Replace server IP with FQDN for kerberos volume + if volume.KerberosEnabled { + volConfig.AccessInfo.NfsServerIP = (volume.MountTargets)[0].ServerFqdn + } + return nil } diff --git a/storage_drivers/azure/azure_anf_subvolume_test.go b/storage_drivers/azure/azure_anf_subvolume_test.go index 396122465..6de3fd4f2 100644 --- a/storage_drivers/azure/azure_anf_subvolume_test.go +++ b/storage_drivers/azure/azure_anf_subvolume_test.go @@ -2264,7 +2264,7 @@ func getStructsForSubvolumePublish() ( MountTargetID: "mountTargetID", FileSystemID: "filesystemID", IPAddress: "1.1.1.1", - SmbServerFqdn: "", + ServerFqdn: "", }, } @@ -3728,7 +3728,7 @@ func TestSubvolumeCreateFollowUp_MountTarget(t *testing.T) { MountTargetID: "mountTargetID", FileSystemID: "filesystemID", IPAddress: "1.1.1.1", - SmbServerFqdn: "", + ServerFqdn: "", }, } diff --git a/storage_drivers/azure/azure_anf_test.go b/storage_drivers/azure/azure_anf_test.go index 327becfb8..8d97b0e28 100644 --- a/storage_drivers/azure/azure_anf_test.go +++ b/storage_drivers/azure/azure_anf_test.go @@ -812,6 +812,7 @@ func TestInitializeStoragePools_NoVirtualPools(t *testing.T) { pool.InternalAttributes()[ResourceGroups] = "RG1,RG2" pool.InternalAttributes()[NetappAccounts] = "NA1,NA2" pool.InternalAttributes()[CapacityPools] = "CP1,CP2" + pool.InternalAttributes()[Kerberos] = "" pool.SetSupportedTopologies(supportedTopologies) @@ -868,6 +869,7 @@ func TestInitializeStoragePools_VirtualPools(t *testing.T) { Zone: "zone2", SupportedTopologies: supportedTopologies, NASType: "nfs", + Kerberos: "sec=krb5i", }, { AzureNASStorageDriverConfigDefaults: drivers.AzureNASStorageDriverConfigDefaults{ @@ -913,6 +915,7 @@ func TestInitializeStoragePools_VirtualPools(t *testing.T) { pool0.InternalAttributes()[ResourceGroups] = "RG1,RG2" pool0.InternalAttributes()[NetappAccounts] = "NA1,NA2" pool0.InternalAttributes()[CapacityPools] = "CP1" + pool0.InternalAttributes()[Kerberos] = "sec=krb5i" pool0.SetSupportedTopologies(supportedTopologies) @@ -938,6 +941,7 @@ func TestInitializeStoragePools_VirtualPools(t *testing.T) { pool1.InternalAttributes()[ResourceGroups] = "RG1,RG2" pool1.InternalAttributes()[NetappAccounts] = "NA1,NA2" pool1.InternalAttributes()[CapacityPools] = "CP2" + pool1.InternalAttributes()[Kerberos] = "" pool1.SetSupportedTopologies(supportedTopologies) @@ -949,6 +953,92 @@ func TestInitializeStoragePools_VirtualPools(t *testing.T) { assert.Equal(t, expectedPools, driver.pools, "pools do not match") } +func TestInitialize_KerberosDisabledInConfig(t *testing.T) { + commonConfig := &drivers.CommonStorageDriverConfig{ + Version: 1, + StorageDriverName: "azure-netapp-files", + BackendName: "myANFBackend", + DriverContext: tridentconfig.ContextCSI, + DebugTraceFlags: debugTraceFlags, + } + + configJSON := ` + { + "version": 1, + "storageDriverName": "azure-netapp-files", + "location": "fake-location", + "subscriptionID": "deadbeef-173f-4bf4-b5b8-f17f8d2fe43b", + "tenantID": "deadbeef-4746-4444-a919-3b34af5f0a3c", + "clientID": "deadbeef-784c-4b35-8329-460f52a3ad50", + "clientSecret": "myClientSecret", + "serviceLevel": "Premium", + "debugTraceFlags": {"method": true, "api": true, "discovery": true}, + "capacityPools": ["RG1/NA1/CP1", "RG1/NA1/CP2"], + "virtualNetwork": "VN1", + "subnet": "RG1/VN1/SN1", + "volumeCreateTimeout": "600", + "sdkTimeout": "60", + "maxCacheAge": "300", + "kerberos": "sec-krb5" + }` + + mockAPI, driver := newMockANFDriver(t) + tridentconfig.DisableExtraFeatures = true + + mockAPI.EXPECT().Init(ctx, gomock.Any()).Return(nil).Times(1) + + result := driver.Initialize(ctx, tridentconfig.ContextCSI, configJSON, commonConfig, + map[string]string{}, BackendUUID) + + assert.Error(t, result, "initialized") + assert.False(t, driver.Initialized(), "initialized") +} + +func TestInitialize_KerberosDisabledInPool(t *testing.T) { + commonConfig := &drivers.CommonStorageDriverConfig{ + Version: 1, + StorageDriverName: "azure-netapp-files", + BackendName: "myANFBackend", + DriverContext: tridentconfig.ContextCSI, + DebugTraceFlags: debugTraceFlags, + } + + configJSON := ` + { + "version": 1, + "storageDriverName": "azure-netapp-files", + "location": "fake-location", + "subscriptionID": "deadbeef-173f-4bf4-b5b8-f17f8d2fe43b", + "tenantID": "deadbeef-4746-4444-a919-3b34af5f0a3c", + "clientID": "deadbeef-784c-4b35-8329-460f52a3ad50", + "clientSecret": "myClientSecret", + "serviceLevel": "Premium", + "debugTraceFlags": {"method": true, "api": true, "discovery": true}, + "capacityPools": ["RG1/NA1/CP1", "RG1/NA1/CP2"], + "virtualNetwork": "VN1", + "subnet": "RG1/VN1/SN1", + "volumeCreateTimeout": "600", + "sdkTimeout": "60", + "maxCacheAge": "300", + "storage": [{"labels":{"type":"kerb"},"kerberos" : "sec=krb5i"}] + }` + + mockAPI, driver := newMockANFDriver(t) + tridentconfig.DisableExtraFeatures = true + + driver.populateConfigurationDefaults(ctx, &driver.Config) + driver.initializeStoragePools(ctx) + driver.initializeTelemetry(ctx, BackendUUID) + + mockAPI.EXPECT().Init(ctx, gomock.Any()).Return(nil).Times(1) + + result := driver.Initialize(ctx, tridentconfig.ContextCSI, configJSON, commonConfig, + map[string]string{}, BackendUUID) + + assert.Error(t, result, "initialized") + assert.False(t, driver.Initialized(), "initialized") +} + func TestValidate_InvalidServiceLevel(t *testing.T) { _, driver := newMockANFDriver(t) driver.Config.ServiceLevel = "invalid" @@ -1358,6 +1448,192 @@ func TestCreate_NFSVolume_MultipleCapacityPools_NoneSucceeds(t *testing.T) { assert.Equal(t, "", volConfig.InternalID, "internal ID set on volConfig") } +func TestCreate_NFSVolume_Kerberos_type5(t *testing.T) { + mockAPI, driver := newMockANFDriver(t) + driver.Config.BackendName = "anf" + driver.Config.ServiceLevel = api.ServiceLevelUltra + driver.Config.NetworkFeatures = api.NetworkFeaturesStandard + driver.Config.NASType = "nfs" + driver.Config.NfsMountOptions = "" + driver.Config.Kerberos = "sec=krb5" + + driver.populateConfigurationDefaults(ctx, &driver.Config) + driver.initializeStoragePools(ctx) + driver.initializeTelemetry(ctx, BackendUUID) + + storagePool := driver.pools["anf_pool"] + + volConfig, capacityPool, subnet, createRequest, filesystem := getStructsForCreateNFSVolume(ctx, driver, storagePool) + + createRequest.KerberosEnabled = true + createRequest.ExportPolicy.Rules[0].Kerberos5ReadWrite = true + createRequest.ExportPolicy.Rules[0].Nfsv41 = true + createRequest.ExportPolicy.Rules[0].Nfsv3 = false + createRequest.ExportPolicy.Rules[0].UnixReadWrite = false + createRequest.ProtocolTypes = []string{api.ProtocolTypeNFSv41} + createRequest.UnixPermissions = "0777" + createRequest.NetworkFeatures = api.NetworkFeaturesStandard + + filesystem.UnixPermissions = "0777" + filesystem.NetworkFeatures = api.NetworkFeaturesStandard + filesystem.KerberosEnabled = true + filesystem.ProtocolTypes = []string{api.ProtocolTypeNFSv41} + + mockAPI.EXPECT().RefreshAzureResources(ctx).Return(nil).Times(1) + mockAPI.EXPECT().VolumeExists(ctx, volConfig).Return(false, nil, nil).Times(1) + mockAPI.EXPECT().HasFeature(api.FeatureUnixPermissions).Return(true).Times(1) + mockAPI.EXPECT().RandomSubnetForStoragePool(ctx, storagePool).Return(subnet).Times(1) + mockAPI.EXPECT().CapacityPoolsForStoragePool(ctx, storagePool, + api.ServiceLevelUltra).Return([]*api.CapacityPool{capacityPool}).Times(1) + mockAPI.EXPECT().CreateVolume(ctx, createRequest).Return(filesystem, nil).Times(1) + mockAPI.EXPECT().WaitForVolumeState(ctx, filesystem, api.StateAvailable, []string{api.StateError}, + driver.volumeCreateTimeout).Return(api.StateAvailable, nil).Times(1) + + result := driver.Create(ctx, volConfig, storagePool, nil) + + assert.NoError(t, result, "create failed") + assert.Equal(t, createRequest.ProtocolTypes, filesystem.ProtocolTypes, "protocol type mismatch") + assert.Equal(t, filesystem.ID, volConfig.InternalID, "internal ID not set on volConfig") + assert.Equal(t, strconv.FormatInt(createRequest.QuotaInBytes, 10), volConfig.Size, "request size mismatch") + assert.Equal(t, api.ServiceLevelUltra, volConfig.ServiceLevel) + assert.Equal(t, "false", volConfig.SnapshotDir) + assert.Equal(t, "0777", volConfig.UnixPermissions) +} + +func TestCreate_NFSVolume_Kerberos_type5I(t *testing.T) { + mockAPI, driver := newMockANFDriver(t) + driver.Config.BackendName = "anf" + driver.Config.ServiceLevel = api.ServiceLevelUltra + driver.Config.NetworkFeatures = api.NetworkFeaturesStandard + driver.Config.NASType = "nfs" + driver.Config.Kerberos = "sec=krb5i" + + driver.populateConfigurationDefaults(ctx, &driver.Config) + driver.initializeStoragePools(ctx) + driver.initializeTelemetry(ctx, BackendUUID) + + storagePool := driver.pools["anf_pool"] + + volConfig, capacityPool, subnet, createRequest, filesystem := getStructsForCreateNFSVolume(ctx, driver, storagePool) + + createRequest.KerberosEnabled = true + createRequest.ExportPolicy.Rules[0].Kerberos5IReadWrite = true + createRequest.ExportPolicy.Rules[0].Nfsv41 = true + createRequest.ExportPolicy.Rules[0].Nfsv3 = false + createRequest.ExportPolicy.Rules[0].UnixReadWrite = false + createRequest.ProtocolTypes = []string{api.ProtocolTypeNFSv41} + createRequest.UnixPermissions = "0777" + createRequest.NetworkFeatures = api.NetworkFeaturesStandard + + filesystem.UnixPermissions = "0777" + filesystem.NetworkFeatures = api.NetworkFeaturesStandard + filesystem.KerberosEnabled = true + filesystem.ProtocolTypes = []string{api.ProtocolTypeNFSv41} + + mockAPI.EXPECT().RefreshAzureResources(ctx).Return(nil).Times(1) + mockAPI.EXPECT().VolumeExists(ctx, volConfig).Return(false, nil, nil).Times(1) + mockAPI.EXPECT().HasFeature(api.FeatureUnixPermissions).Return(true).Times(1) + mockAPI.EXPECT().RandomSubnetForStoragePool(ctx, storagePool).Return(subnet).Times(1) + mockAPI.EXPECT().CapacityPoolsForStoragePool(ctx, storagePool, + api.ServiceLevelUltra).Return([]*api.CapacityPool{capacityPool}).Times(1) + mockAPI.EXPECT().CreateVolume(ctx, createRequest).Return(filesystem, nil).Times(1) + mockAPI.EXPECT().WaitForVolumeState(ctx, filesystem, api.StateAvailable, []string{api.StateError}, + driver.volumeCreateTimeout).Return(api.StateAvailable, nil).Times(1) + + result := driver.Create(ctx, volConfig, storagePool, nil) + + assert.NoError(t, result, "create failed") + assert.Equal(t, createRequest.ProtocolTypes, filesystem.ProtocolTypes, "protocol type mismatch") + assert.Equal(t, filesystem.ID, volConfig.InternalID, "internal ID not set on volConfig") + assert.Equal(t, strconv.FormatInt(createRequest.QuotaInBytes, 10), volConfig.Size, "request size mismatch") + assert.Equal(t, api.ServiceLevelUltra, volConfig.ServiceLevel) + assert.Equal(t, "false", volConfig.SnapshotDir) + assert.Equal(t, "0777", volConfig.UnixPermissions) +} + +func TestCreate_NFSVolume_Kerberos_type5P(t *testing.T) { + mockAPI, driver := newMockANFDriver(t) + driver.Config.BackendName = "anf" + driver.Config.ServiceLevel = api.ServiceLevelUltra + driver.Config.NetworkFeatures = api.NetworkFeaturesStandard + driver.Config.NASType = "nfs" + driver.Config.Kerberos = "sec=krb5p" + + driver.populateConfigurationDefaults(ctx, &driver.Config) + driver.initializeStoragePools(ctx) + driver.initializeTelemetry(ctx, BackendUUID) + + storagePool := driver.pools["anf_pool"] + + volConfig, capacityPool, subnet, createRequest, filesystem := getStructsForCreateNFSVolume(ctx, driver, storagePool) + + createRequest.KerberosEnabled = true + createRequest.ExportPolicy.Rules[0].Kerberos5PReadWrite = true + createRequest.ExportPolicy.Rules[0].Nfsv41 = true + createRequest.ExportPolicy.Rules[0].Nfsv3 = false + createRequest.ExportPolicy.Rules[0].UnixReadWrite = false + createRequest.ProtocolTypes = []string{api.ProtocolTypeNFSv41} + createRequest.UnixPermissions = "0777" + createRequest.NetworkFeatures = api.NetworkFeaturesStandard + + filesystem.UnixPermissions = "0777" + filesystem.NetworkFeatures = api.NetworkFeaturesStandard + filesystem.KerberosEnabled = true + filesystem.ProtocolTypes = []string{api.ProtocolTypeNFSv41} + + mockAPI.EXPECT().RefreshAzureResources(ctx).Return(nil).Times(1) + mockAPI.EXPECT().VolumeExists(ctx, volConfig).Return(false, nil, nil).Times(1) + mockAPI.EXPECT().HasFeature(api.FeatureUnixPermissions).Return(true).Times(1) + mockAPI.EXPECT().RandomSubnetForStoragePool(ctx, storagePool).Return(subnet).Times(1) + mockAPI.EXPECT().CapacityPoolsForStoragePool(ctx, storagePool, + api.ServiceLevelUltra).Return([]*api.CapacityPool{capacityPool}).Times(1) + mockAPI.EXPECT().CreateVolume(ctx, createRequest).Return(filesystem, nil).Times(1) + mockAPI.EXPECT().WaitForVolumeState(ctx, filesystem, api.StateAvailable, []string{api.StateError}, + driver.volumeCreateTimeout).Return(api.StateAvailable, nil).Times(1) + + result := driver.Create(ctx, volConfig, storagePool, nil) + + assert.NoError(t, result, "create failed") + assert.Equal(t, createRequest.ProtocolTypes, filesystem.ProtocolTypes, "protocol type mismatch") + assert.Equal(t, filesystem.ID, volConfig.InternalID, "internal ID not set on volConfig") + assert.Equal(t, strconv.FormatInt(createRequest.QuotaInBytes, 10), volConfig.Size, "request size mismatch") + assert.Equal(t, api.ServiceLevelUltra, volConfig.ServiceLevel) + assert.Equal(t, "false", volConfig.SnapshotDir) + assert.Equal(t, "0777", volConfig.UnixPermissions) +} + +func TestCreate_NFSVolume_Kerberos_type5P_failure(t *testing.T) { + mockAPI, driver := newMockANFDriver(t) + driver.Config.BackendName = "anf" + driver.Config.ServiceLevel = api.ServiceLevelUltra + driver.Config.NetworkFeatures = api.NetworkFeaturesStandard + driver.Config.NASType = "nfs" + driver.Config.Kerberos = "sec=krb5P" + + driver.populateConfigurationDefaults(ctx, &driver.Config) + driver.initializeStoragePools(ctx) + driver.initializeTelemetry(ctx, BackendUUID) + + storagePool := driver.pools["anf_pool"] + + volConfig, _, _, createRequest, filesystem := getStructsForCreateNFSVolume(ctx, driver, storagePool) + + createRequest.UnixPermissions = "0777" + createRequest.NetworkFeatures = api.NetworkFeaturesStandard + + filesystem.UnixPermissions = "0777" + filesystem.NetworkFeatures = api.NetworkFeaturesStandard + + mockAPI.EXPECT().RefreshAzureResources(ctx).Return(nil).Times(1) + mockAPI.EXPECT().VolumeExists(ctx, volConfig).Return(false, nil, nil).Times(1) + mockAPI.EXPECT().HasFeature(api.FeatureUnixPermissions).Return(true).Times(1) + + result := driver.Create(ctx, volConfig, storagePool, nil) + + assert.Error(t, result, "unsupported kerberos type: sec=krb5P", "create succeeded") + assert.NotNil(t, result, "expected nil") +} + func TestCreate_DiscoveryFailed(t *testing.T) { mockAPI, driver := newMockANFDriver(t) driver.Config.BackendName = "anf" @@ -2673,13 +2949,407 @@ func TestCreateClone_SnapshotRefetchFailed(t *testing.T) { api.SnapshotTimeout).Return(nil).Times(1) mockAPI.EXPECT().SnapshotForVolume(ctx, sourceFilesystem, gomock.Any()).Return(nil, errFailed).Times(1) - result := driver.CreateClone(ctx, sourceVolConfig, cloneVolConfig, nil) + result := driver.CreateClone(ctx, sourceVolConfig, cloneVolConfig, nil) + + assert.Error(t, result, "expected error") + assert.Equal(t, "", cloneVolConfig.InternalID, "internal ID set on volConfig") +} + +func TestCreateClone_InvalidLabel(t *testing.T) { + mockAPI, driver := newMockANFDriver(t) + driver.Config.BackendName = "anf" + driver.Config.ServiceLevel = api.ServiceLevelUltra + + driver.populateConfigurationDefaults(ctx, &driver.Config) + driver.initializeStoragePools(ctx) + driver.initializeTelemetry(ctx, BackendUUID) + driver.Config.Labels = map[string]string{ + "key1": "1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890", + "key2": "1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890", + "key3": "1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890", + } + + storagePool := driver.pools["anf_pool"] + + sourceVolConfig, cloneVolConfig, _, sourceFilesystem, cloneFilesystem, snapshot := getStructsForCreateClone(ctx, + driver, storagePool) + + mockAPI.EXPECT().RefreshAzureResources(ctx).Return(nil).Times(1) + mockAPI.EXPECT().Volume(ctx, sourceVolConfig).Return(sourceFilesystem, nil).Times(1) + mockAPI.EXPECT().VolumeExistsByID(ctx, cloneFilesystem.ID).Return(false, nil, nil).Times(1) + mockAPI.EXPECT().CreateSnapshot(ctx, sourceFilesystem, gomock.Any()).Return(snapshot, nil).Times(1) + mockAPI.EXPECT().WaitForSnapshotState(ctx, snapshot, sourceFilesystem, api.StateAvailable, []string{api.StateError}, + api.SnapshotTimeout).Return(nil).Times(1) + mockAPI.EXPECT().SnapshotForVolume(ctx, sourceFilesystem, gomock.Any()).Return(snapshot, nil).Times(1) + + result := driver.CreateClone(ctx, sourceVolConfig, cloneVolConfig, nil) + + assert.Error(t, result, "expected error") + assert.Equal(t, "", cloneVolConfig.InternalID, "internal ID set on volConfig") +} + +func TestCreateClone_CreateFailed(t *testing.T) { + mockAPI, driver := newMockANFDriver(t) + driver.Config.BackendName = "anf" + driver.Config.ServiceLevel = api.ServiceLevelUltra + driver.Config.NASType = "nfs" + + driver.populateConfigurationDefaults(ctx, &driver.Config) + driver.initializeStoragePools(ctx) + driver.initializeTelemetry(ctx, BackendUUID) + + storagePool := driver.pools["anf_pool"] + + sourceVolConfig, cloneVolConfig, createRequest, sourceFilesystem, cloneFilesystem, snapshot := getStructsForCreateClone(ctx, + driver, storagePool) + sourceVolConfig.SnapshotDir = "false" + + mockAPI.EXPECT().RefreshAzureResources(ctx).Return(nil).Times(1) + mockAPI.EXPECT().Volume(ctx, sourceVolConfig).Return(sourceFilesystem, nil).Times(1) + mockAPI.EXPECT().VolumeExistsByID(ctx, cloneFilesystem.ID).Return(false, nil, nil).Times(1) + mockAPI.EXPECT().CreateSnapshot(ctx, sourceFilesystem, gomock.Any()).Return(snapshot, nil).Times(1) + mockAPI.EXPECT().WaitForSnapshotState(ctx, snapshot, sourceFilesystem, api.StateAvailable, []string{api.StateError}, + api.SnapshotTimeout).Return(nil).Times(1) + mockAPI.EXPECT().SnapshotForVolume(ctx, sourceFilesystem, gomock.Any()).Return(snapshot, nil).Times(1) + mockAPI.EXPECT().CreateVolume(ctx, createRequest).Return(nil, errFailed).Times(1) + + result := driver.CreateClone(ctx, sourceVolConfig, cloneVolConfig, nil) + + assert.Error(t, result, "expected error") + assert.Equal(t, "", cloneVolConfig.InternalID, "internal ID set on volConfig") +} + +func getStructsForImport(ctx context.Context, driver *NASStorageDriver) (*storage.VolumeConfig, *api.FileSystem) { + subnetID := api.CreateSubnetID(SubscriptionID, "RG2", "VN1", "SN1") + + volConfig := &storage.VolumeConfig{ + Version: "1", + Name: "testvol1", + InternalName: "trident-testvol1", + } + + volumeID := api.CreateVolumeID(SubscriptionID, "RG1", "NA1", "CP1", "importMe") + + apiExportRule := api.ExportRule{ + AllowedClients: defaultExportRule, + Cifs: false, + Nfsv3: false, + Nfsv41: false, + RuleIndex: 1, + UnixReadOnly: false, + UnixReadWrite: false, + Kerberos5ReadWrite: false, + Kerberos5PReadWrite: false, + Kerberos5IReadWrite: false, + } + + labels := make(map[string]string) + labels[drivers.TridentLabelTag] = driver.getTelemetryLabels(ctx) + labels[storage.ProvisioningLabelTag] = "" + + originalFilesystem := &api.FileSystem{ + ID: volumeID, + ResourceGroup: "RG1", + NetAppAccount: "NA1", + CapacityPool: "CP1", + Name: "importMe", + FullName: "RG1/NA1/CP1/importMe", + Location: Location, + Labels: make(map[string]string), + ProvisioningState: api.StateAvailable, + CreationToken: "importMe", + ProtocolTypes: []string{api.ProtocolTypeNFSv3}, + QuotaInBytes: VolumeSizeI64, + ServiceLevel: api.ServiceLevelUltra, + SnapshotDirectory: true, + SubnetID: subnetID, + UnixPermissions: defaultUnixPermissions, + ExportPolicy: api.ExportPolicy{Rules: []api.ExportRule{apiExportRule}}, + } + + return volConfig, originalFilesystem +} + +func getStructsForSMBImport(ctx context.Context, driver *NASStorageDriver) (*storage.VolumeConfig, *api.FileSystem) { + subnetID := api.CreateSubnetID(SubscriptionID, "RG2", "VN1", "SN1") + + volConfig := &storage.VolumeConfig{ + Version: "1", + Name: "testvol1", + InternalName: "trident-testvol1", + } + + volumeID := api.CreateVolumeID(SubscriptionID, "RG1", "NA1", "CP1", "importMe") + + labels := make(map[string]string) + labels[drivers.TridentLabelTag] = driver.getTelemetryLabels(ctx) + labels[storage.ProvisioningLabelTag] = "" + + originalFilesystem := &api.FileSystem{ + ID: volumeID, + ResourceGroup: "RG1", + NetAppAccount: "NA1", + CapacityPool: "CP1", + Name: "importMe", + FullName: "RG1/NA1/CP1/importMe", + Location: Location, + Labels: make(map[string]string), + ProvisioningState: api.StateAvailable, + CreationToken: "importMe", + ProtocolTypes: []string{api.ProtocolTypeCIFS}, + QuotaInBytes: VolumeSizeI64, + ServiceLevel: api.ServiceLevelUltra, + SnapshotDirectory: true, + SubnetID: subnetID, + } + + return volConfig, originalFilesystem +} + +func TestImport_Managed(t *testing.T) { + mockAPI, driver := newMockANFDriver(t) + driver.Config.BackendName = "anf" + driver.Config.ServiceLevel = api.ServiceLevelUltra + + driver.populateConfigurationDefaults(ctx, &driver.Config) + driver.initializeStoragePools(ctx) + driver.initializeTelemetry(ctx, BackendUUID) + driver.Config.UnixPermissions = "0770" + driver.Config.NASType = "nfs" + + originalName := "importMe" + var snapshotDirAccess bool + + exportRule := api.ExportRule{ + Nfsv41: false, + Kerberos5ReadWrite: false, + Kerberos5IReadWrite: false, + Kerberos5PReadWrite: false, + } + + volConfig, originalFilesystem := getStructsForImport(ctx, driver) + + expectedLabels := map[string]string{ + drivers.TridentLabelTag: driver.getTelemetryLabels(ctx), + } + expectedUnixPermissions := "0770" + + mockAPI.EXPECT().RefreshAzureResources(ctx).Return(nil).Times(1) + mockAPI.EXPECT().VolumeByCreationToken(ctx, originalName).Return(originalFilesystem, nil).Times(1) + mockAPI.EXPECT().EnsureVolumeInValidCapacityPool(ctx, originalFilesystem).Return(nil).Times(1) + mockAPI.EXPECT().ModifyVolume(ctx, originalFilesystem, expectedLabels, + &expectedUnixPermissions, &snapshotDirAccess, &exportRule).Return(nil).Times(1) + mockAPI.EXPECT().WaitForVolumeState(ctx, originalFilesystem, api.StateAvailable, []string{api.StateError}, + driver.defaultTimeout()).Return(api.StateAvailable, nil).Times(1) + + result := driver.Import(ctx, volConfig, originalName) + + assert.NoError(t, result, "import failed") + assert.Equal(t, originalName, volConfig.InternalName, "internal name mismatch") + assert.Equal(t, originalFilesystem.ID, volConfig.InternalID, "internal ID not set on volConfig") +} + +func TestImport_ManagedWithKerberos5(t *testing.T) { + mockAPI, driver := newMockANFDriver(t) + driver.Config.BackendName = "anf" + driver.Config.ServiceLevel = api.ServiceLevelUltra + + driver.populateConfigurationDefaults(ctx, &driver.Config) + driver.initializeStoragePools(ctx) + driver.initializeTelemetry(ctx, BackendUUID) + driver.Config.UnixPermissions = "0770" + driver.Config.NASType = "nfs" + driver.Config.Kerberos = "sec=krb5" + + originalName := "importMe" + var snapshotDirAccess bool + + exportRule := api.ExportRule{ + Nfsv41: true, + Kerberos5ReadWrite: true, + Kerberos5IReadWrite: false, + Kerberos5PReadWrite: false, + } + + volConfig, originalFilesystem := getStructsForImport(ctx, driver) + originalFilesystem.KerberosEnabled = true + originalFilesystem.ExportPolicy.Rules[0].Nfsv41 = true + originalFilesystem.ExportPolicy.Rules[0].Kerberos5ReadWrite = true + + expectedLabels := map[string]string{ + drivers.TridentLabelTag: driver.getTelemetryLabels(ctx), + } + expectedUnixPermissions := "0770" + + mockAPI.EXPECT().RefreshAzureResources(ctx).Return(nil).Times(1) + mockAPI.EXPECT().VolumeByCreationToken(ctx, originalName).Return(originalFilesystem, nil).Times(1) + mockAPI.EXPECT().EnsureVolumeInValidCapacityPool(ctx, originalFilesystem).Return(nil).Times(1) + mockAPI.EXPECT().ModifyVolume(ctx, originalFilesystem, expectedLabels, + &expectedUnixPermissions, &snapshotDirAccess, &exportRule).Return(nil).Times(1) + mockAPI.EXPECT().WaitForVolumeState(ctx, originalFilesystem, api.StateAvailable, []string{api.StateError}, + driver.defaultTimeout()).Return(api.StateAvailable, nil).Times(1) + + result := driver.Import(ctx, volConfig, originalName) + + assert.NoError(t, result, "import failed") + assert.Equal(t, originalName, volConfig.InternalName, "internal name mismatch") + assert.Equal(t, originalFilesystem.ID, volConfig.InternalID, "internal ID not set on volConfig") + assert.True(t, originalFilesystem.ExportPolicy.Rules[0].Kerberos5ReadWrite, "kerberos protocol type mismatch") +} + +func TestImport_ManagedWithKerberos5I(t *testing.T) { + mockAPI, driver := newMockANFDriver(t) + driver.Config.BackendName = "anf" + driver.Config.ServiceLevel = api.ServiceLevelUltra + + driver.populateConfigurationDefaults(ctx, &driver.Config) + driver.initializeStoragePools(ctx) + driver.initializeTelemetry(ctx, BackendUUID) + driver.Config.UnixPermissions = "0770" + driver.Config.NASType = "nfs" + driver.Config.Kerberos = "sec=krb5i" + + originalName := "importMe" + var snapshotDirAccess bool + + exportRule := api.ExportRule{ + Nfsv41: true, + Kerberos5ReadWrite: false, + Kerberos5IReadWrite: true, + Kerberos5PReadWrite: false, + } + + volConfig, originalFilesystem := getStructsForImport(ctx, driver) + originalFilesystem.KerberosEnabled = true + originalFilesystem.ExportPolicy.Rules[0].Nfsv41 = true + originalFilesystem.ExportPolicy.Rules[0].Kerberos5IReadWrite = true + + expectedLabels := map[string]string{ + drivers.TridentLabelTag: driver.getTelemetryLabels(ctx), + } + expectedUnixPermissions := "0770" + + mockAPI.EXPECT().RefreshAzureResources(ctx).Return(nil).Times(1) + mockAPI.EXPECT().VolumeByCreationToken(ctx, originalName).Return(originalFilesystem, nil).Times(1) + mockAPI.EXPECT().EnsureVolumeInValidCapacityPool(ctx, originalFilesystem).Return(nil).Times(1) + mockAPI.EXPECT().ModifyVolume(ctx, originalFilesystem, expectedLabels, + &expectedUnixPermissions, &snapshotDirAccess, &exportRule).Return(nil).Times(1) + mockAPI.EXPECT().WaitForVolumeState(ctx, originalFilesystem, api.StateAvailable, []string{api.StateError}, + driver.defaultTimeout()).Return(api.StateAvailable, nil).Times(1) + + result := driver.Import(ctx, volConfig, originalName) + + assert.NoError(t, result, "import failed") + assert.Equal(t, originalName, volConfig.InternalName, "internal name mismatch") + assert.Equal(t, originalFilesystem.ID, volConfig.InternalID, "internal ID not set on volConfig") + assert.True(t, originalFilesystem.ExportPolicy.Rules[0].Kerberos5IReadWrite, "kerberos protocol type mismatch") +} + +func TestImport_ManagedWithKerberos5P(t *testing.T) { + mockAPI, driver := newMockANFDriver(t) + driver.Config.BackendName = "anf" + driver.Config.ServiceLevel = api.ServiceLevelUltra + + driver.populateConfigurationDefaults(ctx, &driver.Config) + driver.initializeStoragePools(ctx) + driver.initializeTelemetry(ctx, BackendUUID) + driver.Config.UnixPermissions = "0770" + driver.Config.NASType = "nfs" + driver.Config.Kerberos = "sec=krb5p" + + originalName := "importMe" + var snapshotDirAccess bool + + exportRule := api.ExportRule{ + Nfsv41: true, + Kerberos5ReadWrite: false, + Kerberos5IReadWrite: false, + Kerberos5PReadWrite: true, + } + + volConfig, originalFilesystem := getStructsForImport(ctx, driver) + originalFilesystem.KerberosEnabled = true + originalFilesystem.ExportPolicy.Rules[0].Nfsv41 = true + originalFilesystem.ExportPolicy.Rules[0].Kerberos5PReadWrite = true + + expectedLabels := map[string]string{ + drivers.TridentLabelTag: driver.getTelemetryLabels(ctx), + } + expectedUnixPermissions := "0770" + + mockAPI.EXPECT().RefreshAzureResources(ctx).Return(nil).Times(1) + mockAPI.EXPECT().VolumeByCreationToken(ctx, originalName).Return(originalFilesystem, nil).Times(1) + mockAPI.EXPECT().EnsureVolumeInValidCapacityPool(ctx, originalFilesystem).Return(nil).Times(1) + mockAPI.EXPECT().ModifyVolume(ctx, originalFilesystem, expectedLabels, + &expectedUnixPermissions, &snapshotDirAccess, &exportRule).Return(nil).Times(1) + mockAPI.EXPECT().WaitForVolumeState(ctx, originalFilesystem, api.StateAvailable, []string{api.StateError}, + driver.defaultTimeout()).Return(api.StateAvailable, nil).Times(1) + + result := driver.Import(ctx, volConfig, originalName) + + assert.NoError(t, result, "import failed") + assert.Equal(t, originalName, volConfig.InternalName, "internal name mismatch") + assert.Equal(t, originalFilesystem.ID, volConfig.InternalID, "internal ID not set on volConfig") + assert.True(t, originalFilesystem.ExportPolicy.Rules[0].Kerberos5PReadWrite, "kerberos protocol type mismatch") +} + +func TestImport_ManagedWithMultipleKerberosEnabledStoragePools(t *testing.T) { + mockAPI, driver := newMockANFDriver(t) + driver.Config.BackendName = "anf" + driver.Config.ServiceLevel = api.ServiceLevelUltra + + driver.Config.Storage = []drivers.AzureNASStorageDriverPool{ + { + Kerberos: "sec=krb5i", + }, + { + Kerberos: "sec=krb5p", + }, + } + + driver.populateConfigurationDefaults(ctx, &driver.Config) + driver.initializeStoragePools(ctx) + driver.initializeTelemetry(ctx, BackendUUID) + driver.Config.UnixPermissions = "0770" + driver.Config.NASType = "nfs" + + originalName := "importMe" + var snapshotDirAccess bool + + exportRule := api.ExportRule{ + Nfsv41: true, + Kerberos5ReadWrite: false, + Kerberos5IReadWrite: true, + Kerberos5PReadWrite: false, + } + + volConfig, originalFilesystem := getStructsForImport(ctx, driver) + originalFilesystem.KerberosEnabled = true + originalFilesystem.ExportPolicy.Rules[0].Nfsv41 = true + originalFilesystem.ExportPolicy.Rules[0].Kerberos5IReadWrite = true + + expectedLabels := map[string]string{ + drivers.TridentLabelTag: driver.getTelemetryLabels(ctx), + } + expectedUnixPermissions := "0770" + + mockAPI.EXPECT().RefreshAzureResources(ctx).Return(nil).Times(1) + mockAPI.EXPECT().VolumeByCreationToken(ctx, originalName).Return(originalFilesystem, nil).Times(1) + mockAPI.EXPECT().EnsureVolumeInValidCapacityPool(ctx, originalFilesystem).Return(nil).Times(1) + mockAPI.EXPECT().ModifyVolume(ctx, originalFilesystem, expectedLabels, + &expectedUnixPermissions, &snapshotDirAccess, &exportRule).Return(nil).Times(1) + mockAPI.EXPECT().WaitForVolumeState(ctx, originalFilesystem, api.StateAvailable, []string{api.StateError}, + driver.defaultTimeout()).Return(api.StateAvailable, nil).Times(1) + + result := driver.Import(ctx, volConfig, originalName) - assert.Error(t, result, "expected error") - assert.Equal(t, "", cloneVolConfig.InternalID, "internal ID set on volConfig") + assert.NoError(t, result, "import failed") + assert.Equal(t, originalName, volConfig.InternalName, "internal name mismatch") + assert.Equal(t, originalFilesystem.ID, volConfig.InternalID, "internal ID not set on volConfig") + assert.True(t, originalFilesystem.ExportPolicy.Rules[0].Kerberos5IReadWrite, "kerberos protocol type mismatch") } -func TestCreateClone_InvalidLabel(t *testing.T) { +func TestImport_ManagedWithKerberos_IncorrectProtocolType(t *testing.T) { mockAPI, driver := newMockANFDriver(t) driver.Config.BackendName = "anf" driver.Config.ServiceLevel = api.ServiceLevelUltra @@ -2687,136 +3357,97 @@ func TestCreateClone_InvalidLabel(t *testing.T) { driver.populateConfigurationDefaults(ctx, &driver.Config) driver.initializeStoragePools(ctx) driver.initializeTelemetry(ctx, BackendUUID) - driver.Config.Labels = map[string]string{ - "key1": "1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890", - "key2": "1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890", - "key3": "1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890", + driver.Config.UnixPermissions = "0770" + driver.Config.NASType = "nfs" + driver.Config.Kerberos = "sec=krb5" + + originalName := "importMe" + var snapshotDirAccess bool + + exportRule := api.ExportRule{ + Nfsv41: true, + Kerberos5ReadWrite: true, + Kerberos5IReadWrite: false, + Kerberos5PReadWrite: false, } - storagePool := driver.pools["anf_pool"] + volConfig, originalFilesystem := getStructsForImport(ctx, driver) + originalFilesystem.KerberosEnabled = true + originalFilesystem.ExportPolicy.Rules[0].Nfsv41 = true + originalFilesystem.ExportPolicy.Rules[0].Kerberos5ReadWrite = false + originalFilesystem.ExportPolicy.Rules[0].Kerberos5IReadWrite = true - sourceVolConfig, cloneVolConfig, _, sourceFilesystem, cloneFilesystem, snapshot := getStructsForCreateClone(ctx, - driver, storagePool) + expectedLabels := map[string]string{ + drivers.TridentLabelTag: driver.getTelemetryLabels(ctx), + } + expectedUnixPermissions := "0770" mockAPI.EXPECT().RefreshAzureResources(ctx).Return(nil).Times(1) - mockAPI.EXPECT().Volume(ctx, sourceVolConfig).Return(sourceFilesystem, nil).Times(1) - mockAPI.EXPECT().VolumeExistsByID(ctx, cloneFilesystem.ID).Return(false, nil, nil).Times(1) - mockAPI.EXPECT().CreateSnapshot(ctx, sourceFilesystem, gomock.Any()).Return(snapshot, nil).Times(1) - mockAPI.EXPECT().WaitForSnapshotState(ctx, snapshot, sourceFilesystem, api.StateAvailable, []string{api.StateError}, - api.SnapshotTimeout).Return(nil).Times(1) - mockAPI.EXPECT().SnapshotForVolume(ctx, sourceFilesystem, gomock.Any()).Return(snapshot, nil).Times(1) + mockAPI.EXPECT().VolumeByCreationToken(ctx, originalName).Return(originalFilesystem, nil).Times(1) + mockAPI.EXPECT().EnsureVolumeInValidCapacityPool(ctx, originalFilesystem).Return(nil).Times(1) + mockAPI.EXPECT().ModifyVolume(ctx, originalFilesystem, expectedLabels, &expectedUnixPermissions, &snapshotDirAccess, + &exportRule).Return(errors.New("Could not import volume, volume modify failed.")).Times(1) - result := driver.CreateClone(ctx, sourceVolConfig, cloneVolConfig, nil) + result := driver.Import(ctx, volConfig, originalName) - assert.Error(t, result, "expected error") - assert.Equal(t, "", cloneVolConfig.InternalID, "internal ID set on volConfig") + assert.Error(t, result, "import succeeded") + assert.False(t, originalFilesystem.ExportPolicy.Rules[0].Kerberos5ReadWrite, "kerberos protocol type mismatch") } -func TestCreateClone_CreateFailed(t *testing.T) { +func TestImport_ManagedWithKerberosDisabled(t *testing.T) { mockAPI, driver := newMockANFDriver(t) driver.Config.BackendName = "anf" driver.Config.ServiceLevel = api.ServiceLevelUltra - driver.Config.NASType = "nfs" driver.populateConfigurationDefaults(ctx, &driver.Config) driver.initializeStoragePools(ctx) driver.initializeTelemetry(ctx, BackendUUID) + driver.Config.UnixPermissions = "0770" + driver.Config.NASType = "nfs" + driver.Config.Kerberos = "sec=krb5" - storagePool := driver.pools["anf_pool"] + originalName := "importMe" - sourceVolConfig, cloneVolConfig, createRequest, sourceFilesystem, cloneFilesystem, snapshot := getStructsForCreateClone(ctx, - driver, storagePool) - sourceVolConfig.SnapshotDir = "false" + volConfig, originalFilesystem := getStructsForImport(ctx, driver) + originalFilesystem.KerberosEnabled = false mockAPI.EXPECT().RefreshAzureResources(ctx).Return(nil).Times(1) - mockAPI.EXPECT().Volume(ctx, sourceVolConfig).Return(sourceFilesystem, nil).Times(1) - mockAPI.EXPECT().VolumeExistsByID(ctx, cloneFilesystem.ID).Return(false, nil, nil).Times(1) - mockAPI.EXPECT().CreateSnapshot(ctx, sourceFilesystem, gomock.Any()).Return(snapshot, nil).Times(1) - mockAPI.EXPECT().WaitForSnapshotState(ctx, snapshot, sourceFilesystem, api.StateAvailable, []string{api.StateError}, - api.SnapshotTimeout).Return(nil).Times(1) - mockAPI.EXPECT().SnapshotForVolume(ctx, sourceFilesystem, gomock.Any()).Return(snapshot, nil).Times(1) - mockAPI.EXPECT().CreateVolume(ctx, createRequest).Return(nil, errFailed).Times(1) + mockAPI.EXPECT().VolumeByCreationToken(ctx, originalName).Return(originalFilesystem, nil).Times(1) + mockAPI.EXPECT().EnsureVolumeInValidCapacityPool(ctx, originalFilesystem).Return(nil).Times(1) - result := driver.CreateClone(ctx, sourceVolConfig, cloneVolConfig, nil) + result := driver.Import(ctx, volConfig, originalName) - assert.Error(t, result, "expected error") - assert.Equal(t, "", cloneVolConfig.InternalID, "internal ID set on volConfig") + assert.Error(t, result, "import succeeded") + assert.False(t, originalFilesystem.KerberosEnabled, "kerberosEnabled flag is set") } -func getStructsForImport(ctx context.Context, driver *NASStorageDriver) (*storage.VolumeConfig, *api.FileSystem) { - subnetID := api.CreateSubnetID(SubscriptionID, "RG2", "VN1", "SN1") - - volConfig := &storage.VolumeConfig{ - Version: "1", - Name: "testvol1", - InternalName: "trident-testvol1", - } - - volumeID := api.CreateVolumeID(SubscriptionID, "RG1", "NA1", "CP1", "importMe") - - labels := make(map[string]string) - labels[drivers.TridentLabelTag] = driver.getTelemetryLabels(ctx) - labels[storage.ProvisioningLabelTag] = "" - - originalFilesystem := &api.FileSystem{ - ID: volumeID, - ResourceGroup: "RG1", - NetAppAccount: "NA1", - CapacityPool: "CP1", - Name: "importMe", - FullName: "RG1/NA1/CP1/importMe", - Location: Location, - Labels: make(map[string]string), - ProvisioningState: api.StateAvailable, - CreationToken: "importMe", - ProtocolTypes: []string{api.ProtocolTypeNFSv3}, - QuotaInBytes: VolumeSizeI64, - ServiceLevel: api.ServiceLevelUltra, - SnapshotDirectory: true, - SubnetID: subnetID, - UnixPermissions: defaultUnixPermissions, - } - - return volConfig, originalFilesystem -} +func TestImport_ManagedWithKerberosNotSetInConfig(t *testing.T) { + mockAPI, driver := newMockANFDriver(t) + driver.Config.BackendName = "anf" + driver.Config.ServiceLevel = api.ServiceLevelUltra -func getStructsForSMBImport(ctx context.Context, driver *NASStorageDriver) (*storage.VolumeConfig, *api.FileSystem) { - subnetID := api.CreateSubnetID(SubscriptionID, "RG2", "VN1", "SN1") + driver.populateConfigurationDefaults(ctx, &driver.Config) + driver.initializeStoragePools(ctx) + driver.initializeTelemetry(ctx, BackendUUID) + driver.Config.UnixPermissions = "0770" + driver.Config.NASType = "nfs" - volConfig := &storage.VolumeConfig{ - Version: "1", - Name: "testvol1", - InternalName: "trident-testvol1", - } + originalName := "importMe" - volumeID := api.CreateVolumeID(SubscriptionID, "RG1", "NA1", "CP1", "importMe") + volConfig, originalFilesystem := getStructsForImport(ctx, driver) + originalFilesystem.KerberosEnabled = true - labels := make(map[string]string) - labels[drivers.TridentLabelTag] = driver.getTelemetryLabels(ctx) - labels[storage.ProvisioningLabelTag] = "" + mockAPI.EXPECT().RefreshAzureResources(ctx).Return(nil).Times(1) + mockAPI.EXPECT().VolumeByCreationToken(ctx, originalName).Return(originalFilesystem, nil).Times(1) + mockAPI.EXPECT().EnsureVolumeInValidCapacityPool(ctx, originalFilesystem).Return(nil).Times(1) - originalFilesystem := &api.FileSystem{ - ID: volumeID, - ResourceGroup: "RG1", - NetAppAccount: "NA1", - CapacityPool: "CP1", - Name: "importMe", - FullName: "RG1/NA1/CP1/importMe", - Location: Location, - Labels: make(map[string]string), - ProvisioningState: api.StateAvailable, - CreationToken: "importMe", - ProtocolTypes: []string{api.ProtocolTypeCIFS}, - QuotaInBytes: VolumeSizeI64, - ServiceLevel: api.ServiceLevelUltra, - SnapshotDirectory: true, - SubnetID: subnetID, - } + result := driver.Import(ctx, volConfig, originalName) - return volConfig, originalFilesystem + assert.Error(t, result, "import succeeded") + assert.True(t, originalFilesystem.KerberosEnabled, "kerberosEnabled flag is set") } -func TestImport_Managed(t *testing.T) { +func TestImport_ManagedWithSnapshotDir(t *testing.T) { mockAPI, driver := newMockANFDriver(t) driver.Config.BackendName = "anf" driver.Config.ServiceLevel = api.ServiceLevelUltra @@ -2828,10 +3459,19 @@ func TestImport_Managed(t *testing.T) { driver.Config.NASType = "nfs" originalName := "importMe" - var snapshotDirAccess bool + + exportRule := api.ExportRule{ + Nfsv41: false, + Kerberos5ReadWrite: false, + Kerberos5IReadWrite: false, + Kerberos5PReadWrite: false, + } volConfig, originalFilesystem := getStructsForImport(ctx, driver) + volConfig.SnapshotDir = "true" + snapshotDirAccess := true + expectedLabels := map[string]string{ drivers.TridentLabelTag: driver.getTelemetryLabels(ctx), } @@ -2841,7 +3481,7 @@ func TestImport_Managed(t *testing.T) { mockAPI.EXPECT().VolumeByCreationToken(ctx, originalName).Return(originalFilesystem, nil).Times(1) mockAPI.EXPECT().EnsureVolumeInValidCapacityPool(ctx, originalFilesystem).Return(nil).Times(1) mockAPI.EXPECT().ModifyVolume(ctx, originalFilesystem, expectedLabels, - &expectedUnixPermissions, &snapshotDirAccess).Return(nil).Times(1) + &expectedUnixPermissions, &snapshotDirAccess, &exportRule).Return(nil).Times(1) mockAPI.EXPECT().WaitForVolumeState(ctx, originalFilesystem, api.StateAvailable, []string{api.StateError}, driver.defaultTimeout()).Return(api.StateAvailable, nil).Times(1) @@ -2852,7 +3492,7 @@ func TestImport_Managed(t *testing.T) { assert.Equal(t, originalFilesystem.ID, volConfig.InternalID, "internal ID not set on volConfig") } -func TestImport_ManagedWithSnapshotDir(t *testing.T) { +func TestImport_ManagedWithSnapshotDirFalse(t *testing.T) { mockAPI, driver := newMockANFDriver(t) driver.Config.BackendName = "anf" driver.Config.ServiceLevel = api.ServiceLevelUltra @@ -2865,10 +3505,17 @@ func TestImport_ManagedWithSnapshotDir(t *testing.T) { originalName := "importMe" + exportRule := api.ExportRule{ + Nfsv41: false, + Kerberos5ReadWrite: false, + Kerberos5IReadWrite: false, + Kerberos5PReadWrite: false, + } + volConfig, originalFilesystem := getStructsForImport(ctx, driver) - volConfig.SnapshotDir = "true" - snapshotDirAccess := true + volConfig.SnapshotDir = "false" + snapshotDirAccess := false expectedLabels := map[string]string{ drivers.TridentLabelTag: driver.getTelemetryLabels(ctx), @@ -2879,7 +3526,7 @@ func TestImport_ManagedWithSnapshotDir(t *testing.T) { mockAPI.EXPECT().VolumeByCreationToken(ctx, originalName).Return(originalFilesystem, nil).Times(1) mockAPI.EXPECT().EnsureVolumeInValidCapacityPool(ctx, originalFilesystem).Return(nil).Times(1) mockAPI.EXPECT().ModifyVolume(ctx, originalFilesystem, expectedLabels, - &expectedUnixPermissions, &snapshotDirAccess).Return(nil).Times(1) + &expectedUnixPermissions, &snapshotDirAccess, &exportRule).Return(nil).Times(1) mockAPI.EXPECT().WaitForVolumeState(ctx, originalFilesystem, api.StateAvailable, []string{api.StateError}, driver.defaultTimeout()).Return(api.StateAvailable, nil).Times(1) @@ -2890,7 +3537,7 @@ func TestImport_ManagedWithSnapshotDir(t *testing.T) { assert.Equal(t, originalFilesystem.ID, volConfig.InternalID, "internal ID not set on volConfig") } -func TestImport_ManagedWithSnapshotDirFalse(t *testing.T) { +func TestImport_ManagedWithInvalidSnapshotDirValue(t *testing.T) { mockAPI, driver := newMockANFDriver(t) driver.Config.BackendName = "anf" driver.Config.ServiceLevel = api.ServiceLevelUltra @@ -2905,27 +3552,16 @@ func TestImport_ManagedWithSnapshotDirFalse(t *testing.T) { volConfig, originalFilesystem := getStructsForImport(ctx, driver) - volConfig.SnapshotDir = "false" - snapshotDirAccess := false - - expectedLabels := map[string]string{ - drivers.TridentLabelTag: driver.getTelemetryLabels(ctx), - } - expectedUnixPermissions := "0770" + volConfig.SnapshotDir = "xxxffa" mockAPI.EXPECT().RefreshAzureResources(ctx).Return(nil).Times(1) mockAPI.EXPECT().VolumeByCreationToken(ctx, originalName).Return(originalFilesystem, nil).Times(1) mockAPI.EXPECT().EnsureVolumeInValidCapacityPool(ctx, originalFilesystem).Return(nil).Times(1) - mockAPI.EXPECT().ModifyVolume(ctx, originalFilesystem, expectedLabels, - &expectedUnixPermissions, &snapshotDirAccess).Return(nil).Times(1) - mockAPI.EXPECT().WaitForVolumeState(ctx, originalFilesystem, api.StateAvailable, []string{api.StateError}, - driver.defaultTimeout()).Return(api.StateAvailable, nil).Times(1) result := driver.Import(ctx, volConfig, originalName) - assert.NoError(t, result, "import failed") - assert.Equal(t, originalName, volConfig.InternalName, "internal name mismatch") - assert.Equal(t, originalFilesystem.ID, volConfig.InternalID, "internal ID not set on volConfig") + assert.Error(t, result, "import succeeded") + assert.NotNil(t, result, "received nil") } func TestImport_SMB_Managed(t *testing.T) { @@ -2941,6 +3577,13 @@ func TestImport_SMB_Managed(t *testing.T) { originalName := "importMe" var snapshotDirAccess bool + exportRule := api.ExportRule{ + Nfsv41: false, + Kerberos5ReadWrite: false, + Kerberos5IReadWrite: false, + Kerberos5PReadWrite: false, + } + volConfig, originalFilesystem := getStructsForSMBImport(ctx, driver) expectedLabels := map[string]string{ @@ -2951,7 +3594,7 @@ func TestImport_SMB_Managed(t *testing.T) { mockAPI.EXPECT().VolumeByCreationToken(ctx, originalName).Return(originalFilesystem, nil).Times(1) mockAPI.EXPECT().EnsureVolumeInValidCapacityPool(ctx, originalFilesystem).Return(nil).Times(1) mockAPI.EXPECT().ModifyVolume(ctx, originalFilesystem, expectedLabels, - nil, &snapshotDirAccess).Return(nil).Times(1) + nil, &snapshotDirAccess, &exportRule).Return(nil).Times(1) mockAPI.EXPECT().WaitForVolumeState(ctx, originalFilesystem, api.StateAvailable, []string{api.StateError}, driver.defaultTimeout()).Return(api.StateAvailable, nil).Times(1) @@ -2976,6 +3619,13 @@ func TestImport_SMB_Failed(t *testing.T) { originalName := "importMe" var snapshotDirAccess bool + exportRule := api.ExportRule{ + Nfsv41: false, + Kerberos5ReadWrite: false, + Kerberos5IReadWrite: false, + Kerberos5PReadWrite: false, + } + volConfig, originalFilesystem := getStructsForSMBImport(ctx, driver) expectedLabels := map[string]string{ @@ -2986,7 +3636,7 @@ func TestImport_SMB_Failed(t *testing.T) { mockAPI.EXPECT().VolumeByCreationToken(ctx, originalName).Return(originalFilesystem, nil).Times(1) mockAPI.EXPECT().EnsureVolumeInValidCapacityPool(ctx, originalFilesystem).Return(nil).Times(1) mockAPI.EXPECT().ModifyVolume(ctx, originalFilesystem, expectedLabels, - nil, &snapshotDirAccess).Return(errors.New("unix permissions not applicable for SMB")).Times(1) + nil, &snapshotDirAccess, &exportRule).Return(errors.New("unix permissions not applicable for SMB")).Times(1) result := driver.Import(ctx, volConfig, originalName) @@ -3031,6 +3681,13 @@ func TestImport_ManagedWithLabels(t *testing.T) { originalName := "importMe" var snapshotDirAccess bool + exportRule := api.ExportRule{ + Nfsv41: false, + Kerberos5ReadWrite: false, + Kerberos5IReadWrite: false, + Kerberos5PReadWrite: false, + } + volConfig, originalFilesystem := getStructsForImport(ctx, driver) originalFilesystem.UnixPermissions = "0700" originalFilesystem.Labels = map[string]string{ @@ -3047,7 +3704,7 @@ func TestImport_ManagedWithLabels(t *testing.T) { mockAPI.EXPECT().VolumeByCreationToken(ctx, originalName).Return(originalFilesystem, nil).Times(1) mockAPI.EXPECT().EnsureVolumeInValidCapacityPool(ctx, originalFilesystem).Return(nil).Times(1) mockAPI.EXPECT().ModifyVolume(ctx, originalFilesystem, expectedLabels, - &expectedUnixPermissions, &snapshotDirAccess).Return(nil).Times(1) + &expectedUnixPermissions, &snapshotDirAccess, &exportRule).Return(nil).Times(1) mockAPI.EXPECT().WaitForVolumeState(ctx, originalFilesystem, api.StateAvailable, []string{api.StateError}, driver.defaultTimeout()).Return(api.StateAvailable, nil).Times(1) @@ -3196,6 +3853,13 @@ func TestImport_ModifyVolumeFailed(t *testing.T) { originalName := "importMe" var snapshotDirAccess bool + exportRule := api.ExportRule{ + Nfsv41: false, + Kerberos5ReadWrite: false, + Kerberos5IReadWrite: false, + Kerberos5PReadWrite: false, + } + volConfig, originalFilesystem := getStructsForImport(ctx, driver) expectedLabels := map[string]string{ @@ -3207,7 +3871,7 @@ func TestImport_ModifyVolumeFailed(t *testing.T) { mockAPI.EXPECT().VolumeByCreationToken(ctx, originalName).Return(originalFilesystem, nil).Times(1) mockAPI.EXPECT().EnsureVolumeInValidCapacityPool(ctx, originalFilesystem).Return(nil).Times(1) mockAPI.EXPECT().ModifyVolume(ctx, originalFilesystem, expectedLabels, - &expectedUnixPermissions, &snapshotDirAccess).Return(errFailed).Times(1) + &expectedUnixPermissions, &snapshotDirAccess, &exportRule).Return(errFailed).Times(1) result := driver.Import(ctx, volConfig, originalName) @@ -3230,6 +3894,13 @@ func TestImport_VolumeWaitFailed(t *testing.T) { originalName := "importMe" var snapshotDirAccess bool + exportRule := api.ExportRule{ + Nfsv41: false, + Kerberos5ReadWrite: false, + Kerberos5IReadWrite: false, + Kerberos5PReadWrite: false, + } + volConfig, originalFilesystem := getStructsForImport(ctx, driver) expectedLabels := map[string]string{ @@ -3241,7 +3912,7 @@ func TestImport_VolumeWaitFailed(t *testing.T) { mockAPI.EXPECT().VolumeByCreationToken(ctx, originalName).Return(originalFilesystem, nil).Times(1) mockAPI.EXPECT().EnsureVolumeInValidCapacityPool(ctx, originalFilesystem).Return(nil).Times(1) mockAPI.EXPECT().ModifyVolume(ctx, originalFilesystem, expectedLabels, - &expectedUnixPermissions, &snapshotDirAccess).Return(nil).Times(1) + &expectedUnixPermissions, &snapshotDirAccess, &exportRule).Return(nil).Times(1) mockAPI.EXPECT().WaitForVolumeState(ctx, originalFilesystem, api.StateAvailable, []string{api.StateError}, driver.defaultTimeout()).Return("", errFailed).Times(1) @@ -3697,7 +4368,7 @@ func getStructsForPublishNFSVolume( MountTargetID: "mountTargetID", FileSystemID: "filesystemID", IPAddress: "1.1.1.1", - SmbServerFqdn: "", + ServerFqdn: "", }, } @@ -3754,7 +4425,7 @@ func getStructsForPublishSMBVolume( MountTargetID: "mountTargetID", FileSystemID: "filesystemID", IPAddress: "1.1.1.1", - SmbServerFqdn: "trident-1234.trident.com", + ServerFqdn: "trident-1234.trident.com", }, } @@ -3803,6 +4474,60 @@ func TestPublish_NFSVolume(t *testing.T) { assert.Equal(t, "nfsvers=3", publishInfo.MountOptions, "mount options mismatch") } +func TestPublish_NFSVolume_Kerberos_Type5(t *testing.T) { + mockAPI, driver := newMockANFDriver(t) + driver.initializeTelemetry(ctx, BackendUUID) + driver.Config.NASType = "nfs" + driver.Config.Kerberos = "sec=krb5" + + volConfig, filesystem, publishInfo := getStructsForPublishNFSVolume(ctx, driver) + + filesystem.MountTargets[0].ServerFqdn = "trident-1234.trident.com" + filesystem.ProtocolTypes = []string{api.ProtocolTypeNFSv41} + filesystem.KerberosEnabled = true + + volConfig.MountOptions = "nfsvers=4.1" + + publishInfo.NfsPath = volConfig.AccessInfo.NfsPath + + mockAPI.EXPECT().RefreshAzureResources(ctx).Return(nil).Times(1) + mockAPI.EXPECT().Volume(ctx, volConfig).Return(filesystem, nil).Times(1) + + result := driver.Publish(ctx, volConfig, publishInfo) + + assert.Nil(t, result, "not nil") + assert.Equal(t, filesystem.ID, volConfig.InternalID, "internal ID not set on volConfig") + assert.Equal(t, "/trident-testvol1", publishInfo.NfsPath, "NFS path mismatch") + assert.Equal(t, "trident-1234.trident.com", publishInfo.NfsServerIP, "server fqdn mismatch") + assert.Equal(t, "nfs", publishInfo.FilesystemType, "filesystem type mismatch") + assert.Equal(t, "nfsvers=4.1", publishInfo.MountOptions, "mount options mismatch") +} + +func TestPublish_NFSVolume_Kerberos_Type5_NotSet(t *testing.T) { + mockAPI, driver := newMockANFDriver(t) + driver.initializeTelemetry(ctx, BackendUUID) + driver.Config.NASType = "nfs" + driver.Config.Kerberos = "sec=krb5" + + volConfig, filesystem, publishInfo := getStructsForPublishNFSVolume(ctx, driver) + + filesystem.MountTargets[0].ServerFqdn = "trident-1234.trident.com" + filesystem.ProtocolTypes = []string{api.ProtocolTypeNFSv41} + filesystem.KerberosEnabled = false + + volConfig.MountOptions = "nfsvers=4.1" + + publishInfo.NfsPath = volConfig.AccessInfo.NfsPath + + mockAPI.EXPECT().RefreshAzureResources(ctx).Return(nil).Times(1) + mockAPI.EXPECT().Volume(ctx, volConfig).Return(filesystem, nil).Times(1) + + result := driver.Publish(ctx, volConfig, publishInfo) + + assert.Nil(t, result, "not nil") + assert.NotEqual(t, "trident-1234.trident.com", publishInfo.NfsServerIP, "server fqdn mismatch") +} + func TestPublish_ROClone_NFSVolume(t *testing.T) { mockAPI, driver := newMockANFDriver(t) driver.initializeTelemetry(ctx, BackendUUID) @@ -5050,6 +5775,52 @@ func TestCreateFollowup_NFSVolume(t *testing.T) { assert.Equal(t, "nfs", volConfig.FileSystem, "filesystem type mismatch") } +func TestCreateFollowup_NFSVolume_Kerberos_Type5(t *testing.T) { + mockAPI, driver := newMockANFDriver(t) + driver.initializeTelemetry(ctx, BackendUUID) + driver.Config.NASType = "nfs" + driver.Config.Kerberos = "sec=krb5" + + volConfig, filesystem, _ := getStructsForPublishNFSVolume(ctx, driver) + + filesystem.MountTargets[0].ServerFqdn = "trident-1234.trident.com" + filesystem.ProtocolTypes = []string{api.ProtocolTypeNFSv41} + filesystem.KerberosEnabled = true + + mockAPI.EXPECT().RefreshAzureResources(ctx).Return(nil).Times(1) + mockAPI.EXPECT().Volume(ctx, volConfig).Return(filesystem, nil).Times(1) + + result := driver.CreateFollowup(ctx, volConfig) + + assert.Nil(t, result, "not nil") + assert.Equal(t, (filesystem.MountTargets)[0].ServerFqdn, volConfig.AccessInfo.NfsServerIP, + "server fqdn mismatch") + assert.Equal(t, "/"+filesystem.CreationToken, volConfig.AccessInfo.NfsPath, "NFS path mismatch") + assert.Equal(t, "nfs", volConfig.FileSystem, "filesystem type mismatch") +} + +func TestCreateFollowup_NFSVolume_Kerberos_Type5_NotSet(t *testing.T) { + mockAPI, driver := newMockANFDriver(t) + driver.initializeTelemetry(ctx, BackendUUID) + driver.Config.NASType = "nfs" + driver.Config.Kerberos = "sec=krb5" + + volConfig, filesystem, _ := getStructsForPublishNFSVolume(ctx, driver) + + filesystem.MountTargets[0].ServerFqdn = "trident-1234.trident.com" + filesystem.ProtocolTypes = []string{api.ProtocolTypeNFSv41} + filesystem.KerberosEnabled = false + + mockAPI.EXPECT().RefreshAzureResources(ctx).Return(nil).Times(1) + mockAPI.EXPECT().Volume(ctx, volConfig).Return(filesystem, nil).Times(1) + + result := driver.CreateFollowup(ctx, volConfig) + + assert.Nil(t, result, "not nil") + assert.NotEqual(t, (filesystem.MountTargets)[0].ServerFqdn, volConfig.AccessInfo.NfsServerIP, + "server fqdn mismatch") +} + func TestCreateFollowup_ROClone_NFSVolume(t *testing.T) { mockAPI, driver := newMockANFDriver(t) driver.initializeTelemetry(ctx, BackendUUID) @@ -5086,7 +5857,7 @@ func TestCreateFollowup_SMBVolume(t *testing.T) { result := driver.CreateFollowup(ctx, volConfig) assert.Nil(t, result, "not nil") - assert.Equal(t, (filesystem.MountTargets)[0].SmbServerFqdn, volConfig.AccessInfo.SMBServer, "SMB server mismatch") + assert.Equal(t, (filesystem.MountTargets)[0].ServerFqdn, volConfig.AccessInfo.SMBServer, "SMB server mismatch") assert.Equal(t, "\\"+filesystem.CreationToken, volConfig.AccessInfo.SMBPath, "SMB path mismatch") assert.Equal(t, "smb", volConfig.FileSystem, "filesystem type mismatch") } @@ -5108,7 +5879,7 @@ func TestCreateFollowup_ROClone_SMBVolume(t *testing.T) { assert.Nil(t, result, "not nil") assert.NoError(t, result, "error occurred") - assert.Equal(t, (filesystem.MountTargets)[0].SmbServerFqdn, volConfig.AccessInfo.SMBServer, "SMB server mismatch") + assert.Equal(t, (filesystem.MountTargets)[0].ServerFqdn, volConfig.AccessInfo.SMBServer, "SMB server mismatch") assert.Equal(t, "\\testvol1\\~snapshot\\deadbeef-5c0d-4afa-8cd8-afa3fba5665c", volConfig.AccessInfo.SMBPath, "SMB path mismatch") assert.Equal(t, "smb", volConfig.FileSystem, "filesystem type mismatch") diff --git a/storage_drivers/types.go b/storage_drivers/types.go index 7b42e87a4..3bb026538 100644 --- a/storage_drivers/types.go +++ b/storage_drivers/types.go @@ -463,6 +463,7 @@ type AzureNASStorageDriverPool struct { CapacityPools []string `json:"capacityPools"` FilePoolVolumes []string `json:"filePoolVolumes"` NASType string `json:"nasType"` + Kerberos string `json:"kerberos"` AzureNASStorageDriverConfigDefaults `json:"defaults"` }