Implement KEP 4876 Mutable CSINode (#130007)

* Implement KEP-4876 Mutable CSINode Allocatable Count

Signed-off-by: torredil <torredil@amazon.com>

* Update TestGetNodeAllocatableUpdatePeriod

Signed-off-by: torredil <torredil@amazon.com>

* Implement CSINodeUpdater

Signed-off-by: torredil <torredil@amazon.com>

* Use sync.Once in csiNodeUpdater

Signed-off-by: torredil <torredil@amazon.com>

* ImVerify driver is installed before running periodic updates

Signed-off-by: torredil <torredil@amazon.com>

* Update NodeAllocatableUpdatePeriodSeconds type comment

Signed-off-by: torredil <torredil@amazon.com>

* Leverage apivalidation.ValidateImmutableField in ValidateCSINodeUpdate

Signed-off-by: torredil <torredil@amazon.com>

* Update strategy functions

Signed-off-by: torredil <torredil@amazon.com>

* Run hack/update-openapi-spec.sh

Signed-off-by: torredil <torredil@amazon.com>

* Update VolumeError.ErrorCode field

Signed-off-by: torredil <torredil@amazon.com>

* CSINodeUpdater improvements

Signed-off-by: torredil <torredil@amazon.com>

* Iron out concurrency in syncDriverUpdater

Signed-off-by: torredil <torredil@amazon.com>

* Run hack/update-openapi-spec.sh

Signed-off-by: torredil <torredil@amazon.com>

* Revise logging

Signed-off-by: torredil <torredil@amazon.com>

* Revise log in VerifyExhaustedResource

Signed-off-by: torredil <torredil@amazon.com>

* Update API validation

Signed-off-by: torredil <torredil@amazon.com>

* Add more code coverage

Signed-off-by: torredil <torredil@amazon.com>

* Fix pull-kubernetes-linter-hints

Signed-off-by: torredil <torredil@amazon.com>

* Update API types documentation

Signed-off-by: torredil <torredil@amazon.com>

* Update strategy and validation for new errorCode field

Signed-off-by: torredil <torredil@amazon.com>

* Update validation tests after strategy changes

Signed-off-by: torredil <torredil@amazon.com>

* Update VA status strategy

Signed-off-by: torredil <torredil@amazon.com>

---------

Signed-off-by: torredil <torredil@amazon.com>
This commit is contained in:
Eddie Torres 2025-03-18 15:45:49 -04:00 committed by GitHub
parent 55573a0739
commit c766a52356
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
67 changed files with 2100 additions and 418 deletions

View File

@ -16809,6 +16809,11 @@
"description": "fsGroupPolicy defines if the underlying volume supports changing ownership and permission of the volume before being mounted. Refer to the specific FSGroupPolicy values for additional details.\n\nThis field was immutable in Kubernetes < 1.29 and now is mutable.\n\nDefaults to ReadWriteOnceWithFSType, which will examine each volume to determine if Kubernetes should modify ownership and permissions of the volume. With the default policy the defined fsGroup will only be applied if a fstype is defined and the volume's access mode contains ReadWriteOnce.",
"type": "string"
},
"nodeAllocatableUpdatePeriodSeconds": {
"description": "nodeAllocatableUpdatePeriodSeconds specifies the interval between periodic updates of the CSINode allocatable capacity for this driver. When set, both periodic updates and updates triggered by capacity-related failures are enabled. If not set, no updates occur (neither periodic nor upon detecting capacity-related failures), and the allocatable.count remains static. The minimum allowed value for this field is 10 seconds.\n\nThis is an alpha feature and requires the MutableCSINodeAllocatableCount feature gate to be enabled.\n\nThis field is mutable.",
"format": "int64",
"type": "integer"
},
"podInfoOnMount": {
"description": "podInfoOnMount indicates this CSI volume driver requires additional pod information (like podName, podUID, etc.) during mount operations, if set to true. If set to false, pod information will not be passed on mount. Default is false.\n\nThe CSI driver specifies podInfoOnMount as part of driver deployment. If true, Kubelet will pass pod information as VolumeContext in the CSI NodePublishVolume() calls. The CSI driver is responsible for parsing and validating the information passed in as VolumeContext.\n\nThe following VolumeContext will be passed if podInfoOnMount is set to true. This list might grow, but the prefix will be used. \"csi.storage.k8s.io/pod.name\": pod.Name \"csi.storage.k8s.io/pod.namespace\": pod.Namespace \"csi.storage.k8s.io/pod.uid\": string(pod.UID) \"csi.storage.k8s.io/ephemeral\": \"true\" if the volume is an ephemeral inline volume\n defined by a CSIVolumeSource, otherwise \"false\"\n\n\"csi.storage.k8s.io/ephemeral\" is a new feature in Kubernetes 1.16. It is only required for drivers which support both the \"Persistent\" and \"Ephemeral\" VolumeLifecycleMode. Other drivers can leave pod info disabled and/or ignore this field. As Kubernetes 1.15 doesn't support this field, drivers can only support one mode when deployed on such a cluster and the deployment determines which mode that is, for example via a command line parameter of the driver.\n\nThis field was immutable in Kubernetes < 1.29 and now is mutable.",
"type": "boolean"
@ -17301,6 +17306,11 @@
"io.k8s.api.storage.v1.VolumeError": {
"description": "VolumeError captures an error encountered during a volume operation.",
"properties": {
"errorCode": {
"description": "errorCode is a numeric gRPC code representing the error encountered during Attach or Detach operations.\n\nThis is an optional, alpha field that requires the MutableCSINodeAllocatableCount feature gate being enabled to be set.",
"format": "int32",
"type": "integer"
},
"message": {
"description": "message represents the error encountered during Attach or Detach operation. This string may be logged, so it should not contain sensitive information.",
"type": "string"

View File

@ -1294,6 +1294,11 @@
"description": "fsGroupPolicy defines if the underlying volume supports changing ownership and permission of the volume before being mounted. Refer to the specific FSGroupPolicy values for additional details.\n\nThis field was immutable in Kubernetes < 1.29 and now is mutable.\n\nDefaults to ReadWriteOnceWithFSType, which will examine each volume to determine if Kubernetes should modify ownership and permissions of the volume. With the default policy the defined fsGroup will only be applied if a fstype is defined and the volume's access mode contains ReadWriteOnce.",
"type": "string"
},
"nodeAllocatableUpdatePeriodSeconds": {
"description": "nodeAllocatableUpdatePeriodSeconds specifies the interval between periodic updates of the CSINode allocatable capacity for this driver. When set, both periodic updates and updates triggered by capacity-related failures are enabled. If not set, no updates occur (neither periodic nor upon detecting capacity-related failures), and the allocatable.count remains static. The minimum allowed value for this field is 10 seconds.\n\nThis is an alpha feature and requires the MutableCSINodeAllocatableCount feature gate to be enabled.\n\nThis field is mutable.",
"format": "int64",
"type": "integer"
},
"podInfoOnMount": {
"description": "podInfoOnMount indicates this CSI volume driver requires additional pod information (like podName, podUID, etc.) during mount operations, if set to true. If set to false, pod information will not be passed on mount. Default is false.\n\nThe CSI driver specifies podInfoOnMount as part of driver deployment. If true, Kubelet will pass pod information as VolumeContext in the CSI NodePublishVolume() calls. The CSI driver is responsible for parsing and validating the information passed in as VolumeContext.\n\nThe following VolumeContext will be passed if podInfoOnMount is set to true. This list might grow, but the prefix will be used. \"csi.storage.k8s.io/pod.name\": pod.Name \"csi.storage.k8s.io/pod.namespace\": pod.Namespace \"csi.storage.k8s.io/pod.uid\": string(pod.UID) \"csi.storage.k8s.io/ephemeral\": \"true\" if the volume is an ephemeral inline volume\n defined by a CSIVolumeSource, otherwise \"false\"\n\n\"csi.storage.k8s.io/ephemeral\" is a new feature in Kubernetes 1.16. It is only required for drivers which support both the \"Persistent\" and \"Ephemeral\" VolumeLifecycleMode. Other drivers can leave pod info disabled and/or ignore this field. As Kubernetes 1.15 doesn't support this field, drivers can only support one mode when deployed on such a cluster and the deployment determines which mode that is, for example via a command line parameter of the driver.\n\nThis field was immutable in Kubernetes < 1.29 and now is mutable.",
"type": "boolean"
@ -1922,6 +1927,11 @@
"io.k8s.api.storage.v1.VolumeError": {
"description": "VolumeError captures an error encountered during a volume operation.",
"properties": {
"errorCode": {
"description": "errorCode is a numeric gRPC code representing the error encountered during Attach or Detach operations.\n\nThis is an optional, alpha field that requires the MutableCSINodeAllocatableCount feature gate being enabled to be set.",
"format": "int32",
"type": "integer"
},
"message": {
"description": "message represents the error encountered during Attach or Detach operation. This string may be logged, so it should not contain sensitive information.",
"type": "string"

View File

@ -203,6 +203,14 @@ type VolumeError struct {
// information.
// +optional
Message string
// errorCode is a numeric gRPC code representing the error encountered during Attach or Detach operations.
//
// This is an optional, alpha field that requires the MutableCSINodeAllocatableCount feature gate being enabled to be set.
//
// +featureGate=MutableCSINodeAllocatableCount
// +optional
ErrorCode *int32
}
// VolumeBindingMode indicates how PersistentVolumeClaims should be bound.
@ -412,6 +420,20 @@ type CSIDriverSpec struct {
// +featureGate=SELinuxMountReadWriteOncePod
// +optional
SELinuxMount *bool
// nodeAllocatableUpdatePeriodSeconds specifies the interval between periodic updates of
// the CSINode allocatable capacity for this driver. When set, both periodic updates and
// updates triggered by capacity-related failures are enabled. If not set, no updates
// occur (neither periodic nor upon detecting capacity-related failures), and the
// allocatable.count remains static. The minimum allowed value for this field is 10 seconds.
//
// This is an alpha feature and requires the MutableCSINodeAllocatableCount feature gate to be enabled.
//
// This field is mutable.
//
// +featureGate=MutableCSINodeAllocatableCount
// +optional
NodeAllocatableUpdatePeriodSeconds *int64
}
// FSGroupPolicy specifies if a CSI Driver supports modifying
@ -495,6 +517,8 @@ const (
// there are no CSI Drivers available on the node, or the Kubelet version is low
// enough that it doesn't create this object.
// CSINode has an OwnerReference that points to the corresponding node object.
// When the MutableCSINodeAllocatableCount feature gate is enabled, the allocatable.count
// field in CSINodeDriver can be updated.
type CSINode struct {
metav1.TypeMeta

View File

@ -312,6 +312,7 @@ func autoConvert_v1_CSIDriverSpec_To_storage_CSIDriverSpec(in *storagev1.CSIDriv
out.TokenRequests = *(*[]storage.TokenRequest)(unsafe.Pointer(&in.TokenRequests))
out.RequiresRepublish = (*bool)(unsafe.Pointer(in.RequiresRepublish))
out.SELinuxMount = (*bool)(unsafe.Pointer(in.SELinuxMount))
out.NodeAllocatableUpdatePeriodSeconds = (*int64)(unsafe.Pointer(in.NodeAllocatableUpdatePeriodSeconds))
return nil
}
@ -329,6 +330,7 @@ func autoConvert_storage_CSIDriverSpec_To_v1_CSIDriverSpec(in *storage.CSIDriver
out.TokenRequests = *(*[]storagev1.TokenRequest)(unsafe.Pointer(&in.TokenRequests))
out.RequiresRepublish = (*bool)(unsafe.Pointer(in.RequiresRepublish))
out.SELinuxMount = (*bool)(unsafe.Pointer(in.SELinuxMount))
out.NodeAllocatableUpdatePeriodSeconds = (*int64)(unsafe.Pointer(in.NodeAllocatableUpdatePeriodSeconds))
return nil
}
@ -728,6 +730,7 @@ func Convert_storage_VolumeAttachmentStatus_To_v1_VolumeAttachmentStatus(in *sto
func autoConvert_v1_VolumeError_To_storage_VolumeError(in *storagev1.VolumeError, out *storage.VolumeError, s conversion.Scope) error {
out.Time = in.Time
out.Message = in.Message
out.ErrorCode = (*int32)(unsafe.Pointer(in.ErrorCode))
return nil
}
@ -739,6 +742,7 @@ func Convert_v1_VolumeError_To_storage_VolumeError(in *storagev1.VolumeError, ou
func autoConvert_storage_VolumeError_To_v1_VolumeError(in *storage.VolumeError, out *storagev1.VolumeError, s conversion.Scope) error {
out.Time = in.Time
out.Message = in.Message
out.ErrorCode = (*int32)(unsafe.Pointer(in.ErrorCode))
return nil
}

View File

@ -410,6 +410,7 @@ func Convert_storage_VolumeAttributesClassList_To_v1alpha1_VolumeAttributesClass
func autoConvert_v1alpha1_VolumeError_To_storage_VolumeError(in *storagev1alpha1.VolumeError, out *storage.VolumeError, s conversion.Scope) error {
out.Time = in.Time
out.Message = in.Message
out.ErrorCode = (*int32)(unsafe.Pointer(in.ErrorCode))
return nil
}
@ -421,6 +422,7 @@ func Convert_v1alpha1_VolumeError_To_storage_VolumeError(in *storagev1alpha1.Vol
func autoConvert_storage_VolumeError_To_v1alpha1_VolumeError(in *storage.VolumeError, out *storagev1alpha1.VolumeError, s conversion.Scope) error {
out.Time = in.Time
out.Message = in.Message
out.ErrorCode = (*int32)(unsafe.Pointer(in.ErrorCode))
return nil
}

View File

@ -332,6 +332,7 @@ func autoConvert_v1beta1_CSIDriverSpec_To_storage_CSIDriverSpec(in *storagev1bet
out.TokenRequests = *(*[]storage.TokenRequest)(unsafe.Pointer(&in.TokenRequests))
out.RequiresRepublish = (*bool)(unsafe.Pointer(in.RequiresRepublish))
out.SELinuxMount = (*bool)(unsafe.Pointer(in.SELinuxMount))
out.NodeAllocatableUpdatePeriodSeconds = (*int64)(unsafe.Pointer(in.NodeAllocatableUpdatePeriodSeconds))
return nil
}
@ -349,6 +350,7 @@ func autoConvert_storage_CSIDriverSpec_To_v1beta1_CSIDriverSpec(in *storage.CSID
out.TokenRequests = *(*[]storagev1beta1.TokenRequest)(unsafe.Pointer(&in.TokenRequests))
out.RequiresRepublish = (*bool)(unsafe.Pointer(in.RequiresRepublish))
out.SELinuxMount = (*bool)(unsafe.Pointer(in.SELinuxMount))
out.NodeAllocatableUpdatePeriodSeconds = (*int64)(unsafe.Pointer(in.NodeAllocatableUpdatePeriodSeconds))
return nil
}
@ -794,6 +796,7 @@ func Convert_storage_VolumeAttributesClassList_To_v1beta1_VolumeAttributesClassL
func autoConvert_v1beta1_VolumeError_To_storage_VolumeError(in *storagev1beta1.VolumeError, out *storage.VolumeError, s conversion.Scope) error {
out.Time = in.Time
out.Message = in.Message
out.ErrorCode = (*int32)(unsafe.Pointer(in.ErrorCode))
return nil
}
@ -805,6 +808,7 @@ func Convert_v1beta1_VolumeError_To_storage_VolumeError(in *storagev1beta1.Volum
func autoConvert_storage_VolumeError_To_v1beta1_VolumeError(in *storage.VolumeError, out *storagev1beta1.VolumeError, s conversion.Scope) error {
out.Time = in.Time
out.Message = in.Message
out.ErrorCode = (*int32)(unsafe.Pointer(in.ErrorCode))
return nil
}

View File

@ -18,6 +18,7 @@ package validation
import (
"fmt"
"math"
"reflect"
"strings"
"time"
@ -26,6 +27,7 @@ import (
apimachineryvalidation "k8s.io/apimachinery/pkg/api/validation"
metav1validation "k8s.io/apimachinery/pkg/apis/meta/v1/validation"
"k8s.io/apimachinery/pkg/util/sets"
"k8s.io/apimachinery/pkg/util/validation"
"k8s.io/apimachinery/pkg/util/validation/field"
utilfeature "k8s.io/apiserver/pkg/util/feature"
api "k8s.io/kubernetes/pkg/apis/core"
@ -237,6 +239,13 @@ func validateVolumeError(e *storage.VolumeError, fldPath *field.Path) field.Erro
if len(e.Message) > maxVolumeErrorMessageSize {
allErrs = append(allErrs, field.TooLong(fldPath.Child("message"), "" /*unused*/, maxAttachedVolumeMetadataSize))
}
if e.ErrorCode != nil {
value := *e.ErrorCode
if value < 0 {
allErrs = append(allErrs, field.Invalid(fldPath.Child("errorCode"), value, validation.InclusiveRangeError(0, math.MaxInt32)))
}
}
return allErrs
}
@ -304,17 +313,28 @@ func ValidateCSINode(csiNode *storage.CSINode, validationOpts CSINodeValidationO
func ValidateCSINodeUpdate(new, old *storage.CSINode, validationOpts CSINodeValidationOptions) field.ErrorList {
allErrs := ValidateCSINode(new, validationOpts)
// Validate modifying fields inside an existing CSINodeDriver entry is not allowed
// Validate modifying fields inside an existing CSINodeDriver entry
for _, oldDriver := range old.Spec.Drivers {
for _, newDriver := range new.Spec.Drivers {
if oldDriver.Name == newDriver.Name {
if !apiequality.Semantic.DeepEqual(oldDriver, newDriver) {
allErrs = append(allErrs, field.Invalid(field.NewPath("CSINodeDriver"), newDriver, "field is immutable"))
// If MutableCSINodeAllocatableCount feature gate is enabled, compare drivers without the Allocatable field
if utilfeature.DefaultFeatureGate.Enabled(features.MutableCSINodeAllocatableCount) {
oldDriverCopy := oldDriver.DeepCopy()
newDriverCopy := newDriver.DeepCopy()
oldDriverCopy.Allocatable = nil // +k8s:verify-mutation:reason=clone
newDriverCopy.Allocatable = nil // +k8s:verify-mutation:reason=clone
allErrs = append(allErrs,
apivalidation.ValidateImmutableField(newDriverCopy, oldDriverCopy, field.NewPath("spec").Child("drivers"))...,
)
} else {
allErrs = append(allErrs,
apivalidation.ValidateImmutableField(newDriver, oldDriver, field.NewPath("spec").Child("drivers"))...,
)
}
}
}
}
return allErrs
}
@ -435,6 +455,16 @@ func validateCSIDriverSpec(
allErrs = append(allErrs, validateTokenRequests(spec.TokenRequests, fldPath.Child("tokenRequests"))...)
allErrs = append(allErrs, validateVolumeLifecycleModes(spec.VolumeLifecycleModes, fldPath.Child("volumeLifecycleModes"))...)
allErrs = append(allErrs, validateSELinuxMount(spec.SELinuxMount, fldPath.Child("seLinuxMount"))...)
allErrs = append(allErrs, validateNodeAllocatableUpdatePeriodSeconds(spec.NodeAllocatableUpdatePeriodSeconds, fldPath.Child("nodeAllocatableUpdatePeriodSeconds"))...)
return allErrs
}
// validateNodeAllocatableUpdatePeriodSeconds tests if NodeAllocatableUpdatePeriodSeconds is valid for CSIDriver.
func validateNodeAllocatableUpdatePeriodSeconds(period *int64, fldPath *field.Path) field.ErrorList {
allErrs := field.ErrorList{}
if period != nil && *period < 10 {
allErrs = append(allErrs, field.Invalid(fldPath, *period, "must be greater than or equal to 10 seconds"))
}
return allErrs
}

View File

@ -153,6 +153,7 @@ func TestValidateStorageClass(t *testing.T) {
}
func TestVolumeAttachmentValidation(t *testing.T) {
featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.MutableCSINodeAllocatableCount, true)
volumeName := "pv-name"
empty := ""
migrationEnabledSuccessCases := []storage.VolumeAttachment{{
@ -219,6 +220,30 @@ func TestVolumeAttachmentValidation(t *testing.T) {
Message: "hello world",
},
},
}, {
ObjectMeta: metav1.ObjectMeta{Name: "foo-with-valid-error-code"},
Spec: storage.VolumeAttachmentSpec{
Attacher: "myattacher",
Source: storage.VolumeAttachmentSource{
PersistentVolumeName: &volumeName,
},
NodeName: "mynode",
},
Status: storage.VolumeAttachmentStatus{
Attached: true,
AttachmentMetadata: map[string]string{
"foo": "bar",
},
AttachError: &storage.VolumeError{
Time: metav1.Time{},
Message: "hello world",
ErrorCode: utilpointer.Int32(7),
},
DetachError: &storage.VolumeError{
Time: metav1.Time{},
Message: "hello world",
},
},
}}
for _, volumeAttachment := range migrationEnabledSuccessCases {
@ -290,73 +315,101 @@ func TestVolumeAttachmentValidation(t *testing.T) {
Message: strings.Repeat("a", maxVolumeErrorMessageSize+1),
},
},
}, {
// Too long metadata
ObjectMeta: metav1.ObjectMeta{Name: "foo"},
Spec: storage.VolumeAttachmentSpec{
Attacher: "myattacher",
NodeName: "node",
Source: storage.VolumeAttachmentSource{
PersistentVolumeName: &volumeName,
},
{
// InclusiveRangeError error code
ObjectMeta: metav1.ObjectMeta{Name: "foo"},
Spec: storage.VolumeAttachmentSpec{
Attacher: "myattacher",
NodeName: "node",
Source: storage.VolumeAttachmentSource{
PersistentVolumeName: &volumeName,
},
},
},
Status: storage.VolumeAttachmentStatus{
Attached: true,
AttachmentMetadata: map[string]string{
"foo": strings.Repeat("a", maxAttachedVolumeMetadataSize),
},
AttachError: &storage.VolumeError{
Time: metav1.Time{},
Message: "hello world",
},
DetachError: &storage.VolumeError{
Time: metav1.Time{},
Message: "hello world",
},
},
}, {
// VolumeAttachmentSource with no PersistentVolumeName nor InlineSpec
ObjectMeta: metav1.ObjectMeta{Name: "foo"},
Spec: storage.VolumeAttachmentSpec{
Attacher: "myattacher",
NodeName: "node",
Source: storage.VolumeAttachmentSource{},
},
}, {
// VolumeAttachmentSource with PersistentVolumeName and InlineSpec
ObjectMeta: metav1.ObjectMeta{Name: "foo"},
Spec: storage.VolumeAttachmentSpec{
Attacher: "myattacher",
NodeName: "node",
Source: storage.VolumeAttachmentSource{
PersistentVolumeName: &volumeName,
InlineVolumeSpec: &inlineSpec,
},
},
}, {
// VolumeAttachmentSource with InlineSpec without CSI PV Source
ObjectMeta: metav1.ObjectMeta{Name: "foo"},
Spec: storage.VolumeAttachmentSpec{
Attacher: "myattacher",
NodeName: "node",
Source: storage.VolumeAttachmentSource{
PersistentVolumeName: &volumeName,
InlineVolumeSpec: &api.PersistentVolumeSpec{
Capacity: api.ResourceList{
api.ResourceName(api.ResourceStorage): resource.MustParse("10G"),
},
AccessModes: []api.PersistentVolumeAccessMode{api.ReadWriteOnce},
PersistentVolumeSource: api.PersistentVolumeSource{
FlexVolume: &api.FlexPersistentVolumeSource{
Driver: "kubernetes.io/blue",
FSType: "ext4",
},
},
StorageClassName: "test-storage-class",
Status: storage.VolumeAttachmentStatus{
Attached: true,
AttachmentMetadata: map[string]string{
"foo": "bar",
},
AttachError: &storage.VolumeError{
Time: metav1.Time{},
Message: "hello world",
ErrorCode: utilpointer.Int32(-1),
},
DetachError: &storage.VolumeError{
Time: metav1.Time{},
Message: "hello world",
ErrorCode: utilpointer.Int32(5),
},
},
},
}}
{
// Too long metadata
ObjectMeta: metav1.ObjectMeta{Name: "foo"},
Spec: storage.VolumeAttachmentSpec{
Attacher: "myattacher",
NodeName: "node",
Source: storage.VolumeAttachmentSource{
PersistentVolumeName: &volumeName,
},
},
Status: storage.VolumeAttachmentStatus{
Attached: true,
AttachmentMetadata: map[string]string{
"foo": strings.Repeat("a", maxAttachedVolumeMetadataSize),
},
AttachError: &storage.VolumeError{
Time: metav1.Time{},
Message: "hello world",
},
DetachError: &storage.VolumeError{
Time: metav1.Time{},
Message: "hello world",
},
},
}, {
// VolumeAttachmentSource with no PersistentVolumeName nor InlineSpec
ObjectMeta: metav1.ObjectMeta{Name: "foo"},
Spec: storage.VolumeAttachmentSpec{
Attacher: "myattacher",
NodeName: "node",
Source: storage.VolumeAttachmentSource{},
},
}, {
// VolumeAttachmentSource with PersistentVolumeName and InlineSpec
ObjectMeta: metav1.ObjectMeta{Name: "foo"},
Spec: storage.VolumeAttachmentSpec{
Attacher: "myattacher",
NodeName: "node",
Source: storage.VolumeAttachmentSource{
PersistentVolumeName: &volumeName,
InlineVolumeSpec: &inlineSpec,
},
},
}, {
// VolumeAttachmentSource with InlineSpec without CSI PV Source
ObjectMeta: metav1.ObjectMeta{Name: "foo"},
Spec: storage.VolumeAttachmentSpec{
Attacher: "myattacher",
NodeName: "node",
Source: storage.VolumeAttachmentSource{
PersistentVolumeName: &volumeName,
InlineVolumeSpec: &api.PersistentVolumeSpec{
Capacity: api.ResourceList{
api.ResourceName(api.ResourceStorage): resource.MustParse("10G"),
},
AccessModes: []api.PersistentVolumeAccessMode{api.ReadWriteOnce},
PersistentVolumeSource: api.PersistentVolumeSource{
FlexVolume: &api.FlexPersistentVolumeSource{
Driver: "kubernetes.io/blue",
FSType: "ext4",
},
},
StorageClassName: "test-storage-class",
},
},
},
}}
for _, volumeAttachment := range migrationEnabledErrorCases {
if errs := ValidateVolumeAttachment(&volumeAttachment); len(errs) == 0 {
@ -1399,11 +1452,76 @@ func TestCSINodeUpdateValidation(t *testing.T) {
t.Errorf("Expected failure for test: %+v", csiNode)
}
}
// Test with MutableCSINodeAllocatableCount feature gate enabled
featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.MutableCSINodeAllocatableCount, true)
successCases = []storage.CSINode{{
// valid change trying to update allocatable with a different volume limit
ObjectMeta: metav1.ObjectMeta{Name: "foo1"},
Spec: storage.CSINodeSpec{
Drivers: []storage.CSINodeDriver{{
Name: "io.kubernetes.storage.csi.driver-1",
NodeID: nodeID,
TopologyKeys: []string{"company.com/zone1", "company.com/zone2"},
}, {
Name: "io.kubernetes.storage.csi.driver-2",
NodeID: nodeID,
TopologyKeys: []string{"company.com/zone1", "company.com/zone2"},
Allocatable: &storage.VolumeNodeResources{Count: utilpointer.Int32(21)},
}},
},
}}
errorCases = []storage.CSINode{{
// invalid change node id
ObjectMeta: metav1.ObjectMeta{Name: "foo1"},
Spec: storage.CSINodeSpec{
Drivers: []storage.CSINodeDriver{{
Name: "io.kubernetes.storage.csi.driver-1",
NodeID: "nodeB",
TopologyKeys: []string{"company.com/zone1", "company.com/zone2"},
}, {
Name: "io.kubernetes.storage.csi.driver-2",
NodeID: nodeID,
TopologyKeys: []string{"company.com/zone1", "company.com/zone2"},
Allocatable: &storage.VolumeNodeResources{Count: utilpointer.Int32(20)},
}},
},
}, {
// invalid change topology keys
ObjectMeta: metav1.ObjectMeta{Name: "foo1"},
Spec: storage.CSINodeSpec{
Drivers: []storage.CSINodeDriver{{
Name: "io.kubernetes.storage.csi.driver-1",
NodeID: nodeID,
TopologyKeys: []string{"company.com/zone1", "company.com/zone2"},
}, {
Name: "io.kubernetes.storage.csi.driver-2",
NodeID: nodeID,
TopologyKeys: []string{"company.com/zone2"},
Allocatable: &storage.VolumeNodeResources{Count: utilpointer.Int32(20)},
}},
},
}}
for _, csiNode := range errorCases {
if errs := ValidateCSINodeUpdate(&csiNode, &old, shorterIDValidationOption); len(errs) == 0 {
t.Errorf("Expected failure for test: %+v", csiNode)
}
}
for _, csiNode := range successCases {
if errs := ValidateCSINodeUpdate(&csiNode, &old, shorterIDValidationOption); len(errs) != 0 {
t.Errorf("expected success with feature gate enabled: %+v", errs)
}
}
}
func TestCSIDriverValidation(t *testing.T) {
// assume this feature is on for this test, detailed enabled/disabled tests in TestCSIDriverValidationSELinuxMountEnabledDisabled
featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.SELinuxMountReadWriteOncePod, true)
// assume this feature is on for this test, detailed enabled/disabled tests in TestMutableCSINodeAllocatableCountEnabledDisabled
featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.MutableCSINodeAllocatableCount, true)
driverName := "test-driver"
longName := "my-a-b-c-d-c-f-g-h-i-j-k-l-m-n-o-p-q-r-s-t-u-v-w-x-y-z-ABCDEFGHIJKLMNOPQRSTUVWXYZ-driver"
@ -1419,6 +1537,8 @@ func TestCSIDriverValidation(t *testing.T) {
notSELinuxMount := false
supportedFSGroupPolicy := storage.FileFSGroupPolicy
invalidFSGroupPolicy := storage.FSGroupPolicy("invalid-mode")
validNodeAllocatableUpdatePeriodSeconds := int64(10)
invalidNodeAllocatableUpdatePeriodSeconds := int64(9)
successCases := []storage.CSIDriver{{
ObjectMeta: metav1.ObjectMeta{Name: driverName},
Spec: storage.CSIDriverSpec{
@ -1566,6 +1686,28 @@ func TestCSIDriverValidation(t *testing.T) {
StorageCapacity: &storageCapacity,
SELinuxMount: &notSELinuxMount,
},
}, {
// With NodeAllocatableUpdatePeriodSeconds set to nil (valid)
ObjectMeta: metav1.ObjectMeta{Name: driverName},
Spec: storage.CSIDriverSpec{
AttachRequired: &attachNotRequired,
PodInfoOnMount: &notPodInfoOnMount,
RequiresRepublish: &notRequiresRepublish,
StorageCapacity: &storageCapacity,
SELinuxMount: &seLinuxMount,
NodeAllocatableUpdatePeriodSeconds: nil,
},
}, {
// With NodeAllocatableUpdatePeriodSeconds set to valid value (10)
ObjectMeta: metav1.ObjectMeta{Name: driverName},
Spec: storage.CSIDriverSpec{
AttachRequired: &attachNotRequired,
PodInfoOnMount: &notPodInfoOnMount,
RequiresRepublish: &notRequiresRepublish,
StorageCapacity: &storageCapacity,
SELinuxMount: &seLinuxMount,
NodeAllocatableUpdatePeriodSeconds: &validNodeAllocatableUpdatePeriodSeconds,
},
}}
for _, csiDriver := range successCases {
@ -1646,6 +1788,16 @@ func TestCSIDriverValidation(t *testing.T) {
PodInfoOnMount: &notPodInfoOnMount,
StorageCapacity: &storageCapacity,
},
}, {
// NodeAllocatableUpdatePeriodSeconds less than 10 (invalid)
ObjectMeta: metav1.ObjectMeta{Name: driverName},
Spec: storage.CSIDriverSpec{
AttachRequired: &attachNotRequired,
PodInfoOnMount: &notPodInfoOnMount,
StorageCapacity: &storageCapacity,
SELinuxMount: &seLinuxMount,
NodeAllocatableUpdatePeriodSeconds: &invalidNodeAllocatableUpdatePeriodSeconds,
},
}}
for _, csiDriver := range errorCases {
@ -1658,6 +1810,8 @@ func TestCSIDriverValidation(t *testing.T) {
func TestCSIDriverValidationUpdate(t *testing.T) {
// assume this feature is on for this test, detailed enabled/disabled tests in TestCSIDriverValidationSELinuxMountEnabledDisabled
featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.SELinuxMountReadWriteOncePod, true)
// assume this feature is on for this test, detailed enabled/disabled tests in TestMutableCSINodeAllocatableCountEnabledDisabled
featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.MutableCSINodeAllocatableCount, true)
driverName := "test-driver"
longName := "my-a-b-c-d-c-f-g-h-i-j-k-l-m-n-o-p-q-r-s-t-u-v-w-x-y-z-ABCDEFGHIJKLMNOPQRSTUVWXYZ-driver"
@ -1673,9 +1827,11 @@ func TestCSIDriverValidationUpdate(t *testing.T) {
notStorageCapacity := false
seLinuxMount := true
notSELinuxMount := false
resourceVersion := "1"
validNodeAllocatableUpdatePeriodSeconds := int64(10)
invalidNodeAllocatableUpdatePeriodSeconds := int64(9)
old := storage.CSIDriver{
ObjectMeta: metav1.ObjectMeta{Name: driverName, ResourceVersion: resourceVersion},
ObjectMeta: metav1.ObjectMeta{Name: driverName, ResourceVersion: "1"},
Spec: storage.CSIDriverSpec{
AttachRequired: &attachNotRequired,
PodInfoOnMount: &notPodInfoOnMount,
@ -1726,7 +1882,13 @@ func TestCSIDriverValidationUpdate(t *testing.T) {
fileFSGroupPolicy := storage.FileFSGroupPolicy
new.Spec.FSGroupPolicy = &fileFSGroupPolicy
},
}, {
name: "Update NodeAllocatableUpdatePeriodSeconds from nil to valid value",
modify: func(new *storage.CSIDriver) {
new.Spec.NodeAllocatableUpdatePeriodSeconds = &validNodeAllocatableUpdatePeriodSeconds
},
}}
for _, test := range successCases {
t.Run(test.name, func(t *testing.T) {
new := old.DeepCopy()
@ -1737,7 +1899,6 @@ func TestCSIDriverValidationUpdate(t *testing.T) {
})
}
// Each test case changes exactly one field. None of that is valid.
errorCases := []struct {
name string
modify func(new *storage.CSIDriver)
@ -1813,6 +1974,11 @@ func TestCSIDriverValidationUpdate(t *testing.T) {
modify: func(new *storage.CSIDriver) {
new.Spec.SELinuxMount = nil
},
}, {
name: "Update NodeAllocatableUpdatePeriodSeconds to invalid value",
modify: func(new *storage.CSIDriver) {
new.Spec.NodeAllocatableUpdatePeriodSeconds = &invalidNodeAllocatableUpdatePeriodSeconds
},
}}
for _, test := range errorCases {

View File

@ -132,6 +132,11 @@ func (in *CSIDriverSpec) DeepCopyInto(out *CSIDriverSpec) {
*out = new(bool)
**out = **in
}
if in.NodeAllocatableUpdatePeriodSeconds != nil {
in, out := &in.NodeAllocatableUpdatePeriodSeconds, &out.NodeAllocatableUpdatePeriodSeconds
*out = new(int64)
**out = **in
}
return
}
@ -649,6 +654,11 @@ func (in *VolumeAttributesClassList) DeepCopyObject() runtime.Object {
func (in *VolumeError) DeepCopyInto(out *VolumeError) {
*out = *in
in.Time.DeepCopyInto(&out.Time)
if in.ErrorCode != nil {
in, out := &in.ErrorCode, &out.ErrorCode
*out = new(int32)
**out = **in
}
return
}

View File

@ -105,6 +105,8 @@ func (plugin *TestPlugin) NewUnmounter(name string, podUID types.UID) (volume.Un
return nil, nil
}
func (plugin *TestPlugin) VerifyExhaustedResource(spec *volume.Spec, nodeName types.NodeName) {}
func (plugin *TestPlugin) ConstructVolumeSpec(volumeName, mountPath string) (volume.ReconstructedVolume, error) {
fakeVolume := &v1.Volume{
Name: volumeName,

View File

@ -458,6 +458,13 @@ const (
// Enables the dynamic configuration of Service IP ranges
MultiCIDRServiceAllocator featuregate.Feature = "MultiCIDRServiceAllocator"
// owner: torredil
// kep: https://kep.k8s.io/4876
//
// Makes CSINode.Spec.Drivers[*].Allocatable.Count mutable, allowing CSI drivers to
// update the number of volumes that can be allocated on a node
MutableCSINodeAllocatableCount featuregate.Feature = "MutableCSINodeAllocatableCount"
// owner: @danwinship
// kep: https://kep.k8s.io/3866
//

View File

@ -536,6 +536,10 @@ var defaultVersionedKubernetesFeatureGates = map[featuregate.Feature]featuregate
{Version: version.MustParse("1.33"), Default: true, PreRelease: featuregate.GA, LockToDefault: false}, // remove in 1.36
},
MutableCSINodeAllocatableCount: {
{Version: version.MustParse("1.33"), Default: false, PreRelease: featuregate.Alpha},
},
NFTablesProxyMode: {
{Version: version.MustParse("1.29"), Default: false, PreRelease: featuregate.Alpha},
{Version: version.MustParse("1.31"), Default: true, PreRelease: featuregate.Beta},

View File

@ -50705,6 +50705,13 @@ func schema_k8sio_api_storage_v1_CSIDriverSpec(ref common.ReferenceCallback) com
Format: "",
},
},
"nodeAllocatableUpdatePeriodSeconds": {
SchemaProps: spec.SchemaProps{
Description: "nodeAllocatableUpdatePeriodSeconds specifies the interval between periodic updates of the CSINode allocatable capacity for this driver. When set, both periodic updates and updates triggered by capacity-related failures are enabled. If not set, no updates occur (neither periodic nor upon detecting capacity-related failures), and the allocatable.count remains static. The minimum allowed value for this field is 10 seconds.\n\nThis is an alpha feature and requires the MutableCSINodeAllocatableCount feature gate to be enabled.\n\nThis field is mutable.",
Type: []string{"integer"},
Format: "int64",
},
},
},
},
},
@ -51464,6 +51471,13 @@ func schema_k8sio_api_storage_v1_VolumeError(ref common.ReferenceCallback) commo
Format: "",
},
},
"errorCode": {
SchemaProps: spec.SchemaProps{
Description: "errorCode is a numeric gRPC code representing the error encountered during Attach or Detach operations.\n\nThis is an optional, alpha field that requires the MutableCSINodeAllocatableCount feature gate being enabled to be set.",
Type: []string{"integer"},
Format: "int32",
},
},
},
},
},
@ -51959,6 +51973,13 @@ func schema_k8sio_api_storage_v1alpha1_VolumeError(ref common.ReferenceCallback)
Format: "",
},
},
"errorCode": {
SchemaProps: spec.SchemaProps{
Description: "errorCode is a numeric gRPC code representing the error encountered during Attach or Detach operations.\n\nThis is an optional, alpha field that requires the MutableCSINodeAllocatableCount feature gate being enabled to be set.",
Type: []string{"integer"},
Format: "int32",
},
},
},
},
},
@ -52150,6 +52171,13 @@ func schema_k8sio_api_storage_v1beta1_CSIDriverSpec(ref common.ReferenceCallback
Format: "",
},
},
"nodeAllocatableUpdatePeriodSeconds": {
SchemaProps: spec.SchemaProps{
Description: "nodeAllocatableUpdatePeriodSeconds specifies the interval between periodic updates of the CSINode allocatable capacity for this driver. When set, both periodic updates and updates triggered by capacity-related failures are enabled. If not set, no updates occur (neither periodic nor upon detecting capacity-related failures), and the allocatable.count remains static. The minimum allowed value for this field is 10 seconds.\n\nThis is an alpha feature and requires the MutableCSINodeAllocatableCount feature gate to be enabled.\n\nThis field is mutable.",
Type: []string{"integer"},
Format: "int64",
},
},
},
},
},
@ -53020,6 +53048,13 @@ func schema_k8sio_api_storage_v1beta1_VolumeError(ref common.ReferenceCallback)
Format: "",
},
},
"errorCode": {
SchemaProps: spec.SchemaProps{
Description: "errorCode is a numeric gRPC code representing the error encountered during Attach or Detach operations.\n\nThis is an optional, alpha field that requires the MutableCSINodeAllocatableCount feature gate being enabled to be set.",
Type: []string{"integer"},
Format: "int32",
},
},
},
},
},

