mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-23 19:56:01 +00:00
Add RepairVolumeHandle to the csi translation struct
This commit is contained in:
parent
5c8d219dfe
commit
93f7cec5b3
@ -23,7 +23,7 @@ import (
|
|||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"k8s.io/api/core/v1"
|
v1 "k8s.io/api/core/v1"
|
||||||
storage "k8s.io/api/storage/v1"
|
storage "k8s.io/api/storage/v1"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
)
|
)
|
||||||
@ -161,6 +161,10 @@ func (t *awsElasticBlockStoreCSITranslator) GetCSIPluginName() string {
|
|||||||
return AWSEBSDriverName
|
return AWSEBSDriverName
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (t *awsElasticBlockStoreCSITranslator) RepairVolumeHandle(volumeHandle, nodeID string) (string, error) {
|
||||||
|
return volumeHandle, nil
|
||||||
|
}
|
||||||
|
|
||||||
// awsVolumeRegMatch represents Regex Match for AWS volume.
|
// awsVolumeRegMatch represents Regex Match for AWS volume.
|
||||||
var awsVolumeRegMatch = regexp.MustCompile("^vol-[^/]*$")
|
var awsVolumeRegMatch = regexp.MustCompile("^vol-[^/]*$")
|
||||||
|
|
||||||
|
@ -21,7 +21,7 @@ import (
|
|||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"k8s.io/api/core/v1"
|
v1 "k8s.io/api/core/v1"
|
||||||
storage "k8s.io/api/storage/v1"
|
storage "k8s.io/api/storage/v1"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
)
|
)
|
||||||
@ -209,6 +209,10 @@ func (t *azureDiskCSITranslator) GetCSIPluginName() string {
|
|||||||
return AzureDiskDriverName
|
return AzureDiskDriverName
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (t *azureDiskCSITranslator) RepairVolumeHandle(volumeHandle, nodeID string) (string, error) {
|
||||||
|
return volumeHandle, nil
|
||||||
|
}
|
||||||
|
|
||||||
func isManagedDisk(diskURI string) bool {
|
func isManagedDisk(diskURI string) bool {
|
||||||
if len(diskURI) > 4 && strings.ToLower(diskURI[:4]) == "http" {
|
if len(diskURI) > 4 && strings.ToLower(diskURI[:4]) == "http" {
|
||||||
return false
|
return false
|
||||||
|
@ -20,7 +20,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"k8s.io/api/core/v1"
|
v1 "k8s.io/api/core/v1"
|
||||||
storage "k8s.io/api/storage/v1"
|
storage "k8s.io/api/storage/v1"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
)
|
)
|
||||||
@ -176,6 +176,10 @@ func (t *azureFileCSITranslator) GetCSIPluginName() string {
|
|||||||
return AzureFileDriverName
|
return AzureFileDriverName
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (t *azureFileCSITranslator) RepairVolumeHandle(volumeHandle, nodeID string) (string, error) {
|
||||||
|
return volumeHandle, nil
|
||||||
|
}
|
||||||
|
|
||||||
// get file share info according to volume id, e.g.
|
// get file share info according to volume id, e.g.
|
||||||
// input: "rg#f5713de20cde511e8ba4900#pvc-file-dynamic-17e43f84-f474-11e8-acd0-000d3a00df41"
|
// input: "rg#f5713de20cde511e8ba4900#pvc-file-dynamic-17e43f84-f474-11e8-acd0-000d3a00df41"
|
||||||
// output: rg, f5713de20cde511e8ba4900, pvc-file-dynamic-17e43f84-f474-11e8-acd0-000d3a00df41
|
// output: rg, f5713de20cde511e8ba4900, pvc-file-dynamic-17e43f84-f474-11e8-acd0-000d3a00df41
|
||||||
|
@ -21,7 +21,7 @@ import (
|
|||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"k8s.io/api/core/v1"
|
v1 "k8s.io/api/core/v1"
|
||||||
storage "k8s.io/api/storage/v1"
|
storage "k8s.io/api/storage/v1"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/util/sets"
|
"k8s.io/apimachinery/pkg/util/sets"
|
||||||
@ -41,9 +41,14 @@ const (
|
|||||||
// "projects/{projectName}/zones/{zoneName}/disks/{diskName}"
|
// "projects/{projectName}/zones/{zoneName}/disks/{diskName}"
|
||||||
volIDZonalFmt = "projects/%s/zones/%s/disks/%s"
|
volIDZonalFmt = "projects/%s/zones/%s/disks/%s"
|
||||||
// "projects/{projectName}/regions/{regionName}/disks/{diskName}"
|
// "projects/{projectName}/regions/{regionName}/disks/{diskName}"
|
||||||
volIDRegionalFmt = "projects/%s/regions/%s/disks/%s"
|
volIDRegionalFmt = "projects/%s/regions/%s/disks/%s"
|
||||||
volIDDiskNameValue = 5
|
volIDProjectValue = 1
|
||||||
volIDTotalElements = 6
|
volIDRegionalityValue = 2
|
||||||
|
volIDZoneValue = 3
|
||||||
|
volIDDiskNameValue = 5
|
||||||
|
volIDTotalElements = 6
|
||||||
|
|
||||||
|
nodeIDFmt = "projects/%s/zones/%s/instances/%s"
|
||||||
|
|
||||||
// UnspecifiedValue is used for an unknown zone string
|
// UnspecifiedValue is used for an unknown zone string
|
||||||
UnspecifiedValue = "UNSPECIFIED"
|
UnspecifiedValue = "UNSPECIFIED"
|
||||||
@ -328,10 +333,53 @@ func (g *gcePersistentDiskCSITranslator) GetCSIPluginName() string {
|
|||||||
return GCEPDDriverName
|
return GCEPDDriverName
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RepairVolumeHandle returns a fully specified volume handle by inferring
|
||||||
|
// project, zone/region from the node ID if the volume handle has UNSPECIFIED
|
||||||
|
// sections
|
||||||
|
func (g *gcePersistentDiskCSITranslator) RepairVolumeHandle(volumeHandle, nodeID string) (string, error) {
|
||||||
|
var err error
|
||||||
|
tok := strings.Split(volumeHandle, "/")
|
||||||
|
if len(tok) < volIDTotalElements {
|
||||||
|
return "", fmt.Errorf("volume handle has wrong number of elements; got %v, wanted %v or more", len(tok), volIDTotalElements)
|
||||||
|
}
|
||||||
|
if tok[volIDProjectValue] != UnspecifiedValue {
|
||||||
|
return volumeHandle, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
nodeTok := strings.Split(nodeID, "/")
|
||||||
|
if len(nodeTok) < volIDTotalElements {
|
||||||
|
return "", fmt.Errorf("node handle has wrong number of elements; got %v, wanted %v or more", len(nodeTok), volIDTotalElements)
|
||||||
|
}
|
||||||
|
|
||||||
|
switch tok[volIDRegionalityValue] {
|
||||||
|
case "zones":
|
||||||
|
zone := ""
|
||||||
|
if tok[volIDZoneValue] == UnspecifiedValue {
|
||||||
|
zone = nodeTok[volIDZoneValue]
|
||||||
|
} else {
|
||||||
|
zone = tok[volIDZoneValue]
|
||||||
|
}
|
||||||
|
return fmt.Sprintf(volIDZonalFmt, nodeTok[volIDProjectValue], zone, tok[volIDDiskNameValue]), nil
|
||||||
|
case "regions":
|
||||||
|
region := ""
|
||||||
|
if tok[volIDZoneValue] == UnspecifiedValue {
|
||||||
|
region, err = getRegionFromZones([]string{nodeTok[volIDZoneValue]})
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("failed to get region from zone %s: %v", nodeTok[volIDZoneValue], err)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
region = tok[volIDZoneValue]
|
||||||
|
}
|
||||||
|
return fmt.Sprintf(volIDRegionalFmt, nodeTok[volIDProjectValue], region, tok[volIDDiskNameValue]), nil
|
||||||
|
default:
|
||||||
|
return "", fmt.Errorf("expected volume handle to have zones or regions regionality value, got: %s", tok[volIDRegionalityValue])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func pdNameFromVolumeID(id string) (string, error) {
|
func pdNameFromVolumeID(id string) (string, error) {
|
||||||
splitID := strings.Split(id, "/")
|
splitID := strings.Split(id, "/")
|
||||||
if len(splitID) != volIDTotalElements {
|
if len(splitID) < volIDTotalElements {
|
||||||
return "", fmt.Errorf("failed to get id components. Expected projects/{project}/zones/{zone}/disks/{name}. Got: %s", id)
|
return "", fmt.Errorf("failed to get id components.Got: %v, wanted %v components or more. ", len(splitID), volIDTotalElements)
|
||||||
}
|
}
|
||||||
return splitID[volIDDiskNameValue], nil
|
return splitID[volIDDiskNameValue], nil
|
||||||
}
|
}
|
||||||
|
@ -17,10 +17,11 @@ limitations under the License.
|
|||||||
package plugins
|
package plugins
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"k8s.io/api/core/v1"
|
v1 "k8s.io/api/core/v1"
|
||||||
storage "k8s.io/api/storage/v1"
|
storage "k8s.io/api/storage/v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -204,6 +205,84 @@ func TestTranslateAllowedTopologies(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestRepairVolumeHandle(t *testing.T) {
|
||||||
|
testCases := []struct {
|
||||||
|
name string
|
||||||
|
volumeHandle string
|
||||||
|
nodeID string
|
||||||
|
expectedVolumeHandle string
|
||||||
|
expectedErr bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "fully specified",
|
||||||
|
volumeHandle: fmt.Sprintf(volIDZonalFmt, "foo", "bar", "baz"),
|
||||||
|
nodeID: fmt.Sprintf(nodeIDFmt, "bing", "bada", "boom"),
|
||||||
|
expectedVolumeHandle: fmt.Sprintf(volIDZonalFmt, "foo", "bar", "baz"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "fully specified (regional)",
|
||||||
|
volumeHandle: fmt.Sprintf(volIDRegionalFmt, "foo", "us-central1-c", "baz"),
|
||||||
|
nodeID: fmt.Sprintf(nodeIDFmt, "bing", "bada", "boom"),
|
||||||
|
expectedVolumeHandle: fmt.Sprintf(volIDRegionalFmt, "foo", "us-central1-c", "baz"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "no project",
|
||||||
|
volumeHandle: fmt.Sprintf(volIDZonalFmt, UnspecifiedValue, "bar", "baz"),
|
||||||
|
nodeID: fmt.Sprintf(nodeIDFmt, "bing", "bada", "boom"),
|
||||||
|
expectedVolumeHandle: fmt.Sprintf(volIDZonalFmt, "bing", "bar", "baz"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "no project or zone",
|
||||||
|
volumeHandle: fmt.Sprintf(volIDZonalFmt, UnspecifiedValue, UnspecifiedValue, "baz"),
|
||||||
|
nodeID: fmt.Sprintf(nodeIDFmt, "bing", "bada", "boom"),
|
||||||
|
expectedVolumeHandle: fmt.Sprintf(volIDZonalFmt, "bing", "bada", "baz"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "no project or region",
|
||||||
|
volumeHandle: fmt.Sprintf(volIDRegionalFmt, UnspecifiedValue, UnspecifiedValue, "baz"),
|
||||||
|
nodeID: fmt.Sprintf(nodeIDFmt, "bing", "us-central1-c", "boom"),
|
||||||
|
expectedVolumeHandle: fmt.Sprintf(volIDRegionalFmt, "bing", "us-central1", "baz"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "no project (regional)",
|
||||||
|
volumeHandle: fmt.Sprintf(volIDRegionalFmt, UnspecifiedValue, "us-west1", "baz"),
|
||||||
|
nodeID: fmt.Sprintf(nodeIDFmt, "bing", "us-central1-c", "boom"),
|
||||||
|
expectedVolumeHandle: fmt.Sprintf(volIDRegionalFmt, "bing", "us-west1", "baz"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "invalid handle",
|
||||||
|
volumeHandle: "foo",
|
||||||
|
nodeID: fmt.Sprintf(nodeIDFmt, "bing", "us-central1-c", "boom"),
|
||||||
|
expectedErr: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "invalid node ID",
|
||||||
|
volumeHandle: fmt.Sprintf(volIDRegionalFmt, UnspecifiedValue, "us-west1", "baz"),
|
||||||
|
nodeID: "foo",
|
||||||
|
expectedErr: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
g := NewGCEPersistentDiskCSITranslator()
|
||||||
|
for _, tc := range testCases {
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
gotVolumeHandle, err := g.RepairVolumeHandle(tc.volumeHandle, tc.nodeID)
|
||||||
|
if err != nil && !tc.expectedErr {
|
||||||
|
if !tc.expectedErr {
|
||||||
|
t.Fatalf("Got error: %v, but expected none", err)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err == nil && tc.expectedErr {
|
||||||
|
t.Fatal("Got no error, but expected one")
|
||||||
|
}
|
||||||
|
|
||||||
|
if gotVolumeHandle != tc.expectedVolumeHandle {
|
||||||
|
t.Fatalf("Got volume handle %s, but expected %s", gotVolumeHandle, tc.expectedVolumeHandle)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestBackwardCompatibleAccessModes(t *testing.T) {
|
func TestBackwardCompatibleAccessModes(t *testing.T) {
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
name string
|
name string
|
||||||
|
@ -17,7 +17,7 @@ limitations under the License.
|
|||||||
package plugins
|
package plugins
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"k8s.io/api/core/v1"
|
v1 "k8s.io/api/core/v1"
|
||||||
storage "k8s.io/api/storage/v1"
|
storage "k8s.io/api/storage/v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -55,4 +55,7 @@ type InTreePlugin interface {
|
|||||||
|
|
||||||
// GetCSIPluginName returns the name of the CSI plugin that supersedes the in-tree plugin
|
// GetCSIPluginName returns the name of the CSI plugin that supersedes the in-tree plugin
|
||||||
GetCSIPluginName() string
|
GetCSIPluginName() string
|
||||||
|
|
||||||
|
// RepairVolumeHandle generates a correct volume handle based on node ID information.
|
||||||
|
RepairVolumeHandle(volumeHandle, nodeID string) (string, error)
|
||||||
}
|
}
|
||||||
|
@ -19,7 +19,7 @@ package plugins
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"k8s.io/api/core/v1"
|
v1 "k8s.io/api/core/v1"
|
||||||
storage "k8s.io/api/storage/v1"
|
storage "k8s.io/api/storage/v1"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
)
|
)
|
||||||
@ -140,3 +140,7 @@ func (t *osCinderCSITranslator) GetInTreePluginName() string {
|
|||||||
func (t *osCinderCSITranslator) GetCSIPluginName() string {
|
func (t *osCinderCSITranslator) GetCSIPluginName() string {
|
||||||
return CinderDriverName
|
return CinderDriverName
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (t *osCinderCSITranslator) RepairVolumeHandle(volumeHandle, nodeID string) (string, error) {
|
||||||
|
return volumeHandle, nil
|
||||||
|
}
|
||||||
|
@ -186,3 +186,11 @@ func (CSITranslator) IsInlineMigratable(vol *v1.Volume) bool {
|
|||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RepairVolumeHandle generates a correct volume handle based on node ID information.
|
||||||
|
func (CSITranslator) RepairVolumeHandle(driverName, volumeHandle, nodeID string) (string, error) {
|
||||||
|
if plugin, ok := inTreePlugins[driverName]; ok {
|
||||||
|
return plugin.RepairVolumeHandle(volumeHandle, nodeID)
|
||||||
|
}
|
||||||
|
return "", fmt.Errorf("could not find In-Tree driver name for CSI plugin %v", driverName)
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user