diff --git a/api/openapi-spec/swagger.json b/api/openapi-spec/swagger.json index 1035111782d..9f582bd223c 100644 --- a/api/openapi-spec/swagger.json +++ b/api/openapi-spec/swagger.json @@ -15204,10 +15204,22 @@ "description": "If set to true, podInfoOnMount indicates this CSI volume driver requires additional pod information (like podName, podUID, etc.) during mount operations. If set to false, pod information will not be passed on mount. Default is false. The 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. The following VolumeConext 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\" iff 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.", "type": "boolean" }, + "requiresRepublish": { + "description": "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.\n\nThis is an alpha feature and only available when the CSIServiceAccountToken feature is enabled.", + "type": "boolean" + }, "storageCapacity": { "description": "If set to true, 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.\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 is an alpha field and only available when the CSIStorageCapacity feature is enabled. The default is false.", "type": "boolean" }, + "tokenRequests": { + "description": "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 \"\": {\n \"token\": ,\n \"expirationTimestamp\": ,\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.\n\nThis is an alpha feature and only available when the CSIServiceAccountToken feature is enabled.", + "items": { + "$ref": "#/definitions/io.k8s.api.storage.v1.TokenRequest" + }, + "type": "array", + "x-kubernetes-list-type": "atomic" + }, "volumeLifecycleModes": { "description": "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. The 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. For 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. This field is beta.", "items": { @@ -15433,6 +15445,24 @@ } ] }, + "io.k8s.api.storage.v1.TokenRequest": { + "description": "TokenRequest contains parameters of a service account token.", + "properties": { + "audience": { + "description": "Audience is the intended audience of the token in \"TokenRequestSpec\". It will default to the audiences of kube apiserver.", + "type": "string" + }, + "expirationSeconds": { + "description": "ExpirationSeconds is the duration of validity of the token in \"TokenRequestSpec\". It has the same default value of \"ExpirationSeconds\" in \"TokenRequestSpec\".", + "format": "int64", + "type": "integer" + } + }, + "required": [ + "audience" + ], + "type": "object" + }, "io.k8s.api.storage.v1.VolumeAttachment": { "description": "VolumeAttachment captures the intent to attach or detach the specified volume to/from the specified node.\n\nVolumeAttachment objects are non-namespaced.", "properties": { @@ -15826,10 +15856,22 @@ "description": "If set to true, podInfoOnMount indicates this CSI volume driver requires additional pod information (like podName, podUID, etc.) during mount operations. If set to false, pod information will not be passed on mount. Default is false. The 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. The following VolumeConext 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\" iff 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.", "type": "boolean" }, + "requiresRepublish": { + "description": "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.\n\nThis is an alpha feature and only available when the CSIServiceAccountToken feature is enabled.", + "type": "boolean" + }, "storageCapacity": { "description": "If set to true, 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.\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 is an alpha field and only available when the CSIStorageCapacity feature is enabled. The default is false.", "type": "boolean" }, + "tokenRequests": { + "description": "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 \"\": {\n \"token\": ,\n \"expirationTimestamp\": ,\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.\n\nThis is an alpha feature and only available when the CSIServiceAccountToken feature is enabled.", + "items": { + "$ref": "#/definitions/io.k8s.api.storage.v1beta1.TokenRequest" + }, + "type": "array", + "x-kubernetes-list-type": "atomic" + }, "volumeLifecycleModes": { "description": "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. The 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. For 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.", "items": { @@ -16054,6 +16096,24 @@ } ] }, + "io.k8s.api.storage.v1beta1.TokenRequest": { + "description": "TokenRequest contains parameters of a service account token.", + "properties": { + "audience": { + "description": "Audience is the intended audience of the token in \"TokenRequestSpec\". It will default to the audiences of kube apiserver.", + "type": "string" + }, + "expirationSeconds": { + "description": "ExpirationSeconds is the duration of validity of the token in \"TokenRequestSpec\". It has the same default value of \"ExpirationSeconds\" in \"TokenRequestSpec\"", + "format": "int64", + "type": "integer" + } + }, + "required": [ + "audience" + ], + "type": "object" + }, "io.k8s.api.storage.v1beta1.VolumeAttachment": { "description": "VolumeAttachment captures the intent to attach or detach the specified volume to/from the specified node.\n\nVolumeAttachment objects are non-namespaced.", "properties": { diff --git a/pkg/apis/storage/fuzzer/fuzzer.go b/pkg/apis/storage/fuzzer/fuzzer.go index 070e9579b4a..eeade0e85b3 100644 --- a/pkg/apis/storage/fuzzer/fuzzer.go +++ b/pkg/apis/storage/fuzzer/fuzzer.go @@ -87,6 +87,10 @@ var Funcs = func(codecs runtimeserializer.CodecFactory) []interface{} { obj.Spec.FSGroupPolicy = new(storage.FSGroupPolicy) *obj.Spec.FSGroupPolicy = storage.ReadWriteOnceWithFSTypeFSGroupPolicy } + if obj.Spec.RequiresRepublish == nil { + obj.Spec.RequiresRepublish = new(bool) + *(obj.Spec.RequiresRepublish) = false + } if len(obj.Spec.VolumeLifecycleModes) == 0 { obj.Spec.VolumeLifecycleModes = []storage.VolumeLifecycleMode{ storage.VolumeLifecyclePersistent, diff --git a/pkg/apis/storage/types.go b/pkg/apis/storage/types.go index 15befc40266..16c444b093e 100644 --- a/pkg/apis/storage/types.go +++ b/pkg/apis/storage/types.go @@ -337,6 +337,43 @@ type CSIDriverSpec struct { // // +optional StorageCapacity *bool + + // 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": { + // "": { + // "token": , + // "expirationTimestamp": , + // }, + // ... + // } + // + // Note: 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. + // + // This is an alpha feature and only available when the + // CSIServiceAccountToken feature is enabled. + // + // +optional + // +listType=atomic + TokenRequests []TokenRequest + + // RequiresRepublish indicates the CSI driver wants `NodePublishVolume` + // being periodically called to reflect any possible change in the mounted + // volume. This field defaults to false. + // + // Note: 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. + // + // This is an alpha feature and only available when the + // CSIServiceAccountToken feature is enabled. + // + // +optional + RequiresRepublish *bool } // FSGroupPolicy specifies if a CSI Driver supports modifying @@ -374,6 +411,20 @@ const ( // More modes may be added in the future. type VolumeLifecycleMode string +// TokenRequest contains parameters of a service account token. +type TokenRequest struct { + // Audience is the intended audience of the token in "TokenRequestSpec". + // It will default to the audiences of kube apiserver. + // + Audience string + + // ExpirationSeconds is the duration of validity of the token in "TokenRequestSpec". + // It has the same default value of "ExpirationSeconds" in "TokenRequestSpec." + // + // +optional + ExpirationSeconds *int64 +} + const ( // VolumeLifecyclePersistent explicitly confirms that the driver implements // the full CSI spec. It is the default when CSIDriverSpec.VolumeLifecycleModes is not diff --git a/pkg/apis/storage/v1/BUILD b/pkg/apis/storage/v1/BUILD index e76d0c1bde7..54f8a613741 100644 --- a/pkg/apis/storage/v1/BUILD +++ b/pkg/apis/storage/v1/BUILD @@ -58,5 +58,6 @@ go_test( "//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library", "//staging/src/k8s.io/apiserver/pkg/util/feature:go_default_library", "//staging/src/k8s.io/component-base/featuregate/testing:go_default_library", + "//vendor/github.com/google/go-cmp/cmp:go_default_library", ], ) diff --git a/pkg/apis/storage/v1/defaults.go b/pkg/apis/storage/v1/defaults.go index f5b4182521b..8711f0c0847 100644 --- a/pkg/apis/storage/v1/defaults.go +++ b/pkg/apis/storage/v1/defaults.go @@ -60,4 +60,8 @@ func SetDefaults_CSIDriver(obj *storagev1.CSIDriver) { if len(obj.Spec.VolumeLifecycleModes) == 0 && utilfeature.DefaultFeatureGate.Enabled(features.CSIInlineVolume) { obj.Spec.VolumeLifecycleModes = append(obj.Spec.VolumeLifecycleModes, storagev1.VolumeLifecyclePersistent) } + if obj.Spec.RequiresRepublish == nil && utilfeature.DefaultFeatureGate.Enabled(features.CSIServiceAccountToken) { + obj.Spec.RequiresRepublish = new(bool) + *(obj.Spec.RequiresRepublish) = false + } } diff --git a/pkg/apis/storage/v1/defaults_test.go b/pkg/apis/storage/v1/defaults_test.go index 4b7fc118169..4369842b305 100644 --- a/pkg/apis/storage/v1/defaults_test.go +++ b/pkg/apis/storage/v1/defaults_test.go @@ -20,6 +20,7 @@ import ( "reflect" "testing" + "github.com/google/go-cmp/cmp" storagev1 "k8s.io/api/storage/v1" "k8s.io/apimachinery/pkg/runtime" utilfeature "k8s.io/apiserver/pkg/util/feature" @@ -90,3 +91,48 @@ func TestSetDefaultVolumeBindingMode(t *testing.T) { t.Errorf("Expected VolumeBindingMode to be defaulted to: %+v, got: %+v", defaultMode, outMode) } } + +func TestSetDefaultCSIDriver(t *testing.T) { + defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.CSIInlineVolume, true)() + defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.CSIServiceAccountToken, true)() + + enabled := true + disabled := false + tests := []struct { + desc string + field string + wantSpec *storagev1.CSIDriverSpec + }{ + { + desc: "AttachRequired default to true", + field: "AttachRequired", + wantSpec: &storagev1.CSIDriverSpec{AttachRequired: &enabled}, + }, + { + desc: "PodInfoOnMount default to false", + field: "PodInfoOnMount", + wantSpec: &storagev1.CSIDriverSpec{PodInfoOnMount: &disabled}, + }, + { + desc: "VolumeLifecycleModes default to VolumeLifecyclePersistent", + field: "VolumeLifecycleModes", + wantSpec: &storagev1.CSIDriverSpec{VolumeLifecycleModes: []storagev1.VolumeLifecycleMode{storagev1.VolumeLifecyclePersistent}}, + }, + { + desc: "RequiresRepublish default to false", + field: "RequiresRepublish", + wantSpec: &storagev1.CSIDriverSpec{RequiresRepublish: &disabled}, + }, + } + + for _, test := range tests { + t.Run(test.desc, func(t *testing.T) { + gotSpec := roundTrip(t, runtime.Object(&storagev1.CSIDriver{})).(*storagev1.CSIDriver).Spec + got := reflect.Indirect(reflect.ValueOf(gotSpec)).FieldByName(test.field).Interface() + want := reflect.Indirect(reflect.ValueOf(test.wantSpec)).FieldByName(test.field).Interface() + if diff := cmp.Diff(want, got); diff != "" { + t.Errorf("CSIDriver defaults diff (-want +got):\n%s", diff) + } + }) + } +} diff --git a/pkg/apis/storage/v1/zz_generated.conversion.go b/pkg/apis/storage/v1/zz_generated.conversion.go index 4ac067e3f8e..997f0c25e14 100644 --- a/pkg/apis/storage/v1/zz_generated.conversion.go +++ b/pkg/apis/storage/v1/zz_generated.conversion.go @@ -129,6 +129,16 @@ func RegisterConversions(s *runtime.Scheme) error { }); err != nil { return err } + if err := s.AddGeneratedConversionFunc((*v1.TokenRequest)(nil), (*storage.TokenRequest)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_TokenRequest_To_storage_TokenRequest(a.(*v1.TokenRequest), b.(*storage.TokenRequest), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*storage.TokenRequest)(nil), (*v1.TokenRequest)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_storage_TokenRequest_To_v1_TokenRequest(a.(*storage.TokenRequest), b.(*v1.TokenRequest), scope) + }); err != nil { + return err + } if err := s.AddGeneratedConversionFunc((*v1.VolumeAttachment)(nil), (*storage.VolumeAttachment)(nil), func(a, b interface{}, scope conversion.Scope) error { return Convert_v1_VolumeAttachment_To_storage_VolumeAttachment(a.(*v1.VolumeAttachment), b.(*storage.VolumeAttachment), scope) }); err != nil { @@ -276,6 +286,8 @@ func autoConvert_v1_CSIDriverSpec_To_storage_CSIDriverSpec(in *v1.CSIDriverSpec, out.VolumeLifecycleModes = *(*[]storage.VolumeLifecycleMode)(unsafe.Pointer(&in.VolumeLifecycleModes)) out.StorageCapacity = (*bool)(unsafe.Pointer(in.StorageCapacity)) out.FSGroupPolicy = (*storage.FSGroupPolicy)(unsafe.Pointer(in.FSGroupPolicy)) + out.TokenRequests = *(*[]storage.TokenRequest)(unsafe.Pointer(&in.TokenRequests)) + out.RequiresRepublish = (*bool)(unsafe.Pointer(in.RequiresRepublish)) return nil } @@ -290,6 +302,8 @@ func autoConvert_storage_CSIDriverSpec_To_v1_CSIDriverSpec(in *storage.CSIDriver out.PodInfoOnMount = (*bool)(unsafe.Pointer(in.PodInfoOnMount)) out.VolumeLifecycleModes = *(*[]v1.VolumeLifecycleMode)(unsafe.Pointer(&in.VolumeLifecycleModes)) out.StorageCapacity = (*bool)(unsafe.Pointer(in.StorageCapacity)) + out.TokenRequests = *(*[]v1.TokenRequest)(unsafe.Pointer(&in.TokenRequests)) + out.RequiresRepublish = (*bool)(unsafe.Pointer(in.RequiresRepublish)) return nil } @@ -448,6 +462,28 @@ func Convert_storage_StorageClassList_To_v1_StorageClassList(in *storage.Storage return autoConvert_storage_StorageClassList_To_v1_StorageClassList(in, out, s) } +func autoConvert_v1_TokenRequest_To_storage_TokenRequest(in *v1.TokenRequest, out *storage.TokenRequest, s conversion.Scope) error { + out.Audience = in.Audience + out.ExpirationSeconds = (*int64)(unsafe.Pointer(in.ExpirationSeconds)) + return nil +} + +// Convert_v1_TokenRequest_To_storage_TokenRequest is an autogenerated conversion function. +func Convert_v1_TokenRequest_To_storage_TokenRequest(in *v1.TokenRequest, out *storage.TokenRequest, s conversion.Scope) error { + return autoConvert_v1_TokenRequest_To_storage_TokenRequest(in, out, s) +} + +func autoConvert_storage_TokenRequest_To_v1_TokenRequest(in *storage.TokenRequest, out *v1.TokenRequest, s conversion.Scope) error { + out.Audience = in.Audience + out.ExpirationSeconds = (*int64)(unsafe.Pointer(in.ExpirationSeconds)) + return nil +} + +// Convert_storage_TokenRequest_To_v1_TokenRequest is an autogenerated conversion function. +func Convert_storage_TokenRequest_To_v1_TokenRequest(in *storage.TokenRequest, out *v1.TokenRequest, s conversion.Scope) error { + return autoConvert_storage_TokenRequest_To_v1_TokenRequest(in, out, s) +} + func autoConvert_v1_VolumeAttachment_To_storage_VolumeAttachment(in *v1.VolumeAttachment, out *storage.VolumeAttachment, s conversion.Scope) error { out.ObjectMeta = in.ObjectMeta if err := Convert_v1_VolumeAttachmentSpec_To_storage_VolumeAttachmentSpec(&in.Spec, &out.Spec, s); err != nil { diff --git a/pkg/apis/storage/v1beta1/BUILD b/pkg/apis/storage/v1beta1/BUILD index ebc6624e70c..f990920a756 100644 --- a/pkg/apis/storage/v1beta1/BUILD +++ b/pkg/apis/storage/v1beta1/BUILD @@ -58,5 +58,6 @@ go_test( "//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library", "//staging/src/k8s.io/apiserver/pkg/util/feature:go_default_library", "//staging/src/k8s.io/component-base/featuregate/testing:go_default_library", + "//vendor/github.com/google/go-cmp/cmp:go_default_library", ], ) diff --git a/pkg/apis/storage/v1beta1/defaults.go b/pkg/apis/storage/v1beta1/defaults.go index 3601d300951..87040fb52e5 100644 --- a/pkg/apis/storage/v1beta1/defaults.go +++ b/pkg/apis/storage/v1beta1/defaults.go @@ -60,4 +60,8 @@ func SetDefaults_CSIDriver(obj *storagev1beta1.CSIDriver) { if len(obj.Spec.VolumeLifecycleModes) == 0 && utilfeature.DefaultFeatureGate.Enabled(features.CSIInlineVolume) { obj.Spec.VolumeLifecycleModes = append(obj.Spec.VolumeLifecycleModes, storagev1beta1.VolumeLifecyclePersistent) } + if obj.Spec.RequiresRepublish == nil && utilfeature.DefaultFeatureGate.Enabled(features.CSIServiceAccountToken) { + obj.Spec.RequiresRepublish = new(bool) + *(obj.Spec.RequiresRepublish) = false + } } diff --git a/pkg/apis/storage/v1beta1/defaults_test.go b/pkg/apis/storage/v1beta1/defaults_test.go index b60641b1d46..5f25a02fb0f 100644 --- a/pkg/apis/storage/v1beta1/defaults_test.go +++ b/pkg/apis/storage/v1beta1/defaults_test.go @@ -20,6 +20,7 @@ import ( "reflect" "testing" + "github.com/google/go-cmp/cmp" storagev1beta1 "k8s.io/api/storage/v1beta1" "k8s.io/apimachinery/pkg/runtime" utilfeature "k8s.io/apiserver/pkg/util/feature" @@ -138,3 +139,43 @@ func TestSetDefaultVolumeLifecycleModesDisabled(t *testing.T) { t.Errorf("Expected VolumeLifecycleModes to remain nil, got: %+v", outModes) } } + +func TestSetDefaultCSIDriver(t *testing.T) { + defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.CSIInlineVolume, true)() + defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.CSIServiceAccountToken, true)() + + enabled := true + disabled := false + tests := []struct { + desc string + field string + wantSpec *storagev1beta1.CSIDriverSpec + }{ + { + desc: "AttachRequired default to true", + field: "AttachRequired", + wantSpec: &storagev1beta1.CSIDriverSpec{AttachRequired: &enabled}, + }, + { + desc: "PodInfoOnMount default to false", + field: "PodInfoOnMount", + wantSpec: &storagev1beta1.CSIDriverSpec{PodInfoOnMount: &disabled}, + }, + { + desc: "RequiresRepublish default to false", + field: "RequiresRepublish", + wantSpec: &storagev1beta1.CSIDriverSpec{RequiresRepublish: &disabled}, + }, + } + + for _, test := range tests { + t.Run(test.desc, func(t *testing.T) { + gotSpec := roundTrip(t, runtime.Object(&storagev1beta1.CSIDriver{})).(*storagev1beta1.CSIDriver).Spec + got := reflect.Indirect(reflect.ValueOf(gotSpec)).FieldByName(test.field).Interface() + want := reflect.Indirect(reflect.ValueOf(test.wantSpec)).FieldByName(test.field).Interface() + if diff := cmp.Diff(want, got); diff != "" { + t.Errorf("CSIDriver defaults diff (-want +got):\n%s", diff) + } + }) + } +} diff --git a/pkg/apis/storage/v1beta1/zz_generated.conversion.go b/pkg/apis/storage/v1beta1/zz_generated.conversion.go index c21e139365a..961eef4edee 100644 --- a/pkg/apis/storage/v1beta1/zz_generated.conversion.go +++ b/pkg/apis/storage/v1beta1/zz_generated.conversion.go @@ -129,6 +129,16 @@ func RegisterConversions(s *runtime.Scheme) error { }); err != nil { return err } + if err := s.AddGeneratedConversionFunc((*v1beta1.TokenRequest)(nil), (*storage.TokenRequest)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1beta1_TokenRequest_To_storage_TokenRequest(a.(*v1beta1.TokenRequest), b.(*storage.TokenRequest), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*storage.TokenRequest)(nil), (*v1beta1.TokenRequest)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_storage_TokenRequest_To_v1beta1_TokenRequest(a.(*storage.TokenRequest), b.(*v1beta1.TokenRequest), scope) + }); err != nil { + return err + } if err := s.AddGeneratedConversionFunc((*v1beta1.VolumeAttachment)(nil), (*storage.VolumeAttachment)(nil), func(a, b interface{}, scope conversion.Scope) error { return Convert_v1beta1_VolumeAttachment_To_storage_VolumeAttachment(a.(*v1beta1.VolumeAttachment), b.(*storage.VolumeAttachment), scope) }); err != nil { @@ -276,6 +286,8 @@ func autoConvert_v1beta1_CSIDriverSpec_To_storage_CSIDriverSpec(in *v1beta1.CSID out.VolumeLifecycleModes = *(*[]storage.VolumeLifecycleMode)(unsafe.Pointer(&in.VolumeLifecycleModes)) out.StorageCapacity = (*bool)(unsafe.Pointer(in.StorageCapacity)) out.FSGroupPolicy = (*storage.FSGroupPolicy)(unsafe.Pointer(in.FSGroupPolicy)) + out.TokenRequests = *(*[]storage.TokenRequest)(unsafe.Pointer(&in.TokenRequests)) + out.RequiresRepublish = (*bool)(unsafe.Pointer(in.RequiresRepublish)) return nil } @@ -290,6 +302,8 @@ func autoConvert_storage_CSIDriverSpec_To_v1beta1_CSIDriverSpec(in *storage.CSID out.PodInfoOnMount = (*bool)(unsafe.Pointer(in.PodInfoOnMount)) out.VolumeLifecycleModes = *(*[]v1beta1.VolumeLifecycleMode)(unsafe.Pointer(&in.VolumeLifecycleModes)) out.StorageCapacity = (*bool)(unsafe.Pointer(in.StorageCapacity)) + out.TokenRequests = *(*[]v1beta1.TokenRequest)(unsafe.Pointer(&in.TokenRequests)) + out.RequiresRepublish = (*bool)(unsafe.Pointer(in.RequiresRepublish)) return nil } @@ -448,6 +462,28 @@ func Convert_storage_StorageClassList_To_v1beta1_StorageClassList(in *storage.St return autoConvert_storage_StorageClassList_To_v1beta1_StorageClassList(in, out, s) } +func autoConvert_v1beta1_TokenRequest_To_storage_TokenRequest(in *v1beta1.TokenRequest, out *storage.TokenRequest, s conversion.Scope) error { + out.Audience = in.Audience + out.ExpirationSeconds = (*int64)(unsafe.Pointer(in.ExpirationSeconds)) + return nil +} + +// Convert_v1beta1_TokenRequest_To_storage_TokenRequest is an autogenerated conversion function. +func Convert_v1beta1_TokenRequest_To_storage_TokenRequest(in *v1beta1.TokenRequest, out *storage.TokenRequest, s conversion.Scope) error { + return autoConvert_v1beta1_TokenRequest_To_storage_TokenRequest(in, out, s) +} + +func autoConvert_storage_TokenRequest_To_v1beta1_TokenRequest(in *storage.TokenRequest, out *v1beta1.TokenRequest, s conversion.Scope) error { + out.Audience = in.Audience + out.ExpirationSeconds = (*int64)(unsafe.Pointer(in.ExpirationSeconds)) + return nil +} + +// Convert_storage_TokenRequest_To_v1beta1_TokenRequest is an autogenerated conversion function. +func Convert_storage_TokenRequest_To_v1beta1_TokenRequest(in *storage.TokenRequest, out *v1beta1.TokenRequest, s conversion.Scope) error { + return autoConvert_storage_TokenRequest_To_v1beta1_TokenRequest(in, out, s) +} + func autoConvert_v1beta1_VolumeAttachment_To_storage_VolumeAttachment(in *v1beta1.VolumeAttachment, out *storage.VolumeAttachment, s conversion.Scope) error { out.ObjectMeta = in.ObjectMeta if err := Convert_v1beta1_VolumeAttachmentSpec_To_storage_VolumeAttachmentSpec(&in.Spec, &out.Spec, s); err != nil { diff --git a/pkg/apis/storage/validation/validation.go b/pkg/apis/storage/validation/validation.go index 4ba31b66c9d..e8510c152a4 100644 --- a/pkg/apis/storage/validation/validation.go +++ b/pkg/apis/storage/validation/validation.go @@ -20,6 +20,7 @@ import ( "fmt" "reflect" "strings" + "time" apiequality "k8s.io/apimachinery/pkg/api/equality" apimachineryvalidation "k8s.io/apimachinery/pkg/api/validation" @@ -422,6 +423,7 @@ func validateCSIDriverSpec( allErrs = append(allErrs, validatePodInfoOnMount(spec.PodInfoOnMount, fldPath.Child("podInfoOnMount"))...) allErrs = append(allErrs, validateStorageCapacity(spec.StorageCapacity, fldPath.Child("storageCapacity"))...) allErrs = append(allErrs, validateFSGroupPolicy(spec.FSGroupPolicy, fldPath.Child("fsGroupPolicy"))...) + allErrs = append(allErrs, validateTokenRequests(spec.TokenRequests, fldPath.Child("tokenRequests"))...) allErrs = append(allErrs, validateVolumeLifecycleModes(spec.VolumeLifecycleModes, fldPath.Child("volumeLifecycleModes"))...) return allErrs } @@ -473,6 +475,35 @@ func validateFSGroupPolicy(fsGroupPolicy *storage.FSGroupPolicy, fldPath *field. return allErrs } +// validateTokenRequests tests if the Audience in each TokenRequest are different. +// Besides, at most one TokenRequest can ignore Audience. +func validateTokenRequests(tokenRequests []storage.TokenRequest, fldPath *field.Path) field.ErrorList { + const min = 10 * time.Minute + allErrs := field.ErrorList{} + audiences := make(map[string]bool) + for i, tokenRequest := range tokenRequests { + path := fldPath.Index(i) + audience := tokenRequest.Audience + if _, ok := audiences[audience]; ok { + allErrs = append(allErrs, field.Duplicate(path.Child("audience"), audience)) + continue + } + audiences[audience] = true + + if tokenRequest.ExpirationSeconds == nil { + continue + } + if *tokenRequest.ExpirationSeconds < int64(min.Seconds()) { + allErrs = append(allErrs, field.Invalid(path.Child("expirationSeconds"), *tokenRequest.ExpirationSeconds, "may not specify a duration less than 10 minutes")) + } + if *tokenRequest.ExpirationSeconds > 1<<32 { + allErrs = append(allErrs, field.Invalid(path.Child("expirationSeconds"), *tokenRequest.ExpirationSeconds, "may not specify a duration larger than 2^32 seconds")) + } + } + + return allErrs +} + // validateVolumeLifecycleModes tests if mode has one of the allowed values. func validateVolumeLifecycleModes(modes []storage.VolumeLifecycleMode, fldPath *field.Path) field.ErrorList { allErrs := field.ErrorList{} diff --git a/pkg/apis/storage/validation/validation_test.go b/pkg/apis/storage/validation/validation_test.go index 0ec0e7a9c23..10c071f2240 100644 --- a/pkg/apis/storage/validation/validation_test.go +++ b/pkg/apis/storage/validation/validation_test.go @@ -1665,6 +1665,7 @@ func TestCSIDriverValidation(t *testing.T) { attachNotRequired := false podInfoOnMount := true notPodInfoOnMount := false + notRequiresRepublish := false supportedFSGroupPolicy := storage.FileFSGroupPolicy invalidFSGroupPolicy := storage.ReadWriteOnceWithFSTypeFSGroupPolicy invalidFSGroupPolicy = "invalid-mode" @@ -1672,68 +1673,77 @@ func TestCSIDriverValidation(t *testing.T) { { ObjectMeta: metav1.ObjectMeta{Name: driverName}, Spec: storage.CSIDriverSpec{ - AttachRequired: &attachRequired, - PodInfoOnMount: &podInfoOnMount, + AttachRequired: &attachRequired, + PodInfoOnMount: &podInfoOnMount, + RequiresRepublish: ¬RequiresRepublish, }, }, { // driver name: dot only ObjectMeta: metav1.ObjectMeta{Name: "io.kubernetes.storage.csi.driver"}, Spec: storage.CSIDriverSpec{ - AttachRequired: &attachRequired, - PodInfoOnMount: &podInfoOnMount, + AttachRequired: &attachRequired, + PodInfoOnMount: &podInfoOnMount, + RequiresRepublish: ¬RequiresRepublish, }, }, { // driver name: dash only ObjectMeta: metav1.ObjectMeta{Name: "io-kubernetes-storage-csi-driver"}, Spec: storage.CSIDriverSpec{ - AttachRequired: &attachRequired, - PodInfoOnMount: ¬PodInfoOnMount, + AttachRequired: &attachRequired, + PodInfoOnMount: ¬PodInfoOnMount, + RequiresRepublish: ¬RequiresRepublish, }, }, { // driver name: numbers ObjectMeta: metav1.ObjectMeta{Name: "1csi2driver3"}, Spec: storage.CSIDriverSpec{ - AttachRequired: &attachRequired, - PodInfoOnMount: &podInfoOnMount, + AttachRequired: &attachRequired, + PodInfoOnMount: &podInfoOnMount, + RequiresRepublish: ¬RequiresRepublish, }, }, { // driver name: dot and dash ObjectMeta: metav1.ObjectMeta{Name: "io.kubernetes.storage.csi-driver"}, Spec: storage.CSIDriverSpec{ - AttachRequired: &attachRequired, - PodInfoOnMount: &podInfoOnMount, + AttachRequired: &attachRequired, + PodInfoOnMount: &podInfoOnMount, + RequiresRepublish: ¬RequiresRepublish, }, }, { ObjectMeta: metav1.ObjectMeta{Name: driverName}, Spec: storage.CSIDriverSpec{ - AttachRequired: &attachRequired, - PodInfoOnMount: ¬PodInfoOnMount, + AttachRequired: &attachRequired, + PodInfoOnMount: ¬PodInfoOnMount, + RequiresRepublish: ¬RequiresRepublish, }, }, { ObjectMeta: metav1.ObjectMeta{Name: driverName}, Spec: storage.CSIDriverSpec{ - AttachRequired: &attachRequired, - PodInfoOnMount: &podInfoOnMount, + AttachRequired: &attachRequired, + PodInfoOnMount: &podInfoOnMount, + RequiresRepublish: ¬RequiresRepublish, }, }, { ObjectMeta: metav1.ObjectMeta{Name: driverName}, Spec: storage.CSIDriverSpec{ - AttachRequired: &attachNotRequired, - PodInfoOnMount: ¬PodInfoOnMount, + AttachRequired: &attachNotRequired, + PodInfoOnMount: ¬PodInfoOnMount, + RequiresRepublish: ¬RequiresRepublish, }, }, { ObjectMeta: metav1.ObjectMeta{Name: driverName}, Spec: storage.CSIDriverSpec{ - AttachRequired: &attachNotRequired, - PodInfoOnMount: ¬PodInfoOnMount, + AttachRequired: &attachNotRequired, + PodInfoOnMount: ¬PodInfoOnMount, + RequiresRepublish: ¬RequiresRepublish, VolumeLifecycleModes: []storage.VolumeLifecycleMode{ storage.VolumeLifecyclePersistent, }, @@ -1742,8 +1752,9 @@ func TestCSIDriverValidation(t *testing.T) { { ObjectMeta: metav1.ObjectMeta{Name: driverName}, Spec: storage.CSIDriverSpec{ - AttachRequired: &attachNotRequired, - PodInfoOnMount: ¬PodInfoOnMount, + AttachRequired: &attachNotRequired, + PodInfoOnMount: ¬PodInfoOnMount, + RequiresRepublish: ¬RequiresRepublish, VolumeLifecycleModes: []storage.VolumeLifecycleMode{ storage.VolumeLifecycleEphemeral, }, @@ -1752,8 +1763,9 @@ func TestCSIDriverValidation(t *testing.T) { { ObjectMeta: metav1.ObjectMeta{Name: driverName}, Spec: storage.CSIDriverSpec{ - AttachRequired: &attachNotRequired, - PodInfoOnMount: ¬PodInfoOnMount, + AttachRequired: &attachNotRequired, + PodInfoOnMount: ¬PodInfoOnMount, + RequiresRepublish: ¬RequiresRepublish, VolumeLifecycleModes: []storage.VolumeLifecycleMode{ storage.VolumeLifecycleEphemeral, storage.VolumeLifecyclePersistent, @@ -1763,8 +1775,9 @@ func TestCSIDriverValidation(t *testing.T) { { ObjectMeta: metav1.ObjectMeta{Name: driverName}, Spec: storage.CSIDriverSpec{ - AttachRequired: &attachNotRequired, - PodInfoOnMount: ¬PodInfoOnMount, + AttachRequired: &attachNotRequired, + PodInfoOnMount: ¬PodInfoOnMount, + RequiresRepublish: ¬RequiresRepublish, VolumeLifecycleModes: []storage.VolumeLifecycleMode{ storage.VolumeLifecycleEphemeral, storage.VolumeLifecyclePersistent, @@ -1775,9 +1788,10 @@ func TestCSIDriverValidation(t *testing.T) { { ObjectMeta: metav1.ObjectMeta{Name: driverName}, Spec: storage.CSIDriverSpec{ - AttachRequired: &attachNotRequired, - PodInfoOnMount: ¬PodInfoOnMount, - FSGroupPolicy: &supportedFSGroupPolicy, + AttachRequired: &attachNotRequired, + PodInfoOnMount: ¬PodInfoOnMount, + RequiresRepublish: ¬RequiresRepublish, + FSGroupPolicy: &supportedFSGroupPolicy, }, }, } @@ -1855,11 +1869,13 @@ func TestCSIDriverValidationUpdate(t *testing.T) { attachNotRequired := false podInfoOnMount := true notPodInfoOnMount := false + notRequiresRepublish := false old := storage.CSIDriver{ ObjectMeta: metav1.ObjectMeta{Name: driverName}, Spec: storage.CSIDriverSpec{ - AttachRequired: &attachNotRequired, - PodInfoOnMount: ¬PodInfoOnMount, + AttachRequired: &attachNotRequired, + PodInfoOnMount: ¬PodInfoOnMount, + RequiresRepublish: ¬RequiresRepublish, VolumeLifecycleModes: []storage.VolumeLifecycleMode{ storage.VolumeLifecycleEphemeral, storage.VolumeLifecyclePersistent, @@ -2060,3 +2076,77 @@ func TestValidateCSIStorageCapacity(t *testing.T) { } } + +func TestCSIServiceAccountToken(t *testing.T) { + driverName := "test-driver" + gcp := "gcp" + aws := "aws" + notRequiresRepublish := false + tests := []struct { + desc string + csiDriver *storage.CSIDriver + wantErr bool + }{ + { + desc: "invalid - TokenRequests has tokens with the same audience", + csiDriver: &storage.CSIDriver{ + ObjectMeta: metav1.ObjectMeta{Name: driverName}, + Spec: storage.CSIDriverSpec{ + TokenRequests: []storage.TokenRequest{{Audience: gcp}, {Audience: gcp}}, + RequiresRepublish: ¬RequiresRepublish, + }, + }, + wantErr: true, + }, + { + desc: "invalid - TokenRequests has tokens with ExpirationSeconds less than 10min", + csiDriver: &storage.CSIDriver{ + ObjectMeta: metav1.ObjectMeta{Name: driverName}, + Spec: storage.CSIDriverSpec{ + TokenRequests: []storage.TokenRequest{{Audience: gcp, ExpirationSeconds: utilpointer.Int64Ptr(10)}}, + RequiresRepublish: ¬RequiresRepublish, + }, + }, + wantErr: true, + }, + { + desc: "invalid - TokenRequests has tokens with ExpirationSeconds less than 10min", + csiDriver: &storage.CSIDriver{ + ObjectMeta: metav1.ObjectMeta{Name: driverName}, + Spec: storage.CSIDriverSpec{ + TokenRequests: []storage.TokenRequest{{Audience: gcp, ExpirationSeconds: utilpointer.Int64Ptr(1<<32 + 1)}}, + RequiresRepublish: ¬RequiresRepublish, + }, + }, + wantErr: true, + }, + { + desc: "valid - TokenRequests has at most one token with empty string audience", + csiDriver: &storage.CSIDriver{ + ObjectMeta: metav1.ObjectMeta{Name: driverName}, + Spec: storage.CSIDriverSpec{ + TokenRequests: []storage.TokenRequest{{Audience: ""}}, + RequiresRepublish: ¬RequiresRepublish, + }, + }, + }, + { + desc: "valid - TokenRequests has tokens with different audience", + csiDriver: &storage.CSIDriver{ + ObjectMeta: metav1.ObjectMeta{Name: driverName}, + Spec: storage.CSIDriverSpec{ + TokenRequests: []storage.TokenRequest{{}, {Audience: gcp}, {Audience: aws}}, + RequiresRepublish: ¬RequiresRepublish, + }, + }, + }, + } + + for _, test := range tests { + test.csiDriver.Spec.AttachRequired = new(bool) + test.csiDriver.Spec.PodInfoOnMount = new(bool) + if errs := ValidateCSIDriver(test.csiDriver); test.wantErr != (len(errs) != 0) { + t.Errorf("ValidateCSIDriver = %v, want err: %v", errs, test.wantErr) + } + } +} diff --git a/pkg/apis/storage/zz_generated.deepcopy.go b/pkg/apis/storage/zz_generated.deepcopy.go index 0ec57047ec4..8553365dd6d 100644 --- a/pkg/apis/storage/zz_generated.deepcopy.go +++ b/pkg/apis/storage/zz_generated.deepcopy.go @@ -114,6 +114,18 @@ func (in *CSIDriverSpec) DeepCopyInto(out *CSIDriverSpec) { *out = new(bool) **out = **in } + if in.TokenRequests != nil { + in, out := &in.TokenRequests, &out.TokenRequests + *out = make([]TokenRequest, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.RequiresRepublish != nil { + in, out := &in.RequiresRepublish, &out.RequiresRepublish + *out = new(bool) + **out = **in + } return } @@ -398,6 +410,27 @@ func (in *StorageClassList) DeepCopyObject() runtime.Object { return nil } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TokenRequest) DeepCopyInto(out *TokenRequest) { + *out = *in + if in.ExpirationSeconds != nil { + in, out := &in.ExpirationSeconds, &out.ExpirationSeconds + *out = new(int64) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TokenRequest. +func (in *TokenRequest) DeepCopy() *TokenRequest { + if in == nil { + return nil + } + out := new(TokenRequest) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *VolumeAttachment) DeepCopyInto(out *VolumeAttachment) { *out = *in diff --git a/pkg/controller/volume/attachdetach/testing/testvolumespec.go b/pkg/controller/volume/attachdetach/testing/testvolumespec.go index af3cc35d35b..907b4218829 100644 --- a/pkg/controller/volume/attachdetach/testing/testvolumespec.go +++ b/pkg/controller/volume/attachdetach/testing/testvolumespec.go @@ -21,7 +21,7 @@ import ( "sync" "time" - "k8s.io/api/core/v1" + v1 "k8s.io/api/core/v1" storagev1 "k8s.io/api/storage/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" @@ -272,7 +272,7 @@ func (plugin *TestPlugin) CanSupport(spec *volume.Spec) bool { return true } -func (plugin *TestPlugin) RequiresRemount() bool { +func (plugin *TestPlugin) RequiresRemount(spec *volume.Spec) bool { return false } diff --git a/pkg/controller/volume/persistentvolume/framework_test.go b/pkg/controller/volume/persistentvolume/framework_test.go index aeecce3e0aa..5fed836cf41 100644 --- a/pkg/controller/volume/persistentvolume/framework_test.go +++ b/pkg/controller/volume/persistentvolume/framework_test.go @@ -43,6 +43,7 @@ import ( "k8s.io/kubernetes/pkg/controller" pvtesting "k8s.io/kubernetes/pkg/controller/volume/persistentvolume/testing" pvutil "k8s.io/kubernetes/pkg/controller/volume/persistentvolume/util" + "k8s.io/kubernetes/pkg/volume" vol "k8s.io/kubernetes/pkg/volume" "k8s.io/kubernetes/pkg/volume/util/recyclerclient" ) @@ -861,7 +862,7 @@ func (plugin *mockVolumePlugin) CanSupport(spec *vol.Spec) bool { return true } -func (plugin *mockVolumePlugin) RequiresRemount() bool { +func (plugin *mockVolumePlugin) RequiresRemount(spec *volume.Spec) bool { return false } diff --git a/pkg/features/kube_features.go b/pkg/features/kube_features.go index ba6452ca3b2..c90fdc5c382 100644 --- a/pkg/features/kube_features.go +++ b/pkg/features/kube_features.go @@ -693,6 +693,13 @@ const ( // // Enable kubelet exec plugins for image pull credentials. KubeletCredentialProviders featuregate.Feature = "KubeletCredentialProviders" + + // owner: @zshihang + // alpha: v1.20 + // + // Enable kubelet to pass pod's service account token to NodePublishVolume + // call of CSI driver which is mounting volumes for that pod. + CSIServiceAccountToken featuregate.Feature = "CSIServiceAccountToken" ) func init() { @@ -754,6 +761,7 @@ var defaultKubernetesFeatureGates = map[featuregate.Feature]featuregate.FeatureS CSIBlockVolume: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.20 CSIInlineVolume: {Default: true, PreRelease: featuregate.Beta}, CSIStorageCapacity: {Default: false, PreRelease: featuregate.Alpha}, + CSIServiceAccountToken: {Default: false, PreRelease: featuregate.Alpha}, GenericEphemeralVolume: {Default: false, PreRelease: featuregate.Alpha}, CSIVolumeFSGroupPolicy: {Default: false, PreRelease: featuregate.Alpha}, RuntimeClass: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.23 diff --git a/pkg/kubelet/volumemanager/cache/actual_state_of_world.go b/pkg/kubelet/volumemanager/cache/actual_state_of_world.go index d04385d259d..155caebd780 100644 --- a/pkg/kubelet/volumemanager/cache/actual_state_of_world.go +++ b/pkg/kubelet/volumemanager/cache/actual_state_of_world.go @@ -557,7 +557,7 @@ func (asw *actualStateOfWorld) MarkRemountRequired( continue } - if volumePlugin.RequiresRemount() { + if volumePlugin.RequiresRemount(podObj.volumeSpec) { podObj.remountRequired = true asw.attachedVolumes[volumeName].mountedPods[podName] = podObj } diff --git a/pkg/kubelet/volumemanager/volume_manager.go b/pkg/kubelet/volumemanager/volume_manager.go index 249cba33651..86f77e517ad 100644 --- a/pkg/kubelet/volumemanager/volume_manager.go +++ b/pkg/kubelet/volumemanager/volume_manager.go @@ -260,6 +260,11 @@ type volumeManager struct { func (vm *volumeManager) Run(sourcesReady config.SourcesReady, stopCh <-chan struct{}) { defer runtime.HandleCrash() + if vm.kubeClient != nil { + // start informer for CSIDriver + go vm.volumePluginMgr.Run(stopCh) + } + go vm.desiredStateOfWorldPopulator.Run(sourcesReady, stopCh) klog.V(2).Infof("The desired_state_of_world populator starts") @@ -268,11 +273,6 @@ func (vm *volumeManager) Run(sourcesReady config.SourcesReady, stopCh <-chan str metrics.Register(vm.actualStateOfWorld, vm.desiredStateOfWorld, vm.volumePluginMgr) - if vm.kubeClient != nil { - // start informer for CSIDriver - vm.volumePluginMgr.Run(stopCh) - } - <-stopCh klog.Infof("Shutting down Kubelet Volume Manager") } diff --git a/pkg/printers/internalversion/printers.go b/pkg/printers/internalversion/printers.go index 6332746815c..ae1126bc3bc 100644 --- a/pkg/printers/internalversion/printers.go +++ b/pkg/printers/internalversion/printers.go @@ -520,6 +520,12 @@ func AddHandlers(h printers.PrintHandler) { Name: "StorageCapacity", Type: "boolean", Description: storagev1.CSIDriverSpec{}.SwaggerDoc()["storageCapacity"], }) } + if utilfeature.DefaultFeatureGate.Enabled(features.CSIServiceAccountToken) { + csiDriverColumnDefinitions = append(csiDriverColumnDefinitions, []metav1.TableColumnDefinition{ + {Name: "TokenRequests", Type: "string", Description: storagev1.CSIDriverSpec{}.SwaggerDoc()["tokenRequests"]}, + {Name: "RequiresRepublish", Type: "boolean", Description: storagev1.CSIDriverSpec{}.SwaggerDoc()["requiresRepublish"]}, + }...) + } csiDriverColumnDefinitions = append(csiDriverColumnDefinitions, []metav1.TableColumnDefinition{ {Name: "Modes", Type: "string", Description: storagev1.CSIDriverSpec{}.SwaggerDoc()["volumeLifecycleModes"]}, {Name: "Age", Type: "string", Description: metav1.ObjectMeta{}.SwaggerDoc()["creationTimestamp"]}, @@ -1395,6 +1401,21 @@ func printCSIDriver(obj *storage.CSIDriver, options printers.GenerateOptions) ([ } row.Cells = append(row.Cells, storageCapacity) } + if utilfeature.DefaultFeatureGate.Enabled(features.CSIServiceAccountToken) { + tokenRequests := "" + if obj.Spec.TokenRequests != nil { + audiences := []string{} + for _, t := range obj.Spec.TokenRequests { + audiences = append(audiences, t.Audience) + } + tokenRequests = strings.Join(audiences, ",") + } + requiresRepublish := false + if obj.Spec.RequiresRepublish != nil { + requiresRepublish = *obj.Spec.RequiresRepublish + } + row.Cells = append(row.Cells, tokenRequests, requiresRepublish) + } row.Cells = append(row.Cells, modes, translateTimestampSince(obj.CreationTimestamp)) return []metav1.TableRow{row}, nil } diff --git a/pkg/registry/storage/csidriver/storage/storage_test.go b/pkg/registry/storage/csidriver/storage/storage_test.go index a1ff030c8c8..f57c8a9bf65 100644 --- a/pkg/registry/storage/csidriver/storage/storage_test.go +++ b/pkg/registry/storage/csidriver/storage/storage_test.go @@ -48,13 +48,15 @@ func newStorage(t *testing.T) (*REST, *etcd3testing.EtcdTestServer) { func validNewCSIDriver(name string) *storageapi.CSIDriver { attachRequired := true podInfoOnMount := true + requiresRepublish := true return &storageapi.CSIDriver{ ObjectMeta: metav1.ObjectMeta{ Name: name, }, Spec: storageapi.CSIDriverSpec{ - AttachRequired: &attachRequired, - PodInfoOnMount: &podInfoOnMount, + AttachRequired: &attachRequired, + PodInfoOnMount: &podInfoOnMount, + RequiresRepublish: &requiresRepublish, }, } } @@ -68,6 +70,7 @@ func TestCreate(t *testing.T) { csiDriver.ObjectMeta = metav1.ObjectMeta{GenerateName: "foo"} attachNotRequired := false notPodInfoOnMount := false + notRequiresRepublish := false test.TestCreate( // valid csiDriver, @@ -75,8 +78,9 @@ func TestCreate(t *testing.T) { &storageapi.CSIDriver{ ObjectMeta: metav1.ObjectMeta{Name: "*BadName!"}, Spec: storageapi.CSIDriverSpec{ - AttachRequired: &attachNotRequired, - PodInfoOnMount: ¬PodInfoOnMount, + AttachRequired: &attachNotRequired, + PodInfoOnMount: ¬PodInfoOnMount, + RequiresRepublish: ¬RequiresRepublish, }, }, ) diff --git a/pkg/registry/storage/csidriver/strategy.go b/pkg/registry/storage/csidriver/strategy.go index ea3dd853ad4..8cf3f06144d 100644 --- a/pkg/registry/storage/csidriver/strategy.go +++ b/pkg/registry/storage/csidriver/strategy.go @@ -55,6 +55,10 @@ func (csiDriverStrategy) PrepareForCreate(ctx context.Context, obj runtime.Objec if !utilfeature.DefaultFeatureGate.Enabled(features.CSIVolumeFSGroupPolicy) { csiDriver.Spec.FSGroupPolicy = nil } + if !utilfeature.DefaultFeatureGate.Enabled(features.CSIServiceAccountToken) { + csiDriver.Spec.TokenRequests = nil + csiDriver.Spec.RequiresRepublish = nil + } } func (csiDriverStrategy) Validate(ctx context.Context, obj runtime.Object) field.ErrorList { @@ -93,6 +97,17 @@ func (csiDriverStrategy) PrepareForUpdate(ctx context.Context, obj, old runtime. newCSIDriver := obj.(*storage.CSIDriver) newCSIDriver.Spec.FSGroupPolicy = nil } + if old.(*storage.CSIDriver).Spec.TokenRequests == nil && + !utilfeature.DefaultFeatureGate.Enabled(features.CSIServiceAccountToken) { + csiDriver := obj.(*storage.CSIDriver) + csiDriver.Spec.TokenRequests = nil + } + + if old.(*storage.CSIDriver).Spec.RequiresRepublish == nil && + !utilfeature.DefaultFeatureGate.Enabled(features.CSIServiceAccountToken) { + csiDriver := obj.(*storage.CSIDriver) + csiDriver.Spec.RequiresRepublish = nil + } } func (csiDriverStrategy) ValidateUpdate(ctx context.Context, obj, old runtime.Object) field.ErrorList { diff --git a/pkg/registry/storage/csidriver/strategy_test.go b/pkg/registry/storage/csidriver/strategy_test.go index 3088fb85694..c8a1006f754 100644 --- a/pkg/registry/storage/csidriver/strategy_test.go +++ b/pkg/registry/storage/csidriver/strategy_test.go @@ -36,9 +36,10 @@ func getValidCSIDriver(name string) *storage.CSIDriver { Name: name, }, Spec: storage.CSIDriverSpec{ - AttachRequired: &enabled, - PodInfoOnMount: &enabled, - StorageCapacity: &enabled, + AttachRequired: &enabled, + PodInfoOnMount: &enabled, + StorageCapacity: &enabled, + RequiresRepublish: &enabled, }, } } @@ -88,11 +89,13 @@ func TestCSIDriverPrepareForCreate(t *testing.T) { attachRequired := true podInfoOnMount := true storageCapacity := true + requiresRepublish := true tests := []struct { - name string - withCapacity bool - withInline bool + name string + withCapacity bool + withInline bool + withServiceAccountToken bool }{ { name: "inline enabled", @@ -110,12 +113,21 @@ func TestCSIDriverPrepareForCreate(t *testing.T) { name: "capacity disabled", withCapacity: false, }, + { + name: "serviceAccountToken enabled", + withServiceAccountToken: true, + }, + { + name: "serviceAccountToken disabled", + withServiceAccountToken: false, + }, } for _, test := range tests { t.Run(test.name, func(t *testing.T) { defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.CSIStorageCapacity, test.withCapacity)() defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.CSIInlineVolume, test.withInline)() + defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.CSIServiceAccountToken, test.withServiceAccountToken)() csiDriver := &storage.CSIDriver{ ObjectMeta: metav1.ObjectMeta{ @@ -128,6 +140,8 @@ func TestCSIDriverPrepareForCreate(t *testing.T) { VolumeLifecycleModes: []storage.VolumeLifecycleMode{ storage.VolumeLifecyclePersistent, }, + TokenRequests: []storage.TokenRequest{}, + RequiresRepublish: &requiresRepublish, }, } Strategy.PrepareForCreate(ctx, csiDriver) @@ -153,6 +167,21 @@ func TestCSIDriverPrepareForCreate(t *testing.T) { t.Errorf("VolumeLifecycleModes not stripped: %v", csiDriver.Spec) } } + if test.withServiceAccountToken { + if csiDriver.Spec.TokenRequests == nil { + t.Errorf("TokenRequests modified: %v", csiDriver.Spec) + } + if csiDriver.Spec.RequiresRepublish == nil { + t.Errorf("RequiresRepublish modified: %v", csiDriver.Spec) + } + } else { + if csiDriver.Spec.TokenRequests != nil { + t.Errorf("TokenRequests stripped: %v", csiDriver.Spec) + } + if csiDriver.Spec.RequiresRepublish != nil { + t.Errorf("RequiresRepublish stripped: %v", csiDriver.Spec) + } + } }) } } @@ -166,14 +195,10 @@ func TestCSIDriverPrepareForUpdate(t *testing.T) { attachRequired := true podInfoOnMount := true - driverWithoutModes := &storage.CSIDriver{ + driverWithNothing := &storage.CSIDriver{ ObjectMeta: metav1.ObjectMeta{ Name: "foo", }, - Spec: storage.CSIDriverSpec{ - AttachRequired: &attachRequired, - PodInfoOnMount: &podInfoOnMount, - }, } driverWithPersistent := &storage.CSIDriver{ ObjectMeta: metav1.ObjectMeta{ @@ -201,11 +226,8 @@ func TestCSIDriverPrepareForUpdate(t *testing.T) { } enabled := true disabled := false - driverWithoutCapacity := &storage.CSIDriver{ - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - }, - } + gcp := "gcp" + vault := "vault" driverWithCapacityEnabled := &storage.CSIDriver{ ObjectMeta: metav1.ObjectMeta{ Name: "foo", @@ -222,116 +244,121 @@ func TestCSIDriverPrepareForUpdate(t *testing.T) { StorageCapacity: &disabled, }, } + driverWithServiceAccountTokenGCP := &storage.CSIDriver{ + ObjectMeta: metav1.ObjectMeta{ + Name: "foo", + }, + Spec: storage.CSIDriverSpec{ + TokenRequests: []storage.TokenRequest{{Audience: gcp}}, + RequiresRepublish: &enabled, + }, + } + driverWithServiceAccountTokenVault := &storage.CSIDriver{ + ObjectMeta: metav1.ObjectMeta{ + Name: "foo", + }, + Spec: storage.CSIDriverSpec{ + TokenRequests: []storage.TokenRequest{{Audience: vault}}, + RequiresRepublish: &enabled, + }, + } - var resultEmpty []storage.VolumeLifecycleMode resultPersistent := []storage.VolumeLifecycleMode{storage.VolumeLifecyclePersistent} - resultEphemeral := []storage.VolumeLifecycleMode{storage.VolumeLifecycleEphemeral} tests := []struct { name string old, update *storage.CSIDriver - withCapacity, withoutCapacity *bool - withInline, withoutInline []storage.VolumeLifecycleMode + csiStorageCapacityEnabled bool + csiInlineVolumeEnabled bool + csiServiceAccountTokenEnabled bool + wantCapacity *bool + wantModes []storage.VolumeLifecycleMode + wantTokenRequests []storage.TokenRequest + wantRequiresRepublish *bool }{ { - name: "before: no capacity, update: no capacity", - old: driverWithoutCapacity, - update: driverWithoutCapacity, - withCapacity: nil, - withoutCapacity: nil, + name: "capacity feature enabled, before: none, update: enabled", + csiStorageCapacityEnabled: true, + old: driverWithNothing, + update: driverWithCapacityEnabled, + wantCapacity: &enabled, }, { - name: "before: no capacity, update: enabled", - old: driverWithoutCapacity, - update: driverWithCapacityEnabled, - withCapacity: &enabled, - withoutCapacity: nil, + name: "capacity feature disabled, before: none, update: disabled", + old: driverWithNothing, + update: driverWithCapacityDisabled, + wantCapacity: nil, }, { - name: "before: capacity enabled, update: disabled", - old: driverWithCapacityEnabled, - update: driverWithCapacityDisabled, - withCapacity: &disabled, - withoutCapacity: &disabled, + name: "capacity feature disabled, before: enabled, update: disabled", + old: driverWithCapacityEnabled, + update: driverWithCapacityDisabled, + wantCapacity: &disabled, }, { - name: "before: capacity enabled, update: no capacity", - old: driverWithCapacityEnabled, - update: driverWithoutCapacity, - withCapacity: nil, - withoutCapacity: nil, - }, - - { - name: "before: no mode, update: no mode", - old: driverWithoutModes, - update: driverWithoutModes, - withInline: resultEmpty, - withoutInline: resultEmpty, + name: "inline feature enabled, before: none, update: persitent", + csiInlineVolumeEnabled: true, + old: driverWithNothing, + update: driverWithPersistent, + wantModes: resultPersistent, }, { - name: "before: no mode, update: persistent", - old: driverWithoutModes, - update: driverWithPersistent, - withInline: resultPersistent, - withoutInline: resultEmpty, + name: "inline feature disabled, before: none, update: persitent", + old: driverWithNothing, + update: driverWithPersistent, + wantModes: nil, }, { - name: "before: persistent, update: ephemeral", - old: driverWithPersistent, - update: driverWithEphemeral, - withInline: resultEphemeral, - withoutInline: resultEphemeral, + name: "inline feature disabled, before: ephemeral, update: persitent", + old: driverWithEphemeral, + update: driverWithPersistent, + wantModes: resultPersistent, }, { - name: "before: persistent, update: no mode", - old: driverWithPersistent, - update: driverWithoutModes, - withInline: resultEmpty, - withoutInline: resultEmpty, + name: "service account token feature enabled, before: none, update: audience=gcp", + csiServiceAccountTokenEnabled: true, + old: driverWithNothing, + update: driverWithServiceAccountTokenGCP, + wantTokenRequests: []storage.TokenRequest{{Audience: gcp}}, + wantRequiresRepublish: &enabled, + }, + { + name: "service account token feature disabled, before: none, update: audience=gcp", + old: driverWithNothing, + update: driverWithServiceAccountTokenGCP, + wantTokenRequests: nil, + wantRequiresRepublish: nil, + }, + { + name: "service account token feature disabled, before: audience=vault, update: audience=gcp", + old: driverWithServiceAccountTokenVault, + update: driverWithServiceAccountTokenGCP, + wantTokenRequests: []storage.TokenRequest{{Audience: gcp}}, + wantRequiresRepublish: &enabled, }, } - runAll := func(t *testing.T, withCapacity, withInline bool) { - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.CSIStorageCapacity, withCapacity)() - defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.CSIInlineVolume, withInline)() + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.CSIStorageCapacity, test.csiStorageCapacityEnabled)() + defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.CSIInlineVolume, test.csiInlineVolumeEnabled)() + defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.CSIServiceAccountToken, test.csiServiceAccountTokenEnabled)() - csiDriver := test.update.DeepCopy() - Strategy.PrepareForUpdate(ctx, csiDriver, test.old) - if withCapacity { - require.Equal(t, test.withCapacity, csiDriver.Spec.StorageCapacity) - } else { - require.Equal(t, test.withoutCapacity, csiDriver.Spec.StorageCapacity) - } - if withInline { - require.Equal(t, test.withInline, csiDriver.Spec.VolumeLifecycleModes) - } else { - require.Equal(t, test.withoutInline, csiDriver.Spec.VolumeLifecycleModes) - } - }) - } + csiDriver := test.update.DeepCopy() + Strategy.PrepareForUpdate(ctx, csiDriver, test.old) + require.Equal(t, test.wantCapacity, csiDriver.Spec.StorageCapacity) + require.Equal(t, test.wantModes, csiDriver.Spec.VolumeLifecycleModes) + require.Equal(t, test.wantTokenRequests, csiDriver.Spec.TokenRequests) + require.Equal(t, test.wantRequiresRepublish, csiDriver.Spec.RequiresRepublish) + }) } - t.Run("with capacity", func(t *testing.T) { - runAll(t, true, false) - }) - t.Run("without capacity", func(t *testing.T) { - runAll(t, false, false) - }) - - t.Run("with inline volumes", func(t *testing.T) { - runAll(t, false, true) - }) - t.Run("without inline volumes", func(t *testing.T) { - runAll(t, false, false) - }) } func TestCSIDriverValidation(t *testing.T) { enabled := true disabled := true + gcp := "gcp" tests := []struct { name string @@ -350,9 +377,10 @@ func TestCSIDriverValidation(t *testing.T) { Name: "foo", }, Spec: storage.CSIDriverSpec{ - AttachRequired: &enabled, - PodInfoOnMount: &enabled, - StorageCapacity: &enabled, + AttachRequired: &enabled, + PodInfoOnMount: &enabled, + StorageCapacity: &enabled, + RequiresRepublish: &enabled, }, }, false, @@ -364,9 +392,10 @@ func TestCSIDriverValidation(t *testing.T) { Name: "foo", }, Spec: storage.CSIDriverSpec{ - AttachRequired: &disabled, - PodInfoOnMount: &disabled, - StorageCapacity: &disabled, + AttachRequired: &disabled, + PodInfoOnMount: &disabled, + StorageCapacity: &disabled, + RequiresRepublish: &disabled, }, }, false, @@ -378,9 +407,10 @@ func TestCSIDriverValidation(t *testing.T) { Name: "*foo#", }, Spec: storage.CSIDriverSpec{ - AttachRequired: &enabled, - PodInfoOnMount: &enabled, - StorageCapacity: &enabled, + AttachRequired: &enabled, + PodInfoOnMount: &enabled, + StorageCapacity: &enabled, + RequiresRepublish: &enabled, }, }, true, @@ -398,6 +428,7 @@ func TestCSIDriverValidation(t *testing.T) { VolumeLifecycleModes: []storage.VolumeLifecycleMode{ storage.VolumeLifecycleMode("no-such-mode"), }, + RequiresRepublish: &enabled, }, }, true, @@ -415,6 +446,7 @@ func TestCSIDriverValidation(t *testing.T) { VolumeLifecycleModes: []storage.VolumeLifecycleMode{ storage.VolumeLifecyclePersistent, }, + RequiresRepublish: &enabled, }, }, false, @@ -432,6 +464,7 @@ func TestCSIDriverValidation(t *testing.T) { VolumeLifecycleModes: []storage.VolumeLifecycleMode{ storage.VolumeLifecycleEphemeral, }, + RequiresRepublish: &enabled, }, }, false, @@ -450,6 +483,23 @@ func TestCSIDriverValidation(t *testing.T) { storage.VolumeLifecyclePersistent, storage.VolumeLifecycleEphemeral, }, + RequiresRepublish: &enabled, + }, + }, + false, + }, + { + "service account token with gcp as audience", + &storage.CSIDriver{ + ObjectMeta: metav1.ObjectMeta{ + Name: "foo", + }, + Spec: storage.CSIDriverSpec{ + AttachRequired: &enabled, + PodInfoOnMount: &enabled, + StorageCapacity: &enabled, + TokenRequests: []storage.TokenRequest{{Audience: gcp}}, + RequiresRepublish: &enabled, }, }, false, diff --git a/pkg/volume/awsebs/aws_ebs.go b/pkg/volume/awsebs/aws_ebs.go index ef695a935cd..bee0ab3244e 100644 --- a/pkg/volume/awsebs/aws_ebs.go +++ b/pkg/volume/awsebs/aws_ebs.go @@ -87,7 +87,7 @@ func (plugin *awsElasticBlockStorePlugin) CanSupport(spec *volume.Spec) bool { (spec.Volume != nil && spec.Volume.AWSElasticBlockStore != nil) } -func (plugin *awsElasticBlockStorePlugin) RequiresRemount() bool { +func (plugin *awsElasticBlockStorePlugin) RequiresRemount(spec *volume.Spec) bool { return false } diff --git a/pkg/volume/azure_file/azure_file.go b/pkg/volume/azure_file/azure_file.go index 4b77a447f4b..5723a44a48b 100644 --- a/pkg/volume/azure_file/azure_file.go +++ b/pkg/volume/azure_file/azure_file.go @@ -86,7 +86,7 @@ func (plugin *azureFilePlugin) CanSupport(spec *volume.Spec) bool { (spec.Volume != nil && spec.Volume.AzureFile != nil) } -func (plugin *azureFilePlugin) RequiresRemount() bool { +func (plugin *azureFilePlugin) RequiresRemount(spec *volume.Spec) bool { return false } diff --git a/pkg/volume/azuredd/azure_dd.go b/pkg/volume/azuredd/azure_dd.go index 4ce2f5812a1..b4cdce4167b 100644 --- a/pkg/volume/azuredd/azure_dd.go +++ b/pkg/volume/azuredd/azure_dd.go @@ -121,7 +121,7 @@ func (plugin *azureDataDiskPlugin) CanSupport(spec *volume.Spec) bool { (spec.Volume != nil && spec.Volume.AzureDisk != nil) } -func (plugin *azureDataDiskPlugin) RequiresRemount() bool { +func (plugin *azureDataDiskPlugin) RequiresRemount(spec *volume.Spec) bool { return false } diff --git a/pkg/volume/cephfs/cephfs.go b/pkg/volume/cephfs/cephfs.go index 6966b8dd582..20a4119ae09 100644 --- a/pkg/volume/cephfs/cephfs.go +++ b/pkg/volume/cephfs/cephfs.go @@ -73,7 +73,7 @@ func (plugin *cephfsPlugin) CanSupport(spec *volume.Spec) bool { return (spec.Volume != nil && spec.Volume.CephFS != nil) || (spec.PersistentVolume != nil && spec.PersistentVolume.Spec.CephFS != nil) } -func (plugin *cephfsPlugin) RequiresRemount() bool { +func (plugin *cephfsPlugin) RequiresRemount(spec *volume.Spec) bool { return false } diff --git a/pkg/volume/cinder/cinder.go b/pkg/volume/cinder/cinder.go index 689a989d35e..98d5c2690b6 100644 --- a/pkg/volume/cinder/cinder.go +++ b/pkg/volume/cinder/cinder.go @@ -110,7 +110,7 @@ func (plugin *cinderPlugin) CanSupport(spec *volume.Spec) bool { return (spec.Volume != nil && spec.Volume.Cinder != nil) || (spec.PersistentVolume != nil && spec.PersistentVolume.Spec.Cinder != nil) } -func (plugin *cinderPlugin) RequiresRemount() bool { +func (plugin *cinderPlugin) RequiresRemount(spec *volume.Spec) bool { return false } diff --git a/pkg/volume/configmap/configmap.go b/pkg/volume/configmap/configmap.go index 6d2aa4ce926..6a90aafc2be 100644 --- a/pkg/volume/configmap/configmap.go +++ b/pkg/volume/configmap/configmap.go @@ -78,7 +78,7 @@ func (plugin *configMapPlugin) CanSupport(spec *volume.Spec) bool { return spec.Volume != nil && spec.Volume.ConfigMap != nil } -func (plugin *configMapPlugin) RequiresRemount() bool { +func (plugin *configMapPlugin) RequiresRemount(spec *volume.Spec) bool { return true } diff --git a/pkg/volume/csi/BUILD b/pkg/volume/csi/BUILD index 689240b15ea..62123c8ef55 100644 --- a/pkg/volume/csi/BUILD +++ b/pkg/volume/csi/BUILD @@ -22,6 +22,7 @@ go_library( "//pkg/volume/csi/nodeinfomanager:go_default_library", "//pkg/volume/util:go_default_library", "//pkg/volume/util/types:go_default_library", + "//staging/src/k8s.io/api/authentication/v1:go_default_library", "//staging/src/k8s.io/api/core/v1:go_default_library", "//staging/src/k8s.io/api/storage/v1:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/api/errors:go_default_library", @@ -62,12 +63,16 @@ go_test( ], embed = [":go_default_library"], deps = [ + "//pkg/apis/authentication/v1:go_default_library", + "//pkg/apis/core/v1:go_default_library", + "//pkg/apis/storage/v1:go_default_library", "//pkg/features:go_default_library", "//pkg/volume:go_default_library", "//pkg/volume/csi/fake:go_default_library", "//pkg/volume/testing:go_default_library", "//pkg/volume/util:go_default_library", "//pkg/volume/util/types:go_default_library", + "//staging/src/k8s.io/api/authentication/v1:go_default_library", "//staging/src/k8s.io/api/core/v1:go_default_library", "//staging/src/k8s.io/api/storage/v1:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/api/errors:go_default_library", @@ -75,6 +80,7 @@ go_test( "//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/types:go_default_library", + "//staging/src/k8s.io/apimachinery/pkg/util/runtime:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/util/wait:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/watch:go_default_library", "//staging/src/k8s.io/apiserver/pkg/util/feature:go_default_library", @@ -87,6 +93,7 @@ go_test( "//staging/src/k8s.io/client-go/util/testing:go_default_library", "//staging/src/k8s.io/component-base/featuregate/testing:go_default_library", "//vendor/github.com/container-storage-interface/spec/lib/go/csi:go_default_library", + "//vendor/github.com/google/go-cmp/cmp:go_default_library", "//vendor/github.com/stretchr/testify/assert:go_default_library", "//vendor/google.golang.org/grpc/codes:go_default_library", "//vendor/google.golang.org/grpc/status:go_default_library", diff --git a/pkg/volume/csi/csi_mounter.go b/pkg/volume/csi/csi_mounter.go index b5600f04b99..2ff94fe8c80 100644 --- a/pkg/volume/csi/csi_mounter.go +++ b/pkg/volume/csi/csi_mounter.go @@ -19,6 +19,7 @@ package csi import ( "context" "crypto/sha256" + "encoding/json" "errors" "fmt" "os" @@ -27,6 +28,7 @@ import ( "k8s.io/klog/v2" + authenticationv1 "k8s.io/api/authentication/v1" api "k8s.io/api/core/v1" storage "k8s.io/api/storage/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" @@ -224,14 +226,15 @@ func (c *csiMountMgr) SetUpAt(dir string, mounterArgs volume.MounterArgs) error if err != nil { return volumetypes.NewTransientOperationFailure(log("mounter.SetUpAt failed to assemble volume attributes: %v", err)) } - if podAttrs != nil { - if volAttribs == nil { - volAttribs = podAttrs - } else { - for k, v := range podAttrs { - volAttribs[k] = v - } + volAttribs = mergeMap(volAttribs, podAttrs) + + // Inject pod service account token into volume attributes + if utilfeature.DefaultFeatureGate.Enabled(features.CSIServiceAccountToken) { + serviceAccountTokenAttrs, err := c.podServiceAccountTokenAttrs() + if err != nil { + return volumetypes.NewTransientOperationFailure(log("mounter.SetUpAt failed to get service accoount token attributes: %v", err)) } + volAttribs = mergeMap(volAttribs, serviceAccountTokenAttrs) } err = csi.NodePublishVolume( @@ -319,6 +322,57 @@ func (c *csiMountMgr) podAttributes() (map[string]string, error) { return attrs, nil } +func (c *csiMountMgr) podServiceAccountTokenAttrs() (map[string]string, error) { + if c.plugin.serviceAccountTokenGetter == nil { + return nil, errors.New("ServiceAccountTokenGetter is nil") + } + + csiDriver, err := c.plugin.csiDriverLister.Get(string(c.driverName)) + if err != nil { + if apierrors.IsNotFound(err) { + klog.V(5).Infof(log("CSIDriver %q not found, not adding service account token information", c.driverName)) + return nil, nil + } + return nil, err + } + + if len(csiDriver.Spec.TokenRequests) == 0 { + return nil, nil + } + + outputs := map[string]authenticationv1.TokenRequestStatus{} + for _, tokenRequest := range csiDriver.Spec.TokenRequests { + audience := tokenRequest.Audience + audiences := []string{audience} + if audience == "" { + audiences = []string{} + } + tr, err := c.plugin.serviceAccountTokenGetter(c.pod.Namespace, c.pod.Spec.ServiceAccountName, &authenticationv1.TokenRequest{ + Spec: authenticationv1.TokenRequestSpec{ + Audiences: audiences, + ExpirationSeconds: tokenRequest.ExpirationSeconds, + BoundObjectRef: &authenticationv1.BoundObjectReference{ + APIVersion: "v1", + Kind: "Pod", + Name: c.pod.Name, + UID: c.pod.UID, + }, + }, + }) + if err != nil { + return nil, err + } + + outputs[audience] = tr.Status + } + + klog.V(4).Infof(log("Fetched service account token attrs for CSIDriver %q", c.driverName)) + tokens, _ := json.Marshal(outputs) + return map[string]string{ + "csi.storage.k8s.io/serviceAccount.tokens": string(tokens), + }, nil +} + func (c *csiMountMgr) GetAttributes() volume.Attributes { return volume.Attributes{ ReadOnly: c.readOnly, @@ -434,3 +488,13 @@ func makeVolumeHandle(podUID, volSourceSpecName string) string { result := sha256.Sum256([]byte(fmt.Sprintf("%s%s", podUID, volSourceSpecName))) return fmt.Sprintf("csi-%x", result) } + +func mergeMap(first, second map[string]string) map[string]string { + if first == nil && second != nil { + return second + } + for k, v := range second { + first[k] = v + } + return first +} diff --git a/pkg/volume/csi/csi_mounter_test.go b/pkg/volume/csi/csi_mounter_test.go index 151da9a7646..cf313f10431 100644 --- a/pkg/volume/csi/csi_mounter_test.go +++ b/pkg/volume/csi/csi_mounter_test.go @@ -25,19 +25,29 @@ import ( "path" "path/filepath" "testing" + "time" "reflect" + "github.com/google/go-cmp/cmp" "github.com/stretchr/testify/assert" + authenticationv1 "k8s.io/api/authentication/v1" api "k8s.io/api/core/v1" storage "k8s.io/api/storage/v1" + storagev1 "k8s.io/api/storage/v1" meta "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/types" + utilruntime "k8s.io/apimachinery/pkg/util/runtime" utilfeature "k8s.io/apiserver/pkg/util/feature" fakeclient "k8s.io/client-go/kubernetes/fake" + clitesting "k8s.io/client-go/testing" featuregatetesting "k8s.io/component-base/featuregate/testing" + pkgauthenticationv1 "k8s.io/kubernetes/pkg/apis/authentication/v1" + pkgcorev1 "k8s.io/kubernetes/pkg/apis/core/v1" + pkgstoragev1 "k8s.io/kubernetes/pkg/apis/storage/v1" "k8s.io/kubernetes/pkg/features" "k8s.io/kubernetes/pkg/volume" fakecsi "k8s.io/kubernetes/pkg/volume/csi/fake" @@ -927,3 +937,122 @@ func TestIsCorruptedDir(t *testing.T) { assert.Equal(t, test.expectedResult, isCorruptedDir, "TestCase[%d]: %s", i, test.desc) } } + +func TestPodServiceAccountTokenAttrs(t *testing.T) { + defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.CSIServiceAccountToken, true)() + defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.CSIInlineVolume, true)() + scheme := runtime.NewScheme() + utilruntime.Must(pkgauthenticationv1.RegisterDefaults(scheme)) + utilruntime.Must(pkgstoragev1.RegisterDefaults(scheme)) + utilruntime.Must(pkgcorev1.RegisterDefaults(scheme)) + + gcp := "gcp" + + tests := []struct { + desc string + driver *storagev1.CSIDriver + volumeContext map[string]string + wantVolumeContext map[string]string + }{ + { + desc: "csi driver has no ServiceAccountToken", + driver: &storagev1.CSIDriver{ + ObjectMeta: meta.ObjectMeta{ + Name: testDriver, + }, + Spec: storagev1.CSIDriverSpec{}, + }, + wantVolumeContext: nil, + }, + { + desc: "one token with empty string as audience", + driver: &storagev1.CSIDriver{ + ObjectMeta: meta.ObjectMeta{ + Name: testDriver, + }, + Spec: storagev1.CSIDriverSpec{ + TokenRequests: []storagev1.TokenRequest{ + { + Audience: "", + }, + }, + }, + }, + wantVolumeContext: map[string]string{"csi.storage.k8s.io/serviceAccount.tokens": `{"":{"token":"test-ns:test-service-account:3600:[api]","expirationTimestamp":"1970-01-01T00:00:01Z"}}`}, + }, + { + desc: "one token with non-empty string as audience", + driver: &storagev1.CSIDriver{ + ObjectMeta: meta.ObjectMeta{ + Name: testDriver, + }, + Spec: storagev1.CSIDriverSpec{ + TokenRequests: []storagev1.TokenRequest{ + { + Audience: gcp, + }, + }, + }, + }, + wantVolumeContext: map[string]string{"csi.storage.k8s.io/serviceAccount.tokens": `{"gcp":{"token":"test-ns:test-service-account:3600:[gcp]","expirationTimestamp":"1970-01-01T00:00:01Z"}}`}, + }, + } + + for _, test := range tests { + t.Run(test.desc, func(t *testing.T) { + registerFakePlugin(testDriver, "endpoint", []string{"1.0.0"}, t) + client := fakeclient.NewSimpleClientset() + if test.driver != nil { + test.driver.Spec.VolumeLifecycleModes = []storage.VolumeLifecycleMode{ + storage.VolumeLifecycleEphemeral, + storage.VolumeLifecyclePersistent, + } + scheme.Default(test.driver) + client = fakeclient.NewSimpleClientset(test.driver) + } + client.PrependReactor("create", "serviceaccounts", clitesting.ReactionFunc(func(action clitesting.Action) (bool, runtime.Object, error) { + tr := action.(clitesting.CreateAction).GetObject().(*authenticationv1.TokenRequest) + scheme.Default(tr) + if len(tr.Spec.Audiences) == 0 { + tr.Spec.Audiences = []string{"api"} + } + tr.Status.Token = fmt.Sprintf("%v:%v:%d:%v", action.GetNamespace(), testAccount, *tr.Spec.ExpirationSeconds, tr.Spec.Audiences) + tr.Status.ExpirationTimestamp = metav1.NewTime(time.Unix(1, 1)) + return true, tr, nil + })) + plug, tmpDir := newTestPlugin(t, client) + defer os.RemoveAll(tmpDir) + mounter, err := plug.NewMounter( + volume.NewSpecFromVolume(makeTestVol("test", testDriver)), + &api.Pod{ + ObjectMeta: meta.ObjectMeta{UID: testPodUID, Namespace: testns, Name: testPod}, + Spec: api.PodSpec{ + ServiceAccountName: testAccount, + }, + }, + volume.VolumeOptions{}, + ) + if err != nil { + t.Fatalf("Failed to create a csi mounter, err: %v", err) + } + + csiMounter := mounter.(*csiMountMgr) + csiMounter.csiClient = setupClient(t, false) + if err := csiMounter.SetUp(volume.MounterArgs{}); err != nil { + t.Fatalf("mounter.Setup failed: %v", err) + } + + pubs := csiMounter.csiClient.(*fakeCsiDriverClient).nodeClient.GetNodePublishedVolumes() + vol, ok := pubs[csiMounter.volumeID] + if !ok { + t.Error("csi server may not have received NodePublishVolume call") + } + if vol.Path != csiMounter.GetPath() { + t.Errorf("csi server expected path %s, got %s", csiMounter.GetPath(), vol.Path) + } + if diff := cmp.Diff(test.wantVolumeContext, vol.VolumeContext); diff != "" { + t.Errorf("podServiceAccountTokenAttrs() = diff (-want +got):\n%s", diff) + } + }) + } +} diff --git a/pkg/volume/csi/csi_plugin.go b/pkg/volume/csi/csi_plugin.go index 9fe48924d51..7fb89f688ba 100644 --- a/pkg/volume/csi/csi_plugin.go +++ b/pkg/volume/csi/csi_plugin.go @@ -27,6 +27,7 @@ import ( "k8s.io/klog/v2" + authenticationv1 "k8s.io/api/authentication/v1" api "k8s.io/api/core/v1" storage "k8s.io/api/storage/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" @@ -59,10 +60,11 @@ const ( ) type csiPlugin struct { - host volume.VolumeHost - blockEnabled bool - csiDriverLister storagelisters.CSIDriverLister - volumeAttachmentLister storagelisters.VolumeAttachmentLister + host volume.VolumeHost + blockEnabled bool + csiDriverLister storagelisters.CSIDriverLister + serviceAccountTokenGetter func(namespace, name string, tr *authenticationv1.TokenRequest) (*authenticationv1.TokenRequest, error) + volumeAttachmentLister storagelisters.VolumeAttachmentLister } // ProbeVolumePlugins returns implemented plugins @@ -205,6 +207,10 @@ func (p *csiPlugin) Init(host volume.VolumeHost) error { if p.csiDriverLister == nil { klog.Error(log("CSIDriverLister not found on KubeletVolumeHost")) } + p.serviceAccountTokenGetter = host.GetServiceAccountTokenFunc() + if p.serviceAccountTokenGetter == nil { + klog.Error(log("ServiceAccountTokenGetter not found on KubeletVolumeHost")) + } // We don't run the volumeAttachmentLister in the kubelet context p.volumeAttachmentLister = nil } @@ -334,8 +340,24 @@ func (p *csiPlugin) CanSupport(spec *volume.Spec) bool { return spec.PersistentVolume != nil && spec.PersistentVolume.Spec.CSI != nil } -func (p *csiPlugin) RequiresRemount() bool { - return false +func (p *csiPlugin) RequiresRemount(spec *volume.Spec) bool { + if !utilfeature.DefaultFeatureGate.Enabled(features.CSIServiceAccountToken) { + return false + } + if p.csiDriverLister == nil { + return false + } + driverName, err := GetCSIDriverName(spec) + if err != nil { + klog.V(5).Info(log("Failed to mark %q as republish required, err: %v", spec.Name(), err)) + return false + } + csiDriver, err := p.csiDriverLister.Get(driverName) + if err != nil { + klog.V(5).Info(log("Failed to mark %q as republish required, err: %v", spec.Name(), err)) + return false + } + return *csiDriver.Spec.RequiresRepublish } func (p *csiPlugin) NewMounter( diff --git a/pkg/volume/csi/csi_util.go b/pkg/volume/csi/csi_util.go index e15addfd1e9..05cf175daae 100644 --- a/pkg/volume/csi/csi_util.go +++ b/pkg/volume/csi/csi_util.go @@ -176,3 +176,20 @@ func getPVSourceFromSpec(spec *volume.Spec) (*api.CSIPersistentVolumeSource, err func GetCSIMounterPath(path string) string { return filepath.Join(path, "/mount") } + +// GetCSIDriverName returns the csi driver name +func GetCSIDriverName(spec *volume.Spec) (string, error) { + volSrc, pvSrc, err := getSourceFromSpec(spec) + if err != nil { + return "", err + } + + switch { + case volSrc != nil && utilfeature.DefaultFeatureGate.Enabled(features.CSIInlineVolume): + return volSrc.Driver, nil + case pvSrc != nil: + return pvSrc.Driver, nil + default: + return "", errors.New(log("volume source not found in volume.Spec")) + } +} diff --git a/pkg/volume/downwardapi/downwardapi.go b/pkg/volume/downwardapi/downwardapi.go index cc5e70aaa90..bf5ee6ff1e4 100644 --- a/pkg/volume/downwardapi/downwardapi.go +++ b/pkg/volume/downwardapi/downwardapi.go @@ -80,7 +80,7 @@ func (plugin *downwardAPIPlugin) CanSupport(spec *volume.Spec) bool { return spec.Volume != nil && spec.Volume.DownwardAPI != nil } -func (plugin *downwardAPIPlugin) RequiresRemount() bool { +func (plugin *downwardAPIPlugin) RequiresRemount(spec *volume.Spec) bool { return true } diff --git a/pkg/volume/emptydir/empty_dir.go b/pkg/volume/emptydir/empty_dir.go index f0115da99ae..c21160e8859 100644 --- a/pkg/volume/emptydir/empty_dir.go +++ b/pkg/volume/emptydir/empty_dir.go @@ -94,7 +94,7 @@ func (plugin *emptyDirPlugin) CanSupport(spec *volume.Spec) bool { return false } -func (plugin *emptyDirPlugin) RequiresRemount() bool { +func (plugin *emptyDirPlugin) RequiresRemount(spec *volume.Spec) bool { return false } diff --git a/pkg/volume/fc/fc.go b/pkg/volume/fc/fc.go index 5b1728ebd0d..23cb77f1274 100644 --- a/pkg/volume/fc/fc.go +++ b/pkg/volume/fc/fc.go @@ -86,7 +86,7 @@ func (plugin *fcPlugin) CanSupport(spec *volume.Spec) bool { return (spec.Volume != nil && spec.Volume.FC != nil) || (spec.PersistentVolume != nil && spec.PersistentVolume.Spec.FC != nil) } -func (plugin *fcPlugin) RequiresRemount() bool { +func (plugin *fcPlugin) RequiresRemount(spec *volume.Spec) bool { return false } diff --git a/pkg/volume/flexvolume/plugin.go b/pkg/volume/flexvolume/plugin.go index 961afc2a189..b3deeef6535 100644 --- a/pkg/volume/flexvolume/plugin.go +++ b/pkg/volume/flexvolume/plugin.go @@ -148,7 +148,7 @@ func (plugin *flexVolumePlugin) CanSupport(spec *volume.Spec) bool { } // RequiresRemount is part of the volume.VolumePlugin interface. -func (plugin *flexVolumePlugin) RequiresRemount() bool { +func (plugin *flexVolumePlugin) RequiresRemount(spec *volume.Spec) bool { return false } diff --git a/pkg/volume/flocker/flocker.go b/pkg/volume/flocker/flocker.go index 379d79dc3a9..e1c7f246b30 100644 --- a/pkg/volume/flocker/flocker.go +++ b/pkg/volume/flocker/flocker.go @@ -108,7 +108,7 @@ func (p *flockerPlugin) CanSupport(spec *volume.Spec) bool { (spec.Volume != nil && spec.Volume.Flocker != nil) } -func (p *flockerPlugin) RequiresRemount() bool { +func (p *flockerPlugin) RequiresRemount(spec *volume.Spec) bool { return false } diff --git a/pkg/volume/gcepd/gce_pd.go b/pkg/volume/gcepd/gce_pd.go index de992046ba1..c61ada63eb8 100644 --- a/pkg/volume/gcepd/gce_pd.go +++ b/pkg/volume/gcepd/gce_pd.go @@ -98,7 +98,7 @@ func (plugin *gcePersistentDiskPlugin) CanSupport(spec *volume.Spec) bool { (spec.Volume != nil && spec.Volume.GCEPersistentDisk != nil) } -func (plugin *gcePersistentDiskPlugin) RequiresRemount() bool { +func (plugin *gcePersistentDiskPlugin) RequiresRemount(spec *volume.Spec) bool { return false } diff --git a/pkg/volume/git_repo/git_repo.go b/pkg/volume/git_repo/git_repo.go index d16bca2cddd..ba23ceaf0b7 100644 --- a/pkg/volume/git_repo/git_repo.go +++ b/pkg/volume/git_repo/git_repo.go @@ -77,7 +77,7 @@ func (plugin *gitRepoPlugin) CanSupport(spec *volume.Spec) bool { return spec.Volume != nil && spec.Volume.GitRepo != nil } -func (plugin *gitRepoPlugin) RequiresRemount() bool { +func (plugin *gitRepoPlugin) RequiresRemount(spec *volume.Spec) bool { return false } diff --git a/pkg/volume/glusterfs/glusterfs.go b/pkg/volume/glusterfs/glusterfs.go index ce1e76408ba..8c66ff4efa4 100644 --- a/pkg/volume/glusterfs/glusterfs.go +++ b/pkg/volume/glusterfs/glusterfs.go @@ -120,7 +120,7 @@ func (plugin *glusterfsPlugin) CanSupport(spec *volume.Spec) bool { (spec.Volume != nil && spec.Volume.Glusterfs != nil) } -func (plugin *glusterfsPlugin) RequiresRemount() bool { +func (plugin *glusterfsPlugin) RequiresRemount(spec *volume.Spec) bool { return false } diff --git a/pkg/volume/hostpath/host_path.go b/pkg/volume/hostpath/host_path.go index 71a07876e69..ece27cf21e3 100644 --- a/pkg/volume/hostpath/host_path.go +++ b/pkg/volume/hostpath/host_path.go @@ -85,7 +85,7 @@ func (plugin *hostPathPlugin) CanSupport(spec *volume.Spec) bool { (spec.Volume != nil && spec.Volume.HostPath != nil) } -func (plugin *hostPathPlugin) RequiresRemount() bool { +func (plugin *hostPathPlugin) RequiresRemount(spec *volume.Spec) bool { return false } diff --git a/pkg/volume/iscsi/iscsi.go b/pkg/volume/iscsi/iscsi.go index 150a4ef587f..645a8834033 100644 --- a/pkg/volume/iscsi/iscsi.go +++ b/pkg/volume/iscsi/iscsi.go @@ -79,7 +79,7 @@ func (plugin *iscsiPlugin) CanSupport(spec *volume.Spec) bool { return (spec.Volume != nil && spec.Volume.ISCSI != nil) || (spec.PersistentVolume != nil && spec.PersistentVolume.Spec.ISCSI != nil) } -func (plugin *iscsiPlugin) RequiresRemount() bool { +func (plugin *iscsiPlugin) RequiresRemount(spec *volume.Spec) bool { return false } diff --git a/pkg/volume/local/local.go b/pkg/volume/local/local.go index 065318b4bab..81a2f9424c8 100644 --- a/pkg/volume/local/local.go +++ b/pkg/volume/local/local.go @@ -83,7 +83,7 @@ func (plugin *localVolumePlugin) CanSupport(spec *volume.Spec) bool { return (spec.PersistentVolume != nil && spec.PersistentVolume.Spec.Local != nil) } -func (plugin *localVolumePlugin) RequiresRemount() bool { +func (plugin *localVolumePlugin) RequiresRemount(spec *volume.Spec) bool { return false } diff --git a/pkg/volume/nfs/nfs.go b/pkg/volume/nfs/nfs.go index 38d5bda1cc5..34f838a8276 100644 --- a/pkg/volume/nfs/nfs.go +++ b/pkg/volume/nfs/nfs.go @@ -90,7 +90,7 @@ func (plugin *nfsPlugin) CanSupport(spec *volume.Spec) bool { (spec.Volume != nil && spec.Volume.NFS != nil) } -func (plugin *nfsPlugin) RequiresRemount() bool { +func (plugin *nfsPlugin) RequiresRemount(spec *volume.Spec) bool { return false } diff --git a/pkg/volume/noop_expandable_plugin.go b/pkg/volume/noop_expandable_plugin.go index 3d3d5e1dfd7..fac27426301 100644 --- a/pkg/volume/noop_expandable_plugin.go +++ b/pkg/volume/noop_expandable_plugin.go @@ -17,7 +17,7 @@ limitations under the License. package volume import ( - "k8s.io/api/core/v1" + v1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/resource" "k8s.io/apimachinery/pkg/types" ) @@ -48,7 +48,7 @@ func (n *noopExpandableVolumePluginInstance) CanSupport(spec *Spec) bool { return true } -func (n *noopExpandableVolumePluginInstance) RequiresRemount() bool { +func (n *noopExpandableVolumePluginInstance) RequiresRemount(spec *Spec) bool { return false } diff --git a/pkg/volume/plugins.go b/pkg/volume/plugins.go index 4c01236282f..b3fc926d257 100644 --- a/pkg/volume/plugins.go +++ b/pkg/volume/plugins.go @@ -163,7 +163,7 @@ type VolumePlugin interface { // RequiresRemount returns true if this plugin requires mount calls to be // reexecuted. Atomically updating volumes, like Downward API, depend on // this to update the contents of the volume. - RequiresRemount() bool + RequiresRemount(spec *Spec) bool // NewMounter creates a new volume.Mounter from an API specification. // Ownership of the spec pointer in *not* transferred. @@ -1027,6 +1027,7 @@ func (pm *VolumePluginMgr) Run(stopCh <-chan struct{}) { // start informer for CSIDriver informerFactory := kletHost.GetInformerFactory() informerFactory.Start(stopCh) + informerFactory.WaitForCacheSync(stopCh) } } diff --git a/pkg/volume/plugins_test.go b/pkg/volume/plugins_test.go index 7471c00cf71..012ca83c1f2 100644 --- a/pkg/volume/plugins_test.go +++ b/pkg/volume/plugins_test.go @@ -19,7 +19,7 @@ package volume import ( "testing" - "k8s.io/api/core/v1" + v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" ) @@ -75,7 +75,7 @@ func (plugin *testPlugins) CanSupport(spec *Spec) bool { return true } -func (plugin *testPlugins) RequiresRemount() bool { +func (plugin *testPlugins) RequiresRemount(spec *Spec) bool { return false } diff --git a/pkg/volume/portworx/portworx.go b/pkg/volume/portworx/portworx.go index cc0874310db..9d347ba762e 100644 --- a/pkg/volume/portworx/portworx.go +++ b/pkg/volume/portworx/portworx.go @@ -96,7 +96,7 @@ func (plugin *portworxVolumePlugin) CanSupport(spec *volume.Spec) bool { (spec.Volume != nil && spec.Volume.PortworxVolume != nil) } -func (plugin *portworxVolumePlugin) RequiresRemount() bool { +func (plugin *portworxVolumePlugin) RequiresRemount(spec *volume.Spec) bool { return false } diff --git a/pkg/volume/projected/projected.go b/pkg/volume/projected/projected.go index db43cb9d883..443c6f8eb5d 100644 --- a/pkg/volume/projected/projected.go +++ b/pkg/volume/projected/projected.go @@ -93,7 +93,7 @@ func (plugin *projectedPlugin) CanSupport(spec *volume.Spec) bool { return spec.Volume != nil && spec.Volume.Projected != nil } -func (plugin *projectedPlugin) RequiresRemount() bool { +func (plugin *projectedPlugin) RequiresRemount(spec *volume.Spec) bool { return true } diff --git a/pkg/volume/quobyte/quobyte.go b/pkg/volume/quobyte/quobyte.go index 60f8f500c8c..8bc139245b9 100644 --- a/pkg/volume/quobyte/quobyte.go +++ b/pkg/volume/quobyte/quobyte.go @@ -116,7 +116,7 @@ func (plugin *quobytePlugin) CanSupport(spec *volume.Spec) bool { return false } -func (plugin *quobytePlugin) RequiresRemount() bool { +func (plugin *quobytePlugin) RequiresRemount(spec *volume.Spec) bool { return false } diff --git a/pkg/volume/rbd/rbd.go b/pkg/volume/rbd/rbd.go index 387b92e1691..e45385d6e96 100644 --- a/pkg/volume/rbd/rbd.go +++ b/pkg/volume/rbd/rbd.go @@ -107,7 +107,7 @@ func (plugin *rbdPlugin) CanSupport(spec *volume.Spec) bool { return (spec.Volume != nil && spec.Volume.RBD != nil) || (spec.PersistentVolume != nil && spec.PersistentVolume.Spec.RBD != nil) } -func (plugin *rbdPlugin) RequiresRemount() bool { +func (plugin *rbdPlugin) RequiresRemount(spec *volume.Spec) bool { return false } diff --git a/pkg/volume/rbd/rbd_test.go b/pkg/volume/rbd/rbd_test.go index 726fb5842b8..998a78ead5a 100644 --- a/pkg/volume/rbd/rbd_test.go +++ b/pkg/volume/rbd/rbd_test.go @@ -679,7 +679,7 @@ func TestRequiresRemount(t *testing.T) { plugMgr := volume.VolumePluginMgr{} plugMgr.InitPlugins(ProbeVolumePlugins(), nil /* prober */, volumetest.NewFakeVolumeHost(t, tmpDir, nil, nil)) plug, _ := plugMgr.FindPluginByName("kubernetes.io/rbd") - has := plug.RequiresRemount() + has := plug.RequiresRemount(nil) if has { t.Errorf("Exepcted RequiresRemount to be false, got %t", has) } diff --git a/pkg/volume/scaleio/sio_plugin.go b/pkg/volume/scaleio/sio_plugin.go index ec1db929c06..4d0312232bd 100644 --- a/pkg/volume/scaleio/sio_plugin.go +++ b/pkg/volume/scaleio/sio_plugin.go @@ -72,7 +72,7 @@ func (p *sioPlugin) CanSupport(spec *volume.Spec) bool { (spec.Volume != nil && spec.Volume.ScaleIO != nil) } -func (p *sioPlugin) RequiresRemount() bool { +func (p *sioPlugin) RequiresRemount(spec *volume.Spec) bool { return false } diff --git a/pkg/volume/secret/secret.go b/pkg/volume/secret/secret.go index a514e7acf74..3c3ac552546 100644 --- a/pkg/volume/secret/secret.go +++ b/pkg/volume/secret/secret.go @@ -81,7 +81,7 @@ func (plugin *secretPlugin) CanSupport(spec *volume.Spec) bool { return spec.Volume != nil && spec.Volume.Secret != nil } -func (plugin *secretPlugin) RequiresRemount() bool { +func (plugin *secretPlugin) RequiresRemount(spec *volume.Spec) bool { return true } diff --git a/pkg/volume/storageos/storageos.go b/pkg/volume/storageos/storageos.go index cee399f50d4..9d742df7d1d 100644 --- a/pkg/volume/storageos/storageos.go +++ b/pkg/volume/storageos/storageos.go @@ -92,7 +92,7 @@ func (plugin *storageosPlugin) CanSupport(spec *volume.Spec) bool { (spec.Volume != nil && spec.Volume.StorageOS != nil) } -func (plugin *storageosPlugin) RequiresRemount() bool { +func (plugin *storageosPlugin) RequiresRemount(spec *volume.Spec) bool { return false } diff --git a/pkg/volume/testing/testing.go b/pkg/volume/testing/testing.go index ba3324490fa..2b466cc4367 100644 --- a/pkg/volume/testing/testing.go +++ b/pkg/volume/testing/testing.go @@ -47,6 +47,7 @@ import ( utiltesting "k8s.io/client-go/util/testing" cloudprovider "k8s.io/cloud-provider" proxyutil "k8s.io/kubernetes/pkg/proxy/util" + "k8s.io/kubernetes/pkg/volume" . "k8s.io/kubernetes/pkg/volume" "k8s.io/kubernetes/pkg/volume/util" "k8s.io/kubernetes/pkg/volume/util/hostutil" @@ -467,7 +468,7 @@ func (plugin *FakeVolumePlugin) CanSupport(spec *Spec) bool { return true } -func (plugin *FakeVolumePlugin) RequiresRemount() bool { +func (plugin *FakeVolumePlugin) RequiresRemount(spec *volume.Spec) bool { return plugin.SupportsRemount } @@ -724,8 +725,8 @@ func (f *FakeBasicVolumePlugin) NewUnmounter(volName string, podUID types.UID) ( return f.Plugin.NewUnmounter(volName, podUID) } -func (f *FakeBasicVolumePlugin) RequiresRemount() bool { - return f.Plugin.RequiresRemount() +func (f *FakeBasicVolumePlugin) RequiresRemount(spec *volume.Spec) bool { + return f.Plugin.RequiresRemount(spec) } func (f *FakeBasicVolumePlugin) SupportsBulkVolumeVerification() bool { @@ -801,7 +802,7 @@ func (plugin *FakeFileVolumePlugin) CanSupport(spec *Spec) bool { return true } -func (plugin *FakeFileVolumePlugin) RequiresRemount() bool { +func (plugin *FakeFileVolumePlugin) RequiresRemount(spec *volume.Spec) bool { return false } diff --git a/pkg/volume/vsphere_volume/vsphere_volume.go b/pkg/volume/vsphere_volume/vsphere_volume.go index 00d9004b45e..e0fba03aad8 100644 --- a/pkg/volume/vsphere_volume/vsphere_volume.go +++ b/pkg/volume/vsphere_volume/vsphere_volume.go @@ -92,7 +92,7 @@ func (plugin *vsphereVolumePlugin) CanSupport(spec *volume.Spec) bool { (spec.Volume != nil && spec.Volume.VsphereVolume != nil) } -func (plugin *vsphereVolumePlugin) RequiresRemount() bool { +func (plugin *vsphereVolumePlugin) RequiresRemount(spec *volume.Spec) bool { return false } diff --git a/staging/src/k8s.io/api/storage/v1/generated.pb.go b/staging/src/k8s.io/api/storage/v1/generated.pb.go index 2c7088c3898..f6b97e013c5 100644 --- a/staging/src/k8s.io/api/storage/v1/generated.pb.go +++ b/staging/src/k8s.io/api/storage/v1/generated.pb.go @@ -298,10 +298,38 @@ func (m *StorageClassList) XXX_DiscardUnknown() { var xxx_messageInfo_StorageClassList proto.InternalMessageInfo +func (m *TokenRequest) Reset() { *m = TokenRequest{} } +func (*TokenRequest) ProtoMessage() {} +func (*TokenRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_3b530c1983504d8d, []int{9} +} +func (m *TokenRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *TokenRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil +} +func (m *TokenRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_TokenRequest.Merge(m, src) +} +func (m *TokenRequest) XXX_Size() int { + return m.Size() +} +func (m *TokenRequest) XXX_DiscardUnknown() { + xxx_messageInfo_TokenRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_TokenRequest proto.InternalMessageInfo + func (m *VolumeAttachment) Reset() { *m = VolumeAttachment{} } func (*VolumeAttachment) ProtoMessage() {} func (*VolumeAttachment) Descriptor() ([]byte, []int) { - return fileDescriptor_3b530c1983504d8d, []int{9} + return fileDescriptor_3b530c1983504d8d, []int{10} } func (m *VolumeAttachment) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -329,7 +357,7 @@ var xxx_messageInfo_VolumeAttachment proto.InternalMessageInfo func (m *VolumeAttachmentList) Reset() { *m = VolumeAttachmentList{} } func (*VolumeAttachmentList) ProtoMessage() {} func (*VolumeAttachmentList) Descriptor() ([]byte, []int) { - return fileDescriptor_3b530c1983504d8d, []int{10} + return fileDescriptor_3b530c1983504d8d, []int{11} } func (m *VolumeAttachmentList) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -357,7 +385,7 @@ var xxx_messageInfo_VolumeAttachmentList proto.InternalMessageInfo func (m *VolumeAttachmentSource) Reset() { *m = VolumeAttachmentSource{} } func (*VolumeAttachmentSource) ProtoMessage() {} func (*VolumeAttachmentSource) Descriptor() ([]byte, []int) { - return fileDescriptor_3b530c1983504d8d, []int{11} + return fileDescriptor_3b530c1983504d8d, []int{12} } func (m *VolumeAttachmentSource) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -385,7 +413,7 @@ var xxx_messageInfo_VolumeAttachmentSource proto.InternalMessageInfo func (m *VolumeAttachmentSpec) Reset() { *m = VolumeAttachmentSpec{} } func (*VolumeAttachmentSpec) ProtoMessage() {} func (*VolumeAttachmentSpec) Descriptor() ([]byte, []int) { - return fileDescriptor_3b530c1983504d8d, []int{12} + return fileDescriptor_3b530c1983504d8d, []int{13} } func (m *VolumeAttachmentSpec) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -413,7 +441,7 @@ var xxx_messageInfo_VolumeAttachmentSpec proto.InternalMessageInfo func (m *VolumeAttachmentStatus) Reset() { *m = VolumeAttachmentStatus{} } func (*VolumeAttachmentStatus) ProtoMessage() {} func (*VolumeAttachmentStatus) Descriptor() ([]byte, []int) { - return fileDescriptor_3b530c1983504d8d, []int{13} + return fileDescriptor_3b530c1983504d8d, []int{14} } func (m *VolumeAttachmentStatus) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -441,7 +469,7 @@ var xxx_messageInfo_VolumeAttachmentStatus proto.InternalMessageInfo func (m *VolumeError) Reset() { *m = VolumeError{} } func (*VolumeError) ProtoMessage() {} func (*VolumeError) Descriptor() ([]byte, []int) { - return fileDescriptor_3b530c1983504d8d, []int{14} + return fileDescriptor_3b530c1983504d8d, []int{15} } func (m *VolumeError) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -469,7 +497,7 @@ var xxx_messageInfo_VolumeError proto.InternalMessageInfo func (m *VolumeNodeResources) Reset() { *m = VolumeNodeResources{} } func (*VolumeNodeResources) ProtoMessage() {} func (*VolumeNodeResources) Descriptor() ([]byte, []int) { - return fileDescriptor_3b530c1983504d8d, []int{15} + return fileDescriptor_3b530c1983504d8d, []int{16} } func (m *VolumeNodeResources) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -505,6 +533,7 @@ func init() { proto.RegisterType((*StorageClass)(nil), "k8s.io.api.storage.v1.StorageClass") proto.RegisterMapType((map[string]string)(nil), "k8s.io.api.storage.v1.StorageClass.ParametersEntry") proto.RegisterType((*StorageClassList)(nil), "k8s.io.api.storage.v1.StorageClassList") + proto.RegisterType((*TokenRequest)(nil), "k8s.io.api.storage.v1.TokenRequest") proto.RegisterType((*VolumeAttachment)(nil), "k8s.io.api.storage.v1.VolumeAttachment") proto.RegisterType((*VolumeAttachmentList)(nil), "k8s.io.api.storage.v1.VolumeAttachmentList") proto.RegisterType((*VolumeAttachmentSource)(nil), "k8s.io.api.storage.v1.VolumeAttachmentSource") @@ -520,95 +549,101 @@ func init() { } var fileDescriptor_3b530c1983504d8d = []byte{ - // 1395 bytes of a gzipped FileDescriptorProto + // 1500 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x57, 0xcf, 0x6f, 0x1b, 0xc5, - 0x17, 0xcf, 0xc6, 0x76, 0x7e, 0x8c, 0x93, 0xc6, 0x99, 0xe4, 0xfb, 0xfd, 0xfa, 0x9b, 0x83, 0x37, - 0x5a, 0x2a, 0x08, 0x85, 0xae, 0x9b, 0x52, 0xaa, 0xaa, 0x52, 0x91, 0xe2, 0xc4, 0xa5, 0x11, 0x71, - 0x12, 0x8d, 0x4b, 0x85, 0x10, 0x20, 0x26, 0xbb, 0x13, 0x67, 0x1b, 0xef, 0xce, 0x76, 0x77, 0x6c, - 0xf0, 0x8d, 0x13, 0x37, 0x24, 0xb8, 0xf2, 0x57, 0x80, 0x04, 0x17, 0x8e, 0x9c, 0xca, 0xad, 0xe2, - 0xd4, 0xd3, 0x8a, 0x2e, 0x67, 0xb8, 0x71, 0xc9, 0x09, 0xcd, 0xec, 0xd8, 0xfb, 0xc3, 0xeb, 0x34, - 0xbd, 0xe4, 0xe6, 0x79, 0xef, 0x7d, 0x3e, 0xef, 0xbd, 0x79, 0x3f, 0x66, 0x0d, 0xde, 0x3b, 0xbd, - 0xe3, 0xeb, 0x16, 0xad, 0x9f, 0xf6, 0x8e, 0x88, 0xe7, 0x10, 0x46, 0xfc, 0x7a, 0x9f, 0x38, 0x26, - 0xf5, 0xea, 0x52, 0x81, 0x5d, 0xab, 0xee, 0x33, 0xea, 0xe1, 0x0e, 0xa9, 0xf7, 0x37, 0xeb, 0x1d, - 0xe2, 0x10, 0x0f, 0x33, 0x62, 0xea, 0xae, 0x47, 0x19, 0x85, 0xff, 0x89, 0xcc, 0x74, 0xec, 0x5a, - 0xba, 0x34, 0xd3, 0xfb, 0x9b, 0x6b, 0xd7, 0x3b, 0x16, 0x3b, 0xe9, 0x1d, 0xe9, 0x06, 0xb5, 0xeb, - 0x1d, 0xda, 0xa1, 0x75, 0x61, 0x7d, 0xd4, 0x3b, 0x16, 0x27, 0x71, 0x10, 0xbf, 0x22, 0x96, 0x35, - 0x2d, 0xe1, 0xcc, 0xa0, 0x5e, 0x9e, 0xa7, 0xb5, 0x5b, 0xb1, 0x8d, 0x8d, 0x8d, 0x13, 0xcb, 0x21, - 0xde, 0xa0, 0xee, 0x9e, 0x76, 0xb8, 0xc0, 0xaf, 0xdb, 0x84, 0xe1, 0x3c, 0x54, 0x7d, 0x12, 0xca, - 0xeb, 0x39, 0xcc, 0xb2, 0xc9, 0x18, 0xe0, 0xf6, 0xcb, 0x00, 0xbe, 0x71, 0x42, 0x6c, 0x9c, 0xc5, - 0x69, 0x3f, 0x2b, 0x60, 0x7e, 0xbb, 0xbd, 0xbb, 0xe3, 0x59, 0x7d, 0xe2, 0xc1, 0xcf, 0xc1, 0x1c, - 0x8f, 0xc8, 0xc4, 0x0c, 0x57, 0x95, 0x75, 0x65, 0xa3, 0x7c, 0xf3, 0x86, 0x1e, 0xdf, 0xd4, 0x88, - 0x58, 0x77, 0x4f, 0x3b, 0x5c, 0xe0, 0xeb, 0xdc, 0x5a, 0xef, 0x6f, 0xea, 0x07, 0x47, 0x8f, 0x89, - 0xc1, 0x5a, 0x84, 0xe1, 0x06, 0x7c, 0x1a, 0xa8, 0x53, 0x61, 0xa0, 0x82, 0x58, 0x86, 0x46, 0xac, - 0xf0, 0x3e, 0x28, 0xfa, 0x2e, 0x31, 0xaa, 0xd3, 0x82, 0xfd, 0xaa, 0x9e, 0x5b, 0x07, 0x7d, 0x14, - 0x51, 0xdb, 0x25, 0x46, 0x63, 0x41, 0x32, 0x16, 0xf9, 0x09, 0x09, 0xbc, 0xf6, 0x93, 0x02, 0x16, - 0x47, 0x56, 0x7b, 0x96, 0xcf, 0xe0, 0x27, 0x63, 0xb1, 0xeb, 0x17, 0x8b, 0x9d, 0xa3, 0x45, 0xe4, - 0x15, 0xe9, 0x67, 0x6e, 0x28, 0x49, 0xc4, 0xdd, 0x04, 0x25, 0x8b, 0x11, 0xdb, 0xaf, 0x4e, 0xaf, - 0x17, 0x36, 0xca, 0x37, 0xd7, 0x5f, 0x16, 0x78, 0x63, 0x51, 0x92, 0x95, 0x76, 0x39, 0x0c, 0x45, - 0x68, 0xed, 0x9f, 0xe9, 0x44, 0xd8, 0x3c, 0x1d, 0x78, 0x17, 0x5c, 0xc1, 0x8c, 0x61, 0xe3, 0x04, - 0x91, 0x27, 0x3d, 0xcb, 0x23, 0xa6, 0x08, 0x7e, 0xae, 0x01, 0xc3, 0x40, 0xbd, 0xb2, 0x95, 0xd2, - 0xa0, 0x8c, 0x25, 0xc7, 0xba, 0xd4, 0xdc, 0x75, 0x8e, 0xe9, 0x81, 0xd3, 0xa2, 0x3d, 0x87, 0x89, - 0x6b, 0x95, 0xd8, 0xc3, 0x94, 0x06, 0x65, 0x2c, 0xa1, 0x01, 0x56, 0xfb, 0xb4, 0xdb, 0xb3, 0xc9, - 0x9e, 0x75, 0x4c, 0x8c, 0x81, 0xd1, 0x25, 0x2d, 0x6a, 0x12, 0xbf, 0x5a, 0x58, 0x2f, 0x6c, 0xcc, - 0x37, 0xea, 0x61, 0xa0, 0xae, 0x3e, 0xca, 0xd1, 0x9f, 0x05, 0xea, 0x4a, 0x8e, 0x1c, 0xe5, 0x92, - 0xc1, 0x7b, 0x60, 0x49, 0x5e, 0xce, 0x36, 0x76, 0xb1, 0x61, 0xb1, 0x41, 0xb5, 0x28, 0x22, 0x5c, - 0x09, 0x03, 0x75, 0xa9, 0x9d, 0x56, 0xa1, 0xac, 0x2d, 0x7c, 0x00, 0x16, 0x8f, 0xfd, 0xf7, 0x3d, - 0xda, 0x73, 0x0f, 0x69, 0xd7, 0x32, 0x06, 0xd5, 0xd2, 0xba, 0xb2, 0x31, 0xdf, 0xd0, 0xc2, 0x40, - 0x5d, 0xbc, 0xdf, 0x4e, 0x28, 0xce, 0xb2, 0x02, 0x94, 0x06, 0x6a, 0x3f, 0x2a, 0x60, 0x76, 0xbb, - 0xbd, 0xbb, 0x4f, 0x4d, 0x72, 0x09, 0x4d, 0xbe, 0x93, 0x6a, 0x72, 0x6d, 0x72, 0xaf, 0xf0, 0x78, - 0x26, 0xb6, 0xf8, 0xdf, 0x51, 0x8b, 0x73, 0x1b, 0x39, 0x9e, 0xeb, 0xa0, 0xe8, 0x60, 0x9b, 0x88, - 0xa8, 0xe7, 0x63, 0xcc, 0x3e, 0xb6, 0x09, 0x12, 0x1a, 0xf8, 0x3a, 0x98, 0x71, 0xa8, 0x49, 0x76, - 0x77, 0x84, 0xef, 0xf9, 0xc6, 0x15, 0x69, 0x33, 0xb3, 0x2f, 0xa4, 0x48, 0x6a, 0xe1, 0x2d, 0xb0, - 0xc0, 0xa8, 0x4b, 0xbb, 0xb4, 0x33, 0xf8, 0x80, 0x0c, 0x86, 0x55, 0xaf, 0x84, 0x81, 0xba, 0xf0, - 0x30, 0x21, 0x47, 0x29, 0x2b, 0xf8, 0x29, 0x28, 0xe3, 0x6e, 0x97, 0x1a, 0x98, 0xe1, 0xa3, 0x2e, - 0x11, 0xa5, 0x2c, 0xdf, 0xbc, 0x36, 0x21, 0xbd, 0xa8, 0x4b, 0xb8, 0x5f, 0x44, 0x7c, 0xda, 0xf3, - 0x0c, 0xe2, 0x37, 0x96, 0xc2, 0x40, 0x2d, 0x6f, 0xc5, 0x14, 0x28, 0xc9, 0xa7, 0xfd, 0xa0, 0x80, - 0xb2, 0x4c, 0xf8, 0x12, 0x26, 0x7a, 0x3b, 0x3d, 0xd1, 0xb5, 0xf3, 0xab, 0x34, 0x61, 0x9e, 0x3f, - 0x1b, 0x45, 0x2c, 0x86, 0xf9, 0x00, 0xcc, 0x9a, 0xa2, 0x54, 0x7e, 0x55, 0x11, 0xac, 0x57, 0xcf, - 0x67, 0x95, 0xbb, 0x62, 0x49, 0x72, 0xcf, 0x46, 0x67, 0x1f, 0x0d, 0x59, 0xb4, 0x6f, 0x66, 0xc0, - 0xc2, 0x70, 0x4c, 0xba, 0xd8, 0xf7, 0x2f, 0xa1, 0x79, 0xdf, 0x05, 0x65, 0xd7, 0xa3, 0x7d, 0xcb, - 0xb7, 0xa8, 0x43, 0x3c, 0xd9, 0x47, 0x2b, 0x12, 0x52, 0x3e, 0x8c, 0x55, 0x28, 0x69, 0x07, 0x3b, - 0x00, 0xb8, 0xd8, 0xc3, 0x36, 0x61, 0x3c, 0xfb, 0x82, 0xc8, 0xfe, 0x9d, 0x09, 0xd9, 0x27, 0x33, - 0xd2, 0x0f, 0x47, 0xa8, 0xa6, 0xc3, 0xbc, 0x41, 0x1c, 0x5d, 0xac, 0x40, 0x09, 0x6a, 0x78, 0x0a, - 0x16, 0x3d, 0x62, 0x74, 0xb1, 0x65, 0xcb, 0xa5, 0x50, 0x14, 0x11, 0x36, 0xf9, 0x52, 0x40, 0x49, - 0xc5, 0x59, 0xa0, 0xde, 0x18, 0x7f, 0xa0, 0xf5, 0x43, 0xe2, 0xf9, 0x96, 0xcf, 0x88, 0xc3, 0xa2, - 0x0e, 0x4d, 0x61, 0x50, 0x9a, 0x9b, 0xcf, 0x89, 0xcd, 0xd7, 0xe5, 0x81, 0xcb, 0x2c, 0xea, 0xf8, - 0xd5, 0x52, 0x3c, 0x27, 0xad, 0x84, 0x1c, 0xa5, 0xac, 0xe0, 0x1e, 0x58, 0xe5, 0x7d, 0xfd, 0x45, - 0xe4, 0xa0, 0xf9, 0xa5, 0x8b, 0x1d, 0x7e, 0x4b, 0xd5, 0x19, 0xb1, 0xfb, 0xaa, 0x7c, 0xb7, 0x6e, - 0xe5, 0xe8, 0x51, 0x2e, 0x0a, 0x7e, 0x04, 0x96, 0xa3, 0xe5, 0xda, 0xb0, 0x1c, 0xd3, 0x72, 0x3a, - 0x7c, 0xb5, 0x56, 0x67, 0x45, 0xd2, 0xd7, 0xc2, 0x40, 0x5d, 0x7e, 0x94, 0x55, 0x9e, 0xe5, 0x09, - 0xd1, 0x38, 0x09, 0x7c, 0x02, 0x96, 0x85, 0x47, 0x62, 0xca, 0xa1, 0xb7, 0x88, 0x5f, 0x9d, 0x13, - 0xa5, 0xdb, 0x48, 0x96, 0x8e, 0x5f, 0x1d, 0xaf, 0xdb, 0x70, 0x35, 0xb4, 0x49, 0x97, 0x18, 0x8c, - 0x7a, 0x0f, 0x89, 0x67, 0x37, 0xfe, 0x2f, 0xeb, 0xb5, 0xbc, 0x95, 0xa5, 0x42, 0xe3, 0xec, 0x6b, - 0xf7, 0xc0, 0x52, 0xa6, 0xe0, 0xb0, 0x02, 0x0a, 0xa7, 0x64, 0x10, 0x2d, 0x35, 0xc4, 0x7f, 0xc2, - 0x55, 0x50, 0xea, 0xe3, 0x6e, 0x8f, 0x44, 0xcd, 0x87, 0xa2, 0xc3, 0xdd, 0xe9, 0x3b, 0x8a, 0xf6, - 0x8b, 0x02, 0x2a, 0xc9, 0xee, 0xb9, 0x84, 0x3d, 0xf1, 0x20, 0xbd, 0x27, 0x5e, 0xbb, 0x40, 0x4f, - 0x4f, 0x58, 0x16, 0xdf, 0x4f, 0x83, 0x4a, 0x54, 0x97, 0xe8, 0x5d, 0xb7, 0x89, 0xc3, 0x2e, 0x61, - 0xa0, 0x5b, 0xa9, 0xd7, 0xe8, 0xad, 0x73, 0xd7, 0x75, 0x1c, 0xd8, 0xa4, 0x67, 0x09, 0x7e, 0x08, - 0x66, 0x7c, 0x86, 0x59, 0x8f, 0x0f, 0x39, 0x27, 0xbc, 0x7e, 0x51, 0x42, 0x01, 0x8a, 0x5f, 0xa4, - 0xe8, 0x8c, 0x24, 0x99, 0xf6, 0xab, 0x02, 0x56, 0xb3, 0x90, 0x4b, 0xa8, 0xee, 0x5e, 0xba, 0xba, - 0x6f, 0x5c, 0x30, 0x99, 0x09, 0x15, 0xfe, 0x5d, 0x01, 0xff, 0x1d, 0xcb, 0x5b, 0xbc, 0x7d, 0x7c, - 0x27, 0xb8, 0x99, 0xcd, 0xb3, 0x1f, 0xbf, 0xe5, 0x62, 0x27, 0x1c, 0xe6, 0xe8, 0x51, 0x2e, 0x0a, - 0x3e, 0x06, 0x15, 0xcb, 0xe9, 0x5a, 0x0e, 0x89, 0x64, 0xed, 0xb8, 0xbe, 0xb9, 0x83, 0x9b, 0x65, - 0x16, 0xc5, 0x5d, 0x0d, 0x03, 0xb5, 0xb2, 0x9b, 0x61, 0x41, 0x63, 0xbc, 0xda, 0x6f, 0x39, 0x95, - 0x11, 0xaf, 0xdd, 0xdb, 0x60, 0x2e, 0xfa, 0x20, 0x25, 0x9e, 0x4c, 0x63, 0x74, 0xd3, 0x5b, 0x52, - 0x8e, 0x46, 0x16, 0xa2, 0x6f, 0xc4, 0x55, 0xc8, 0x40, 0x2f, 0xdc, 0x37, 0x02, 0x94, 0xe8, 0x1b, - 0x71, 0x46, 0x92, 0x8c, 0x07, 0xc1, 0xbf, 0x69, 0xc4, 0x5d, 0x16, 0xd2, 0x41, 0xec, 0x4b, 0x39, - 0x1a, 0x59, 0x68, 0x7f, 0x15, 0x72, 0x0a, 0x24, 0x1a, 0x30, 0x91, 0xcd, 0xf0, 0x13, 0x3c, 0x9b, - 0x8d, 0x39, 0xca, 0xc6, 0x84, 0xdf, 0x29, 0x00, 0xe2, 0x11, 0x45, 0x6b, 0xd8, 0xa0, 0x51, 0x17, - 0x35, 0x5f, 0x69, 0x24, 0xf4, 0xad, 0x31, 0x9e, 0xe8, 0x25, 0x5c, 0x93, 0xfe, 0xe1, 0xb8, 0x01, - 0xca, 0x71, 0x0e, 0x4d, 0x50, 0x8e, 0xa4, 0x4d, 0xcf, 0xa3, 0x9e, 0x1c, 0x4f, 0xed, 0xdc, 0x58, - 0x84, 0x65, 0xa3, 0x26, 0x3e, 0xcb, 0x62, 0xe8, 0x59, 0xa0, 0x96, 0x13, 0x7a, 0x94, 0xa4, 0xe5, - 0x5e, 0x4c, 0x12, 0x7b, 0x29, 0xbe, 0x9a, 0x97, 0x1d, 0x32, 0xd9, 0x4b, 0x82, 0x76, 0xad, 0x09, - 0xfe, 0x37, 0xe1, 0x5a, 0x5e, 0xe9, 0xbd, 0xf8, 0x5a, 0x01, 0x49, 0x1f, 0x70, 0x0f, 0x14, 0xf9, - 0xbf, 0x61, 0xb9, 0x48, 0xae, 0x5d, 0x6c, 0x91, 0x3c, 0xb4, 0x6c, 0x12, 0xaf, 0x42, 0x7e, 0x42, - 0x82, 0x05, 0xbe, 0x09, 0x66, 0x6d, 0xe2, 0xfb, 0xb8, 0x23, 0x3d, 0xc7, 0x1f, 0x72, 0xad, 0x48, - 0x8c, 0x86, 0x7a, 0xed, 0x36, 0x58, 0xc9, 0xf9, 0x20, 0x86, 0x2a, 0x28, 0x19, 0xe2, 0x8f, 0x1b, - 0x0f, 0xa8, 0xd4, 0x98, 0xe7, 0x1b, 0x65, 0x5b, 0xfc, 0x5f, 0x8b, 0xe4, 0x8d, 0x8d, 0xa7, 0x2f, - 0x6a, 0x53, 0xcf, 0x5e, 0xd4, 0xa6, 0x9e, 0xbf, 0xa8, 0x4d, 0x7d, 0x15, 0xd6, 0x94, 0xa7, 0x61, - 0x4d, 0x79, 0x16, 0xd6, 0x94, 0xe7, 0x61, 0x4d, 0xf9, 0x23, 0xac, 0x29, 0xdf, 0xfe, 0x59, 0x9b, - 0xfa, 0x78, 0xba, 0xbf, 0xf9, 0x6f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x9e, 0x83, 0x24, 0x44, 0x13, - 0x11, 0x00, 0x00, + 0x17, 0xcf, 0xc6, 0xce, 0xaf, 0x71, 0xd2, 0x24, 0x93, 0xf4, 0xfb, 0x35, 0x39, 0xd8, 0xd1, 0xb6, + 0x82, 0x50, 0xe8, 0xba, 0x29, 0xa5, 0xaa, 0x2a, 0x15, 0x29, 0x9b, 0xb8, 0x34, 0x22, 0xbf, 0x34, + 0x0e, 0x15, 0x42, 0x80, 0x3a, 0xd9, 0x9d, 0x38, 0x5b, 0x7b, 0x77, 0xb6, 0x3b, 0x63, 0x53, 0xdf, + 0xe0, 0xc2, 0x0d, 0x09, 0xae, 0x88, 0x3f, 0x02, 0x24, 0xb8, 0x70, 0xe4, 0x54, 0x6e, 0x15, 0xa7, + 0x9e, 0x2c, 0x6a, 0xce, 0xf0, 0x07, 0xe4, 0x84, 0x66, 0x76, 0xec, 0xfd, 0xe1, 0x75, 0x9a, 0x5e, + 0x72, 0xf3, 0xbe, 0x1f, 0x9f, 0xf7, 0x66, 0xde, 0x7b, 0x9f, 0x37, 0x06, 0x1f, 0x34, 0xee, 0x30, + 0xc3, 0xa1, 0x95, 0x46, 0xeb, 0x88, 0x04, 0x1e, 0xe1, 0x84, 0x55, 0xda, 0xc4, 0xb3, 0x69, 0x50, + 0x51, 0x0a, 0xec, 0x3b, 0x15, 0xc6, 0x69, 0x80, 0xeb, 0xa4, 0xd2, 0x5e, 0xaf, 0xd4, 0x89, 0x47, + 0x02, 0xcc, 0x89, 0x6d, 0xf8, 0x01, 0xe5, 0x14, 0x5e, 0x0e, 0xcd, 0x0c, 0xec, 0x3b, 0x86, 0x32, + 0x33, 0xda, 0xeb, 0x2b, 0xd7, 0xeb, 0x0e, 0x3f, 0x69, 0x1d, 0x19, 0x16, 0x75, 0x2b, 0x75, 0x5a, + 0xa7, 0x15, 0x69, 0x7d, 0xd4, 0x3a, 0x96, 0x5f, 0xf2, 0x43, 0xfe, 0x0a, 0x51, 0x56, 0xf4, 0x58, + 0x30, 0x8b, 0x06, 0x59, 0x91, 0x56, 0x6e, 0x45, 0x36, 0x2e, 0xb6, 0x4e, 0x1c, 0x8f, 0x04, 0x9d, + 0x8a, 0xdf, 0xa8, 0x0b, 0x01, 0xab, 0xb8, 0x84, 0xe3, 0x2c, 0xaf, 0xca, 0x28, 0xaf, 0xa0, 0xe5, + 0x71, 0xc7, 0x25, 0x43, 0x0e, 0xb7, 0x5f, 0xe5, 0xc0, 0xac, 0x13, 0xe2, 0xe2, 0xb4, 0x9f, 0xfe, + 0xab, 0x06, 0x66, 0x36, 0x6b, 0xdb, 0x5b, 0x81, 0xd3, 0x26, 0x01, 0x7c, 0x04, 0xa6, 0x45, 0x46, + 0x36, 0xe6, 0xb8, 0xa8, 0xad, 0x6a, 0x6b, 0x85, 0x9b, 0x37, 0x8c, 0xe8, 0xa6, 0x06, 0xc0, 0x86, + 0xdf, 0xa8, 0x0b, 0x01, 0x33, 0x84, 0xb5, 0xd1, 0x5e, 0x37, 0xf6, 0x8f, 0x1e, 0x13, 0x8b, 0xef, + 0x12, 0x8e, 0x4d, 0xf8, 0xac, 0x5b, 0x1e, 0xeb, 0x75, 0xcb, 0x20, 0x92, 0xa1, 0x01, 0x2a, 0xbc, + 0x0f, 0xf2, 0xcc, 0x27, 0x56, 0x71, 0x5c, 0xa2, 0x5f, 0x35, 0x32, 0xeb, 0x60, 0x0c, 0x32, 0xaa, + 0xf9, 0xc4, 0x32, 0x67, 0x15, 0x62, 0x5e, 0x7c, 0x21, 0xe9, 0xaf, 0xff, 0xa2, 0x81, 0xb9, 0x81, + 0xd5, 0x8e, 0xc3, 0x38, 0xfc, 0x6c, 0x28, 0x77, 0xe3, 0x7c, 0xb9, 0x0b, 0x6f, 0x99, 0xf9, 0x82, + 0x8a, 0x33, 0xdd, 0x97, 0xc4, 0xf2, 0xae, 0x82, 0x09, 0x87, 0x13, 0x97, 0x15, 0xc7, 0x57, 0x73, + 0x6b, 0x85, 0x9b, 0xab, 0xaf, 0x4a, 0xdc, 0x9c, 0x53, 0x60, 0x13, 0xdb, 0xc2, 0x0d, 0x85, 0xde, + 0xfa, 0x8f, 0xf9, 0x58, 0xda, 0xe2, 0x38, 0xf0, 0x2e, 0xb8, 0x84, 0x39, 0xc7, 0xd6, 0x09, 0x22, + 0x4f, 0x5a, 0x4e, 0x40, 0x6c, 0x99, 0xfc, 0xb4, 0x09, 0x7b, 0xdd, 0xf2, 0xa5, 0x8d, 0x84, 0x06, + 0xa5, 0x2c, 0x85, 0xaf, 0x4f, 0xed, 0x6d, 0xef, 0x98, 0xee, 0x7b, 0xbb, 0xb4, 0xe5, 0x71, 0x79, + 0xad, 0xca, 0xf7, 0x20, 0xa1, 0x41, 0x29, 0x4b, 0x68, 0x81, 0xe5, 0x36, 0x6d, 0xb6, 0x5c, 0xb2, + 0xe3, 0x1c, 0x13, 0xab, 0x63, 0x35, 0xc9, 0x2e, 0xb5, 0x09, 0x2b, 0xe6, 0x56, 0x73, 0x6b, 0x33, + 0x66, 0xa5, 0xd7, 0x2d, 0x2f, 0x3f, 0xcc, 0xd0, 0x9f, 0x76, 0xcb, 0x4b, 0x19, 0x72, 0x94, 0x09, + 0x06, 0xef, 0x81, 0x79, 0x75, 0x39, 0x9b, 0xd8, 0xc7, 0x96, 0xc3, 0x3b, 0xc5, 0xbc, 0xcc, 0x70, + 0xa9, 0xd7, 0x2d, 0xcf, 0xd7, 0x92, 0x2a, 0x94, 0xb6, 0x85, 0x0f, 0xc0, 0xdc, 0x31, 0xfb, 0x30, + 0xa0, 0x2d, 0xff, 0x80, 0x36, 0x1d, 0xab, 0x53, 0x9c, 0x58, 0xd5, 0xd6, 0x66, 0x4c, 0xbd, 0xd7, + 0x2d, 0xcf, 0xdd, 0xaf, 0xc5, 0x14, 0xa7, 0x69, 0x01, 0x4a, 0x3a, 0xc2, 0x47, 0x60, 0x8e, 0xd3, + 0x06, 0xf1, 0xc4, 0xd5, 0x11, 0xc6, 0x59, 0x71, 0x52, 0x96, 0xf1, 0xca, 0x88, 0x32, 0x1e, 0xc6, + 0x6c, 0xcd, 0xcb, 0xaa, 0x92, 0x73, 0x71, 0x29, 0x43, 0x49, 0x40, 0xb8, 0x09, 0x16, 0x83, 0xb0, + 0x2e, 0x0c, 0x11, 0xbf, 0x75, 0xd4, 0x74, 0xd8, 0x49, 0x71, 0x4a, 0x1e, 0xf6, 0x72, 0xaf, 0x5b, + 0x5e, 0x44, 0x69, 0x25, 0x1a, 0xb6, 0xd7, 0x7f, 0xd6, 0xc0, 0xd4, 0x66, 0x6d, 0x7b, 0x8f, 0xda, + 0xe4, 0x02, 0x66, 0x71, 0x2b, 0x31, 0x8b, 0xfa, 0xe8, 0x96, 0x16, 0xf9, 0x8c, 0x9c, 0xc4, 0x7f, + 0xc3, 0x49, 0x14, 0x36, 0x8a, 0x45, 0x56, 0x41, 0xde, 0xc3, 0x2e, 0x91, 0x59, 0xcf, 0x44, 0x3e, + 0x7b, 0xd8, 0x25, 0x48, 0x6a, 0xe0, 0x9b, 0x60, 0xd2, 0xa3, 0x36, 0xd9, 0xde, 0x92, 0xb1, 0x67, + 0xcc, 0x4b, 0xca, 0x66, 0x72, 0x4f, 0x4a, 0x91, 0xd2, 0xc2, 0x5b, 0x60, 0x96, 0x53, 0x9f, 0x36, + 0x69, 0xbd, 0xf3, 0x11, 0xe9, 0xf4, 0x9b, 0x73, 0xa1, 0xd7, 0x2d, 0xcf, 0x1e, 0xc6, 0xe4, 0x28, + 0x61, 0x05, 0x3f, 0x07, 0x05, 0xdc, 0x6c, 0x52, 0x0b, 0x73, 0x7c, 0xd4, 0x24, 0xb2, 0xe3, 0x0a, + 0x37, 0xaf, 0x8d, 0x38, 0x5e, 0xd8, 0xcc, 0x22, 0x2e, 0x22, 0x8c, 0xb6, 0x02, 0x8b, 0x30, 0x73, + 0xbe, 0xd7, 0x2d, 0x17, 0x36, 0x22, 0x08, 0x14, 0xc7, 0xd3, 0x7f, 0xd2, 0x40, 0x41, 0x1d, 0xf8, + 0x02, 0x88, 0x67, 0x33, 0x49, 0x3c, 0xa5, 0xb3, 0xab, 0x34, 0x82, 0x76, 0xbe, 0x18, 0x64, 0x2c, + 0x39, 0x67, 0x1f, 0x4c, 0xd9, 0xb2, 0x54, 0xac, 0xa8, 0x49, 0xd4, 0xab, 0x67, 0xa3, 0x2a, 0x4a, + 0x9b, 0x57, 0xd8, 0x53, 0xe1, 0x37, 0x43, 0x7d, 0x14, 0xfd, 0xdb, 0x49, 0x30, 0xdb, 0x9f, 0xe6, + 0x26, 0x66, 0xec, 0x02, 0x9a, 0xf7, 0x7d, 0x50, 0xf0, 0x03, 0xda, 0x76, 0x98, 0x43, 0x3d, 0x12, + 0xa8, 0x3e, 0x5a, 0x52, 0x2e, 0x85, 0x83, 0x48, 0x85, 0xe2, 0x76, 0xb0, 0x0e, 0x80, 0x8f, 0x03, + 0xec, 0x12, 0x2e, 0x4e, 0x9f, 0x93, 0xa7, 0x7f, 0x6f, 0xc4, 0xe9, 0xe3, 0x27, 0x32, 0x0e, 0x06, + 0x5e, 0x55, 0x8f, 0x07, 0x9d, 0x28, 0xbb, 0x48, 0x81, 0x62, 0xd0, 0xb0, 0x01, 0xe6, 0x02, 0x62, + 0x35, 0xb1, 0xe3, 0x2a, 0xee, 0xca, 0xcb, 0x0c, 0xab, 0x82, 0x48, 0x50, 0x5c, 0x71, 0xda, 0x2d, + 0xdf, 0x18, 0x7e, 0x47, 0x18, 0x07, 0x24, 0x60, 0x0e, 0xe3, 0xc4, 0xe3, 0x61, 0x87, 0x26, 0x7c, + 0x50, 0x12, 0x5b, 0xcc, 0x89, 0x2b, 0x58, 0x7d, 0xdf, 0xe7, 0x0e, 0xf5, 0x58, 0x71, 0x22, 0x9a, + 0x93, 0xdd, 0x98, 0x1c, 0x25, 0xac, 0xe0, 0x0e, 0x58, 0x16, 0x7d, 0xfd, 0x65, 0x18, 0xa0, 0xfa, + 0xd4, 0xc7, 0x9e, 0xb8, 0xa5, 0xe2, 0xa4, 0x64, 0xad, 0xa2, 0x58, 0x01, 0x1b, 0x19, 0x7a, 0x94, + 0xe9, 0x05, 0x3f, 0x01, 0x8b, 0xe1, 0x0e, 0x30, 0x1d, 0xcf, 0x76, 0xbc, 0xba, 0xd8, 0x00, 0x92, + 0x00, 0x67, 0xcc, 0x6b, 0x82, 0x00, 0x1f, 0xa6, 0x95, 0xa7, 0x59, 0x42, 0x34, 0x0c, 0x02, 0x9f, + 0x80, 0x45, 0x19, 0x91, 0xd8, 0x6a, 0xe8, 0x1d, 0xc2, 0x8a, 0xd3, 0xb2, 0x74, 0x6b, 0xf1, 0xd2, + 0x89, 0xab, 0x0b, 0xd9, 0x3b, 0x24, 0x83, 0x1a, 0x69, 0x12, 0x8b, 0xd3, 0xe0, 0x90, 0x04, 0xae, + 0xf9, 0x86, 0xaa, 0xd7, 0xe2, 0x46, 0x1a, 0x0a, 0x0d, 0xa3, 0xaf, 0xdc, 0x03, 0xf3, 0xa9, 0x82, + 0xc3, 0x05, 0x90, 0x6b, 0x90, 0x4e, 0x48, 0x6a, 0x48, 0xfc, 0x84, 0xcb, 0x60, 0xa2, 0x8d, 0x9b, + 0x2d, 0x12, 0x36, 0x1f, 0x0a, 0x3f, 0xee, 0x8e, 0xdf, 0xd1, 0xf4, 0xdf, 0x34, 0xb0, 0x10, 0xef, + 0x9e, 0x0b, 0xe0, 0x89, 0x07, 0x49, 0x9e, 0xb8, 0x72, 0x8e, 0x9e, 0x1e, 0x41, 0x16, 0x5f, 0x6b, + 0x60, 0x36, 0xbe, 0xea, 0xe0, 0xbb, 0x60, 0x1a, 0xb7, 0x6c, 0x87, 0x78, 0x56, 0x9f, 0xd3, 0x07, + 0x89, 0x6c, 0x28, 0x39, 0x1a, 0x58, 0x88, 0x45, 0x48, 0x9e, 0xfa, 0x4e, 0x80, 0x45, 0x93, 0xd5, + 0x88, 0x45, 0x3d, 0x9b, 0xc9, 0x1b, 0xca, 0x85, 0x8b, 0xb0, 0x9a, 0x56, 0xa2, 0x61, 0x7b, 0xfd, + 0x87, 0x71, 0xb0, 0x10, 0xf6, 0x46, 0xf8, 0x04, 0x72, 0x89, 0xc7, 0x2f, 0x80, 0x54, 0x76, 0x13, + 0x1b, 0xf1, 0x9d, 0x33, 0x57, 0x46, 0x94, 0xd8, 0xa8, 0xd5, 0x08, 0x3f, 0x06, 0x93, 0x8c, 0x63, + 0xde, 0x12, 0x44, 0x23, 0x00, 0xaf, 0x9f, 0x17, 0x50, 0x3a, 0x45, 0x5b, 0x31, 0xfc, 0x46, 0x0a, + 0x4c, 0xff, 0x5d, 0x03, 0xcb, 0x69, 0x97, 0x0b, 0xe8, 0xb0, 0x9d, 0x64, 0x87, 0xbd, 0x75, 0xce, + 0xc3, 0x8c, 0xe8, 0xb2, 0x3f, 0x35, 0xf0, 0xbf, 0xa1, 0x73, 0xcb, 0xfd, 0x2b, 0x78, 0xc9, 0x4f, + 0xb1, 0xdf, 0x5e, 0xf4, 0x9e, 0x90, 0xbc, 0x74, 0x90, 0xa1, 0x47, 0x99, 0x5e, 0xf0, 0x31, 0x58, + 0x70, 0xbc, 0xa6, 0xe3, 0x91, 0x50, 0x56, 0x8b, 0xea, 0x9b, 0x49, 0x1e, 0x69, 0x64, 0x59, 0xdc, + 0xe5, 0x5e, 0xb7, 0xbc, 0xb0, 0x9d, 0x42, 0x41, 0x43, 0xb8, 0xfa, 0x1f, 0x19, 0x95, 0x91, 0x1b, + 0x57, 0x8c, 0x90, 0x94, 0x90, 0x60, 0x68, 0x84, 0x94, 0x1c, 0x0d, 0x2c, 0x64, 0xdf, 0xc8, 0xab, + 0x50, 0x89, 0x9e, 0xbb, 0x6f, 0xa4, 0x53, 0xac, 0x6f, 0xe4, 0x37, 0x52, 0x60, 0x22, 0x09, 0xf1, + 0xae, 0x92, 0x77, 0x99, 0x4b, 0x26, 0xb1, 0xa7, 0xe4, 0x68, 0x60, 0xa1, 0xff, 0x93, 0xcb, 0x28, + 0x90, 0x6c, 0xc0, 0xd8, 0x69, 0xfa, 0xff, 0x56, 0xd2, 0xa7, 0xb1, 0x07, 0xa7, 0xb1, 0xe1, 0xf7, + 0x1a, 0x80, 0x78, 0x00, 0xb1, 0xdb, 0x6f, 0xd0, 0xb0, 0x8b, 0xaa, 0xaf, 0x35, 0x12, 0xc6, 0xc6, + 0x10, 0x4e, 0xb8, 0x8d, 0x57, 0x54, 0x7c, 0x38, 0x6c, 0x80, 0x32, 0x82, 0x43, 0x1b, 0x14, 0x42, + 0x69, 0x35, 0x08, 0x68, 0xa0, 0xc6, 0x53, 0x3f, 0x33, 0x17, 0x69, 0x69, 0x96, 0xe4, 0xd3, 0x30, + 0x72, 0x3d, 0xed, 0x96, 0x0b, 0x31, 0x3d, 0x8a, 0xc3, 0x8a, 0x28, 0x36, 0x89, 0xa2, 0xe4, 0x5f, + 0x2f, 0xca, 0x16, 0x19, 0x1d, 0x25, 0x06, 0xbb, 0x52, 0x05, 0xff, 0x1f, 0x71, 0x2d, 0xaf, 0xb5, + 0xb3, 0xbe, 0xd1, 0x40, 0x3c, 0x06, 0xdc, 0x01, 0x79, 0xee, 0xa8, 0xa9, 0x4b, 0x3e, 0x9f, 0xcf, + 0x20, 0x92, 0x43, 0xc7, 0x25, 0x11, 0x15, 0x8a, 0x2f, 0x24, 0x51, 0xe0, 0xdb, 0x60, 0xca, 0x25, + 0x8c, 0xe1, 0xba, 0x8a, 0x1c, 0x3d, 0x26, 0x77, 0x43, 0x31, 0xea, 0xeb, 0xf5, 0xdb, 0x60, 0x29, + 0xe3, 0x51, 0x0e, 0xcb, 0x60, 0xc2, 0x92, 0xff, 0x71, 0x45, 0x42, 0x13, 0xe6, 0x8c, 0x60, 0x94, + 0x4d, 0xf9, 0xd7, 0x36, 0x94, 0x9b, 0x6b, 0xcf, 0x5e, 0x96, 0xc6, 0x9e, 0xbf, 0x2c, 0x8d, 0xbd, + 0x78, 0x59, 0x1a, 0xfb, 0xaa, 0x57, 0xd2, 0x9e, 0xf5, 0x4a, 0xda, 0xf3, 0x5e, 0x49, 0x7b, 0xd1, + 0x2b, 0x69, 0x7f, 0xf5, 0x4a, 0xda, 0x77, 0x7f, 0x97, 0xc6, 0x3e, 0x1d, 0x6f, 0xaf, 0xff, 0x17, + 0x00, 0x00, 0xff, 0xff, 0x02, 0xb2, 0x6f, 0xe2, 0x3e, 0x12, 0x00, 0x00, } func (m *CSIDriver) Marshal() (dAtA []byte, err error) { @@ -721,6 +756,30 @@ func (m *CSIDriverSpec) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if m.RequiresRepublish != nil { + i-- + if *m.RequiresRepublish { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x38 + } + if len(m.TokenRequests) > 0 { + for iNdEx := len(m.TokenRequests) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.TokenRequests[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenerated(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x32 + } + } if m.FSGroupPolicy != nil { i -= len(*m.FSGroupPolicy) copy(dAtA[i:], *m.FSGroupPolicy) @@ -1107,6 +1166,39 @@ func (m *StorageClassList) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } +func (m *TokenRequest) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *TokenRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *TokenRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.ExpirationSeconds != nil { + i = encodeVarintGenerated(dAtA, i, uint64(*m.ExpirationSeconds)) + i-- + dAtA[i] = 0x10 + } + i -= len(m.Audience) + copy(dAtA[i:], m.Audience) + i = encodeVarintGenerated(dAtA, i, uint64(len(m.Audience))) + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + func (m *VolumeAttachment) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -1503,6 +1595,15 @@ func (m *CSIDriverSpec) Size() (n int) { l = len(*m.FSGroupPolicy) n += 1 + l + sovGenerated(uint64(l)) } + if len(m.TokenRequests) > 0 { + for _, e := range m.TokenRequests { + l = e.Size() + n += 1 + l + sovGenerated(uint64(l)) + } + } + if m.RequiresRepublish != nil { + n += 2 + } return n } @@ -1635,6 +1736,20 @@ func (m *StorageClassList) Size() (n int) { return n } +func (m *TokenRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Audience) + n += 1 + l + sovGenerated(uint64(l)) + if m.ExpirationSeconds != nil { + n += 1 + sovGenerated(uint64(*m.ExpirationSeconds)) + } + return n +} + func (m *VolumeAttachment) Size() (n int) { if m == nil { return 0 @@ -1787,12 +1902,19 @@ func (this *CSIDriverSpec) String() string { if this == nil { return "nil" } + repeatedStringForTokenRequests := "[]TokenRequest{" + for _, f := range this.TokenRequests { + repeatedStringForTokenRequests += strings.Replace(strings.Replace(f.String(), "TokenRequest", "TokenRequest", 1), `&`, ``, 1) + "," + } + repeatedStringForTokenRequests += "}" s := strings.Join([]string{`&CSIDriverSpec{`, `AttachRequired:` + valueToStringGenerated(this.AttachRequired) + `,`, `PodInfoOnMount:` + valueToStringGenerated(this.PodInfoOnMount) + `,`, `VolumeLifecycleModes:` + fmt.Sprintf("%v", this.VolumeLifecycleModes) + `,`, `StorageCapacity:` + valueToStringGenerated(this.StorageCapacity) + `,`, `FSGroupPolicy:` + valueToStringGenerated(this.FSGroupPolicy) + `,`, + `TokenRequests:` + repeatedStringForTokenRequests + `,`, + `RequiresRepublish:` + valueToStringGenerated(this.RequiresRepublish) + `,`, `}`, }, "") return s @@ -1900,6 +2022,17 @@ func (this *StorageClassList) String() string { }, "") return s } +func (this *TokenRequest) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&TokenRequest{`, + `Audience:` + fmt.Sprintf("%v", this.Audience) + `,`, + `ExpirationSeconds:` + valueToStringGenerated(this.ExpirationSeconds) + `,`, + `}`, + }, "") + return s +} func (this *VolumeAttachment) String() string { if this == nil { return "nil" @@ -2399,6 +2532,61 @@ func (m *CSIDriverSpec) Unmarshal(dAtA []byte) error { s := FSGroupPolicy(dAtA[iNdEx:postIndex]) m.FSGroupPolicy = &s iNdEx = postIndex + case 6: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field TokenRequests", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.TokenRequests = append(m.TokenRequests, TokenRequest{}) + if err := m.TokenRequests[len(m.TokenRequests)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 7: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field RequiresRepublish", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + b := bool(v != 0) + m.RequiresRepublish = &b default: iNdEx = preIndex skippy, err := skipGenerated(dAtA[iNdEx:]) @@ -3452,6 +3640,111 @@ func (m *StorageClassList) Unmarshal(dAtA []byte) error { } return nil } +func (m *TokenRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: TokenRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: TokenRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Audience", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Audience = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field ExpirationSeconds", 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.ExpirationSeconds = &v + default: + iNdEx = preIndex + skippy, err := skipGenerated(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func (m *VolumeAttachment) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 diff --git a/staging/src/k8s.io/api/storage/v1/generated.proto b/staging/src/k8s.io/api/storage/v1/generated.proto index 86a8a8fdc6f..d6b4d9cbd0f 100644 --- a/staging/src/k8s.io/api/storage/v1/generated.proto +++ b/staging/src/k8s.io/api/storage/v1/generated.proto @@ -146,6 +146,43 @@ message CSIDriverSpec { // that enable the CSIVolumeFSGroupPolicy feature gate. // +optional optional string fsGroupPolicy = 5; + + // 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": { + // "": { + // "token": , + // "expirationTimestamp": , + // }, + // ... + // } + // + // Note: 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. + // + // This is an alpha feature and only available when the + // CSIServiceAccountToken feature is enabled. + // + // +optional + // +listType=atomic + repeated TokenRequest tokenRequests = 6; + + // RequiresRepublish indicates the CSI driver wants `NodePublishVolume` + // being periodically called to reflect any possible change in the mounted + // volume. This field defaults to false. + // + // Note: 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. + // + // This is an alpha feature and only available when the + // CSIServiceAccountToken feature is enabled. + // + // +optional + optional bool requiresRepublish = 7; } // CSINode holds information about all CSI drivers installed on a node. @@ -281,6 +318,19 @@ message StorageClassList { repeated StorageClass items = 2; } +// TokenRequest contains parameters of a service account token. +message TokenRequest { + // Audience is the intended audience of the token in "TokenRequestSpec". + // It will default to the audiences of kube apiserver. + optional string audience = 1; + + // ExpirationSeconds is the duration of validity of the token in "TokenRequestSpec". + // It has the same default value of "ExpirationSeconds" in "TokenRequestSpec". + // + // +optional + optional int64 expirationSeconds = 2; +} + // VolumeAttachment captures the intent to attach or detach the specified volume // to/from the specified node. // diff --git a/staging/src/k8s.io/api/storage/v1/types.go b/staging/src/k8s.io/api/storage/v1/types.go index 27e06debb1a..18d0fb8772c 100644 --- a/staging/src/k8s.io/api/storage/v1/types.go +++ b/staging/src/k8s.io/api/storage/v1/types.go @@ -344,6 +344,43 @@ type CSIDriverSpec struct { // that enable the CSIVolumeFSGroupPolicy feature gate. // +optional FSGroupPolicy *FSGroupPolicy `json:"fsGroupPolicy,omitempty" protobuf:"bytes,5,opt,name=fsGroupPolicy"` + + // 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": { + // "": { + // "token": , + // "expirationTimestamp": , + // }, + // ... + // } + // + // Note: 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. + // + // This is an alpha feature and only available when the + // CSIServiceAccountToken feature is enabled. + // + // +optional + // +listType=atomic + TokenRequests []TokenRequest `json:"tokenRequests,omitempty" protobuf:"bytes,6,opt,name=tokenRequests"` + + // RequiresRepublish indicates the CSI driver wants `NodePublishVolume` + // being periodically called to reflect any possible change in the mounted + // volume. This field defaults to false. + // + // Note: 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. + // + // This is an alpha feature and only available when the + // CSIServiceAccountToken feature is enabled. + // + // +optional + RequiresRepublish *bool `json:"requiresRepublish,omitempty" protobuf:"varint,7,opt,name=requiresRepublish"` } // FSGroupPolicy specifies if a CSI Driver supports modifying @@ -381,6 +418,20 @@ const ( // provided by a CSI driver. More modes may be added in the future. type VolumeLifecycleMode string +// TokenRequest contains parameters of a service account token. +type TokenRequest struct { + // Audience is the intended audience of the token in "TokenRequestSpec". + // It will default to the audiences of kube apiserver. + // + Audience string `json:"audience" protobuf:"bytes,1,opt,name=audience"` + + // ExpirationSeconds is the duration of validity of the token in "TokenRequestSpec". + // It has the same default value of "ExpirationSeconds" in "TokenRequestSpec". + // + // +optional + ExpirationSeconds *int64 `json:"expirationSeconds,omitempty" protobuf:"varint,2,opt,name=expirationSeconds"` +} + const ( // VolumeLifecyclePersistent explicitly confirms that the driver implements // the full CSI spec. It is the default when CSIDriverSpec.VolumeLifecycleModes is not diff --git a/staging/src/k8s.io/api/storage/v1/types_swagger_doc_generated.go b/staging/src/k8s.io/api/storage/v1/types_swagger_doc_generated.go index 606cda4dbc8..0e28b1d2f1d 100644 --- a/staging/src/k8s.io/api/storage/v1/types_swagger_doc_generated.go +++ b/staging/src/k8s.io/api/storage/v1/types_swagger_doc_generated.go @@ -54,6 +54,8 @@ var map_CSIDriverSpec = map[string]string{ "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. The 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. For 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. This field is beta.", "storageCapacity": "If set to true, 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.\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 is an alpha field and only available when the CSIStorageCapacity feature is enabled. The default is false.", "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. This field is alpha-level, and is only honored by servers that enable the CSIVolumeFSGroupPolicy feature gate.", + "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 \"\": {\n \"token\": ,\n \"expirationTimestamp\": ,\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.\n\nThis is an alpha feature and only available when the CSIServiceAccountToken feature is enabled.", + "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.\n\nThis is an alpha feature and only available when the CSIServiceAccountToken feature is enabled.", } func (CSIDriverSpec) SwaggerDoc() map[string]string { @@ -127,6 +129,16 @@ func (StorageClassList) SwaggerDoc() map[string]string { return map_StorageClassList } +var map_TokenRequest = map[string]string{ + "": "TokenRequest contains parameters of a service account token.", + "audience": "Audience is the intended audience of the token in \"TokenRequestSpec\". It will default to the audiences of kube apiserver.", + "expirationSeconds": "ExpirationSeconds is the duration of validity of the token in \"TokenRequestSpec\". It has the same default value of \"ExpirationSeconds\" in \"TokenRequestSpec\".", +} + +func (TokenRequest) SwaggerDoc() map[string]string { + return map_TokenRequest +} + var map_VolumeAttachment = map[string]string{ "": "VolumeAttachment captures the intent to attach or detach the specified volume to/from the specified node.\n\nVolumeAttachment objects are non-namespaced.", "metadata": "Standard object metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata", diff --git a/staging/src/k8s.io/api/storage/v1/zz_generated.deepcopy.go b/staging/src/k8s.io/api/storage/v1/zz_generated.deepcopy.go index 5eb0225a06b..f4de9421610 100644 --- a/staging/src/k8s.io/api/storage/v1/zz_generated.deepcopy.go +++ b/staging/src/k8s.io/api/storage/v1/zz_generated.deepcopy.go @@ -113,6 +113,18 @@ func (in *CSIDriverSpec) DeepCopyInto(out *CSIDriverSpec) { *out = new(FSGroupPolicy) **out = **in } + if in.TokenRequests != nil { + in, out := &in.TokenRequests, &out.TokenRequests + *out = make([]TokenRequest, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.RequiresRepublish != nil { + in, out := &in.RequiresRepublish, &out.RequiresRepublish + *out = new(bool) + **out = **in + } return } @@ -328,6 +340,27 @@ func (in *StorageClassList) DeepCopyObject() runtime.Object { return nil } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TokenRequest) DeepCopyInto(out *TokenRequest) { + *out = *in + if in.ExpirationSeconds != nil { + in, out := &in.ExpirationSeconds, &out.ExpirationSeconds + *out = new(int64) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TokenRequest. +func (in *TokenRequest) DeepCopy() *TokenRequest { + if in == nil { + return nil + } + out := new(TokenRequest) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *VolumeAttachment) DeepCopyInto(out *VolumeAttachment) { *out = *in diff --git a/staging/src/k8s.io/api/storage/v1beta1/generated.pb.go b/staging/src/k8s.io/api/storage/v1beta1/generated.pb.go index cec77515e1e..21f664094e2 100644 --- a/staging/src/k8s.io/api/storage/v1beta1/generated.pb.go +++ b/staging/src/k8s.io/api/storage/v1beta1/generated.pb.go @@ -298,10 +298,38 @@ func (m *StorageClassList) XXX_DiscardUnknown() { var xxx_messageInfo_StorageClassList proto.InternalMessageInfo +func (m *TokenRequest) Reset() { *m = TokenRequest{} } +func (*TokenRequest) ProtoMessage() {} +func (*TokenRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_7d2980599fd0de80, []int{9} +} +func (m *TokenRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *TokenRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil +} +func (m *TokenRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_TokenRequest.Merge(m, src) +} +func (m *TokenRequest) XXX_Size() int { + return m.Size() +} +func (m *TokenRequest) XXX_DiscardUnknown() { + xxx_messageInfo_TokenRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_TokenRequest proto.InternalMessageInfo + func (m *VolumeAttachment) Reset() { *m = VolumeAttachment{} } func (*VolumeAttachment) ProtoMessage() {} func (*VolumeAttachment) Descriptor() ([]byte, []int) { - return fileDescriptor_7d2980599fd0de80, []int{9} + return fileDescriptor_7d2980599fd0de80, []int{10} } func (m *VolumeAttachment) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -329,7 +357,7 @@ var xxx_messageInfo_VolumeAttachment proto.InternalMessageInfo func (m *VolumeAttachmentList) Reset() { *m = VolumeAttachmentList{} } func (*VolumeAttachmentList) ProtoMessage() {} func (*VolumeAttachmentList) Descriptor() ([]byte, []int) { - return fileDescriptor_7d2980599fd0de80, []int{10} + return fileDescriptor_7d2980599fd0de80, []int{11} } func (m *VolumeAttachmentList) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -357,7 +385,7 @@ var xxx_messageInfo_VolumeAttachmentList proto.InternalMessageInfo func (m *VolumeAttachmentSource) Reset() { *m = VolumeAttachmentSource{} } func (*VolumeAttachmentSource) ProtoMessage() {} func (*VolumeAttachmentSource) Descriptor() ([]byte, []int) { - return fileDescriptor_7d2980599fd0de80, []int{11} + return fileDescriptor_7d2980599fd0de80, []int{12} } func (m *VolumeAttachmentSource) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -385,7 +413,7 @@ var xxx_messageInfo_VolumeAttachmentSource proto.InternalMessageInfo func (m *VolumeAttachmentSpec) Reset() { *m = VolumeAttachmentSpec{} } func (*VolumeAttachmentSpec) ProtoMessage() {} func (*VolumeAttachmentSpec) Descriptor() ([]byte, []int) { - return fileDescriptor_7d2980599fd0de80, []int{12} + return fileDescriptor_7d2980599fd0de80, []int{13} } func (m *VolumeAttachmentSpec) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -413,7 +441,7 @@ var xxx_messageInfo_VolumeAttachmentSpec proto.InternalMessageInfo func (m *VolumeAttachmentStatus) Reset() { *m = VolumeAttachmentStatus{} } func (*VolumeAttachmentStatus) ProtoMessage() {} func (*VolumeAttachmentStatus) Descriptor() ([]byte, []int) { - return fileDescriptor_7d2980599fd0de80, []int{13} + return fileDescriptor_7d2980599fd0de80, []int{14} } func (m *VolumeAttachmentStatus) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -441,7 +469,7 @@ var xxx_messageInfo_VolumeAttachmentStatus proto.InternalMessageInfo func (m *VolumeError) Reset() { *m = VolumeError{} } func (*VolumeError) ProtoMessage() {} func (*VolumeError) Descriptor() ([]byte, []int) { - return fileDescriptor_7d2980599fd0de80, []int{14} + return fileDescriptor_7d2980599fd0de80, []int{15} } func (m *VolumeError) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -469,7 +497,7 @@ var xxx_messageInfo_VolumeError proto.InternalMessageInfo func (m *VolumeNodeResources) Reset() { *m = VolumeNodeResources{} } func (*VolumeNodeResources) ProtoMessage() {} func (*VolumeNodeResources) Descriptor() ([]byte, []int) { - return fileDescriptor_7d2980599fd0de80, []int{15} + return fileDescriptor_7d2980599fd0de80, []int{16} } func (m *VolumeNodeResources) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -505,6 +533,7 @@ func init() { proto.RegisterType((*StorageClass)(nil), "k8s.io.api.storage.v1beta1.StorageClass") proto.RegisterMapType((map[string]string)(nil), "k8s.io.api.storage.v1beta1.StorageClass.ParametersEntry") proto.RegisterType((*StorageClassList)(nil), "k8s.io.api.storage.v1beta1.StorageClassList") + proto.RegisterType((*TokenRequest)(nil), "k8s.io.api.storage.v1beta1.TokenRequest") proto.RegisterType((*VolumeAttachment)(nil), "k8s.io.api.storage.v1beta1.VolumeAttachment") proto.RegisterType((*VolumeAttachmentList)(nil), "k8s.io.api.storage.v1beta1.VolumeAttachmentList") proto.RegisterType((*VolumeAttachmentSource)(nil), "k8s.io.api.storage.v1beta1.VolumeAttachmentSource") @@ -520,95 +549,102 @@ func init() { } var fileDescriptor_7d2980599fd0de80 = []byte{ - // 1400 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x57, 0x3d, 0x6f, 0xdb, 0x46, - 0x1f, 0x37, 0x2d, 0xc9, 0x2f, 0x27, 0x3b, 0x96, 0xcf, 0xc6, 0xf3, 0xe8, 0xd1, 0x20, 0x1a, 0x7a, - 0xd0, 0xc6, 0x09, 0x12, 0x2a, 0x31, 0xd2, 0x20, 0x08, 0x90, 0xc1, 0x72, 0xdc, 0x46, 0x89, 0xe5, - 0xb8, 0x27, 0x23, 0x28, 0x82, 0x0e, 0x3d, 0x91, 0x67, 0x99, 0xb1, 0xc8, 0x63, 0xc8, 0x93, 0x5a, - 0x6d, 0x9d, 0x3a, 0x17, 0x1d, 0xfa, 0x09, 0xfa, 0x15, 0x5a, 0xa0, 0x5d, 0x3a, 0x36, 0x53, 0x11, - 0x74, 0xca, 0x44, 0x34, 0xec, 0x47, 0x28, 0xba, 0x18, 0x1d, 0x8a, 0x3b, 0x9e, 0xc4, 0x17, 0x51, - 0xb1, 0xdd, 0xc1, 0x1b, 0xef, 0xff, 0xf2, 0xfb, 0xbf, 0xff, 0xef, 0x08, 0x76, 0x4e, 0xee, 0x79, - 0x9a, 0x49, 0xeb, 0x27, 0xfd, 0x0e, 0x71, 0x6d, 0xc2, 0x88, 0x57, 0x1f, 0x10, 0xdb, 0xa0, 0x6e, - 0x5d, 0x32, 0xb0, 0x63, 0xd6, 0x3d, 0x46, 0x5d, 0xdc, 0x25, 0xf5, 0xc1, 0xed, 0x0e, 0x61, 0xf8, - 0x76, 0xbd, 0x4b, 0x6c, 0xe2, 0x62, 0x46, 0x0c, 0xcd, 0x71, 0x29, 0xa3, 0xb0, 0x12, 0xca, 0x6a, - 0xd8, 0x31, 0x35, 0x29, 0xab, 0x49, 0xd9, 0xca, 0xcd, 0xae, 0xc9, 0x8e, 0xfb, 0x1d, 0x4d, 0xa7, - 0x56, 0xbd, 0x4b, 0xbb, 0xb4, 0x2e, 0x54, 0x3a, 0xfd, 0x23, 0x71, 0x12, 0x07, 0xf1, 0x15, 0x42, - 0x55, 0x6a, 0x31, 0xb3, 0x3a, 0x75, 0xb9, 0xcd, 0xb4, 0xb9, 0xca, 0x9d, 0x48, 0xc6, 0xc2, 0xfa, - 0xb1, 0x69, 0x13, 0x77, 0x58, 0x77, 0x4e, 0xba, 0x9c, 0xe0, 0xd5, 0x2d, 0xc2, 0x70, 0x96, 0x56, - 0x7d, 0x9a, 0x96, 0xdb, 0xb7, 0x99, 0x69, 0x91, 0x09, 0x85, 0xbb, 0x67, 0x29, 0x78, 0xfa, 0x31, - 0xb1, 0x70, 0x5a, 0xaf, 0xf6, 0x93, 0x02, 0x16, 0x77, 0xda, 0xcd, 0x87, 0xae, 0x39, 0x20, 0x2e, - 0xfc, 0x0c, 0x2c, 0x70, 0x8f, 0x0c, 0xcc, 0x70, 0x59, 0xd9, 0x50, 0x36, 0x8b, 0x5b, 0xb7, 0xb4, - 0x28, 0x5d, 0x63, 0x60, 0xcd, 0x39, 0xe9, 0x72, 0x82, 0xa7, 0x71, 0x69, 0x6d, 0x70, 0x5b, 0x7b, - 0xda, 0x79, 0x41, 0x74, 0xd6, 0x22, 0x0c, 0x37, 0xe0, 0x2b, 0x5f, 0x9d, 0x09, 0x7c, 0x15, 0x44, - 0x34, 0x34, 0x46, 0x85, 0x4f, 0x40, 0xde, 0x73, 0x88, 0x5e, 0x9e, 0x15, 0xe8, 0xd7, 0xb4, 0xe9, - 0xc5, 0xd0, 0xc6, 0x6e, 0xb5, 0x1d, 0xa2, 0x37, 0x96, 0x24, 0x6c, 0x9e, 0x9f, 0x90, 0x00, 0xa9, - 0xfd, 0xa8, 0x80, 0xe5, 0xb1, 0xd4, 0x9e, 0xe9, 0x31, 0xf8, 0xe9, 0x44, 0x00, 0xda, 0xf9, 0x02, - 0xe0, 0xda, 0xc2, 0xfd, 0x92, 0xb4, 0xb3, 0x30, 0xa2, 0xc4, 0x9c, 0x7f, 0x0c, 0x0a, 0x26, 0x23, - 0x96, 0x57, 0x9e, 0xdd, 0xc8, 0x6d, 0x16, 0xb7, 0xde, 0x3b, 0x97, 0xf7, 0x8d, 0x65, 0x89, 0x58, - 0x68, 0x72, 0x5d, 0x14, 0x42, 0xd4, 0xfe, 0x9a, 0x8d, 0xf9, 0xce, 0x63, 0x82, 0xf7, 0xc1, 0x15, - 0xcc, 0x18, 0xd6, 0x8f, 0x11, 0x79, 0xd9, 0x37, 0x5d, 0x62, 0x88, 0x08, 0x16, 0x1a, 0x30, 0xf0, - 0xd5, 0x2b, 0xdb, 0x09, 0x0e, 0x4a, 0x49, 0x72, 0x5d, 0x87, 0x1a, 0x4d, 0xfb, 0x88, 0x3e, 0xb5, - 0x5b, 0xb4, 0x6f, 0x33, 0x91, 0x60, 0xa9, 0x7b, 0x90, 0xe0, 0xa0, 0x94, 0x24, 0xd4, 0xc1, 0xfa, - 0x80, 0xf6, 0xfa, 0x16, 0xd9, 0x33, 0x8f, 0x88, 0x3e, 0xd4, 0x7b, 0xa4, 0x45, 0x0d, 0xe2, 0x95, - 0x73, 0x1b, 0xb9, 0xcd, 0xc5, 0x46, 0x3d, 0xf0, 0xd5, 0xf5, 0x67, 0x19, 0xfc, 0x53, 0x5f, 0x5d, - 0xcb, 0xa0, 0xa3, 0x4c, 0x30, 0xf8, 0x00, 0xac, 0xc8, 0x0c, 0xed, 0x60, 0x07, 0xeb, 0x26, 0x1b, - 0x96, 0xf3, 0xc2, 0xc3, 0xb5, 0xc0, 0x57, 0x57, 0xda, 0x49, 0x16, 0x4a, 0xcb, 0xc2, 0x47, 0x60, - 0xf9, 0xc8, 0xfb, 0xc8, 0xa5, 0x7d, 0xe7, 0x80, 0xf6, 0x4c, 0x7d, 0x58, 0x2e, 0x6c, 0x28, 0x9b, - 0x8b, 0x8d, 0x5a, 0xe0, 0xab, 0xcb, 0x1f, 0xb6, 0x63, 0x8c, 0xd3, 0x34, 0x01, 0x25, 0x15, 0x6b, - 0x3f, 0x28, 0x60, 0x7e, 0xa7, 0xdd, 0xdc, 0xa7, 0x06, 0xb9, 0x84, 0x76, 0x6f, 0x26, 0xda, 0xfd, - 0xea, 0x19, 0x0d, 0xc3, 0x9d, 0x9a, 0xda, 0xec, 0x7f, 0x86, 0xcd, 0xce, 0x65, 0xe4, 0xb4, 0x6e, - 0x80, 0xbc, 0x8d, 0x2d, 0x22, 0x5c, 0x5f, 0x8c, 0x74, 0xf6, 0xb1, 0x45, 0x90, 0xe0, 0xc0, 0xf7, - 0xc1, 0x9c, 0x4d, 0x0d, 0xd2, 0x7c, 0x28, 0x1c, 0x58, 0x6c, 0x5c, 0x91, 0x32, 0x73, 0xfb, 0x82, - 0x8a, 0x24, 0x17, 0xde, 0x01, 0x4b, 0x8c, 0x3a, 0xb4, 0x47, 0xbb, 0xc3, 0x27, 0x64, 0x38, 0x2a, - 0x7d, 0x29, 0xf0, 0xd5, 0xa5, 0xc3, 0x18, 0x1d, 0x25, 0xa4, 0x60, 0x07, 0x14, 0x71, 0xaf, 0x47, - 0x75, 0xcc, 0x70, 0xa7, 0x47, 0x44, 0x3d, 0x8b, 0x5b, 0xf5, 0x77, 0xc5, 0x18, 0xf6, 0x0b, 0x37, - 0x8e, 0x88, 0x47, 0xfb, 0xae, 0x4e, 0xbc, 0xc6, 0x4a, 0xe0, 0xab, 0xc5, 0xed, 0x08, 0x07, 0xc5, - 0x41, 0x6b, 0xdf, 0x2b, 0xa0, 0x28, 0xa3, 0xbe, 0x84, 0x01, 0x7f, 0x94, 0x1c, 0xf0, 0xff, 0x9f, - 0xa3, 0x5e, 0x53, 0xc6, 0x5b, 0x1f, 0xbb, 0x2d, 0x66, 0xfb, 0x10, 0xcc, 0x1b, 0xa2, 0x68, 0x5e, - 0x59, 0x11, 0xd0, 0xd7, 0xce, 0x01, 0x2d, 0xf7, 0xc7, 0x8a, 0x34, 0x30, 0x1f, 0x9e, 0x3d, 0x34, - 0x82, 0xaa, 0x7d, 0x33, 0x07, 0x96, 0x46, 0xa3, 0xd3, 0xc3, 0x9e, 0x77, 0x09, 0x0d, 0xfd, 0x01, - 0x28, 0x3a, 0x2e, 0x1d, 0x98, 0x9e, 0x49, 0x6d, 0xe2, 0xca, 0xb6, 0x5a, 0x93, 0x2a, 0xc5, 0x83, - 0x88, 0x85, 0xe2, 0x72, 0xb0, 0x07, 0x80, 0x83, 0x5d, 0x6c, 0x11, 0xc6, 0x53, 0x90, 0x13, 0x29, - 0xb8, 0xf7, 0xae, 0x14, 0xc4, 0xc3, 0xd2, 0x0e, 0xc6, 0xaa, 0xbb, 0x36, 0x73, 0x87, 0x91, 0x8b, - 0x11, 0x03, 0xc5, 0xf0, 0xe1, 0x09, 0x58, 0x76, 0x89, 0xde, 0xc3, 0xa6, 0x25, 0xb7, 0x45, 0x5e, - 0xb8, 0xb9, 0xcb, 0xb7, 0x05, 0x8a, 0x33, 0x4e, 0x7d, 0xf5, 0xd6, 0xe4, 0x1d, 0xae, 0x1d, 0x10, - 0xd7, 0x33, 0x3d, 0x46, 0x6c, 0x16, 0x36, 0x6c, 0x42, 0x07, 0x25, 0xb1, 0xf9, 0xec, 0x58, 0x7c, - 0x8f, 0x3e, 0x75, 0x98, 0x49, 0x6d, 0xaf, 0x5c, 0x88, 0x66, 0xa7, 0x15, 0xa3, 0xa3, 0x84, 0x14, - 0xdc, 0x03, 0xeb, 0xbc, 0xcd, 0x3f, 0x0f, 0x0d, 0xec, 0x7e, 0xe1, 0x60, 0x9b, 0xa7, 0xaa, 0x3c, - 0x27, 0x96, 0x62, 0x99, 0x2f, 0xdd, 0xed, 0x0c, 0x3e, 0xca, 0xd4, 0x82, 0x9f, 0x80, 0xd5, 0x70, - 0xeb, 0x36, 0x4c, 0xdb, 0x30, 0xed, 0x2e, 0xdf, 0xb9, 0xe5, 0x79, 0x11, 0xf4, 0xf5, 0xc0, 0x57, - 0x57, 0x9f, 0xa5, 0x99, 0xa7, 0x59, 0x44, 0x34, 0x09, 0x02, 0x5f, 0x82, 0x55, 0x61, 0x91, 0x18, - 0x72, 0x11, 0x98, 0xc4, 0x2b, 0x2f, 0x88, 0xfa, 0x6d, 0xc6, 0xeb, 0xc7, 0x53, 0xc7, 0x1b, 0x69, - 0xb4, 0x2e, 0xda, 0xa4, 0x47, 0x74, 0x46, 0xdd, 0x43, 0xe2, 0x5a, 0x8d, 0xff, 0xc9, 0x7a, 0xad, - 0x6e, 0xa7, 0xa1, 0xd0, 0x24, 0x7a, 0xe5, 0x01, 0x58, 0x49, 0x15, 0x1c, 0x96, 0x40, 0xee, 0x84, - 0x0c, 0xc3, 0x45, 0x87, 0xf8, 0x27, 0x5c, 0x07, 0x85, 0x01, 0xee, 0xf5, 0x49, 0xd8, 0x81, 0x28, - 0x3c, 0xdc, 0x9f, 0xbd, 0xa7, 0xd4, 0x7e, 0x56, 0x40, 0x29, 0xde, 0x3d, 0x97, 0xb0, 0x36, 0x5a, - 0xc9, 0xb5, 0xb1, 0x79, 0xde, 0xc6, 0x9e, 0xb2, 0x3b, 0xbe, 0x9b, 0x05, 0xa5, 0xb0, 0x38, 0xe1, - 0xad, 0x6f, 0x11, 0x9b, 0x5d, 0xc2, 0x68, 0xa3, 0xc4, 0x5d, 0x75, 0xeb, 0xec, 0x3d, 0x1e, 0x79, - 0x37, 0xed, 0xd2, 0x82, 0xcf, 0xc1, 0x9c, 0xc7, 0x30, 0xeb, 0xf3, 0x99, 0xe7, 0xa8, 0x5b, 0x17, - 0x42, 0x15, 0x9a, 0xd1, 0xa5, 0x15, 0x9e, 0x91, 0x44, 0xac, 0xfd, 0xa2, 0x80, 0xf5, 0xb4, 0xca, - 0x25, 0x14, 0xfb, 0xe3, 0x64, 0xb1, 0x6f, 0x5c, 0x24, 0xa2, 0x29, 0x05, 0xff, 0x4d, 0x01, 0xff, - 0x99, 0x08, 0x5e, 0x5c, 0x8f, 0x7c, 0x4f, 0x38, 0xa9, 0x6d, 0xb4, 0x1f, 0xdd, 0xf9, 0x62, 0x4f, - 0x1c, 0x64, 0xf0, 0x51, 0xa6, 0x16, 0x7c, 0x01, 0x4a, 0xa6, 0xdd, 0x33, 0x6d, 0x12, 0xd2, 0xda, - 0x51, 0xb9, 0x33, 0x87, 0x39, 0x8d, 0x2c, 0xca, 0xbc, 0x1e, 0xf8, 0x6a, 0xa9, 0x99, 0x42, 0x41, - 0x13, 0xb8, 0xb5, 0x5f, 0x33, 0xca, 0x23, 0xee, 0xc2, 0x1b, 0x60, 0x21, 0x7c, 0xbd, 0x12, 0x57, - 0x86, 0x31, 0x4e, 0xf7, 0xb6, 0xa4, 0xa3, 0xb1, 0x84, 0xe8, 0x20, 0x91, 0x0a, 0xe9, 0xe8, 0xc5, - 0x3a, 0x48, 0x68, 0xc6, 0x3a, 0x48, 0x9c, 0x91, 0x44, 0xe4, 0x9e, 0xf0, 0x07, 0x90, 0x48, 0x68, - 0x2e, 0xe9, 0xc9, 0xbe, 0xa4, 0xa3, 0xb1, 0x44, 0xed, 0xef, 0x5c, 0x46, 0x95, 0x44, 0x2b, 0xc6, - 0x42, 0x1a, 0x3d, 0xda, 0xd3, 0x21, 0x19, 0xe3, 0x90, 0x0c, 0xf8, 0xad, 0x02, 0x20, 0x1e, 0x43, - 0xb4, 0x46, 0xad, 0x1a, 0xf6, 0xd3, 0xe3, 0x8b, 0x4f, 0x88, 0xb6, 0x3d, 0x01, 0x16, 0xde, 0x93, - 0x15, 0xe9, 0x04, 0x9c, 0x14, 0x40, 0x19, 0x1e, 0x40, 0x13, 0x14, 0x43, 0xea, 0xae, 0xeb, 0x52, - 0x57, 0x8e, 0xec, 0xd5, 0xb3, 0x1d, 0x12, 0xe2, 0x8d, 0xaa, 0x78, 0xc8, 0x45, 0xfa, 0xa7, 0xbe, - 0x5a, 0x8c, 0xf1, 0x51, 0x1c, 0x9b, 0x9b, 0x32, 0x48, 0x64, 0x2a, 0xff, 0x2f, 0x4c, 0x3d, 0x24, - 0xd3, 0x4d, 0xc5, 0xb0, 0x2b, 0xbb, 0xe0, 0xbf, 0x53, 0x12, 0x74, 0xa1, 0x7b, 0xe5, 0x2b, 0x05, - 0xc4, 0x6d, 0xc0, 0x3d, 0x90, 0xe7, 0x3f, 0xd6, 0x72, 0xc3, 0x5c, 0x3f, 0xdf, 0x86, 0x39, 0x34, - 0x2d, 0x12, 0x2d, 0x4a, 0x7e, 0x42, 0x02, 0x05, 0x5e, 0x03, 0xf3, 0x16, 0xf1, 0x3c, 0xdc, 0x95, - 0x96, 0xa3, 0x57, 0x5f, 0x2b, 0x24, 0xa3, 0x11, 0xbf, 0x76, 0x17, 0xac, 0x65, 0xbc, 0xa3, 0xa1, - 0x0a, 0x0a, 0xba, 0xf8, 0xf3, 0xe3, 0x0e, 0x15, 0x1a, 0x8b, 0x7c, 0xcb, 0xec, 0x88, 0x1f, 0xbe, - 0x90, 0xde, 0xb8, 0xf9, 0xea, 0x6d, 0x75, 0xe6, 0xf5, 0xdb, 0xea, 0xcc, 0x9b, 0xb7, 0xd5, 0x99, - 0x2f, 0x83, 0xaa, 0xf2, 0x2a, 0xa8, 0x2a, 0xaf, 0x83, 0xaa, 0xf2, 0x26, 0xa8, 0x2a, 0xbf, 0x07, - 0x55, 0xe5, 0xeb, 0x3f, 0xaa, 0x33, 0xcf, 0xe7, 0x65, 0xbe, 0xff, 0x09, 0x00, 0x00, 0xff, 0xff, - 0x4b, 0x3f, 0x49, 0x6e, 0x6d, 0x11, 0x00, 0x00, + // 1508 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x57, 0xbd, 0x6f, 0x1b, 0x47, + 0x16, 0xd7, 0x8a, 0xd4, 0xd7, 0x50, 0xb2, 0xa4, 0x91, 0x7c, 0xc7, 0x53, 0x41, 0x0a, 0x3c, 0xdc, + 0x59, 0x36, 0xec, 0xa5, 0x2d, 0xf8, 0x0c, 0xc3, 0x80, 0x0b, 0xad, 0xac, 0x3b, 0xcb, 0x96, 0x64, + 0xdd, 0x50, 0x30, 0x0e, 0xc6, 0x15, 0x19, 0xee, 0x3e, 0x51, 0x6b, 0x71, 0x77, 0xd6, 0x3b, 0x43, + 0xc5, 0xec, 0x92, 0x26, 0x75, 0x90, 0x22, 0x7d, 0x80, 0xfc, 0x0b, 0x09, 0x90, 0x34, 0x29, 0xe3, + 0x2a, 0x30, 0x52, 0xb9, 0x22, 0x62, 0xe6, 0x4f, 0x48, 0x27, 0xa4, 0x08, 0x66, 0x76, 0xc8, 0xfd, + 0x20, 0x69, 0x49, 0x29, 0xd4, 0x71, 0xde, 0xc7, 0xef, 0xbd, 0x79, 0xef, 0xcd, 0xef, 0x2d, 0xd1, + 0xe6, 0xf1, 0x7d, 0x6e, 0xba, 0xac, 0x7a, 0xdc, 0xaa, 0x43, 0xe8, 0x83, 0x00, 0x5e, 0x3d, 0x01, + 0xdf, 0x61, 0x61, 0x55, 0x2b, 0x68, 0xe0, 0x56, 0xb9, 0x60, 0x21, 0x6d, 0x40, 0xf5, 0xe4, 0x4e, + 0x1d, 0x04, 0xbd, 0x53, 0x6d, 0x80, 0x0f, 0x21, 0x15, 0xe0, 0x98, 0x41, 0xc8, 0x04, 0xc3, 0x2b, + 0x91, 0xad, 0x49, 0x03, 0xd7, 0xd4, 0xb6, 0xa6, 0xb6, 0x5d, 0xb9, 0xd5, 0x70, 0xc5, 0x51, 0xab, + 0x6e, 0xda, 0xcc, 0xab, 0x36, 0x58, 0x83, 0x55, 0x95, 0x4b, 0xbd, 0x75, 0xa8, 0x4e, 0xea, 0xa0, + 0x7e, 0x45, 0x50, 0x2b, 0x95, 0x44, 0x58, 0x9b, 0x85, 0x32, 0x66, 0x36, 0xdc, 0xca, 0xdd, 0xd8, + 0xc6, 0xa3, 0xf6, 0x91, 0xeb, 0x43, 0xd8, 0xae, 0x06, 0xc7, 0x0d, 0x29, 0xe0, 0x55, 0x0f, 0x04, + 0x1d, 0xe6, 0x55, 0x1d, 0xe5, 0x15, 0xb6, 0x7c, 0xe1, 0x7a, 0x30, 0xe0, 0x70, 0xef, 0x2c, 0x07, + 0x6e, 0x1f, 0x81, 0x47, 0xb3, 0x7e, 0x95, 0xef, 0x0d, 0x34, 0xb3, 0x59, 0xdb, 0x7e, 0x14, 0xba, + 0x27, 0x10, 0xe2, 0x8f, 0xd0, 0xb4, 0xcc, 0xc8, 0xa1, 0x82, 0x16, 0x8d, 0x55, 0x63, 0xad, 0xb0, + 0x7e, 0xdb, 0x8c, 0xcb, 0xd5, 0x07, 0x36, 0x83, 0xe3, 0x86, 0x14, 0x70, 0x53, 0x5a, 0x9b, 0x27, + 0x77, 0xcc, 0x67, 0xf5, 0x97, 0x60, 0x8b, 0x5d, 0x10, 0xd4, 0xc2, 0x6f, 0x3a, 0xe5, 0xb1, 0x6e, + 0xa7, 0x8c, 0x62, 0x19, 0xe9, 0xa3, 0xe2, 0xa7, 0x28, 0xcf, 0x03, 0xb0, 0x8b, 0xe3, 0x0a, 0xfd, + 0xba, 0x39, 0xba, 0x19, 0x66, 0x3f, 0xad, 0x5a, 0x00, 0xb6, 0x35, 0xab, 0x61, 0xf3, 0xf2, 0x44, + 0x14, 0x48, 0xe5, 0x3b, 0x03, 0xcd, 0xf5, 0xad, 0x76, 0x5c, 0x2e, 0xf0, 0xff, 0x07, 0x2e, 0x60, + 0x9e, 0xef, 0x02, 0xd2, 0x5b, 0xa5, 0xbf, 0xa0, 0xe3, 0x4c, 0xf7, 0x24, 0x89, 0xe4, 0x9f, 0xa0, + 0x09, 0x57, 0x80, 0xc7, 0x8b, 0xe3, 0xab, 0xb9, 0xb5, 0xc2, 0xfa, 0x3f, 0xce, 0x95, 0xbd, 0x35, + 0xa7, 0x11, 0x27, 0xb6, 0xa5, 0x2f, 0x89, 0x20, 0x2a, 0x5f, 0xe5, 0x13, 0xb9, 0xcb, 0x3b, 0xe1, + 0x07, 0xe8, 0x0a, 0x15, 0x82, 0xda, 0x47, 0x04, 0x5e, 0xb5, 0xdc, 0x10, 0x1c, 0x75, 0x83, 0x69, + 0x0b, 0x77, 0x3b, 0xe5, 0x2b, 0x1b, 0x29, 0x0d, 0xc9, 0x58, 0x4a, 0xdf, 0x80, 0x39, 0xdb, 0xfe, + 0x21, 0x7b, 0xe6, 0xef, 0xb2, 0x96, 0x2f, 0x54, 0x81, 0xb5, 0xef, 0x7e, 0x4a, 0x43, 0x32, 0x96, + 0xd8, 0x46, 0xcb, 0x27, 0xac, 0xd9, 0xf2, 0x60, 0xc7, 0x3d, 0x04, 0xbb, 0x6d, 0x37, 0x61, 0x97, + 0x39, 0xc0, 0x8b, 0xb9, 0xd5, 0xdc, 0xda, 0x8c, 0x55, 0xed, 0x76, 0xca, 0xcb, 0xcf, 0x87, 0xe8, + 0x4f, 0x3b, 0xe5, 0xa5, 0x21, 0x72, 0x32, 0x14, 0x0c, 0x3f, 0x44, 0xf3, 0xba, 0x42, 0x9b, 0x34, + 0xa0, 0xb6, 0x2b, 0xda, 0xc5, 0xbc, 0xca, 0x70, 0xa9, 0xdb, 0x29, 0xcf, 0xd7, 0xd2, 0x2a, 0x92, + 0xb5, 0xc5, 0x8f, 0xd1, 0xdc, 0x21, 0xff, 0x4f, 0xc8, 0x5a, 0xc1, 0x3e, 0x6b, 0xba, 0x76, 0xbb, + 0x38, 0xb1, 0x6a, 0xac, 0xcd, 0x58, 0x95, 0x6e, 0xa7, 0x3c, 0xf7, 0xef, 0x5a, 0x42, 0x71, 0x9a, + 0x15, 0x90, 0xb4, 0x23, 0x06, 0x34, 0x27, 0xd8, 0x31, 0xf8, 0xb2, 0x74, 0xc0, 0x05, 0x2f, 0x4e, + 0xaa, 0x5e, 0xae, 0x7d, 0xa8, 0x97, 0x07, 0x09, 0x07, 0xeb, 0xaa, 0x6e, 0xe7, 0x5c, 0x52, 0xca, + 0x49, 0x1a, 0x15, 0x6f, 0xa2, 0xc5, 0x30, 0x6a, 0x0e, 0x27, 0x10, 0xb4, 0xea, 0x4d, 0x97, 0x1f, + 0x15, 0xa7, 0xd4, 0x8d, 0xaf, 0x76, 0x3b, 0xe5, 0x45, 0x92, 0x55, 0x92, 0x41, 0xfb, 0xca, 0xb7, + 0x06, 0x9a, 0xda, 0xac, 0x6d, 0xef, 0x31, 0x07, 0x2e, 0xe1, 0x69, 0x6e, 0xa7, 0x9e, 0xe6, 0xb5, + 0x33, 0x86, 0x5b, 0x26, 0x35, 0xf2, 0x61, 0xfe, 0x16, 0x3d, 0x4c, 0x69, 0xa3, 0x99, 0x65, 0x15, + 0xe5, 0x7d, 0xea, 0x81, 0x4a, 0x7d, 0x26, 0xf6, 0xd9, 0xa3, 0x1e, 0x10, 0xa5, 0xc1, 0xff, 0x44, + 0x93, 0x3e, 0x73, 0x60, 0xfb, 0x91, 0x4a, 0x60, 0xc6, 0xba, 0xa2, 0x6d, 0x26, 0xf7, 0x94, 0x94, + 0x68, 0x2d, 0xbe, 0x8b, 0x66, 0x05, 0x0b, 0x58, 0x93, 0x35, 0xda, 0x4f, 0xa1, 0xdd, 0x1b, 0xd3, + 0x85, 0x6e, 0xa7, 0x3c, 0x7b, 0x90, 0x90, 0x93, 0x94, 0x15, 0xae, 0xa3, 0x02, 0x6d, 0x36, 0x99, + 0x4d, 0x05, 0xad, 0x37, 0x41, 0xcd, 0x5e, 0x61, 0xbd, 0xfa, 0xa1, 0x3b, 0x46, 0xb3, 0x2d, 0x83, + 0x13, 0xe0, 0xac, 0x15, 0xda, 0xc0, 0xad, 0xf9, 0x6e, 0xa7, 0x5c, 0xd8, 0x88, 0x71, 0x48, 0x12, + 0xb4, 0xf2, 0x8d, 0x81, 0x0a, 0xfa, 0xd6, 0x97, 0x40, 0x46, 0x8f, 0xd3, 0x64, 0xf4, 0xf7, 0x73, + 0xf4, 0x6b, 0x04, 0x15, 0xd9, 0xfd, 0xb4, 0x15, 0x0f, 0x1d, 0xa0, 0x29, 0x47, 0x35, 0x8d, 0x17, + 0x0d, 0x05, 0x7d, 0xfd, 0x1c, 0xd0, 0x9a, 0xeb, 0xe6, 0x75, 0x80, 0xa9, 0xe8, 0xcc, 0x49, 0x0f, + 0xaa, 0xf2, 0xc5, 0x24, 0x9a, 0xed, 0x3d, 0xf3, 0x26, 0xe5, 0xfc, 0x12, 0x06, 0xfa, 0x5f, 0xa8, + 0x10, 0x84, 0xec, 0xc4, 0xe5, 0x2e, 0xf3, 0x21, 0xd4, 0x63, 0xb5, 0xa4, 0x5d, 0x0a, 0xfb, 0xb1, + 0x8a, 0x24, 0xed, 0x70, 0x13, 0xa1, 0x80, 0x86, 0xd4, 0x03, 0x21, 0x4b, 0x90, 0x53, 0x25, 0xb8, + 0xff, 0xa1, 0x12, 0x24, 0xaf, 0x65, 0xee, 0xf7, 0x5d, 0xb7, 0x7c, 0x11, 0xb6, 0xe3, 0x14, 0x63, + 0x05, 0x49, 0xe0, 0xe3, 0x63, 0x34, 0x17, 0x82, 0xdd, 0xa4, 0xae, 0xa7, 0x99, 0x2d, 0xaf, 0xd2, + 0xdc, 0x92, 0x0c, 0x43, 0x92, 0x8a, 0xd3, 0x4e, 0xf9, 0xf6, 0xe0, 0xf7, 0x86, 0xb9, 0x0f, 0x21, + 0x77, 0xb9, 0x00, 0x5f, 0x44, 0x03, 0x9b, 0xf2, 0x21, 0x69, 0x6c, 0xf9, 0x76, 0x3c, 0xc9, 0xf9, + 0xcf, 0x02, 0xe1, 0x32, 0x9f, 0x17, 0x27, 0xe2, 0xb7, 0xb3, 0x9b, 0x90, 0x93, 0x94, 0x15, 0xde, + 0x41, 0xcb, 0x72, 0xcc, 0x3f, 0x8e, 0x02, 0x6c, 0xbd, 0x0e, 0xa8, 0x2f, 0x4b, 0x55, 0x9c, 0x54, + 0x74, 0x56, 0x94, 0x0b, 0x62, 0x63, 0x88, 0x9e, 0x0c, 0xf5, 0xc2, 0xff, 0x43, 0x8b, 0xd1, 0x86, + 0xb0, 0x5c, 0xdf, 0x71, 0xfd, 0x86, 0xdc, 0x0f, 0x8a, 0x19, 0x67, 0xac, 0x1b, 0x92, 0x19, 0x9f, + 0x67, 0x95, 0xa7, 0xc3, 0x84, 0x64, 0x10, 0x04, 0xbf, 0x42, 0x8b, 0x2a, 0x22, 0x38, 0x9a, 0x08, + 0x5c, 0xe0, 0xc5, 0xe9, 0x41, 0x7a, 0x97, 0xa5, 0x93, 0x83, 0xd4, 0xa3, 0x8b, 0x1a, 0x34, 0xc1, + 0x16, 0x2c, 0x3c, 0x80, 0xd0, 0xb3, 0xfe, 0xa6, 0xfb, 0xb5, 0xb8, 0x91, 0x85, 0x22, 0x83, 0xe8, + 0x2b, 0x0f, 0xd1, 0x7c, 0xa6, 0xe1, 0x78, 0x01, 0xe5, 0x8e, 0xa1, 0x1d, 0x11, 0x1d, 0x91, 0x3f, + 0xf1, 0x32, 0x9a, 0x38, 0xa1, 0xcd, 0x16, 0x44, 0x13, 0x48, 0xa2, 0xc3, 0x83, 0xf1, 0xfb, 0x46, + 0xe5, 0x07, 0x03, 0x2d, 0x24, 0xa7, 0xe7, 0x12, 0x68, 0x63, 0x37, 0x4d, 0x1b, 0x6b, 0xe7, 0x1d, + 0xec, 0x11, 0xdc, 0xf1, 0xa9, 0x81, 0x66, 0x93, 0x8b, 0x10, 0xdf, 0x44, 0xd3, 0xb4, 0xe5, 0xb8, + 0xe0, 0xdb, 0x3d, 0xb2, 0xef, 0x67, 0xb3, 0xa1, 0xe5, 0xa4, 0x6f, 0x21, 0xd7, 0x24, 0xbc, 0x0e, + 0xdc, 0x90, 0xca, 0x49, 0xab, 0x81, 0xcd, 0x7c, 0x87, 0xab, 0x32, 0xe5, 0xa2, 0x35, 0xb9, 0x95, + 0x55, 0x92, 0x41, 0xfb, 0xca, 0xd7, 0xe3, 0x68, 0x21, 0x1a, 0x90, 0xe8, 0x2b, 0xc9, 0x03, 0x5f, + 0x5c, 0x02, 0xbd, 0x90, 0xd4, 0xbe, 0xbc, 0x7d, 0xf6, 0x2e, 0x89, 0xb3, 0x1b, 0xb5, 0x38, 0xf1, + 0x0b, 0x34, 0xc9, 0x05, 0x15, 0x2d, 0xc9, 0x3b, 0x12, 0x75, 0xfd, 0x42, 0xa8, 0xca, 0x33, 0x5e, + 0x9c, 0xd1, 0x99, 0x68, 0xc4, 0xca, 0x8f, 0x06, 0x5a, 0xce, 0xba, 0x5c, 0xc2, 0xc0, 0xfd, 0x37, + 0x3d, 0x70, 0x37, 0x2f, 0x72, 0xa3, 0x11, 0x43, 0xf7, 0xb3, 0x81, 0xfe, 0x32, 0x70, 0x79, 0xb5, + 0xa2, 0x25, 0x57, 0x05, 0x19, 0x46, 0xdc, 0x8b, 0xbf, 0x3b, 0x14, 0x57, 0xed, 0x0f, 0xd1, 0x93, + 0xa1, 0x5e, 0xf8, 0x25, 0x5a, 0x70, 0xfd, 0xa6, 0xeb, 0x43, 0x24, 0xab, 0xc5, 0xed, 0x1e, 0x4a, + 0x28, 0x59, 0x64, 0xd5, 0xe6, 0xe5, 0x6e, 0xa7, 0xbc, 0xb0, 0x9d, 0x41, 0x21, 0x03, 0xb8, 0x95, + 0x9f, 0x86, 0xb4, 0x47, 0xed, 0x63, 0xf9, 0xa2, 0x94, 0x04, 0xc2, 0x81, 0x17, 0xa5, 0xe5, 0xa4, + 0x6f, 0xa1, 0x26, 0x48, 0x95, 0x42, 0x27, 0x7a, 0xb1, 0x09, 0x52, 0x9e, 0x89, 0x09, 0x52, 0x67, + 0xa2, 0x11, 0x65, 0x26, 0xf2, 0x23, 0x4c, 0x15, 0x34, 0x97, 0xce, 0x64, 0x4f, 0xcb, 0x49, 0xdf, + 0xa2, 0xf2, 0x7b, 0x6e, 0x48, 0x97, 0xd4, 0x28, 0x26, 0xae, 0xd4, 0xfb, 0x93, 0x93, 0xbd, 0x92, + 0xd3, 0xbf, 0x92, 0x83, 0xbf, 0x34, 0x10, 0xa6, 0x7d, 0x88, 0xdd, 0xde, 0xa8, 0x46, 0xf3, 0xf4, + 0xe4, 0xe2, 0x2f, 0xc4, 0xdc, 0x18, 0x00, 0x8b, 0x76, 0xf5, 0x8a, 0x4e, 0x02, 0x0f, 0x1a, 0x90, + 0x21, 0x19, 0x60, 0x17, 0x15, 0x22, 0xe9, 0x56, 0x18, 0xb2, 0x50, 0x3f, 0xd9, 0x6b, 0x67, 0x27, + 0xa4, 0xcc, 0xad, 0x92, 0xfa, 0x98, 0x8c, 0xfd, 0x4f, 0x3b, 0xe5, 0x42, 0x42, 0x4f, 0x92, 0xd8, + 0x32, 0x94, 0x03, 0x71, 0xa8, 0xfc, 0x9f, 0x08, 0xf5, 0x08, 0x46, 0x87, 0x4a, 0x60, 0xaf, 0x6c, + 0xa1, 0xbf, 0x8e, 0x28, 0xd0, 0x85, 0x76, 0xdb, 0x67, 0x06, 0x4a, 0xc6, 0xc0, 0x3b, 0x28, 0x2f, + 0x5c, 0xfd, 0x12, 0x0b, 0xeb, 0x37, 0xce, 0xc7, 0x30, 0x07, 0xae, 0x07, 0x31, 0x51, 0xca, 0x13, + 0x51, 0x28, 0xf8, 0x3a, 0x9a, 0xf2, 0x80, 0x73, 0xda, 0xd0, 0x91, 0xe3, 0x2f, 0xcf, 0xdd, 0x48, + 0x4c, 0x7a, 0xfa, 0xca, 0x3d, 0xb4, 0x34, 0xe4, 0x5b, 0x1e, 0x97, 0xd1, 0x84, 0xad, 0xfe, 0x29, + 0xcb, 0x84, 0x26, 0xac, 0x19, 0xc9, 0x32, 0x9b, 0xea, 0x0f, 0x72, 0x24, 0xb7, 0x6e, 0xbd, 0x79, + 0x5f, 0x1a, 0x7b, 0xfb, 0xbe, 0x34, 0xf6, 0xee, 0x7d, 0x69, 0xec, 0x93, 0x6e, 0xc9, 0x78, 0xd3, + 0x2d, 0x19, 0x6f, 0xbb, 0x25, 0xe3, 0x5d, 0xb7, 0x64, 0xfc, 0xd2, 0x2d, 0x19, 0x9f, 0xff, 0x5a, + 0x1a, 0x7b, 0x31, 0xa5, 0xeb, 0xfd, 0x47, 0x00, 0x00, 0x00, 0xff, 0xff, 0x6a, 0xb1, 0x9d, 0x65, + 0x9d, 0x12, 0x00, 0x00, } func (m *CSIDriver) Marshal() (dAtA []byte, err error) { @@ -721,6 +757,30 @@ func (m *CSIDriverSpec) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if m.RequiresRepublish != nil { + i-- + if *m.RequiresRepublish { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x38 + } + if len(m.TokenRequests) > 0 { + for iNdEx := len(m.TokenRequests) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.TokenRequests[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenerated(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x32 + } + } if m.FSGroupPolicy != nil { i -= len(*m.FSGroupPolicy) copy(dAtA[i:], *m.FSGroupPolicy) @@ -1107,6 +1167,39 @@ func (m *StorageClassList) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } +func (m *TokenRequest) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *TokenRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *TokenRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.ExpirationSeconds != nil { + i = encodeVarintGenerated(dAtA, i, uint64(*m.ExpirationSeconds)) + i-- + dAtA[i] = 0x10 + } + i -= len(m.Audience) + copy(dAtA[i:], m.Audience) + i = encodeVarintGenerated(dAtA, i, uint64(len(m.Audience))) + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + func (m *VolumeAttachment) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -1503,6 +1596,15 @@ func (m *CSIDriverSpec) Size() (n int) { l = len(*m.FSGroupPolicy) n += 1 + l + sovGenerated(uint64(l)) } + if len(m.TokenRequests) > 0 { + for _, e := range m.TokenRequests { + l = e.Size() + n += 1 + l + sovGenerated(uint64(l)) + } + } + if m.RequiresRepublish != nil { + n += 2 + } return n } @@ -1635,6 +1737,20 @@ func (m *StorageClassList) Size() (n int) { return n } +func (m *TokenRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Audience) + n += 1 + l + sovGenerated(uint64(l)) + if m.ExpirationSeconds != nil { + n += 1 + sovGenerated(uint64(*m.ExpirationSeconds)) + } + return n +} + func (m *VolumeAttachment) Size() (n int) { if m == nil { return 0 @@ -1787,12 +1903,19 @@ func (this *CSIDriverSpec) String() string { if this == nil { return "nil" } + repeatedStringForTokenRequests := "[]TokenRequest{" + for _, f := range this.TokenRequests { + repeatedStringForTokenRequests += strings.Replace(strings.Replace(f.String(), "TokenRequest", "TokenRequest", 1), `&`, ``, 1) + "," + } + repeatedStringForTokenRequests += "}" s := strings.Join([]string{`&CSIDriverSpec{`, `AttachRequired:` + valueToStringGenerated(this.AttachRequired) + `,`, `PodInfoOnMount:` + valueToStringGenerated(this.PodInfoOnMount) + `,`, `VolumeLifecycleModes:` + fmt.Sprintf("%v", this.VolumeLifecycleModes) + `,`, `StorageCapacity:` + valueToStringGenerated(this.StorageCapacity) + `,`, `FSGroupPolicy:` + valueToStringGenerated(this.FSGroupPolicy) + `,`, + `TokenRequests:` + repeatedStringForTokenRequests + `,`, + `RequiresRepublish:` + valueToStringGenerated(this.RequiresRepublish) + `,`, `}`, }, "") return s @@ -1900,6 +2023,17 @@ func (this *StorageClassList) String() string { }, "") return s } +func (this *TokenRequest) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&TokenRequest{`, + `Audience:` + fmt.Sprintf("%v", this.Audience) + `,`, + `ExpirationSeconds:` + valueToStringGenerated(this.ExpirationSeconds) + `,`, + `}`, + }, "") + return s +} func (this *VolumeAttachment) String() string { if this == nil { return "nil" @@ -2399,6 +2533,61 @@ func (m *CSIDriverSpec) Unmarshal(dAtA []byte) error { s := FSGroupPolicy(dAtA[iNdEx:postIndex]) m.FSGroupPolicy = &s iNdEx = postIndex + case 6: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field TokenRequests", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.TokenRequests = append(m.TokenRequests, TokenRequest{}) + if err := m.TokenRequests[len(m.TokenRequests)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 7: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field RequiresRepublish", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + b := bool(v != 0) + m.RequiresRepublish = &b default: iNdEx = preIndex skippy, err := skipGenerated(dAtA[iNdEx:]) @@ -3452,6 +3641,111 @@ func (m *StorageClassList) Unmarshal(dAtA []byte) error { } return nil } +func (m *TokenRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: TokenRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: TokenRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Audience", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Audience = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field ExpirationSeconds", 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.ExpirationSeconds = &v + default: + iNdEx = preIndex + skippy, err := skipGenerated(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func (m *VolumeAttachment) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 diff --git a/staging/src/k8s.io/api/storage/v1beta1/generated.proto b/staging/src/k8s.io/api/storage/v1beta1/generated.proto index 48345b1fac1..1eb4e1f88c4 100644 --- a/staging/src/k8s.io/api/storage/v1beta1/generated.proto +++ b/staging/src/k8s.io/api/storage/v1beta1/generated.proto @@ -147,6 +147,43 @@ message CSIDriverSpec { // that enable the CSIVolumeFSGroupPolicy feature gate. // +optional optional string fsGroupPolicy = 5; + + // 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": { + // "": { + // "token": , + // "expirationTimestamp": , + // }, + // ... + // } + // + // Note: 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. + // + // This is an alpha feature and only available when the + // CSIServiceAccountToken feature is enabled. + // + // +optional + // +listType=atomic + repeated TokenRequest tokenRequests = 6; + + // RequiresRepublish indicates the CSI driver wants `NodePublishVolume` + // being periodically called to reflect any possible change in the mounted + // volume. This field defaults to false. + // + // Note: 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. + // + // This is an alpha feature and only available when the + // CSIServiceAccountToken feature is enabled. + // + // +optional + optional bool requiresRepublish = 7; } // DEPRECATED - This group version of CSINode is deprecated by storage/v1/CSINode. @@ -283,6 +320,19 @@ message StorageClassList { repeated StorageClass items = 2; } +// TokenRequest contains parameters of a service account token. +message TokenRequest { + // Audience is the intended audience of the token in "TokenRequestSpec". + // It will default to the audiences of kube apiserver. + optional string audience = 1; + + // ExpirationSeconds is the duration of validity of the token in "TokenRequestSpec". + // It has the same default value of "ExpirationSeconds" in "TokenRequestSpec" + // + // +optional + optional int64 expirationSeconds = 2; +} + // VolumeAttachment captures the intent to attach or detach the specified volume // to/from the specified node. // diff --git a/staging/src/k8s.io/api/storage/v1beta1/types.go b/staging/src/k8s.io/api/storage/v1beta1/types.go index 7946663a3f7..10df2baa7a5 100644 --- a/staging/src/k8s.io/api/storage/v1beta1/types.go +++ b/staging/src/k8s.io/api/storage/v1beta1/types.go @@ -364,6 +364,43 @@ type CSIDriverSpec struct { // that enable the CSIVolumeFSGroupPolicy feature gate. // +optional FSGroupPolicy *FSGroupPolicy `json:"fsGroupPolicy,omitempty" protobuf:"bytes,5,opt,name=fsGroupPolicy"` + + // 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": { + // "": { + // "token": , + // "expirationTimestamp": , + // }, + // ... + // } + // + // Note: 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. + // + // This is an alpha feature and only available when the + // CSIServiceAccountToken feature is enabled. + // + // +optional + // +listType=atomic + TokenRequests []TokenRequest `json:"tokenRequests,omitempty" protobuf:"bytes,6,opt,name=tokenRequests"` + + // RequiresRepublish indicates the CSI driver wants `NodePublishVolume` + // being periodically called to reflect any possible change in the mounted + // volume. This field defaults to false. + // + // Note: 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. + // + // This is an alpha feature and only available when the + // CSIServiceAccountToken feature is enabled. + // + // +optional + RequiresRepublish *bool `json:"requiresRepublish,omitempty" protobuf:"varint,7,opt,name=requiresRepublish"` } // FSGroupPolicy specifies if a CSI Driver supports modifying @@ -395,6 +432,20 @@ const ( // provided by a CSI driver. More modes may be added in the future. type VolumeLifecycleMode string +// TokenRequest contains parameters of a service account token. +type TokenRequest struct { + // Audience is the intended audience of the token in "TokenRequestSpec". + // It will default to the audiences of kube apiserver. + // + Audience string `json:"audience" protobuf:"bytes,1,opt,name=audience"` + + // ExpirationSeconds is the duration of validity of the token in "TokenRequestSpec". + // It has the same default value of "ExpirationSeconds" in "TokenRequestSpec" + // + // +optional + ExpirationSeconds *int64 `json:"expirationSeconds,omitempty" protobuf:"varint,2,opt,name=expirationSeconds"` +} + const ( // VolumeLifecyclePersistent explicitly confirms that the driver implements // the full CSI spec. It is the default when CSIDriverSpec.VolumeLifecycleModes is not diff --git a/staging/src/k8s.io/api/storage/v1beta1/types_swagger_doc_generated.go b/staging/src/k8s.io/api/storage/v1beta1/types_swagger_doc_generated.go index 60cc4c6a45e..c51950d7c87 100644 --- a/staging/src/k8s.io/api/storage/v1beta1/types_swagger_doc_generated.go +++ b/staging/src/k8s.io/api/storage/v1beta1/types_swagger_doc_generated.go @@ -54,6 +54,8 @@ var map_CSIDriverSpec = map[string]string{ "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. The 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. For 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.", "storageCapacity": "If set to true, 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.\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 is an alpha field and only available when the CSIStorageCapacity feature is enabled. The default is false.", "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. This field is alpha-level, and is only honored by servers that enable the CSIVolumeFSGroupPolicy feature gate.", + "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 \"\": {\n \"token\": ,\n \"expirationTimestamp\": ,\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.\n\nThis is an alpha feature and only available when the CSIServiceAccountToken feature is enabled.", + "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.\n\nThis is an alpha feature and only available when the CSIServiceAccountToken feature is enabled.", } func (CSIDriverSpec) SwaggerDoc() map[string]string { @@ -127,6 +129,16 @@ func (StorageClassList) SwaggerDoc() map[string]string { return map_StorageClassList } +var map_TokenRequest = map[string]string{ + "": "TokenRequest contains parameters of a service account token.", + "audience": "Audience is the intended audience of the token in \"TokenRequestSpec\". It will default to the audiences of kube apiserver.", + "expirationSeconds": "ExpirationSeconds is the duration of validity of the token in \"TokenRequestSpec\". It has the same default value of \"ExpirationSeconds\" in \"TokenRequestSpec\"", +} + +func (TokenRequest) SwaggerDoc() map[string]string { + return map_TokenRequest +} + var map_VolumeAttachment = map[string]string{ "": "VolumeAttachment captures the intent to attach or detach the specified volume to/from the specified node.\n\nVolumeAttachment objects are non-namespaced.", "metadata": "Standard object metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata", diff --git a/staging/src/k8s.io/api/storage/v1beta1/zz_generated.deepcopy.go b/staging/src/k8s.io/api/storage/v1beta1/zz_generated.deepcopy.go index a1538c13195..89a102901ca 100644 --- a/staging/src/k8s.io/api/storage/v1beta1/zz_generated.deepcopy.go +++ b/staging/src/k8s.io/api/storage/v1beta1/zz_generated.deepcopy.go @@ -113,6 +113,18 @@ func (in *CSIDriverSpec) DeepCopyInto(out *CSIDriverSpec) { *out = new(FSGroupPolicy) **out = **in } + if in.TokenRequests != nil { + in, out := &in.TokenRequests, &out.TokenRequests + *out = make([]TokenRequest, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.RequiresRepublish != nil { + in, out := &in.RequiresRepublish, &out.RequiresRepublish + *out = new(bool) + **out = **in + } return } @@ -328,6 +340,27 @@ func (in *StorageClassList) DeepCopyObject() runtime.Object { return nil } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TokenRequest) DeepCopyInto(out *TokenRequest) { + *out = *in + if in.ExpirationSeconds != nil { + in, out := &in.ExpirationSeconds, &out.ExpirationSeconds + *out = new(int64) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TokenRequest. +func (in *TokenRequest) DeepCopy() *TokenRequest { + if in == nil { + return nil + } + out := new(TokenRequest) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *VolumeAttachment) DeepCopyInto(out *VolumeAttachment) { *out = *in diff --git a/staging/src/k8s.io/api/testdata/HEAD/storage.k8s.io.v1.CSIDriver.json b/staging/src/k8s.io/api/testdata/HEAD/storage.k8s.io.v1.CSIDriver.json index 6fe7dbd2b46..9722155d873 100644 --- a/staging/src/k8s.io/api/testdata/HEAD/storage.k8s.io.v1.CSIDriver.json +++ b/staging/src/k8s.io/api/testdata/HEAD/storage.k8s.io.v1.CSIDriver.json @@ -47,6 +47,13 @@ "r鯹)晿\u003co,c鮽ort昍řČ扷5ƗǸ" ], "storageCapacity": true, - "fsGroupPolicy": "/ʕVŚ(ĿȊ甞谐颋DžSǡ" + "fsGroupPolicy": "/ʕVŚ(ĿȊ甞谐颋DžSǡ", + "tokenRequests": [ + { + "audience": "19", + "expirationSeconds": -8506428344202195448 + } + ], + "requiresRepublish": false } } \ No newline at end of file diff --git a/staging/src/k8s.io/api/testdata/HEAD/storage.k8s.io.v1.CSIDriver.pb b/staging/src/k8s.io/api/testdata/HEAD/storage.k8s.io.v1.CSIDriver.pb index fd70e9d3998..79357298d9b 100644 Binary files a/staging/src/k8s.io/api/testdata/HEAD/storage.k8s.io.v1.CSIDriver.pb and b/staging/src/k8s.io/api/testdata/HEAD/storage.k8s.io.v1.CSIDriver.pb differ diff --git a/staging/src/k8s.io/api/testdata/HEAD/storage.k8s.io.v1.CSIDriver.yaml b/staging/src/k8s.io/api/testdata/HEAD/storage.k8s.io.v1.CSIDriver.yaml index 9e7b4cf89c2..21c07739d57 100644 --- a/staging/src/k8s.io/api/testdata/HEAD/storage.k8s.io.v1.CSIDriver.yaml +++ b/staging/src/k8s.io/api/testdata/HEAD/storage.k8s.io.v1.CSIDriver.yaml @@ -33,6 +33,10 @@ spec: attachRequired: false fsGroupPolicy: /ʕVŚ(ĿȊ甞谐颋DžSǡ podInfoOnMount: false + requiresRepublish: false storageCapacity: true + tokenRequests: + - audience: "19" + expirationSeconds: -8506428344202195448 volumeLifecycleModes: - r鯹)晿" && len(vv) != 0)) { foundAttributes.Insert(k) - framework.Logf("Found volume attribute %s: %s", k, v) + framework.Logf("Found volume attribute %s: %s", k, vv) } } } @@ -1584,23 +1658,16 @@ func checkPodLogs(cs clientset.Interface, namespace, driverPodName, driverContai numNodeUnpublishVolume++ } } - if numNodePublishVolume == 0 { - return fmt.Errorf("NodePublish was never called") + if numNodePublishVolume < expectedNumNodePublish { + return fmt.Errorf("NodePublish should be called at least %d", expectedNumNodePublish) } if numNodeUnpublishVolume == 0 { return fmt.Errorf("NodeUnpublish was never called") } - if expectPodInfo { - if foundAttributes.Len() != len(expectedAttributes) { - return fmt.Errorf("number of found volume attributes does not match, expected %d, got %d", len(expectedAttributes), foundAttributes.Len()) - } - return nil + if foundAttributes.Len() != len(expectedAttributes) { + return fmt.Errorf("number of found volume attributes does not match, expected %d, got %d", len(expectedAttributes), foundAttributes.Len()) } - if foundAttributes.Len() != 0 { - return fmt.Errorf("some unexpected volume attributes were found: %+v", foundAttributes.List()) - } - return nil } diff --git a/test/e2e/storage/drivers/csi.go b/test/e2e/storage/drivers/csi.go index 83307ba7d82..1c92cee8d6f 100644 --- a/test/e2e/storage/drivers/csi.go +++ b/test/e2e/storage/drivers/csi.go @@ -253,6 +253,8 @@ type mockCSIDriver struct { enableNodeExpansion bool cleanupHandle framework.CleanupActionHandle javascriptHooks map[string]string + tokenRequests []storagev1.TokenRequest + requiresRepublish *bool } // CSIMockDriverOpts defines options used for csi driver @@ -267,6 +269,8 @@ type CSIMockDriverOpts struct { EnableNodeExpansion bool EnableSnapshot bool JavascriptHooks map[string]string + TokenRequests []storagev1.TokenRequest + RequiresRepublish *bool } var _ testsuites.TestDriver = &mockCSIDriver{} @@ -324,6 +328,8 @@ func InitMockCSIDriver(driverOpts CSIMockDriverOpts) testsuites.TestDriver { attachLimit: driverOpts.AttachLimit, enableNodeExpansion: driverOpts.EnableNodeExpansion, javascriptHooks: driverOpts.JavascriptHooks, + tokenRequests: driverOpts.TokenRequests, + requiresRepublish: driverOpts.RequiresRepublish, } } @@ -425,6 +431,8 @@ func (m *mockCSIDriver) PrepareTest(f *framework.Framework) (*testsuites.PerTest storagev1.VolumeLifecyclePersistent, storagev1.VolumeLifecycleEphemeral, }, + TokenRequests: m.tokenRequests, + RequiresRepublish: m.requiresRepublish, } cleanup, err := utils.CreateFromManifests(f, driverNamespace, func(item interface{}) error { return utils.PatchCSIDeployment(f, o, item) diff --git a/test/e2e/storage/utils/deployment.go b/test/e2e/storage/utils/deployment.go index 2692e833405..c83b9194da6 100644 --- a/test/e2e/storage/utils/deployment.go +++ b/test/e2e/storage/utils/deployment.go @@ -133,6 +133,12 @@ func PatchCSIDeployment(f *framework.Framework, o PatchCSIOptions, object interf if o.VolumeLifecycleModes != nil { object.Spec.VolumeLifecycleModes = *o.VolumeLifecycleModes } + if o.TokenRequests != nil { + object.Spec.TokenRequests = o.TokenRequests + } + if o.RequiresRepublish != nil { + object.Spec.RequiresRepublish = o.RequiresRepublish + } } return nil @@ -180,4 +186,12 @@ type PatchCSIOptions struct { // field *if* the driver deploys a CSIDriver object. Ignored // otherwise. VolumeLifecycleModes *[]storagev1.VolumeLifecycleMode + // If not nil, the value to use for the CSIDriver.Spec.TokenRequests + // field *if* the driver deploys a CSIDriver object. Ignored + // otherwise. + TokenRequests []storagev1.TokenRequest + // If not nil, the value to use for the CSIDriver.Spec.RequiresRepublish + // field *if* the driver deploys a CSIDriver object. Ignored + // otherwise. + RequiresRepublish *bool }