View File

@ -50,6 +50,9 @@ func (csiDriverStrategy) PrepareForCreate(ctx context.Context, obj runtime.Objec
if !utilfeature.DefaultFeatureGate.Enabled(features.SELinuxMountReadWriteOncePod) {
csiDriver.Spec.SELinuxMount = nil
}
if !utilfeature.DefaultFeatureGate.Enabled(features.MutableCSINodeAllocatableCount) {
csiDriver.Spec.NodeAllocatableUpdatePeriodSeconds = nil
}
}
func (csiDriverStrategy) Validate(ctx context.Context, obj runtime.Object) field.ErrorList {
@ -83,6 +86,11 @@ func (csiDriverStrategy) PrepareForUpdate(ctx context.Context, obj, old runtime.
newCSIDriver.Spec.SELinuxMount = nil
}
if oldCSIDriver.Spec.NodeAllocatableUpdatePeriodSeconds == nil &&
!utilfeature.DefaultFeatureGate.Enabled(features.MutableCSINodeAllocatableCount) {
newCSIDriver.Spec.NodeAllocatableUpdatePeriodSeconds = nil
}
// Any changes to the spec increment the generation number.
if !apiequality.Semantic.DeepEqual(oldCSIDriver.Spec, newCSIDriver.Spec) {
newCSIDriver.Generation = oldCSIDriver.Generation + 1

View File

@ -192,18 +192,39 @@ func TestCSIDriverPrepareForUpdate(t *testing.T) {
},
}
thirty := int64(30)
sixty := int64(60)
driverWithNodeAllocatableUpdatePeriodSeconds30 := &storage.CSIDriver{
ObjectMeta: metav1.ObjectMeta{
Name: "foo",
},
Spec: storage.CSIDriverSpec{
NodeAllocatableUpdatePeriodSeconds: &thirty,
},
}
driverWithNodeAllocatableUpdatePeriodSeconds60 := &storage.CSIDriver{
ObjectMeta: metav1.ObjectMeta{
Name: "foo",
},
Spec: storage.CSIDriverSpec{
NodeAllocatableUpdatePeriodSeconds: &sixty,
},
}
resultPersistent := []storage.VolumeLifecycleMode{storage.VolumeLifecyclePersistent}
tests := []struct {
name string
old, update *storage.CSIDriver
seLinuxMountReadWriteOncePodEnabled bool
wantCapacity *bool
wantModes []storage.VolumeLifecycleMode
wantTokenRequests []storage.TokenRequest
wantRequiresRepublish *bool
wantGeneration int64
wantSELinuxMount *bool
name string
old, update *storage.CSIDriver
seLinuxMountReadWriteOncePodEnabled bool
mutableCSINodeAllocatableCountEnabled bool
wantCapacity *bool
wantModes []storage.VolumeLifecycleMode
wantTokenRequests []storage.TokenRequest
wantRequiresRepublish *bool
wantGeneration int64
wantSELinuxMount *bool
wantNodeAllocatableUpdatePeriodSeconds *int64
}{
{
name: "podInfoOnMount feature enabled, before: none, update: enabled",
@ -348,11 +369,36 @@ func TestCSIDriverPrepareForUpdate(t *testing.T) {
wantSELinuxMount: &disabled,
wantGeneration: 1,
},
{
name: "NodeAllocatableUpdatePeriod feature enabled, before: nil, update: 30s",
mutableCSINodeAllocatableCountEnabled: true,
old: driverWithNothing,
update: driverWithNodeAllocatableUpdatePeriodSeconds30,
wantNodeAllocatableUpdatePeriodSeconds: &thirty,
wantGeneration: 1,
},
{
name: "NodeAllocatableUpdatePeriod feature enabled, before: 30s, update: 60s",
mutableCSINodeAllocatableCountEnabled: true,
old: driverWithNodeAllocatableUpdatePeriodSeconds30,
update: driverWithNodeAllocatableUpdatePeriodSeconds60,
wantNodeAllocatableUpdatePeriodSeconds: &sixty,
wantGeneration: 1,
},
{
name: "NodeAllocatableUpdatePeriod feature disabled, before: nil, update: 30s",
mutableCSINodeAllocatableCountEnabled: false,
old: driverWithNothing,
update: driverWithNodeAllocatableUpdatePeriodSeconds30,
wantNodeAllocatableUpdatePeriodSeconds: nil,
wantGeneration: 0,
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.SELinuxMountReadWriteOncePod, test.seLinuxMountReadWriteOncePodEnabled)
featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.MutableCSINodeAllocatableCount, test.mutableCSINodeAllocatableCountEnabled)
csiDriver := test.update.DeepCopy()
Strategy.PrepareForUpdate(ctx, csiDriver, test.old)
@ -362,6 +408,7 @@ func TestCSIDriverPrepareForUpdate(t *testing.T) {
require.Equal(t, test.wantTokenRequests, csiDriver.Spec.TokenRequests)
require.Equal(t, test.wantRequiresRepublish, csiDriver.Spec.RequiresRepublish)
require.Equal(t, test.wantSELinuxMount, csiDriver.Spec.SELinuxMount)
require.Equal(t, test.wantNodeAllocatableUpdatePeriodSeconds, csiDriver.Spec.NodeAllocatableUpdatePeriodSeconds)
})
}
}
@ -370,6 +417,8 @@ func TestCSIDriverValidation(t *testing.T) {
enabled := true
disabled := true
gcp := "gcp"
validNodeAllocatableUpdatePeriodSeconds := int64(30)
invalidNodeAllocatableUpdatePeriodSeconds := int64(3)
tests := []struct {
name string
@ -538,12 +587,45 @@ func TestCSIDriverValidation(t *testing.T) {
},
true,
},
{
"valid NodeAllocatableUpdatePeriodSeconds - greater than 10s",
&storage.CSIDriver{
ObjectMeta: metav1.ObjectMeta{
Name: "foo",
},
Spec: storage.CSIDriverSpec{
AttachRequired: &enabled,
PodInfoOnMount: &enabled,
StorageCapacity: &enabled,
SELinuxMount: &enabled,
NodeAllocatableUpdatePeriodSeconds: &validNodeAllocatableUpdatePeriodSeconds,
},
},
false,
},
{
"invalid NodeAllocatableUpdatePeriodSeconds - less than 10s",
&storage.CSIDriver{
ObjectMeta: metav1.ObjectMeta{
Name: "foo",
},
Spec: storage.CSIDriverSpec{
AttachRequired: &enabled,
PodInfoOnMount: &enabled,
StorageCapacity: &enabled,
SELinuxMount: &enabled,
NodeAllocatableUpdatePeriodSeconds: &invalidNodeAllocatableUpdatePeriodSeconds,
},
},
true,
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
// assume this feature is on for this test, detailed enabled/disabled tests in TestCSIDriverValidationSELinuxMountEnabledDisabled
featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.SELinuxMountReadWriteOncePod, true)
featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.MutableCSINodeAllocatableCount, true)
testValidation := func(csiDriver *storage.CSIDriver, apiVersion string) field.ErrorList {
ctx := genericapirequest.WithRequestInfo(genericapirequest.NewContext(), &genericapirequest.RequestInfo{

View File

@ -23,9 +23,11 @@ import (
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/util/validation/field"
"k8s.io/apiserver/pkg/storage/names"
"k8s.io/apiserver/pkg/util/feature"
"k8s.io/kubernetes/pkg/api/legacyscheme"
"k8s.io/kubernetes/pkg/apis/storage"
"k8s.io/kubernetes/pkg/apis/storage/validation"
"k8s.io/kubernetes/pkg/features"
"sigs.k8s.io/structured-merge-diff/v4/fieldpath"
)
@ -139,4 +141,18 @@ func (volumeAttachmentStatusStrategy) PrepareForUpdate(ctx context.Context, obj,
newVolumeAttachment.Spec = oldVolumeAttachment.Spec
metav1.ResetObjectMetaForStatus(&newVolumeAttachment.ObjectMeta, &oldVolumeAttachment.ObjectMeta)
if !feature.DefaultFeatureGate.Enabled(features.MutableCSINodeAllocatableCount) {
// Only clear ErrorCode field if it isn't set in the old object
if newVolumeAttachment.Status.AttachError != nil {
if oldVolumeAttachment.Status.AttachError == nil || oldVolumeAttachment.Status.AttachError.ErrorCode == nil {
newVolumeAttachment.Status.AttachError.ErrorCode = nil
}
}
if newVolumeAttachment.Status.DetachError != nil {
if oldVolumeAttachment.Status.DetachError == nil || oldVolumeAttachment.Status.DetachError.ErrorCode == nil {
newVolumeAttachment.Status.DetachError.ErrorCode = nil
}
}
}
}

View File

@ -25,8 +25,11 @@ import (
"k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
genericapirequest "k8s.io/apiserver/pkg/endpoints/request"
"k8s.io/apiserver/pkg/util/feature"
featuregatetesting "k8s.io/component-base/featuregate/testing"
api "k8s.io/kubernetes/pkg/apis/core"
"k8s.io/kubernetes/pkg/apis/storage"
"k8s.io/kubernetes/pkg/features"
)
func getValidVolumeAttachment(name string) *storage.VolumeAttachment {
@ -177,6 +180,72 @@ func TestVolumeAttachmentStatusStrategy(t *testing.T) {
if !apiequality.Semantic.DeepEqual(newVolumeAttachment, volumeAttachment) {
t.Errorf("unexpected objects difference after modifying spec: %v", cmp.Diff(newVolumeAttachment, volumeAttachment))
}
// Verify that error codes are dropped when the feature gate is disabled.
featuregatetesting.SetFeatureGateDuringTest(t, feature.DefaultFeatureGate, features.MutableCSINodeAllocatableCount, false)
statusWithError := volumeAttachment.DeepCopy()
statusErrCode := int32(7)
statusWithError.Status = storage.VolumeAttachmentStatus{
Attached: true,
AttachError: &storage.VolumeError{
Message: "attach error",
ErrorCode: &statusErrCode,
},
DetachError: &storage.VolumeError{
Message: "detach error",
ErrorCode: &statusErrCode,
},
}
StatusStrategy.PrepareForUpdate(ctx, statusWithError, volumeAttachment)
if statusWithError.Status.AttachError != nil && statusWithError.Status.AttachError.ErrorCode != nil {
t.Errorf("expected AttachError.ErrorCode to be nil, got %v", *statusWithError.Status.AttachError.ErrorCode)
}
if statusWithError.Status.DetachError != nil && statusWithError.Status.DetachError.ErrorCode != nil {
t.Errorf("expected DetachError.ErrorCode to be nil, got %v", *statusWithError.Status.DetachError.ErrorCode)
}
// Verify that error codes are not dropped when set in the old object.
oldStatusWithError := volumeAttachment.DeepCopy()
oldStatusErrCode := int32(8)
oldStatusWithError.Status = storage.VolumeAttachmentStatus{
Attached: true,
AttachError: &storage.VolumeError{
Message: "old attach error",
ErrorCode: &oldStatusErrCode,
},
DetachError: &storage.VolumeError{
Message: "old detach error",
ErrorCode: &oldStatusErrCode,
},
}
newStatusWithError := oldStatusWithError.DeepCopy()
newStatusErrCode := int32(9)
newStatusWithError.Status = storage.VolumeAttachmentStatus{
Attached: true,
AttachError: &storage.VolumeError{
Message: "new attach error",
ErrorCode: &newStatusErrCode,
},
DetachError: &storage.VolumeError{
Message: "new detach error",
ErrorCode: &newStatusErrCode,
},
}
StatusStrategy.PrepareForUpdate(ctx, newStatusWithError, oldStatusWithError)
if newStatusWithError.Status.AttachError == nil || newStatusWithError.Status.AttachError.ErrorCode == nil {
t.Errorf("expected AttachError.ErrorCode to be preserved, got nil")
} else if *newStatusWithError.Status.AttachError.ErrorCode != newStatusErrCode {
t.Errorf("expected AttachError.ErrorCode to be %v, got %v", newStatusErrCode, *newStatusWithError.Status.AttachError.ErrorCode)
}
if newStatusWithError.Status.DetachError == nil || newStatusWithError.Status.DetachError.ErrorCode == nil {
t.Errorf("expected DetachError.ErrorCode to be preserved, got nil")
} else if *newStatusWithError.Status.DetachError.ErrorCode != newStatusErrCode {
t.Errorf("expected DetachError.ErrorCode to be %v, got %v", newStatusErrCode, *newStatusWithError.Status.DetachError.ErrorCode)
}
}
func TestUpdatePreventsStatusWrite(t *testing.T) {

View File

@ -88,6 +88,7 @@ func (pl *CSILimits) EventsToRegister(_ context.Context) ([]framework.ClusterEve
// We don't register any `QueueingHintFn` intentionally
// because any new CSINode could make pods that were rejected by CSI volumes schedulable.
{Event: framework.ClusterEvent{Resource: framework.CSINode, ActionType: framework.Add}},
{Event: framework.ClusterEvent{Resource: framework.CSINode, ActionType: framework.Update}, QueueingHintFn: pl.isSchedulableAfterCSINodeUpdated},
{Event: framework.ClusterEvent{Resource: framework.Pod, ActionType: framework.Delete}, QueueingHintFn: pl.isSchedulableAfterPodDeleted},
{Event: framework.ClusterEvent{Resource: framework.PersistentVolumeClaim, ActionType: framework.Add}, QueueingHintFn: pl.isSchedulableAfterPVCAdded},
{Event: framework.ClusterEvent{Resource: framework.VolumeAttachment, ActionType: framework.Delete}, QueueingHintFn: pl.isSchedulableAfterVolumeAttachmentDeleted},
@ -188,6 +189,47 @@ func (pl *CSILimits) isSchedulableAfterVolumeAttachmentDeleted(logger klog.Logge
return framework.QueueSkip, nil
}
func (pl *CSILimits) isSchedulableAfterCSINodeUpdated(logger klog.Logger, pod *v1.Pod, oldObj, newObj interface{}) (framework.QueueingHint, error) {
oldCSINode, newCSINode, err := util.As[*storagev1.CSINode](oldObj, newObj)
if err != nil {
return framework.Queue, fmt.Errorf("unexpected objects in isSchedulableAfterCSINodeUpdated: %w", err)
}
oldLimits := make(map[string]int32)
for _, d := range oldCSINode.Spec.Drivers {
var count int32
if d.Allocatable != nil && d.Allocatable.Count != nil {
count = *d.Allocatable.Count
}
oldLimits[d.Name] = count
}
// Compare new driver limits vs. old. If limit increased, queue pod.
for _, d := range newCSINode.Spec.Drivers {
var oldLimit int32
if val, exists := oldLimits[d.Name]; exists {
oldLimit = val
}
newLimit := int32(0)
if d.Allocatable != nil && d.Allocatable.Count != nil {
newLimit = *d.Allocatable.Count
}
if newLimit > oldLimit {
logger.V(5).Info("CSINode driver limit increased, might make this pod schedulable",
"pod", klog.KObj(pod),
"driver", d.Name,
"oldLimit", oldLimit,
"newLimit", newLimit,
)
return framework.Queue, nil
}
}
// If no driver limit was increased, skip queueing.
return framework.QueueSkip, nil
}
// PreFilter invoked at the prefilter extension point
//
// If the pod haven't those types of volumes, we'll skip the Filter phase

View File

@ -976,6 +976,100 @@ func TestCSILimitsDeletedVolumeAttachmentQHint(t *testing.T) {
}
}
func TestCSILimitsAfterCSINodeUpdatedQHint(t *testing.T) {
p := &CSILimits{}
testPod := st.MakePod().Name("test-pod").Namespace("ns1").
PVC("csi-ebs.csi.aws.com-0").Obj()
logger, _ := ktesting.NewTestContext(t)
tests := []struct {
name string
oldDrivers []storagev1.CSINodeDriver
newDrivers []storagev1.CSINodeDriver
wantQHint framework.QueueingHint
}{
{
name: "limit raised, queue",
oldDrivers: []storagev1.CSINodeDriver{{
Name: "ebs.csi.aws.com",
NodeID: "test-node",
Allocatable: &storagev1.VolumeNodeResources{
Count: ptr.To(int32(1)),
},
}},
newDrivers: []storagev1.CSINodeDriver{{
Name: "ebs.csi.aws.com",
NodeID: "test-node",
Allocatable: &storagev1.VolumeNodeResources{
Count: ptr.To(int32(2)),
},
}},
wantQHint: framework.Queue,
},
{
name: "limit decreased, skip queueing",
oldDrivers: []storagev1.CSINodeDriver{{
Name: "ebs.csi.aws.com",
NodeID: "test-node",
Allocatable: &storagev1.VolumeNodeResources{
Count: ptr.To(int32(2)),
},
}},
newDrivers: []storagev1.CSINodeDriver{{
Name: "ebs.csi.aws.com",
NodeID: "test-node",
Allocatable: &storagev1.VolumeNodeResources{
Count: ptr.To(int32(1)),
},
}},
wantQHint: framework.QueueSkip,
},
{
name: "limit unchanged, skip queueing",
oldDrivers: []storagev1.CSINodeDriver{{
Name: "ebs.csi.aws.com",
NodeID: "test-node",
Allocatable: &storagev1.VolumeNodeResources{
Count: ptr.To(int32(1)),
},
}},
newDrivers: []storagev1.CSINodeDriver{{
Name: "ebs.csi.aws.com",
NodeID: "test-node",
Allocatable: &storagev1.VolumeNodeResources{
Count: ptr.To(int32(1)),
},
}},
wantQHint: framework.QueueSkip,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
oldCSINode := &storagev1.CSINode{
ObjectMeta: metav1.ObjectMeta{Name: "test-node"},
Spec: storagev1.CSINodeSpec{
Drivers: tt.oldDrivers,
},
}
newCSINode := &storagev1.CSINode{
ObjectMeta: metav1.ObjectMeta{Name: "test-node"},
Spec: storagev1.CSINodeSpec{
Drivers: tt.newDrivers,
},
}
qhint, err := p.isSchedulableAfterCSINodeUpdated(logger, testPod, oldCSINode, newCSINode)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if qhint != tt.wantQHint {
t.Errorf("wrong qhint: got=%v, want=%v", qhint, tt.wantQHint)
}
})
}
}
func getFakeVolumeAttachmentLister(count int, driverNames ...string) tf.VolumeAttachmentLister {
vaLister := tf.VolumeAttachmentLister{}
for _, driver := range driverNames {

View File

@ -0,0 +1,199 @@
/*
Copyright 2025 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 csi
import (
"fmt"
"sync"
"time"
v1 "k8s.io/api/storage/v1"
"k8s.io/client-go/tools/cache"
"k8s.io/klog/v2"
)
// csiNodeUpdater watches for changes to CSIDriver objects and manages the lifecycle
// of per-driver goroutines that periodically update CSINodeDriver.Allocatable information
// based on the NodeAllocatableUpdatePeriodSeconds setting.
type csiNodeUpdater struct {
// Informer for CSIDriver objects
driverInformer cache.SharedIndexInformer
// Map of driver names to stop channels for update goroutines
driverUpdaters sync.Map
// Ensures the updater is only started once
once sync.Once
}
// NewCSINodeUpdater creates a new csiNodeUpdater
func NewCSINodeUpdater(driverInformer cache.SharedIndexInformer) (*csiNodeUpdater, error) {
if driverInformer == nil {
return nil, fmt.Errorf("driverInformer must not be nil")
}
return &csiNodeUpdater{
driverInformer: driverInformer,
driverUpdaters: sync.Map{},
}, nil
}
// Run starts the csiNodeUpdater by registering event handlers.
func (u *csiNodeUpdater) Run() {
u.once.Do(func() {
_, err := u.driverInformer.AddEventHandler(cache.ResourceEventHandlerFuncs{
AddFunc: u.onDriverAdd,
UpdateFunc: u.onDriverUpdate,
DeleteFunc: u.onDriverDelete,
})
if err != nil {
klog.ErrorS(err, "Failed to add event handler for CSI driver informer")
return
}
klog.V(4).InfoS("csiNodeUpdater initialized successfully")
})
}
// onDriverAdd handles the addition of a new CSIDriver object.
func (u *csiNodeUpdater) onDriverAdd(obj interface{}) {
driver, ok := obj.(*v1.CSIDriver)
if !ok {
return
}
klog.V(7).InfoS("onDriverAdd event", "driver", driver.Name)
u.syncDriverUpdater(driver.Name)
}
// onDriverUpdate handles updates to CSIDriver objects.
func (u *csiNodeUpdater) onDriverUpdate(oldObj, newObj interface{}) {
oldDriver, ok := oldObj.(*v1.CSIDriver)
if !ok {
return
}
newDriver, ok := newObj.(*v1.CSIDriver)
if !ok {
return
}
// Only reconfigure if the NodeAllocatableUpdatePeriodSeconds field is updated.
oldPeriod := getNodeAllocatableUpdatePeriod(oldDriver)
newPeriod := getNodeAllocatableUpdatePeriod(newDriver)
if oldPeriod != newPeriod {
klog.V(4).InfoS("NodeAllocatableUpdatePeriodSeconds updated", "driver", newDriver.Name, "oldPeriod", oldPeriod, "newPeriod", newPeriod)
u.syncDriverUpdater(newDriver.Name)
}
}
// onDriverDelete handles deletion of CSIDriver objects.
func (u *csiNodeUpdater) onDriverDelete(obj interface{}) {
driver, ok := obj.(*v1.CSIDriver)
if !ok {
return
}
klog.V(7).InfoS("onDriverDelete event", "driver", driver.Name)
u.syncDriverUpdater(driver.Name)
}
// syncDriverUpdater re-evaluates whether the periodic updater for a given driver should run.
// It is invoked from informer events (Add/Update/Delete) and from plugin registration/deregistration.
func (u *csiNodeUpdater) syncDriverUpdater(driverName string) {
// Check if the CSI plugin is installed on this node.
if !isDriverInstalled(driverName) {
klog.V(4).InfoS("Driver not installed; stopping csiNodeUpdater", "driver", driverName)
u.unregisterDriver(driverName)
return
}
// Get the CSIDriver object from the informer cache.
obj, exists, err := u.driverInformer.GetStore().GetByKey(driverName)
if err != nil {
u.unregisterDriver(driverName)
klog.ErrorS(err, "Error retrieving CSIDriver from store", "driver", driverName)
return
}
if !exists {
klog.InfoS("CSIDriver object not found; stopping csiNodeUpdater", "driver", driverName)
u.unregisterDriver(driverName)
return
}
driver, ok := obj.(*v1.CSIDriver)
if !ok {
klog.ErrorS(fmt.Errorf("invalid CSIDriver object type"), "failed to cast CSIDriver object", "driver", driverName)
return
}
// Get the update period.
period := getNodeAllocatableUpdatePeriod(driver)
if period == 0 {
klog.V(7).InfoS("NodeAllocatableUpdatePeriodSeconds is not configured; disabling updates", "driver", driverName)
u.unregisterDriver(driverName)
return
}
newStopCh := make(chan struct{})
prevStopCh, loaded := u.driverUpdaters.Swap(driverName, newStopCh)
// If an updater is already running, stop it so we can reconfigure.
if loaded && prevStopCh != nil {
if stopCh, ok := prevStopCh.(chan struct{}); ok {
close(stopCh)
}
}
// Start the periodic update goroutine.
go u.runPeriodicUpdate(driverName, period, newStopCh)
}
// unregisterDriver stops any running periodic update goroutine for the given driver.
func (u *csiNodeUpdater) unregisterDriver(driverName string) {
prev, loaded := u.driverUpdaters.LoadAndDelete(driverName)
if loaded && prev != nil {
if stopCh, ok := prev.(chan struct{}); ok {
close(stopCh)
}
}
}
// runPeriodicUpdate runs the periodic update loop for a driver.
func (u *csiNodeUpdater) runPeriodicUpdate(driverName string, period time.Duration, stopCh <-chan struct{}) {
ticker := time.NewTicker(period)
defer ticker.Stop()
klog.V(7).InfoS("Starting periodic updates for driver", "driver", driverName, "period", period)
for {
select {
case <-ticker.C:
if err := updateCSIDriver(driverName); err != nil {
klog.ErrorS(err, "Failed to update CSIDriver", "driver", driverName)
}
case <-stopCh:
klog.V(4).InfoS("Stopping periodic updates for driver", "driver", driverName, "period", period)
return
}
}
}
// isDriverInstalled checks if the CSI driver is installed on the node by checking the global csiDrivers map
func isDriverInstalled(driverName string) bool {
_, ok := csiDrivers.Get(driverName)
return ok
}
// getNodeAllocatableUpdatePeriod returns the NodeAllocatableUpdatePeriodSeconds value from the CSIDriver
func getNodeAllocatableUpdatePeriod(driver *v1.CSIDriver) time.Duration {
if driver == nil || driver.Spec.NodeAllocatableUpdatePeriodSeconds == nil {
return 0
}
return time.Duration(*driver.Spec.NodeAllocatableUpdatePeriodSeconds) * time.Second
}

View File

@ -0,0 +1,247 @@
/*
Copyright 2025 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 csi
import (
"reflect"
"testing"
v1 "k8s.io/api/storage/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
utilversion "k8s.io/apimachinery/pkg/util/version"
"k8s.io/client-go/informers"
fakeclient "k8s.io/client-go/kubernetes/fake"
"k8s.io/client-go/tools/cache"
)
const testDriverName = "test-driver"
type testFixture struct {
client *fakeclient.Clientset
factory informers.SharedInformerFactory
driverInformer cache.SharedIndexInformer
updater *csiNodeUpdater
stopCh chan struct{}
}
func setupTest(t *testing.T, driver *v1.CSIDriver) *testFixture {
var clientObjects []runtime.Object
if driver != nil {
clientObjects = append(clientObjects, driver)
}
client := fakeclient.NewSimpleClientset(clientObjects...)
factory := informers.NewSharedInformerFactory(client, 0)
driverInformer := factory.Storage().V1().CSIDrivers().Informer()
stopCh := make(chan struct{})
factory.Start(stopCh)
if !cache.WaitForCacheSync(stopCh, driverInformer.HasSynced) {
close(stopCh)
t.Fatalf("Timed out waiting for caches to sync")
}
updater, err := NewCSINodeUpdater(driverInformer)
if err != nil {
close(stopCh)
t.Fatalf("Failed to create CSINodeUpdater: %v", err)
}
return &testFixture{
client: client,
factory: factory,
driverInformer: driverInformer,
updater: updater,
stopCh: stopCh,
}
}
func TestNewCSINodeUpdater(t *testing.T) {
t.Run("valid informer", func(t *testing.T) {
f := setupTest(t, nil)
defer f.cleanup()
updater, err := NewCSINodeUpdater(f.driverInformer)
if err != nil {
t.Errorf("Expected no error but got: %v", err)
}
if updater == nil {
t.Errorf("Expected non-nil updater")
}
})
t.Run("nil informer", func(t *testing.T) {
updater, err := NewCSINodeUpdater(nil)
if err == nil {
t.Errorf("Expected error but got none")
}
if updater != nil {
t.Errorf("Expected nil updater when error occurs")
}
})
}
func TestSyncDriverUpdater(t *testing.T) {
t.Run("driver not installed, should stop updater", func(t *testing.T) {
f := setupTest(t, nil)
defer f.cleanup()
updaterStopCh := make(chan struct{})
f.updater.driverUpdaters.Store(testDriverName, updaterStopCh)
// Verify the initial state - updater should exist for the driver
verifyUpdaterState(t, f.updater, testDriverName, true)
// Detect the driver is not installed
f.updater.syncDriverUpdater(testDriverName)
// Verify the driver was unregistered from the updater map
verifyUpdaterState(t, f.updater, testDriverName, false)
if !isChannelClosed(updaterStopCh) {
t.Errorf("Stop channel was not closed")
}
})
t.Run("driver not found in informer, should stop updater", func(t *testing.T) {
f := setupTest(t, nil)
defer f.cleanup()
// Register driver in global map but not in informer
registerTestDriver(testDriverName)
defer unregisterTestDriver(testDriverName)
updaterStopCh := make(chan struct{})
f.updater.driverUpdaters.Store(testDriverName, updaterStopCh)
verifyUpdaterState(t, f.updater, testDriverName, true)
// Detect the driver exists in global map but not in informer
f.updater.syncDriverUpdater(testDriverName)
verifyUpdaterState(t, f.updater, testDriverName, false)
if !isChannelClosed(updaterStopCh) {
t.Errorf("Stop channel was not closed")
}
})
t.Run("driver with unset updatePeriodSeconds, should stop updater", func(t *testing.T) {
driver := createTestDriver(testDriverName, nil)
f := setupTest(t, driver)
defer f.cleanup()
registerTestDriver(testDriverName)
defer unregisterTestDriver(testDriverName)
updaterStopCh := make(chan struct{})
f.updater.driverUpdaters.Store(testDriverName, updaterStopCh)
verifyUpdaterState(t, f.updater, testDriverName, true)
// Detect the driver has unset updatePeriodSeconds
f.updater.syncDriverUpdater(testDriverName)
verifyUpdaterState(t, f.updater, testDriverName, false)
if !isChannelClosed(updaterStopCh) {
t.Errorf("Stop channel was not closed")
}
})
t.Run("replace existing updater", func(t *testing.T) {
updatePeriod := int64(60)
driver := createTestDriver(testDriverName, &updatePeriod)
f := setupTest(t, driver)
defer f.cleanup()
registerTestDriver(testDriverName)
defer unregisterTestDriver(testDriverName)
oldStopCh := make(chan struct{})
f.updater.driverUpdaters.Store(testDriverName, oldStopCh)
verifyUpdaterState(t, f.updater, testDriverName, true)
// Replace the old updater with a new one
f.updater.syncDriverUpdater(testDriverName)
if !isChannelClosed(oldStopCh) {
t.Errorf("Previous stop channel was not closed during updater replacement")
}
// Verify a new entry was added and is different from old one
value, exists := f.updater.driverUpdaters.Load(testDriverName)
if !exists {
t.Errorf("No updater entry exists after replacement")
} else {
newStopCh, ok := value.(chan struct{})
if !ok {
t.Errorf("Updated entry is not a channel")
} else if reflect.ValueOf(newStopCh).Pointer() == reflect.ValueOf(oldStopCh).Pointer() {
t.Errorf("New stop channel is the same as the old one")
}
close(newStopCh)
}
})
}
func (f *testFixture) cleanup() {
close(f.stopCh)
}
func createTestDriver(name string, updatePeriodSeconds *int64) *v1.CSIDriver {
return &v1.CSIDriver{
ObjectMeta: metav1.ObjectMeta{
Name: name,
},
Spec: v1.CSIDriverSpec{
NodeAllocatableUpdatePeriodSeconds: updatePeriodSeconds,
},
}
}
func registerTestDriver(name string) {
csiDrivers.Set(name, Driver{
endpoint: "test-endpoint",
highestSupportedVersion: &utilversion.Version{},
})
}
func unregisterTestDriver(name string) {
csiDrivers.Delete(name)
}
func isChannelClosed(ch chan struct{}) bool {
select {
case <-ch:
return true
default:
return false
}
}
func verifyUpdaterState(t *testing.T, updater *csiNodeUpdater, driverName string, shouldExist bool) {
_, exists := updater.driverUpdaters.Load(driverName)
if shouldExist && !exists {
t.Errorf("Expected updater for driver %s to exist, but it doesn't", driverName)
} else if !shouldExist && exists {
t.Errorf("Expected updater for driver %s to not exist, but it does", driverName)
}
}

View File

@ -25,6 +25,7 @@ import (
"strings"
"time"
"google.golang.org/grpc/codes"
"k8s.io/klog/v2"
authenticationv1 "k8s.io/api/authentication/v1"
@ -39,6 +40,7 @@ import (
utilfeature "k8s.io/apiserver/pkg/util/feature"
clientset "k8s.io/client-go/kubernetes"
storagelisters "k8s.io/client-go/listers/storage/v1"
"k8s.io/client-go/tools/cache"
csitranslationplugins "k8s.io/csi-translation-lib/plugins"
"k8s.io/kubernetes/pkg/features"
"k8s.io/kubernetes/pkg/kubelet/util"
@ -64,6 +66,7 @@ const (
type csiPlugin struct {
host volume.VolumeHost
csiDriverLister storagelisters.CSIDriverLister
csiDriverInformer cache.SharedIndexInformer
serviceAccountTokenGetter func(namespace, name string, tr *authenticationv1.TokenRequest) (*authenticationv1.TokenRequest, error)
volumeAttachmentLister storagelisters.VolumeAttachmentLister
}
@ -81,6 +84,7 @@ var _ volume.VolumePlugin = &csiPlugin{}
// RegistrationHandler is the handler which is fed to the pluginwatcher API.
type RegistrationHandler struct {
csiPlugin *csiPlugin
}
// TODO (verult) consider using a struct instead of global variables
@ -90,6 +94,8 @@ var csiDrivers = &DriversStore{}
var nim nodeinfomanager.Interface
var csiNodeUpdaterVar *csiNodeUpdater
// PluginHandler is the plugin registration handler interface passed to the
// pluginwatcher module in kubelet
var PluginHandler = &RegistrationHandler{}
@ -156,9 +162,81 @@ func (h *RegistrationHandler) RegisterPlugin(pluginName string, endpoint string,
return err
}
if csiNodeUpdaterVar != nil {
csiNodeUpdaterVar.syncDriverUpdater(pluginName)
}
return nil
}
func updateCSIDriver(pluginName string) error {
csi, err := newCsiDriverClient(csiDriverName(pluginName))
if err != nil {
return fmt.Errorf("failed to create CSI client for driver %q: %w", pluginName, err)
}
ctx, cancel := context.WithTimeout(context.Background(), csiTimeout)
defer cancel()
driverNodeID, maxVolumePerNode, accessibleTopology, err := csi.NodeGetInfo(ctx)
if err != nil {
return fmt.Errorf("failed to get NodeGetInfo from driver %q: %w", pluginName, err)
}
if err := nim.UpdateCSIDriver(pluginName, driverNodeID, maxVolumePerNode, accessibleTopology); err != nil {
return fmt.Errorf("failed to update driver %q: %w", pluginName, err)
}
return nil
}
func (p *csiPlugin) VerifyExhaustedResource(spec *volume.Spec, nodeName types.NodeName) {
if spec == nil || spec.PersistentVolume == nil || spec.PersistentVolume.Spec.CSI == nil {
klog.ErrorS(nil, "Invalid volume spec for CSI", "nodeName", nodeName)
return
}
pluginName := spec.PersistentVolume.Spec.CSI.Driver
driver, err := p.getCSIDriver(pluginName)
if err != nil {
klog.ErrorS(err, "Failed to retrieve CSIDriver", "pluginName", pluginName)
return
}
period := getNodeAllocatableUpdatePeriod(driver)
if period == 0 {
return
}
volumeHandle := spec.PersistentVolume.Spec.CSI.VolumeHandle
attachmentName := getAttachmentName(volumeHandle, pluginName, string(nodeName))
kubeClient := p.host.GetKubeClient()
ctx, cancel := context.WithTimeout(context.Background(), csiTimeout)
defer cancel()
attachment, err := kubeClient.StorageV1().VolumeAttachments().Get(ctx, attachmentName, meta.GetOptions{})
if err != nil {
klog.ErrorS(err, "Failed to get volume attachment", "attachmentName", attachmentName)
return
}
if isResourceExhaustError(attachment) {
klog.V(4).InfoS("Detected ResourceExhausted error for volume", "pluginName", pluginName, "volumeHandle", volumeHandle)
if err := updateCSIDriver(pluginName); err != nil {
klog.ErrorS(err, "Failed to update CSIDriver", "pluginName", pluginName)
}
}
}
func isResourceExhaustError(attachment *storage.VolumeAttachment) bool {
if attachment == nil || attachment.Status.AttachError == nil {
return false
}
return attachment.Status.AttachError.ErrorCode != nil &&
*attachment.Status.AttachError.ErrorCode == int32(codes.ResourceExhausted)
}
func (h *RegistrationHandler) validateVersions(callerName, pluginName string, endpoint string, versions []string) (*utilversion.Version, error) {
if len(versions) == 0 {
return nil, errors.New(log("%s for CSI driver %q failed. Plugin returned an empty list for supported versions", callerName, pluginName))
@ -192,6 +270,10 @@ func (h *RegistrationHandler) DeRegisterPlugin(pluginName string) {
if err := unregisterDriver(pluginName); err != nil {
klog.Error(log("registrationHandler.DeRegisterPlugin failed: %v", err))
}
if csiNodeUpdaterVar != nil {
csiNodeUpdaterVar.syncDriverUpdater(pluginName)
}
}
func (p *csiPlugin) Init(host volume.VolumeHost) error {
@ -228,6 +310,13 @@ func (p *csiPlugin) Init(host volume.VolumeHost) error {
}
// We don't run the volumeAttachmentLister in the kubelet context
p.volumeAttachmentLister = nil
informerFactory := kletHost.GetInformerFactory()
if informerFactory == nil {
klog.Error(log("InformerFactory not found on KubeletVolumeHost"))
} else {
p.csiDriverInformer = informerFactory.Storage().V1().CSIDrivers().Informer()
}
}
}
@ -257,17 +346,17 @@ func (p *csiPlugin) Init(host volume.VolumeHost) error {
// Initializing the label management channels
nim = nodeinfomanager.NewNodeInfoManager(host.GetNodeName(), host, migratedPlugins)
PluginHandler.csiPlugin = p
// This function prevents Kubelet from posting Ready status until CSINode
// is both installed and initialized
if err := initializeCSINode(host); err != nil {
if err := initializeCSINode(host, p.csiDriverInformer); err != nil {
return errors.New(log("failed to initialize CSINode: %v", err))
}
return nil
}
func initializeCSINode(host volume.VolumeHost) error {
func initializeCSINode(host volume.VolumeHost, csiDriverInformer cache.SharedIndexInformer) error {
kvh, ok := host.(volume.KubeletVolumeHost)
if !ok {
klog.V(4).Info("Cast from VolumeHost to KubeletVolumeHost failed. Skipping CSINode initialization, not running on kubelet")
@ -322,6 +411,18 @@ func initializeCSINode(host volume.VolumeHost) error {
klog.Fatalf("Failed to initialize CSINode after retrying: %v", err)
}
}()
if utilfeature.DefaultFeatureGate.Enabled(features.MutableCSINodeAllocatableCount) && csiNodeUpdaterVar == nil {
if csiDriverInformer != nil {
var err error
csiNodeUpdaterVar, err = NewCSINodeUpdater(csiDriverInformer)
if err != nil {
klog.ErrorS(err, "Failed to create CSINodeUpdater")
} else {
go csiNodeUpdaterVar.Run()
}
}
}
return nil
}

View File

@ -24,6 +24,7 @@ import (
"testing"
"time"
"google.golang.org/grpc/codes"
api "k8s.io/api/core/v1"
storage "k8s.io/api/storage/v1"
meta "k8s.io/apimachinery/pkg/apis/meta/v1"
@ -1429,3 +1430,118 @@ func TestValidatePluginExistingDriver(t *testing.T) {
}
}
}
func TestGetNodeAllocatableUpdatePeriod(t *testing.T) {
tests := []struct {
name string
driver *storage.CSIDriver
expected time.Duration
}{
{
name: "nil driver",
driver: nil,
expected: 0,
},
{
name: "nil NodeAllocatableUpdatePeriodSeconds",
driver: &storage.CSIDriver{
Spec: storage.CSIDriverSpec{
NodeAllocatableUpdatePeriodSeconds: nil,
},
},
expected: 0,
},
{
name: "NodeAllocatableUpdatePeriodSeconds set to 60",
driver: &storage.CSIDriver{
Spec: storage.CSIDriverSpec{
NodeAllocatableUpdatePeriodSeconds: &[]int64{60}[0],
},
},
expected: 60 * time.Second,
},
}
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
actual := getNodeAllocatableUpdatePeriod(tc.driver)
if actual != tc.expected {
t.Errorf("Expected %v, got %v", tc.expected, actual)
}
})
}
}
func TestIsResourceExhaustError(t *testing.T) {
tests := []struct {
name string
attachment *storage.VolumeAttachment
expected bool
}{
{
name: "nil attachment",
attachment: nil,
expected: false,
},
{
name: "nil AttachError",
attachment: &storage.VolumeAttachment{
Status: storage.VolumeAttachmentStatus{
AttachError: nil,
},
},
expected: false,
},
{
name: "nil ErrorCode",
attachment: &storage.VolumeAttachment{
Status: storage.VolumeAttachmentStatus{
AttachError: &storage.VolumeError{
Message: "an error occurred",
ErrorCode: nil,
},
},
},
expected: false,
},
{
name: "non-resource exhausted error code",
attachment: &storage.VolumeAttachment{
Status: storage.VolumeAttachmentStatus{
AttachError: &storage.VolumeError{
Message: "volume not found",
ErrorCode: func() *int32 {
code := int32(codes.NotFound)
return &code
}(),
},
},
},
expected: false,
},
{
name: "resource exhausted error code",
attachment: &storage.VolumeAttachment{
Status: storage.VolumeAttachmentStatus{
AttachError: &storage.VolumeError{
Message: "resource exhausted",
ErrorCode: func() *int32 {
code := int32(codes.ResourceExhausted)
return &code
}(),
},
},
},
expected: true,
},
}
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
actual := isResourceExhaustError(tc.attachment)
if actual != tc.expected {
t.Errorf("Expected isResourceExhaustError to return %v, but got %v", tc.expected, actual)
}
})
}
}

View File

@ -84,6 +84,9 @@ type Interface interface {
// to other methods in this interface.
InstallCSIDriver(driverName string, driverNodeID string, maxVolumeLimit int64, topology map[string]string) error
// UpdateCSIDriver updates CSIDrivers field in the CSINode object.
UpdateCSIDriver(driverName string, driverNodeID string, maxAttachLimit int64, topology map[string]string) error
// Remove in the cluster node information from the CSI driver with the given name.
// Concurrent calls to UninstallCSIDriver() is allowed, but they should not be intertwined with calls
// to other methods in this interface.
@ -130,6 +133,15 @@ func (nim *nodeInfoManager) InstallCSIDriver(driverName string, driverNodeID str
return nil
}
// UpdateCSIDriver updates CSIDrivers field in the CSINode object.
func (nim *nodeInfoManager) UpdateCSIDriver(driverName string, driverNodeID string, maxAttachLimit int64, topology map[string]string) error {
err := nim.updateCSINode(driverName, driverNodeID, maxAttachLimit, topology)
if err != nil {
return fmt.Errorf("error updating CSINode object with CSI driver node info: %w", err)
}
return nil
}
// UninstallCSIDriver removes the node ID annotation from the Node object and CSIDrivers field from the
// CSINode object. If the CSINodeInfo object contains no CSIDrivers, it will be deleted.
// If multiple calls to UninstallCSIDriver() are made in parallel, some calls might receive Node or

View File

@ -74,6 +74,8 @@ func (attacher *fcAttacher) VolumesAreAttached(specs []*volume.Spec, nodeName ty
return volumesAttachedCheck, nil
}
func (plugin *fcPlugin) VerifyExhaustedResource(spec *volume.Spec, nodeName types.NodeName) {}
func (attacher *fcAttacher) WaitForAttach(spec *volume.Spec, devicePath string, _ *v1.Pod, timeout time.Duration) (string, error) {
mounter, err := volumeSpecToMounter(spec, attacher.host)
if err != nil {

View File

@ -101,6 +101,8 @@ func (plugin *flexVolumePlugin) Init(host volume.VolumeHost) error {
return nil
}
func (plugin *flexVolumePlugin) VerifyExhaustedResource(spec *volume.Spec, nodeName types.NodeName) {}
func (plugin *flexVolumePlugin) getExecutable() string {
parts := strings.Split(plugin.driverName, "/")
execName := parts[len(parts)-1]

View File

@ -53,6 +53,8 @@ func (plugin *iscsiPlugin) NewAttacher() (volume.Attacher, error) {
}, nil
}
func (plugin *iscsiPlugin) VerifyExhaustedResource(spec *volume.Spec, nodeName types.NodeName) {}
func (plugin *iscsiPlugin) NewDeviceMounter() (volume.DeviceMounter, error) {
return plugin.NewAttacher()
}

View File

@ -234,6 +234,7 @@ type AttachableVolumePlugin interface {
NewDetacher() (Detacher, error)
// CanAttach tests if provided volume spec is attachable
CanAttach(spec *Spec) (bool, error)
VerifyExhaustedResource(spec *Spec, nodeName types.NodeName)
}
// DeviceMountableVolumePlugin is an extended interface of VolumePlugin and is used

View File

@ -437,6 +437,8 @@ func (plugin *FakeVolumePlugin) CanAttach(spec *volume.Spec) (bool, error) {
return !plugin.NonAttachable, nil
}
func (plugin *FakeVolumePlugin) VerifyExhaustedResource(spec *volume.Spec, nodeName types.NodeName) {}
func (plugin *FakeVolumePlugin) CanDeviceMount(spec *volume.Spec) (bool, error) {
return true, nil
}
@ -617,6 +619,9 @@ func (f *FakeAttachableVolumePlugin) CanAttach(spec *volume.Spec) (bool, error)
return true, nil
}
func (f *FakeAttachableVolumePlugin) VerifyExhaustedResource(spec *volume.Spec, nodeName types.NodeName) {
}
var _ volume.VolumePlugin = &FakeAttachableVolumePlugin{}
var _ volume.AttachableVolumePlugin = &FakeAttachableVolumePlugin{}

View File

@ -1477,6 +1477,13 @@ func (og *operationGenerator) GenerateVerifyControllerAttachedVolumeFunc(
}
}
// Volume is not attached - check if this is due to resource exhaustion before returning the error
if utilfeature.DefaultFeatureGate.Enabled(features.MutableCSINodeAllocatableCount) {
if attachablePlugin, pluginErr := og.volumePluginMgr.FindAttachablePluginBySpec(volumeToMount.VolumeSpec); pluginErr == nil && attachablePlugin != nil {
attachablePlugin.VerifyExhaustedResource(volumeToMount.VolumeSpec, nodeName)
}
}
// Volume not attached, return error. Caller will log and retry.
eventErr, detailedErr := volumeToMount.GenerateError("Volume not attached according to node status", nil)
return volumetypes.NewOperationContext(eventErr, detailedErr, migrated)

View File

@ -609,111 +609,114 @@ func init() {
}
var fileDescriptor_662262cc70094b41 = []byte{
// 1655 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x58, 0xbd, 0x6f, 0x1b, 0xc9,
0x15, 0xd7, 0x8a, 0xd4, 0xd7, 0x50, 0xb2, 0xa4, 0x91, 0xe4, 0x30, 0x2a, 0x48, 0x61, 0xed, 0x24,
0xb2, 0x13, 0x2f, 0x6d, 0xd9, 0x31, 0x0c, 0x07, 0x2e, 0xb4, 0x12, 0x1d, 0x0b, 0x11, 0x25, 0x65,
0xa8, 0x18, 0x46, 0x90, 0x04, 0x1e, 0xed, 0x8e, 0xa8, 0xb1, 0xb8, 0x1f, 0xde, 0x19, 0x2a, 0x62,
0xaa, 0xa4, 0x49, 0x17, 0x20, 0x69, 0xf3, 0x57, 0x24, 0x40, 0xd2, 0x5c, 0x79, 0xc5, 0xc1, 0xd7,
0x19, 0x57, 0xb9, 0x22, 0xce, 0xbc, 0xfa, 0xae, 0xbc, 0x42, 0xd5, 0x61, 0x66, 0x87, 0xdc, 0x0f,
0x2e, 0x65, 0xa9, 0x61, 0xc7, 0x99, 0xf7, 0xde, 0xef, 0xbd, 0x99, 0xf7, 0xde, 0x6f, 0xde, 0x12,
0xfc, 0xe4, 0xf4, 0x09, 0x33, 0xa8, 0x57, 0xc1, 0x3e, 0xad, 0x30, 0xee, 0x05, 0xb8, 0x41, 0x2a,
0x67, 0x0f, 0x2a, 0x0d, 0xe2, 0x92, 0x00, 0x73, 0x62, 0x1b, 0x7e, 0xe0, 0x71, 0x0f, 0xae, 0x84,
0x6a, 0x06, 0xf6, 0xa9, 0xa1, 0xd4, 0x8c, 0xb3, 0x07, 0xab, 0xf7, 0x1a, 0x94, 0x9f, 0xb4, 0x8e,
0x0c, 0xcb, 0x73, 0x2a, 0x0d, 0xaf, 0xe1, 0x55, 0xa4, 0xf6, 0x51, 0xeb, 0x58, 0xae, 0xe4, 0x42,
0xfe, 0x0a, 0x51, 0x56, 0xf5, 0x98, 0x33, 0xcb, 0x0b, 0xb2, 0x3c, 0xad, 0x3e, 0x8a, 0x74, 0x1c,
0x6c, 0x9d, 0x50, 0x97, 0x04, 0xed, 0x8a, 0x7f, 0xda, 0x90, 0x46, 0x01, 0x61, 0x5e, 0x2b, 0xb0,
0xc8, 0xb5, 0xac, 0x58, 0xc5, 0x21, 0x1c, 0x67, 0xf9, 0xaa, 0x0c, 0xb3, 0x0a, 0x5a, 0x2e, 0xa7,
0xce, 0xa0, 0x9b, 0xc7, 0x9f, 0x32, 0x60, 0xd6, 0x09, 0x71, 0x70, 0xda, 0x4e, 0xff, 0xbf, 0x06,
0x66, 0xb6, 0xea, 0x3b, 0xdb, 0x01, 0x3d, 0x23, 0x01, 0x7c, 0x0d, 0xa6, 0x45, 0x44, 0x36, 0xe6,
0xb8, 0xa8, 0xad, 0x69, 0xeb, 0x85, 0x8d, 0xfb, 0x46, 0x74, 0xbf, 0x7d, 0x60, 0xc3, 0x3f, 0x6d,
0x88, 0x0d, 0x66, 0x08, 0x6d, 0xe3, 0xec, 0x81, 0xb1, 0x7f, 0xf4, 0x86, 0x58, 0xbc, 0x46, 0x38,
0x36, 0xe1, 0xbb, 0x4e, 0x79, 0xac, 0xdb, 0x29, 0x83, 0x68, 0x0f, 0xf5, 0x51, 0xe1, 0x73, 0x90,
0x67, 0x3e, 0xb1, 0x8a, 0xe3, 0x12, 0xfd, 0xb6, 0x91, 0x99, 0x3d, 0xa3, 0x1f, 0x51, 0xdd, 0x27,
0x96, 0x39, 0xab, 0x10, 0xf3, 0x62, 0x85, 0xa4, 0xbd, 0xfe, 0x3f, 0x0d, 0xcc, 0xf5, 0xb5, 0x76,
0x29, 0xe3, 0xf0, 0x0f, 0x03, 0xb1, 0x1b, 0x57, 0x8b, 0x5d, 0x58, 0xcb, 0xc8, 0x17, 0x94, 0x9f,
0xe9, 0xde, 0x4e, 0x2c, 0xee, 0x2a, 0x98, 0xa0, 0x9c, 0x38, 0xac, 0x38, 0xbe, 0x96, 0x5b, 0x2f,
0x6c, 0xac, 0x7d, 0x2a, 0x70, 0x73, 0x4e, 0x81, 0x4d, 0xec, 0x08, 0x33, 0x14, 0x5a, 0xeb, 0x5f,
0xe5, 0x63, 0x61, 0x8b, 0xe3, 0xc0, 0xa7, 0xe0, 0x06, 0xe6, 0x1c, 0x5b, 0x27, 0x88, 0xbc, 0x6d,
0xd1, 0x80, 0xd8, 0x32, 0xf8, 0x69, 0x13, 0x76, 0x3b, 0xe5, 0x1b, 0x9b, 0x09, 0x09, 0x4a, 0x69,
0x0a, 0x5b, 0xdf, 0xb3, 0x77, 0xdc, 0x63, 0x6f, 0xdf, 0xad, 0x79, 0x2d, 0x97, 0xcb, 0x6b, 0x55,
0xb6, 0x07, 0x09, 0x09, 0x4a, 0x69, 0x42, 0x0b, 0x2c, 0x9f, 0x79, 0xcd, 0x96, 0x43, 0x76, 0xe9,
0x31, 0xb1, 0xda, 0x56, 0x93, 0xd4, 0x3c, 0x9b, 0xb0, 0x62, 0x6e, 0x2d, 0xb7, 0x3e, 0x63, 0x56,
0xba, 0x9d, 0xf2, 0xf2, 0xcb, 0x0c, 0xf9, 0x45, 0xa7, 0xbc, 0x94, 0xb1, 0x8f, 0x32, 0xc1, 0xe0,
0x33, 0x30, 0xaf, 0x2e, 0x67, 0x0b, 0xfb, 0xd8, 0xa2, 0xbc, 0x5d, 0xcc, 0xcb, 0x08, 0x97, 0xba,
0x9d, 0xf2, 0x7c, 0x3d, 0x29, 0x42, 0x69, 0x5d, 0xf8, 0x02, 0xcc, 0x1d, 0xb3, 0x5f, 0x07, 0x5e,
0xcb, 0x3f, 0xf0, 0x9a, 0xd4, 0x6a, 0x17, 0x27, 0xd6, 0xb4, 0xf5, 0x19, 0x53, 0xef, 0x76, 0xca,
0x73, 0xcf, 0xeb, 0x31, 0xc1, 0x45, 0x7a, 0x03, 0x25, 0x0d, 0xe1, 0x6b, 0x30, 0xc7, 0xbd, 0x53,
0xe2, 0x8a, 0xab, 0x23, 0x8c, 0xb3, 0xe2, 0xa4, 0x4c, 0xe3, 0xad, 0x21, 0x69, 0x3c, 0x8c, 0xe9,
0x9a, 0x2b, 0x2a, 0x93, 0x73, 0xf1, 0x5d, 0x86, 0x92, 0x80, 0x70, 0x0b, 0x2c, 0x06, 0x61, 0x5e,
0x18, 0x22, 0x7e, 0xeb, 0xa8, 0x49, 0xd9, 0x49, 0x71, 0x4a, 0x1e, 0x76, 0xa5, 0xdb, 0x29, 0x2f,
0xa2, 0xb4, 0x10, 0x0d, 0xea, 0xc3, 0x47, 0x60, 0x96, 0x91, 0x5d, 0xea, 0xb6, 0xce, 0xc3, 0x74,
0x4e, 0x4b, 0xfb, 0x85, 0x6e, 0xa7, 0x3c, 0x5b, 0xaf, 0x46, 0xfb, 0x28, 0xa1, 0xa5, 0xff, 0x57,
0x03, 0x53, 0x5b, 0xf5, 0x9d, 0x3d, 0xcf, 0x26, 0x23, 0xe8, 0xe0, 0xed, 0x44, 0x07, 0xeb, 0xc3,
0x1b, 0x41, 0xc4, 0x33, 0xb4, 0x7f, 0xbf, 0x0b, 0xfb, 0x57, 0xe8, 0x28, 0xee, 0x59, 0x03, 0x79,
0x17, 0x3b, 0x44, 0x46, 0x3d, 0x13, 0xd9, 0xec, 0x61, 0x87, 0x20, 0x29, 0x81, 0x3f, 0x05, 0x93,
0xae, 0x67, 0x93, 0x9d, 0x6d, 0xe9, 0x7b, 0xc6, 0xbc, 0xa1, 0x74, 0x26, 0xf7, 0xe4, 0x2e, 0x52,
0x52, 0x71, 0x8b, 0xdc, 0xf3, 0xbd, 0xa6, 0xd7, 0x68, 0xff, 0x86, 0xb4, 0x7b, 0x25, 0x2d, 0x6f,
0xf1, 0x30, 0xb6, 0x8f, 0x12, 0x5a, 0xf0, 0x8f, 0xa0, 0x80, 0x9b, 0x4d, 0xcf, 0xc2, 0x1c, 0x1f,
0x35, 0x89, 0xac, 0xd3, 0xc2, 0xc6, 0xdd, 0x21, 0xc7, 0x0b, 0x5b, 0x40, 0xf8, 0x45, 0x8a, 0xf8,
0x99, 0x39, 0xdf, 0xed, 0x94, 0x0b, 0x9b, 0x11, 0x04, 0x8a, 0xe3, 0xe9, 0xff, 0xd1, 0x40, 0x41,
0x1d, 0x78, 0x04, 0x74, 0xb5, 0x95, 0xa4, 0xab, 0xd2, 0xe5, 0x59, 0x1a, 0x42, 0x56, 0x7f, 0xea,
0x47, 0x2c, 0x99, 0x6a, 0x1f, 0x4c, 0xd9, 0x32, 0x55, 0xac, 0xa8, 0x49, 0xd4, 0xdb, 0x97, 0xa3,
0x2a, 0x22, 0x9c, 0x57, 0xd8, 0x53, 0xe1, 0x9a, 0xa1, 0x1e, 0x8a, 0xfe, 0x7d, 0x0e, 0xc0, 0xad,
0xfa, 0x4e, 0x8a, 0x06, 0x46, 0x50, 0xc2, 0x14, 0xcc, 0x8a, 0x52, 0xe9, 0x15, 0x83, 0x2a, 0xe5,
0x87, 0x57, 0xbc, 0x7f, 0x7c, 0x44, 0x9a, 0x75, 0xd2, 0x24, 0x16, 0xf7, 0x82, 0xb0, 0xaa, 0xf6,
0x62, 0x60, 0x28, 0x01, 0x0d, 0xb7, 0xc1, 0x42, 0x8f, 0xd5, 0x9a, 0x98, 0x31, 0x51, 0xcd, 0xc5,
0x9c, 0xac, 0xde, 0xa2, 0x0a, 0x71, 0xa1, 0x9e, 0x92, 0xa3, 0x01, 0x0b, 0xf8, 0x0a, 0x4c, 0x5b,
0x71, 0x02, 0xfd, 0x44, 0xb1, 0x18, 0xbd, 0x69, 0xc4, 0xf8, 0x6d, 0x0b, 0xbb, 0x9c, 0xf2, 0xb6,
0x39, 0x2b, 0x0a, 0xa5, 0xcf, 0xb4, 0x7d, 0x34, 0xc8, 0xc0, 0xa2, 0x83, 0xcf, 0xa9, 0xd3, 0x72,
0xc2, 0x92, 0xae, 0xd3, 0xbf, 0x10, 0x49, 0xb3, 0xd7, 0x77, 0x21, 0x69, 0xae, 0x96, 0x06, 0x43,
0x83, 0xf8, 0xfa, 0x17, 0x1a, 0xb8, 0x39, 0x98, 0xf8, 0x11, 0xb4, 0xc5, 0x5e, 0xb2, 0x2d, 0xee,
0x0c, 0x2f, 0xe0, 0x54, 0x6c, 0x43, 0x3a, 0xe4, 0x1f, 0x93, 0x60, 0x36, 0x9e, 0xbe, 0x11, 0xd4,
0xee, 0x2f, 0x41, 0xc1, 0x0f, 0xbc, 0x33, 0xca, 0xa8, 0xe7, 0x92, 0x40, 0x31, 0xe1, 0x92, 0x32,
0x29, 0x1c, 0x44, 0x22, 0x14, 0xd7, 0x83, 0x0d, 0x00, 0x7c, 0x1c, 0x60, 0x87, 0x70, 0xd1, 0xbf,
0x39, 0x79, 0xfc, 0x87, 0x43, 0x8e, 0x1f, 0x3f, 0x91, 0x71, 0xd0, 0xb7, 0xaa, 0xba, 0x3c, 0x68,
0x47, 0xd1, 0x45, 0x02, 0x14, 0x83, 0x86, 0xa7, 0x60, 0x2e, 0x20, 0x56, 0x13, 0x53, 0x47, 0xbd,
0xd9, 0x79, 0x19, 0x61, 0x55, 0x3c, 0xa0, 0x28, 0x2e, 0xb8, 0xe8, 0x94, 0xef, 0x0f, 0x4e, 0xdd,
0xc6, 0x01, 0x09, 0x18, 0x65, 0x9c, 0xb8, 0x3c, 0x2c, 0x98, 0x84, 0x0d, 0x4a, 0x62, 0x0b, 0xa6,
0x77, 0xc4, 0x13, 0xb8, 0xef, 0x73, 0xea, 0xb9, 0xac, 0x38, 0x11, 0x31, 0x7d, 0x2d, 0xb6, 0x8f,
0x12, 0x5a, 0x70, 0x17, 0x2c, 0x0b, 0x66, 0xfe, 0x73, 0xe8, 0xa0, 0x7a, 0xee, 0x63, 0x57, 0xdc,
0x52, 0x71, 0x52, 0xbe, 0xb6, 0x45, 0x31, 0xfa, 0x6c, 0x66, 0xc8, 0x51, 0xa6, 0x15, 0x7c, 0x05,
0x16, 0xc3, 0xd9, 0xc7, 0xa4, 0xae, 0x4d, 0xdd, 0x86, 0x98, 0x7c, 0xe4, 0xc3, 0x3f, 0x63, 0xde,
0x15, 0x1d, 0xf1, 0x32, 0x2d, 0xbc, 0xc8, 0xda, 0x44, 0x83, 0x20, 0xf0, 0x2d, 0x58, 0x94, 0x1e,
0x89, 0xad, 0xe8, 0x84, 0x12, 0x56, 0x9c, 0x96, 0xa9, 0x5b, 0x8f, 0xa7, 0x4e, 0x5c, 0x5d, 0x38,
0xb5, 0x84, 0xa4, 0xd3, 0x23, 0xa7, 0x43, 0x12, 0x38, 0xe6, 0x8f, 0x55, 0xbe, 0x16, 0x37, 0xd3,
0x50, 0x68, 0x10, 0x7d, 0xf5, 0x19, 0x98, 0x4f, 0x25, 0x1c, 0x2e, 0x80, 0xdc, 0x29, 0x69, 0x87,
0xcf, 0x32, 0x12, 0x3f, 0xe1, 0x32, 0x98, 0x38, 0xc3, 0xcd, 0x16, 0x09, 0x8b, 0x0f, 0x85, 0x8b,
0xa7, 0xe3, 0x4f, 0x34, 0xfd, 0x33, 0x0d, 0x24, 0xe8, 0x6c, 0x04, 0x2d, 0xfd, 0x22, 0xd9, 0xd2,
0xb7, 0xae, 0x50, 0xd3, 0x43, 0x9a, 0xf9, 0x6f, 0x1a, 0x98, 0x8d, 0x8f, 0x78, 0xf0, 0x17, 0x60,
0x1a, 0xb7, 0x6c, 0x4a, 0x5c, 0xab, 0x37, 0x95, 0xf4, 0x03, 0xd9, 0x54, 0xfb, 0xa8, 0xaf, 0x21,
0x06, 0x40, 0x72, 0xee, 0xd3, 0x00, 0x8b, 0x22, 0xab, 0x13, 0xcb, 0x73, 0x6d, 0x26, 0x6f, 0x28,
0x17, 0x32, 0x63, 0x35, 0x2d, 0x44, 0x83, 0xfa, 0xfa, 0xbf, 0xc7, 0xc1, 0x42, 0x58, 0x1b, 0xe1,
0xe8, 0xef, 0x10, 0x97, 0x8f, 0x80, 0x54, 0x6a, 0x89, 0x99, 0xee, 0xe7, 0x97, 0x0e, 0x3d, 0x51,
0x60, 0xc3, 0x86, 0x3b, 0xf8, 0x3b, 0x30, 0xc9, 0x38, 0xe6, 0x2d, 0x26, 0x9f, 0xba, 0xc2, 0xc6,
0xbd, 0xab, 0x02, 0x4a, 0xa3, 0x68, 0xae, 0x0b, 0xd7, 0x48, 0x81, 0xe9, 0x9f, 0x6b, 0x60, 0x39,
0x6d, 0x32, 0x82, 0x0a, 0xdb, 0x4d, 0x56, 0xd8, 0xcf, 0xae, 0x78, 0x98, 0x61, 0x5f, 0x80, 0x1a,
0xb8, 0x39, 0x70, 0x6e, 0xf9, 0x92, 0x0a, 0x5e, 0xf2, 0x53, 0xec, 0xb7, 0x17, 0x4d, 0xc4, 0x92,
0x97, 0x0e, 0x32, 0xe4, 0x28, 0xd3, 0x0a, 0xbe, 0x01, 0x0b, 0xd4, 0x6d, 0x52, 0x97, 0xa8, 0x87,
0x37, 0xca, 0x6f, 0x26, 0x79, 0xa4, 0x91, 0x65, 0x72, 0x97, 0xc5, 0x7c, 0xb2, 0x93, 0x42, 0x41,
0x03, 0xb8, 0xfa, 0x97, 0x19, 0x99, 0x91, 0x33, 0xa3, 0x68, 0x21, 0xb9, 0x43, 0x82, 0x81, 0x16,
0x52, 0xfb, 0xa8, 0xaf, 0x21, 0xeb, 0x46, 0x5e, 0x85, 0x0a, 0xf4, 0xca, 0x75, 0x23, 0x8d, 0x62,
0x75, 0x23, 0xd7, 0x48, 0x81, 0x89, 0x20, 0xc4, 0x4c, 0x16, 0x9b, 0xbd, 0xfa, 0x41, 0xec, 0xa9,
0x7d, 0xd4, 0xd7, 0xd0, 0xbf, 0xcd, 0x65, 0x24, 0x48, 0x16, 0x60, 0xec, 0x34, 0xbd, 0xaf, 0xf4,
0xf4, 0x69, 0xec, 0xfe, 0x69, 0x6c, 0xf8, 0x2f, 0x0d, 0x40, 0xdc, 0x87, 0xa8, 0xf5, 0x0a, 0x34,
0xac, 0xa2, 0xea, 0xb5, 0x5a, 0xc2, 0xd8, 0x1c, 0xc0, 0x09, 0x5f, 0xe3, 0x55, 0xe5, 0x1f, 0x0e,
0x2a, 0xa0, 0x0c, 0xe7, 0xd0, 0x06, 0x85, 0x70, 0xb7, 0x1a, 0x04, 0x5e, 0xa0, 0xda, 0x53, 0xbf,
0x34, 0x16, 0xa9, 0x69, 0x96, 0xe4, 0xc7, 0x4d, 0x64, 0x7a, 0xd1, 0x29, 0x17, 0x62, 0x72, 0x14,
0x87, 0x15, 0x5e, 0x6c, 0x12, 0x79, 0xc9, 0x5f, 0xcf, 0xcb, 0x36, 0x19, 0xee, 0x25, 0x06, 0xbb,
0x5a, 0x05, 0x3f, 0x1a, 0x72, 0x2d, 0xd7, 0x7a, 0xb3, 0xfe, 0xae, 0x81, 0xb8, 0x0f, 0xb8, 0x0b,
0xf2, 0x9c, 0xaa, 0xae, 0x4b, 0x7e, 0x00, 0x5e, 0x42, 0x24, 0x87, 0xd4, 0x21, 0x11, 0x15, 0x8a,
0x15, 0x92, 0x28, 0xf0, 0x0e, 0x98, 0x72, 0x08, 0x63, 0xb8, 0xa1, 0x3c, 0x47, 0x9f, 0x43, 0xb5,
0x70, 0x1b, 0xf5, 0xe4, 0xfa, 0x63, 0xb0, 0x94, 0xf1, 0x59, 0x09, 0xcb, 0x60, 0xc2, 0x92, 0x7f,
0x06, 0x88, 0x80, 0x26, 0xcc, 0x19, 0xc1, 0x28, 0x5b, 0xf2, 0x5f, 0x80, 0x70, 0xdf, 0xfc, 0xd5,
0xbb, 0x8f, 0xa5, 0xb1, 0xf7, 0x1f, 0x4b, 0x63, 0x1f, 0x3e, 0x96, 0xc6, 0xfe, 0xda, 0x2d, 0x69,
0xef, 0xba, 0x25, 0xed, 0x7d, 0xb7, 0xa4, 0x7d, 0xe8, 0x96, 0xb4, 0xaf, 0xbb, 0x25, 0xed, 0x9f,
0xdf, 0x94, 0xc6, 0x7e, 0xbf, 0x92, 0xf9, 0x77, 0xea, 0x0f, 0x01, 0x00, 0x00, 0xff, 0xff, 0x7a,
0x55, 0x95, 0x9f, 0x66, 0x15, 0x00, 0x00,
// 1711 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x58, 0x4b, 0x73, 0x2b, 0x47,
0x15, 0xf6, 0x58, 0x96, 0x6d, 0xb5, 0xac, 0x6b, 0xbb, 0xaf, 0x1d, 0x06, 0x2f, 0x24, 0xd7, 0x24,
0x04, 0x27, 0x21, 0xa3, 0x5c, 0x27, 0xa4, 0x52, 0xa1, 0xb2, 0xf0, 0xc8, 0x0a, 0x71, 0x61, 0xd9,
0xa6, 0xe5, 0xa4, 0x52, 0x14, 0x50, 0x69, 0xcf, 0xb4, 0xe5, 0x8e, 0x35, 0x8f, 0x4c, 0xb7, 0x84,
0xc5, 0x0a, 0x7e, 0x00, 0x55, 0xb0, 0xe5, 0x57, 0x40, 0x01, 0x1b, 0x96, 0x2c, 0xa8, 0x0b, 0xab,
0x14, 0xab, 0xbb, 0x52, 0x71, 0xc5, 0x1a, 0x96, 0x2c, 0xbc, 0x4a, 0x75, 0x4f, 0x4b, 0xf3, 0xd0,
0xc8, 0x8f, 0x8d, 0x76, 0xea, 0xf3, 0xf8, 0xce, 0xe9, 0x3e, 0xa7, 0xbf, 0x3e, 0x23, 0xf0, 0x9d,
0xeb, 0x0f, 0x98, 0x49, 0xfd, 0x3a, 0x0e, 0x68, 0x9d, 0x71, 0x3f, 0xc4, 0x1d, 0x52, 0xef, 0x3f,
0xab, 0x77, 0x88, 0x47, 0x42, 0xcc, 0x89, 0x63, 0x06, 0xa1, 0xcf, 0x7d, 0xb8, 0x1d, 0x99, 0x99,
0x38, 0xa0, 0xa6, 0x32, 0x33, 0xfb, 0xcf, 0x76, 0xde, 0xee, 0x50, 0x7e, 0xd5, 0xbb, 0x30, 0x6d,
0xdf, 0xad, 0x77, 0xfc, 0x8e, 0x5f, 0x97, 0xd6, 0x17, 0xbd, 0x4b, 0xb9, 0x92, 0x0b, 0xf9, 0x2b,
0x42, 0xd9, 0x31, 0x12, 0xc1, 0x6c, 0x3f, 0xcc, 0x8b, 0xb4, 0xf3, 0x5e, 0x6c, 0xe3, 0x62, 0xfb,
0x8a, 0x7a, 0x24, 0x1c, 0xd4, 0x83, 0xeb, 0x8e, 0x74, 0x0a, 0x09, 0xf3, 0x7b, 0xa1, 0x4d, 0x1e,
0xe5, 0xc5, 0xea, 0x2e, 0xe1, 0x38, 0x2f, 0x56, 0x7d, 0x96, 0x57, 0xd8, 0xf3, 0x38, 0x75, 0xa7,
0xc3, 0xbc, 0x7f, 0x9f, 0x03, 0xb3, 0xaf, 0x88, 0x8b, 0xb3, 0x7e, 0xc6, 0x5f, 0x34, 0x50, 0x6a,
0xb4, 0x8f, 0x0e, 0x43, 0xda, 0x27, 0x21, 0xfc, 0x02, 0xac, 0x8a, 0x8c, 0x1c, 0xcc, 0xb1, 0xae,
0xed, 0x6a, 0x7b, 0xe5, 0xfd, 0x77, 0xcc, 0xf8, 0x7c, 0x27, 0xc0, 0x66, 0x70, 0xdd, 0x11, 0x02,
0x66, 0x0a, 0x6b, 0xb3, 0xff, 0xcc, 0x3c, 0xbd, 0xf8, 0x92, 0xd8, 0xbc, 0x45, 0x38, 0xb6, 0xe0,
0xf3, 0x61, 0x6d, 0x61, 0x34, 0xac, 0x81, 0x58, 0x86, 0x26, 0xa8, 0xf0, 0x63, 0xb0, 0xc4, 0x02,
0x62, 0xeb, 0x8b, 0x12, 0xfd, 0x35, 0x33, 0xb7, 0x7a, 0xe6, 0x24, 0xa3, 0x76, 0x40, 0x6c, 0x6b,
0x4d, 0x21, 0x2e, 0x89, 0x15, 0x92, 0xfe, 0xc6, 0x9f, 0x35, 0x50, 0x99, 0x58, 0x1d, 0x53, 0xc6,
0xe1, 0x4f, 0xa7, 0x72, 0x37, 0x1f, 0x96, 0xbb, 0xf0, 0x96, 0x99, 0x6f, 0xa8, 0x38, 0xab, 0x63,
0x49, 0x22, 0xef, 0x26, 0x28, 0x52, 0x4e, 0x5c, 0xa6, 0x2f, 0xee, 0x16, 0xf6, 0xca, 0xfb, 0xbb,
0xf7, 0x25, 0x6e, 0x55, 0x14, 0x58, 0xf1, 0x48, 0xb8, 0xa1, 0xc8, 0xdb, 0xf8, 0x67, 0x31, 0x91,
0xb6, 0xd8, 0x0e, 0xfc, 0x10, 0x3c, 0xc1, 0x9c, 0x63, 0xfb, 0x0a, 0x91, 0xaf, 0x7a, 0x34, 0x24,
0x8e, 0x4c, 0x7e, 0xd5, 0x82, 0xa3, 0x61, 0xed, 0xc9, 0x41, 0x4a, 0x83, 0x32, 0x96, 0xc2, 0x37,
0xf0, 0x9d, 0x23, 0xef, 0xd2, 0x3f, 0xf5, 0x5a, 0x7e, 0xcf, 0xe3, 0xf2, 0x58, 0x95, 0xef, 0x59,
0x4a, 0x83, 0x32, 0x96, 0xd0, 0x06, 0x5b, 0x7d, 0xbf, 0xdb, 0x73, 0xc9, 0x31, 0xbd, 0x24, 0xf6,
0xc0, 0xee, 0x92, 0x96, 0xef, 0x10, 0xa6, 0x17, 0x76, 0x0b, 0x7b, 0x25, 0xab, 0x3e, 0x1a, 0xd6,
0xb6, 0x3e, 0xcb, 0xd1, 0xdf, 0x0e, 0x6b, 0x4f, 0x73, 0xe4, 0x28, 0x17, 0x0c, 0x7e, 0x04, 0xd6,
0xd5, 0xe1, 0x34, 0x70, 0x80, 0x6d, 0xca, 0x07, 0xfa, 0x92, 0xcc, 0xf0, 0xe9, 0x68, 0x58, 0x5b,
0x6f, 0xa7, 0x55, 0x28, 0x6b, 0x0b, 0x3f, 0x01, 0x95, 0x4b, 0xf6, 0xc3, 0xd0, 0xef, 0x05, 0x67,
0x7e, 0x97, 0xda, 0x03, 0xbd, 0xb8, 0xab, 0xed, 0x95, 0x2c, 0x63, 0x34, 0xac, 0x55, 0x3e, 0x6e,
0x27, 0x14, 0xb7, 0x59, 0x01, 0x4a, 0x3b, 0xc2, 0x2f, 0x40, 0x85, 0xfb, 0xd7, 0xc4, 0x13, 0x47,
0x47, 0x18, 0x67, 0xfa, 0xb2, 0x2c, 0xe3, 0xab, 0x33, 0xca, 0x78, 0x9e, 0xb0, 0xb5, 0xb6, 0x55,
0x25, 0x2b, 0x49, 0x29, 0x43, 0x69, 0x40, 0xd8, 0x00, 0x9b, 0x61, 0x54, 0x17, 0x86, 0x48, 0xd0,
0xbb, 0xe8, 0x52, 0x76, 0xa5, 0xaf, 0xc8, 0xcd, 0x6e, 0x8f, 0x86, 0xb5, 0x4d, 0x94, 0x55, 0xa2,
0x69, 0x7b, 0xf8, 0x1e, 0x58, 0x63, 0xe4, 0x98, 0x7a, 0xbd, 0x9b, 0xa8, 0x9c, 0xab, 0xd2, 0x7f,
0x63, 0x34, 0xac, 0xad, 0xb5, 0x9b, 0xb1, 0x1c, 0xa5, 0xac, 0x60, 0x1f, 0x18, 0x9e, 0xef, 0x90,
0x83, 0x6e, 0xd7, 0xb7, 0x31, 0xc7, 0x17, 0x5d, 0xf2, 0x69, 0xe0, 0x60, 0x4e, 0xce, 0x48, 0x48,
0x7d, 0xa7, 0x4d, 0x6c, 0xdf, 0x73, 0x98, 0x5e, 0xda, 0xd5, 0xf6, 0x0a, 0xd6, 0xeb, 0xa3, 0x61,
0xcd, 0x38, 0xb9, 0xd7, 0x1a, 0x3d, 0x00, 0xd1, 0xf8, 0xa3, 0x06, 0x56, 0x1a, 0xed, 0x23, 0x81,
0x36, 0x07, 0xe6, 0x38, 0x4c, 0x31, 0x87, 0x31, 0xfb, 0x02, 0x8a, 0x7c, 0x66, 0xf2, 0xc6, 0xff,
0x22, 0xde, 0x10, 0x36, 0x8a, 0xf3, 0x76, 0xc1, 0x92, 0x87, 0x5d, 0x22, 0xb3, 0x2e, 0xc5, 0x3e,
0x27, 0xd8, 0x25, 0x48, 0x6a, 0xe0, 0xeb, 0x60, 0x59, 0x9c, 0xc6, 0xd1, 0xa1, 0x8c, 0x5d, 0xb2,
0x9e, 0x28, 0x9b, 0xe5, 0x13, 0x29, 0x45, 0x4a, 0x2b, 0xaa, 0xc7, 0xfd, 0xc0, 0xef, 0xfa, 0x9d,
0xc1, 0x8f, 0xc8, 0x60, 0x7c, 0x95, 0x64, 0xf5, 0xce, 0x13, 0x72, 0x94, 0xb2, 0x82, 0x3f, 0x03,
0x65, 0x1c, 0x9f, 0xb3, 0xbc, 0x1f, 0xe5, 0xfd, 0x37, 0x67, 0x6c, 0x2f, 0xba, 0x7a, 0x22, 0x2e,
0x52, 0x0f, 0x0e, 0xb3, 0xd6, 0x47, 0xc3, 0x5a, 0x39, 0x51, 0x2a, 0x94, 0xc4, 0x33, 0xfe, 0xa0,
0x81, 0xb2, 0xda, 0xf0, 0x1c, 0x68, 0xb2, 0x91, 0xa6, 0xc9, 0xea, 0xdd, 0x55, 0x9a, 0x41, 0x92,
0x3f, 0x9f, 0x64, 0x2c, 0x19, 0xf2, 0x14, 0xac, 0x38, 0xb2, 0x54, 0x4c, 0xd7, 0x24, 0xea, 0x6b,
0x77, 0xa3, 0x2a, 0x02, 0x5e, 0x57, 0xd8, 0x2b, 0xd1, 0x9a, 0xa1, 0x31, 0x8a, 0xf1, 0xff, 0x02,
0x80, 0x8d, 0xf6, 0x51, 0x86, 0x7e, 0xe6, 0xd0, 0xc2, 0x14, 0xac, 0x89, 0x56, 0x19, 0x37, 0x83,
0x6a, 0xe5, 0x77, 0x1f, 0x78, 0xfe, 0xf8, 0x82, 0x74, 0xdb, 0xa4, 0x4b, 0x6c, 0xee, 0x87, 0x51,
0x57, 0x9d, 0x24, 0xc0, 0x50, 0x0a, 0x1a, 0x1e, 0x82, 0x8d, 0x31, 0x9b, 0x76, 0x31, 0x63, 0xa2,
0x9b, 0xf5, 0x82, 0xec, 0x5e, 0x5d, 0xa5, 0xb8, 0xd1, 0xce, 0xe8, 0xd1, 0x94, 0x07, 0xfc, 0x1c,
0xac, 0xda, 0x49, 0xe2, 0xbe, 0xa7, 0x59, 0xcc, 0xf1, 0x14, 0x64, 0xfe, 0xb8, 0x87, 0x3d, 0x4e,
0xf9, 0xc0, 0x5a, 0x13, 0x8d, 0x32, 0x61, 0xf8, 0x09, 0x1a, 0x64, 0x60, 0xd3, 0xc5, 0x37, 0xd4,
0xed, 0xb9, 0x51, 0x4b, 0xb7, 0xe9, 0x2f, 0x89, 0xa4, 0xf7, 0xc7, 0x87, 0x90, 0xf4, 0xda, 0xca,
0x82, 0xa1, 0x69, 0x7c, 0xe3, 0xef, 0x1a, 0x78, 0x65, 0xba, 0xf0, 0x73, 0xb8, 0x16, 0x27, 0xe9,
0x6b, 0xf1, 0xc6, 0xec, 0x06, 0xce, 0xe4, 0x36, 0xe3, 0x86, 0xfc, 0x66, 0x19, 0xac, 0x25, 0xcb,
0x37, 0x87, 0xde, 0xfd, 0x3e, 0x28, 0x07, 0xa1, 0xdf, 0xa7, 0x8c, 0xfa, 0x1e, 0x09, 0x15, 0x13,
0x3e, 0x55, 0x2e, 0xe5, 0xb3, 0x58, 0x85, 0x92, 0x76, 0xb0, 0x03, 0x40, 0x80, 0x43, 0xec, 0x12,
0x2e, 0xee, 0x6f, 0x41, 0x6e, 0xff, 0xdd, 0x19, 0xdb, 0x4f, 0xee, 0xc8, 0x3c, 0x9b, 0x78, 0x35,
0x3d, 0x1e, 0x0e, 0xe2, 0xec, 0x62, 0x05, 0x4a, 0x40, 0xc3, 0x6b, 0x50, 0x09, 0x89, 0xdd, 0xc5,
0xd4, 0x55, 0xb3, 0xc2, 0x92, 0xcc, 0xb0, 0x29, 0x1e, 0x6e, 0x94, 0x54, 0xdc, 0x0e, 0x6b, 0xef,
0x4c, 0x4f, 0xfb, 0xe6, 0x19, 0x09, 0x19, 0x65, 0x9c, 0x78, 0x3c, 0x6a, 0x98, 0x94, 0x0f, 0x4a,
0x63, 0x0b, 0xa6, 0x77, 0xc5, 0xd3, 0x7b, 0x1a, 0x70, 0xea, 0x7b, 0x4c, 0x2f, 0xc6, 0x4c, 0xdf,
0x4a, 0xc8, 0x51, 0xca, 0x0a, 0x1e, 0x83, 0x2d, 0xc1, 0xcc, 0xbf, 0x88, 0x02, 0x34, 0x6f, 0x02,
0xec, 0x89, 0x53, 0xd2, 0x97, 0xe5, 0x2b, 0xaf, 0x8b, 0x91, 0xeb, 0x20, 0x47, 0x8f, 0x72, 0xbd,
0xe0, 0xe7, 0x60, 0x33, 0x9a, 0xb9, 0x2c, 0xea, 0x39, 0xd4, 0xeb, 0x88, 0x89, 0x4b, 0x0e, 0x1c,
0x25, 0xeb, 0x4d, 0x71, 0x23, 0x3e, 0xcb, 0x2a, 0x6f, 0xf3, 0x84, 0x68, 0x1a, 0x04, 0x7e, 0x05,
0x36, 0x65, 0x44, 0xe2, 0x28, 0x3a, 0xa1, 0x84, 0xe9, 0xab, 0xb2, 0x74, 0x7b, 0xc9, 0xd2, 0x89,
0xa3, 0x8b, 0xa6, 0xa5, 0x88, 0x74, 0xc6, 0xe4, 0x74, 0x4e, 0x42, 0xd7, 0xfa, 0xb6, 0xaa, 0xd7,
0xe6, 0x41, 0x16, 0x0a, 0x4d, 0xa3, 0xef, 0x7c, 0x04, 0xd6, 0x33, 0x05, 0x87, 0x1b, 0xa0, 0x70,
0x4d, 0x06, 0xd1, 0xb3, 0x8c, 0xc4, 0x4f, 0xb8, 0x05, 0x8a, 0x7d, 0xdc, 0xed, 0x91, 0xa8, 0xf9,
0x50, 0xb4, 0xf8, 0x70, 0xf1, 0x03, 0xcd, 0xf8, 0xab, 0x06, 0x52, 0x74, 0x36, 0x87, 0x2b, 0xfd,
0x49, 0xfa, 0x4a, 0xbf, 0xfa, 0x80, 0x9e, 0x9e, 0x71, 0x99, 0x7f, 0xad, 0x81, 0xb5, 0xe4, 0x68,
0x09, 0xbf, 0x07, 0x56, 0x71, 0xcf, 0xa1, 0xc4, 0xb3, 0xc7, 0x53, 0xc9, 0x24, 0x91, 0x03, 0x25,
0x47, 0x13, 0x0b, 0x31, 0x78, 0x92, 0x9b, 0x80, 0x86, 0x58, 0x34, 0xd9, 0x78, 0xd8, 0x5b, 0x94,
0xc3, 0x9e, 0x64, 0xc6, 0x66, 0x56, 0x89, 0xa6, 0xed, 0x8d, 0xdf, 0x2f, 0x82, 0x8d, 0xa8, 0x37,
0xa2, 0x4f, 0x0e, 0x97, 0x78, 0x7c, 0x0e, 0xa4, 0xd2, 0x4a, 0xcd, 0x74, 0x6f, 0xdd, 0x39, 0xf4,
0xc4, 0x89, 0xcd, 0x1a, 0xee, 0xe0, 0xa7, 0x60, 0x99, 0x71, 0xcc, 0x7b, 0x4c, 0x3e, 0x75, 0xe5,
0xfd, 0xb7, 0x1f, 0x0a, 0x28, 0x9d, 0xe2, 0xb9, 0x2e, 0x5a, 0x23, 0x05, 0x66, 0xfc, 0x4d, 0x03,
0x5b, 0x59, 0x97, 0x39, 0x74, 0xd8, 0x71, 0xba, 0xc3, 0xbe, 0xfb, 0xc0, 0xcd, 0xcc, 0xe8, 0xb2,
0x7f, 0x69, 0xe0, 0x95, 0xa9, 0x7d, 0xcb, 0x97, 0x54, 0xf0, 0x52, 0x90, 0x61, 0xbf, 0x93, 0x78,
0x22, 0x96, 0xbc, 0x74, 0x96, 0xa3, 0x47, 0xb9, 0x5e, 0xf0, 0x4b, 0xb0, 0x41, 0xbd, 0x2e, 0xf5,
0x88, 0x7a, 0x78, 0xe3, 0xfa, 0xe6, 0x92, 0x47, 0x16, 0x59, 0x16, 0x77, 0x4b, 0xcc, 0x27, 0x47,
0x19, 0x14, 0x34, 0x85, 0x6b, 0xfc, 0x23, 0xa7, 0x32, 0x72, 0x66, 0x14, 0x57, 0x48, 0x4a, 0x48,
0x38, 0x75, 0x85, 0x94, 0x1c, 0x4d, 0x2c, 0x64, 0xdf, 0xc8, 0xa3, 0x50, 0x89, 0x3e, 0xb8, 0x6f,
0xa4, 0x53, 0xa2, 0x6f, 0xe4, 0x1a, 0x29, 0x30, 0x91, 0x84, 0x98, 0xc9, 0x12, 0xb3, 0xd7, 0x24,
0x89, 0x13, 0x25, 0x47, 0x13, 0x0b, 0xe3, 0xbf, 0x85, 0x9c, 0x02, 0xc9, 0x06, 0x4c, 0xec, 0x66,
0xfc, 0xef, 0x40, 0x76, 0x37, 0xce, 0x64, 0x37, 0x0e, 0xfc, 0x9d, 0x06, 0x20, 0x9e, 0x40, 0xb4,
0xc6, 0x0d, 0x1a, 0x75, 0x51, 0xf3, 0x51, 0x57, 0xc2, 0x3c, 0x98, 0xc2, 0x89, 0x5e, 0xe3, 0x1d,
0x15, 0x1f, 0x4e, 0x1b, 0xa0, 0x9c, 0xe0, 0xd0, 0x01, 0xe5, 0x48, 0xda, 0x0c, 0x43, 0x3f, 0x54,
0xd7, 0xd3, 0xb8, 0x33, 0x17, 0x69, 0x69, 0x55, 0xe5, 0xc7, 0x4d, 0xec, 0x7a, 0x3b, 0xac, 0x95,
0x13, 0x7a, 0x94, 0x84, 0x15, 0x51, 0x1c, 0x12, 0x47, 0x59, 0x7a, 0x5c, 0x94, 0x43, 0x32, 0x3b,
0x4a, 0x02, 0x76, 0xa7, 0x09, 0xbe, 0x35, 0xe3, 0x58, 0x1e, 0xf5, 0x66, 0xfd, 0x49, 0x03, 0xc9,
0x18, 0xf0, 0x18, 0x2c, 0x71, 0xaa, 0x6e, 0x5d, 0xfa, 0x03, 0xf0, 0x0e, 0x22, 0x39, 0xa7, 0x2e,
0x89, 0xa9, 0x50, 0xac, 0x90, 0x44, 0x81, 0x6f, 0x80, 0x15, 0x97, 0x30, 0x86, 0x3b, 0x2a, 0x72,
0xfc, 0x39, 0xd4, 0x8a, 0xc4, 0x68, 0xac, 0x87, 0x6f, 0x81, 0x12, 0x11, 0x19, 0x34, 0xc4, 0x00,
0x21, 0x2a, 0x53, 0xb4, 0x2a, 0xa3, 0x61, 0xad, 0xd4, 0x1c, 0x0b, 0x51, 0xac, 0x37, 0xde, 0x07,
0x4f, 0x73, 0xbe, 0x41, 0x61, 0x0d, 0x14, 0x6d, 0xf9, 0x8f, 0x85, 0x26, 0xfd, 0x4b, 0x82, 0x7e,
0x1a, 0xf2, 0xaf, 0x8a, 0x48, 0x6e, 0xfd, 0xe0, 0xf9, 0xcb, 0xea, 0xc2, 0xd7, 0x2f, 0xab, 0x0b,
0x2f, 0x5e, 0x56, 0x17, 0x7e, 0x35, 0xaa, 0x6a, 0xcf, 0x47, 0x55, 0xed, 0xeb, 0x51, 0x55, 0x7b,
0x31, 0xaa, 0x6a, 0xff, 0x1e, 0x55, 0xb5, 0xdf, 0xfe, 0xa7, 0xba, 0xf0, 0x93, 0xed, 0xdc, 0xff,
0x7c, 0xbf, 0x09, 0x00, 0x00, 0xff, 0xff, 0x39, 0x5a, 0x51, 0xe9, 0x0b, 0x16, 0x00, 0x00,
}
func (m *CSIDriver) Marshal() (dAtA []byte, err error) {
@ -826,6 +829,11 @@ func (m *CSIDriverSpec) MarshalToSizedBuffer(dAtA []byte) (int, error) {
_ = i
var l int
_ = l
if m.NodeAllocatableUpdatePeriodSeconds != nil {
i = encodeVarintGenerated(dAtA, i, uint64(*m.NodeAllocatableUpdatePeriodSeconds))
i--
dAtA[i] = 0x48
}
if m.SELinuxMount != nil {
i--
if *m.SELinuxMount {
@ -1684,6 +1692,11 @@ func (m *VolumeError) MarshalToSizedBuffer(dAtA []byte) (int, error) {
_ = i
var l int
_ = l
if m.ErrorCode != nil {
i = encodeVarintGenerated(dAtA, i, uint64(*m.ErrorCode))
i--
dAtA[i] = 0x18
}
i -= len(m.Message)
copy(dAtA[i:], m.Message)
i = encodeVarintGenerated(dAtA, i, uint64(len(m.Message)))
@ -1808,6 +1821,9 @@ func (m *CSIDriverSpec) Size() (n int) {
if m.SELinuxMount != nil {
n += 2
}
if m.NodeAllocatableUpdatePeriodSeconds != nil {
n += 1 + sovGenerated(uint64(*m.NodeAllocatableUpdatePeriodSeconds))
}
return n
}
@ -2096,6 +2112,9 @@ func (m *VolumeError) Size() (n int) {
n += 1 + l + sovGenerated(uint64(l))
l = len(m.Message)
n += 1 + l + sovGenerated(uint64(l))
if m.ErrorCode != nil {
n += 1 + sovGenerated(uint64(*m.ErrorCode))
}
return n
}
@ -2162,6 +2181,7 @@ func (this *CSIDriverSpec) String() string {
`TokenRequests:` + repeatedStringForTokenRequests + `,`,
`RequiresRepublish:` + valueToStringGenerated(this.RequiresRepublish) + `,`,
`SELinuxMount:` + valueToStringGenerated(this.SELinuxMount) + `,`,
`NodeAllocatableUpdatePeriodSeconds:` + valueToStringGenerated(this.NodeAllocatableUpdatePeriodSeconds) + `,`,
`}`,
}, "")
return s
@ -2391,6 +2411,7 @@ func (this *VolumeError) String() string {
s := strings.Join([]string{`&VolumeError{`,
`Time:` + strings.Replace(strings.Replace(fmt.Sprintf("%v", this.Time), "Time", "v1.Time", 1), `&`, ``, 1) + `,`,
`Message:` + fmt.Sprintf("%v", this.Message) + `,`,
`ErrorCode:` + valueToStringGenerated(this.ErrorCode) + `,`,
`}`,
}, "")
return s
@ -2879,6 +2900,26 @@ func (m *CSIDriverSpec) Unmarshal(dAtA []byte) error {
}
b := bool(v != 0)
m.SELinuxMount = &b
case 9:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field NodeAllocatableUpdatePeriodSeconds", wireType)
}
var v int64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowGenerated
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
v |= int64(b&0x7F) << shift
if b < 0x80 {
break
}
}
m.NodeAllocatableUpdatePeriodSeconds = &v
default:
iNdEx = preIndex
skippy, err := skipGenerated(dAtA[iNdEx:])
@ -5248,6 +5289,26 @@ func (m *VolumeError) Unmarshal(dAtA []byte) error {
}
m.Message = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
case 3:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field ErrorCode", wireType)
}
var v int32
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowGenerated
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
v |= int32(b&0x7F) << shift
if b < 0x80 {
break
}
}
m.ErrorCode = &v
default:
iNdEx = preIndex
skippy, err := skipGenerated(dAtA[iNdEx:])

View File

@ -212,6 +212,20 @@ message CSIDriverSpec {
// +featureGate=SELinuxMountReadWriteOncePod
// +optional
optional bool seLinuxMount = 8;
// nodeAllocatableUpdatePeriodSeconds specifies the interval between periodic updates of
// the CSINode allocatable capacity for this driver. When set, both periodic updates and
// updates triggered by capacity-related failures are enabled. If not set, no updates
// occur (neither periodic nor upon detecting capacity-related failures), and the
// allocatable.count remains static. The minimum allowed value for this field is 10 seconds.
//
// This is an alpha feature and requires the MutableCSINodeAllocatableCount feature gate to be enabled.
//
// This field is mutable.
//
// +featureGate=MutableCSINodeAllocatableCount
// +optional
optional int64 nodeAllocatableUpdatePeriodSeconds = 9;
}
// CSINode holds information about all CSI drivers installed on a node.
@ -561,6 +575,14 @@ message VolumeError {
// information.
// +optional
optional string message = 2;
// errorCode is a numeric gRPC code representing the error encountered during Attach or Detach operations.
//
// This is an optional, alpha field that requires the MutableCSINodeAllocatableCount feature gate being enabled to be set.
//
// +featureGate=MutableCSINodeAllocatableCount
// +optional
optional int32 errorCode = 3;
}
// VolumeNodeResources is a set of resource limits for scheduling of volumes.

View File

@ -226,6 +226,14 @@ type VolumeError struct {
// information.
// +optional
Message string `json:"message,omitempty" protobuf:"bytes,2,opt,name=message"`
// errorCode is a numeric gRPC code representing the error encountered during Attach or Detach operations.
//
// This is an optional, alpha field that requires the MutableCSINodeAllocatableCount feature gate being enabled to be set.
//
// +featureGate=MutableCSINodeAllocatableCount
// +optional
ErrorCode *int32 `json:"errorCode,omitempty" protobuf:"varint,3,opt,name=errorCode"`
}
// +genclient
@ -422,6 +430,20 @@ type CSIDriverSpec struct {
// +featureGate=SELinuxMountReadWriteOncePod
// +optional
SELinuxMount *bool `json:"seLinuxMount,omitempty" protobuf:"varint,8,opt,name=seLinuxMount"`
// nodeAllocatableUpdatePeriodSeconds specifies the interval between periodic updates of
// the CSINode allocatable capacity for this driver. When set, both periodic updates and
// updates triggered by capacity-related failures are enabled. If not set, no updates
// occur (neither periodic nor upon detecting capacity-related failures), and the
// allocatable.count remains static. The minimum allowed value for this field is 10 seconds.
//
// This is an alpha feature and requires the MutableCSINodeAllocatableCount feature gate to be enabled.
//
// This field is mutable.
//
// +featureGate=MutableCSINodeAllocatableCount
// +optional
NodeAllocatableUpdatePeriodSeconds *int64 `json:"nodeAllocatableUpdatePeriodSeconds,omitempty" protobuf:"varint,9,opt,name=nodeAllocatableUpdatePeriodSeconds"`
}
// FSGroupPolicy specifies if a CSI Driver supports modifying

View File

@ -48,15 +48,16 @@ func (CSIDriverList) SwaggerDoc() map[string]string {
}
var map_CSIDriverSpec = map[string]string{
"": "CSIDriverSpec is the specification of a CSIDriver.",
"attachRequired": "attachRequired indicates this CSI volume driver requires an attach operation (because it implements the CSI ControllerPublishVolume() method), and that the Kubernetes attach detach controller should call the attach volume interface which checks the volumeattachment status and waits until the volume is attached before proceeding to mounting. The CSI external-attacher coordinates with CSI volume driver and updates the volumeattachment status when the attach operation is complete. If the CSIDriverRegistry feature gate is enabled and the value is specified to false, the attach operation will be skipped. Otherwise the attach operation will be called.\n\nThis field is immutable.",
"podInfoOnMount": "podInfoOnMount indicates this CSI volume driver requires additional pod information (like podName, podUID, etc.) during mount operations, if set to true. If set to false, pod information will not be passed on mount. Default is false.\n\nThe CSI driver specifies podInfoOnMount as part of driver deployment. If true, Kubelet will pass pod information as VolumeContext in the CSI NodePublishVolume() calls. The CSI driver is responsible for parsing and validating the information passed in as VolumeContext.\n\nThe following VolumeContext will be passed if podInfoOnMount is set to true. This list might grow, but the prefix will be used. \"csi.storage.k8s.io/pod.name\": pod.Name \"csi.storage.k8s.io/pod.namespace\": pod.Namespace \"csi.storage.k8s.io/pod.uid\": string(pod.UID) \"csi.storage.k8s.io/ephemeral\": \"true\" if the volume is an ephemeral inline volume\n defined by a CSIVolumeSource, otherwise \"false\"\n\n\"csi.storage.k8s.io/ephemeral\" is a new feature in Kubernetes 1.16. It is only required for drivers which support both the \"Persistent\" and \"Ephemeral\" VolumeLifecycleMode. Other drivers can leave pod info disabled and/or ignore this field. As Kubernetes 1.15 doesn't support this field, drivers can only support one mode when deployed on such a cluster and the deployment determines which mode that is, for example via a command line parameter of the driver.\n\nThis field was immutable in Kubernetes < 1.29 and now is mutable.",
"volumeLifecycleModes": "volumeLifecycleModes defines what kind of volumes this CSI volume driver supports. The default if the list is empty is \"Persistent\", which is the usage defined by the CSI specification and implemented in Kubernetes via the usual PV/PVC mechanism.\n\nThe other mode is \"Ephemeral\". In this mode, volumes are defined inline inside the pod spec with CSIVolumeSource and their lifecycle is tied to the lifecycle of that pod. A driver has to be aware of this because it is only going to get a NodePublishVolume call for such a volume.\n\nFor more information about implementing this mode, see https://kubernetes-csi.github.io/docs/ephemeral-local-volumes.html A driver can support one or more of these modes and more modes may be added in the future.\n\nThis field is beta. This field is immutable.",
"storageCapacity": "storageCapacity indicates that the CSI volume driver wants pod scheduling to consider the storage capacity that the driver deployment will report by creating CSIStorageCapacity objects with capacity information, if set to true.\n\nThe check can be enabled immediately when deploying a driver. In that case, provisioning new volumes with late binding will pause until the driver deployment has published some suitable CSIStorageCapacity object.\n\nAlternatively, the driver can be deployed with the field unset or false and it can be flipped later when storage capacity information has been published.\n\nThis field was immutable in Kubernetes <= 1.22 and now is mutable.",
"fsGroupPolicy": "fsGroupPolicy defines if the underlying volume supports changing ownership and permission of the volume before being mounted. Refer to the specific FSGroupPolicy values for additional details.\n\nThis field was immutable in Kubernetes < 1.29 and now is mutable.\n\nDefaults to ReadWriteOnceWithFSType, which will examine each volume to determine if Kubernetes should modify ownership and permissions of the volume. With the default policy the defined fsGroup will only be applied if a fstype is defined and the volume's access mode contains ReadWriteOnce.",
"tokenRequests": "tokenRequests indicates the CSI driver needs pods' service account tokens it is mounting volume for to do necessary authentication. Kubelet will pass the tokens in VolumeContext in the CSI NodePublishVolume calls. The CSI driver should parse and validate the following VolumeContext: \"csi.storage.k8s.io/serviceAccount.tokens\": {\n \"<audience>\": {\n \"token\": <token>,\n \"expirationTimestamp\": <expiration timestamp in RFC3339>,\n },\n ...\n}\n\nNote: Audience in each TokenRequest should be different and at most one token is empty string. To receive a new token after expiry, RequiresRepublish can be used to trigger NodePublishVolume periodically.",
"requiresRepublish": "requiresRepublish indicates the CSI driver wants `NodePublishVolume` being periodically called to reflect any possible change in the mounted volume. This field defaults to false.\n\nNote: After a successful initial NodePublishVolume call, subsequent calls to NodePublishVolume should only update the contents of the volume. New mount points will not be seen by a running container.",
"seLinuxMount": "seLinuxMount specifies if the CSI driver supports \"-o context\" mount option.\n\nWhen \"true\", the CSI driver must ensure that all volumes provided by this CSI driver can be mounted separately with different `-o context` options. This is typical for storage backends that provide volumes as filesystems on block devices or as independent shared volumes. Kubernetes will call NodeStage / NodePublish with \"-o context=xyz\" mount option when mounting a ReadWriteOncePod volume used in Pod that has explicitly set SELinux context. In the future, it may be expanded to other volume AccessModes. In any case, Kubernetes will ensure that the volume is mounted only with a single SELinux context.\n\nWhen \"false\", Kubernetes won't pass any special SELinux mount options to the driver. This is typical for volumes that represent subdirectories of a bigger shared filesystem.\n\nDefault is \"false\".",
"": "CSIDriverSpec is the specification of a CSIDriver.",
"attachRequired": "attachRequired indicates this CSI volume driver requires an attach operation (because it implements the CSI ControllerPublishVolume() method), and that the Kubernetes attach detach controller should call the attach volume interface which checks the volumeattachment status and waits until the volume is attached before proceeding to mounting. The CSI external-attacher coordinates with CSI volume driver and updates the volumeattachment status when the attach operation is complete. If the CSIDriverRegistry feature gate is enabled and the value is specified to false, the attach operation will be skipped. Otherwise the attach operation will be called.\n\nThis field is immutable.",
"podInfoOnMount": "podInfoOnMount indicates this CSI volume driver requires additional pod information (like podName, podUID, etc.) during mount operations, if set to true. If set to false, pod information will not be passed on mount. Default is false.\n\nThe CSI driver specifies podInfoOnMount as part of driver deployment. If true, Kubelet will pass pod information as VolumeContext in the CSI NodePublishVolume() calls. The CSI driver is responsible for parsing and validating the information passed in as VolumeContext.\n\nThe following VolumeContext will be passed if podInfoOnMount is set to true. This list might grow, but the prefix will be used. \"csi.storage.k8s.io/pod.name\": pod.Name \"csi.storage.k8s.io/pod.namespace\": pod.Namespace \"csi.storage.k8s.io/pod.uid\": string(pod.UID) \"csi.storage.k8s.io/ephemeral\": \"true\" if the volume is an ephemeral inline volume\n defined by a CSIVolumeSource, otherwise \"false\"\n\n\"csi.storage.k8s.io/ephemeral\" is a new feature in Kubernetes 1.16. It is only required for drivers which support both the \"Persistent\" and \"Ephemeral\" VolumeLifecycleMode. Other drivers can leave pod info disabled and/or ignore this field. As Kubernetes 1.15 doesn't support this field, drivers can only support one mode when deployed on such a cluster and the deployment determines which mode that is, for example via a command line parameter of the driver.\n\nThis field was immutable in Kubernetes < 1.29 and now is mutable.",
"volumeLifecycleModes": "volumeLifecycleModes defines what kind of volumes this CSI volume driver supports. The default if the list is empty is \"Persistent\", which is the usage defined by the CSI specification and implemented in Kubernetes via the usual PV/PVC mechanism.\n\nThe other mode is \"Ephemeral\". In this mode, volumes are defined inline inside the pod spec with CSIVolumeSource and their lifecycle is tied to the lifecycle of that pod. A driver has to be aware of this because it is only going to get a NodePublishVolume call for such a volume.\n\nFor more information about implementing this mode, see https://kubernetes-csi.github.io/docs/ephemeral-local-volumes.html A driver can support one or more of these modes and more modes may be added in the future.\n\nThis field is beta. This field is immutable.",
"storageCapacity": "storageCapacity indicates that the CSI volume driver wants pod scheduling to consider the storage capacity that the driver deployment will report by creating CSIStorageCapacity objects with capacity information, if set to true.\n\nThe check can be enabled immediately when deploying a driver. In that case, provisioning new volumes with late binding will pause until the driver deployment has published some suitable CSIStorageCapacity object.\n\nAlternatively, the driver can be deployed with the field unset or false and it can be flipped later when storage capacity information has been published.\n\nThis field was immutable in Kubernetes <= 1.22 and now is mutable.",
"fsGroupPolicy": "fsGroupPolicy defines if the underlying volume supports changing ownership and permission of the volume before being mounted. Refer to the specific FSGroupPolicy values for additional details.\n\nThis field was immutable in Kubernetes < 1.29 and now is mutable.\n\nDefaults to ReadWriteOnceWithFSType, which will examine each volume to determine if Kubernetes should modify ownership and permissions of the volume. With the default policy the defined fsGroup will only be applied if a fstype is defined and the volume's access mode contains ReadWriteOnce.",
"tokenRequests": "tokenRequests indicates the CSI driver needs pods' service account tokens it is mounting volume for to do necessary authentication. Kubelet will pass the tokens in VolumeContext in the CSI NodePublishVolume calls. The CSI driver should parse and validate the following VolumeContext: \"csi.storage.k8s.io/serviceAccount.tokens\": {\n \"<audience>\": {\n \"token\": <token>,\n \"expirationTimestamp\": <expiration timestamp in RFC3339>,\n },\n ...\n}\n\nNote: Audience in each TokenRequest should be different and at most one token is empty string. To receive a new token after expiry, RequiresRepublish can be used to trigger NodePublishVolume periodically.",
"requiresRepublish": "requiresRepublish indicates the CSI driver wants `NodePublishVolume` being periodically called to reflect any possible change in the mounted volume. This field defaults to false.\n\nNote: After a successful initial NodePublishVolume call, subsequent calls to NodePublishVolume should only update the contents of the volume. New mount points will not be seen by a running container.",
"seLinuxMount": "seLinuxMount specifies if the CSI driver supports \"-o context\" mount option.\n\nWhen \"true\", the CSI driver must ensure that all volumes provided by this CSI driver can be mounted separately with different `-o context` options. This is typical for storage backends that provide volumes as filesystems on block devices or as independent shared volumes. Kubernetes will call NodeStage / NodePublish with \"-o context=xyz\" mount option when mounting a ReadWriteOncePod volume used in Pod that has explicitly set SELinux context. In the future, it may be expanded to other volume AccessModes. In any case, Kubernetes will ensure that the volume is mounted only with a single SELinux context.\n\nWhen \"false\", Kubernetes won't pass any special SELinux mount options to the driver. This is typical for volumes that represent subdirectories of a bigger shared filesystem.\n\nDefault is \"false\".",
"nodeAllocatableUpdatePeriodSeconds": "nodeAllocatableUpdatePeriodSeconds specifies the interval between periodic updates of the CSINode allocatable capacity for this driver. When set, both periodic updates and updates triggered by capacity-related failures are enabled. If not set, no updates occur (neither periodic nor upon detecting capacity-related failures), and the allocatable.count remains static. The minimum allowed value for this field is 10 seconds.\n\nThis is an alpha feature and requires the MutableCSINodeAllocatableCount feature gate to be enabled.\n\nThis field is mutable.",
}
func (CSIDriverSpec) SwaggerDoc() map[string]string {
@ -217,9 +218,10 @@ func (VolumeAttachmentStatus) SwaggerDoc() map[string]string {
}
var map_VolumeError = map[string]string{
"": "VolumeError captures an error encountered during a volume operation.",
"time": "time represents the time the error was encountered.",
"message": "message represents the error encountered during Attach or Detach operation. This string may be logged, so it should not contain sensitive information.",
"": "VolumeError captures an error encountered during a volume operation.",
"time": "time represents the time the error was encountered.",
"message": "message represents the error encountered during Attach or Detach operation. This string may be logged, so it should not contain sensitive information.",
"errorCode": "errorCode is a numeric gRPC code representing the error encountered during Attach or Detach operations.\n\nThis is an optional, alpha field that requires the MutableCSINodeAllocatableCount feature gate being enabled to be set.",
}
func (VolumeError) SwaggerDoc() map[string]string {

View File

@ -132,6 +132,11 @@ func (in *CSIDriverSpec) DeepCopyInto(out *CSIDriverSpec) {
*out = new(bool)
**out = **in
}
if in.NodeAllocatableUpdatePeriodSeconds != nil {
in, out := &in.NodeAllocatableUpdatePeriodSeconds, &out.NodeAllocatableUpdatePeriodSeconds
*out = new(int64)
**out = **in
}
return
}
@ -583,6 +588,11 @@ func (in *VolumeAttachmentStatus) DeepCopy() *VolumeAttachmentStatus {
func (in *VolumeError) DeepCopyInto(out *VolumeError) {
*out = *in
in.Time.DeepCopyInto(&out.Time)
if in.ErrorCode != nil {
in, out := &in.ErrorCode, &out.ErrorCode
*out = new(int32)
**out = **in
}
return
}

View File

@ -347,71 +347,72 @@ func init() {
}
var fileDescriptor_02e7952e43280c27 = []byte{
// 1009 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x57, 0x3d, 0x6f, 0x23, 0x45,
0x18, 0xce, 0xda, 0xce, 0x9d, 0x6f, 0x1c, 0x38, 0xdf, 0xc8, 0x77, 0x18, 0x9f, 0xb4, 0x3e, 0xb9,
0x32, 0x1f, 0x37, 0x4b, 0x02, 0x42, 0x27, 0x24, 0x0a, 0x6f, 0x92, 0x22, 0x22, 0x09, 0xc7, 0x38,
0x02, 0x04, 0x14, 0x8c, 0xd7, 0x83, 0x3d, 0x89, 0xf7, 0x43, 0x33, 0xb3, 0x16, 0xa6, 0xa2, 0xa2,
0xa6, 0xe3, 0x1f, 0xf0, 0x5b, 0x52, 0x20, 0x71, 0xba, 0xea, 0x2a, 0x8b, 0x2c, 0xfc, 0x06, 0x0a,
0x1a, 0xd0, 0xce, 0x8e, 0xd7, 0x1b, 0xaf, 0x1d, 0x9c, 0x14, 0xe9, 0x3c, 0x33, 0xef, 0xfb, 0x3c,
0xef, 0xc7, 0xf3, 0xbe, 0x9b, 0x80, 0x77, 0xce, 0x9e, 0x09, 0xc4, 0x7c, 0x8b, 0x04, 0xcc, 0x12,
0xd2, 0xe7, 0x64, 0x40, 0xad, 0xf1, 0x36, 0x19, 0x05, 0x43, 0xb2, 0x6d, 0x0d, 0xa8, 0x47, 0x39,
0x91, 0xb4, 0x8f, 0x02, 0xee, 0x4b, 0x1f, 0x3e, 0x4e, 0x8c, 0x11, 0x09, 0x18, 0xd2, 0xc6, 0x68,
0x66, 0xdc, 0x78, 0x3a, 0x60, 0x72, 0x18, 0xf6, 0x90, 0xe3, 0xbb, 0xd6, 0xc0, 0x1f, 0xf8, 0x96,
0xf2, 0xe9, 0x85, 0xdf, 0xa9, 0x93, 0x3a, 0xa8, 0x5f, 0x09, 0x56, 0xa3, 0x95, 0x21, 0x76, 0x7c,
0x1e, 0xb3, 0x2e, 0xf2, 0x35, 0x3e, 0x98, 0xdb, 0xb8, 0xc4, 0x19, 0x32, 0x8f, 0xf2, 0x89, 0x15,
0x9c, 0x0d, 0x94, 0x13, 0xa7, 0xc2, 0x0f, 0xb9, 0x43, 0xaf, 0xe5, 0x25, 0x2c, 0x97, 0x4a, 0xb2,
0x8c, 0xcb, 0x5a, 0xe5, 0xc5, 0x43, 0x4f, 0x32, 0x37, 0x4f, 0xf3, 0xe1, 0xff, 0x39, 0x08, 0x67,
0x48, 0x5d, 0xb2, 0xe8, 0xd7, 0xfa, 0xbb, 0x08, 0xe0, 0x6e, 0xf7, 0xa0, 0x9b, 0xd4, 0x6f, 0x97,
0x04, 0xc4, 0x61, 0x72, 0x02, 0xbf, 0x05, 0xe5, 0x38, 0xb4, 0x3e, 0x91, 0xa4, 0x6e, 0x3c, 0x31,
0xda, 0x95, 0x9d, 0xf7, 0xd0, 0xbc, 0xdc, 0x29, 0x03, 0x0a, 0xce, 0x06, 0xf1, 0x85, 0x40, 0xb1,
0x35, 0x1a, 0x6f, 0xa3, 0x4f, 0x7b, 0xa7, 0xd4, 0x91, 0x47, 0x54, 0x12, 0x1b, 0x9e, 0x4f, 0x9b,
0x1b, 0xd1, 0xb4, 0x09, 0xe6, 0x77, 0x38, 0x45, 0x85, 0x0c, 0x6c, 0x79, 0x7e, 0x9f, 0x9e, 0xf8,
0x81, 0x3f, 0xf2, 0x07, 0x93, 0x7a, 0x41, 0xb1, 0xbc, 0xbf, 0x1e, 0xcb, 0x21, 0xe9, 0xd1, 0x51,
0x97, 0x8e, 0xa8, 0x23, 0x7d, 0x6e, 0x57, 0xa3, 0x69, 0x73, 0xeb, 0x38, 0x03, 0x86, 0x2f, 0x41,
0xc3, 0x3d, 0x50, 0xd5, 0xfa, 0xd8, 0x1d, 0x11, 0x21, 0x8e, 0x89, 0x4b, 0xeb, 0xc5, 0x27, 0x46,
0xfb, 0x9e, 0x5d, 0xd7, 0x21, 0x56, 0xbb, 0x0b, 0xef, 0x38, 0xe7, 0x01, 0xbf, 0x04, 0x65, 0x47,
0x97, 0xa7, 0x5e, 0x52, 0xc1, 0xa2, 0xab, 0x82, 0x45, 0x33, 0x45, 0xa0, 0xcf, 0x42, 0xe2, 0x49,
0x26, 0x27, 0xf6, 0x56, 0x34, 0x6d, 0x96, 0x67, 0x25, 0xc6, 0x29, 0x1a, 0x14, 0xe0, 0x81, 0x4b,
0xbe, 0x67, 0x6e, 0xe8, 0x7e, 0xee, 0x8f, 0x42, 0x97, 0x76, 0xd9, 0x0f, 0xb4, 0xbe, 0x79, 0x23,
0x8a, 0x87, 0xd1, 0xb4, 0xf9, 0xe0, 0x68, 0x11, 0x0c, 0xe7, 0xf1, 0x5b, 0xbf, 0x19, 0xe0, 0x51,
0xbe, 0xf1, 0x87, 0x4c, 0x48, 0xf8, 0x4d, 0xae, 0xf9, 0x68, 0xcd, 0xb6, 0x30, 0x91, 0xb4, 0xbe,
0xaa, 0xeb, 0x5a, 0x9e, 0xdd, 0x64, 0x1a, 0x7f, 0x02, 0x36, 0x99, 0xa4, 0xae, 0xa8, 0x17, 0x9e,
0x14, 0xdb, 0x95, 0x1d, 0x0b, 0x5d, 0x31, 0xc6, 0x28, 0x1f, 0xa1, 0xfd, 0x9a, 0xc6, 0xde, 0x3c,
0x88, 0x51, 0x70, 0x02, 0xd6, 0xfa, 0xb5, 0x00, 0xaa, 0x49, 0x76, 0x1d, 0x29, 0x89, 0x33, 0x74,
0xa9, 0x27, 0x6f, 0x41, 0xc5, 0x5d, 0x50, 0x12, 0x01, 0x75, 0xb4, 0x7a, 0xb7, 0xaf, 0xcc, 0x65,
0x31, 0xbc, 0x6e, 0x40, 0x1d, 0x7b, 0x4b, 0xc3, 0x97, 0xe2, 0x13, 0x56, 0x60, 0xf0, 0x6b, 0x70,
0x47, 0x48, 0x22, 0x43, 0xa1, 0x54, 0x7a, 0x79, 0x28, 0xd6, 0x80, 0x55, 0xae, 0xf6, 0xeb, 0x1a,
0xf8, 0x4e, 0x72, 0xc6, 0x1a, 0xb2, 0x75, 0x6e, 0x80, 0xda, 0xa2, 0xcb, 0x2d, 0x74, 0x1d, 0x5f,
0xee, 0xfa, 0xd3, 0x6b, 0xa5, 0xb4, 0xa2, 0xe7, 0x2f, 0x0d, 0xf0, 0x28, 0x97, 0xbd, 0x1a, 0x08,
0x78, 0x08, 0x6a, 0x01, 0xe5, 0x82, 0x09, 0x49, 0x3d, 0x99, 0xd8, 0xa8, 0xb1, 0x37, 0x92, 0xb1,
0x8f, 0xa6, 0xcd, 0xda, 0xf3, 0x25, 0xef, 0x78, 0xa9, 0x17, 0x3c, 0x05, 0x55, 0xe6, 0x8d, 0x98,
0x47, 0xf5, 0xfc, 0xcc, 0x3b, 0xde, 0xce, 0xe6, 0x11, 0x7f, 0x38, 0xe2, 0x82, 0x2c, 0x22, 0xab,
0x46, 0xd7, 0xe2, 0x35, 0x73, 0xb0, 0x80, 0x82, 0x73, 0xb8, 0xad, 0xdf, 0x97, 0xf4, 0x27, 0x7e,
0x80, 0xef, 0x82, 0x32, 0x51, 0x37, 0x94, 0xeb, 0x34, 0xd2, 0x7a, 0x77, 0xf4, 0x3d, 0x4e, 0x2d,
0x94, 0x86, 0x54, 0x29, 0x96, 0x2c, 0xd6, 0x35, 0x34, 0xa4, 0x5c, 0x33, 0x1a, 0x52, 0x67, 0xac,
0x21, 0xe3, 0x50, 0xe2, 0x05, 0x9b, 0x59, 0xa4, 0x69, 0x28, 0xc7, 0xfa, 0x1e, 0xa7, 0x16, 0xad,
0x7f, 0x8b, 0x4b, 0xda, 0xa4, 0xc4, 0x98, 0xc9, 0xa9, 0xaf, 0x72, 0x2a, 0xe7, 0x72, 0xea, 0xa7,
0x39, 0xf5, 0xe1, 0x2f, 0x06, 0x80, 0x24, 0x85, 0x38, 0x9a, 0x89, 0x35, 0x51, 0xd4, 0x27, 0x37,
0x18, 0x12, 0xd4, 0xc9, 0xa1, 0xed, 0x7b, 0x92, 0x4f, 0xec, 0x86, 0x8e, 0x02, 0xe6, 0x0d, 0xf0,
0x92, 0x10, 0xe0, 0x29, 0xa8, 0x24, 0xb7, 0xfb, 0x9c, 0xfb, 0x5c, 0x8f, 0x6d, 0x7b, 0x8d, 0x88,
0x94, 0xbd, 0x6d, 0x46, 0xd3, 0x66, 0xa5, 0x33, 0x07, 0xf8, 0x67, 0xda, 0xac, 0x64, 0xde, 0x71,
0x16, 0x3c, 0xe6, 0xea, 0xd3, 0x39, 0x57, 0xe9, 0x26, 0x5c, 0x7b, 0x74, 0x35, 0x57, 0x06, 0xbc,
0xb1, 0x0f, 0xde, 0x58, 0x51, 0x22, 0x58, 0x05, 0xc5, 0x33, 0x3a, 0x49, 0x94, 0x88, 0xe3, 0x9f,
0xb0, 0x06, 0x36, 0xc7, 0x64, 0x14, 0x26, 0x8a, 0xbb, 0x87, 0x93, 0xc3, 0x47, 0x85, 0x67, 0x46,
0xeb, 0xaf, 0x02, 0x78, 0x98, 0x76, 0x80, 0xb3, 0x5e, 0x28, 0xa9, 0x50, 0x1f, 0xd6, 0x5b, 0xd8,
0xd0, 0x3b, 0x00, 0xf4, 0x39, 0x1b, 0x53, 0xae, 0xd4, 0xaa, 0x42, 0x9b, 0x7b, 0xec, 0xa5, 0x2f,
0x38, 0x63, 0x05, 0xc7, 0x00, 0x04, 0x84, 0x13, 0x97, 0x4a, 0xca, 0xe3, 0x25, 0x1c, 0xeb, 0xcb,
0x5e, 0x4f, 0x5f, 0xd9, 0xec, 0xd0, 0xf3, 0x14, 0x24, 0x91, 0x55, 0xca, 0x3b, 0x7f, 0xc0, 0x19,
0xa6, 0xc6, 0xc7, 0xe0, 0xfe, 0x82, 0xcb, 0xb5, 0xca, 0xfc, 0xd2, 0x00, 0x6f, 0x2e, 0x0d, 0xe4,
0x16, 0xf6, 0xfb, 0x17, 0x97, 0xf7, 0xfb, 0xce, 0xf5, 0xab, 0xb5, 0x62, 0xc9, 0xff, 0x64, 0x80,
0xac, 0x3e, 0xe1, 0x21, 0x28, 0xc5, 0x7f, 0xcf, 0xea, 0x14, 0xde, 0x5e, 0x2f, 0x85, 0x13, 0xe6,
0xd2, 0xf9, 0xa7, 0x36, 0x3e, 0x61, 0x85, 0x02, 0xdf, 0x02, 0x77, 0x5d, 0x2a, 0x04, 0x19, 0xcc,
0xa4, 0x71, 0x5f, 0x1b, 0xdd, 0x3d, 0x4a, 0xae, 0xf1, 0xec, 0xdd, 0xee, 0x9c, 0x5f, 0x98, 0x1b,
0x2f, 0x2e, 0xcc, 0x8d, 0x57, 0x17, 0xe6, 0xc6, 0x8f, 0x91, 0x69, 0x9c, 0x47, 0xa6, 0xf1, 0x22,
0x32, 0x8d, 0x57, 0x91, 0x69, 0xfc, 0x11, 0x99, 0xc6, 0xcf, 0x7f, 0x9a, 0x1b, 0x5f, 0x3d, 0xbe,
0xe2, 0x3f, 0x98, 0xff, 0x02, 0x00, 0x00, 0xff, 0xff, 0xd7, 0x19, 0x2c, 0xaa, 0xdf, 0x0c, 0x00,
0x00,
// 1031 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x57, 0x4d, 0x6f, 0x1b, 0x45,
0x18, 0xce, 0xfa, 0xa3, 0x75, 0xc6, 0x29, 0x75, 0x47, 0x6e, 0x31, 0xae, 0xb4, 0xae, 0x7c, 0x32,
0x94, 0xee, 0x92, 0x80, 0x50, 0x85, 0xc4, 0xc1, 0x9b, 0xe4, 0x10, 0x91, 0x84, 0x32, 0x8e, 0x00,
0x01, 0x07, 0xc6, 0xeb, 0xc1, 0x9e, 0xc4, 0xfb, 0xa1, 0x99, 0x59, 0x0b, 0x73, 0xe2, 0x27, 0x70,
0xe3, 0x1f, 0xf0, 0x07, 0xf8, 0x13, 0x39, 0x20, 0x51, 0xf5, 0xd4, 0x93, 0x45, 0x16, 0x7e, 0x03,
0x07, 0x2e, 0xa0, 0x9d, 0x1d, 0xef, 0x6e, 0xbc, 0x76, 0x70, 0x72, 0xc8, 0xcd, 0xf3, 0x7e, 0x3c,
0xef, 0xd7, 0xf3, 0xbe, 0x9b, 0x80, 0xa7, 0x67, 0xcf, 0xb9, 0x41, 0x3d, 0x13, 0xfb, 0xd4, 0xe4,
0xc2, 0x63, 0x78, 0x48, 0xcc, 0xc9, 0x36, 0x1e, 0xfb, 0x23, 0xbc, 0x6d, 0x0e, 0x89, 0x4b, 0x18,
0x16, 0x64, 0x60, 0xf8, 0xcc, 0x13, 0x1e, 0x7c, 0x1c, 0x1b, 0x1b, 0xd8, 0xa7, 0x86, 0x32, 0x36,
0xe6, 0xc6, 0xcd, 0x67, 0x43, 0x2a, 0x46, 0x41, 0xdf, 0xb0, 0x3d, 0xc7, 0x1c, 0x7a, 0x43, 0xcf,
0x94, 0x3e, 0xfd, 0xe0, 0x3b, 0xf9, 0x92, 0x0f, 0xf9, 0x2b, 0xc6, 0x6a, 0xb6, 0x33, 0x81, 0x6d,
0x8f, 0x45, 0x51, 0x17, 0xe3, 0x35, 0x3f, 0x48, 0x6d, 0x1c, 0x6c, 0x8f, 0xa8, 0x4b, 0xd8, 0xd4,
0xf4, 0xcf, 0x86, 0xd2, 0x89, 0x11, 0xee, 0x05, 0xcc, 0x26, 0xd7, 0xf2, 0xe2, 0xa6, 0x43, 0x04,
0x5e, 0x16, 0xcb, 0x5c, 0xe5, 0xc5, 0x02, 0x57, 0x50, 0x27, 0x1f, 0xe6, 0xc3, 0xff, 0x73, 0xe0,
0xf6, 0x88, 0x38, 0x78, 0xd1, 0xaf, 0xfd, 0x77, 0x11, 0xc0, 0xdd, 0xde, 0x41, 0x2f, 0xee, 0xdf,
0x2e, 0xf6, 0xb1, 0x4d, 0xc5, 0x14, 0x7e, 0x0b, 0x2a, 0x51, 0x6a, 0x03, 0x2c, 0x70, 0x43, 0x7b,
0xa2, 0x75, 0xaa, 0x3b, 0xef, 0x19, 0x69, 0xbb, 0x93, 0x08, 0x86, 0x7f, 0x36, 0x8c, 0x04, 0xdc,
0x88, 0xac, 0x8d, 0xc9, 0xb6, 0xf1, 0x69, 0xff, 0x94, 0xd8, 0xe2, 0x88, 0x08, 0x6c, 0xc1, 0xf3,
0x59, 0x6b, 0x23, 0x9c, 0xb5, 0x40, 0x2a, 0x43, 0x09, 0x2a, 0xa4, 0x60, 0xcb, 0xf5, 0x06, 0xe4,
0xc4, 0xf3, 0xbd, 0xb1, 0x37, 0x9c, 0x36, 0x0a, 0x32, 0xca, 0xfb, 0xeb, 0x45, 0x39, 0xc4, 0x7d,
0x32, 0xee, 0x91, 0x31, 0xb1, 0x85, 0xc7, 0xac, 0x5a, 0x38, 0x6b, 0x6d, 0x1d, 0x67, 0xc0, 0xd0,
0x25, 0x68, 0xb8, 0x07, 0x6a, 0x8a, 0x1f, 0xbb, 0x63, 0xcc, 0xf9, 0x31, 0x76, 0x48, 0xa3, 0xf8,
0x44, 0xeb, 0x6c, 0x5a, 0x0d, 0x95, 0x62, 0xad, 0xb7, 0xa0, 0x47, 0x39, 0x0f, 0xf8, 0x25, 0xa8,
0xd8, 0xaa, 0x3d, 0x8d, 0x92, 0x4c, 0xd6, 0xb8, 0x2a, 0x59, 0x63, 0xce, 0x08, 0xe3, 0xb3, 0x00,
0xbb, 0x82, 0x8a, 0xa9, 0xb5, 0x15, 0xce, 0x5a, 0x95, 0x79, 0x8b, 0x51, 0x82, 0x06, 0x39, 0x78,
0xe0, 0xe0, 0xef, 0xa9, 0x13, 0x38, 0x9f, 0x7b, 0xe3, 0xc0, 0x21, 0x3d, 0xfa, 0x03, 0x69, 0x94,
0x6f, 0x14, 0xe2, 0x61, 0x38, 0x6b, 0x3d, 0x38, 0x5a, 0x04, 0x43, 0x79, 0xfc, 0xf6, 0x6f, 0x1a,
0x78, 0x94, 0x1f, 0xfc, 0x21, 0xe5, 0x02, 0x7e, 0x93, 0x1b, 0xbe, 0xb1, 0xe6, 0x58, 0x28, 0x8f,
0x47, 0x5f, 0x53, 0x7d, 0xad, 0xcc, 0x25, 0x99, 0xc1, 0x9f, 0x80, 0x32, 0x15, 0xc4, 0xe1, 0x8d,
0xc2, 0x93, 0x62, 0xa7, 0xba, 0x63, 0x1a, 0x57, 0xac, 0xb1, 0x91, 0xcf, 0xd0, 0xba, 0xa7, 0xb0,
0xcb, 0x07, 0x11, 0x0a, 0x8a, 0xc1, 0xda, 0xbf, 0x14, 0x40, 0x2d, 0xae, 0xae, 0x2b, 0x04, 0xb6,
0x47, 0x0e, 0x71, 0xc5, 0x2d, 0xb0, 0xb8, 0x07, 0x4a, 0xdc, 0x27, 0xb6, 0x62, 0xef, 0xf6, 0x95,
0xb5, 0x2c, 0xa6, 0xd7, 0xf3, 0x89, 0x6d, 0x6d, 0x29, 0xf8, 0x52, 0xf4, 0x42, 0x12, 0x0c, 0x7e,
0x0d, 0xee, 0x70, 0x81, 0x45, 0xc0, 0x25, 0x4b, 0x2f, 0x2f, 0xc5, 0x1a, 0xb0, 0xd2, 0xd5, 0x7a,
0x43, 0x01, 0xdf, 0x89, 0xdf, 0x48, 0x41, 0xb6, 0xcf, 0x35, 0x50, 0x5f, 0x74, 0xb9, 0x85, 0xa9,
0xa3, 0xcb, 0x53, 0x7f, 0x76, 0xad, 0x92, 0x56, 0xcc, 0xfc, 0x95, 0x06, 0x1e, 0xe5, 0xaa, 0x97,
0x0b, 0x01, 0x0f, 0x41, 0xdd, 0x27, 0x8c, 0x53, 0x2e, 0x88, 0x2b, 0x62, 0x1b, 0xb9, 0xf6, 0x5a,
0xbc, 0xf6, 0xe1, 0xac, 0x55, 0x7f, 0xb1, 0x44, 0x8f, 0x96, 0x7a, 0xc1, 0x53, 0x50, 0xa3, 0xee,
0x98, 0xba, 0x44, 0xed, 0x4f, 0x3a, 0xf1, 0x4e, 0xb6, 0x8e, 0xe8, 0xc3, 0x11, 0x35, 0x64, 0x11,
0x59, 0x0e, 0xba, 0x1e, 0x9d, 0x99, 0x83, 0x05, 0x14, 0x94, 0xc3, 0x6d, 0xff, 0xbe, 0x64, 0x3e,
0x91, 0x02, 0xbe, 0x0b, 0x2a, 0x58, 0x4a, 0x08, 0x53, 0x65, 0x24, 0xfd, 0xee, 0x2a, 0x39, 0x4a,
0x2c, 0x24, 0x87, 0x64, 0x2b, 0x96, 0x1c, 0xd6, 0x35, 0x38, 0x24, 0x5d, 0x33, 0x1c, 0x92, 0x6f,
0xa4, 0x20, 0xa3, 0x54, 0xa2, 0x03, 0x9b, 0x39, 0xa4, 0x49, 0x2a, 0xc7, 0x4a, 0x8e, 0x12, 0x8b,
0xf6, 0xbf, 0xc5, 0x25, 0x63, 0x92, 0x64, 0xcc, 0xd4, 0x34, 0x90, 0x35, 0x55, 0x72, 0x35, 0x0d,
0x92, 0x9a, 0x06, 0xf0, 0x67, 0x0d, 0x40, 0x9c, 0x40, 0x1c, 0xcd, 0xc9, 0x1a, 0x33, 0xea, 0x93,
0x1b, 0x2c, 0x89, 0xd1, 0xcd, 0xa1, 0xed, 0xbb, 0x82, 0x4d, 0xad, 0xa6, 0xca, 0x02, 0xe6, 0x0d,
0xd0, 0x92, 0x14, 0xe0, 0x29, 0xa8, 0xc6, 0xd2, 0x7d, 0xc6, 0x3c, 0xa6, 0xd6, 0xb6, 0xb3, 0x46,
0x46, 0xd2, 0xde, 0xd2, 0xc3, 0x59, 0xab, 0xda, 0x4d, 0x01, 0xfe, 0x99, 0xb5, 0xaa, 0x19, 0x3d,
0xca, 0x82, 0x47, 0xb1, 0x06, 0x24, 0x8d, 0x55, 0xba, 0x49, 0xac, 0x3d, 0xb2, 0x3a, 0x56, 0x06,
0xbc, 0xb9, 0x0f, 0xde, 0x5c, 0xd1, 0x22, 0x58, 0x03, 0xc5, 0x33, 0x32, 0x8d, 0x99, 0x88, 0xa2,
0x9f, 0xb0, 0x0e, 0xca, 0x13, 0x3c, 0x0e, 0x62, 0xc6, 0x6d, 0xa2, 0xf8, 0xf1, 0x51, 0xe1, 0xb9,
0xd6, 0xfe, 0xab, 0x00, 0x1e, 0x26, 0x13, 0x60, 0xb4, 0x1f, 0x08, 0xc2, 0xe5, 0x87, 0xf5, 0x16,
0x2e, 0xf4, 0x0e, 0x00, 0x03, 0x46, 0x27, 0x84, 0x49, 0xb6, 0xca, 0xd4, 0x52, 0x8f, 0xbd, 0x44,
0x83, 0x32, 0x56, 0x70, 0x02, 0x80, 0x8f, 0x19, 0x76, 0x88, 0x20, 0x2c, 0x3a, 0xc2, 0x11, 0xbf,
0xac, 0xf5, 0xf8, 0x95, 0xad, 0xce, 0x78, 0x91, 0x80, 0xc4, 0xb4, 0x4a, 0xe2, 0xa6, 0x0a, 0x94,
0x89, 0xd4, 0xfc, 0x18, 0xdc, 0x5f, 0x70, 0xb9, 0x56, 0x9b, 0x5f, 0x69, 0xe0, 0xad, 0xa5, 0x89,
0xdc, 0xc2, 0x7d, 0xff, 0xe2, 0xf2, 0x7d, 0xdf, 0xb9, 0x7e, 0xb7, 0x56, 0x1c, 0xf9, 0x5f, 0x35,
0x90, 0xe5, 0x27, 0x3c, 0x04, 0xa5, 0xe8, 0xef, 0x59, 0x55, 0xc2, 0x3b, 0xeb, 0x95, 0x70, 0x42,
0x1d, 0x92, 0x7e, 0x6a, 0xa3, 0x17, 0x92, 0x28, 0xf0, 0x6d, 0x70, 0xd7, 0x21, 0x9c, 0xe3, 0xe1,
0x9c, 0x1a, 0xf7, 0x95, 0xd1, 0xdd, 0xa3, 0x58, 0x8c, 0xe6, 0x7a, 0xf8, 0x14, 0x6c, 0x92, 0x28,
0x83, 0x5d, 0x6f, 0x10, 0x5f, 0xbd, 0xb2, 0x75, 0x2f, 0x9c, 0xb5, 0x36, 0xf7, 0xe7, 0x42, 0x94,
0xea, 0xad, 0xee, 0xf9, 0x85, 0xbe, 0xf1, 0xf2, 0x42, 0xdf, 0x78, 0x7d, 0xa1, 0x6f, 0xfc, 0x18,
0xea, 0xda, 0x79, 0xa8, 0x6b, 0x2f, 0x43, 0x5d, 0x7b, 0x1d, 0xea, 0xda, 0x1f, 0xa1, 0xae, 0xfd,
0xf4, 0xa7, 0xbe, 0xf1, 0xd5, 0xe3, 0x2b, 0xfe, 0xdd, 0xf9, 0x2f, 0x00, 0x00, 0xff, 0xff, 0x23,
0x8e, 0x6a, 0x20, 0x0c, 0x0d, 0x00, 0x00,
}
func (m *CSIStorageCapacity) Marshal() (dAtA []byte, err error) {
@ -928,6 +929,11 @@ func (m *VolumeError) MarshalToSizedBuffer(dAtA []byte) (int, error) {
_ = i
var l int
_ = l
if m.ErrorCode != nil {
i = encodeVarintGenerated(dAtA, i, uint64(*m.ErrorCode))
i--
dAtA[i] = 0x18
}
i -= len(m.Message)
copy(dAtA[i:], m.Message)
i = encodeVarintGenerated(dAtA, i, uint64(len(m.Message)))
@ -1137,6 +1143,9 @@ func (m *VolumeError) Size() (n int) {
n += 1 + l + sovGenerated(uint64(l))
l = len(m.Message)
n += 1 + l + sovGenerated(uint64(l))
if m.ErrorCode != nil {
n += 1 + sovGenerated(uint64(*m.ErrorCode))
}
return n
}
@ -1295,6 +1304,7 @@ func (this *VolumeError) String() string {
s := strings.Join([]string{`&VolumeError{`,
`Time:` + strings.Replace(strings.Replace(fmt.Sprintf("%v", this.Time), "Time", "v1.Time", 1), `&`, ``, 1) + `,`,
`Message:` + fmt.Sprintf("%v", this.Message) + `,`,
`ErrorCode:` + valueToStringGenerated(this.ErrorCode) + `,`,
`}`,
}, "")
return s
@ -2901,6 +2911,26 @@ func (m *VolumeError) Unmarshal(dAtA []byte) error {
}
m.Message = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
case 3:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field ErrorCode", wireType)
}
var v int32
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowGenerated
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
v |= int32(b&0x7F) << shift
if b < 0x80 {
break
}
}
m.ErrorCode = &v
default:
iNdEx = preIndex
skippy, err := skipGenerated(dAtA[iNdEx:])

View File

@ -265,5 +265,13 @@ message VolumeError {
// information.
// +optional
optional string message = 2;
// errorCode is a numeric gRPC code representing the error encountered during Attach or Detach operations.
//
// This is an optional, alpha field that requires the MutableCSINodeAllocatableCount feature gate being enabled to be set.
//
// +featureGate=MutableCSINodeAllocatableCount
// +optional
optional int32 errorCode = 3;
}

View File

@ -141,6 +141,14 @@ type VolumeError struct {
// information.
// +optional
Message string `json:"message,omitempty" protobuf:"bytes,2,opt,name=message"`
// errorCode is a numeric gRPC code representing the error encountered during Attach or Detach operations.
//
// This is an optional, alpha field that requires the MutableCSINodeAllocatableCount feature gate being enabled to be set.
//
// +featureGate=MutableCSINodeAllocatableCount
// +optional
ErrorCode *int32 `json:"errorCode,omitempty" protobuf:"varint,3,opt,name=errorCode"`
}
// +genclient

View File

@ -125,9 +125,10 @@ func (VolumeAttributesClassList) SwaggerDoc() map[string]string {
}
var map_VolumeError = map[string]string{
"": "VolumeError captures an error encountered during a volume operation.",
"time": "time represents the time the error was encountered.",
"message": "message represents the error encountered during Attach or Detach operation. This string maybe logged, so it should not contain sensitive information.",
"": "VolumeError captures an error encountered during a volume operation.",
"time": "time represents the time the error was encountered.",
"message": "message represents the error encountered during Attach or Detach operation. This string maybe logged, so it should not contain sensitive information.",
"errorCode": "errorCode is a numeric gRPC code representing the error encountered during Attach or Detach operations.\n\nThis is an optional, alpha field that requires the MutableCSINodeAllocatableCount feature gate being enabled to be set.",
}
func (VolumeError) SwaggerDoc() map[string]string {

View File

@ -308,6 +308,11 @@ func (in *VolumeAttributesClassList) DeepCopyObject() runtime.Object {
func (in *VolumeError) DeepCopyInto(out *VolumeError) {
*out = *in
in.Time.DeepCopyInto(&out.Time)
if in.ErrorCode != nil {
in, out := &in.ErrorCode, &out.ErrorCode
*out = new(int32)
**out = **in
}
return
}

View File

@ -668,115 +668,119 @@ func init() {
}
var fileDescriptor_73e4f72503e71065 = []byte{
// 1728 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x58, 0xcd, 0x6f, 0x23, 0x49,
0x15, 0x4f, 0xc7, 0xce, 0x57, 0x39, 0x99, 0x24, 0x35, 0x99, 0xc5, 0xeb, 0x83, 0x1d, 0x19, 0xc1,
0x66, 0x46, 0x4b, 0x7b, 0x12, 0x96, 0xd5, 0x68, 0xa5, 0x95, 0x48, 0x27, 0x81, 0xf5, 0x6e, 0x9c,
0xc9, 0x96, 0xa3, 0xd1, 0x6a, 0xc5, 0x81, 0x72, 0xbb, 0xe2, 0xd4, 0xc6, 0xfd, 0xb1, 0x5d, 0xd5,
0x21, 0xe6, 0x04, 0x17, 0xce, 0x88, 0x03, 0x7f, 0x01, 0xff, 0x02, 0x48, 0x70, 0xe1, 0xc8, 0x48,
0x48, 0x68, 0xe1, 0xc2, 0x9e, 0x2c, 0xc6, 0xf3, 0x27, 0x20, 0x71, 0x88, 0x38, 0xa0, 0xaa, 0x2e,
0xf7, 0xb7, 0x27, 0x36, 0x2b, 0xf9, 0xe6, 0x7a, 0x1f, 0xbf, 0x7a, 0x55, 0xef, 0xf7, 0x5e, 0xbd,
0x36, 0x78, 0x72, 0xfd, 0x8c, 0xe9, 0xd4, 0x69, 0x60, 0x97, 0x36, 0x18, 0x77, 0x3c, 0xdc, 0x23,
0x8d, 0x9b, 0xfd, 0x0e, 0xe1, 0x78, 0xbf, 0xd1, 0x23, 0x36, 0xf1, 0x30, 0x27, 0x5d, 0xdd, 0xf5,
0x1c, 0xee, 0xc0, 0x4a, 0x60, 0xab, 0x63, 0x97, 0xea, 0xca, 0x56, 0x57, 0xb6, 0x95, 0xef, 0xf5,
0x28, 0xbf, 0xf2, 0x3b, 0xba, 0xe9, 0x58, 0x8d, 0x9e, 0xd3, 0x73, 0x1a, 0xd2, 0xa5, 0xe3, 0x5f,
0xca, 0x95, 0x5c, 0xc8, 0x5f, 0x01, 0x54, 0xa5, 0x1e, 0xdb, 0xd6, 0x74, 0x3c, 0xb1, 0x67, 0x7a,
0xbb, 0xca, 0x7b, 0x91, 0x8d, 0x85, 0xcd, 0x2b, 0x6a, 0x13, 0x6f, 0xd0, 0x70, 0xaf, 0x7b, 0xd2,
0xc9, 0x23, 0xcc, 0xf1, 0x3d, 0x93, 0xcc, 0xe4, 0xc5, 0x1a, 0x16, 0xe1, 0x38, 0x6f, 0xaf, 0xc6,
0x24, 0x2f, 0xcf, 0xb7, 0x39, 0xb5, 0xb2, 0xdb, 0xbc, 0x7f, 0x9f, 0x03, 0x33, 0xaf, 0x88, 0x85,
0xd3, 0x7e, 0xf5, 0x3f, 0x69, 0x60, 0xed, 0xa8, 0xdd, 0x3c, 0xf6, 0xe8, 0x0d, 0xf1, 0xe0, 0x4f,
0xc1, 0xaa, 0x88, 0xa8, 0x8b, 0x39, 0x2e, 0x6b, 0xbb, 0xda, 0x5e, 0xe9, 0xe0, 0xa9, 0x1e, 0x5d,
0x72, 0x08, 0xac, 0xbb, 0xd7, 0x3d, 0x21, 0x60, 0xba, 0xb0, 0xd6, 0x6f, 0xf6, 0xf5, 0xe7, 0x9d,
0x2f, 0x88, 0xc9, 0x5b, 0x84, 0x63, 0x03, 0xbe, 0x1c, 0xd6, 0x16, 0x46, 0xc3, 0x1a, 0x88, 0x64,
0x28, 0x44, 0x85, 0x9f, 0x80, 0x22, 0x73, 0x89, 0x59, 0x5e, 0x94, 0xe8, 0x8f, 0xf5, 0xc9, 0x29,
0xd4, 0xc3, 0xb0, 0xda, 0x2e, 0x31, 0x8d, 0x75, 0x05, 0x5b, 0x14, 0x2b, 0x24, 0x41, 0xea, 0x7f,
0xd4, 0xc0, 0x46, 0x68, 0x75, 0x4a, 0x19, 0x87, 0x3f, 0xc9, 0x1c, 0x40, 0x9f, 0xee, 0x00, 0xc2,
0x5b, 0x86, 0xbf, 0xa5, 0xf6, 0x59, 0x1d, 0x4b, 0x62, 0xc1, 0x7f, 0x0c, 0x96, 0x28, 0x27, 0x16,
0x2b, 0x2f, 0xee, 0x16, 0xf6, 0x4a, 0x07, 0xdf, 0x99, 0x2a, 0x7a, 0x63, 0x43, 0x21, 0x2e, 0x35,
0x85, 0x2f, 0x0a, 0x20, 0xea, 0xff, 0x2c, 0xc6, 0x62, 0x17, 0x67, 0x82, 0x1f, 0x80, 0x07, 0x98,
0x73, 0x6c, 0x5e, 0x21, 0xf2, 0xa5, 0x4f, 0x3d, 0xd2, 0x95, 0x27, 0x58, 0x35, 0xe0, 0x68, 0x58,
0x7b, 0x70, 0x98, 0xd0, 0xa0, 0x94, 0xa5, 0xf0, 0x75, 0x9d, 0x6e, 0xd3, 0xbe, 0x74, 0x9e, 0xdb,
0x2d, 0xc7, 0xb7, 0xb9, 0xbc, 0x60, 0xe5, 0x7b, 0x9e, 0xd0, 0xa0, 0x94, 0x25, 0x34, 0xc1, 0xce,
0x8d, 0xd3, 0xf7, 0x2d, 0x72, 0x4a, 0x2f, 0x89, 0x39, 0x30, 0xfb, 0xa4, 0xe5, 0x74, 0x09, 0x2b,
0x17, 0x76, 0x0b, 0x7b, 0x6b, 0x46, 0x63, 0x34, 0xac, 0xed, 0xbc, 0xc8, 0xd1, 0xdf, 0x0d, 0x6b,
0x0f, 0x73, 0xe4, 0x28, 0x17, 0x0c, 0x7e, 0x08, 0x36, 0xd5, 0x0d, 0x1d, 0x61, 0x17, 0x9b, 0x94,
0x0f, 0xca, 0x45, 0x19, 0xe1, 0xc3, 0xd1, 0xb0, 0xb6, 0xd9, 0x4e, 0xaa, 0x50, 0xda, 0x16, 0x7e,
0x04, 0x36, 0x2e, 0xd9, 0x8f, 0x3d, 0xc7, 0x77, 0xcf, 0x9d, 0x3e, 0x35, 0x07, 0xe5, 0xa5, 0x5d,
0x6d, 0x6f, 0xcd, 0xa8, 0x8f, 0x86, 0xb5, 0x8d, 0x1f, 0xb5, 0x63, 0x8a, 0xbb, 0xb4, 0x00, 0x25,
0x1d, 0x21, 0x01, 0x1b, 0xdc, 0xb9, 0x26, 0xb6, 0xb8, 0x3a, 0xc2, 0x38, 0x2b, 0x2f, 0xcb, 0x5c,
0xee, 0xbd, 0x29, 0x97, 0x17, 0x31, 0x07, 0xe3, 0x91, 0x4a, 0xe7, 0x46, 0x5c, 0xca, 0x50, 0x12,
0x15, 0x1e, 0x81, 0x6d, 0x2f, 0x48, 0x0e, 0x43, 0xc4, 0xf5, 0x3b, 0x7d, 0xca, 0xae, 0xca, 0x2b,
0xf2, 0xc4, 0x8f, 0x46, 0xc3, 0xda, 0x36, 0x4a, 0x2b, 0x51, 0xd6, 0x1e, 0xbe, 0x07, 0xd6, 0x19,
0x39, 0xa5, 0xb6, 0x7f, 0x1b, 0xe4, 0x74, 0x55, 0xfa, 0x6f, 0x8d, 0x86, 0xb5, 0xf5, 0xf6, 0x49,
0x24, 0x47, 0x09, 0xab, 0xfa, 0x1f, 0x34, 0xb0, 0x72, 0xd4, 0x6e, 0x9e, 0x39, 0x5d, 0x32, 0x87,
0x82, 0x6e, 0x26, 0x0a, 0xfa, 0x9d, 0x7b, 0x4a, 0x42, 0x04, 0x35, 0xb1, 0x9c, 0xff, 0x1d, 0x94,
0xb3, 0xb0, 0x51, 0xfd, 0x68, 0x17, 0x14, 0x6d, 0x6c, 0x11, 0x19, 0xfa, 0x5a, 0xe4, 0x73, 0x86,
0x2d, 0x82, 0xa4, 0x06, 0x7e, 0x17, 0x2c, 0xdb, 0x4e, 0x97, 0x34, 0x8f, 0x65, 0x00, 0x6b, 0xc6,
0x03, 0x65, 0xb3, 0x7c, 0x26, 0xa5, 0x48, 0x69, 0xc5, 0x55, 0x72, 0xc7, 0x75, 0xfa, 0x4e, 0x6f,
0xf0, 0x09, 0x19, 0x8c, 0xc9, 0x2d, 0xaf, 0xf2, 0x22, 0x26, 0x47, 0x09, 0x2b, 0xd8, 0x01, 0x25,
0xdc, 0xef, 0x3b, 0x26, 0xe6, 0xb8, 0xd3, 0x27, 0x92, 0xb1, 0xa5, 0x83, 0xc6, 0x9b, 0xce, 0x18,
0x54, 0x84, 0xd8, 0x1c, 0xa9, 0x17, 0x81, 0x19, 0x9b, 0xa3, 0x61, 0xad, 0x74, 0x18, 0xe1, 0xa0,
0x38, 0x68, 0xfd, 0xf7, 0x1a, 0x28, 0xa9, 0x53, 0xcf, 0xa1, 0x85, 0x7d, 0x94, 0x6c, 0x61, 0xdf,
0x9e, 0x22, 0x5f, 0x13, 0x1a, 0x98, 0x19, 0x86, 0x2d, 0xbb, 0xd7, 0x05, 0x58, 0xe9, 0xca, 0xa4,
0xb1, 0xb2, 0x26, 0xa1, 0x1f, 0x4f, 0x01, 0xad, 0x3a, 0xe4, 0xa6, 0xda, 0x60, 0x25, 0x58, 0x33,
0x34, 0x86, 0xaa, 0xff, 0xa7, 0x00, 0xe0, 0x51, 0xbb, 0x99, 0xea, 0x0f, 0x73, 0xa0, 0x35, 0x05,
0xeb, 0x82, 0x39, 0x63, 0x6e, 0x28, 0x7a, 0x7f, 0x7f, 0xca, 0x4c, 0xe0, 0x0e, 0xe9, 0xb7, 0x49,
0x9f, 0x98, 0xdc, 0xf1, 0x02, 0x92, 0x9d, 0xc5, 0xc0, 0x50, 0x02, 0x1a, 0x1e, 0x83, 0xad, 0x71,
0xbb, 0xeb, 0x63, 0xc6, 0x04, 0xb9, 0xcb, 0x05, 0x49, 0xe6, 0xb2, 0x0a, 0x71, 0xab, 0x9d, 0xd2,
0xa3, 0x8c, 0x07, 0xfc, 0x0c, 0xac, 0x9a, 0xf1, 0xce, 0x7a, 0x0f, 0x6d, 0xf4, 0xf1, 0xc0, 0xa2,
0x7f, 0xea, 0x63, 0x9b, 0x53, 0x3e, 0x30, 0xd6, 0x05, 0x65, 0xc2, 0x16, 0x1c, 0xa2, 0x41, 0x06,
0xb6, 0x2d, 0x7c, 0x4b, 0x2d, 0xdf, 0x0a, 0xc8, 0xdd, 0xa6, 0x3f, 0x27, 0xb2, 0xff, 0xce, 0xbe,
0x85, 0x6c, 0x7d, 0xad, 0x34, 0x18, 0xca, 0xe2, 0xd7, 0xff, 0xaa, 0x81, 0xb7, 0xb2, 0x89, 0x9f,
0x43, 0x81, 0xb4, 0x93, 0x05, 0xa2, 0xdf, 0xc3, 0xe2, 0x54, 0x80, 0x13, 0x6a, 0xe5, 0x37, 0xcb,
0x60, 0x3d, 0x9e, 0xc3, 0x39, 0x10, 0xf8, 0x07, 0xa0, 0xe4, 0x7a, 0xce, 0x0d, 0x65, 0xd4, 0xb1,
0x89, 0xa7, 0xba, 0xe3, 0x43, 0xe5, 0x52, 0x3a, 0x8f, 0x54, 0x28, 0x6e, 0x07, 0xfb, 0x00, 0xb8,
0xd8, 0xc3, 0x16, 0xe1, 0xa2, 0x92, 0x0b, 0xf2, 0x0e, 0x9e, 0xbd, 0xe9, 0x0e, 0xe2, 0xc7, 0xd2,
0xcf, 0x43, 0xd7, 0x13, 0x9b, 0x7b, 0x83, 0x28, 0xc4, 0x48, 0x81, 0x62, 0xf8, 0xf0, 0x1a, 0x6c,
0x78, 0xc4, 0xec, 0x63, 0x6a, 0xa9, 0x67, 0xbd, 0x28, 0xc3, 0x3c, 0x11, 0xcf, 0x2b, 0x8a, 0x2b,
0xee, 0x86, 0xb5, 0xa7, 0xd9, 0x11, 0x5d, 0x3f, 0x27, 0x1e, 0xa3, 0x8c, 0x13, 0x9b, 0x07, 0xd4,
0x49, 0xf8, 0xa0, 0x24, 0xb6, 0x78, 0x02, 0x2c, 0xf1, 0x40, 0x3e, 0x77, 0x39, 0x75, 0x6c, 0x56,
0x5e, 0x8a, 0x9e, 0x80, 0x56, 0x4c, 0x8e, 0x12, 0x56, 0xf0, 0x14, 0xec, 0x88, 0x6e, 0xfd, 0xb3,
0x60, 0x83, 0x93, 0x5b, 0x17, 0xdb, 0xe2, 0xaa, 0xca, 0xcb, 0xf2, 0x2d, 0x2e, 0x8b, 0xe9, 0xe8,
0x30, 0x47, 0x8f, 0x72, 0xbd, 0xe0, 0x67, 0x60, 0x3b, 0x18, 0x8f, 0x0c, 0x6a, 0x77, 0xa9, 0xdd,
0x13, 0xc3, 0x91, 0x1c, 0x0b, 0xd6, 0x8c, 0x27, 0xa2, 0x36, 0x5e, 0xa4, 0x95, 0x77, 0x79, 0x42,
0x94, 0x05, 0x81, 0x5f, 0x82, 0x6d, 0xb9, 0x23, 0xe9, 0xaa, 0xc6, 0x42, 0x09, 0x2b, 0xaf, 0x66,
0x67, 0x1b, 0x71, 0x75, 0x82, 0x48, 0xe3, 0xf6, 0x33, 0x6e, 0x53, 0x17, 0xc4, 0xb3, 0x8c, 0xb7,
0x55, 0xbe, 0xb6, 0x0f, 0xd3, 0x50, 0x28, 0x8b, 0x5e, 0xf9, 0x10, 0x6c, 0xa6, 0x12, 0x0e, 0xb7,
0x40, 0xe1, 0x9a, 0x0c, 0x82, 0xf7, 0x1a, 0x89, 0x9f, 0x70, 0x07, 0x2c, 0xdd, 0xe0, 0xbe, 0x4f,
0x02, 0x06, 0xa2, 0x60, 0xf1, 0xc1, 0xe2, 0x33, 0xad, 0xfe, 0x67, 0x0d, 0x24, 0x1a, 0xdb, 0x1c,
0x8a, 0xbb, 0x95, 0x2c, 0xee, 0xbd, 0x69, 0x89, 0x3d, 0xa1, 0xac, 0x7f, 0xa9, 0x81, 0xf5, 0xf8,
0x14, 0x08, 0xdf, 0x05, 0xab, 0xd8, 0xef, 0x52, 0x62, 0x9b, 0xe3, 0x99, 0x25, 0x8c, 0xe6, 0x50,
0xc9, 0x51, 0x68, 0x21, 0x66, 0x44, 0x72, 0xeb, 0x52, 0x0f, 0x0b, 0xa6, 0xb5, 0x89, 0xe9, 0xd8,
0x5d, 0x26, 0xaf, 0xa9, 0x10, 0x34, 0xca, 0x93, 0xb4, 0x12, 0x65, 0xed, 0xeb, 0xbf, 0x5b, 0x04,
0x5b, 0x01, 0x41, 0x82, 0x4f, 0x04, 0x8b, 0xd8, 0x7c, 0x0e, 0xed, 0x05, 0x25, 0xc6, 0xbe, 0xa7,
0xf7, 0x8f, 0x44, 0x51, 0x74, 0x93, 0xe6, 0x3f, 0xf8, 0x39, 0x58, 0x66, 0x1c, 0x73, 0x9f, 0xc9,
0xe7, 0xaf, 0x74, 0x70, 0x30, 0x13, 0xaa, 0xf4, 0x8c, 0xe6, 0xbf, 0x60, 0x8d, 0x14, 0x62, 0xfd,
0x2f, 0x1a, 0xd8, 0x49, 0xbb, 0xcc, 0x81, 0x70, 0x9f, 0x26, 0x09, 0xf7, 0xee, 0x2c, 0x27, 0x9a,
0x40, 0xba, 0x7f, 0x68, 0xe0, 0xad, 0xcc, 0xe1, 0xe5, 0x3b, 0x2b, 0x7a, 0x95, 0x9b, 0xea, 0x88,
0x67, 0xd1, 0xf8, 0x2c, 0x7b, 0xd5, 0x79, 0x8e, 0x1e, 0xe5, 0x7a, 0xc1, 0x2f, 0xc0, 0x16, 0xb5,
0xfb, 0xd4, 0x26, 0xea, 0x59, 0x8e, 0xd2, 0x9d, 0xdb, 0x50, 0xd2, 0xc8, 0x32, 0xcd, 0x3b, 0x62,
0x7a, 0x69, 0xa6, 0x50, 0x50, 0x06, 0xb7, 0xfe, 0xb7, 0x9c, 0xf4, 0xc8, 0xb1, 0x52, 0x54, 0x94,
0x94, 0x10, 0x2f, 0x53, 0x51, 0x4a, 0x8e, 0x42, 0x0b, 0xc9, 0x20, 0x79, 0x15, 0x2a, 0xd0, 0xd9,
0x18, 0x24, 0x3d, 0x63, 0x0c, 0x92, 0x6b, 0xa4, 0x10, 0x45, 0x24, 0x62, 0x6c, 0x8b, 0x8d, 0x67,
0x61, 0x24, 0x67, 0x4a, 0x8e, 0x42, 0x8b, 0xfa, 0x7f, 0x0b, 0x39, 0x59, 0x92, 0x54, 0x8c, 0x1d,
0x69, 0xfc, 0x85, 0x9f, 0x3e, 0x52, 0x37, 0x3c, 0x52, 0x17, 0xfe, 0x56, 0x03, 0x10, 0x87, 0x10,
0xad, 0x31, 0x55, 0x03, 0x3e, 0x7d, 0x3c, 0x7b, 0x85, 0xe8, 0x87, 0x19, 0xb0, 0xe0, 0xad, 0xae,
0xa8, 0x20, 0x60, 0xd6, 0x00, 0xe5, 0x44, 0x00, 0x29, 0x28, 0x05, 0xd2, 0x13, 0xcf, 0x73, 0x3c,
0x55, 0xb2, 0xef, 0xdc, 0x1f, 0x90, 0x34, 0x37, 0xaa, 0xf2, 0x9b, 0x28, 0xf2, 0xbf, 0x1b, 0xd6,
0x4a, 0x31, 0x3d, 0x8a, 0x63, 0x8b, 0xad, 0xba, 0x24, 0xda, 0xaa, 0xf8, 0x7f, 0x6c, 0x75, 0x4c,
0x26, 0x6f, 0x15, 0xc3, 0xae, 0x9c, 0x80, 0x6f, 0x4d, 0xb8, 0xa0, 0x99, 0xde, 0xb6, 0xd7, 0x8b,
0xe0, 0x51, 0x78, 0xff, 0x1e, 0xed, 0xf8, 0x9c, 0xb0, 0x79, 0x4d, 0x7e, 0x07, 0x00, 0x04, 0x9f,
0x4f, 0x92, 0xaa, 0xc1, 0xe0, 0x17, 0x7a, 0x1c, 0x87, 0x1a, 0x14, 0xb3, 0x82, 0x7e, 0xce, 0xd8,
0x77, 0x38, 0x15, 0xb9, 0xe2, 0x87, 0x9b, 0x75, 0xfe, 0xfb, 0xa6, 0x13, 0xc4, 0xdf, 0x35, 0xf0,
0x76, 0x6e, 0x20, 0x73, 0xe8, 0xec, 0x2f, 0x92, 0x9d, 0x7d, 0x7f, 0xe6, 0xcb, 0x9a, 0xd0, 0xde,
0x7f, 0xa5, 0x81, 0x38, 0x3b, 0xe1, 0x29, 0x28, 0x72, 0xaa, 0x7a, 0x78, 0xe9, 0xe0, 0xc9, 0x74,
0x27, 0xb8, 0xa0, 0x16, 0x89, 0x9e, 0x58, 0xb1, 0x42, 0x12, 0x05, 0x3e, 0x06, 0x2b, 0x16, 0x61,
0x0c, 0xf7, 0xc6, 0xc4, 0x08, 0x3f, 0xbd, 0x5b, 0x81, 0x18, 0x8d, 0xf5, 0xf5, 0xf7, 0xc1, 0xc3,
0x9c, 0x3f, 0x33, 0x60, 0x0d, 0x2c, 0x99, 0xf2, 0xcf, 0x28, 0x11, 0xd0, 0x92, 0xb1, 0x26, 0x0e,
0x70, 0x24, 0xff, 0x85, 0x0a, 0xe4, 0xc6, 0x0f, 0x5f, 0xbe, 0xaa, 0x2e, 0x7c, 0xf5, 0xaa, 0xba,
0xf0, 0xf5, 0xab, 0xea, 0xc2, 0x2f, 0x46, 0x55, 0xed, 0xe5, 0xa8, 0xaa, 0x7d, 0x35, 0xaa, 0x6a,
0x5f, 0x8f, 0xaa, 0xda, 0xbf, 0x46, 0x55, 0xed, 0xd7, 0xaf, 0xab, 0x0b, 0x9f, 0x57, 0x26, 0xff,
0xcf, 0xff, 0xbf, 0x00, 0x00, 0x00, 0xff, 0xff, 0x3a, 0x30, 0xdb, 0x24, 0x04, 0x18, 0x00, 0x00,
// 1787 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x59, 0x4f, 0x6f, 0x24, 0x47,
0x15, 0x77, 0x7b, 0xfc, 0x6f, 0x6a, 0xec, 0xb5, 0x5d, 0xeb, 0x0d, 0x13, 0x1f, 0x66, 0xac, 0x46,
0x24, 0xde, 0x25, 0xf4, 0xec, 0x9a, 0x10, 0xad, 0x22, 0x45, 0xc2, 0x6d, 0x1b, 0xe2, 0xc4, 0xf6,
0x3a, 0x35, 0x66, 0x15, 0x45, 0x1c, 0xa8, 0xe9, 0xae, 0x1d, 0x57, 0x3c, 0xfd, 0x27, 0x5d, 0xd5,
0xc6, 0xc3, 0x09, 0xbe, 0x01, 0xe2, 0xc0, 0x27, 0xe0, 0x1b, 0x20, 0x90, 0xe0, 0xc2, 0x91, 0x95,
0x90, 0x20, 0x70, 0xca, 0x69, 0xc4, 0x4e, 0x3e, 0x02, 0x12, 0x07, 0x8b, 0x03, 0xaa, 0xea, 0x9a,
0xfe, 0x3f, 0xeb, 0x19, 0x90, 0xe6, 0xe6, 0x7a, 0x7f, 0x7e, 0xf5, 0xaa, 0xde, 0x7b, 0xbf, 0x7a,
0x3d, 0x06, 0x8f, 0xae, 0x9e, 0x32, 0x83, 0x7a, 0x2d, 0xec, 0xd3, 0x16, 0xe3, 0x5e, 0x80, 0xbb,
0xa4, 0x75, 0xfd, 0xa4, 0x43, 0x38, 0x7e, 0xd2, 0xea, 0x12, 0x97, 0x04, 0x98, 0x13, 0xdb, 0xf0,
0x03, 0x8f, 0x7b, 0x70, 0x3b, 0xb2, 0x35, 0xb0, 0x4f, 0x0d, 0x65, 0x6b, 0x28, 0xdb, 0xed, 0xef,
0x74, 0x29, 0xbf, 0x0c, 0x3b, 0x86, 0xe5, 0x39, 0xad, 0xae, 0xd7, 0xf5, 0x5a, 0xd2, 0xa5, 0x13,
0xbe, 0x90, 0x2b, 0xb9, 0x90, 0x7f, 0x45, 0x50, 0xdb, 0x7a, 0x6a, 0x5b, 0xcb, 0x0b, 0xc4, 0x9e,
0xf9, 0xed, 0xb6, 0xdf, 0x4d, 0x6c, 0x1c, 0x6c, 0x5d, 0x52, 0x97, 0x04, 0xfd, 0x96, 0x7f, 0xd5,
0x95, 0x4e, 0x01, 0x61, 0x5e, 0x18, 0x58, 0x64, 0x2a, 0x2f, 0xd6, 0x72, 0x08, 0xc7, 0x65, 0x7b,
0xb5, 0xc6, 0x79, 0x05, 0xa1, 0xcb, 0xa9, 0x53, 0xdc, 0xe6, 0xbd, 0xbb, 0x1c, 0x98, 0x75, 0x49,
0x1c, 0x9c, 0xf7, 0xd3, 0xff, 0xa8, 0x81, 0xea, 0x41, 0xfb, 0xf8, 0x30, 0xa0, 0xd7, 0x24, 0x80,
0x3f, 0x01, 0x2b, 0x22, 0x22, 0x1b, 0x73, 0x5c, 0xd7, 0x76, 0xb4, 0xdd, 0xda, 0xde, 0x63, 0x23,
0xb9, 0xe4, 0x18, 0xd8, 0xf0, 0xaf, 0xba, 0x42, 0xc0, 0x0c, 0x61, 0x6d, 0x5c, 0x3f, 0x31, 0x9e,
0x75, 0x3e, 0x27, 0x16, 0x3f, 0x25, 0x1c, 0x9b, 0xf0, 0xe5, 0xa0, 0x39, 0x37, 0x1c, 0x34, 0x41,
0x22, 0x43, 0x31, 0x2a, 0xfc, 0x18, 0x2c, 0x30, 0x9f, 0x58, 0xf5, 0x79, 0x89, 0xfe, 0xd0, 0x18,
0x9f, 0x42, 0x23, 0x0e, 0xab, 0xed, 0x13, 0xcb, 0x5c, 0x55, 0xb0, 0x0b, 0x62, 0x85, 0x24, 0x88,
0xfe, 0x07, 0x0d, 0xac, 0xc5, 0x56, 0x27, 0x94, 0x71, 0xf8, 0xe3, 0xc2, 0x01, 0x8c, 0xc9, 0x0e,
0x20, 0xbc, 0x65, 0xf8, 0x1b, 0x6a, 0x9f, 0x95, 0x91, 0x24, 0x15, 0xfc, 0x47, 0x60, 0x91, 0x72,
0xe2, 0xb0, 0xfa, 0xfc, 0x4e, 0x65, 0xb7, 0xb6, 0xf7, 0xad, 0x89, 0xa2, 0x37, 0xd7, 0x14, 0xe2,
0xe2, 0xb1, 0xf0, 0x45, 0x11, 0x84, 0xfe, 0xb7, 0xc5, 0x54, 0xec, 0xe2, 0x4c, 0xf0, 0x7d, 0x70,
0x0f, 0x73, 0x8e, 0xad, 0x4b, 0x44, 0xbe, 0x08, 0x69, 0x40, 0x6c, 0x79, 0x82, 0x15, 0x13, 0x0e,
0x07, 0xcd, 0x7b, 0xfb, 0x19, 0x0d, 0xca, 0x59, 0x0a, 0x5f, 0xdf, 0xb3, 0x8f, 0xdd, 0x17, 0xde,
0x33, 0xf7, 0xd4, 0x0b, 0x5d, 0x2e, 0x2f, 0x58, 0xf9, 0x9e, 0x67, 0x34, 0x28, 0x67, 0x09, 0x2d,
0xb0, 0x75, 0xed, 0xf5, 0x42, 0x87, 0x9c, 0xd0, 0x17, 0xc4, 0xea, 0x5b, 0x3d, 0x72, 0xea, 0xd9,
0x84, 0xd5, 0x2b, 0x3b, 0x95, 0xdd, 0xaa, 0xd9, 0x1a, 0x0e, 0x9a, 0x5b, 0xcf, 0x4b, 0xf4, 0xb7,
0x83, 0xe6, 0xfd, 0x12, 0x39, 0x2a, 0x05, 0x83, 0x1f, 0x80, 0x75, 0x75, 0x43, 0x07, 0xd8, 0xc7,
0x16, 0xe5, 0xfd, 0xfa, 0x82, 0x8c, 0xf0, 0xfe, 0x70, 0xd0, 0x5c, 0x6f, 0x67, 0x55, 0x28, 0x6f,
0x0b, 0x3f, 0x04, 0x6b, 0x2f, 0xd8, 0x0f, 0x03, 0x2f, 0xf4, 0xcf, 0xbd, 0x1e, 0xb5, 0xfa, 0xf5,
0xc5, 0x1d, 0x6d, 0xb7, 0x6a, 0xea, 0xc3, 0x41, 0x73, 0xed, 0x07, 0xed, 0x94, 0xe2, 0x36, 0x2f,
0x40, 0x59, 0x47, 0x48, 0xc0, 0x1a, 0xf7, 0xae, 0x88, 0x2b, 0xae, 0x8e, 0x30, 0xce, 0xea, 0x4b,
0x32, 0x97, 0xbb, 0xaf, 0xcb, 0xe5, 0x45, 0xca, 0xc1, 0x7c, 0xa0, 0xd2, 0xb9, 0x96, 0x96, 0x32,
0x94, 0x45, 0x85, 0x07, 0x60, 0x33, 0x88, 0x92, 0xc3, 0x10, 0xf1, 0xc3, 0x4e, 0x8f, 0xb2, 0xcb,
0xfa, 0xb2, 0x3c, 0xf1, 0x83, 0xe1, 0xa0, 0xb9, 0x89, 0xf2, 0x4a, 0x54, 0xb4, 0x87, 0xef, 0x82,
0x55, 0x46, 0x4e, 0xa8, 0x1b, 0xde, 0x44, 0x39, 0x5d, 0x91, 0xfe, 0x1b, 0xc3, 0x41, 0x73, 0xb5,
0x7d, 0x94, 0xc8, 0x51, 0xc6, 0x0a, 0x5e, 0x03, 0xdd, 0xf5, 0x6c, 0xb2, 0xdf, 0xeb, 0x79, 0x16,
0xe6, 0xb8, 0xd3, 0x23, 0x3f, 0xf2, 0x6d, 0xcc, 0xc9, 0x39, 0x09, 0xa8, 0x67, 0xb7, 0x89, 0xe5,
0xb9, 0x36, 0xab, 0x57, 0x77, 0xb4, 0xdd, 0x8a, 0xf9, 0xd6, 0x70, 0xd0, 0xd4, 0xcf, 0xee, 0xb4,
0x46, 0x13, 0x20, 0xea, 0xbf, 0xd7, 0xc0, 0xf2, 0x41, 0xfb, 0x58, 0xa0, 0xcd, 0x80, 0x48, 0x8e,
0x33, 0x44, 0xf2, 0xf6, 0x1d, 0xad, 0x28, 0x82, 0x1a, 0x4b, 0x23, 0xff, 0x8a, 0x68, 0x44, 0xd8,
0x28, 0x1e, 0xdc, 0x01, 0x0b, 0x2e, 0x76, 0x88, 0x0c, 0xbd, 0x9a, 0xf8, 0x9c, 0x61, 0x87, 0x20,
0xa9, 0x81, 0x6f, 0x81, 0x25, 0x71, 0x25, 0xc7, 0x87, 0x32, 0x80, 0xaa, 0x79, 0x4f, 0xd9, 0x2c,
0x9d, 0x49, 0x29, 0x52, 0x5a, 0x91, 0x42, 0xee, 0xf9, 0x5e, 0xcf, 0xeb, 0xf6, 0x3f, 0x26, 0xfd,
0x51, 0x53, 0xc9, 0x14, 0x5e, 0xa4, 0xe4, 0x28, 0x63, 0x05, 0x3b, 0xa0, 0x86, 0x93, 0xcb, 0x96,
0x9d, 0x52, 0xdb, 0x6b, 0xbd, 0xee, 0x8c, 0x51, 0x27, 0x8a, 0xcd, 0x91, 0x7a, 0x89, 0x98, 0xb9,
0x3e, 0x1c, 0x34, 0x6b, 0xa9, 0xa4, 0xa1, 0x34, 0xa8, 0xfe, 0x3b, 0x0d, 0xd4, 0xd4, 0xa9, 0x67,
0x40, 0x9d, 0x1f, 0x66, 0xa9, 0xf3, 0x9b, 0x13, 0xe4, 0x6b, 0x0c, 0x71, 0x5a, 0x71, 0xd8, 0x92,
0x35, 0x2f, 0xc0, 0xb2, 0x2d, 0x93, 0xc6, 0xea, 0x9a, 0x84, 0x7e, 0x38, 0x01, 0xb4, 0x62, 0xe6,
0x75, 0xb5, 0xc1, 0x72, 0xb4, 0x66, 0x68, 0x04, 0xa5, 0xff, 0xbb, 0x02, 0xe0, 0x41, 0xfb, 0x38,
0xc7, 0x4b, 0x33, 0x28, 0x6b, 0x0a, 0x56, 0x45, 0xe5, 0x8c, 0x6a, 0x43, 0x95, 0xf7, 0x77, 0x27,
0xcc, 0x04, 0xee, 0x90, 0x5e, 0x9b, 0xf4, 0x88, 0xc5, 0xbd, 0x20, 0x2a, 0xb2, 0xb3, 0x14, 0x18,
0xca, 0x40, 0xc3, 0x43, 0xb0, 0x31, 0xa2, 0xd9, 0x1e, 0x66, 0x4c, 0x14, 0x77, 0xbd, 0x22, 0x8b,
0xb9, 0xae, 0x42, 0xdc, 0x68, 0xe7, 0xf4, 0xa8, 0xe0, 0x01, 0x3f, 0x05, 0x2b, 0x56, 0x9a, 0xd1,
0xef, 0x28, 0x1b, 0x63, 0x34, 0x28, 0x19, 0x9f, 0x84, 0xd8, 0xe5, 0x94, 0xf7, 0xcd, 0x55, 0x51,
0x32, 0x31, 0xf5, 0xc7, 0x68, 0x90, 0x81, 0x4d, 0x07, 0xdf, 0x50, 0x27, 0x74, 0xa2, 0xe2, 0x6e,
0xd3, 0x9f, 0x11, 0xc9, 0xfb, 0xd3, 0x6f, 0x21, 0x29, 0xf7, 0x34, 0x0f, 0x86, 0x8a, 0xf8, 0xfa,
0x5f, 0x34, 0xf0, 0x46, 0x31, 0xf1, 0x33, 0x68, 0x90, 0x76, 0xb6, 0x41, 0x8c, 0x3b, 0xaa, 0x38,
0x17, 0xe0, 0x98, 0x5e, 0xf9, 0xd5, 0x12, 0x58, 0x4d, 0xe7, 0x70, 0x06, 0x05, 0xfc, 0x3d, 0x50,
0xf3, 0x03, 0xef, 0x9a, 0x32, 0xea, 0xb9, 0x24, 0x50, 0xec, 0x78, 0x5f, 0xb9, 0xd4, 0xce, 0x13,
0x15, 0x4a, 0xdb, 0xc1, 0x1e, 0x00, 0x3e, 0x0e, 0xb0, 0x43, 0xb8, 0xe8, 0xe4, 0x8a, 0xbc, 0x83,
0xa7, 0xaf, 0xbb, 0x83, 0xf4, 0xb1, 0x8c, 0xf3, 0xd8, 0xf5, 0xc8, 0xe5, 0x41, 0x3f, 0x09, 0x31,
0x51, 0xa0, 0x14, 0x3e, 0xbc, 0x02, 0x6b, 0x01, 0xb1, 0x7a, 0x98, 0x3a, 0x6a, 0x9c, 0x58, 0x90,
0x61, 0x1e, 0x89, 0x67, 0x1d, 0xa5, 0x15, 0xb7, 0x83, 0xe6, 0xe3, 0xe2, 0xa7, 0x81, 0x71, 0x4e,
0x02, 0x46, 0x19, 0x27, 0x2e, 0x8f, 0x4a, 0x27, 0xe3, 0x83, 0xb2, 0xd8, 0xe2, 0x09, 0x70, 0xc4,
0xc3, 0xfc, 0xcc, 0xe7, 0xd4, 0x73, 0x59, 0x7d, 0x31, 0x79, 0x02, 0x4e, 0x53, 0x72, 0x94, 0xb1,
0x82, 0x27, 0x60, 0x4b, 0xb0, 0xf5, 0x4f, 0xa3, 0x0d, 0x8e, 0x6e, 0x7c, 0xec, 0x8a, 0xab, 0xaa,
0x2f, 0xc9, 0x19, 0xa0, 0x2e, 0xa6, 0xb2, 0xfd, 0x12, 0x3d, 0x2a, 0xf5, 0x82, 0x9f, 0x82, 0xcd,
0x68, 0x2c, 0x33, 0xa9, 0x6b, 0x53, 0xb7, 0x2b, 0x86, 0x32, 0x39, 0x8e, 0x54, 0xcd, 0x47, 0xa2,
0x37, 0x9e, 0xe7, 0x95, 0xb7, 0x65, 0x42, 0x54, 0x04, 0x81, 0x5f, 0x80, 0x4d, 0xb9, 0x23, 0xb1,
0x15, 0xb1, 0x50, 0xc2, 0xea, 0x2b, 0xc5, 0x99, 0x4a, 0x5c, 0x9d, 0x28, 0xa4, 0x11, 0xfd, 0x8c,
0x68, 0xea, 0x82, 0x04, 0x8e, 0xf9, 0xa6, 0xca, 0xd7, 0xe6, 0x7e, 0x1e, 0x0a, 0x15, 0xd1, 0xb7,
0x3f, 0x00, 0xeb, 0xb9, 0x84, 0xc3, 0x0d, 0x50, 0xb9, 0x22, 0xfd, 0xe8, 0xbd, 0x46, 0xe2, 0x4f,
0xb8, 0x05, 0x16, 0xaf, 0x71, 0x2f, 0x24, 0x51, 0x05, 0xa2, 0x68, 0xf1, 0xfe, 0xfc, 0x53, 0x4d,
0xff, 0x93, 0x06, 0x32, 0xc4, 0x36, 0x83, 0xe6, 0x3e, 0xcd, 0x36, 0xf7, 0xee, 0xa4, 0x85, 0x3d,
0xa6, 0xad, 0x7f, 0xa1, 0x81, 0xd5, 0xf4, 0xf4, 0x09, 0xdf, 0x01, 0x2b, 0x38, 0xb4, 0x29, 0x71,
0xad, 0xd1, 0xcc, 0x12, 0x47, 0xb3, 0xaf, 0xe4, 0x28, 0xb6, 0x10, 0xb3, 0x29, 0xb9, 0xf1, 0x69,
0x80, 0x45, 0xa5, 0x8d, 0xe6, 0xc1, 0x79, 0x39, 0x0f, 0x4a, 0xa2, 0x3c, 0xca, 0x2b, 0x51, 0xd1,
0x5e, 0xff, 0xcd, 0x3c, 0xd8, 0x88, 0x0a, 0x24, 0xfa, 0x34, 0x71, 0x88, 0xcb, 0x67, 0x40, 0x2f,
0x28, 0x33, 0xf6, 0x3d, 0xbe, 0x7b, 0x24, 0x4a, 0xa2, 0x1b, 0x37, 0xff, 0xc1, 0xcf, 0xc0, 0x12,
0xe3, 0x98, 0x87, 0x4c, 0x3e, 0x7f, 0xb5, 0xbd, 0xbd, 0xa9, 0x50, 0xa5, 0x67, 0x32, 0xff, 0x45,
0x6b, 0xa4, 0x10, 0xf5, 0x3f, 0x6b, 0x60, 0x2b, 0xef, 0x32, 0x83, 0x82, 0xfb, 0x24, 0x5b, 0x70,
0xef, 0x4c, 0x73, 0xa2, 0x31, 0x45, 0xf7, 0x0f, 0x0d, 0xbc, 0x51, 0x38, 0xbc, 0x7c, 0x67, 0x05,
0x57, 0xf9, 0x39, 0x46, 0x3c, 0x4b, 0xc6, 0x67, 0xc9, 0x55, 0xe7, 0x25, 0x7a, 0x54, 0xea, 0x05,
0x3f, 0x07, 0x1b, 0xd4, 0xed, 0x51, 0x97, 0xa8, 0x67, 0x39, 0x49, 0x77, 0x29, 0xa1, 0xe4, 0x91,
0x65, 0x9a, 0xb7, 0xc4, 0xf4, 0x72, 0x9c, 0x43, 0x41, 0x05, 0x5c, 0xfd, 0xaf, 0x25, 0xe9, 0x91,
0x63, 0xa5, 0xe8, 0x28, 0x29, 0x21, 0x41, 0xa1, 0xa3, 0x94, 0x1c, 0xc5, 0x16, 0xb2, 0x82, 0xe4,
0x55, 0xa8, 0x40, 0xa7, 0xab, 0x20, 0xe9, 0x99, 0xaa, 0x20, 0xb9, 0x46, 0x0a, 0x51, 0x44, 0x22,
0xc6, 0xb6, 0xd4, 0x78, 0x16, 0x47, 0x72, 0xa6, 0xe4, 0x28, 0xb6, 0xd0, 0xff, 0x53, 0x29, 0xc9,
0x92, 0x2c, 0xc5, 0xd4, 0x91, 0x46, 0xbf, 0x2c, 0xe4, 0x8f, 0x64, 0xc7, 0x47, 0xb2, 0xe1, 0xaf,
0x35, 0x00, 0x71, 0x0c, 0x71, 0x3a, 0x2a, 0xd5, 0xa8, 0x9e, 0x3e, 0x9a, 0xbe, 0x43, 0x8c, 0xfd,
0x02, 0x58, 0xf4, 0x56, 0x6f, 0xab, 0x20, 0x60, 0xd1, 0x00, 0x95, 0x44, 0x00, 0x29, 0xa8, 0x45,
0xd2, 0xa3, 0x20, 0xf0, 0x02, 0xd5, 0xb2, 0x6f, 0xdf, 0x1d, 0x90, 0x34, 0x37, 0x1b, 0xf2, 0x9b,
0x28, 0xf1, 0xbf, 0x1d, 0x34, 0x6b, 0x29, 0x3d, 0x4a, 0x63, 0x8b, 0xad, 0x6c, 0x92, 0x6c, 0xb5,
0xf0, 0x3f, 0x6c, 0x75, 0x48, 0xc6, 0x6f, 0x95, 0xc2, 0xde, 0x3e, 0x02, 0xdf, 0x18, 0x73, 0x41,
0x53, 0xbd, 0x6d, 0x5f, 0xcf, 0x83, 0x07, 0xf1, 0xfd, 0x07, 0xb4, 0x13, 0x72, 0xc2, 0x66, 0x35,
0xf9, 0xed, 0x01, 0x10, 0x7d, 0x3e, 0xc9, 0x52, 0x8d, 0x06, 0xbf, 0xd8, 0xe3, 0x30, 0xd6, 0xa0,
0x94, 0x15, 0x0c, 0x4b, 0xc6, 0xbe, 0xfd, 0x89, 0x8a, 0x2b, 0x7d, 0xb8, 0x69, 0xe7, 0xbf, 0xff,
0x77, 0x82, 0xf8, 0xbb, 0x06, 0xde, 0x2c, 0x0d, 0x64, 0x06, 0xcc, 0xfe, 0x3c, 0xcb, 0xec, 0x4f,
0xa6, 0xbe, 0xac, 0x31, 0xf4, 0xfe, 0x5b, 0x0d, 0xa4, 0xab, 0x13, 0x9e, 0x80, 0x05, 0x4e, 0x15,
0x87, 0xd7, 0xf6, 0x1e, 0x4d, 0x76, 0x82, 0x0b, 0xea, 0x90, 0xe4, 0x89, 0x15, 0x2b, 0x24, 0x51,
0xe0, 0x43, 0xb0, 0xec, 0x10, 0xc6, 0x70, 0x77, 0x54, 0x18, 0xf1, 0xa7, 0xf7, 0x69, 0x24, 0x46,
0x23, 0x3d, 0xfc, 0x36, 0xa8, 0x12, 0x11, 0xc1, 0x81, 0x18, 0x51, 0x45, 0x77, 0x2f, 0x9a, 0x6b,
0xc3, 0x41, 0xb3, 0x7a, 0x34, 0x12, 0xa2, 0x44, 0xaf, 0xbf, 0x07, 0xee, 0x97, 0xfc, 0xf2, 0x01,
0x9b, 0x60, 0xd1, 0x92, 0xbf, 0x98, 0x69, 0xd2, 0xbf, 0x2a, 0x4e, 0x7b, 0x20, 0x7f, 0x2a, 0x8b,
0xe4, 0xe6, 0xf7, 0x5f, 0xbe, 0x6a, 0xcc, 0x7d, 0xf9, 0xaa, 0x31, 0xf7, 0xd5, 0xab, 0xc6, 0xdc,
0xcf, 0x87, 0x0d, 0xed, 0xe5, 0xb0, 0xa1, 0x7d, 0x39, 0x6c, 0x68, 0x5f, 0x0d, 0x1b, 0xda, 0x3f,
0x87, 0x0d, 0xed, 0x97, 0x5f, 0x37, 0xe6, 0x3e, 0xdb, 0x1e, 0xff, 0xcf, 0x88, 0xff, 0x06, 0x00,
0x00, 0xff, 0xff, 0x4a, 0x00, 0x2b, 0x10, 0xa9, 0x18, 0x00, 0x00,
}
func (m *CSIDriver) Marshal() (dAtA []byte, err error) {
@ -889,6 +893,11 @@ func (m *CSIDriverSpec) MarshalToSizedBuffer(dAtA []byte) (int, error) {
_ = i
var l int
_ = l
if m.NodeAllocatableUpdatePeriodSeconds != nil {
i = encodeVarintGenerated(dAtA, i, uint64(*m.NodeAllocatableUpdatePeriodSeconds))
i--
dAtA[i] = 0x48
}
if m.SELinuxMount != nil {
i--
if *m.SELinuxMount {
@ -1856,6 +1865,11 @@ func (m *VolumeError) MarshalToSizedBuffer(dAtA []byte) (int, error) {
_ = i
var l int
_ = l
if m.ErrorCode != nil {
i = encodeVarintGenerated(dAtA, i, uint64(*m.ErrorCode))
i--
dAtA[i] = 0x18
}
i -= len(m.Message)
copy(dAtA[i:], m.Message)
i = encodeVarintGenerated(dAtA, i, uint64(len(m.Message)))
@ -1980,6 +1994,9 @@ func (m *CSIDriverSpec) Size() (n int) {
if m.SELinuxMount != nil {
n += 2
}
if m.NodeAllocatableUpdatePeriodSeconds != nil {
n += 1 + sovGenerated(uint64(*m.NodeAllocatableUpdatePeriodSeconds))
}
return n
}
@ -2306,6 +2323,9 @@ func (m *VolumeError) Size() (n int) {
n += 1 + l + sovGenerated(uint64(l))
l = len(m.Message)
n += 1 + l + sovGenerated(uint64(l))
if m.ErrorCode != nil {
n += 1 + sovGenerated(uint64(*m.ErrorCode))
}
return n
}
@ -2372,6 +2392,7 @@ func (this *CSIDriverSpec) String() string {
`TokenRequests:` + repeatedStringForTokenRequests + `,`,
`RequiresRepublish:` + valueToStringGenerated(this.RequiresRepublish) + `,`,
`SELinuxMount:` + valueToStringGenerated(this.SELinuxMount) + `,`,
`NodeAllocatableUpdatePeriodSeconds:` + valueToStringGenerated(this.NodeAllocatableUpdatePeriodSeconds) + `,`,
`}`,
}, "")
return s
@ -2639,6 +2660,7 @@ func (this *VolumeError) String() string {
s := strings.Join([]string{`&VolumeError{`,
`Time:` + strings.Replace(strings.Replace(fmt.Sprintf("%v", this.Time), "Time", "v1.Time", 1), `&`, ``, 1) + `,`,
`Message:` + fmt.Sprintf("%v", this.Message) + `,`,
`ErrorCode:` + valueToStringGenerated(this.ErrorCode) + `,`,
`}`,
}, "")
return s
@ -3127,6 +3149,26 @@ func (m *CSIDriverSpec) Unmarshal(dAtA []byte) error {
}
b := bool(v != 0)
m.SELinuxMount = &b
case 9:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field NodeAllocatableUpdatePeriodSeconds", wireType)
}
var v int64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowGenerated
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
v |= int64(b&0x7F) << shift
if b < 0x80 {
break
}
}
m.NodeAllocatableUpdatePeriodSeconds = &v
default:
iNdEx = preIndex
skippy, err := skipGenerated(dAtA[iNdEx:])
@ -5855,6 +5897,26 @@ func (m *VolumeError) Unmarshal(dAtA []byte) error {
}
m.Message = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
case 3:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field ErrorCode", wireType)
}
var v int32
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowGenerated
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
v |= int32(b&0x7F) << shift
if b < 0x80 {
break
}
}
m.ErrorCode = &v
default:
iNdEx = preIndex
skippy, err := skipGenerated(dAtA[iNdEx:])

View File

@ -214,6 +214,20 @@ message CSIDriverSpec {
// +featureGate=SELinuxMountReadWriteOncePod
// +optional
optional bool seLinuxMount = 8;
// nodeAllocatableUpdatePeriodSeconds specifies the interval between periodic updates of
// the CSINode allocatable capacity for this driver. When set, both periodic updates and
// updates triggered by capacity-related failures are enabled. If not set, no updates
// occur (neither periodic nor upon detecting capacity-related failures), and the
// allocatable.count remains static. The minimum allowed value for this field is 10 seconds.
//
// This is an alpha feature and requires the MutableCSINodeAllocatableCount feature gate to be enabled.
//
// This field is mutable.
//
// +featureGate=MutableCSINodeAllocatableCount
// +optional
optional int64 nodeAllocatableUpdatePeriodSeconds = 9;
}
// DEPRECATED - This group version of CSINode is deprecated by storage/v1/CSINode.
@ -603,6 +617,14 @@ message VolumeError {
// information.
// +optional
optional string message = 2;
// errorCode is a numeric gRPC code representing the error encountered during Attach or Detach operations.
//
// This is an optional, alpha field that requires the MutableCSINodeAllocatableCount feature gate being enabled to be set.
//
// +featureGate=MutableCSINodeAllocatableCount
// +optional
optional int32 errorCode = 3;
}
// VolumeNodeResources is a set of resource limits for scheduling of volumes.

View File

@ -233,6 +233,14 @@ type VolumeError struct {
// information.
// +optional
Message string `json:"message,omitempty" protobuf:"bytes,2,opt,name=message"`
// errorCode is a numeric gRPC code representing the error encountered during Attach or Detach operations.
//
// This is an optional, alpha field that requires the MutableCSINodeAllocatableCount feature gate being enabled to be set.
//
// +featureGate=MutableCSINodeAllocatableCount
// +optional
ErrorCode *int32 `json:"errorCode,omitempty" protobuf:"varint,3,opt,name=errorCode"`
}
// +genclient
@ -435,6 +443,20 @@ type CSIDriverSpec struct {
// +featureGate=SELinuxMountReadWriteOncePod
// +optional
SELinuxMount *bool `json:"seLinuxMount,omitempty" protobuf:"varint,8,opt,name=seLinuxMount"`
// nodeAllocatableUpdatePeriodSeconds specifies the interval between periodic updates of
// the CSINode allocatable capacity for this driver. When set, both periodic updates and
// updates triggered by capacity-related failures are enabled. If not set, no updates
// occur (neither periodic nor upon detecting capacity-related failures), and the
// allocatable.count remains static. The minimum allowed value for this field is 10 seconds.
//
// This is an alpha feature and requires the MutableCSINodeAllocatableCount feature gate to be enabled.
//
// This field is mutable.
//
// +featureGate=MutableCSINodeAllocatableCount
// +optional
NodeAllocatableUpdatePeriodSeconds *int64 `json:"nodeAllocatableUpdatePeriodSeconds,omitempty" protobuf:"varint,9,opt,name=nodeAllocatableUpdatePeriodSeconds"`
}
// FSGroupPolicy specifies if a CSI Driver supports modifying

View File

@ -48,15 +48,16 @@ func (CSIDriverList) SwaggerDoc() map[string]string {
}
var map_CSIDriverSpec = map[string]string{
"": "CSIDriverSpec is the specification of a CSIDriver.",
"attachRequired": "attachRequired indicates this CSI volume driver requires an attach operation (because it implements the CSI ControllerPublishVolume() method), and that the Kubernetes attach detach controller should call the attach volume interface which checks the volumeattachment status and waits until the volume is attached before proceeding to mounting. The CSI external-attacher coordinates with CSI volume driver and updates the volumeattachment status when the attach operation is complete. If the CSIDriverRegistry feature gate is enabled and the value is specified to false, the attach operation will be skipped. Otherwise the attach operation will be called.\n\nThis field is immutable.",
"podInfoOnMount": "podInfoOnMount indicates this CSI volume driver requires additional pod information (like podName, podUID, etc.) during mount operations, if set to true. If set to false, pod information will not be passed on mount. Default is false.\n\nThe CSI driver specifies podInfoOnMount as part of driver deployment. If true, Kubelet will pass pod information as VolumeContext in the CSI NodePublishVolume() calls. The CSI driver is responsible for parsing and validating the information passed in as VolumeContext.\n\nThe following VolumeContext will be passed if podInfoOnMount is set to true. This list might grow, but the prefix will be used. \"csi.storage.k8s.io/pod.name\": pod.Name \"csi.storage.k8s.io/pod.namespace\": pod.Namespace \"csi.storage.k8s.io/pod.uid\": string(pod.UID) \"csi.storage.k8s.io/ephemeral\": \"true\" if the volume is an ephemeral inline volume\n defined by a CSIVolumeSource, otherwise \"false\"\n\n\"csi.storage.k8s.io/ephemeral\" is a new feature in Kubernetes 1.16. It is only required for drivers which support both the \"Persistent\" and \"Ephemeral\" VolumeLifecycleMode. Other drivers can leave pod info disabled and/or ignore this field. As Kubernetes 1.15 doesn't support this field, drivers can only support one mode when deployed on such a cluster and the deployment determines which mode that is, for example via a command line parameter of the driver.\n\nThis field is immutable.",
"volumeLifecycleModes": "volumeLifecycleModes defines what kind of volumes this CSI volume driver supports. The default if the list is empty is \"Persistent\", which is the usage defined by the CSI specification and implemented in Kubernetes via the usual PV/PVC mechanism.\n\nThe other mode is \"Ephemeral\". In this mode, volumes are defined inline inside the pod spec with CSIVolumeSource and their lifecycle is tied to the lifecycle of that pod. A driver has to be aware of this because it is only going to get a NodePublishVolume call for such a volume.\n\nFor more information about implementing this mode, see https://kubernetes-csi.github.io/docs/ephemeral-local-volumes.html A driver can support one or more of these modes and more modes may be added in the future.\n\nThis field is immutable.",
"storageCapacity": "storageCapacity indicates that the CSI volume driver wants pod scheduling to consider the storage capacity that the driver deployment will report by creating CSIStorageCapacity objects with capacity information, if set to true.\n\nThe check can be enabled immediately when deploying a driver. In that case, provisioning new volumes with late binding will pause until the driver deployment has published some suitable CSIStorageCapacity object.\n\nAlternatively, the driver can be deployed with the field unset or false and it can be flipped later when storage capacity information has been published.\n\nThis field was immutable in Kubernetes <= 1.22 and now is mutable.",
"fsGroupPolicy": "fsGroupPolicy defines if the underlying volume supports changing ownership and permission of the volume before being mounted. Refer to the specific FSGroupPolicy values for additional details.\n\nThis field is immutable.\n\nDefaults to ReadWriteOnceWithFSType, which will examine each volume to determine if Kubernetes should modify ownership and permissions of the volume. With the default policy the defined fsGroup will only be applied if a fstype is defined and the volume's access mode contains ReadWriteOnce.",
"tokenRequests": "tokenRequests indicates the CSI driver needs pods' service account tokens it is mounting volume for to do necessary authentication. Kubelet will pass the tokens in VolumeContext in the CSI NodePublishVolume calls. The CSI driver should parse and validate the following VolumeContext: \"csi.storage.k8s.io/serviceAccount.tokens\": {\n \"<audience>\": {\n \"token\": <token>,\n \"expirationTimestamp\": <expiration timestamp in RFC3339>,\n },\n ...\n}\n\nNote: Audience in each TokenRequest should be different and at most one token is empty string. To receive a new token after expiry, RequiresRepublish can be used to trigger NodePublishVolume periodically.",
"requiresRepublish": "requiresRepublish indicates the CSI driver wants `NodePublishVolume` being periodically called to reflect any possible change in the mounted volume. This field defaults to false.\n\nNote: After a successful initial NodePublishVolume call, subsequent calls to NodePublishVolume should only update the contents of the volume. New mount points will not be seen by a running container.",
"seLinuxMount": "seLinuxMount specifies if the CSI driver supports \"-o context\" mount option.\n\nWhen \"true\", the CSI driver must ensure that all volumes provided by this CSI driver can be mounted separately with different `-o context` options. This is typical for storage backends that provide volumes as filesystems on block devices or as independent shared volumes. Kubernetes will call NodeStage / NodePublish with \"-o context=xyz\" mount option when mounting a ReadWriteOncePod volume used in Pod that has explicitly set SELinux context. In the future, it may be expanded to other volume AccessModes. In any case, Kubernetes will ensure that the volume is mounted only with a single SELinux context.\n\nWhen \"false\", Kubernetes won't pass any special SELinux mount options to the driver. This is typical for volumes that represent subdirectories of a bigger shared filesystem.\n\nDefault is \"false\".",
"": "CSIDriverSpec is the specification of a CSIDriver.",
"attachRequired": "attachRequired indicates this CSI volume driver requires an attach operation (because it implements the CSI ControllerPublishVolume() method), and that the Kubernetes attach detach controller should call the attach volume interface which checks the volumeattachment status and waits until the volume is attached before proceeding to mounting. The CSI external-attacher coordinates with CSI volume driver and updates the volumeattachment status when the attach operation is complete. If the CSIDriverRegistry feature gate is enabled and the value is specified to false, the attach operation will be skipped. Otherwise the attach operation will be called.\n\nThis field is immutable.",
"podInfoOnMount": "podInfoOnMount indicates this CSI volume driver requires additional pod information (like podName, podUID, etc.) during mount operations, if set to true. If set to false, pod information will not be passed on mount. Default is false.\n\nThe CSI driver specifies podInfoOnMount as part of driver deployment. If true, Kubelet will pass pod information as VolumeContext in the CSI NodePublishVolume() calls. The CSI driver is responsible for parsing and validating the information passed in as VolumeContext.\n\nThe following VolumeContext will be passed if podInfoOnMount is set to true. This list might grow, but the prefix will be used. \"csi.storage.k8s.io/pod.name\": pod.Name \"csi.storage.k8s.io/pod.namespace\": pod.Namespace \"csi.storage.k8s.io/pod.uid\": string(pod.UID) \"csi.storage.k8s.io/ephemeral\": \"true\" if the volume is an ephemeral inline volume\n defined by a CSIVolumeSource, otherwise \"false\"\n\n\"csi.storage.k8s.io/ephemeral\" is a new feature in Kubernetes 1.16. It is only required for drivers which support both the \"Persistent\" and \"Ephemeral\" VolumeLifecycleMode. Other drivers can leave pod info disabled and/or ignore this field. As Kubernetes 1.15 doesn't support this field, drivers can only support one mode when deployed on such a cluster and the deployment determines which mode that is, for example via a command line parameter of the driver.\n\nThis field is immutable.",
"volumeLifecycleModes": "volumeLifecycleModes defines what kind of volumes this CSI volume driver supports. The default if the list is empty is \"Persistent\", which is the usage defined by the CSI specification and implemented in Kubernetes via the usual PV/PVC mechanism.\n\nThe other mode is \"Ephemeral\". In this mode, volumes are defined inline inside the pod spec with CSIVolumeSource and their lifecycle is tied to the lifecycle of that pod. A driver has to be aware of this because it is only going to get a NodePublishVolume call for such a volume.\n\nFor more information about implementing this mode, see https://kubernetes-csi.github.io/docs/ephemeral-local-volumes.html A driver can support one or more of these modes and more modes may be added in the future.\n\nThis field is immutable.",
"storageCapacity": "storageCapacity indicates that the CSI volume driver wants pod scheduling to consider the storage capacity that the driver deployment will report by creating CSIStorageCapacity objects with capacity information, if set to true.\n\nThe check can be enabled immediately when deploying a driver. In that case, provisioning new volumes with late binding will pause until the driver deployment has published some suitable CSIStorageCapacity object.\n\nAlternatively, the driver can be deployed with the field unset or false and it can be flipped later when storage capacity information has been published.\n\nThis field was immutable in Kubernetes <= 1.22 and now is mutable.",
"fsGroupPolicy": "fsGroupPolicy defines if the underlying volume supports changing ownership and permission of the volume before being mounted. Refer to the specific FSGroupPolicy values for additional details.\n\nThis field is immutable.\n\nDefaults to ReadWriteOnceWithFSType, which will examine each volume to determine if Kubernetes should modify ownership and permissions of the volume. With the default policy the defined fsGroup will only be applied if a fstype is defined and the volume's access mode contains ReadWriteOnce.",
"tokenRequests": "tokenRequests indicates the CSI driver needs pods' service account tokens it is mounting volume for to do necessary authentication. Kubelet will pass the tokens in VolumeContext in the CSI NodePublishVolume calls. The CSI driver should parse and validate the following VolumeContext: \"csi.storage.k8s.io/serviceAccount.tokens\": {\n \"<audience>\": {\n \"token\": <token>,\n \"expirationTimestamp\": <expiration timestamp in RFC3339>,\n },\n ...\n}\n\nNote: Audience in each TokenRequest should be different and at most one token is empty string. To receive a new token after expiry, RequiresRepublish can be used to trigger NodePublishVolume periodically.",
"requiresRepublish": "requiresRepublish indicates the CSI driver wants `NodePublishVolume` being periodically called to reflect any possible change in the mounted volume. This field defaults to false.\n\nNote: After a successful initial NodePublishVolume call, subsequent calls to NodePublishVolume should only update the contents of the volume. New mount points will not be seen by a running container.",
"seLinuxMount": "seLinuxMount specifies if the CSI driver supports \"-o context\" mount option.\n\nWhen \"true\", the CSI driver must ensure that all volumes provided by this CSI driver can be mounted separately with different `-o context` options. This is typical for storage backends that provide volumes as filesystems on block devices or as independent shared volumes. Kubernetes will call NodeStage / NodePublish with \"-o context=xyz\" mount option when mounting a ReadWriteOncePod volume used in Pod that has explicitly set SELinux context. In the future, it may be expanded to other volume AccessModes. In any case, Kubernetes will ensure that the volume is mounted only with a single SELinux context.\n\nWhen \"false\", Kubernetes won't pass any special SELinux mount options to the driver. This is typical for volumes that represent subdirectories of a bigger shared filesystem.\n\nDefault is \"false\".",
"nodeAllocatableUpdatePeriodSeconds": "nodeAllocatableUpdatePeriodSeconds specifies the interval between periodic updates of the CSINode allocatable capacity for this driver. When set, both periodic updates and updates triggered by capacity-related failures are enabled. If not set, no updates occur (neither periodic nor upon detecting capacity-related failures), and the allocatable.count remains static. The minimum allowed value for this field is 10 seconds.\n\nThis is an alpha feature and requires the MutableCSINodeAllocatableCount feature gate to be enabled.\n\nThis field is mutable.",
}
func (CSIDriverSpec) SwaggerDoc() map[string]string {
@ -238,9 +239,10 @@ func (VolumeAttributesClassList) SwaggerDoc() map[string]string {
}
var map_VolumeError = map[string]string{
"": "VolumeError captures an error encountered during a volume operation.",
"time": "time represents the time the error was encountered.",
"message": "message represents the error encountered during Attach or Detach operation. This string may be logged, so it should not contain sensitive information.",
"": "VolumeError captures an error encountered during a volume operation.",
"time": "time represents the time the error was encountered.",
"message": "message represents the error encountered during Attach or Detach operation. This string may be logged, so it should not contain sensitive information.",
"errorCode": "errorCode is a numeric gRPC code representing the error encountered during Attach or Detach operations.\n\nThis is an optional, alpha field that requires the MutableCSINodeAllocatableCount feature gate being enabled to be set.",
}
func (VolumeError) SwaggerDoc() map[string]string {

View File

@ -132,6 +132,11 @@ func (in *CSIDriverSpec) DeepCopyInto(out *CSIDriverSpec) {
*out = new(bool)
**out = **in
}
if in.NodeAllocatableUpdatePeriodSeconds != nil {
in, out := &in.NodeAllocatableUpdatePeriodSeconds, &out.NodeAllocatableUpdatePeriodSeconds
*out = new(int64)
**out = **in
}
return
}
@ -649,6 +654,11 @@ func (in *VolumeAttributesClassList) DeepCopyObject() runtime.Object {
func (in *VolumeError) DeepCopyInto(out *VolumeError) {
*out = *in
in.Time.DeepCopyInto(&out.Time)
if in.ErrorCode != nil {
in, out := &in.ErrorCode, &out.ErrorCode
*out = new(int32)
**out = **in
}
return
}

View File

@ -58,6 +58,7 @@
}
],
"requiresRepublish": true,
"seLinuxMount": true
"seLinuxMount": true,
"nodeAllocatableUpdatePeriodSeconds": 9
}
}

View File

@ -35,6 +35,7 @@ metadata:
spec:
attachRequired: true
fsGroupPolicy: fsGroupPolicyValue
nodeAllocatableUpdatePeriodSeconds: 9
podInfoOnMount: true
requiresRepublish: true
seLinuxMount: true

View File

@ -316,11 +316,13 @@
},
"attachError": {
"time": "2001-01-01T01:01:01Z",
"message": "messageValue"
"message": "messageValue",
"errorCode": 3
},
"detachError": {
"time": "2001-01-01T01:01:01Z",
"message": "messageValue"
"message": "messageValue",
"errorCode": 3
}
}
}

View File

@ -239,11 +239,13 @@ spec:
persistentVolumeName: persistentVolumeNameValue
status:
attachError:
errorCode: 3
message: messageValue
time: "2001-01-01T01:01:01Z"
attached: true
attachmentMetadata:
attachmentMetadataKey: attachmentMetadataValue
detachError:
errorCode: 3
message: messageValue
time: "2001-01-01T01:01:01Z"

View File

@ -316,11 +316,13 @@
},
"attachError": {
"time": "2001-01-01T01:01:01Z",
"message": "messageValue"
"message": "messageValue",
"errorCode": 3
},
"detachError": {
"time": "2001-01-01T01:01:01Z",
"message": "messageValue"
"message": "messageValue",
"errorCode": 3
}
}
}

View File

@ -239,11 +239,13 @@ spec:
persistentVolumeName: persistentVolumeNameValue
status:
attachError:
errorCode: 3
message: messageValue
time: "2001-01-01T01:01:01Z"
attached: true
attachmentMetadata:
attachmentMetadataKey: attachmentMetadataValue
detachError:
errorCode: 3
message: messageValue
time: "2001-01-01T01:01:01Z"

View File

@ -58,6 +58,7 @@
}
],
"requiresRepublish": true,
"seLinuxMount": true
"seLinuxMount": true,
"nodeAllocatableUpdatePeriodSeconds": 9
}
}

View File

@ -35,6 +35,7 @@ metadata:
spec:
attachRequired: true
fsGroupPolicy: fsGroupPolicyValue
nodeAllocatableUpdatePeriodSeconds: 9
podInfoOnMount: true
requiresRepublish: true
seLinuxMount: true

View File

@ -316,11 +316,13 @@
},
"attachError": {
"time": "2001-01-01T01:01:01Z",
"message": "messageValue"
"message": "messageValue",
"errorCode": 3
},
"detachError": {
"time": "2001-01-01T01:01:01Z",
"message": "messageValue"
"message": "messageValue",
"errorCode": 3
}
}
}

View File

@ -239,11 +239,13 @@ spec:
persistentVolumeName: persistentVolumeNameValue
status:
attachError:
errorCode: 3
message: messageValue
time: "2001-01-01T01:01:01Z"
attached: true
attachmentMetadata:
attachmentMetadataKey: attachmentMetadataValue
detachError:
errorCode: 3
message: messageValue
time: "2001-01-01T01:01:01Z"

View File

@ -13572,6 +13572,9 @@ var schemaYAML = typed.YAMLObject(`types:
- name: fsGroupPolicy
type:
scalar: string
- name: nodeAllocatableUpdatePeriodSeconds
type:
scalar: numeric
- name: podInfoOnMount
type:
scalar: boolean
@ -13789,6 +13792,9 @@ var schemaYAML = typed.YAMLObject(`types:
- name: io.k8s.api.storage.v1.VolumeError
map:
fields:
- name: errorCode
type:
scalar: numeric
- name: message
type:
scalar: string
@ -13915,6 +13921,9 @@ var schemaYAML = typed.YAMLObject(`types:
- name: io.k8s.api.storage.v1alpha1.VolumeError
map:
fields:
- name: errorCode
type:
scalar: numeric
- name: message
type:
scalar: string
@ -13947,6 +13956,9 @@ var schemaYAML = typed.YAMLObject(`types:
- name: fsGroupPolicy
type:
scalar: string
- name: nodeAllocatableUpdatePeriodSeconds
type:
scalar: numeric
- name: podInfoOnMount
type:
scalar: boolean
@ -14186,6 +14198,9 @@ var schemaYAML = typed.YAMLObject(`types:
- name: io.k8s.api.storage.v1beta1.VolumeError
map:
fields:
- name: errorCode
type:
scalar: numeric
- name: message
type:
scalar: string

View File

@ -25,14 +25,15 @@ import (
// CSIDriverSpecApplyConfiguration represents a declarative configuration of the CSIDriverSpec type for use
// with apply.
type CSIDriverSpecApplyConfiguration struct {
AttachRequired *bool `json:"attachRequired,omitempty"`
PodInfoOnMount *bool `json:"podInfoOnMount,omitempty"`
VolumeLifecycleModes []storagev1.VolumeLifecycleMode `json:"volumeLifecycleModes,omitempty"`
StorageCapacity *bool `json:"storageCapacity,omitempty"`
FSGroupPolicy *storagev1.FSGroupPolicy `json:"fsGroupPolicy,omitempty"`
TokenRequests []TokenRequestApplyConfiguration `json:"tokenRequests,omitempty"`
RequiresRepublish *bool `json:"requiresRepublish,omitempty"`
SELinuxMount *bool `json:"seLinuxMount,omitempty"`
AttachRequired *bool `json:"attachRequired,omitempty"`
PodInfoOnMount *bool `json:"podInfoOnMount,omitempty"`
VolumeLifecycleModes []storagev1.VolumeLifecycleMode `json:"volumeLifecycleModes,omitempty"`
StorageCapacity *bool `json:"storageCapacity,omitempty"`
FSGroupPolicy *storagev1.FSGroupPolicy `json:"fsGroupPolicy,omitempty"`
TokenRequests []TokenRequestApplyConfiguration `json:"tokenRequests,omitempty"`
RequiresRepublish *bool `json:"requiresRepublish,omitempty"`
SELinuxMount *bool `json:"seLinuxMount,omitempty"`
NodeAllocatableUpdatePeriodSeconds *int64 `json:"nodeAllocatableUpdatePeriodSeconds,omitempty"`
}
// CSIDriverSpecApplyConfiguration constructs a declarative configuration of the CSIDriverSpec type for use with
@ -111,3 +112,11 @@ func (b *CSIDriverSpecApplyConfiguration) WithSELinuxMount(value bool) *CSIDrive
b.SELinuxMount = &value
return b
}
// WithNodeAllocatableUpdatePeriodSeconds sets the NodeAllocatableUpdatePeriodSeconds field in the declarative configuration to the given value
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
// If called multiple times, the NodeAllocatableUpdatePeriodSeconds field is set to the value of the last call.
func (b *CSIDriverSpecApplyConfiguration) WithNodeAllocatableUpdatePeriodSeconds(value int64) *CSIDriverSpecApplyConfiguration {
b.NodeAllocatableUpdatePeriodSeconds = &value
return b
}

View File

@ -25,8 +25,9 @@ import (
// VolumeErrorApplyConfiguration represents a declarative configuration of the VolumeError type for use
// with apply.
type VolumeErrorApplyConfiguration struct {
Time *metav1.Time `json:"time,omitempty"`
Message *string `json:"message,omitempty"`
Time *metav1.Time `json:"time,omitempty"`
Message *string `json:"message,omitempty"`
ErrorCode *int32 `json:"errorCode,omitempty"`
}
// VolumeErrorApplyConfiguration constructs a declarative configuration of the VolumeError type for use with
@ -50,3 +51,11 @@ func (b *VolumeErrorApplyConfiguration) WithMessage(value string) *VolumeErrorAp
b.Message = &value
return b
}
// WithErrorCode sets the ErrorCode field in the declarative configuration to the given value
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
// If called multiple times, the ErrorCode field is set to the value of the last call.
func (b *VolumeErrorApplyConfiguration) WithErrorCode(value int32) *VolumeErrorApplyConfiguration {
b.ErrorCode = &value
return b
}

View File

@ -25,8 +25,9 @@ import (
// VolumeErrorApplyConfiguration represents a declarative configuration of the VolumeError type for use
// with apply.
type VolumeErrorApplyConfiguration struct {
Time *v1.Time `json:"time,omitempty"`
Message *string `json:"message,omitempty"`
Time *v1.Time `json:"time,omitempty"`
Message *string `json:"message,omitempty"`
ErrorCode *int32 `json:"errorCode,omitempty"`
}
// VolumeErrorApplyConfiguration constructs a declarative configuration of the VolumeError type for use with
@ -50,3 +51,11 @@ func (b *VolumeErrorApplyConfiguration) WithMessage(value string) *VolumeErrorAp
b.Message = &value
return b
}
// WithErrorCode sets the ErrorCode field in the declarative configuration to the given value
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
// If called multiple times, the ErrorCode field is set to the value of the last call.
func (b *VolumeErrorApplyConfiguration) WithErrorCode(value int32) *VolumeErrorApplyConfiguration {
b.ErrorCode = &value
return b
}

View File

@ -25,14 +25,15 @@ import (
// CSIDriverSpecApplyConfiguration represents a declarative configuration of the CSIDriverSpec type for use
// with apply.
type CSIDriverSpecApplyConfiguration struct {
AttachRequired *bool `json:"attachRequired,omitempty"`
PodInfoOnMount *bool `json:"podInfoOnMount,omitempty"`
VolumeLifecycleModes []storagev1beta1.VolumeLifecycleMode `json:"volumeLifecycleModes,omitempty"`
StorageCapacity *bool `json:"storageCapacity,omitempty"`
FSGroupPolicy *storagev1beta1.FSGroupPolicy `json:"fsGroupPolicy,omitempty"`
TokenRequests []TokenRequestApplyConfiguration `json:"tokenRequests,omitempty"`
RequiresRepublish *bool `json:"requiresRepublish,omitempty"`
SELinuxMount *bool `json:"seLinuxMount,omitempty"`
AttachRequired *bool `json:"attachRequired,omitempty"`
PodInfoOnMount *bool `json:"podInfoOnMount,omitempty"`
VolumeLifecycleModes []storagev1beta1.VolumeLifecycleMode `json:"volumeLifecycleModes,omitempty"`
StorageCapacity *bool `json:"storageCapacity,omitempty"`
FSGroupPolicy *storagev1beta1.FSGroupPolicy `json:"fsGroupPolicy,omitempty"`
TokenRequests []TokenRequestApplyConfiguration `json:"tokenRequests,omitempty"`
RequiresRepublish *bool `json:"requiresRepublish,omitempty"`
SELinuxMount *bool `json:"seLinuxMount,omitempty"`
NodeAllocatableUpdatePeriodSeconds *int64 `json:"nodeAllocatableUpdatePeriodSeconds,omitempty"`
}
// CSIDriverSpecApplyConfiguration constructs a declarative configuration of the CSIDriverSpec type for use with
@ -111,3 +112,11 @@ func (b *CSIDriverSpecApplyConfiguration) WithSELinuxMount(value bool) *CSIDrive
b.SELinuxMount = &value
return b
}
// WithNodeAllocatableUpdatePeriodSeconds sets the NodeAllocatableUpdatePeriodSeconds field in the declarative configuration to the given value
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
// If called multiple times, the NodeAllocatableUpdatePeriodSeconds field is set to the value of the last call.
func (b *CSIDriverSpecApplyConfiguration) WithNodeAllocatableUpdatePeriodSeconds(value int64) *CSIDriverSpecApplyConfiguration {
b.NodeAllocatableUpdatePeriodSeconds = &value
return b
}

View File

@ -25,8 +25,9 @@ import (
// VolumeErrorApplyConfiguration represents a declarative configuration of the VolumeError type for use
// with apply.
type VolumeErrorApplyConfiguration struct {
Time *v1.Time `json:"time,omitempty"`
Message *string `json:"message,omitempty"`
Time *v1.Time `json:"time,omitempty"`
Message *string `json:"message,omitempty"`
ErrorCode *int32 `json:"errorCode,omitempty"`
}
// VolumeErrorApplyConfiguration constructs a declarative configuration of the VolumeError type for use with
@ -50,3 +51,11 @@ func (b *VolumeErrorApplyConfiguration) WithMessage(value string) *VolumeErrorAp
b.Message = &value
return b
}
// WithErrorCode sets the ErrorCode field in the declarative configuration to the given value
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
// If called multiple times, the ErrorCode field is set to the value of the last call.
func (b *VolumeErrorApplyConfiguration) WithErrorCode(value int32) *VolumeErrorApplyConfiguration {
b.ErrorCode = &value
return b
}

View File

@ -857,6 +857,12 @@
lockToDefault: false
preRelease: GA
version: "1.33"
- name: MutableCSINodeAllocatableCount
versionedSpecs:
- default: false
lockToDefault: false
preRelease: Alpha
version: "1.33"
- name: MutatingAdmissionPolicy
versionedSpecs:
- default: false