mirror of
https://github.com/k3s-io/kubernetes.git
synced 2026-01-05 15:37:24 +00:00
Merge pull request #55204 from vladimirvivien/k8s-csi-volume-source
Automatic merge from submit-queue. If you want to cherry-pick this change to another branch, please follow the instructions <a href="https://github.com/kubernetes/community/blob/master/contributors/devel/cherry-picks.md">here</a>. Kubernetes CSI - Persistent Volume Source Type **What this PR does / why we need it**: This PR is to track the addition of new API type `CSIPersistentVolumeSource` that will be used as PersistentVolume for storage sources managed by CSI drivers. **Which issue(s) this PR fixes** *(optional, in `fixes #<issue number>(, fixes #<issue_number>, ...)` format, will close the issue(s) when PR gets merged)*: xref https://github.com/kubernetes/features/issues/178 **Special notes for your reviewer**: - Implements API `PersistentVolume` type `CSIPersistentVolumeSource` - Part of implementation for https://github.com/kubernetes/features/issues/178 - Designed at https://github.com/kubernetes/community/pull/1258 Other CSI Volume Plugin PRs: - Plugin Mounter/Unmounter https://github.com/kubernetes/kubernetes/pull/54529 - Plugin Attacher/Detacher https://github.com/kubernetes/kubernetes/pull/55809 **Release note**: ```release-note NONE ```
This commit is contained in:
@@ -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
|
||||
// plugin’s 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
|
||||
|
||||
28
pkg/apis/core/v1/zz_generated.conversion.go
generated
28
pkg/apis/core/v1/zz_generated.conversion.go
generated
@@ -55,6 +55,8 @@ func RegisterConversions(scheme *runtime.Scheme) error {
|
||||
Convert_core_AzureFileVolumeSource_To_v1_AzureFileVolumeSource,
|
||||
Convert_v1_Binding_To_core_Binding,
|
||||
Convert_core_Binding_To_v1_Binding,
|
||||
Convert_v1_CSIPersistentVolumeSource_To_core_CSIPersistentVolumeSource,
|
||||
Convert_core_CSIPersistentVolumeSource_To_v1_CSIPersistentVolumeSource,
|
||||
Convert_v1_Capabilities_To_core_Capabilities,
|
||||
Convert_core_Capabilities_To_v1_Capabilities,
|
||||
Convert_v1_CephFSPersistentVolumeSource_To_core_CephFSPersistentVolumeSource,
|
||||
@@ -600,6 +602,30 @@ func Convert_core_Binding_To_v1_Binding(in *core.Binding, out *v1.Binding, s con
|
||||
return autoConvert_core_Binding_To_v1_Binding(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvert_v1_CSIPersistentVolumeSource_To_core_CSIPersistentVolumeSource(in *v1.CSIPersistentVolumeSource, out *core.CSIPersistentVolumeSource, s conversion.Scope) error {
|
||||
out.Driver = in.Driver
|
||||
out.VolumeHandle = in.VolumeHandle
|
||||
out.ReadOnly = in.ReadOnly
|
||||
return nil
|
||||
}
|
||||
|
||||
// Convert_v1_CSIPersistentVolumeSource_To_core_CSIPersistentVolumeSource is an autogenerated conversion function.
|
||||
func Convert_v1_CSIPersistentVolumeSource_To_core_CSIPersistentVolumeSource(in *v1.CSIPersistentVolumeSource, out *core.CSIPersistentVolumeSource, s conversion.Scope) error {
|
||||
return autoConvert_v1_CSIPersistentVolumeSource_To_core_CSIPersistentVolumeSource(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvert_core_CSIPersistentVolumeSource_To_v1_CSIPersistentVolumeSource(in *core.CSIPersistentVolumeSource, out *v1.CSIPersistentVolumeSource, s conversion.Scope) error {
|
||||
out.Driver = in.Driver
|
||||
out.VolumeHandle = in.VolumeHandle
|
||||
out.ReadOnly = in.ReadOnly
|
||||
return nil
|
||||
}
|
||||
|
||||
// Convert_core_CSIPersistentVolumeSource_To_v1_CSIPersistentVolumeSource is an autogenerated conversion function.
|
||||
func Convert_core_CSIPersistentVolumeSource_To_v1_CSIPersistentVolumeSource(in *core.CSIPersistentVolumeSource, out *v1.CSIPersistentVolumeSource, s conversion.Scope) error {
|
||||
return autoConvert_core_CSIPersistentVolumeSource_To_v1_CSIPersistentVolumeSource(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvert_v1_Capabilities_To_core_Capabilities(in *v1.Capabilities, out *core.Capabilities, s conversion.Scope) error {
|
||||
out.Add = *(*[]core.Capability)(unsafe.Pointer(&in.Add))
|
||||
out.Drop = *(*[]core.Capability)(unsafe.Pointer(&in.Drop))
|
||||
@@ -3144,6 +3170,7 @@ func autoConvert_v1_PersistentVolumeSource_To_core_PersistentVolumeSource(in *v1
|
||||
out.ScaleIO = (*core.ScaleIOPersistentVolumeSource)(unsafe.Pointer(in.ScaleIO))
|
||||
out.Local = (*core.LocalVolumeSource)(unsafe.Pointer(in.Local))
|
||||
out.StorageOS = (*core.StorageOSPersistentVolumeSource)(unsafe.Pointer(in.StorageOS))
|
||||
out.CSI = (*core.CSIPersistentVolumeSource)(unsafe.Pointer(in.CSI))
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -3174,6 +3201,7 @@ func autoConvert_core_PersistentVolumeSource_To_v1_PersistentVolumeSource(in *co
|
||||
out.ScaleIO = (*v1.ScaleIOPersistentVolumeSource)(unsafe.Pointer(in.ScaleIO))
|
||||
out.Local = (*v1.LocalVolumeSource)(unsafe.Pointer(in.Local))
|
||||
out.StorageOS = (*v1.StorageOSPersistentVolumeSource)(unsafe.Pointer(in.StorageOS))
|
||||
out.CSI = (*v1.CSIPersistentVolumeSource)(unsafe.Pointer(in.CSI))
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -1318,6 +1318,24 @@ func validateStorageOSPersistentVolumeSource(storageos *core.StorageOSPersistent
|
||||
return allErrs
|
||||
}
|
||||
|
||||
func validateCSIPersistentVolumeSource(csi *core.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"))
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
25
pkg/apis/core/zz_generated.deepcopy.go
generated
25
pkg/apis/core/zz_generated.deepcopy.go
generated
@@ -246,6 +246,22 @@ func (in *Binding) DeepCopyObject() runtime.Object {
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *CSIPersistentVolumeSource) DeepCopyInto(out *CSIPersistentVolumeSource) {
|
||||
*out = *in
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CSIPersistentVolumeSource.
|
||||
func (in *CSIPersistentVolumeSource) DeepCopy() *CSIPersistentVolumeSource {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(CSIPersistentVolumeSource)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *Capabilities) DeepCopyInto(out *Capabilities) {
|
||||
*out = *in
|
||||
@@ -3159,6 +3175,15 @@ func (in *PersistentVolumeSource) DeepCopyInto(out *PersistentVolumeSource) {
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
}
|
||||
if in.CSI != nil {
|
||||
in, out := &in.CSI, &out.CSI
|
||||
if *in == nil {
|
||||
*out = nil
|
||||
} else {
|
||||
*out = new(CSIPersistentVolumeSource)
|
||||
**out = **in
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user