Unverified Commit 774fa8b4 authored by Kubernetes Prow Robot's avatar Kubernetes Prow Robot Committed by GitHub

Merge pull request #72770 from ddebroy/ddebroy-csi-translation-1

Populate Staging repo csi-translation-lib
parents 3b0b74f5 913bd97b
......@@ -199,3 +199,10 @@
- k8s.io/client-go
- k8s.io/csi-api
- k8s.io/klog
- baseImportPath: "./vendor/k8s.io/csi-translation-lib/"
allowedImports:
- k8s.io/api
- k8s.io/apimachinery
- k8s.io/klog
- k8s.io/csi-translation-lib
......@@ -17,6 +17,7 @@ Repositories currently staged here:
- [`k8s.io/code-generator`](https://github.com/kubernetes/code-generator)
- [`k8s.io/component-base`](https://github.com/kubernetes/component-base)
- [`k8s.io/csi-api`](https://github.com/kubernetes/csi-api)
- [`k8s.io/csi-translation-lib`](https://github.com/kubernetes/csi-translation-lib)
- [`k8s.io/kube-aggregator`](https://github.com/kubernetes/kube-aggregator)
- [`k8s.io/kube-controller-manager`](https://github.com/kubernetes/kube-controller-manager)
- [`k8s.io/kube-proxy`](https://github.com/kubernetes/kube-proxy)
......
......@@ -213,6 +213,7 @@ filegroup(
"//staging/src/k8s.io/csi-api/pkg/client/informers/externalversions:all-srcs",
"//staging/src/k8s.io/csi-api/pkg/client/listers/csi/v1alpha1:all-srcs",
"//staging/src/k8s.io/csi-api/pkg/crd:all-srcs",
"//staging/src/k8s.io/csi-translation-lib:all-srcs",
"//staging/src/k8s.io/kube-aggregator:all-srcs",
"//staging/src/k8s.io/kube-controller-manager/config/v1alpha1:all-srcs",
"//staging/src/k8s.io/kube-proxy/config/v1alpha1:all-srcs",
......
Sorry, we do not accept changes directly against this repository. Please see
CONTRIBUTING.md for information on where and how to contribute instead.
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
go_library(
name = "go_default_library",
srcs = ["translate.go"],
importmap = "k8s.io/kubernetes/vendor/k8s.io/csi-translation-lib",
importpath = "k8s.io/csi-translation-lib",
visibility = ["//visibility:public"],
deps = [
"//staging/src/k8s.io/api/core/v1:go_default_library",
"//staging/src/k8s.io/csi-translation-lib/plugins:go_default_library",
],
)
go_test(
name = "go_default_test",
srcs = ["translate_test.go"],
embed = [":go_default_library"],
deps = ["//staging/src/k8s.io/api/core/v1:go_default_library"],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [
":package-srcs",
"//staging/src/k8s.io/csi-translation-lib/plugins:all-srcs",
],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)
# Contributing guidelines
Do not open pull requests directly against this repository, they will be ignored. Instead, please open pull requests against [kubernetes/kubernetes](https://git.k8s.io/kubernetes/). Please follow the same [contributing guide](https://git.k8s.io/kubernetes/CONTRIBUTING.md) you would follow for any other pull request made to kubernetes/kubernetes.
This repository is published from [kubernetes/kubernetes/staging/src/k8s.io/csi-api](https://git.k8s.io/kubernetes/staging/src/k8s.io/csi-api) by the [kubernetes publishing-bot](https://git.k8s.io/publishing-bot).
Please see [Staging Directory and Publishing](https://git.k8s.io/community/contributors/devel/staging.md) for more information.
{
"ImportPath": "k8s.io/csi-translation-lib",
"GoVersion": "go1.11",
"GodepVersion": "v80-k8s-r1",
"Packages": [
"./..."
],
"Deps": [
{
"ImportPath": "github.com/gogo/protobuf/proto",
"Rev": "342cbe0a04158f6dcb03ca0079991a51a4248c02"
},
{
"ImportPath": "github.com/gogo/protobuf/sortkeys",
"Rev": "342cbe0a04158f6dcb03ca0079991a51a4248c02"
},
{
"ImportPath": "github.com/google/gofuzz",
"Rev": "44d81051d367757e1c7c6a5a86423ece9afcf63c"
},
{
"ImportPath": "golang.org/x/net/http2",
"Rev": "0ed95abb35c445290478a5348a7b38bb154135fd"
},
{
"ImportPath": "golang.org/x/net/http2/hpack",
"Rev": "0ed95abb35c445290478a5348a7b38bb154135fd"
},
{
"ImportPath": "golang.org/x/net/idna",
"Rev": "0ed95abb35c445290478a5348a7b38bb154135fd"
},
{
"ImportPath": "golang.org/x/net/lex/httplex",
"Rev": "0ed95abb35c445290478a5348a7b38bb154135fd"
},
{
"ImportPath": "golang.org/x/text/secure/bidirule",
"Rev": "b19bf474d317b857955b12035d2c5acb57ce8b01"
},
{
"ImportPath": "golang.org/x/text/transform",
"Rev": "b19bf474d317b857955b12035d2c5acb57ce8b01"
},
{
"ImportPath": "golang.org/x/text/unicode/bidi",
"Rev": "b19bf474d317b857955b12035d2c5acb57ce8b01"
},
{
"ImportPath": "golang.org/x/text/unicode/norm",
"Rev": "b19bf474d317b857955b12035d2c5acb57ce8b01"
},
{
"ImportPath": "gopkg.in/inf.v0",
"Rev": "3887ee99ecf07df5b447e9b00d9c0b2adaa9f3e4"
},
{
"ImportPath": "k8s.io/api/core/v1",
"Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/api/resource",
"Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/apis/meta/v1",
"Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/conversion",
"Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/conversion/queryparams",
"Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/fields",
"Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/labels",
"Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/runtime",
"Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/runtime/schema",
"Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/selection",
"Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/types",
"Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/errors",
"Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/intstr",
"Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/json",
"Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/naming",
"Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/net",
"Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/runtime",
"Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/sets",
"Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/validation",
"Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/validation/field",
"Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/watch",
"Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
},
{
"ImportPath": "k8s.io/apimachinery/third_party/forked/golang/reflect",
"Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
},
{
"ImportPath": "k8s.io/klog",
"Rev": "8139d8cb77af419532b33dfa7dd09fbc5f1d344f"
}
]
}
reviewers:
- davidz627
- saad-ali
- msau42
- ddebroy
- leakingtapan
approvers:
- davidz627
- saad-ali
- msau42
## Purpose
This repository contains functions to be consumed by various Kubernetes and
out-of-tree CSI components like external provisioner to facilitate migration of
code from Kubernetes In-tree plugin code to CSI plugin repositories.
Consumers can make use of this repository can make use of functions like
`TranslateToCSI` and `TranslateToInTree` functions to translate PV sources.
## Community, discussion, contribution, and support
Learn how to engage with the Kubernetes community on the [community
page](http://kubernetes.io/community/).
You can reach the maintainers of this repository at:
- Slack: #sig-storage (on https://kubernetes.slack.com -- get an
invite at slack.kubernetes.io)
- Mailing List:
https://groups.google.com/forum/#!forum/kubernetes-sig-storage
### Code of Conduct
Participation in the Kubernetes community is governed by the [Kubernetes
Code of Conduct](code-of-conduct.md).
### Contibution Guidelines
See [CONTRIBUTING.md](CONTRIBUTING.md) for more information.
# Defined below are the security contacts for this repo.
#
# They are the contact point for the Product Security Team to reach out
# to for triaging and handling of incoming issues.
#
# The below names agree to abide by the
# [Embargo Policy](https://github.com/kubernetes/sig-release/blob/master/security-release-process-documentation/security-release-process.md#embargo-policy)
# and will be removed and replaced if they violate that agreement.
#
# DO NOT REPORT SECURITY VULNERABILITIES DIRECTLY TO THESE NAMES, FOLLOW THE
# INSTRUCTIONS AT https://kubernetes.io/security/
saad-ali
# Kubernetes Community Code of Conduct
Please refer to our [Kubernetes Community Code of Conduct](https://git.k8s.io/community/code-of-conduct.md)
load("@io_bazel_rules_go//go:def.bzl", "go_library")
go_library(
name = "go_default_library",
srcs = [
"aws_ebs.go",
"gce_pd.go",
"in_tree_volume.go",
],
importmap = "k8s.io/kubernetes/vendor/k8s.io/csi-translation-lib/plugins",
importpath = "k8s.io/csi-translation-lib/plugins",
visibility = ["//visibility:public"],
deps = [
"//staging/src/k8s.io/api/core/v1:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/sets:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)
/*
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"
"strconv"
"k8s.io/api/core/v1"
)
const (
// AWSEBSDriverName is the name of the CSI driver for EBS
AWSEBSDriverName = "ebs.csi.aws.com"
// AWSEBSInTreePluginName is the name of the intree plugin for EBS
AWSEBSInTreePluginName = "kubernetes.io/aws-ebs"
)
// AWSEBS handles translation of PV spec from In-tree EBS to CSI EBS and vice versa
type AWSEBS struct{}
// TranslateInTreePVToCSI takes a PV with AWSElasticBlockStore set from in-tree
// and converts the AWSElasticBlockStore source to a CSIPersistentVolumeSource
func (t *AWSEBS) TranslateInTreePVToCSI(pv *v1.PersistentVolume) (*v1.PersistentVolume, error) {
if pv == nil || pv.Spec.AWSElasticBlockStore == nil {
return nil, fmt.Errorf("pv is nil or AWS EBS not defined on pv")
}
ebsSource := pv.Spec.AWSElasticBlockStore
csiSource := &v1.CSIPersistentVolumeSource{
Driver: AWSEBSDriverName,
VolumeHandle: ebsSource.VolumeID,
ReadOnly: ebsSource.ReadOnly,
FSType: ebsSource.FSType,
VolumeAttributes: map[string]string{
"partition": strconv.FormatInt(int64(ebsSource.Partition), 10),
},
}
pv.Spec.AWSElasticBlockStore = nil
pv.Spec.CSI = csiSource
return pv, nil
}
// TranslateCSIPVToInTree takes a PV with CSIPersistentVolumeSource set and
// translates the EBS CSI source to a AWSElasticBlockStore source.
func (t *AWSEBS) 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
ebsSource := &v1.AWSElasticBlockStoreVolumeSource{
VolumeID: csiSource.VolumeHandle,
FSType: csiSource.FSType,
ReadOnly: csiSource.ReadOnly,
}
if partition, ok := csiSource.VolumeAttributes["partition"]; ok {
partValue, err := strconv.Atoi(partition)
if err != nil {
return nil, fmt.Errorf("Failed to convert partition %v to integer: %v", partition, err)
}
ebsSource.Partition = int32(partValue)
}
pv.Spec.CSI = nil
pv.Spec.AWSElasticBlockStore = ebsSource
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 *AWSEBS) CanSupport(pv *v1.PersistentVolume) bool {
return pv != nil && pv.Spec.AWSElasticBlockStore != nil
}
// GetInTreePluginName returns the name of the intree plugin driver
func (t *AWSEBS) GetInTreePluginName() string {
return AWSEBSInTreePluginName
}
/*
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"
"strconv"
"strings"
"k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/util/sets"
)
const (
// GCEPDDriverName is the name of the CSI driver for GCE PD
GCEPDDriverName = "pd.csi.storage.gke.io"
// GCEPDInTreePluginName is the name of the intree plugin for GCE PD
GCEPDInTreePluginName = "kubernetes.io/gce-pd"
// Volume ID Expected Format
// "projects/{projectName}/zones/{zoneName}/disks/{diskName}"
volIDZonalFmt = "projects/%s/zones/%s/disks/%s"
// "projects/{projectName}/regions/{regionName}/disks/{diskName}"
volIDRegionalFmt = "projects/%s/regions/%s/disks/%s"
volIDDiskNameValue = 5
volIDTotalElements = 6
// LabelZoneFailureDomain is the label on PVs indicating the zone they are provisioned in
LabelZoneFailureDomain = "failure-domain.beta.kubernetes.io/zone"
// LabelMultiZoneDelimiter separates zones for RePD volumes
LabelMultiZoneDelimiter = "__"
// UnspecifiedValue is used for an unknown zone string
UnspecifiedValue = "UNSPECIFIED"
)
// GCEPD handles translation of PV spec from In-tree GCE PD to CSI GCE PD and vice versa
type GCEPD struct{}
// TranslateInTreePVToCSI takes a PV with GCEPersistentDisk set from in-tree
// and converts the GCEPersistentDisk source to a CSIPersistentVolumeSource
func (g *GCEPD) TranslateInTreePVToCSI(pv *v1.PersistentVolume) (*v1.PersistentVolume, error) {
var volID string
if pv == nil || pv.Spec.GCEPersistentDisk == nil {
return nil, fmt.Errorf("pv is nil or GCE Persistent Disk source not defined on pv")
}
zonesLabel := pv.Labels[LabelZoneFailureDomain]
zones := strings.Split(zonesLabel, LabelMultiZoneDelimiter)
if len(zones) == 1 && len(zones[0]) != 0 {
// Zonal
volID = fmt.Sprintf(volIDZonalFmt, UnspecifiedValue, zones[0], pv.Spec.GCEPersistentDisk.PDName)
} else if len(zones) > 1 {
// Regional
region, err := getRegionFromZones(zones)
if err != nil {
return nil, fmt.Errorf("failed to get region from zones: %v", err)
}
volID = fmt.Sprintf(volIDZonalFmt, UnspecifiedValue, region, pv.Spec.GCEPersistentDisk.PDName)
} else {
// Unspecified
volID = fmt.Sprintf(volIDZonalFmt, UnspecifiedValue, UnspecifiedValue, pv.Spec.GCEPersistentDisk.PDName)
}
gceSource := pv.Spec.PersistentVolumeSource.GCEPersistentDisk
csiSource := &v1.CSIPersistentVolumeSource{
Driver: GCEPDDriverName,
VolumeHandle: volID,
ReadOnly: gceSource.ReadOnly,
FSType: gceSource.FSType,
VolumeAttributes: map[string]string{
"partition": strconv.FormatInt(int64(gceSource.Partition), 10),
},
}
pv.Spec.PersistentVolumeSource.GCEPersistentDisk = nil
pv.Spec.PersistentVolumeSource.CSI = csiSource
return pv, nil
}
// TranslateCSIPVToInTree takes a PV with CSIPersistentVolumeSource set and
// translates the GCE PD CSI source to a GCEPersistentDisk source.
func (g *GCEPD) 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
pdName, err := pdNameFromVolumeID(csiSource.VolumeHandle)
if err != nil {
return nil, err
}
gceSource := &v1.GCEPersistentDiskVolumeSource{
PDName: pdName,
FSType: csiSource.FSType,
ReadOnly: csiSource.ReadOnly,
}
if partition, ok := csiSource.VolumeAttributes["partition"]; ok {
partInt, err := strconv.Atoi(partition)
if err != nil {
return nil, fmt.Errorf("Failed to convert partition %v to integer: %v", partition, err)
}
gceSource.Partition = int32(partInt)
}
// TODO: Take the zone/regional information and stick it into the label.
pv.Spec.CSI = nil
pv.Spec.GCEPersistentDisk = gceSource
return pv, nil
}
// CanSupport tests whether the plugin supports a given volume
// specification from the API. The spec pointer should be considered
// const.
func (g *GCEPD) CanSupport(pv *v1.PersistentVolume) bool {
return pv != nil && pv.Spec.GCEPersistentDisk != nil
}
// GetInTreePluginName returns the name of the intree plugin driver
func (g *GCEPD) GetInTreePluginName() string {
return GCEPDInTreePluginName
}
func pdNameFromVolumeID(id string) (string, error) {
splitID := strings.Split(id, "/")
if len(splitID) != volIDTotalElements {
return "", fmt.Errorf("failed to get id components. Expected projects/{project}/zones/{zone}/disks/{name}. Got: %s", id)
}
return splitID[volIDDiskNameValue], nil
}
// TODO: Replace this with the imported one from GCE PD CSI Driver when
// the driver removes all k8s/k8s dependencies
func getRegionFromZones(zones []string) (string, error) {
regions := sets.String{}
if len(zones) < 1 {
return "", fmt.Errorf("no zones specified")
}
for _, zone := range zones {
// Zone expected format {locale}-{region}-{zone}
splitZone := strings.Split(zone, "-")
if len(splitZone) != 3 {
return "", fmt.Errorf("zone in unexpected format, expected: {locale}-{region}-{zone}, got: %v", zone)
}
regions.Insert(strings.Join(splitZone[0:2], "-"))
}
if regions.Len() != 1 {
return "", fmt.Errorf("multiple or no regions gotten from zones, got: %v", regions)
}
return regions.UnsortedList()[0], nil
}
/*
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 "k8s.io/api/core/v1"
// InTreePlugin handles translations between CSI and in-tree sources in a PV
type InTreePlugin interface {
// TranslateInTreePVToCSI takes a persistent volume and will translate
// the in-tree source to a CSI Source. The input persistent volume can be modified
TranslateInTreePVToCSI(pv *v1.PersistentVolume) (*v1.PersistentVolume, error)
// TranslateCSIPVToInTree takes a PV with a CSI PersistentVolume Source and will translate
// it to a in-tree Persistent Volume Source for the in-tree volume
// by the `Driver` field in the CSI Source. The input PV object can be modified
TranslateCSIPVToInTree(pv *v1.PersistentVolume) (*v1.PersistentVolume, error)
// CanSupport tests whether the plugin supports a given volume
// specification from the API.
CanSupport(pv *v1.PersistentVolume) bool
// GetInTreePluginName returns the in-tree plugin name this migrates
GetInTreePluginName() string
}
/*
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 csitranslation
import (
"fmt"
"k8s.io/api/core/v1"
"k8s.io/csi-translation-lib/plugins"
)
var (
inTreePlugins = map[string]plugins.InTreePlugin{
plugins.GCEPDDriverName: &plugins.GCEPD{},
plugins.AWSEBSDriverName: &plugins.AWSEBS{},
}
)
// TranslateInTreePVToCSI takes a persistent volume and will translate
// the in-tree source to a CSI Source if the translation logic
// has been implemented. The input persistent volume will not
// be modified
func TranslateInTreePVToCSI(pv *v1.PersistentVolume) (*v1.PersistentVolume, error) {
if pv == nil {
return nil, fmt.Errorf("persistent volume was nil")
}
copiedPV := pv.DeepCopy()
for _, curPlugin := range inTreePlugins {
if curPlugin.CanSupport(copiedPV) {
return curPlugin.TranslateInTreePVToCSI(copiedPV)
}
}
return nil, fmt.Errorf("could not find in-tree plugin translation logic for %#v", copiedPV.Name)
}
// TranslateCSIPVToInTree takes a PV with a CSI PersistentVolume Source and will translate
// it to a in-tree Persistent Volume Source for the specific in-tree volume specified
// by the `Driver` field in the CSI Source. The input PV object will not be modified.
func TranslateCSIPVToInTree(pv *v1.PersistentVolume) (*v1.PersistentVolume, error) {
if pv == nil || pv.Spec.CSI == nil {
return nil, fmt.Errorf("CSI persistent volume was nil")
}
copiedPV := pv.DeepCopy()
for driverName, curPlugin := range inTreePlugins {
if copiedPV.Spec.CSI.Driver == driverName {
return curPlugin.TranslateCSIPVToInTree(copiedPV)
}
}
return nil, fmt.Errorf("could not find in-tree plugin translation logic for %s", copiedPV.Spec.CSI.Driver)
}
// IsMigratableByName tests whether there is Migration logic for the in-tree plugin
// for the given `pluginName`
func IsMigratableByName(pluginName string) bool {
for _, curPlugin := range inTreePlugins {
if curPlugin.GetInTreePluginName() == pluginName {
return true
}
}
return false
}
// GetCSINameFromIntreeName maps the name of a CSI driver to its in-tree version
func GetCSINameFromIntreeName(pluginName string) (string, error) {
for csiDriverName, curPlugin := range inTreePlugins {
if curPlugin.GetInTreePluginName() == pluginName {
return csiDriverName, nil
}
}
return "", fmt.Errorf("Could not find CSI Driver name for plugin %v", pluginName)
}
// IsPVMigratable tests whether there is Migration logic for the given Persistent Volume
func IsPVMigratable(pv *v1.PersistentVolume) bool {
for _, curPlugin := range inTreePlugins {
if curPlugin.CanSupport(pv) {
return true
}
}
return false
}
// IsInlineMigratable tests whether there is Migration logic for the given Inline Volume
func IsInlineMigratable(vol *v1.Volume) bool {
return false
}
/*
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 csitranslation
import (
"reflect"
"testing"
"k8s.io/api/core/v1"
)
func TestTranslationStability(t *testing.T) {
testCases := []struct {
name string
pv *v1.PersistentVolume
}{
{
name: "GCE PD PV Source",
pv: &v1.PersistentVolume{
Spec: v1.PersistentVolumeSpec{
PersistentVolumeSource: v1.PersistentVolumeSource{
GCEPersistentDisk: &v1.GCEPersistentDiskVolumeSource{
PDName: "test-disk",
FSType: "ext4",
Partition: 0,
ReadOnly: false,
},
},
},
},
},
{
name: "AWS EBS PV Source",
pv: &v1.PersistentVolume{
Spec: v1.PersistentVolumeSpec{
PersistentVolumeSource: v1.PersistentVolumeSource{
AWSElasticBlockStore: &v1.AWSElasticBlockStoreVolumeSource{
VolumeID: "vol01",
FSType: "ext3",
Partition: 1,
ReadOnly: true,
},
},
},
},
},
}
for _, test := range testCases {
t.Logf("Testing %v", test.name)
csiSource, err := TranslateInTreePVToCSI(test.pv)
if err != nil {
t.Errorf("Error when translating to CSI: %v", err)
}
newPV, err := TranslateCSIPVToInTree(csiSource)
if err != nil {
t.Errorf("Error when translating CSI Source to in tree volume: %v", err)
}
if !reflect.DeepEqual(newPV, test.pv) {
t.Errorf("Volumes after translation and back not equal:\n\nOriginal Volume: %#v\n\nRound-trip Volume: %#v", test.pv, newPV)
}
}
}
// TODO: test for not modifying the original PV.
../../staging/src/k8s.io/csi-translation-lib
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment