mirror of
				https://github.com/optim-enterprises-bv/kubernetes.git
				synced 2025-10-31 18:28:13 +00:00 
			
		
		
		
	Merge pull request #118236 from andyzhangx/remove-azurefile
removed the deprecated `azureFile` in-tree storage plugin
This commit is contained in:
		| @@ -25,7 +25,6 @@ import ( | ||||
| 	"k8s.io/klog/v2" | ||||
| 	"k8s.io/kubernetes/pkg/features" | ||||
| 	"k8s.io/kubernetes/pkg/volume" | ||||
| 	"k8s.io/kubernetes/pkg/volume/azure_file" | ||||
| 	"k8s.io/kubernetes/pkg/volume/csimigration" | ||||
| 	"k8s.io/kubernetes/pkg/volume/gcepd" | ||||
| 	"k8s.io/kubernetes/pkg/volume/portworx" | ||||
| @@ -81,24 +80,5 @@ func appendExpandableLegacyProviderVolumes(logger klog.Logger, allPlugins []volu | ||||
| } | ||||
|  | ||||
| func appendLegacyProviderVolumes(logger klog.Logger, allPlugins []volume.VolumePlugin, featureGate featuregate.FeatureGate) ([]volume.VolumePlugin, error) { | ||||
| 	var err error | ||||
| 	// First append attachable volumes | ||||
| 	allPlugins, err = appendAttachableLegacyProviderVolumes(logger, allPlugins, featureGate) | ||||
| 	if err != nil { | ||||
| 		return allPlugins, err | ||||
| 	} | ||||
|  | ||||
| 	// Then append non-attachable volumes | ||||
| 	pluginName := plugins.AzureFileInTreePluginName | ||||
| 	pluginInfo := pluginInfo{ | ||||
| 		pluginMigrationFeature:  features.CSIMigrationAzureFile, | ||||
| 		pluginUnregisterFeature: features.InTreePluginAzureFileUnregister, | ||||
| 		pluginProbeFunction:     azure_file.ProbeVolumePlugins, | ||||
| 	} | ||||
| 	allPlugins, err = appendPluginBasedOnFeatureFlags(logger, allPlugins, pluginName, featureGate, pluginInfo) | ||||
| 	if err != nil { | ||||
| 		return allPlugins, err | ||||
| 	} | ||||
|  | ||||
| 	return allPlugins, nil | ||||
| 	return appendAttachableLegacyProviderVolumes(logger, allPlugins, featureGate) | ||||
| } | ||||
|   | ||||
| @@ -29,7 +29,6 @@ import ( | ||||
| 	"k8s.io/klog/v2" | ||||
| 	"k8s.io/kubernetes/pkg/features" | ||||
| 	"k8s.io/kubernetes/pkg/volume" | ||||
| 	"k8s.io/kubernetes/pkg/volume/azure_file" | ||||
| 	"k8s.io/kubernetes/pkg/volume/csimigration" | ||||
| 	"k8s.io/kubernetes/pkg/volume/gcepd" | ||||
| 	"k8s.io/kubernetes/pkg/volume/portworx" | ||||
| @@ -67,7 +66,6 @@ type pluginInfo struct { | ||||
| func appendLegacyProviderVolumes(allPlugins []volume.VolumePlugin, featureGate featuregate.FeatureGate) ([]volume.VolumePlugin, error) { | ||||
| 	pluginMigrationStatus := make(map[string]pluginInfo) | ||||
| 	pluginMigrationStatus[plugins.GCEPDInTreePluginName] = pluginInfo{pluginMigrationFeature: features.CSIMigrationGCE, pluginUnregisterFeature: features.InTreePluginGCEUnregister, pluginProbeFunction: gcepd.ProbeVolumePlugins} | ||||
| 	pluginMigrationStatus[plugins.AzureFileInTreePluginName] = pluginInfo{pluginMigrationFeature: features.CSIMigrationAzureFile, pluginUnregisterFeature: features.InTreePluginAzureFileUnregister, pluginProbeFunction: azure_file.ProbeVolumePlugins} | ||||
| 	pluginMigrationStatus[plugins.VSphereInTreePluginName] = pluginInfo{pluginMigrationFeature: features.CSIMigrationvSphere, pluginUnregisterFeature: features.InTreePluginvSphereUnregister, pluginProbeFunction: vsphere_volume.ProbeVolumePlugins} | ||||
| 	pluginMigrationStatus[plugins.PortworxVolumePluginName] = pluginInfo{pluginMigrationFeature: features.CSIMigrationPortworx, pluginUnregisterFeature: features.InTreePluginPortworxUnregister, pluginProbeFunction: portworx.ProbeVolumePlugins} | ||||
| 	pluginMigrationStatus[plugins.RBDVolumePluginName] = pluginInfo{pluginMigrationFeature: features.CSIMigrationRBD, pluginUnregisterFeature: features.InTreePluginRBDUnregister, pluginProbeFunction: rbd.ProbeVolumePlugins} | ||||
|   | ||||
| @@ -122,14 +122,6 @@ const ( | ||||
| 	// Allow the usage of options to fine-tune the cpumanager policies. | ||||
| 	CPUManagerPolicyOptions featuregate.Feature = "CPUManagerPolicyOptions" | ||||
|  | ||||
| 	// owner: @andyzhangx | ||||
| 	// alpha: v1.15 | ||||
| 	// beta: v1.21 | ||||
| 	// GA: v1.26 | ||||
| 	// | ||||
| 	// Enables the Azure File in-tree driver to Azure File Driver migration feature. | ||||
| 	CSIMigrationAzureFile featuregate.Feature = "CSIMigrationAzureFile" | ||||
|  | ||||
| 	// owner: @davidz627 | ||||
| 	// alpha: v1.14 | ||||
| 	// beta: v1.17 | ||||
| @@ -876,8 +868,6 @@ var defaultKubernetesFeatureGates = map[featuregate.Feature]featuregate.FeatureS | ||||
|  | ||||
| 	CPUManagerPolicyOptions: {Default: true, PreRelease: featuregate.Beta}, | ||||
|  | ||||
| 	CSIMigrationAzureFile: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.28 | ||||
|  | ||||
| 	CSIMigrationGCE: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.27 | ||||
|  | ||||
| 	CSIMigrationPortworx: {Default: false, PreRelease: featuregate.Beta}, // Off by default (requires Portworx CSI driver) | ||||
|   | ||||
| @@ -1,18 +0,0 @@ | ||||
| # See the OWNERS docs at https://go.k8s.io/owners | ||||
|  | ||||
| approvers: | ||||
|   - andyzhangx | ||||
|   - feiskyer | ||||
|   - khenidak | ||||
| reviewers: | ||||
|   - andyzhangx | ||||
|   - feiskyer | ||||
|   - jsafrane | ||||
|   - jingxu97 | ||||
|   - khenidak | ||||
|   - msau42 | ||||
|   - saad-ali | ||||
| emeritus_approvers: | ||||
|   - karataliu | ||||
|   - rootfs | ||||
|   - brendandburns | ||||
| @@ -1,414 +0,0 @@ | ||||
| //go:build !providerless | ||||
| // +build !providerless | ||||
|  | ||||
| /* | ||||
| Copyright 2016 The Kubernetes Authors. | ||||
|  | ||||
| Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| you may not use this file except in compliance with the License. | ||||
| You may obtain a copy of the License at | ||||
|  | ||||
|     http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  | ||||
| Unless required by applicable law or agreed to in writing, software | ||||
| distributed under the License is distributed on an "AS IS" BASIS, | ||||
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| See the License for the specific language governing permissions and | ||||
| limitations under the License. | ||||
| */ | ||||
|  | ||||
| package azure_file | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"io/ioutil" | ||||
| 	"os" | ||||
| 	"runtime" | ||||
| 	"time" | ||||
|  | ||||
| 	"k8s.io/klog/v2" | ||||
| 	"k8s.io/mount-utils" | ||||
| 	utilstrings "k8s.io/utils/strings" | ||||
|  | ||||
| 	v1 "k8s.io/api/core/v1" | ||||
| 	"k8s.io/apimachinery/pkg/api/resource" | ||||
| 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||||
| 	"k8s.io/apimachinery/pkg/types" | ||||
| 	"k8s.io/apimachinery/pkg/util/wait" | ||||
| 	cloudprovider "k8s.io/cloud-provider" | ||||
| 	volumehelpers "k8s.io/cloud-provider/volume/helpers" | ||||
| 	"k8s.io/kubernetes/pkg/volume" | ||||
| 	volutil "k8s.io/kubernetes/pkg/volume/util" | ||||
| 	"k8s.io/legacy-cloud-providers/azure" | ||||
| ) | ||||
|  | ||||
| // ProbeVolumePlugins is the primary endpoint for volume plugins | ||||
| func ProbeVolumePlugins() []volume.VolumePlugin { | ||||
| 	return []volume.VolumePlugin{&azureFilePlugin{nil}} | ||||
| } | ||||
|  | ||||
| type azureFilePlugin struct { | ||||
| 	host volume.VolumeHost | ||||
| } | ||||
|  | ||||
| var _ volume.VolumePlugin = &azureFilePlugin{} | ||||
| var _ volume.PersistentVolumePlugin = &azureFilePlugin{} | ||||
| var _ volume.ExpandableVolumePlugin = &azureFilePlugin{} | ||||
|  | ||||
| const ( | ||||
| 	azureFilePluginName     = "kubernetes.io/azure-file" | ||||
| 	minimumPremiumShareSize = 100 // GB | ||||
| ) | ||||
|  | ||||
| func getPath(uid types.UID, volName string, host volume.VolumeHost) string { | ||||
| 	return host.GetPodVolumeDir(uid, utilstrings.EscapeQualifiedName(azureFilePluginName), volName) | ||||
| } | ||||
|  | ||||
| func (plugin *azureFilePlugin) Init(host volume.VolumeHost) error { | ||||
| 	plugin.host = host | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (plugin *azureFilePlugin) GetPluginName() string { | ||||
| 	return azureFilePluginName | ||||
| } | ||||
|  | ||||
| func (plugin *azureFilePlugin) GetVolumeName(spec *volume.Spec) (string, error) { | ||||
| 	share, _, err := getVolumeSource(spec) | ||||
| 	if err != nil { | ||||
| 		return "", err | ||||
| 	} | ||||
|  | ||||
| 	return share, nil | ||||
| } | ||||
|  | ||||
| func (plugin *azureFilePlugin) CanSupport(spec *volume.Spec) bool { | ||||
| 	//TODO: check if mount.cifs is there | ||||
| 	return (spec.PersistentVolume != nil && spec.PersistentVolume.Spec.AzureFile != nil) || | ||||
| 		(spec.Volume != nil && spec.Volume.AzureFile != nil) | ||||
| } | ||||
|  | ||||
| func (plugin *azureFilePlugin) RequiresRemount(spec *volume.Spec) bool { | ||||
| 	return false | ||||
| } | ||||
|  | ||||
| func (plugin *azureFilePlugin) SupportsMountOption() bool { | ||||
| 	return true | ||||
| } | ||||
|  | ||||
| func (plugin *azureFilePlugin) SupportsBulkVolumeVerification() bool { | ||||
| 	return false | ||||
| } | ||||
|  | ||||
| func (plugin *azureFilePlugin) SupportsSELinuxContextMount(spec *volume.Spec) (bool, error) { | ||||
| 	return false, nil | ||||
| } | ||||
|  | ||||
| func (plugin *azureFilePlugin) GetAccessModes() []v1.PersistentVolumeAccessMode { | ||||
| 	return []v1.PersistentVolumeAccessMode{ | ||||
| 		v1.ReadWriteOnce, | ||||
| 		v1.ReadOnlyMany, | ||||
| 		v1.ReadWriteMany, | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (plugin *azureFilePlugin) NewMounter(spec *volume.Spec, pod *v1.Pod, _ volume.VolumeOptions) (volume.Mounter, error) { | ||||
| 	return plugin.newMounterInternal(spec, pod, &azureSvc{}, plugin.host.GetMounter(plugin.GetPluginName())) | ||||
| } | ||||
|  | ||||
| func (plugin *azureFilePlugin) newMounterInternal(spec *volume.Spec, pod *v1.Pod, util azureUtil, mounter mount.Interface) (volume.Mounter, error) { | ||||
| 	share, readOnly, err := getVolumeSource(spec) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	secretName, secretNamespace, err := getSecretNameAndNamespace(spec, pod.Namespace) | ||||
| 	if err != nil { | ||||
| 		// Log-and-continue instead of returning an error for now | ||||
| 		// due to unspecified backwards compatibility concerns (a subject to revise) | ||||
| 		klog.Errorf("get secret name and namespace from pod(%s) return with error: %v", pod.Name, err) | ||||
| 	} | ||||
| 	return &azureFileMounter{ | ||||
| 		azureFile: &azureFile{ | ||||
| 			volName:         spec.Name(), | ||||
| 			mounter:         mounter, | ||||
| 			pod:             pod, | ||||
| 			plugin:          plugin, | ||||
| 			MetricsProvider: volume.NewMetricsStatFS(getPath(pod.UID, spec.Name(), plugin.host)), | ||||
| 		}, | ||||
| 		util:            util, | ||||
| 		secretNamespace: secretNamespace, | ||||
| 		secretName:      secretName, | ||||
| 		shareName:       share, | ||||
| 		readOnly:        readOnly, | ||||
| 		mountOptions:    volutil.MountOptionFromSpec(spec), | ||||
| 	}, nil | ||||
| } | ||||
|  | ||||
| func (plugin *azureFilePlugin) NewUnmounter(volName string, podUID types.UID) (volume.Unmounter, error) { | ||||
| 	return plugin.newUnmounterInternal(volName, podUID, plugin.host.GetMounter(plugin.GetPluginName())) | ||||
| } | ||||
|  | ||||
| func (plugin *azureFilePlugin) newUnmounterInternal(volName string, podUID types.UID, mounter mount.Interface) (volume.Unmounter, error) { | ||||
| 	return &azureFileUnmounter{&azureFile{ | ||||
| 		volName:         volName, | ||||
| 		mounter:         mounter, | ||||
| 		pod:             &v1.Pod{ObjectMeta: metav1.ObjectMeta{UID: podUID}}, | ||||
| 		plugin:          plugin, | ||||
| 		MetricsProvider: volume.NewMetricsStatFS(getPath(podUID, volName, plugin.host)), | ||||
| 	}}, nil | ||||
| } | ||||
|  | ||||
| func (plugin *azureFilePlugin) RequiresFSResize() bool { | ||||
| 	return false | ||||
| } | ||||
|  | ||||
| func (plugin *azureFilePlugin) ExpandVolumeDevice( | ||||
| 	spec *volume.Spec, | ||||
| 	newSize resource.Quantity, | ||||
| 	oldSize resource.Quantity) (resource.Quantity, error) { | ||||
|  | ||||
| 	if spec.PersistentVolume == nil || spec.PersistentVolume.Spec.AzureFile == nil { | ||||
| 		return oldSize, fmt.Errorf("invalid PV spec") | ||||
| 	} | ||||
| 	shareName := spec.PersistentVolume.Spec.AzureFile.ShareName | ||||
| 	azure, resourceGroup, err := getAzureCloudProvider(plugin.host.GetCloudProvider()) | ||||
| 	if err != nil { | ||||
| 		return oldSize, err | ||||
| 	} | ||||
| 	if spec.PersistentVolume.ObjectMeta.Annotations[resourceGroupAnnotation] != "" { | ||||
| 		resourceGroup = spec.PersistentVolume.ObjectMeta.Annotations[resourceGroupAnnotation] | ||||
| 	} | ||||
|  | ||||
| 	secretName, secretNamespace, err := getSecretNameAndNamespace(spec, spec.PersistentVolume.Spec.ClaimRef.Namespace) | ||||
| 	if err != nil { | ||||
| 		return oldSize, err | ||||
| 	} | ||||
|  | ||||
| 	accountName, _, err := (&azureSvc{}).GetAzureCredentials(plugin.host, secretNamespace, secretName) | ||||
| 	if err != nil { | ||||
| 		return oldSize, err | ||||
| 	} | ||||
|  | ||||
| 	requestGiB, err := volumehelpers.RoundUpToGiBInt(newSize) | ||||
|  | ||||
| 	if err != nil { | ||||
| 		return oldSize, err | ||||
| 	} | ||||
|  | ||||
| 	if err := azure.ResizeFileShare(resourceGroup, accountName, shareName, requestGiB); err != nil { | ||||
| 		return oldSize, err | ||||
| 	} | ||||
|  | ||||
| 	return newSize, nil | ||||
| } | ||||
|  | ||||
| func (plugin *azureFilePlugin) ConstructVolumeSpec(volName, mountPath string) (volume.ReconstructedVolume, error) { | ||||
| 	azureVolume := &v1.Volume{ | ||||
| 		Name: volName, | ||||
| 		VolumeSource: v1.VolumeSource{ | ||||
| 			AzureFile: &v1.AzureFileVolumeSource{ | ||||
| 				SecretName: volName, | ||||
| 				ShareName:  volName, | ||||
| 			}, | ||||
| 		}, | ||||
| 	} | ||||
| 	return volume.ReconstructedVolume{ | ||||
| 		Spec: volume.NewSpecFromVolume(azureVolume), | ||||
| 	}, nil | ||||
| } | ||||
|  | ||||
| // azureFile volumes represent mount of an AzureFile share. | ||||
| type azureFile struct { | ||||
| 	volName string | ||||
| 	podUID  types.UID | ||||
| 	pod     *v1.Pod | ||||
| 	mounter mount.Interface | ||||
| 	plugin  *azureFilePlugin | ||||
| 	volume.MetricsProvider | ||||
| } | ||||
|  | ||||
| func (azureFileVolume *azureFile) GetPath() string { | ||||
| 	return getPath(azureFileVolume.pod.UID, azureFileVolume.volName, azureFileVolume.plugin.host) | ||||
| } | ||||
|  | ||||
| type azureFileMounter struct { | ||||
| 	*azureFile | ||||
| 	util            azureUtil | ||||
| 	secretName      string | ||||
| 	secretNamespace string | ||||
| 	shareName       string | ||||
| 	readOnly        bool | ||||
| 	mountOptions    []string | ||||
| } | ||||
|  | ||||
| var _ volume.Mounter = &azureFileMounter{} | ||||
|  | ||||
| func (b *azureFileMounter) GetAttributes() volume.Attributes { | ||||
| 	return volume.Attributes{ | ||||
| 		ReadOnly:       b.readOnly, | ||||
| 		Managed:        !b.readOnly, | ||||
| 		SELinuxRelabel: false, | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // SetUp attaches the disk and bind mounts to the volume path. | ||||
| func (b *azureFileMounter) SetUp(mounterArgs volume.MounterArgs) error { | ||||
| 	return b.SetUpAt(b.GetPath(), mounterArgs) | ||||
| } | ||||
|  | ||||
| func (b *azureFileMounter) SetUpAt(dir string, mounterArgs volume.MounterArgs) error { | ||||
| 	notMnt, err := b.mounter.IsLikelyNotMountPoint(dir) | ||||
| 	klog.V(4).Infof("AzureFile mount set up: %s %v %v", dir, !notMnt, err) | ||||
| 	if err != nil && !os.IsNotExist(err) { | ||||
| 		return err | ||||
| 	} | ||||
| 	if !notMnt { | ||||
| 		// testing original mount point, make sure the mount link is valid | ||||
| 		if _, err := ioutil.ReadDir(dir); err == nil { | ||||
| 			klog.V(4).Infof("azureFile - already mounted to target %s", dir) | ||||
| 			return nil | ||||
| 		} | ||||
| 		// mount link is invalid, now unmount and remount later | ||||
| 		klog.Warningf("azureFile - ReadDir %s failed with %v, unmount this directory", dir, err) | ||||
| 		if err := b.mounter.Unmount(dir); err != nil { | ||||
| 			klog.Errorf("azureFile - Unmount directory %s failed with %v", dir, err) | ||||
| 			return err | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	var accountKey, accountName string | ||||
| 	if accountName, accountKey, err = b.util.GetAzureCredentials(b.plugin.host, b.secretNamespace, b.secretName); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	var mountOptions []string | ||||
| 	var sensitiveMountOptions []string | ||||
| 	source := "" | ||||
| 	osSeparator := string(os.PathSeparator) | ||||
| 	source = fmt.Sprintf("%s%s%s.file.%s%s%s", osSeparator, osSeparator, accountName, getStorageEndpointSuffix(b.plugin.host.GetCloudProvider()), osSeparator, b.shareName) | ||||
|  | ||||
| 	if runtime.GOOS == "windows" { | ||||
| 		mountOptions = []string{fmt.Sprintf("AZURE\\%s", accountName)} | ||||
| 		sensitiveMountOptions = []string{accountKey} | ||||
| 	} else { | ||||
| 		if err := os.MkdirAll(dir, 0700); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		// parameters suggested by https://azure.microsoft.com/en-us/documentation/articles/storage-how-to-use-files-linux/ | ||||
| 		options := []string{} | ||||
| 		sensitiveMountOptions = []string{fmt.Sprintf("username=%s,password=%s", accountName, accountKey)} | ||||
| 		if b.readOnly { | ||||
| 			options = append(options, "ro") | ||||
| 		} | ||||
| 		mountOptions = volutil.JoinMountOptions(b.mountOptions, options) | ||||
| 		mountOptions = appendDefaultMountOptions(mountOptions, mounterArgs.FsGroup) | ||||
| 	} | ||||
|  | ||||
| 	mountComplete := false | ||||
| 	err = wait.PollImmediate(1*time.Second, 2*time.Minute, func() (bool, error) { | ||||
| 		err := b.mounter.MountSensitiveWithoutSystemd(source, dir, "cifs", mountOptions, sensitiveMountOptions) | ||||
| 		mountComplete = true | ||||
| 		return true, err | ||||
| 	}) | ||||
| 	if !mountComplete { | ||||
| 		return fmt.Errorf("volume(%s) mount on %s timeout(10m)", source, dir) | ||||
| 	} | ||||
| 	if err != nil { | ||||
| 		notMnt, mntErr := b.mounter.IsLikelyNotMountPoint(dir) | ||||
| 		if mntErr != nil { | ||||
| 			klog.Errorf("IsLikelyNotMountPoint check failed: %v", mntErr) | ||||
| 			return err | ||||
| 		} | ||||
| 		if !notMnt { | ||||
| 			if mntErr = b.mounter.Unmount(dir); mntErr != nil { | ||||
| 				klog.Errorf("Failed to unmount: %v", mntErr) | ||||
| 				return err | ||||
| 			} | ||||
| 			notMnt, mntErr := b.mounter.IsLikelyNotMountPoint(dir) | ||||
| 			if mntErr != nil { | ||||
| 				klog.Errorf("IsLikelyNotMountPoint check failed: %v", mntErr) | ||||
| 				return err | ||||
| 			} | ||||
| 			if !notMnt { | ||||
| 				// This is very odd, we don't expect it.  We'll try again next sync loop. | ||||
| 				klog.Errorf("%s is still mounted, despite call to unmount().  Will try again next sync loop.", dir) | ||||
| 				return err | ||||
| 			} | ||||
| 		} | ||||
| 		os.Remove(dir) | ||||
| 		return err | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| var _ volume.Unmounter = &azureFileUnmounter{} | ||||
|  | ||||
| type azureFileUnmounter struct { | ||||
| 	*azureFile | ||||
| } | ||||
|  | ||||
| func (c *azureFileUnmounter) TearDown() error { | ||||
| 	return c.TearDownAt(c.GetPath()) | ||||
| } | ||||
|  | ||||
| func (c *azureFileUnmounter) TearDownAt(dir string) error { | ||||
| 	return mount.CleanupMountPoint(dir, c.mounter, false) | ||||
| } | ||||
|  | ||||
| func getVolumeSource(spec *volume.Spec) (string, bool, error) { | ||||
| 	if spec.Volume != nil && spec.Volume.AzureFile != nil { | ||||
| 		share := spec.Volume.AzureFile.ShareName | ||||
| 		readOnly := spec.Volume.AzureFile.ReadOnly | ||||
| 		return share, readOnly, nil | ||||
| 	} else if spec.PersistentVolume != nil && | ||||
| 		spec.PersistentVolume.Spec.AzureFile != nil { | ||||
| 		share := spec.PersistentVolume.Spec.AzureFile.ShareName | ||||
| 		readOnly := spec.ReadOnly | ||||
| 		return share, readOnly, nil | ||||
| 	} | ||||
| 	return "", false, fmt.Errorf("Spec does not reference an AzureFile volume type") | ||||
| } | ||||
|  | ||||
| func getSecretNameAndNamespace(spec *volume.Spec, defaultNamespace string) (string, string, error) { | ||||
| 	secretName := "" | ||||
| 	secretNamespace := "" | ||||
| 	if spec.Volume != nil && spec.Volume.AzureFile != nil { | ||||
| 		secretName = spec.Volume.AzureFile.SecretName | ||||
| 		secretNamespace = defaultNamespace | ||||
|  | ||||
| 	} else if spec.PersistentVolume != nil && | ||||
| 		spec.PersistentVolume.Spec.AzureFile != nil { | ||||
| 		secretNamespace = defaultNamespace | ||||
| 		if spec.PersistentVolume.Spec.AzureFile.SecretNamespace != nil { | ||||
| 			secretNamespace = *spec.PersistentVolume.Spec.AzureFile.SecretNamespace | ||||
| 		} | ||||
| 		secretName = spec.PersistentVolume.Spec.AzureFile.SecretName | ||||
| 	} else { | ||||
| 		return "", "", fmt.Errorf("Spec does not reference an AzureFile volume type") | ||||
| 	} | ||||
|  | ||||
| 	if len(secretNamespace) == 0 { | ||||
| 		return "", "", fmt.Errorf("invalid Azure volume: nil namespace") | ||||
| 	} | ||||
| 	return secretName, secretNamespace, nil | ||||
|  | ||||
| } | ||||
|  | ||||
| func getAzureCloud(cloudProvider cloudprovider.Interface) (*azure.Cloud, error) { | ||||
| 	azure, ok := cloudProvider.(*azure.Cloud) | ||||
| 	if !ok || azure == nil { | ||||
| 		return nil, fmt.Errorf("failed to get Azure Cloud Provider. GetCloudProvider returned %v instead", cloudProvider) | ||||
| 	} | ||||
|  | ||||
| 	return azure, nil | ||||
| } | ||||
|  | ||||
| func getStorageEndpointSuffix(cloudprovider cloudprovider.Interface) string { | ||||
| 	const publicCloudStorageEndpointSuffix = "core.windows.net" | ||||
| 	azure, err := getAzureCloud(cloudprovider) | ||||
| 	if err != nil { | ||||
| 		klog.Warningf("No Azure cloud provider found. Using the Azure public cloud endpoint: %s", publicCloudStorageEndpointSuffix) | ||||
| 		return publicCloudStorageEndpointSuffix | ||||
| 	} | ||||
| 	return azure.Environment.StorageEndpointSuffix | ||||
| } | ||||
| @@ -1,454 +0,0 @@ | ||||
| //go:build !providerless | ||||
| // +build !providerless | ||||
|  | ||||
| /* | ||||
| Copyright 2016 The Kubernetes Authors. | ||||
|  | ||||
| Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| you may not use this file except in compliance with the License. | ||||
| You may obtain a copy of the License at | ||||
|  | ||||
|     http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  | ||||
| Unless required by applicable law or agreed to in writing, software | ||||
| distributed under the License is distributed on an "AS IS" BASIS, | ||||
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| See the License for the specific language governing permissions and | ||||
| limitations under the License. | ||||
| */ | ||||
|  | ||||
| package azure_file | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"io/ioutil" | ||||
| 	"os" | ||||
| 	"path/filepath" | ||||
| 	"reflect" | ||||
| 	goruntime "runtime" | ||||
| 	"strings" | ||||
| 	"testing" | ||||
|  | ||||
| 	v1 "k8s.io/api/core/v1" | ||||
| 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||||
| 	"k8s.io/apimachinery/pkg/types" | ||||
| 	"k8s.io/client-go/kubernetes/fake" | ||||
| 	fakecloud "k8s.io/cloud-provider/fake" | ||||
| 	"k8s.io/mount-utils" | ||||
| 	"k8s.io/utils/pointer" | ||||
|  | ||||
| 	"k8s.io/kubernetes/pkg/volume" | ||||
| 	volumetest "k8s.io/kubernetes/pkg/volume/testing" | ||||
| 	"k8s.io/legacy-cloud-providers/azure" | ||||
| ) | ||||
|  | ||||
| func TestCanSupport(t *testing.T) { | ||||
| 	tmpDir, err := ioutil.TempDir(os.TempDir(), "azureFileTest") | ||||
| 	if err != nil { | ||||
| 		t.Fatalf("can't make a temp dir: %v", err) | ||||
| 	} | ||||
| 	defer os.RemoveAll(tmpDir) | ||||
| 	plugMgr := volume.VolumePluginMgr{} | ||||
| 	plugMgr.InitPlugins(ProbeVolumePlugins(), nil /* prober */, volumetest.NewFakeVolumeHost(t, tmpDir, nil, nil)) | ||||
|  | ||||
| 	plug, err := plugMgr.FindPluginByName("kubernetes.io/azure-file") | ||||
| 	if err != nil { | ||||
| 		t.Fatal("Can't find the plugin by name") | ||||
| 	} | ||||
| 	if plug.GetPluginName() != "kubernetes.io/azure-file" { | ||||
| 		t.Errorf("Wrong name: %s", plug.GetPluginName()) | ||||
| 	} | ||||
| 	if !plug.CanSupport(&volume.Spec{Volume: &v1.Volume{VolumeSource: v1.VolumeSource{AzureFile: &v1.AzureFileVolumeSource{}}}}) { | ||||
| 		t.Errorf("Expected true") | ||||
| 	} | ||||
| 	if !plug.CanSupport(&volume.Spec{PersistentVolume: &v1.PersistentVolume{Spec: v1.PersistentVolumeSpec{PersistentVolumeSource: v1.PersistentVolumeSource{AzureFile: &v1.AzureFilePersistentVolumeSource{}}}}}) { | ||||
| 		t.Errorf("Expected true") | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestGetAccessModes(t *testing.T) { | ||||
| 	tmpDir, err := ioutil.TempDir(os.TempDir(), "azureFileTest") | ||||
| 	if err != nil { | ||||
| 		t.Fatalf("can't make a temp dir: %v", err) | ||||
| 	} | ||||
| 	defer os.RemoveAll(tmpDir) | ||||
| 	plugMgr := volume.VolumePluginMgr{} | ||||
| 	plugMgr.InitPlugins(ProbeVolumePlugins(), nil /* prober */, volumetest.NewFakeVolumeHost(t, tmpDir, nil, nil)) | ||||
|  | ||||
| 	plug, err := plugMgr.FindPersistentPluginByName("kubernetes.io/azure-file") | ||||
| 	if err != nil { | ||||
| 		t.Errorf("Can't find the plugin by name") | ||||
| 	} | ||||
| 	if !volumetest.ContainsAccessMode(plug.GetAccessModes(), v1.ReadWriteOnce) || !volumetest.ContainsAccessMode(plug.GetAccessModes(), v1.ReadOnlyMany) || !volumetest.ContainsAccessMode(plug.GetAccessModes(), v1.ReadWriteMany) { | ||||
| 		t.Errorf("Expected three AccessModeTypes:  %s, %s, and %s", v1.ReadWriteOnce, v1.ReadOnlyMany, v1.ReadWriteMany) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func getAzureTestCloud(t *testing.T) *azure.Cloud { | ||||
| 	config := `{ | ||||
|                 "aadClientId": "--aad-client-id--", | ||||
|                 "aadClientSecret": "--aad-client-secret--" | ||||
|         }` | ||||
| 	configReader := strings.NewReader(config) | ||||
| 	azureCloud, err := azure.NewCloudWithoutFeatureGates(configReader) | ||||
| 	if err != nil { | ||||
| 		t.Error(err) | ||||
| 	} | ||||
| 	return azureCloud | ||||
| } | ||||
|  | ||||
| func getTestTempDir(t *testing.T) string { | ||||
| 	tmpDir, err := ioutil.TempDir(os.TempDir(), "azurefileTest") | ||||
| 	if err != nil { | ||||
| 		t.Fatalf("can't make a temp dir: %v", err) | ||||
| 	} | ||||
| 	return tmpDir | ||||
| } | ||||
|  | ||||
| func TestPluginAzureCloudProvider(t *testing.T) { | ||||
| 	tmpDir := getTestTempDir(t) | ||||
| 	defer os.RemoveAll(tmpDir) | ||||
| 	testPlugin(t, tmpDir, volumetest.NewFakeVolumeHostWithCloudProvider(t, tmpDir, nil, nil, getAzureTestCloud(t))) | ||||
| } | ||||
|  | ||||
| func TestPluginWithoutCloudProvider(t *testing.T) { | ||||
| 	tmpDir := getTestTempDir(t) | ||||
| 	defer os.RemoveAll(tmpDir) | ||||
| 	testPlugin(t, tmpDir, volumetest.NewFakeVolumeHost(t, tmpDir, nil, nil)) | ||||
| } | ||||
|  | ||||
| func TestPluginWithOtherCloudProvider(t *testing.T) { | ||||
| 	tmpDir := getTestTempDir(t) | ||||
| 	defer os.RemoveAll(tmpDir) | ||||
| 	cloud := &fakecloud.Cloud{} | ||||
| 	testPlugin(t, tmpDir, volumetest.NewFakeVolumeHostWithCloudProvider(t, tmpDir, nil, nil, cloud)) | ||||
| } | ||||
|  | ||||
| func testPlugin(t *testing.T, tmpDir string, volumeHost volume.VolumeHost) { | ||||
| 	plugMgr := volume.VolumePluginMgr{} | ||||
| 	plugMgr.InitPlugins(ProbeVolumePlugins(), nil /* prober */, volumeHost) | ||||
|  | ||||
| 	plug, err := plugMgr.FindPluginByName("kubernetes.io/azure-file") | ||||
| 	if err != nil { | ||||
| 		t.Errorf("Can't find the plugin by name") | ||||
| 	} | ||||
| 	spec := &v1.Volume{ | ||||
| 		Name: "vol1", | ||||
| 		VolumeSource: v1.VolumeSource{ | ||||
| 			AzureFile: &v1.AzureFileVolumeSource{ | ||||
| 				SecretName: "secret", | ||||
| 				ShareName:  "share", | ||||
| 			}, | ||||
| 		}, | ||||
| 	} | ||||
| 	fake := mount.NewFakeMounter(nil) | ||||
| 	pod := &v1.Pod{ObjectMeta: metav1.ObjectMeta{UID: types.UID("poduid")}} | ||||
| 	mounter, err := plug.(*azureFilePlugin).newMounterInternal(volume.NewSpecFromVolume(spec), pod, &fakeAzureSvc{}, fake) | ||||
| 	if err != nil { | ||||
| 		t.Errorf("Failed to make a new Mounter: %v", err) | ||||
| 	} | ||||
| 	if mounter == nil { | ||||
| 		t.Errorf("Got a nil Mounter") | ||||
| 	} | ||||
| 	volPath := filepath.Join(tmpDir, "pods/poduid/volumes/kubernetes.io~azure-file/vol1") | ||||
| 	path := mounter.GetPath() | ||||
| 	if path != volPath { | ||||
| 		t.Errorf("Got unexpected path: %s", path) | ||||
| 	} | ||||
|  | ||||
| 	if err := mounter.SetUp(volume.MounterArgs{}); err != nil { | ||||
| 		t.Errorf("Expected success, got: %v", err) | ||||
| 	} | ||||
| 	// On Windows, Mount will create the parent of dir and mklink (create a symbolic link) at the volume path later, | ||||
| 	// so mounter.SetUp will not create the directory. Otherwise mklink will error: "Cannot create a file when that file already exists". | ||||
| 	if goruntime.GOOS != "windows" { | ||||
| 		if _, err := os.Stat(path); err != nil { | ||||
| 			if os.IsNotExist(err) { | ||||
| 				t.Errorf("SetUp() failed, volume path not created: %s", path) | ||||
| 			} else { | ||||
| 				t.Errorf("SetUp() failed: %v", err) | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	unmounter, err := plug.(*azureFilePlugin).newUnmounterInternal("vol1", types.UID("poduid"), mount.NewFakeMounter(nil)) | ||||
| 	if err != nil { | ||||
| 		t.Errorf("Failed to make a new Unmounter: %v", err) | ||||
| 	} | ||||
| 	if unmounter == nil { | ||||
| 		t.Errorf("Got a nil Unmounter") | ||||
| 	} | ||||
|  | ||||
| 	if err := unmounter.TearDown(); err != nil { | ||||
| 		t.Errorf("Expected success, got: %v", err) | ||||
| 	} | ||||
| 	if _, err := os.Stat(path); err == nil { | ||||
| 		t.Errorf("TearDown() failed, volume path still exists: %s", path) | ||||
| 	} else if !os.IsNotExist(err) { | ||||
| 		t.Errorf("TearDown() failed: %v", err) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestPersistentClaimReadOnlyFlag(t *testing.T) { | ||||
| 	pv := &v1.PersistentVolume{ | ||||
| 		ObjectMeta: metav1.ObjectMeta{ | ||||
| 			Name: "pvA", | ||||
| 		}, | ||||
| 		Spec: v1.PersistentVolumeSpec{ | ||||
| 			PersistentVolumeSource: v1.PersistentVolumeSource{ | ||||
| 				AzureFile: &v1.AzureFilePersistentVolumeSource{}, | ||||
| 			}, | ||||
| 			ClaimRef: &v1.ObjectReference{ | ||||
| 				Name: "claimA", | ||||
| 			}, | ||||
| 		}, | ||||
| 	} | ||||
|  | ||||
| 	claim := &v1.PersistentVolumeClaim{ | ||||
| 		ObjectMeta: metav1.ObjectMeta{ | ||||
| 			Name:      "claimA", | ||||
| 			Namespace: "nsA", | ||||
| 		}, | ||||
| 		Spec: v1.PersistentVolumeClaimSpec{ | ||||
| 			VolumeName: "pvA", | ||||
| 		}, | ||||
| 		Status: v1.PersistentVolumeClaimStatus{ | ||||
| 			Phase: v1.ClaimBound, | ||||
| 		}, | ||||
| 	} | ||||
|  | ||||
| 	client := fake.NewSimpleClientset(pv, claim) | ||||
|  | ||||
| 	plugMgr := volume.VolumePluginMgr{} | ||||
| 	plugMgr.InitPlugins(ProbeVolumePlugins(), nil /* prober */, volumetest.NewFakeVolumeHost(t, filepath.Join(os.TempDir(), "fake"), client, nil)) | ||||
| 	plug, _ := plugMgr.FindPluginByName(azureFilePluginName) | ||||
|  | ||||
| 	// readOnly bool is supplied by persistent-claim volume source when its mounter creates other volumes | ||||
| 	spec := volume.NewSpecFromPersistentVolume(pv, true) | ||||
| 	pod := &v1.Pod{ObjectMeta: metav1.ObjectMeta{UID: types.UID("poduid")}} | ||||
| 	mounter, _ := plug.NewMounter(spec, pod, volume.VolumeOptions{}) | ||||
| 	if mounter == nil { | ||||
| 		t.Fatalf("Got a nil Mounter") | ||||
| 	} | ||||
|  | ||||
| 	if !mounter.GetAttributes().ReadOnly { | ||||
| 		t.Errorf("Expected true for mounter.IsReadOnly") | ||||
| 	} | ||||
| } | ||||
|  | ||||
| type fakeAzureSvc struct{} | ||||
|  | ||||
| func (s *fakeAzureSvc) GetAzureCredentials(host volume.VolumeHost, nameSpace, secretName string) (string, string, error) { | ||||
| 	return "name", "key", nil | ||||
| } | ||||
| func (s *fakeAzureSvc) SetAzureCredentials(host volume.VolumeHost, nameSpace, accountName, accountKey string) (string, error) { | ||||
| 	return "secret", nil | ||||
| } | ||||
|  | ||||
| func TestMounterAndUnmounterTypeAssert(t *testing.T) { | ||||
| 	tmpDir, err := ioutil.TempDir(os.TempDir(), "azurefileTest") | ||||
| 	if err != nil { | ||||
| 		t.Fatalf("can't make a temp dir: %v", err) | ||||
| 	} | ||||
| 	defer os.RemoveAll(tmpDir) | ||||
| 	plugMgr := volume.VolumePluginMgr{} | ||||
| 	plugMgr.InitPlugins(ProbeVolumePlugins(), nil /* prober */, volumetest.NewFakeVolumeHost(t, tmpDir, nil, nil)) | ||||
|  | ||||
| 	plug, err := plugMgr.FindPluginByName("kubernetes.io/azure-file") | ||||
| 	if err != nil { | ||||
| 		t.Errorf("Can't find the plugin by name") | ||||
| 	} | ||||
| 	spec := &v1.Volume{ | ||||
| 		Name: "vol1", | ||||
| 		VolumeSource: v1.VolumeSource{ | ||||
| 			AzureFile: &v1.AzureFileVolumeSource{ | ||||
| 				SecretName: "secret", | ||||
| 				ShareName:  "share", | ||||
| 			}, | ||||
| 		}, | ||||
| 	} | ||||
| 	fake := mount.NewFakeMounter(nil) | ||||
| 	pod := &v1.Pod{ObjectMeta: metav1.ObjectMeta{UID: types.UID("poduid")}} | ||||
| 	mounter, err := plug.(*azureFilePlugin).newMounterInternal(volume.NewSpecFromVolume(spec), pod, &fakeAzureSvc{}, fake) | ||||
| 	if err != nil { | ||||
| 		t.Errorf("MounterInternal() failed: %v", err) | ||||
| 	} | ||||
| 	if _, ok := mounter.(volume.Unmounter); ok { | ||||
| 		t.Errorf("Volume Mounter can be type-assert to Unmounter") | ||||
| 	} | ||||
|  | ||||
| 	unmounter, err := plug.(*azureFilePlugin).newUnmounterInternal("vol1", types.UID("poduid"), mount.NewFakeMounter(nil)) | ||||
| 	if err != nil { | ||||
| 		t.Errorf("MounterInternal() failed: %v", err) | ||||
| 	} | ||||
| 	if _, ok := unmounter.(volume.Mounter); ok { | ||||
| 		t.Errorf("Volume Unmounter can be type-assert to Mounter") | ||||
| 	} | ||||
| } | ||||
|  | ||||
| type testcase struct { | ||||
| 	name      string | ||||
| 	defaultNs string | ||||
| 	spec      *volume.Spec | ||||
| 	// Expected return of the test | ||||
| 	expectedName  string | ||||
| 	expectedNs    string | ||||
| 	expectedError error | ||||
| } | ||||
|  | ||||
| func TestGetSecretNameAndNamespaceForPV(t *testing.T) { | ||||
| 	secretNs := "ns" | ||||
| 	tests := []testcase{ | ||||
| 		{ | ||||
| 			name:      "persistent volume source", | ||||
| 			defaultNs: "default", | ||||
| 			spec: &volume.Spec{ | ||||
| 				PersistentVolume: &v1.PersistentVolume{ | ||||
| 					Spec: v1.PersistentVolumeSpec{ | ||||
| 						PersistentVolumeSource: v1.PersistentVolumeSource{ | ||||
| 							AzureFile: &v1.AzureFilePersistentVolumeSource{ | ||||
| 								ShareName:       "share", | ||||
| 								SecretName:      "name", | ||||
| 								SecretNamespace: &secretNs, | ||||
| 							}, | ||||
| 						}, | ||||
| 					}, | ||||
| 				}, | ||||
| 			}, | ||||
| 			expectedName:  "name", | ||||
| 			expectedNs:    "ns", | ||||
| 			expectedError: nil, | ||||
| 		}, | ||||
| 		{ | ||||
| 			name:      "persistent volume source without namespace", | ||||
| 			defaultNs: "default", | ||||
| 			spec: &volume.Spec{ | ||||
| 				PersistentVolume: &v1.PersistentVolume{ | ||||
| 					Spec: v1.PersistentVolumeSpec{ | ||||
| 						PersistentVolumeSource: v1.PersistentVolumeSource{ | ||||
| 							AzureFile: &v1.AzureFilePersistentVolumeSource{ | ||||
| 								ShareName:  "share", | ||||
| 								SecretName: "name", | ||||
| 							}, | ||||
| 						}, | ||||
| 					}, | ||||
| 				}, | ||||
| 			}, | ||||
| 			expectedName:  "name", | ||||
| 			expectedNs:    "default", | ||||
| 			expectedError: nil, | ||||
| 		}, | ||||
| 		{ | ||||
| 			name:      "pod volume source", | ||||
| 			defaultNs: "default", | ||||
| 			spec: &volume.Spec{ | ||||
| 				Volume: &v1.Volume{ | ||||
| 					VolumeSource: v1.VolumeSource{ | ||||
| 						AzureFile: &v1.AzureFileVolumeSource{ | ||||
| 							ShareName:  "share", | ||||
| 							SecretName: "name", | ||||
| 						}, | ||||
| 					}, | ||||
| 				}, | ||||
| 			}, | ||||
| 			expectedName:  "name", | ||||
| 			expectedNs:    "default", | ||||
| 			expectedError: nil, | ||||
| 		}, | ||||
| 	} | ||||
| 	for _, testcase := range tests { | ||||
| 		resultName, resultNs, err := getSecretNameAndNamespace(testcase.spec, testcase.defaultNs) | ||||
| 		if err != testcase.expectedError || resultName != testcase.expectedName || resultNs != testcase.expectedNs { | ||||
| 			t.Errorf("%s failed: expected err=%v ns=%q name=%q, got %v/%q/%q", testcase.name, testcase.expectedError, testcase.expectedNs, testcase.expectedName, | ||||
| 				err, resultNs, resultName) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| } | ||||
|  | ||||
| func TestAppendDefaultMountOptions(t *testing.T) { | ||||
| 	tests := []struct { | ||||
| 		options  []string | ||||
| 		fsGroup  *int64 | ||||
| 		expected []string | ||||
| 	}{ | ||||
| 		{ | ||||
| 			options: []string{"dir_mode=0777"}, | ||||
| 			fsGroup: nil, | ||||
| 			expected: []string{"dir_mode=0777", | ||||
| 				fmt.Sprintf("%s=%s", fileMode, defaultFileMode), | ||||
| 				fmt.Sprintf("%s=%s", vers, defaultVers), | ||||
| 				fmt.Sprintf("%s=%s", actimeo, defaultActimeo), | ||||
| 				mfsymlinks, | ||||
| 			}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			options: []string{"file_mode=0777"}, | ||||
| 			fsGroup: pointer.Int64(0), | ||||
| 			expected: []string{"file_mode=0777", | ||||
| 				fmt.Sprintf("%s=%s", dirMode, defaultDirMode), | ||||
| 				fmt.Sprintf("%s=%s", vers, defaultVers), | ||||
| 				fmt.Sprintf("%s=0", gid), | ||||
| 				fmt.Sprintf("%s=%s", actimeo, defaultActimeo), | ||||
| 				mfsymlinks, | ||||
| 			}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			options: []string{"vers=2.1"}, | ||||
| 			fsGroup: pointer.Int64(1000), | ||||
| 			expected: []string{"vers=2.1", | ||||
| 				fmt.Sprintf("%s=%s", fileMode, defaultFileMode), | ||||
| 				fmt.Sprintf("%s=%s", dirMode, defaultDirMode), | ||||
| 				fmt.Sprintf("%s=1000", gid), | ||||
| 				fmt.Sprintf("%s=%s", actimeo, defaultActimeo), | ||||
| 				mfsymlinks, | ||||
| 			}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			options: []string{""}, | ||||
| 			expected: []string{"", fmt.Sprintf("%s=%s", | ||||
| 				fileMode, defaultFileMode), | ||||
| 				fmt.Sprintf("%s=%s", dirMode, defaultDirMode), | ||||
| 				fmt.Sprintf("%s=%s", vers, defaultVers), | ||||
| 				fmt.Sprintf("%s=%s", actimeo, defaultActimeo), | ||||
| 				mfsymlinks, | ||||
| 			}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			options: []string{"file_mode=0777", "dir_mode=0777"}, | ||||
| 			expected: []string{"file_mode=0777", "dir_mode=0777", | ||||
| 				fmt.Sprintf("%s=%s", vers, defaultVers), | ||||
| 				fmt.Sprintf("%s=%s", actimeo, defaultActimeo), | ||||
| 				mfsymlinks, | ||||
| 			}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			options: []string{"gid=2000"}, | ||||
| 			fsGroup: pointer.Int64(1000), | ||||
| 			expected: []string{"gid=2000", | ||||
| 				fmt.Sprintf("%s=%s", fileMode, defaultFileMode), | ||||
| 				fmt.Sprintf("%s=%s", dirMode, defaultDirMode), | ||||
| 				"vers=3.0", | ||||
| 				fmt.Sprintf("%s=%s", actimeo, defaultActimeo), | ||||
| 				mfsymlinks, | ||||
| 			}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			options: []string{"actimeo=3"}, | ||||
| 			expected: []string{ | ||||
| 				"actimeo=3", | ||||
| 				fmt.Sprintf("%s=%s", fileMode, defaultFileMode), | ||||
| 				fmt.Sprintf("%s=%s", dirMode, defaultDirMode), | ||||
| 				fmt.Sprintf("%s=%s", vers, defaultVers), | ||||
| 				mfsymlinks, | ||||
| 			}, | ||||
| 		}, | ||||
| 	} | ||||
|  | ||||
| 	for _, test := range tests { | ||||
| 		result := appendDefaultMountOptions(test.options, test.fsGroup) | ||||
| 		if !reflect.DeepEqual(result, test.expected) { | ||||
| 			t.Errorf("input: %q, appendDefaultMountOptions result: %q, expected: %q", test.options, result, test.expected) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| @@ -1,284 +0,0 @@ | ||||
| //go:build !providerless | ||||
| // +build !providerless | ||||
|  | ||||
| /* | ||||
| Copyright 2017 The Kubernetes Authors. | ||||
|  | ||||
| Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| you may not use this file except in compliance with the License. | ||||
| You may obtain a copy of the License at | ||||
|  | ||||
|     http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  | ||||
| Unless required by applicable law or agreed to in writing, software | ||||
| distributed under the License is distributed on an "AS IS" BASIS, | ||||
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| See the License for the specific language governing permissions and | ||||
| limitations under the License. | ||||
| */ | ||||
|  | ||||
| package azure_file | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"strings" | ||||
|  | ||||
| 	"github.com/Azure/azure-sdk-for-go/services/storage/mgmt/2019-06-01/storage" | ||||
| 	v1 "k8s.io/api/core/v1" | ||||
| 	"k8s.io/apimachinery/pkg/api/resource" | ||||
| 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||||
| 	cloudprovider "k8s.io/cloud-provider" | ||||
| 	volumehelpers "k8s.io/cloud-provider/volume/helpers" | ||||
| 	"k8s.io/klog/v2" | ||||
| 	"k8s.io/kubernetes/pkg/volume" | ||||
| 	"k8s.io/kubernetes/pkg/volume/util" | ||||
| 	"k8s.io/legacy-cloud-providers/azure" | ||||
| 	"k8s.io/legacy-cloud-providers/azure/clients/fileclient" | ||||
| 	utilstrings "k8s.io/utils/strings" | ||||
| ) | ||||
|  | ||||
| var ( | ||||
| 	_ volume.DeletableVolumePlugin     = &azureFilePlugin{} | ||||
| 	_ volume.ProvisionableVolumePlugin = &azureFilePlugin{} | ||||
|  | ||||
| 	resourceGroupAnnotation = "kubernetes.io/azure-file-resource-group" | ||||
| ) | ||||
|  | ||||
| // Abstract interface to file share operations. | ||||
| // azure cloud provider should implement it | ||||
| type azureCloudProvider interface { | ||||
| 	// create a file share | ||||
| 	CreateFileShare(account *azure.AccountOptions, fileShare *fileclient.ShareOptions) (string, string, error) | ||||
| 	// delete a file share | ||||
| 	DeleteFileShare(resourceGroup, accountName, shareName string) error | ||||
| 	// resize a file share | ||||
| 	ResizeFileShare(resourceGroup, accountName, name string, sizeGiB int) error | ||||
| } | ||||
|  | ||||
| type azureFileDeleter struct { | ||||
| 	*azureFile | ||||
| 	resourceGroup, accountName, shareName string | ||||
| 	azureProvider                         azureCloudProvider | ||||
| } | ||||
|  | ||||
| func (plugin *azureFilePlugin) NewDeleter(logger klog.Logger, spec *volume.Spec) (volume.Deleter, error) { | ||||
| 	azure, resourceGroup, err := getAzureCloudProvider(plugin.host.GetCloudProvider()) | ||||
| 	if err != nil { | ||||
| 		klog.V(4).Infof("failed to get azure provider") | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	if spec.PersistentVolume != nil && spec.PersistentVolume.ObjectMeta.Annotations[resourceGroupAnnotation] != "" { | ||||
| 		resourceGroup = spec.PersistentVolume.ObjectMeta.Annotations[resourceGroupAnnotation] | ||||
| 	} | ||||
|  | ||||
| 	return plugin.newDeleterInternal(spec, &azureSvc{}, azure, resourceGroup) | ||||
| } | ||||
|  | ||||
| func (plugin *azureFilePlugin) newDeleterInternal(spec *volume.Spec, util azureUtil, azure azureCloudProvider, resourceGroup string) (volume.Deleter, error) { | ||||
| 	if spec.PersistentVolume != nil && spec.PersistentVolume.Spec.AzureFile == nil { | ||||
| 		return nil, fmt.Errorf("invalid PV spec") | ||||
| 	} | ||||
|  | ||||
| 	secretName, secretNamespace, err := getSecretNameAndNamespace(spec, spec.PersistentVolume.Spec.ClaimRef.Namespace) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	shareName := spec.PersistentVolume.Spec.AzureFile.ShareName | ||||
| 	if accountName, _, err := util.GetAzureCredentials(plugin.host, secretNamespace, secretName); err != nil { | ||||
| 		return nil, err | ||||
| 	} else { | ||||
|  | ||||
| 		return &azureFileDeleter{ | ||||
| 			azureFile: &azureFile{ | ||||
| 				volName: spec.Name(), | ||||
| 				plugin:  plugin, | ||||
| 			}, | ||||
| 			resourceGroup: resourceGroup, | ||||
| 			shareName:     shareName, | ||||
| 			accountName:   accountName, | ||||
| 			azureProvider: azure, | ||||
| 		}, nil | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (plugin *azureFilePlugin) NewProvisioner(logger klog.Logger, options volume.VolumeOptions) (volume.Provisioner, error) { | ||||
| 	azure, resourceGroup, err := getAzureCloudProvider(plugin.host.GetCloudProvider()) | ||||
| 	if err != nil { | ||||
| 		klog.V(4).Infof("failed to get azure provider") | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	if len(options.PVC.Spec.AccessModes) == 0 { | ||||
| 		options.PVC.Spec.AccessModes = plugin.GetAccessModes() | ||||
| 	} | ||||
| 	if resourceGroup != "" { | ||||
| 		options.PVC.ObjectMeta.Annotations[resourceGroupAnnotation] = resourceGroup | ||||
| 	} | ||||
| 	return plugin.newProvisionerInternal(options, azure) | ||||
| } | ||||
|  | ||||
| func (plugin *azureFilePlugin) newProvisionerInternal(options volume.VolumeOptions, azure azureCloudProvider) (volume.Provisioner, error) { | ||||
| 	return &azureFileProvisioner{ | ||||
| 		azureFile: &azureFile{ | ||||
| 			plugin: plugin, | ||||
| 		}, | ||||
| 		azureProvider: azure, | ||||
| 		util:          &azureSvc{}, | ||||
| 		options:       options, | ||||
| 	}, nil | ||||
| } | ||||
|  | ||||
| var _ volume.Deleter = &azureFileDeleter{} | ||||
|  | ||||
| func (f *azureFileDeleter) GetPath() string { | ||||
| 	name := azureFilePluginName | ||||
| 	return f.plugin.host.GetPodVolumeDir(f.podUID, utilstrings.EscapeQualifiedName(name), f.volName) | ||||
| } | ||||
|  | ||||
| func (f *azureFileDeleter) Delete() error { | ||||
| 	klog.V(4).Infof("deleting volume %s", f.shareName) | ||||
| 	return f.azureProvider.DeleteFileShare(f.resourceGroup, f.accountName, f.shareName) | ||||
| } | ||||
|  | ||||
| type azureFileProvisioner struct { | ||||
| 	*azureFile | ||||
| 	azureProvider azureCloudProvider | ||||
| 	util          azureUtil | ||||
| 	options       volume.VolumeOptions | ||||
| } | ||||
|  | ||||
| var _ volume.Provisioner = &azureFileProvisioner{} | ||||
|  | ||||
| func (a *azureFileProvisioner) Provision(selectedNode *v1.Node, allowedTopologies []v1.TopologySelectorTerm) (*v1.PersistentVolume, error) { | ||||
| 	if !util.ContainsAllAccessModes(a.plugin.GetAccessModes(), a.options.PVC.Spec.AccessModes) { | ||||
| 		return nil, fmt.Errorf("invalid AccessModes %v: only AccessModes %v are supported", a.options.PVC.Spec.AccessModes, a.plugin.GetAccessModes()) | ||||
| 	} | ||||
| 	if util.CheckPersistentVolumeClaimModeBlock(a.options.PVC) { | ||||
| 		return nil, fmt.Errorf("%s does not support block volume provisioning", a.plugin.GetPluginName()) | ||||
| 	} | ||||
|  | ||||
| 	var sku, resourceGroup, location, account, shareName, customTags string | ||||
|  | ||||
| 	capacity := a.options.PVC.Spec.Resources.Requests[v1.ResourceName(v1.ResourceStorage)] | ||||
| 	requestGiB, err := volumehelpers.RoundUpToGiBInt(capacity) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	secretNamespace := a.options.PVC.Namespace | ||||
| 	// Apply ProvisionerParameters (case-insensitive). We leave validation of | ||||
| 	// the values to the cloud provider. | ||||
| 	for k, v := range a.options.Parameters { | ||||
| 		switch strings.ToLower(k) { | ||||
| 		case "skuname": | ||||
| 			sku = v | ||||
| 		case "location": | ||||
| 			location = v | ||||
| 		case "storageaccount": | ||||
| 			account = v | ||||
| 		case "secretnamespace": | ||||
| 			secretNamespace = v | ||||
| 		case "resourcegroup": | ||||
| 			resourceGroup = v | ||||
| 		case "sharename": | ||||
| 			shareName = v | ||||
| 		case "tags": | ||||
| 			customTags = v | ||||
| 		default: | ||||
| 			return nil, fmt.Errorf("invalid option %q for volume plugin %s", k, a.plugin.GetPluginName()) | ||||
| 		} | ||||
| 	} | ||||
| 	// TODO: implement c.options.ProvisionerSelector parsing | ||||
| 	if a.options.PVC.Spec.Selector != nil { | ||||
| 		return nil, fmt.Errorf("claim.Spec.Selector is not supported for dynamic provisioning on Azure file") | ||||
| 	} | ||||
|  | ||||
| 	tags, err := azure.ConvertTagsToMap(customTags) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	if shareName == "" { | ||||
| 		// File share name has a length limit of 63, it cannot contain two consecutive '-'s, and all letters must be lower case. | ||||
| 		name := util.GenerateVolumeName(a.options.ClusterName, a.options.PVName, 63) | ||||
| 		shareName = strings.Replace(name, "--", "-", -1) | ||||
| 		shareName = strings.ToLower(shareName) | ||||
| 	} | ||||
|  | ||||
| 	if resourceGroup == "" { | ||||
| 		resourceGroup = a.options.PVC.ObjectMeta.Annotations[resourceGroupAnnotation] | ||||
| 	} | ||||
|  | ||||
| 	fileShareSize := int(requestGiB) | ||||
| 	// when use azure file premium, account kind should be specified as FileStorage | ||||
| 	accountKind := string(storage.StorageV2) | ||||
| 	if strings.HasPrefix(strings.ToLower(sku), "premium") { | ||||
| 		accountKind = string(storage.FileStorage) | ||||
| 		// when using azure file premium, the shares have a minimum size | ||||
| 		if fileShareSize < minimumPremiumShareSize { | ||||
| 			fileShareSize = minimumPremiumShareSize | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	accountOptions := &azure.AccountOptions{ | ||||
| 		Name:          account, | ||||
| 		Type:          sku, | ||||
| 		Kind:          accountKind, | ||||
| 		ResourceGroup: resourceGroup, | ||||
| 		Location:      location, | ||||
| 		Tags:          tags, | ||||
| 	} | ||||
|  | ||||
| 	shareOptions := &fileclient.ShareOptions{ | ||||
| 		Name:       shareName, | ||||
| 		Protocol:   storage.SMB, | ||||
| 		RequestGiB: fileShareSize, | ||||
| 	} | ||||
|  | ||||
| 	account, key, err := a.azureProvider.CreateFileShare(accountOptions, shareOptions) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	// create a secret for storage account and key | ||||
| 	secretName, err := a.util.SetAzureCredentials(a.plugin.host, secretNamespace, account, key) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	// create PV | ||||
| 	pv := &v1.PersistentVolume{ | ||||
| 		ObjectMeta: metav1.ObjectMeta{ | ||||
| 			Name:   a.options.PVName, | ||||
| 			Labels: map[string]string{}, | ||||
| 			Annotations: map[string]string{ | ||||
| 				util.VolumeDynamicallyCreatedByKey: "azure-file-dynamic-provisioner", | ||||
| 				resourceGroupAnnotation:            resourceGroup, | ||||
| 			}, | ||||
| 		}, | ||||
| 		Spec: v1.PersistentVolumeSpec{ | ||||
| 			PersistentVolumeReclaimPolicy: a.options.PersistentVolumeReclaimPolicy, | ||||
| 			AccessModes:                   a.options.PVC.Spec.AccessModes, | ||||
| 			Capacity: v1.ResourceList{ | ||||
| 				v1.ResourceName(v1.ResourceStorage): resource.MustParse(fmt.Sprintf("%dGi", fileShareSize)), | ||||
| 			}, | ||||
| 			PersistentVolumeSource: v1.PersistentVolumeSource{ | ||||
| 				AzureFile: &v1.AzureFilePersistentVolumeSource{ | ||||
| 					SecretName:      secretName, | ||||
| 					ShareName:       shareName, | ||||
| 					SecretNamespace: &secretNamespace, | ||||
| 				}, | ||||
| 			}, | ||||
| 			MountOptions: a.options.MountOptions, | ||||
| 		}, | ||||
| 	} | ||||
| 	return pv, nil | ||||
| } | ||||
|  | ||||
| // Return cloud provider | ||||
| func getAzureCloudProvider(cloudProvider cloudprovider.Interface) (azureCloudProvider, string, error) { | ||||
| 	azureCloudProvider, ok := cloudProvider.(*azure.Cloud) | ||||
| 	if !ok || azureCloudProvider == nil { | ||||
| 		return nil, "", fmt.Errorf("failed to get Azure Cloud Provider. GetCloudProvider returned %v instead", cloudProvider) | ||||
| 	} | ||||
|  | ||||
| 	return azureCloudProvider, azureCloudProvider.ResourceGroup, nil | ||||
| } | ||||
| @@ -1,162 +0,0 @@ | ||||
| //go:build !providerless | ||||
| // +build !providerless | ||||
|  | ||||
| /* | ||||
| Copyright 2016 The Kubernetes Authors. | ||||
|  | ||||
| Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| you may not use this file except in compliance with the License. | ||||
| You may obtain a copy of the License at | ||||
|  | ||||
|     http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  | ||||
| Unless required by applicable law or agreed to in writing, software | ||||
| distributed under the License is distributed on an "AS IS" BASIS, | ||||
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| See the License for the specific language governing permissions and | ||||
| limitations under the License. | ||||
| */ | ||||
|  | ||||
| package azure_file | ||||
|  | ||||
| import ( | ||||
| 	"context" | ||||
| 	"fmt" | ||||
| 	"strings" | ||||
|  | ||||
| 	v1 "k8s.io/api/core/v1" | ||||
| 	"k8s.io/apimachinery/pkg/api/errors" | ||||
| 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||||
| 	"k8s.io/kubernetes/pkg/volume" | ||||
| ) | ||||
|  | ||||
| const ( | ||||
| 	fileMode        = "file_mode" | ||||
| 	dirMode         = "dir_mode" | ||||
| 	gid             = "gid" | ||||
| 	vers            = "vers" | ||||
| 	actimeo         = "actimeo" | ||||
| 	mfsymlinks      = "mfsymlinks" | ||||
| 	defaultFileMode = "0777" | ||||
| 	defaultDirMode  = "0777" | ||||
| 	defaultVers     = "3.0" | ||||
| 	defaultActimeo  = "30" | ||||
| ) | ||||
|  | ||||
| // Abstract interface to azure file operations. | ||||
| type azureUtil interface { | ||||
| 	GetAzureCredentials(host volume.VolumeHost, nameSpace, secretName string) (string, string, error) | ||||
| 	SetAzureCredentials(host volume.VolumeHost, nameSpace, accountName, accountKey string) (string, error) | ||||
| } | ||||
|  | ||||
| type azureSvc struct{} | ||||
|  | ||||
| func (s *azureSvc) GetAzureCredentials(host volume.VolumeHost, nameSpace, secretName string) (string, string, error) { | ||||
| 	var accountKey, accountName string | ||||
| 	kubeClient := host.GetKubeClient() | ||||
| 	if kubeClient == nil { | ||||
| 		return "", "", fmt.Errorf("cannot get kube client") | ||||
| 	} | ||||
|  | ||||
| 	keys, err := kubeClient.CoreV1().Secrets(nameSpace).Get(context.TODO(), secretName, metav1.GetOptions{}) | ||||
| 	if err != nil { | ||||
| 		return "", "", fmt.Errorf("couldn't get secret %v/%v", nameSpace, secretName) | ||||
| 	} | ||||
| 	for name, data := range keys.Data { | ||||
| 		if name == "azurestorageaccountname" { | ||||
| 			accountName = string(data) | ||||
| 		} | ||||
| 		if name == "azurestorageaccountkey" { | ||||
| 			accountKey = string(data) | ||||
| 		} | ||||
| 	} | ||||
| 	if accountName == "" || accountKey == "" { | ||||
| 		return "", "", fmt.Errorf("invalid %v/%v, couldn't extract azurestorageaccountname or azurestorageaccountkey", nameSpace, secretName) | ||||
| 	} | ||||
| 	accountName = strings.TrimSpace(accountName) | ||||
| 	return accountName, accountKey, nil | ||||
| } | ||||
|  | ||||
| func (s *azureSvc) SetAzureCredentials(host volume.VolumeHost, nameSpace, accountName, accountKey string) (string, error) { | ||||
| 	kubeClient := host.GetKubeClient() | ||||
| 	if kubeClient == nil { | ||||
| 		return "", fmt.Errorf("cannot get kube client") | ||||
| 	} | ||||
| 	secretName := "azure-storage-account-" + accountName + "-secret" | ||||
| 	secret := &v1.Secret{ | ||||
| 		ObjectMeta: metav1.ObjectMeta{ | ||||
| 			Namespace: nameSpace, | ||||
| 			Name:      secretName, | ||||
| 		}, | ||||
| 		Data: map[string][]byte{ | ||||
| 			"azurestorageaccountname": []byte(accountName), | ||||
| 			"azurestorageaccountkey":  []byte(accountKey), | ||||
| 		}, | ||||
| 		Type: "Opaque", | ||||
| 	} | ||||
| 	_, err := kubeClient.CoreV1().Secrets(nameSpace).Create(context.TODO(), secret, metav1.CreateOptions{}) | ||||
| 	if errors.IsAlreadyExists(err) { | ||||
| 		err = nil | ||||
| 	} | ||||
| 	if err != nil { | ||||
| 		return "", fmt.Errorf("couldn't create secret %v", err) | ||||
| 	} | ||||
| 	return secretName, err | ||||
| } | ||||
|  | ||||
| // check whether mountOptions contain file_mode, dir_mode, vers, gid, if not, append default mode | ||||
| func appendDefaultMountOptions(mountOptions []string, fsGroup *int64) []string { | ||||
| 	fileModeFlag := false | ||||
| 	dirModeFlag := false | ||||
| 	versFlag := false | ||||
| 	gidFlag := false | ||||
| 	actimeoFlag := false | ||||
| 	mfsymlinksFlag := false | ||||
|  | ||||
| 	for _, mountOption := range mountOptions { | ||||
| 		if strings.HasPrefix(mountOption, fileMode) { | ||||
| 			fileModeFlag = true | ||||
| 		} | ||||
| 		if strings.HasPrefix(mountOption, dirMode) { | ||||
| 			dirModeFlag = true | ||||
| 		} | ||||
| 		if strings.HasPrefix(mountOption, vers) { | ||||
| 			versFlag = true | ||||
| 		} | ||||
| 		if strings.HasPrefix(mountOption, gid) { | ||||
| 			gidFlag = true | ||||
| 		} | ||||
| 		if strings.HasPrefix(mountOption, actimeo) { | ||||
| 			actimeoFlag = true | ||||
| 		} | ||||
| 		if strings.HasPrefix(mountOption, mfsymlinks) { | ||||
| 			mfsymlinksFlag = true | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	allMountOptions := mountOptions | ||||
| 	if !fileModeFlag { | ||||
| 		allMountOptions = append(allMountOptions, fmt.Sprintf("%s=%s", fileMode, defaultFileMode)) | ||||
| 	} | ||||
|  | ||||
| 	if !dirModeFlag { | ||||
| 		allMountOptions = append(allMountOptions, fmt.Sprintf("%s=%s", dirMode, defaultDirMode)) | ||||
| 	} | ||||
|  | ||||
| 	if !versFlag { | ||||
| 		allMountOptions = append(allMountOptions, fmt.Sprintf("%s=%s", vers, defaultVers)) | ||||
| 	} | ||||
|  | ||||
| 	if !gidFlag && fsGroup != nil { | ||||
| 		allMountOptions = append(allMountOptions, fmt.Sprintf("%s=%d", gid, *fsGroup)) | ||||
| 	} | ||||
|  | ||||
| 	if !actimeoFlag { | ||||
| 		allMountOptions = append(allMountOptions, fmt.Sprintf("%s=%s", actimeo, defaultActimeo)) | ||||
| 	} | ||||
|  | ||||
| 	if !mfsymlinksFlag { | ||||
| 		allMountOptions = append(allMountOptions, mfsymlinks) | ||||
| 	} | ||||
| 	return allMountOptions | ||||
| } | ||||
| @@ -1,19 +0,0 @@ | ||||
| /* | ||||
| Copyright 2016 The Kubernetes Authors. | ||||
|  | ||||
| Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| you may not use this file except in compliance with the License. | ||||
| You may obtain a copy of the License at | ||||
|  | ||||
|     http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  | ||||
| Unless required by applicable law or agreed to in writing, software | ||||
| distributed under the License is distributed on an "AS IS" BASIS, | ||||
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| See the License for the specific language governing permissions and | ||||
| limitations under the License. | ||||
| */ | ||||
|  | ||||
| // Package azure_file contains the internal representation of | ||||
| // Azure File Service Volume | ||||
| package azure_file // import "k8s.io/kubernetes/pkg/volume/azure_file" | ||||
| @@ -229,7 +229,7 @@ func (p *csiPlugin) Init(host volume.VolumeHost) error { | ||||
| 			return true | ||||
| 		}, | ||||
| 		csitranslationplugins.AzureFileInTreePluginName: func() bool { | ||||
| 			return utilfeature.DefaultFeatureGate.Enabled(features.CSIMigrationAzureFile) | ||||
| 			return true | ||||
| 		}, | ||||
| 		csitranslationplugins.VSphereInTreePluginName: func() bool { | ||||
| 			return utilfeature.DefaultFeatureGate.Enabled(features.CSIMigrationvSphere) | ||||
|   | ||||
| @@ -93,7 +93,7 @@ func (pm PluginManager) IsMigrationEnabledForPlugin(pluginName string) bool { | ||||
| 	case csilibplugins.GCEPDInTreePluginName: | ||||
| 		return pm.featureGate.Enabled(features.CSIMigrationGCE) | ||||
| 	case csilibplugins.AzureFileInTreePluginName: | ||||
| 		return pm.featureGate.Enabled(features.CSIMigrationAzureFile) | ||||
| 		return true | ||||
| 	case csilibplugins.AzureDiskInTreePluginName: | ||||
| 		return true | ||||
| 	case csilibplugins.CinderInTreePluginName: | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Kubernetes Prow Robot
					Kubernetes Prow Robot