mirror of https://github.com/k3s-io/k3s
Merge pull request #71167 from msau42/block-beta
Promote raw block volume support to betapull/58/head
commit
ec2e767e59
|
@ -84268,7 +84268,7 @@
|
|||
"type": "boolean"
|
||||
},
|
||||
"volumeDevices": {
|
||||
"description": "volumeDevices is the list of block devices to be used by the container. This is an alpha feature and may change in the future.",
|
||||
"description": "volumeDevices is the list of block devices to be used by the container. This is a beta feature.",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/io.k8s.api.core.v1.VolumeDevice"
|
||||
|
@ -86221,7 +86221,7 @@
|
|||
"type": "string"
|
||||
},
|
||||
"volumeMode": {
|
||||
"description": "volumeMode defines what type of volume is required by the claim. Value of Filesystem is implied when not included in claim spec. This is an alpha feature and may change in the future.",
|
||||
"description": "volumeMode defines what type of volume is required by the claim. Value of Filesystem is implied when not included in claim spec. This is a beta feature.",
|
||||
"type": "string"
|
||||
},
|
||||
"volumeName": {
|
||||
|
@ -86437,7 +86437,7 @@
|
|||
"$ref": "#/definitions/io.k8s.api.core.v1.StorageOSPersistentVolumeSource"
|
||||
},
|
||||
"volumeMode": {
|
||||
"description": "volumeMode defines if a volume is intended to be used with a formatted filesystem or to remain in raw block state. Value of Filesystem is implied when not included in spec. This is an alpha feature and may change in the future.",
|
||||
"description": "volumeMode defines if a volume is intended to be used with a formatted filesystem or to remain in raw block state. Value of Filesystem is implied when not included in spec. This is a beta feature.",
|
||||
"type": "string"
|
||||
},
|
||||
"vsphereVolume": {
|
||||
|
|
|
@ -8227,7 +8227,7 @@
|
|||
"items": {
|
||||
"$ref": "v1.VolumeDevice"
|
||||
},
|
||||
"description": "volumeDevices is the list of block devices to be used by the container. This is an alpha feature and may change in the future."
|
||||
"description": "volumeDevices is the list of block devices to be used by the container. This is a beta feature."
|
||||
},
|
||||
"livenessProbe": {
|
||||
"$ref": "v1.Probe",
|
||||
|
@ -9796,7 +9796,7 @@
|
|||
},
|
||||
"volumeMode": {
|
||||
"$ref": "v1.PersistentVolumeMode",
|
||||
"description": "volumeMode defines what type of volume is required by the claim. Value of Filesystem is implied when not included in claim spec. This is an alpha feature and may change in the future."
|
||||
"description": "volumeMode defines what type of volume is required by the claim. Value of Filesystem is implied when not included in claim spec. This is a beta feature."
|
||||
},
|
||||
"dataSource": {
|
||||
"$ref": "v1.TypedLocalObjectReference",
|
||||
|
|
|
@ -5739,7 +5739,7 @@
|
|||
"items": {
|
||||
"$ref": "v1.VolumeDevice"
|
||||
},
|
||||
"description": "volumeDevices is the list of block devices to be used by the container. This is an alpha feature and may change in the future."
|
||||
"description": "volumeDevices is the list of block devices to be used by the container. This is a beta feature."
|
||||
},
|
||||
"livenessProbe": {
|
||||
"$ref": "v1.Probe",
|
||||
|
@ -6982,7 +6982,7 @@
|
|||
},
|
||||
"volumeMode": {
|
||||
"$ref": "v1.PersistentVolumeMode",
|
||||
"description": "volumeMode defines what type of volume is required by the claim. Value of Filesystem is implied when not included in claim spec. This is an alpha feature and may change in the future."
|
||||
"description": "volumeMode defines what type of volume is required by the claim. Value of Filesystem is implied when not included in claim spec. This is a beta feature."
|
||||
},
|
||||
"dataSource": {
|
||||
"$ref": "v1.TypedLocalObjectReference",
|
||||
|
|
|
@ -8227,7 +8227,7 @@
|
|||
"items": {
|
||||
"$ref": "v1.VolumeDevice"
|
||||
},
|
||||
"description": "volumeDevices is the list of block devices to be used by the container. This is an alpha feature and may change in the future."
|
||||
"description": "volumeDevices is the list of block devices to be used by the container. This is a beta feature."
|
||||
},
|
||||
"livenessProbe": {
|
||||
"$ref": "v1.Probe",
|
||||
|
@ -9800,7 +9800,7 @@
|
|||
},
|
||||
"volumeMode": {
|
||||
"$ref": "v1.PersistentVolumeMode",
|
||||
"description": "volumeMode defines what type of volume is required by the claim. Value of Filesystem is implied when not included in claim spec. This is an alpha feature and may change in the future."
|
||||
"description": "volumeMode defines what type of volume is required by the claim. Value of Filesystem is implied when not included in claim spec. This is a beta feature."
|
||||
},
|
||||
"dataSource": {
|
||||
"$ref": "v1.TypedLocalObjectReference",
|
||||
|
|
|
@ -2923,7 +2923,7 @@
|
|||
"items": {
|
||||
"$ref": "v1.VolumeDevice"
|
||||
},
|
||||
"description": "volumeDevices is the list of block devices to be used by the container. This is an alpha feature and may change in the future."
|
||||
"description": "volumeDevices is the list of block devices to be used by the container. This is a beta feature."
|
||||
},
|
||||
"livenessProbe": {
|
||||
"$ref": "v1.Probe",
|
||||
|
|
|
@ -2978,7 +2978,7 @@
|
|||
"items": {
|
||||
"$ref": "v1.VolumeDevice"
|
||||
},
|
||||
"description": "volumeDevices is the list of block devices to be used by the container. This is an alpha feature and may change in the future."
|
||||
"description": "volumeDevices is the list of block devices to be used by the container. This is a beta feature."
|
||||
},
|
||||
"livenessProbe": {
|
||||
"$ref": "v1.Probe",
|
||||
|
|
|
@ -2978,7 +2978,7 @@
|
|||
"items": {
|
||||
"$ref": "v1.VolumeDevice"
|
||||
},
|
||||
"description": "volumeDevices is the list of block devices to be used by the container. This is an alpha feature and may change in the future."
|
||||
"description": "volumeDevices is the list of block devices to be used by the container. This is a beta feature."
|
||||
},
|
||||
"livenessProbe": {
|
||||
"$ref": "v1.Probe",
|
||||
|
|
|
@ -8923,7 +8923,7 @@
|
|||
"items": {
|
||||
"$ref": "v1.VolumeDevice"
|
||||
},
|
||||
"description": "volumeDevices is the list of block devices to be used by the container. This is an alpha feature and may change in the future."
|
||||
"description": "volumeDevices is the list of block devices to be used by the container. This is a beta feature."
|
||||
},
|
||||
"livenessProbe": {
|
||||
"$ref": "v1.Probe",
|
||||
|
|
|
@ -19987,7 +19987,7 @@
|
|||
},
|
||||
"volumeMode": {
|
||||
"$ref": "v1.PersistentVolumeMode",
|
||||
"description": "volumeMode defines what type of volume is required by the claim. Value of Filesystem is implied when not included in claim spec. This is an alpha feature and may change in the future."
|
||||
"description": "volumeMode defines what type of volume is required by the claim. Value of Filesystem is implied when not included in claim spec. This is a beta feature."
|
||||
},
|
||||
"dataSource": {
|
||||
"$ref": "v1.TypedLocalObjectReference",
|
||||
|
@ -20320,7 +20320,7 @@
|
|||
},
|
||||
"volumeMode": {
|
||||
"$ref": "v1.PersistentVolumeMode",
|
||||
"description": "volumeMode defines if a volume is intended to be used with a formatted filesystem or to remain in raw block state. Value of Filesystem is implied when not included in spec. This is an alpha feature and may change in the future."
|
||||
"description": "volumeMode defines if a volume is intended to be used with a formatted filesystem or to remain in raw block state. Value of Filesystem is implied when not included in spec. This is a beta feature."
|
||||
},
|
||||
"nodeAffinity": {
|
||||
"$ref": "v1.VolumeNodeAffinity",
|
||||
|
@ -22143,7 +22143,7 @@
|
|||
"items": {
|
||||
"$ref": "v1.VolumeDevice"
|
||||
},
|
||||
"description": "volumeDevices is the list of block devices to be used by the container. This is an alpha feature and may change in the future."
|
||||
"description": "volumeDevices is the list of block devices to be used by the container. This is a beta feature."
|
||||
},
|
||||
"livenessProbe": {
|
||||
"$ref": "v1.Probe",
|
||||
|
|
|
@ -1012,7 +1012,7 @@ span.icon > [class^="icon-"], span.icon > [class*=" icon-"] { cursor: default; }
|
|||
</tr>
|
||||
<tr>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">volumeMode</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">volumeMode defines what type of volume is required by the claim. Value of Filesystem is implied when not included in claim spec. This is an alpha feature and may change in the future.</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">volumeMode defines what type of volume is required by the claim. Value of Filesystem is implied when not included in claim spec. This is a beta feature.</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="#_v1_persistentvolumemode">v1.PersistentVolumeMode</a></p></td>
|
||||
<td class="tableblock halign-left valign-top"></td>
|
||||
|
@ -5718,7 +5718,7 @@ Examples:<br>
|
|||
</tr>
|
||||
<tr>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">volumeDevices</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">volumeDevices is the list of block devices to be used by the container. This is an alpha feature and may change in the future.</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">volumeDevices is the list of block devices to be used by the container. This is a beta feature.</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="#_v1_volumedevice">v1.VolumeDevice</a> array</p></td>
|
||||
<td class="tableblock halign-left valign-top"></td>
|
||||
|
|
|
@ -1040,7 +1040,7 @@ span.icon > [class^="icon-"], span.icon > [class*=" icon-"] { cursor: default; }
|
|||
</tr>
|
||||
<tr>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">volumeMode</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">volumeMode defines what type of volume is required by the claim. Value of Filesystem is implied when not included in claim spec. This is an alpha feature and may change in the future.</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">volumeMode defines what type of volume is required by the claim. Value of Filesystem is implied when not included in claim spec. This is a beta feature.</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="#_v1_persistentvolumemode">v1.PersistentVolumeMode</a></p></td>
|
||||
<td class="tableblock halign-left valign-top"></td>
|
||||
|
@ -5853,7 +5853,7 @@ Examples:<br>
|
|||
</tr>
|
||||
<tr>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">volumeDevices</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">volumeDevices is the list of block devices to be used by the container. This is an alpha feature and may change in the future.</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">volumeDevices is the list of block devices to be used by the container. This is a beta feature.</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="#_v1_volumedevice">v1.VolumeDevice</a> array</p></td>
|
||||
<td class="tableblock halign-left valign-top"></td>
|
||||
|
|
|
@ -987,7 +987,7 @@ span.icon > [class^="icon-"], span.icon > [class*=" icon-"] { cursor: default; }
|
|||
</tr>
|
||||
<tr>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">volumeMode</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">volumeMode defines what type of volume is required by the claim. Value of Filesystem is implied when not included in claim spec. This is an alpha feature and may change in the future.</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">volumeMode defines what type of volume is required by the claim. Value of Filesystem is implied when not included in claim spec. This is a beta feature.</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="#_v1_persistentvolumemode">v1.PersistentVolumeMode</a></p></td>
|
||||
<td class="tableblock halign-left valign-top"></td>
|
||||
|
@ -6187,7 +6187,7 @@ Examples:<br>
|
|||
</tr>
|
||||
<tr>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">volumeDevices</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">volumeDevices is the list of block devices to be used by the container. This is an alpha feature and may change in the future.</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">volumeDevices is the list of block devices to be used by the container. This is a beta feature.</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="#_v1_volumedevice">v1.VolumeDevice</a> array</p></td>
|
||||
<td class="tableblock halign-left valign-top"></td>
|
||||
|
|
|
@ -4610,7 +4610,7 @@ Examples:<br>
|
|||
</tr>
|
||||
<tr>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">volumeDevices</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">volumeDevices is the list of block devices to be used by the container. This is an alpha feature and may change in the future.</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">volumeDevices is the list of block devices to be used by the container. This is a beta feature.</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="#_v1_volumedevice">v1.VolumeDevice</a> array</p></td>
|
||||
<td class="tableblock halign-left valign-top"></td>
|
||||
|
|
|
@ -4761,7 +4761,7 @@ Examples:<br>
|
|||
</tr>
|
||||
<tr>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">volumeDevices</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">volumeDevices is the list of block devices to be used by the container. This is an alpha feature and may change in the future.</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">volumeDevices is the list of block devices to be used by the container. This is a beta feature.</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="#_v1_volumedevice">v1.VolumeDevice</a> array</p></td>
|
||||
<td class="tableblock halign-left valign-top"></td>
|
||||
|
|
|
@ -4617,7 +4617,7 @@ Examples:<br>
|
|||
</tr>
|
||||
<tr>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">volumeDevices</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">volumeDevices is the list of block devices to be used by the container. This is an alpha feature and may change in the future.</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">volumeDevices is the list of block devices to be used by the container. This is a beta feature.</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="#_v1_volumedevice">v1.VolumeDevice</a> array</p></td>
|
||||
<td class="tableblock halign-left valign-top"></td>
|
||||
|
|
|
@ -6565,7 +6565,7 @@ If PodSelector is also set, then the NetworkPolicyPeer as a whole selects the Po
|
|||
</tr>
|
||||
<tr>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">volumeDevices</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">volumeDevices is the list of block devices to be used by the container. This is an alpha feature and may change in the future.</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">volumeDevices is the list of block devices to be used by the container. This is a beta feature.</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="#_v1_volumedevice">v1.VolumeDevice</a> array</p></td>
|
||||
<td class="tableblock halign-left valign-top"></td>
|
||||
|
|
|
@ -689,7 +689,7 @@ span.icon > [class^="icon-"], span.icon > [class*=" icon-"] { cursor: default; }
|
|||
</tr>
|
||||
<tr>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">volumeMode</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">volumeMode defines what type of volume is required by the claim. Value of Filesystem is implied when not included in claim spec. This is an alpha feature and may change in the future.</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">volumeMode defines what type of volume is required by the claim. Value of Filesystem is implied when not included in claim spec. This is a beta feature.</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="#_v1_persistentvolumemode">v1.PersistentVolumeMode</a></p></td>
|
||||
<td class="tableblock halign-left valign-top"></td>
|
||||
|
@ -4282,7 +4282,7 @@ Examples:<br>
|
|||
</tr>
|
||||
<tr>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">volumeMode</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">volumeMode defines if a volume is intended to be used with a formatted filesystem or to remain in raw block state. Value of Filesystem is implied when not included in spec. This is an alpha feature and may change in the future.</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">volumeMode defines if a volume is intended to be used with a formatted filesystem or to remain in raw block state. Value of Filesystem is implied when not included in spec. This is a beta feature.</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="#_v1_persistentvolumemode">v1.PersistentVolumeMode</a></p></td>
|
||||
<td class="tableblock halign-left valign-top"></td>
|
||||
|
@ -10595,7 +10595,7 @@ More info: <a href="https://kubernetes.io/docs/concepts/workloads/pods/pod-lifec
|
|||
</tr>
|
||||
<tr>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">volumeDevices</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">volumeDevices is the list of block devices to be used by the container. This is an alpha feature and may change in the future.</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">volumeDevices is the list of block devices to be used by the container. This is a beta feature.</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="#_v1_volumedevice">v1.VolumeDevice</a> array</p></td>
|
||||
<td class="tableblock halign-left valign-top"></td>
|
||||
|
|
|
@ -403,11 +403,15 @@ var Funcs = func(codecs runtimeserializer.CodecFactory) []interface{} {
|
|||
pv.Status.Message = c.RandString()
|
||||
reclamationPolicies := []core.PersistentVolumeReclaimPolicy{core.PersistentVolumeReclaimRecycle, core.PersistentVolumeReclaimRetain}
|
||||
pv.Spec.PersistentVolumeReclaimPolicy = reclamationPolicies[c.Rand.Intn(len(reclamationPolicies))]
|
||||
volumeModes := []core.PersistentVolumeMode{core.PersistentVolumeFilesystem, core.PersistentVolumeBlock}
|
||||
pv.Spec.VolumeMode = &volumeModes[c.Rand.Intn(len(volumeModes))]
|
||||
},
|
||||
func(pvc *core.PersistentVolumeClaim, c fuzz.Continue) {
|
||||
c.FuzzNoCustom(pvc) // fuzz self without calling this function again
|
||||
types := []core.PersistentVolumeClaimPhase{core.ClaimBound, core.ClaimPending, core.ClaimLost}
|
||||
pvc.Status.Phase = types[c.Rand.Intn(len(types))]
|
||||
volumeModes := []core.PersistentVolumeMode{core.PersistentVolumeFilesystem, core.PersistentVolumeBlock}
|
||||
pvc.Spec.VolumeMode = &volumeModes[c.Rand.Intn(len(volumeModes))]
|
||||
},
|
||||
func(obj *core.AzureDiskVolumeSource, c fuzz.Continue) {
|
||||
if obj.CachingMode == nil {
|
||||
|
|
|
@ -298,7 +298,7 @@ type PersistentVolumeSpec struct {
|
|||
MountOptions []string
|
||||
// volumeMode defines if a volume is intended to be used with a formatted filesystem
|
||||
// or to remain in raw block state. Value of Filesystem is implied when not included in spec.
|
||||
// This is an alpha feature and may change in the future.
|
||||
// This is a beta feature.
|
||||
// +optional
|
||||
VolumeMode *PersistentVolumeMode
|
||||
// NodeAffinity defines constraints that limit what nodes this volume can be accessed from.
|
||||
|
@ -410,7 +410,7 @@ type PersistentVolumeClaimSpec struct {
|
|||
StorageClassName *string
|
||||
// volumeMode defines what type of volume is required by the claim.
|
||||
// Value of Filesystem is implied when not included in claim spec.
|
||||
// This is an alpha feature and may change in the future.
|
||||
// This is a beta feature.
|
||||
// +optional
|
||||
VolumeMode *PersistentVolumeMode
|
||||
// This field requires the VolumeSnapshotDataSource alpha feature gate to be
|
||||
|
@ -1968,7 +1968,7 @@ type Container struct {
|
|||
// +optional
|
||||
VolumeMounts []VolumeMount
|
||||
// volumeDevices is the list of block devices to be used by the container.
|
||||
// This is an alpha feature and may change in the future.
|
||||
// This is a beta feature.
|
||||
// +optional
|
||||
VolumeDevices []VolumeDevice
|
||||
// +optional
|
||||
|
|
|
@ -27,8 +27,10 @@ import (
|
|||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/util/intstr"
|
||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||
utilfeaturetesting "k8s.io/apiserver/pkg/util/feature/testing"
|
||||
"k8s.io/kubernetes/pkg/api/legacyscheme"
|
||||
corev1 "k8s.io/kubernetes/pkg/apis/core/v1"
|
||||
"k8s.io/kubernetes/pkg/features"
|
||||
utilpointer "k8s.io/utils/pointer"
|
||||
|
||||
// enforce that all types are installed
|
||||
|
@ -803,6 +805,7 @@ func TestSetDefaultSecret(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestSetDefaultPersistentVolume(t *testing.T) {
|
||||
defer utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.BlockVolume, false)()
|
||||
pv := &v1.PersistentVolume{}
|
||||
obj2 := roundTrip(t, runtime.Object(pv))
|
||||
pv2 := obj2.(*v1.PersistentVolume)
|
||||
|
@ -822,10 +825,7 @@ func TestSetDefaultPersistentVolume(t *testing.T) {
|
|||
}
|
||||
|
||||
// When feature gate is enabled, field should be defaulted
|
||||
err := utilfeature.DefaultFeatureGate.Set("BlockVolume=true")
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to enable feature gate for BlockVolume: %v", err)
|
||||
}
|
||||
defer utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.BlockVolume, true)()
|
||||
obj3 := roundTrip(t, runtime.Object(pv)).(*v1.PersistentVolume)
|
||||
outputMode3 := obj3.Spec.VolumeMode
|
||||
|
||||
|
@ -834,15 +834,10 @@ func TestSetDefaultPersistentVolume(t *testing.T) {
|
|||
} else if *outputMode3 != defaultMode {
|
||||
t.Errorf("Expected VolumeMode to be defaulted to: %+v, got: %+v", defaultMode, outputMode3)
|
||||
}
|
||||
|
||||
err = utilfeature.DefaultFeatureGate.Set("BlockVolume=false")
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to disable feature gate for BlockVolume: %v", err)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestSetDefaultPersistentVolumeClaim(t *testing.T) {
|
||||
defer utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.BlockVolume, false)()
|
||||
pvc := &v1.PersistentVolumeClaim{}
|
||||
obj2 := roundTrip(t, runtime.Object(pvc))
|
||||
pvc2 := obj2.(*v1.PersistentVolumeClaim)
|
||||
|
@ -859,10 +854,7 @@ func TestSetDefaultPersistentVolumeClaim(t *testing.T) {
|
|||
}
|
||||
|
||||
// When feature gate is enabled, field should be defaulted
|
||||
err := utilfeature.DefaultFeatureGate.Set("BlockVolume=true")
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to enable feature gate for BlockVolume: %v", err)
|
||||
}
|
||||
defer utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.BlockVolume, true)()
|
||||
obj3 := roundTrip(t, runtime.Object(pvc)).(*v1.PersistentVolumeClaim)
|
||||
outputMode3 := obj3.Spec.VolumeMode
|
||||
|
||||
|
@ -871,11 +863,6 @@ func TestSetDefaultPersistentVolumeClaim(t *testing.T) {
|
|||
} else if *outputMode3 != defaultMode {
|
||||
t.Errorf("Expected VolumeMode to be defaulted to: %+v, got: %+v", defaultMode, outputMode3)
|
||||
}
|
||||
|
||||
err = utilfeature.DefaultFeatureGate.Set("BlockVolume=false")
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to disable feature gate for BlockVolume: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSetDefaulEndpointsProtocol(t *testing.T) {
|
||||
|
|
|
@ -66,9 +66,11 @@ func testVolume(name string, namespace string, spec core.PersistentVolumeSpec) *
|
|||
|
||||
func TestValidatePersistentVolumes(t *testing.T) {
|
||||
validMode := core.PersistentVolumeFilesystem
|
||||
invalidMode := core.PersistentVolumeMode("fakeVolumeMode")
|
||||
scenarios := map[string]struct {
|
||||
isExpectedFailure bool
|
||||
volume *core.PersistentVolume
|
||||
disableBlock bool
|
||||
}{
|
||||
"good-volume": {
|
||||
isExpectedFailure: false,
|
||||
|
@ -147,6 +149,22 @@ func TestValidatePersistentVolumes(t *testing.T) {
|
|||
PersistentVolumeReclaimPolicy: core.PersistentVolumeReclaimRetain,
|
||||
}),
|
||||
},
|
||||
"good-volume-with-volume-mode": {
|
||||
isExpectedFailure: false,
|
||||
volume: testVolume("foo", "", core.PersistentVolumeSpec{
|
||||
Capacity: core.ResourceList{
|
||||
core.ResourceName(core.ResourceStorage): resource.MustParse("10G"),
|
||||
},
|
||||
AccessModes: []core.PersistentVolumeAccessMode{core.ReadWriteOnce},
|
||||
PersistentVolumeSource: core.PersistentVolumeSource{
|
||||
HostPath: &core.HostPathVolumeSource{
|
||||
Path: "/foo",
|
||||
Type: newHostPathType(string(core.HostPathDirectory)),
|
||||
},
|
||||
},
|
||||
VolumeMode: &validMode,
|
||||
}),
|
||||
},
|
||||
"invalid-accessmode": {
|
||||
isExpectedFailure: true,
|
||||
volume: testVolume("foo", "", core.PersistentVolumeSpec{
|
||||
|
@ -178,6 +196,22 @@ func TestValidatePersistentVolumes(t *testing.T) {
|
|||
PersistentVolumeReclaimPolicy: "fakeReclaimPolicy",
|
||||
}),
|
||||
},
|
||||
"invalid-volume-mode": {
|
||||
isExpectedFailure: true,
|
||||
volume: testVolume("foo", "", core.PersistentVolumeSpec{
|
||||
Capacity: core.ResourceList{
|
||||
core.ResourceName(core.ResourceStorage): resource.MustParse("10G"),
|
||||
},
|
||||
AccessModes: []core.PersistentVolumeAccessMode{core.ReadWriteOnce},
|
||||
PersistentVolumeSource: core.PersistentVolumeSource{
|
||||
HostPath: &core.HostPathVolumeSource{
|
||||
Path: "/foo",
|
||||
Type: newHostPathType(string(core.HostPathDirectory)),
|
||||
},
|
||||
},
|
||||
VolumeMode: &invalidMode,
|
||||
}),
|
||||
},
|
||||
"unexpected-namespace": {
|
||||
isExpectedFailure: true,
|
||||
volume: testVolume("foo", "unexpected-namespace", core.PersistentVolumeSpec{
|
||||
|
@ -336,9 +370,8 @@ func TestValidatePersistentVolumes(t *testing.T) {
|
|||
StorageClassName: "-invalid-",
|
||||
}),
|
||||
},
|
||||
// VolumeMode alpha feature disabled
|
||||
// TODO: remove when no longer alpha
|
||||
"alpha disabled valid volume mode": {
|
||||
"feature disabled valid volume mode": {
|
||||
disableBlock: true,
|
||||
isExpectedFailure: true,
|
||||
volume: testVolume("foo", "", core.PersistentVolumeSpec{
|
||||
Capacity: core.ResourceList{
|
||||
|
@ -400,13 +433,16 @@ func TestValidatePersistentVolumes(t *testing.T) {
|
|||
}
|
||||
|
||||
for name, scenario := range scenarios {
|
||||
errs := ValidatePersistentVolume(scenario.volume)
|
||||
if len(errs) == 0 && scenario.isExpectedFailure {
|
||||
t.Errorf("Unexpected success for scenario: %s", name)
|
||||
}
|
||||
if len(errs) > 0 && !scenario.isExpectedFailure {
|
||||
t.Errorf("Unexpected failure for scenario: %s - %+v", name, errs)
|
||||
}
|
||||
t.Run(name, func(t *testing.T) {
|
||||
defer utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.BlockVolume, !scenario.disableBlock)()
|
||||
errs := ValidatePersistentVolume(scenario.volume)
|
||||
if len(errs) == 0 && scenario.isExpectedFailure {
|
||||
t.Errorf("Unexpected success for scenario: %s", name)
|
||||
}
|
||||
if len(errs) > 0 && !scenario.isExpectedFailure {
|
||||
t.Errorf("Unexpected failure for scenario: %s - %+v", name, errs)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -791,10 +827,12 @@ func testVolumeClaimStorageClassInAnnotationAndSpec(name, namespace, scNameInAnn
|
|||
func TestValidatePersistentVolumeClaim(t *testing.T) {
|
||||
invalidClassName := "-invalid-"
|
||||
validClassName := "valid"
|
||||
invalidMode := core.PersistentVolumeMode("fakeVolumeMode")
|
||||
validMode := core.PersistentVolumeFilesystem
|
||||
scenarios := map[string]struct {
|
||||
isExpectedFailure bool
|
||||
claim *core.PersistentVolumeClaim
|
||||
disableBlock bool
|
||||
}{
|
||||
"good-claim": {
|
||||
isExpectedFailure: false,
|
||||
|
@ -817,6 +855,7 @@ func TestValidatePersistentVolumeClaim(t *testing.T) {
|
|||
},
|
||||
},
|
||||
StorageClassName: &validClassName,
|
||||
VolumeMode: &validMode,
|
||||
}),
|
||||
},
|
||||
"invalid-claim-zero-capacity": {
|
||||
|
@ -988,9 +1027,8 @@ func TestValidatePersistentVolumeClaim(t *testing.T) {
|
|||
StorageClassName: &invalidClassName,
|
||||
}),
|
||||
},
|
||||
// VolumeMode alpha feature disabled
|
||||
// TODO: remove when no longer alpha
|
||||
"disabled alpha valid volume mode": {
|
||||
"feature disabled valid volume mode": {
|
||||
disableBlock: true,
|
||||
isExpectedFailure: true,
|
||||
claim: testVolumeClaim("foo", "ns", core.PersistentVolumeClaimSpec{
|
||||
Selector: &metav1.LabelSelector{
|
||||
|
@ -1014,16 +1052,34 @@ func TestValidatePersistentVolumeClaim(t *testing.T) {
|
|||
VolumeMode: &validMode,
|
||||
}),
|
||||
},
|
||||
"invalid-volume-mode": {
|
||||
isExpectedFailure: true,
|
||||
claim: testVolumeClaim("foo", "ns", core.PersistentVolumeClaimSpec{
|
||||
AccessModes: []core.PersistentVolumeAccessMode{
|
||||
core.ReadWriteOnce,
|
||||
core.ReadOnlyMany,
|
||||
},
|
||||
Resources: core.ResourceRequirements{
|
||||
Requests: core.ResourceList{
|
||||
core.ResourceName(core.ResourceStorage): resource.MustParse("10G"),
|
||||
},
|
||||
},
|
||||
VolumeMode: &invalidMode,
|
||||
}),
|
||||
},
|
||||
}
|
||||
|
||||
for name, scenario := range scenarios {
|
||||
errs := ValidatePersistentVolumeClaim(scenario.claim)
|
||||
if len(errs) == 0 && scenario.isExpectedFailure {
|
||||
t.Errorf("Unexpected success for scenario: %s", name)
|
||||
}
|
||||
if len(errs) > 0 && !scenario.isExpectedFailure {
|
||||
t.Errorf("Unexpected failure for scenario: %s - %+v", name, errs)
|
||||
}
|
||||
t.Run(name, func(t *testing.T) {
|
||||
defer utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.BlockVolume, !scenario.disableBlock)()
|
||||
errs := ValidatePersistentVolumeClaim(scenario.claim)
|
||||
if len(errs) == 0 && scenario.isExpectedFailure {
|
||||
t.Errorf("Unexpected success for scenario: %s", name)
|
||||
}
|
||||
if len(errs) > 0 && !scenario.isExpectedFailure {
|
||||
t.Errorf("Unexpected failure for scenario: %s - %+v", name, errs)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1106,15 +1162,17 @@ func TestAlphaPVVolumeModeUpdate(t *testing.T) {
|
|||
}
|
||||
|
||||
for name, scenario := range scenarios {
|
||||
// ensure we have a resource version specified for updates
|
||||
toggleBlockVolumeFeature(scenario.enableBlock, t)
|
||||
errs := ValidatePersistentVolumeUpdate(scenario.newPV, scenario.oldPV)
|
||||
if len(errs) == 0 && scenario.isExpectedFailure {
|
||||
t.Errorf("Unexpected success for scenario: %s", name)
|
||||
}
|
||||
if len(errs) > 0 && !scenario.isExpectedFailure {
|
||||
t.Errorf("Unexpected failure for scenario: %s - %+v", name, errs)
|
||||
}
|
||||
t.Run(name, func(t *testing.T) {
|
||||
// ensure we have a resource version specified for updates
|
||||
defer utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.BlockVolume, scenario.enableBlock)()
|
||||
errs := ValidatePersistentVolumeUpdate(scenario.newPV, scenario.oldPV)
|
||||
if len(errs) == 0 && scenario.isExpectedFailure {
|
||||
t.Errorf("Unexpected success for scenario: %s", name)
|
||||
}
|
||||
if len(errs) > 0 && !scenario.isExpectedFailure {
|
||||
t.Errorf("Unexpected failure for scenario: %s - %+v", name, errs)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1558,8 +1616,7 @@ func TestValidatePersistentVolumeClaimUpdate(t *testing.T) {
|
|||
t.Run(name, func(t *testing.T) {
|
||||
// ensure we have a resource version specified for updates
|
||||
defer utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.ExpandPersistentVolumes, scenario.enableResize)()
|
||||
|
||||
toggleBlockVolumeFeature(scenario.enableBlock, t)
|
||||
defer utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.BlockVolume, scenario.enableBlock)()
|
||||
scenario.oldClaim.ResourceVersion = "1"
|
||||
scenario.newClaim.ResourceVersion = "1"
|
||||
errs := ValidatePersistentVolumeClaimUpdate(scenario.newClaim, scenario.oldClaim)
|
||||
|
@ -1573,23 +1630,6 @@ func TestValidatePersistentVolumeClaimUpdate(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func toggleBlockVolumeFeature(toggleFlag bool, t *testing.T) {
|
||||
if toggleFlag {
|
||||
// Enable alpha feature BlockVolume
|
||||
err := utilfeature.DefaultFeatureGate.Set("BlockVolume=true")
|
||||
if err != nil {
|
||||
t.Errorf("Failed to enable feature gate for BlockVolume: %v", err)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
err := utilfeature.DefaultFeatureGate.Set("BlockVolume=false")
|
||||
if err != nil {
|
||||
t.Errorf("Failed to disable feature gate for BlockVolume: %v", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateKeyToPath(t *testing.T) {
|
||||
testCases := []struct {
|
||||
kp core.KeyToPath
|
||||
|
@ -3880,13 +3920,9 @@ func TestAlphaHugePagesIsolation(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestAlphaPVCVolumeMode(t *testing.T) {
|
||||
// Enable alpha feature BlockVolume for PVC
|
||||
err := utilfeature.DefaultFeatureGate.Set("BlockVolume=true")
|
||||
if err != nil {
|
||||
t.Errorf("Failed to enable feature gate for BlockVolume: %v", err)
|
||||
return
|
||||
}
|
||||
func TestPVCVolumeMode(t *testing.T) {
|
||||
// Enable feature BlockVolume for PVC
|
||||
defer utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.BlockVolume, true)()
|
||||
|
||||
block := core.PersistentVolumeBlock
|
||||
file := core.PersistentVolumeFilesystem
|
||||
|
@ -3917,13 +3953,9 @@ func TestAlphaPVCVolumeMode(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestAlphaPVVolumeMode(t *testing.T) {
|
||||
// Enable alpha feature BlockVolume for PV
|
||||
err := utilfeature.DefaultFeatureGate.Set("BlockVolume=true")
|
||||
if err != nil {
|
||||
t.Errorf("Failed to enable feature gate for BlockVolume: %v", err)
|
||||
return
|
||||
}
|
||||
func TestPVVolumeMode(t *testing.T) {
|
||||
// Enable feature BlockVolume for PVC
|
||||
defer utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.BlockVolume, true)()
|
||||
|
||||
block := core.PersistentVolumeBlock
|
||||
file := core.PersistentVolumeFilesystem
|
||||
|
@ -5088,12 +5120,8 @@ func TestAlphaValidateVolumeDevices(t *testing.T) {
|
|||
{Name: "abc-123", MountPath: "/this/path/exists"},
|
||||
}
|
||||
|
||||
// enable Alpha BlockVolume
|
||||
err1 := utilfeature.DefaultFeatureGate.Set("BlockVolume=true")
|
||||
if err1 != nil {
|
||||
t.Errorf("Failed to enable feature gate for BlockVolume: %v", err1)
|
||||
return
|
||||
}
|
||||
// enable BlockVolume
|
||||
defer utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.BlockVolume, true)()
|
||||
// Success Cases:
|
||||
// Validate normal success cases - only PVC volumeSource
|
||||
if errs := ValidateVolumeDevices(successCase, GetVolumeMountMap(goodVolumeMounts), vols, field.NewPath("field")); len(errs) != 0 {
|
||||
|
@ -5108,12 +5136,8 @@ func TestAlphaValidateVolumeDevices(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
// disable Alpha BlockVolume
|
||||
err2 := utilfeature.DefaultFeatureGate.Set("BlockVolume=false")
|
||||
if err2 != nil {
|
||||
t.Errorf("Failed to disable feature gate for BlockVolume: %v", err2)
|
||||
return
|
||||
}
|
||||
// disable BlockVolume
|
||||
defer utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.BlockVolume, false)()
|
||||
if errs := ValidateVolumeDevices(disabledAlphaVolDevice, GetVolumeMountMap(goodVolumeMounts), vols, field.NewPath("field")); len(errs) == 0 {
|
||||
t.Errorf("expected failure: %v", errs)
|
||||
}
|
||||
|
|
|
@ -23,6 +23,8 @@ import (
|
|||
storage "k8s.io/api/storage/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||
utilfeaturetesting "k8s.io/apiserver/pkg/util/feature/testing"
|
||||
"k8s.io/kubernetes/pkg/features"
|
||||
)
|
||||
|
||||
// Test single call to syncClaim and syncVolume methods.
|
||||
|
@ -35,8 +37,6 @@ func TestSync(t *testing.T) {
|
|||
"foo": "true",
|
||||
"bar": "false",
|
||||
}
|
||||
modeBlock := v1.PersistentVolumeBlock
|
||||
modeFile := v1.PersistentVolumeFilesystem
|
||||
|
||||
tests := []controllerTest{
|
||||
// [Unit test set 1] User did not care which PV they get.
|
||||
|
@ -589,9 +589,22 @@ func TestSync(t *testing.T) {
|
|||
newClaimArray("claim13-5", "uid13-5", "1Gi", "volume13-5", v1.ClaimBound, nil, annBoundByController, annBindCompleted),
|
||||
noevents, noerrors, testSyncClaim,
|
||||
},
|
||||
}
|
||||
|
||||
// All of these should bind as feature set is not enabled for BlockVolume
|
||||
// meaning volumeMode will be ignored and dropped
|
||||
runSyncTests(t, tests, []*storage.StorageClass{
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{Name: classWait},
|
||||
VolumeBindingMode: &modeWait,
|
||||
},
|
||||
}, []*v1.Pod{})
|
||||
}
|
||||
|
||||
func TestSyncBlockVolumeDisabled(t *testing.T) {
|
||||
modeBlock := v1.PersistentVolumeBlock
|
||||
modeFile := v1.PersistentVolumeFilesystem
|
||||
// All of these should bind as feature set is not enabled for BlockVolume
|
||||
// meaning volumeMode will be ignored and dropped
|
||||
tests := []controllerTest{
|
||||
{
|
||||
// syncVolume binds a requested block claim to a block volume
|
||||
"14-1 - binding to volumeMode block",
|
||||
|
@ -639,6 +652,7 @@ func TestSync(t *testing.T) {
|
|||
},
|
||||
}
|
||||
|
||||
defer utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.BlockVolume, false)()
|
||||
runSyncTests(t, tests, []*storage.StorageClass{
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{Name: classWait},
|
||||
|
@ -647,7 +661,7 @@ func TestSync(t *testing.T) {
|
|||
}, []*v1.Pod{})
|
||||
}
|
||||
|
||||
func TestSyncAlphaBlockVolume(t *testing.T) {
|
||||
func TestSyncBlockVolume(t *testing.T) {
|
||||
modeBlock := v1.PersistentVolumeBlock
|
||||
modeFile := v1.PersistentVolumeFilesystem
|
||||
|
||||
|
@ -827,12 +841,7 @@ func TestSyncAlphaBlockVolume(t *testing.T) {
|
|||
},
|
||||
}
|
||||
|
||||
err := utilfeature.DefaultFeatureGate.Set("BlockVolume=true")
|
||||
if err != nil {
|
||||
t.Errorf("Failed to enable feature gate for BlockVolume: %v", err)
|
||||
return
|
||||
}
|
||||
defer utilfeature.DefaultFeatureGate.Set("BlockVolume=false")
|
||||
defer utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.BlockVolume, true)()
|
||||
|
||||
runSyncTests(t, tests, []*storage.StorageClass{}, []*v1.Pod{})
|
||||
}
|
||||
|
|
|
@ -38,6 +38,7 @@ import (
|
|||
"k8s.io/apimachinery/pkg/util/diff"
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
"k8s.io/apimachinery/pkg/watch"
|
||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||
"k8s.io/client-go/informers"
|
||||
clientset "k8s.io/client-go/kubernetes"
|
||||
"k8s.io/client-go/kubernetes/fake"
|
||||
|
@ -48,6 +49,7 @@ import (
|
|||
"k8s.io/client-go/tools/record"
|
||||
"k8s.io/kubernetes/pkg/api/testapi"
|
||||
"k8s.io/kubernetes/pkg/controller"
|
||||
"k8s.io/kubernetes/pkg/features"
|
||||
vol "k8s.io/kubernetes/pkg/volume"
|
||||
"k8s.io/kubernetes/pkg/volume/util/recyclerclient"
|
||||
)
|
||||
|
@ -179,6 +181,12 @@ func (r *volumeReactor) React(action core.Action) (handled bool, ret runtime.Obj
|
|||
return true, nil, fmt.Errorf("Cannot create volume %s: volume already exists", volume.Name)
|
||||
}
|
||||
|
||||
// mimic apiserver defaulting
|
||||
if volume.Spec.VolumeMode == nil && utilfeature.DefaultFeatureGate.Enabled(features.BlockVolume) {
|
||||
volume.Spec.VolumeMode = new(v1.PersistentVolumeMode)
|
||||
*volume.Spec.VolumeMode = v1.PersistentVolumeFilesystem
|
||||
}
|
||||
|
||||
// Store the updated object to appropriate places.
|
||||
r.volumes[volume.Name] = volume
|
||||
r.changedObjects = append(r.changedObjects, volume)
|
||||
|
@ -630,6 +638,7 @@ func newTestController(kubeClient clientset.Interface, informerFactory informers
|
|||
|
||||
// newVolume returns a new volume with given attributes
|
||||
func newVolume(name, capacity, boundToClaimUID, boundToClaimName string, phase v1.PersistentVolumePhase, reclaimPolicy v1.PersistentVolumeReclaimPolicy, class string, annotations ...string) *v1.PersistentVolume {
|
||||
fs := v1.PersistentVolumeFilesystem
|
||||
volume := v1.PersistentVolume{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: name,
|
||||
|
@ -645,6 +654,7 @@ func newVolume(name, capacity, boundToClaimUID, boundToClaimName string, phase v
|
|||
AccessModes: []v1.PersistentVolumeAccessMode{v1.ReadWriteOnce, v1.ReadOnlyMany},
|
||||
PersistentVolumeReclaimPolicy: reclaimPolicy,
|
||||
StorageClassName: class,
|
||||
VolumeMode: &fs,
|
||||
},
|
||||
Status: v1.PersistentVolumeStatus{
|
||||
Phase: phase,
|
||||
|
@ -740,6 +750,7 @@ func newVolumeArray(name, capacity, boundToClaimUID, boundToClaimName string, ph
|
|||
|
||||
// newClaim returns a new claim with given attributes
|
||||
func newClaim(name, claimUID, capacity, boundToVolume string, phase v1.PersistentVolumeClaimPhase, class *string, annotations ...string) *v1.PersistentVolumeClaim {
|
||||
fs := v1.PersistentVolumeFilesystem
|
||||
claim := v1.PersistentVolumeClaim{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: name,
|
||||
|
@ -756,6 +767,7 @@ func newClaim(name, claimUID, capacity, boundToVolume string, phase v1.Persisten
|
|||
},
|
||||
VolumeName: boundToVolume,
|
||||
StorageClassName: class,
|
||||
VolumeMode: &fs,
|
||||
},
|
||||
Status: v1.PersistentVolumeClaimStatus{
|
||||
Phase: phase,
|
||||
|
@ -1226,6 +1238,7 @@ func (plugin *mockVolumePlugin) Provision(selectedNode *v1.Node, allowedTopologi
|
|||
Phase: v1.VolumeAvailable,
|
||||
},
|
||||
}
|
||||
pv.Spec.VolumeMode = plugin.provisionOptions.PVC.Spec.VolumeMode
|
||||
}
|
||||
|
||||
plugin.provisionCallCounter++
|
||||
|
|
|
@ -158,13 +158,13 @@ func findMatchingVolume(
|
|||
|
||||
volumeQty := volume.Spec.Capacity[v1.ResourceStorage]
|
||||
|
||||
// check if volumeModes do not match (Alpha and feature gate protected)
|
||||
isMisMatch, err := checkVolumeModeMisMatches(&claim.Spec, &volume.Spec)
|
||||
// check if volumeModes do not match (feature gate protected)
|
||||
isMismatch, err := checkVolumeModeMismatches(&claim.Spec, &volume.Spec)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error checking if volumeMode was a mismatch: %v", err)
|
||||
}
|
||||
// filter out mismatching volumeModes
|
||||
if isMisMatch {
|
||||
if isMismatch {
|
||||
continue
|
||||
}
|
||||
|
||||
|
@ -258,25 +258,24 @@ func findMatchingVolume(
|
|||
return nil, nil
|
||||
}
|
||||
|
||||
// checkVolumeModeMatches is a convenience method that checks volumeMode for PersistentVolume
|
||||
// and PersistentVolumeClaims along with making sure that the Alpha feature gate BlockVolume is
|
||||
// enabled.
|
||||
// This is Alpha and could change in the future.
|
||||
func checkVolumeModeMisMatches(pvcSpec *v1.PersistentVolumeClaimSpec, pvSpec *v1.PersistentVolumeSpec) (bool, error) {
|
||||
if utilfeature.DefaultFeatureGate.Enabled(features.BlockVolume) {
|
||||
if pvSpec.VolumeMode != nil && pvcSpec.VolumeMode != nil {
|
||||
requestedVolumeMode := *pvcSpec.VolumeMode
|
||||
pvVolumeMode := *pvSpec.VolumeMode
|
||||
return requestedVolumeMode != pvVolumeMode, nil
|
||||
} else {
|
||||
// This also should retrun an error, this means that
|
||||
// the defaulting has failed.
|
||||
return true, fmt.Errorf("api defaulting for volumeMode failed")
|
||||
}
|
||||
} else {
|
||||
// feature gate is disabled
|
||||
// checkVolumeModeMismatches is a convenience method that checks volumeMode for PersistentVolume
|
||||
// and PersistentVolumeClaims
|
||||
func checkVolumeModeMismatches(pvcSpec *v1.PersistentVolumeClaimSpec, pvSpec *v1.PersistentVolumeSpec) (bool, error) {
|
||||
if !utilfeature.DefaultFeatureGate.Enabled(features.BlockVolume) {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// In HA upgrades, we cannot guarantee that the apiserver is on a version >= controller-manager.
|
||||
// So we default a nil volumeMode to filesystem
|
||||
requestedVolumeMode := v1.PersistentVolumeFilesystem
|
||||
if pvcSpec.VolumeMode != nil {
|
||||
requestedVolumeMode = *pvcSpec.VolumeMode
|
||||
}
|
||||
pvVolumeMode := v1.PersistentVolumeFilesystem
|
||||
if pvSpec.VolumeMode != nil {
|
||||
pvVolumeMode = *pvSpec.VolumeMode
|
||||
}
|
||||
return requestedVolumeMode != pvVolumeMode, nil
|
||||
}
|
||||
|
||||
// findBestMatchForClaim is a convenience method that finds a volume by the claim's AccessModes and requests for Storage
|
||||
|
|
|
@ -33,6 +33,7 @@ import (
|
|||
)
|
||||
|
||||
func makePVC(size string, modfn func(*v1.PersistentVolumeClaim)) *v1.PersistentVolumeClaim {
|
||||
fs := v1.PersistentVolumeFilesystem
|
||||
pvc := v1.PersistentVolumeClaim{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "claim01",
|
||||
|
@ -45,6 +46,7 @@ func makePVC(size string, modfn func(*v1.PersistentVolumeClaim)) *v1.PersistentV
|
|||
v1.ResourceName(v1.ResourceStorage): resource.MustParse(size),
|
||||
},
|
||||
},
|
||||
VolumeMode: &fs,
|
||||
},
|
||||
}
|
||||
if modfn != nil {
|
||||
|
@ -197,6 +199,7 @@ func TestMatchVolume(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestMatchingWithBoundVolumes(t *testing.T) {
|
||||
fs := v1.PersistentVolumeFilesystem
|
||||
volumeIndex := newPersistentVolumeOrderedIndex()
|
||||
// two similar volumes, one is bound
|
||||
pv1 := &v1.PersistentVolume{
|
||||
|
@ -213,7 +216,8 @@ func TestMatchingWithBoundVolumes(t *testing.T) {
|
|||
},
|
||||
AccessModes: []v1.PersistentVolumeAccessMode{v1.ReadWriteOnce, v1.ReadOnlyMany},
|
||||
// this one we're pretending is already bound
|
||||
ClaimRef: &v1.ObjectReference{UID: "abc123"},
|
||||
ClaimRef: &v1.ObjectReference{UID: "abc123"},
|
||||
VolumeMode: &fs,
|
||||
},
|
||||
Status: v1.PersistentVolumeStatus{
|
||||
Phase: v1.VolumeBound,
|
||||
|
@ -233,6 +237,7 @@ func TestMatchingWithBoundVolumes(t *testing.T) {
|
|||
GCEPersistentDisk: &v1.GCEPersistentDiskVolumeSource{},
|
||||
},
|
||||
AccessModes: []v1.PersistentVolumeAccessMode{v1.ReadWriteOnce, v1.ReadOnlyMany},
|
||||
VolumeMode: &fs,
|
||||
},
|
||||
Status: v1.PersistentVolumeStatus{
|
||||
Phase: v1.VolumeAvailable,
|
||||
|
@ -254,6 +259,7 @@ func TestMatchingWithBoundVolumes(t *testing.T) {
|
|||
v1.ResourceName(v1.ResourceStorage): resource.MustParse("1G"),
|
||||
},
|
||||
},
|
||||
VolumeMode: &fs,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -328,6 +334,7 @@ func TestAllPossibleAccessModes(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestFindingVolumeWithDifferentAccessModes(t *testing.T) {
|
||||
fs := v1.PersistentVolumeFilesystem
|
||||
gce := &v1.PersistentVolume{
|
||||
ObjectMeta: metav1.ObjectMeta{UID: "001", Name: "gce"},
|
||||
Spec: v1.PersistentVolumeSpec{
|
||||
|
@ -337,6 +344,7 @@ func TestFindingVolumeWithDifferentAccessModes(t *testing.T) {
|
|||
v1.ReadWriteOnce,
|
||||
v1.ReadOnlyMany,
|
||||
},
|
||||
VolumeMode: &fs,
|
||||
},
|
||||
Status: v1.PersistentVolumeStatus{
|
||||
Phase: v1.VolumeAvailable,
|
||||
|
@ -351,6 +359,7 @@ func TestFindingVolumeWithDifferentAccessModes(t *testing.T) {
|
|||
AccessModes: []v1.PersistentVolumeAccessMode{
|
||||
v1.ReadWriteOnce,
|
||||
},
|
||||
VolumeMode: &fs,
|
||||
},
|
||||
Status: v1.PersistentVolumeStatus{
|
||||
Phase: v1.VolumeAvailable,
|
||||
|
@ -367,6 +376,7 @@ func TestFindingVolumeWithDifferentAccessModes(t *testing.T) {
|
|||
v1.ReadOnlyMany,
|
||||
v1.ReadWriteMany,
|
||||
},
|
||||
VolumeMode: &fs,
|
||||
},
|
||||
Status: v1.PersistentVolumeStatus{
|
||||
Phase: v1.VolumeAvailable,
|
||||
|
@ -381,6 +391,7 @@ func TestFindingVolumeWithDifferentAccessModes(t *testing.T) {
|
|||
Spec: v1.PersistentVolumeClaimSpec{
|
||||
AccessModes: []v1.PersistentVolumeAccessMode{v1.ReadWriteOnce},
|
||||
Resources: v1.ResourceRequirements{Requests: v1.ResourceList{v1.ResourceName(v1.ResourceStorage): resource.MustParse("1G")}},
|
||||
VolumeMode: &fs,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -440,6 +451,7 @@ func TestFindingVolumeWithDifferentAccessModes(t *testing.T) {
|
|||
}
|
||||
|
||||
func createTestVolumes() []*v1.PersistentVolume {
|
||||
fs := v1.PersistentVolumeFilesystem
|
||||
// these volumes are deliberately out-of-order to test indexing and sorting
|
||||
return []*v1.PersistentVolume{
|
||||
{
|
||||
|
@ -458,6 +470,7 @@ func createTestVolumes() []*v1.PersistentVolume {
|
|||
v1.ReadWriteOnce,
|
||||
v1.ReadOnlyMany,
|
||||
},
|
||||
VolumeMode: &fs,
|
||||
},
|
||||
Status: v1.PersistentVolumeStatus{
|
||||
Phase: v1.VolumeAvailable,
|
||||
|
@ -480,7 +493,8 @@ func createTestVolumes() []*v1.PersistentVolume {
|
|||
v1.ReadOnlyMany,
|
||||
},
|
||||
// this one we're pretending is already bound
|
||||
ClaimRef: &v1.ObjectReference{UID: "def456"},
|
||||
ClaimRef: &v1.ObjectReference{UID: "def456"},
|
||||
VolumeMode: &fs,
|
||||
},
|
||||
Status: v1.PersistentVolumeStatus{
|
||||
Phase: v1.VolumeBound,
|
||||
|
@ -503,6 +517,7 @@ func createTestVolumes() []*v1.PersistentVolume {
|
|||
v1.ReadOnlyMany,
|
||||
v1.ReadWriteMany,
|
||||
},
|
||||
VolumeMode: &fs,
|
||||
},
|
||||
Status: v1.PersistentVolumeStatus{
|
||||
Phase: v1.VolumeAvailable,
|
||||
|
@ -525,7 +540,8 @@ func createTestVolumes() []*v1.PersistentVolume {
|
|||
v1.ReadOnlyMany,
|
||||
},
|
||||
// this one we're pretending is already bound
|
||||
ClaimRef: &v1.ObjectReference{UID: "abc123"},
|
||||
ClaimRef: &v1.ObjectReference{UID: "abc123"},
|
||||
VolumeMode: &fs,
|
||||
},
|
||||
Status: v1.PersistentVolumeStatus{
|
||||
Phase: v1.VolumeBound,
|
||||
|
@ -548,6 +564,7 @@ func createTestVolumes() []*v1.PersistentVolume {
|
|||
v1.ReadOnlyMany,
|
||||
v1.ReadWriteMany,
|
||||
},
|
||||
VolumeMode: &fs,
|
||||
},
|
||||
Status: v1.PersistentVolumeStatus{
|
||||
Phase: v1.VolumeAvailable,
|
||||
|
@ -569,6 +586,7 @@ func createTestVolumes() []*v1.PersistentVolume {
|
|||
v1.ReadWriteOnce,
|
||||
v1.ReadOnlyMany,
|
||||
},
|
||||
VolumeMode: &fs,
|
||||
},
|
||||
Status: v1.PersistentVolumeStatus{
|
||||
Phase: v1.VolumeAvailable,
|
||||
|
@ -591,6 +609,7 @@ func createTestVolumes() []*v1.PersistentVolume {
|
|||
v1.ReadOnlyMany,
|
||||
v1.ReadWriteMany,
|
||||
},
|
||||
VolumeMode: &fs,
|
||||
},
|
||||
Status: v1.PersistentVolumeStatus{
|
||||
Phase: v1.VolumeAvailable,
|
||||
|
@ -614,6 +633,7 @@ func createTestVolumes() []*v1.PersistentVolume {
|
|||
AccessModes: []v1.PersistentVolumeAccessMode{
|
||||
v1.ReadWriteOnce,
|
||||
},
|
||||
VolumeMode: &fs,
|
||||
},
|
||||
Status: v1.PersistentVolumeStatus{
|
||||
Phase: v1.VolumeAvailable,
|
||||
|
@ -638,6 +658,7 @@ func createTestVolumes() []*v1.PersistentVolume {
|
|||
v1.ReadWriteOnce,
|
||||
},
|
||||
StorageClassName: classSilver,
|
||||
VolumeMode: &fs,
|
||||
},
|
||||
Status: v1.PersistentVolumeStatus{
|
||||
Phase: v1.VolumeAvailable,
|
||||
|
@ -659,6 +680,7 @@ func createTestVolumes() []*v1.PersistentVolume {
|
|||
v1.ReadWriteOnce,
|
||||
},
|
||||
StorageClassName: classSilver,
|
||||
VolumeMode: &fs,
|
||||
},
|
||||
Status: v1.PersistentVolumeStatus{
|
||||
Phase: v1.VolumeAvailable,
|
||||
|
@ -680,6 +702,7 @@ func createTestVolumes() []*v1.PersistentVolume {
|
|||
v1.ReadWriteOnce,
|
||||
},
|
||||
StorageClassName: classGold,
|
||||
VolumeMode: &fs,
|
||||
},
|
||||
Status: v1.PersistentVolumeStatus{
|
||||
Phase: v1.VolumeAvailable,
|
||||
|
@ -703,6 +726,7 @@ func createTestVolumes() []*v1.PersistentVolume {
|
|||
v1.ReadWriteMany,
|
||||
},
|
||||
StorageClassName: classLarge,
|
||||
VolumeMode: &fs,
|
||||
},
|
||||
Status: v1.PersistentVolumeStatus{
|
||||
Phase: v1.VolumeAvailable,
|
||||
|
@ -726,6 +750,7 @@ func createTestVolumes() []*v1.PersistentVolume {
|
|||
v1.ReadWriteMany,
|
||||
},
|
||||
StorageClassName: classLarge,
|
||||
VolumeMode: &fs,
|
||||
},
|
||||
Status: v1.PersistentVolumeStatus{
|
||||
Phase: v1.VolumeAvailable,
|
||||
|
@ -749,6 +774,7 @@ func createTestVolumes() []*v1.PersistentVolume {
|
|||
},
|
||||
StorageClassName: classWait,
|
||||
NodeAffinity: getVolumeNodeAffinity("key1", "value1"),
|
||||
VolumeMode: &fs,
|
||||
},
|
||||
Status: v1.PersistentVolumeStatus{
|
||||
Phase: v1.VolumeAvailable,
|
||||
|
@ -772,6 +798,7 @@ func createTestVolumes() []*v1.PersistentVolume {
|
|||
},
|
||||
StorageClassName: classWait,
|
||||
NodeAffinity: getVolumeNodeAffinity("key1", "value1"),
|
||||
VolumeMode: &fs,
|
||||
},
|
||||
Status: v1.PersistentVolumeStatus{
|
||||
Phase: v1.VolumeAvailable,
|
||||
|
@ -796,6 +823,7 @@ func createTestVolumes() []*v1.PersistentVolume {
|
|||
StorageClassName: classWait,
|
||||
ClaimRef: &v1.ObjectReference{Name: "claim02", Namespace: "myns"},
|
||||
NodeAffinity: getVolumeNodeAffinity("key1", "value1"),
|
||||
VolumeMode: &fs,
|
||||
},
|
||||
Status: v1.PersistentVolumeStatus{
|
||||
Phase: v1.VolumeAvailable,
|
||||
|
@ -819,6 +847,7 @@ func createTestVolumes() []*v1.PersistentVolume {
|
|||
},
|
||||
StorageClassName: classWait,
|
||||
NodeAffinity: getVolumeNodeAffinity("key1", "value3"),
|
||||
VolumeMode: &fs,
|
||||
},
|
||||
Status: v1.PersistentVolumeStatus{
|
||||
Phase: v1.VolumeAvailable,
|
||||
|
@ -842,6 +871,7 @@ func createTestVolumes() []*v1.PersistentVolume {
|
|||
},
|
||||
StorageClassName: classWait,
|
||||
NodeAffinity: getVolumeNodeAffinity("key1", "value4"),
|
||||
VolumeMode: &fs,
|
||||
},
|
||||
Status: v1.PersistentVolumeStatus{
|
||||
Phase: v1.VolumePending,
|
||||
|
@ -865,6 +895,7 @@ func createTestVolumes() []*v1.PersistentVolume {
|
|||
},
|
||||
StorageClassName: classWait,
|
||||
NodeAffinity: getVolumeNodeAffinity("key1", "value4"),
|
||||
VolumeMode: &fs,
|
||||
},
|
||||
Status: v1.PersistentVolumeStatus{
|
||||
Phase: v1.VolumeFailed,
|
||||
|
@ -888,6 +919,7 @@ func createTestVolumes() []*v1.PersistentVolume {
|
|||
},
|
||||
StorageClassName: classWait,
|
||||
NodeAffinity: getVolumeNodeAffinity("key1", "value4"),
|
||||
VolumeMode: &fs,
|
||||
},
|
||||
Status: v1.PersistentVolumeStatus{
|
||||
Phase: v1.VolumeReleased,
|
||||
|
@ -911,12 +943,14 @@ func createTestVolumes() []*v1.PersistentVolume {
|
|||
},
|
||||
StorageClassName: classWait,
|
||||
NodeAffinity: getVolumeNodeAffinity("key1", "value4"),
|
||||
VolumeMode: &fs,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func testVolume(name, size string) *v1.PersistentVolume {
|
||||
fs := v1.PersistentVolumeFilesystem
|
||||
return &v1.PersistentVolume{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: name,
|
||||
|
@ -926,6 +960,7 @@ func testVolume(name, size string) *v1.PersistentVolume {
|
|||
Capacity: v1.ResourceList{v1.ResourceName(v1.ResourceStorage): resource.MustParse(size)},
|
||||
PersistentVolumeSource: v1.PersistentVolumeSource{HostPath: &v1.HostPathVolumeSource{}},
|
||||
AccessModes: []v1.PersistentVolumeAccessMode{v1.ReadWriteOnce},
|
||||
VolumeMode: &fs,
|
||||
},
|
||||
Status: v1.PersistentVolumeStatus{
|
||||
Phase: v1.VolumeAvailable,
|
||||
|
@ -1003,34 +1038,36 @@ func createVolumeModeFilesystemTestVolume() *v1.PersistentVolume {
|
|||
}
|
||||
}
|
||||
|
||||
func createVolumeModeNilTestVolume() *v1.PersistentVolume {
|
||||
return &v1.PersistentVolume{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
UID: "local-1",
|
||||
Name: "nil-mode",
|
||||
},
|
||||
Spec: v1.PersistentVolumeSpec{
|
||||
Capacity: v1.ResourceList{
|
||||
v1.ResourceName(v1.ResourceStorage): resource.MustParse("10G"),
|
||||
},
|
||||
PersistentVolumeSource: v1.PersistentVolumeSource{
|
||||
Local: &v1.LocalVolumeSource{},
|
||||
},
|
||||
AccessModes: []v1.PersistentVolumeAccessMode{
|
||||
v1.ReadWriteOnce,
|
||||
},
|
||||
},
|
||||
Status: v1.PersistentVolumeStatus{
|
||||
Phase: v1.VolumeAvailable,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func createTestVolOrderedIndex(pv *v1.PersistentVolume) persistentVolumeOrderedIndex {
|
||||
volFile := newPersistentVolumeOrderedIndex()
|
||||
volFile.store.Add(pv)
|
||||
return volFile
|
||||
}
|
||||
|
||||
func toggleFeature(toggleFlag bool, featureName string, t *testing.T) {
|
||||
var valueStr string
|
||||
if toggleFlag {
|
||||
// Enable feature
|
||||
valueStr = featureName + "=true"
|
||||
err := utilfeature.DefaultFeatureGate.Set(valueStr)
|
||||
if err != nil {
|
||||
t.Errorf("Failed to enable feature gate for %s: %v", featureName, err)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
// Disable feature
|
||||
valueStr = featureName + "=false"
|
||||
err := utilfeature.DefaultFeatureGate.Set(valueStr)
|
||||
if err != nil {
|
||||
t.Errorf("Failed to disable feature gate for %s: %v", featureName, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestAlphaVolumeModeCheck(t *testing.T) {
|
||||
func TestVolumeModeCheck(t *testing.T) {
|
||||
|
||||
blockMode := v1.PersistentVolumeBlock
|
||||
filesystemMode := v1.PersistentVolumeFilesystem
|
||||
|
@ -1038,55 +1075,85 @@ func TestAlphaVolumeModeCheck(t *testing.T) {
|
|||
// If feature gate is enabled, VolumeMode will always be defaulted
|
||||
// If feature gate is disabled, VolumeMode is dropped by API and ignored
|
||||
scenarios := map[string]struct {
|
||||
isExpectedMisMatch bool
|
||||
isExpectedMismatch bool
|
||||
vol *v1.PersistentVolume
|
||||
pvc *v1.PersistentVolumeClaim
|
||||
enableBlock bool
|
||||
}{
|
||||
"feature enabled - pvc block and pv filesystem": {
|
||||
isExpectedMisMatch: true,
|
||||
isExpectedMismatch: true,
|
||||
vol: createVolumeModeFilesystemTestVolume(),
|
||||
pvc: makeVolumeModePVC("8G", &blockMode, nil),
|
||||
enableBlock: true,
|
||||
},
|
||||
"feature enabled - pvc filesystem and pv block": {
|
||||
isExpectedMisMatch: true,
|
||||
isExpectedMismatch: true,
|
||||
vol: createVolumeModeBlockTestVolume(),
|
||||
pvc: makeVolumeModePVC("8G", &filesystemMode, nil),
|
||||
enableBlock: true,
|
||||
},
|
||||
"feature enabled - pvc block and pv block": {
|
||||
isExpectedMisMatch: false,
|
||||
isExpectedMismatch: false,
|
||||
vol: createVolumeModeBlockTestVolume(),
|
||||
pvc: makeVolumeModePVC("8G", &blockMode, nil),
|
||||
enableBlock: true,
|
||||
},
|
||||
"feature enabled - pvc filesystem and pv filesystem": {
|
||||
isExpectedMisMatch: false,
|
||||
isExpectedMismatch: false,
|
||||
vol: createVolumeModeFilesystemTestVolume(),
|
||||
pvc: makeVolumeModePVC("8G", &filesystemMode, nil),
|
||||
enableBlock: true,
|
||||
},
|
||||
"feature enabled - pvc filesystem and pv nil": {
|
||||
isExpectedMismatch: false,
|
||||
vol: createVolumeModeNilTestVolume(),
|
||||
pvc: makeVolumeModePVC("8G", &filesystemMode, nil),
|
||||
enableBlock: true,
|
||||
},
|
||||
"feature enabled - pvc nil and pv filesytem": {
|
||||
isExpectedMismatch: false,
|
||||
vol: createVolumeModeFilesystemTestVolume(),
|
||||
pvc: makeVolumeModePVC("8G", nil, nil),
|
||||
enableBlock: true,
|
||||
},
|
||||
"feature enabled - pvc nil and pv nil": {
|
||||
isExpectedMismatch: false,
|
||||
vol: createVolumeModeNilTestVolume(),
|
||||
pvc: makeVolumeModePVC("8G", nil, nil),
|
||||
enableBlock: true,
|
||||
},
|
||||
"feature enabled - pvc nil and pv block": {
|
||||
isExpectedMismatch: true,
|
||||
vol: createVolumeModeBlockTestVolume(),
|
||||
pvc: makeVolumeModePVC("8G", nil, nil),
|
||||
enableBlock: true,
|
||||
},
|
||||
"feature enabled - pvc block and pv nil": {
|
||||
isExpectedMismatch: true,
|
||||
vol: createVolumeModeNilTestVolume(),
|
||||
pvc: makeVolumeModePVC("8G", &blockMode, nil),
|
||||
enableBlock: true,
|
||||
},
|
||||
"feature disabled - pvc block and pv filesystem": {
|
||||
isExpectedMisMatch: false,
|
||||
isExpectedMismatch: false,
|
||||
vol: createVolumeModeFilesystemTestVolume(),
|
||||
pvc: makeVolumeModePVC("8G", &blockMode, nil),
|
||||
enableBlock: false,
|
||||
},
|
||||
"feature disabled - pvc filesystem and pv block": {
|
||||
isExpectedMisMatch: false,
|
||||
isExpectedMismatch: false,
|
||||
vol: createVolumeModeBlockTestVolume(),
|
||||
pvc: makeVolumeModePVC("8G", &filesystemMode, nil),
|
||||
enableBlock: false,
|
||||
},
|
||||
"feature disabled - pvc block and pv block": {
|
||||
isExpectedMisMatch: false,
|
||||
isExpectedMismatch: false,
|
||||
vol: createVolumeModeBlockTestVolume(),
|
||||
pvc: makeVolumeModePVC("8G", &blockMode, nil),
|
||||
enableBlock: false,
|
||||
},
|
||||
"feature disabled - pvc filesystem and pv filesystem": {
|
||||
isExpectedMisMatch: false,
|
||||
isExpectedMismatch: false,
|
||||
vol: createVolumeModeFilesystemTestVolume(),
|
||||
pvc: makeVolumeModePVC("8G", &filesystemMode, nil),
|
||||
enableBlock: false,
|
||||
|
@ -1094,25 +1161,23 @@ func TestAlphaVolumeModeCheck(t *testing.T) {
|
|||
}
|
||||
|
||||
for name, scenario := range scenarios {
|
||||
toggleFeature(scenario.enableBlock, "BlockVolume", t)
|
||||
expectedMisMatch, err := checkVolumeModeMisMatches(&scenario.pvc.Spec, &scenario.vol.Spec)
|
||||
recover := utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.BlockVolume, scenario.enableBlock)
|
||||
expectedMismatch, err := checkVolumeModeMismatches(&scenario.pvc.Spec, &scenario.vol.Spec)
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected failure for checkVolumeModeMisMatches: %v", err)
|
||||
t.Errorf("Unexpected failure for checkVolumeModeMismatches: %v", err)
|
||||
}
|
||||
// expected to match but either got an error or no returned pvmatch
|
||||
if expectedMisMatch && !scenario.isExpectedMisMatch {
|
||||
if expectedMismatch && !scenario.isExpectedMismatch {
|
||||
t.Errorf("Unexpected failure for scenario, expected not to mismatch on modes but did: %s", name)
|
||||
}
|
||||
if !expectedMisMatch && scenario.isExpectedMisMatch {
|
||||
if !expectedMismatch && scenario.isExpectedMismatch {
|
||||
t.Errorf("Unexpected failure for scenario, did not mismatch on mode when expected to mismatch: %s", name)
|
||||
}
|
||||
recover()
|
||||
}
|
||||
|
||||
// make sure feature gate is turned off
|
||||
toggleFeature(false, "BlockVolume", t)
|
||||
}
|
||||
|
||||
func TestAlphaFilteringVolumeModes(t *testing.T) {
|
||||
func TestFilteringVolumeModes(t *testing.T) {
|
||||
blockMode := v1.PersistentVolumeBlock
|
||||
filesystemMode := v1.PersistentVolumeFilesystem
|
||||
|
||||
|
@ -1187,7 +1252,7 @@ func TestAlphaFilteringVolumeModes(t *testing.T) {
|
|||
}
|
||||
|
||||
for name, scenario := range scenarios {
|
||||
toggleFeature(scenario.enableBlock, "BlockVolume", t)
|
||||
recover := utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.BlockVolume, scenario.enableBlock)
|
||||
pvmatch, err := scenario.vol.findBestMatchForClaim(scenario.pvc, false)
|
||||
// expected to match but either got an error or no returned pvmatch
|
||||
if pvmatch == nil && scenario.isExpectedMatch {
|
||||
|
@ -1203,13 +1268,12 @@ func TestAlphaFilteringVolumeModes(t *testing.T) {
|
|||
if err != nil && !scenario.isExpectedMatch {
|
||||
t.Errorf("Unexpected failure for scenario: %s - %+v", name, err)
|
||||
}
|
||||
recover()
|
||||
}
|
||||
|
||||
// make sure feature gate is turned off
|
||||
toggleFeature(false, "BlockVolume", t)
|
||||
}
|
||||
|
||||
func TestStorageObjectInUseProtectionFiltering(t *testing.T) {
|
||||
fs := v1.PersistentVolumeFilesystem
|
||||
pv := &v1.PersistentVolume{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "pv1",
|
||||
|
@ -1219,6 +1283,7 @@ func TestStorageObjectInUseProtectionFiltering(t *testing.T) {
|
|||
Capacity: v1.ResourceList{v1.ResourceName(v1.ResourceStorage): resource.MustParse("1G")},
|
||||
PersistentVolumeSource: v1.PersistentVolumeSource{HostPath: &v1.HostPathVolumeSource{}},
|
||||
AccessModes: []v1.PersistentVolumeAccessMode{v1.ReadWriteOnce},
|
||||
VolumeMode: &fs,
|
||||
},
|
||||
Status: v1.PersistentVolumeStatus{
|
||||
Phase: v1.VolumeAvailable,
|
||||
|
@ -1237,6 +1302,7 @@ func TestStorageObjectInUseProtectionFiltering(t *testing.T) {
|
|||
Spec: v1.PersistentVolumeClaimSpec{
|
||||
AccessModes: []v1.PersistentVolumeAccessMode{v1.ReadWriteOnce},
|
||||
Resources: v1.ResourceRequirements{Requests: v1.ResourceList{v1.ResourceName(v1.ResourceStorage): resource.MustParse("1G")}},
|
||||
VolumeMode: &fs,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -1343,6 +1409,7 @@ func TestStorageObjectInUseProtectionFiltering(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestFindingPreboundVolumes(t *testing.T) {
|
||||
fs := v1.PersistentVolumeFilesystem
|
||||
claim := &v1.PersistentVolumeClaim{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "claim01",
|
||||
|
@ -1352,6 +1419,7 @@ func TestFindingPreboundVolumes(t *testing.T) {
|
|||
Spec: v1.PersistentVolumeClaimSpec{
|
||||
AccessModes: []v1.PersistentVolumeAccessMode{v1.ReadWriteOnce},
|
||||
Resources: v1.ResourceRequirements{Requests: v1.ResourceList{v1.ResourceName(v1.ResourceStorage): resource.MustParse("1Gi")}},
|
||||
VolumeMode: &fs,
|
||||
},
|
||||
}
|
||||
claimRef, err := ref.GetReference(scheme.Scheme, claim)
|
||||
|
|
|
@ -270,11 +270,11 @@ func checkVolumeSatisfyClaim(volume *v1.PersistentVolume, claim *v1.PersistentVo
|
|||
return fmt.Errorf("storageClassName does not match")
|
||||
}
|
||||
|
||||
isMisMatch, err := checkVolumeModeMisMatches(&claim.Spec, &volume.Spec)
|
||||
isMismatch, err := checkVolumeModeMismatches(&claim.Spec, &volume.Spec)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error checking volumeMode: %v", err)
|
||||
}
|
||||
if isMisMatch {
|
||||
if isMismatch {
|
||||
return fmt.Errorf("incompatible volumeMode")
|
||||
}
|
||||
|
||||
|
@ -613,7 +613,7 @@ func (ctrl *PersistentVolumeController) syncVolume(volume *v1.PersistentVolume)
|
|||
}
|
||||
return nil
|
||||
} else if claim.Spec.VolumeName == "" {
|
||||
if isMisMatch, err := checkVolumeModeMisMatches(&claim.Spec, &volume.Spec); err != nil || isMisMatch {
|
||||
if isMismatch, err := checkVolumeModeMismatches(&claim.Spec, &volume.Spec); err != nil || isMismatch {
|
||||
// Binding for the volume won't be called in syncUnboundClaim,
|
||||
// because findBestMatchForClaim won't return the volume due to volumeMode mismatch.
|
||||
volumeMsg := fmt.Sprintf("Cannot bind PersistentVolume to requested PersistentVolumeClaim %q due to incompatible volumeMode.", claim.Name)
|
||||
|
|
|
@ -426,6 +426,7 @@ const (
|
|||
)
|
||||
|
||||
func makeTestPVC(name, size, node string, pvcBoundState int, pvName, resourceVersion string, className *string) *v1.PersistentVolumeClaim {
|
||||
fs := v1.PersistentVolumeFilesystem
|
||||
pvc := &v1.PersistentVolumeClaim{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: "PersistentVolumeClaim",
|
||||
|
@ -445,6 +446,7 @@ func makeTestPVC(name, size, node string, pvcBoundState int, pvName, resourceVer
|
|||
},
|
||||
},
|
||||
StorageClassName: className,
|
||||
VolumeMode: &fs,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -462,6 +464,7 @@ func makeTestPVC(name, size, node string, pvcBoundState int, pvName, resourceVer
|
|||
}
|
||||
|
||||
func makeBadPVC() *v1.PersistentVolumeClaim {
|
||||
fs := v1.PersistentVolumeFilesystem
|
||||
return &v1.PersistentVolumeClaim{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "bad-pvc",
|
||||
|
@ -477,11 +480,13 @@ func makeBadPVC() *v1.PersistentVolumeClaim {
|
|||
},
|
||||
},
|
||||
StorageClassName: &waitClass,
|
||||
VolumeMode: &fs,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func makeTestPV(name, node, capacity, version string, boundToPVC *v1.PersistentVolumeClaim, className string) *v1.PersistentVolume {
|
||||
fs := v1.PersistentVolumeFilesystem
|
||||
pv := &v1.PersistentVolume{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: name,
|
||||
|
@ -492,6 +497,7 @@ func makeTestPV(name, node, capacity, version string, boundToPVC *v1.PersistentV
|
|||
v1.ResourceName(v1.ResourceStorage): resource.MustParse(capacity),
|
||||
},
|
||||
StorageClassName: className,
|
||||
VolumeMode: &fs,
|
||||
},
|
||||
Status: v1.PersistentVolumeStatus{
|
||||
Phase: v1.VolumeAvailable,
|
||||
|
|
|
@ -217,6 +217,7 @@ const (
|
|||
|
||||
// owner: @screeley44
|
||||
// alpha: v1.9
|
||||
// beta: v1.13
|
||||
//
|
||||
// Enable Block volume support in containers.
|
||||
BlockVolume utilfeature.Feature = "BlockVolume"
|
||||
|
@ -433,7 +434,7 @@ var defaultKubernetesFeatureGates = map[utilfeature.Feature]utilfeature.FeatureS
|
|||
CSIDriverRegistry: {Default: false, PreRelease: utilfeature.Alpha},
|
||||
CSINodeInfo: {Default: false, PreRelease: utilfeature.Alpha},
|
||||
CustomPodDNS: {Default: true, PreRelease: utilfeature.Beta},
|
||||
BlockVolume: {Default: false, PreRelease: utilfeature.Alpha},
|
||||
BlockVolume: {Default: true, PreRelease: utilfeature.Beta},
|
||||
StorageObjectInUseProtection: {Default: true, PreRelease: utilfeature.GA},
|
||||
ResourceLimitsPriorityFunction: {Default: false, PreRelease: utilfeature.Alpha},
|
||||
SupportIPVSProxyMode: {Default: true, PreRelease: utilfeature.GA},
|
||||
|
|
|
@ -46,12 +46,14 @@ import (
|
|||
|
||||
func TestFindAndAddNewPods_FindAndRemoveDeletedPods(t *testing.T) {
|
||||
// create dswp
|
||||
mode := v1.PersistentVolumeFilesystem
|
||||
pv := &v1.PersistentVolume{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "dswp-test-volume-name",
|
||||
},
|
||||
Spec: v1.PersistentVolumeSpec{
|
||||
ClaimRef: &v1.ObjectReference{Namespace: "ns", Name: "file-bound"},
|
||||
ClaimRef: &v1.ObjectReference{Namespace: "ns", Name: "file-bound"},
|
||||
VolumeMode: &mode,
|
||||
},
|
||||
}
|
||||
pvc := &v1.PersistentVolumeClaim{
|
||||
|
@ -453,6 +455,7 @@ func TestCreateVolumeSpec_Invalid_Block_VolumeMounts(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestCheckVolumeFSResize(t *testing.T) {
|
||||
mode := v1.PersistentVolumeFilesystem
|
||||
pv := &v1.PersistentVolume{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "dswp-test-volume-name",
|
||||
|
@ -461,6 +464,7 @@ func TestCheckVolumeFSResize(t *testing.T) {
|
|||
PersistentVolumeSource: v1.PersistentVolumeSource{RBD: &v1.RBDPersistentVolumeSource{}},
|
||||
Capacity: volumeCapacity(1),
|
||||
ClaimRef: &v1.ObjectReference{Namespace: "ns", Name: "file-bound"},
|
||||
VolumeMode: &mode,
|
||||
},
|
||||
}
|
||||
pvc := &v1.PersistentVolumeClaim{
|
||||
|
|
|
@ -950,13 +950,15 @@ func Test_GenerateUnmapDeviceFunc_Plugin_Not_Found(t *testing.T) {
|
|||
func Test_Run_Positive_VolumeFSResizeControllerAttachEnabled(t *testing.T) {
|
||||
defer utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.ExpandInUsePersistentVolumes, true)()
|
||||
|
||||
fs := v1.PersistentVolumeFilesystem
|
||||
pv := &v1.PersistentVolume{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "pv",
|
||||
UID: "pvuid",
|
||||
},
|
||||
Spec: v1.PersistentVolumeSpec{
|
||||
ClaimRef: &v1.ObjectReference{Name: "pvc"},
|
||||
ClaimRef: &v1.ObjectReference{Name: "pvc"},
|
||||
VolumeMode: &fs,
|
||||
},
|
||||
}
|
||||
pvc := &v1.PersistentVolumeClaim{
|
||||
|
@ -966,6 +968,7 @@ func Test_Run_Positive_VolumeFSResizeControllerAttachEnabled(t *testing.T) {
|
|||
},
|
||||
Spec: v1.PersistentVolumeClaimSpec{
|
||||
VolumeName: "pv",
|
||||
VolumeMode: &fs,
|
||||
},
|
||||
}
|
||||
pod := &v1.Pod{
|
||||
|
|
|
@ -167,6 +167,7 @@ func TestGetExtraSupplementalGroupsForPod(t *testing.T) {
|
|||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
fs := v1.PersistentVolumeFilesystem
|
||||
pv := &v1.PersistentVolume{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "pvA",
|
||||
|
@ -183,6 +184,7 @@ func TestGetExtraSupplementalGroupsForPod(t *testing.T) {
|
|||
ClaimRef: &v1.ObjectReference{
|
||||
Name: claim.ObjectMeta.Name,
|
||||
},
|
||||
VolumeMode: &fs,
|
||||
},
|
||||
}
|
||||
kubeClient := fake.NewSimpleClientset(node, pod, pv, claim)
|
||||
|
@ -273,6 +275,7 @@ func createObjects() (*v1.Node, *v1.Pod, *v1.PersistentVolume, *v1.PersistentVol
|
|||
},
|
||||
},
|
||||
}
|
||||
fs := v1.PersistentVolumeFilesystem
|
||||
pv := &v1.PersistentVolume{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "pvA",
|
||||
|
@ -286,6 +289,7 @@ func createObjects() (*v1.Node, *v1.Pod, *v1.PersistentVolume, *v1.PersistentVol
|
|||
ClaimRef: &v1.ObjectReference{
|
||||
Name: "claimA",
|
||||
},
|
||||
VolumeMode: &fs,
|
||||
},
|
||||
}
|
||||
claim := &v1.PersistentVolumeClaim{
|
||||
|
|
|
@ -254,6 +254,7 @@ func TestPluginVolume(t *testing.T) {
|
|||
|
||||
func TestPluginPersistentVolume(t *testing.T) {
|
||||
lun := int32(0)
|
||||
fs := v1.PersistentVolumeFilesystem
|
||||
vol := &v1.PersistentVolume{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "vol1",
|
||||
|
@ -266,6 +267,7 @@ func TestPluginPersistentVolume(t *testing.T) {
|
|||
Lun: &lun,
|
||||
},
|
||||
},
|
||||
VolumeMode: &fs,
|
||||
},
|
||||
}
|
||||
doTestPlugin(t, volume.NewSpecFromPersistentVolume(vol, false))
|
||||
|
@ -285,6 +287,7 @@ func TestPluginVolumeWWIDs(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestPluginPersistentVolumeWWIDs(t *testing.T) {
|
||||
fs := v1.PersistentVolumeFilesystem
|
||||
vol := &v1.PersistentVolume{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "vol1",
|
||||
|
@ -296,6 +299,7 @@ func TestPluginPersistentVolumeWWIDs(t *testing.T) {
|
|||
FSType: "ext4",
|
||||
},
|
||||
},
|
||||
VolumeMode: &fs,
|
||||
},
|
||||
}
|
||||
doTestPlugin(t, volume.NewSpecFromPersistentVolume(vol, false))
|
||||
|
@ -314,6 +318,7 @@ func TestPluginVolumeNoDiskInfo(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestPluginPersistentVolumeNoDiskInfo(t *testing.T) {
|
||||
fs := v1.PersistentVolumeFilesystem
|
||||
vol := &v1.PersistentVolume{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "vol1",
|
||||
|
@ -324,6 +329,7 @@ func TestPluginPersistentVolumeNoDiskInfo(t *testing.T) {
|
|||
FSType: "ext4",
|
||||
},
|
||||
},
|
||||
VolumeMode: &fs,
|
||||
},
|
||||
}
|
||||
doTestPluginNilMounter(t, volume.NewSpecFromPersistentVolume(vol, false))
|
||||
|
@ -337,6 +343,7 @@ func TestPersistentClaimReadOnlyFlag(t *testing.T) {
|
|||
defer os.RemoveAll(tmpDir)
|
||||
|
||||
lun := int32(0)
|
||||
fs := v1.PersistentVolumeFilesystem
|
||||
pv := &v1.PersistentVolume{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "pvA",
|
||||
|
@ -352,6 +359,7 @@ func TestPersistentClaimReadOnlyFlag(t *testing.T) {
|
|||
ClaimRef: &v1.ObjectReference{
|
||||
Name: "claimA",
|
||||
},
|
||||
VolumeMode: &fs,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -362,6 +370,7 @@ func TestPersistentClaimReadOnlyFlag(t *testing.T) {
|
|||
},
|
||||
Spec: v1.PersistentVolumeClaimSpec{
|
||||
VolumeName: "pvA",
|
||||
VolumeMode: &fs,
|
||||
},
|
||||
Status: v1.PersistentVolumeClaimStatus{
|
||||
Phase: v1.ClaimBound,
|
||||
|
|
|
@ -641,7 +641,7 @@ message Container {
|
|||
repeated VolumeMount volumeMounts = 9;
|
||||
|
||||
// volumeDevices is the list of block devices to be used by the container.
|
||||
// This is an alpha feature and may change in the future.
|
||||
// This is a beta feature.
|
||||
// +patchMergeKey=devicePath
|
||||
// +patchStrategy=merge
|
||||
// +optional
|
||||
|
@ -2320,7 +2320,7 @@ message PersistentVolumeClaimSpec {
|
|||
|
||||
// volumeMode defines what type of volume is required by the claim.
|
||||
// Value of Filesystem is implied when not included in claim spec.
|
||||
// This is an alpha feature and may change in the future.
|
||||
// This is a beta feature.
|
||||
// +optional
|
||||
optional string volumeMode = 6;
|
||||
|
||||
|
@ -2536,7 +2536,7 @@ message PersistentVolumeSpec {
|
|||
|
||||
// volumeMode defines if a volume is intended to be used with a formatted filesystem
|
||||
// or to remain in raw block state. Value of Filesystem is implied when not included in spec.
|
||||
// This is an alpha feature and may change in the future.
|
||||
// This is a beta feature.
|
||||
// +optional
|
||||
optional string volumeMode = 8;
|
||||
|
||||
|
|
|
@ -326,7 +326,7 @@ type PersistentVolumeSpec struct {
|
|||
MountOptions []string `json:"mountOptions,omitempty" protobuf:"bytes,7,opt,name=mountOptions"`
|
||||
// volumeMode defines if a volume is intended to be used with a formatted filesystem
|
||||
// or to remain in raw block state. Value of Filesystem is implied when not included in spec.
|
||||
// This is an alpha feature and may change in the future.
|
||||
// This is a beta feature.
|
||||
// +optional
|
||||
VolumeMode *PersistentVolumeMode `json:"volumeMode,omitempty" protobuf:"bytes,8,opt,name=volumeMode,casttype=PersistentVolumeMode"`
|
||||
// NodeAffinity defines constraints that limit what nodes this volume can be accessed from.
|
||||
|
@ -455,7 +455,7 @@ type PersistentVolumeClaimSpec struct {
|
|||
StorageClassName *string `json:"storageClassName,omitempty" protobuf:"bytes,5,opt,name=storageClassName"`
|
||||
// volumeMode defines what type of volume is required by the claim.
|
||||
// Value of Filesystem is implied when not included in claim spec.
|
||||
// This is an alpha feature and may change in the future.
|
||||
// This is a beta feature.
|
||||
// +optional
|
||||
VolumeMode *PersistentVolumeMode `json:"volumeMode,omitempty" protobuf:"bytes,6,opt,name=volumeMode,casttype=PersistentVolumeMode"`
|
||||
// This field requires the VolumeSnapshotDataSource alpha feature gate to be
|
||||
|
@ -2114,7 +2114,7 @@ type Container struct {
|
|||
// +patchStrategy=merge
|
||||
VolumeMounts []VolumeMount `json:"volumeMounts,omitempty" patchStrategy:"merge" patchMergeKey:"mountPath" protobuf:"bytes,9,rep,name=volumeMounts"`
|
||||
// volumeDevices is the list of block devices to be used by the container.
|
||||
// This is an alpha feature and may change in the future.
|
||||
// This is a beta feature.
|
||||
// +patchMergeKey=devicePath
|
||||
// +patchStrategy=merge
|
||||
// +optional
|
||||
|
|
|
@ -321,7 +321,7 @@ var map_Container = map[string]string{
|
|||
"env": "List of environment variables to set in the container. Cannot be updated.",
|
||||
"resources": "Compute Resources required by this container. Cannot be updated. More info: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/",
|
||||
"volumeMounts": "Pod volumes to mount into the container's filesystem. Cannot be updated.",
|
||||
"volumeDevices": "volumeDevices is the list of block devices to be used by the container. This is an alpha feature and may change in the future.",
|
||||
"volumeDevices": "volumeDevices is the list of block devices to be used by the container. This is a beta feature.",
|
||||
"livenessProbe": "Periodic probe of container liveness. Container will be restarted if the probe fails. Cannot be updated. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes",
|
||||
"readinessProbe": "Periodic probe of container service readiness. Container will be removed from service endpoints if the probe fails. Cannot be updated. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes",
|
||||
"lifecycle": "Actions that the management system should take in response to container lifecycle events. Cannot be updated.",
|
||||
|
@ -1222,7 +1222,7 @@ var map_PersistentVolumeClaimSpec = map[string]string{
|
|||
"resources": "Resources represents the minimum resources the volume should have. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#resources",
|
||||
"volumeName": "VolumeName is the binding reference to the PersistentVolume backing this claim.",
|
||||
"storageClassName": "Name of the StorageClass required by the claim. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1",
|
||||
"volumeMode": "volumeMode defines what type of volume is required by the claim. Value of Filesystem is implied when not included in claim spec. This is an alpha feature and may change in the future.",
|
||||
"volumeMode": "volumeMode defines what type of volume is required by the claim. Value of Filesystem is implied when not included in claim spec. This is a beta feature.",
|
||||
"dataSource": "This field requires the VolumeSnapshotDataSource alpha feature gate to be enabled and currently VolumeSnapshot is the only supported data source. If the provisioner can support VolumeSnapshot data source, it will create a new volume and data will be restored to the volume at the same time. If the provisioner does not support VolumeSnapshot data source, volume will not be created and the failure will be reported as an event. In the future, we plan to support more data source types and the behavior of the provisioner may change.",
|
||||
}
|
||||
|
||||
|
@ -1300,7 +1300,7 @@ var map_PersistentVolumeSpec = map[string]string{
|
|||
"persistentVolumeReclaimPolicy": "What happens to a persistent volume when released from its claim. Valid options are Retain (default for manually created PersistentVolumes), Delete (default for dynamically provisioned PersistentVolumes), and Recycle (deprecated). Recycle must be supported by the volume plugin underlying this PersistentVolume. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#reclaiming",
|
||||
"storageClassName": "Name of StorageClass to which this persistent volume belongs. Empty value means that this volume does not belong to any StorageClass.",
|
||||
"mountOptions": "A list of mount options, e.g. [\"ro\", \"soft\"]. Not validated - mount will simply fail if one is invalid. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes/#mount-options",
|
||||
"volumeMode": "volumeMode defines if a volume is intended to be used with a formatted filesystem or to remain in raw block state. Value of Filesystem is implied when not included in spec. This is an alpha feature and may change in the future.",
|
||||
"volumeMode": "volumeMode defines if a volume is intended to be used with a formatted filesystem or to remain in raw block state. Value of Filesystem is implied when not included in spec. This is a beta feature.",
|
||||
"nodeAffinity": "NodeAffinity defines constraints that limit what nodes this volume can be accessed from. This field influences the scheduling of pods that use this volume.",
|
||||
}
|
||||
|
||||
|
|
|
@ -58,6 +58,7 @@ var upgradeTests = []upgrades.Test{
|
|||
&apps.DaemonSetUpgradeTest{},
|
||||
&upgrades.IngressUpgradeTest{},
|
||||
&upgrades.AppArmorUpgradeTest{},
|
||||
&storage.VolumeModeDowngradeTest{},
|
||||
}
|
||||
|
||||
var gpuUpgradeTests = []upgrades.Test{
|
||||
|
|
|
@ -218,11 +218,7 @@ var _ = utils.SIGDescribe("PersistentVolumes-local ", func() {
|
|||
if testVolType == GCELocalSSDVolumeType {
|
||||
serialStr = " [Serial]"
|
||||
}
|
||||
alphaStr := ""
|
||||
if testVolType == BlockLocalVolumeType {
|
||||
alphaStr = " [Feature:BlockVolume]"
|
||||
}
|
||||
ctxString := fmt.Sprintf("[Volume type: %s]%v%v", testVolType, serialStr, alphaStr)
|
||||
ctxString := fmt.Sprintf("[Volume type: %s]%v", testVolType, serialStr)
|
||||
testMode := immediateMode
|
||||
|
||||
Context(ctxString, func() {
|
||||
|
|
|
@ -186,7 +186,7 @@ func testProvisioning(input *provisioningTestInput) {
|
|||
TestDynamicProvisioning(input.testCase, input.cs, input.pvc, input.sc)
|
||||
})
|
||||
|
||||
It("should create and delete block persistent volumes [Feature:BlockVolume]", func() {
|
||||
It("should create and delete block persistent volumes", func() {
|
||||
if !input.dInfo.IsBlockSupported {
|
||||
framework.Skipf("Driver %q does not support BlockVolume - skipping", input.dInfo.Name)
|
||||
}
|
||||
|
|
|
@ -47,8 +47,7 @@ var _ TestSuite = &volumeModeTestSuite{}
|
|||
func InitVolumeModeTestSuite() TestSuite {
|
||||
return &volumeModeTestSuite{
|
||||
tsInfo: TestSuiteInfo{
|
||||
name: "volumeMode",
|
||||
featureTag: "[Feature:BlockVolume]",
|
||||
name: "volumeMode",
|
||||
testPatterns: []testpatterns.TestPattern{
|
||||
testpatterns.FsVolModePreprovisionedPV,
|
||||
testpatterns.FsVolModeDynamicPV,
|
||||
|
@ -304,10 +303,10 @@ func testVolumeModeSuccessForPreprovisionedPV(input *volumeModeTestInput) {
|
|||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
By("Checking if persistent volume exists as expected volume mode")
|
||||
checkVolumeModeOfPath(pod, input.volMode, "/mnt/volume1")
|
||||
utils.CheckVolumeModeOfPath(pod, input.volMode, "/mnt/volume1")
|
||||
|
||||
By("Checking if read/write to persistent volume works properly")
|
||||
checkReadWriteToPath(pod, input.volMode, "/mnt/volume1")
|
||||
utils.CheckReadWriteToPath(pod, input.volMode, "/mnt/volume1")
|
||||
})
|
||||
// TODO(mkimuram): Add more tests
|
||||
}
|
||||
|
@ -366,10 +365,10 @@ func testVolumeModeSuccessForDynamicPV(input *volumeModeTestInput) {
|
|||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
By("Checking if persistent volume exists as expected volume mode")
|
||||
checkVolumeModeOfPath(pod, input.volMode, "/mnt/volume1")
|
||||
utils.CheckVolumeModeOfPath(pod, input.volMode, "/mnt/volume1")
|
||||
|
||||
By("Checking if read/write to persistent volume works properly")
|
||||
checkReadWriteToPath(pod, input.volMode, "/mnt/volume1")
|
||||
utils.CheckReadWriteToPath(pod, input.volMode, "/mnt/volume1")
|
||||
})
|
||||
// TODO(mkimuram): Add more tests
|
||||
}
|
||||
|
@ -401,45 +400,3 @@ func generateConfigsForPreprovisionedPVTest(scName string, volBindMode storagev1
|
|||
|
||||
return scConfig, pvConfig, pvcConfig
|
||||
}
|
||||
|
||||
func checkVolumeModeOfPath(pod *v1.Pod, volMode v1.PersistentVolumeMode, path string) {
|
||||
if volMode == v1.PersistentVolumeBlock {
|
||||
// Check if block exists
|
||||
utils.VerifyExecInPodSucceed(pod, fmt.Sprintf("test -b %s", path))
|
||||
|
||||
// Double check that it's not directory
|
||||
utils.VerifyExecInPodFail(pod, fmt.Sprintf("test -d %s", path), 1)
|
||||
} else {
|
||||
// Check if directory exists
|
||||
utils.VerifyExecInPodSucceed(pod, fmt.Sprintf("test -d %s", path))
|
||||
|
||||
// Double check that it's not block
|
||||
utils.VerifyExecInPodFail(pod, fmt.Sprintf("test -b %s", path), 1)
|
||||
}
|
||||
}
|
||||
|
||||
func checkReadWriteToPath(pod *v1.Pod, volMode v1.PersistentVolumeMode, path string) {
|
||||
if volMode == v1.PersistentVolumeBlock {
|
||||
// random -> file1
|
||||
utils.VerifyExecInPodSucceed(pod, "dd if=/dev/urandom of=/tmp/file1 bs=64 count=1")
|
||||
// file1 -> dev (write to dev)
|
||||
utils.VerifyExecInPodSucceed(pod, fmt.Sprintf("dd if=/tmp/file1 of=%s bs=64 count=1", path))
|
||||
// dev -> file2 (read from dev)
|
||||
utils.VerifyExecInPodSucceed(pod, fmt.Sprintf("dd if=%s of=/tmp/file2 bs=64 count=1", path))
|
||||
// file1 == file2 (check contents)
|
||||
utils.VerifyExecInPodSucceed(pod, "diff /tmp/file1 /tmp/file2")
|
||||
// Clean up temp files
|
||||
utils.VerifyExecInPodSucceed(pod, "rm -f /tmp/file1 /tmp/file2")
|
||||
|
||||
// Check that writing file to block volume fails
|
||||
utils.VerifyExecInPodFail(pod, fmt.Sprintf("echo 'Hello world.' > %s/file1.txt", path), 1)
|
||||
} else {
|
||||
// text -> file1 (write to file)
|
||||
utils.VerifyExecInPodSucceed(pod, fmt.Sprintf("echo 'Hello world.' > %s/file1.txt", path))
|
||||
// grep file1 (read from file and check contents)
|
||||
utils.VerifyExecInPodSucceed(pod, fmt.Sprintf("grep 'Hello world.' %s/file1.txt", path))
|
||||
|
||||
// Check that writing to directory as block volume fails
|
||||
utils.VerifyExecInPodFail(pod, fmt.Sprintf("dd if=/dev/urandom of=%s bs=64 count=1", path), 1)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -441,3 +441,45 @@ func PrivilegedTestPSPClusterRoleBinding(client clientset.Interface,
|
|||
|
||||
}
|
||||
}
|
||||
|
||||
func CheckVolumeModeOfPath(pod *v1.Pod, volMode v1.PersistentVolumeMode, path string) {
|
||||
if volMode == v1.PersistentVolumeBlock {
|
||||
// Check if block exists
|
||||
VerifyExecInPodSucceed(pod, fmt.Sprintf("test -b %s", path))
|
||||
|
||||
// Double check that it's not directory
|
||||
VerifyExecInPodFail(pod, fmt.Sprintf("test -d %s", path), 1)
|
||||
} else {
|
||||
// Check if directory exists
|
||||
VerifyExecInPodSucceed(pod, fmt.Sprintf("test -d %s", path))
|
||||
|
||||
// Double check that it's not block
|
||||
VerifyExecInPodFail(pod, fmt.Sprintf("test -b %s", path), 1)
|
||||
}
|
||||
}
|
||||
|
||||
func CheckReadWriteToPath(pod *v1.Pod, volMode v1.PersistentVolumeMode, path string) {
|
||||
if volMode == v1.PersistentVolumeBlock {
|
||||
// random -> file1
|
||||
VerifyExecInPodSucceed(pod, "dd if=/dev/urandom of=/tmp/file1 bs=64 count=1")
|
||||
// file1 -> dev (write to dev)
|
||||
VerifyExecInPodSucceed(pod, fmt.Sprintf("dd if=/tmp/file1 of=%s bs=64 count=1", path))
|
||||
// dev -> file2 (read from dev)
|
||||
VerifyExecInPodSucceed(pod, fmt.Sprintf("dd if=%s of=/tmp/file2 bs=64 count=1", path))
|
||||
// file1 == file2 (check contents)
|
||||
VerifyExecInPodSucceed(pod, "diff /tmp/file1 /tmp/file2")
|
||||
// Clean up temp files
|
||||
VerifyExecInPodSucceed(pod, "rm -f /tmp/file1 /tmp/file2")
|
||||
|
||||
// Check that writing file to block volume fails
|
||||
VerifyExecInPodFail(pod, fmt.Sprintf("echo 'Hello world.' > %s/file1.txt", path), 1)
|
||||
} else {
|
||||
// text -> file1 (write to file)
|
||||
VerifyExecInPodSucceed(pod, fmt.Sprintf("echo 'Hello world.' > %s/file1.txt", path))
|
||||
// grep file1 (read from file and check contents)
|
||||
VerifyExecInPodSucceed(pod, fmt.Sprintf("grep 'Hello world.' %s/file1.txt", path))
|
||||
|
||||
// Check that writing to directory as block volume fails
|
||||
VerifyExecInPodFail(pod, fmt.Sprintf("dd if=/dev/urandom of=%s bs=64 count=1", path), 1)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,12 +7,18 @@ load(
|
|||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["persistent_volumes.go"],
|
||||
srcs = [
|
||||
"persistent_volumes.go",
|
||||
"volume_mode.go",
|
||||
],
|
||||
importpath = "k8s.io/kubernetes/test/e2e/upgrades/storage",
|
||||
deps = [
|
||||
"//staging/src/k8s.io/api/core/v1:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/util/errors:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/util/version:go_default_library",
|
||||
"//test/e2e/framework:go_default_library",
|
||||
"//test/e2e/storage/utils:go_default_library",
|
||||
"//test/e2e/upgrades:go_default_library",
|
||||
"//vendor/github.com/onsi/ginkgo:go_default_library",
|
||||
"//vendor/github.com/onsi/gomega:go_default_library",
|
||||
|
|
|
@ -0,0 +1,125 @@
|
|||
/*
|
||||
Copyright 2018 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package storage
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/util/version"
|
||||
"k8s.io/kubernetes/test/e2e/framework"
|
||||
"k8s.io/kubernetes/test/e2e/storage/utils"
|
||||
"k8s.io/kubernetes/test/e2e/upgrades"
|
||||
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
const devicePath = "/mnt/volume1"
|
||||
|
||||
// VolumeModeDowngradeTest tests that a VolumeMode Block PV is not mistakenly
|
||||
// formatted and mounted like a nil/Filesystem PV after a downgrade to a version
|
||||
// where the BlockVolume feature is disabled
|
||||
type VolumeModeDowngradeTest struct {
|
||||
pvSource *v1.PersistentVolumeSource
|
||||
pv *v1.PersistentVolume
|
||||
pvc *v1.PersistentVolumeClaim
|
||||
pod *v1.Pod
|
||||
}
|
||||
|
||||
func (VolumeModeDowngradeTest) Name() string {
|
||||
return "[sig-storage] volume-mode-downgrade"
|
||||
}
|
||||
|
||||
func (t *VolumeModeDowngradeTest) Skip(upgCtx upgrades.UpgradeContext) bool {
|
||||
if !framework.ProviderIs("openstack", "gce", "aws", "gke", "vsphere", "azure") {
|
||||
return true
|
||||
}
|
||||
|
||||
// Only run when downgrading from >= 1.13 to < 1.13
|
||||
blockVersion := version.MustParseSemantic("1.13.0-alpha.0")
|
||||
if upgCtx.Versions[0].Version.LessThan(blockVersion) {
|
||||
return true
|
||||
}
|
||||
if !upgCtx.Versions[1].Version.LessThan(blockVersion) {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// Setup creates a block pv and then verifies that a pod can consume it. The pod writes data to the volume.
|
||||
func (t *VolumeModeDowngradeTest) Setup(f *framework.Framework) {
|
||||
|
||||
var err error
|
||||
|
||||
cs := f.ClientSet
|
||||
ns := f.Namespace.Name
|
||||
|
||||
By("Creating a PVC")
|
||||
block := v1.PersistentVolumeBlock
|
||||
pvcConfig := framework.PersistentVolumeClaimConfig{
|
||||
StorageClassName: nil,
|
||||
VolumeMode: &block,
|
||||
}
|
||||
t.pvc = framework.MakePersistentVolumeClaim(pvcConfig, ns)
|
||||
t.pvc, err = framework.CreatePVC(cs, ns, t.pvc)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
err = framework.WaitForPersistentVolumeClaimPhase(v1.ClaimBound, cs, ns, t.pvc.Name, framework.Poll, framework.ClaimProvisionTimeout)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
t.pvc, err = cs.CoreV1().PersistentVolumeClaims(t.pvc.Namespace).Get(t.pvc.Name, metav1.GetOptions{})
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
t.pv, err = cs.CoreV1().PersistentVolumes().Get(t.pvc.Spec.VolumeName, metav1.GetOptions{})
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
By("Consuming the PVC before downgrade")
|
||||
t.pod, err = framework.CreateSecPod(cs, ns, []*v1.PersistentVolumeClaim{t.pvc}, false, "", false, false, framework.SELinuxLabel, nil, framework.PodStartTimeout)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
By("Checking if PV exists as expected volume mode")
|
||||
utils.CheckVolumeModeOfPath(t.pod, block, devicePath)
|
||||
|
||||
By("Checking if read/write to PV works properly")
|
||||
utils.CheckReadWriteToPath(t.pod, block, devicePath)
|
||||
}
|
||||
|
||||
// Test waits for the downgrade to complete, and then verifies that a pod can no
|
||||
// longer consume the pv as it is not mapped nor mounted into the pod
|
||||
func (t *VolumeModeDowngradeTest) Test(f *framework.Framework, done <-chan struct{}, upgrade upgrades.UpgradeType) {
|
||||
By("Waiting for downgrade to finish")
|
||||
<-done
|
||||
|
||||
By("Verifying that nothing exists at the device path in the pod")
|
||||
utils.VerifyExecInPodFail(t.pod, fmt.Sprintf("test -e %s", devicePath), 1)
|
||||
}
|
||||
|
||||
// Teardown cleans up any remaining resources.
|
||||
func (t *VolumeModeDowngradeTest) Teardown(f *framework.Framework) {
|
||||
By("Deleting the pod")
|
||||
framework.ExpectNoError(framework.DeletePodWithWait(f, f.ClientSet, t.pod))
|
||||
|
||||
By("Deleting the PVC")
|
||||
framework.ExpectNoError(f.ClientSet.CoreV1().PersistentVolumeClaims(t.pvc.Namespace).Delete(t.pvc.Name, nil))
|
||||
|
||||
By("Waiting for the PV to be deleted")
|
||||
framework.ExpectNoError(framework.WaitForPersistentVolumeDeleted(f.ClientSet, t.pv.Name, 5*time.Second, 20*time.Minute))
|
||||
}
|
Loading…
Reference in New Issue