mirror of
				https://github.com/optim-enterprises-bv/kubernetes.git
				synced 2025-11-03 19:58:17 +00:00 
			
		
		
		
	Remove Azure file 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
 | 
			
		||||
@@ -868,8 +860,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