mirror of https://github.com/k3s-io/k3s
Merge pull request #78356 from andyzhangx/csi-translation-azurefile
Add support for Azure File plugin to csi-translation-libk3s-v1.15.3
commit
ade661c7cb
|
@ -423,6 +423,12 @@ const (
|
||||||
// Enables the Azure Disk in-tree driver to Azure Disk Driver migration feature.
|
// Enables the Azure Disk in-tree driver to Azure Disk Driver migration feature.
|
||||||
CSIMigrationAzureDisk featuregate.Feature = "CSIMigrationAzureDisk"
|
CSIMigrationAzureDisk featuregate.Feature = "CSIMigrationAzureDisk"
|
||||||
|
|
||||||
|
// owner: @andyzhangx
|
||||||
|
// alpha: v1.15
|
||||||
|
//
|
||||||
|
// Enables the Azure File in-tree driver to Azure File Driver migration feature.
|
||||||
|
CSIMigrationAzureFile featuregate.Feature = "CSIMigrationAzureFile"
|
||||||
|
|
||||||
// owner: @RobertKrawitz
|
// owner: @RobertKrawitz
|
||||||
// beta: v1.15
|
// beta: v1.15
|
||||||
//
|
//
|
||||||
|
@ -503,6 +509,7 @@ var defaultKubernetesFeatureGates = map[featuregate.Feature]featuregate.FeatureS
|
||||||
CSIMigrationGCE: {Default: false, PreRelease: featuregate.Alpha},
|
CSIMigrationGCE: {Default: false, PreRelease: featuregate.Alpha},
|
||||||
CSIMigrationAWS: {Default: false, PreRelease: featuregate.Alpha},
|
CSIMigrationAWS: {Default: false, PreRelease: featuregate.Alpha},
|
||||||
CSIMigrationAzureDisk: {Default: false, PreRelease: featuregate.Alpha},
|
CSIMigrationAzureDisk: {Default: false, PreRelease: featuregate.Alpha},
|
||||||
|
CSIMigrationAzureFile: {Default: false, PreRelease: featuregate.Alpha},
|
||||||
RunAsGroup: {Default: true, PreRelease: featuregate.Beta},
|
RunAsGroup: {Default: true, PreRelease: featuregate.Beta},
|
||||||
CSIMigrationOpenStack: {Default: false, PreRelease: featuregate.Alpha},
|
CSIMigrationOpenStack: {Default: false, PreRelease: featuregate.Alpha},
|
||||||
VolumeSubpath: {Default: true, PreRelease: featuregate.GA},
|
VolumeSubpath: {Default: true, PreRelease: featuregate.GA},
|
||||||
|
|
|
@ -16,6 +16,7 @@ go_library(
|
||||||
],
|
],
|
||||||
importpath = "k8s.io/kubernetes/pkg/volume/azure_file",
|
importpath = "k8s.io/kubernetes/pkg/volume/azure_file",
|
||||||
deps = [
|
deps = [
|
||||||
|
"//pkg/features:go_default_library",
|
||||||
"//pkg/util/mount:go_default_library",
|
"//pkg/util/mount:go_default_library",
|
||||||
"//pkg/volume:go_default_library",
|
"//pkg/volume:go_default_library",
|
||||||
"//pkg/volume/util:go_default_library",
|
"//pkg/volume/util:go_default_library",
|
||||||
|
@ -24,6 +25,7 @@ go_library(
|
||||||
"//staging/src/k8s.io/apimachinery/pkg/api/resource:go_default_library",
|
"//staging/src/k8s.io/apimachinery/pkg/api/resource:go_default_library",
|
||||||
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||||
"//staging/src/k8s.io/apimachinery/pkg/types:go_default_library",
|
"//staging/src/k8s.io/apimachinery/pkg/types:go_default_library",
|
||||||
|
"//staging/src/k8s.io/apiserver/pkg/util/feature:go_default_library",
|
||||||
"//staging/src/k8s.io/cloud-provider:go_default_library",
|
"//staging/src/k8s.io/cloud-provider:go_default_library",
|
||||||
"//staging/src/k8s.io/cloud-provider/volume/helpers:go_default_library",
|
"//staging/src/k8s.io/cloud-provider/volume/helpers:go_default_library",
|
||||||
"//staging/src/k8s.io/legacy-cloud-providers/azure:go_default_library",
|
"//staging/src/k8s.io/legacy-cloud-providers/azure:go_default_library",
|
||||||
|
|
|
@ -26,9 +26,11 @@ import (
|
||||||
"k8s.io/apimachinery/pkg/api/resource"
|
"k8s.io/apimachinery/pkg/api/resource"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/types"
|
"k8s.io/apimachinery/pkg/types"
|
||||||
|
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||||
cloudprovider "k8s.io/cloud-provider"
|
cloudprovider "k8s.io/cloud-provider"
|
||||||
volumehelpers "k8s.io/cloud-provider/volume/helpers"
|
volumehelpers "k8s.io/cloud-provider/volume/helpers"
|
||||||
"k8s.io/klog"
|
"k8s.io/klog"
|
||||||
|
"k8s.io/kubernetes/pkg/features"
|
||||||
"k8s.io/kubernetes/pkg/util/mount"
|
"k8s.io/kubernetes/pkg/util/mount"
|
||||||
"k8s.io/kubernetes/pkg/volume"
|
"k8s.io/kubernetes/pkg/volume"
|
||||||
volutil "k8s.io/kubernetes/pkg/volume/util"
|
volutil "k8s.io/kubernetes/pkg/volume/util"
|
||||||
|
@ -82,7 +84,8 @@ func (plugin *azureFilePlugin) CanSupport(spec *volume.Spec) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (plugin *azureFilePlugin) IsMigratedToCSI() bool {
|
func (plugin *azureFilePlugin) IsMigratedToCSI() bool {
|
||||||
return false
|
return utilfeature.DefaultFeatureGate.Enabled(features.CSIMigration) &&
|
||||||
|
utilfeature.DefaultFeatureGate.Enabled(features.CSIMigrationAzureFile)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (plugin *azureFilePlugin) RequiresRemount() bool {
|
func (plugin *azureFilePlugin) RequiresRemount() bool {
|
||||||
|
|
|
@ -5,6 +5,7 @@ go_library(
|
||||||
srcs = [
|
srcs = [
|
||||||
"aws_ebs.go",
|
"aws_ebs.go",
|
||||||
"azure_disk.go",
|
"azure_disk.go",
|
||||||
|
"azure_file.go",
|
||||||
"gce_pd.go",
|
"gce_pd.go",
|
||||||
"in_tree_volume.go",
|
"in_tree_volume.go",
|
||||||
"openstack_cinder.go",
|
"openstack_cinder.go",
|
||||||
|
@ -39,6 +40,7 @@ go_test(
|
||||||
srcs = [
|
srcs = [
|
||||||
"aws_ebs_test.go",
|
"aws_ebs_test.go",
|
||||||
"azure_disk_test.go",
|
"azure_disk_test.go",
|
||||||
|
"azure_file_test.go",
|
||||||
"gce_pd_test.go",
|
"gce_pd_test.go",
|
||||||
],
|
],
|
||||||
embed = [":go_default_library"],
|
embed = [":go_default_library"],
|
||||||
|
|
|
@ -0,0 +1,148 @@
|
||||||
|
/*
|
||||||
|
Copyright 2019 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 plugins
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"k8s.io/api/core/v1"
|
||||||
|
storage "k8s.io/api/storage/v1"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// AzureFileDriverName is the name of the CSI driver for Azure File
|
||||||
|
AzureFileDriverName = "file.csi.azure.com"
|
||||||
|
// AzureFileInTreePluginName is the name of the intree plugin for Azure file
|
||||||
|
AzureFileInTreePluginName = "kubernetes.io/azure-file"
|
||||||
|
|
||||||
|
separator = "#"
|
||||||
|
volumeIDTemplate = "%s#%s#%s"
|
||||||
|
// Parameter names defined in azure file CSI driver, refer to
|
||||||
|
// https://github.com/kubernetes-sigs/azurefile-csi-driver/blob/master/docs/driver-parameters.md
|
||||||
|
azureFileShareName = "shareName"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ InTreePlugin = &azureFileCSITranslator{}
|
||||||
|
|
||||||
|
// azureFileCSITranslator handles translation of PV spec from In-tree
|
||||||
|
// Azure File to CSI Azure File and vice versa
|
||||||
|
type azureFileCSITranslator struct{}
|
||||||
|
|
||||||
|
// NewAzureFileCSITranslator returns a new instance of azureFileTranslator
|
||||||
|
func NewAzureFileCSITranslator() InTreePlugin {
|
||||||
|
return &azureFileCSITranslator{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TranslateInTreeStorageClassParametersToCSI translates InTree Azure File storage class parameters to CSI storage class
|
||||||
|
func (t *azureFileCSITranslator) TranslateInTreeStorageClassToCSI(sc *storage.StorageClass) (*storage.StorageClass, error) {
|
||||||
|
return sc, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// TranslateInTreePVToCSI takes a PV with AzureFile set from in-tree
|
||||||
|
// and converts the AzureFile source to a CSIPersistentVolumeSource
|
||||||
|
func (t *azureFileCSITranslator) TranslateInTreePVToCSI(pv *v1.PersistentVolume) (*v1.PersistentVolume, error) {
|
||||||
|
if pv == nil || pv.Spec.AzureFile == nil {
|
||||||
|
return nil, fmt.Errorf("pv is nil or Azure File source not defined on pv")
|
||||||
|
}
|
||||||
|
|
||||||
|
azureSource := pv.Spec.PersistentVolumeSource.AzureFile
|
||||||
|
|
||||||
|
volumeID := fmt.Sprintf(volumeIDTemplate, "", azureSource.SecretName, azureSource.ShareName)
|
||||||
|
// refer to https://github.com/kubernetes-sigs/azurefile-csi-driver/blob/master/docs/driver-parameters.md
|
||||||
|
csiSource := &v1.CSIPersistentVolumeSource{
|
||||||
|
VolumeHandle: volumeID,
|
||||||
|
ReadOnly: azureSource.ReadOnly,
|
||||||
|
VolumeAttributes: map[string]string{azureFileShareName: azureSource.ShareName},
|
||||||
|
}
|
||||||
|
|
||||||
|
csiSource.NodePublishSecretRef = &v1.SecretReference{
|
||||||
|
Name: azureSource.ShareName,
|
||||||
|
Namespace: *azureSource.SecretNamespace,
|
||||||
|
}
|
||||||
|
|
||||||
|
pv.Spec.PersistentVolumeSource.AzureFile = nil
|
||||||
|
pv.Spec.PersistentVolumeSource.CSI = csiSource
|
||||||
|
pv.Spec.AccessModes = backwardCompatibleAccessModes(pv.Spec.AccessModes)
|
||||||
|
|
||||||
|
return pv, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// TranslateCSIPVToInTree takes a PV with CSIPersistentVolumeSource set and
|
||||||
|
// translates the Azure File CSI source to a AzureFile source.
|
||||||
|
func (t *azureFileCSITranslator) TranslateCSIPVToInTree(pv *v1.PersistentVolume) (*v1.PersistentVolume, error) {
|
||||||
|
if pv == nil || pv.Spec.CSI == nil {
|
||||||
|
return nil, fmt.Errorf("pv is nil or CSI source not defined on pv")
|
||||||
|
}
|
||||||
|
csiSource := pv.Spec.CSI
|
||||||
|
|
||||||
|
// refer to https://github.com/kubernetes-sigs/azurefile-csi-driver/blob/master/docs/driver-parameters.md
|
||||||
|
azureSource := &v1.AzureFilePersistentVolumeSource{
|
||||||
|
ReadOnly: csiSource.ReadOnly,
|
||||||
|
}
|
||||||
|
|
||||||
|
if csiSource.NodePublishSecretRef != nil && csiSource.NodePublishSecretRef.Name != "" {
|
||||||
|
azureSource.SecretName = csiSource.NodePublishSecretRef.Name
|
||||||
|
azureSource.SecretNamespace = &csiSource.NodePublishSecretRef.Namespace
|
||||||
|
if csiSource.VolumeAttributes != nil {
|
||||||
|
if shareName, ok := csiSource.VolumeAttributes[azureFileShareName]; ok {
|
||||||
|
azureSource.ShareName = shareName
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
_, _, fileShareName, err := getFileShareInfo(csiSource.VolumeHandle)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
azureSource.ShareName = fileShareName
|
||||||
|
// to-do: for dynamic provision scenario in CSI, it uses cluster's identity to get storage account key
|
||||||
|
// secret for the file share is not created, we may create a serect here
|
||||||
|
}
|
||||||
|
|
||||||
|
pv.Spec.CSI = nil
|
||||||
|
pv.Spec.AzureFile = azureSource
|
||||||
|
|
||||||
|
return pv, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CanSupport tests whether the plugin supports a given volume
|
||||||
|
// specification from the API. The spec pointer should be considered
|
||||||
|
// const.
|
||||||
|
func (t *azureFileCSITranslator) CanSupport(pv *v1.PersistentVolume) bool {
|
||||||
|
return pv != nil && pv.Spec.AzureFile != nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetInTreePluginName returns the name of the intree plugin driver
|
||||||
|
func (t *azureFileCSITranslator) GetInTreePluginName() string {
|
||||||
|
return AzureFileInTreePluginName
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetCSIPluginName returns the name of the CSI plugin
|
||||||
|
func (t *azureFileCSITranslator) GetCSIPluginName() string {
|
||||||
|
return AzureFileDriverName
|
||||||
|
}
|
||||||
|
|
||||||
|
// get file share info according to volume id, e.g.
|
||||||
|
// input: "rg#f5713de20cde511e8ba4900#pvc-file-dynamic-17e43f84-f474-11e8-acd0-000d3a00df41"
|
||||||
|
// output: rg, f5713de20cde511e8ba4900, pvc-file-dynamic-17e43f84-f474-11e8-acd0-000d3a00df41
|
||||||
|
func getFileShareInfo(id string) (string, string, string, error) {
|
||||||
|
segments := strings.Split(id, separator)
|
||||||
|
if len(segments) < 3 {
|
||||||
|
return "", "", "", fmt.Errorf("error parsing volume id: %q, should at least contain two #", id)
|
||||||
|
}
|
||||||
|
return segments[0], segments[1], segments[2], nil
|
||||||
|
}
|
|
@ -0,0 +1,71 @@
|
||||||
|
/*
|
||||||
|
Copyright 2019 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 plugins
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestGetFileShareInfo(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
options string
|
||||||
|
expected1 string
|
||||||
|
expected2 string
|
||||||
|
expected3 string
|
||||||
|
expected4 error
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
options: "rg#f5713de20cde511e8ba4900#pvc-file-dynamic-17e43f84-f474-11e8-acd0-000d3a00df41",
|
||||||
|
expected1: "rg",
|
||||||
|
expected2: "f5713de20cde511e8ba4900",
|
||||||
|
expected3: "pvc-file-dynamic-17e43f84-f474-11e8-acd0-000d3a00df41",
|
||||||
|
expected4: nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
options: "rg#f5713de20cde511e8ba4900",
|
||||||
|
expected1: "",
|
||||||
|
expected2: "",
|
||||||
|
expected3: "",
|
||||||
|
expected4: fmt.Errorf("error parsing volume id: \"rg#f5713de20cde511e8ba4900\", should at least contain two #"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
options: "rg",
|
||||||
|
expected1: "",
|
||||||
|
expected2: "",
|
||||||
|
expected3: "",
|
||||||
|
expected4: fmt.Errorf("error parsing volume id: \"rg\", should at least contain two #"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
options: "",
|
||||||
|
expected1: "",
|
||||||
|
expected2: "",
|
||||||
|
expected3: "",
|
||||||
|
expected4: fmt.Errorf("error parsing volume id: \"\", should at least contain two #"),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range tests {
|
||||||
|
result1, result2, result3, result4 := getFileShareInfo(test.options)
|
||||||
|
if !reflect.DeepEqual(result1, test.expected1) || !reflect.DeepEqual(result2, test.expected2) ||
|
||||||
|
!reflect.DeepEqual(result3, test.expected3) || !reflect.DeepEqual(result4, test.expected4) {
|
||||||
|
t.Errorf("input: %q, getFileShareInfo result1: %q, expected1: %q, result2: %q, expected2: %q, result3: %q, expected3: %q, result4: %q, expected4: %q", test.options, result1, test.expected1, result2, test.expected2,
|
||||||
|
result3, test.expected3, result4, test.expected4)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -31,6 +31,7 @@ var (
|
||||||
plugins.AWSEBSDriverName: plugins.NewAWSElasticBlockStoreCSITranslator(),
|
plugins.AWSEBSDriverName: plugins.NewAWSElasticBlockStoreCSITranslator(),
|
||||||
plugins.CinderDriverName: plugins.NewOpenStackCinderCSITranslator(),
|
plugins.CinderDriverName: plugins.NewOpenStackCinderCSITranslator(),
|
||||||
plugins.AzureDiskDriverName: plugins.NewAzureDiskCSITranslator(),
|
plugins.AzureDiskDriverName: plugins.NewAzureDiskCSITranslator(),
|
||||||
|
plugins.AzureFileDriverName: plugins.NewAzureFileCSITranslator(),
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue