mirror of
https://github.com/optim-enterprises-bv/kubernetes.git
synced 2025-11-01 10:48:15 +00:00
API changes to support CSI migration of inline volumes
Signed-off-by: Deep Debroy <ddebroy@docker.com>
This commit is contained in:
@@ -705,11 +705,15 @@ func validateISCSIVolumeSource(iscsi *core.ISCSIVolumeSource, fldPath *field.Pat
|
||||
return allErrs
|
||||
}
|
||||
|
||||
func validateISCSIPersistentVolumeSource(iscsi *core.ISCSIPersistentVolumeSource, fldPath *field.Path) field.ErrorList {
|
||||
func validateISCSIPersistentVolumeSource(iscsi *core.ISCSIPersistentVolumeSource, pvName string, fldPath *field.Path) field.ErrorList {
|
||||
allErrs := field.ErrorList{}
|
||||
if len(iscsi.TargetPortal) == 0 {
|
||||
allErrs = append(allErrs, field.Required(fldPath.Child("targetPortal"), ""))
|
||||
}
|
||||
if iscsi.InitiatorName != nil && len(pvName+":"+iscsi.TargetPortal) > 64 {
|
||||
tooLongErr := "Total length of <volume name>:<iscsi.targetPortal> must be under 64 characters if iscsi.initiatorName is specified."
|
||||
allErrs = append(allErrs, field.Invalid(fldPath.Child("targetportal"), iscsi.TargetPortal, tooLongErr))
|
||||
}
|
||||
if len(iscsi.IQN) == 0 {
|
||||
allErrs = append(allErrs, field.Required(fldPath.Child("iqn"), ""))
|
||||
} else {
|
||||
@@ -1539,247 +1543,287 @@ var supportedDataSourceAPIGroupKinds = map[schema.GroupKind]bool{
|
||||
{Group: "snapshot.storage.k8s.io", Kind: "VolumeSnapshot"}: true,
|
||||
}
|
||||
|
||||
func ValidatePersistentVolume(pv *core.PersistentVolume) field.ErrorList {
|
||||
metaPath := field.NewPath("metadata")
|
||||
allErrs := ValidateObjectMeta(&pv.ObjectMeta, false, ValidatePersistentVolumeName, metaPath)
|
||||
func ValidatePersistentVolumeSpec(pvSpec *core.PersistentVolumeSpec, pvName string, validateInlinePersistentVolumeSpec bool, fldPath *field.Path) field.ErrorList {
|
||||
allErrs := field.ErrorList{}
|
||||
|
||||
specPath := field.NewPath("spec")
|
||||
if len(pv.Spec.AccessModes) == 0 {
|
||||
allErrs = append(allErrs, field.Required(specPath.Child("accessModes"), ""))
|
||||
if validateInlinePersistentVolumeSpec {
|
||||
if pvSpec.ClaimRef != nil {
|
||||
allErrs = append(allErrs, field.Forbidden(fldPath.Child("claimRef"), "may not be specified in the context of inline volumes"))
|
||||
}
|
||||
if len(pvSpec.Capacity) != 0 {
|
||||
allErrs = append(allErrs, field.Forbidden(fldPath.Child("capacity"), "may not be specified in the context of inline volumes"))
|
||||
}
|
||||
if pvSpec.CSI == nil {
|
||||
allErrs = append(allErrs, field.Required(fldPath.Child("csi"), "has to be specified in the context of inline volumes"))
|
||||
}
|
||||
}
|
||||
for _, mode := range pv.Spec.AccessModes {
|
||||
|
||||
if len(pvSpec.AccessModes) == 0 {
|
||||
allErrs = append(allErrs, field.Required(fldPath.Child("accessModes"), ""))
|
||||
}
|
||||
for _, mode := range pvSpec.AccessModes {
|
||||
if !supportedAccessModes.Has(string(mode)) {
|
||||
allErrs = append(allErrs, field.NotSupported(specPath.Child("accessModes"), mode, supportedAccessModes.List()))
|
||||
allErrs = append(allErrs, field.NotSupported(fldPath.Child("accessModes"), mode, supportedAccessModes.List()))
|
||||
}
|
||||
}
|
||||
|
||||
if len(pv.Spec.Capacity) == 0 {
|
||||
allErrs = append(allErrs, field.Required(specPath.Child("capacity"), ""))
|
||||
}
|
||||
if !validateInlinePersistentVolumeSpec {
|
||||
if len(pvSpec.Capacity) == 0 {
|
||||
allErrs = append(allErrs, field.Required(fldPath.Child("capacity"), ""))
|
||||
}
|
||||
|
||||
if _, ok := pv.Spec.Capacity[core.ResourceStorage]; !ok || len(pv.Spec.Capacity) > 1 {
|
||||
allErrs = append(allErrs, field.NotSupported(specPath.Child("capacity"), pv.Spec.Capacity, []string{string(core.ResourceStorage)}))
|
||||
}
|
||||
capPath := specPath.Child("capacity")
|
||||
for r, qty := range pv.Spec.Capacity {
|
||||
allErrs = append(allErrs, validateBasicResource(qty, capPath.Key(string(r)))...)
|
||||
allErrs = append(allErrs, ValidatePositiveQuantityValue(qty, capPath.Key(string(r)))...)
|
||||
}
|
||||
if len(string(pv.Spec.PersistentVolumeReclaimPolicy)) > 0 {
|
||||
if !supportedReclaimPolicy.Has(string(pv.Spec.PersistentVolumeReclaimPolicy)) {
|
||||
allErrs = append(allErrs, field.NotSupported(specPath.Child("persistentVolumeReclaimPolicy"), pv.Spec.PersistentVolumeReclaimPolicy, supportedReclaimPolicy.List()))
|
||||
if _, ok := pvSpec.Capacity[core.ResourceStorage]; !ok || len(pvSpec.Capacity) > 1 {
|
||||
allErrs = append(allErrs, field.NotSupported(fldPath.Child("capacity"), pvSpec.Capacity, []string{string(core.ResourceStorage)}))
|
||||
}
|
||||
capPath := fldPath.Child("capacity")
|
||||
for r, qty := range pvSpec.Capacity {
|
||||
allErrs = append(allErrs, validateBasicResource(qty, capPath.Key(string(r)))...)
|
||||
allErrs = append(allErrs, ValidatePositiveQuantityValue(qty, capPath.Key(string(r)))...)
|
||||
}
|
||||
}
|
||||
|
||||
nodeAffinitySpecified, errs := validateVolumeNodeAffinity(pv.Spec.NodeAffinity, specPath.Child("nodeAffinity"))
|
||||
allErrs = append(allErrs, errs...)
|
||||
|
||||
numVolumes := 0
|
||||
if pv.Spec.HostPath != nil {
|
||||
if numVolumes > 0 {
|
||||
allErrs = append(allErrs, field.Forbidden(specPath.Child("hostPath"), "may not specify more than 1 volume type"))
|
||||
if len(string(pvSpec.PersistentVolumeReclaimPolicy)) > 0 {
|
||||
if validateInlinePersistentVolumeSpec {
|
||||
if pvSpec.PersistentVolumeReclaimPolicy != core.PersistentVolumeReclaimRetain {
|
||||
allErrs = append(allErrs, field.Forbidden(fldPath.Child("persistentVolumeReclaimPolicy"), "may only be "+string(core.PersistentVolumeReclaimRetain)+" in the context of inline volumes"))
|
||||
}
|
||||
} else {
|
||||
numVolumes++
|
||||
allErrs = append(allErrs, validateHostPathVolumeSource(pv.Spec.HostPath, specPath.Child("hostPath"))...)
|
||||
}
|
||||
}
|
||||
if pv.Spec.GCEPersistentDisk != nil {
|
||||
if numVolumes > 0 {
|
||||
allErrs = append(allErrs, field.Forbidden(specPath.Child("gcePersistentDisk"), "may not specify more than 1 volume type"))
|
||||
} else {
|
||||
numVolumes++
|
||||
allErrs = append(allErrs, validateGCEPersistentDiskVolumeSource(pv.Spec.GCEPersistentDisk, specPath.Child("persistentDisk"))...)
|
||||
}
|
||||
}
|
||||
if pv.Spec.AWSElasticBlockStore != nil {
|
||||
if numVolumes > 0 {
|
||||
allErrs = append(allErrs, field.Forbidden(specPath.Child("awsElasticBlockStore"), "may not specify more than 1 volume type"))
|
||||
} else {
|
||||
numVolumes++
|
||||
allErrs = append(allErrs, validateAWSElasticBlockStoreVolumeSource(pv.Spec.AWSElasticBlockStore, specPath.Child("awsElasticBlockStore"))...)
|
||||
}
|
||||
}
|
||||
if pv.Spec.Glusterfs != nil {
|
||||
if numVolumes > 0 {
|
||||
allErrs = append(allErrs, field.Forbidden(specPath.Child("glusterfs"), "may not specify more than 1 volume type"))
|
||||
} else {
|
||||
numVolumes++
|
||||
allErrs = append(allErrs, validateGlusterfsPersistentVolumeSource(pv.Spec.Glusterfs, specPath.Child("glusterfs"))...)
|
||||
}
|
||||
}
|
||||
if pv.Spec.Flocker != nil {
|
||||
if numVolumes > 0 {
|
||||
allErrs = append(allErrs, field.Forbidden(specPath.Child("flocker"), "may not specify more than 1 volume type"))
|
||||
} else {
|
||||
numVolumes++
|
||||
allErrs = append(allErrs, validateFlockerVolumeSource(pv.Spec.Flocker, specPath.Child("flocker"))...)
|
||||
}
|
||||
}
|
||||
if pv.Spec.NFS != nil {
|
||||
if numVolumes > 0 {
|
||||
allErrs = append(allErrs, field.Forbidden(specPath.Child("nfs"), "may not specify more than 1 volume type"))
|
||||
} else {
|
||||
numVolumes++
|
||||
allErrs = append(allErrs, validateNFSVolumeSource(pv.Spec.NFS, specPath.Child("nfs"))...)
|
||||
}
|
||||
}
|
||||
if pv.Spec.RBD != nil {
|
||||
if numVolumes > 0 {
|
||||
allErrs = append(allErrs, field.Forbidden(specPath.Child("rbd"), "may not specify more than 1 volume type"))
|
||||
} else {
|
||||
numVolumes++
|
||||
allErrs = append(allErrs, validateRBDPersistentVolumeSource(pv.Spec.RBD, specPath.Child("rbd"))...)
|
||||
}
|
||||
}
|
||||
if pv.Spec.Quobyte != nil {
|
||||
if numVolumes > 0 {
|
||||
allErrs = append(allErrs, field.Forbidden(specPath.Child("quobyte"), "may not specify more than 1 volume type"))
|
||||
} else {
|
||||
numVolumes++
|
||||
allErrs = append(allErrs, validateQuobyteVolumeSource(pv.Spec.Quobyte, specPath.Child("quobyte"))...)
|
||||
}
|
||||
}
|
||||
if pv.Spec.CephFS != nil {
|
||||
if numVolumes > 0 {
|
||||
allErrs = append(allErrs, field.Forbidden(specPath.Child("cephFS"), "may not specify more than 1 volume type"))
|
||||
} else {
|
||||
numVolumes++
|
||||
allErrs = append(allErrs, validateCephFSPersistentVolumeSource(pv.Spec.CephFS, specPath.Child("cephfs"))...)
|
||||
}
|
||||
}
|
||||
if pv.Spec.ISCSI != nil {
|
||||
if numVolumes > 0 {
|
||||
allErrs = append(allErrs, field.Forbidden(specPath.Child("iscsi"), "may not specify more than 1 volume type"))
|
||||
} else {
|
||||
numVolumes++
|
||||
allErrs = append(allErrs, validateISCSIPersistentVolumeSource(pv.Spec.ISCSI, specPath.Child("iscsi"))...)
|
||||
}
|
||||
if pv.Spec.ISCSI.InitiatorName != nil && len(pv.ObjectMeta.Name+":"+pv.Spec.ISCSI.TargetPortal) > 64 {
|
||||
tooLongErr := "Total length of <volume name>:<iscsi.targetPortal> must be under 64 characters if iscsi.initiatorName is specified."
|
||||
allErrs = append(allErrs, field.Invalid(metaPath.Child("name"), pv.ObjectMeta.Name, tooLongErr))
|
||||
}
|
||||
}
|
||||
if pv.Spec.Cinder != nil {
|
||||
if numVolumes > 0 {
|
||||
allErrs = append(allErrs, field.Forbidden(specPath.Child("cinder"), "may not specify more than 1 volume type"))
|
||||
} else {
|
||||
numVolumes++
|
||||
allErrs = append(allErrs, validateCinderPersistentVolumeSource(pv.Spec.Cinder, specPath.Child("cinder"))...)
|
||||
}
|
||||
}
|
||||
if pv.Spec.FC != nil {
|
||||
if numVolumes > 0 {
|
||||
allErrs = append(allErrs, field.Forbidden(specPath.Child("fc"), "may not specify more than 1 volume type"))
|
||||
} else {
|
||||
numVolumes++
|
||||
allErrs = append(allErrs, validateFCVolumeSource(pv.Spec.FC, specPath.Child("fc"))...)
|
||||
}
|
||||
}
|
||||
if pv.Spec.FlexVolume != nil {
|
||||
numVolumes++
|
||||
allErrs = append(allErrs, validateFlexPersistentVolumeSource(pv.Spec.FlexVolume, specPath.Child("flexVolume"))...)
|
||||
}
|
||||
if pv.Spec.AzureFile != nil {
|
||||
if numVolumes > 0 {
|
||||
allErrs = append(allErrs, field.Forbidden(specPath.Child("azureFile"), "may not specify more than 1 volume type"))
|
||||
|
||||
} else {
|
||||
numVolumes++
|
||||
allErrs = append(allErrs, validateAzureFilePV(pv.Spec.AzureFile, specPath.Child("azureFile"))...)
|
||||
}
|
||||
}
|
||||
|
||||
if pv.Spec.VsphereVolume != nil {
|
||||
if numVolumes > 0 {
|
||||
allErrs = append(allErrs, field.Forbidden(specPath.Child("vsphereVolume"), "may not specify more than 1 volume type"))
|
||||
} else {
|
||||
numVolumes++
|
||||
allErrs = append(allErrs, validateVsphereVolumeSource(pv.Spec.VsphereVolume, specPath.Child("vsphereVolume"))...)
|
||||
}
|
||||
}
|
||||
if pv.Spec.PhotonPersistentDisk != nil {
|
||||
if numVolumes > 0 {
|
||||
allErrs = append(allErrs, field.Forbidden(specPath.Child("photonPersistentDisk"), "may not specify more than 1 volume type"))
|
||||
} else {
|
||||
numVolumes++
|
||||
allErrs = append(allErrs, validatePhotonPersistentDiskVolumeSource(pv.Spec.PhotonPersistentDisk, specPath.Child("photonPersistentDisk"))...)
|
||||
}
|
||||
}
|
||||
if pv.Spec.PortworxVolume != nil {
|
||||
if numVolumes > 0 {
|
||||
allErrs = append(allErrs, field.Forbidden(specPath.Child("portworxVolume"), "may not specify more than 1 volume type"))
|
||||
} else {
|
||||
numVolumes++
|
||||
allErrs = append(allErrs, validatePortworxVolumeSource(pv.Spec.PortworxVolume, specPath.Child("portworxVolume"))...)
|
||||
}
|
||||
}
|
||||
if pv.Spec.AzureDisk != nil {
|
||||
if numVolumes > 0 {
|
||||
allErrs = append(allErrs, field.Forbidden(specPath.Child("azureDisk"), "may not specify more than 1 volume type"))
|
||||
} else {
|
||||
numVolumes++
|
||||
allErrs = append(allErrs, validateAzureDisk(pv.Spec.AzureDisk, specPath.Child("azureDisk"))...)
|
||||
}
|
||||
}
|
||||
if pv.Spec.ScaleIO != nil {
|
||||
if numVolumes > 0 {
|
||||
allErrs = append(allErrs, field.Forbidden(specPath.Child("scaleIO"), "may not specify more than 1 volume type"))
|
||||
} else {
|
||||
numVolumes++
|
||||
allErrs = append(allErrs, validateScaleIOPersistentVolumeSource(pv.Spec.ScaleIO, specPath.Child("scaleIO"))...)
|
||||
}
|
||||
}
|
||||
if pv.Spec.Local != nil {
|
||||
if numVolumes > 0 {
|
||||
allErrs = append(allErrs, field.Forbidden(specPath.Child("local"), "may not specify more than 1 volume type"))
|
||||
} else {
|
||||
numVolumes++
|
||||
allErrs = append(allErrs, validateLocalVolumeSource(pv.Spec.Local, specPath.Child("local"))...)
|
||||
|
||||
// NodeAffinity is required
|
||||
if !nodeAffinitySpecified {
|
||||
allErrs = append(allErrs, field.Required(metaPath.Child("annotations"), "Local volume requires node affinity"))
|
||||
if !supportedReclaimPolicy.Has(string(pvSpec.PersistentVolumeReclaimPolicy)) {
|
||||
allErrs = append(allErrs, field.NotSupported(fldPath.Child("persistentVolumeReclaimPolicy"), pvSpec.PersistentVolumeReclaimPolicy, supportedReclaimPolicy.List()))
|
||||
}
|
||||
}
|
||||
}
|
||||
if pv.Spec.StorageOS != nil {
|
||||
|
||||
var nodeAffinitySpecified bool
|
||||
var errs field.ErrorList
|
||||
if pvSpec.NodeAffinity != nil {
|
||||
if validateInlinePersistentVolumeSpec {
|
||||
allErrs = append(allErrs, field.Forbidden(fldPath.Child("nodeAffinity"), "may not be specified in the context of inline volumes"))
|
||||
} else {
|
||||
nodeAffinitySpecified, errs = validateVolumeNodeAffinity(pvSpec.NodeAffinity, fldPath.Child("nodeAffinity"))
|
||||
allErrs = append(allErrs, errs...)
|
||||
}
|
||||
}
|
||||
numVolumes := 0
|
||||
if pvSpec.HostPath != nil {
|
||||
if numVolumes > 0 {
|
||||
allErrs = append(allErrs, field.Forbidden(specPath.Child("storageos"), "may not specify more than 1 volume type"))
|
||||
allErrs = append(allErrs, field.Forbidden(fldPath.Child("hostPath"), "may not specify more than 1 volume type"))
|
||||
} else {
|
||||
numVolumes++
|
||||
allErrs = append(allErrs, validateStorageOSPersistentVolumeSource(pv.Spec.StorageOS, specPath.Child("storageos"))...)
|
||||
allErrs = append(allErrs, validateHostPathVolumeSource(pvSpec.HostPath, fldPath.Child("hostPath"))...)
|
||||
}
|
||||
}
|
||||
if pvSpec.GCEPersistentDisk != nil {
|
||||
if numVolumes > 0 {
|
||||
allErrs = append(allErrs, field.Forbidden(fldPath.Child("gcePersistentDisk"), "may not specify more than 1 volume type"))
|
||||
} else {
|
||||
numVolumes++
|
||||
allErrs = append(allErrs, validateGCEPersistentDiskVolumeSource(pvSpec.GCEPersistentDisk, fldPath.Child("persistentDisk"))...)
|
||||
}
|
||||
}
|
||||
if pvSpec.AWSElasticBlockStore != nil {
|
||||
if numVolumes > 0 {
|
||||
allErrs = append(allErrs, field.Forbidden(fldPath.Child("awsElasticBlockStore"), "may not specify more than 1 volume type"))
|
||||
} else {
|
||||
numVolumes++
|
||||
allErrs = append(allErrs, validateAWSElasticBlockStoreVolumeSource(pvSpec.AWSElasticBlockStore, fldPath.Child("awsElasticBlockStore"))...)
|
||||
}
|
||||
}
|
||||
if pvSpec.Glusterfs != nil {
|
||||
if numVolumes > 0 {
|
||||
allErrs = append(allErrs, field.Forbidden(fldPath.Child("glusterfs"), "may not specify more than 1 volume type"))
|
||||
} else {
|
||||
numVolumes++
|
||||
allErrs = append(allErrs, validateGlusterfsPersistentVolumeSource(pvSpec.Glusterfs, fldPath.Child("glusterfs"))...)
|
||||
}
|
||||
}
|
||||
if pvSpec.Flocker != nil {
|
||||
if numVolumes > 0 {
|
||||
allErrs = append(allErrs, field.Forbidden(fldPath.Child("flocker"), "may not specify more than 1 volume type"))
|
||||
} else {
|
||||
numVolumes++
|
||||
allErrs = append(allErrs, validateFlockerVolumeSource(pvSpec.Flocker, fldPath.Child("flocker"))...)
|
||||
}
|
||||
}
|
||||
if pvSpec.NFS != nil {
|
||||
if numVolumes > 0 {
|
||||
allErrs = append(allErrs, field.Forbidden(fldPath.Child("nfs"), "may not specify more than 1 volume type"))
|
||||
} else {
|
||||
numVolumes++
|
||||
allErrs = append(allErrs, validateNFSVolumeSource(pvSpec.NFS, fldPath.Child("nfs"))...)
|
||||
}
|
||||
}
|
||||
if pvSpec.RBD != nil {
|
||||
if numVolumes > 0 {
|
||||
allErrs = append(allErrs, field.Forbidden(fldPath.Child("rbd"), "may not specify more than 1 volume type"))
|
||||
} else {
|
||||
numVolumes++
|
||||
allErrs = append(allErrs, validateRBDPersistentVolumeSource(pvSpec.RBD, fldPath.Child("rbd"))...)
|
||||
}
|
||||
}
|
||||
if pvSpec.Quobyte != nil {
|
||||
if numVolumes > 0 {
|
||||
allErrs = append(allErrs, field.Forbidden(fldPath.Child("quobyte"), "may not specify more than 1 volume type"))
|
||||
} else {
|
||||
numVolumes++
|
||||
allErrs = append(allErrs, validateQuobyteVolumeSource(pvSpec.Quobyte, fldPath.Child("quobyte"))...)
|
||||
}
|
||||
}
|
||||
if pvSpec.CephFS != nil {
|
||||
if numVolumes > 0 {
|
||||
allErrs = append(allErrs, field.Forbidden(fldPath.Child("cephFS"), "may not specify more than 1 volume type"))
|
||||
} else {
|
||||
numVolumes++
|
||||
allErrs = append(allErrs, validateCephFSPersistentVolumeSource(pvSpec.CephFS, fldPath.Child("cephfs"))...)
|
||||
}
|
||||
}
|
||||
if pvSpec.ISCSI != nil {
|
||||
if numVolumes > 0 {
|
||||
allErrs = append(allErrs, field.Forbidden(fldPath.Child("iscsi"), "may not specify more than 1 volume type"))
|
||||
} else {
|
||||
numVolumes++
|
||||
allErrs = append(allErrs, validateISCSIPersistentVolumeSource(pvSpec.ISCSI, pvName, fldPath.Child("iscsi"))...)
|
||||
}
|
||||
}
|
||||
if pvSpec.Cinder != nil {
|
||||
if numVolumes > 0 {
|
||||
allErrs = append(allErrs, field.Forbidden(fldPath.Child("cinder"), "may not specify more than 1 volume type"))
|
||||
} else {
|
||||
numVolumes++
|
||||
allErrs = append(allErrs, validateCinderPersistentVolumeSource(pvSpec.Cinder, fldPath.Child("cinder"))...)
|
||||
}
|
||||
}
|
||||
if pvSpec.FC != nil {
|
||||
if numVolumes > 0 {
|
||||
allErrs = append(allErrs, field.Forbidden(fldPath.Child("fc"), "may not specify more than 1 volume type"))
|
||||
} else {
|
||||
numVolumes++
|
||||
allErrs = append(allErrs, validateFCVolumeSource(pvSpec.FC, fldPath.Child("fc"))...)
|
||||
}
|
||||
}
|
||||
if pvSpec.FlexVolume != nil {
|
||||
numVolumes++
|
||||
allErrs = append(allErrs, validateFlexPersistentVolumeSource(pvSpec.FlexVolume, fldPath.Child("flexVolume"))...)
|
||||
}
|
||||
if pvSpec.AzureFile != nil {
|
||||
if numVolumes > 0 {
|
||||
allErrs = append(allErrs, field.Forbidden(fldPath.Child("azureFile"), "may not specify more than 1 volume type"))
|
||||
|
||||
} else {
|
||||
numVolumes++
|
||||
allErrs = append(allErrs, validateAzureFilePV(pvSpec.AzureFile, fldPath.Child("azureFile"))...)
|
||||
}
|
||||
}
|
||||
|
||||
if pv.Spec.CSI != nil {
|
||||
if pvSpec.VsphereVolume != nil {
|
||||
if numVolumes > 0 {
|
||||
allErrs = append(allErrs, field.Forbidden(specPath.Child("csi"), "may not specify more than 1 volume type"))
|
||||
allErrs = append(allErrs, field.Forbidden(fldPath.Child("vsphereVolume"), "may not specify more than 1 volume type"))
|
||||
} else {
|
||||
numVolumes++
|
||||
allErrs = append(allErrs, validateCSIPersistentVolumeSource(pv.Spec.CSI, specPath.Child("csi"))...)
|
||||
allErrs = append(allErrs, validateVsphereVolumeSource(pvSpec.VsphereVolume, fldPath.Child("vsphereVolume"))...)
|
||||
}
|
||||
}
|
||||
if pvSpec.PhotonPersistentDisk != nil {
|
||||
if numVolumes > 0 {
|
||||
allErrs = append(allErrs, field.Forbidden(fldPath.Child("photonPersistentDisk"), "may not specify more than 1 volume type"))
|
||||
} else {
|
||||
numVolumes++
|
||||
allErrs = append(allErrs, validatePhotonPersistentDiskVolumeSource(pvSpec.PhotonPersistentDisk, fldPath.Child("photonPersistentDisk"))...)
|
||||
}
|
||||
}
|
||||
if pvSpec.PortworxVolume != nil {
|
||||
if numVolumes > 0 {
|
||||
allErrs = append(allErrs, field.Forbidden(fldPath.Child("portworxVolume"), "may not specify more than 1 volume type"))
|
||||
} else {
|
||||
numVolumes++
|
||||
allErrs = append(allErrs, validatePortworxVolumeSource(pvSpec.PortworxVolume, fldPath.Child("portworxVolume"))...)
|
||||
}
|
||||
}
|
||||
if pvSpec.AzureDisk != nil {
|
||||
if numVolumes > 0 {
|
||||
allErrs = append(allErrs, field.Forbidden(fldPath.Child("azureDisk"), "may not specify more than 1 volume type"))
|
||||
} else {
|
||||
numVolumes++
|
||||
allErrs = append(allErrs, validateAzureDisk(pvSpec.AzureDisk, fldPath.Child("azureDisk"))...)
|
||||
}
|
||||
}
|
||||
if pvSpec.ScaleIO != nil {
|
||||
if numVolumes > 0 {
|
||||
allErrs = append(allErrs, field.Forbidden(fldPath.Child("scaleIO"), "may not specify more than 1 volume type"))
|
||||
} else {
|
||||
numVolumes++
|
||||
allErrs = append(allErrs, validateScaleIOPersistentVolumeSource(pvSpec.ScaleIO, fldPath.Child("scaleIO"))...)
|
||||
}
|
||||
}
|
||||
if pvSpec.Local != nil {
|
||||
if numVolumes > 0 {
|
||||
allErrs = append(allErrs, field.Forbidden(fldPath.Child("local"), "may not specify more than 1 volume type"))
|
||||
} else {
|
||||
numVolumes++
|
||||
allErrs = append(allErrs, validateLocalVolumeSource(pvSpec.Local, fldPath.Child("local"))...)
|
||||
// NodeAffinity is required
|
||||
if !nodeAffinitySpecified {
|
||||
allErrs = append(allErrs, field.Required(fldPath.Child("nodeAffinity"), "Local volume requires node affinity"))
|
||||
}
|
||||
}
|
||||
}
|
||||
if pvSpec.StorageOS != nil {
|
||||
if numVolumes > 0 {
|
||||
allErrs = append(allErrs, field.Forbidden(fldPath.Child("storageos"), "may not specify more than 1 volume type"))
|
||||
} else {
|
||||
numVolumes++
|
||||
allErrs = append(allErrs, validateStorageOSPersistentVolumeSource(pvSpec.StorageOS, fldPath.Child("storageos"))...)
|
||||
}
|
||||
}
|
||||
|
||||
if pvSpec.CSI != nil {
|
||||
if numVolumes > 0 {
|
||||
allErrs = append(allErrs, field.Forbidden(fldPath.Child("csi"), "may not specify more than 1 volume type"))
|
||||
} else {
|
||||
numVolumes++
|
||||
allErrs = append(allErrs, validateCSIPersistentVolumeSource(pvSpec.CSI, fldPath.Child("csi"))...)
|
||||
}
|
||||
}
|
||||
|
||||
if numVolumes == 0 {
|
||||
allErrs = append(allErrs, field.Required(specPath, "must specify a volume type"))
|
||||
allErrs = append(allErrs, field.Required(fldPath, "must specify a volume type"))
|
||||
}
|
||||
|
||||
// do not allow hostPath mounts of '/' to have a 'recycle' reclaim policy
|
||||
if pv.Spec.HostPath != nil && path.Clean(pv.Spec.HostPath.Path) == "/" && pv.Spec.PersistentVolumeReclaimPolicy == core.PersistentVolumeReclaimRecycle {
|
||||
allErrs = append(allErrs, field.Forbidden(specPath.Child("persistentVolumeReclaimPolicy"), "may not be 'recycle' for a hostPath mount of '/'"))
|
||||
if pvSpec.HostPath != nil && path.Clean(pvSpec.HostPath.Path) == "/" && pvSpec.PersistentVolumeReclaimPolicy == core.PersistentVolumeReclaimRecycle {
|
||||
allErrs = append(allErrs, field.Forbidden(fldPath.Child("persistentVolumeReclaimPolicy"), "may not be 'recycle' for a hostPath mount of '/'"))
|
||||
}
|
||||
|
||||
if len(pv.Spec.StorageClassName) > 0 {
|
||||
for _, msg := range ValidateClassName(pv.Spec.StorageClassName, false) {
|
||||
allErrs = append(allErrs, field.Invalid(specPath.Child("storageClassName"), pv.Spec.StorageClassName, msg))
|
||||
if len(pvSpec.StorageClassName) > 0 {
|
||||
if validateInlinePersistentVolumeSpec {
|
||||
allErrs = append(allErrs, field.Forbidden(fldPath.Child("storageClassName"), "may not be specified in the context of inline volumes"))
|
||||
} else {
|
||||
for _, msg := range ValidateClassName(pvSpec.StorageClassName, false) {
|
||||
allErrs = append(allErrs, field.Invalid(fldPath.Child("storageClassName"), pvSpec.StorageClassName, msg))
|
||||
}
|
||||
}
|
||||
}
|
||||
if pv.Spec.VolumeMode != nil && !supportedVolumeModes.Has(string(*pv.Spec.VolumeMode)) {
|
||||
allErrs = append(allErrs, field.NotSupported(specPath.Child("volumeMode"), *pv.Spec.VolumeMode, supportedVolumeModes.List()))
|
||||
if pvSpec.VolumeMode != nil {
|
||||
if validateInlinePersistentVolumeSpec {
|
||||
if *pvSpec.VolumeMode != core.PersistentVolumeFilesystem {
|
||||
allErrs = append(allErrs, field.Forbidden(fldPath.Child("volumeMode"), "may not specify volumeMode other than "+string(core.PersistentVolumeFilesystem)+" in the context of inline volumes"))
|
||||
}
|
||||
} else {
|
||||
if !supportedVolumeModes.Has(string(*pvSpec.VolumeMode)) {
|
||||
allErrs = append(allErrs, field.NotSupported(fldPath.Child("volumeMode"), *pvSpec.VolumeMode, supportedVolumeModes.List()))
|
||||
}
|
||||
}
|
||||
}
|
||||
return allErrs
|
||||
}
|
||||
|
||||
func ValidatePersistentVolume(pv *core.PersistentVolume) field.ErrorList {
|
||||
metaPath := field.NewPath("metadata")
|
||||
allErrs := ValidateObjectMeta(&pv.ObjectMeta, false, ValidatePersistentVolumeName, metaPath)
|
||||
allErrs = append(allErrs, ValidatePersistentVolumeSpec(&pv.Spec, pv.ObjectMeta.Name, false, field.NewPath("spec"))...)
|
||||
return allErrs
|
||||
}
|
||||
|
||||
// ValidatePersistentVolumeUpdate tests to see if the update is legal for an end user to make.
|
||||
// newPv is updated with fields that cannot be changed.
|
||||
func ValidatePersistentVolumeUpdate(newPv, oldPv *core.PersistentVolume) field.ErrorList {
|
||||
|
||||
Reference in New Issue
Block a user