mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-26 05:03:09 +00:00
Merge pull request #45345 from codablock/storageclass_fstype
Automatic merge from submit-queue (batch tested with PRs 45345, 49470, 49407, 49448, 49486) Support "fstype" parameter in dynamically provisioned PVs This PR is a replacement for https://github.com/kubernetes/kubernetes/pull/40805. I was not able to push fixes and rebases to the original branch as I don't have access to the Github organization anymore. I assume the PR will need a new "ok to test" **ORIGINAL PR DESCRIPTION** **What this PR does / why we need it**: This PR allows specifying the desired FSType when dynamically provisioning volumes with storage classes. The FSType can now be set as a parameter: ```yaml kind: StorageClass apiVersion: storage.k8s.io/v1beta1 metadata: name: test provisioner: kubernetes.io/azure-disk parameters: fstype: xfs ``` **Which issue this PR fixes** *(optional, in `fixes #<issue number>(, fixes #<issue_number>, ...)` format, will close that issue when PR gets merged)*: fixes #37801 **Special notes for your reviewer**: The PR also implicitly adds checks for unsupported parameters. **Release note**: ```release-note Support specifying of FSType in StorageClass ```
This commit is contained in:
commit
d286f56221
@ -244,7 +244,7 @@ func (plugin *awsElasticBlockStorePlugin) ConstructVolumeSpec(volName, mountPath
|
|||||||
|
|
||||||
// Abstract interface to PD operations.
|
// Abstract interface to PD operations.
|
||||||
type ebsManager interface {
|
type ebsManager interface {
|
||||||
CreateVolume(provisioner *awsElasticBlockStoreProvisioner) (volumeID aws.KubernetesVolumeID, volumeSizeGB int, labels map[string]string, err error)
|
CreateVolume(provisioner *awsElasticBlockStoreProvisioner) (volumeID aws.KubernetesVolumeID, volumeSizeGB int, labels map[string]string, fstype string, err error)
|
||||||
// Deletes a volume
|
// Deletes a volume
|
||||||
DeleteVolume(deleter *awsElasticBlockStoreDeleter) error
|
DeleteVolume(deleter *awsElasticBlockStoreDeleter) error
|
||||||
}
|
}
|
||||||
@ -434,12 +434,16 @@ func (c *awsElasticBlockStoreProvisioner) Provision() (*v1.PersistentVolume, err
|
|||||||
return nil, fmt.Errorf("invalid AccessModes %v: only AccessModes %v are supported", c.options.PVC.Spec.AccessModes, c.plugin.GetAccessModes())
|
return nil, fmt.Errorf("invalid AccessModes %v: only AccessModes %v are supported", c.options.PVC.Spec.AccessModes, c.plugin.GetAccessModes())
|
||||||
}
|
}
|
||||||
|
|
||||||
volumeID, sizeGB, labels, err := c.manager.CreateVolume(c)
|
volumeID, sizeGB, labels, fstype, err := c.manager.CreateVolume(c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Errorf("Provision failed: %v", err)
|
glog.Errorf("Provision failed: %v", err)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if fstype == "" {
|
||||||
|
fstype = "ext4"
|
||||||
|
}
|
||||||
|
|
||||||
pv := &v1.PersistentVolume{
|
pv := &v1.PersistentVolume{
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
Name: c.options.PVName,
|
Name: c.options.PVName,
|
||||||
@ -457,7 +461,7 @@ func (c *awsElasticBlockStoreProvisioner) Provision() (*v1.PersistentVolume, err
|
|||||||
PersistentVolumeSource: v1.PersistentVolumeSource{
|
PersistentVolumeSource: v1.PersistentVolumeSource{
|
||||||
AWSElasticBlockStore: &v1.AWSElasticBlockStoreVolumeSource{
|
AWSElasticBlockStore: &v1.AWSElasticBlockStoreVolumeSource{
|
||||||
VolumeID: string(volumeID),
|
VolumeID: string(volumeID),
|
||||||
FSType: "ext4",
|
FSType: fstype,
|
||||||
Partition: 0,
|
Partition: 0,
|
||||||
ReadOnly: false,
|
ReadOnly: false,
|
||||||
},
|
},
|
||||||
|
@ -93,10 +93,10 @@ type fakePDManager struct {
|
|||||||
|
|
||||||
// TODO(jonesdl) To fully test this, we could create a loopback device
|
// TODO(jonesdl) To fully test this, we could create a loopback device
|
||||||
// and mount that instead.
|
// and mount that instead.
|
||||||
func (fake *fakePDManager) CreateVolume(c *awsElasticBlockStoreProvisioner) (volumeID aws.KubernetesVolumeID, volumeSizeGB int, labels map[string]string, err error) {
|
func (fake *fakePDManager) CreateVolume(c *awsElasticBlockStoreProvisioner) (volumeID aws.KubernetesVolumeID, volumeSizeGB int, labels map[string]string, fstype string, err error) {
|
||||||
labels = make(map[string]string)
|
labels = make(map[string]string)
|
||||||
labels["fakepdmanager"] = "yes"
|
labels["fakepdmanager"] = "yes"
|
||||||
return "test-aws-volume-name", 100, labels, nil
|
return "test-aws-volume-name", 100, labels, "", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fake *fakePDManager) DeleteVolume(cd *awsElasticBlockStoreDeleter) error {
|
func (fake *fakePDManager) DeleteVolume(cd *awsElasticBlockStoreDeleter) error {
|
||||||
|
@ -65,10 +65,10 @@ func (util *AWSDiskUtil) DeleteVolume(d *awsElasticBlockStoreDeleter) error {
|
|||||||
|
|
||||||
// CreateVolume creates an AWS EBS volume.
|
// CreateVolume creates an AWS EBS volume.
|
||||||
// Returns: volumeID, volumeSizeGB, labels, error
|
// Returns: volumeID, volumeSizeGB, labels, error
|
||||||
func (util *AWSDiskUtil) CreateVolume(c *awsElasticBlockStoreProvisioner) (aws.KubernetesVolumeID, int, map[string]string, error) {
|
func (util *AWSDiskUtil) CreateVolume(c *awsElasticBlockStoreProvisioner) (aws.KubernetesVolumeID, int, map[string]string, string, error) {
|
||||||
cloud, err := getCloudProvider(c.awsElasticBlockStore.plugin.host.GetCloudProvider())
|
cloud, err := getCloudProvider(c.awsElasticBlockStore.plugin.host.GetCloudProvider())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", 0, nil, err
|
return "", 0, nil, "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
// AWS volumes don't have Name field, store the name in Name tag
|
// AWS volumes don't have Name field, store the name in Name tag
|
||||||
@ -89,6 +89,7 @@ func (util *AWSDiskUtil) CreateVolume(c *awsElasticBlockStoreProvisioner) (aws.K
|
|||||||
Tags: tags,
|
Tags: tags,
|
||||||
PVCName: c.options.PVC.Name,
|
PVCName: c.options.PVC.Name,
|
||||||
}
|
}
|
||||||
|
fstype := ""
|
||||||
// Apply Parameters (case-insensitive). We leave validation of
|
// Apply Parameters (case-insensitive). We leave validation of
|
||||||
// the values to the cloud provider.
|
// the values to the cloud provider.
|
||||||
volumeOptions.ZonePresent = false
|
volumeOptions.ZonePresent = false
|
||||||
@ -106,33 +107,35 @@ func (util *AWSDiskUtil) CreateVolume(c *awsElasticBlockStoreProvisioner) (aws.K
|
|||||||
case "iopspergb":
|
case "iopspergb":
|
||||||
volumeOptions.IOPSPerGB, err = strconv.Atoi(v)
|
volumeOptions.IOPSPerGB, err = strconv.Atoi(v)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", 0, nil, fmt.Errorf("invalid iopsPerGB value %q, must be integer between 1 and 30: %v", v, err)
|
return "", 0, nil, "", fmt.Errorf("invalid iopsPerGB value %q, must be integer between 1 and 30: %v", v, err)
|
||||||
}
|
}
|
||||||
case "encrypted":
|
case "encrypted":
|
||||||
volumeOptions.Encrypted, err = strconv.ParseBool(v)
|
volumeOptions.Encrypted, err = strconv.ParseBool(v)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", 0, nil, fmt.Errorf("invalid encrypted boolean value %q, must be true or false: %v", v, err)
|
return "", 0, nil, "", fmt.Errorf("invalid encrypted boolean value %q, must be true or false: %v", v, err)
|
||||||
}
|
}
|
||||||
case "kmskeyid":
|
case "kmskeyid":
|
||||||
volumeOptions.KmsKeyId = v
|
volumeOptions.KmsKeyId = v
|
||||||
|
case volume.VolumeParameterFSType:
|
||||||
|
fstype = v
|
||||||
default:
|
default:
|
||||||
return "", 0, nil, fmt.Errorf("invalid option %q for volume plugin %s", k, c.plugin.GetPluginName())
|
return "", 0, nil, "", fmt.Errorf("invalid option %q for volume plugin %s", k, c.plugin.GetPluginName())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if volumeOptions.ZonePresent && volumeOptions.ZonesPresent {
|
if volumeOptions.ZonePresent && volumeOptions.ZonesPresent {
|
||||||
return "", 0, nil, fmt.Errorf("both zone and zones StorageClass parameters must not be used at the same time")
|
return "", 0, nil, "", fmt.Errorf("both zone and zones StorageClass parameters must not be used at the same time")
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: implement PVC.Selector parsing
|
// TODO: implement PVC.Selector parsing
|
||||||
if c.options.PVC.Spec.Selector != nil {
|
if c.options.PVC.Spec.Selector != nil {
|
||||||
return "", 0, nil, fmt.Errorf("claim.Spec.Selector is not supported for dynamic provisioning on AWS")
|
return "", 0, nil, "", fmt.Errorf("claim.Spec.Selector is not supported for dynamic provisioning on AWS")
|
||||||
}
|
}
|
||||||
|
|
||||||
name, err := cloud.CreateDisk(volumeOptions)
|
name, err := cloud.CreateDisk(volumeOptions)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.V(2).Infof("Error creating EBS Disk volume: %v", err)
|
glog.V(2).Infof("Error creating EBS Disk volume: %v", err)
|
||||||
return "", 0, nil, err
|
return "", 0, nil, "", err
|
||||||
}
|
}
|
||||||
glog.V(2).Infof("Successfully created EBS Disk volume %s", name)
|
glog.V(2).Infof("Successfully created EBS Disk volume %s", name)
|
||||||
|
|
||||||
@ -142,7 +145,7 @@ func (util *AWSDiskUtil) CreateVolume(c *awsElasticBlockStoreProvisioner) (aws.K
|
|||||||
glog.Errorf("error building labels for new EBS volume %q: %v", name, err)
|
glog.Errorf("error building labels for new EBS volume %q: %v", name, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return name, int(requestGB), labels, nil
|
return name, int(requestGB), labels, fstype, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns the first path that exists, or empty string if none exist.
|
// Returns the first path that exists, or empty string if none exist.
|
||||||
|
@ -113,7 +113,7 @@ func (p *azureDiskProvisioner) Provision() (*v1.PersistentVolume, error) {
|
|||||||
strKind = v
|
strKind = v
|
||||||
case "cachingmode":
|
case "cachingmode":
|
||||||
cachingMode = v1.AzureDataDiskCachingMode(v)
|
cachingMode = v1.AzureDataDiskCachingMode(v)
|
||||||
case "fstype":
|
case volume.VolumeParameterFSType:
|
||||||
fsType = strings.ToLower(v)
|
fsType = strings.ToLower(v)
|
||||||
default:
|
default:
|
||||||
return nil, fmt.Errorf("AzureDisk - invalid option %s in storage class", k)
|
return nil, fmt.Errorf("AzureDisk - invalid option %s in storage class", k)
|
||||||
|
@ -32,7 +32,7 @@ import (
|
|||||||
"k8s.io/kubernetes/pkg/cloudprovider/providers/rackspace"
|
"k8s.io/kubernetes/pkg/cloudprovider/providers/rackspace"
|
||||||
"k8s.io/kubernetes/pkg/util/keymutex"
|
"k8s.io/kubernetes/pkg/util/keymutex"
|
||||||
"k8s.io/kubernetes/pkg/util/mount"
|
"k8s.io/kubernetes/pkg/util/mount"
|
||||||
"k8s.io/kubernetes/pkg/util/strings"
|
kstrings "k8s.io/kubernetes/pkg/util/strings"
|
||||||
"k8s.io/kubernetes/pkg/volume"
|
"k8s.io/kubernetes/pkg/volume"
|
||||||
"k8s.io/kubernetes/pkg/volume/util"
|
"k8s.io/kubernetes/pkg/volume/util"
|
||||||
"k8s.io/kubernetes/pkg/volume/util/volumehelper"
|
"k8s.io/kubernetes/pkg/volume/util/volumehelper"
|
||||||
@ -241,7 +241,7 @@ type cdManager interface {
|
|||||||
// Detaches the disk from the kubelet's host machine.
|
// Detaches the disk from the kubelet's host machine.
|
||||||
DetachDisk(unmounter *cinderVolumeUnmounter) error
|
DetachDisk(unmounter *cinderVolumeUnmounter) error
|
||||||
// Creates a volume
|
// Creates a volume
|
||||||
CreateVolume(provisioner *cinderVolumeProvisioner) (volumeID string, volumeSizeGB int, labels map[string]string, err error)
|
CreateVolume(provisioner *cinderVolumeProvisioner) (volumeID string, volumeSizeGB int, labels map[string]string, fstype string, err error)
|
||||||
// Deletes a volume
|
// Deletes a volume
|
||||||
DeleteVolume(deleter *cinderVolumeDeleter) error
|
DeleteVolume(deleter *cinderVolumeDeleter) error
|
||||||
}
|
}
|
||||||
@ -380,7 +380,7 @@ func makeGlobalPDName(host volume.VolumeHost, devName string) string {
|
|||||||
|
|
||||||
func (cd *cinderVolume) GetPath() string {
|
func (cd *cinderVolume) GetPath() string {
|
||||||
name := cinderVolumePluginName
|
name := cinderVolumePluginName
|
||||||
return cd.plugin.host.GetPodVolumeDir(cd.podUID, strings.EscapeQualifiedNameForDisk(name), cd.volName)
|
return cd.plugin.host.GetPodVolumeDir(cd.podUID, kstrings.EscapeQualifiedNameForDisk(name), cd.volName)
|
||||||
}
|
}
|
||||||
|
|
||||||
type cinderVolumeUnmounter struct {
|
type cinderVolumeUnmounter struct {
|
||||||
@ -467,7 +467,7 @@ var _ volume.Deleter = &cinderVolumeDeleter{}
|
|||||||
|
|
||||||
func (r *cinderVolumeDeleter) GetPath() string {
|
func (r *cinderVolumeDeleter) GetPath() string {
|
||||||
name := cinderVolumePluginName
|
name := cinderVolumePluginName
|
||||||
return r.plugin.host.GetPodVolumeDir(r.podUID, strings.EscapeQualifiedNameForDisk(name), r.volName)
|
return r.plugin.host.GetPodVolumeDir(r.podUID, kstrings.EscapeQualifiedNameForDisk(name), r.volName)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *cinderVolumeDeleter) Delete() error {
|
func (r *cinderVolumeDeleter) Delete() error {
|
||||||
@ -486,7 +486,7 @@ func (c *cinderVolumeProvisioner) Provision() (*v1.PersistentVolume, error) {
|
|||||||
return nil, fmt.Errorf("invalid AccessModes %v: only AccessModes %v are supported", c.options.PVC.Spec.AccessModes, c.plugin.GetAccessModes())
|
return nil, fmt.Errorf("invalid AccessModes %v: only AccessModes %v are supported", c.options.PVC.Spec.AccessModes, c.plugin.GetAccessModes())
|
||||||
}
|
}
|
||||||
|
|
||||||
volumeID, sizeGB, labels, err := c.manager.CreateVolume(c)
|
volumeID, sizeGB, labels, fstype, err := c.manager.CreateVolume(c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -508,7 +508,7 @@ func (c *cinderVolumeProvisioner) Provision() (*v1.PersistentVolume, error) {
|
|||||||
PersistentVolumeSource: v1.PersistentVolumeSource{
|
PersistentVolumeSource: v1.PersistentVolumeSource{
|
||||||
Cinder: &v1.CinderVolumeSource{
|
Cinder: &v1.CinderVolumeSource{
|
||||||
VolumeID: volumeID,
|
VolumeID: volumeID,
|
||||||
FSType: "ext4",
|
FSType: fstype,
|
||||||
ReadOnly: false,
|
ReadOnly: false,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -116,8 +116,8 @@ func (fake *fakePDManager) DetachDisk(c *cinderVolumeUnmounter) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fake *fakePDManager) CreateVolume(c *cinderVolumeProvisioner) (volumeID string, volumeSizeGB int, labels map[string]string, err error) {
|
func (fake *fakePDManager) CreateVolume(c *cinderVolumeProvisioner) (volumeID string, volumeSizeGB int, labels map[string]string, fstype string, err error) {
|
||||||
return "test-volume-name", 1, nil, nil
|
return "test-volume-name", 1, nil, "", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fake *fakePDManager) DeleteVolume(cd *cinderVolumeDeleter) error {
|
func (fake *fakePDManager) DeleteVolume(cd *cinderVolumeDeleter) error {
|
||||||
|
@ -158,10 +158,10 @@ func getZonesFromNodes(kubeClient clientset.Interface) (sets.String, error) {
|
|||||||
return zones, nil
|
return zones, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (util *CinderDiskUtil) CreateVolume(c *cinderVolumeProvisioner) (volumeID string, volumeSizeGB int, volumeLabels map[string]string, err error) {
|
func (util *CinderDiskUtil) CreateVolume(c *cinderVolumeProvisioner) (volumeID string, volumeSizeGB int, volumeLabels map[string]string, fstype string, err error) {
|
||||||
cloud, err := c.plugin.getCloudProvider()
|
cloud, err := c.plugin.getCloudProvider()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", 0, nil, err
|
return "", 0, nil, "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
capacity := c.options.PVC.Spec.Resources.Requests[v1.ResourceName(v1.ResourceStorage)]
|
capacity := c.options.PVC.Spec.Resources.Requests[v1.ResourceName(v1.ResourceStorage)]
|
||||||
@ -179,13 +179,15 @@ func (util *CinderDiskUtil) CreateVolume(c *cinderVolumeProvisioner) (volumeID s
|
|||||||
vtype = v
|
vtype = v
|
||||||
case "availability":
|
case "availability":
|
||||||
availability = v
|
availability = v
|
||||||
|
case volume.VolumeParameterFSType:
|
||||||
|
fstype = v
|
||||||
default:
|
default:
|
||||||
return "", 0, nil, fmt.Errorf("invalid option %q for volume plugin %s", k, c.plugin.GetPluginName())
|
return "", 0, nil, "", fmt.Errorf("invalid option %q for volume plugin %s", k, c.plugin.GetPluginName())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// TODO: implement PVC.Selector parsing
|
// TODO: implement PVC.Selector parsing
|
||||||
if c.options.PVC.Spec.Selector != nil {
|
if c.options.PVC.Spec.Selector != nil {
|
||||||
return "", 0, nil, fmt.Errorf("claim.Spec.Selector is not supported for dynamic provisioning on Cinder")
|
return "", 0, nil, "", fmt.Errorf("claim.Spec.Selector is not supported for dynamic provisioning on Cinder")
|
||||||
}
|
}
|
||||||
|
|
||||||
if availability == "" {
|
if availability == "" {
|
||||||
@ -193,7 +195,7 @@ func (util *CinderDiskUtil) CreateVolume(c *cinderVolumeProvisioner) (volumeID s
|
|||||||
zones, err := getZonesFromNodes(c.plugin.host.GetKubeClient())
|
zones, err := getZonesFromNodes(c.plugin.host.GetKubeClient())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.V(2).Infof("error getting zone information: %v", err)
|
glog.V(2).Infof("error getting zone information: %v", err)
|
||||||
return "", 0, nil, err
|
return "", 0, nil, "", err
|
||||||
}
|
}
|
||||||
// if we did not get any zones, lets leave it blank and gophercloud will
|
// if we did not get any zones, lets leave it blank and gophercloud will
|
||||||
// use zone "nova" as default
|
// use zone "nova" as default
|
||||||
@ -205,7 +207,7 @@ func (util *CinderDiskUtil) CreateVolume(c *cinderVolumeProvisioner) (volumeID s
|
|||||||
volumeID, volumeAZ, errr := cloud.CreateVolume(name, volSizeGB, vtype, availability, c.options.CloudTags)
|
volumeID, volumeAZ, errr := cloud.CreateVolume(name, volSizeGB, vtype, availability, c.options.CloudTags)
|
||||||
if errr != nil {
|
if errr != nil {
|
||||||
glog.V(2).Infof("Error creating cinder volume: %v", errr)
|
glog.V(2).Infof("Error creating cinder volume: %v", errr)
|
||||||
return "", 0, nil, errr
|
return "", 0, nil, "", errr
|
||||||
}
|
}
|
||||||
glog.V(2).Infof("Successfully created cinder volume %s", volumeID)
|
glog.V(2).Infof("Successfully created cinder volume %s", volumeID)
|
||||||
|
|
||||||
@ -213,7 +215,7 @@ func (util *CinderDiskUtil) CreateVolume(c *cinderVolumeProvisioner) (volumeID s
|
|||||||
volumeLabels = make(map[string]string)
|
volumeLabels = make(map[string]string)
|
||||||
volumeLabels[kubeletapis.LabelZoneFailureDomain] = volumeAZ
|
volumeLabels[kubeletapis.LabelZoneFailureDomain] = volumeAZ
|
||||||
|
|
||||||
return volumeID, volSizeGB, volumeLabels, nil
|
return volumeID, volSizeGB, volumeLabels, fstype, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func probeAttachedVolume() error {
|
func probeAttachedVolume() error {
|
||||||
|
@ -28,7 +28,7 @@ import (
|
|||||||
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"
|
||||||
"k8s.io/kubernetes/pkg/util/mount"
|
"k8s.io/kubernetes/pkg/util/mount"
|
||||||
"k8s.io/kubernetes/pkg/util/strings"
|
kstrings "k8s.io/kubernetes/pkg/util/strings"
|
||||||
"k8s.io/kubernetes/pkg/volume"
|
"k8s.io/kubernetes/pkg/volume"
|
||||||
"k8s.io/kubernetes/pkg/volume/util"
|
"k8s.io/kubernetes/pkg/volume/util"
|
||||||
"k8s.io/kubernetes/pkg/volume/util/volumehelper"
|
"k8s.io/kubernetes/pkg/volume/util/volumehelper"
|
||||||
@ -53,7 +53,7 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func getPath(uid types.UID, volName string, host volume.VolumeHost) string {
|
func getPath(uid types.UID, volName string, host volume.VolumeHost) string {
|
||||||
return host.GetPodVolumeDir(uid, strings.EscapeQualifiedNameForDisk(gcePersistentDiskPluginName), volName)
|
return host.GetPodVolumeDir(uid, kstrings.EscapeQualifiedNameForDisk(gcePersistentDiskPluginName), volName)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (plugin *gcePersistentDiskPlugin) Init(host volume.VolumeHost) error {
|
func (plugin *gcePersistentDiskPlugin) Init(host volume.VolumeHost) error {
|
||||||
@ -211,7 +211,7 @@ func (plugin *gcePersistentDiskPlugin) ConstructVolumeSpec(volumeName, mountPath
|
|||||||
// Abstract interface to PD operations.
|
// Abstract interface to PD operations.
|
||||||
type pdManager interface {
|
type pdManager interface {
|
||||||
// Creates a volume
|
// Creates a volume
|
||||||
CreateVolume(provisioner *gcePersistentDiskProvisioner) (volumeID string, volumeSizeGB int, labels map[string]string, err error)
|
CreateVolume(provisioner *gcePersistentDiskProvisioner) (volumeID string, volumeSizeGB int, labels map[string]string, fstype string, err error)
|
||||||
// Deletes a volume
|
// Deletes a volume
|
||||||
DeleteVolume(deleter *gcePersistentDiskDeleter) error
|
DeleteVolume(deleter *gcePersistentDiskDeleter) error
|
||||||
}
|
}
|
||||||
@ -379,11 +379,15 @@ func (c *gcePersistentDiskProvisioner) Provision() (*v1.PersistentVolume, error)
|
|||||||
return nil, fmt.Errorf("invalid AccessModes %v: only AccessModes %v are supported", c.options.PVC.Spec.AccessModes, c.plugin.GetAccessModes())
|
return nil, fmt.Errorf("invalid AccessModes %v: only AccessModes %v are supported", c.options.PVC.Spec.AccessModes, c.plugin.GetAccessModes())
|
||||||
}
|
}
|
||||||
|
|
||||||
volumeID, sizeGB, labels, err := c.manager.CreateVolume(c)
|
volumeID, sizeGB, labels, fstype, err := c.manager.CreateVolume(c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if fstype == "" {
|
||||||
|
fstype = "ext4"
|
||||||
|
}
|
||||||
|
|
||||||
pv := &v1.PersistentVolume{
|
pv := &v1.PersistentVolume{
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
Name: c.options.PVName,
|
Name: c.options.PVName,
|
||||||
@ -403,6 +407,7 @@ func (c *gcePersistentDiskProvisioner) Provision() (*v1.PersistentVolume, error)
|
|||||||
PDName: volumeID,
|
PDName: volumeID,
|
||||||
Partition: 0,
|
Partition: 0,
|
||||||
ReadOnly: false,
|
ReadOnly: false,
|
||||||
|
FSType: fstype,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -86,10 +86,10 @@ func contains(modes []v1.PersistentVolumeAccessMode, mode v1.PersistentVolumeAcc
|
|||||||
type fakePDManager struct {
|
type fakePDManager struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fake *fakePDManager) CreateVolume(c *gcePersistentDiskProvisioner) (volumeID string, volumeSizeGB int, labels map[string]string, err error) {
|
func (fake *fakePDManager) CreateVolume(c *gcePersistentDiskProvisioner) (volumeID string, volumeSizeGB int, labels map[string]string, fstype string, err error) {
|
||||||
labels = make(map[string]string)
|
labels = make(map[string]string)
|
||||||
labels["fakepdmanager"] = "yes"
|
labels["fakepdmanager"] = "yes"
|
||||||
return "test-gce-volume-name", 100, labels, nil
|
return "test-gce-volume-name", 100, labels, "", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fake *fakePDManager) DeleteVolume(cd *gcePersistentDiskDeleter) error {
|
func (fake *fakePDManager) DeleteVolume(cd *gcePersistentDiskDeleter) error {
|
||||||
|
@ -71,10 +71,10 @@ func (util *GCEDiskUtil) DeleteVolume(d *gcePersistentDiskDeleter) error {
|
|||||||
|
|
||||||
// CreateVolume creates a GCE PD.
|
// CreateVolume creates a GCE PD.
|
||||||
// Returns: volumeID, volumeSizeGB, labels, error
|
// Returns: volumeID, volumeSizeGB, labels, error
|
||||||
func (gceutil *GCEDiskUtil) CreateVolume(c *gcePersistentDiskProvisioner) (string, int, map[string]string, error) {
|
func (gceutil *GCEDiskUtil) CreateVolume(c *gcePersistentDiskProvisioner) (string, int, map[string]string, string, error) {
|
||||||
cloud, err := getCloudProvider(c.gcePersistentDisk.plugin.host.GetCloudProvider())
|
cloud, err := getCloudProvider(c.gcePersistentDisk.plugin.host.GetCloudProvider())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", 0, nil, err
|
return "", 0, nil, "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
name := volume.GenerateVolumeName(c.options.ClusterName, c.options.PVName, 63) // GCE PD name can have up to 63 characters
|
name := volume.GenerateVolumeName(c.options.ClusterName, c.options.PVName, 63) // GCE PD name can have up to 63 characters
|
||||||
@ -90,6 +90,7 @@ func (gceutil *GCEDiskUtil) CreateVolume(c *gcePersistentDiskProvisioner) (strin
|
|||||||
configuredZones := ""
|
configuredZones := ""
|
||||||
zonePresent := false
|
zonePresent := false
|
||||||
zonesPresent := false
|
zonesPresent := false
|
||||||
|
fstype := ""
|
||||||
for k, v := range c.options.Parameters {
|
for k, v := range c.options.Parameters {
|
||||||
switch strings.ToLower(k) {
|
switch strings.ToLower(k) {
|
||||||
case "type":
|
case "type":
|
||||||
@ -100,18 +101,20 @@ func (gceutil *GCEDiskUtil) CreateVolume(c *gcePersistentDiskProvisioner) (strin
|
|||||||
case "zones":
|
case "zones":
|
||||||
zonesPresent = true
|
zonesPresent = true
|
||||||
configuredZones = v
|
configuredZones = v
|
||||||
|
case volume.VolumeParameterFSType:
|
||||||
|
fstype = v
|
||||||
default:
|
default:
|
||||||
return "", 0, nil, fmt.Errorf("invalid option %q for volume plugin %s", k, c.plugin.GetPluginName())
|
return "", 0, nil, "", fmt.Errorf("invalid option %q for volume plugin %s", k, c.plugin.GetPluginName())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if zonePresent && zonesPresent {
|
if zonePresent && zonesPresent {
|
||||||
return "", 0, nil, fmt.Errorf("both zone and zones StorageClass parameters must not be used at the same time")
|
return "", 0, nil, "", fmt.Errorf("both zone and zones StorageClass parameters must not be used at the same time")
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: implement PVC.Selector parsing
|
// TODO: implement PVC.Selector parsing
|
||||||
if c.options.PVC.Spec.Selector != nil {
|
if c.options.PVC.Spec.Selector != nil {
|
||||||
return "", 0, nil, fmt.Errorf("claim.Spec.Selector is not supported for dynamic provisioning on GCE")
|
return "", 0, nil, "", fmt.Errorf("claim.Spec.Selector is not supported for dynamic provisioning on GCE")
|
||||||
}
|
}
|
||||||
|
|
||||||
var zones sets.String
|
var zones sets.String
|
||||||
@ -119,17 +122,17 @@ func (gceutil *GCEDiskUtil) CreateVolume(c *gcePersistentDiskProvisioner) (strin
|
|||||||
zones, err = cloud.GetAllZones()
|
zones, err = cloud.GetAllZones()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.V(2).Infof("error getting zone information from GCE: %v", err)
|
glog.V(2).Infof("error getting zone information from GCE: %v", err)
|
||||||
return "", 0, nil, err
|
return "", 0, nil, "", err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !zonePresent && zonesPresent {
|
if !zonePresent && zonesPresent {
|
||||||
if zones, err = volume.ZonesToSet(configuredZones); err != nil {
|
if zones, err = volume.ZonesToSet(configuredZones); err != nil {
|
||||||
return "", 0, nil, err
|
return "", 0, nil, "", err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if zonePresent && !zonesPresent {
|
if zonePresent && !zonesPresent {
|
||||||
if err := volume.ValidateZone(configuredZone); err != nil {
|
if err := volume.ValidateZone(configuredZone); err != nil {
|
||||||
return "", 0, nil, err
|
return "", 0, nil, "", err
|
||||||
}
|
}
|
||||||
zones = make(sets.String)
|
zones = make(sets.String)
|
||||||
zones.Insert(configuredZone)
|
zones.Insert(configuredZone)
|
||||||
@ -139,7 +142,7 @@ func (gceutil *GCEDiskUtil) CreateVolume(c *gcePersistentDiskProvisioner) (strin
|
|||||||
err = cloud.CreateDisk(name, diskType, zone, int64(requestGB), *c.options.CloudTags)
|
err = cloud.CreateDisk(name, diskType, zone, int64(requestGB), *c.options.CloudTags)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.V(2).Infof("Error creating GCE PD volume: %v", err)
|
glog.V(2).Infof("Error creating GCE PD volume: %v", err)
|
||||||
return "", 0, nil, err
|
return "", 0, nil, "", err
|
||||||
}
|
}
|
||||||
glog.V(2).Infof("Successfully created GCE PD volume %s", name)
|
glog.V(2).Infof("Successfully created GCE PD volume %s", name)
|
||||||
|
|
||||||
@ -149,7 +152,7 @@ func (gceutil *GCEDiskUtil) CreateVolume(c *gcePersistentDiskProvisioner) (strin
|
|||||||
glog.Errorf("error getting labels for volume %q: %v", name, err)
|
glog.Errorf("error getting labels for volume %q: %v", name, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return name, int(requestGB), labels, nil
|
return name, int(requestGB), labels, fstype, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns the first path that exists, or empty string if none exist.
|
// Returns the first path that exists, or empty string if none exist.
|
||||||
|
@ -102,7 +102,7 @@ func (util *PhotonDiskUtil) CreateVolume(p *photonPersistentDiskProvisioner) (pd
|
|||||||
switch strings.ToLower(parameter) {
|
switch strings.ToLower(parameter) {
|
||||||
case "flavor":
|
case "flavor":
|
||||||
volumeOptions.Flavor = value
|
volumeOptions.Flavor = value
|
||||||
case "fstype":
|
case volume.VolumeParameterFSType:
|
||||||
fstype = value
|
fstype = value
|
||||||
glog.V(4).Infof("Photon Controller Util: Setting fstype to %s", fstype)
|
glog.V(4).Infof("Photon Controller Util: Setting fstype to %s", fstype)
|
||||||
default:
|
default:
|
||||||
|
@ -34,6 +34,14 @@ import (
|
|||||||
"k8s.io/kubernetes/pkg/util/mount"
|
"k8s.io/kubernetes/pkg/util/mount"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// Common parameter which can be specified in StorageClass to specify the desired FSType
|
||||||
|
// Provisioners SHOULD implement support for this if they are block device based
|
||||||
|
// Must be a filesystem type supported by the host operating system.
|
||||||
|
// Ex. "ext4", "xfs", "ntfs". Default value depends on the provisioner
|
||||||
|
VolumeParameterFSType = "fstype"
|
||||||
|
)
|
||||||
|
|
||||||
// VolumeOptions contains option information about a volume.
|
// VolumeOptions contains option information about a volume.
|
||||||
type VolumeOptions struct {
|
type VolumeOptions struct {
|
||||||
// The attributes below are required by volume.Provisioner
|
// The attributes below are required by volume.Provisioner
|
||||||
|
@ -275,6 +275,7 @@ func (r *rbdVolumeProvisioner) Provision() (*v1.PersistentVolume, error) {
|
|||||||
secretName := ""
|
secretName := ""
|
||||||
secret := ""
|
secret := ""
|
||||||
imageFormat := rbdImageFormat1
|
imageFormat := rbdImageFormat1
|
||||||
|
fstype := ""
|
||||||
|
|
||||||
for k, v := range r.options.Parameters {
|
for k, v := range r.options.Parameters {
|
||||||
switch dstrings.ToLower(k) {
|
switch dstrings.ToLower(k) {
|
||||||
@ -306,6 +307,8 @@ func (r *rbdVolumeProvisioner) Provision() (*v1.PersistentVolume, error) {
|
|||||||
r.imageFeatures = append(r.imageFeatures, f)
|
r.imageFeatures = append(r.imageFeatures, f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
case volume.VolumeParameterFSType:
|
||||||
|
fstype = v
|
||||||
default:
|
default:
|
||||||
return nil, fmt.Errorf("invalid option %q for volume plugin %s", k, r.plugin.GetPluginName())
|
return nil, fmt.Errorf("invalid option %q for volume plugin %s", k, r.plugin.GetPluginName())
|
||||||
}
|
}
|
||||||
@ -353,6 +356,7 @@ func (r *rbdVolumeProvisioner) Provision() (*v1.PersistentVolume, error) {
|
|||||||
rbd.SecretRef = new(v1.LocalObjectReference)
|
rbd.SecretRef = new(v1.LocalObjectReference)
|
||||||
rbd.SecretRef.Name = secretName
|
rbd.SecretRef.Name = secretName
|
||||||
rbd.RadosUser = r.Id
|
rbd.RadosUser = r.Id
|
||||||
|
rbd.FSType = fstype
|
||||||
pv.Spec.PersistentVolumeSource.RBD = rbd
|
pv.Spec.PersistentVolumeSource.RBD = rbd
|
||||||
pv.Spec.PersistentVolumeReclaimPolicy = r.options.PersistentVolumeReclaimPolicy
|
pv.Spec.PersistentVolumeReclaimPolicy = r.options.PersistentVolumeReclaimPolicy
|
||||||
pv.Spec.AccessModes = r.options.PVC.Spec.AccessModes
|
pv.Spec.AccessModes = r.options.PVC.Spec.AccessModes
|
||||||
|
@ -38,7 +38,6 @@ const (
|
|||||||
diskSCSIPrefix = "wwn-0x"
|
diskSCSIPrefix = "wwn-0x"
|
||||||
diskformat = "diskformat"
|
diskformat = "diskformat"
|
||||||
datastore = "datastore"
|
datastore = "datastore"
|
||||||
Fstype = "fstype"
|
|
||||||
StoragePolicyName = "storagepolicyname"
|
StoragePolicyName = "storagepolicyname"
|
||||||
|
|
||||||
HostFailuresToTolerateCapability = "hostfailurestotolerate"
|
HostFailuresToTolerateCapability = "hostfailurestotolerate"
|
||||||
@ -109,7 +108,7 @@ func (util *VsphereDiskUtil) CreateVolume(v *vsphereVolumeProvisioner) (volSpec
|
|||||||
volumeOptions.DiskFormat = value
|
volumeOptions.DiskFormat = value
|
||||||
case datastore:
|
case datastore:
|
||||||
volumeOptions.Datastore = value
|
volumeOptions.Datastore = value
|
||||||
case Fstype:
|
case volume.VolumeParameterFSType:
|
||||||
fstype = value
|
fstype = value
|
||||||
glog.V(4).Infof("Setting fstype as %q", fstype)
|
glog.V(4).Infof("Setting fstype as %q", fstype)
|
||||||
case StoragePolicyName:
|
case StoragePolicyName:
|
||||||
|
Loading…
Reference in New Issue
Block a user