Introduce storage v1alpha1 and VolumeAttachment

Introduce the v1alpha1 version to the Kubernetes storage API. And add a
new VolumeAttachment object to that version. This object will initially
be used only by the new CSI Volume Plugin. Eventually existing volume
plugins can be refactored to use it too.
This commit is contained in:
Saad Ali
2017-11-09 21:49:08 -08:00
parent 81fa823a6c
commit d96c105d71
27 changed files with 1301 additions and 9 deletions

View File

@@ -20,6 +20,7 @@ import (
"reflect"
"strings"
apiequality "k8s.io/apimachinery/pkg/api/equality"
"k8s.io/apimachinery/pkg/util/sets"
"k8s.io/apimachinery/pkg/util/validation"
"k8s.io/apimachinery/pkg/util/validation/field"
@@ -30,6 +31,14 @@ import (
"k8s.io/kubernetes/pkg/features"
)
const (
maxProvisionerParameterSize = 256 * (1 << 10) // 256 kB
maxProvisionerParameterLen = 512
maxAttachedVolumeMetadataSize = 256 * (1 << 10) // 256 kB
maxVolumeErrorMessageSize = 1024
)
// ValidateStorageClass validates a StorageClass.
func ValidateStorageClass(storageClass *storage.StorageClass) field.ErrorList {
allErrs := apivalidation.ValidateObjectMeta(&storageClass.ObjectMeta, false, apivalidation.ValidateClassName, field.NewPath("metadata"))
@@ -72,9 +81,6 @@ func validateProvisioner(provisioner string, fldPath *field.Path) field.ErrorLis
return allErrs
}
const maxProvisionerParameterSize = 256 * (1 << 10) // 256 kB
const maxProvisionerParameterLen = 512
// validateParameters tests that keys are qualified names and that provisionerParameter are < 256kB.
func validateParameters(params map[string]string, fldPath *field.Path) field.ErrorList {
var totalSize int64
@@ -121,3 +127,94 @@ func validateAllowVolumeExpansion(allowExpand *bool, fldPath *field.Path) field.
}
return allErrs
}
// ValidateVolumeAttachment validates a VolumeAttachment.
func ValidateVolumeAttachment(volumeAttachment *storage.VolumeAttachment) field.ErrorList {
allErrs := apivalidation.ValidateObjectMeta(&volumeAttachment.ObjectMeta, false, apivalidation.ValidateClassName, field.NewPath("metadata"))
allErrs = append(allErrs, validateVolumeAttachmentSpec(&volumeAttachment.Spec, field.NewPath("spec"))...)
allErrs = append(allErrs, validateVolumeAttachmentStatus(&volumeAttachment.Status, field.NewPath("status"))...)
return allErrs
}
// ValidateVolumeAttachmentSpec tests that the specified VolumeAttachmentSpec
// has valid data.
func validateVolumeAttachmentSpec(
spec *storage.VolumeAttachmentSpec, fldPath *field.Path) field.ErrorList {
allErrs := field.ErrorList{}
allErrs = append(allErrs, validateAttacher(spec.Attacher, fldPath.Child("attacher"))...)
allErrs = append(allErrs, validateVolumeAttachmentSource(&spec.Source, fldPath.Child("source"))...)
allErrs = append(allErrs, validateNodeName(spec.NodeName, fldPath.Child("nodeName"))...)
return allErrs
}
// validateAttacher tests if attacher is a valid qualified name.
func validateAttacher(attacher string, fldPath *field.Path) field.ErrorList {
allErrs := field.ErrorList{}
if len(attacher) == 0 {
allErrs = append(allErrs, field.Required(fldPath, attacher))
}
return allErrs
}
// validateSource tests if the source is valid for VolumeAttachment.
func validateVolumeAttachmentSource(source *storage.VolumeAttachmentSource, fldPath *field.Path) field.ErrorList {
allErrs := field.ErrorList{}
if source.PersistentVolumeName == nil || len(*source.PersistentVolumeName) == 0 {
allErrs = append(allErrs, field.Required(fldPath, ""))
}
return allErrs
}
// validateNodeName tests if the nodeName is valid for VolumeAttachment.
func validateNodeName(nodeName string, fldPath *field.Path) field.ErrorList {
allErrs := field.ErrorList{}
for _, msg := range apivalidation.ValidateNodeName(nodeName, false /* prefix */) {
allErrs = append(allErrs, field.Invalid(fldPath, nodeName, msg))
}
return allErrs
}
// validaVolumeAttachmentStatus tests if volumeAttachmentStatus is valid.
func validateVolumeAttachmentStatus(status *storage.VolumeAttachmentStatus, fldPath *field.Path) field.ErrorList {
allErrs := field.ErrorList{}
allErrs = append(allErrs, validateAttachmentMetadata(status.AttachmentMetadata, fldPath.Child("attachmentMetadata"))...)
allErrs = append(allErrs, validateVolumeError(status.AttachError, fldPath.Child("attachError"))...)
allErrs = append(allErrs, validateVolumeError(status.DetachError, fldPath.Child("detachError"))...)
return allErrs
}
func validateAttachmentMetadata(metadata map[string]string, fldPath *field.Path) field.ErrorList {
allErrs := field.ErrorList{}
var size int64
for k, v := range metadata {
size += (int64)(len(k)) + (int64)(len(v))
}
if size > maxAttachedVolumeMetadataSize {
allErrs = append(allErrs, field.TooLong(fldPath, metadata, maxAttachedVolumeMetadataSize))
}
return allErrs
}
func validateVolumeError(e *storage.VolumeError, fldPath *field.Path) field.ErrorList {
allErrs := field.ErrorList{}
if e == nil {
return allErrs
}
if len(e.Message) > maxVolumeErrorMessageSize {
allErrs = append(allErrs, field.TooLong(fldPath.Child("message"), e.Message, maxAttachedVolumeMetadataSize))
}
return allErrs
}
// ValidateVolumeAttachmentUpdate validates a VolumeAttachment.
func ValidateVolumeAttachmentUpdate(new, old *storage.VolumeAttachment) field.ErrorList {
allErrs := ValidateVolumeAttachment(new)
// Spec is read-only
if !apiequality.Semantic.DeepEqual(old.Spec, new.Spec) {
allErrs = append(allErrs, field.Invalid(field.NewPath("spec"), new.Spec, "field is immutable"))
}
return allErrs
}