From e65fba6499c0b1634cd9af6a161e03725c9d2f7d Mon Sep 17 00:00:00 2001 From: andyzhangx Date: Sat, 25 May 2019 03:56:57 +0000 Subject: [PATCH 1/2] Add support for Azure Disk to csi-translation-lib rename to azure_disk add more translation fields fix typo --- .../k8s.io/csi-translation-lib/plugins/BUILD | 2 + .../csi-translation-lib/plugins/azure_disk.go | 168 ++++++++++++++++++ .../plugins/azure_disk_test.go | 93 ++++++++++ 3 files changed, 263 insertions(+) create mode 100644 staging/src/k8s.io/csi-translation-lib/plugins/azure_disk.go create mode 100644 staging/src/k8s.io/csi-translation-lib/plugins/azure_disk_test.go diff --git a/staging/src/k8s.io/csi-translation-lib/plugins/BUILD b/staging/src/k8s.io/csi-translation-lib/plugins/BUILD index 88c1a91f080..43d2f4e141e 100644 --- a/staging/src/k8s.io/csi-translation-lib/plugins/BUILD +++ b/staging/src/k8s.io/csi-translation-lib/plugins/BUILD @@ -4,6 +4,7 @@ go_library( name = "go_default_library", srcs = [ "aws_ebs.go", + "azure_disk.go", "gce_pd.go", "in_tree_volume.go", "openstack_cinder.go", @@ -37,6 +38,7 @@ go_test( name = "go_default_test", srcs = [ "aws_ebs_test.go", + "azure_disk_test.go", "gce_pd_test.go", ], embed = [":go_default_library"], diff --git a/staging/src/k8s.io/csi-translation-lib/plugins/azure_disk.go b/staging/src/k8s.io/csi-translation-lib/plugins/azure_disk.go new file mode 100644 index 00000000000..d5f0d605e7c --- /dev/null +++ b/staging/src/k8s.io/csi-translation-lib/plugins/azure_disk.go @@ -0,0 +1,168 @@ +/* +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" + "regexp" + "strings" + + "k8s.io/api/core/v1" + storage "k8s.io/api/storage/v1" +) + +const ( + // AzureDiskDriverName is the name of the CSI driver for Azure Disk + AzureDiskDriverName = "disk.csi.azure.com" + // AzureDiskInTreePluginName is the name of the intree plugin for Azure Disk + AzureDiskInTreePluginName = "kubernetes.io/azure-disk" + + // Parameter names defined in azure disk CSI driver, refer to + // https://github.com/kubernetes-sigs/azuredisk-csi-driver/blob/master/docs/driver-parameters.md + azureDiskCachingMode = "cachingMode" + azureDiskFSType = "fsType" +) + +var ( + managedDiskPathRE = regexp.MustCompile(`.*/subscriptions/(?:.*)/resourceGroups/(?:.*)/providers/Microsoft.Compute/disks/(.+)`) + unmanagedDiskPathRE = regexp.MustCompile(`http(?:.*)://(?:.*)/vhds/(.+)`) +) + +var _ InTreePlugin = &azureDiskCSITranslator{} + +// azureDiskCSITranslator handles translation of PV spec from In-tree +// Azure Disk to CSI Azure Disk and vice versa +type azureDiskCSITranslator struct{} + +// NewAzureDiskCSITranslator returns a new instance of azureDiskTranslator +func NewAzureDiskCSITranslator() InTreePlugin { + return &azureDiskCSITranslator{} +} + +// TranslateInTreeStorageClassParametersToCSI translates InTree Azure Disk storage class parameters to CSI storage class +func (t *azureDiskCSITranslator) TranslateInTreeStorageClassToCSI(sc *storage.StorageClass) (*storage.StorageClass, error) { + return sc, nil +} + +// TranslateInTreePVToCSI takes a PV with AzureDisk set from in-tree +// and converts the AzureDisk source to a CSIPersistentVolumeSource +func (t *azureDiskCSITranslator) TranslateInTreePVToCSI(pv *v1.PersistentVolume) (*v1.PersistentVolume, error) { + if pv == nil || pv.Spec.AzureDisk == nil { + return nil, fmt.Errorf("pv is nil or Azure Disk source not defined on pv") + } + + azureSource := pv.Spec.PersistentVolumeSource.AzureDisk + + // refer to https://github.com/kubernetes-sigs/azuredisk-csi-driver/blob/master/docs/driver-parameters.md + csiSource := &v1.CSIPersistentVolumeSource{ + Driver: AzureDiskDriverName, + VolumeHandle: azureSource.DataDiskURI, + ReadOnly: *azureSource.ReadOnly, + FSType: *azureSource.FSType, + VolumeAttributes: map[string]string{}, + } + + if *azureSource.CachingMode != "" { + csiSource.VolumeAttributes[azureDiskCachingMode] = string(*azureSource.CachingMode) + } + + if *azureSource.FSType != "" { + csiSource.VolumeAttributes[azureDiskFSType] = *azureSource.FSType + } + + pv.Spec.PersistentVolumeSource.AzureDisk = 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 Disk CSI source to a AzureDisk source. +func (t *azureDiskCSITranslator) 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 + + diskURI := csiSource.VolumeHandle + diskName, err := getDiskName(diskURI) + if err != nil { + return nil, err + } + + // refer to https://github.com/kubernetes-sigs/azuredisk-csi-driver/blob/master/docs/driver-parameters.md + azureSource := &v1.AzureDiskVolumeSource{ + DiskName: diskName, + DataDiskURI: diskURI, + FSType: &csiSource.FSType, + ReadOnly: &csiSource.ReadOnly, + } + + if csiSource.VolumeAttributes != nil { + if cachingMode, ok := csiSource.VolumeAttributes[azureDiskCachingMode]; ok { + mode := v1.AzureDataDiskCachingMode(cachingMode) + azureSource.CachingMode = &mode + } + + if fsType, ok := csiSource.VolumeAttributes[azureDiskFSType]; ok && fsType != "" { + azureSource.FSType = &fsType + } + } + + pv.Spec.CSI = nil + pv.Spec.AzureDisk = 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 *azureDiskCSITranslator) CanSupport(pv *v1.PersistentVolume) bool { + return pv != nil && pv.Spec.AzureDisk != nil +} + +// GetInTreePluginName returns the name of the intree plugin driver +func (t *azureDiskCSITranslator) GetInTreePluginName() string { + return AzureDiskInTreePluginName +} + +// GetCSIPluginName returns the name of the CSI plugin +func (t *azureDiskCSITranslator) GetCSIPluginName() string { + return AzureDiskDriverName +} + +func isManagedDisk(diskURI string) bool { + if len(diskURI) > 4 && strings.ToLower(diskURI[:4]) == "http" { + return false + } + return true +} + +func getDiskName(diskURI string) (string, error) { + diskPathRE := managedDiskPathRE + if !isManagedDisk(diskURI) { + diskPathRE = unmanagedDiskPathRE + } + + matches := diskPathRE.FindStringSubmatch(diskURI) + if len(matches) != 2 { + return "", fmt.Errorf("could not get disk name from %s, correct format: %s", diskURI, diskPathRE) + } + return matches[1], nil +} diff --git a/staging/src/k8s.io/csi-translation-lib/plugins/azure_disk_test.go b/staging/src/k8s.io/csi-translation-lib/plugins/azure_disk_test.go new file mode 100644 index 00000000000..b97bfe8ba6a --- /dev/null +++ b/staging/src/k8s.io/csi-translation-lib/plugins/azure_disk_test.go @@ -0,0 +1,93 @@ +/* +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 TestIsManagedDisk(t *testing.T) { + tests := []struct { + options string + expected bool + }{ + { + options: "testurl/subscriptions/12/resourceGroups/23/providers/Microsoft.Compute/disks/name", + expected: true, + }, + { + options: "test.com", + expected: true, + }, + { + options: "HTTP://test.com", + expected: false, + }, + { + options: "http://test.com/vhds/name", + expected: false, + }, + } + + for _, test := range tests { + result := isManagedDisk(test.options) + if !reflect.DeepEqual(result, test.expected) { + t.Errorf("input: %q, isManagedDisk result: %t, expected: %t", test.options, result, test.expected) + } + } +} + +func TestGetDiskName(t *testing.T) { + mDiskPathRE := managedDiskPathRE + uDiskPathRE := unmanagedDiskPathRE + tests := []struct { + options string + expected1 string + expected2 error + }{ + { + options: "testurl/subscriptions/12/resourceGroups/23/providers/Microsoft.Compute/disks/name", + expected1: "name", + expected2: nil, + }, + { + options: "testurl/subscriptions/23/providers/Microsoft.Compute/disks/name", + expected1: "", + expected2: fmt.Errorf("could not get disk name from testurl/subscriptions/23/providers/Microsoft.Compute/disks/name, correct format: %s", mDiskPathRE), + }, + { + options: "http://test.com/vhds/name", + expected1: "name", + expected2: nil, + }, + { + options: "http://test.io/name", + expected1: "", + expected2: fmt.Errorf("could not get disk name from http://test.io/name, correct format: %s", uDiskPathRE), + }, + } + + for _, test := range tests { + result1, result2 := getDiskName(test.options) + if !reflect.DeepEqual(result1, test.expected1) || !reflect.DeepEqual(result2, test.expected2) { + t.Errorf("input: %q, getDiskName result1: %q, expected1: %q, result2: %q, expected2: %q", test.options, result1, test.expected1, + result2, test.expected2) + } + } +} From 6f2902e0a38a46d2f81d4d266229cbf773d87932 Mon Sep 17 00:00:00 2001 From: andyzhangx Date: Tue, 28 May 2019 14:33:45 +0000 Subject: [PATCH 2/2] add feature gate for azure disk fix gofmt error --- pkg/features/kube_features.go | 7 +++++++ pkg/volume/azure_dd/azure_dd.go | 5 ++++- staging/src/k8s.io/csi-translation-lib/translate.go | 7 ++++--- 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/pkg/features/kube_features.go b/pkg/features/kube_features.go index 0bf79e5ddd7..4e8141a58b6 100644 --- a/pkg/features/kube_features.go +++ b/pkg/features/kube_features.go @@ -417,6 +417,12 @@ const ( // Enables the AWS EBS in-tree driver to AWS EBS CSI Driver migration feature. CSIMigrationAWS featuregate.Feature = "CSIMigrationAWS" + // owner: @andyzhangx + // alpha: v1.15 + // + // Enables the Azure Disk in-tree driver to Azure Disk Driver migration feature. + CSIMigrationAzureDisk featuregate.Feature = "CSIMigrationAzureDisk" + // owner: @RobertKrawitz // beta: v1.15 // @@ -496,6 +502,7 @@ var defaultKubernetesFeatureGates = map[featuregate.Feature]featuregate.FeatureS CSIMigration: {Default: false, PreRelease: featuregate.Alpha}, CSIMigrationGCE: {Default: false, PreRelease: featuregate.Alpha}, CSIMigrationAWS: {Default: false, PreRelease: featuregate.Alpha}, + CSIMigrationAzureDisk: {Default: false, PreRelease: featuregate.Alpha}, RunAsGroup: {Default: true, PreRelease: featuregate.Beta}, CSIMigrationOpenStack: {Default: false, PreRelease: featuregate.Alpha}, VolumeSubpath: {Default: true, PreRelease: featuregate.GA}, diff --git a/pkg/volume/azure_dd/azure_dd.go b/pkg/volume/azure_dd/azure_dd.go index 613408955fb..0f5fe506cac 100644 --- a/pkg/volume/azure_dd/azure_dd.go +++ b/pkg/volume/azure_dd/azure_dd.go @@ -29,6 +29,8 @@ import ( "k8s.io/apimachinery/pkg/api/resource" "k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/util/sets" + utilfeature "k8s.io/apiserver/pkg/util/feature" + "k8s.io/kubernetes/pkg/features" "k8s.io/kubernetes/pkg/volume" "k8s.io/kubernetes/pkg/volume/util" "k8s.io/legacy-cloud-providers/azure" @@ -119,7 +121,8 @@ func (plugin *azureDataDiskPlugin) CanSupport(spec *volume.Spec) bool { } func (plugin *azureDataDiskPlugin) IsMigratedToCSI() bool { - return false + return utilfeature.DefaultFeatureGate.Enabled(features.CSIMigration) && + utilfeature.DefaultFeatureGate.Enabled(features.CSIMigrationAzureDisk) } func (plugin *azureDataDiskPlugin) RequiresRemount() bool { diff --git a/staging/src/k8s.io/csi-translation-lib/translate.go b/staging/src/k8s.io/csi-translation-lib/translate.go index a13ac422df2..67296f3163d 100644 --- a/staging/src/k8s.io/csi-translation-lib/translate.go +++ b/staging/src/k8s.io/csi-translation-lib/translate.go @@ -27,9 +27,10 @@ import ( var ( inTreePlugins = map[string]plugins.InTreePlugin{ - plugins.GCEPDDriverName: plugins.NewGCEPersistentDiskCSITranslator(), - plugins.AWSEBSDriverName: plugins.NewAWSElasticBlockStoreCSITranslator(), - plugins.CinderDriverName: plugins.NewOpenStackCinderCSITranslator(), + plugins.GCEPDDriverName: plugins.NewGCEPersistentDiskCSITranslator(), + plugins.AWSEBSDriverName: plugins.NewAWSElasticBlockStoreCSITranslator(), + plugins.CinderDriverName: plugins.NewOpenStackCinderCSITranslator(), + plugins.AzureDiskDriverName: plugins.NewAzureDiskCSITranslator(), } )