Add storageClass.mountOptions and use it in all applicable plugins

pull/6/head
Matthew Wong 2017-08-23 17:29:54 -04:00
parent 25da6e64e2
commit 5e772b8e4b
17 changed files with 69 additions and 6 deletions

View File

@ -54,6 +54,11 @@ type StorageClass struct {
// PersistentVolumes of this storage class are created with
// +optional
ReclaimPolicy *api.PersistentVolumeReclaimPolicy
// mountOptions are the mount options that dynamically provisioned
// PersistentVolumes of this storage class are created with
// +optional
MountOptions []string
}
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object

View File

@ -807,12 +807,13 @@ const operationDelete = "Delete"
const operationRecycle = "Recycle"
var (
classGold string = "gold"
classSilver string = "silver"
classEmpty string = ""
classNonExisting string = "non-existing"
classExternal string = "external"
classUnknownInternal string = "unknown-internal"
classGold string = "gold"
classSilver string = "silver"
classEmpty string = ""
classNonExisting string = "non-existing"
classExternal string = "external"
classUnknownInternal string = "unknown-internal"
classUnsupportedMountOptions string = "unsupported-mountoptions"
)
// wrapTestWithPluginCalls returns a testCall that:

View File

@ -81,6 +81,18 @@ var storageClasses = []*storage.StorageClass{
Parameters: class1Parameters,
ReclaimPolicy: &deleteReclaimPolicy,
},
{
TypeMeta: metav1.TypeMeta{
Kind: "StorageClass",
},
ObjectMeta: metav1.ObjectMeta{
Name: "unsupported-mountoptions",
},
Provisioner: mockPluginName,
Parameters: class1Parameters,
ReclaimPolicy: &deleteReclaimPolicy,
MountOptions: []string{"foo"},
},
}
// call to storageClass 1, returning an error
@ -392,6 +404,17 @@ func TestProvisionSync(t *testing.T) {
testSyncClaim,
),
},
{
// No provisioning + warning event with unsupported storageClass.mountOptions
"11-20 - unsupported storageClass.mountOptions",
novolumes,
novolumes,
newClaimArray("claim11-20", "uid11-20", "1Gi", "", v1.ClaimPending, &classUnsupportedMountOptions),
newClaimArray("claim11-20", "uid11-20", "1Gi", "", v1.ClaimPending, &classUnsupportedMountOptions, annStorageProvisioner),
// Expect event to be prefixed with "Mount options" because saving PV will fail anyway
[]string{"Warning ProvisioningFailed Mount options"},
noerrors, wrapTestWithProvisionCalls([]provisionCall{}, testSyncClaim),
},
}
runSyncTests(t, tests, storageClasses)
}

View File

@ -1320,6 +1320,7 @@ func (ctrl *PersistentVolumeController) provisionClaimOperation(claimObj interfa
options := vol.VolumeOptions{
PersistentVolumeReclaimPolicy: *storageClass.ReclaimPolicy,
MountOptions: storageClass.MountOptions,
CloudTags: &tags,
ClusterName: ctrl.clusterName,
PVName: pvName,
@ -1327,6 +1328,15 @@ func (ctrl *PersistentVolumeController) provisionClaimOperation(claimObj interfa
Parameters: storageClass.Parameters,
}
// Refuse to provision if the plugin doesn't support mount options, creation
// of PV would be rejected by validation anyway
if !plugin.SupportsMountOption() && len(options.MountOptions) > 0 {
strerr := fmt.Sprintf("Mount options are not supported by the provisioner but StorageClass %q has mount options %v", storageClass.Name, options.MountOptions)
glog.V(2).Infof("Mount options are not supported by the provisioner but claim %q's StorageClass %q has mount options %v", claimToClaimKey(claim), storageClass.Name, options.MountOptions)
ctrl.eventRecorder.Event(claim, v1.EventTypeWarning, events.ProvisioningFailed, strerr)
return
}
// Provision the volume
provisioner, err := plugin.NewProvisioner(options)
if err != nil {

View File

@ -465,6 +465,7 @@ func (c *awsElasticBlockStoreProvisioner) Provision() (*v1.PersistentVolume, err
ReadOnly: false,
},
},
MountOptions: c.options.MountOptions,
},
}

View File

@ -198,6 +198,7 @@ func (p *azureDiskProvisioner) Provision() (*v1.PersistentVolume, error) {
FSType: &fsType,
},
},
MountOptions: p.options.MountOptions,
},
}
return pv, nil

View File

@ -196,6 +196,7 @@ func (a *azureFileProvisioner) Provision() (*v1.PersistentVolume, error) {
SecretNamespace: &secretNamespace,
},
},
MountOptions: a.options.MountOptions,
},
}
return pv, nil

View File

@ -499,6 +499,7 @@ func (c *cinderVolumeProvisioner) Provision() (*v1.PersistentVolume, error) {
ReadOnly: false,
},
},
MountOptions: c.options.MountOptions,
},
}
if len(c.options.PVC.Spec.AccessModes) == 0 {

View File

@ -410,6 +410,7 @@ func (c *gcePersistentDiskProvisioner) Provision() (*v1.PersistentVolume, error)
FSType: fstype,
},
},
MountOptions: c.options.MountOptions,
},
}
if len(c.options.PVC.Spec.AccessModes) == 0 {

View File

@ -711,6 +711,7 @@ func (p *glusterfsVolumeProvisioner) Provision() (*v1.PersistentVolume, error) {
if len(pv.Spec.AccessModes) == 0 {
pv.Spec.AccessModes = p.plugin.GetAccessModes()
}
pv.Spec.MountOptions = p.options.MountOptions
gidStr := strconv.FormatInt(int64(gid), 10)

View File

@ -375,6 +375,7 @@ func (p *photonPersistentDiskProvisioner) Provision() (*v1.PersistentVolume, err
FSType: fstype,
},
},
MountOptions: p.options.MountOptions,
},
}
if len(p.options.PVC.Spec.AccessModes) == 0 {

View File

@ -50,6 +50,8 @@ type VolumeOptions struct {
// Reclamation policy for a persistent volume
PersistentVolumeReclaimPolicy v1.PersistentVolumeReclaimPolicy
// Mount options for a persistent volume
MountOptions []string
// Suggested PV.Name of the PersistentVolume to provision.
// This is a generated name guaranteed to be unique in Kubernetes cluster.
// If you choose not to use it as volume name, ensure uniqueness by either

View File

@ -420,6 +420,7 @@ func (provisioner *quobyteVolumeProvisioner) Provision() (*v1.PersistentVolume,
pv.Spec.Capacity = v1.ResourceList{
v1.ResourceName(v1.ResourceStorage): resource.MustParse(fmt.Sprintf("%dGi", sizeGB)),
}
pv.Spec.MountOptions = provisioner.options.MountOptions
return pv, nil
}

View File

@ -383,6 +383,7 @@ func (r *rbdVolumeProvisioner) Provision() (*v1.PersistentVolume, error) {
pv.Spec.Capacity = v1.ResourceList{
v1.ResourceName(v1.ResourceStorage): resource.MustParse(fmt.Sprintf("%dMi", sizeMB)),
}
pv.Spec.MountOptions = r.options.MountOptions
return pv, nil
}

View File

@ -379,6 +379,7 @@ func (v *vsphereVolumeProvisioner) Provision() (*v1.PersistentVolume, error) {
StoragePolicyID: volSpec.StoragePolicyID,
},
},
MountOptions: v.options.MountOptions,
},
}
if len(v.options.PVC.Spec.AccessModes) == 0 {

View File

@ -49,6 +49,12 @@ type StorageClass struct {
// created with this reclaimPolicy. Defaults to Delete.
// +optional
ReclaimPolicy *v1.PersistentVolumeReclaimPolicy `json:"reclaimPolicy,omitempty" protobuf:"bytes,4,opt,name=reclaimPolicy,casttype=k8s.io/api/core/v1.PersistentVolumeReclaimPolicy"`
// Dynamically provisioned PersistentVolumes of this storage class are
// created with these mountOptions, e.g. ["ro", "soft"]. Not validated -
// mount of the PVs will simply fail if one is invalid.
// +optional
MountOptions []string `json:"mountOptions,omitempty" protobuf:"bytes,5,opt,name=mountOptions"`
}
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object

View File

@ -49,6 +49,12 @@ type StorageClass struct {
// created with this reclaimPolicy. Defaults to Delete.
// +optional
ReclaimPolicy *v1.PersistentVolumeReclaimPolicy `json:"reclaimPolicy,omitempty" protobuf:"bytes,4,opt,name=reclaimPolicy,casttype=k8s.io/api/core/v1.PersistentVolumeReclaimPolicy"`
// Dynamically provisioned PersistentVolumes of this storage class are
// created with these mountOptions, e.g. ["ro", "soft"]. Not validated -
// mount of the PVs will simply fail if one is invalid.
// +optional
MountOptions []string `json:"mountOptions,omitempty" protobuf:"bytes,5,opt,name=mountOptions"`
}
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object