removed the deprecated azureFile in-tree storage plugin

This commit is contained in:
carlory 2024-01-04 14:41:33 +08:00
parent 6aac45ff1e
commit 55e1646fa4
11 changed files with 3 additions and 1386 deletions

View File

@ -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/portworx"
"k8s.io/kubernetes/pkg/volume/rbd"
@ -77,24 +76,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)
}

View File

@ -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/portworx"
"k8s.io/kubernetes/pkg/volume/rbd"
@ -64,7 +63,6 @@ type pluginInfo struct {
func appendLegacyProviderVolumes(allPlugins []volume.VolumePlugin, featureGate featuregate.FeatureGate) ([]volume.VolumePlugin, error) {
pluginMigrationStatus := make(map[string]pluginInfo)
pluginMigrationStatus[plugins.AzureFileInTreePluginName] = pluginInfo{pluginMigrationFeature: features.CSIMigrationAzureFile, pluginUnregisterFeature: features.InTreePluginAzureFileUnregister, pluginProbeFunction: azure_file.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}
var err error

View File

@ -129,14 +129,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: @mfordjody
// alpha: v1.26
//
@ -961,8 +953,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
CSIMigrationPortworx: {Default: false, PreRelease: featuregate.Beta}, // Off by default (requires Portworx CSI driver)
CSIMigrationRBD: {Default: false, PreRelease: featuregate.Deprecated}, // deprecated in 1.28, remove in 1.31

View File

@ -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

View File

@ -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
}

View File

@ -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)
}
}
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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"

View File

@ -234,7 +234,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 true

View File

@ -93,7 +93,7 @@ func (pm PluginManager) IsMigrationEnabledForPlugin(pluginName string) bool {
case csilibplugins.GCEPDInTreePluginName:
return true
case csilibplugins.AzureFileInTreePluginName:
return pm.featureGate.Enabled(features.CSIMigrationAzureFile)
return true
case csilibplugins.AzureDiskInTreePluginName:
return true
case csilibplugins.CinderInTreePluginName: