CSI - API change for CSI volume source type

This commit tracks source code update to support the CSI volume source type additionn.
pull/6/head
Vladimir Vivien 2017-10-24 22:44:48 -04:00
parent 6a3d3a42db
commit af0c2bda94
8 changed files with 144 additions and 0 deletions

View File

@ -391,6 +391,9 @@ type PersistentVolumeSource struct {
// More info: https://releases.k8s.io/HEAD/examples/volumes/storageos/README.md
// +optional
StorageOS *StorageOSPersistentVolumeSource
// CSI (Container Storage Interface) represents storage that handled by an external CSI driver
// +optional
CSI *CSIPersistentVolumeSource
}
type PersistentVolumeClaimVolumeSource struct {
@ -1503,6 +1506,23 @@ type LocalVolumeSource struct {
Path string
}
// Represents storage that is managed by an external CSI volume driver
type CSIPersistentVolumeSource struct {
// Driver is the name of the driver to use for this volume.
// Required.
Driver string
// VolumeHandle is the unique volume name returned by the CSI volume
// plugins CreateVolume to refer to the volume on all subsequent calls.
// Required.
VolumeHandle string
// Optional: The value to pass to ControllerPublishVolumeRequest.
// Defaults to false (read/write).
// +optional
ReadOnly bool
}
// ContainerPort represents a network port in a single container
type ContainerPort struct {
// Optional: If specified, this must be an IANA_SVC_NAME Each named port

View File

@ -1318,6 +1318,24 @@ func validateStorageOSPersistentVolumeSource(storageos *core.StorageOSPersistent
return allErrs
}
func validateCSIPersistentVolumeSource(csi *api.CSIPersistentVolumeSource, fldPath *field.Path) field.ErrorList {
allErrs := field.ErrorList{}
if !utilfeature.DefaultFeatureGate.Enabled(features.CSIPersistentVolume) {
allErrs = append(allErrs, field.Forbidden(fldPath, "CSIPersistentVolume disabled by feature-gate"))
}
if len(csi.Driver) == 0 {
allErrs = append(allErrs, field.Required(fldPath.Child("driver"), ""))
}
if len(csi.VolumeHandle) == 0 {
allErrs = append(allErrs, field.Required(fldPath.Child("volumeHandle"), ""))
}
return allErrs
}
// ValidatePersistentVolumeName checks that a name is appropriate for a
// PersistentVolumeName object.
var ValidatePersistentVolumeName = NameIsDNSSubdomain
@ -1541,6 +1559,15 @@ func ValidatePersistentVolume(pv *core.PersistentVolume) field.ErrorList {
}
}
if pv.Spec.CSI != nil {
if numVolumes > 0 {
allErrs = append(allErrs, field.Forbidden(specPath.Child("csi"), "may not specify more than 1 volume type"))
} else {
numVolumes++
allErrs = append(allErrs, validateCSIPersistentVolumeSource(pv.Spec.CSI, specPath.Child("csi"))...)
}
}
if numVolumes == 0 {
allErrs = append(allErrs, field.Required(specPath, "must specify a volume type"))
}

View File

@ -1353,6 +1353,64 @@ func TestValidateGlusterfs(t *testing.T) {
}
}
func TestValidateCSIVolumeSource(t *testing.T) {
testCases := []struct {
name string
csi *api.CSIPersistentVolumeSource
errtype field.ErrorType
errfield string
}{
{
name: "all required fields ok",
csi: &api.CSIPersistentVolumeSource{Driver: "test-driver", VolumeHandle: "test-123", ReadOnly: true},
},
{
name: "with default values ok",
csi: &api.CSIPersistentVolumeSource{Driver: "test-driver", VolumeHandle: "test-123"},
},
{
name: "missing driver name",
csi: &api.CSIPersistentVolumeSource{VolumeHandle: "test-123"},
errtype: field.ErrorTypeRequired,
errfield: "driver",
},
{
name: "missing volume handle",
csi: &api.CSIPersistentVolumeSource{Driver: "my-driver"},
errtype: field.ErrorTypeRequired,
errfield: "volumeHandle",
},
}
err := utilfeature.DefaultFeatureGate.Set("CSIPersistentVolume=true")
if err != nil {
t.Errorf("Failed to enable feature gate for CSIPersistentVolumes: %v", err)
return
}
for i, tc := range testCases {
errs := validateCSIPersistentVolumeSource(tc.csi, field.NewPath("field"))
if len(errs) > 0 && tc.errtype == "" {
t.Errorf("[%d: %q] unexpected error(s): %v", i, tc.name, errs)
} else if len(errs) == 0 && tc.errtype != "" {
t.Errorf("[%d: %q] expected error type %v", i, tc.name, tc.errtype)
} else if len(errs) >= 1 {
if errs[0].Type != tc.errtype {
t.Errorf("[%d: %q] expected error type %v, got %v", i, tc.name, tc.errtype, errs[0].Type)
} else if !strings.HasSuffix(errs[0].Field, "."+tc.errfield) {
t.Errorf("[%d: %q] expected error on field %q, got %q", i, tc.name, tc.errfield, errs[0].Field)
}
}
}
err = utilfeature.DefaultFeatureGate.Set("CSIPersistentVolume=false")
if err != nil {
t.Errorf("Failed to disable feature gate for CSIPersistentVolumes: %v", err)
return
}
}
// helper
func newInt32(val int) *int32 {
p := new(int32)

View File

@ -919,6 +919,7 @@ var (
Projected FSType = "projected"
PortworxVolume FSType = "portworxVolume"
ScaleIO FSType = "scaleIO"
CSI FSType = "csi"
All FSType = "*"
)

View File

@ -181,6 +181,12 @@ const (
//
// Extend the default scheduler to be aware of PV topology and handle PV binding
VolumeScheduling utilfeature.Feature = "VolumeScheduling"
// owner: @vladimirvivien
// alpha: v1.9
//
// Enable mount/attachment of Container Storage Interface (CSI) backed PVs
CSIPersistentVolume utilfeature.Feature = "CSIPersistentVolume"
)
func init() {
@ -215,6 +221,7 @@ var defaultKubernetesFeatureGates = map[utilfeature.Feature]utilfeature.FeatureS
ServiceNodeExclusion: {Default: false, PreRelease: utilfeature.Alpha},
MountContainers: {Default: false, PreRelease: utilfeature.Alpha},
VolumeScheduling: {Default: false, PreRelease: utilfeature.Alpha},
CSIPersistentVolume: {Default: false, PreRelease: utilfeature.Alpha},
// inherited features from generic apiserver, relisted here to get a conflict if it is changed
// unintentionally on either side:

View File

@ -1073,6 +1073,14 @@ func printFlockerVolumeSource(flocker *api.FlockerVolumeSource, w PrefixWriter)
flocker.DatasetName, flocker.DatasetUUID)
}
func printCSIPersistentVolumeSource(csi *api.CSIPersistentVolumeSource, w PrefixWriter) {
w.Write(LEVEL_2, "Type:\tCSI (a Container Storage Interface (CSI) volume source)\n"+
" Driver:\t%v\n"+
" VolumeHandle:\t%v\n",
" ReadOnly:\t%v\n",
csi.Driver, csi.VolumeHandle, csi.ReadOnly)
}
type PersistentVolumeDescriber struct {
clientset.Interface
}
@ -1156,6 +1164,8 @@ func describePersistentVolume(pv *api.PersistentVolume, events *api.EventList) (
printFlexVolumeSource(pv.Spec.FlexVolume, w)
case pv.Spec.Flocker != nil:
printFlockerVolumeSource(pv.Spec.Flocker, w)
case pv.Spec.CSI != nil:
printCSIPersistentVolumeSource(pv.Spec.CSI, w)
default:
w.Write(LEVEL_1, "<unknown>\n")
}

View File

@ -67,6 +67,7 @@ func GetAllFSTypesAsSet() sets.String {
string(extensions.Projected),
string(extensions.PortworxVolume),
string(extensions.ScaleIO),
string(extensions.CSI),
)
return fstypes
}

View File

@ -448,6 +448,9 @@ type PersistentVolumeSource struct {
// More info: https://releases.k8s.io/HEAD/examples/volumes/storageos/README.md
// +optional
StorageOS *StorageOSPersistentVolumeSource `json:"storageos,omitempty" protobuf:"bytes,21,opt,name=storageos"`
// CSI represents storage that handled by an external CSI driver
// +optional
CSI *CSIPersistentVolumeSource `json:"csi,omitempty" protobuf:"bytes,22,opt,name=csi"`
}
const (
@ -1621,6 +1624,23 @@ type LocalVolumeSource struct {
Path string `json:"path" protobuf:"bytes,1,opt,name=path"`
}
// Represents storage that is managed by an external CSI volume driver
type CSIPersistentVolumeSource struct {
// Driver is the name of the driver to use for this volume.
// Required.
Driver string `json:"driver" protobuf:"bytes,1,opt,name=driver"`
// VolumeHandle is the unique volume name returned by the CSI volume
// plugins CreateVolume to refer to the volume on all subsequent calls.
// Required.
VolumeHandle string `json:"volumeHandle" protobuf:"bytes,2,opt,name=volumeHandle"`
// Optional: The value to pass to ControllerPublishVolumeRequest.
// Defaults to false (read/write).
// +optional
ReadOnly bool `json:"readOnly,omitempty" protobuf:"varint,3,opt,name=readOnly"`
}
// ContainerPort represents a network port in a single container.
type ContainerPort struct {
// If specified, this must be an IANA_SVC_NAME and unique within the pod. Each